diff --git a/python/core/auto_generated/layout/qgslayoutexporter.sip.in b/python/core/auto_generated/layout/qgslayoutexporter.sip.in index fb803fff967f..5324456cad42 100644 --- a/python/core/auto_generated/layout/qgslayoutexporter.sip.in +++ b/python/core/auto_generated/layout/qgslayoutexporter.sip.in @@ -194,6 +194,8 @@ Constructor for PdfExportSettings bool simplifyGeometries; + bool writeGeoPdf; + }; ExportResult exportToPdf( const QString &filePath, const QgsLayoutExporter::PdfExportSettings &settings ); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f90cad67d63c..3044a2944794 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -402,6 +402,7 @@ SET(QGIS_CORE_SRCS layout/qgslayoutgridsettings.cpp layout/qgslayoutguidecollection.cpp layout/qgslayoutframe.cpp + layout/qgslayoutgeopdfexporter.cpp layout/qgslayoutitem.cpp layout/qgslayoutitemattributetable.cpp layout/qgslayoutitemgroup.cpp @@ -1091,6 +1092,7 @@ SET(QGIS_CORE_HDRS layout/qgsmasterlayoutinterface.h layout/qgslayoutaligner.h layout/qgslayoutexporter.h + layout/qgslayoutgeopdfexporter.h layout/qgslayoutgridsettings.h layout/qgslayoutitemundocommand.h layout/qgslayoutmeasurement.h diff --git a/src/core/layout/qgslayoutexporter.cpp b/src/core/layout/qgslayoutexporter.cpp index ba2298d626f7..ef44e75b0d97 100644 --- a/src/core/layout/qgslayoutexporter.cpp +++ b/src/core/layout/qgslayoutexporter.cpp @@ -25,6 +25,7 @@ #include "qgslayoutguidecollection.h" #include "qgsabstractlayoutiterator.h" #include "qgsfeedback.h" +#include "qgslayoutgeopdfexporter.h" #include #include #include @@ -517,6 +518,10 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( const QString &f mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() ); } + std::unique_ptr< QgsLayoutGeoPdfExporter > geoPdfExporter; + if ( settings.writeGeoPdf ) + geoPdfExporter = qgis::make_unique< QgsLayoutGeoPdfExporter >( mLayout ); + mLayout->renderContext().setFlags( settings.flags ); // If we are not printing as raster, temporarily disable advanced effects diff --git a/src/core/layout/qgslayoutexporter.h b/src/core/layout/qgslayoutexporter.h index 30231e3f1e4f..8ad0bd2b922c 100644 --- a/src/core/layout/qgslayoutexporter.h +++ b/src/core/layout/qgslayoutexporter.h @@ -302,6 +302,19 @@ class CORE_EXPORT QgsLayoutExporter */ bool simplifyGeometries = true; + /** + * TRUE if GeoPDF files should be created, instead of normal PDF files. + * + * Whilst GeoPDF files can include some desirable properties like the ability to interactively + * query map features, they also can result in lower-quality output files, or forced rasterization + * of layers. + * + * \note Requires builds based on GDAL 3.0 or greater. + * + * \since QGIS 3.10 + */ + bool writeGeoPdf = true; + }; /** diff --git a/src/core/layout/qgslayoutgeopdfexporter.cpp b/src/core/layout/qgslayoutgeopdfexporter.cpp new file mode 100644 index 000000000000..c92c96ec47f2 --- /dev/null +++ b/src/core/layout/qgslayoutgeopdfexporter.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + qgslayoutgeopdfexporter.cpp + -------------------------- + begin : August 2019 + copyright : (C) 2019 by Nyall Dawson + email : nyall dot dawson at gmail dot com + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgslayoutgeopdfexporter.h" +#include "qgsrenderedfeaturehandlerinterface.h" +#include "qgsfeaturerequest.h" +#include "qgslayout.h" +#include "qgslogger.h" + +class QgsGeoPdfRenderedFeatureHandler: public QgsRenderedFeatureHandlerInterface +{ + public: + void handleRenderedFeature( const QgsFeature &feature, const QgsGeometry &renderedBounds, const QgsRenderedFeatureHandlerInterface::RenderedFeatureContext &context ) override + { + QgsDebugMsg( QStringLiteral( "%1: %2" ).arg( context.renderContext->expressionContext().variable( QStringLiteral( "layer_id" ) ).toString() ).arg( feature.attribute( 0 ).toString() ) ); + } + + QSet usedAttributes( QgsVectorLayer *, const QgsRenderContext & ) const override + { + return QSet< QString >() << QgsFeatureRequest::ALL_ATTRIBUTES; + } +}; + + +QgsLayoutGeoPdfExporter::QgsLayoutGeoPdfExporter( QgsLayout *layout ) + : mLayout( layout ) + , mHandler( qgis::make_unique< QgsGeoPdfRenderedFeatureHandler >() ) +{ + // on construction, we install a rendered feature handler on layout item maps + mLayout->layoutItems( mMaps ); + for ( QgsLayoutItemMap *map : qgis::as_const( mMaps ) ) + { + map->addRenderedFeatureHandler( mHandler.get() ); + } +} + +QgsLayoutGeoPdfExporter::~QgsLayoutGeoPdfExporter() +{ + // cleanup - remove rendered feature handler from all maps + for ( QgsLayoutItemMap *map : qgis::as_const( mMaps ) ) + { + map->removeRenderedFeatureHandler( mHandler.get() ); + } +} + diff --git a/src/core/layout/qgslayoutgeopdfexporter.h b/src/core/layout/qgslayoutgeopdfexporter.h new file mode 100644 index 000000000000..6615bea01d52 --- /dev/null +++ b/src/core/layout/qgslayoutgeopdfexporter.h @@ -0,0 +1,66 @@ +/*************************************************************************** + qgslayoutgeopdfexporter.h + -------------------------- + begin : August 2019 + copyright : (C) 2019 by Nyall Dawson + email : nyall dot dawson at gmail dot com + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef QGSLAYOUTGEOPDFEXPORTER_H +#define QGSLAYOUTGEOPDFEXPORTER_H + +#include "qgis_core.h" +#include "qgslayoutitemmap.h" +#include + +#define SIP_NO_FILE + +class QgsLayout; +class QgsGeoPdfRenderedFeatureHandler; + +/** + * \class QgsLayoutGeoPdfExporter + * \ingroup core + * + * Handles GeoPDF export specific setup, cleanup and processing steps. + * + * This class is a low level implementation detail only. Generally, you should use the high level interface exposed by + * QgsLayoutExporter instead. + * + * \warning QgsLayoutGeoPdfExporter is designed to be a short lived object. It should be created for a + * single layout export operation only, and then immediately destroyed. Failure to correctly + * destroy the object after exporting a layout will leave the layout in an inconsistent, unstable state. + * + * \note Not available in Python bindings + * + * \since QGIS 3.10 + */ +class CORE_EXPORT QgsLayoutGeoPdfExporter +{ + public: + + QgsLayoutGeoPdfExporter( QgsLayout *layout ); + + + ~QgsLayoutGeoPdfExporter(); + + private: + + QgsLayout *mLayout = nullptr; + QList< QgsLayoutItemMap * > mMaps; + + std::unique_ptr< QgsGeoPdfRenderedFeatureHandler > mHandler; + +}; + +#endif //QGSLAYOUTGEOPDFEXPORTER_H + + +