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 ) );
529 if ( !mLayout || mLayout->pageCollection()->pageCount() == 0 )
533 if ( settings.
dpi <= 0 )
534 settings.
dpi = mLayout->renderContext().dpi();
536 mErrorFileName.clear();
538 LayoutContextPreviewSettingRestorer restorer( mLayout );
540 LayoutContextSettingsRestorer contextRestorer( mLayout );
541 ( void )contextRestorer;
542 mLayout->renderContext().setDpi( settings.
dpi );
547 mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
550 std::unique_ptr< QgsLayoutGeoPdfExporter > geoPdfExporter;
552 geoPdfExporter = std::make_unique< QgsLayoutGeoPdfExporter >( mLayout );
554 mLayout->renderContext().setFlags( settings.
flags );
562 mLayout->renderContext().setExportThemes( settings.
exportThemes );
574 const QList<QGraphicsItem *> items = mLayout->items( Qt::AscendingOrder );
576 QList< QgsLayoutGeoPdfExporter::ComponentLayerDetail > pdfComponents;
585 component.
name = layerDetail.name;
586 component.
mapLayerId = layerDetail.mapLayerId;
587 component.
opacity = layerDetail.opacity;
589 component.
group = layerDetail.mapTheme;
590 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' ) ) );
591 pdfComponents << component;
593 preparePrintAsPdf( mLayout, &printer, component.
sourcePdfPath );
594 preparePrint( mLayout, &printer,
false );
596 if ( !p.begin( &printer ) )
604 return layerExportResult;
606 result = handleLayeredExport( items, exportFunc );
610 if ( settings.writeGeoPdf )
613 details.
dpi = settings.dpi;
615 QgsLayoutSize pageSize = mLayout->pageCollection()->page( 0 )->sizeWithUnits();
616 QgsLayoutSize pageSizeMM = mLayout->renderContext().measurementConverter().convert( pageSize, Qgis::LayoutUnit::Millimeters );
619 if ( settings.exportMetadata )
622 details.
author = mLayout->project()->metadata().author();
625 details.
creationDateTime = mLayout->project()->metadata().creationDateTime();
626 details.
subject = mLayout->project()->metadata().abstract();
627 details.
title = mLayout->project()->metadata().title();
628 details.
keywords = mLayout->project()->metadata().keywords();
631 const QList< QgsMapLayer * > layers = mLayout->project()->mapLayers().values();
637 if ( settings.appendGeoreference )
640 QList< QgsLayoutItemMap * > maps;
641 mLayout->layoutItems( maps );
645 georef.
crs = map->crs();
647 const QPointF topLeft = map->mapToScene( QPointF( 0, 0 ) );
648 const QPointF topRight = map->mapToScene( QPointF( map->rect().width(), 0 ) );
649 const QPointF bottomLeft = map->mapToScene( QPointF( 0, map->rect().height() ) );
650 const QPointF bottomRight = map->mapToScene( QPointF( map->rect().width(), map->rect().height() ) );
651 const QgsLayoutPoint topLeftMm = mLayout->convertFromLayoutUnits( topLeft, Qgis::LayoutUnit::Millimeters );
652 const QgsLayoutPoint topRightMm = mLayout->convertFromLayoutUnits( topRight, Qgis::LayoutUnit::Millimeters );
653 const QgsLayoutPoint bottomLeftMm = mLayout->convertFromLayoutUnits( bottomLeft, Qgis::LayoutUnit::Millimeters );
654 const QgsLayoutPoint bottomRightMm = mLayout->convertFromLayoutUnits( bottomRight, Qgis::LayoutUnit::Millimeters );
663 const QTransform t = map->layoutToMapCoordsTransform();
664 const QgsPointXY topLeftMap = t.map( topLeft );
665 const QgsPointXY topRightMap = t.map( topRight );
666 const QgsPointXY bottomLeftMap = t.map( bottomLeft );
667 const QgsPointXY bottomRightMap = t.map( bottomRight );
679 details.
layerOrder = geoPdfExporter->layerOrder();
684 if ( !geoPdfExporter->finalize( pdfComponents, filePath, details ) )
694 QPdfWriter printer = QPdfWriter( filePath );
695 preparePrintAsPdf( mLayout, &printer, filePath );
696 preparePrint( mLayout, &printer,
false );
698 if ( !p.begin( &printer ) )
707 bool shouldAppendGeoreference = settings.
appendGeoreference && mLayout && mLayout->referenceMap() && mLayout->referenceMap()->page() == 0;
710 georeferenceOutputPrivate( filePath,
nullptr, QRectF(), settings.
dpi, shouldAppendGeoreference, settings.
exportMetadata );
713 captureLabelingResults();
726 QPdfWriter printer = QPdfWriter( fileName );
729 int total = iterator->
count();
730 double step = total > 0 ? 100.0 / total : 100.0;
733 while ( iterator->
next() )
738 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
740 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ) );
752 LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
754 LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
755 ( void )contextRestorer;
777 preparePrintAsPdf( iterator->
layout(), &printer, fileName );
778 preparePrint( iterator->
layout(), &printer,
false );
780 if ( !p.begin( &printer ) )
794 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 ) );
818 int total = iterator->
count();
819 double step = total > 0 ? 100.0 / total : 100.0;
821 while ( iterator->
next() )
826 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
828 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
837 QString filePath = iterator->
filePath( baseFilePath, QStringLiteral(
"pdf" ) );
844 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 ) );
867 if ( settings.
dpi <= 0 )
868 settings.
dpi = mLayout->renderContext().dpi();
870 mErrorFileName.clear();
872 LayoutContextPreviewSettingRestorer restorer( mLayout );
874 LayoutContextSettingsRestorer contextRestorer( mLayout );
875 ( void )contextRestorer;
876 mLayout->renderContext().setDpi( settings.
dpi );
878 mLayout->renderContext().setFlags( settings.
flags );
885 preparePrint( mLayout, &printer,
true );
887 if ( !p.begin( &printer ) )
896 captureLabelingResults();
911 int total = iterator->
count();
912 double step = total > 0 ? 100.0 / total : 100.0;
915 while ( iterator->
next() )
920 feedback->setProperty(
"progress", QObject::tr(
"Printing %1 of %2" ).arg( i + 1 ).arg( total ) );
922 feedback->setProperty(
"progress", QObject::tr(
"Printing section %1" ).arg( i + 1 ).arg( total ) );
934 LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
936 LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
937 ( void )contextRestorer;
950 preparePrint( iterator->
layout(), &printer,
true );
952 if ( !p.begin( &printer ) )
988 if ( settings.
dpi <= 0 )
989 settings.
dpi = mLayout->renderContext().dpi();
991 mErrorFileName.clear();
993 LayoutContextPreviewSettingRestorer restorer( mLayout );
995 LayoutContextSettingsRestorer contextRestorer( mLayout );
996 ( void )contextRestorer;
997 mLayout->renderContext().setDpi( settings.
dpi );
999 mLayout->renderContext().setFlags( settings.
flags );
1006 mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
1009 QFileInfo fi( filePath );
1012 pageDetails.
baseName = fi.baseName();
1013 pageDetails.
extension = fi.completeSuffix();
1015 double inchesToLayoutUnits = mLayout->convertToLayoutUnits(
QgsLayoutMeasurement( 1, Qgis::LayoutUnit::Inches ) );
1017 for (
int i = 0; i < mLayout->pageCollection()->pageCount(); ++i )
1019 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1024 pageDetails.
page = i;
1031 if ( mLayout->pageCollection()->pageCount() == 1 )
1034 bounds = mLayout->layoutBounds(
true );
1039 bounds = mLayout->pageItemBounds( i,
true );
1048 bounds = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
1052 int width =
static_cast< int >( bounds.width() * settings.
dpi / inchesToLayoutUnits );
1054 int height =
static_cast< int >( bounds.height() * settings.
dpi / inchesToLayoutUnits );
1055 if ( width == 0 || height == 0 )
1064 const QRectF paperRect = QRectF( pageItem->pos().x(),
1065 pageItem->pos().y(),
1066 pageItem->rect().width(),
1067 pageItem->rect().height() );
1069 QDomNode svgDocRoot;
1070 const QList<QGraphicsItem *> items = mLayout->items( paperRect,
1071 Qt::IntersectsItemBoundingRect,
1072 Qt::AscendingOrder );
1076 return renderToLayeredSvg( settings, width, height, i, bounds, fileName, layerId, layerDetail.name, svg, svgDocRoot, settings.
exportMetadata );
1078 ExportResult res = handleLayeredExport( items, exportFunc );
1083 appendMetadataToSvg( svg );
1085 QFile out( fileName );
1086 bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
1089 mErrorFileName = fileName;
1093 out.write( svg.toByteArray() );
1099 QSvgGenerator generator;
1102 generator.setTitle( mLayout->project()->metadata().title() );
1103 generator.setDescription( mLayout->project()->metadata().abstract() );
1105 generator.setOutputDevice( &svgBuffer );
1106 generator.setSize( QSize( width, height ) );
1107 generator.setViewBox( QRect( 0, 0, width, height ) );
1108 generator.setResolution(
static_cast< int >( std::round( settings.
dpi ) ) );
1111 bool createOk = p.begin( &generator );
1114 mErrorFileName = fileName;
1127 svgBuffer.open( QIODevice::ReadOnly );
1131 if ( ! svg.setContent( &svgBuffer,
false, &errorMsg, &errorLine ) )
1133 mErrorFileName = fileName;
1138 appendMetadataToSvg( svg );
1140 QFile out( fileName );
1141 bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
1144 mErrorFileName = fileName;
1148 out.write( svg.toByteArray() );
1152 captureLabelingResults();
1163 int total = iterator->
count();
1164 double step = total > 0 ? 100.0 / total : 100.0;
1166 while ( iterator->
next() )
1171 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
1173 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
1183 QString filePath = iterator->
filePath( baseFilePath, QStringLiteral(
"svg" ) );
1190 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 ) );
1209 return mLabelingResults;
1214 QMap<QString, QgsLabelingResults *> res;
1215 std::swap( mLabelingResults, res );
1219void QgsLayoutExporter::preparePrintAsPdf(
QgsLayout *layout, QPagedPaintDevice *device,
const QString &filePath )
1221 QFileInfo fi( filePath );
1223 if ( !dir.exists( fi.absolutePath() ) )
1225 dir.mkpath( fi.absolutePath() );
1228 updatePrinterPageSize(
layout, device, firstPageToBeExported(
layout ) );
1234#if defined(HAS_KDE_QT5_PDF_TRANSFORM_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
1241void QgsLayoutExporter::preparePrint(
QgsLayout *layout, QPagedPaintDevice *device,
bool setFirstPageSize )
1243 if ( QPdfWriter *pdf =
dynamic_cast<QPdfWriter *
>( device ) )
1247#ifndef QT_NO_PRINTER
1248 else if ( QPrinter *printer =
dynamic_cast<QPrinter *
>( device ) )
1250 printer->setFullPage(
true );
1251 printer->setColorMode( QPrinter::Color );
1257 if ( setFirstPageSize )
1259 updatePrinterPageSize(
layout, device, firstPageToBeExported(
layout ) );
1265 if ( mLayout->pageCollection()->pageCount() == 0 )
1268 preparePrint( mLayout, device,
true );
1270 if ( !p.begin( device ) )
1276 printPrivate( device, p );
1281QgsLayoutExporter::ExportResult QgsLayoutExporter::printPrivate( QPagedPaintDevice *device, QPainter &painter,
bool startNewPage,
double dpi,
bool rasterize )
1285 int toPage = mLayout->pageCollection()->pageCount() - 1;
1287#ifndef QT_NO_PRINTER
1288 if ( QPrinter *printer =
dynamic_cast<QPrinter *
>( device ) )
1290 if ( printer->fromPage() >= 1 )
1291 fromPage = printer->fromPage() - 1;
1292 if ( printer->toPage() >= 1 )
1293 toPage = printer->toPage() - 1;
1297 bool pageExported =
false;
1300 for (
int i = fromPage; i <= toPage; ++i )
1302 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1307 updatePrinterPageSize( mLayout, device, i );
1308 if ( ( pageExported && i > fromPage ) || startNewPage )
1314 if ( !image.isNull() )
1316 QRectF targetArea( 0, 0, image.width(), image.height() );
1317 painter.drawImage( targetArea, image, targetArea );
1323 pageExported =
true;
1328 for (
int i = fromPage; i <= toPage; ++i )
1330 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1335 updatePrinterPageSize( mLayout, device, i );
1337 if ( ( pageExported && i > fromPage ) || startNewPage )
1342 pageExported =
true;
1348void QgsLayoutExporter::updatePrinterPageSize(
QgsLayout *layout, QPagedPaintDevice *device,
int page )
1353 QPageLayout pageLayout( QPageSize( pageSizeMM.
toQSizeF(), QPageSize::Millimeter ),
1354 QPageLayout::Portrait,
1355 QMarginsF( 0, 0, 0, 0 ) );
1356 pageLayout.setMode( QPageLayout::FullPageMode );
1357 device->setPageLayout( pageLayout );
1358 device->setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
1360#ifndef QT_NO_PRINTER
1361 if ( QPrinter *printer =
dynamic_cast<QPrinter *
>( device ) )
1363 printer->setFullPage(
true );
1368QgsLayoutExporter::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
1372 QSvgGenerator generator;
1373 if ( includeMetadata )
1376 generator.setTitle( l->name() );
1377 else if ( mLayout->project() )
1378 generator.setTitle( mLayout->project()->title() );
1381 generator.setOutputDevice( &svgBuffer );
1382 generator.setSize( QSize(
static_cast< int >( std::round( width ) ),
1383 static_cast< int >( std::round( height ) ) ) );
1384 generator.setViewBox( QRect( 0, 0,
1385 static_cast< int >( std::round( width ) ),
1386 static_cast< int >( std::round( height ) ) ) );
1387 generator.setResolution(
static_cast< int >( std::round( settings.dpi ) ) );
1389 QPainter svgPainter( &generator );
1390 if ( settings.cropToContents )
1401 svgBuffer.open( QIODevice::ReadOnly );
1405 if ( ! doc.setContent( &svgBuffer,
false, &errorMsg, &errorLine ) )
1407 mErrorFileName = filename;
1410 if ( 1 == svgLayerId )
1412 svg = QDomDocument( doc.doctype() );
1413 svg.appendChild( svg.importNode( doc.firstChild(),
false ) );
1414 svgDocRoot = svg.importNode( doc.elementsByTagName( QStringLiteral(
"svg" ) ).at( 0 ),
false );
1415 svgDocRoot.toElement().setAttribute( QStringLiteral(
"xmlns:inkscape" ), QStringLiteral(
"http://www.inkscape.org/namespaces/inkscape" ) );
1416 svg.appendChild( svgDocRoot );
1418 QDomNode mainGroup = svg.importNode( doc.elementsByTagName( QStringLiteral(
"g" ) ).at( 0 ),
true );
1419 mainGroup.toElement().setAttribute( QStringLiteral(
"id" ), layerName );
1420 mainGroup.toElement().setAttribute( QStringLiteral(
"inkscape:label" ), layerName );
1421 mainGroup.toElement().setAttribute( QStringLiteral(
"inkscape:groupmode" ), QStringLiteral(
"layer" ) );
1422 QDomNode defs = svg.importNode( doc.elementsByTagName( QStringLiteral(
"defs" ) ).at( 0 ),
true );
1423 svgDocRoot.appendChild( defs );
1424 svgDocRoot.appendChild( mainGroup );
1429void QgsLayoutExporter::appendMetadataToSvg( QDomDocument &svg )
const
1432 QDomElement metadataElement = svg.createElement( QStringLiteral(
"metadata" ) );
1433 QDomElement rdfElement = svg.createElement( QStringLiteral(
"rdf:RDF" ) );
1434 rdfElement.setAttribute( QStringLiteral(
"xmlns:rdf" ), QStringLiteral(
"http://www.w3.org/1999/02/22-rdf-syntax-ns#" ) );
1435 rdfElement.setAttribute( QStringLiteral(
"xmlns:rdfs" ), QStringLiteral(
"http://www.w3.org/2000/01/rdf-schema#" ) );
1436 rdfElement.setAttribute( QStringLiteral(
"xmlns:dc" ), QStringLiteral(
"http://purl.org/dc/elements/1.1/" ) );
1437 QDomElement descriptionElement = svg.createElement( QStringLiteral(
"rdf:Description" ) );
1438 QDomElement workElement = svg.createElement( QStringLiteral(
"cc:Work" ) );
1439 workElement.setAttribute( QStringLiteral(
"rdf:about" ), QString() );
1441 auto addTextNode = [&workElement, &descriptionElement, &svg](
const QString & tag,
const QString & value )
1444 QDomElement element = svg.createElement( tag );
1445 QDomText t = svg.createTextNode( value );
1446 element.appendChild( t );
1447 workElement.appendChild( element );
1450 descriptionElement.setAttribute( tag, value );
1453 addTextNode( QStringLiteral(
"dc:format" ), QStringLiteral(
"image/svg+xml" ) );
1454 addTextNode( QStringLiteral(
"dc:title" ), metadata.
title() );
1455 addTextNode( QStringLiteral(
"dc:date" ), metadata.
creationDateTime().toString( Qt::ISODate ) );
1456 addTextNode( QStringLiteral(
"dc:identifier" ), metadata.
identifier() );
1457 addTextNode( QStringLiteral(
"dc:description" ), metadata.
abstract() );
1459 auto addAgentNode = [&workElement, &descriptionElement, &svg](
const QString & tag,
const QString & value )
1462 QDomElement inkscapeElement = svg.createElement( tag );
1463 QDomElement agentElement = svg.createElement( QStringLiteral(
"cc:Agent" ) );
1464 QDomElement titleElement = svg.createElement( QStringLiteral(
"dc:title" ) );
1465 QDomText t = svg.createTextNode( value );
1466 titleElement.appendChild( t );
1467 agentElement.appendChild( titleElement );
1468 inkscapeElement.appendChild( agentElement );
1469 workElement.appendChild( inkscapeElement );
1472 QDomElement bagElement = svg.createElement( QStringLiteral(
"rdf:Bag" ) );
1473 QDomElement liElement = svg.createElement( QStringLiteral(
"rdf:li" ) );
1474 t = svg.createTextNode( value );
1475 liElement.appendChild( t );
1476 bagElement.appendChild( liElement );
1478 QDomElement element = svg.createElement( tag );
1479 element.appendChild( bagElement );
1480 descriptionElement.appendChild( element );
1483 addAgentNode( QStringLiteral(
"dc:creator" ), metadata.
author() );
1484 addAgentNode( QStringLiteral(
"dc:publisher" ), QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() ) );
1488 QDomElement element = svg.createElement( QStringLiteral(
"dc:subject" ) );
1489 QDomElement bagElement = svg.createElement( QStringLiteral(
"rdf:Bag" ) );
1491 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
1493 const QStringList words = it.value();
1494 for (
const QString &keyword : words )
1496 QDomElement liElement = svg.createElement( QStringLiteral(
"rdf:li" ) );
1497 QDomText t = svg.createTextNode( keyword );
1498 liElement.appendChild( t );
1499 bagElement.appendChild( liElement );
1502 element.appendChild( bagElement );
1503 workElement.appendChild( element );
1504 descriptionElement.appendChild( element );
1507 rdfElement.appendChild( descriptionElement );
1508 rdfElement.appendChild( workElement );
1509 metadataElement.appendChild( rdfElement );
1510 svg.documentElement().appendChild( metadataElement );
1511 svg.documentElement().setAttribute( QStringLiteral(
"xmlns:cc" ), QStringLiteral(
"http://creativecommons.org/ns#" ) );
1514std::unique_ptr<double[]> QgsLayoutExporter::computeGeoTransform(
const QgsLayoutItemMap *map,
const QRectF ®ion,
double dpi )
const
1517 map = mLayout->referenceMap();
1523 dpi = mLayout->renderContext().dpi();
1526 QRectF exportRegion = region;
1527 if ( !exportRegion.isValid() )
1529 int pageNumber = map->
page();
1532 double pageY = page->pos().y();
1533 QSizeF pageSize = page->rect().size();
1534 exportRegion = QRectF( 0, pageY, pageSize.width(), pageSize.height() );
1538 QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
1541 double outputHeightMM = exportRegion.height();
1542 double outputWidthMM = exportRegion.width();
1546 double mapXCenter = mapExtent.
center().
x();
1547 double mapYCenter = mapExtent.
center().
y();
1549 double sinAlpha = std::sin( alpha );
1550 double cosAlpha = std::cos( alpha );
1553 QPointF mapItemPos = map->pos();
1555 mapItemPos.rx() -= exportRegion.left();
1556 mapItemPos.ry() -= exportRegion.top();
1559 double xRatio = mapExtent.
width() / mapItemSceneRect.width();
1560 double yRatio = mapExtent.
height() / mapItemSceneRect.height();
1561 double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
1562 double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
1563 QgsRectangle paperExtent( xmin, ymax - outputHeightMM * yRatio, xmin + outputWidthMM * xRatio, ymax );
1566 double X0 = paperExtent.xMinimum();
1567 double Y0 = paperExtent.yMaximum();
1572 double X1 = X0 - mapXCenter;
1573 double Y1 = Y0 - mapYCenter;
1574 double X2 = X1 * cosAlpha + Y1 * sinAlpha;
1575 double Y2 = -X1 * sinAlpha + Y1 * cosAlpha;
1576 X0 = X2 + mapXCenter;
1577 Y0 = Y2 + mapYCenter;
1581 int pageWidthPixels =
static_cast< int >( dpi * outputWidthMM / 25.4 );
1582 int pageHeightPixels =
static_cast< int >( dpi * outputHeightMM / 25.4 );
1583 double pixelWidthScale = paperExtent.width() / pageWidthPixels;
1584 double pixelHeightScale = paperExtent.height() / pageHeightPixels;
1587 std::unique_ptr<double[]> t(
new double[6] );
1589 t[1] = cosAlpha * pixelWidthScale;
1590 t[2] = -sinAlpha * pixelWidthScale;
1592 t[4] = -sinAlpha * pixelHeightScale;
1593 t[5] = -cosAlpha * pixelHeightScale;
1598void QgsLayoutExporter::writeWorldFile(
const QString &worldFileName,
double a,
double b,
double c,
double d,
double e,
double f )
const
1600 QFile worldFile( worldFileName );
1601 if ( !worldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
1605 QTextStream fout( &worldFile );
1609 fout << QString::number( a,
'f', 12 ) <<
"\r\n";
1610 fout << QString::number( d,
'f', 12 ) <<
"\r\n";
1611 fout << QString::number( b,
'f', 12 ) <<
"\r\n";
1612 fout << QString::number( e,
'f', 12 ) <<
"\r\n";
1613 fout << QString::number(
c,
'f', 12 ) <<
"\r\n";
1614 fout << QString::number( f,
'f', 12 ) <<
"\r\n";
1619 return georeferenceOutputPrivate( file, map, exportRegion, dpi,
false );
1622bool QgsLayoutExporter::georeferenceOutputPrivate(
const QString &file,
QgsLayoutItemMap *map,
const QRectF &exportRegion,
double dpi,
bool includeGeoreference,
bool includeMetadata )
const
1627 if ( !map && includeGeoreference )
1628 map = mLayout->referenceMap();
1630 std::unique_ptr<double[]> t;
1632 if ( map && includeGeoreference )
1635 dpi = mLayout->renderContext().dpi();
1637 t = computeGeoTransform( map, exportRegion, dpi );
1642 CPLSetConfigOption(
"GDAL_PDF_DPI", QString::number( dpi ).toUtf8().constData() );
1647 GDALSetGeoTransform( outputDS.get(), t.get() );
1649 if ( includeMetadata )
1651 QString creationDateString;
1652 const QDateTime creationDateTime = mLayout->project()->metadata().creationDateTime();
1653 if ( creationDateTime.isValid() )
1655 creationDateString = QStringLiteral(
"D:%1" ).arg( mLayout->project()->metadata().creationDateTime().toString( QStringLiteral(
"yyyyMMddHHmmss" ) ) );
1656 if ( creationDateTime.timeZone().isValid() )
1658 int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
1659 creationDateString += ( offsetFromUtc >= 0 ) ?
'+' :
'-';
1660 offsetFromUtc = std::abs( offsetFromUtc );
1661 int offsetHours = offsetFromUtc / 3600;
1662 int offsetMins = ( offsetFromUtc % 3600 ) / 60;
1663 creationDateString += QStringLiteral(
"%1'%2'" ).arg( offsetHours ).arg( offsetMins );
1666 GDALSetMetadataItem( outputDS.get(),
"CREATION_DATE", creationDateString.toUtf8().constData(),
nullptr );
1668 GDALSetMetadataItem( outputDS.get(),
"AUTHOR", mLayout->project()->metadata().author().toUtf8().constData(),
nullptr );
1669 const QString creator = QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() );
1670 GDALSetMetadataItem( outputDS.get(),
"CREATOR", creator.toUtf8().constData(),
nullptr );
1671 GDALSetMetadataItem( outputDS.get(),
"PRODUCER", creator.toUtf8().constData(),
nullptr );
1672 GDALSetMetadataItem( outputDS.get(),
"SUBJECT", mLayout->project()->metadata().abstract().toUtf8().constData(),
nullptr );
1673 GDALSetMetadataItem( outputDS.get(),
"TITLE", mLayout->project()->metadata().title().toUtf8().constData(),
nullptr );
1676 QStringList allKeywords;
1677 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
1679 allKeywords.append( QStringLiteral(
"%1: %2" ).arg( it.key(), it.value().join(
',' ) ) );
1681 const QString keywordString = allKeywords.join(
';' );
1682 GDALSetMetadataItem( outputDS.get(),
"KEYWORDS", keywordString.toUtf8().constData(),
nullptr );
1688 CPLSetConfigOption(
"GDAL_PDF_DPI",
nullptr );
1695 if ( items.count() == 1 )
1699 QString name = layoutItem->displayName();
1701 if ( name.startsWith(
'<' ) && name.endsWith(
'>' ) )
1702 name = name.mid( 1, name.length() - 2 );
1706 else if ( items.count() > 1 )
1708 QStringList currentLayerItemTypes;
1709 for ( QGraphicsItem *item : items )
1715 if ( !currentLayerItemTypes.contains( itemType ) && !currentLayerItemTypes.contains( itemTypePlural ) )
1716 currentLayerItemTypes << itemType;
1717 else if ( currentLayerItemTypes.contains( itemType ) )
1719 currentLayerItemTypes.replace( currentLayerItemTypes.indexOf( itemType ), itemTypePlural );
1724 if ( !currentLayerItemTypes.contains( QObject::tr(
"Other" ) ) )
1725 currentLayerItemTypes.append( QObject::tr(
"Other" ) );
1728 return currentLayerItemTypes.join( QLatin1String(
", " ) );
1730 return QObject::tr(
"Layer %1" ).arg( layerId );
1736 LayoutItemHider itemHider( items );
1741 unsigned int layerId = 1;
1743 itemHider.hideAll();
1744 const QList< QGraphicsItem * > itemsToIterate = itemHider.itemsToIterate();
1745 QList< QGraphicsItem * > currentLayerItems;
1746 for ( QGraphicsItem *item : itemsToIterate )
1750 bool canPlaceInExistingLayer =
false;
1757 switch ( prevItemBehavior )
1760 canPlaceInExistingLayer =
true;
1764 canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
1769 canPlaceInExistingLayer =
false;
1777 switch ( prevItemBehavior )
1781 canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
1786 canPlaceInExistingLayer =
false;
1794 canPlaceInExistingLayer =
false;
1799 canPlaceInExistingLayer =
false;
1803 prevType = layoutItem->
type();
1810 if ( canPlaceInExistingLayer )
1812 currentLayerItems << item;
1817 if ( !currentLayerItems.isEmpty() )
1821 ExportResult result = exportFunc( layerId, layerDetails );
1825 currentLayerItems.clear();
1828 itemHider.hideAll();
1833 int layoutItemLayerIdx = 0;
1835 mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
1841 mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
1845 ExportResult result = exportFunc( layerId, layerDetails );
1850 layoutItemLayerIdx++;
1852 layerDetails.mapLayerId.clear();
1854 mLayout->renderContext().setCurrentExportLayer( -1 );
1857 currentLayerItems.clear();
1861 currentLayerItems << item;
1865 if ( !currentLayerItems.isEmpty() )
1868 ExportResult result = exportFunc( layerId, layerDetails );
1883 return simplifyMethod;
1897 int pageNumber = map->
page();
1899 double pageY = page->pos().y();
1900 QSizeF pageSize = page->rect().size();
1901 QRectF pageRect( 0, pageY, pageSize.width(), pageSize.height() );
1917 double destinationHeight = exportRegion.height();
1918 double destinationWidth = exportRegion.width();
1920 QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
1925 double xRatio = mapExtent.
width() / mapItemSceneRect.width();
1926 double yRatio = mapExtent.
height() / mapItemSceneRect.height();
1928 double xCenter = mapExtent.
center().
x();
1929 double yCenter = mapExtent.
center().
y();
1932 QPointF mapItemPos = map->pos();
1934 mapItemPos.rx() -= exportRegion.left();
1935 mapItemPos.ry() -= exportRegion.top();
1937 double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
1938 double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
1939 QgsRectangle paperExtent( xmin, ymax - destinationHeight * yRatio, xmin + destinationWidth * xRatio, ymax );
1941 double X0 = paperExtent.
xMinimum();
1942 double Y0 = paperExtent.
yMinimum();
1945 dpi = mLayout->renderContext().dpi();
1947 int widthPx =
static_cast< int >( dpi * destinationWidth / 25.4 );
1948 int heightPx =
static_cast< int >( dpi * destinationHeight / 25.4 );
1950 double Ww = paperExtent.
width() / widthPx;
1951 double Hh = paperExtent.
height() / heightPx;
1960 s[5] = Y0 + paperExtent.
height();
1964 r[0] = std::cos( alpha );
1965 r[1] = -std::sin( alpha );
1966 r[2] = xCenter * ( 1 - std::cos( alpha ) ) + yCenter * std::sin( alpha );
1967 r[3] = std::sin( alpha );
1968 r[4] = std::cos( alpha );
1969 r[5] = - xCenter * std::sin( alpha ) + yCenter * ( 1 - std::cos( alpha ) );
1972 a = r[0] * s[0] + r[1] * s[3];
1973 b = r[0] * s[1] + r[1] * s[4];
1974 c = r[0] * s[2] + r[1] * s[5] + r[2];
1975 d = r[3] * s[0] + r[4] * s[3];
1976 e = r[3] * s[1] + r[4] * s[4];
1977 f = r[3] * s[2] + r[4] * s[5] + r[5];
1985 QList< QgsLayoutItem *> items;
1991 if ( currentItem->isVisible() && currentItem->requiresRasterization() )
2002 QList< QgsLayoutItem *> items;
2008 if ( currentItem->isVisible() && currentItem->containsAdvancedEffects() )
2021 if ( mLayout->pageCollection()->pageCount() == 1 )
2024 bounds = mLayout->layoutBounds(
true );
2029 bounds = mLayout->pageItemBounds( page,
true );
2031 if ( bounds.width() <= 0 || bounds.height() <= 0 )
2038 double pixelToLayoutUnits = mLayout->convertToLayoutUnits(
QgsLayoutMeasurement( 1, Qgis::LayoutUnit::Pixels ) );
2039 bounds = bounds.adjusted( -settings.
cropMargins.
left() * pixelToLayoutUnits,
2051int QgsLayoutExporter::firstPageToBeExported(
QgsLayout *layout )
2054 for (
int i = 0; i < pageCount; ++i )
2068 if ( details.
page == 0 )
2078void QgsLayoutExporter::captureLabelingResults()
2080 qDeleteAll( mLabelingResults );
2081 mLabelingResults.clear();
2083 QList< QgsLayoutItemMap * > maps;
2084 mLayout->layoutItems( maps );
2088 mLabelingResults[ map->
uuid() ] = map->mExportLabelingResults.release();
2092bool QgsLayoutExporter::saveImage(
const QImage &image,
const QString &imageFilename,
const QString &imageFormat,
QgsProject *projectForMetadata )
2094 QImageWriter w( imageFilename, imageFormat.toLocal8Bit().constData() );
2095 if ( imageFormat.compare( QLatin1String(
"tiff" ), Qt::CaseInsensitive ) == 0 || imageFormat.compare( QLatin1String(
"tif" ), Qt::CaseInsensitive ) == 0 )
2097 w.setCompression( 1 );
2099 if ( projectForMetadata )
2101 w.setText( QStringLiteral(
"Author" ), projectForMetadata->
metadata().
author() );
2102 const QString creator = QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() );
2103 w.setText( QStringLiteral(
"Creator" ), creator );
2104 w.setText( QStringLiteral(
"Producer" ), creator );
2105 w.setText( QStringLiteral(
"Subject" ), projectForMetadata->
metadata().
abstract() );
2106 w.setText( QStringLiteral(
"Created" ), projectForMetadata->
metadata().
creationDateTime().toString( Qt::ISODate ) );
2107 w.setText( QStringLiteral(
"Title" ), projectForMetadata->
metadata().
title() );
2110 QStringList allKeywords;
2111 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
2113 allKeywords.append( QStringLiteral(
"%1: %2" ).arg( it.key(), it.value().join(
',' ) ) );
2115 const QString keywordString = allKeywords.join(
';' );
2116 w.setText( QStringLiteral(
"Keywords" ), keywordString );
2118 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.