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 const bool res = outputDataset.get() !=
nullptr;
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" ) );
421 if ( section.crs.isValid() )
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 );
437 if ( !section.pageBoundsPolygon.isEmpty() )
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" ) );
466 boundingBox.setAttribute( QStringLiteral(
"x1" ),
qgsDoubleToString( section.pageBoundsMm.xMinimum() / 25.4 * 72 ) );
467 boundingBox.setAttribute( QStringLiteral(
"y1" ),
qgsDoubleToString( section.pageBoundsMm.yMinimum() / 25.4 * 72 ) );
468 boundingBox.setAttribute( QStringLiteral(
"x2" ),
qgsDoubleToString( section.pageBoundsMm.xMaximum() / 25.4 * 72 ) );
469 boundingBox.setAttribute( QStringLiteral(
"y2" ),
qgsDoubleToString( section.pageBoundsMm.yMaximum() / 25.4 * 72 ) );
470 georeferencing.appendChild( boundingBox );
473 for (
const ControlPoint &point : section.controlPoints )
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 QgsDebugError( QStringLiteral(
"Unsupported PDF blend mode %1" ).arg( mode ) );
623 return QStringLiteral(
"Normal" );
@ NoSymbology
Export only data.
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).
@ WKT_PREFERRED_GDAL
Preferred format for conversion of CRS to WKT for use with the GDAL library.
Contains information about the context in which a coordinate transform is executed.
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
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 '...
Options to pass to writeAsVectorFormat()
QString driverName
OGR driver to use.
Qgis::FeatureSymbologyExport 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
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
bool includeFeatures
true if feature vector information (such as attributes) should be exported.
Contains information about a feature rendered inside the PDF.
QgsFeature feature
Rendered feature.
QgsGeometry renderedBounds
Bounds, in PDF units, of rendered feature.