บันทึกมุมมองนักแต่งเพลงพิมพ์ / แผนที่ QGIS เป็น PNG / PDF โดยใช้ Python (โดยไม่ต้องเปลี่ยนอะไรในเค้าโครงที่มองเห็นได้)?


11

ฉันเปิดมุมมองผู้แต่ง / พิมพ์ QGIS พร้อมองค์ประกอบทั้งหมดที่ปรับตามที่ฉันต้องการ ตอนนี้ฉันต้องพิมพ์ / บันทึก / ส่งออกเป็นไฟล์ PNG หรือ PDF จาก Python console / Python script

ฉันไม่ต้องการเปลี่ยนแปลงอะไรในเค้าโครงปัจจุบัน ตัวอย่างส่วนใหญ่ที่ฉันพบ (ตัวอย่างเช่น: สิ่งนี้ ) เปลี่ยนตำแหน่งบนแผนที่หรือขนาดในเอาต์พุต PDF เปรียบเทียบกับสิ่งที่ฉันเห็นในมุมมองนักแต่งเพลงปัจจุบันของฉัน ฉันต้องการที่จะได้รับผลตรงเช่นเดียวกับฉันจะได้รับเมื่อฉันคลิกที่พิมพ์ -> ส่งออกเป็นภาพ

ฉันจะทำสิ่งนั้นได้อย่างไร Atlas ไม่ใช่ทางออกสำหรับฉัน

คำตอบ:


7

ฉันแนะนำให้ใช้สคริปต์ต่อไปนี้โดย Tim Sutton เพื่อเป็นพื้นฐานมันทำงานได้ดีสำหรับฉัน: - http://kartoza.com/how-to-create-a-qgis-pdf-report-with-a-few-lines- ของหลาม /

เพียงส่งคำสั่งที่ว่างไปยังฟังก์ชั่น composition.loadFromTemplate () แทน 'แผนที่ทดแทน' ที่เขาใช้เนื่องจากคุณไม่สนใจฟังก์ชั่นนั้น

นอกจากนี้เมื่อคุณถามเกี่ยวกับ "ส่งออกเป็นภาพ" แทนที่จะเป็น "ส่งออกเป็น PDF" คุณจะต้องทำงานมากกว่าใช้ฟังก์ชัน exportAsPDF () สมาชิกอีกเล็กน้อย

ด้านล่างนี้เป็นรหัสของ Tim ที่ได้รับการแก้ไขซึ่งควรทำเคล็ดลับซึ่งทำงานจากสคริปต์ 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()

ฉันสนใจที่จะใช้รหัสของคุณ อย่างไรก็ตามฉันได้รับแผนที่เปล่า ... ฉันได้โพสต์คำถามเกี่ยวกับที่นี่หากคุณมีความคิดใด ๆ : gis.stackexchange.com/questions/216376/…
user25976

ฉันสนใจที่จะใช้สิ่งนี้เช่นกัน ฉันคิดว่าฉันค่อนข้างใกล้ แต่ฉันได้รับ 'AttributeError:' QgsComposerItem 'วัตถุไม่มีแอตทริบิวต์' setMapCanvas '' ฉันกำลังสูญเสียว่าจะไปจากที่นั่น
jamierob

ฉันจะหารหัสในลิงค์ในคำตอบนี้ได้อย่างไร ฉันได้ลองใช้เบราว์เซอร์ที่แตกต่างกันสองตัวและดูเหมือนจะไม่พบ "ตัวอย่าง" โพสต์ที่อ้างถึงเลยpython generate_pdf.py
ฟาเอล

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 และแสดงฉลากและรูปร่างที่จัดเก็บไว้ในผู้แต่งอย่างถูกต้อง

อย่างไรก็ตามมันล้มเหลวในการโหลดองค์ประกอบทั้งหมดที่เกี่ยวข้องกับแผนที่ & เลเยอร์จริง (ฉลากที่มีการแสดงออกจากเลเยอร์จะไม่ถูกวาด) ฉันคิดว่าฉันพลาดไปเล็กน้อยว่าโครงการจะต้องโหลดและเชื่อมโยงกับผู้แต่งอย่างไร

บางคนในความคิดเห็นของบทความต้นฉบับจาก 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 : https://gis.stackexchange.com/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()

ฉันเพิ่งตั้งค่า VM ด้วย Unbuntu 14.04 และรหัสนี้ทำงานเหมือนสายลม ดังนั้นปัญหาถูกเชื่อมโยงกับ PyQgis เวอร์ชั่น Windows (ทดสอบบน Window10 พร้อมติดตั้ง Osgeo4w64) ฉันจะดูว่าตั๋วเปิดอยู่แล้วในตัวติดตามบั๊ก
MarHoff

1

อีกตัวเลือกที่ทันสมัยมากขึ้นคือการดูเครื่องมือ 2 ชุดที่พัฒนาโดยชุมชน QGIS เนื่องจาก Map-sprinter ได้รับการสนับสนุนอย่างแข็งขันคุณควรคาดหวังว่าสคริปต์จะได้รับการอัพเดตด้วย QGIS รุ่นที่กำลังจะมาถึง

เครื่องมือทั้งสองมี GUI แต่สคริปต์พื้นฐานเขียนด้วย Python

ส่งออกผู้แต่งไปยังไฟล์ - https://github.com/DelazJ/MapsPrinter
ส่งออกผู้แต่งจากหลายโครงการ - https://github.com/gacarrillor/QGIS-Resources

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.