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