25#include "cpl_string.h"
28#include <QMutexLocker>
29#include <QDomDocument>
38 GDALDriverH hDriverMem = GDALGetDriverByName(
"PDF" );
44 const char *pHavePoppler = GDALGetMetadataItem( hDriverMem,
"HAVE_POPPLER",
nullptr );
45 if ( pHavePoppler && strstr( pHavePoppler,
"YES" ) )
48 const char *pHavePdfium = GDALGetMetadataItem( hDriverMem,
"HAVE_PDFIUM",
nullptr );
49 if ( pHavePdfium && strstr( pHavePdfium,
"YES" ) )
58 GDALDriverH hDriverMem = GDALGetDriverByName(
"PDF" );
61 return QObject::tr(
"No GDAL PDF driver available." );
64 const char *pHavePoppler = GDALGetMetadataItem( hDriverMem,
"HAVE_POPPLER",
nullptr );
65 if ( pHavePoppler && strstr( pHavePoppler,
"YES" ) )
68 const char *pHavePdfium = GDALGetMetadataItem( hDriverMem,
"HAVE_PDFIUM",
nullptr );
69 if ( pHavePdfium && strstr( pHavePdfium,
"YES" ) )
72 return QObject::tr(
"GDAL PDF driver was not built with PDF read support. A build with PDF read support is required for GeoPDF creation." );
80 const QString composition = createCompositionXml( components, details );
82 if ( composition.isEmpty() )
86 GDALDriverH driver = GDALGetDriverByName(
"PDF" );
89 mErrorMessage = QObject::tr(
"Cannot load GDAL PDF driver" );
94 QFile file( xmlFilePath );
95 if ( file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
97 QTextStream out( &file );
98#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
99 out.setCodec(
"UTF-8" );
105 mErrorMessage = QObject::tr(
"Could not create GeoPDF composition file" );
109 char **papszOptions = CSLSetNameValue(
nullptr,
"COMPOSITION_FILE", xmlFilePath.toUtf8().constData() );
112 gdal::dataset_unique_ptr outputDataset( GDALCreate( driver, destinationFile.toUtf8().constData(), 0, 0, 0, GDT_Unknown, papszOptions ) );
113 bool res = outputDataset.get();
114 outputDataset.reset();
116 CSLDestroy( papszOptions );
130 case QPainter::CompositionMode_SourceOver:
131 case QPainter::CompositionMode_Multiply:
132 case QPainter::CompositionMode_Screen:
133 case QPainter::CompositionMode_Overlay:
134 case QPainter::CompositionMode_Darken:
135 case QPainter::CompositionMode_Lighten:
136 case QPainter::CompositionMode_ColorDodge:
137 case QPainter::CompositionMode_ColorBurn:
138 case QPainter::CompositionMode_HardLight:
139 case QPainter::CompositionMode_SoftLight:
140 case QPainter::CompositionMode_Difference:
141 case QPainter::CompositionMode_Exclusion:
154 QMutexLocker locker( &mMutex );
159 mCollatedFeatures[ group ][ layerId ].append( f );
162bool QgsAbstractGeoPdfExporter::saveTemporaryLayers()
164 for (
auto groupIt = mCollatedFeatures.constBegin(); groupIt != mCollatedFeatures.constEnd(); ++groupIt )
166 for (
auto it = groupIt->constBegin(); it != groupIt->constEnd(); ++it )
170 VectorComponentDetail detail = componentDetailForLayerId( it.key() );
171 detail.sourceVectorPath = filePath;
172 detail.group = groupIt.key();
178 saveOptions.
driverName = QStringLiteral(
"GPKG" );
181 if ( writer->hasError() )
183 mErrorMessage = writer->errorMessage();
192 mErrorMessage = writer->errorMessage();
197 detail.sourceVectorLayer = layerName;
198 mVectorComponents << detail;
204QString QgsAbstractGeoPdfExporter::createCompositionXml(
const QList<ComponentLayerDetail> &components,
const ExportDetails &details )
208 QDomElement compositionElem = doc.createElement( QStringLiteral(
"PDFComposition" ) );
211 QDomElement metadata = doc.createElement( QStringLiteral(
"Metadata" ) );
212 if ( !details.author.isEmpty() )
214 QDomElement author = doc.createElement( QStringLiteral(
"Author" ) );
215 author.appendChild( doc.createTextNode( details.author ) );
216 metadata.appendChild( author );
218 if ( !details.producer.isEmpty() )
220 QDomElement producer = doc.createElement( QStringLiteral(
"Producer" ) );
221 producer.appendChild( doc.createTextNode( details.producer ) );
222 metadata.appendChild( producer );
224 if ( !details.creator.isEmpty() )
226 QDomElement creator = doc.createElement( QStringLiteral(
"Creator" ) );
227 creator.appendChild( doc.createTextNode( details.creator ) );
228 metadata.appendChild( creator );
230 if ( details.creationDateTime.isValid() )
232 QDomElement creationDate = doc.createElement( QStringLiteral(
"CreationDate" ) );
233 QString creationDateString = QStringLiteral(
"D:%1" ).arg( details.creationDateTime.toString( QStringLiteral(
"yyyyMMddHHmmss" ) ) );
234 if ( details.creationDateTime.timeZone().isValid() )
236 int offsetFromUtc = details.creationDateTime.timeZone().offsetFromUtc( details.creationDateTime );
237 creationDateString += ( offsetFromUtc >= 0 ) ?
'+' :
'-';
238 offsetFromUtc = std::abs( offsetFromUtc );
239 int offsetHours = offsetFromUtc / 3600;
240 int offsetMins = ( offsetFromUtc % 3600 ) / 60;
241 creationDateString += QStringLiteral(
"%1'%2'" ).arg( offsetHours ).arg( offsetMins );
243 creationDate.appendChild( doc.createTextNode( creationDateString ) );
244 metadata.appendChild( creationDate );
246 if ( !details.subject.isEmpty() )
248 QDomElement subject = doc.createElement( QStringLiteral(
"Subject" ) );
249 subject.appendChild( doc.createTextNode( details.subject ) );
250 metadata.appendChild( subject );
252 if ( !details.title.isEmpty() )
254 QDomElement title = doc.createElement( QStringLiteral(
"Title" ) );
255 title.appendChild( doc.createTextNode( details.title ) );
256 metadata.appendChild( title );
258 if ( !details.keywords.empty() )
260 QStringList allKeywords;
261 for (
auto it = details.keywords.constBegin(); it != details.keywords.constEnd(); ++it )
263 allKeywords.append( QStringLiteral(
"%1: %2" ).arg( it.key(), it.value().join(
',' ) ) );
265 QDomElement keywords = doc.createElement( QStringLiteral(
"Keywords" ) );
266 keywords.appendChild( doc.createTextNode( allKeywords.join(
';' ) ) );
267 metadata.appendChild( keywords );
269 compositionElem.appendChild( metadata );
271 QMap< QString, QSet< QString > > createdLayerIds;
272 QMap< QString, QDomElement > groupLayerMap;
273 QMap< QString, QString > customGroupNamesToIds;
275 QMultiMap< QString, QDomElement > pendingLayerTreeElements;
277 if ( details.includeFeatures )
279 for (
const VectorComponentDetail &component : std::as_const( mVectorComponents ) )
281 if ( details.customLayerTreeGroups.contains( component.mapLayerId ) )
284 QDomElement layer = doc.createElement( QStringLiteral(
"Layer" ) );
285 layer.setAttribute( QStringLiteral(
"id" ), component.group.isEmpty() ? component.mapLayerId : QStringLiteral(
"%1_%2" ).arg( component.group, component.mapLayerId ) );
286 layer.setAttribute( QStringLiteral(
"name" ), details.layerIdToPdfLayerTreeNameMap.contains( component.mapLayerId ) ? details.layerIdToPdfLayerTreeNameMap.value( component.mapLayerId ) : component.name );
287 layer.setAttribute( QStringLiteral(
"initiallyVisible" ), details.initialLayerVisibility.value( component.mapLayerId,
true ) ? QStringLiteral(
"true" ) : QStringLiteral(
"false" ) );
289 if ( !component.group.isEmpty() )
291 if ( groupLayerMap.contains( component.group ) )
293 groupLayerMap[ component.group ].appendChild( layer );
297 QDomElement group = doc.createElement( QStringLiteral(
"Layer" ) );
298 group.setAttribute( QStringLiteral(
"id" ), QStringLiteral(
"group_%1" ).arg( component.group ) );
299 group.setAttribute( QStringLiteral(
"name" ), component.group );
300 group.setAttribute( QStringLiteral(
"initiallyVisible" ), groupLayerMap.empty() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" ) );
301 group.setAttribute( QStringLiteral(
"mutuallyExclusiveGroupId" ), QStringLiteral(
"__mutually_exclusive_groups__" ) );
302 pendingLayerTreeElements.insert( component.mapLayerId, group );
303 group.appendChild( layer );
304 groupLayerMap[ component.group ] = group;
309 pendingLayerTreeElements.insert( component.mapLayerId, layer );
312 createdLayerIds[ component.group ].insert( component.mapLayerId );
316 for (
const ComponentLayerDetail &component : components )
318 if ( component.mapLayerId.isEmpty() || createdLayerIds.value( component.group ).contains( component.mapLayerId ) )
321 if ( details.customLayerTreeGroups.contains( component.mapLayerId ) )
324 QDomElement layer = doc.createElement( QStringLiteral(
"Layer" ) );
325 layer.setAttribute( QStringLiteral(
"id" ), component.group.isEmpty() ? component.mapLayerId : QStringLiteral(
"%1_%2" ).arg( component.group, component.mapLayerId ) );
326 layer.setAttribute( QStringLiteral(
"name" ), details.layerIdToPdfLayerTreeNameMap.contains( component.mapLayerId ) ? details.layerIdToPdfLayerTreeNameMap.value( component.mapLayerId ) : component.name );
327 layer.setAttribute( QStringLiteral(
"initiallyVisible" ), details.initialLayerVisibility.value( component.mapLayerId,
true ) ? QStringLiteral(
"true" ) : QStringLiteral(
"false" ) );
329 if ( !component.group.isEmpty() )
331 if ( groupLayerMap.contains( component.group ) )
333 groupLayerMap[ component.group ].appendChild( layer );
337 QDomElement group = doc.createElement( QStringLiteral(
"Layer" ) );
338 group.setAttribute( QStringLiteral(
"id" ), QStringLiteral(
"group_%1" ).arg( component.group ) );
339 group.setAttribute( QStringLiteral(
"name" ), component.group );
340 group.setAttribute( QStringLiteral(
"initiallyVisible" ), groupLayerMap.empty() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" ) );
341 group.setAttribute( QStringLiteral(
"mutuallyExclusiveGroupId" ), QStringLiteral(
"__mutually_exclusive_groups__" ) );
342 pendingLayerTreeElements.insert( component.mapLayerId, group );
343 group.appendChild( layer );
344 groupLayerMap[ component.group ] = group;
349 pendingLayerTreeElements.insert( component.mapLayerId, layer );
352 createdLayerIds[ component.group ].insert( component.mapLayerId );
356 QDomElement
layerTree = doc.createElement( QStringLiteral(
"LayerTree" ) );
360 for (
auto it = details.customLayerTreeGroups.constBegin(); it != details.customLayerTreeGroups.constEnd(); ++it )
362 if ( customGroupNamesToIds.contains( it.value() ) )
365 QDomElement layer = doc.createElement( QStringLiteral(
"Layer" ) );
366 const QString
id = QUuid::createUuid().toString();
367 customGroupNamesToIds[ it.value() ] = id;
368 layer.setAttribute( QStringLiteral(
"id" ),
id );
369 layer.setAttribute( QStringLiteral(
"name" ), it.value() );
370 layer.setAttribute( QStringLiteral(
"initiallyVisible" ), QStringLiteral(
"true" ) );
375 for (
const QString &layerId : details.layerOrder )
377 const QList< QDomElement> elements = pendingLayerTreeElements.values( layerId );
378 for (
const QDomElement &element : elements )
382 for (
auto it = pendingLayerTreeElements.constBegin(); it != pendingLayerTreeElements.constEnd(); ++it )
384 if ( details.layerOrder.contains( it.key() ) )
393 compositionElem.appendChild(
layerTree );
396 QDomElement page = doc.createElement( QStringLiteral(
"Page" ) );
397 QDomElement dpi = doc.createElement( QStringLiteral(
"DPI" ) );
400 page.appendChild( dpi );
402 QDomElement width = doc.createElement( QStringLiteral(
"Width" ) );
403 const double pageWidthPdfUnits = std::ceil( details.pageSizeMm.width() / 25.4 * 72 );
404 width.appendChild( doc.createTextNode(
qgsDoubleToString( pageWidthPdfUnits ) ) );
405 page.appendChild( width );
406 QDomElement height = doc.createElement( QStringLiteral(
"Height" ) );
407 const double pageHeightPdfUnits = std::ceil( details.pageSizeMm.height() / 25.4 * 72 );
408 height.appendChild( doc.createTextNode(
qgsDoubleToString( pageHeightPdfUnits ) ) );
409 page.appendChild( height );
416 QDomElement georeferencing = doc.createElement( QStringLiteral(
"Georeferencing" ) );
417 georeferencing.setAttribute( QStringLiteral(
"id" ), QStringLiteral(
"georeferenced_%1" ).arg( i++ ) );
418 georeferencing.setAttribute( QStringLiteral(
"OGCBestPracticeFormat" ), details.useOgcBestPracticeFormatGeoreferencing ? QStringLiteral(
"true" ) : QStringLiteral(
"false" ) );
419 georeferencing.setAttribute( QStringLiteral(
"ISO32000ExtensionFormat" ), details.useIso32000ExtensionFormatGeoreferencing ? QStringLiteral(
"true" ) : QStringLiteral(
"false" ) );
423 QDomElement srs = doc.createElement( QStringLiteral(
"SRS" ) );
426 if ( !section.
crs.
authid().startsWith( QStringLiteral(
"user" ), Qt::CaseInsensitive ) )
428 srs.appendChild( doc.createTextNode( section.
crs.
authid() ) );
434 georeferencing.appendChild( srs );
446 QDomElement boundingPolygon = doc.createElement( QStringLiteral(
"BoundingPolygon" ) );
449 QTransform t = QTransform::fromTranslate( 0, pageHeightPdfUnits ).scale( pageWidthPdfUnits / details.pageSizeMm.width(),
450 -pageHeightPdfUnits / details.pageSizeMm.height() );
454 boundingPolygon.appendChild( doc.createTextNode( p.
asWkt() ) );
456 georeferencing.appendChild( boundingPolygon );
465 QDomElement boundingBox = doc.createElement( QStringLiteral(
"BoundingBox" ) );
470 georeferencing.appendChild( boundingBox );
475 QDomElement cp1 = doc.createElement( QStringLiteral(
"ControlPoint" ) );
476 cp1.setAttribute( QStringLiteral(
"x" ),
qgsDoubleToString( point.pagePoint.x() / 25.4 * 72 ) );
477 cp1.setAttribute( QStringLiteral(
"y" ),
qgsDoubleToString( ( details.pageSizeMm.height() - point.pagePoint.y() ) / 25.4 * 72 ) );
478 cp1.setAttribute( QStringLiteral(
"GeoX" ),
qgsDoubleToString( point.geoPoint.x() ) );
479 cp1.setAttribute( QStringLiteral(
"GeoY" ),
qgsDoubleToString( point.geoPoint.y() ) );
480 georeferencing.appendChild( cp1 );
483 page.appendChild( georeferencing );
486 auto createPdfDatasetElement = [&doc](
const ComponentLayerDetail & component ) -> QDomElement
488 QDomElement pdfDataset = doc.createElement( QStringLiteral(
"PDF" ) );
489 pdfDataset.setAttribute( QStringLiteral(
"dataset" ), component.sourcePdfPath );
490 if ( component.opacity != 1.0 || component.compositionMode != QPainter::CompositionMode_SourceOver )
492 QDomElement blendingElement = doc.createElement( QStringLiteral(
"Blending" ) );
493 blendingElement.setAttribute( QStringLiteral(
"opacity" ), component.opacity );
494 blendingElement.setAttribute( QStringLiteral(
"function" ), compositionModeToString( component.compositionMode ) );
496 pdfDataset.appendChild( blendingElement );
502 QDomElement content = doc.createElement( QStringLiteral(
"Content" ) );
503 for (
const ComponentLayerDetail &component : components )
505 if ( component.mapLayerId.isEmpty() )
507 content.appendChild( createPdfDatasetElement( component ) );
509 else if ( !component.group.isEmpty() )
512 QDomElement ifGroupOn = doc.createElement( QStringLiteral(
"IfLayerOn" ) );
513 ifGroupOn.setAttribute( QStringLiteral(
"layerId" ), QStringLiteral(
"group_%1" ).arg( component.group ) );
514 QDomElement ifLayerOn = doc.createElement( QStringLiteral(
"IfLayerOn" ) );
515 if ( details.customLayerTreeGroups.contains( component.mapLayerId ) )
516 ifLayerOn.setAttribute( QStringLiteral(
"layerId" ), customGroupNamesToIds.value( details.customLayerTreeGroups.value( component.mapLayerId ) ) );
517 else if ( component.group.isEmpty() )
518 ifLayerOn.setAttribute( QStringLiteral(
"layerId" ), component.mapLayerId );
520 ifLayerOn.setAttribute( QStringLiteral(
"layerId" ), QStringLiteral(
"%1_%2" ).arg( component.group, component.mapLayerId ) );
522 ifLayerOn.appendChild( createPdfDatasetElement( component ) );
523 ifGroupOn.appendChild( ifLayerOn );
524 content.appendChild( ifGroupOn );
528 QDomElement ifLayerOn = doc.createElement( QStringLiteral(
"IfLayerOn" ) );
529 if ( details.customLayerTreeGroups.contains( component.mapLayerId ) )
530 ifLayerOn.setAttribute( QStringLiteral(
"layerId" ), customGroupNamesToIds.value( details.customLayerTreeGroups.value( component.mapLayerId ) ) );
531 else if ( component.group.isEmpty() )
532 ifLayerOn.setAttribute( QStringLiteral(
"layerId" ), component.mapLayerId );
534 ifLayerOn.setAttribute( QStringLiteral(
"layerId" ), QStringLiteral(
"%1_%2" ).arg( component.group, component.mapLayerId ) );
535 ifLayerOn.appendChild( createPdfDatasetElement( component ) );
536 content.appendChild( ifLayerOn );
541 if ( details.includeFeatures )
543 for (
const VectorComponentDetail &component : std::as_const( mVectorComponents ) )
545 QDomElement ifLayerOn = doc.createElement( QStringLiteral(
"IfLayerOn" ) );
546 if ( details.customLayerTreeGroups.contains( component.mapLayerId ) )
547 ifLayerOn.setAttribute( QStringLiteral(
"layerId" ), customGroupNamesToIds.value( details.customLayerTreeGroups.value( component.mapLayerId ) ) );
548 else if ( component.group.isEmpty() )
549 ifLayerOn.setAttribute( QStringLiteral(
"layerId" ), component.mapLayerId );
551 ifLayerOn.setAttribute( QStringLiteral(
"layerId" ), QStringLiteral(
"%1_%2" ).arg( component.group, component.mapLayerId ) );
552 QDomElement vectorDataset = doc.createElement( QStringLiteral(
"Vector" ) );
553 vectorDataset.setAttribute( QStringLiteral(
"dataset" ), component.sourceVectorPath );
554 vectorDataset.setAttribute( QStringLiteral(
"layer" ), component.sourceVectorLayer );
555 vectorDataset.setAttribute( QStringLiteral(
"visible" ), QStringLiteral(
"false" ) );
556 QDomElement logicalStructure = doc.createElement( QStringLiteral(
"LogicalStructure" ) );
557 logicalStructure.setAttribute( QStringLiteral(
"displayLayerName" ), component.name );
558 if ( !component.displayAttribute.isEmpty() )
559 logicalStructure.setAttribute( QStringLiteral(
"fieldToDisplay" ), component.displayAttribute );
560 vectorDataset.appendChild( logicalStructure );
561 ifLayerOn.appendChild( vectorDataset );
562 content.appendChild( ifLayerOn );
566 page.appendChild( content );
567 compositionElem.appendChild( page );
569 doc.appendChild( compositionElem );
572 QTextStream stream( &composition );
573 doc.save( stream, -1 );
578QString QgsAbstractGeoPdfExporter::compositionModeToString( QPainter::CompositionMode mode )
582 case QPainter::CompositionMode_SourceOver:
583 return QStringLiteral(
"Normal" );
585 case QPainter::CompositionMode_Multiply:
586 return QStringLiteral(
"Multiply" );
588 case QPainter::CompositionMode_Screen:
589 return QStringLiteral(
"Screen" );
591 case QPainter::CompositionMode_Overlay:
592 return QStringLiteral(
"Overlay" );
594 case QPainter::CompositionMode_Darken:
595 return QStringLiteral(
"Darken" );
597 case QPainter::CompositionMode_Lighten:
598 return QStringLiteral(
"Lighten" );
600 case QPainter::CompositionMode_ColorDodge:
601 return QStringLiteral(
"ColorDodge" );
603 case QPainter::CompositionMode_ColorBurn:
604 return QStringLiteral(
"ColorBurn" );
606 case QPainter::CompositionMode_HardLight:
607 return QStringLiteral(
"HardLight" );
609 case QPainter::CompositionMode_SoftLight:
610 return QStringLiteral(
"SoftLight" );
612 case QPainter::CompositionMode_Difference:
613 return QStringLiteral(
"Difference" );
615 case QPainter::CompositionMode_Exclusion:
616 return QStringLiteral(
"Exclusion" );
622 QgsDebugMsg( QStringLiteral(
"Unsupported PDF blend mode %1" ).arg( mode ) );
623 return QStringLiteral(
"Normal" );
void pushRenderedFeature(const QString &layerId, const QgsAbstractGeoPdfExporter::RenderedFeature &feature, const QString &group=QString())
Called multiple times during the rendering operation, whenever a feature associated with the specifie...
QString generateTemporaryFilepath(const QString &filename) const
Returns a file path to use for temporary files required for GeoPDF creation.
static bool geoPDFCreationAvailable()
Returns true if the current QGIS build is capable of GeoPDF support.
static bool compositionModeSupported(QPainter::CompositionMode mode)
Returns true if the specified composition mode is supported for layers during GeoPDF exports.
static QString geoPDFAvailabilityExplanation()
Returns a user-friendly, translated string explaining why GeoPDF export support is not available on t...
bool finalize(const QList< QgsAbstractGeoPdfExporter::ComponentLayerDetail > &components, const QString &destinationFile, const ExportDetails &details)
To be called after the rendering operation is complete.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
@ WKT_PREFERRED_GDAL
Preferred format for conversion of CRS to WKT for use with the GDAL library.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Contains information about the context in which a coordinate transform is executed.
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
static QString stringToSafeFilename(const QString &string)
Converts a string to a safe filename, replacing characters which are not safe for filenames with an '...
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Options to pass to writeAsVectorFormat()
QString driverName
OGR driver to use.
QgsVectorFileWriter::SymbologyExport symbologyExport
Symbology to export.
static QgsVectorFileWriter * create(const QString &fileName, const QgsFields &fields, Qgis::WkbType geometryType, const QgsCoordinateReferenceSystem &srs, const QgsCoordinateTransformContext &transformContext, const QgsVectorFileWriter::SaveVectorOptions &options, QgsFeatureSink::SinkFlags sinkFlags=QgsFeatureSink::SinkFlags(), QString *newFilename=nullptr, QString *newLayer=nullptr)
Create a new vector file writer.
QgsLayerTree * layerTree(const QgsWmsRenderContext &context)
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QList< QgsFeature > QgsFeatureList
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.
QgsPolygon pageBoundsPolygon
Bounds of the georeferenced section on the page, in millimeters, as a free-form polygon.
QList< QgsAbstractGeoPdfExporter::ControlPoint > controlPoints
List of control points corresponding to this georeferenced section.
Contains information about a feature rendered inside the PDF.
QgsFeature feature
Rendered feature.
QgsGeometry renderedBounds
Bounds, in PDF units, of rendered feature.