I'm trying to setup an application for my company, that generates a PDF file for specific user generated coordinates:
- The user enters an address into the frontend (Flask generated), which is translated via Here Maps Geocoder API to coordinates.
- The coordinates are sent to pyQGIS running on the company server.
- PyQGIS connects to PostgreSQL, performing some spatial joins. This way suitable information for the coordinates is collected in a PDF file being returned to the user.
The good thing: It works! Except for when loading QGIS Command Prompt says:
libpng warning: iCCP: known incorrect sRGB profile
QObject::connect: invalid null parameter
But it seems to be no big issue, it works anyway.
The bad thing: It only works when all the PyQGIS code is in one single script, looking like this (shortened, loading only the PDF cover):
def print_pdf(new_address_dict):
x = new_address_dict['x']
y = new_address_dict['y']
address = new_address_dict['address']
path = os.path.dirname(os.path.abspath(__file__))
QgsApplication.setPrefixPath("C:/Program Files/QGIS 3.4", False)
# Create a reference to the QgsApplication. Setting the
# second argument to False disables the GUI.
qgs = QgsApplication([], False)
# Load providers
qgs.initQgis()
print('QGIS initialisiert, Brudi')
# Load project
project = QgsProject.instance()
composition = QgsPrintLayout(project)
document = QDomDocument()
project.read(path + '/pyqgis/dynamischer_test.qgz')
# Load layout
layout = project.layoutManager().layoutByName("dynamisches_layout")
# Set Headline
headline = layout.itemById('00 Titel')
headline.setText(address)
headline_shadow = layout.itemById('00 Schatten')
headline_shadow.setText(address)
# Set extent
refmap = layout.itemById('00 HG')
xmin = x - 250
ymin = y - 250
xmax = x + 250
ymax = y + 250
bb = QgsRectangle(xmin, ymin, xmax, ymax)
refmap.setExtent(bb)
# Set background
hintergrund = project.mapLayersByName('gruen')[0]
project.layerTreeRoot().findLayer(hintergrund.id()).setItemVisibilityChecked(True)
print('Cover done')
# Print pdf
pdf_path = os.path.join(path + '/pyqgis/', 'test.pdf')
exporter = QgsLayoutExporter(layout)
image_settings = QgsLayoutExporter.PdfExportSettings()
image_settings.dpi = 300
result = exporter.exportToPdf(pdf_path, image_settings)
# Exit QGIS
qgs.exitQgis()
print('Done!')
This isn't very clean and also QGIS is being loaded every time the user presses the 'Generate PDF'-button, which ist very unefficient. So I tried to move all the startup code, like creating a QgsApplication reference, loading the project etc, into an own method, which is called right at the start of the script. Also I wanted to have an own method for each of the pages in the PDF, like load_cover(), load_page1(), etc. I passed the project and layout variables into these new methods like this:
def load_cover(project, layout, address, x, y):
headline = layout.itemById('00 Titel')
headline.setText(address)
...
But when I things this way, there seems to be some issue with the context or threads or something. Python crashes at the very last line:
result = exporter.exportToPdf(pdf_path, image_settings)
And Command Prompt says the following:
QPrinter: Must construct a QCoreApplication before a QPrinter
I'm new to python and PyQGIS and I'm stuck with this. Please help! I'm using Python 3.8 and QGIS 3.4.