31#include <QImageWriter>
33#include <QSvgGenerator>
42class LayoutContextPreviewSettingRestorer
46 LayoutContextPreviewSettingRestorer(
QgsLayout *layout )
48 , mPreviousSetting( layout->renderContext().mIsPreviewRender )
50 mLayout->renderContext().mIsPreviewRender =
false;
53 ~LayoutContextPreviewSettingRestorer()
55 mLayout->renderContext().mIsPreviewRender = mPreviousSetting;
58 LayoutContextPreviewSettingRestorer(
const LayoutContextPreviewSettingRestorer &other ) =
delete;
59 LayoutContextPreviewSettingRestorer &operator=(
const LayoutContextPreviewSettingRestorer &other ) =
delete;
63 bool mPreviousSetting =
false;
73 const QList< QgsLayoutGuide * > guides = mLayout->guides().guides();
76 mPrevVisibility.insert( guide, guide->item()->isVisible() );
77 guide->item()->setVisible(
false );
83 for (
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
85 it.key()->item()->setVisible( it.value() );
89 LayoutGuideHider(
const LayoutGuideHider &other ) =
delete;
90 LayoutGuideHider &operator=(
const LayoutGuideHider &other ) =
delete;
94 QHash< QgsLayoutGuide *, bool > mPrevVisibility;
100 explicit LayoutItemHider(
const QList<QGraphicsItem *> &items )
102 mItemsToIterate.reserve( items.count() );
103 for ( QGraphicsItem *item : items )
105 const bool isVisible = item->isVisible();
106 mPrevVisibility[item] = isVisible;
108 mItemsToIterate.append( item );
110 layoutItem->setProperty(
"wasVisible", isVisible );
118 for (
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
126 for (
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
128 it.key()->setVisible( it.value() );
130 layoutItem->setProperty(
"wasVisible", QVariant() );
134 QList< QGraphicsItem * > itemsToIterate()
const {
return mItemsToIterate; }
136 LayoutItemHider(
const LayoutItemHider &other ) =
delete;
137 LayoutItemHider &operator=(
const LayoutItemHider &other ) =
delete;
141 QList<QGraphicsItem * > mItemsToIterate;
142 QHash<QGraphicsItem *, bool> mPrevVisibility;
155 qDeleteAll( mLabelingResults );
168 if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
179 LayoutContextPreviewSettingRestorer restorer( mLayout );
182 QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
191 if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
202 LayoutContextPreviewSettingRestorer restorer( mLayout );
205 QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
207 const double imageAspectRatio =
static_cast< double >( imageSize.width() ) / imageSize.height();
208 const double paperAspectRatio = paperRect.width() / paperRect.height();
209 if ( imageSize.isValid() && ( !
qgsDoubleNear( imageAspectRatio, paperAspectRatio, 0.008 ) ) )
214 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 );
222class LayoutItemCacheSettingRestorer
226 LayoutItemCacheSettingRestorer(
QgsLayout *layout )
229 const QList< QGraphicsItem * > items = mLayout->items();
230 for ( QGraphicsItem *item : items )
232 mPrevCacheMode.insert( item, item->cacheMode() );
233 item->setCacheMode( QGraphicsItem::NoCache );
237 ~LayoutItemCacheSettingRestorer()
239 for (
auto it = mPrevCacheMode.constBegin(); it != mPrevCacheMode.constEnd(); ++it )
241 it.key()->setCacheMode( it.value() );
245 LayoutItemCacheSettingRestorer(
const LayoutItemCacheSettingRestorer &other ) =
delete;
246 LayoutItemCacheSettingRestorer &operator=(
const LayoutItemCacheSettingRestorer &other ) =
delete;
250 QHash< QGraphicsItem *, QGraphicsItem::CacheMode > mPrevCacheMode;
257 QPaintDevice *paintDevice = painter->device();
258 if ( !paintDevice || !mLayout )
263 LayoutItemCacheSettingRestorer cacheRestorer( mLayout );
264 ( void )cacheRestorer;
265 LayoutContextPreviewSettingRestorer restorer( mLayout );
267 LayoutGuideHider guideHider( mLayout );
272 mLayout->render( painter, QRectF( 0, 0, paintDevice->width(), paintDevice->height() ), region );
280 LayoutContextPreviewSettingRestorer restorer( mLayout );
283 double resolution = mLayout->renderContext().dpi();
284 double oneInchInLayoutUnits = mLayout->convertToLayoutUnits(
QgsLayoutMeasurement( 1, Qgis::LayoutUnit::Inches ) );
285 if ( imageSize.isValid() )
289 resolution = ( imageSize.width() / region.width()
290 + imageSize.height() / region.height() ) / 2.0 * oneInchInLayoutUnits;
298 int width = imageSize.isValid() ? imageSize.width()
299 :
static_cast< int >( resolution * region.width() / oneInchInLayoutUnits );
300 int height = imageSize.isValid() ? imageSize.height()
301 :
static_cast< int >( resolution * region.height() / oneInchInLayoutUnits );
303 QImage image( QSize( width, height ), QImage::Format_ARGB32 );
304 if ( !image.isNull() )
307 if ( width > 32768 || height > 32768 )
308 QgsMessageLog::logMessage( QObject::tr(
"Error: output width or height is larger than 32768 pixel, result will be clipped" ) );
309 image.setDotsPerMeterX(
static_cast< int >( std::round( resolution / 25.4 * 1000 ) ) );
310 image.setDotsPerMeterY(
static_cast< int>( std::round( resolution / 25.4 * 1000 ) ) );
311 image.fill( Qt::transparent );
312 QPainter imagePainter( &image );
314 if ( !imagePainter.isActive() )
322class LayoutContextSettingsRestorer
327 LayoutContextSettingsRestorer(
QgsLayout *layout )
329 , mPreviousDpi( layout->renderContext().dpi() )
330 , mPreviousFlags( layout->renderContext().flags() )
331 , mPreviousTextFormat( layout->renderContext().textRenderFormat() )
332 , mPreviousExportLayer( layout->renderContext().currentExportLayer() )
333 , mPreviousSimplifyMethod( layout->renderContext().simplifyMethod() )
334 , mExportThemes( layout->renderContext().exportThemes() )
335 , mPredefinedScales( layout->renderContext().predefinedScales() )
340 ~LayoutContextSettingsRestorer()
342 mLayout->renderContext().setDpi( mPreviousDpi );
343 mLayout->renderContext().setFlags( mPreviousFlags );
344 mLayout->renderContext().setTextRenderFormat( mPreviousTextFormat );
346 mLayout->renderContext().setCurrentExportLayer( mPreviousExportLayer );
348 mLayout->renderContext().setSimplifyMethod( mPreviousSimplifyMethod );
349 mLayout->renderContext().setExportThemes( mExportThemes );
350 mLayout->renderContext().setPredefinedScales( mPredefinedScales );
353 LayoutContextSettingsRestorer(
const LayoutContextSettingsRestorer &other ) =
delete;
354 LayoutContextSettingsRestorer &operator=(
const LayoutContextSettingsRestorer &other ) =
delete;
358 double mPreviousDpi = 0;
359 QgsLayoutRenderContext::Flags mPreviousFlags = QgsLayoutRenderContext::Flags();
361 int mPreviousExportLayer = 0;
363 QStringList mExportThemes;
364 QVector< double > mPredefinedScales;
375 if ( settings.
dpi <= 0 )
376 settings.
dpi = mLayout->renderContext().dpi();
378 mErrorFileName.clear();
380 int worldFilePageNo = -1;
383 worldFilePageNo = referenceMap->page();
386 QFileInfo fi( filePath );
388 if ( !dir.exists( fi.absolutePath() ) )
390 dir.mkpath( fi.absolutePath() );
395 pageDetails.
baseName = fi.completeBaseName();
398 LayoutContextPreviewSettingRestorer restorer( mLayout );
400 LayoutContextSettingsRestorer dpiRestorer( mLayout );
402 mLayout->renderContext().setDpi( settings.
dpi );
403 mLayout->renderContext().setFlags( settings.
flags );
407 if ( settings.
pages.empty() )
409 for (
int page = 0; page < mLayout->pageCollection()->pageCount(); ++page )
414 for (
int page : std::as_const( settings.
pages ) )
416 if ( page >= 0 && page < mLayout->pageCollection()->pageCount() )
421 for (
int page : std::as_const( pages ) )
423 if ( !mLayout->pageCollection()->shouldExportPage( page ) )
430 QImage image = createImage( settings, page, bounds, skip );
435 pageDetails.
page = page;
438 if ( image.isNull() )
440 mErrorFileName = outputFilePath;
444 if ( !saveImage( image, outputFilePath, pageDetails.
extension, settings.
exportMetadata ? mLayout->project() :
nullptr ) )
446 mErrorFileName = outputFilePath;
450 const bool shouldGeoreference = ( page == worldFilePageNo );
451 if ( shouldGeoreference )
453 georeferenceOutputPrivate( outputFilePath,
nullptr, bounds, settings.
dpi, shouldGeoreference );
458 double a, b,
c, d, e, f;
459 if ( bounds.isValid() )
464 QFileInfo fi( outputFilePath );
466 QString outputSuffix = fi.suffix();
467 QString worldFileName = fi.absolutePath() +
'/' + fi.completeBaseName() +
'.'
468 + outputSuffix.at( 0 ) + outputSuffix.at( fi.suffix().size() - 1 ) +
'w';
470 writeWorldFile( worldFileName, a, b,
c, d, e, f );
475 captureLabelingResults();
486 int total = iterator->
count();
487 double step = total > 0 ? 100.0 / total : 100.0;
489 while ( iterator->
next() )
494 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
496 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
506 QString filePath = iterator->
filePath( baseFilePath, extension );
511 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 ) );
530 if ( !mLayout || mLayout->pageCollection()->pageCount() == 0 )
534 if ( settings.
dpi <= 0 )
535 settings.
dpi = mLayout->renderContext().dpi();
537 mErrorFileName.clear();
539 LayoutContextPreviewSettingRestorer restorer( mLayout );
541 LayoutContextSettingsRestorer contextRestorer( mLayout );
542 ( void )contextRestorer;
543 mLayout->renderContext().setDpi( settings.
dpi );
548 mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
551 std::unique_ptr< QgsLayoutGeoPdfExporter > geoPdfExporter;
553 geoPdfExporter = std::make_unique< QgsLayoutGeoPdfExporter >( mLayout );
555 mLayout->renderContext().setFlags( settings.
flags );
563 mLayout->renderContext().setExportThemes( settings.
exportThemes );
575 const QList<QGraphicsItem *> items = mLayout->items( Qt::AscendingOrder );
577 QList< QgsLayoutGeoPdfExporter::ComponentLayerDetail > pdfComponents;
587 component.
name = layerDetail.name;
588 component.
mapLayerId = layerDetail.mapLayerId;
589 component.
opacity = layerDetail.opacity;
591 component.
group = layerDetail.mapTheme;
592 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' ) ) );
593 pdfComponents << component;
594 preparePrintAsPdf( mLayout, printer, component.
sourcePdfPath );
595 preparePrint( mLayout, printer,
false );
597 if ( !p.begin( &printer ) )
605 return layerExportResult;
607 result = handleLayeredExport( items, exportFunc );
611 if ( settings.writeGeoPdf )
614 details.
dpi = settings.dpi;
616 QgsLayoutSize pageSize = mLayout->pageCollection()->page( 0 )->sizeWithUnits();
617 QgsLayoutSize pageSizeMM = mLayout->renderContext().measurementConverter().convert( pageSize, Qgis::LayoutUnit::Millimeters );
620 if ( settings.exportMetadata )
623 details.
author = mLayout->project()->metadata().author();
626 details.
creationDateTime = mLayout->project()->metadata().creationDateTime();
627 details.
subject = mLayout->project()->metadata().abstract();
628 details.
title = mLayout->project()->metadata().title();
629 details.
keywords = mLayout->project()->metadata().keywords();
632 const QList< QgsMapLayer * > layers = mLayout->project()->mapLayers().values();
638 if ( settings.appendGeoreference )
641 QList< QgsLayoutItemMap * > maps;
642 mLayout->layoutItems( maps );
646 georef.
crs = map->crs();
648 const QPointF topLeft = map->mapToScene( QPointF( 0, 0 ) );
649 const QPointF topRight = map->mapToScene( QPointF( map->rect().width(), 0 ) );
650 const QPointF bottomLeft = map->mapToScene( QPointF( 0, map->rect().height() ) );
651 const QPointF bottomRight = map->mapToScene( QPointF( map->rect().width(), map->rect().height() ) );
652 const QgsLayoutPoint topLeftMm = mLayout->convertFromLayoutUnits( topLeft, Qgis::LayoutUnit::Millimeters );
653 const QgsLayoutPoint topRightMm = mLayout->convertFromLayoutUnits( topRight, Qgis::LayoutUnit::Millimeters );
654 const QgsLayoutPoint bottomLeftMm = mLayout->convertFromLayoutUnits( bottomLeft, Qgis::LayoutUnit::Millimeters );
655 const QgsLayoutPoint bottomRightMm = mLayout->convertFromLayoutUnits( bottomRight, Qgis::LayoutUnit::Millimeters );
664 const QTransform t = map->layoutToMapCoordsTransform();
665 const QgsPointXY topLeftMap = t.map( topLeft );
666 const QgsPointXY topRightMap = t.map( topRight );
667 const QgsPointXY bottomLeftMap = t.map( bottomLeft );
668 const QgsPointXY bottomRightMap = t.map( bottomRight );
680 details.
layerOrder = geoPdfExporter->layerOrder();
685 if ( !geoPdfExporter->finalize( pdfComponents, filePath, details ) )
696 preparePrintAsPdf( mLayout, printer, filePath );
697 preparePrint( mLayout, printer,
false );
699 if ( !p.begin( &printer ) )
708 bool shouldAppendGeoreference = settings.
appendGeoreference && mLayout && mLayout->referenceMap() && mLayout->referenceMap()->page() == 0;
711 georeferenceOutputPrivate( filePath,
nullptr, QRectF(), settings.
dpi, shouldAppendGeoreference, settings.
exportMetadata );
714 captureLabelingResults();
734 int total = iterator->
count();
735 double step = total > 0 ? 100.0 / total : 100.0;
738 while ( iterator->
next() )
743 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
745 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ) );
757 LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
759 LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
760 ( void )contextRestorer;
782 preparePrintAsPdf( iterator->
layout(), printer, fileName );
783 preparePrint( iterator->
layout(), printer,
false );
785 if ( !p.begin( &printer ) )
799 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 ) );
827 int total = iterator->
count();
828 double step = total > 0 ? 100.0 / total : 100.0;
830 while ( iterator->
next() )
835 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
837 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
846 QString filePath = iterator->
filePath( baseFilePath, QStringLiteral(
"pdf" ) );
853 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 ) );
879 if ( settings.
dpi <= 0 )
880 settings.
dpi = mLayout->renderContext().dpi();
882 mErrorFileName.clear();
884 LayoutContextPreviewSettingRestorer restorer( mLayout );
886 LayoutContextSettingsRestorer contextRestorer( mLayout );
887 ( void )contextRestorer;
888 mLayout->renderContext().setDpi( settings.
dpi );
890 mLayout->renderContext().setFlags( settings.
flags );
897 preparePrint( mLayout, printer,
true );
899 if ( !p.begin( &printer ) )
908 captureLabelingResults();
923 int total = iterator->
count();
924 double step = total > 0 ? 100.0 / total : 100.0;
927 while ( iterator->
next() )
932 feedback->setProperty(
"progress", QObject::tr(
"Printing %1 of %2" ).arg( i + 1 ).arg( total ) );
934 feedback->setProperty(
"progress", QObject::tr(
"Printing section %1" ).arg( i + 1 ).arg( total ) );
946 LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
948 LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
949 ( void )contextRestorer;
962 preparePrint( iterator->
layout(), printer,
true );
964 if ( !p.begin( &printer ) )
1000 if ( settings.
dpi <= 0 )
1001 settings.
dpi = mLayout->renderContext().dpi();
1003 mErrorFileName.clear();
1005 LayoutContextPreviewSettingRestorer restorer( mLayout );
1007 LayoutContextSettingsRestorer contextRestorer( mLayout );
1008 ( void )contextRestorer;
1009 mLayout->renderContext().setDpi( settings.
dpi );
1011 mLayout->renderContext().setFlags( settings.
flags );
1018 mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
1021 QFileInfo fi( filePath );
1024 pageDetails.
baseName = fi.baseName();
1025 pageDetails.
extension = fi.completeSuffix();
1027 double inchesToLayoutUnits = mLayout->convertToLayoutUnits(
QgsLayoutMeasurement( 1, Qgis::LayoutUnit::Inches ) );
1029 for (
int i = 0; i < mLayout->pageCollection()->pageCount(); ++i )
1031 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1036 pageDetails.
page = i;
1043 if ( mLayout->pageCollection()->pageCount() == 1 )
1046 bounds = mLayout->layoutBounds(
true );
1051 bounds = mLayout->pageItemBounds( i,
true );
1060 bounds = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
1064 int width =
static_cast< int >( bounds.width() * settings.
dpi / inchesToLayoutUnits );
1066 int height =
static_cast< int >( bounds.height() * settings.
dpi / inchesToLayoutUnits );
1067 if ( width == 0 || height == 0 )
1076 const QRectF paperRect = QRectF( pageItem->pos().x(),
1077 pageItem->pos().y(),
1078 pageItem->rect().width(),
1079 pageItem->rect().height() );
1081 QDomNode svgDocRoot;
1082 const QList<QGraphicsItem *> items = mLayout->items( paperRect,
1083 Qt::IntersectsItemBoundingRect,
1084 Qt::AscendingOrder );
1088 return renderToLayeredSvg( settings, width, height, i, bounds, fileName, layerId, layerDetail.name, svg, svgDocRoot, settings.
exportMetadata );
1090 ExportResult res = handleLayeredExport( items, exportFunc );
1095 appendMetadataToSvg( svg );
1097 QFile out( fileName );
1098 bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
1101 mErrorFileName = fileName;
1105 out.write( svg.toByteArray() );
1111 QSvgGenerator generator;
1114 generator.setTitle( mLayout->project()->metadata().title() );
1115 generator.setDescription( mLayout->project()->metadata().abstract() );
1117 generator.setOutputDevice( &svgBuffer );
1118 generator.setSize( QSize( width, height ) );
1119 generator.setViewBox( QRect( 0, 0, width, height ) );
1120 generator.setResolution(
static_cast< int >( std::round( settings.
dpi ) ) );
1123 bool createOk = p.begin( &generator );
1126 mErrorFileName = fileName;
1139 svgBuffer.open( QIODevice::ReadOnly );
1143 if ( ! svg.setContent( &svgBuffer,
false, &errorMsg, &errorLine ) )
1145 mErrorFileName = fileName;
1150 appendMetadataToSvg( svg );
1152 QFile out( fileName );
1153 bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
1156 mErrorFileName = fileName;
1160 out.write( svg.toByteArray() );
1164 captureLabelingResults();
1175 int total = iterator->
count();
1176 double step = total > 0 ? 100.0 / total : 100.0;
1178 while ( iterator->
next() )
1183 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
1185 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
1195 QString filePath = iterator->
filePath( baseFilePath, QStringLiteral(
"svg" ) );
1202 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 ) );
1221 return mLabelingResults;
1226 QMap<QString, QgsLabelingResults *> res;
1227 std::swap( mLabelingResults, res );
1231#ifndef QT_NO_PRINTER
1232void QgsLayoutExporter::preparePrintAsPdf(
QgsLayout *layout, QPrinter &printer,
const QString &filePath )
1234 QFileInfo fi( filePath );
1236 if ( !dir.exists( fi.absolutePath() ) )
1238 dir.mkpath( fi.absolutePath() );
1241 printer.setOutputFileName( filePath );
1242 printer.setOutputFormat( QPrinter::PdfFormat );
1244 updatePrinterPageSize(
layout, printer, firstPageToBeExported(
layout ) );
1250#if defined(HAS_KDE_QT5_PDF_TRANSFORM_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
1257void QgsLayoutExporter::preparePrint(
QgsLayout *layout, QPrinter &printer,
bool setFirstPageSize )
1259 printer.setFullPage(
true );
1260 printer.setColorMode( QPrinter::Color );
1265 if ( setFirstPageSize )
1267 updatePrinterPageSize(
layout, printer, firstPageToBeExported(
layout ) );
1273 if ( mLayout->pageCollection()->pageCount() == 0 )
1276 preparePrint( mLayout, printer,
true );
1278 if ( !p.begin( &printer ) )
1284 printPrivate( printer, p );
1292 int fromPage = ( printer.fromPage() < 1 ) ? 0 : printer.fromPage() - 1;
1293 int toPage = ( printer.toPage() < 1 ) ? mLayout->pageCollection()->pageCount() - 1 : printer.toPage() - 1;
1295 bool pageExported =
false;
1298 for (
int i = fromPage; i <= toPage; ++i )
1300 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1305 updatePrinterPageSize( mLayout, printer, i );
1306 if ( ( pageExported && i > fromPage ) || startNewPage )
1312 if ( !image.isNull() )
1314 QRectF targetArea( 0, 0, image.width(), image.height() );
1315 painter.drawImage( targetArea, image, targetArea );
1321 pageExported =
true;
1326 for (
int i = fromPage; i <= toPage; ++i )
1328 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1333 updatePrinterPageSize( mLayout, printer, i );
1335 if ( ( pageExported && i > fromPage ) || startNewPage )
1340 pageExported =
true;
1346void QgsLayoutExporter::updatePrinterPageSize(
QgsLayout *layout, QPrinter &printer,
int page )
1351 QPageLayout pageLayout( QPageSize( pageSizeMM.
toQSizeF(), QPageSize::Millimeter ),
1352 QPageLayout::Portrait,
1353 QMarginsF( 0, 0, 0, 0 ) );
1354 pageLayout.setMode( QPageLayout::FullPageMode );
1355 printer.setPageLayout( pageLayout );
1356 printer.setFullPage(
true );
1357 printer.setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
1361QgsLayoutExporter::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
1365 QSvgGenerator generator;
1366 if ( includeMetadata )
1369 generator.setTitle( l->name() );
1370 else if ( mLayout->project() )
1371 generator.setTitle( mLayout->project()->title() );
1374 generator.setOutputDevice( &svgBuffer );
1375 generator.setSize( QSize(
static_cast< int >( std::round( width ) ),
1376 static_cast< int >( std::round( height ) ) ) );
1377 generator.setViewBox( QRect( 0, 0,
1378 static_cast< int >( std::round( width ) ),
1379 static_cast< int >( std::round( height ) ) ) );
1380 generator.setResolution(
static_cast< int >( std::round( settings.dpi ) ) );
1382 QPainter svgPainter( &generator );
1383 if ( settings.cropToContents )
1394 svgBuffer.open( QIODevice::ReadOnly );
1398 if ( ! doc.setContent( &svgBuffer,
false, &errorMsg, &errorLine ) )
1400 mErrorFileName = filename;
1403 if ( 1 == svgLayerId )
1405 svg = QDomDocument( doc.doctype() );
1406 svg.appendChild( svg.importNode( doc.firstChild(),
false ) );
1407 svgDocRoot = svg.importNode( doc.elementsByTagName( QStringLiteral(
"svg" ) ).at( 0 ),
false );
1408 svgDocRoot.toElement().setAttribute( QStringLiteral(
"xmlns:inkscape" ), QStringLiteral(
"http://www.inkscape.org/namespaces/inkscape" ) );
1409 svg.appendChild( svgDocRoot );
1411 QDomNode mainGroup = svg.importNode( doc.elementsByTagName( QStringLiteral(
"g" ) ).at( 0 ),
true );
1412 mainGroup.toElement().setAttribute( QStringLiteral(
"id" ), layerName );
1413 mainGroup.toElement().setAttribute( QStringLiteral(
"inkscape:label" ), layerName );
1414 mainGroup.toElement().setAttribute( QStringLiteral(
"inkscape:groupmode" ), QStringLiteral(
"layer" ) );
1415 QDomNode defs = svg.importNode( doc.elementsByTagName( QStringLiteral(
"defs" ) ).at( 0 ),
true );
1416 svgDocRoot.appendChild( defs );
1417 svgDocRoot.appendChild( mainGroup );
1422void QgsLayoutExporter::appendMetadataToSvg( QDomDocument &svg )
const
1425 QDomElement metadataElement = svg.createElement( QStringLiteral(
"metadata" ) );
1426 QDomElement rdfElement = svg.createElement( QStringLiteral(
"rdf:RDF" ) );
1427 rdfElement.setAttribute( QStringLiteral(
"xmlns:rdf" ), QStringLiteral(
"http://www.w3.org/1999/02/22-rdf-syntax-ns#" ) );
1428 rdfElement.setAttribute( QStringLiteral(
"xmlns:rdfs" ), QStringLiteral(
"http://www.w3.org/2000/01/rdf-schema#" ) );
1429 rdfElement.setAttribute( QStringLiteral(
"xmlns:dc" ), QStringLiteral(
"http://purl.org/dc/elements/1.1/" ) );
1430 QDomElement descriptionElement = svg.createElement( QStringLiteral(
"rdf:Description" ) );
1431 QDomElement workElement = svg.createElement( QStringLiteral(
"cc:Work" ) );
1432 workElement.setAttribute( QStringLiteral(
"rdf:about" ), QString() );
1434 auto addTextNode = [&workElement, &descriptionElement, &svg](
const QString & tag,
const QString & value )
1437 QDomElement element = svg.createElement( tag );
1438 QDomText t = svg.createTextNode( value );
1439 element.appendChild( t );
1440 workElement.appendChild( element );
1443 descriptionElement.setAttribute( tag, value );
1446 addTextNode( QStringLiteral(
"dc:format" ), QStringLiteral(
"image/svg+xml" ) );
1447 addTextNode( QStringLiteral(
"dc:title" ), metadata.
title() );
1448 addTextNode( QStringLiteral(
"dc:date" ), metadata.
creationDateTime().toString( Qt::ISODate ) );
1449 addTextNode( QStringLiteral(
"dc:identifier" ), metadata.
identifier() );
1450 addTextNode( QStringLiteral(
"dc:description" ), metadata.
abstract() );
1452 auto addAgentNode = [&workElement, &descriptionElement, &svg](
const QString & tag,
const QString & value )
1455 QDomElement inkscapeElement = svg.createElement( tag );
1456 QDomElement agentElement = svg.createElement( QStringLiteral(
"cc:Agent" ) );
1457 QDomElement titleElement = svg.createElement( QStringLiteral(
"dc:title" ) );
1458 QDomText t = svg.createTextNode( value );
1459 titleElement.appendChild( t );
1460 agentElement.appendChild( titleElement );
1461 inkscapeElement.appendChild( agentElement );
1462 workElement.appendChild( inkscapeElement );
1465 QDomElement bagElement = svg.createElement( QStringLiteral(
"rdf:Bag" ) );
1466 QDomElement liElement = svg.createElement( QStringLiteral(
"rdf:li" ) );
1467 t = svg.createTextNode( value );
1468 liElement.appendChild( t );
1469 bagElement.appendChild( liElement );
1471 QDomElement element = svg.createElement( tag );
1472 element.appendChild( bagElement );
1473 descriptionElement.appendChild( element );
1476 addAgentNode( QStringLiteral(
"dc:creator" ), metadata.
author() );
1477 addAgentNode( QStringLiteral(
"dc:publisher" ), QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() ) );
1481 QDomElement element = svg.createElement( QStringLiteral(
"dc:subject" ) );
1482 QDomElement bagElement = svg.createElement( QStringLiteral(
"rdf:Bag" ) );
1484 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
1486 const QStringList words = it.value();
1487 for (
const QString &keyword : words )
1489 QDomElement liElement = svg.createElement( QStringLiteral(
"rdf:li" ) );
1490 QDomText t = svg.createTextNode( keyword );
1491 liElement.appendChild( t );
1492 bagElement.appendChild( liElement );
1495 element.appendChild( bagElement );
1496 workElement.appendChild( element );
1497 descriptionElement.appendChild( element );
1500 rdfElement.appendChild( descriptionElement );
1501 rdfElement.appendChild( workElement );
1502 metadataElement.appendChild( rdfElement );
1503 svg.documentElement().appendChild( metadataElement );
1504 svg.documentElement().setAttribute( QStringLiteral(
"xmlns:cc" ), QStringLiteral(
"http://creativecommons.org/ns#" ) );
1507std::unique_ptr<double[]> QgsLayoutExporter::computeGeoTransform(
const QgsLayoutItemMap *map,
const QRectF ®ion,
double dpi )
const
1510 map = mLayout->referenceMap();
1516 dpi = mLayout->renderContext().dpi();
1519 QRectF exportRegion = region;
1520 if ( !exportRegion.isValid() )
1522 int pageNumber = map->
page();
1525 double pageY = page->pos().y();
1526 QSizeF pageSize = page->rect().size();
1527 exportRegion = QRectF( 0, pageY, pageSize.width(), pageSize.height() );
1531 QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
1534 double outputHeightMM = exportRegion.height();
1535 double outputWidthMM = exportRegion.width();
1539 double mapXCenter = mapExtent.
center().
x();
1540 double mapYCenter = mapExtent.
center().
y();
1542 double sinAlpha = std::sin( alpha );
1543 double cosAlpha = std::cos( alpha );
1546 QPointF mapItemPos = map->pos();
1548 mapItemPos.rx() -= exportRegion.left();
1549 mapItemPos.ry() -= exportRegion.top();
1552 double xRatio = mapExtent.
width() / mapItemSceneRect.width();
1553 double yRatio = mapExtent.
height() / mapItemSceneRect.height();
1554 double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
1555 double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
1556 QgsRectangle paperExtent( xmin, ymax - outputHeightMM * yRatio, xmin + outputWidthMM * xRatio, ymax );
1559 double X0 = paperExtent.xMinimum();
1560 double Y0 = paperExtent.yMaximum();
1565 double X1 = X0 - mapXCenter;
1566 double Y1 = Y0 - mapYCenter;
1567 double X2 = X1 * cosAlpha + Y1 * sinAlpha;
1568 double Y2 = -X1 * sinAlpha + Y1 * cosAlpha;
1569 X0 = X2 + mapXCenter;
1570 Y0 = Y2 + mapYCenter;
1574 int pageWidthPixels =
static_cast< int >( dpi * outputWidthMM / 25.4 );
1575 int pageHeightPixels =
static_cast< int >( dpi * outputHeightMM / 25.4 );
1576 double pixelWidthScale = paperExtent.width() / pageWidthPixels;
1577 double pixelHeightScale = paperExtent.height() / pageHeightPixels;
1580 std::unique_ptr<double[]> t(
new double[6] );
1582 t[1] = cosAlpha * pixelWidthScale;
1583 t[2] = -sinAlpha * pixelWidthScale;
1585 t[4] = -sinAlpha * pixelHeightScale;
1586 t[5] = -cosAlpha * pixelHeightScale;
1591void QgsLayoutExporter::writeWorldFile(
const QString &worldFileName,
double a,
double b,
double c,
double d,
double e,
double f )
const
1593 QFile worldFile( worldFileName );
1594 if ( !worldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
1598 QTextStream fout( &worldFile );
1602 fout << QString::number( a,
'f', 12 ) <<
"\r\n";
1603 fout << QString::number( d,
'f', 12 ) <<
"\r\n";
1604 fout << QString::number( b,
'f', 12 ) <<
"\r\n";
1605 fout << QString::number( e,
'f', 12 ) <<
"\r\n";
1606 fout << QString::number(
c,
'f', 12 ) <<
"\r\n";
1607 fout << QString::number( f,
'f', 12 ) <<
"\r\n";
1612 return georeferenceOutputPrivate( file, map, exportRegion, dpi,
false );
1615bool QgsLayoutExporter::georeferenceOutputPrivate(
const QString &file,
QgsLayoutItemMap *map,
const QRectF &exportRegion,
double dpi,
bool includeGeoreference,
bool includeMetadata )
const
1620 if ( !map && includeGeoreference )
1621 map = mLayout->referenceMap();
1623 std::unique_ptr<double[]> t;
1625 if ( map && includeGeoreference )
1628 dpi = mLayout->renderContext().dpi();
1630 t = computeGeoTransform( map, exportRegion, dpi );
1635 CPLSetConfigOption(
"GDAL_PDF_DPI", QString::number( dpi ).toUtf8().constData() );
1640 GDALSetGeoTransform( outputDS.get(), t.get() );
1642 if ( includeMetadata )
1644 QString creationDateString;
1645 const QDateTime creationDateTime = mLayout->project()->metadata().creationDateTime();
1646 if ( creationDateTime.isValid() )
1648 creationDateString = QStringLiteral(
"D:%1" ).arg( mLayout->project()->metadata().creationDateTime().toString( QStringLiteral(
"yyyyMMddHHmmss" ) ) );
1649 if ( creationDateTime.timeZone().isValid() )
1651 int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
1652 creationDateString += ( offsetFromUtc >= 0 ) ?
'+' :
'-';
1653 offsetFromUtc = std::abs( offsetFromUtc );
1654 int offsetHours = offsetFromUtc / 3600;
1655 int offsetMins = ( offsetFromUtc % 3600 ) / 60;
1656 creationDateString += QStringLiteral(
"%1'%2'" ).arg( offsetHours ).arg( offsetMins );
1659 GDALSetMetadataItem( outputDS.get(),
"CREATION_DATE", creationDateString.toUtf8().constData(),
nullptr );
1661 GDALSetMetadataItem( outputDS.get(),
"AUTHOR", mLayout->project()->metadata().author().toUtf8().constData(),
nullptr );
1662 const QString creator = QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() );
1663 GDALSetMetadataItem( outputDS.get(),
"CREATOR", creator.toUtf8().constData(),
nullptr );
1664 GDALSetMetadataItem( outputDS.get(),
"PRODUCER", creator.toUtf8().constData(),
nullptr );
1665 GDALSetMetadataItem( outputDS.get(),
"SUBJECT", mLayout->project()->metadata().abstract().toUtf8().constData(),
nullptr );
1666 GDALSetMetadataItem( outputDS.get(),
"TITLE", mLayout->project()->metadata().title().toUtf8().constData(),
nullptr );
1669 QStringList allKeywords;
1670 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
1672 allKeywords.append( QStringLiteral(
"%1: %2" ).arg( it.key(), it.value().join(
',' ) ) );
1674 const QString keywordString = allKeywords.join(
';' );
1675 GDALSetMetadataItem( outputDS.get(),
"KEYWORDS", keywordString.toUtf8().constData(),
nullptr );
1681 CPLSetConfigOption(
"GDAL_PDF_DPI",
nullptr );
1688 if ( items.count() == 1 )
1692 QString name = layoutItem->displayName();
1694 if ( name.startsWith(
'<' ) && name.endsWith(
'>' ) )
1695 name = name.mid( 1, name.length() - 2 );
1699 else if ( items.count() > 1 )
1701 QStringList currentLayerItemTypes;
1702 for ( QGraphicsItem *item : items )
1708 if ( !currentLayerItemTypes.contains( itemType ) && !currentLayerItemTypes.contains( itemTypePlural ) )
1709 currentLayerItemTypes << itemType;
1710 else if ( currentLayerItemTypes.contains( itemType ) )
1712 currentLayerItemTypes.replace( currentLayerItemTypes.indexOf( itemType ), itemTypePlural );
1717 if ( !currentLayerItemTypes.contains( QObject::tr(
"Other" ) ) )
1718 currentLayerItemTypes.append( QObject::tr(
"Other" ) );
1721 return currentLayerItemTypes.join( QLatin1String(
", " ) );
1723 return QObject::tr(
"Layer %1" ).arg( layerId );
1729 LayoutItemHider itemHider( items );
1734 unsigned int layerId = 1;
1736 itemHider.hideAll();
1737 const QList< QGraphicsItem * > itemsToIterate = itemHider.itemsToIterate();
1738 QList< QGraphicsItem * > currentLayerItems;
1739 for ( QGraphicsItem *item : itemsToIterate )
1743 bool canPlaceInExistingLayer =
false;
1750 switch ( prevItemBehavior )
1753 canPlaceInExistingLayer =
true;
1757 canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
1762 canPlaceInExistingLayer =
false;
1770 switch ( prevItemBehavior )
1774 canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
1779 canPlaceInExistingLayer =
false;
1787 canPlaceInExistingLayer =
false;
1792 canPlaceInExistingLayer =
false;
1796 prevType = layoutItem->
type();
1803 if ( canPlaceInExistingLayer )
1805 currentLayerItems << item;
1810 if ( !currentLayerItems.isEmpty() )
1814 ExportResult result = exportFunc( layerId, layerDetails );
1818 currentLayerItems.clear();
1821 itemHider.hideAll();
1826 int layoutItemLayerIdx = 0;
1828 mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
1834 mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
1838 ExportResult result = exportFunc( layerId, layerDetails );
1843 layoutItemLayerIdx++;
1845 layerDetails.mapLayerId.clear();
1847 mLayout->renderContext().setCurrentExportLayer( -1 );
1850 currentLayerItems.clear();
1854 currentLayerItems << item;
1858 if ( !currentLayerItems.isEmpty() )
1861 ExportResult result = exportFunc( layerId, layerDetails );
1876 return simplifyMethod;
1890 int pageNumber = map->
page();
1892 double pageY = page->pos().y();
1893 QSizeF pageSize = page->rect().size();
1894 QRectF pageRect( 0, pageY, pageSize.width(), pageSize.height() );
1910 double destinationHeight = exportRegion.height();
1911 double destinationWidth = exportRegion.width();
1913 QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
1918 double xRatio = mapExtent.
width() / mapItemSceneRect.width();
1919 double yRatio = mapExtent.
height() / mapItemSceneRect.height();
1921 double xCenter = mapExtent.
center().
x();
1922 double yCenter = mapExtent.
center().
y();
1925 QPointF mapItemPos = map->pos();
1927 mapItemPos.rx() -= exportRegion.left();
1928 mapItemPos.ry() -= exportRegion.top();
1930 double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
1931 double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
1932 QgsRectangle paperExtent( xmin, ymax - destinationHeight * yRatio, xmin + destinationWidth * xRatio, ymax );
1934 double X0 = paperExtent.
xMinimum();
1935 double Y0 = paperExtent.
yMinimum();
1938 dpi = mLayout->renderContext().dpi();
1940 int widthPx =
static_cast< int >( dpi * destinationWidth / 25.4 );
1941 int heightPx =
static_cast< int >( dpi * destinationHeight / 25.4 );
1943 double Ww = paperExtent.
width() / widthPx;
1944 double Hh = paperExtent.
height() / heightPx;
1953 s[5] = Y0 + paperExtent.
height();
1957 r[0] = std::cos( alpha );
1958 r[1] = -std::sin( alpha );
1959 r[2] = xCenter * ( 1 - std::cos( alpha ) ) + yCenter * std::sin( alpha );
1960 r[3] = std::sin( alpha );
1961 r[4] = std::cos( alpha );
1962 r[5] = - xCenter * std::sin( alpha ) + yCenter * ( 1 - std::cos( alpha ) );
1965 a = r[0] * s[0] + r[1] * s[3];
1966 b = r[0] * s[1] + r[1] * s[4];
1967 c = r[0] * s[2] + r[1] * s[5] + r[2];
1968 d = r[3] * s[0] + r[4] * s[3];
1969 e = r[3] * s[1] + r[4] * s[4];
1970 f = r[3] * s[2] + r[4] * s[5] + r[5];
1978 QList< QgsLayoutItem *> items;
1984 if ( currentItem->isVisible() && currentItem->requiresRasterization() )
1995 QList< QgsLayoutItem *> items;
2001 if ( currentItem->isVisible() && currentItem->containsAdvancedEffects() )
2014 if ( mLayout->pageCollection()->pageCount() == 1 )
2017 bounds = mLayout->layoutBounds(
true );
2022 bounds = mLayout->pageItemBounds( page,
true );
2024 if ( bounds.width() <= 0 || bounds.height() <= 0 )
2031 double pixelToLayoutUnits = mLayout->convertToLayoutUnits(
QgsLayoutMeasurement( 1, Qgis::LayoutUnit::Pixels ) );
2032 bounds = bounds.adjusted( -settings.
cropMargins.
left() * pixelToLayoutUnits,
2044int QgsLayoutExporter::firstPageToBeExported(
QgsLayout *layout )
2047 for (
int i = 0; i < pageCount; ++i )
2061 if ( details.
page == 0 )
2071void QgsLayoutExporter::captureLabelingResults()
2073 qDeleteAll( mLabelingResults );
2074 mLabelingResults.clear();
2076 QList< QgsLayoutItemMap * > maps;
2077 mLayout->layoutItems( maps );
2081 mLabelingResults[ map->
uuid() ] = map->mExportLabelingResults.release();
2085bool QgsLayoutExporter::saveImage(
const QImage &image,
const QString &imageFilename,
const QString &imageFormat,
QgsProject *projectForMetadata )
2087 QImageWriter w( imageFilename, imageFormat.toLocal8Bit().constData() );
2088 if ( imageFormat.compare( QLatin1String(
"tiff" ), Qt::CaseInsensitive ) == 0 || imageFormat.compare( QLatin1String(
"tif" ), Qt::CaseInsensitive ) == 0 )
2090 w.setCompression( 1 );
2092 if ( projectForMetadata )
2094 w.setText( QStringLiteral(
"Author" ), projectForMetadata->
metadata().
author() );
2095 const QString creator = QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() );
2096 w.setText( QStringLiteral(
"Creator" ), creator );
2097 w.setText( QStringLiteral(
"Producer" ), creator );
2098 w.setText( QStringLiteral(
"Subject" ), projectForMetadata->
metadata().
abstract() );
2099 w.setText( QStringLiteral(
"Created" ), projectForMetadata->
metadata().
creationDateTime().toString( Qt::ISODate ) );
2100 w.setText( QStringLiteral(
"Title" ), projectForMetadata->
metadata().
title() );
2103 QStringList allKeywords;
2104 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
2106 allKeywords.append( QStringLiteral(
"%1: %2" ).arg( it.key(), it.value().join(
',' ) ) );
2108 const QString keywordString = allKeywords.join(
';' );
2109 w.setText( QStringLiteral(
"Keywords" ), keywordString );
2111 return w.write( image );
static QString version()
Version string.
TextRenderFormat
Options for rendering text.
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.
@ WKT_PREFERRED_GDAL
Preferred format for conversion of CRS to WKT for use with the GDAL library.
QString toWkt(WktVariant variant=WKT1_GDAL, 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 SIP_HOLDGIL
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.
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.
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.
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.
ExportResult print(QPrinter &printer, const QgsLayoutExporter::PrintExportSettings &settings)
Prints the layout to a printer, using the specified export settings.
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.
QgsLayoutExporter(QgsLayout *layout)
Constructor for QgsLayoutExporter, for the specified layout.
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.
@ 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 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.
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 yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
This class contains information how to simplify geometries fetched from a vector layer.
void setSimplifyHints(SimplifyHints simplifyHints)
Sets the simplification hints of the vector layer managed.
void setThreshold(float threshold)
Sets the simplification threshold of the vector layer managed.
void setSimplifyAlgorithm(SimplifyAlgorithm simplifyAlgorithm)
Sets the local simplification algorithm of the vector layer managed.
void setForceLocalOptimization(bool localOptimization)
Sets where the simplification executes, after fetch the geometries from provider, or when supported,...
@ 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,...
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 ISO3200 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.
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.