[FEATURE] Add possibility to export metadata when saving map canvas as PDF

This commit is contained in:
nirvn 2019-08-27 14:26:59 +07:00 committed by Mathieu Pellerin
parent a817a8e247
commit f801d1716d
6 changed files with 103 additions and 35 deletions

View File

@ -10,6 +10,7 @@
class QgsMapRendererTask : QgsTask
{
%Docstring
@ -63,6 +64,11 @@ Adds ``decorations`` to be rendered on the map.
void setSaveWorldFile( bool save );
%Docstring
Sets whether the image file will be georeferenced (embedded or via a world file).
%End
void setExportMetadata( bool exportMetadata );
%Docstring
Sets whether metadata such as title and subject will be exported whenever possible.
%End
virtual void cancel();

View File

@ -148,6 +148,7 @@ QgsMapSaveDialog::QgsMapSaveDialog( QWidget *parent, QgsMapCanvas *mapCanvas, co
case Image:
{
mExportMetadataCheckBox->hide();
mGeoPDFGroupBox->hide();
mAdvancedPdfSettings->hide();
mTextExportLabel->hide();
@ -307,6 +308,11 @@ bool QgsMapSaveDialog::saveWorldFile() const
return mSaveWorldFile->isChecked();
}
bool QgsMapSaveDialog::exportMetadata() const
{
return mExportMetadataCheckBox->isChecked();;
}
bool QgsMapSaveDialog::saveAsRaster() const
{
return mSaveAsRaster->isChecked();
@ -502,19 +508,20 @@ void QgsMapSaveDialog::onAccepted()
ms.setTextRenderFormat( static_cast< QgsRenderContext::TextRenderFormat >( mTextRenderFormatComboBox->currentData().toInt() ) );
QgsAbstractGeoPdfExporter::ExportDetails geoPdfExportDetails;
if ( mExportMetadataCheckBox->isChecked() )
{
// These details will be used on non-GeoPDF exports is the export metadata checkbox is checked
geoPdfExportDetails.author = QgsProject::instance()->metadata().author();
geoPdfExportDetails.producer = QStringLiteral( "QGIS %1" ).arg( Qgis::QGIS_VERSION );
geoPdfExportDetails.creator = QStringLiteral( "QGIS %1" ).arg( Qgis::QGIS_VERSION );
geoPdfExportDetails.creationDateTime = QDateTime::currentDateTime();
geoPdfExportDetails.subject = QgsProject::instance()->metadata().abstract();
geoPdfExportDetails.title = QgsProject::instance()->metadata().title();
geoPdfExportDetails.keywords = QgsProject::instance()->metadata().keywords();
}
if ( mGeoPDFGroupBox->isChecked() )
{
if ( mExportMetadataCheckBox->isChecked() )
{
geoPdfExportDetails.author = QgsProject::instance()->metadata().author();
geoPdfExportDetails.producer = QStringLiteral( "QGIS %1" ).arg( Qgis::QGIS_VERSION );
geoPdfExportDetails.creator = QStringLiteral( "QGIS %1" ).arg( Qgis::QGIS_VERSION );
geoPdfExportDetails.creationDateTime = QDateTime::currentDateTime();
geoPdfExportDetails.subject = QgsProject::instance()->metadata().abstract();
geoPdfExportDetails.title = QgsProject::instance()->metadata().title();
geoPdfExportDetails.keywords = QgsProject::instance()->metadata().keywords();
}
if ( mGeoPdfFormatComboBox->currentIndex() == 0 )
{
geoPdfExportDetails.useIso32000ExtensionFormatGeoreferencing = true;
@ -542,6 +549,11 @@ void QgsMapSaveDialog::onAccepted()
mapRendererTask->setSaveWorldFile( saveWorldFile() );
if ( exportMetadata() )
{
mapRendererTask->setExportMetadata( exportMetadata() );
}
connect( mapRendererTask, &QgsMapRendererTask::renderingComplete, [ = ]
{
QgisApp::instance()->messageBar()->pushSuccess( tr( "Save as PDF" ), tr( "Successfully saved map to <a href=\"%1\">%2</a>" )

View File

@ -74,6 +74,9 @@ class APP_EXPORT QgsMapSaveDialog: public QDialog, private Ui::QgsMapSaveDialog
//! returns whether the resulting image will be georeferenced (embedded or via world file)
bool saveWorldFile() const;
//! returns whether metadata such as title and subject will be exported whenever possible
bool exportMetadata() const;
//! returns whether the map will be rasterized
bool saveAsRaster() const;

View File

@ -26,6 +26,7 @@
#include "qgsrenderedfeaturehandlerinterface.h"
#include "qgsfeaturerequest.h"
#include "qgsvectorlayer.h"
#include <QFile>
#include <QTextStream>
#ifndef QT_NO_PRINTER
@ -299,21 +300,60 @@ bool QgsMapRendererTask::run()
pp.end();
}
if ( mSaveWorldFile )
if ( mSaveWorldFile || mExportMetadata )
{
CPLSetThreadLocalConfigOption( "GDAL_PDF_DPI", QString::number( mMapSettings.outputDpi() ).toLocal8Bit().constData() );
gdal::dataset_unique_ptr outputDS( GDALOpen( mFileName.toLocal8Bit().constData(), GA_Update ) );
if ( outputDS )
{
double a, b, c, d, e, f;
QgsMapSettingsUtils::worldFileParameters( mMapSettings, a, b, c, d, e, f );
c -= 0.5 * a;
c -= 0.5 * b;
f -= 0.5 * d;
f -= 0.5 * e;
double geoTransform[6] = { c, a, b, f, d, e };
GDALSetGeoTransform( outputDS.get(), geoTransform );
GDALSetProjection( outputDS.get(), mMapSettings.destinationCrs().toWkt().toLocal8Bit().constData() );
if ( mSaveWorldFile )
{
double a, b, c, d, e, f;
QgsMapSettingsUtils::worldFileParameters( mMapSettings, a, b, c, d, e, f );
c -= 0.5 * a;
c -= 0.5 * b;
f -= 0.5 * d;
f -= 0.5 * e;
double geoTransform[6] = { c, a, b, f, d, e };
GDALSetGeoTransform( outputDS.get(), geoTransform );
GDALSetProjection( outputDS.get(), mMapSettings.destinationCrs().toWkt().toLocal8Bit().constData() );
}
if ( mExportMetadata )
{
QString creationDateString;
const QDateTime creationDateTime = mGeoPdfExportDetails.creationDateTime;
if ( creationDateTime.isValid() )
{
creationDateString = QStringLiteral( "D:%1" ).arg( mGeoPdfExportDetails.creationDateTime.toString( QStringLiteral( "yyyyMMddHHmmss" ) ) );
if ( creationDateTime.timeZone().isValid() )
{
int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
creationDateString += ( offsetFromUtc >= 0 ) ? '+' : '-';
offsetFromUtc = std::abs( offsetFromUtc );
int offsetHours = offsetFromUtc / 3600;
int offsetMins = ( offsetFromUtc % 3600 ) / 60;
creationDateString += QStringLiteral( "%1'%2'" ).arg( offsetHours ).arg( offsetMins );
}
}
GDALSetMetadataItem( outputDS.get(), "CREATION_DATE", creationDateString.toLocal8Bit().constData(), nullptr );
GDALSetMetadataItem( outputDS.get(), "AUTHOR", mGeoPdfExportDetails.author.toLocal8Bit().constData(), nullptr );
const QString creator = QStringLiteral( "QGIS %1" ).arg( Qgis::QGIS_VERSION );
GDALSetMetadataItem( outputDS.get(), "CREATOR", creator.toLocal8Bit().constData(), nullptr );
GDALSetMetadataItem( outputDS.get(), "PRODUCER", creator.toLocal8Bit().constData(), nullptr );
GDALSetMetadataItem( outputDS.get(), "SUBJECT", mGeoPdfExportDetails.subject.toLocal8Bit().constData(), nullptr );
GDALSetMetadataItem( outputDS.get(), "TITLE", mGeoPdfExportDetails.title.toLocal8Bit().constData(), nullptr );
const QgsAbstractMetadataBase::KeywordMap keywords = mGeoPdfExportDetails.keywords;
QStringList allKeywords;
for ( auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
{
allKeywords.append( QStringLiteral( "%1: %2" ).arg( it.key(), it.value().join( ',' ) ) );
}
const QString keywordString = allKeywords.join( ';' );
GDALSetMetadataItem( outputDS.get(), "KEYWORDS", keywordString.toLocal8Bit().constData(), nullptr );
}
}
CPLSetThreadLocalConfigOption( "GDAL_PDF_DPI", nullptr );
}

View File

@ -32,6 +32,7 @@
#ifndef QT_NO_PRINTER
#include <QPrinter>
#endif
class QgsMapRendererCustomPainterJob;
class QgsAbstractGeoPdfExporter;
@ -98,6 +99,11 @@ class CORE_EXPORT QgsMapRendererTask : public QgsTask
*/
void setSaveWorldFile( bool save ) { mSaveWorldFile = save; }
/**
* Sets whether metadata such as title and subject will be exported whenever possible.
*/
void setExportMetadata( bool exportMetadata ) { mExportMetadata = exportMetadata; }
void cancel() override;
signals:
@ -144,6 +150,7 @@ class CORE_EXPORT QgsMapRendererTask : public QgsTask
QString mFileFormat;
bool mForceRaster = false;
bool mSaveWorldFile = false;
bool mExportMetadata = false;
bool mGeoPDF = false;
QgsAbstractGeoPdfExporter::ExportDetails mGeoPdfExportDetails;

View File

@ -33,6 +33,16 @@
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QCheckBox" name="mExportMetadataCheckBox">
<property name="text">
<string>Export RDF metadata (title, author, etc.)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QgsScaleWidget" name="mScaleWidget" native="true"/>
</item>
@ -46,7 +56,7 @@
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<item row="9" column="0" colspan="2">
<widget class="QGroupBox" name="mGeoPDFGroupBox">
<property name="title">
<string>Create Geospatial PDF (GeoPDF)</string>
@ -100,16 +110,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="mExportMetadataCheckBox">
<property name="text">
<string>Export RDF metadata (title, author, etc.)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mGeoPdfFormatComboBox"/>
</item>
@ -120,7 +120,7 @@
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="mExportGeoPdfFeaturesCheckBox">
<property name="text">
<string>Include vector feature information</string>
@ -137,7 +137,7 @@
</layout>
</widget>
</item>
<item row="9" column="0" colspan="2">
<item row="10" column="0" colspan="2">
<widget class="QgsCollapsibleGroupBox" name="mAdvancedPdfSettings">
<property name="title">
<string>Advanced Settings</string>
@ -329,7 +329,7 @@ Rasterizing the map is recommended when such effects are used.</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="2">
<item row="11" column="0" colspan="2">
<widget class="QLabel" name="mInfo">
<property name="wordWrap">
<bool>true</bool>