QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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 public:
51 QgsMapRendererTaskGeospatialPdfExporter( const QgsMapSettings &ms )
52 {
53 // collect details upfront, while we are still in the main thread
54 const QList< QgsMapLayer * > layers = ms.layers();
55 for ( const QgsMapLayer *layer : layers )
56 {
57 VectorComponentDetail detail;
58 detail.name = layer->name();
59 detail.mapLayerId = layer->id();
60 if ( const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) )
61 {
62 detail.displayAttribute = vl->displayField();
63 }
64 mLayerDetails[layer->id()] = detail;
65 }
66 }
67
68 private:
69 QgsAbstractGeospatialPdfExporter::VectorComponentDetail componentDetailForLayerId( const QString &layerId ) override { return mLayerDetails.value( layerId ); }
70
71 QMap< QString, VectorComponentDetail > mLayerDetails;
72};
73
74
75class QgsMapRendererTaskRenderedFeatureHandler : public QgsRenderedFeatureHandlerInterface
76{
77 public:
78 QgsMapRendererTaskRenderedFeatureHandler( QgsMapRendererTaskGeospatialPdfExporter *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( u"layer_id"_s ).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, QgsAbstractGeospatialPdfExporter::RenderedFeature( feature, transformed ) );
101 }
102
103 QSet<QString> usedAttributes( QgsVectorLayer *, const QgsRenderContext & ) const override { return QSet< QString >() << QgsFeatureRequest::ALL_ATTRIBUTES; }
104
105 private:
106 QgsMapRendererTaskGeospatialPdfExporter *mExporter = nullptr;
107 QgsMapSettings mMapSettings;
109 QTransform mTransform;
110};
111
113
115 const QgsMapSettings &ms, const QString &fileName, const QString &fileFormat, const bool forceRaster, QgsTask::Flags flags, const bool geoPDF, const QgsAbstractGeospatialPdfExporter::ExportDetails &geospatialPdfExportDetails
116)
117 : QgsTask( fileFormat == "PDF"_L1 ? tr( "Saving as PDF" ) : tr( "Saving as image" ), flags )
118 , mMapSettings( ms )
119 , mFileName( fileName )
120 , mFileFormat( fileFormat )
121 , mForceRaster( forceRaster )
122 , mGeospatialPDF( geoPDF && mFileFormat == "PDF"_L1 && QgsAbstractGeospatialPdfExporter::geospatialPDFCreationAvailable() )
123 , mGeospatialPdfExportDetails( geospatialPdfExportDetails )
124{
125 if ( mFileFormat == "PDF"_L1 && !qgsDoubleNear( mMapSettings.devicePixelRatio(), 1.0 ) )
126 {
127 mMapSettings.setOutputSize( mMapSettings.outputSize() * mMapSettings.devicePixelRatio() );
128 mMapSettings.setOutputDpi( mMapSettings.outputDpi() * mMapSettings.devicePixelRatio() );
129 mMapSettings.setDevicePixelRatio( 1.0 );
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 ( mGeospatialPDF )
178 {
179 QList< QgsAbstractGeospatialPdfExporter::ComponentLayerDetail > pdfComponents;
180
181 QgsMapRendererStagedRenderJob *job = static_cast< QgsMapRendererStagedRenderJob * >( mJob.get() );
182 int outputLayer = 1;
183 while ( !job->isFinished() )
184 {
186
187 component.name = u"layer_%1"_s.arg( outputLayer );
188 component.mapLayerId = job->currentLayerId();
189 component.opacity = job->currentLayerOpacity();
191 component.sourcePdfPath = mGeospatialPdfExporter->generateTemporaryFilepath( u"layer_%1.pdf"_s.arg( outputLayer ) );
192 pdfComponents << component;
193
194 QPdfWriter pdfWriter( component.sourcePdfPath );
195 pdfWriter.setPageOrientation( QPageLayout::Orientation::Portrait );
196 // paper size needs to be given in millimeters in order to be able to set a resolution to pass onto the map renderer
197 const QSizeF outputSize = mMapSettings.outputSize();
198 const QPageSize pageSize( outputSize * 25.4 / mMapSettings.outputDpi(), QPageSize::Unit::Millimeter );
199 pdfWriter.setPageSize( pageSize );
200 pdfWriter.setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
201 pdfWriter.setResolution( static_cast<int>( mMapSettings.outputDpi() ) );
202
203 QPainter p( &pdfWriter );
204 job->renderCurrentPart( &p );
205 p.end();
206
207 outputLayer++;
208 job->nextPart();
209 }
210 QgsAbstractGeospatialPdfExporter::ExportDetails exportDetails = mGeospatialPdfExportDetails;
211 const double pageWidthMM = mMapSettings.outputSize().width() * 25.4 / mMapSettings.outputDpi();
212 const double pageHeightMM = mMapSettings.outputSize().height() * 25.4 / mMapSettings.outputDpi();
213 exportDetails.pageSizeMm = QSizeF( pageWidthMM, pageHeightMM );
214 exportDetails.dpi = mMapSettings.outputDpi();
215
216 exportDetails.layerIdToPdfLayerTreeNameMap = mLayerIdToLayerNameMap;
217 exportDetails.layerOrder = mMapLayerOrder;
218
219 if ( mSaveWorldFile )
220 {
221 // setup georeferencing
223 georef.crs = mMapSettings.destinationCrs();
224 georef.pageBoundsMm = QgsRectangle( 0, 0, pageWidthMM, pageHeightMM );
225 georef.controlPoints.reserve( 4 );
226 georef.controlPoints << QgsAbstractGeospatialPdfExporter::ControlPoint( QgsPointXY( 0, 0 ), mMapSettings.mapToPixel().toMapCoordinates( 0, 0 ) );
227 georef.controlPoints << QgsAbstractGeospatialPdfExporter::ControlPoint( QgsPointXY( pageWidthMM, 0 ), mMapSettings.mapToPixel().toMapCoordinates( mMapSettings.outputSize().width(), 0 ) );
228 georef.controlPoints << QgsAbstractGeospatialPdfExporter::
229 ControlPoint( QgsPointXY( pageWidthMM, pageHeightMM ), mMapSettings.mapToPixel().toMapCoordinates( mMapSettings.outputSize().width(), mMapSettings.outputSize().height() ) );
230 georef.controlPoints << QgsAbstractGeospatialPdfExporter::ControlPoint( QgsPointXY( 0, pageHeightMM ), mMapSettings.mapToPixel().toMapCoordinates( 0, mMapSettings.outputSize().height() ) );
231 exportDetails.georeferencedSections << georef;
232 }
233
234 const bool res = mGeospatialPdfExporter->finalize( pdfComponents, mFileName, exportDetails );
235 mGeospatialPdfExporter.reset();
236 mTempPainter.reset();
237 mPdfWriter.reset();
238 return res;
239 }
240 else
241 static_cast< QgsMapRendererCustomPainterJob *>( mJob.get() )->renderPrepared();
242
243 mJobMutex.lock();
244 mJob.reset( nullptr );
245 mJobMutex.unlock();
246
247 if ( isCanceled() )
248 return false;
249
250 QgsRenderContext context = QgsRenderContext::fromMapSettings( mMapSettings );
251 context.setPainter( mDestPainter );
252
253 const auto constMDecorations = mDecorations;
254 for ( QgsMapDecoration *decoration : constMDecorations )
255 {
256 decoration->render( mMapSettings, context );
257 }
258
259 const auto constMAnnotations = mAnnotations;
260 for ( QgsAnnotation *annotation : constMAnnotations )
261 {
262 if ( isCanceled() )
263 return false;
264
265 if ( !annotation || !annotation->isVisible() )
266 {
267 continue;
268 }
269 if ( annotation->mapLayer() && !mMapSettings.layers().contains( annotation->mapLayer() ) )
270 {
271 continue;
272 }
273
274 const QgsScopedQPainterState painterState( context.painter() );
276
277 double itemX, itemY;
278 if ( annotation->hasFixedMapPosition() )
279 {
280 itemX = mMapSettings.outputSize().width() * ( annotation->mapPosition().x() - mMapSettings.extent().xMinimum() ) / mMapSettings.extent().width();
281 itemY = mMapSettings.outputSize().height() * ( 1 - ( annotation->mapPosition().y() - mMapSettings.extent().yMinimum() ) / mMapSettings.extent().height() );
282 }
283 else
284 {
285 itemX = annotation->relativePosition().x() * mMapSettings.outputSize().width();
286 itemY = annotation->relativePosition().y() * mMapSettings.outputSize().height();
287 }
288
289 context.painter()->translate( itemX, itemY );
290
291 annotation->render( context );
292 }
293
294 if ( !mFileName.isEmpty() )
295 {
296 mDestPainter->end();
297
298 if ( mFileFormat == "PDF"_L1 )
299 {
300 if ( mForceRaster )
301 {
302 QPainter pp;
303 pp.begin( mPdfWriter.get() );
304 const QRectF rect( 0, 0, mImage.width(), mImage.height() );
305 pp.drawImage( rect, mImage, rect );
306 pp.end();
307 }
308
309 if ( mSaveWorldFile || mExportMetadata )
310 {
311 CPLSetThreadLocalConfigOption( "GDAL_PDF_DPI", QString::number( mMapSettings.outputDpi() ).toLocal8Bit().constData() );
312 const gdal::dataset_unique_ptr outputDS( GDALOpen( mFileName.toUtf8().constData(), GA_Update ) );
313 if ( outputDS )
314 {
315 if ( mSaveWorldFile )
316 {
317 double a, b, c, d, e, f;
318 QgsMapSettingsUtils::worldFileParameters( mMapSettings, a, b, c, d, e, f );
319 c -= 0.5 * a;
320 c -= 0.5 * b;
321 f -= 0.5 * d;
322 f -= 0.5 * e;
323 double geoTransform[6] = { c, a, b, f, d, e };
324 GDALSetGeoTransform( outputDS.get(), geoTransform );
325 GDALSetProjection( outputDS.get(), mMapSettings.destinationCrs().toWkt( Qgis::CrsWktVariant::PreferredGdal ).toLocal8Bit().constData() );
326 }
327
328 if ( mExportMetadata )
329 {
330 QString creationDateString;
331 const QDateTime creationDateTime = mGeospatialPdfExportDetails.creationDateTime;
332#if QT_FEATURE_timezone > 0
333 if ( creationDateTime.isValid() )
334 {
335 creationDateString = u"D:%1"_s.arg( mGeospatialPdfExportDetails.creationDateTime.toString( u"yyyyMMddHHmmss"_s ) );
336 if ( creationDateTime.timeZone().isValid() )
337 {
338 int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
339 creationDateString += ( offsetFromUtc >= 0 ) ? '+' : '-';
340 offsetFromUtc = std::abs( offsetFromUtc );
341 const int offsetHours = offsetFromUtc / 3600;
342 const int offsetMins = ( offsetFromUtc % 3600 ) / 60;
343 creationDateString += u"%1'%2'"_s.arg( offsetHours ).arg( offsetMins );
344 }
345 }
346#else
347 QgsDebugError( u"Qt is built without timezone support, skipping timezone for pdf export"_s );
348#endif
349 GDALSetMetadataItem( outputDS.get(), "CREATION_DATE", creationDateString.toUtf8().constData(), nullptr );
350
351 GDALSetMetadataItem( outputDS.get(), "AUTHOR", mGeospatialPdfExportDetails.author.toUtf8().constData(), nullptr );
352 const QString creator = u"QGIS %1"_s.arg( Qgis::version() );
353 GDALSetMetadataItem( outputDS.get(), "CREATOR", creator.toUtf8().constData(), nullptr );
354 GDALSetMetadataItem( outputDS.get(), "PRODUCER", creator.toUtf8().constData(), nullptr );
355 GDALSetMetadataItem( outputDS.get(), "SUBJECT", mGeospatialPdfExportDetails.subject.toUtf8().constData(), nullptr );
356 GDALSetMetadataItem( outputDS.get(), "TITLE", mGeospatialPdfExportDetails.title.toUtf8().constData(), nullptr );
357
358 const QgsAbstractMetadataBase::KeywordMap keywords = mGeospatialPdfExportDetails.keywords;
359 QStringList allKeywords;
360 for ( auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
361 {
362 allKeywords.append( u"%1: %2"_s.arg( it.key(), it.value().join( ',' ) ) );
363 }
364 const QString keywordString = allKeywords.join( ';' );
365 GDALSetMetadataItem( outputDS.get(), "KEYWORDS", keywordString.toUtf8().constData(), nullptr );
366 }
367 }
368 CPLSetThreadLocalConfigOption( "GDAL_PDF_DPI", nullptr );
369 }
370 }
371 else if ( mFileFormat != "PDF"_L1 )
372 {
373 QImageWriter writer( mFileName, mFileFormat.toLocal8Bit().data() );
374 if ( mFileFormat.compare( "TIF"_L1, Qt::CaseInsensitive ) == 0 || mFileFormat.compare( "TIFF"_L1, Qt::CaseInsensitive ) == 0 )
375 {
376 // Enable LZW compression
377 writer.setCompression( 1 );
378 }
379 const bool success = writer.write( mImage );
380 if ( !success )
381 {
382 mError = ImageSaveFail;
383 return false;
384 }
385
386 if ( mSaveWorldFile )
387 {
388 const QFileInfo info = QFileInfo( mFileName );
389
390 // build the world file name
391 const QString outputSuffix = info.suffix();
392 bool skipWorldFile = false;
393 if ( outputSuffix.compare( "TIF"_L1, Qt::CaseInsensitive ) == 0 || outputSuffix.compare( "TIFF"_L1, Qt::CaseInsensitive ) == 0 )
394 {
395 const gdal::dataset_unique_ptr outputDS( GDALOpen( mFileName.toUtf8().constData(), GA_Update ) );
396 if ( outputDS )
397 {
398 skipWorldFile = true;
399 double a, b, c, d, e, f;
400 QgsMapSettingsUtils::worldFileParameters( mMapSettings, a, b, c, d, e, f );
401 c -= 0.5 * a;
402 c -= 0.5 * b;
403 f -= 0.5 * d;
404 f -= 0.5 * e;
405 double geoTransform[] = { c, a, b, f, d, e };
406 GDALSetGeoTransform( outputDS.get(), geoTransform );
407 GDALSetProjection( outputDS.get(), mMapSettings.destinationCrs().toWkt( Qgis::CrsWktVariant::PreferredGdal ).toLocal8Bit().constData() );
408 }
409 }
410
411 if ( !skipWorldFile )
412 {
413 const QString worldFileName = info.absolutePath() + '/' + info.completeBaseName() + '.' + 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 ( mGeospatialPDF )
446 {
447 mGeospatialPdfExporter = std::make_unique< QgsMapRendererTaskGeospatialPdfExporter >( mMapSettings );
448 if ( mGeospatialPdfExportDetails.includeFeatures )
449 {
450 mRenderedFeatureHandler = std::make_unique< QgsMapRendererTaskRenderedFeatureHandler >( static_cast< QgsMapRendererTaskGeospatialPdfExporter * >( mGeospatialPdfExporter.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
461 mJob = std::make_unique<QgsMapRendererStagedRenderJob>( mMapSettings, QgsMapRendererStagedRenderJob::RenderLabelsByMapLayer );
462 mJob->start();
463 return;
464 }
465
466 mDestPainter = mPainter;
467
468 if ( mFileFormat == "PDF"_L1 )
469 {
470 mPdfWriter = std::make_unique<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 = std::make_unique<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 = std::make_unique<QPainter>( &mImage );
502 mDestPainter = mTempPainter.get();
503 }
504
505 if ( !mDestPainter )
506 {
507 mErrored = true;
508 return;
509 }
510
511 mJob = std::make_unique<QgsMapRendererCustomPainterJob>( mMapSettings, mDestPainter );
512 static_cast< QgsMapRendererCustomPainterJob *>( mJob.get() )->prepare();
513}
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:2530
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:6975
#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.