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') 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.