10. Renderização em impressão de mapas

Dica

Os trechos de código nesta página precisam das seguintes importações:

 1import os
 2
 3from qgis.core import (
 4    QgsGeometry,
 5    QgsMapSettings,
 6    QgsPrintLayout,
 7    QgsMapSettings,
 8    QgsMapRendererParallelJob,
 9    QgsLayoutItemLabel,
10    QgsLayoutItemLegend,
11    QgsLayoutItemMap,
12    QgsLayoutItemPolygon,
13    QgsLayoutItemScaleBar,
14    QgsLayoutExporter,
15    QgsLayoutItem,
16    QgsLayoutPoint,
17    QgsLayoutSize,
18    QgsUnitTypes,
19    QgsProject,
20    QgsFillSymbol,
21)
22
23from qgis.PyQt.QtGui import (
24    QPolygonF,
25    QColor,
26)
27
28from qgis.PyQt.QtCore import (
29    QPointF,
30    QRectF,
31    QSize,
32)

Geralmente, existem duas abordagens em que os dados de entrada devem ser renderizados como um mapa: seja rápido usando QgsMapRendererJob ou produza uma saída mais ajustada compondo o mapa com a classe QgsLayout.

10.1. Renderização simples

A renderização é feita criando um objeto QgsMapSettings para definir as configurações de renderização e, em seguida, construindo um QgsMapRendererJob com essas configurações. O último é usado para criar a imagem resultante.

He aquí un ejemplo:

 1image_location = os.path.join(QgsProject.instance().homePath(), "render.png")
 2
 3vlayer = iface.activeLayer()
 4settings = QgsMapSettings()
 5settings.setLayers([vlayer])
 6settings.setBackgroundColor(QColor(255, 255, 255))
 7settings.setOutputSize(QSize(800, 600))
 8settings.setExtent(vlayer.extent())
 9
10render = QgsMapRendererParallelJob(settings)
11
12def finished():
13    img = render.renderedImage()
14    # save the image; e.g. img.save("/Users/myuser/render.png","png")
15    img.save(image_location, "png")
16
17render.finished.connect(finished)
18
19# Start the rendering
20render.start()
21
22# The following loop is not normally required, we
23# are using it here because this is a standalone example.
24from qgis.PyQt.QtCore import QEventLoop
25loop = QEventLoop()
26render.finished.connect(loop.quit)
27loop.exec_()

10.2. Renderizando camadas com CRS diferente

Se você tiver mais de uma camada e eles tiverem SRC diferente, o exemplo simples acima provavelmente não funcionará: para obter os valores corretos a partir dos cálculos de extensão, você deve definir explicitamente o SRC de destino

layers = [iface.activeLayer()]
settings = QgsMapSettings()
settings.setLayers(layers)
settings.setDestinationCrs(layers[0].crs())

10.3. Saída usando layout de impressão

O layout de impressão é uma ferramenta muito útil se você deseja obter uma saída mais sofisticada do que a simples renderização mostrada acima. É possível criar layouts de mapas complexos que consistem em visualizações de mapas, rõtulos, legendas, tabelas e outros elementos que geralmente estão presentes nos mapas em papel. Os layouts podem ser exportados para PDF, imagens raster ou diretamente impressas em uma impressora.

O layout consiste de várias classes. Todos eles pertencem à biblioteca principal. O aplicativo QGIS possui uma GUI conveniente para a colocação dos elementos, embora não esteja disponível na biblioteca da GUI. Se você não estiver familiarizado com a estrutura Qt Graphics View, recomendamos que verifique a documentação agora, porque o layout é baseado nela .

A classe central do layout é a classe QgsLayout, que é derivada da classe Qt QGraphicsScene. Vamos criar uma instância dele:

project = QgsProject.instance()
layout = QgsPrintLayout(project)
layout.initializeDefaults()

This initializes the layout with some default settings, specifically by adding an empty A4 page to the layout. You can create layouts without calling the initializeDefaults() method, but you’ll need to take care of adding pages to the layout yourself.

The previous code creates a “temporary” layout that is not visible in the GUI. It can be handy to e.g. quickly add some items and export without modifying the project itself nor expose these changes to the user. If you want the layout to be saved/restored along with the project and available in the layout manager, then add:

layout.setName("MyLayout")
project.layoutManager().addLayout(layout)

