33#include <QImageWriter>
35#include <QSvgGenerator>
44class LayoutContextPreviewSettingRestorer
48 LayoutContextPreviewSettingRestorer(
QgsLayout *layout )
50 , mPreviousSetting( layout->renderContext().mIsPreviewRender )
52 mLayout->renderContext().mIsPreviewRender =
false;
55 ~LayoutContextPreviewSettingRestorer()
57 mLayout->renderContext().mIsPreviewRender = mPreviousSetting;
60 LayoutContextPreviewSettingRestorer(
const LayoutContextPreviewSettingRestorer &other ) =
delete;
61 LayoutContextPreviewSettingRestorer &operator=(
const LayoutContextPreviewSettingRestorer &other ) =
delete;
65 bool mPreviousSetting =
false;
75 const QList< QgsLayoutGuide * > guides = mLayout->guides().guides();
78 mPrevVisibility.insert( guide, guide->item()->isVisible() );
79 guide->item()->setVisible(
false );
85 for (
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
87 it.key()->item()->setVisible( it.value() );
91 LayoutGuideHider(
const LayoutGuideHider &other ) =
delete;
92 LayoutGuideHider &operator=(
const LayoutGuideHider &other ) =
delete;
96 QHash< QgsLayoutGuide *, bool > mPrevVisibility;
102 explicit LayoutItemHider(
const QList<QGraphicsItem *> &items )
104 mItemsToIterate.reserve( items.count() );
105 for ( QGraphicsItem *item : items )
107 const bool isVisible = item->isVisible();
108 mPrevVisibility[item] = isVisible;
110 mItemsToIterate.append( item );
112 layoutItem->setProperty(
"wasVisible", isVisible );
120 for (
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
128 for (
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
130 it.key()->setVisible( it.value() );
132 layoutItem->setProperty(
"wasVisible", QVariant() );
136 QList< QGraphicsItem * > itemsToIterate()
const {
return mItemsToIterate; }
138 LayoutItemHider(
const LayoutItemHider &other ) =
delete;
139 LayoutItemHider &operator=(
const LayoutItemHider &other ) =
delete;
143 QList<QGraphicsItem * > mItemsToIterate;
144 QHash<QGraphicsItem *, bool> mPrevVisibility;
161 qDeleteAll( mLabelingResults );
174 if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
185 LayoutContextPreviewSettingRestorer restorer( mLayout );
188 QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
197 if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
208 LayoutContextPreviewSettingRestorer restorer( mLayout );
211 QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
213 const double imageAspectRatio =
static_cast< double >( imageSize.width() ) / imageSize.height();
214 const double paperAspectRatio = paperRect.width() / paperRect.height();
215 if ( imageSize.isValid() && ( !
qgsDoubleNear( imageAspectRatio, paperAspectRatio, 0.008 ) ) )
220 QgsMessageLog::logMessage( QObject::tr(
"Ignoring custom image size because aspect ratio %1 does not match paper ratio %2" ).arg( QString::number( imageAspectRatio,
'g', 3 ), QString::number( paperAspectRatio,
'g', 3 ) ), QStringLiteral(
"Layout" ),
Qgis::MessageLevel::Warning );
228class LayoutItemCacheSettingRestorer
232 LayoutItemCacheSettingRestorer(
QgsLayout *layout )
235 const QList< QGraphicsItem * > items = mLayout->items();
236 for ( QGraphicsItem *item : items )
238 mPrevCacheMode.insert( item, item->cacheMode() );
239 item->setCacheMode( QGraphicsItem::NoCache );
243 ~LayoutItemCacheSettingRestorer()
245 for (
auto it = mPrevCacheMode.constBegin(); it != mPrevCacheMode.constEnd(); ++it )
247 it.key()->setCacheMode( it.value() );
251 LayoutItemCacheSettingRestorer(
const LayoutItemCacheSettingRestorer &other ) =
delete;
252 LayoutItemCacheSettingRestorer &operator=(
const LayoutItemCacheSettingRestorer &other ) =
delete;
256 QHash< QGraphicsItem *, QGraphicsItem::CacheMode > mPrevCacheMode;
263 QPaintDevice *paintDevice = painter->device();
264 if ( !paintDevice || !mLayout )
269 LayoutItemCacheSettingRestorer cacheRestorer( mLayout );
270 ( void )cacheRestorer;
271 LayoutContextPreviewSettingRestorer restorer( mLayout );
273 LayoutGuideHider guideHider( mLayout );
278 mLayout->render( painter, QRectF( 0, 0, paintDevice->width(), paintDevice->height() ), region );
286 LayoutContextPreviewSettingRestorer restorer( mLayout );
289 double resolution = mLayout->renderContext().dpi();
291 if ( imageSize.isValid() )
295 resolution = ( imageSize.width() / region.width()
296 + imageSize.height() / region.height() ) / 2.0 * oneInchInLayoutUnits;
304 int width = imageSize.isValid() ? imageSize.width()
305 :
static_cast< int >( resolution * region.width() / oneInchInLayoutUnits );
306 int height = imageSize.isValid() ? imageSize.height()
307 :
static_cast< int >( resolution * region.height() / oneInchInLayoutUnits );
309 QImage image( QSize( width, height ), QImage::Format_ARGB32 );
310 if ( !image.isNull() )
313 if ( width > 32768 || height > 32768 )
314 QgsMessageLog::logMessage( QObject::tr(
"Error: output width or height is larger than 32768 pixel, result will be clipped" ) );
315 image.setDotsPerMeterX(
static_cast< int >( std::round( resolution / 25.4 * 1000 ) ) );
316 image.setDotsPerMeterY(
static_cast< int>( std::round( resolution / 25.4 * 1000 ) ) );
317 image.fill( Qt::transparent );
318 QPainter imagePainter( &image );
320 if ( !imagePainter.isActive() )
328class LayoutContextSettingsRestorer
333 LayoutContextSettingsRestorer(
QgsLayout *layout )
335 , mPreviousDpi( layout->renderContext().dpi() )
336 , mPreviousFlags( layout->renderContext().flags() )
337 , mPreviousTextFormat( layout->renderContext().textRenderFormat() )
338 , mPreviousExportLayer( layout->renderContext().currentExportLayer() )
339 , mPreviousSimplifyMethod( layout->renderContext().simplifyMethod() )
340 , mPreviousMaskSettings( layout->renderContext().maskSettings() )
341 , mExportThemes( layout->renderContext().exportThemes() )
342 , mPredefinedScales( layout->renderContext().predefinedScales() )
347 ~LayoutContextSettingsRestorer()
349 mLayout->renderContext().setDpi( mPreviousDpi );
350 mLayout->renderContext().setFlags( mPreviousFlags );
351 mLayout->renderContext().setTextRenderFormat( mPreviousTextFormat );
353 mLayout->renderContext().setCurrentExportLayer( mPreviousExportLayer );
355 mLayout->renderContext().setSimplifyMethod( mPreviousSimplifyMethod );
356 mLayout->renderContext().setMaskSettings( mPreviousMaskSettings );
357 mLayout->renderContext().setExportThemes( mExportThemes );
358 mLayout->renderContext().setPredefinedScales( mPredefinedScales );
361 LayoutContextSettingsRestorer(
const LayoutContextSettingsRestorer &other ) =
delete;
362 LayoutContextSettingsRestorer &operator=(
const LayoutContextSettingsRestorer &other ) =
delete;
366 double mPreviousDpi = 0;
369 int mPreviousExportLayer = 0;
372 QStringList mExportThemes;
373 QVector< double > mPredefinedScales;
384 if ( settings.
dpi <= 0 )
385 settings.
dpi = mLayout->renderContext().dpi();
387 mErrorFileName.clear();
389 int worldFilePageNo = -1;
392 worldFilePageNo = referenceMap->page();
395 QFileInfo fi( filePath );
397 if ( !dir.exists( fi.absolutePath() ) )
399 dir.mkpath( fi.absolutePath() );
404 pageDetails.
baseName = fi.completeBaseName();
407 LayoutContextPreviewSettingRestorer restorer( mLayout );
409 LayoutContextSettingsRestorer dpiRestorer( mLayout );
411 mLayout->renderContext().setDpi( settings.
dpi );
412 mLayout->renderContext().setFlags( settings.
flags );
416 if ( settings.
pages.empty() )
418 for (
int page = 0; page < mLayout->pageCollection()->pageCount(); ++page )
423 for (
int page : std::as_const( settings.
pages ) )
425 if ( page >= 0 && page < mLayout->pageCollection()->pageCount() )
430 for (
int page : std::as_const( pages ) )
432 if ( !mLayout->pageCollection()->shouldExportPage( page ) )
439 QImage image = createImage( settings, page, bounds, skip );
444 pageDetails.
page = page;
447 if ( image.isNull() )
449 mErrorFileName = outputFilePath;
453 if ( !saveImage( image, outputFilePath, pageDetails.
extension, settings.
exportMetadata ? mLayout->project() : nullptr ) )
455 mErrorFileName = outputFilePath;
459 const bool shouldGeoreference = ( page == worldFilePageNo );
460 if ( shouldGeoreference )
462 georeferenceOutputPrivate( outputFilePath,
nullptr, bounds, settings.
dpi, shouldGeoreference );
467 double a, b,
c, d, e, f;
468 if ( bounds.isValid() )
473 QFileInfo fi( outputFilePath );
475 QString outputSuffix = fi.suffix();
476 QString worldFileName = fi.absolutePath() +
'/' + fi.completeBaseName() +
'.'
477 + outputSuffix.at( 0 ) + outputSuffix.at( fi.suffix().size() - 1 ) +
'w';
479 writeWorldFile( worldFileName, a, b,
c, d, e, f );
484 captureLabelingResults();
495 int total = iterator->
count();
496 double step = total > 0 ? 100.0 / total : 100.0;
498 while ( iterator->
next() )
503 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
505 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
515 QString filePath = iterator->
filePath( baseFilePath, extension );
520 error = QObject::tr(
"Cannot write to %1. This file may be open in another application or may be an invalid path." ).arg( QDir::toNativeSeparators( filePath ) );
540 if ( !mLayout || mLayout->pageCollection()->pageCount() == 0 )
544 if ( settings.
dpi <= 0 )
545 settings.
dpi = mLayout->renderContext().dpi();
547 mErrorFileName.clear();
549 LayoutContextPreviewSettingRestorer restorer( mLayout );
551 LayoutContextSettingsRestorer contextRestorer( mLayout );
552 ( void )contextRestorer;
553 mLayout->renderContext().setDpi( settings.
dpi );
555 mLayout->renderContext().setMaskSettings( createExportMaskSettings() );
559 mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
562 std::unique_ptr< QgsLayoutGeoPdfExporter > geoPdfExporter;
564 geoPdfExporter = std::make_unique< QgsLayoutGeoPdfExporter >( mLayout );
566 mLayout->renderContext().setFlags( settings.
flags );
579 mLayout->renderContext().setExportThemes( settings.
exportThemes );
591 const QList<QGraphicsItem *> items = mLayout->items( Qt::AscendingOrder );
593 QList< QgsLayoutGeoPdfExporter::ComponentLayerDetail > pdfComponents;
602 component.
name = layerDetail.name;
603 component.
mapLayerId = layerDetail.mapLayerId;
604 component.
opacity = layerDetail.opacity;
606 component.
group = layerDetail.mapTheme;
607 component.
sourcePdfPath = settings.writeGeoPdf ? geoPdfExporter->generateTemporaryFilepath( QStringLiteral(
"layer_%1.pdf" ).arg( layerId ) ) : baseDir.filePath( QStringLiteral(
"%1_%2.pdf" ).arg( baseFileName ).arg( layerId, 4, 10, QChar(
'0' ) ) );
608 pdfComponents << component;
610 preparePrintAsPdf( mLayout, &printer, component.
sourcePdfPath );
611 preparePrint( mLayout, &printer,
false );
613 if ( !p.begin( &printer ) )
621 return layerExportResult;
623 result = handleLayeredExport( items, exportFunc );
627 if ( settings.writeGeoPdf )
630 details.
dpi = settings.dpi;
632 QgsLayoutSize pageSize = mLayout->pageCollection()->page( 0 )->sizeWithUnits();
636 if ( settings.exportMetadata )
639 details.
author = mLayout->project()->metadata().author();
642 details.
creationDateTime = mLayout->project()->metadata().creationDateTime();
643 details.
subject = mLayout->project()->metadata().abstract();
644 details.
title = mLayout->project()->metadata().title();
645 details.
keywords = mLayout->project()->metadata().keywords();
648 const QList< QgsMapLayer * > layers = mLayout->project()->mapLayers().values();
654 if ( settings.appendGeoreference )
657 QList< QgsLayoutItemMap * > maps;
658 mLayout->layoutItems( maps );
662 georef.
crs = map->crs();
664 const QPointF topLeft = map->mapToScene( QPointF( 0, 0 ) );
665 const QPointF topRight = map->mapToScene( QPointF( map->rect().width(), 0 ) );
666 const QPointF bottomLeft = map->mapToScene( QPointF( 0, map->rect().height() ) );
667 const QPointF bottomRight = map->mapToScene( QPointF( map->rect().width(), map->rect().height() ) );
680 const QTransform t = map->layoutToMapCoordsTransform();
681 const QgsPointXY topLeftMap = t.map( topLeft );
682 const QgsPointXY topRightMap = t.map( topRight );
683 const QgsPointXY bottomLeftMap = t.map( bottomLeft );
684 const QgsPointXY bottomRightMap = t.map( bottomRight );
696 details.
layerOrder = geoPdfExporter->layerOrder();
702 if ( !geoPdfExporter->finalize( pdfComponents, filePath, details ) )
705 mErrorMessage = geoPdfExporter->errorMessage();
715 QPdfWriter printer = QPdfWriter( filePath );
716 preparePrintAsPdf( mLayout, &printer, filePath );
717 preparePrint( mLayout, &printer,
false );
719 if ( !p.begin( &printer ) )
728 bool shouldAppendGeoreference = settings.
appendGeoreference && mLayout && mLayout->referenceMap() && mLayout->referenceMap()->page() == 0;
731 georeferenceOutputPrivate( filePath,
nullptr, QRectF(), settings.
dpi, shouldAppendGeoreference, settings.
exportMetadata );
734 captureLabelingResults();
747 QPdfWriter printer = QPdfWriter( fileName );
750 int total = iterator->
count();
751 double step = total > 0 ? 100.0 / total : 100.0;
754 while ( iterator->
next() )
759 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
761 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ) );
773 LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
775 LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
776 ( void )contextRestorer;
799 preparePrintAsPdf( iterator->
layout(), &printer, fileName );
800 preparePrint( iterator->
layout(), &printer,
false );
802 if ( !p.begin( &printer ) )
816 error = QObject::tr(
"Cannot write to %1. This file may be open in another application or may be an invalid path." ).arg( QDir::toNativeSeparators( fileName ) );
843 int total = iterator->
count();
844 double step = total > 0 ? 100.0 / total : 100.0;
846 while ( iterator->
next() )
851 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
853 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
862 QString filePath = iterator->
filePath( baseFilePath, QStringLiteral(
"pdf" ) );
869 error = QObject::tr(
"Cannot write to %1. This file may be open in another application or may be an invalid path." ).arg( QDir::toNativeSeparators( filePath ) );
887#if defined( HAVE_QTPRINTER )
894 if ( settings.
dpi <= 0 )
895 settings.
dpi = mLayout->renderContext().dpi();
897 mErrorFileName.clear();
899 LayoutContextPreviewSettingRestorer restorer( mLayout );
901 LayoutContextSettingsRestorer contextRestorer( mLayout );
902 ( void )contextRestorer;
903 mLayout->renderContext().setDpi( settings.
dpi );
905 mLayout->renderContext().setFlags( settings.
flags );
912 preparePrint( mLayout, &printer,
true );
914 if ( !p.begin( &printer ) )
923 captureLabelingResults();
934 PrintExportSettings settings = s;
938 int total = iterator->
count();
939 double step = total > 0 ? 100.0 / total : 100.0;
942 while ( iterator->
next() )
947 feedback->setProperty(
"progress", QObject::tr(
"Printing %1 of %2" ).arg( i + 1 ).arg( total ) );
949 feedback->setProperty(
"progress", QObject::tr(
"Printing section %1" ).arg( i + 1 ).arg( total ) );
961 LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
963 LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
964 ( void )contextRestorer;
977 preparePrint( iterator->
layout(), &printer,
true );
979 if ( !p.begin( &printer ) )
989 ExportResult result = exporter.printPrivate( &printer, p, !first, settings.dpi, settings.rasterizeWholeImage );
993 error = exporter.errorMessage();
1016 if ( settings.
dpi <= 0 )
1017 settings.
dpi = mLayout->renderContext().dpi();
1019 mErrorFileName.clear();
1021 LayoutContextPreviewSettingRestorer restorer( mLayout );
1023 LayoutContextSettingsRestorer contextRestorer( mLayout );
1024 ( void )contextRestorer;
1025 mLayout->renderContext().setDpi( settings.
dpi );
1027 mLayout->renderContext().setFlags( settings.
flags );
1031 mLayout->renderContext().setMaskSettings( createExportMaskSettings() );
1035 mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
1038 QFileInfo fi( filePath );
1041 pageDetails.
baseName = fi.baseName();
1042 pageDetails.
extension = fi.completeSuffix();
1046 for (
int i = 0; i < mLayout->pageCollection()->pageCount(); ++i )
1048 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1053 pageDetails.
page = i;
1060 if ( mLayout->pageCollection()->pageCount() == 1 )
1063 bounds = mLayout->layoutBounds(
true );
1068 bounds = mLayout->pageItemBounds( i,
true );
1077 bounds = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
1081 int width =
static_cast< int >( bounds.width() * settings.
dpi / inchesToLayoutUnits );
1083 int height =
static_cast< int >( bounds.height() * settings.
dpi / inchesToLayoutUnits );
1084 if ( width == 0 || height == 0 )
1093 const QRectF paperRect = QRectF( pageItem->pos().x(),
1094 pageItem->pos().y(),
1095 pageItem->rect().width(),
1096 pageItem->rect().height() );
1098 QDomNode svgDocRoot;
1099 const QList<QGraphicsItem *> items = mLayout->items( paperRect,
1100 Qt::IntersectsItemBoundingRect,
1101 Qt::AscendingOrder );
1105 return renderToLayeredSvg( settings, width, height, i, bounds, fileName, layerId, layerDetail.name, svg, svgDocRoot, settings.
exportMetadata );
1107 ExportResult res = handleLayeredExport( items, exportFunc );
1112 appendMetadataToSvg( svg );
1114 QFile out( fileName );
1115 bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
1118 mErrorFileName = fileName;
1122 out.write( svg.toByteArray() );
1128 QSvgGenerator generator;
1131 generator.setTitle( mLayout->project()->metadata().title() );
1132 generator.setDescription( mLayout->project()->metadata().abstract() );
1134 generator.setOutputDevice( &svgBuffer );
1135 generator.setSize( QSize( width, height ) );
1136 generator.setViewBox( QRect( 0, 0, width, height ) );
1137 generator.setResolution(
static_cast< int >( std::round( settings.
dpi ) ) );
1140 bool createOk = p.begin( &generator );
1143 mErrorFileName = fileName;
1156 svgBuffer.open( QIODevice::ReadOnly );
1160 if ( ! svg.setContent( &svgBuffer,
false, &errorMsg, &errorLine ) )
1162 mErrorFileName = fileName;
1167 appendMetadataToSvg( svg );
1169 QFile out( fileName );
1170 bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
1173 mErrorFileName = fileName;
1177 out.write( svg.toByteArray() );
1181 captureLabelingResults();
1192 int total = iterator->
count();
1193 double step = total > 0 ? 100.0 / total : 100.0;
1195 while ( iterator->
next() )
1200 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
1202 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
1212 QString filePath = iterator->
filePath( baseFilePath, QStringLiteral(
"svg" ) );
1219 error = QObject::tr(
"Cannot write to %1. This file may be open in another application or may be an invalid path." ).arg( QDir::toNativeSeparators( filePath ) );
1240 return mLabelingResults;
1245 QMap<QString, QgsLabelingResults *> res;
1246 std::swap( mLabelingResults, res );
1250void QgsLayoutExporter::preparePrintAsPdf(
QgsLayout *layout, QPagedPaintDevice *device,
const QString &filePath )
1252 QFileInfo fi( filePath );
1254 if ( !dir.exists( fi.absolutePath() ) )
1256 dir.mkpath( fi.absolutePath() );
1259 updatePrinterPageSize(
layout, device, firstPageToBeExported(
layout ) );
1265#if defined(HAS_KDE_QT5_PDF_TRANSFORM_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
1272void QgsLayoutExporter::preparePrint(
QgsLayout *layout, QPagedPaintDevice *device,
bool setFirstPageSize )
1274 if ( QPdfWriter *pdf =
dynamic_cast<QPdfWriter *
>( device ) )
1278#if defined( HAVE_QTPRINTER )
1279 else if ( QPrinter *printer =
dynamic_cast<QPrinter *
>( device ) )
1281 printer->setFullPage(
true );
1282 printer->setColorMode( QPrinter::Color );
1288 if ( setFirstPageSize )
1290 updatePrinterPageSize(
layout, device, firstPageToBeExported(
layout ) );
1296 if ( mLayout->pageCollection()->pageCount() == 0 )
1299 preparePrint( mLayout, device,
true );
1301 if ( !p.begin( device ) )
1307 printPrivate( device, p );
1312QgsLayoutExporter::ExportResult QgsLayoutExporter::printPrivate( QPagedPaintDevice *device, QPainter &painter,
bool startNewPage,
double dpi,
bool rasterize )
1316 int toPage = mLayout->pageCollection()->pageCount() - 1;
1318#if defined( HAVE_QTPRINTER )
1319 if ( QPrinter *printer =
dynamic_cast<QPrinter *
>( device ) )
1321 if ( printer->fromPage() >= 1 )
1322 fromPage = printer->fromPage() - 1;
1323 if ( printer->toPage() >= 1 )
1324 toPage = printer->toPage() - 1;
1328 bool pageExported =
false;
1331 for (
int i = fromPage; i <= toPage; ++i )
1333 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1338 updatePrinterPageSize( mLayout, device, i );
1339 if ( ( pageExported && i > fromPage ) || startNewPage )
1345 if ( !image.isNull() )
1347 QRectF targetArea( 0, 0, image.width(), image.height() );
1348 painter.drawImage( targetArea, image, targetArea );
1354 pageExported =
true;
1359 for (
int i = fromPage; i <= toPage; ++i )
1361 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1366 updatePrinterPageSize( mLayout, device, i );
1368 if ( ( pageExported && i > fromPage ) || startNewPage )
1373 pageExported =
true;
1379void QgsLayoutExporter::updatePrinterPageSize(
QgsLayout *layout, QPagedPaintDevice *device,
int page )
1384 QPageLayout pageLayout( QPageSize( pageSizeMM.
toQSizeF(), QPageSize::Millimeter ),
1385 QPageLayout::Portrait,
1386 QMarginsF( 0, 0, 0, 0 ) );
1387 pageLayout.setMode( QPageLayout::FullPageMode );
1388 device->setPageLayout( pageLayout );
1389 device->setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
1391#if defined( HAVE_QTPRINTER )
1392 if ( QPrinter *printer =
dynamic_cast<QPrinter *
>( device ) )
1394 printer->setFullPage(
true );
1399QgsLayoutExporter::ExportResult QgsLayoutExporter::renderToLayeredSvg(
const SvgExportSettings &settings,
double width,
double height,
int page,
const QRectF &bounds,
const QString &filename,
unsigned int svgLayerId,
const QString &layerName, QDomDocument &svg, QDomNode &svgDocRoot,
bool includeMetadata )
const
1403 QSvgGenerator generator;
1404 if ( includeMetadata )
1407 generator.setTitle( l->name() );
1408 else if ( mLayout->project() )
1409 generator.setTitle( mLayout->project()->title() );
1412 generator.setOutputDevice( &svgBuffer );
1413 generator.setSize( QSize(
static_cast< int >( std::round( width ) ),
1414 static_cast< int >( std::round( height ) ) ) );
1415 generator.setViewBox( QRect( 0, 0,
1416 static_cast< int >( std::round( width ) ),
1417 static_cast< int >( std::round( height ) ) ) );
1418 generator.setResolution(
static_cast< int >( std::round( settings.dpi ) ) );
1420 QPainter svgPainter( &generator );
1421 if ( settings.cropToContents )
1432 svgBuffer.open( QIODevice::ReadOnly );
1436 if ( ! doc.setContent( &svgBuffer,
false, &errorMsg, &errorLine ) )
1438 mErrorFileName = filename;
1441 if ( 1 == svgLayerId )
1443 svg = QDomDocument( doc.doctype() );
1444 svg.appendChild( svg.importNode( doc.firstChild(),
false ) );
1445 svgDocRoot = svg.importNode( doc.elementsByTagName( QStringLiteral(
"svg" ) ).at( 0 ),
false );
1446 svgDocRoot.toElement().setAttribute( QStringLiteral(
"xmlns:inkscape" ), QStringLiteral(
"http://www.inkscape.org/namespaces/inkscape" ) );
1447 svg.appendChild( svgDocRoot );
1449 QDomNode mainGroup = svg.importNode( doc.elementsByTagName( QStringLiteral(
"g" ) ).at( 0 ),
true );
1450 mainGroup.toElement().setAttribute( QStringLiteral(
"id" ), layerName );
1451 mainGroup.toElement().setAttribute( QStringLiteral(
"inkscape:label" ), layerName );
1452 mainGroup.toElement().setAttribute( QStringLiteral(
"inkscape:groupmode" ), QStringLiteral(
"layer" ) );
1453 QDomNode defs = svg.importNode( doc.elementsByTagName( QStringLiteral(
"defs" ) ).at( 0 ),
true );
1454 svgDocRoot.appendChild( defs );
1455 svgDocRoot.appendChild( mainGroup );
1460void QgsLayoutExporter::appendMetadataToSvg( QDomDocument &svg )
const
1463 QDomElement metadataElement = svg.createElement( QStringLiteral(
"metadata" ) );
1464 QDomElement rdfElement = svg.createElement( QStringLiteral(
"rdf:RDF" ) );
1465 rdfElement.setAttribute( QStringLiteral(
"xmlns:rdf" ), QStringLiteral(
"http://www.w3.org/1999/02/22-rdf-syntax-ns#" ) );
1466 rdfElement.setAttribute( QStringLiteral(
"xmlns:rdfs" ), QStringLiteral(
"http://www.w3.org/2000/01/rdf-schema#" ) );
1467 rdfElement.setAttribute( QStringLiteral(
"xmlns:dc" ), QStringLiteral(
"http://purl.org/dc/elements/1.1/" ) );
1468 QDomElement descriptionElement = svg.createElement( QStringLiteral(
"rdf:Description" ) );
1469 QDomElement workElement = svg.createElement( QStringLiteral(
"cc:Work" ) );
1470 workElement.setAttribute( QStringLiteral(
"rdf:about" ), QString() );
1472 auto addTextNode = [&workElement, &descriptionElement, &svg](
const QString & tag,
const QString & value )
1475 QDomElement element = svg.createElement( tag );
1476 QDomText t = svg.createTextNode( value );
1477 element.appendChild( t );
1478 workElement.appendChild( element );
1481 descriptionElement.setAttribute( tag, value );
1484 addTextNode( QStringLiteral(
"dc:format" ), QStringLiteral(
"image/svg+xml" ) );
1485 addTextNode( QStringLiteral(
"dc:title" ), metadata.
title() );
1486 addTextNode( QStringLiteral(
"dc:date" ), metadata.
creationDateTime().toString( Qt::ISODate ) );
1487 addTextNode( QStringLiteral(
"dc:identifier" ), metadata.
identifier() );
1488 addTextNode( QStringLiteral(
"dc:description" ), metadata.
abstract() );
1490 auto addAgentNode = [&workElement, &descriptionElement, &svg](
const QString & tag,
const QString & value )
1493 QDomElement inkscapeElement = svg.createElement( tag );
1494 QDomElement agentElement = svg.createElement( QStringLiteral(
"cc:Agent" ) );
1495 QDomElement titleElement = svg.createElement( QStringLiteral(
"dc:title" ) );
1496 QDomText t = svg.createTextNode( value );
1497 titleElement.appendChild( t );
1498 agentElement.appendChild( titleElement );
1499 inkscapeElement.appendChild( agentElement );
1500 workElement.appendChild( inkscapeElement );
1503 QDomElement bagElement = svg.createElement( QStringLiteral(
"rdf:Bag" ) );
1504 QDomElement liElement = svg.createElement( QStringLiteral(
"rdf:li" ) );
1505 t = svg.createTextNode( value );
1506 liElement.appendChild( t );
1507 bagElement.appendChild( liElement );
1509 QDomElement element = svg.createElement( tag );
1510 element.appendChild( bagElement );
1511 descriptionElement.appendChild( element );
1514 addAgentNode( QStringLiteral(
"dc:creator" ), metadata.
author() );
1515 addAgentNode( QStringLiteral(
"dc:publisher" ), QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() ) );
1519 QDomElement element = svg.createElement( QStringLiteral(
"dc:subject" ) );
1520 QDomElement bagElement = svg.createElement( QStringLiteral(
"rdf:Bag" ) );
1522 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
1524 const QStringList words = it.value();
1525 for (
const QString &keyword : words )
1527 QDomElement liElement = svg.createElement( QStringLiteral(
"rdf:li" ) );
1528 QDomText t = svg.createTextNode( keyword );
1529 liElement.appendChild( t );
1530 bagElement.appendChild( liElement );
1533 element.appendChild( bagElement );
1534 workElement.appendChild( element );
1535 descriptionElement.appendChild( element );
1538 rdfElement.appendChild( descriptionElement );
1539 rdfElement.appendChild( workElement );
1540 metadataElement.appendChild( rdfElement );
1541 svg.documentElement().appendChild( metadataElement );
1542 svg.documentElement().setAttribute( QStringLiteral(
"xmlns:cc" ), QStringLiteral(
"http://creativecommons.org/ns#" ) );
1545std::unique_ptr<double[]> QgsLayoutExporter::computeGeoTransform(
const QgsLayoutItemMap *map,
const QRectF ®ion,
double dpi )
const
1548 map = mLayout->referenceMap();
1554 dpi = mLayout->renderContext().dpi();
1557 QRectF exportRegion = region;
1558 if ( !exportRegion.isValid() )
1560 int pageNumber = map->
page();
1563 double pageY = page->pos().y();
1564 QSizeF pageSize = page->rect().size();
1565 exportRegion = QRectF( 0, pageY, pageSize.width(), pageSize.height() );
1569 QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
1572 double outputHeightMM = exportRegion.height();
1573 double outputWidthMM = exportRegion.width();
1577 double mapXCenter = mapExtent.
center().
x();
1578 double mapYCenter = mapExtent.
center().
y();
1580 double sinAlpha = std::sin( alpha );
1581 double cosAlpha = std::cos( alpha );
1584 QPointF mapItemPos = map->pos();
1586 mapItemPos.rx() -= exportRegion.left();
1587 mapItemPos.ry() -= exportRegion.top();
1590 double xRatio = mapExtent.
width() / mapItemSceneRect.width();
1591 double yRatio = mapExtent.
height() / mapItemSceneRect.height();
1592 double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
1593 double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
1594 QgsRectangle paperExtent( xmin, ymax - outputHeightMM * yRatio, xmin + outputWidthMM * xRatio, ymax );
1597 double X0 = paperExtent.xMinimum();
1598 double Y0 = paperExtent.yMaximum();
1603 double X1 = X0 - mapXCenter;
1604 double Y1 = Y0 - mapYCenter;
1605 double X2 = X1 * cosAlpha + Y1 * sinAlpha;
1606 double Y2 = -X1 * sinAlpha + Y1 * cosAlpha;
1607 X0 = X2 + mapXCenter;
1608 Y0 = Y2 + mapYCenter;
1612 int pageWidthPixels =
static_cast< int >( dpi * outputWidthMM / 25.4 );
1613 int pageHeightPixels =
static_cast< int >( dpi * outputHeightMM / 25.4 );
1614 double pixelWidthScale = paperExtent.width() / pageWidthPixels;
1615 double pixelHeightScale = paperExtent.height() / pageHeightPixels;
1618 std::unique_ptr<double[]> t(
new double[6] );
1620 t[1] = cosAlpha * pixelWidthScale;
1621 t[2] = -sinAlpha * pixelWidthScale;
1623 t[4] = -sinAlpha * pixelHeightScale;
1624 t[5] = -cosAlpha * pixelHeightScale;
1629void QgsLayoutExporter::writeWorldFile(
const QString &worldFileName,
double a,
double b,
double c,
double d,
double e,
double f )
const
1631 QFile worldFile( worldFileName );
1632 if ( !worldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
1636 QTextStream fout( &worldFile );
1640 fout << QString::number( a,
'f', 12 ) <<
"\r\n";
1641 fout << QString::number( d,
'f', 12 ) <<
"\r\n";
1642 fout << QString::number( b,
'f', 12 ) <<
"\r\n";
1643 fout << QString::number( e,
'f', 12 ) <<
"\r\n";
1644 fout << QString::number(
c,
'f', 12 ) <<
"\r\n";
1645 fout << QString::number( f,
'f', 12 ) <<
"\r\n";
1650 return georeferenceOutputPrivate( file, map, exportRegion, dpi,
false );
1653bool QgsLayoutExporter::georeferenceOutputPrivate(
const QString &file,
QgsLayoutItemMap *map,
const QRectF &exportRegion,
double dpi,
bool includeGeoreference,
bool includeMetadata )
const
1658 if ( !map && includeGeoreference )
1659 map = mLayout->referenceMap();
1661 std::unique_ptr<double[]> t;
1663 if ( map && includeGeoreference )
1666 dpi = mLayout->renderContext().dpi();
1668 t = computeGeoTransform( map, exportRegion, dpi );
1673 CPLSetConfigOption(
"GDAL_PDF_DPI", QString::number( dpi ).toUtf8().constData() );
1678 GDALSetGeoTransform( outputDS.get(), t.get() );
1680 if ( includeMetadata )
1682 QString creationDateString;
1683 const QDateTime creationDateTime = mLayout->project()->metadata().creationDateTime();
1684 if ( creationDateTime.isValid() )
1686 creationDateString = QStringLiteral(
"D:%1" ).arg( mLayout->project()->metadata().creationDateTime().toString( QStringLiteral(
"yyyyMMddHHmmss" ) ) );
1687 if ( creationDateTime.timeZone().isValid() )
1689 int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
1690 creationDateString += ( offsetFromUtc >= 0 ) ?
'+' :
'-';
1691 offsetFromUtc = std::abs( offsetFromUtc );
1692 int offsetHours = offsetFromUtc / 3600;
1693 int offsetMins = ( offsetFromUtc % 3600 ) / 60;
1694 creationDateString += QStringLiteral(
"%1'%2'" ).arg( offsetHours ).arg( offsetMins );
1697 GDALSetMetadataItem( outputDS.get(),
"CREATION_DATE", creationDateString.toUtf8().constData(),
nullptr );
1699 GDALSetMetadataItem( outputDS.get(),
"AUTHOR", mLayout->project()->metadata().author().toUtf8().constData(),
nullptr );
1700 const QString creator = QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() );
1701 GDALSetMetadataItem( outputDS.get(),
"CREATOR", creator.toUtf8().constData(),
nullptr );
1702 GDALSetMetadataItem( outputDS.get(),
"PRODUCER", creator.toUtf8().constData(),
nullptr );
1703 GDALSetMetadataItem( outputDS.get(),
"SUBJECT", mLayout->project()->metadata().abstract().toUtf8().constData(),
nullptr );
1704 GDALSetMetadataItem( outputDS.get(),
"TITLE", mLayout->project()->metadata().title().toUtf8().constData(),
nullptr );
1707 QStringList allKeywords;
1708 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
1710 allKeywords.append( QStringLiteral(
"%1: %2" ).arg( it.key(), it.value().join(
',' ) ) );
1712 const QString keywordString = allKeywords.join(
';' );
1713 GDALSetMetadataItem( outputDS.get(),
"KEYWORDS", keywordString.toUtf8().constData(),
nullptr );
1719 CPLSetConfigOption(
"GDAL_PDF_DPI",
nullptr );
1726 if ( items.count() == 1 )
1730 QString name = layoutItem->displayName();
1732 if ( name.startsWith(
'<' ) && name.endsWith(
'>' ) )
1733 name = name.mid( 1, name.length() - 2 );
1737 else if ( items.count() > 1 )
1739 QStringList currentLayerItemTypes;
1740 for ( QGraphicsItem *item : items )
1746 if ( !currentLayerItemTypes.contains( itemType ) && !currentLayerItemTypes.contains( itemTypePlural ) )
1747 currentLayerItemTypes << itemType;
1748 else if ( currentLayerItemTypes.contains( itemType ) )
1750 currentLayerItemTypes.replace( currentLayerItemTypes.indexOf( itemType ), itemTypePlural );
1755 if ( !currentLayerItemTypes.contains( QObject::tr(
"Other" ) ) )
1756 currentLayerItemTypes.append( QObject::tr(
"Other" ) );
1759 return currentLayerItemTypes.join( QLatin1String(
", " ) );
1761 return QObject::tr(
"Layer %1" ).arg( layerId );
1767 LayoutItemHider itemHider( items );
1772 unsigned int layerId = 1;
1774 itemHider.hideAll();
1775 const QList< QGraphicsItem * > itemsToIterate = itemHider.itemsToIterate();
1776 QList< QGraphicsItem * > currentLayerItems;
1777 for ( QGraphicsItem *item : itemsToIterate )
1781 bool canPlaceInExistingLayer =
false;
1788 switch ( prevItemBehavior )
1791 canPlaceInExistingLayer =
true;
1795 canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
1800 canPlaceInExistingLayer =
false;
1808 switch ( prevItemBehavior )
1812 canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
1817 canPlaceInExistingLayer =
false;
1825 canPlaceInExistingLayer =
false;
1830 canPlaceInExistingLayer =
false;
1834 prevType = layoutItem->
type();
1841 if ( canPlaceInExistingLayer )
1843 currentLayerItems << item;
1848 if ( !currentLayerItems.isEmpty() )
1852 ExportResult result = exportFunc( layerId, layerDetails );
1856 currentLayerItems.clear();
1859 itemHider.hideAll();
1864 int layoutItemLayerIdx = 0;
1866 mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
1872 mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
1876 ExportResult result = exportFunc( layerId, layerDetails );
1881 layoutItemLayerIdx++;
1883 layerDetails.mapLayerId.clear();
1885 mLayout->renderContext().setCurrentExportLayer( -1 );
1888 currentLayerItems.clear();
1892 currentLayerItems << item;
1896 if ( !currentLayerItems.isEmpty() )
1899 ExportResult result = exportFunc( layerId, layerDetails );
1914 return simplifyMethod;
1937 int pageNumber = map->
page();
1939 double pageY = page->pos().y();
1940 QSizeF pageSize = page->rect().size();
1941 QRectF pageRect( 0, pageY, pageSize.width(), pageSize.height() );
1957 double destinationHeight = exportRegion.height();
1958 double destinationWidth = exportRegion.width();
1960 QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
1965 double xRatio = mapExtent.
width() / mapItemSceneRect.width();
1966 double yRatio = mapExtent.
height() / mapItemSceneRect.height();
1968 double xCenter = mapExtent.
center().
x();
1969 double yCenter = mapExtent.
center().
y();
1972 QPointF mapItemPos = map->pos();
1974 mapItemPos.rx() -= exportRegion.left();
1975 mapItemPos.ry() -= exportRegion.top();
1977 double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
1978 double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
1979 QgsRectangle paperExtent( xmin, ymax - destinationHeight * yRatio, xmin + destinationWidth * xRatio, ymax );
1981 double X0 = paperExtent.
xMinimum();
1982 double Y0 = paperExtent.
yMinimum();
1985 dpi = mLayout->renderContext().dpi();
1987 int widthPx =
static_cast< int >( dpi * destinationWidth / 25.4 );
1988 int heightPx =
static_cast< int >( dpi * destinationHeight / 25.4 );
1990 double Ww = paperExtent.
width() / widthPx;
1991 double Hh = paperExtent.
height() / heightPx;
2000 s[5] = Y0 + paperExtent.
height();
2004 r[0] = std::cos( alpha );
2005 r[1] = -std::sin( alpha );
2006 r[2] = xCenter * ( 1 - std::cos( alpha ) ) + yCenter * std::sin( alpha );
2007 r[3] = std::sin( alpha );
2008 r[4] = std::cos( alpha );
2009 r[5] = - xCenter * std::sin( alpha ) + yCenter * ( 1 - std::cos( alpha ) );
2012 a = r[0] * s[0] + r[1] * s[3];
2013 b = r[0] * s[1] + r[1] * s[4];
2014 c = r[0] * s[2] + r[1] * s[5] + r[2];
2015 d = r[3] * s[0] + r[4] * s[3];
2016 e = r[3] * s[1] + r[4] * s[4];
2017 f = r[3] * s[2] + r[4] * s[5] + r[5];
2025 QList< QgsLayoutItem *> items;
2031 if ( currentItem->isVisible() && currentItem->requiresRasterization() )
2042 QList< QgsLayoutItem *> items;
2048 if ( currentItem->isVisible() && currentItem->containsAdvancedEffects() )
2061 if ( mLayout->pageCollection()->pageCount() == 1 )
2064 bounds = mLayout->layoutBounds(
true );
2069 bounds = mLayout->pageItemBounds( page,
true );
2071 if ( bounds.width() <= 0 || bounds.height() <= 0 )
2079 bounds = bounds.adjusted( -settings.
cropMargins.
left() * pixelToLayoutUnits,
2091int QgsLayoutExporter::firstPageToBeExported(
QgsLayout *layout )
2094 for (
int i = 0; i < pageCount; ++i )
2108 if ( details.
page == 0 )
2118void QgsLayoutExporter::captureLabelingResults()
2120 qDeleteAll( mLabelingResults );
2121 mLabelingResults.clear();
2123 QList< QgsLayoutItemMap * > maps;
2124 mLayout->layoutItems( maps );
2128 mLabelingResults[ map->
uuid() ] = map->mExportLabelingResults.release();
2132bool QgsLayoutExporter::saveImage(
const QImage &image,
const QString &imageFilename,
const QString &imageFormat,
QgsProject *projectForMetadata )
2134 QImageWriter w( imageFilename, imageFormat.toLocal8Bit().constData() );
2135 if ( imageFormat.compare( QLatin1String(
"tiff" ), Qt::CaseInsensitive ) == 0 || imageFormat.compare( QLatin1String(
"tif" ), Qt::CaseInsensitive ) == 0 )
2137 w.setCompression( 1 );
2139 if ( projectForMetadata )
2141 w.setText( QStringLiteral(
"Author" ), projectForMetadata->
metadata().
author() );
2142 const QString creator = QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() );
2143 w.setText( QStringLiteral(
"Creator" ), creator );
2144 w.setText( QStringLiteral(
"Producer" ), creator );
2145 w.setText( QStringLiteral(
"Subject" ), projectForMetadata->
metadata().
abstract() );
2146 w.setText( QStringLiteral(
"Created" ), projectForMetadata->
metadata().
creationDateTime().toString( Qt::ISODate ) );
2147 w.setText( QStringLiteral(
"Title" ), projectForMetadata->
metadata().
title() );
2150 QStringList allKeywords;
2151 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
2153 allKeywords.append( QStringLiteral(
"%1: %2" ).arg( it.key(), it.value().join(
',' ) ) );
2155 const QString keywordString = allKeywords.join(
';' );
2156 w.setText( QStringLiteral(
"Keywords" ), keywordString );
2158 return w.write( image );
static QString version()
Version string.
@ Millimeters
Millimeters.
@ GeometrySimplification
The geometries can be simplified using the current map2pixel context state.
@ SnappedToGridGlobal
Snap to a global grid based on the tolerance. Good for consistent results for incoming vertices,...
@ Warning
Warning message.
TextRenderFormat
Options for rendering text.
@ AlwaysOutlines
Always render text using path objects (AKA outlines/curves). This setting guarantees the best quality...
@ PreferredGdal
Preferred format for conversion of CRS to WKT for use with the GDAL library.
An abstract base class for QgsLayout based classes which can be exported by QgsLayoutExporter.
virtual bool endRender()=0
Ends the render, performing any required cleanup tasks.
virtual QgsLayout * layout()=0
Returns the layout associated with the iterator.
virtual bool next()=0
Iterates to next feature, returning false if no more features exist to iterate over.
virtual bool beginRender()=0
Called when rendering begins, before iteration commences.
virtual QString filePath(const QString &baseFilePath, const QString &extension)=0
Returns the file path for the current feature, based on a specified base file path and extension.
virtual int count() const =0
Returns the number of features to iterate over.
static QgsLayoutItemRegistry * layoutItemRegistry()
Returns the application's layout item registry, used for layout item types.
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
Handles rendering and exports of layouts to various formats.
ExportResult exportToSvg(const QString &filePath, const QgsLayoutExporter::SvgExportSettings &settings)
Exports the layout as an SVG to the filePath, using the specified export settings.
ExportResult exportToImage(const QString &filePath, const QgsLayoutExporter::ImageExportSettings &settings)
Exports the layout to the filePath, using the specified export settings.
QString errorMessage() const
Returns a string describing the last error encountered during an export.
ExportResult exportToPdf(const QString &filePath, const QgsLayoutExporter::PdfExportSettings &settings)
Exports the layout as a PDF to the filePath, using the specified export settings.
virtual ~QgsLayoutExporter()
QImage renderRegionToImage(const QRectF ®ion, QSize imageSize=QSize(), double dpi=-1) const
Renders a region of the layout to an image.
QMap< QString, QgsLabelingResults * > takeLabelingResults()
Takes the labeling results for all map items included in the export.
static bool requiresRasterization(const QgsLayout *layout)
Returns true if the specified layout contains visible items which have settings that require rasteriz...
QgsLayout * layout() const
Returns the layout linked to this exporter.
bool georeferenceOutput(const QString &file, QgsLayoutItemMap *referenceMap=nullptr, const QRectF &exportRegion=QRectF(), double dpi=-1) const
Georeferences a file (image of PDF) exported from the layout.
static const QgsSettingsEntryBool * settingOpenAfterExportingPdf
Settings entry - Whether to automatically open pdfs after exporting them.
virtual QString generateFileName(const PageExportDetails &details) const
Generates the file name for a page during export.
ExportResult
Result codes for exporting layouts.
@ Canceled
Export was canceled.
@ MemoryError
Unable to allocate memory required to export.
@ PrintError
Could not start printing to destination device.
@ IteratorError
Error iterating over layout.
@ FileError
Could not write to destination file, likely due to a lock held by another application.
@ Success
Export was successful.
@ SvgLayerError
Could not create layered SVG file.
QImage renderPageToImage(int page, QSize imageSize=QSize(), double dpi=-1) const
Renders a full page to an image.
QgsLayoutExporter(QgsLayout *layout)
Constructor for QgsLayoutExporter, for the specified layout.
static ExportResult exportToPdfs(QgsAbstractLayoutIterator *iterator, const QString &baseFilePath, const QgsLayoutExporter::PdfExportSettings &settings, QString &error, QgsFeedback *feedback=nullptr)
Exports a layout iterator to multiple PDF files, with the specified export settings.
void computeWorldFileParameters(double &a, double &b, double &c, double &d, double &e, double &f, double dpi=-1) const
Compute world file parameters.
void renderPage(QPainter *painter, int page) const
Renders a full page to a destination painter.
static const QgsSettingsEntryBool * settingOpenAfterExportingImage
Settings entry - Whether to automatically open images after exporting them.
static const QgsSettingsEntryBool * settingOpenAfterExportingSvg
Settings entry - Whether to automatically open svgs after exporting them.
QMap< QString, QgsLabelingResults * > labelingResults()
Returns the labeling results for all map items included in the export.
static bool containsAdvancedEffects(const QgsLayout *layout)
Returns true if the specified layout contains visible items which have settings such as opacity which...
void renderRegion(QPainter *painter, const QRectF ®ion) const
Renders a region from the layout to a painter.
Contains the configuration for a single snap guide used by a layout.
Layout graphical items for displaying a map.
double mapRotation(QgsLayoutObject::PropertyValueType valueType=QgsLayoutObject::EvaluatedValue) const
Returns the rotation used for drawing the map within the layout item, in degrees clockwise.
QgsRectangle extent() const
Returns the current map extent.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
Item representing the paper in a layout.
QgsLayoutItemAbstractMetadata * itemMetadata(int type) const
Returns the metadata for the specified item type.
Base class for graphical items within a QgsLayout.
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
virtual QgsLayoutItem::ExportLayerDetail exportLayerDetails() const
Returns the details for the specified current export layer.
virtual bool nextExportPart()
Moves to the next export part for a multi-layered export item, during a multi-layered export.
virtual void startLayeredExport()
Starts a multi-layer export operation.
int page() const
Returns the page the item is currently on, with the first page returning 0.
int type() const override
Returns a unique graphics item type identifier.
virtual void stopLayeredExport()
Stops a multi-layer export operation.
virtual QString uuid() const
Returns the item identification string.
ExportLayerBehavior
Behavior of item when exporting to layered outputs.
@ ItemContainsSubLayers
Item contains multiple sublayers which must be individually exported.
@ MustPlaceInOwnLayer
Item must be placed in its own individual layer.
@ CanGroupWithItemsOfSameType
Item can only be placed on layers with other items of the same type, but multiple items of this type ...
@ CanGroupWithAnyOtherItem
Item can be placed on a layer with any other item (default behavior)
virtual ExportLayerBehavior exportLayerBehavior() const
Returns the behavior of this item during exporting to layered exports (e.g.
QgsLayoutMeasurement convert(QgsLayoutMeasurement measurement, Qgis::LayoutUnit targetUnits) const
Converts a measurement from one unit to another.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
int pageCount() const
Returns the number of pages in the collection.
bool shouldExportPage(int page) const
Returns whether the specified page number should be included in exports of the layouts.
QgsLayoutItemPage * page(int pageNumber)
Returns a specific page (by pageNumber) from the collection.
This class provides a method of storing points, consisting of an x and y coordinate,...
double x() const
Returns x coordinate of point.
double y() const
Returns y coordinate of point.
void setDpi(double dpi)
Sets the dpi for outputting the layout.
void setSimplifyMethod(const QgsVectorSimplifyMethod &method)
Sets the simplification setting to use when rendering vector layers.
void setTextRenderFormat(Qgis::TextRenderFormat format)
Sets the text render format, which dictates how text is rendered (e.g.
QgsLayoutRenderContext::Flags flags() const
Returns the current combination of flags used for rendering the layout.
void setFlag(QgsLayoutRenderContext::Flag flag, bool on=true)
Enables or disables a particular rendering flag for the layout.
double dpi() const
Returns the dpi for outputting the layout.
@ FlagRenderLabelsByMapLayer
When rendering map items to multi-layered exports, render labels belonging to different layers into s...
@ FlagUseAdvancedEffects
Enable advanced effects such as blend modes.
@ FlagLosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
@ FlagAntialiasing
Use antialiasing when drawing items.
@ FlagSynchronousLegendGraphics
Query legend graphics synchronously.
@ FlagForceVectorOutput
Force output in vector format where possible, even if items require rasterization to keep their corre...
void setPredefinedScales(const QVector< qreal > &scales)
Sets the list of predefined scales to use with the layout.
void setMaskSettings(const QgsMaskRenderSettings &settings)
Sets the mask render settings, which control how masks are drawn and behave during map renders.
void setFlags(QgsLayoutRenderContext::Flags flags)
Sets the combination of flags that will be used for rendering the layout.
const QgsLayoutMeasurementConverter & measurementConverter() const
Returns the layout measurement converter to be used in the layout.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
QSizeF toQSizeF() const
Converts the layout size to a QSizeF.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout's render context, which stores information relating to the current ...
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout's page collection, which stores and manages page items in the layout.
void layoutItems(QList< T * > &itemList) const
Returns a list of layout items of a specific type.
Line string geometry type, with support for z-dimension and m-values.
Base class for all map layer types.
double top() const
Returns the top margin.
double right() const
Returns the right margin.
double bottom() const
Returns the bottom margin.
double left() const
Returns the left margin.
Contains settings regarding how masks are calculated and handled during a map render.
void setSimplificationTolerance(double tolerance)
Sets a simplification tolerance (in painter units) to use for on-the-fly simplification of mask paths...
Interface for master layout type objects, such as print layouts and reports.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static void fixEngineFlags(QPaintEngine *engine)
A class to represent a 2D point.
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
QgsProjectMetadata metadata
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double width() const
Returns the width of the rectangle.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
QgsPointXY center() const
Returns the center point of the rectangle.
double height() const
Returns the height of the rectangle.
A boolean settings entry.
static QgsSettingsTreeNode * sTreeLayout
This class contains information how to simplify geometries fetched from a vector layer.
void setThreshold(float threshold)
Sets the simplification threshold of the vector layer managed.
void setForceLocalOptimization(bool localOptimization)
Sets where the simplification executes, after fetch the geometries from provider, or when supported,...
void setSimplifyHints(Qgis::VectorRenderingSimplificationFlags simplifyHints)
Sets the simplification hints of the vector layer managed.
void setSimplifyAlgorithm(Qgis::VectorSimplificationAlgorithm simplifyAlgorithm)
Sets the local simplification algorithm of the vector layer managed.
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
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QString nameForLayerWithItems(const QList< QGraphicsItem * > &items, unsigned int layerId)
Contains details of a particular input component to be used during PDF composition.
QString sourcePdfPath
File path to the (already created) PDF to use as the source for this component layer.
QString mapLayerId
Associated map layer ID, or an empty string if this component layer is not associated with a map laye...
QPainter::CompositionMode compositionMode
Component composition mode.
QString group
Optional group name, for arranging layers in top-level groups.
QString name
User-friendly name for the generated PDF layer.
double opacity
Component opacity.
Contains details of a control point used during georeferencing GeoPDF outputs.
QgsAbstractMetadataBase::KeywordMap keywords
Metadata keyword map.
bool useIso32000ExtensionFormatGeoreferencing
true if ISO32000 extension format georeferencing should be used.
QMap< QString, QString > layerIdToPdfLayerTreeNameMap
Optional map of map layer ID to custom layer tree name to show in the created PDF file.
bool useOgcBestPracticeFormatGeoreferencing
true if OGC "best practice" format georeferencing should be used.
QDateTime creationDateTime
Metadata creation datetime.
QSizeF pageSizeMm
Page size, in millimeters.
QList< QgsAbstractGeoPdfExporter::GeoReferencedSection > georeferencedSections
List of georeferenced sections.
QStringList layerTreeGroupOrder
Specifies the ordering of layer tree groups in the generated GeoPDF file.
QString author
Metadata author tag.
QMap< QString, bool > initialLayerVisibility
Optional map of map layer ID to initial visibility state.
QString producer
Metadata producer tag.
QString creator
Metadata creator tag.
QMap< QString, QString > customLayerTreeGroups
Optional map of map layer ID to custom logical layer tree group in created PDF file.
bool includeFeatures
true if feature vector information (such as attributes) should be exported.
QStringList layerOrder
Optional list of layer IDs, in the order desired to appear in the generated GeoPDF file.
QString subject
Metadata subject tag.
QString title
Metadata title tag.
QgsCoordinateReferenceSystem crs
Coordinate reference system for georeferenced section.
QgsPolygon pageBoundsPolygon
Bounds of the georeferenced section on the page, in millimeters, as a free-form polygon.
QList< QgsAbstractGeoPdfExporter::ControlPoint > controlPoints
List of control points corresponding to this georeferenced section.
Contains settings relating to exporting layouts to raster images.
QgsMargins cropMargins
Crop to content margins, in pixels.
QList< int > pages
List of specific pages to export, or an empty list to export all pages.
bool generateWorldFile
Set to true to generate an external world file alongside exported images.
QSize imageSize
Manual size in pixels for output image.
bool exportMetadata
Indicates whether image export should include metadata generated from the layout's project's metadata...
QgsLayoutRenderContext::Flags flags
Layout context flags, which control how the export will be created.
bool cropToContents
Set to true if image should be cropped so only parts of the layout containing items are exported.
double dpi
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
QVector< qreal > predefinedMapScales
A list of predefined scales to use with the layout.
Contains details of a page being exported by the class.
QString baseName
Base part of filename (i.e. file name without extension or '.')
QString extension
File suffix/extension (without the leading '.')
QString directory
Target folder.
int page
Page number, where 0 = first page.
Contains settings relating to exporting layouts to PDF.
bool forceVectorOutput
Set to true to force vector object exports, even when the resultant appearance will differ from the l...
bool rasterizeWholeImage
Set to true to force whole layout to be rasterized while exporting.
QStringList exportThemes
Optional list of map themes to export as GeoPDF layer groups.
bool exportMetadata
Indicates whether PDF export should include metadata generated from the layout's project's metadata.
bool appendGeoreference
Indicates whether PDF export should append georeference data.
QgsLayoutRenderContext::Flags flags
Layout context flags, which control how the export will be created.
bool writeGeoPdf
true if GeoPDF files should be created, instead of normal PDF files.
double dpi
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
QVector< qreal > predefinedMapScales
A list of predefined scales to use with the layout.
bool exportLayersAsSeperateFiles
true if individual layers from the layout should be rendered to separate PDF files.
bool simplifyGeometries
Indicates whether vector geometries should be simplified to avoid redundant extraneous detail,...
Qgis::TextRenderFormat textRenderFormat
Text rendering format, which controls how text should be rendered in the export (e....
Contains settings relating to printing layouts.
QVector< qreal > predefinedMapScales
A list of predefined scales to use with the layout.
double dpi
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
QgsLayoutRenderContext::Flags flags
Layout context flags, which control how the export will be created.
bool rasterizeWholeImage
Set to true to force whole layout to be rasterized while exporting.
Contains settings relating to exporting layouts to SVG.
bool forceVectorOutput
Set to true to force vector object exports, even when the resultant appearance will differ from the l...
Qgis::TextRenderFormat textRenderFormat
Text rendering format, which controls how text should be rendered in the export (e....
bool exportAsLayers
Set to true to export as a layered SVG file.
bool simplifyGeometries
Indicates whether vector geometries should be simplified to avoid redundant extraneous detail,...
bool exportMetadata
Indicates whether SVG export should include RDF metadata generated from the layout's project's metada...
double dpi
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
QgsLayoutRenderContext::Flags flags
Layout context flags, which control how the export will be created.
QVector< qreal > predefinedMapScales
A list of predefined scales to use with the layout.
bool exportLabelsToSeparateLayers
Set to true to export labels to separate layers (grouped by map layer) in layered SVG exports.
bool cropToContents
Set to true if image should be cropped so only parts of the layout containing items are exported.
QgsMargins cropMargins
Crop to content margins, in layout units.
Contains details of a particular export layer relating to a layout item.
QString name
User-friendly name for the export layer.