2

I have many vector layers which I want to display and print, one at a time. The following script works well for producing an image from the map canvas, but I want to produce an image from a print composer and that part does not work - the images from the print composer show all the layers visible in the map canvas at the time the script is run.

from PyQt4.QtCore import *
from PyQt4.QtGui import *

outputFolder = "C:/Users/fsc/Documents/Temp/"

layers = iface.legendInterface().layers()
settings = iface.mapCanvas().mapSettings()

for lyr in layers:

  # display layer and wait for completion
  settings.setLayers([lyr.id()])
  job = QgsMapRendererParallelJob(settings)
  job.start()
  job.waitForFinished()

  # save image from map canvas
  image = job.renderedImage()
  image.save(outputFolder + lyr.name() + ".png")

  # generate image from print composer
  c = iface.activeComposers()[0].composition()
  c.refreshItems()
  dpi = c.printResolution()
  dpmm = dpi / 25.4
  width = int(dpmm * c.paperWidth())
  height = int(dpmm * c.paperHeight())

  # create output image and initialize it
  image = QImage(QSize(width, height), QImage.Format_ARGB32)
  image.setDotsPerMeterX(dpmm * 1000)
  image.setDotsPerMeterY(dpmm * 1000)
  image.fill(0)

  # render the composition
  imagePainter = QPainter(image)
  sourceArea = QRectF(0, 0, c.paperWidth(), c.paperHeight())
  targetArea = QRectF(0, 0, width, height)
  c.render(imagePainter, targetArea, sourceArea)
  imagePainter.end()

  # save image from print composer
  image.save(outputFolder + lyr.name() + "-comp.png", "png")

I have tried turning the visibility of all layers off and then turning each on inside the loop before producing the output, but in that case the print composer just produces blank maps. (I think that would have worked before the introduction of multi-threaded rendering - MTR - but not now.) Any ideas anyone?

  • I've edited the original post to make the question more explicit and add a full demonstration script. – Rich Burkmar Mar 6 '16 at 19:02
1

This code seems to work for me:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

outputFolder = "C:/Users/fsc/Documents/Temp/"

layers = iface.legendInterface().layers()
settings = iface.mapCanvas().mapSettings()

for lyr in layers:

    # display layer and wait for completion
    settings.setLayers([lyr.id()])
    job = QgsMapRendererParallelJob(settings)
    job.start()
    job.waitForFinished()

    # save image from map canvas
    image = job.renderedImage()
    image.save(outputFolder + lyr.name() + ".png")

    # generate image from print composer
    c = QgsComposition(settings)


    x, y = 0, 0 # define offsets (in mm) for printing
    w, h = c.paperWidth(), c.paperHeight()
    composerMap = QgsComposerMap(c, x ,y, w, h)
    c.addItem(composerMap)

    dpi = c.printResolution()
    c.setPrintResolution(dpi)
    dpmm = dpi / 25.4
    width = int(dpmm * c.paperWidth())
    height = int(dpmm * c.paperHeight())

    # define a QgsRectangle containing the loaded layer and set the layer extent as its extent
    rect = QgsRectangle(settings.fullExtent())
    composerMap.setNewExtent(rect)
    composerMap.updateItem()
    c.addComposerMap(composerMap)

    # create output image and initialize it
    image = QImage(QSize(width, height), QImage.Format_ARGB32)
    image.setDotsPerMeterX(dpmm * 1000)
    image.setDotsPerMeterY(dpmm * 1000)
    image.fill(0)

    # render the composition
    imagePainter = QPainter(image)
    sourceArea = QRectF(0, 0, c.paperWidth(), c.paperHeight())
    targetArea = QRectF(0, 0, width, height)
    c.render(imagePainter, targetArea, sourceArea)
    imagePainter.end()

    # save image from print composer
    image.save(outputFolder + lyr.name() + "-comp.png", "png")

As desired, it prints only one layer per time from the print composer. For this case, I noted that the printed resolution is not optimal (I will try to investigate).

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.