21#include "moc_qgsmaprenderertask.cpp" 
   32#include <QImageWriter> 
   47    QgsMapRendererTaskGeospatialPdfExporter( 
const QgsMapSettings &ms )
 
   50      const QList< QgsMapLayer * > layers = ms.
layers();
 
   53        VectorComponentDetail detail;
 
   54        detail.name = layer->name();
 
   55        detail.mapLayerId = layer->id();
 
   56        if ( 
const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) )
 
   58          detail.displayAttribute = vl->displayField();
 
   60        mLayerDetails[ layer->id() ] = detail;
 
   68      return mLayerDetails.value( layerId );
 
   71    QMap< QString, VectorComponentDetail > mLayerDetails;
 
   79    QgsMapRendererTaskRenderedFeatureHandler( QgsMapRendererTaskGeospatialPdfExporter *exporter, 
const QgsMapSettings &settings )
 
   80      : mExporter( exporter )
 
   81      , mMapSettings( settings )
 
   84      const double pageHeightPdfUnits = settings.
outputSize().height() * 72.0 / settings.
outputDpi();
 
   85      mTransform = QTransform::fromTranslate( 0, pageHeightPdfUnits ).scale( 72.0 / mMapSettings.outputDpi(), -72.0 / mMapSettings.outputDpi() );
 
  111    QgsMapRendererTaskGeospatialPdfExporter *mExporter = 
nullptr;
 
  114    QTransform mTransform;
 
  122  : 
QgsTask( fileFormat == QLatin1String( 
"PDF" ) ? tr( 
"Saving as PDF" ) : tr( 
"Saving as image" ), flags )
 
  124  , mFileName( fileName )
 
  125  , mFileFormat( fileFormat )
 
  126  , mForceRaster( forceRaster )
 
  128  , mGeospatialPdfExportDetails( geospatialPdfExportDetails )
 
 
  140  : 
QgsTask( tr( 
"Rendering to painter" ) )
 
 
  151  qDeleteAll( mAnnotations );
 
  152  mAnnotations.clear();
 
  154  const auto constAnnotations = annotations;
 
  157    mAnnotations << a->clone();
 
 
  163  mDecorations = decorations;
 
 
  171    mJob->cancelWithoutBlocking();
 
 
  182  if ( mGeospatialPDF )
 
  184    QList< QgsAbstractGeospatialPdfExporter::ComponentLayerDetail > pdfComponents;
 
  192      component.
name = QStringLiteral( 
"layer_%1" ).arg( outputLayer );
 
  196      component.
sourcePdfPath = mGeospatialPdfExporter->generateTemporaryFilepath( QStringLiteral( 
"layer_%1.pdf" ).arg( outputLayer ) );
 
  197      pdfComponents << component;
 
  200      pdfWriter.setPageOrientation( QPageLayout::Orientation::Portrait );
 
  202      const QSizeF outputSize = mMapSettings.
outputSize();
 
  203      const QPageSize pageSize( outputSize  * 25.4 / mMapSettings.
outputDpi(), QPageSize::Unit::Millimeter );
 
  204      pdfWriter.setPageSize( pageSize );
 
  205      pdfWriter.setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
 
  206      pdfWriter.setResolution( 
static_cast<int>( mMapSettings.
outputDpi() ) );
 
  208      QPainter p( &pdfWriter );
 
  216    const double pageWidthMM = mMapSettings.
outputSize().width() * 25.4 / mMapSettings.
outputDpi();
 
  217    const double pageHeightMM = mMapSettings.
outputSize().height() * 25.4 / mMapSettings.
outputDpi();
 
  218    exportDetails.
pageSizeMm = QSizeF( pageWidthMM, pageHeightMM );
 
  224    if ( mSaveWorldFile )
 
  238    const bool res = mGeospatialPdfExporter->finalize( pdfComponents, mFileName, exportDetails );
 
  239    mGeospatialPdfExporter.reset();
 
  240    mTempPainter.reset();
 
  248  mJob.reset( 
nullptr );
 
  257  const auto constMDecorations = mDecorations;
 
  260    decoration->render( mMapSettings, context );
 
  263  const auto constMAnnotations = mAnnotations;
 
  269    if ( !annotation || !annotation->isVisible() )
 
  273    if ( annotation->mapLayer() && !mMapSettings.
layers().contains( annotation->mapLayer() ) )
 
  282    if ( annotation->hasFixedMapPosition() )
 
  289      itemX = annotation->relativePosition().x() * mMapSettings.
outputSize().width();
 
  290      itemY = annotation->relativePosition().y() * mMapSettings.
outputSize().height();
 
  293    context.
