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