使用Python将Print / Map QGIS composer视图保存为PNG / PDF(不更改可见布局中的任何内容)吗?


11

我打开了QGIS作曲者/打印视图,并根据需要调整了所有元素。现在,我需要从Python控制台/ Python脚本将此文件打印/保存/导出为PNG或PDF文件。

我不想更改当前布局中的任何内容。与我在当前作曲家视图中看到的相比,我发现的大多数示例(例如:this)都会更改输出PDF中的地图位置或大小。我希望获得与单击“打印-> 导出为图像”时得到的结果完全相同的结果。

我怎样才能做到这一点?Atlas对我来说不是解决方案。

Answers:


7

我建议使用蒂姆·萨顿(Tim Sutton)的以下脚本作为基础,它对我来说效果很好:-http : //kartoza.com/how-to-create-a-qgis-pdf-report-with-a-few-lines-的python /

只需将空字典传递给composition.loadFromTemplate()函数而不是他使用的“替换图”,因为您对该功能不感兴趣。

另外,由于您询问的是“导出为图像”而不是“导出为PDF”,因此您必须比使用exportAsPDF()成员函数做更多的工作。

以下是Tim的代码的修改版本,应该可以使用外部Python脚本来解决问题。根据需要设置DPI和project + composer文件变量。

(如果您在QGIS中使用Python控制台而不是作为外部脚本来执行此操作,则可以使用qgis.iface获取当前的地图画布,而无需使用所有项目加载等代码)。

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

我对使用您的代码感兴趣。但是,我得到一个空白的地图......我在这里发布了关于它的问题,如果你碰巧有任何想法:gis.stackexchange.com/questions/216376/...
user25976

我也有兴趣使用它。我想我已经很接近了,但是我得到了'AttributeError:'QgsComposerItem'对象没有属性'setMapCanvas'。我对从那里去哪里一无所知。
jamierob '16

如何在此答案的链接中找到代码?我尝试使用两种不同的浏览器,但似乎找不到该帖子所指的“示例”python generate_pdf.py
raphael

3

您可以自己编程,也可以重用Maps Printer插件中的方法。我将描述第二个选项,因为它更简单。

您需要Maps Printer安装插件,使用配置的作曲家打开QGIS项目,打开QGIS Python控制台并运行此代码段(您需要在本Your settings节中使用自己的设置进行调整)。

# 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

运行之后,您将在中获得一个新文件/path/to/export_folder/my composer.png。您也可以使用'.pdf'扩展名将作曲家导出为PDF。


3

也许也可以看看我的其他答案,因为自从这个工具出现以来,出现了更多新的最新工具。


我来了下面的代码,不幸的是它并没有完全起作用。这是基于上述解决方案以及以下其他问题的:

如何以编程方式将构图导出为图像?
如何从XML读取QgsPaperItem的设置?
使用QGIS以编程方式将Map Canvas保存为具有透明背景的PNG吗?

我的代码能够从.qgs文件中提取.qpt并从模板成功加载作曲家。它还将作曲家打印到.png文件,并正确显示存储在作曲家中的标签和形状。

但是,它无法加载与实际“地图和图层”相关的所有元素(也不会绘制包含来自图层的表达式的标签)。我想我错过了一些关于项目如何加载并链接到作曲家的想法。

有人在评论蒂姆·萨顿(Tim Sutton)的原始文章时提到,他们在Windows下处于同一阶段(这是我的情况)。这真的很令人沮丧,因为我觉得答案真的非常接近。亲爱的互联网请帮忙!

这也是我第一次尝试python,所以我希望你会很友善;)

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



我从前面的代码中删除了这些行,因为它们似乎根本不起作用。他们没有产生任何错误,但没有做得更好。

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

并且那些也被删除,因为在使用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()

我只是用Unbuntu 14.04设置了一个虚拟机,此代码像微风一样工作。因此,该问题与Windows版本的PyQgis相关联(已在Windows10上安装Osgeo4w64进行了测试),我将查看错误跟踪器中是否已打开票证。
MarHoff 2015年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.