Zapisać widok wydruku / mapy kompozytora QGIS jako PNG / PDF przy użyciu Pythona (bez zmiany czegokolwiek w widocznym układzie)?
11
Mam otwarty widok kompozytora / wydruku QGIS ze wszystkimi elementami dostosowanymi zgodnie z życzeniem. Teraz muszę wydrukować / zapisać / wyeksportować to jako plik PNG lub PDF ze konsoli Python / skryptu Python.
Nie chcę niczego zmieniać w bieżącym układzie. Większość przykładów, które znalazłem (na przykład: to ), zmienia pozycję mapy lub rozmiar wyjściowego pliku PDF w porównaniu z tym, co widzę w moim bieżącym widoku kompozytora. Chcę uzyskać dokładnie taki sam wynik, jak po kliknięciu opcji Drukuj -> Eksportuj jako obraz .
Jak mogę to zrobić? Atlas nie jest dla mnie rozwiązaniem.
Po prostu przekaż pusty dykt do funkcji Composition.loadFromTemplate () zamiast używanej przez niego „mapy zastępczej”, ponieważ ta funkcja nie jest zainteresowana.
Ponadto, ponieważ zapytałeś o „eksportuj jako obraz” zamiast „eksportuj jako PDF”, musisz wykonać nieco więcej pracy niż użyć funkcji członkowskiej exportAsPDF ().
Poniżej znajduje się zmodyfikowana wersja kodu Tima, która powinna załatwić sprawę, pracując z zewnętrznego skryptu Python. Ustaw odpowiednio DPI i zmienne projektu + kompozytora pliku.
(Jeśli używasz konsoli Python w QGIS zamiast robić to jako zewnętrzny skrypt, możesz pobrać bieżące płótno mapy za pomocą qgis.iface i nie musisz używać całego kodu ładowania projektu itp.).
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()
Jestem zainteresowany użyciem twojego kodu. Dostaję jednak pustą mapę ... opublikowałem tutaj pytanie, jeśli masz jakieś pomysły: gis.stackexchange.com/questions/216376/…
user25976
Jestem również zainteresowany tym. Wydaje mi się, że jestem dość blisko, ale dostaję błąd „AttributeError: Obiekt„ QgsComposerItem ”nie ma atrybutu„ setMapCanvas ”. Nie wiem, dokąd mam się udać.
jamierob
Jak mogę znaleźć kod w linku w tej odpowiedzi? Próbowałem na dwóch różnych przeglądarkach i nie mogę znaleźć „przykładu”, do którego odnosi się postpython generate_pdf.py
raphael
3
Możesz go zaprogramować samodzielnie lub ponownie użyć metody z Maps Printerwtyczki. Opiszę drugą opcję, ponieważ jest prostsza.
Musisz mieć Maps Printerzainstalowaną wtyczkę, otworzyć projekt QGIS ze skonfigurowanym kompozytorem, otworzyć konsolę QGIS Python i uruchomić ten fragment kodu (należy dostosować go przy użyciu własnych ustawień w Your settingssekcji).
# 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
Po uruchomieniu skończysz z nowym plikiem w /path/to/export_folder/my composer.png. Możesz także użyć '.pdf'jako rozszerzenia do eksportowania kompozytora jako PDF.
Mój kod jest w stanie wyodrębnić .qpt z pliku .qgs i pomyślnie załadować kompozytora z szablonu. Drukuje również kompozytora do pliku .png i wyświetla poprawnie etykiety i kształty zapisane w kompozytorze.
Jednak nie ładuje wszystkich elementów związanych z rzeczywistą mapą i warstwami (etykieta zawierająca wyrażenie z warstwy również nie jest rysowana). Myślę, że trochę mi brakowało, w jaki sposób projekt musi zostać załadowany i powiązany z kompozytorem.
Niektóre osoby w komentarzu do oryginalnego artykułu Tima Suttona wspomniały, że utknęły na tym samym etapie pod Windows (to mój przypadek). To jest naprawdę frustrujące, ponieważ czuję, że odpowiedź jest naprawdę bardzo blisko. Drogi Internecie, proszę o pomoc!
To także moje pierwsze próby Pythona, więc mam nadzieję, że będziesz miły;)
#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/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()
Usunąłem tezy z poprzedniego kodu, ponieważ wydawały się w ogóle nic nie robić. Nie pojawił się żaden błąd, ale nie zrobił nic lepszego.
# 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()
i te też są usuwane, ponieważ wydawały się niepotrzebne podczas używania printPageAsRaster ()
Właśnie skonfigurowałem maszynę wirtualną z Unbuntu 14.04 i ten kod działa jak wiatr. Więc problem jest związany z wersją PyQgis dla Windows (testowaną na Windows10 z instalacją Osgeo4w64), sprawdzę, czy bilet jest już otwarty w narzędziu do śledzenia błędów.
MarHoff,
1
Kolejną bardziej aktualną opcją byłoby przyjrzenie się 2 zestawom narzędzi opracowanych przez społeczność QGIS. Ponieważ Map-sprinter jest aktywnie wspierany, należy spodziewać się, że skrypty zostaną zaktualizowane o nadchodzące wersje QGIS.
Oba narzędzia zapewniają graficzny interfejs użytkownika, ale bazowe skrypty są napisane w języku Python
python generate_pdf.py
Możesz go zaprogramować samodzielnie lub ponownie użyć metody z
Maps Printer
wtyczki. Opiszę drugą opcję, ponieważ jest prostsza.Musisz mieć
Maps Printer
zainstalowaną wtyczkę, otworzyć projekt QGIS ze skonfigurowanym kompozytorem, otworzyć konsolę QGIS Python i uruchomić ten fragment kodu (należy dostosować go przy użyciu własnych ustawień wYour settings
sekcji).Po uruchomieniu skończysz z nowym plikiem w
/path/to/export_folder/my composer.png
. Możesz także użyć'.pdf'
jako rozszerzenia do eksportowania kompozytora jako PDF.źródło
Być może rzuć okiem na moją drugą odpowiedź , ponieważ od tego czasu pojawiły się nowe, bardziej aktualne narzędzia.
Doszedłem do kodu poniżej, który niestety nie jest w pełni funkcjonalny. Jest to oparte na powyższym rozwiązaniu i na innych pytaniach:
Jak programowo wyeksportować kompozycję jako obraz?
Jak mogę odczytać ustawienia QgsPaperItem z XML?
Zapisujesz płótno mapy w formacie PNG z przezroczystym tłem programowo z QGIS?
Mój kod jest w stanie wyodrębnić .qpt z pliku .qgs i pomyślnie załadować kompozytora z szablonu. Drukuje również kompozytora do pliku .png i wyświetla poprawnie etykiety i kształty zapisane w kompozytorze.
Jednak nie ładuje wszystkich elementów związanych z rzeczywistą mapą i warstwami (etykieta zawierająca wyrażenie z warstwy również nie jest rysowana). Myślę, że trochę mi brakowało, w jaki sposób projekt musi zostać załadowany i powiązany z kompozytorem.
Niektóre osoby w komentarzu do oryginalnego artykułu Tima Suttona wspomniały, że utknęły na tym samym etapie pod Windows (to mój przypadek). To jest naprawdę frustrujące, ponieważ czuję, że odpowiedź jest naprawdę bardzo blisko. Drogi Internecie, proszę o pomoc!
To także moje pierwsze próby Pythona, więc mam nadzieję, że będziesz miły;)
Usunąłem tezy z poprzedniego kodu, ponieważ wydawały się w ogóle nic nie robić. Nie pojawił się żaden błąd, ale nie zrobił nic lepszego.
i te też są usuwane, ponieważ wydawały się niepotrzebne podczas używania printPageAsRaster ()
źródło
Kolejną bardziej aktualną opcją byłoby przyjrzenie się 2 zestawom narzędzi opracowanych przez społeczność QGIS. Ponieważ Map-sprinter jest aktywnie wspierany, należy spodziewać się, że skrypty zostaną zaktualizowane o nadchodzące wersje QGIS.
Oba narzędzia zapewniają graficzny interfejs użytkownika, ale bazowe skrypty są napisane w języku Python
Eksportuj kompozytorów do plików - https://github.com/DelazJ/MapsPrinter
Eksportuj kompozytorów z wielu projektów - https://github.com/gacarrillor/QGIS-Resources
źródło