QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsalgorithmlayouttoimage.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmlayouttoimage.cpp
3  ---------------------
4  begin : June 2020
5  copyright : (C) 2020 by Nyall Dawson
6  email : nyall dot dawson 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 "qgslayoutitemmap.h"
21 #include "qgsprintlayout.h"
22 #include "qgsprocessingoutputs.h"
23 #include "qgslayoutexporter.h"
24 #include <QImageWriter>
25 
27 
28 QString QgsLayoutToImageAlgorithm::name() const
29 {
30  return QStringLiteral( "printlayouttoimage" );
31 }
32 
33 QString QgsLayoutToImageAlgorithm::displayName() const
34 {
35  return QObject::tr( "Export print layout as image" );
36 }
37 
38 QStringList QgsLayoutToImageAlgorithm::tags() const
39 {
40  return QObject::tr( "layout,composer,composition,save,png,jpeg,jpg" ).split( ',' );
41 }
42 
43 QString QgsLayoutToImageAlgorithm::group() const
44 {
45  return QObject::tr( "Cartography" );
46 }
47 
48 QString QgsLayoutToImageAlgorithm::groupId() const
49 {
50  return QStringLiteral( "cartography" );
51 }
52 
53 QString QgsLayoutToImageAlgorithm::shortDescription() const
54 {
55  return QObject::tr( "Exports a print layout as an image." );
56 }
57 
58 QString QgsLayoutToImageAlgorithm::shortHelpString() const
59 {
60  return QObject::tr( "This algorithm outputs a print layout as an image file (e.g. PNG or JPEG images)." );
61 }
62 
63 void QgsLayoutToImageAlgorithm::initAlgorithm( const QVariantMap & )
64 {
65  addParameter( new QgsProcessingParameterLayout( QStringLiteral( "LAYOUT" ), QObject::tr( "Print layout" ) ) );
66 
67  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 );
68  layersParam->setFlags( layersParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
69  addParameter( layersParam.release() );
70 
71  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 );
72  dpiParam->setFlags( dpiParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
73  addParameter( dpiParam.release() );
74 
75  std::unique_ptr< QgsProcessingParameterBoolean > appendGeorefParam = qgis::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "GEOREFERENCE" ), QObject::tr( "Generate world file" ), true );
76  appendGeorefParam->setFlags( appendGeorefParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
77  addParameter( appendGeorefParam.release() );
78 
79  std::unique_ptr< QgsProcessingParameterBoolean > exportRDFParam = qgis::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "INCLUDE_METADATA" ), QObject::tr( "Export RDF metadata (title, author, etc.)" ), true );
80  exportRDFParam->setFlags( exportRDFParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
81  addParameter( exportRDFParam.release() );
82 
83  std::unique_ptr< QgsProcessingParameterBoolean > antialias = qgis::make_unique< QgsProcessingParameterBoolean >( QStringLiteral( "ANTIALIAS" ), QObject::tr( "Enable antialiasing" ), true );
84  antialias->setFlags( antialias->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
85  addParameter( antialias.release() );
86 
87  QStringList imageFilters;
88  const auto supportedImageFormats { QImageWriter::supportedImageFormats() };
89  for ( const QByteArray &format : supportedImageFormats )
90  {
91  if ( format == "svg" )
92  continue;
93 
94  QString longName = format.toUpper() + QObject::tr( " format" );
95  QString glob = QStringLiteral( "*." ) + format;
96 
97  if ( format == "png" && !imageFilters.empty() )
98  imageFilters.insert( 0, QStringLiteral( "%1 (%2 %3)" ).arg( longName, glob.toLower(), glob.toUpper() ) );
99  else
100  imageFilters.append( QStringLiteral( "%1 (%2 %3)" ).arg( longName, glob.toLower(), glob.toUpper() ) );
101  }
102 
103  addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Image file" ), imageFilters.join( QLatin1String( ";;" ) ) ) );
104 }
105 
106 QgsProcessingAlgorithm::Flags QgsLayoutToImageAlgorithm::flags() const
107 {
108  return QgsProcessingAlgorithm::flags() | FlagNoThreading;
109 }
110 
111 QgsLayoutToImageAlgorithm *QgsLayoutToImageAlgorithm::createInstance() const
112 {
113  return new QgsLayoutToImageAlgorithm();
114 }
115 
116 QVariantMap QgsLayoutToImageAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
117 {
118  // this needs to be done in main thread, layouts are not thread safe
119  QgsPrintLayout *l = parameterAsLayout( parameters, QStringLiteral( "LAYOUT" ), context );
120  if ( !l )
121  throw QgsProcessingException( QObject::tr( "Cannot find layout with name \"%1\"" ).arg( parameters.value( QStringLiteral( "LAYOUT" ) ).toString() ) );
122  std::unique_ptr< QgsPrintLayout > layout( l->clone() );
123 
124  const QList< QgsMapLayer * > layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
125  if ( layers.size() > 0 )
126  {
127  const QList<QGraphicsItem *> items = layout->items();
128  for ( QGraphicsItem *graphicsItem : items )
129  {
130  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
131  QgsLayoutItemMap *map = dynamic_cast<QgsLayoutItemMap *>( item );
132  if ( map && !map->followVisibilityPreset() && !map->keepLayerSet() )
133  {
134  map->setKeepLayerSet( true );
135  map->setLayers( layers );
136  }
137  }
138  }
139 
140  const QString dest = parameterAsFileOutput( parameters, QStringLiteral( "OUTPUT" ), context );
141 
142  QgsLayoutExporter exporter( layout.get() );
144 
145  if ( parameters.value( QStringLiteral( "DPI" ) ).isValid() )
146  {
147  settings.dpi = parameterAsDouble( parameters, QStringLiteral( "DPI" ), context );
148  }
149 
150  settings.exportMetadata = parameterAsBool( parameters, QStringLiteral( "INCLUDE_METADATA" ), context );
151  settings.generateWorldFile = parameterAsBool( parameters, QStringLiteral( "GEOREFERENCE" ), context );
152 
153  if ( parameterAsBool( parameters, QStringLiteral( "ANTIALIAS" ), context ) )
155  else
156  settings.flags = settings.flags & ~QgsLayoutRenderContext::FlagAntialiasing;
157 
158  switch ( exporter.exportToImage( dest, settings ) )
159  {
161  {
162  feedback->pushInfo( QObject::tr( "Successfully exported layout to %1" ).arg( QDir::toNativeSeparators( dest ) ) );
163  break;
164  }
165 
167  throw QgsProcessingException( QObject::tr( "Cannot write to %1.\n\nThis file may be open in another application." ).arg( QDir::toNativeSeparators( dest ) ) );
168 
170  throw QgsProcessingException( QObject::tr( "Trying to create the image "
171  "resulted in a memory overflow.\n\n"
172  "Please try a lower resolution or a smaller paper size." ) );
173 
178  // no meaning for imageexports, will not be encountered
179  break;
180  }
181 
182  feedback->setProgress( 100 );
183 
184  QVariantMap outputs;
185  outputs.insert( QStringLiteral( "OUTPUT" ), dest );
186  return outputs;
187 }
188 
190 
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
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
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
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:44
QgsProcessingParameterFileDestination
A generic file based destination parameter, for specifying the destination path for a file (non-map l...
Definition: qgsprocessingparameters.h:3127
QgsLayoutExporter
Handles rendering and exports of layouts to various formats.
Definition: qgslayoutexporter.h:45
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
QgsLayoutItemMap
Layout graphical items for displaying a map.
Definition: qgslayoutitemmap.h:318
qgsprocessingoutputs.h
qgsalgorithmlayouttoimage.h
QgsLayoutExporter::ImageExportSettings
Contains settings relating to exporting layouts to raster images.
Definition: qgslayoutexporter.h:149
QgsLayoutExporter::IteratorError
@ IteratorError
Error iterating over layout.
Definition: qgslayoutexporter.h:144
qgsprintlayout.h
QgsLayoutExporter::ImageExportSettings::generateWorldFile
bool generateWorldFile
Set to true to generate an external world file alongside exported images.
Definition: qgslayoutexporter.h:197
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
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
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