Сохранить Print / Map QGIS composer view как PNG / PDF с использованием Python (без изменений в видимом макете)?

11

У меня открывается окно просмотра / печати QGIS со всеми элементами, отрегулированными так, как я хочу. Теперь мне нужно распечатать / сохранить / экспортировать это как файл PNG или PDF из консоли Python / скрипта Python.

Я не хочу ничего менять в текущем макете. Большинство примеров, которые я нашел (например, это ), изменяют положение или размер карты в выходном PDF по сравнению с тем, что я вижу в моем текущем представлении композитора. Я хочу получить точно такой же результат, как и при нажатии «Печать» -> « Экспортировать как изображение» .

Как я могу это сделать? Атлас не является решением для меня.

matandked
источник

Ответы:

7

Я рекомендую использовать следующий сценарий Тима Саттона в качестве основы, он хорошо сработал для меня: - http://kartoza.com/how-to-create-a-qgis-pdf-report-with-a-few-lines- из-Python /

Просто передайте пустой dict в функцию component.loadFromTemplate () вместо «карты замещения», которую он использует, поскольку вас не интересует эта функциональность.

Кроме того, поскольку вы спрашивали о «экспортировать как изображение», а не «экспортировать как PDF», вам придется выполнить немного больше работы, чем использовать функцию-член exportAsPDF ().

Ниже приведена модифицированная версия кода Тима, которая должна сделать свое дело, работая из внешнего скрипта Python. Установите DPI и переменные файла project + composer, как требуется.

(Если вы используете консоль Python в QGIS вместо того, чтобы делать это как внешний скрипт, вы можете получить текущий холст карты, используя 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()
patdevelop
источник
Я заинтересован в использовании вашего кода. Тем не менее, я получаю пустую карту ... Я разместил вопрос об этом здесь, если у вас есть какие-либо идеи: gis.stackexchange.com/questions/216376/…
user25976
Я тоже заинтересован в использовании этого. Я думаю, что я довольно близко, но я получаю 'AttributeError:' QgsComposerItem 'объект не имеет атрибута' setMapCanvas '' Я не знаю, куда идти дальше.
jamierob
Как я могу найти код в ссылке в этом ответе? Я пробовал в двух разных браузерах и, похоже, не могу найти «пример», на который ссылается пост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

Возможно также посмотрите на мой другой ответ, поскольку новые более современные инструменты появились после этого.


Я пришел к приведенному ниже коду, который, к сожалению, не полностью функционален. Это основано на решении выше и на этих других вопросах:

Как программно экспортировать композицию как изображение?
Как я могу прочитать настройки для QgsPaperItem из XML?
Сохранить Map Canvas в формате PNG с прозрачным фоном программно с помощью QGIS?

Мой код может извлечь .qpt из файла .qgs и успешно загрузить композитор из шаблона. Он также печатает композитор в файл .png и правильно отображает метки и формы, хранящиеся в композиторе.

Однако не удается загрузить все элементы, связанные с фактической картой и слоями (метка, содержащая выражение из слоя, также не рисуется). Я думаю, что я немного упустил, как проект должен быть загружен и связан с композитором.

Некоторые люди в комментарии к оригинальной статье Тима Саттона упоминали, что они застряли на одной и той же стадии под 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()
MarHoff
источник
Я только что установил виртуальную машину с Unbuntu 14.04, и этот код работает очень быстро. Так что проблема связана с версией PyQgis для Windows (протестирована на Window10 с установкой Osgeo4w64), я посмотрю, открыт ли тикет в трекере ошибок.
MarHoff
1

Еще один более актуальный вариант - взглянуть на набор инструментов, разработанный сообществом QGIS. Поскольку Map-sprinter активно поддерживается, следует ожидать, что скрипты будут обновлены в следующих версиях QGIS.

Оба инструмента предоставляют графический интерфейс, но базовые сценарии написаны на Python

Экспорт композиторов в файлы - https://github.com/DelazJ/MapsPrinter
Экспорт композиторов из нескольких проектов - https://github.com/gacarrillor/QGIS-Resources

MarHoff
источник