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