Simpan Cetak / Peta tampilan komponis QGIS sebagai PNG / PDF menggunakan Python (tanpa mengubah apa pun dalam tata letak yang terlihat)?

11

Saya memiliki tampilan komposer / cetak QGIS dibuka dengan semua elemen disesuaikan seperti yang saya inginkan. Sekarang saya perlu mencetak / menyimpan / mengekspor ini sebagai file PNG atau PDF dari Python console / Python script.

Saya tidak ingin mengubah apa pun dalam tata letak saat ini. Sebagian besar contoh yang saya temukan (misalnya: ini ), mengubah posisi atau ukuran peta dalam output PDF dibandingkan dengan apa yang saya lihat dalam tampilan komposer saya saat ini. Saya ingin menerima hasil yang persis sama dengan yang saya dapatkan ketika saya mengklik Cetak -> Ekspor sebagai Gambar .

Bagaimana saya bisa melakukan itu? Atlas bukan solusi bagi saya.

matandked
sumber

Jawaban:

7

Saya sarankan menggunakan skrip berikut oleh Tim Sutton sebagai basis, itu bekerja dengan baik untuk saya: - http://kartoza.com/how-to-create-a-qgis-pdf-report-with-a-few-lines- dari-python /

Cukup berikan dict kosong ke fungsi komposisi.loadFromTemplate () alih-alih 'peta substitusi' yang digunakannya, karena Anda tidak tertarik dengan fungsionalitas itu.

Juga, karena Anda bertanya tentang "ekspor sebagai gambar" daripada "ekspor sebagai PDF", Anda harus melakukan lebih banyak pekerjaan daripada menggunakan fungsi anggota exportAsPDF ().

Di bawah ini adalah versi modifikasi dari kode Tim yang seharusnya melakukan trik, bekerja dari skrip Python eksternal. Tetapkan DPI, dan variabel file proyek + komposer sesuai kebutuhan.

(Jika Anda menggunakan konsol Python dalam QGIS daripada melakukan ini sebagai skrip eksternal, Anda bisa mendapatkan kanvas peta saat ini menggunakan qgis.iface dan tidak perlu menggunakan semua proyek yang memuat kode dll).

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()
pengembangan
sumber
Saya tertarik menggunakan kode Anda. Namun, saya mendapatkan peta kosong ... saya telah memposting pertanyaan tentang itu di sini jika Anda memiliki ide: gis.stackexchange.com/questions/216376/…
user25976
Saya tertarik menggunakan ini juga. Saya pikir saya cukup dekat, tapi saya mendapatkan objek 'AttributeError:' QgsComposerItem 'tidak memiliki atribut' setMapCanvas '' Saya bingung ke mana harus pergi dari sana.
jamierob
Bagaimana saya dapat menemukan kode di tautan dalam jawaban ini? Saya sudah mencoba dua browser yang berbeda dan sepertinya tidak dapat menemukan "contoh" yang dimaksud oleh pospython generate_pdf.py
raphael
3

Anda dapat memprogramnya sendiri atau menggunakan kembali metode dari Maps Printerplugin. Saya akan menjelaskan opsi kedua karena lebih sederhana.

Anda perlu Maps Printermenginstal plugin, buka proyek QGIS dengan komposer yang dikonfigurasi, buka konsol QGIS Python dan jalankan cuplikan kode ini (Anda perlu menyesuaikannya dengan pengaturan Anda sendiri di Your settingsbagian).

# 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

Setelah menjalankannya, Anda akan berakhir dengan file baru /path/to/export_folder/my composer.png. Anda juga dapat menggunakan '.pdf'ekstensi untuk mengekspor komposer sebagai PDF.

Germán Carrillo
sumber
3

Mungkin juga melihat jawaban saya yang lain karena alat baru yang lebih baru telah muncul sejak ini.


Saya datang ke kode di bawah ini yang sayangnya tidak berfungsi penuh. Ini didasarkan pada solusi di atas dan pada pertanyaan-pertanyaan tesis lainnya:

Bagaimana cara pemrograman mengekspor komposisi sebagai gambar?
Bagaimana saya bisa membaca pengaturan untuk QgsPaperItem dari XML?
Menyimpan Peta Kanvas sebagai PNG dengan latar belakang transparan secara terprogram dengan QGIS?

Kode saya dapat mengekstrak .qpt dari file .qgs dan berhasil memuat komposer dari templat. Ini juga mencetak komposer ke file .png dan menampilkan dengan benar label dan bentuk yang disimpan dalam komposer.

Namun gagal memuat semua elemen yang terkait dengan Map & Layers yang sebenarnya (label yang mengandung ekspresi dari layer juga tidak diambil). Saya rasa saya sedikit ketinggalan tentang bagaimana proyek harus dimuat dan ditautkan ke komposer.

Beberapa orang dalam komentar dari artikel asli dari Tim Sutton menyebutkan bahwa mereka terjebak pada tahap yang sama di bawah Windows (ini kasus saya). Ini sangat frustasi karena saya merasa jawabannya sangat dekat. Internet yang terhormat, tolong bantu!

Juga ini adalah upaya pertama saya di python jadi saya harap Anda akan baik;)

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



Saya membuang baris tesis dari kode sebelumnya karena mereka sepertinya tidak melakukan apa-apa. Mereka tidak menghasilkan kesalahan tetapi tidak melakukan yang lebih baik.

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

dan mereka juga dihilangkan karena sepertinya tidak diperlukan saat menggunakan 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
sumber
Saya baru saja menyiapkan VM dengan Unbuntu 14.04 dan kode ini bekerja sangat mudah. Jadi masalahnya terkait dengan versi Windows dari PyQgis (diuji pada Window10 dengan instal Osgeo4w64), saya akan melihat apakah tiket sudah terbuka di pelacak bug.
MarHoff
1

Opsi lain yang lebih terkini adalah dengan melihat 2 perangkat alat yang dikembangkan oleh komunitas QGIS. Karena Map-sprinter didukung secara aktif, Anda harus berharap bahwa skrip akan diperbarui dengan versi QGIS yang akan datang.

Kedua alat menyediakan GUI tetapi skrip yang mendasarinya ditulis dalam Python

Ekspor komposer ke file - https://github.com/DelazJ/MapsPrinter
Ekspor komposer dari berbagai proyek - https://github.com/gacarrillor/QGIS-Resources

MarHoff
sumber