Saya mencoba menulis skrip yang akan menyimpan rendering beberapa layer menggunakan komposer peta. Masalah yang saya temui adalah script menyimpan sebelum qgis selesai merender semua layer.
Berdasarkan beberapa jawaban lain ( 1 , 2 , 3 ), saya telah berusaha untuk menggunakan iface.mapCanvas.mapCanvasRefreshed.connect()
dan menempatkan penyimpanan gambar di dalam suatu fungsi, tetapi saya masih menghadapi masalah yang sama - gambar tidak termasuk semua lapisan.
Kode yang saya gunakan, serta gambar-gambar seperti apa tampilan jendela utama dan rendering tercantum di bawah ini.
Saya perhatikan bahwa jika saya memiliki jendela konsol terbuka dan menghapus tanda komentar tiga print layerList
baris, bahwa program akan menunggu render selesai sebelum menyimpan gambar. Saya tidak yakin apakah ini karena peningkatan waktu pemrosesan, atau apakah itu mengubah cara program dijalankan.
Bagaimana cara menerapkan ini dengan benar sehingga semua lapisan termasuk dalam gambar?
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")
Seperti apa di jendela utama QGIS (ada peta raster acak yang sedang ditampilkan):
Sebagai informasi lebih lanjut, saya menggunakan QGIS 2.18.7 pada Windows 7
mapCanv.mapCanvasRefreshed.connect(custFunc)
denganmapCanv.renderComplete.connect(custFunc)
?layerP .commitChanges()
). Meskipun saya tidak mengerti mengapa itu bisa membantu karena Anda hanya menyimpan gambar tetapi patut dicoba kurasa. Kalau tidak mudah-mudahan orang lain dapat menyarankan :)commitChanges()
, tetapi tidak berhasil, sayangnya. Terima kasih untuk sarannya.Jawaban:
Ada berbagai masalah yang muncul di sini
Rendering di layar vs rendering ke gambar
Sinyal
mapCanvasRefreshed
dipancarkan berulang kali saat kanvas ditampilkan ke layar. Untuk tampilan di layar ini memberikan umpan balik yang lebih cepat yang dapat menyenangkan bagi pengguna untuk melihat sesuatu yang terjadi atau membantu dalam navigasi.Untuk rendering di luar layar seperti menyimpan ke file, ini tidak dapat diandalkan (karena Anda hanya akan memiliki gambar lengkap jika renderingnya cukup cepat).
Apa yang bisa dilakukan: kita tidak perlu kanvas peta untuk membuat gambar Anda. Kami hanya dapat menyalin
QgsMapSettings
dari kanvas peta. Pengaturan ini adalah parameter yang dikirim ke renderer dan menentukan apa yang sebenarnya dan bagaimana tepatnya hal-hal yang harus dikonversi dari semua penyedia data ke gambar raster.Registri layer vs kanvas peta
Lapisan yang ditambahkan ke registri tidak berakhir di kanvas segera tetapi hanya dalam menjalankan berikutnya dari acara. Karena itu Anda lebih baik melakukan salah satu dari dua hal berikut ini
Mulai rendering gambar dalam timer.
QTimer.singleShot(10, render_image)
JalankanIni berfungsi tetapi itu adalah panggilan berbahaya untuk digunakan (kadang-kadang menyebabkan crash aneh) dan karenanya harus dihindari.QApplication.processEvents()
setelah menambahkan layer.Tunjukkan kodenya
Kode berikut melakukan ini (sedikit disesuaikan dari QFieldSync , lihat di sana jika Anda tertarik pada lebih banyak penyesuaian)
sumber
renderComplete
sinyal tidak bekerja?painter
dipancarkan di mana Anda masih bisa menggambar hal-hal tambahan yang akan berakhir pada gambar akhir (dan dari mana Anda mungkin juga dapat mengambil gambar akhir untuk membuat pendekatan ini berfungsi).QTimer.singleShot(10, render_image)