QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgsmaprenderertask.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaprenderertask.h
3  -------------------------
4  begin : Apr 2017
5  copyright : (C) 2017 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 
18 #include "qgsannotation.h"
19 #include "qgsannotationmanager.h"
20 #include "qgsmaprenderertask.h"
21 #include "qgsmapsettingsutils.h"
22 #include "qgsogrutils.h"
23 #include "qgslogger.h"
27 #include "qgsfeaturerequest.h"
28 #include "qgsvectorlayer.h"
29 
30 #include <QFile>
31 #include <QTextStream>
32 #include <QTimeZone>
33 #ifndef QT_NO_PRINTER
34 #include <QPrinter>
35 #endif
36 
37 #include "gdal.h"
38 #include "cpl_conv.h"
39 
41 
42 class QgsMapRendererTaskGeoPdfExporter : public QgsAbstractGeoPdfExporter
43 {
44 
45  public:
46 
47  QgsMapRendererTaskGeoPdfExporter( const QgsMapSettings &ms )
48  {
49  // collect details upfront, while we are still in the main thread
50  const QList< QgsMapLayer * > layers = ms.layers();
51  for ( const QgsMapLayer *layer : layers )
52  {
53  VectorComponentDetail detail;
54  detail.name = layer->name();
55  detail.mapLayerId = layer->id();
56  if ( const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) )
57  {
58  detail.displayAttribute = vl->displayField();
59  }
60  mLayerDetails[ layer->id() ] = detail;
61  }
62  }
63 
64  private:
65 
66  QgsAbstractGeoPdfExporter::VectorComponentDetail componentDetailForLayerId( const QString &layerId ) override
67  {
68  return mLayerDetails.value( layerId );
69  }
70 
71  QMap< QString, VectorComponentDetail > mLayerDetails;
72 };
73 
74 
75 class QgsMapRendererTaskRenderedFeatureHandler : public QgsRenderedFeatureHandlerInterface
76 {
77  public:
78 
79  QgsMapRendererTaskRenderedFeatureHandler( QgsMapRendererTaskGeoPdfExporter *exporter, const QgsMapSettings &settings )
80  : mExporter( exporter )
81  , mMapSettings( settings )
82  {
83  // PDF coordinate space uses a hardcoded DPI of 72, also vertical dimension is flipped from QGIS dimension
84  const double pageHeightPdfUnits = settings.outputSize().height() * 72.0 / settings.outputDpi();
85  mTransform = QTransform::fromTranslate( 0, pageHeightPdfUnits ).scale( 72.0 / mMapSettings.outputDpi(), -72.0 / mMapSettings.outputDpi() );
86  }
87 
88  void handleRenderedFeature( const QgsFeature &feature, const QgsGeometry &renderedBounds, const QgsRenderedFeatureHandlerInterface::RenderedFeatureContext &context ) override
89  {
90  // is it a hack retrieving the layer ID from an expression context like this? possibly... BUT
91  // the alternative is adding a layer ID member to QgsRenderContext, and that's just asking for people to abuse it
92  // and use it to retrieve QgsMapLayers mid-way through a render operation. Lesser of two evils it is!
93  const QString layerId = context.renderContext.expressionContext().variable( QStringLiteral( "layer_id" ) ).toString();
94 
95  QgsGeometry transformed = renderedBounds;
96  transformed.transform( mTransform );
97 
98  // always convert to multitype, to make things consistent
99  transformed.convertToMultiType();
100 
101  mExporter->pushRenderedFeature( layerId, QgsAbstractGeoPdfExporter::RenderedFeature( feature, transformed ) );
102  }
103 
104  QSet<QString> usedAttributes( QgsVectorLayer *, const QgsRenderContext & ) const override
105  {
106  return QSet< QString >() << QgsFeatureRequest::ALL_ATTRIBUTES;
107  }
108 
109  private:
110 
111  QgsMapRendererTaskGeoPdfExporter *mExporter = nullptr;
112  QgsMapSettings mMapSettings;
114  QTransform mTransform;
115 
116 };
117 
119 
120 QgsMapRendererTask::QgsMapRendererTask( const QgsMapSettings &ms, const QString &fileName, const QString &fileFormat, const bool forceRaster,
121  const bool geoPDF, const QgsAbstractGeoPdfExporter::ExportDetails &geoPdfExportDetails )
122  : QgsTask( fileFormat == QLatin1String( "PDF" ) ? tr( "Saving as PDF" ) : tr( "Saving as image" ) )
123  , mMapSettings( ms )
124  , mFileName( fileName )
125  , mFileFormat( fileFormat )
126  , mForceRaster( forceRaster )
127  , mGeoPDF( geoPDF && mFileFormat == QLatin1String( "PDF" ) && QgsAbstractGeoPdfExporter::geoPDFCreationAvailable() )
128  , mGeoPdfExportDetails( geoPdfExportDetails )
129 {
130  prepare();
131 }
132 
134  : QgsTask( tr( "Rendering to painter" ) )
135  , mMapSettings( ms )
136  , mPainter( p )
137 {
138  prepare();
139 }
140 
142 
143 void QgsMapRendererTask::addAnnotations( const QList< QgsAnnotation * > &annotations )
144 {
145  qDeleteAll( mAnnotations );
146  mAnnotations.clear();
147 
148  const auto constAnnotations = annotations;
149  for ( const QgsAnnotation *a : constAnnotations )
150  {
151  mAnnotations << a->clone();
152  }
153 }
154 
155 void QgsMapRendererTask::addDecorations( const QList< QgsMapDecoration * > &decorations )
156 {
157  mDecorations = decorations;
158 }
159 
160 
162 {
163  mJobMutex.lock();
164  if ( mJob )
165  mJob->cancelWithoutBlocking();
166  mJobMutex.unlock();
167 
168  QgsTask::cancel();
169 }
170 
172 {
173  if ( mErrored )
174  return false;
175 
176  if ( mGeoPDF )
177  {
178 #ifdef QT_NO_PRINTER
179  return false;
180 #else
181  QList< QgsAbstractGeoPdfExporter::ComponentLayerDetail > pdfComponents;
182 
183  QgsMapRendererStagedRenderJob *job = static_cast< QgsMapRendererStagedRenderJob * >( mJob.get() );
184  int outputLayer = 1;
185  while ( !job->isFinished() )
186  {
188 
189  component.name = QStringLiteral( "layer_%1" ).arg( outputLayer );
190  component.mapLayerId = job->currentLayerId();
191  component.opacity = job->currentLayerOpacity();
192  component.compositionMode = job->currentLayerCompositionMode();
193  component.sourcePdfPath = mGeoPdfExporter->generateTemporaryFilepath( QStringLiteral( "layer_%1.pdf" ).arg( outputLayer ) );
194  pdfComponents << component;
195 
196  QPrinter printer;
197  printer.setOutputFileName( component.sourcePdfPath );
198  printer.setOutputFormat( QPrinter::PdfFormat );
199 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
200  printer.setOrientation( QPrinter::Portrait );
201  // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
202  QSizeF outputSize = mMapSettings.outputSize();
203  printer.setPaperSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPrinter::Millimeter );
204  printer.setPageMargins( 0, 0, 0, 0, QPrinter::Millimeter );
205 #else
206  printer.setPageOrientation( QPageLayout::Orientation::Portrait );
207  // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
208  const QSizeF outputSize = mMapSettings.outputSize();
209  const QPageSize pageSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPageSize::Unit::Millimeter );
210  printer.setPageSize( pageSize );
211  printer.setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
212 #endif
213  printer.setResolution( mMapSettings.outputDpi() );
214 
215  QPainter p( &printer );
216  job->renderCurrentPart( &p );
217  p.end();
218 
219  outputLayer++;
220  job->nextPart();
221  }
222  QgsAbstractGeoPdfExporter::ExportDetails exportDetails = mGeoPdfExportDetails;
223  const double pageWidthMM = mMapSettings.outputSize().width() * 25.4 / mMapSettings.outputDpi();
224  const double pageHeightMM = mMapSettings.outputSize().height() * 25.4 / mMapSettings.outputDpi();
225  exportDetails.pageSizeMm = QSizeF( pageWidthMM, pageHeightMM );
226  exportDetails.dpi = mMapSettings.outputDpi();
227 
228  exportDetails.layerIdToPdfLayerTreeNameMap = mLayerIdToLayerNameMap;
229  exportDetails.layerOrder = mMapLayerOrder;
230 
231  if ( mSaveWorldFile )
232  {
233  // setup georeferencing
235  georef.crs = mMapSettings.destinationCrs();
236  georef.pageBoundsMm = QgsRectangle( 0, 0, pageWidthMM, pageHeightMM );
237  georef.controlPoints.reserve( 4 );
239  georef.controlPoints << QgsAbstractGeoPdfExporter::ControlPoint( QgsPointXY( pageWidthMM, 0 ), mMapSettings.mapToPixel().toMapCoordinates( mMapSettings.outputSize().width(), 0 ) );
240  georef.controlPoints << QgsAbstractGeoPdfExporter::ControlPoint( QgsPointXY( pageWidthMM, pageHeightMM ), mMapSettings.mapToPixel().toMapCoordinates( mMapSettings.outputSize().width(), mMapSettings.outputSize().height() ) );
241  georef.controlPoints << QgsAbstractGeoPdfExporter::ControlPoint( QgsPointXY( 0, pageHeightMM ), mMapSettings.mapToPixel().toMapCoordinates( 0, mMapSettings.outputSize().height() ) );
242  exportDetails.georeferencedSections << georef;
243  }
244 
245  const bool res = mGeoPdfExporter->finalize( pdfComponents, mFileName, exportDetails );
246  mGeoPdfExporter.reset();
247  mTempPainter.reset();
248  mPrinter.reset();
249  return res;
250 #endif
251  }
252  else
253  static_cast< QgsMapRendererCustomPainterJob *>( mJob.get() )->renderPrepared();
254 
255  mJobMutex.lock();
256  mJob.reset( nullptr );
257  mJobMutex.unlock();
258 
259  if ( isCanceled() )
260  return false;
261 
262  QgsRenderContext context = QgsRenderContext::fromMapSettings( mMapSettings );
263  context.setPainter( mDestPainter );
264 
265  const auto constMDecorations = mDecorations;
266  for ( QgsMapDecoration *decoration : constMDecorations )
267  {
268  decoration->render( mMapSettings, context );
269  }
270 
271  const auto constMAnnotations = mAnnotations;
272  for ( QgsAnnotation *annotation : constMAnnotations )
273  {
274  if ( isCanceled() )
275  return false;
276 
277  if ( !annotation || !annotation->isVisible() )
278  {
279  continue;
280  }
281  if ( annotation->mapLayer() && !mMapSettings.layers().contains( annotation->mapLayer() ) )
282  {
283  continue;
284  }
285 
286  const QgsScopedQPainterState painterState( context.painter() );
287  context.setPainterFlagsUsingContext();
288 
289  double itemX, itemY;
290  if ( annotation->hasFixedMapPosition() )
291  {
292  itemX = mMapSettings.outputSize().width() * ( annotation->mapPosition().x() - mMapSettings.extent().xMinimum() ) / mMapSettings.extent().width();
293  itemY = mMapSettings.outputSize().height() * ( 1 - ( annotation->mapPosition().y() - mMapSettings.extent().yMinimum() ) / mMapSettings.extent().height() );
294  }
295  else
296  {
297  itemX = annotation->relativePosition().x() * mMapSettings.outputSize().width();
298  itemY = annotation->relativePosition().y() * mMapSettings.outputSize().height();
299  }
300 
301  context.painter()->translate( itemX, itemY );
302 
303  annotation->render( context );
304  }
305 
306  if ( !mFileName.isEmpty() )
307  {
308  mDestPainter->end();
309 
310  if ( mFileFormat == QLatin1String( "PDF" ) )
311  {
312 #ifndef QT_NO_PRINTER
313  if ( mForceRaster )
314  {
315  QPainter pp;
316  pp.begin( mPrinter.get() );
317  const QRectF rect( 0, 0, mImage.width(), mImage.height() );
318  pp.drawImage( rect, mImage, rect );
319  pp.end();
320  }
321 
322  if ( mSaveWorldFile || mExportMetadata )
323  {
324  CPLSetThreadLocalConfigOption( "GDAL_PDF_DPI", QString::number( mMapSettings.outputDpi() ).toLocal8Bit().constData() );
325  const gdal::dataset_unique_ptr outputDS( GDALOpen( mFileName.toLocal8Bit().constData(), GA_Update ) );
326  if ( outputDS )
327  {
328  if ( mSaveWorldFile )
329  {
330  double a, b, c, d, e, f;
331  QgsMapSettingsUtils::worldFileParameters( mMapSettings, a, b, c, d, e, f );
332  c -= 0.5 * a;
333  c -= 0.5 * b;
334  f -= 0.5 * d;
335  f -= 0.5 * e;
336  double geoTransform[6] = { c, a, b, f, d, e };
337  GDALSetGeoTransform( outputDS.get(), geoTransform );
338  GDALSetProjection( outputDS.get(), mMapSettings.destinationCrs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED_GDAL ).toLocal8Bit().constData() );
339  }
340 
341  if ( mExportMetadata )
342  {
343  QString creationDateString;
344  const QDateTime creationDateTime = mGeoPdfExportDetails.creationDateTime;
345  if ( creationDateTime.isValid() )
346  {
347  creationDateString = QStringLiteral( "D:%1" ).arg( mGeoPdfExportDetails.creationDateTime.toString( QStringLiteral( "yyyyMMddHHmmss" ) ) );
348  if ( creationDateTime.timeZone().isValid() )
349  {
350  int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
351  creationDateString += ( offsetFromUtc >= 0 ) ? '+' : '-';
352  offsetFromUtc = std::abs( offsetFromUtc );
353  const int offsetHours = offsetFromUtc / 3600;
354  const int offsetMins = ( offsetFromUtc % 3600 ) / 60;
355  creationDateString += QStringLiteral( "%1'%2'" ).arg( offsetHours ).arg( offsetMins );
356  }
357  }
358  GDALSetMetadataItem( outputDS.get(), "CREATION_DATE", creationDateString.toUtf8().constData(), nullptr );
359 
360  GDALSetMetadataItem( outputDS.get(), "AUTHOR", mGeoPdfExportDetails.author.toUtf8().constData(), nullptr );
361  const QString creator = QStringLiteral( "QGIS %1" ).arg( Qgis::version() );
362  GDALSetMetadataItem( outputDS.get(), "CREATOR", creator.toUtf8().constData(), nullptr );
363  GDALSetMetadataItem( outputDS.get(), "PRODUCER", creator.toUtf8().constData(), nullptr );
364  GDALSetMetadataItem( outputDS.get(), "SUBJECT", mGeoPdfExportDetails.subject.toUtf8().constData(), nullptr );
365  GDALSetMetadataItem( outputDS.get(), "TITLE", mGeoPdfExportDetails.title.toUtf8().constData(), nullptr );
366 
367  const QgsAbstractMetadataBase::KeywordMap keywords = mGeoPdfExportDetails.keywords;
368  QStringList allKeywords;
369  for ( auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
370  {
371  allKeywords.append( QStringLiteral( "%1: %2" ).arg( it.key(), it.value().join( ',' ) ) );
372  }
373  const QString keywordString = allKeywords.join( ';' );
374  GDALSetMetadataItem( outputDS.get(), "KEYWORDS", keywordString.toUtf8().constData(), nullptr );
375  }
376  }
377  CPLSetThreadLocalConfigOption( "GDAL_PDF_DPI", nullptr );
378  }
379 #else
380  mError = ImageUnsupportedFormat;
381  return false;
382 #endif // !QT_NO_PRINTER
383  }
384  else if ( mFileFormat != QLatin1String( "PDF" ) )
385  {
386  const bool success = mImage.save( mFileName, mFileFormat.toLocal8Bit().data() );
387  if ( !success )
388  {
389  mError = ImageSaveFail;
390  return false;
391  }
392 
393  if ( mSaveWorldFile )
394  {
395  const QFileInfo info = QFileInfo( mFileName );
396 
397  // build the world file name
398  const QString outputSuffix = info.suffix();
399  bool skipWorldFile = false;
400  if ( outputSuffix == QLatin1String( "tif" ) || outputSuffix == QLatin1String( "tiff" ) )
401  {
402  const gdal::dataset_unique_ptr outputDS( GDALOpen( mFileName.toLocal8Bit().constData(), GA_Update ) );
403  if ( outputDS )
404  {
405  skipWorldFile = true;
406  double a, b, c, d, e, f;
407  QgsMapSettingsUtils::worldFileParameters( mMapSettings, a, b, c, d, e, f );
408  c -= 0.5 * a;
409  c -= 0.5 * b;
410  f -= 0.5 * d;
411  f -= 0.5 * e;
412  double geoTransform[] = { c, a, b, f, d, e };
413  GDALSetGeoTransform( outputDS.get(), geoTransform );
414  GDALSetProjection( outputDS.get(), mMapSettings.destinationCrs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED_GDAL ).toLocal8Bit().constData() );
415  }
416  }
417 
418  if ( !skipWorldFile )
419  {
420  const QString worldFileName = info.absolutePath() + '/' + info.completeBaseName() + '.'
421  + outputSuffix.at( 0 ) + outputSuffix.at( info.suffix().size() - 1 ) + 'w';
422  QFile worldFile( worldFileName );
423 
424  if ( worldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) //don't use QIODevice::Text
425  {
426  QTextStream stream( &worldFile );
427  stream << QgsMapSettingsUtils::worldFileContent( mMapSettings );
428  }
429  }
430  }
431  }
432  }
433 
434  mTempPainter.reset();
435 #ifndef QT_NO_PRINTER
436  mPrinter.reset();
437 #endif
438 
439  return true;
440 }
441 
442 void QgsMapRendererTask::finished( bool result )
443 {
444  qDeleteAll( mAnnotations );
445  mAnnotations.clear();
446 
447  if ( result )
448  emit renderingComplete();
449  else
450  emit errorOccurred( mError );
451 }
452 
453 void QgsMapRendererTask::prepare()
454 {
455  if ( mGeoPDF )
456  {
457  mGeoPdfExporter = std::make_unique< QgsMapRendererTaskGeoPdfExporter >( mMapSettings );
458  if ( mGeoPdfExportDetails.includeFeatures )
459  {
460  mRenderedFeatureHandler = std::make_unique< QgsMapRendererTaskRenderedFeatureHandler >( static_cast< QgsMapRendererTaskGeoPdfExporter * >( mGeoPdfExporter.get() ), mMapSettings );
461  mMapSettings.addRenderedFeatureHandler( mRenderedFeatureHandler.get() );
462  }
463 
464  const QList< QgsMapLayer * > layers = mMapSettings.layers();
465  for ( const QgsMapLayer *layer : layers )
466  {
467  mLayerIdToLayerNameMap.insert( layer->id(), layer->name() );
468  mMapLayerOrder << layer->id();
469  }
470 
472  mJob->start();
473  return;
474  }
475 
476  mDestPainter = mPainter;
477 
478  if ( mFileFormat == QLatin1String( "PDF" ) )
479  {
480 #ifndef QT_NO_PRINTER
481  mPrinter.reset( new QPrinter() );
482  mPrinter->setOutputFileName( mFileName );
483  mPrinter->setOutputFormat( QPrinter::PdfFormat );
484 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
485  mPrinter->setOrientation( QPrinter::Portrait );
486  // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
487  QSizeF outputSize = mMapSettings.outputSize();
488  mPrinter->setPaperSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPrinter::Millimeter );
489  mPrinter->setPageMargins( 0, 0, 0, 0, QPrinter::Millimeter );
490 #else
491  mPrinter->setPageOrientation( QPageLayout::Orientation::Portrait );
492  // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
493  const QSizeF outputSize = mMapSettings.outputSize();
494  const QPageSize pageSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPageSize::Unit::Millimeter );
495  mPrinter->setPageSize( pageSize );
496  mPrinter->setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
497 #endif
498  mPrinter->setResolution( mMapSettings.outputDpi() );
499 
500  if ( !mForceRaster )
501  {
502  mTempPainter.reset( new QPainter( mPrinter.get() ) );
503  mDestPainter = mTempPainter.get();
504  }
505 #else
506  mError = ImageUnsupportedFormat;
507 #endif // ! QT_NO_PRINTER
508  }
509 
510  if ( !mDestPainter )
511  {
512  // save rendered map to an image file
513  mImage = QImage( mMapSettings.outputSize(), QImage::Format_ARGB32 );
514  if ( mImage.isNull() )
515  {
516  mErrored = true;
517  mError = ImageAllocationFail;
518  return;
519  }
520 
521  mImage.setDotsPerMeterX( 1000 * mMapSettings.outputDpi() / 25.4 );
522  mImage.setDotsPerMeterY( 1000 * mMapSettings.outputDpi() / 25.4 );
523 
524  mTempPainter.reset( new QPainter( &mImage ) );
525  mDestPainter = mTempPainter.get();
526  }
527 
528  if ( !mDestPainter )
529  {
530  mErrored = true;
531  return;
532  }
533 
534  mJob.reset( new QgsMapRendererCustomPainterJob( mMapSettings, mDestPainter ) );
535  static_cast< QgsMapRendererCustomPainterJob *>( mJob.get() )->prepare();
536 }
static QString version()
Version string.
Definition: qgis.cpp:277
Abstract base class for GeoPDF exporters.
QMap< QString, QStringList > KeywordMap
Map of vocabulary string to keyword list.
Abstract base class for annotation items which are drawn over a map.
Definition: qgsannotation.h:54
@ WKT_PREFERRED_GDAL
Preferred format for conversion of CRS to WKT for use with the GDAL library.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
Interface for map decorations.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
Job implementation that renders everything sequentially using a custom painter.
Render job implementation that renders maps in stages, allowing different stages (e....
double currentLayerOpacity() const
Returns the opacity for the current layer about to be rendered in the next render operation.
@ RenderLabelsByMapLayer
Labels should be rendered in individual stages by map layer. This allows separation of labels belongi...
QPainter::CompositionMode currentLayerCompositionMode() const
Returns the composition mode for the current layer about to be rendered in the next render operation.
QString currentLayerId() const
Returns the ID of the current layer about to be rendered in the next render operation.
bool isFinished() const
Returns true if the job is finished, and nothing remains to render.
bool nextPart()
Iterates to the next part to render.
bool renderCurrentPart(QPainter *painter)
Renders the current part of the map to the specified painter.
void addDecorations(const QList< QgsMapDecoration * > &decorations)
Adds decorations to be rendered on the map.
bool run() override
Performs the task's operation.
void errorOccurred(int error)
Emitted when map rendering failed.
@ ImageUnsupportedFormat
Format is unsupported on the platform.
@ ImageSaveFail
Image save failure.
@ ImageAllocationFail
Image allocation failure.
QgsMapRendererTask(const QgsMapSettings &ms, const QString &fileName, const QString &fileFormat=QString("PNG"), bool forceRaster=false, bool geoPdf=false, const QgsAbstractGeoPdfExporter::ExportDetails &geoPdfExportDetails=QgsAbstractGeoPdfExporter::ExportDetails())
Constructor for QgsMapRendererTask to render a map to an image file.
void addAnnotations(const QList< QgsAnnotation * > &annotations)
Adds annotations to be rendered on the map.
void finished(bool result) override
If the task is managed by a QgsTaskManager, this will be called after the task has finished (whether ...
~QgsMapRendererTask() override
void cancel() override
Notifies the task that it should terminate.
void renderingComplete()
Emitted when the map rendering is successfully completed.
static void worldFileParameters(const QgsMapSettings &mapSettings, double &a, double &b, double &c, double &d, double &e, double &f)
Computes the six parameters of a world file.
static QString worldFileContent(const QgsMapSettings &mapSettings)
Creates the content of a world file.
The QgsMapSettings class contains configuration for rendering of the map.
QList< QgsMapLayer * > layers(bool expandGroupLayers=false) const
Returns the list of layers which will be rendered in the map.
void addRenderedFeatureHandler(QgsRenderedFeatureHandlerInterface *handler)
Adds a rendered feature handler to use while rendering the map settings.
QSize outputSize() const
Returns the size of the resulting map image, in pixels.
QgsRectangle extent() const
Returns geographical coordinates of the rectangle that should be rendered.
const QgsMapToPixel & mapToPixel() const
double outputDpi() const
Returns the DPI (dots per inch) used for conversion between real world units (e.g.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
A class to represent a 2D point.
Definition: qgspointxy.h:59
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
An interface for classes which provider custom handlers for features rendered as part of a map render...
virtual void handleRenderedFeature(const QgsFeature &feature, const QgsGeometry &renderedBounds, const QgsRenderedFeatureHandlerInterface::RenderedFeatureContext &context)=0
Called whenever a feature is rendered during a map render job.
virtual QSet< QString > usedAttributes(QgsVectorLayer *layer, const QgsRenderContext &context) const
Returns a list of attributes required by this handler, for the specified layer.
Scoped object for saving and restoring a QPainter object's state.
Abstract base class for long running background tasks.
virtual void cancel()
Notifies the task that it should terminate.
bool isCanceled() const
Will return true if task should terminate ASAP.
Represents a vector layer which manages a vector based data sets.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
Definition: qgsogrutils.h:138
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Contains details of a particular input component to be used during PDF composition.
QString sourcePdfPath
File path to the (already created) PDF to use as the source for this component layer.
QString mapLayerId
Associated map layer ID, or an empty string if this component layer is not associated with a map laye...
QPainter::CompositionMode compositionMode
Component composition mode.
QString name
User-friendly name for the generated PDF layer.
Contains details of a control point used during georeferencing GeoPDF outputs.
QgsAbstractMetadataBase::KeywordMap keywords
Metadata keyword map.
QMap< QString, QString > layerIdToPdfLayerTreeNameMap
Optional map of map layer ID to custom layer tree name to show in the created PDF file.
QDateTime creationDateTime
Metadata creation datetime.
QList< QgsAbstractGeoPdfExporter::GeoReferencedSection > georeferencedSections
List of georeferenced sections.
bool includeFeatures
true if feature vector information (such as attributes) should be exported.
QStringList layerOrder
Optional list of layer IDs, in the order desired to appear in the generated GeoPDF file.
QgsRectangle pageBoundsMm
Bounds of the georeferenced section on the page, in millimeters.
QgsCoordinateReferenceSystem crs
Coordinate reference system for georeferenced section.
QList< QgsAbstractGeoPdfExporter::ControlPoint > controlPoints
List of control points corresponding to this georeferenced section.
Contains information about a feature rendered inside the PDF.
Contains information relating to a single PDF layer in the GeoPDF export.
const QgsRenderContext & renderContext
The render context which was used while rendering feature.