Salvar a visualização do compositor de impressão / mapa QGIS como PNG / PDF usando Python (sem alterar nada no layout visível)?

11

Eu tenho uma visualização do compositor / impressão do QGIS aberta com todos os elementos ajustados conforme desejar. Agora eu preciso imprimir / salvar / exportar isso como um arquivo PNG ou PDF a partir do console Python / script Python.

Não quero mudar nada no layout atual. A maioria dos exemplos que encontrei (por exemplo: isto ) altera uma posição ou tamanho do mapa no PDF de saída, comparando com o que vejo na minha visualização atual do compositor. Desejo receber exatamente o mesmo resultado que obteria ao clicar em Imprimir -> Exportar como imagem .

Como eu posso fazer isso? Atlas não é uma solução para mim.

matandked
fonte

Respostas:

7

Eu recomendo usar o seguinte script de Tim Sutton como base, funcionou bem para mim: - http://kartoza.com/how-to-create-a-qgis-pdf-report-with-a-few-lines- of-python /

Basta passar um ditado vazio para a função composition.loadFromTemplate () em vez do 'mapa de substituição' que ele usa, pois você não está interessado nessa funcionalidade.

Além disso, como você perguntou sobre "exportar como imagem" em vez de "exportar como PDF", é necessário um pouco mais de trabalho do que usar a função de membro exportAsPDF ().

Abaixo está uma versão modificada do código de Tim que deve fazer o truque, trabalhando a partir de um script Python externo. Defina as variáveis ​​de DPI e projeto + compositor, conforme necessário.

(Se você estiver usando o console Python no QGIS, em vez de fazer isso como um script externo, poderá obter a tela de mapa atual usando o qgis.iface e não precisará usar todo o projeto que carrega o código etc).

import sys
from qgis.core import (
    QgsProject, QgsComposition, QgsApplication, QgsProviderRegistry)
from qgis.gui import QgsMapCanvas, QgsLayerTreeMapCanvasBridge
from PyQt4.QtCore import QFileInfo
from PyQt4.QtXml import QDomDocument

gui_flag = True
app = QgsApplication(sys.argv, gui_flag)

# Make sure QGIS_PREFIX_PATH is set in your env if needed!
app.initQgis()

# Probably you want to tweak this
project_path = 'project.qgs'

# and this
template_path = 'template.qpt'

# Set output DPI
dpi = 300

canvas = QgsMapCanvas()
# Load our project
QgsProject.instance().read(QFileInfo(project_path))
bridge = QgsLayerTreeMapCanvasBridge(
    QgsProject.instance().layerTreeRoot(), canvas)
bridge.setCanvasLayers()

template_file = file(template_path)
template_content = template_file.read()
template_file.close()
document = QDomDocument()
document.setContent(template_content)
ms = canvas.mapSettings())
composition = QgsComposition(ms)
composition.loadFromTemplate(document, {})
# You must set the id in the template
map_item = composition.getComposerItemById('map')
map_item.setMapCanvas(canvas)
map_item.zoomToExtent(canvas.extent())
# You must set the id in the template
legend_item = composition.getComposerItemById('legend')
legend_item.updateLegend()
composition.refreshItems()

dpmm = dpi / 25.4
width = int(dpmm * composition.paperWidth())
height = int(dpmm * composition.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)
composition.renderPage(imagePainter, 0)
imagePainter.end()

image.save("out.png", "png")

QgsProject.instance().clear()
QgsApplication.exitQgis()
patdevelop
fonte
Estou interessado em usar seu código. No entanto, estou ficando um mapa em branco ... Eu postei uma pergunta sobre isso aqui, se acontecer de você ter quaisquer ideias: gis.stackexchange.com/questions/216376/...
user25976
Estou interessado em usar isso também. Acho que estou bem perto, mas recebo o objeto 'AttributeError:' QgsComposerItem 'não tem nenhum atributo' setMapCanvas '' Estou sem saber o que fazer a partir daí.
jamierob
Como posso encontrar o código no link nesta resposta? Eu tentei em dois navegadores diferentes e não consigo encontrar o "exemplo" o post refere-se alémpython generate_pdf.py
raphael
3

Você pode programá-lo sozinho ou reutilizar um método do Maps Printerplug - in. Vou descrever a segunda opção porque é mais simples.

Você precisa ter o Maps Printerplug - in instalado, abrir o projeto QGIS com o compositor configurado, abrir o console do QGIS Python e executar esse trecho de código (você precisará ajustá-lo com suas próprias configurações na Your settingsseção).

# Your settings
composerTitle = 'my composer' # Name of the composer you want to export
folder = '/path/to/export_folder/'
extension = '.png' # Any extension supported by the plugin

mp = qgis.utils.plugins['MapsPrinter']

for composer in iface.activeComposers():
    title = composer.composerWindow().windowTitle()
    if title == composerTitle:
        mp.exportCompo( composer, folder, title, extension )
        break

Após executá-lo, você terminará com um novo arquivo /path/to/export_folder/my composer.png. Você também pode usar '.pdf'como extensão para exportar o compositor como PDF.

Germán Carrillo
fonte
3

Talvez também dê uma olhada na minha outra resposta, pois novas ferramentas mais atualizadas surgiram desde essa.


Eu vim para o código abaixo, que infelizmente não é totalmente funcional. Isso se baseia na solução acima e em outras questões:

