Your script ran successfully for me in the "Python script console" of QGIS.
Inspired by Save Print/Map QGIS composer view as PNG/PDF using Python (without changing anything in visible layout)?, How to export a configurated Atlas with a python script / command line?, QGIS: Automatisation de la génération d'un Atlas avec script python, Search for "[qgis] standalone script" on gis stackexchange, How to run a simple python script for QGIS from outside (e.g. Sublime Text)?, Using PyQGIS in custom applications, Generate a QGIS map PDF using python, How to create a QGIS PDF report with a few lines of python, QGIS Server Plugin Filters: Add a new request to print a specific atlas feature, QGIS export “save as image” automate with python?, I wrote the following exportAtlas.py python script:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from qgis.core import QgsApplication, QgsProject, QgsComposition
from qgis.gui import QgsMapCanvas, QgsLayerTreeMapCanvasBridge
from PyQt4.QtCore import QFile, QFileInfo, QByteArray, QTextStream
from PyQt4.QtXml import QDomDocument
import os
import sys
projectPath = sys.argv[1]
renderingPath = sys.argv[2]
def printAtlas(projectPath, renderingPath):
# Inspired by [Save Print/Map QGIS composer view as PNG/PDF using Python (without changing anything in visible layout)?](https://gis.stackexchange.com/a/164196/73088), [How to export a configurated Atlas with a python script / command line?](https://gis.stackexchange.com/q/272839/73088), [QGIS: Automatisation de la génération d'un Atlas avec script python](https://georezo.net/forum/viewtopic.php?pid=284842), [Search for "[qgis] standalone script" on gis stackexchange](https://gis.stackexchange.com/search?page=2&tab=Relevance&q=%5bqgis%5d%20standalone%20script), [How to run a simple python script for QGIS from outside (e.g. Sublime Text)?](https://gis.stackexchange.com/a/29597/73088), [Using PyQGIS in custom applications](https://docs.qgis.org/2.18/en/docs/pyqgis_developer_cookbook/intro.html#using-pyqgis-in-custom-applications), [Generate a QGIS map PDF using python](https://gist.github.com/timlinux/486793ad61db4c1dec9d), [How to create a QGIS PDF report with a few lines of python](http://kartoza.com/en/blog/how-to-create-a-qgis-pdf-report-with-a-few-lines-of-python/), [QGIS Server Plugin Filters: Add a new request to print a specific atlas feature](https://github.com/3liz/qgis-atlasprint/blob/master/filters/atlasprintFilter.py), [QGIS export “save as image” automate with python?](https://gis.stackexchange.com/a/213065/73088)
#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)
composerAsNode = projectAsDocument.elementsByTagName("Composer").at(0)
# Only way to convert a QDomNode to a QDomDocument root, inspired by https://gis.stackexchange.com/a/164196/73088 & [Convert QDomElement to QDomDocument and vs](https://stackoverflow.com/q/18868993/535203) & read the documentation http://doc.qt.io/archives/qt-4.8/qtextstream.html & http://doc.qt.io/archives/qt-4.8/qdomnode.html .
# Using a QByteArray because QString pointer can't be passed in python and QString is not available by default in QGIS python scripts [QGIS PyQt4 missing QString class](https://stackoverflow.com/q/28632169/535203)
composerAsString = QByteArray()
composerAsNode.save(QTextStream(composerAsString), 2)
composerAsDocument = QDomDocument()
composerAsDocument.setContent(composerAsString)
#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, {})
atlas = composition.atlasComposition()
composition.setAtlasMode(QgsComposition.ExportAtlas)
print 'Found %d features to render.' % atlas.numFeatures()
atlas.beginRender()
for i in range(1, atlas.numFeatures()):
print 'Rendering feature %d...' % i
atlas.prepareForFeature(i)
featureRenderingBasePath = os.path.join(renderingPath, str(format(i)))
composition.exportAsPDF(featureRenderingBasePath + '.pdf')
img = composition.printPageAsRaster(0)
img.save(featureRenderingBasePath + '.jpg', 'jpg')
atlas.endRender()
#Some cleanup maybe?
QgsProject.instance().clear()
# supply path to qgis install location
#QgsApplication.setPrefixPath("/usr", True) #already set in the right place "/usr" by default
# create a reference to the QgsApplication
# setting the second argument to True enables the GUI, which we need to do
# since this is a custom application
qgs = QgsApplication([], True)
# load providers
qgs.initQgis()
printAtlas(projectPath, renderingPath)
# When your script is complete, call exitQgis() to remove the provider and
# layer registries from memory
qgs.exitQgis()
It can be called this way: python exportAtlas.py '/path/to/the/project.qgs' '/path/to/the/folder/where/to/generate/images/and/pdfs/'
I was able to launch it into a Docker container with the following command: docker run -it --rm -v ${HOME}:/home/${USER} -v /tmp/.X11-unix:/tmp/.X11-unix -v /dev/shm:/dev/shm -e DISPLAY=unix$DISPLAY kartoza/qgis-desktop bash and then inside the terminal ran:
USER_ID=`ls -lahn /home | tail -1 | awk {'print $3'}`
GROUP_ID=`ls -lahn /home | tail -1 | awk {'print $4'}`
USER_NAME=`ls -lah /home/ | tail -1 | awk '{print $9}'`
groupadd -g $GROUP_ID qgis
useradd --shell /bin/bash --uid $USER_ID --gid $GROUP_ID $USER_NAME
export LD_LIBRARY_PATH=/usr/lib
su $USER_NAME -c "PYTHONPATH=/usr/share/qgis/python python /home/$USER_NAME/exportAtlas.py '/path/to/the/project.qgs' '/path/to/the/folder/where/to/generate/images/and/pdfs/'"
The problem with this script is that it doesn't take into consideration a layer which uses the Mask plugin.
I've fixed this in another answer.
QgsLayoutExporter.exportToImage(layout.atlas(), '/home/me/output/test','png', settings)and it'll handle the begin/endRender calls and iteration for you! – ndawson Jul 09 '19 at 00:16