Görüntüyü kaydetmeden önce tuvalin oluşturmayı bitirmesini bekleyin


11

Harita bestecisini kullanarak çeşitli katmanların oluşturulmasını kaydedecek bir komut dosyası yazmaya çalışıyorum. Karşılaştığım sorun, qgis tüm katmanları oluşturmayı tamamlamadan önce komut dosyasının kaydetmesidir.

Diğer birkaç cevaba ( 1 , 2 , 3 ) dayanarak iface.mapCanvas.mapCanvasRefreshed.connect(), görüntü kaydetmeyi bir fonksiyonun içine koymaya çalıştım, ancak yine de aynı sorunla karşılaşıyorum - görüntüler tüm katmanları içermiyor.

Kullandığım kodun yanı sıra ana pencerenin ve kaplamaların nasıl göründüğünün görüntüleri aşağıda listelenmiştir.

Konsol penceresini açıp üç print layerListçizgiyi kaldırırsam , programın görüntüleri kaydetmeden önce oluşturma işleminin bitmesini bekleyeceğini fark ettim . Bunun artan işlem süresinden kaynaklanıp kaynaklanmadığından veya programın çalışma şeklini değiştirip değiştirmediğinden emin değilim.

Tüm katmanlar görüntüye dahil edilecek şekilde bunu nasıl düzgün bir şekilde uygulayabilirim?

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 ana penceresinde neye benziyor (üzerinde görüntülenen rastgele bir raster haritası var): resim açıklamasını buraya girin

Ne kaydedilir: resim açıklamasını buraya girin

Daha fazla bilgi için, Windows 7'de QGIS 2.18.7 kullanıyorum


Ayrıca 1 ve 2 gibi birkaç web sayfasına da başvurdum . Bunları yayınlanmak için eklemeye çalıştım, ancak temsilcim yeterince yüksek değil
EastWest

İkinci geçen doğrultusunda, değiştirilmesi çalış mapCanv.mapCanvasRefreshed.connect(custFunc)ile mapCanv.renderComplete.connect(custFunc)?
Joseph

@Joseph Ne yazık ki, bir fark yaratmadı. Hala yukarıdaki ile aynı sonucu alıyorum
EastWest

Belki katmana eklediğiniz özellikleri yerine getirmeyi deneyin? (yani layerP .commitChanges()). Her ne kadar sadece görüntüyü kaydettiğinizden eminim ki neden yardımcı olması gerektiğini anlamıyorum. Aksi takdirde umarım diğerleri tavsiye :)
Joseph

@Joseph denedim commitChanges()ama maalesef şans yok. Önerin için teşekkürler.
EastWest

Yanıtlar:


5

Burada ortaya çıkan farklı sorunlar var

Ekrana görüntü oluşturma veya görüntü oluşturma

mapCanvasRefreshedTuval ekrana yansıtılırken sinyal tekrar tekrar yayılır. Ekran görüntüsü için bu, kullanıcının bir şey olup olmadığını görmesi veya navigasyonda yardımcı olması için daha hızlı bir geri bildirim sağlar.

Bir dosyaya kaydetmek gibi ekran dışı işleme için bu güvenilir değildir (yalnızca oluşturma yeterince hızlıysa tam bir görüntünüz olacaktır).

Ne yapılabilir: resminizi oluşturmak için harita tuvaline ihtiyacımız yok. Sadece QgsMapSettingsharita tuvalinden kopyalayabiliriz . Bu ayarlar, oluşturucuya gönderilen parametrelerdir ve tüm veri sağlayıcılardan bir raster görüntüsüne neyin tam olarak ve nasıl tam olarak dönüştürülmesi gerektiğini tanımlar.

Harita tuvaline karşı katman kaydı

Kayıt defterine eklenen katmanlar hemen tuvalde değil, yalnızca olay döngüsünün sonraki çalıştırmasında sona erer. Bu nedenle, aşağıdaki iki şeyden birini yapmaktan daha iyisiniz

  • Görüntü oluşturmayı bir zamanlayıcıda başlatın. QTimer.singleShot(10, render_image)

  • QApplication.processEvents()Katmanı ekledikten sonra çalıştırın . Bu işe yarıyor, ancak tehlikeli bir kullanım çağrısı (bazen garip çökmelere neden oluyor) ve bu nedenle kaçınılmalıdır.

Bana kodu göster

Aşağıdaki kod bunu yapar ( QFieldSync'ten biraz ayarlanmış, daha fazla özelleştirme ile ilgileniyorsanız buraya bakın)

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)

1
renderCompleteSinyal çalışmadığı hakkında bir fikriniz var mı?
Joseph

Tüm bilgiler için teşekkürler! Ne yazık ki, komut dosyasıma önerilen kodu eklemeyi denedim, tamamen harita bestecisi bölümünü değiştirdim ve hala aynı sorunla karşılaşıyorum. Kaydedilen görüntüde çizgi veya nokta katmanları bulunmaz, yalnızca önceden yüklenmiş tarama bulunur.
EastWest

Sanırım iş tamamlandı ve görüntü ekrana çekiliyor. painterÜzerinde yayılan bir parametre var, ki bu hala son görüntüde ortaya çıkacak ek şeyler çizebilirsiniz (ve muhtemelen bu yaklaşımı çalıştırabilmek için son görüntüyü de çekebilirsiniz).
Matthias Kuhn

1
Bu çözüm gibi görünüyor. Yardımların için teşekkür ederim. Birisi bunu buluyorsa kısa bir not - QTimer'in düzgün çalışmasını sağlamak için, render_image'den sonra parantez dışında bırakın, aksi takdirde python bir uyarı atar. OkumalısınızQTimer.singleShot(10, render_image)
Eastwest

Hata! Yukarıdaki kodda çözüldü
Matthias Kuhn
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.