Salva Stampa / Mappa vista compositore QGIS come PNG / PDF usando Python (senza cambiare nulla nel layout visibile)?


11

Ho una vista compositore / stampa QGIS aperta con tutti gli elementi regolati come desidero. Ora ho bisogno di stampare / salvare / esportare questo come un file PNG o PDF dalla console Python / script Python.

Non voglio cambiare nulla nel layout attuale. La maggior parte degli esempi che ho trovato (ad esempio: questo ), modifica la posizione o la dimensione della mappa nel PDF di output rispetto a quello che vedo nella mia vista compositore attuale. Desidero ricevere esattamente lo stesso risultato che otterrei quando faccio clic su Stampa -> Esporta come immagine .

Come posso fare ciò? Atlas non è una soluzione per me.

Risposte:


7

Consiglio di usare il seguente script di Tim Sutton come base, ha funzionato bene per me: - http://kartoza.com/how-to-create-a-qgis-pdf-report-with-a-few-lines- di-python /

Basta passare un dict vuoto alla funzione composition.loadFromTemplate () invece della "mappa di sostituzione" che utilizza, poiché non ti interessa quella funzionalità.

Inoltre, poiché hai chiesto "esporta come immagine" anziché "esporta come PDF", devi fare un po 'più di lavoro che utilizzare la funzione membro exportAsPDF ().

Di seguito è una versione modificata del codice di Tim che dovrebbe fare il trucco, lavorando da uno script Python esterno. Impostare il DPI e le variabili del file project + composer come richiesto.

(Se si utilizza la console Python in QGIS invece di farlo come uno script esterno, è possibile ottenere il canvas della mappa corrente utilizzando qgis.iface e non è necessario utilizzare tutto il codice di caricamento del progetto ecc.).

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

Sono interessato a usare il tuo codice. Tuttavia, sto ottenendo una mappa vuota ... ho pubblicato una domanda al riguardo qui se hai qualche idea: gis.stackexchange.com/questions/216376/…
user25976

Sono interessato a usare anche questo. Penso di essere abbastanza vicino, ma ottengo 'AttributeError: l'oggetto' QgsComposerItem 'non ha alcun attributo' setMapCanvas '' Sono in perdita su dove andare da lì.
jamierob,

Come posso trovare il codice nel link in questa risposta? Ho provato su due diversi browser e non riesco a trovare l '"esempio" a cui il post fa riferimento oltrepython generate_pdf.py
Raffaello,

3

Puoi programmarlo da solo o riutilizzare un metodo dal Maps Printerplugin. Descriverò la seconda opzione perché è più semplice.

Devi avere Maps Printerinstallato il plugin, aprire il progetto QGIS con il tuo compositore configurato, aprire la console QGIS Python ed eseguire questo frammento di codice (dovrai regolarlo con le tue impostazioni nella Your settingssezione).

# 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

Dopo averlo eseguito, finirai con un nuovo file in /path/to/export_folder/my composer.png. È inoltre possibile utilizzare '.pdf'come estensione per esportare il compositore come PDF.


3

Forse dai un'occhiata anche alla mia altra risposta, poiché da questo sono nati nuovi strumenti più aggiornati.


Sono arrivato al codice qui sotto che purtroppo non è completamente funzionale. Questo si basa sulla soluzione sopra e su queste altre domande:

Come esportare programmaticamente una composizione come immagine?
Come posso leggere le impostazioni per QgsPaperItem da XML?
Salvataggio di Map Canvas come PNG con sfondo trasparente a livello di programmazione con QGIS?

Il mio codice è in grado di estrarre .qpt da un file .qgs e caricare con successo un compositore dal modello. Inoltre, stampa un compositore in un file .png e visualizza correttamente le etichette e le forme memorizzate nel compositore.

Tuttavia, non riesce a caricare tutti gli elementi relativi alla mappa e ai livelli effettivi (neanche l'etichetta contenente l'espressione dal livello). Penso di essermi perso un po 'su come il progetto deve essere caricato e collegato al compositore.

Alcune persone nel commento dell'articolo originale di Tim Sutton hanno affermato che erano bloccati nella stessa fase sotto Windows (è il mio caso). Questo è davvero frustrante perché sento che la risposta è davvero molto vicina. Cara Internet, per favore, aiutatemi!

Anche questi sono i miei primi tentativi di Python, quindi spero che sarai gentile;)

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



Ho eliminato queste righe dal codice precedente in quanto sembravano non fare nulla. Non hanno generato errori ma non hanno fatto di meglio.

# 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 anche quelli vengono rimossi perché non sembravano necessari quando si utilizza 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()

Ho appena impostato una VM con Unbuntu 14.04 e questo codice funziona come un gioco da ragazzi. Quindi il problema è collegato alla versione Windows di PyQgis (testato su Windows 10 con installazione Osgeo4w64), cercherò se un tracker è già aperto nel tracker dei bug.
MarHoff,

1

Un'altra opzione più aggiornata sarebbe quella di esaminare questi 2 set di strumenti sviluppati dalla comunità QGIS. Poiché Map-sprinter è attivamente supportato, dovresti aspettarti che gli script vengano aggiornati con le prossime versioni di QGIS.

Entrambi gli strumenti forniscono una GUI ma gli script sottostanti sono scritti in Python

Esporta i compositori in file - https://github.com/DelazJ/MapsPrinter
Esporta i compositori da più progetti - https://github.com/gacarrillor/QGIS-Resources

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.