Como exportar programaticamente uma composição como imagem?
Como posso ler as configurações do QgsPaperItem do XML?
Salvar o Canvas do mapa como PNG com fundo transparente programaticamente com o QGIS?

Meu código é capaz de extrair o .qpt de um arquivo .qgs e carregar com êxito um compositor do modelo. Também imprime um compositor em um arquivo .png e exibe corretamente as etiquetas e formas armazenadas no compositor.

No entanto, ele falha ao carregar todos os elementos relacionados ao Mapa e Camadas reais (o rótulo que contém a expressão da camada também não é desenhado). Acho que perdi um pouco de como o projeto deve ser carregado e vinculado ao compositor.

Algumas pessoas no comentário do artigo original de Tim Sutton mencionaram que estavam presas no mesmo estágio no Windows (é o meu caso). Isso é realmente frustrante, porque sinto que a resposta está realmente muito próxima. Caro Internet, por favor me ajude!

Além disso, esta é a minha primeira tentativa de python, então eu espero que você seja gentil;)

#This python code aim to programmatically export the first composer stored in a qgs file using PyQgis API v 2.10
#Version 0.4 (non functional) WTFPL MarHoff 2015 - This code is mostly a "frankenstein" stub made with a lot of other snippets. Feel welcome to improve!
#Credits to gis.stackexchange community : drnextgis,ndawson,patdevelop,dakcarto,ahoi, underdark & Tim Sutton from kartoza
#More informations and feedback can be found at /gis/144792/

#This script assume your environement is setup for PyGis as a stand-alone script. Some nice hints for windows users : /gis//a/130102/17548

import sys
from PyQt4.QtCore import *
from PyQt4.QtXml import *
from qgis.core import *
from qgis.gui import *

gui_flag = True
app = QgsApplication(sys.argv, gui_flag)

# Make sure QGIS_PREFIX_PATH is set in your env if needed!
app.initQgis()

# Name of the .qgs file without extension
project_name = 'myproject'

#Important : The code is assuming that the .py file is in the same folder as the project
folderPath = QString(sys.path[0])+'/'
projectPath = QString(folderPath+project_name+'.qgs')
templatePath = QString(folderPath+project_name+'_firstcomposer.qpt')
imagePath = QString(folderPath+project_name+'.png')

#Getting project as Qfile and the first composer of the project as a QDomElement from the .qgs
projectAsFile = QFile(projectPath)
projectAsDocument = QDomDocument()
projectAsDocument.setContent(projectAsFile)
composerAsElement = projectAsDocument.elementsByTagName("Composer").at(0).toElement()

#This block store the composer into a template file
templateFile = QFile(templatePath)
templateFile.open(QIODevice.WriteOnly)
out = QTextStream(templateFile)
#I need next line cause UTF-8 is somewhat tricky in my setup, comment out if needed
out.setCodec("UTF-8")
param = QString
composerAsElement.save(out,2)
templateFile.close()

#And this block load back the composer into a QDomDocument
#Nb: This is ugly as hell, i guess there is a way to convert a QDomElement to a QDomDocument but every attemps failed on my side...
composerAsDocument = QDomDocument()
composerAsDocument.setContent(templateFile)

#Now that we got all we can open our project
canvas = QgsMapCanvas()
QgsProject.instance().read(QFileInfo(projectAsFile))
bridge = QgsLayerTreeMapCanvasBridge(
    QgsProject.instance().layerTreeRoot(), canvas)
bridge.setCanvasLayers()


#Lets try load that composer template we just extracted
composition = QgsComposition(canvas.mapSettings())
composition.loadFromTemplate(composerAsDocument, {})


#And lets print in our .png
image = composition.printPageAsRaster(0)
image.save(imagePath,'png')

#Some cleanup maybe?
QgsProject.instance().clear()
QgsApplication.exitQgis()



Larguei essas linhas do código anterior, pois elas pareciam não fazer nada. Eles não geraram erros, mas não se saíram melhor.

# You must set the id in the template
map_item = composition.getComposerItemById('map')
map_item.setMapCanvas(canvas)
map_item.zoomToExtent(canvas.extent())
# You must set the id in the template
legend_item = composition.getComposerItemById('legend')
legend_item.updateLegend()
composition.refreshItems()

e essas também são removidas porque pareciam desnecessárias ao usar printPageAsRaster ()

dpmm = dpi / 25.4
width = int(dpmm * composition.paperWidth())
height = int(dpmm * composition.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)
composition.renderPage(imagePainter, 0)
imagePainter.end()
MarHoff
fonte
Acabei de configurar uma VM com o Unbuntu 14.04 e esse código funciona como uma brisa. Portanto, como o problema está vinculado à versão do PyQgis para Windows (testada no Window10 com a instalação do Osgeo4w64), examinarei se um ticket já está aberto no rastreador de erros.
MarHoff 28/09
1

Outra opção mais atualizada seria examinar esses 2 conjuntos de ferramentas desenvolvidas pela comunidade QGIS. Como o Map-sprinter é suportado ativamente, você deve esperar que os scripts sejam atualizados com as próximas versões do QGIS.

Ambas as ferramentas fornecem uma GUI, mas os scripts subjacentes são escritos em Python

Exportar compositores para arquivos - https://github.com/DelazJ/MapsPrinter
Exportar compositores de vários projetos - https://github.com/gacarrillor/QGIS-Resources

MarHoff
fonte