QGIS Headless + Python - Exportieren von PDF mit Xyz -FliesenschichtPython

Python-Programme
Anonymous
 QGIS Headless + Python - Exportieren von PDF mit Xyz -Fliesenschicht

Post by Anonymous »

Ich habe ein Skript, das eine PDF -Datei von QGIS -Kopfless auf Ubuntu erzeugt. Der zweite Lauf desselben Skripts erzeugt ein korrektes PDF. Der zweite Lauf verwendet zwischengespeicherte Kacheln und keine Fehler, die Ocurne. Aber korrigieren Sie mich, wenn ich falsch liege. (Gleiches passiert beim Erzeugen einer PNG -Ausgabe) < /p>
Dies ist mein Skript: < /p>

Code: Select all

import os
os.environ["QT_QPA_PLATFORM"] = "offscreen"
os.environ["QGIS_DISABLE_CACHE"] = "1"

import sys

from qgis.PyQt.QtGui import QColor
from qgis.PyQt.QtXml import QDomDocument

from qgis.core import (
QgsApplication,
QgsVectorLayer,
QgsRasterLayer,
QgsProject,
QgsCoordinateReferenceSystem,
QgsPrintLayout,
QgsLayoutItemMap,
QgsLayoutExporter,
QgsReadWriteContext,
QgsCoordinateTransform,
QgsNetworkAccessManager
)

printTemplatePath = os.path.join("assets", "print_template.qpt")

MAPBOX_MAP_TOKEN = "***"

props = {
"color": [255, 16, 16],
"opacity": 0.75,
"strokeColor": [255, 36, 36],
"strokeWidth": 0.5,
}

def loadLayer(geojsonPath):
layer = QgsVectorLayer(geojsonPath, "geojsonLayer", "ogr")
if not layer.isValid():
print(f"Failed to load: {geojsonPath}")
qgs.exitQgis()
sys.exit(1)
QgsProject.instance().addMapLayer(layer)
return layer

def setSymbology(layer):
singleSymbolRenderer = layer.renderer()
symbol = singleSymbolRenderer.symbol()
symbol.setColor(QColor.fromRgb(props['color'][0], props['color'][1], props['color'][2]))
symbol.setOpacity(props['opacity'])
symbol.symbolLayer(0).setStrokeColor(QColor(props['strokeColor'][0], props['strokeColor'][1], props['strokeColor'][2]))
symbol.symbolLayer(0).setStrokeWidth(props['strokeWidth'])

layer.triggerRepaint()

def addMapboxLayer():
username = "***"
style_id = "***"

try:
uri = f"type=xyz&url=https://api.mapbox.com/styles/v1/{username}/{style_id}/tiles/256/{{z}}/{{x}}/{{y}}?access_token={MAPBOX_MAP_TOKEN}"

layer = QgsRasterLayer(uri, "Mapbox Style", "wms")

QgsProject.instance().addMapLayer(layer)
root = QgsProject.instance().layerTreeRoot()
node = root.findLayer(layer.id())
clone = node.clone()
root.insertChildNode(-1, clone)
root.removeChildNode(node)
except Exception as e:
print(f"Error with tile layer: {e}")
exit(4)

def waitForMapReady():
# need to determine when all the tiles are loaded
pass

def setProjectCrs():
crs = QgsCoordinateReferenceSystem("EPSG:8857")
QgsProject.instance().setCrs(crs)

def getAdjustedLayerExtentForMapFrame(mapItem, polygons, layerCrs, padding):
frameRect = mapItem.rect()
targetAspect = frameRect.width() / frameRect.height()

# combine extents of all polygons
combinedExtent = None
for geom in polygons:
if geom and not geom.isEmpty():
if combinedExtent is None:
combinedExtent = geom.boundingBox()
else:
combinedExtent.combineExtentWith(geom.boundingBox())

# transform to project CRS if needed
projectCrs = QgsProject.instance().crs()
if layerCrs != projectCrs:
tr = QgsCoordinateTransform(layerCrs, projectCrs, QgsProject.instance())
extentProj = tr.transformBoundingBox(combinedExtent)
else:
extentProj = combinedExtent

# apply padding
extentProj.setXMinimum(extentProj.xMinimum() - extentProj.width()*(padding-1)/2)
extentProj.setXMaximum(extentProj.xMaximum() + extentProj.width()*(padding-1)/2)
extentProj.setYMinimum(extentProj.yMinimum() - extentProj.height()*(padding-1)/2)
extentProj.setYMaximum(extentProj.yMaximum() + extentProj.height()*(padding-1)/2)

