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