QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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 "qgsmaprenderertask.h"
19
20#include <cpl_conv.h>
21#include <gdal.h>
22#include <memory>
23
25#include "qgsannotation.h"
27#include "qgsfeaturerequest.h"
28#include "qgslogger.h"
30#include "qgsmapsettingsutils.h"
31#include "qgsogrutils.h"
33#include "qgsvectorlayer.h"
34
35#include <QFile>
36#include <QImageWriter>
37#include <QPdfWriter>
38#include <QTextStream>
39#include <QTimeZone>
40
41#include "moc_qgsmaprenderertask.cpp"
42
44
45class QgsMapRendererTaskGeospatialPdfExporter : public QgsAbstractGeospatialPdfExporter
46{
47
48 public:
49
50 QgsMapRendererTaskGeospatialPdfExporter( const QgsMapSettings &ms )
51 {
52 // collect details upfront, while we are still in the main thread
53 const QList< QgsMapLayer * > layers = ms.layers();
54 for ( const QgsMapLayer *layer : layers )
55 {
56 VectorComponentDetail detail;
57 detail.name = layer->name();
58 detail.mapLayerId = layer->id();
59 if ( const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) )
60 {
61 detail.displayAttribute = vl->displayField();
62 }
63 mLayerDetails[ layer->id() ] = detail;
64 }
65 }
66
67 private:
68
69 QgsAbstractGeospatialPdfExporter::VectorComponentDetail componentDetailForLayerId( const QString &layerId ) override
70 {
71 return mLayerDetails.value( layerId );
72 }
73
74 QMap< QString, VectorComponentDetail > mLayerDetails;
75};
76
77
78class QgsMapRendererTaskRenderedFeatureHandler : public QgsRenderedFeatureHandlerInterface
79{
80 public:
81
82 QgsMapRendererTaskRenderedFeatureHandler( QgsMapRendererTaskGeospatialPdfExporter *exporter, const QgsMapSettings &settings )
83 : mExporter( exporter )
84 , mMapSettings( settings )
85 {
86 // PDF coordinate space uses a hardcoded DPI of 72, also vertical dimension is flipped from QGIS dimension
87 const double pageHeightPdfUnits = settings.outputSize().height() * 72.0 / settings.outputDpi();
88 mTransform = QTransform::fromTranslate( 0, pageHeightPdfUnits ).scale( 72.0 / mMapSettings.outputDpi(), -72.0 / mMapSettings.outputDpi() );
89 }
90
91 void handleRenderedFeature( const QgsFeature &feature, const QgsGeometry &renderedBounds, const QgsRenderedFeatureHandlerInterface::RenderedFeatureContext &context ) override
92 {
93 // is it a hack retrieving the layer ID from an expression context like this? possibly... BUT
94 // the alternative is adding a layer ID member to QgsRenderContext, and that's just asking for people to abuse it
95 // and use it to retrieve QgsMapLayers mid-way through a render operation. Lesser of two evils it is!
96 const QString layerId = context.renderContext.expressionContext().variable( QStringLiteral( "layer_id" ) ).toString();
97
98 QgsGeometry transformed = renderedBounds;
99 transformed.transform( mTransform );
100
101 // always convert to multitype, to make things consistent
102 transformed.convertToMultiType();
103
104 mExporter->pushRenderedFeature( layerId, QgsAbstractGeospatialPdfExporter::RenderedFeature( feature, transformed ) );
105 }
106
107 QSet<QString> usedAttributes( QgsVectorLayer *, const QgsRenderContext & ) const override
108 {
109 return QSet< QString >() << QgsFeatureRequest::ALL_ATTRIBUTES;
110 }
111
112 private:
113
114 QgsMapRendererTaskGeospatialPdfExporter *mExporter = nullptr;
115 QgsMapSettings mMapSettings;
117 QTransform mTransform;
118
119};
120
122
123QgsMapRendererTask::QgsMapRendererTask( const QgsMapSettings &ms, const QString &fileName, const QString &fileFormat, const bool forceRaster, QgsTask::Flags flags,
124 const bool geoPDF, const QgsAbstractGeospatialPdfExporter::ExportDetails &geospatialPdfExportDetails )
125 : QgsTask( fileFormat == QLatin1String( "PDF" ) ? tr( "Saving as PDF" ) : tr( "Saving as image" ), flags )
126 , mMapSettings( ms )
127 , mFileName( fileName )
128 , mFileFormat( fileFormat )
129 , mForceRaster( forceRaster )
130 , mGeospatialPDF( geoPDF && mFileFormat == QLatin1String( "PDF" ) && QgsAbstractGeospatialPdfExporter::geospatialPDFCreationAvailable() )
131 , mGeospatialPdfExportDetails( geospatialPdfExportDetails )
132{
133 if ( mFileFormat == QLatin1String( "PDF" ) && !qgsDoubleNear( mMapSettings.devicePixelRatio(), 1.0 ) )
134 {
135 mMapSettings.setOutputSize( mMapSettings.outputSize() * mMapSettings.devicePixelRatio() );
136 mMapSettings.setOutputDpi( mMapSettings.outputDpi() * mMapSettings.devicePixelRatio() );
137 mMapSettings.setDevicePixelRatio( 1.0 );
138 }
139 prepare();
140}
141
143 : QgsTask( tr( "Rendering to painter" ) )
144 , mMapSettings( ms )
145 , mPainter( p )
146{
147 prepare();
148}
149
151
152void QgsMapRendererTask::addAnnotations( const QList< QgsAnnotation * > &annotations )
153{
154 qDeleteAll( mAnnotations );
155 mAnnotations.clear();
156
157 const auto constAnnotations = annotations;
158 for ( const QgsAnnotation *a : constAnnotations )
159 {
160 mAnnotations << a->clone();
161 }
162}
163
164void QgsMapRendererTask::addDecorations( const QList< QgsMapDecoration * > &decorations )
165{
166 mDecorations = decorations;
167}
168
169
171{
172 mJobMutex.lock();
173 if ( mJob )
174 mJob->cancelWithoutBlocking();
175 mJobMutex.unlock();
176
178}
179
181{
182 if ( mErrored )
183 return false;
184
185 if ( mGeospatialPDF )
186 {
187 QList< QgsAbstractGeospatialPdfExporter::ComponentLayerDetail > pdfComponents;
188
189 QgsMapRendererStagedRenderJob *job = static_cast< QgsMapRendererStagedRenderJob * >( mJob.get() );
190 int outputLayer = 1;
191 while ( !job->isFinished() )
192 {
194
195 component.name = QStringLiteral( "layer_%1" ).arg( outputLayer );
196 component.mapLayerId = job->currentLayerId();
197 component.opacity = job->currentLayerOpacity();
199 component.sourcePdfPath = mGeospatialPdfExporter->generateTemporaryFilepath( QStringLiteral( "layer_%1.pdf" ).arg( outputLayer ) );
200 pdfComponents << component;
201
202 QPdfWriter pdfWriter( component.sourcePdfPath );
203 pdfWriter.setPageOrientation( QPageLayout::Orientation::Portrait );
204 // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
205 const QSizeF outputSize = mMapSettings.outputSize();
206 const QPageSize pageSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPageSize::Unit::Millimeter );
207 pdfWriter.setPageSize( pageSize );
208 pdfWriter.setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
209 pdfWriter.setResolution( static_cast<int>( mMapSettings.outputDpi() ) );
210
211 QPainter p( &pdfWriter );
212 job->renderCurrentPart( &p );
213 p.end();
214
215 outputLayer++;
216 job->nextPart();
217 }
218 QgsAbstractGeospatialPdfExporter::ExportDetails exportDetails = mGeospatialPdfExportDetails;
219 const double pageWidthMM = mMapSettings.outputSize().width() * 25.4 / mMapSettings.outputDpi();
220 const double pageHeightMM = mMapSettings.outputSize().height() * 25.4 / mMapSettings.outputDpi();
221 exportDetails.pageSizeMm = QSizeF( pageWidthMM, pageHeightMM );
222 exportDetails.dpi = mMapSettings.outputDpi();
223
224 exportDetails.layerIdToPdfLayerTreeNameMap = mLayerIdToLayerNameMap;
225 exportDetails.layerOrder = mMapLayerOrder;
226
227 if ( mSaveWorldFile )
228 {
229 // setup georeferencing
231 georef.crs = mMapSettings.destinationCrs();
232 georef.pageBoundsMm = QgsRectangle( 0, 0, pageWidthMM, pageHeightMM );
233 georef.controlPoints.reserve( 4 );
234 georef.controlPoints << QgsAbstractGeospatialPdfExporter::ControlPoint( QgsPointXY( 0, 0 ), mMapSettings.mapToPixel().toMapCoordinates( 0, 0 ) );
235 georef.controlPoints << QgsAbstractGeospatialPdfExporter::ControlPoint( QgsPointXY( pageWidthMM, 0 ), mMapSettings.mapToPixel().toMapCoordinates( mMapSettings.outputSize().width(), 0 ) );
236 georef.controlPoints << QgsAbstractGeospatialPdfExporter::ControlPoint( QgsPointXY( pageWidthMM, pageHeightMM ), mMapSettings.mapToPixel().toMapCoordinates( mMapSettings.outputSize().width(), mMapSettings.outputSize().height() ) );
237 georef.controlPoints << QgsAbstractGeospatialPdfExporter::ControlPoint( QgsPointXY( 0, pageHeightMM ), mMapSettings.mapToPixel().toMapCoordinates( 0, mMapSettings.outputSize().height() ) );
238 exportDetails.georeferencedSections << georef;
239 }
240
241 const bool res = mGeospatialPdfExporter->finalize( pdfComponents, mFileName, exportDetails );
242 mGeospatialPdfExporter.reset();
243 mTempPainter.reset();
244 mPdfWriter.reset();
245 return res;
246 }
247 else
248 static_cast< QgsMapRendererCustomPainterJob *>( mJob.get() )->renderPrepared();
249
250 mJobMutex.lock();
251 mJob.reset( nullptr );
252 mJobMutex.unlock();
253
254 if ( isCanceled() )
255 return false;
256
257 QgsRenderContext context = QgsRenderContext::fromMapSettings( mMapSettings );
258 context.setPainter( mDestPainter );
259
260 const auto constMDecorations = mDecorations;
261 for ( QgsMapDecoration *decoration : constMDecorations )
262 {
263 decoration->render( mMapSettings, context );
264 }
265
266 const auto constMAnnotations = mAnnotations;
267 for ( QgsAnnotation *annotation : constMAnnotations )
268 {
269 if ( isCanceled() )
270 return false;
271
272 if ( !annotation || !annotation->isVisible() )
273 {
274 continue;
275 }
276 if ( annotation->mapLayer() && !mMapSettings.layers().contains( annotation->mapLayer() ) )
277 {
278 continue;
279 }
280
281 const QgsScopedQPainterState painterState( context.painter() );
283
284 double itemX, itemY;
285 if ( annotation->hasFixedMapPosition() )
286 {
287 itemX = mMapSettings.outputSize().width() * ( annotation->mapPosition().x() - mMapSettings.extent().xMinimum() ) / mMapSettings.extent().width();
288 itemY = mMapSettings.outputSize().height() * ( 1 - ( annotation->mapPosition().y() - mMapSettings.extent().yMinimum() ) / mMapSettings.extent().height() );
289 }
290 else
291 {
292 itemX = annotation->relativePosition().x() * mMapSettings.outputSize().width();
293 itemY = annotation->relativePosition().y() * mMapSettings.outputSize().height();
294 }
295
296 context.painter()->translate( itemX, itemY );
297
298 annotation->render( context );
299 }
300
301 if ( !mFileName.isEmpty() )
302 {
303 mDestPainter->end();
304
305 if ( mFileFormat == QLatin1String( "PDF" ) )
306 {
307 if ( mForceRaster )
308 {
309 QPainter pp;
310 pp.begin( mPdfWriter.get() );
311 const QRectF rect( 0, 0, mImage.width(), mImage.height() );
312 pp.drawImage( rect, mImage, rect );
313 pp.end();
314 }
315
316 if ( mSaveWorldFile || mExportMetadata )
317 {
318 CPLSetThreadLocalConfigOption( "GDAL_PDF_DPI", QString::number( mMapSettings.outputDpi() ).toLocal8Bit().constData() );
319 const gdal::dataset_unique_ptr outputDS( GDALOpen( mFileName.toUtf8().constData(), GA_Update ) );
320 if ( outputDS )
321 {
322 if ( mSaveWorldFile )
323 {
324 double a, b, c, d, e, f;
325 QgsMapSettingsUtils::worldFileParameters( mMapSettings, a, b, c, d, e, f );
326 c -= 0.5 * a;
327 c -= 0.5 * b;
328 f -= 0.5 * d;
329 f -= 0.5 * e;
330 double geoTransform[6] = { c, a, b, f, d, e };
331 GDALSetGeoTransform( outputDS.get(), geoTransform );
332 GDALSetProjection( outputDS.get(), mMapSettings.destinationCrs().toWkt( Qgis::CrsWktVariant::PreferredGdal ).toLocal8Bit().constData() );
333 }
334
335 if ( mExportMetadata )
336 {
337 QString creationDateString;
338 const QDateTime creationDateTime = mGeospatialPdfExportDetails.creationDateTime;
339#if QT_FEATURE_timezone > 0
340 if ( creationDateTime.isValid() )
341 {
342 creationDateString = QStringLiteral( "D:%1" ).arg( mGeospatialPdfExportDetails.creationDateTime.toString( QStringLiteral( "yyyyMMddHHmmss" ) ) );
343 if ( creationDateTime.timeZone().isValid() )
344 {
345 int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
346 creationDateString += ( offsetFromUtc >= 0 ) ? '+' : '-';
347 offsetFromUtc = std::abs( offsetFromUtc );
348 const int offsetHours = offsetFromUtc / 3600;
349 const int offsetMins = ( offsetFromUtc % 3600 ) / 60;
350 creationDateString += QStringLiteral( "%1'%2'" ).arg( offsetHours ).arg( offsetMins );
351 }
352 }
353#else
354 QgsDebugError( QStringLiteral( "Qt is built without timezone support, skipping timezone for pdf export" ) );
355#endif
356 GDALSetMetadataItem( outputDS.get(), "CREATION_DATE", creationDateString.toUtf8().constData(), nullptr );
357
358 GDALSetMetadataItem( outputDS.get(), "AUTHOR", mGeospatialPdfExportDetails.author.toUtf8().constData(), nullptr );
359 const QString creator = QStringLiteral( "QGIS %1" ).arg( Qgis::version() );
360 GDALSetMetadataItem( outputDS.get(), "CREATOR", creator.toUtf8().constData(), nullptr );
361 GDALSetMetadataItem( outputDS.get(), "PRODUCER", creator.toUtf8().constData(), nullptr );
362 GDALSetMetadataItem( outputDS.get(), "SUBJECT", mGeospatialPdfExportDetails.subject.toUtf8().constData(), nullptr );
363 GDALSetMetadataItem( outputDS.get(), "TITLE", mGeospatialPdfExportDetails.title.toUtf8().constData(), nullptr );
364
365 const QgsAbstractMetadataBase::KeywordMap keywords = mGeospatialPdfExportDetails.keywords;
366 QStringList allKeywords;
367 for ( auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
368 {
369 allKeywords.append( QStringLiteral( "%1: %2" ).arg( it.key(), it.value().join( ',' ) ) );
370 }
371 const QString keywordString = allKeywords.join( ';' );
372 GDALSetMetadataItem( outputDS.get(), "KEYWORDS", keywordString.toUtf8().constData(), nullptr );
373 }
374 }
375 CPLSetThreadLocalConfigOption( "GDAL_PDF_DPI", nullptr );
376 }
377 }
378 else if ( mFileFormat != QLatin1String( "PDF" ) )
379 {
380 QImageWriter writer( mFileName, mFileFormat.toLocal8Bit().data() );
381 if ( mFileFormat.compare( QLatin1String( "TIF" ), Qt::CaseInsensitive ) == 0 || mFileFormat.compare( QLatin1String( "TIFF" ), Qt::CaseInsensitive ) == 0 )
382 {
383 // Enable LZW compression
384 writer.setCompression( 1 );
385 }
386 const bool success = writer.write( mImage );
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.compare( QLatin1String( "TIF" ), Qt::CaseInsensitive ) == 0 || outputSuffix.compare( QLatin1String( "TIFF" ), Qt::CaseInsensitive ) == 0 )
401 {
402 const gdal::dataset_unique_ptr outputDS( GDALOpen( mFileName.toUtf8().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( Qgis::CrsWktVariant::PreferredGdal ).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 mPdfWriter.reset();
436
437 return true;
438}
439
441{
442 qDeleteAll( mAnnotations );
443 mAnnotations.clear();
444
445 if ( result )
446 emit renderingComplete();
447 else
448 emit errorOccurred( mError );
449}
450
451void QgsMapRendererTask::prepare()
452{
453 if ( mGeospatialPDF )
454 {
455 mGeospatialPdfExporter = std::make_unique< QgsMapRendererTaskGeospatialPdfExporter >( mMapSettings );
456 if ( mGeospatialPdfExportDetails.includeFeatures )
457 {
458 mRenderedFeatureHandler = std::make_unique< QgsMapRendererTaskRenderedFeatureHandler >( static_cast< QgsMapRendererTaskGeospatialPdfExporter * >( mGeospatialPdfExporter.get() ), mMapSettings );
459 mMapSettings.addRenderedFeatureHandler( mRenderedFeatureHandler.get() );
460 }
461
462 const QList< QgsMapLayer * > layers = mMapSettings.layers();
463 for ( const QgsMapLayer *layer : layers )
464 {
465 mLayerIdToLayerNameMap.insert( layer->id(), layer->name() );
466 mMapLayerOrder << layer->id();
467 }
468
469 mJob = std::make_unique<QgsMapRendererStagedRenderJob>( mMapSettings, QgsMapRendererStagedRenderJob::RenderLabelsByMapLayer );
470 mJob->start();
471 return;
472 }
473
474 mDestPainter = mPainter;
475
476 if ( mFileFormat == QLatin1String( "PDF" ) )
477 {
478 mPdfWriter = std::make_unique<QPdfWriter>( mFileName );
479 mPdfWriter->setPageOrientation( QPageLayout::Orientation::Portrait );
480 // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
481 const QSizeF outputSize = mMapSettings.outputSize();
482 const QPageSize pageSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPageSize::Unit::Millimeter );
483 mPdfWriter->setPageSize( pageSize );
484 mPdfWriter->setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
485 mPdfWriter->setResolution( static_cast<int>( mMapSettings.outputDpi() ) );
486
487 if ( !mForceRaster )
488 {
489 mTempPainter = std::make_unique<QPainter>( mPdfWriter.get() );
490 mDestPainter = mTempPainter.get();
491 }
492 }
493
494 if ( !mDestPainter )
495 {
496 // save rendered map to an image file
497 mImage = QImage( mMapSettings.outputSize() * mMapSettings.devicePixelRatio(), QImage::Format_ARGB32 );
498 if ( mImage.isNull() )
499 {
500 mErrored = true;
501 mError = ImageAllocationFail;
502 return;
503 }
504
505 mImage.setDevicePixelRatio( mMapSettings.devicePixelRatio() );
506 mImage.setDotsPerMeterX( 1000 * mMapSettings.outputDpi() / 25.4 );
507 mImage.setDotsPerMeterY( 1000 * mMapSettings.outputDpi() / 25.4 );
508
509 mTempPainter = std::make_unique<QPainter>( &mImage );
510 mDestPainter = mTempPainter.get();
511 }
512
513 if ( !mDestPainter )
514 {
515 mErrored = true;
516 return;
517 }
518
519 mJob = std::make_unique<QgsMapRendererCustomPainterJob>( mMapSettings, mDestPainter );
520 static_cast< QgsMapRendererCustomPainterJob *>( mJob.get() )->prepare();
521}
static QString version()
Version string.
Definition qgis.cpp:677
@ PreferredGdal
Preferred format for conversion of CRS to WKT for use with the GDAL library.
Definition qgis.h:2441
Abstract base class for Geospatial PDF exporters.
QMap< QString, QStringList > KeywordMap
Map of vocabulary string to keyword list.
Abstract base class for annotation items which are drawn over a map.
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.
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.
Job implementation that renders everything sequentially using a custom painter.
void renderPrepared()
Render a pre-prepared job.
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.
@ ImageSaveFail
Image save failure.
@ ImageAllocationFail
Image allocation failure.
QgsMapRendererTask(const QgsMapSettings &ms, const QString &fileName, const QString &fileFormat=QString("PNG"), bool forceRaster=false, QgsTask::Flags flags=QgsTask::CanCancel, bool geospatialPdf=false, const QgsAbstractGeospatialPdfExporter::ExportDetails &geospatialPdfExportDetails=QgsAbstractGeospatialPdfExporter::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.
Contains configuration for rendering maps.
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.
double outputDpi() const
Returns the DPI (dots per inch) used for conversion between real world units (e.g.
Represents a 2D point.
Definition qgspointxy.h:60
A rectangle specified with double values.
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 provide 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.
Flags flags() const
Returns the flags associated with the task.
QFlags< Flag > Flags
virtual void cancel()
Notifies the task that it should terminate.
QgsTask(const QString &description=QString(), QgsTask::Flags flags=AllFlags)
Constructor for QgsTask.
bool isCanceled() const
Will return true if task should terminate ASAP.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
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:6607
#define QgsDebugError(str)
Definition qgslogger.h:57
Contains details of a particular input component to be used during PDF composition.
QString mapLayerId
Associated map layer ID, or an empty string if this component layer is not associated with a map laye...
QString name
User-friendly name for the generated PDF layer.
QPainter::CompositionMode compositionMode
Component composition mode.
QString sourcePdfPath
File path to the (already created) PDF to use as the source for this component layer.
Contains details of a control point used during georeferencing Geospatial PDF outputs.
QList< QgsAbstractGeospatialPdfExporter::GeoReferencedSection > georeferencedSections
List of georeferenced sections.
QStringList layerOrder
Optional list of layer IDs, in the order desired to appear in the generated Geospatial PDF file.
QMap< QString, QString > layerIdToPdfLayerTreeNameMap
Optional map of map layer ID to custom layer tree name to show in the created PDF file.
bool includeFeatures
true if feature vector information (such as attributes) should be exported.
QgsRectangle pageBoundsMm
Bounds of the georeferenced section on the page, in millimeters.
QgsCoordinateReferenceSystem crs
Coordinate reference system for georeferenced section.
QList< QgsAbstractGeospatialPdfExporter::ControlPoint > controlPoints
List of control points corresponding to this georeferenced section.
const QgsRenderContext & renderContext
The render context which was used while rendering feature.