Skip to content

Commit

Permalink
Use GADL to create actual GeoPDF from composition file
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Aug 17, 2019
1 parent 522dacf commit 39b12a6
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/core/layout/qgslayoutexporter.cpp
Expand Up @@ -547,7 +547,7 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( const QString &f
p.end();

if ( geoPdfExporter )
geoPdfExporter->finalize();
geoPdfExporter->finalize( filePath );

bool shouldAppendGeoreference = settings.appendGeoreference && mLayout && mLayout->referenceMap() && mLayout->referenceMap()->page() == 0;
if ( settings.appendGeoreference || settings.exportMetadata )
Expand Down
52 changes: 48 additions & 4 deletions src/core/layout/qgslayoutgeopdfexporter.cpp
Expand Up @@ -21,6 +21,11 @@
#include "qgslogger.h"
#include "qgsgeometry.h"
#include "qgsvectorfilewriter.h"

#include <gdal.h>
#include "qgsgdalutils.h"
#include "cpl_string.h"

#include <QMutex>
#include <QMutexLocker>
#include <QDomDocument>
Expand Down Expand Up @@ -109,7 +114,7 @@ QMap<QString, QVector<QgsLayoutGeoPdfExporter::RenderedFeature> > QgsLayoutGeoPd
return mMapHandlers.value( map )->renderedFeatures;
}

bool QgsLayoutGeoPdfExporter::finalize()
bool QgsLayoutGeoPdfExporter::finalize( const QString &sourcePdf )
{
// collate all the features from different maps which belong to the same layer, replace their geometries with the rendered feature bounds
for ( auto mapIt = mMapHandlers.constBegin(); mapIt != mMapHandlers.constEnd(); ++mapIt )
Expand All @@ -132,11 +137,43 @@ bool QgsLayoutGeoPdfExporter::finalize()
if ( !saveTemporaryLayers() )
return false;

const QString composition = createCompositionXml();
const QString composition = createCompositionXml( sourcePdf );
if ( composition.isEmpty() )
return false;

return true;
// do the creation!
GDALDriverH driver = GDALGetDriverByName( "PDF" );
if ( !driver )
{
mErrorMessage = QObject::tr( "Cannot load GDAL PDF driver" );
return false;
}

const QString xmlFilePath = mTemporaryDir.filePath( QStringLiteral( "composition.xml" ) );
QFile file( xmlFilePath );
if ( file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
{
QTextStream out( &file );
out << composition;
}
else
{
mErrorMessage = QObject::tr( "Could not create GeoPDF composition file" );
return false;
}

char **papszOptions = CSLSetNameValue( nullptr, "COMPOSITION_FILE", xmlFilePath.toUtf8().constData() );

QString outputFile = "/home/nyall/Temporary/geopdf/test.pdf";

// return a non-null (fake) dataset in case of success, nullptr otherwise.
gdal::dataset_unique_ptr outputDataset( GDALCreate( driver, outputFile.toUtf8().constData(), 0, 0, 0, GDT_Unknown, papszOptions ) );
bool res = outputDataset.get();
outputDataset.reset();

CSLDestroy( papszOptions );

return res;
}

bool QgsLayoutGeoPdfExporter::saveTemporaryLayers()
Expand Down Expand Up @@ -169,7 +206,7 @@ bool QgsLayoutGeoPdfExporter::saveTemporaryLayers()
return true;
}

QString QgsLayoutGeoPdfExporter::createCompositionXml()
QString QgsLayoutGeoPdfExporter::createCompositionXml( const QString &sourcePdf )
{
QDomDocument doc;

Expand Down Expand Up @@ -235,12 +272,19 @@ QString QgsLayoutGeoPdfExporter::createCompositionXml()
ifLayerOn.setAttribute( QStringLiteral( "layerId" ), it.key() );
QDomElement vectorDataset = doc.createElement( QStringLiteral( "Vector" ) );
vectorDataset.setAttribute( QStringLiteral( "dataset" ), it.value() );
QFileInfo fi( it.value() );
vectorDataset.setAttribute( QStringLiteral( "layer" ), fi.completeBaseName() );
vectorDataset.setAttribute( QStringLiteral( "visible" ), QStringLiteral( "true" ) ); // actually false!
QDomElement logicalStructure = doc.createElement( QStringLiteral( "LogicalStructure" ) );
logicalStructure.setAttribute( QStringLiteral( "displayLayerName" ), it.key() );
//logicalStructure.setAttribute( QStringLiteral( "fieldToDisplay" ), it.key() );
vectorDataset.appendChild( logicalStructure );
ifLayerOn.appendChild( vectorDataset );

QDomElement pdfDataset = doc.createElement( QStringLiteral( "PDF" ) );
pdfDataset.setAttribute( QStringLiteral( "dataset" ), sourcePdf );
ifLayerOn.appendChild( pdfDataset );

content.appendChild( ifLayerOn );
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/layout/qgslayoutgeopdfexporter.h
Expand Up @@ -93,7 +93,7 @@ class CORE_EXPORT QgsLayoutGeoPdfExporter
* Returns TRUE if the operation was successful, or FALSE if an error occurred. If an error occurred, it
* can be retrieved by calling errorMessage().
*/
bool finalize();
bool finalize( const QString &sourcePdf );

/**
* Returns the last error message encountered during the export.
Expand All @@ -113,7 +113,7 @@ class CORE_EXPORT QgsLayoutGeoPdfExporter

bool saveTemporaryLayers();

QString createCompositionXml();
QString createCompositionXml( const QString &sourcePdf );

friend class TestQgsLayoutGeoPdfExport;
};
Expand Down
9 changes: 6 additions & 3 deletions tests/src/core/testqgslayoutgeopdfexport.cpp
Expand Up @@ -111,7 +111,10 @@ void TestQgsLayoutGeoPdfExport::testCollectingFeatures()

// trigger render
QgsLayoutExporter exporter( &l );
exporter.renderPageToImage( 0 );
QString outputFile = "/home/nyall/Temporary/geopdf/test_src.pdf";
QgsLayoutExporter::PdfExportSettings settings;
settings.writeGeoPdf = false;
exporter.exportToPdf( outputFile, settings );

// check that features were collected
QMap< QString, QVector< QgsLayoutGeoPdfExporter::RenderedFeature > > renderedFeatures = geoPdfExporter.renderedFeatures( map );
Expand Down Expand Up @@ -181,7 +184,7 @@ void TestQgsLayoutGeoPdfExport::testCollectingFeatures()
QCOMPARE( pointGeometry3b.asWkt( 1 ), QStringLiteral( "MultiPolygon (((167 102, 178.2 102, 178.2 113.3, 167 113.3, 167 102)))" ) );

// finalize and test collation
geoPdfExporter.finalize();
QVERIFY( geoPdfExporter.finalize( outputFile ) );

QMap< QString, QgsFeatureList > collatedFeatures = geoPdfExporter.mCollatedFeatures;
QCOMPARE( collatedFeatures.count(), 2 );
Expand All @@ -205,7 +208,7 @@ void TestQgsLayoutGeoPdfExport::testCollectingFeatures()
lineTemp.reset();

// test creation of the composition xml
QString composition = geoPdfExporter.createCompositionXml();
QString composition = geoPdfExporter.createCompositionXml( outputFile );
QgsDebugMsg( composition );
QVERIFY( composition.contains( QStringLiteral( "id=\"%1\"" ).arg( linesLayer->id() ) ) );
QVERIFY( composition.contains( QStringLiteral( "id=\"%1\"" ).arg( pointsLayer->id() ) ) );
Expand Down

0 comments on commit 39b12a6

Please sign in to comment.