33#include <QImageWriter>
35#include <QSvgGenerator>
44class LayoutContextPreviewSettingRestorer
48 LayoutContextPreviewSettingRestorer(
QgsLayout *layout )
50 , mPreviousSetting( layout->renderContext().mIsPreviewRender )
52 mLayout->renderContext().mIsPreviewRender =
false;
55 ~LayoutContextPreviewSettingRestorer()
57 mLayout->renderContext().mIsPreviewRender = mPreviousSetting;
60 LayoutContextPreviewSettingRestorer(
const LayoutContextPreviewSettingRestorer &other ) =
delete;
61 LayoutContextPreviewSettingRestorer &operator=(
const LayoutContextPreviewSettingRestorer &other ) =
delete;
65 bool mPreviousSetting =
false;
75 const QList< QgsLayoutGuide * > guides = mLayout->guides().guides();
78 mPrevVisibility.insert( guide, guide->item()->isVisible() );
79 guide->item()->setVisible(
false );
85 for (
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
87 it.key()->item()->setVisible( it.value() );
91 LayoutGuideHider(
const LayoutGuideHider &other ) =
delete;
92 LayoutGuideHider &operator=(
const LayoutGuideHider &other ) =
delete;
96 QHash< QgsLayoutGuide *, bool > mPrevVisibility;
102 explicit LayoutItemHider(
const QList<QGraphicsItem *> &items )
104 mItemsToIterate.reserve( items.count() );
105 for ( QGraphicsItem *item : items )
107 const bool isVisible = item->isVisible();
108 mPrevVisibility[item] = isVisible;
110 mItemsToIterate.append( item );
112 layoutItem->setProperty(
"wasVisible", isVisible );
120 for (
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
128 for (
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
130 it.key()->setVisible( it.value() );
132 layoutItem->setProperty(
"wasVisible", QVariant() );
136 QList< QGraphicsItem * > itemsToIterate()
const {
return mItemsToIterate; }
138 LayoutItemHider(
const LayoutItemHider &other ) =
delete;
139 LayoutItemHider &operator=(
const LayoutItemHider &other ) =
delete;
143 QList<QGraphicsItem * > mItemsToIterate;
144 QHash<QGraphicsItem *, bool> mPrevVisibility;
161 qDeleteAll( mLabelingResults );
174 if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
185 LayoutContextPreviewSettingRestorer restorer( mLayout );
188 QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
197 if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
208 LayoutContextPreviewSettingRestorer restorer( mLayout );
211 QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
213 const double imageAspectRatio =
static_cast< double >( imageSize.width() ) / imageSize.height();
214 const double paperAspectRatio = paperRect.width() / paperRect.height();
215 if ( imageSize.isValid() && ( !
qgsDoubleNear( imageAspectRatio, paperAspectRatio, 0.008 ) ) )
220 QgsMessageLog::logMessage( QObject::tr(
"Ignoring custom image size because aspect ratio %1 does not match paper ratio %2" ).arg( QString::number( imageAspectRatio,
'g', 3 ), QString::number( paperAspectRatio,
'g', 3 ) ), QStringLiteral(
"Layout" ),
Qgis::MessageLevel::Warning );
228class LayoutItemCacheSettingRestorer
232 LayoutItemCacheSettingRestorer(
QgsLayout *layout )
235 const QList< QGraphicsItem * > items = mLayout->items();
236 for ( QGraphicsItem *item : items )
238 mPrevCacheMode.insert( item, item->cacheMode() );
239 item->setCacheMode( QGraphicsItem::NoCache );
243 ~LayoutItemCacheSettingRestorer()
245 for (
auto it = mPrevCacheMode.constBegin(); it != mPrevCacheMode.constEnd(); ++it )
247 it.key()->setCacheMode( it.value() );
251 LayoutItemCacheSettingRestorer(
const LayoutItemCacheSettingRestorer &other ) =
delete;
252 LayoutItemCacheSettingRestorer &operator=(
const LayoutItemCacheSettingRestorer &other ) =
delete;
256 QHash< QGraphicsItem *, QGraphicsItem::CacheMode > mPrevCacheMode;
263 QPaintDevice *paintDevice = painter->device();
264 if ( !paintDevice || !mLayout )
269 LayoutItemCacheSettingRestorer cacheRestorer( mLayout );
270 ( void )cacheRestorer;
271 LayoutContextPreviewSettingRestorer restorer( mLayout );
273 LayoutGuideHider guideHider( mLayout );
278 mLayout->render( painter, QRectF( 0, 0, paintDevice->width(), paintDevice->height() ), region );
286 LayoutContextPreviewSettingRestorer restorer( mLayout );
289 double resolution = mLayout->renderContext().dpi();
291 if ( imageSize.isValid() )
295 resolution = ( imageSize.width() / region.width()
296 + imageSize.height() / region.height() ) / 2.0 * oneInchInLayoutUnits;
304 int width = imageSize.isValid() ? imageSize.width()
305 :
static_cast< int >( resolution * region.width() / oneInchInLayoutUnits );
306 int height = imageSize.isValid() ? imageSize.height()
307 :
static_cast< int >( resolution * region.height() / oneInchInLayoutUnits );
309 QImage image( QSize( width, height ), QImage::Format_ARGB32 );
310 if ( !image.isNull() )
313 if ( width > 32768 || height > 32768 )
314 QgsMessageLog::logMessage( QObject::tr(
"Error: output width or height is larger than 32768 pixel, result will be clipped" ) );
315 image.setDotsPerMeterX(
static_cast< int >( std::round( resolution / 25.4 * 1000 ) ) );
316 image.setDotsPerMeterY(
static_cast< int>( std::round( resolution / 25.4 * 1000 ) ) );
317 image.fill( Qt::transparent );
318 QPainter imagePainter( &image );
320 if ( !imagePainter.isActive() )
328class LayoutContextSettingsRestorer
333 LayoutContextSettingsRestorer(
QgsLayout *layout )
335 , mPreviousDpi( layout->renderContext().dpi() )
336 , mPreviousFlags( layout->renderContext().flags() )
337 , mPreviousTextFormat( layout->renderContext().textRenderFormat() )
338 , mPreviousExportLayer( layout->renderContext().currentExportLayer() )
339 , mPreviousSimplifyMethod( layout->renderContext().simplifyMethod() )
340 , mExportThemes( layout->renderContext().exportThemes() )
341 , mPredefinedScales( layout->renderContext().predefinedScales() )
346 ~LayoutContextSettingsRestorer()
348 mLayout->renderContext().setDpi( mPreviousDpi );
349 mLayout->renderContext().setFlags( mPreviousFlags );
350 mLayout->renderContext().setTextRenderFormat( mPreviousTextFormat );
352 mLayout->renderContext().setCurrentExportLayer( mPreviousExportLayer );
354 mLayout->renderContext().setSimplifyMethod( mPreviousSimplifyMethod );
355 mLayout->renderContext().setExportThemes( mExportThemes );
356 mLayout->renderContext().setPredefinedScales( mPredefinedScales );
359 LayoutContextSettingsRestorer(
const LayoutContextSettingsRestorer &other ) =
delete;
360 LayoutContextSettingsRestorer &operator=(
const LayoutContextSettingsRestorer &other ) =
delete;
364 double mPreviousDpi = 0;
365 QgsLayoutRenderContext::Flags mPreviousFlags = QgsLayoutRenderContext::Flags();
367 int mPreviousExportLayer = 0;
369 QStringList mExportThemes;
370 QVector< double > mPredefinedScales;
381 if ( settings.
dpi <= 0 )
382 settings.
dpi = mLayout->renderContext().dpi();
384 mErrorFileName.clear();
386 int worldFilePageNo = -1;
389 worldFilePageNo = referenceMap->page();
392 QFileInfo fi( filePath );
394 if ( !dir.exists( fi.absolutePath() ) )
396 dir.mkpath( fi.absolutePath() );
401 pageDetails.
baseName = fi.completeBaseName();
404 LayoutContextPreviewSettingRestorer restorer( mLayout );
406 LayoutContextSettingsRestorer dpiRestorer( mLayout );
408 mLayout->renderContext().setDpi( settings.
dpi );
409 mLayout->renderContext().setFlags( settings.
flags );
413 if ( settings.
pages.empty() )
415 for (
int page = 0; page < mLayout->pageCollection()->pageCount(); ++page )
420 for (
int page : std::as_const( settings.
pages ) )
422 if ( page >= 0 && page < mLayout->pageCollection()->pageCount() )
427 for (
int page : std::as_const( pages ) )
429 if ( !mLayout->pageCollection()->shouldExportPage( page ) )
436 QImage image = createImage( settings, page, bounds, skip );
441 pageDetails.
page = page;
444 if ( image.isNull() )
446 mErrorFileName = outputFilePath;
450 if ( !saveImage( image, outputFilePath, pageDetails.
extension, settings.
exportMetadata ? mLayout->project() : nullptr ) )
452 mErrorFileName = outputFilePath;
456 const bool shouldGeoreference = ( page == worldFilePageNo );
457 if ( shouldGeoreference )
459 georeferenceOutputPrivate( outputFilePath,
nullptr, bounds, settings.
dpi, shouldGeoreference );
464 double a, b,
c, d, e, f;
465 if ( bounds.isValid() )
470 QFileInfo fi( outputFilePath );
472 QString outputSuffix = fi.suffix();
473 QString worldFileName = fi.absolutePath() +
'/' + fi.completeBaseName() +
'.'
474 + outputSuffix.at( 0 ) + outputSuffix.at( fi.suffix().size() - 1 ) +
'w';
476 writeWorldFile( worldFileName, a, b,
c, d, e, f );
481 captureLabelingResults();
492 int total = iterator->
count();
493 double step = total > 0 ? 100.0 / total : 100.0;
495 while ( iterator->
next() )
500 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
502 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
512 QString filePath = iterator->
filePath( baseFilePath, extension );
517 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 ) );
535 if ( !mLayout || mLayout->pageCollection()->pageCount() == 0 )
539 if ( settings.
dpi <= 0 )
540 settings.
dpi = mLayout->renderContext().dpi();
542 mErrorFileName.clear();
544 LayoutContextPreviewSettingRestorer restorer( mLayout );
546 LayoutContextSettingsRestorer contextRestorer( mLayout );
547 ( void )contextRestorer;
548 mLayout->renderContext().setDpi( settings.
dpi );
553 mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
556 std::unique_ptr< QgsLayoutGeoPdfExporter > geoPdfExporter;
558 geoPdfExporter = std::make_unique< QgsLayoutGeoPdfExporter >( mLayout );
560 mLayout->renderContext().setFlags( settings.
flags );
573 mLayout->renderContext().setExportThemes( settings.
exportThemes );
585 const QList<QGraphicsItem *> items = mLayout->items( Qt::AscendingOrder );
587 QList< QgsLayoutGeoPdfExporter::ComponentLayerDetail > pdfComponents;
596 component.
name = layerDetail.name;
597 component.
mapLayerId = layerDetail.mapLayerId;
598 component.
opacity = layerDetail.opacity;
600 component.
group = layerDetail.mapTheme;
601 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' ) ) );
602 pdfComponents << component;
604 preparePrintAsPdf( mLayout, &printer, component.
sourcePdfPath );
605 preparePrint( mLayout, &printer,
false );
607 if ( !p.begin( &printer ) )
615 return layerExportResult;
617 result = handleLayeredExport( items, exportFunc );
621 if ( settings.writeGeoPdf )
624 details.
dpi = settings.dpi;
626 QgsLayoutSize pageSize = mLayout->pageCollection()->page( 0 )->sizeWithUnits();
630 if ( settings.exportMetadata )
633 details.
author = mLayout->project()->metadata().author();
636 details.
creationDateTime = mLayout->project()->metadata().creationDateTime();
637 details.
subject = mLayout->project()->metadata().abstract();
638 details.
title = mLayout->project()->metadata().title();
639 details.
keywords = mLayout->project()->metadata().keywords();
642 const QList< QgsMapLayer * > layers = mLayout->project()->mapLayers().values();
648 if ( settings.appendGeoreference )
651 QList< QgsLayoutItemMap * > maps;
652 mLayout->layoutItems( maps );
656 georef.
crs = map->crs();
658 const QPointF topLeft = map->mapToScene( QPointF( 0, 0 ) );
659 const QPointF topRight = map->mapToScene( QPointF( map->rect().width(), 0 ) );
660 const QPointF bottomLeft = map->mapToScene( QPointF( 0, map->rect().height() ) );
661 const QPointF bottomRight = map->mapToScene( QPointF( map->rect().width(), map->rect().height() ) );
674 const QTransform t = map->layoutToMapCoordsTransform();
675 const QgsPointXY topLeftMap = t.map( topLeft );
676 const QgsPointXY topRightMap = t.map( topRight );
677 const QgsPointXY bottomLeftMap = t.map( bottomLeft );
678 const QgsPointXY bottomRightMap = t.map( bottomRight );
690 details.
layerOrder = geoPdfExporter->layerOrder();
695 if ( !geoPdfExporter->finalize( pdfComponents, filePath, details ) )
705 QPdfWriter printer = QPdfWriter( filePath );
706 preparePrintAsPdf( mLayout, &printer, filePath );
707 preparePrint( mLayout, &printer,
false );
709 if ( !p.begin( &printer ) )
718 bool shouldAppendGeoreference = settings.
appendGeoreference && mLayout && mLayout->referenceMap() && mLayout->referenceMap()->page() == 0;
721 georeferenceOutputPrivate( filePath,
nullptr, QRectF(), settings.
dpi, shouldAppendGeoreference, settings.
exportMetadata );
724 captureLabelingResults();
737 QPdfWriter printer = QPdfWriter( fileName );
740 int total = iterator->
count();
741 double step = total > 0 ? 100.0 / total : 100.0;
744 while ( iterator->
next() )
749 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
751 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ) );
763 LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
765 LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
766 ( void )contextRestorer;
788 preparePrintAsPdf( iterator->
layout(), &printer, fileName );
789 preparePrint( iterator->
layout(), &printer,
false );
791 if ( !p.begin( &printer ) )
805 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 ) );
829 int total = iterator->
count();
830 double step = total > 0 ? 100.0 / total : 100.0;
832 while ( iterator->
next() )
837 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
839 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
848 QString filePath = iterator->
filePath( baseFilePath, QStringLiteral(
"pdf" ) );
855 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 ) );
871#if defined( HAVE_QTPRINTER )
878 if ( settings.
dpi <= 0 )
879 settings.
dpi = mLayout->renderContext().dpi();
881 mErrorFileName.clear();
883 LayoutContextPreviewSettingRestorer restorer( mLayout );
885 LayoutContextSettingsRestorer contextRestorer( mLayout );
886 ( void )contextRestorer;
887 mLayout->renderContext().setDpi( settings.
dpi );
889 mLayout->renderContext().setFlags( settings.
flags );
896 preparePrint( mLayout, &printer,
true );
898 if ( !p.begin( &printer ) )
907 captureLabelingResults();
918 PrintExportSettings settings = s;
922 int total = iterator->
count();
923 double step = total > 0 ? 100.0 / total : 100.0;
926 while ( iterator->
next() )
931 feedback->setProperty(
"progress", QObject::tr(
"Printing %1 of %2" ).arg( i + 1 ).arg( total ) );
933 feedback->setProperty(
"progress", QObject::tr(
"Printing section %1" ).arg( i + 1 ).arg( total ) );
945 LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
947 LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
948 ( void )contextRestorer;
961 preparePrint( iterator->
layout(), &printer,
true );
963 if ( !p.begin( &printer ) )
973 ExportResult result = exporter.printPrivate( &printer, p, !first, settings.dpi, settings.rasterizeWholeImage );
999 if ( settings.
dpi <= 0 )
1000 settings.
dpi = mLayout->renderContext().dpi();
1002 mErrorFileName.clear();
1004 LayoutContextPreviewSettingRestorer restorer( mLayout );
1006 LayoutContextSettingsRestorer contextRestorer( mLayout );
1007 ( void )contextRestorer;
1008 mLayout->renderContext().setDpi( settings.
dpi );
1010 mLayout->renderContext().setFlags( settings.
flags );
1017 mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
1020 QFileInfo fi( filePath );
1023 pageDetails.
baseName = fi.baseName();
1024 pageDetails.
extension = fi.completeSuffix();
1028 for (
int i = 0; i < mLayout->pageCollection()->pageCount(); ++i )
1030 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1035 pageDetails.
page = i;
1042 if ( mLayout->pageCollection()->pageCount() == 1 )
1045 bounds = mLayout->layoutBounds(
true );
1050 bounds = mLayout->pageItemBounds( i,
true );
1059 bounds = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
1063 int width =
static_cast< int >( bounds.width() * settings.
dpi / inchesToLayoutUnits );
1065 int height =
static_cast< int >( bounds.height() * settings.
dpi / inchesToLayoutUnits );
1066 if ( width == 0 || height == 0 )
1075 const QRectF paperRect = QRectF( pageItem->pos().x(),
1076 pageItem->pos().y(),
1077 pageItem->rect().width(),
1078 pageItem->rect().height() );
1080 QDomNode svgDocRoot;
1081 const QList<QGraphicsItem *> items = mLayout->items( paperRect,
1082 Qt::IntersectsItemBoundingRect,
1083 Qt::AscendingOrder );
1087 return renderToLayeredSvg( settings, width, height, i, bounds, fileName, layerId, layerDetail.name, svg, svgDocRoot, settings.
exportMetadata );
1089 ExportResult res = handleLayeredExport( items, exportFunc );
1094 appendMetadataToSvg( svg );
1096 QFile out( fileName );
1097 bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
1100 mErrorFileName = fileName;
1104 out.write( svg.toByteArray() );
1110 QSvgGenerator generator;
1113 generator.setTitle( mLayout->project()->metadata().title() );
1114 generator.setDescription( mLayout->project()->metadata().abstract() );
1116 generator.setOutputDevice( &svgBuffer );
1117 generator.setSize( QSize( width, height ) );
1118 generator.setViewBox( QRect( 0, 0, width, height ) );
1119 generator.setResolution(
static_cast< int >( std::round( settings.
dpi ) ) );
1122 bool createOk = p.begin( &generator );
1125 mErrorFileName = fileName;
1138 svgBuffer.open( QIODevice::ReadOnly );
1142 if ( ! svg.setContent( &svgBuffer,
false, &errorMsg, &errorLine ) )
1144 mErrorFileName = fileName;
1149 appendMetadataToSvg( svg );
1151 QFile out( fileName );
1152 bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
1155 mErrorFileName = fileName;
1159 out.write( svg.toByteArray() );
1163 captureLabelingResults();
1174 int total = iterator->
count();
1175 double step = total > 0 ? 100.0 / total : 100.0;
1177 while ( iterator->
next() )
1182 feedback->setProperty(
"progress", QObject::tr(
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
1184 feedback->setProperty(
"progress", QObject::tr(
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
1194 QString filePath = iterator->
filePath( baseFilePath, QStringLiteral(
"svg" ) );
1201 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 ) );
1220 return mLabelingResults;
1225 QMap<QString, QgsLabelingResults *> res;
1226 std::swap( mLabelingResults, res );
1230void QgsLayoutExporter::preparePrintAsPdf(
QgsLayout *layout, QPagedPaintDevice *device,
const QString &filePath )
1232 QFileInfo fi( filePath );
1234 if ( !dir.exists( fi.absolutePath() ) )
1236 dir.mkpath( fi.absolutePath() );
1239 updatePrinterPageSize(
layout, device, firstPageToBeExported(
layout ) );
1245#if defined(HAS_KDE_QT5_PDF_TRANSFORM_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
1252void QgsLayoutExporter::preparePrint(
QgsLayout *layout, QPagedPaintDevice *device,
bool setFirstPageSize )
1254 if ( QPdfWriter *pdf =
dynamic_cast<QPdfWriter *
>( device ) )
1258#if defined( HAVE_QTPRINTER )
1259 else if ( QPrinter *printer =
dynamic_cast<QPrinter *
>( device ) )
1261 printer->setFullPage(
true );
1262 printer->setColorMode( QPrinter::Color );
1268 if ( setFirstPageSize )
1270 updatePrinterPageSize(
layout, device, firstPageToBeExported(
layout ) );
1276 if ( mLayout->pageCollection()->pageCount() == 0 )
1279 preparePrint( mLayout, device,
true );
1281 if ( !p.begin( device ) )
1287 printPrivate( device, p );
1292QgsLayoutExporter::ExportResult QgsLayoutExporter::printPrivate( QPagedPaintDevice *device, QPainter &painter,
bool startNewPage,
double dpi,
bool rasterize )
1296 int toPage = mLayout->pageCollection()->pageCount() - 1;
1298#if defined( HAVE_QTPRINTER )
1299 if ( QPrinter *printer =
dynamic_cast<QPrinter *
>( device ) )
1301 if ( printer->fromPage() >= 1 )
1302 fromPage = printer->fromPage() - 1;
1303 if ( printer->toPage() >= 1 )
1304 toPage = printer->toPage() - 1;
1308 bool pageExported =
false;
1311 for (
int i = fromPage; i <= toPage; ++i )
1313 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1318 updatePrinterPageSize( mLayout, device, i );
1319 if ( ( pageExported && i > fromPage ) || startNewPage )
1325 if ( !image.isNull() )
1327 QRectF targetArea( 0, 0, image.width(), image.height() );
1328 painter.drawImage( targetArea, image, targetArea );
1334 pageExported =
true;
1339 for (
int i = fromPage; i <= toPage; ++i )
1341 if ( !mLayout->pageCollection()->shouldExportPage( i ) )
1346 updatePrinterPageSize( mLayout, device, i );
1348 if ( ( pageExported && i > fromPage ) || startNewPage )
1353 pageExported =
true;
1359void QgsLayoutExporter::updatePrinterPageSize(
QgsLayout *layout, QPagedPaintDevice *device,
int page )
1364 QPageLayout pageLayout( QPageSize( pageSizeMM.
toQSizeF(), QPageSize::Millimeter ),
1365 QPageLayout::Portrait,
1366 QMarginsF( 0, 0, 0, 0 ) );
1367 pageLayout.setMode( QPageLayout::FullPageMode );
1368 device->setPageLayout( pageLayout );
1369 device->setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
1371#if defined( HAVE_QTPRINTER )
1372 if ( QPrinter *printer =
dynamic_cast<QPrinter *
>( device ) )
1374 printer->setFullPage(
true );
1379QgsLayoutExporter::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
1383 QSvgGenerator generator;
1384 if ( includeMetadata )
1387 generator.setTitle( l->name() );
1388 else if ( mLayout->project() )
1389 generator.setTitle( mLayout->project()->title() );
1392 generator.setOutputDevice( &svgBuffer );
1393 generator.setSize( QSize(
static_cast< int >( std::round( width ) ),
1394 static_cast< int >( std::round( height ) ) ) );
1395 generator.setViewBox( QRect( 0, 0,
1396 static_cast< int >( std::round( width ) ),
1397 static_cast< int >( std::round( height ) ) ) );
1398 generator.setResolution(
static_cast< int >( std::round( settings.dpi ) ) );
1400 QPainter svgPainter( &generator );
1401 if ( settings.cropToContents )
1412 svgBuffer.open( QIODevice::ReadOnly );
1416 if ( ! doc.setContent( &svgBuffer,
false, &errorMsg, &errorLine ) )
1418 mErrorFileName = filename;
1421 if ( 1 == svgLayerId )
1423 svg = QDomDocument( doc.doctype() );
1424 svg.appendChild( svg.importNode( doc.firstChild(),
false ) );
1425 svgDocRoot = svg.importNode( doc.elementsByTagName( QStringLiteral(
"svg" ) ).at( 0 ),
false );
1426 svgDocRoot.toElement().setAttribute( QStringLiteral(
"xmlns:inkscape" ), QStringLiteral(
"http://www.inkscape.org/namespaces/inkscape" ) );
1427 svg.appendChild( svgDocRoot );
1429 QDomNode mainGroup = svg.importNode( doc.elementsByTagName( QStringLiteral(
"g" ) ).at( 0 ),
true );
1430 mainGroup.toElement().setAttribute( QStringLiteral(
"id" ), layerName );
1431 mainGroup.toElement().setAttribute( QStringLiteral(
"inkscape:label" ), layerName );
1432 mainGroup.toElement().setAttribute( QStringLiteral(
"inkscape:groupmode" ), QStringLiteral(
"layer" ) );
1433 QDomNode defs = svg.importNode( doc.elementsByTagName( QStringLiteral(
"defs" ) ).at( 0 ),
true );
1434 svgDocRoot.appendChild( defs );
1435 svgDocRoot.appendChild( mainGroup );
1440void QgsLayoutExporter::appendMetadataToSvg( QDomDocument &svg )
const
1443 QDomElement metadataElement = svg.createElement( QStringLiteral(
"metadata" ) );
1444 QDomElement rdfElement = svg.createElement( QStringLiteral(
"rdf:RDF" ) );
1445 rdfElement.setAttribute( QStringLiteral(
"xmlns:rdf" ), QStringLiteral(
"http://www.w3.org/1999/02/22-rdf-syntax-ns#" ) );
1446 rdfElement.setAttribute( QStringLiteral(
"xmlns:rdfs" ), QStringLiteral(
"http://www.w3.org/2000/01/rdf-schema#" ) );
1447 rdfElement.setAttribute( QStringLiteral(
"xmlns:dc" ), QStringLiteral(
"http://purl.org/dc/elements/1.1/" ) );
1448 QDomElement descriptionElement = svg.createElement( QStringLiteral(
"rdf:Description" ) );
1449 QDomElement workElement = svg.createElement( QStringLiteral(
"cc:Work" ) );
1450 workElement.setAttribute( QStringLiteral(
"rdf:about" ), QString() );
1452 auto addTextNode = [&workElement, &descriptionElement, &svg](
const QString & tag,
const QString & value )
1455 QDomElement element = svg.createElement( tag );
1456 QDomText t = svg.createTextNode( value );
1457 element.appendChild( t );
1458 workElement.appendChild( element );
1461 descriptionElement.setAttribute( tag, value );
1464 addTextNode( QStringLiteral(
"dc:format" ), QStringLiteral(
"image/svg+xml" ) );
1465 addTextNode( QStringLiteral(
"dc:title" ), metadata.
title() );
1466 addTextNode( QStringLiteral(
"dc:date" ), metadata.
creationDateTime().toString( Qt::ISODate ) );
1467 addTextNode( QStringLiteral(
"dc:identifier" ), metadata.
identifier() );
1468 addTextNode( QStringLiteral(
"dc:description" ), metadata.
abstract() );
1470 auto addAgentNode = [&workElement, &descriptionElement, &svg](
const QString & tag,
const QString & value )
1473 QDomElement inkscapeElement = svg.createElement( tag );
1474 QDomElement agentElement = svg.createElement( QStringLiteral(
"cc:Agent" ) );
1475 QDomElement titleElement = svg.createElement( QStringLiteral(
"dc:title" ) );
1476 QDomText t = svg.createTextNode( value );
1477 titleElement.appendChild( t );
1478 agentElement.appendChild( titleElement );
1479 inkscapeElement.appendChild( agentElement );
1480 workElement.appendChild( inkscapeElement );
1483 QDomElement bagElement = svg.createElement( QStringLiteral(
"rdf:Bag" ) );
1484 QDomElement liElement = svg.createElement( QStringLiteral(
"rdf:li" ) );
1485 t = svg.createTextNode( value );
1486 liElement.appendChild( t );
1487 bagElement.appendChild( liElement );
1489 QDomElement element = svg.createElement( tag );
1490 element.appendChild( bagElement );
1491 descriptionElement.appendChild( element );
1494 addAgentNode( QStringLiteral(
"dc:creator" ), metadata.
author() );
1495 addAgentNode( QStringLiteral(
"dc:publisher" ), QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() ) );
1499 QDomElement element = svg.createElement( QStringLiteral(
"dc:subject" ) );
1500 QDomElement bagElement = svg.createElement( QStringLiteral(
"rdf:Bag" ) );
1502 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
1504 const QStringList words = it.value();
1505 for (
const QString &keyword : words )
1507 QDomElement liElement = svg.createElement( QStringLiteral(
"rdf:li" ) );
1508 QDomText t = svg.createTextNode( keyword );
1509 liElement.appendChild( t );
1510 bagElement.appendChild( liElement );
1513 element.appendChild( bagElement );
1514 workElement.appendChild( element );
1515 descriptionElement.appendChild( element );
1518 rdfElement.appendChild( descriptionElement );
1519 rdfElement.appendChild( workElement );
1520 metadataElement.appendChild( rdfElement );
1521 svg.documentElement().appendChild( metadataElement );
1522 svg.documentElement().setAttribute( QStringLiteral(
"xmlns:cc" ), QStringLiteral(
"http://creativecommons.org/ns#" ) );
1525std::unique_ptr<double[]> QgsLayoutExporter::computeGeoTransform(
const QgsLayoutItemMap *map,
const QRectF ®ion,
double dpi )
const
1528 map = mLayout->referenceMap();
1534 dpi = mLayout->renderContext().dpi();
1537 QRectF exportRegion = region;
1538 if ( !exportRegion.isValid() )
1540 int pageNumber = map->
page();
1543 double pageY = page->pos().y();
1544 QSizeF pageSize = page->rect().size();
1545 exportRegion = QRectF( 0, pageY, pageSize.width(), pageSize.height() );
1549 QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
1552 double outputHeightMM = exportRegion.height();
1553 double outputWidthMM = exportRegion.width();
1557 double mapXCenter = mapExtent.
center().
x();
1558 double mapYCenter = mapExtent.
center().
y();
1560 double sinAlpha = std::sin( alpha );
1561 double cosAlpha = std::cos( alpha );
1564 QPointF mapItemPos = map->pos();
1566 mapItemPos.rx() -= exportRegion.left();
1567 mapItemPos.ry() -= exportRegion.top();
1570 double xRatio = mapExtent.
width() / mapItemSceneRect.width();
1571 double yRatio = mapExtent.
height() / mapItemSceneRect.height();
1572 double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
1573 double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
1574 QgsRectangle paperExtent( xmin, ymax - outputHeightMM * yRatio, xmin + outputWidthMM * xRatio, ymax );
1577 double X0 = paperExtent.xMinimum();
1578 double Y0 = paperExtent.yMaximum();
1583 double X1 = X0 - mapXCenter;
1584 double Y1 = Y0 - mapYCenter;
1585 double X2 = X1 * cosAlpha + Y1 * sinAlpha;
1586 double Y2 = -X1 * sinAlpha + Y1 * cosAlpha;
1587 X0 = X2 + mapXCenter;
1588 Y0 = Y2 + mapYCenter;
1592 int pageWidthPixels =
static_cast< int >( dpi * outputWidthMM / 25.4 );
1593 int pageHeightPixels =
static_cast< int >( dpi * outputHeightMM / 25.4 );
1594 double pixelWidthScale = paperExtent.width() / pageWidthPixels;
1595 double pixelHeightScale = paperExtent.height() / pageHeightPixels;
1598 std::unique_ptr<double[]> t(
new double[6] );
1600 t[1] = cosAlpha * pixelWidthScale;
1601 t[2] = -sinAlpha * pixelWidthScale;
1603 t[4] = -sinAlpha * pixelHeightScale;
1604 t[5] = -cosAlpha * pixelHeightScale;
1609void QgsLayoutExporter::writeWorldFile(
const QString &worldFileName,
double a,
double b,
double c,
double d,
double e,
double f )
const
1611 QFile worldFile( worldFileName );
1612 if ( !worldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
1616 QTextStream fout( &worldFile );
1620 fout << QString::number( a,
'f', 12 ) <<
"\r\n";
1621 fout << QString::number( d,
'f', 12 ) <<
"\r\n";
1622 fout << QString::number( b,
'f', 12 ) <<
"\r\n";
1623 fout << QString::number( e,
'f', 12 ) <<
"\r\n";
1624 fout << QString::number(
c,
'f', 12 ) <<
"\r\n";
1625 fout << QString::number( f,
'f', 12 ) <<
"\r\n";
1630 return georeferenceOutputPrivate( file, map, exportRegion, dpi,
false );
1633bool QgsLayoutExporter::georeferenceOutputPrivate(
const QString &file,
QgsLayoutItemMap *map,
const QRectF &exportRegion,
double dpi,
bool includeGeoreference,
bool includeMetadata )
const
1638 if ( !map && includeGeoreference )
1639 map = mLayout->referenceMap();
1641 std::unique_ptr<double[]> t;
1643 if ( map && includeGeoreference )
1646 dpi = mLayout->renderContext().dpi();
1648 t = computeGeoTransform( map, exportRegion, dpi );
1653 CPLSetConfigOption(
"GDAL_PDF_DPI", QString::number( dpi ).toUtf8().constData() );
1658 GDALSetGeoTransform( outputDS.get(), t.get() );
1660 if ( includeMetadata )
1662 QString creationDateString;
1663 const QDateTime creationDateTime = mLayout->project()->metadata().creationDateTime();
1664 if ( creationDateTime.isValid() )
1666 creationDateString = QStringLiteral(
"D:%1" ).arg( mLayout->project()->metadata().creationDateTime().toString( QStringLiteral(
"yyyyMMddHHmmss" ) ) );
1667 if ( creationDateTime.timeZone().isValid() )
1669 int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
1670 creationDateString += ( offsetFromUtc >= 0 ) ?
'+' :
'-';
1671 offsetFromUtc = std::abs( offsetFromUtc );
1672 int offsetHours = offsetFromUtc / 3600;
1673 int offsetMins = ( offsetFromUtc % 3600 ) / 60;
1674 creationDateString += QStringLiteral(
"%1'%2'" ).arg( offsetHours ).arg( offsetMins );
1677 GDALSetMetadataItem( outputDS.get(),
"CREATION_DATE", creationDateString.toUtf8().constData(),
nullptr );
1679 GDALSetMetadataItem( outputDS.get(),
"AUTHOR", mLayout->project()->metadata().author().toUtf8().constData(),
nullptr );
1680 const QString creator = QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() );
1681 GDALSetMetadataItem( outputDS.get(),
"CREATOR", creator.toUtf8().constData(),
nullptr );
1682 GDALSetMetadataItem( outputDS.get(),
"PRODUCER", creator.toUtf8().constData(),
nullptr );
1683 GDALSetMetadataItem( outputDS.get(),
"SUBJECT", mLayout->project()->metadata().abstract().toUtf8().constData(),
nullptr );
1684 GDALSetMetadataItem( outputDS.get(),
"TITLE", mLayout->project()->metadata().title().toUtf8().constData(),
nullptr );
1687 QStringList allKeywords;
1688 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
1690 allKeywords.append( QStringLiteral(
"%1: %2" ).arg( it.key(), it.value().join(
',' ) ) );
1692 const QString keywordString = allKeywords.join(
';' );
1693 GDALSetMetadataItem( outputDS.get(),
"KEYWORDS", keywordString.toUtf8().constData(),
nullptr );
1699 CPLSetConfigOption(
"GDAL_PDF_DPI",
nullptr );
1706 if ( items.count() == 1 )
1710 QString name = layoutItem->displayName();
1712 if ( name.startsWith(
'<' ) && name.endsWith(
'>' ) )
1713 name = name.mid( 1, name.length() - 2 );
1717 else if ( items.count() > 1 )
1719 QStringList currentLayerItemTypes;
1720 for ( QGraphicsItem *item : items )
1726 if ( !currentLayerItemTypes.contains( itemType ) && !currentLayerItemTypes.contains( itemTypePlural ) )
1727 currentLayerItemTypes << itemType;
1728 else if ( currentLayerItemTypes.contains( itemType ) )
1730 currentLayerItemTypes.replace( currentLayerItemTypes.indexOf( itemType ), itemTypePlural );
1735 if ( !currentLayerItemTypes.contains( QObject::tr(
"Other" ) ) )
1736 currentLayerItemTypes.append( QObject::tr(
"Other" ) );
1739 return currentLayerItemTypes.join( QLatin1String(
", " ) );
1741 return QObject::tr(
"Layer %1" ).arg( layerId );
1747 LayoutItemHider itemHider( items );
1752 unsigned int layerId = 1;
1754 itemHider.hideAll();
1755 const QList< QGraphicsItem * > itemsToIterate = itemHider.itemsToIterate();
1756 QList< QGraphicsItem * > currentLayerItems;
1757 for ( QGraphicsItem *item : itemsToIterate )
1761 bool canPlaceInExistingLayer =
false;
1768 switch ( prevItemBehavior )
1771 canPlaceInExistingLayer =
true;
1775 canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
1780 canPlaceInExistingLayer =
false;
1788 switch ( prevItemBehavior )
1792 canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
1797 canPlaceInExistingLayer =
false;
1805 canPlaceInExistingLayer =
false;
1810 canPlaceInExistingLayer =
false;
1814 prevType = layoutItem->
type();
1821 if ( canPlaceInExistingLayer )
1823 currentLayerItems << item;
1828 if ( !currentLayerItems.isEmpty() )
1832 ExportResult result = exportFunc( layerId, layerDetails );
1836 currentLayerItems.clear();
1839 itemHider.hideAll();
1844 int layoutItemLayerIdx = 0;
1846 mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
1852 mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
1856 ExportResult result = exportFunc( layerId, layerDetails );
1861 layoutItemLayerIdx++;
1863 layerDetails.mapLayerId.clear();
1865 mLayout->renderContext().setCurrentExportLayer( -1 );
1868 currentLayerItems.clear();
1872 currentLayerItems << item;
1876 if ( !currentLayerItems.isEmpty() )
1879 ExportResult result = exportFunc( layerId, layerDetails );
1894 return simplifyMethod;
1908 int pageNumber = map->
page();
1910 double pageY = page->pos().y();
1911 QSizeF pageSize = page->rect().size();
1912 QRectF pageRect( 0, pageY, pageSize.width(), pageSize.height() );
1928 double destinationHeight = exportRegion.height();
1929 double destinationWidth = exportRegion.width();
1931 QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
1936 double xRatio = mapExtent.
width() / mapItemSceneRect.width();
1937 double yRatio = mapExtent.
height() / mapItemSceneRect.height();
1939 double xCenter = mapExtent.
center().
x();
1940 double yCenter = mapExtent.
center().
y();
1943 QPointF mapItemPos = map->pos();
1945 mapItemPos.rx() -= exportRegion.left();
1946 mapItemPos.ry() -= exportRegion.top();
1948 double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
1949 double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
1950 QgsRectangle paperExtent( xmin, ymax - destinationHeight * yRatio, xmin + destinationWidth * xRatio, ymax );
1952 double X0 = paperExtent.
xMinimum();
1953 double Y0 = paperExtent.
yMinimum();
1956 dpi = mLayout->renderContext().dpi();
1958 int widthPx =
static_cast< int >( dpi * destinationWidth / 25.4 );
1959 int heightPx =
static_cast< int >( dpi * destinationHeight / 25.4 );
1961 double Ww = paperExtent.
width() / widthPx;
1962 double Hh = paperExtent.
height() / heightPx;
1971 s[5] = Y0 + paperExtent.
height();
1975 r[0] = std::cos( alpha );
1976 r[1] = -std::sin( alpha );
1977 r[2] = xCenter * ( 1 - std::cos( alpha ) ) + yCenter * std::sin( alpha );
1978 r[3] = std::sin( alpha );
1979 r[4] = std::cos( alpha );
1980 r[5] = - xCenter * std::sin( alpha ) + yCenter * ( 1 - std::cos( alpha ) );
1983 a = r[0] * s[0] + r[1] * s[3];
1984 b = r[0] * s[1] + r[1] * s[4];
1985 c = r[0] * s[2] + r[1] * s[5] + r[2];
1986 d = r[3] * s[0] + r[4] * s[3];
1987 e = r[3] * s[1] + r[4] * s[4];
1988 f = r[3] * s[2] + r[4] * s[5] + r[5];
1996 QList< QgsLayoutItem *> items;
2002 if ( currentItem->isVisible() && currentItem->requiresRasterization() )
2013 QList< QgsLayoutItem *> items;
2019 if ( currentItem->isVisible() && currentItem->containsAdvancedEffects() )
2032 if ( mLayout->pageCollection()->pageCount() == 1 )
2035 bounds = mLayout->layoutBounds(
true );
2040 bounds = mLayout->pageItemBounds( page,
true );
2042 if ( bounds.width() <= 0 || bounds.height() <= 0 )
2050 bounds = bounds.adjusted( -settings.
cropMargins.
left() * pixelToLayoutUnits,
2062int QgsLayoutExporter::firstPageToBeExported(
QgsLayout *layout )
2065 for (
int i = 0; i < pageCount; ++i )
2079 if ( details.
page == 0 )
2089void QgsLayoutExporter::captureLabelingResults()
2091 qDeleteAll( mLabelingResults );
2092 mLabelingResults.clear();
2094 QList< QgsLayoutItemMap * > maps;
2095 mLayout->layoutItems( maps );
2099 mLabelingResults[ map->
uuid() ] = map->mExportLabelingResults.release();
2103bool QgsLayoutExporter::saveImage(
const QImage &image,
const QString &imageFilename,
const QString &imageFormat,
QgsProject *projectForMetadata )
2105 QImageWriter w( imageFilename, imageFormat.toLocal8Bit().constData() );
2106 if ( imageFormat.compare( QLatin1String(
"tiff" ), Qt::CaseInsensitive ) == 0 || imageFormat.compare( QLatin1String(
"tif" ), Qt::CaseInsensitive ) == 0 )
2108 w.setCompression( 1 );
2110 if ( projectForMetadata )
2112 w.setText( QStringLiteral(
"Author" ), projectForMetadata->
metadata().
author() );
2113 const QString creator = QStringLiteral(
"QGIS %1" ).arg(
Qgis::version() );
2114 w.setText( QStringLiteral(
"Creator" ), creator );
2115 w.setText( QStringLiteral(
"Producer" ), creator );
2116 w.setText( QStringLiteral(
"Subject" ), projectForMetadata->
metadata().
abstract() );
2117 w.setText( QStringLiteral(
"Created" ), projectForMetadata->
metadata().
creationDateTime().toString( Qt::ISODate ) );
2118 w.setText( QStringLiteral(
"Title" ), projectForMetadata->
metadata().
title() );
2121 QStringList allKeywords;
2122 for (
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
2124 allKeywords.append( QStringLiteral(
"%1: %2" ).arg( it.key(), it.value().join(
',' ) ) );
2126 const QString keywordString = allKeywords.join(
';' );
2127 w.setText( QStringLiteral(
"Keywords" ), keywordString );
2129 return w.write( image );
static QString version()
Version string.
@ Millimeters
Millimeters.
@ Warning
Warning message.
TextRenderFormat
Flags which control how map layer renderers behave.
@ AlwaysOutlines
Always render text using path objects (AKA outlines/curves). This setting guarantees the best quality...
@ PreferredGdal
Preferred format for conversion of CRS to WKT for use with the GDAL library.
An abstract base class for QgsLayout based classes which can be exported by QgsLayoutExporter.
virtual bool endRender()=0
Ends the render, performing any required cleanup tasks.
virtual QgsLayout * layout()=0
Returns the layout associated with the iterator.
virtual bool next()=0
Iterates to next feature, returning false if no more features exist to iterate over.
virtual bool beginRender()=0
Called when rendering begins, before iteration commences.
virtual QString filePath(const QString &baseFilePath, const QString &extension)=0
Returns the file path for the current feature, based on a specified base file path and extension.
virtual int count() const =0
Returns the number of features to iterate over.
static QgsLayoutItemRegistry * layoutItemRegistry()
Returns the application's layout item registry, used for layout item types.
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
Handles rendering and exports of layouts to various formats.
ExportResult exportToSvg(const QString &filePath, const QgsLayoutExporter::SvgExportSettings &settings)
Exports the layout as an SVG to the filePath, using the specified export settings.
ExportResult exportToImage(const QString &filePath, const QgsLayoutExporter::ImageExportSettings &settings)
Exports the layout to the filePath, using the specified export settings.
ExportResult exportToPdf(const QString &filePath, const QgsLayoutExporter::PdfExportSettings &settings)
Exports the layout as a PDF to the filePath, using the specified export settings.
virtual ~QgsLayoutExporter()
QImage renderRegionToImage(const QRectF ®ion, QSize imageSize=QSize(), double dpi=-1) const
Renders a region of the layout to an image.
QMap< QString, QgsLabelingResults * > takeLabelingResults()
Takes the labeling results for all map items included in the export.
static bool requiresRasterization(const QgsLayout *layout)
Returns true if the specified layout contains visible items which have settings that require rasteriz...
QgsLayout * layout() const
Returns the layout linked to this exporter.
bool georeferenceOutput(const QString &file, QgsLayoutItemMap *referenceMap=nullptr, const QRectF &exportRegion=QRectF(), double dpi=-1) const
Georeferences a file (image of PDF) exported from the layout.
static const QgsSettingsEntryBool * settingOpenAfterExportingPdf
Settings entry - Whether to automatically open pdfs after exporting them.
virtual QString generateFileName(const PageExportDetails &details) const
Generates the file name for a page during export.
ExportResult
Result codes for exporting layouts.
@ Canceled
Export was canceled.
@ MemoryError
Unable to allocate memory required to export.
@ PrintError
Could not start printing to destination device.
@ IteratorError
Error iterating over layout.
@ FileError
Could not write to destination file, likely due to a lock held by another application.
@ Success
Export was successful.
@ SvgLayerError
Could not create layered SVG file.
QImage renderPageToImage(int page, QSize imageSize=QSize(), double dpi=-1) const
Renders a full page to an image.
QgsLayoutExporter(QgsLayout *layout)
Constructor for QgsLayoutExporter, for the specified layout.
static ExportResult exportToPdfs(QgsAbstractLayoutIterator *iterator, const QString &baseFilePath, const QgsLayoutExporter::PdfExportSettings &settings, QString &error, QgsFeedback *feedback=nullptr)
Exports a layout iterator to multiple PDF files, with the specified export settings.
void computeWorldFileParameters(double &a, double &b, double &c, double &d, double &e, double &f, double dpi=-1) const
Compute world file parameters.
void renderPage(QPainter *painter, int page) const
Renders a full page to a destination painter.
static const QgsSettingsEntryBool * settingOpenAfterExportingImage
Settings entry - Whether to automatically open images after exporting them.
static const QgsSettingsEntryBool * settingOpenAfterExportingSvg
Settings entry - Whether to automatically open svgs after exporting them.
QMap< QString, QgsLabelingResults * > labelingResults()
Returns the labeling results for all map items included in the export.
static bool containsAdvancedEffects(const QgsLayout *layout)
Returns true if the specified layout contains visible items which have settings such as opacity which...
void renderRegion(QPainter *painter, const QRectF ®ion) const
Renders a region from the layout to a painter.
Contains the configuration for a single snap guide used by a layout.
Layout graphical items for displaying a map.
double mapRotation(QgsLayoutObject::PropertyValueType valueType=QgsLayoutObject::EvaluatedValue) const
Returns the rotation used for drawing the map within the layout item, in degrees clockwise.
QgsRectangle extent() const
Returns the current map extent.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
Item representing the paper in a layout.
QgsLayoutItemAbstractMetadata * itemMetadata(int type) const
Returns the metadata for the specified item type.
Base class for graphical items within a QgsLayout.
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
virtual QgsLayoutItem::ExportLayerDetail exportLayerDetails() const
Returns the details for the specified current export layer.
virtual bool nextExportPart()
Moves to the next export part for a multi-layered export item, during a multi-layered export.
virtual void startLayeredExport()
Starts a multi-layer export operation.
int page() const
Returns the page the item is currently on, with the first page returning 0.
int type() const override
Returns a unique graphics item type identifier.
virtual void stopLayeredExport()
Stops a multi-layer export operation.
virtual QString uuid() const
Returns the item identification string.
ExportLayerBehavior
Behavior of item when exporting to layered outputs.
@ ItemContainsSubLayers
Item contains multiple sublayers which must be individually exported.
@ MustPlaceInOwnLayer
Item must be placed in its own individual layer.
@ CanGroupWithItemsOfSameType
Item can only be placed on layers with other items of the same type, but multiple items of this type ...
@ CanGroupWithAnyOtherItem
Item can be placed on a layer with any other item (default behavior)
virtual ExportLayerBehavior exportLayerBehavior() const
Returns the behavior of this item during exporting to layered exports (e.g.
QgsLayoutMeasurement convert(QgsLayoutMeasurement measurement, Qgis::LayoutUnit targetUnits) const
Converts a measurement from one unit to another.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
int pageCount() const
Returns the number of pages in the collection.
bool shouldExportPage(int page) const
Returns whether the specified page number should be included in exports of the layouts.
QgsLayoutItemPage * page(int pageNumber)
Returns a specific page (by pageNumber) from the collection.
This class provides a method of storing points, consisting of an x and y coordinate,...
double x() const
Returns x coordinate of point.
double y() const
Returns y coordinate of point.
void setDpi(double dpi)
Sets the dpi for outputting the layout.
void setSimplifyMethod(const QgsVectorSimplifyMethod &method)
Sets the simplification setting to use when rendering vector layers.
void setTextRenderFormat(Qgis::TextRenderFormat format)
Sets the text render format, which dictates how text is rendered (e.g.
QgsLayoutRenderContext::Flags flags() const
Returns the current combination of flags used for rendering the layout.
void setFlag(QgsLayoutRenderContext::Flag flag, bool on=true)
Enables or disables a particular rendering flag for the layout.
double dpi() const
Returns the dpi for outputting the layout.
@ FlagRenderLabelsByMapLayer
When rendering map items to multi-layered exports, render labels belonging to different layers into s...
@ FlagUseAdvancedEffects
Enable advanced effects such as blend modes.
@ FlagLosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
@ FlagAntialiasing
Use antialiasing when drawing items.
@ FlagSynchronousLegendGraphics
Query legend graphics synchronously.
@ FlagForceVectorOutput
Force output in vector format where possible, even if items require rasterization to keep their corre...
void setPredefinedScales(const QVector< qreal > &scales)
Sets the list of predefined scales to use with the layout.
void 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 xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double width() const
Returns the width of the rectangle.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
QgsPointXY center() const
Returns the center point of the rectangle.
double height() const
Returns the height of the rectangle.
A boolean settings entry.
static QgsSettingsTreeNode * sTreeLayout
This class contains information how to simplify geometries fetched from a vector layer.
void 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 ISO32000 extension format georeferencing should be used.
QMap< QString, QString > layerIdToPdfLayerTreeNameMap
Optional map of map layer ID to custom layer tree name to show in the created PDF file.
bool useOgcBestPracticeFormatGeoreferencing
true if OGC "best practice" format georeferencing should be used.
QDateTime creationDateTime
Metadata creation datetime.
QSizeF pageSizeMm
Page size, in millimeters.
QList< QgsAbstractGeoPdfExporter::GeoReferencedSection > georeferencedSections
List of georeferenced sections.
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.