Guardar impresión / mapa QGIS compositor vista como PNG / PDF usando Python (sin cambiar nada en el diseño visible)?
11
Tengo una vista de composición / impresión de QGIS abierta con todos los elementos ajustados como deseo. Ahora necesito imprimir / guardar / exportar esto como un archivo PNG o PDF desde la consola Python / script Python.
No quiero cambiar nada en el diseño actual. La mayoría de los ejemplos que encontré (por ejemplo: esto ), cambian la posición o el tamaño del mapa en el PDF de salida en comparación con lo que veo en mi vista actual del compositor. Deseo recibir exactamente el mismo resultado que obtendría al hacer clic en Imprimir -> Exportar como imagen .
¿Cómo puedo hacer eso? Atlas no es una solución para mí.
Simplemente pase un dict vacío a la función composition.loadFromTemplate () en lugar del 'mapa de sustitución' que usa, ya que no está interesado en esa funcionalidad.
Además, dado que preguntó sobre "exportar como imagen" en lugar de "exportar como PDF", debe hacer un poco más de trabajo que usar la función de miembro exportAsPDF ().
A continuación se muestra una versión modificada del código de Tim que debería funcionar, desde un script externo de Python. Establezca las variables de archivo DPI y project + composer según sea necesario.
(Si está utilizando la consola de Python dentro de QGIS en lugar de hacerlo como un script externo, puede obtener el lienzo del mapa actual usando qgis.iface y no necesita usar todo el código de carga del proyecto, etc.).
import sysfrom qgis.core import(QgsProject,QgsComposition,QgsApplication,QgsProviderRegistry)from qgis.gui importQgsMapCanvas,QgsLayerTreeMapCanvasBridgefromPyQt4.QtCoreimportQFileInfofromPyQt4.QtXmlimportQDomDocument
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 projectQgsProject.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()
Estoy interesado en usar tu código. Sin embargo, obtengo un mapa en blanco ... He publicado una pregunta al respecto aquí si tienes alguna idea: gis.stackexchange.com/questions/216376/…
user25976
Estoy interesado en usar esto también. Creo que estoy bastante cerca, pero obtengo 'AttributeError: el objeto' QgsComposerItem 'no tiene el atributo' setMapCanvas '' No sé a dónde ir desde allí.
jamierob
¿Cómo puedo encontrar el código en el enlace de esta respuesta? He intentado en dos navegadores diferentes y parece que no puedo encontrar el "ejemplo" al que se refiere la publicación más allápython generate_pdf.py
Rafael
3
Puede programarlo usted mismo o reutilizar un método desde el Maps Printercomplemento. Describiré la segunda opción porque es más simple.
Debe tener el Maps Printercomplemento instalado, abrir el proyecto QGIS con su compositor configurado, abrir la consola QGIS Python y ejecutar este fragmento de código (necesitaría ajustarlo con su propia configuración en la Your settingssección).
# 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
Después de ejecutarlo, terminarás con un nuevo archivo /path/to/export_folder/my composer.png. También puede usar '.pdf'como extensión para exportar el compositor como PDF.
Mi código puede extraer el .qpt de un archivo .qgs y cargar con éxito un compositor desde la plantilla. También imprime un compositor en un archivo .png y muestra correctamente las etiquetas y formas almacenadas en el compositor.
Sin embargo, no puede cargar todos los elementos relacionados con el mapa y las capas reales (la etiqueta que contiene la expresión de la capa tampoco se dibuja). Creo que me perdí un poco en cuanto a cómo el proyecto debe cargarse y vincularse al compositor.
Algunas personas en el comentario del artículo original de Tim Sutton mencionaron que estaban atrapados en la misma etapa bajo Windows (es mi caso). Esto es realmente frustrante porque siento que la respuesta está realmente muy cerca. Estimado Internet por favor ayuda!
También este es mi primer intento en Python, así que espero que sea amable;)
#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/17548import sysfromPyQt4.QtCoreimport*fromPyQt4.QtXmlimport*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()
Solté estas líneas del código anterior ya que parecían no hacer nada en absoluto. No generaron ningún error, pero no lo hicieron mejor.
# 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()
y estos también se eliminan porque parecían innecesarios al usar printPageAsRaster ()
Acabo de configurar una máquina virtual con Unbuntu 14.04 y este código funciona como una brisa. Entonces, el problema está vinculado a la versión de Windows de PyQgis (probado en Window10 con la instalación de Osgeo4w64), buscaré si ya hay un ticket abierto en el rastreador de errores.
MarHoff
1
Otra opción más actualizada sería mirar este conjunto de herramientas 2 desarrollado por la comunidad QGIS. Como Map-sprinter es compatible activamente, debe esperar que los scripts se actualicen con las próximas versiones de QGIS.
Ambas herramientas proporcionan una GUI, pero los scripts subyacentes están escritos en Python
python generate_pdf.py
Puede programarlo usted mismo o reutilizar un método desde el
Maps Printer
complemento. Describiré la segunda opción porque es más simple.Debe tener el
Maps Printer
complemento instalado, abrir el proyecto QGIS con su compositor configurado, abrir la consola QGIS Python y ejecutar este fragmento de código (necesitaría ajustarlo con su propia configuración en laYour settings
sección).Después de ejecutarlo, terminarás con un nuevo archivo
/path/to/export_folder/my composer.png
. También puede usar'.pdf'
como extensión para exportar el compositor como PDF.fuente
Tal vez también eche un vistazo a mi otra respuesta, ya que han surgido nuevas herramientas más actualizadas desde esta.
He llegado al siguiente código, que desafortunadamente no es completamente funcional. Esto se basa en la solución anterior y en estas otras preguntas:
¿Cómo exportar mediante programación una composición como imagen?
¿Cómo puedo leer la configuración de QgsPaperItem desde XML?
¿Guardar Map Canvas como PNG con fondo transparente programáticamente con QGIS?
Mi código puede extraer el .qpt de un archivo .qgs y cargar con éxito un compositor desde la plantilla. También imprime un compositor en un archivo .png y muestra correctamente las etiquetas y formas almacenadas en el compositor.
Sin embargo, no puede cargar todos los elementos relacionados con el mapa y las capas reales (la etiqueta que contiene la expresión de la capa tampoco se dibuja). Creo que me perdí un poco en cuanto a cómo el proyecto debe cargarse y vincularse al compositor.
Algunas personas en el comentario del artículo original de Tim Sutton mencionaron que estaban atrapados en la misma etapa bajo Windows (es mi caso). Esto es realmente frustrante porque siento que la respuesta está realmente muy cerca. Estimado Internet por favor ayuda!
También este es mi primer intento en Python, así que espero que sea amable;)
Solté estas líneas del código anterior ya que parecían no hacer nada en absoluto. No generaron ningún error, pero no lo hicieron mejor.
y estos también se eliminan porque parecían innecesarios al usar printPageAsRaster ()
fuente
Otra opción más actualizada sería mirar este conjunto de herramientas 2 desarrollado por la comunidad QGIS. Como Map-sprinter es compatible activamente, debe esperar que los scripts se actualicen con las próximas versiones de QGIS.
Ambas herramientas proporcionan una GUI, pero los scripts subyacentes están escritos en Python
Exportar compositores a archivos - https://github.com/DelazJ/MapsPrinter
Exportar compositores de múltiples proyectos - https://github.com/gacarrillor/QGIS-Resources
fuente