QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsalgorithmlayoutatlastoimage.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmlayoutatlastoimage.cpp
3  ---------------------
4  begin : June 2020
5  copyright : (C) 2020 by Mathieu Pellerin
6  email : nirvn dot asia at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 #include "qgslayout.h"
20 #include "qgslayoutatlas.h"
21 #include "qgslayoutitemmap.h"
22 #include "qgslayoututils.h"
23 #include "qgsprintlayout.h"
24 #include "qgsprocessingoutputs.h"
25 #include "qgslayoutexporter.h"
26 
27 #include <QImageWriter>
28 
30 
31 QString QgsLayoutAtlasToImageAlgorithm::name() const
32 {
33  return QStringLiteral( "atlaslayouttoimage" );
34 }
35 
36 QString QgsLayoutAtlasToImageAlgorithm::displayName() const
37 {
38  return QObject::tr( "Export atlas layout as image" );
39 }
40 
41 QStringList QgsLayoutAtlasToImageAlgorithm::tags() const
42 {
43  return QObject::tr( "layout,atlas,composer,composition,save,png,jpeg,jpg" ).split( ',' );
44 }
45 
46 QString QgsLayoutAtlasToImageAlgorithm::group() const
47 {
48  return QObject::tr( "Cartography" );
49 }
50 
51 QString QgsLayoutAtlasToImageAlgorithm::groupId() const
52 {
53  return QStringLiteral( "cartography" );
54 }
55 
56 QString QgsLayoutAtlasToImageAlgorithm::shortDescription() const
57 {
58  return QObject::tr( "Exports an atlas layout as a set of images." );
59 }
60 
61 QString QgsLayoutAtlasToImageAlgorithm::shortHelpString() const
62 {
63  return QObject::tr( "This algorithm outputs an atlas layout to a set of image files (e.g. PNG or JPEG images).\n\n"
64  "If a coverage layer is set, the selected layout's atlas settings exposed in this algorithm "
65  "will be overwritten. In this case, an empty filter or sort by expression will turn those "
66  "settings off." );
67 }
68 
69 void QgsLayoutAtlasToImageAlgorithm::initAlgorithm( const QVariantMap & )
70 {
71  addParameter( new QgsProcessingParameterLayout( QStringLiteral( "LAYOUT" ), QObject::tr( "Atlas layout" ) ) );
72 
73  addParameter( new QgsProcessingParameterVectorLayer( QStringLiteral( "COVERAGE_LAYER" ), QObject::tr( "Coverage layer" ), QList< int >(), QVariant(), true ) );
74  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "FILTER_EXPRESSION" ), QObject::tr( "Filter expression" ), QString(), QStringLiteral( "COVERAGE_LAYER" ), true ) );
75  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "SORTBY_EXPRESSION" ), QObject::tr( "Sort expression" ), QString(), QStringLiteral( "COVERAGE_LAYER" ), true ) );
76  addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SORTBY_REVERSE" ), QObject::tr( "Reverse sort order (used when a sort expression is provided)" ), false, true ) );
77 
78  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "FILENAME_EXPRESSION" ), QObject::tr( "Output filename expression" ), QStringLiteral( "'output_'||@atlas_featurenumber" ), QStringLiteral( "COVERAGE_LAYER" ) ) );
79  addParameter( new QgsProcessingParameterFile( QStringLiteral( "FOLDER" ), QObject::tr( "Output folder" ), QgsProcessingParameterFile::Folder ) );
80 
81 
82  std::unique_ptr< QgsProcessingParameterMultipleLayers > layersParam = std::make_unique< QgsProcessingParameterMultipleLayers>( QStringLiteral( "LAYERS" ), QObject::tr( "Map layers to assign to unlocked map item(s)" ), QgsProcessing::TypeMapLayer, QVariant(), true );
83  layersParam->setFlags( layersParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
84  addParameter( layersParam.release() );
85 
86  QStringList imageFormats;
87  const QList<QByteArray> supportedImageFormats { QImageWriter::supportedImageFormats() };
88  for ( const QByteArray &format : supportedImageFormats )
89  {
90  if ( format == QByteArray( "svg" ) )
91  continue;
92  imageFormats << QString( format );
93  }
94  std::unique_ptr< QgsProcessingParameterEnum > extensionParam = std::make_unique< QgsProcessingParameterEnum >( QStringLiteral( "EXTENSION" ), QObject::tr( "Image format" ), imageFormats, false, imageFormats.indexOf( QLatin1String( "png" ) ) );
95  extensionParam->setFlags( extensionParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
96  addParameter( extensionParam.release() );
97 
98  std::unique_ptr< QgsProcessingParameterNumber > dpiParam = std::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DPI" ), QObject::tr( "DPI (leave blank for default layout DPI)" ), QgsProcessingParameterNumber::Double, QVariant(), true, 0 );
99  dpiParam->setFlags( dpiParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
100  addParameter( dpiParam.release() );
101 
102  std::unique_ptr< QgsProcessingParameterBoolean > appendGeorefParam = std::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "GEOREFERENCE" ), QObject::tr( "Generate world file" ), true );
103  appendGeorefParam->setFlags( appendGeorefParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
104  addParameter( appendGeorefParam.release() );
105 
106  std::unique_ptr< QgsProcessingParameterBoolean > exportRDFParam = std::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "INCLUDE_METADATA" ), QObject::tr( "Export RDF metadata (title, author, etc.)" ), true );
107  exportRDFParam->setFlags( exportRDFParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
108  addParameter( exportRDFParam.release() );
109 
110  std::unique_ptr< QgsProcessingParameterBoolean > antialias = std::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "ANTIALIAS" ), QObject::tr( "Enable antialiasing" ), true );
111  antialias->setFlags( antialias->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
112  addParameter( antialias.release() );
113 }
114 
115 QgsProcessingAlgorithm::Flags QgsLayoutAtlasToImageAlgorithm::flags() const
116 {
117  return QgsProcessingAlgorithm::flags() | FlagNoThreading;
118 }
119 
120 QgsLayoutAtlasToImageAlgorithm *QgsLayoutAtlasToImageAlgorithm::createInstance() const
121 {
122  return new QgsLayoutAtlasToImageAlgorithm();
123 }
124 
125 QVariantMap QgsLayoutAtlasToImageAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
126 {
127  // this needs to be done in main thread, layouts are not thread safe
128  QgsPrintLayout *l = parameterAsLayout( parameters, QStringLiteral( "LAYOUT" ), context );
129  if ( !l )
130  throw QgsProcessingException( QObject::tr( "Cannot find layout with name \"%1\"" ).arg( parameters.value( QStringLiteral( "LAYOUT" ) ).toString() ) );
131 
132  std::unique_ptr< QgsPrintLayout > layout( l->clone() );
133  QgsLayoutAtlas *atlas = layout->atlas();
134 
135  QString expression, error;
136  QgsVectorLayer *layer = parameterAsVectorLayer( parameters, QStringLiteral( "COVERAGE_LAYER" ), context );
137  if ( layer )
138  {
139  atlas->setEnabled( true );
140  atlas->setCoverageLayer( layer );
141 
142  expression = parameterAsString( parameters, QStringLiteral( "FILTER_EXPRESSION" ), context );
143  atlas->setFilterExpression( expression, error );
144  atlas->setFilterFeatures( !expression.isEmpty() && error.isEmpty() );
145  if ( !expression.isEmpty() && !error.isEmpty() )
146  {
147  throw QgsProcessingException( QObject::tr( "Error setting atlas filter expression" ) );
148  }
149  error.clear();
150 
151  expression = parameterAsString( parameters, QStringLiteral( "SORTBY_EXPRESSION" ), context );
152  if ( !expression.isEmpty() )
153  {
154  const bool sortByReverse = parameterAsBool( parameters, QStringLiteral( "SORTBY_REVERSE" ), context );
155  atlas->setSortFeatures( true );
156  atlas->setSortExpression( expression );
157  atlas->setSortAscending( !sortByReverse );
158  }
159  else
160  {
161  atlas->setSortFeatures( false );
162  }
163  }
164  else if ( !atlas->enabled() )
165  {
166  throw QgsProcessingException( QObject::tr( "Layout being export doesn't have an enabled atlas" ) );
167  }
168 
169  expression = parameterAsString( parameters, QStringLiteral( "FILENAME_EXPRESSION" ), context );
170  atlas->setFilenameExpression( expression, error );
171  if ( !error.isEmpty() )
172  {
173  throw QgsProcessingException( QObject::tr( "Error setting atlas filename expression" ) );
174  }
175 
176  const QString directory = parameterAsFileOutput( parameters, QStringLiteral( "FOLDER" ), context );
177  const QString fileName = QDir( directory ).filePath( QStringLiteral( "atlas" ) );
178 
179  QStringList imageFormats;
180  const QList<QByteArray> supportedImageFormats { QImageWriter::supportedImageFormats() };
181  for ( const QByteArray &format : supportedImageFormats )
182  {
183  if ( format == QByteArray( "svg" ) )
184  continue;
185  imageFormats << QString( format );
186  }
187  const int idx = parameterAsEnum( parameters, QStringLiteral( "EXTENSION" ), context );
188  const QString extension = '.' + imageFormats.at( idx );
189 
191 
192  if ( parameters.value( QStringLiteral( "DPI" ) ).isValid() )
193  {
194  settings.dpi = parameterAsDouble( parameters, QStringLiteral( "DPI" ), context );
195  }
196 
197  settings.exportMetadata = parameterAsBool( parameters, QStringLiteral( "INCLUDE_METADATA" ), context );
198  settings.generateWorldFile = parameterAsBool( parameters, QStringLiteral( "GEOREFERENCE" ), context );
199 
200  if ( parameterAsBool( parameters, QStringLiteral( "ANTIALIAS" ), context ) )
202  else
203  settings.flags = settings.flags & ~QgsLayoutRenderContext::FlagAntialiasing;
204 
205  settings.predefinedMapScales = QgsLayoutUtils::predefinedScales( layout.get() );
206 
207  const QList< QgsMapLayer * > layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
208  if ( layers.size() > 0 )
209  {
210  const QList<QGraphicsItem *> items = layout->items();
211  for ( QGraphicsItem *graphicsItem : items )
212  {
213  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
214  QgsLayoutItemMap *map = dynamic_cast<QgsLayoutItemMap *>( item );
215  if ( map && !map->followVisibilityPreset() && !map->keepLayerSet() )
216  {
217  map->setKeepLayerSet( true );
218  map->setLayers( layers );
219  }
220  }
221  }
222 
223  if ( atlas->updateFeatures() )
224  {
225  feedback->pushInfo( QObject::tr( "Exporting %n atlas feature(s)", "", atlas->count() ) );
226  switch ( QgsLayoutExporter::exportToImage( atlas, fileName, extension, settings, error, feedback ) )
227  {
229  {
230  feedback->pushInfo( QObject::tr( "Successfully exported layout to %1" ).arg( QDir::toNativeSeparators( directory ) ) );
231  break;
232  }
233 
235  throw QgsProcessingException( QObject::tr( "Cannot write to %1.\n\nThis file may be open in another application." ).arg( QDir::toNativeSeparators( directory ) ) );
236 
238  throw QgsProcessingException( QObject::tr( "Trying to create the image "
239  "resulted in a memory overflow.\n\n"
240  "Please try a lower resolution or a smaller paper size." ) );
241 
243  throw QgsProcessingException( QObject::tr( "Error encountered while exporting atlas." ) );
244 
248  // no meaning for imageexports, will not be encountered
249  break;
250  }
251  }
252  else
253  {
254  feedback->reportError( QObject::tr( "No atlas features found" ) );
255  }
256 
257  feedback->setProgress( 100 );
258 
259  QVariantMap outputs;
260  outputs.insert( QStringLiteral( "FOLDER" ), directory );
261  return outputs;
262 }
263 
265 
QgsLayoutExporter::ImageExportSettings::exportMetadata
bool exportMetadata
Indicates whether image export should include metadata generated from the layout's project's metadata...
Definition: qgslayoutexporter.h:207
QgsFeedback::setProgress
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:76
QgsProcessingParameterNumber::Double
@ Double
Double/float values.
Definition: qgsprocessingparameters.h:2187
QgsLayoutUtils::predefinedScales
static QVector< double > predefinedScales(const QgsLayout *layout)
Returns a list of predefined scales associated with a layout.
Definition: qgslayoututils.cpp:514
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:37
QgsLayoutExporter::PrintError
@ PrintError
Could not start printing to destination device.
Definition: qgslayoutexporter.h:144
QgsLayoutAtlas::count
int count() const override
Returns the number of features to iterate over.
Definition: qgslayoutatlas.cpp:401
QgsProcessingFeedback::pushInfo
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
Definition: qgsprocessingfeedback.cpp:77
QgsLayoutExporter::ImageExportSettings::flags
QgsLayoutRenderContext::Flags flags
Layout context flags, which control how the export will be created.
Definition: qgslayoutexporter.h:213
QgsProcessingFeedback::reportError
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
Definition: qgsprocessingfeedback.cpp:59
QgsProcessingParameterFile::Folder
@ Folder
Parameter is a folder.
Definition: qgsprocessingparameters.h:1915
QgsLayoutAtlas::updateFeatures
int updateFeatures()
Requeries the current atlas coverage layer and applies filtering and sorting.
Definition: qgslayoutatlas.cpp:262
QgsLayoutExporter::Success
@ Success
Export was successful.
Definition: qgslayoutexporter.h:140
QgsLayoutRenderContext
Stores information relating to the current rendering settings for a layout.
Definition: qgslayoutrendercontext.h:36
QgsProcessingParameterDefinition::FlagAdvanced
@ FlagAdvanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition: qgsprocessingparameters.h:451
QgsLayoutAtlas::setEnabled
void setEnabled(bool enabled)
Sets whether the atlas is enabled.
Definition: qgslayoutatlas.cpp:126
QgsLayoutExporter::Canceled
@ Canceled
Export was canceled.
Definition: qgslayoutexporter.h:141
QgsLayoutItemMap::followVisibilityPreset
bool followVisibilityPreset() const
Returns whether the map should follow a map theme.
Definition: qgslayoutitemmap.h:565
QgsLayoutExporter::ImageExportSettings::predefinedMapScales
QVector< qreal > predefinedMapScales
A list of predefined scales to use with the layout.
Definition: qgslayoutexporter.h:220
QgsLayoutExporter::MemoryError
@ MemoryError
Unable to allocate memory required to export.
Definition: qgslayoutexporter.h:142
qgslayoututils.h
qgslayoutexporter.h
QgsLayoutExporter::SvgLayerError
@ SvgLayerError
Could not create layered SVG file.
Definition: qgslayoutexporter.h:145
QgsLayoutExporter::exportToImage
ExportResult exportToImage(const QString &filePath, const QgsLayoutExporter::ImageExportSettings &settings)
Exports the layout to the filePath, using the specified export settings.
Definition: qgslayoutexporter.cpp:370
QgsPrintLayout
Print layout, a QgsLayout subclass for static or atlas-based layouts.
Definition: qgsprintlayout.h:30
QgsProcessing::TypeMapLayer
@ TypeMapLayer
Any map layer type (raster, vector, mesh, point cloud, annotation or plugin layer)
Definition: qgsprocessing.h:47
QgsLayoutAtlas::enabled
bool enabled() const
Returns whether the atlas generation is enabled.
Definition: qgslayoutatlas.h:67
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:46
QgsProcessingParameterFile
An input file or folder parameter for processing algorithms.
Definition: qgsprocessingparameters.h:1907
qgsalgorithmlayoutatlastoimage.h
QgsProcessingParameterVectorLayer
A vector layer (with or without geometry) parameter for processing algorithms. Consider using the mor...
Definition: qgsprocessingparameters.h:2827
QgsLayoutItem
Base class for graphical items within a QgsLayout.
Definition: qgslayoutitem.h:112
qgslayout.h
QgsProcessingParameterLayout
A print layout parameter, allowing users to select a print layout.
Definition: qgsprocessingparameters.h:3623
QgsLayoutAtlas::setSortAscending
void setSortAscending(bool ascending)
Sets whether features should be sorted in an ascending order.
Definition: qgslayoutatlas.cpp:194
QgsLayoutItemMap
Layout graphical items for displaying a map.
Definition: qgslayoutitemmap.h:317
qgsprocessingoutputs.h
QgsLayoutExporter::ImageExportSettings
Contains settings relating to exporting layouts to raster images.
Definition: qgslayoutexporter.h:150
QgsProcessingParameterBoolean
A boolean parameter for processing algorithms.
Definition: qgsprocessingparameters.h:1709
QgsLayoutAtlas::setSortExpression
void setSortExpression(const QString &expression)
Sets the expression (or field name) to use for sorting features.
Definition: qgslayoutatlas.cpp:203
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsProcessingParameterExpression
An expression parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2739
QgsLayoutExporter::IteratorError
@ IteratorError
Error iterating over layout.
Definition: qgslayoutexporter.h:146
qgsprintlayout.h
QgsLayoutAtlas::setCoverageLayer
void setCoverageLayer(QgsVectorLayer *layer)
Sets the coverage layer to use for the atlas features.
Definition: qgslayoutatlas.cpp:157
QgsLayoutExporter::ImageExportSettings::generateWorldFile
bool generateWorldFile
Set to true to generate an external world file alongside exported images.
Definition: qgslayoutexporter.h:199
QgsLayoutAtlas::setFilterExpression
bool setFilterExpression(const QString &expression, QString &errorString)
Sets the expression used for filtering features in the coverage layer.
Definition: qgslayoutatlas.cpp:221
QgsProcessingAlgorithm::flags
virtual Flags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Definition: qgsprocessingalgorithm.cpp:90
QgsLayoutRenderContext::FlagAntialiasing
@ FlagAntialiasing
Use antialiasing when drawing items.
Definition: qgslayoutrendercontext.h:48
QgsLayoutAtlas::setFilterFeatures
void setFilterFeatures(bool filtered)
Sets whether features should be filtered in the coverage layer.
Definition: qgslayoutatlas.cpp:212
QgsLayoutItemMap::setKeepLayerSet
void setKeepLayerSet(bool enabled)
Sets whether the stored layer set should be used or the current layer set of the associated project.
Definition: qgslayoutitemmap.h:505
QgsLayoutAtlas
Class used to render QgsLayout as an atlas, by iterating over the features from an associated vector ...
Definition: qgslayoutatlas.h:41
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
QgsLayoutExporter::ImageExportSettings::dpi
double dpi
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
Definition: qgslayoutexporter.h:158
QgsPrintLayout::clone
QgsPrintLayout * clone() const override
Creates a clone of the layout.
Definition: qgsprintlayout.cpp:29
QgsLayoutAtlas::setSortFeatures
void setSortFeatures(bool enabled)
Sets whether features should be sorted in the atlas.
Definition: qgslayoutatlas.cpp:185
QgsLayoutAtlas::setFilenameExpression
bool setFilenameExpression(const QString &expression, QString &errorString)
Sets the filename expression used for generating output filenames for each atlas page.
Definition: qgslayoutatlas.cpp:492
QgsLayoutExporter::FileError
@ FileError
Could not write to destination file, likely due to a lock held by another application.
Definition: qgslayoutexporter.h:143
QgsLayoutItemMap::setLayers
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the stored layers set.
Definition: qgslayoutitemmap.cpp:331
QgsLayoutItemMap::keepLayerSet
bool keepLayerSet() const
Returns whether a stored layer set should be used or the current layer set from the project associate...
Definition: qgslayoutitemmap.h:495
qgslayoutitemmap.h
qgslayoutatlas.h