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()

Isto inicializa o layout com algumas configurações padrão, especificamente adicionando uma página A4 vazia ao layout. Você pode criar layouts sem chamar o método initializeDefaults(), mas você mesmo terá que se encarregar de adicionar páginas ao layout.

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.

  • mapa — Aqui nós criamos um mapa de um tamanho personalizado e renderizamos a tela do mapa atual

    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))

Uma moldura é desenhada ao redor de cada item por padrão. Você pode removê-la da seguinte forma:

# 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.