QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 "qgsprintlayout.h"
23 #include "qgsprocessingoutputs.h"
24 #include "qgslayoutexporter.h"
25 
26 #include <QImageWriter>
27 
29 
30 QString QgsLayoutAtlasToImageAlgorithm::name() const
31 {
32  return QStringLiteral( "atlaslayouttoimage" );
33 }
34 
35 QString QgsLayoutAtlasToImageAlgorithm::displayName() const
36 {
37  return QObject::tr( "Export atlas layout as image" );
38 }
39 
40 QStringList QgsLayoutAtlasToImageAlgorithm::tags() const
41 {
42  return QObject::tr( "layout,atlas,composer,composition,save,png,jpeg,jpg" ).split( ',' );
43 }
44 
45 QString QgsLayoutAtlasToImageAlgorithm::group() const
46 {
47  return QObject::tr( "Cartography" );
48 }
49 
50 QString QgsLayoutAtlasToImageAlgorithm::groupId() const
51 {
52  return QStringLiteral( "cartography" );
53 }
54 
55 QString QgsLayoutAtlasToImageAlgorithm::shortDescription() const
56 {
57  return QObject::tr( "Exports an atlas layout as a set of images." );
58 }
59 
60 QString QgsLayoutAtlasToImageAlgorithm::shortHelpString() const
61 {
62  return QObject::tr( "This algorithm outputs an atlas layout to a set of image files (e.g. PNG or JPEG images).\n\n"
63  "If a coverage layer is set, the selected layout's atlas settings exposed in this algorithm "
64  "will be overwritten. In this case, an empty filter or sort by expression will turn those "
65  "settings off." );
66 }
67 
68 void QgsLayoutAtlasToImageAlgorithm::initAlgorithm( const QVariantMap & )
69 {
70  addParameter( new QgsProcessingParameterLayout( QStringLiteral( "LAYOUT" ), QObject::tr( "Atlas layout" ) ) );
71 
72  addParameter( new QgsProcessingParameterVectorLayer( QStringLiteral( "COVERAGE_LAYER" ), QObject::tr( "Coverage layer" ), QList< int >(), QVariant(), true ) );
73  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "FILTER_EXPRESSION" ), QObject::tr( "Filter expression" ), QString(), QStringLiteral( "COVERAGE_LAYER" ), true ) );
74  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "SORTBY_EXPRESSION" ), QObject::tr( "Sort expression" ), QString(), QStringLiteral( "COVERAGE_LAYER" ), true ) );
75  addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SORTBY_REVERSE" ), QObject::tr( "Reverse sort order (used when a sort expression is provided)" ), false, true ) );
76 
77  addParameter( new QgsProcessingParameterExpression( QStringLiteral( "FILENAME_EXPRESSION" ), QObject::tr( "Output filename expression" ), QStringLiteral( "'output_'||@atlas_featurenumber" ), QStringLiteral( "COVERAGE_LAYER" ) ) );
78  addParameter( new QgsProcessingParameterFile( QStringLiteral( "FOLDER" ), QObject::tr( "Output folder" ), QgsProcessingParameterFile::Folder ) );
79 
80 
81  std::unique_ptr< QgsProcessingParameterMultipleLayers > layersParam = qgis::make_unique< QgsProcessingParameterMultipleLayers>( QStringLiteral( "LAYERS" ), QObject::tr( "Map layers to assign to unlocked map item(s)" ), QgsProcessing::TypeMapLayer, QVariant(), true );
82  layersParam->setFlags( layersParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
83  addParameter( layersParam.release() );
84 
85  QStringList imageFormats;
86  const QList<QByteArray> supportedImageFormats { QImageWriter::supportedImageFormats() };
87  for ( const QByteArray &format : supportedImageFormats )
88  {
89  if ( format == QByteArray( "svg" ) )
90  continue;
91  imageFormats << QString( format );
92  }
93  std::unique_ptr< QgsProcessingParameterEnum > extensionParam = qgis::make_unique< QgsProcessingParameterEnum >( QStringLiteral( "EXTENSION" ), QObject::tr( "Image format" ), imageFormats, false, imageFormats.indexOf( QLatin1String( "png" ) ) );
94  extensionParam->setFlags( extensionParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
95  addParameter( extensionParam.release() );
96 
97  std::unique_ptr< QgsProcessingParameterNumber > dpiParam = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DPI" ), QObject::tr( "DPI (leave blank for default layout DPI)" ), QgsProcessingParameterNumber::Double, QVariant(), true, 0 );
98  dpiParam->setFlags( dpiParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
99  addParameter( dpiParam.release() );
100 
101  std::unique_ptr< QgsProcessingParameterBoolean > appendGeorefParam = qgis::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "GEOREFERENCE" ), QObject::tr( "Generate world file" ), true );
102  appendGeorefParam->setFlags( appendGeorefParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
103  addParameter( appendGeorefParam.release() );
104 
105  std::unique_ptr< QgsProcessingParameterBoolean > exportRDFParam = qgis::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "INCLUDE_METADATA" ), QObject::tr( "Export RDF metadata (title, author, etc.)" ), true );
106  exportRDFParam->setFlags( exportRDFParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
107  addParameter( exportRDFParam.release() );
108 
109  std::unique_ptr< QgsProcessingParameterBoolean > antialias = qgis::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "ANTIALIAS" ), QObject::tr( "Enable antialiasing" ), true );
110  antialias->setFlags( antialias->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
111  addParameter( antialias.release() );
112 }
113 
114 QgsProcessingAlgorithm::Flags QgsLayoutAtlasToImageAlgorithm::flags() const
115 {
116  return QgsProcessingAlgorithm::flags() | FlagNoThreading;
117 }
118 
119 QgsLayoutAtlasToImageAlgorithm *QgsLayoutAtlasToImageAlgorithm::createInstance() const
120 {
121  return new QgsLayoutAtlasToImageAlgorithm();
122 }
123 
124 QVariantMap QgsLayoutAtlasToImageAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
125 {
126  // this needs to be done in main thread, layouts are not thread safe
127  QgsPrintLayout *l = parameterAsLayout( parameters, QStringLiteral( "LAYOUT" ), context );
128  if ( !l )
129  throw QgsProcessingException( QObject::tr( "Cannot find layout with name \"%1\"" ).arg( parameters.value( QStringLiteral( "LAYOUT" ) ).toString() ) );
130 
131  std::unique_ptr< QgsPrintLayout > layout( l->clone() );
132  QgsLayoutAtlas *atlas = layout->atlas();
133 
134  QString expression, error;
135  QgsVectorLayer *layer = parameterAsVectorLayer( parameters, QStringLiteral( "COVERAGE_LAYER" ), context );
136  if ( layer )
137  {
138  atlas->setEnabled( true );
139  atlas->setCoverageLayer( layer );
140 
141  expression = parameterAsString( parameters, QStringLiteral( "FILTER_EXPRESSION" ), context );
142  atlas->setFilterExpression( expression, error );
143  if ( !expression.isEmpty() && !error.isEmpty() )
144  {
145  throw QgsProcessingException( QObject::tr( "Error setting atlas filter expression" ) );
146  }
147  error.clear();
148 
149  expression = parameterAsString( parameters, QStringLiteral( "SORTBY_EXPRESSION" ), context );
150  if ( !expression.isEmpty() )
151  {
152  const bool sortByReverse = parameterAsBool( parameters, QStringLiteral( "SORTBY_REVERSE" ), context );
153  atlas->setSortFeatures( true );
154  atlas->setSortExpression( expression );
155  atlas->setSortAscending( !sortByReverse );
156  }
157  else
158  {
159  atlas->setSortFeatures( false );
160  }
161  }
162  else if ( !atlas->enabled() )
163  {
164  throw QgsProcessingException( QObject::tr( "Layout being export doesn't have an enabled atlas" ) );
165  }
166 
167  expression = parameterAsString( parameters, QStringLiteral( "FILENAME_EXPRESSION" ), context );
168  atlas->setFilenameExpression( expression, error );
169  if ( !error.isEmpty() )
170  {
171  throw QgsProcessingException( QObject::tr( "Error setting atlas filename expression" ) );
172  }
173 
174  const QString directory = parameterAsFileOutput( parameters, QStringLiteral( "FOLDER" ), context );
175  QString fileName = QDir( directory ).filePath( QStringLiteral( "atlas" ) );
176 
177  QStringList imageFormats;
178  const QList<QByteArray> supportedImageFormats { QImageWriter::supportedImageFormats() };
179  for ( const QByteArray &format : supportedImageFormats )
180  {
181  if ( format == QByteArray( "svg" ) )
182  continue;
183  imageFormats << QString( format );
184  }
185  int idx = parameterAsEnum( parameters, QStringLiteral( "EXTENSION" ), context );
186  QString extension = '.' + imageFormats.at( idx );
187 
188  QgsLayoutExporter exporter( layout.get() );
190 
191  if ( parameters.value( QStringLiteral( "DPI" ) ).isValid() )
192  {
193  settings.dpi = parameterAsDouble( parameters, QStringLiteral( "DPI" ), context );
194  }
195 
196  settings.exportMetadata = parameterAsBool( parameters, QStringLiteral( "INCLUDE_METADATA" ), context );
197  settings.generateWorldFile = parameterAsBool( parameters, QStringLiteral( "GEOREFERENCE" ), context );
198 
199  if ( parameterAsBool( parameters, QStringLiteral( "ANTIALIAS" ), context ) )
201  else
202  settings.flags = settings.flags & ~QgsLayoutRenderContext::FlagAntialiasing;
203 
204  const QList< QgsMapLayer * > layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
205  if ( layers.size() > 0 )
206  {
207  const QList<QGraphicsItem *> items = layout->items();
208  for ( QGraphicsItem *graphicsItem : items )
209  {
210  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
211  QgsLayoutItemMap *map = dynamic_cast<QgsLayoutItemMap *>( item );
212  if ( map && !map->followVisibilityPreset() && !map->keepLayerSet() )
213  {
214  map->setKeepLayerSet( true );
215  map->setLayers( layers );
216  }
217  }
218  }
219 
220  switch ( exporter.exportToImage( atlas, fileName, extension, settings, error, feedback ) )
221  {
223  {
224  feedback->pushInfo( QObject::tr( "Successfully exported layout to %1" ).arg( QDir::toNativeSeparators( directory ) ) );
225  break;
226  }
227 
229  throw QgsProcessingException( QObject::tr( "Cannot write to %1.\n\nThis file may be open in another application." ).arg( QDir::toNativeSeparators( directory ) ) );
230 
232  throw QgsProcessingException( QObject::tr( "Trying to create the image "
233  "resulted in a memory overflow.\n\n"
234  "Please try a lower resolution or a smaller paper size." ) );
235 
237  throw QgsProcessingException( QObject::tr( "Error encountered while exporting atlas." ) );
238 
242  // no meaning for imageexports, will not be encountered
243  break;
244  }
245 
246  feedback->setProgress( 100 );
247 
248  QVariantMap outputs;
249  outputs.insert( QStringLiteral( "FOLDER" ), directory );
250  return outputs;
251 }
252 
254 
QgsLayoutExporter::ImageExportSettings::exportMetadata
bool exportMetadata
Indicates whether image export should include metadata generated from the layout's project's metadata...
Definition: qgslayoutexporter.h:205
QgsFeedback::setProgress
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:62
QgsProcessingParameterNumber::Double
@ Double
Double/float values.
Definition: qgsprocessingparameters.h:1967
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:38
QgsLayoutExporter::PrintError
@ PrintError
Could not start printing to destination device.
Definition: qgslayoutexporter.h:142
QgsProcessingFeedback::pushInfo
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
Definition: qgsprocessingfeedback.cpp:48
QgsLayoutExporter::ImageExportSettings::flags
QgsLayoutRenderContext::Flags flags
Layout context flags, which control how the export will be created.
Definition: qgslayoutexporter.h:211
QgsProcessingParameterFile::Folder
@ Folder
Parameter is a folder.
Definition: qgsprocessingparameters.h:1696
QgsLayoutExporter::Success
@ Success
Export was successful.
Definition: qgslayoutexporter.h:138
QgsLayoutRenderContext
Stores information relating to the current rendering settings for a layout.
Definition: qgslayoutrendercontext.h:33
QgsProcessingParameterDefinition::FlagAdvanced
@ FlagAdvanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition: qgsprocessingparameters.h:423
QgsLayoutAtlas::setEnabled
void setEnabled(bool enabled)
Sets whether the atlas is enabled.
Definition: qgslayoutatlas.cpp:123
QgsLayoutExporter::Canceled
@ Canceled
Export was canceled.
Definition: qgslayoutexporter.h:139
QgsLayoutItemMap::followVisibilityPreset
bool followVisibilityPreset() const
Returns whether the map should follow a map theme.
Definition: qgslayoutitemmap.h:562
QgsLayoutExporter::MemoryError
@ MemoryError
Unable to allocate memory required to export.
Definition: qgslayoutexporter.h:140
qgslayoutexporter.h
QgsLayoutExporter::SvgLayerError
@ SvgLayerError
Could not create layered SVG file.
Definition: qgslayoutexporter.h:143
QgsPrintLayout
Print layout, a QgsLayout subclass for static or atlas-based layouts.
Definition: qgsprintlayout.h:31
QgsProcessing::TypeMapLayer
@ TypeMapLayer
Any map layer type (raster or vector or mesh)
Definition: qgsprocessing.h:46
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:44
QgsLayoutExporter
Handles rendering and exports of layouts to various formats.
Definition: qgslayoutexporter.h:45
QgsProcessingParameterFile
An input file or folder parameter for processing algorithms.
Definition: qgsprocessingparameters.h:1689
qgsalgorithmlayoutatlastoimage.h
QgsProcessingParameterVectorLayer
A vector layer (with or without geometry) parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2504
QgsLayoutItem
Base class for graphical items within a QgsLayout.
Definition: qgslayoutitem.h:113
qgslayout.h
QgsProcessingParameterLayout
A print layout parameter, allowing users to select a print layout.
Definition: qgsprocessingparameters.h:3300
QgsLayoutAtlas::setSortAscending
void setSortAscending(bool ascending)
Sets whether features should be sorted in an ascending order.
Definition: qgslayoutatlas.cpp:191
QgsLayoutItemMap
Layout graphical items for displaying a map.
Definition: qgslayoutitemmap.h:318
qgsprocessingoutputs.h
QgsLayoutExporter::ImageExportSettings
Contains settings relating to exporting layouts to raster images.
Definition: qgslayoutexporter.h:149
QgsProcessingParameterBoolean
A boolean parameter for processing algorithms.
Definition: qgsprocessingparameters.h:1507
QgsLayoutAtlas::setSortExpression
void setSortExpression(const QString &expression)
Sets the expression (or field name) to use for sorting features.
Definition: qgslayoutatlas.cpp:200
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsProcessingParameterExpression
An expression parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2416
QgsLayoutExporter::IteratorError
@ IteratorError
Error iterating over layout.
Definition: qgslayoutexporter.h:144
qgsprintlayout.h
QgsLayoutAtlas::setCoverageLayer
void setCoverageLayer(QgsVectorLayer *layer)
Sets the coverage layer to use for the atlas features.
Definition: qgslayoutatlas.cpp:154
QgsLayoutExporter::ImageExportSettings::generateWorldFile
bool generateWorldFile
Set to true to generate an external world file alongside exported images.
Definition: qgslayoutexporter.h:197
QgsLayoutAtlas::setFilterExpression
bool setFilterExpression(const QString &expression, QString &errorString)
Sets the expression used for filtering features in the coverage layer.
Definition: qgslayoutatlas.cpp:218
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:88
QgsLayoutRenderContext::FlagAntialiasing
@ FlagAntialiasing
Use antialiasing when drawing items.
Definition: qgslayoutrendercontext.h:44
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:42
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
QgsLayoutExporter::ImageExportSettings::dpi
double dpi
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
Definition: qgslayoutexporter.h:156
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:182
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:482
QgsLayoutExporter::FileError
@ FileError
Could not write to destination file, likely due to a lock held by another application.
Definition: qgslayoutexporter.h:141
QgsLayoutItemMap::setLayers
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the stored layers set.
Definition: qgslayoutitemmap.cpp:311
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