Agora podemos adicionar vários elementos (mapa, rõtulo, …) ao layout. Todos esses objetos são representados por classes que herdam da classe base QgsLayoutItem.

Aqui está uma descrição de alguns dos principais itens de layout que podem ser adicionados a um layout.

  • map — Here we create a map of a custom size and render the current map canvas

    1map = QgsLayoutItemMap(layout)
    2# Set map item position and size (by default, it is a 0 width/0 height item placed at 0,0)
    3map.attemptMove(QgsLayoutPoint(5,5, QgsUnitTypes.LayoutMillimeters))
    4map.attemptResize(QgsLayoutSize(200,200, QgsUnitTypes.LayoutMillimeters))
    5# Provide an extent to render
    6map.zoomToExtent(iface.mapCanvas().extent())
    7layout.addLayoutItem(map)
    
  • label — permite exibir rótulos. É possível modificar a sua fonte, cor, alinhamento e margem

    label = QgsLayoutItemLabel(layout)
    label.setText("Hello world")
    label.adjustSizeToText()
    layout.addLayoutItem(label)
    
  • legenda

    legend = QgsLayoutItemLegend(layout)
    legend.setLinkedMap(map) # map is an instance of QgsLayoutItemMap
    layout.addLayoutItem(legend)
    
  • barra de escala

    1item = QgsLayoutItemScaleBar(layout)
    2item.setStyle('Numeric') # optionally modify the style
    3item.setLinkedMap(map) # map is an instance of QgsLayoutItemMap
    4item.applyDefaultSize()
    5layout.addLayoutItem(item)
    
  • Seta

  • Imagem

  • forma básica

  • forma baseada em nós

     1polygon = QPolygonF()
     2polygon.append(QPointF(0.0, 0.0))
     3polygon.append(QPointF(100.0, 0.0))
     4polygon.append(QPointF(200.0, 100.0))
     5polygon.append(QPointF(100.0, 200.0))
     6
     7polygonItem = QgsLayoutItemPolygon(polygon, layout)
     8layout.addLayoutItem(polygonItem)
     9
    10props = {}
    11props["color"] = "green"
    12props["style"] = "solid"
    13props["style_border"] = "solid"
    14props["color_border"] = "black"
    15props["width_border"] = "10.0"
    16props["joinstyle"] = "miter"
    17
    18symbol = QgsFillSymbol.createSimple(props)
    19polygonItem.setSymbol(symbol)
    
  • Tabela

Depois que um item é adicionado ao layout, ele pode ser movido e redimensionado:

item.attemptMove(QgsLayoutPoint(1.4, 1.8, QgsUnitTypes.LayoutCentimeters))
item.attemptResize(QgsLayoutSize(2.8, 2.2, QgsUnitTypes.LayoutCentimeters))

A frame is drawn around each item by default. You can remove it as follows:

# for a composer label
label.setFrameEnabled(False)

Além de criar os itens de layout manualmente, o QGIS oferece suporte a modelos de layout que são essencialmente composições com todos os itens salvos em um arquivo .qpt (com sintaxe XML).

Quando a composição estiver pronta (os itens de layout foram criados e adicionados à composição), podemos continuar produzindo uma saída raster e/ou vetorial.

10.3.1. Exportando o layout

Para exportar um layout, a classe :class: QgsLayoutExporter <qgis.core.QgsLayoutExporter> deve ser usada.

1base_path = os.path.join(QgsProject.instance().homePath())
2pdf_path = os.path.join(base_path, "output.pdf")
3
4exporter = QgsLayoutExporter(layout)
5exporter.exportToPdf(pdf_path, QgsLayoutExporter.PdfExportSettings())

Use exportToImage () caso deseje exportar para uma imagem em vez de um arquivo PDF.

10.3.2. Exportando um atlas como layout

Se você deseja exportar todas as páginas de um layout que tenha a opção atlas configurada e ativada, use o método atlas () no exportador (:class:` QgsLayoutExporter <qgis.core.QgsLayoutExporter>`) com pequenos ajustes. No exemplo a seguir, as páginas são exportadas para imagens PNG:

exporter.exportToImage(layout.atlas(), base_path, 'png', QgsLayoutExporter.ImageExportSettings())

Observe que as saídas serão salvas na pasta do caminho base, usando a expressão do nome do arquivo de saída configurada no atlas.