3

I have the following function:

def createScreenshots(layer):
  counter = 0
  for feature in layer.getFeatures():
    counter += 1
    point = feature.geometry().asPoint()
    qgis.utils.iface.mapCanvas().setCenter(point)
    qgis.utils.iface.mapCanvas().refreshAllLayers()
    qgis.utils.iface.mapCanvas().saveAsImage("D:\\\\m\\testing\\" + str(counter) + ".png")

Screenshots are not in real coordinates, .pgw header is not in right coordinates, therefore resulting png images are shifted.

Question: How to wait for rendering of canvas after setCenter is called?

  • Are you aware of the builtin atlas feature in the print composer? – Matthias Kuhn Mar 11 '17 at 20:13
  • In this case, I didn't need Print composition. – Marcel GJS Mar 13 '17 at 14:03
3

You can use QgsMapCanvas.mapCanvasRefreshed SIGNAL to only save the map when canvas has finished painting layers. After saving, zoom to the next feature, and so on.

layer = iface.activeLayer()
ids = layer.allFeatureIds()

def exportMap():
    global ids
    iface.mapCanvas().saveAsImage( u"/output/folder/{}.png".format( ids.pop() ) )
    if ids:
        setNextFeatureExtent()
    else: # We're done
        iface.mapCanvas().mapCanvasRefreshed.disconnect( exportMap )

def setNextFeatureExtent():
    iface.mapCanvas().zoomToFeatureIds( layer, [ids[-1]] )

iface.mapCanvas().mapCanvasRefreshed.connect( exportMap )
setNextFeatureExtent() # Let's start

You could easily adjust the code snippet above to use setExtent() or setCenter() methods, after which you would need to call mapCanvas.refresh() anyway.

2

You may use a QTimer class, which allows waiting some milliseconds before running a specified function/instruction.

The line to use is something like this:

QTimer.singleShot(1000, saveMap)

where the first argument is expressed in milliseconds (1000 ms = 1 second) and the second argument is the function to call.

You may rewrite your original code in this way:

def createScreenshots(layer):
    counter = 0

    def saveMap():
        qgis.utils.iface.mapCanvas().saveAsImage("D:\\\\m\\testing\\" + str(counter) + ".png")

    for feature in layer.getFeatures():
        counter += 1
        point = feature.geometry().asPoint()
        qgis.utils.iface.mapCanvas().setCenter(point)
        qgis.utils.iface.mapCanvas().refreshAllLayers()
        QTimer.singleShot(1000, saveMap)

I think that 1000 milliseconds should be enough for reflecting the changes, otherwise you may adapt it to your specific case.

  • 1
    Thank you, but QGIS is setting center to the last feature and is making screenshot image. Other features are ignored. – Marcel GJS Mar 9 '17 at 15:54
2
ids = None

def createScreenshot4(layer):
  global ids
  ids = layer.allFeatureIds()

  def exportMap():
    global ids
    qgis.utils.iface.mapCanvas().saveAsImage( "D:\\\\ma\\bo\\{}.png".format( ids.pop() ) )
    if ids:
        setNextFeatureExtent()
    else: # We're done
        qgis.utils.iface.mapCanvas().mapCanvasRefreshed.disconnect( exportMap )

  def setNextFeatureExtent():
    reqq = QgsFeatureRequest()
    reqq.setFilterFid(ids[-1])
    for feature in layer.getFeatures(reqq):
        point = feature.geometry().asPoint()
        qgis.utils.iface.mapCanvas().setCenter(point)
        qgis.utils.iface.mapCanvas().refreshAllLayers()


  qgis.utils.iface.mapCanvas().mapCanvasRefreshed.connect( exportMap )
  setNextFeatureExtent() # Let's start

Resulted code with setCenter and refreshAllLayers.

  • Note: the default saveAsImage process gives non-georeferenced PNG files - no SRS in the PGW, or in the PNG itself. You can't change the SRS on PNG files using gdal_edit. The QGIS API docs show that there are two optional parameters that can be passed to iface.mapcanvas().saveAsimage("[filename]" , QPixmap,"[format]"); putting None for QPixmap gives a Python error (global name nullptr is not defined) for every saved image, but the images still save so meh to the error. Then for %f in *.tiff do gdal_edit -a_SRS EPSG:3857 %f ... result: fixed-resolution geoTIFFs. – GT. Jun 20 '17 at 22:30
  • Update : there's clearly something I don't understand about the QPixmap parameter. Everyone who's ever asked about it has set it to None seemingly without incident, but doing so in 2.18.9 will make a loop-based feature-saving script gag every 20 or so features (the Python error notification will change from an ignorable box at the top of the map canvas, to a process-interrupting popup). The .cpp file passes the input to *theQPixmap (at line 665), and if it exists sets the image to be painted to theQPixmap->toImage(), else mMap->contentImage().copy() (at line 673-688). – GT. Jun 20 '17 at 23:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.