# adjust to match map frame aspect ratio
extentWidth = extentProj.width()
extentHeight = extentProj.height()
layerAspect = extentWidth / extentHeight

if layerAspect >  targetAspect:
newHeight = extentWidth / targetAspect
yCenter = (extentProj.yMinimum() + extentProj.yMaximum()) / 2
extentProj.setYMinimum(yCenter - newHeight/2)
extentProj.setYMaximum(yCenter + newHeight/2)
else:
newWidth = extentHeight * targetAspect
xCenter = (extentProj.xMinimum() + extentProj.xMaximum()) / 2
extentProj.setXMinimum(xCenter - newWidth/2)
extentProj.setXMaximum(xCenter + newWidth/2)

return extentProj

def printPdf(geojsonLayer, features, templatePath, outputFileName):
project = QgsProject.instance()
layout = QgsPrintLayout(project)
layout.initializeDefaults()

with open(templatePath) as f:
templateContent = f.read()
doc = QDomDocument()
doc.setContent(templateContent)
context = QgsReadWriteContext()
layout.loadFromTemplate(doc, context)

mapItems = [item for item in layout.items() if isinstance(item, QgsLayoutItemMap)]
if not mapItems:
raise Exception("No map item found in layout!")
mapItem = mapItems[0]

polygons = [f.geometry() for f in features if f.hasGeometry()]
if not polygons:
raise ValueError("No valid geometries found in features")

# Adjust map extent
adjustedExtent = getAdjustedLayerExtentForMapFrame(mapItem, polygons, geojsonLayer.crs(), padding=1.2)
mapItem.setExtent(adjustedExtent)
mapItem.refresh()

waitForMapReady()

exporter = QgsLayoutExporter(layout)
pdfSettings = QgsLayoutExporter.PdfExportSettings()
pdfSettings.appendGeoreference = False
pdfSettings.exportMetadata = False
pdfSettings.rasterizeWholeImage = True
pdfSettings.dpi = 144
pdfSettings.imageCompression = "JPEG"
pdfSettings.quality = 70
if exporter.exportToPdf(outputFileName, pdfSettings) == QgsLayoutExporter.Success:
print(f"Exported PDF: {outputFileName}")
return outputFileName
else:
print(f"Failed to export PDF: {pdfPath}")

def main():
if len(sys.argv) < 3:
print("Usage: python3  ")
sys.exit(1)

inputJson = sys.argv[1]
outputFileName = sys.argv[2]

qgs = QgsApplication([], False)
QgsApplication.setPrefixPath("/usr", True)
QgsApplication.setMaxThreads(1)
QgsNetworkAccessManager.instance()
qgs.initQgis()

addMapboxLayer()
geojsonLayer = loadLayer(inputJson)
setSymbology(geojsonLayer)
setProjectCrs()
features = [f for f in geojsonLayer.getFeatures()]
printPdf(geojsonLayer, features, printTemplatePath, outputFileName)

qgs.exitQgis()

if __name__ == "__main__":
main()
Bearbeiten:
Hier ist der Backtrace des Fehlers:

Code: Select all

