31 #include <QTextStream> 49 const QList< QgsMapLayer * > layers = ms.
layers();
52 VectorComponentDetail detail;
53 detail.name = layer->name();
54 detail.mapLayerId = layer->id();
55 if (
const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer ) )
57 detail.displayAttribute = vl->displayField();
59 mLayerDetails[ layer->id() ] = detail;
67 return mLayerDetails.value( layerId );
70 QMap< QString, VectorComponentDetail > mLayerDetails;
78 QgsMapRendererTaskRenderedFeatureHandler( QgsMapRendererTaskGeoPdfExporter *exporter,
const QgsMapSettings &settings )
79 : mExporter( exporter )
80 , mMapSettings( settings )
83 const double pageHeightPdfUnits = settings.
outputSize().height() * 72.0 / settings.
outputDpi();
84 mTransform = QTransform::fromTranslate( 0, pageHeightPdfUnits ).scale( 72.0 / mMapSettings.outputDpi(), -72.0 / mMapSettings.outputDpi() );
110 QgsMapRendererTaskGeoPdfExporter *mExporter =
nullptr;
113 QTransform mTransform;
121 :
QgsTask( fileFormat == QStringLiteral(
"PDF" ) ? tr(
"Saving as PDF" ) : tr(
"Saving as image" ) )
123 , mFileName( fileName )
124 , mFileFormat( fileFormat )
125 , mForceRaster( forceRaster )
127 , mGeoPdfExportDetails( geoPdfExportDetails )
133 :
QgsTask( tr(
"Rendering to painter" ) )
144 qDeleteAll( mAnnotations );
145 mAnnotations.clear();
147 const auto constAnnotations = annotations;
150 mAnnotations << a->clone();
156 mDecorations = decorations;
164 mJob->cancelWithoutBlocking();
180 QList< QgsAbstractGeoPdfExporter::ComponentLayerDetail > pdfComponents;
187 component.
name = QStringLiteral(
"layer_%1" ).arg( outputLayer );
189 component.
sourcePdfPath = mGeoPdfExporter->generateTemporaryFilepath( QStringLiteral(
"layer_%1.pdf" ).arg( outputLayer ) );
190 pdfComponents << component;
193 printer.setOutputFileName( component.sourcePdfPath );
194 printer.setOutputFormat( QPrinter::PdfFormat );
195 printer.setOrientation( QPrinter::Portrait );
197 QSizeF outputSize = mMapSettings.
outputSize();
198 printer.setPaperSize( outputSize * 25.4 / mMapSettings.
outputDpi(), QPrinter::Millimeter );
199 printer.setPageMargins( 0, 0, 0, 0, QPrinter::Millimeter );
200 printer.setResolution( mMapSettings.
outputDpi() );
202 QPainter p( &printer );
210 const double pageWidthMM = mMapSettings.
outputSize().width() * 25.4 / mMapSettings.
outputDpi();
211 const double pageHeightMM = mMapSettings.
outputSize().height() * 25.4 / mMapSettings.
outputDpi();
212 exportDetails.
pageSizeMm = QSizeF( pageWidthMM, pageHeightMM );
215 if ( mSaveWorldFile )
229 const bool res = mGeoPdfExporter->finalize( pdfComponents, mFileName, exportDetails );
230 mGeoPdfExporter.reset();
231 mTempPainter.reset();
240 mJob.reset(
nullptr );
249 const auto constMDecorations = mDecorations;
252 decoration->render( mMapSettings, context );
255 const auto constMAnnotations = mAnnotations;
261 if ( !annotation || !annotation->isVisible() )
265 if ( annotation->mapLayer() && !mMapSettings.
layers().contains( annotation->mapLayer() ) )
274 if ( annotation->hasFixedMapPosition() )
281 itemX = annotation->relativePosition().x() * mMapSettings.
outputSize().width();
282 itemY = annotation->relativePosition().y() * mMapSettings.
outputSize().height();
285 context.
painter()->translate( itemX, itemY );
287 annotation->render( context );
291 if ( !mFileName.isEmpty() )
295 if ( mFileFormat == QStringLiteral(
"PDF" ) )
297 #ifndef QT_NO_PRINTER 301 pp.begin( mPrinter.get() );
302 QRectF rect( 0, 0, mImage.width(), mImage.height() );
303 pp.drawImage( rect, mImage, rect );
307 if ( mSaveWorldFile || mExportMetadata )
309 CPLSetThreadLocalConfigOption(
"GDAL_PDF_DPI", QString::number( mMapSettings.
outputDpi() ).toLocal8Bit().constData() );
313 if ( mSaveWorldFile )
315 double a, b,
c, d, e, f;
321 double geoTransform[6] = {
c, a, b, f, d, e };
322 GDALSetGeoTransform( outputDS.get(), geoTransform );
323 GDALSetProjection( outputDS.get(), mMapSettings.
destinationCrs().
toWkt().toLocal8Bit().constData() );
326 if ( mExportMetadata )
328 QString creationDateString;
330 if ( creationDateTime.isValid() )
332 creationDateString = QStringLiteral(
"D:%1" ).arg( mGeoPdfExportDetails.
creationDateTime.toString( QStringLiteral(
"yyyyMMddHHmmss" ) ) );
333 if ( creationDateTime.timeZone().isValid() )
335 int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
336 creationDateString += ( offsetFromUtc >= 0 ) ?
'+' :
'-';
337 offsetFromUtc = std::abs( offsetFromUtc );
338 int offsetHours = offsetFromUtc / 3600;
339 int offsetMins = ( offsetFromUtc % 3600 ) / 60;
340 creationDateString += QStringLiteral(
"%1'%2'" ).arg( offsetHours ).arg( offsetMins );
343 GDALSetMetadataItem( outputDS.get(),
"CREATION_DATE", creationDateString.toLocal8Bit().constData(), nullptr );
345 GDALSetMetadataItem( outputDS.get(),
"AUTHOR", mGeoPdfExportDetails.
author.toLocal8Bit().constData(), nullptr );
347 GDALSetMetadataItem( outputDS.get(),
"CREATOR", creator.toLocal8Bit().constData(), nullptr );
348 GDALSetMetadataItem( outputDS.get(),
"PRODUCER", creator.toLocal8Bit().constData(), nullptr );
349 GDALSetMetadataItem( outputDS.get(),
"SUBJECT", mGeoPdfExportDetails.
subject.toLocal8Bit().constData(), nullptr );
350 GDALSetMetadataItem( outputDS.get(),
"TITLE", mGeoPdfExportDetails.
title.toLocal8Bit().constData(), nullptr );
353 QStringList allKeywords;
354 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
356 allKeywords.append( QStringLiteral(
"%1: %2" ).arg( it.key(), it.value().join(
',' ) ) );
358 const QString keywordString = allKeywords.join(
';' );
359 GDALSetMetadataItem( outputDS.get(),
"KEYWORDS", keywordString.toLocal8Bit().constData(), nullptr );
362 CPLSetThreadLocalConfigOption(
"GDAL_PDF_DPI",
nullptr );
367 #endif // !QT_NO_PRINTER 369 else if ( mFileFormat != QStringLiteral(
"PDF" ) )
371 bool success = mImage.save( mFileName, mFileFormat.toLocal8Bit().data() );
378 if ( mSaveWorldFile )
380 QFileInfo info = QFileInfo( mFileName );
383 QString outputSuffix = info.suffix();
384 bool skipWorldFile =
false;
385 if ( outputSuffix == QStringLiteral(
"tif" ) || outputSuffix == QStringLiteral(
"tiff" ) )
390 skipWorldFile =
true;
391 double a, b,
c, d, e, f;
397 double geoTransform[] = {
c, a, b, f, d, e };
398 GDALSetGeoTransform( outputDS.get(), geoTransform );
399 GDALSetProjection( outputDS.get(), mMapSettings.
destinationCrs().
toWkt().toLocal8Bit().constData() );
403 if ( !skipWorldFile )
405 QString worldFileName = info.absolutePath() +
'/' + info.baseName() +
'.' 406 + outputSuffix.at( 0 ) + outputSuffix.at( info.suffix().size() - 1 ) +
'w';
407 QFile worldFile( worldFileName );
409 if ( worldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
411 QTextStream stream( &worldFile );
419 mTempPainter.reset();
420 #ifndef QT_NO_PRINTER 429 qDeleteAll( mAnnotations );
430 mAnnotations.clear();
438 void QgsMapRendererTask::prepare()
442 mGeoPdfExporter = qgis::make_unique< QgsMapRendererTaskGeoPdfExporter >( mMapSettings );
445 mRenderedFeatureHandler = qgis::make_unique< QgsMapRendererTaskRenderedFeatureHandler >(
static_cast< QgsMapRendererTaskGeoPdfExporter *
>( mGeoPdfExporter.get() ), mMapSettings );
453 mDestPainter = mPainter;
455 if ( mFileFormat == QStringLiteral(
"PDF" ) )
457 #ifndef QT_NO_PRINTER 458 mPrinter.reset(
new QPrinter() );
459 mPrinter->setOutputFileName( mFileName );
460 mPrinter->setOutputFormat( QPrinter::PdfFormat );
461 mPrinter->setOrientation( QPrinter::Portrait );
463 QSizeF outputSize = mMapSettings.
outputSize();
464 mPrinter->setPaperSize( outputSize * 25.4 / mMapSettings.
outputDpi(), QPrinter::Millimeter );
465 mPrinter->setPageMargins( 0, 0, 0, 0, QPrinter::Millimeter );
466 mPrinter->setResolution( mMapSettings.
outputDpi() );
470 mTempPainter.reset(
new QPainter( mPrinter.get() ) );
471 mDestPainter = mTempPainter.get();
475 #endif // ! QT_NO_PRINTER 481 mImage = QImage( mMapSettings.
outputSize(), QImage::Format_ARGB32 );
482 if ( mImage.isNull() )
489 mImage.setDotsPerMeterX( 1000 * mMapSettings.
outputDpi() / 25.4 );
490 mImage.setDotsPerMeterY( 1000 * mMapSettings.
outputDpi() / 25.4 );
492 mTempPainter.reset(
new QPainter( &mImage ) );
493 mDestPainter = mTempPainter.get();
Abstract base class for GeoPDF exporters.
QList< QgsAbstractGeoPdfExporter::GeoReferencedSection > georeferencedSections
List of georeferenced sections.
bool includeFeatures
true if feature vector information (such as attributes) should be exported.
void addAnnotations(const QList< QgsAnnotation *> &annotations)
Adds annotations to be rendered on the map.
const QgsRenderContext & renderContext
The render context which was used while rendering feature.
A rectangle specified with double values.
Base class for all map layer types.
Job implementation that renders everything sequentially using a custom painter.
bool run() override
Performs the task's operation.
static const QString QGIS_VERSION
Version string.
QString author
Metadata author tag.
QString currentLayerId()
Returns the ID of the current layer about to be rendered in the next render operation.
QString mapLayerId
Associated map layer ID, or an empty string if this component layer is not associated with a map laye...
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Use antialiasing while drawing.
Interface for map decorations.
A class to represent a 2D point.
QgsAbstractMetadataBase::KeywordMap keywords
Metadata keyword map.
A geometry is the spatial representation of a feature.
Flags flags() const
Returns combination of flags used for rendering.
QSizeF pageSizeMm
Page size, in millimeters.
QList< QgsMapLayer * > layers() const
Gets list of layers for map rendering The layers are stored in the reverse order of how they are rend...
bool isCanceled() const
Will return true if task should terminate ASAP.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
void addDecorations(const QList< QgsMapDecoration *> &decorations)
Adds decorations to be rendered on the map.
static QString worldFileContent(const QgsMapSettings &mapSettings)
Creates the content of a world file.
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
Abstract base class for annotation items which are drawn over a map.
QDateTime creationDateTime
Metadata creation datetime.
The QgsMapSettings class contains configuration for rendering of the map.
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
Contains details of a control point used during georeferencing GeoPDF outputs.
QgsRectangle extent() const
Returns geographical coordinates of the rectangle that should be rendered.
bool nextPart()
Iterates to the next part to render.
QgsMapRendererTask(const QgsMapSettings &ms, const QString &fileName, const QString &fileFormat=QString("PNG"), bool forceRaster=false, bool geoPdf=false, const QgsAbstractGeoPdfExporter::ExportDetails &geoPdfExportDetails=QgsAbstractGeoPdfExporter::ExportDetails())
Constructor for QgsMapRendererTask to render a map to an image file.
double width() const
Returns the width of the rectangle.
QList< QgsAbstractGeoPdfExporter::ControlPoint > controlPoints
List of control points corresponding to this georeferenced section.
QgsCoordinateReferenceSystem crs
Coordinate reference system for georeferenced section.
An interface for classes which provider custom handlers for features rendered as part of a map render...
Contains information about a feature rendered inside the PDF.
Abstract base class for long running background tasks.
Render job implementation that renders maps in stages, allowing different stages (e.g.
QString subject
Metadata subject tag.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
static const QString ALL_ATTRIBUTES
A special attribute that if set matches all attributes.
Contains information relating to a single PDF layer in the GeoPDF export.
QgsRectangle pageBoundsMm
Bounds of the georeferenced section on the page, in millimeters.
const QgsMapToPixel & mapToPixel() const
Format is unsupported on the platform.
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.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Contains details of a particular input component to be used during PDF composition.
QgsExpressionContext & expressionContext()
Gets the expression context.
virtual void cancel()
Notifies the task that it should terminate.
double outputDpi() const
Returns DPI used for conversion between real world units (e.g.
void finished(bool result) override
If the task is managed by a QgsTaskManager, this will be called after the task has finished (whether ...
Contains information about the context of a rendering operation.
void errorOccurred(int error)
Emitted when map rendering failed.
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
QPainter * painter()
Returns the destination QPainter for the render operation.
QString name
User-friendly name for the generated PDF layer.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
~QgsMapRendererTask() override
void cancel() override
Notifies the task that it should terminate.
bool renderCurrentPart(QPainter *painter)
Renders the current part of the map to the specified painter.
QString title
Metadata title tag.
Image allocation failure.
QString sourcePdfPath
File path to the (already created) PDF to use as the source for this component layer.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
bool isFinished()
Returns true if the job is finished, and nothing remains to render.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
void addRenderedFeatureHandler(QgsRenderedFeatureHandlerInterface *handler)
Adds a rendered feature handler to use while rendering the map settings.
Represents a vector layer which manages a vector based data sets.
QSize outputSize() const
Returns the size of the resulting map image.
QgsPointXY toMapCoordinates(int x, int y) const
Transform device coordinates to map (world) coordinates.
void renderingComplete()
Emitted when the map rendering is successfully completed.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
double height() const
Returns the height of the rectangle.
Labels should be rendered in individual stages by map layer. This allows separation of labels belongi...