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" ) );
 
  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  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).
 
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.
 
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.
 
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.