Thread 1 "python3"  received signal SIGSEGV, Segmentation fault.
0x00007fffece36619 in QGraphicsItemPrivate::removeExtraItemCache() () from /lib/x86_64-linux-gnu/libQt5Widgets.so.5
(gdb) bt
#0  0x00007fffece36619 in QGraphicsItemPrivate::removeExtraItemCache() () from /lib/x86_64-linux-gnu/libQt5Widgets.so.5
#1  0x00007fffece396d1 in QGraphicsItem::setCacheMode(QGraphicsItem::CacheMode, QSize const&) ()
from /lib/x86_64-linux-gnu/libQt5Widgets.so.5
#2  0x00007fffee3a6b26 in QgsLayoutExporter::renderRegion(QPainter*, QRectF const&) const ()
from /lib/libqgis_core.so.3.40.9
#3  0x00007fffee3a7014 in QgsLayoutExporter::renderRegionToImage(QRectF const&, QSize, double) const ()
from /lib/libqgis_core.so.3.40.9
#4  0x00007fffee3a8129 in QgsLayoutExporter::renderPageToImage(int, QSize, double) const ()
from /lib/libqgis_core.so.3.40.9
#5  0x00007fffee3a8632 in QgsLayoutExporter::printPrivate(QPagedPaintDevice*, QPainter&, bool, double, bool) ()
from /lib/libqgis_core.so.3.40.9
#6  0x00007fffee3b23a3 in QgsLayoutExporter::exportToPdf(QString const&, QgsLayoutExporter::PdfExportSettings const&)
() from /lib/libqgis_core.so.3.40.9
#7  0x00007fffdf477f89 in ?? () from /usr/lib/python3/dist-packages/qgis/_core.cpython-312-x86_64-linux-gnu.so
#8  0x0000000000581a6f in cfunction_call (func=0x7fffdc22d760, args=, kwargs=)
at ../Objects/methodobject.c:537
#9  0x00000000005492f5 in _PyObject_MakeTpCall (tstate=0xba6ac8 , callable=0x7fffdc22d760,
args=, nargs=2, keywords=0x0) at ../Objects/call.c:240
#10 0x0000000000549d2d in _PyObject_VectorcallTstate (kwnames=, nargsf=,
args=, callable=, tstate=) at ../Include/internal/pycore_call.h:90
#11 0x00000000005d68bf in _PyEval_EvalFrameDefault (tstate=tstate@entry=0xba6ac8 ,
frame=, frame@entry=0x7ffff7fb2020, throwflag=throwflag@entry=0) at Python/bytecodes.c:2706
#12 0x00000000005d4dab in _PyEval_EvalFrame (throwflag=0, frame=0x7ffff7fb2020, tstate=0xba6ac8 )
at ../Include/internal/pycore_ceval.h:89
#13 _PyEval_Vector (kwnames=0x0, argcount=0, args=0x0, locals=0x7ffff7c0dbc0, func=0x7ffff7bee160,
tstate=0xba6ac8 ) at ../Python/ceval.c:1683
#14 PyEval_EvalCode (co=co@entry=0x7ffff7b3dc30, globals=globals@entry=0x7ffff7c0dbc0,
locals=locals@entry=0x7ffff7c0dbc0) at ../Python/ceval.c:578
#15 0x0000000000607fc2 in run_eval_code_obj (locals=0x7ffff7c0dbc0, globals=0x7ffff7c0dbc0, co=0x7ffff7b3dc30,
#16 run_mod (mod=, filename=, globals=0x7ffff7c0dbc0, locals=0x7ffff7c0dbc0,
flags=, arena=) at ../Python/pythonrun.c:1743
#17 0x00000000006b4393 in pyrun_file (fp=fp@entry=0xbab490, filename=filename@entry=0x7ffff79bdc50,
start=start@entry=257, globals=globals@entry=0x7ffff7c0dbc0, locals=locals@entry=0x7ffff7c0dbc0,
closeit=closeit@entry=1, flags=0x7fffffffda48) at ../Python/pythonrun.c:1643
#18 0x00000000006b40fa in _PyRun_SimpleFileObject (fp=fp@entry=0xbab490, filename=filename@entry=0x7ffff79bdc50,
closeit=closeit@entry=1, flags=flags@entry=0x7fffffffda48) at ../Python/pythonrun.c:433
#19 0x00000000006b3f2f in _PyRun_AnyFileObject (fp=0xbab490, filename=filename@entry=0x7ffff79bdc50,
closeit=closeit@entry=1, flags=flags@entry=0x7fffffffda48) at ../Python/pythonrun.c:78
#20 0x00000000006bbf45 in pymain_run_file_obj (skip_source_first_line=0, filename=0x7ffff79bdc50,
program_name=0x7ffff7c0dcf0) at ../Modules/main.c:360
#21 pymain_run_file (config=0xb496a8 ) at ../Modules/main.c:379
#22 pymain_run_python (exitcode=0x7fffffffda3c) at ../Modules/main.c:629
#23 Py_RunMain () at ../Modules/main.c:709
#24 0x00000000006bba2d in Py_BytesMain (argc=, argv=) at ../Modules/main.c:763
#25 0x00007ffff7c991ca in __libc_start_call_main (main=main@entry=0x518bd0 , argc=argc@entry=4,
argv=argv@entry=0x7fffffffdc88) at ../sysdeps/nptl/libc_start_call_main.h:58
#26 0x00007ffff7c9928b in __libc_start_main_impl (main=0x518bd0 , argc=4, argv=0x7fffffffdc88,
init=, fini=, rtld_fini=, stack_end=0x7fffffffdc78)
at ../csu/libc-start.c:360
#27 0x0000000000656a35 in _start ()

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post