painter()->translate( itemX, itemY );
 
  295    annotation->render( context );
 
  298  if ( !mFileName.isEmpty() )
 
  302    if ( mFileFormat == QLatin1String( 
"PDF" ) )
 
  307        pp.begin( mPdfWriter.get() );
 
  308        const QRectF rect( 0, 0, mImage.width(), mImage.height() );
 
  309        pp.drawImage( rect, mImage, rect );
 
  313      if ( mSaveWorldFile || mExportMetadata )
 
  315        CPLSetThreadLocalConfigOption( 
"GDAL_PDF_DPI", QString::number( mMapSettings.
outputDpi() ).toLocal8Bit().constData() );
 
  319          if ( mSaveWorldFile )
 
  321            double a, b, 
c, d, e, f;
 
  327            double geoTransform[6] = { 
c, a, b, f, d, e };
 
  328            GDALSetGeoTransform( outputDS.get(), geoTransform );
 
  332          if ( mExportMetadata )
 
  334            QString creationDateString;
 
  335            const QDateTime creationDateTime = mGeospatialPdfExportDetails.
creationDateTime;
 
  336            if ( creationDateTime.isValid() )
 
  338              creationDateString = QStringLiteral( 
"D:%1" ).arg( mGeospatialPdfExportDetails.
creationDateTime.toString( QStringLiteral( 
"yyyyMMddHHmmss" ) ) );
 
  339              if ( creationDateTime.timeZone().isValid() )
 
  341                int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
 
  342                creationDateString += ( offsetFromUtc >= 0 ) ? 
