이미지를 저장하기 전에 캔버스가 렌더링을 완료 할 때까지 기다리십시오. 또는 프로그램 실행 방법이 변경되는지 확실하지 않습니다. 모든

지도 작성기를 사용하여 여러 레이어의 렌더링을 저장하는 스크립트를 작성하려고합니다. 내가 겪고있는 문제는 qgis가 모든 레이어 렌더링을 완료하기 전에 스크립트가 저장된다는 것입니다.

몇 가지 다른 답변 ( 1 , 2 , 3 )을 기반으로 iface.mapCanvas.mapCanvasRefreshed.connect()이미지 저장 기능 을 사용 하고 함수 내부에 넣으 려고 했지만 여전히 동일한 문제가 발생합니다. 이미지에 모든 레이어가 포함되어 있지 않습니다.

내가 사용하는 코드와 기본 창 및 렌더링 이미지는 다음과 같습니다.

콘솔 창을 열고 세 print layerList줄의 주석 처리를 제거 하면 이미지를 저장하기 전에 프로그램이 렌더링이 완료 될 때까지 기다립니다. 처리 시간이 길어 졌는지 또는 프로그램 실행 방법이 변경되는지 확실하지 않습니다.

모든 레이어가 이미지에 포함되도록 어떻게 올바르게 구현합니까?

from qgis.core import *
from qgis.utils import *
from qgis.gui import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import os.path

##StackExchange Version=name
##Map_Save_Folder=folder
##Map_Save_Name=string roadmap

# Create save file location
mapName = "%s.png" %Map_Save_Name
outfile = os.path.join(Map_Save_Folder,mapName)
pdfName = "%s.pdf" %Map_Save_Name
outPDF = os.path.join(Map_Save_Folder,pdfName)

# Create point and line layers for later
URIstrP = "Point?crs=EPSG:3035"
layerP = QgsVectorLayer(URIstrP,"pointsPath","memory")
provP = layerP.dataProvider()
URIstrL = "LineString?crs=EPSG:3035"
layerL = QgsVectorLayer(URIstrL,"linePath","memory")
provL = layerL.dataProvider()

# Add points to point layer
feat1 = QgsFeature()
feat2 = QgsFeature()
feat3 = QgsFeature()
feat1.setGeometry(QgsGeometry.fromPoint(QgsPoint(5200000,2600000)))
feat2.setGeometry(QgsGeometry.fromPoint(QgsPoint(5300000,2800000)))
provP.addFeatures([feat1, feat2])

# Add line to line layer
feat3.setGeometry(QgsGeometry.fromPolyline([feat1.geometry().asPoint(),feat2.geometry().asPoint()]))
provL.addFeatures([feat3])

# Set symbology for line layer
symReg = QgsSymbolLayerV2Registry.instance()
metaRegL = symReg.symbolLayerMetadata("SimpleLine")
symLayL = QgsSymbolV2.defaultSymbol(layerL.geometryType())
metaL = metaRegL.createSymbolLayer({'width':'1','color':'0,0,0'})
symLayL.deleteSymbolLayer(0)
symLayL.appendSymbolLayer(metaL)
symRendL = QgsSingleSymbolRendererV2(symLayL)
layerL.setRendererV2(symRendL)

# Set symbology for point layer
metaRegP = symReg.symbolLayerMetadata("SimpleMarker")
symLayP = QgsSymbolV2.defaultSymbol(layerP.geometryType())
metaP = metaRegP.createSymbolLayer({'size':'3','color':'0,0,0'})
symLayP.deleteSymbolLayer(0)
symLayP.appendSymbolLayer(metaP)
symRendP = QgsSingleSymbolRendererV2(symLayP)
layerP.setRendererV2(symRendP)

# Load the layers
QgsMapLayerRegistry.instance().addMapLayer(layerP)
QgsMapLayerRegistry.instance().addMapLayer(layerL)
iface.mapCanvas().refresh()


# --------------------- Using Map Composer -----------------
def custFunc():
    mapComp.exportAsPDF(outPDF)
    mapImage.save(outfile,"png")
    mapCanv.mapCanvasRefreshed.disconnect(custFunc)
    return

layerList = []
for layer in QgsMapLayerRegistry.instance().mapLayers().values():
    layerList.append(layer.id())
#print layerList
#print layerList
#print layerList

