4

I am trying to write a processing script that takes a template file as input and writes out the current canvas content as a PDF. The processing script works fine. But when I use the script in a model, the map output is blank.

The model starts with a blank canvas. A layer is generated by the model and loaded in the canvas. Following that step the algorithm containing the script is called to generate the pdf. I have also set the previous step of the model as the parent, but no luck.

Below is the processing script.

from PyQt5.QtCore import QCoreApplication
from qgis.core import QgsProject, QgsLayout, QgsLayoutExporter, QgsReadWriteContext, QgsMapSettings, QgsProcessingAlgorithm, QgsProcessingParameterFileDestination, QgsProcessingParameterFile
from PyQt5.QtXml import QDomDocument

class ExportLayoutAlgorithm(QgsProcessingAlgorithm):
    """Saves the attributes of a vector layer to a CSV file."""
    OUTPUT = 'OUTPUT'
    INPUT = 'INPUT'

    def flags(self):
          return super().flags() | QgsProcessingAlgorithm.FlagNoThreading


    def initAlgorithm(self, config=None):
        self.addParameter(
            QgsProcessingParameterFile(
                self.INPUT,
                self.tr('Template File'),
            )
        )

        # We add a file output of type CSV.
        self.addParameter(
            QgsProcessingParameterFileDestination(
                self.OUTPUT,
                self.tr('Output File'),
                'PDF File (*.pdf)',
            )
        )

    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsFile(parameters, 'INPUT', context)
        pdf = self.parameterAsFileOutput(parameters, 'OUTPUT', context)
        # Load template from file
        p = context.project()
        l = QgsLayout(p)
        l.initializeDefaults()

        with open(source) as f:
            template_content = f.read()
        doc = QDomDocument()
        doc.setContent(template_content)

        # adding to existing items
        items, ok = l.loadFromTemplate(doc, QgsReadWriteContext(), False)
        title = l.itemById('Title')
        title.setText('My Map')
        map = l.itemById('Map')

        exporter = QgsLayoutExporter(l)
        exporter.exportToPdf(
             pdf, QgsLayoutExporter.PdfExportSettings())

        return {'OUTPUT': pdf}

    def name(self):
        return 'export_layout'

    def displayName(self):
        return self.tr('Export Layout As PDF')

    def group(self):
        return self.tr(self.groupId())

    def groupId(self):
        return ''

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return ExportLayoutAlgorithm()
1

I was able to solve this by adding a vector layer input to the script and adding it to the project from the script itself before exporting the layout.

layer = self.parameterAsLayer(parameters, 'LAYER', context)
p = context.project()
p.addMapLayer(layer)

Now this script can be used inside a model where it takes the styled vector layer generated in the previous step as an input 'LAYER' and renders a PDF.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.