'+' : 
'-';
 
  343                offsetFromUtc = std::abs( offsetFromUtc );
 
  344                const int offsetHours = offsetFromUtc / 3600;
 
  345                const int offsetMins = ( offsetFromUtc % 3600 ) / 60;
 
  346                creationDateString += QStringLiteral( 
"%1'%2'" ).arg( offsetHours ).arg( offsetMins );
 
  349            GDALSetMetadataItem( outputDS.get(), 
"CREATION_DATE", creationDateString.toUtf8().constData(), 
nullptr );
 
  351            GDALSetMetadataItem( outputDS.get(), 
"AUTHOR", mGeospatialPdfExportDetails.
author.toUtf8().constData(), 
nullptr );
 
  352            const QString creator = QStringLiteral( 
"QGIS %1" ).arg( 
Qgis::version() );
 
  353            GDALSetMetadataItem( outputDS.get(), 
"CREATOR", creator.toUtf8().constData(), 
nullptr );
 
  354            GDALSetMetadataItem( outputDS.get(), 
"PRODUCER", creator.toUtf8().constData(), 
nullptr );
 
  355            GDALSetMetadataItem( outputDS.get(), 
"SUBJECT", mGeospatialPdfExportDetails.
subject.toUtf8().constData(), 
nullptr );
 
  356            GDALSetMetadataItem( outputDS.get(), 
"TITLE", mGeospatialPdfExportDetails.
title.toUtf8().constData(), 
nullptr );
 
  359            QStringList allKeywords;
 
  360            for ( 
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
 
  362              allKeywords.append( QStringLiteral( 
"%1: %2" ).arg( it.key(), it.value().join( 
',' ) ) );
 
  364            const QString keywordString = allKeywords.join( 
';' );
 
  365            GDALSetMetadataItem( outputDS.get(), 
"KEYWORDS", keywordString.toUtf8().constData(), 
nullptr );
 
  368        CPLSetThreadLocalConfigOption( 
"GDAL_PDF_DPI", 
nullptr );
 
  371    else if ( mFileFormat != QLatin1String( 
"PDF" ) )
 
  373      QImageWriter writer( mFileName, mFileFormat.toLocal8Bit().data() );
 
  374      if ( mFileFormat.compare( QLatin1String( 
"TIF" ), Qt::CaseInsensitive ) == 0 || mFileFormat.compare( QLatin1String( 
"TIFF" ), Qt::CaseInsensitive ) == 0 )
 
  377        writer.setCompression( 1 );
 
  379      const bool success = writer.write( mImage );
 
  386      if ( mSaveWorldFile )
 
  388        const QFileInfo info  = QFileInfo( mFileName );
 
  391        const QString outputSuffix = info.suffix();
 
  392        bool skipWorldFile = 
false;
 
  393        if ( outputSuffix.compare( QLatin1String( 
"TIF" ), Qt::CaseInsensitive ) == 0 || outputSuffix.compare( QLatin1String( 
"TIFF" ), Qt::CaseInsensitive ) == 0 )
 
  398            skipWorldFile = 
true;
 
  399            double a, b, 
c, d, e, f;
 
  405            double geoTransform[] = { 
c, a, b, f, d, e };
 
  406            GDALSetGeoTransform( outputDS.get(), geoTransform );
 
  411        if ( !skipWorldFile )
 
  413          const QString worldFileName = info.absolutePath() + 
'/' + info.completeBaseName() + 
'.' 
  414                                        + outputSuffix.at( 0 ) + outputSuffix.at( info.suffix().size() - 1 ) + 
'w';
 
  415          QFile worldFile( worldFileName );
 
  417          if ( worldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) 
 
  419            QTextStream stream( &worldFile );
 
  427  mTempPainter.reset();
 
 
  435  qDeleteAll( mAnnotations );
 
  436  mAnnotations.clear();
 
 
  444void QgsMapRendererTask::prepare()
 
  446  if ( mGeospatialPDF )
 
  448    mGeospatialPdfExporter = std::make_unique< QgsMapRendererTaskGeospatialPdfExporter >( mMapSettings );
 
  451      mRenderedFeatureHandler = std::make_unique< QgsMapRendererTaskRenderedFeatureHandler >( 
static_cast< QgsMapRendererTaskGeospatialPdfExporter * 
>( mGeospatialPdfExporter.get() ), mMapSettings );
 
  455    const QList< QgsMapLayer * > layers = mMapSettings.
layers();
 
  458      mLayerIdToLayerNameMap.insert( layer->id(), layer->name() );
 
  459      mMapLayerOrder << layer->id();
 
  467  mDestPainter = mPainter;
 
  469  if ( mFileFormat == QLatin1String( 
"PDF" ) )
 
  471    mPdfWriter.reset( 
new QPdfWriter( mFileName ) );
 
  472    mPdfWriter->setPageOrientation( QPageLayout::Orientation::Portrait );
 
  474    const QSizeF outputSize = mMapSettings.
outputSize();
 
  475    const QPageSize pageSize( outputSize  * 25.4 / mMapSettings.
outputDpi(), QPageSize::Unit::Millimeter );
 
  476    mPdfWriter->setPageSize( pageSize );
 
  477    mPdfWriter->setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
 
  478    mPdfWriter->setResolution( 
static_cast<int>( mMapSettings.
outputDpi() ) );
 
  482      mTempPainter.reset( 
new QPainter( mPdfWriter.get() ) );
 
  483      mDestPainter = mTempPainter.get();
 
  491    if ( mImage.isNull() )
 
  499    mImage.setDotsPerMeterX( 1000 * mMapSettings.
outputDpi() / 25.4 );
 
  500    mImage.setDotsPerMeterY( 1000 * mMapSettings.
outputDpi() / 25.4 );
 
  502    mTempPainter.reset( 
new QPainter( &mImage ) );
 
  503    mDestPainter = mTempPainter.get();
 
static QString version()
Version string.
 
@ PreferredGdal
Preferred format for conversion of CRS to WKT for use with the GDAL library.
 
Abstract base class for Geospatial PDF exporters.
 
Abstract base class for annotation items which are drawn over a map.
 
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
 
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
 
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
A geometry is the spatial representation of a feature.
 
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
 
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
 
Interface for map decorations.
 
Base class for all map layer types.
 
Job implementation that renders everything sequentially using a custom painter.
 
Render job implementation that renders maps in stages, allowing different stages (e....
 
double currentLayerOpacity() const
Returns the opacity for the current layer about to be rendered in the next render operation.
 
@ RenderLabelsByMapLayer
Labels should be rendered in individual stages by map layer. This allows separation of labels belongi...
 
QPainter::CompositionMode currentLayerCompositionMode() const
Returns the composition mode for the current layer about to be rendered in the next render operation.
 
QString currentLayerId() const
Returns the ID of the current layer about to be rendered in the next render operation.
 
bool isFinished() const
Returns true if the job is finished, and nothing remains to render.
 
bool nextPart()
Iterates to the next part to render.
 
bool renderCurrentPart(QPainter *painter)
Renders the current part of the map to the specified painter.
 
void addDecorations(const QList< QgsMapDecoration * > &decorations)
Adds decorations to be rendered on the map.
 
bool run() override
Performs the task's operation.
 
void errorOccurred(int error)
Emitted when map rendering failed.
 
@ ImageSaveFail
Image save failure.
 
@ ImageAllocationFail
Image allocation failure.
 
QgsMapRendererTask(const QgsMapSettings &ms, const QString &fileName, const QString &fileFormat=QString("PNG"), bool forceRaster=false, QgsTask::Flags flags=QgsTask::CanCancel, bool geospatialPdf=false, const QgsAbstractGeospatialPdfExporter::ExportDetails &geospatialPdfExportDetails=QgsAbstractGeospatialPdfExporter::ExportDetails())
Constructor for QgsMapRendererTask to render a map to an image file.
 
void addAnnotations(const QList< QgsAnnotation * > &annotations)
Adds annotations to be rendered on the map.
 
void finished(bool result) override
If the task is managed by a QgsTaskManager, this will be called after the task has finished (whether ...
 
~QgsMapRendererTask() override
 
void cancel() override
Notifies the task that it should terminate.
 
void renderingComplete()
Emitted when the map rendering is successfully completed.
 
static void worldFileParameters(const QgsMapSettings &mapSettings, double &a, double &b, double &c, double &d, double &e, double &f)
Computes the six parameters of a world file.
 
static QString worldFileContent(const QgsMapSettings &mapSettings)
Creates the content of a world file.
 
Contains configuration for rendering maps.
 
QList< QgsMapLayer * > layers(bool expandGroupLayers=false) const
Returns the list of layers which will be rendered in the map.
 
void addRenderedFeatureHandler(QgsRenderedFeatureHandlerInterface *handler)
Adds a rendered feature handler to use while rendering the map settings.
 
void setDevicePixelRatio(float dpr)
Sets the device pixel ratio.
 
void setOutputDpi(double dpi)
Sets the dpi (dots per inch) used for conversion between real world units (e.g.
 
const QgsMapToPixel & mapToPixel() const
 
float devicePixelRatio() const
Returns the device pixel ratio.
 
QSize outputSize() const
Returns the size of the resulting map image, in pixels.
 
QgsRectangle extent() const
Returns geographical coordinates of the rectangle that should be rendered.
 
double outputDpi() const
Returns the DPI (dots per inch) used for conversion between real world units (e.g.
 
void setOutputSize(QSize size)
Sets the size of the resulting map image, in pixels.
 
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
 
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
 
A rectangle specified with double values.
 
Contains information about the context of a rendering operation.
 
QPainter * painter()
Returns the destination QPainter for the render operation.
 
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
 
QgsExpressionContext & expressionContext()
Gets the expression context.
 
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
 
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
 
An interface for classes which provide custom handlers for features rendered as part of a map render ...
 
virtual QSet< QString > usedAttributes(QgsVectorLayer *layer, const QgsRenderContext &context) const
Returns a list of attributes required by this handler, for the specified layer.
 
virtual void handleRenderedFeature(const QgsFeature &feature, const QgsGeometry &renderedBounds, const QgsRenderedFeatureHandlerInterface::RenderedFeatureContext &context)=0
Called whenever a feature is rendered during a map render job.
 
Scoped object for saving and restoring a QPainter object's state.
 
Abstract base class for long running background tasks.
 
virtual void cancel()
Notifies the task that it should terminate.
 
bool isCanceled() const
Will return true if task should terminate ASAP.
 
Represents a vector layer which manages a vector based dataset.
 
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
 
Contains details of a particular input component to be used during PDF composition.
 
QString mapLayerId
Associated map layer ID, or an empty string if this component layer is not associated with a map laye...
 
double opacity
Component opacity.
 
QString name
User-friendly name for the generated PDF layer.
 
QPainter::CompositionMode compositionMode
Component composition mode.
 
QString sourcePdfPath
File path to the (already created) PDF to use as the source for this component layer.
 
Contains details of a control point used during georeferencing Geospatial PDF outputs.
 
QList< QgsAbstractGeospatialPdfExporter::GeoReferencedSection > georeferencedSections
List of georeferenced sections.
 
QStringList layerOrder
Optional list of layer IDs, in the order desired to appear in the generated Geospatial PDF file.
 
QMap< QString, QString > layerIdToPdfLayerTreeNameMap
Optional map of map layer ID to custom layer tree name to show in the created PDF file.
 
QgsAbstractMetadataBase::KeywordMap keywords
Metadata keyword map.
 
QSizeF pageSizeMm
Page size, in millimeters.
 
QString author
Metadata author tag.
 
QString subject
Metadata subject tag.
 
QString title
Metadata title tag.
 
QDateTime creationDateTime
Metadata creation datetime.
 
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.
 
QList< QgsAbstractGeospatialPdfExporter::ControlPoint > controlPoints
List of control points corresponding to this georeferenced section.
 
Contains information about a feature rendered inside the PDF.
 
Contains information relating to a single PDF layer in the Geospatial PDF export.
 
const QgsRenderContext & renderContext
The render context which was used while rendering feature.