QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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"
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 <QImageWriter>
32#include <QTextStream>
33#include <QTimeZone>
34#ifndef QT_NO_PRINTER
35#include <QPrinter>
36#endif
37
38#include "gdal.h"
39#include "cpl_conv.h"
40
42
43class QgsMapRendererTaskGeoPdfExporter : public QgsAbstractGeoPdfExporter
44{
45
46 public:
47
48 QgsMapRendererTaskGeoPdfExporter( const QgsMapSettings &ms )
49 {
50 // collect details upfront, while we are still in the main thread
51 const QList< QgsMapLayer * > layers = ms.layers();
52 for ( const QgsMapLayer *layer : layers )
53 {
54 VectorComponentDetail detail;
55 detail.name = layer->name();
56 detail.mapLayerId = layer->id();
57 if ( const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) )
58 {
59 detail.displayAttribute = vl->displayField();
60 }
61 mLayerDetails[ layer->id() ] = detail;
62 }
63 }
64
65 private:
66
67 QgsAbstractGeoPdfExporter::VectorComponentDetail componentDetailForLayerId( const QString &layerId ) override
68 {
69 return mLayerDetails.value( layerId );
70 }
71
72 QMap< QString, VectorComponentDetail > mLayerDetails;
73};
74
75
76class QgsMapRendererTaskRenderedFeatureHandler : public QgsRenderedFeatureHandlerInterface
77{
78 public:
79
80 QgsMapRendererTaskRenderedFeatureHandler( QgsMapRendererTaskGeoPdfExporter *exporter, const QgsMapSettings &settings )
81 : mExporter( exporter )
82 , mMapSettings( settings )
83 {
84 // PDF coordinate space uses a hardcoded DPI of 72, also vertical dimension is flipped from QGIS dimension
85 const double pageHeightPdfUnits = settings.outputSize().height() * 72.0 / settings.outputDpi();
86 mTransform = QTransform::fromTranslate( 0, pageHeightPdfUnits ).scale( 72.0 / mMapSettings.outputDpi(), -72.0 / mMapSettings.outputDpi() );
87 }
88
89 void handleRenderedFeature( const QgsFeature &feature, const QgsGeometry &renderedBounds, const QgsRenderedFeatureHandlerInterface::RenderedFeatureContext &context ) override
90 {
91 // is it a hack retrieving the layer ID from an expression context like this? possibly... BUT
92 // the alternative is adding a layer ID member to QgsRenderContext, and that's just asking for people to abuse it
93 // and use it to retrieve QgsMapLayers mid-way through a render operation. Lesser of two evils it is!
94 const QString layerId = context.renderContext.expressionContext().variable( QStringLiteral( "layer_id" ) ).toString();
95
96 QgsGeometry transformed = renderedBounds;
97 transformed.transform( mTransform );
98
99 // always convert to multitype, to make things consistent
100 transformed.convertToMultiType();
101
102 mExporter->pushRenderedFeature( layerId, QgsAbstractGeoPdfExporter::RenderedFeature( feature, transformed ) );
103 }
104
105 QSet<QString> usedAttributes( QgsVectorLayer *, const QgsRenderContext & ) const override
106 {
107 return QSet< QString >() << QgsFeatureRequest::ALL_ATTRIBUTES;
108 }
109
110 private:
111
112 QgsMapRendererTaskGeoPdfExporter *mExporter = nullptr;
113 QgsMapSettings mMapSettings;
115 QTransform mTransform;
116
117};
118
120
121QgsMapRendererTask::QgsMapRendererTask( const QgsMapSettings &ms, const QString &fileName, const QString &fileFormat, const bool forceRaster, QgsTask::Flags flags,
122 const bool geoPDF, const QgsAbstractGeoPdfExporter::ExportDetails &geoPdfExportDetails )
123 : QgsTask( fileFormat == QLatin1String( "PDF" ) ? tr( "Saving as PDF" ) : tr( "Saving as image" ), flags )
124 , mMapSettings( ms )
125 , mFileName( fileName )
126 , mFileFormat( fileFormat )
127 , mForceRaster( forceRaster )
128 , mGeoPDF( geoPDF && mFileFormat == QLatin1String( "PDF" ) && QgsAbstractGeoPdfExporter::geoPDFCreationAvailable() )
129 , mGeoPdfExportDetails( geoPdfExportDetails )
130{
131 prepare();
132}
133
135 : QgsTask( tr( "Rendering to painter" ) )
136 , mMapSettings( ms )
137 , mPainter( p )
138{
139 prepare();
140}
141
143
144void QgsMapRendererTask::addAnnotations( const QList< QgsAnnotation * > &annotations )
145{
146 qDeleteAll( mAnnotations );
147 mAnnotations.clear();
148
149 const auto constAnnotations = annotations;
150 for ( const QgsAnnotation *a : constAnnotations )
151 {
152 mAnnotations << a->clone();
153 }
154}
155
156void QgsMapRendererTask::addDecorations( const QList< QgsMapDecoration * > &decorations )
157{
158 mDecorations = decorations;
159}
160
161
163{
164 mJobMutex.lock();
165 if ( mJob )
166 mJob->cancelWithoutBlocking();
167 mJobMutex.unlock();
168
170}
171
173{
174 if ( mErrored )
175 return false;
176
177 if ( mGeoPDF )
178 {
179#ifdef QT_NO_PRINTER
180 return false;
181#else
182 QList< QgsAbstractGeoPdfExporter::ComponentLayerDetail > pdfComponents;
183
184 QgsMapRendererStagedRenderJob *job = static_cast< QgsMapRendererStagedRenderJob * >( mJob.get() );
185 int outputLayer = 1;
186 while ( !job->isFinished() )
187 {
189
190 component.name = QStringLiteral( "layer_%1" ).arg( outputLayer );
191 component.mapLayerId = job->currentLayerId();
192 component.opacity = job->currentLayerOpacity();
194 component.sourcePdfPath = mGeoPdfExporter->generateTemporaryFilepath( QStringLiteral( "layer_%1.pdf" ).arg( outputLayer ) );
195 pdfComponents << component;
196
197 QPrinter printer;
198 printer.setOutputFileName( component.sourcePdfPath );
199 printer.setOutputFormat( QPrinter::PdfFormat );
200#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
201 printer.setOrientation( QPrinter::Portrait );
202 // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
203 QSizeF outputSize = mMapSettings.outputSize();
204 printer.setPaperSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPrinter::Millimeter );
205 printer.setPageMargins( 0, 0, 0, 0, QPrinter::Millimeter );
206#else
207 printer.setPageOrientation( QPageLayout::Orientation::Portrait );
208 // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
209 const QSizeF outputSize = mMapSettings.outputSize();
210 const QPageSize pageSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPageSize::Unit::Millimeter );
211 printer.setPageSize( pageSize );
212 printer.setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
213#endif
214 printer.setResolution( mMapSettings.outputDpi() );
215
216 QPainter p( &printer );
217 job->renderCurrentPart( &p );
218 p.end();
219
220 outputLayer++;
221 job->nextPart();
222 }
223 QgsAbstractGeoPdfExporter::ExportDetails exportDetails = mGeoPdfExportDetails;
224 const double pageWidthMM = mMapSettings.outputSize().width() * 25.4 / mMapSettings.outputDpi();
225 const double pageHeightMM = mMapSettings.outputSize().height() * 25.4 / mMapSettings.outputDpi();
226 exportDetails.pageSizeMm = QSizeF( pageWidthMM, pageHeightMM );
227 exportDetails.dpi = mMapSettings.outputDpi();
228
229 exportDetails.layerIdToPdfLayerTreeNameMap = mLayerIdToLayerNameMap;
230 exportDetails.layerOrder = mMapLayerOrder;
231
232 if ( mSaveWorldFile )
233 {
234 // setup georeferencing
236 georef.crs = mMapSettings.destinationCrs();
237 georef.pageBoundsMm = QgsRectangle( 0, 0, pageWidthMM, pageHeightMM );
238 georef.controlPoints.reserve( 4 );
240 georef.controlPoints << QgsAbstractGeoPdfExporter::ControlPoint( QgsPointXY( pageWidthMM, 0 ), mMapSettings.mapToPixel().toMapCoordinates( mMapSettings.outputSize().width(), 0 ) );
241 georef.controlPoints << QgsAbstractGeoPdfExporter::ControlPoint( QgsPointXY( pageWidthMM, pageHeightMM ), mMapSettings.mapToPixel().toMapCoordinates( mMapSettings.outputSize().width(), mMapSettings.outputSize().height() ) );
242 georef.controlPoints << QgsAbstractGeoPdfExporter::ControlPoint( QgsPointXY( 0, pageHeightMM ), mMapSettings.mapToPixel().toMapCoordinates( 0, mMapSettings.outputSize().height() ) );
243 exportDetails.georeferencedSections << georef;
244 }
245
246 const bool res = mGeoPdfExporter->finalize( pdfComponents, mFileName, exportDetails );
247 mGeoPdfExporter.reset();
248 mTempPainter.reset();
249 mPrinter.reset();
250 return res;
251#endif
252 }
253 else
254 static_cast< QgsMapRendererCustomPainterJob *>( mJob.get() )->renderPrepared();
255
256 mJobMutex.lock();
257 mJob.reset( nullptr );
258 mJobMutex.unlock();
259
260 if ( isCanceled() )
261 return false;
262
263 QgsRenderContext context = QgsRenderContext::fromMapSettings( mMapSettings );
264 context.setPainter( mDestPainter );
265
266 const auto constMDecorations = mDecorations;
267 for ( QgsMapDecoration *decoration : constMDecorations )
268 {
269 decoration->render( mMapSettings, context );
270 }
271
272 const auto constMAnnotations = mAnnotations;
273 for ( QgsAnnotation *annotation : constMAnnotations )
274 {
275 if ( isCanceled() )
276 return false;
277
278 if ( !annotation || !annotation->isVisible() )
279 {
280 continue;
281 }
282 if ( annotation->mapLayer() && !mMapSettings.layers().contains( annotation->mapLayer() ) )
283 {
284 continue;
285 }
286
287 const QgsScopedQPainterState painterState( context.painter() );
289
290 double itemX, itemY;
291 if ( annotation->hasFixedMapPosition() )
292 {
293 itemX = mMapSettings.outputSize().width() * ( annotation->mapPosition().x() - mMapSettings.extent().xMinimum() ) / mMapSettings.extent().width();
294 itemY = mMapSettings.outputSize().height() * ( 1 - ( annotation->mapPosition().y() - mMapSettings.extent().yMinimum() ) / mMapSettings.extent().height() );
295 }
296 else
297 {
298 itemX = annotation->relativePosition().x() * mMapSettings.outputSize().width();
299 itemY = annotation->relativePosition().y() * mMapSettings.outputSize().height();
300 }
301
302 context.painter()->translate( itemX, itemY );
303
304 annotation->render( context );
305 }
306
307 if ( !mFileName.isEmpty() )
308 {
309 mDestPainter->end();
310
311 if ( mFileFormat == QLatin1String( "PDF" ) )
312 {
313#ifndef QT_NO_PRINTER
314 if ( mForceRaster )
315 {
316 QPainter pp;
317 pp.begin( mPrinter.get() );
318 const QRectF rect( 0, 0, mImage.width(), mImage.height() );
319 pp.drawImage( rect, mImage, rect );
320 pp.end();
321 }
322
323 if ( mSaveWorldFile || mExportMetadata )
324 {
325 CPLSetThreadLocalConfigOption( "GDAL_PDF_DPI", QString::number( mMapSettings.outputDpi() ).toLocal8Bit().constData() );
326 const gdal::dataset_unique_ptr outputDS( GDALOpen( mFileName.toUtf8().constData(), GA_Update ) );
327 if ( outputDS )
328 {
329 if ( mSaveWorldFile )
330 {
331 double a, b, c, d, e, f;
332 QgsMapSettingsUtils::worldFileParameters( mMapSettings, a, b, c, d, e, f );
333 c -= 0.5 * a;
334 c -= 0.5 * b;
335 f -= 0.5 * d;
336 f -= 0.5 * e;
337 double geoTransform[6] = { c, a, b, f, d, e };
338 GDALSetGeoTransform( outputDS.get(), geoTransform );
339 GDALSetProjection( outputDS.get(), mMapSettings.destinationCrs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED_GDAL ).toLocal8Bit().constData() );
340 }
341
342 if ( mExportMetadata )
343 {
344 QString creationDateString;
345 const QDateTime creationDateTime = mGeoPdfExportDetails.creationDateTime;
346 if ( creationDateTime.isValid() )
347 {
348 creationDateString = QStringLiteral( "D:%1" ).arg( mGeoPdfExportDetails.creationDateTime.toString( QStringLiteral( "yyyyMMddHHmmss" ) ) );
349 if ( creationDateTime.timeZone().isValid() )
350 {
351 int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
352 creationDateString += ( offsetFromUtc >= 0 ) ? '+' : '-';
353 offsetFromUtc = std::abs( offsetFromUtc );
354 const int offsetHours = offsetFromUtc / 3600;
355 const int offsetMins = ( offsetFromUtc % 3600 ) / 60;
356 creationDateString += QStringLiteral( "%1'%2'" ).arg( offsetHours ).arg( offsetMins );
357 }
358 }
359 GDALSetMetadataItem( outputDS.get(), "CREATION_DATE", creationDateString.toUtf8().constData(), nullptr );
360
361 GDALSetMetadataItem( outputDS.get(), "AUTHOR", mGeoPdfExportDetails.author.toUtf8().constData(), nullptr );
362 const QString creator = QStringLiteral( "QGIS %1" ).arg( Qgis::version() );
363 GDALSetMetadataItem( outputDS.get(), "CREATOR", creator.toUtf8().constData(), nullptr );
364 GDALSetMetadataItem( outputDS.get(), "PRODUCER", creator.toUtf8().constData(), nullptr );
365 GDALSetMetadataItem( outputDS.get(), "SUBJECT", mGeoPdfExportDetails.subject.toUtf8().constData(), nullptr );
366 GDALSetMetadataItem( outputDS.get(), "TITLE", mGeoPdfExportDetails.title.toUtf8().constData(), nullptr );
367
368 const QgsAbstractMetadataBase::KeywordMap keywords = mGeoPdfExportDetails.keywords;
369 QStringList allKeywords;
370 for ( auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
371 {
372 allKeywords.append( QStringLiteral( "%1: %2" ).arg( it.key(), it.value().join( ',' ) ) );
373 }
374 const QString keywordString = allKeywords.join( ';' );
375 GDALSetMetadataItem( outputDS.get(), "KEYWORDS", keywordString.toUtf8().constData(), nullptr );
376 }
377 }
378 CPLSetThreadLocalConfigOption( "GDAL_PDF_DPI", nullptr );
379 }
380#else
381 mError = ImageUnsupportedFormat;
382 return false;
383#endif // !QT_NO_PRINTER
384 }
385 else if ( mFileFormat != QLatin1String( "PDF" ) )
386 {
387 QImageWriter writer( mFileName, mFileFormat.toLocal8Bit().data() );
388 if ( mFileFormat.compare( QLatin1String( "TIF" ), Qt::CaseInsensitive ) == 0 || mFileFormat.compare( QLatin1String( "TIFF" ), Qt::CaseInsensitive ) == 0 )
389 {
390 // Enable LZW compression
391 writer.setCompression( 1 );
392 }
393 const bool success = writer.write( mImage );
394 if ( !success )
395 {
396 mError = ImageSaveFail;
397 return false;
398 }
399
400 if ( mSaveWorldFile )
401 {
402 const QFileInfo info = QFileInfo( mFileName );
403
404 // build the world file name
405 const QString outputSuffix = info.suffix();
406 bool skipWorldFile = false;
407 if ( outputSuffix.compare( QLatin1String( "TIF" ), Qt::CaseInsensitive ) == 0 || outputSuffix.compare( QLatin1String( "TIFF" ), Qt::CaseInsensitive ) == 0 )
408 {
409 const gdal::dataset_unique_ptr outputDS( GDALOpen( mFileName.toUtf8().constData(), GA_Update ) );
410 if ( outputDS )
411 {
412 skipWorldFile = true;
413 double a, b, c, d, e, f;
414 QgsMapSettingsUtils::worldFileParameters( mMapSettings, a, b, c, d, e, f );
415 c -= 0.5 * a;
416 c -= 0.5 * b;
417 f -= 0.5 * d;
418 f -= 0.5 * e;
419 double geoTransform[] = { c, a, b, f, d, e };
420 GDALSetGeoTransform( outputDS.get(), geoTransform );
421 GDALSetProjection( outputDS.get(), mMapSettings.destinationCrs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED_GDAL ).toLocal8Bit().constData() );
422 }
423 }
424
425 if ( !skipWorldFile )
426 {
427 const QString worldFileName = info.absolutePath() + '/' + info.completeBaseName() + '.'
428 + outputSuffix.at( 0 ) + outputSuffix.at( info.suffix().size() - 1 ) + 'w';
429 QFile worldFile( worldFileName );
430
431 if ( worldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) //don't use QIODevice::Text
432 {
433 QTextStream stream( &worldFile );
434 stream << QgsMapSettingsUtils::worldFileContent( mMapSettings );
435 }
436 }
437 }
438 }
439 }
440
441 mTempPainter.reset();
442#ifndef QT_NO_PRINTER
443 mPrinter.reset();
444#endif
445
446 return true;
447}
448
450{
451 qDeleteAll( mAnnotations );
452 mAnnotations.clear();
453
454 if ( result )
455 emit renderingComplete();
456 else
457 emit errorOccurred( mError );
458}
459
460void QgsMapRendererTask::prepare()
461{
462 if ( mGeoPDF )
463 {
464 mGeoPdfExporter = std::make_unique< QgsMapRendererTaskGeoPdfExporter >( mMapSettings );
465 if ( mGeoPdfExportDetails.includeFeatures )
466 {
467 mRenderedFeatureHandler = std::make_unique< QgsMapRendererTaskRenderedFeatureHandler >( static_cast< QgsMapRendererTaskGeoPdfExporter * >( mGeoPdfExporter.get() ), mMapSettings );
468 mMapSettings.addRenderedFeatureHandler( mRenderedFeatureHandler.get() );
469 }
470
471 const QList< QgsMapLayer * > layers = mMapSettings.layers();
472 for ( const QgsMapLayer *layer : layers )
473 {
474 mLayerIdToLayerNameMap.insert( layer->id(), layer->name() );
475 mMapLayerOrder << layer->id();
476 }
477
479 mJob->start();
480 return;
481 }
482
483 mDestPainter = mPainter;
484
485 if ( mFileFormat == QLatin1String( "PDF" ) )
486 {
487#ifndef QT_NO_PRINTER
488 mPrinter.reset( new QPrinter() );
489 mPrinter->setOutputFileName( mFileName );
490 mPrinter->setOutputFormat( QPrinter::PdfFormat );
491#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
492 mPrinter->setOrientation( QPrinter::Portrait );
493 // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
494 QSizeF outputSize = mMapSettings.outputSize();
495 mPrinter->setPaperSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPrinter::Millimeter );
496 mPrinter->setPageMargins( 0, 0, 0, 0, QPrinter::Millimeter );
497#else
498 mPrinter->setPageOrientation( QPageLayout::Orientation::Portrait );
499 // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
500 const QSizeF outputSize = mMapSettings.outputSize();
501 const QPageSize pageSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPageSize::Unit::Millimeter );
502 mPrinter->setPageSize( pageSize );
503 mPrinter->setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
504#endif
505 mPrinter->setResolution( mMapSettings.outputDpi() );
506
507 if ( !mForceRaster )
508 {
509 mTempPainter.reset( new QPainter( mPrinter.get() ) );
510 mDestPainter = mTempPainter.get();
511 }
512#else
513 mError = ImageUnsupportedFormat;
514#endif // ! QT_NO_PRINTER
515 }
516
517 if ( !mDestPainter )
518 {
519 // save rendered map to an image file
520 mImage = QImage( mMapSettings.outputSize(), QImage::Format_ARGB32 );
521 if ( mImage.isNull() )
522 {
523 mErrored = true;
524 mError = ImageAllocationFail;
525 return;
526 }
527
528 mImage.setDotsPerMeterX( 1000 * mMapSettings.outputDpi() / 25.4 );
529 mImage.setDotsPerMeterY( 1000 * mMapSettings.outputDpi() / 25.4 );
530
531 mTempPainter.reset( new QPainter( &mImage ) );
532 mDestPainter = mTempPainter.get();
533 }
534
535 if ( !mDestPainter )
536 {
537 mErrored = true;
538 return;
539 }
540
541 mJob.reset( new QgsMapRendererCustomPainterJob( mMapSettings, mDestPainter ) );
542 static_cast< QgsMapRendererCustomPainterJob *>( mJob.get() )->prepare();
543}
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:164
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.
QgsMapRendererTask(const QgsMapSettings &ms, const QString &fileName, const QString &fileFormat=QString("PNG"), bool forceRaster=false, QgsTask::Flags flags=QgsTask::CanCancel, bool geoPdf=false, const QgsAbstractGeoPdfExporter::ExportDetails &geoPdfExportDetails=QgsAbstractGeoPdfExporter::ExportDetails())
Constructor for QgsMapRendererTask to render a map to an image file.
@ ImageUnsupportedFormat
Format is unsupported on the platform.
@ ImageSaveFail
Image save failure.
@ ImageAllocationFail
Image allocation failure.
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.
const QgsMapToPixel & mapToPixel() const
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.
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.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
QgsExpressionContext & expressionContext()
Gets the expression context.
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 QSet< QString > usedAttributes(QgsVectorLayer *layer, const QgsRenderContext &context) const
Returns a list of attributes required by this handler, for the specified layer.
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.
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:157
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.