mapCanv = iface.mapCanvas()
bound = layerP.extent()
bound.scale(1.25)
mapCanv.setExtent(bound)

mapRend = mapCanv.mapRenderer()
mapComp = QgsComposition(mapRend)
mapComp.setPaperSize(250,250)
mapComp.setPlotStyle(QgsComposition.Print)

x, y = 0, 0
w, h = mapComp.paperWidth(), mapComp.paperHeight()

composerMap = QgsComposerMap(mapComp, x, y, w, h)
composerMap.zoomToExtent(bound)
mapComp.addItem(composerMap)
#mapComp.exportAsPDF(outPDF)

mapRend.setLayerSet(layerList)
mapRend.setExtent(bound)

dpmm = dpmm = mapComp.printResolution() / 25.4
mapImage = QImage(QSize(int(dpmm*w),int(dpmm*h)), QImage.Format_ARGB32)
mapImage.setDotsPerMeterX(dpmm * 1000)
mapImage.setDotsPerMeterY(dpmm * 1000)

mapPaint = QPainter()
mapPaint.begin(mapImage)

mapRend.render(mapPaint)

mapComp.renderPage(mapPaint,0)
mapPaint.end()
mapCanv.mapCanvasRefreshed.connect(custFunc)
#mapImage.save(outfile,"png")

QGIS 메인 창에 보이는 모습 (임의의 래스터 맵이 표시됩니다) :
여기에 이미지 설명을 입력하십시오

저장되는 내용 :

추가 정보로 Windows 7에서 QGIS 2.18.7을 사용하고 있습니다.



답변

여기에 떠오르는 다른 문제가 있습니다

화면에서의 렌더링 및 이미지로의 렌더링

mapCanvasRefreshed캔버스가 화면에 렌더링되는 동안 신호 가 반복적으로 방출됩니다. 화면 표시의 경우 사용자가 진행중인 작업을 보거나 탐색에 도움을 줄 수있는 빠른 피드백을 제공합니다.

파일로 저장하는 것과 같은 오프 스크린 렌더링의 경우 신뢰할 수 없습니다 (렌더링이 충분히 빠르면 완전한 이미지 만 제공되므로).

수행 할 수있는 작업 : 이미지를 렌더링하기 위해 맵 캔버스가 필요하지 않습니다. QgsMapSettings맵 캔버스에서를 복사하면 됩니다. 이 설정은 렌더러로 전송되는 매개 변수이며 모든 데이터 제공 업체에서 래스터 이미지로 정확히 무엇이 정확하게 변환되어야 하는지를 정의합니다.

레이어 레지스트리와 맵 캔버스

레지스트리에 추가 된 레이어는 캔버스에서 즉시 끝나지 않고 다음 이벤트 루프 실행시에만 나타납니다. 따라서 다음 두 가지 중 하나를 수행하는 것이 좋습니다.

  • 타이머에서 이미지 렌더링을 시작하십시오. QTimer.singleShot(10, render_image)

  • QApplication.processEvents()레이어를 추가 한 후 실행하십시오 . 이것은 작동하지만 사용하기에 위험한 전화 (때로는 이상한 충돌로 이어짐)를 피해야합니다.

코드를 보여줘

다음 코드는 이것을 수행합니다 ( QFieldSync 에서 약간 조정 , 더 많은 사용자 정의에 관심이 있다면 거기를 살펴보십시오)

from PyQt4.QtGui import QImage, QPainter

def render_image():
    size = iface.mapCanvas().size()
    image = QImage(size, QImage.Format_RGB32)

    painter = QPainter(image)
    settings = iface.mapCanvas().mapSettings()

    # You can fine tune the settings here for different
    # dpi, extent, antialiasing...
    # Just make sure the size of the target image matches

    # You can also add additional layers. In the case here,
    # this helps to add layers that haven't been added to the
    # canvas yet
    layers = settings.layers()
    settings.setLayers([layerP.id(), layerL.id()] + layers)

    job = QgsMapRendererCustomPainterJob(settings, painter)
    job.renderSynchronously()
    painter.end()
    image.save('/tmp/image.png')

# If you don't want to add additional layers manually to the
# mapSettings() you can also do this:
# Give QGIS give a tiny bit of time to bring the layers from 
# the registry to the canvas (the 10 ms do not matter, the important
# part is that it's posted to the event loop)

# QTimer.singleShot(10, render_image)