32 #include <QImageWriter> 
   34 #include <QSvgGenerator> 
   37 #include <QTextStream> 
   43 class LayoutContextPreviewSettingRestorer
 
   47     LayoutContextPreviewSettingRestorer( 
QgsLayout *layout )
 
   49       , mPreviousSetting( layout->renderContext().mIsPreviewRender )
 
   51       mLayout->renderContext().mIsPreviewRender = 
false;
 
   54     ~LayoutContextPreviewSettingRestorer()
 
   56       mLayout->renderContext().mIsPreviewRender = mPreviousSetting;
 
   59     LayoutContextPreviewSettingRestorer( 
const LayoutContextPreviewSettingRestorer &other ) = 
delete;
 
   60     LayoutContextPreviewSettingRestorer &operator=( 
const LayoutContextPreviewSettingRestorer &other ) = 
delete;
 
   64     bool mPreviousSetting = 
false;
 
   67 class LayoutGuideHider
 
   74       const QList< QgsLayoutGuide * > guides = mLayout->guides().guides();
 
   77         mPrevVisibility.insert( guide, guide->item()->isVisible() );
 
   78         guide->item()->setVisible( 
false );
 
   84       for ( 
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
 
   86         it.key()->item()->setVisible( it.value() );
 
   90     LayoutGuideHider( 
const LayoutGuideHider &other ) = 
delete;
 
   91     LayoutGuideHider &operator=( 
const LayoutGuideHider &other ) = 
delete;
 
   95     QHash< QgsLayoutGuide *, bool > mPrevVisibility;
 
  101     explicit LayoutItemHider( 
const QList<QGraphicsItem *> &items )
 
  103       mItemsToIterate.reserve( items.count() );
 
  104       for ( QGraphicsItem *item : items )
 
  106         const bool isVisible = item->isVisible();
 
  107         mPrevVisibility[item] = isVisible;
 
  109           mItemsToIterate.append( item );
 
  111           layoutItem->setProperty( 
"wasVisible", isVisible );
 
  119       for ( 
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
 
  127       for ( 
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
 
  129         it.key()->setVisible( it.value() );
 
  131           layoutItem->setProperty( 
"wasVisible", QVariant() );
 
  135     QList< QGraphicsItem * > itemsToIterate()
 const { 
return mItemsToIterate; }
 
  137     LayoutItemHider( 
const LayoutItemHider &other ) = 
delete;
 
  138     LayoutItemHider &operator=( 
const LayoutItemHider &other ) = 
delete;
 
  142     QList<QGraphicsItem * > mItemsToIterate;
 
  143     QHash<QGraphicsItem *, bool> mPrevVisibility;
 
  156   qDeleteAll( mLabelingResults );
 
  169   if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
 
  180   LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  183   QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
 
  192   if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
 
  203   LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  206   QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
 
  208   const double imageAspectRatio = 
static_cast< double >( imageSize.width() ) / imageSize.height();
 
  209   const double paperAspectRatio = paperRect.width() / paperRect.height();
 
  210   if ( imageSize.isValid() && ( !
qgsDoubleNear( imageAspectRatio, paperAspectRatio, 0.008 ) ) )
 
  215     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 );
 
  223 class LayoutItemCacheSettingRestorer
 
  227     LayoutItemCacheSettingRestorer( 
QgsLayout *layout )
 
  230       const QList< QGraphicsItem * > items = mLayout->items();
 
  231       for ( QGraphicsItem *item : items )
 
  233         mPrevCacheMode.insert( item, item->cacheMode() );
 
  234         item->setCacheMode( QGraphicsItem::NoCache );
 
  238     ~LayoutItemCacheSettingRestorer()
 
  240       for ( 
auto it = mPrevCacheMode.constBegin(); it != mPrevCacheMode.constEnd(); ++it )
 
  242         it.key()->setCacheMode( it.value() );
 
  246     LayoutItemCacheSettingRestorer( 
const LayoutItemCacheSettingRestorer &other ) = 
delete;
 
  247     LayoutItemCacheSettingRestorer &operator=( 
const LayoutItemCacheSettingRestorer &other ) = 
delete;
 
  251     QHash< QGraphicsItem *, QGraphicsItem::CacheMode > mPrevCacheMode;
 
  258   QPaintDevice *paintDevice = painter->device();
 
  259   if ( !paintDevice || !mLayout )
 
  264   LayoutItemCacheSettingRestorer cacheRestorer( mLayout );
 
  265   ( void )cacheRestorer;
 
  266   LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  268   LayoutGuideHider guideHider( mLayout );
 
  273   mLayout->render( painter, QRectF( 0, 0, paintDevice->width(), paintDevice->height() ), region );
 
  281   LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  284   double resolution = mLayout->renderContext().dpi();
 
  286   if ( imageSize.isValid() )
 
  290     resolution = ( imageSize.width() / region.width()
 
  291                    + imageSize.height() / region.height() ) / 2.0 * oneInchInLayoutUnits;
 
  299   int width = imageSize.isValid() ? imageSize.width()
 
  300               : 
static_cast< int >( resolution * region.width() / oneInchInLayoutUnits );
 
  301   int height = imageSize.isValid() ? imageSize.height()
 
  302                : 
static_cast< int >( resolution * region.height() / oneInchInLayoutUnits );
 
  304   QImage image( QSize( width, height ), QImage::Format_ARGB32 );
 
  305   if ( !image.isNull() )
 
  308     if ( width > 32768 || height > 32768 )
 
  309       QgsMessageLog::logMessage( QObject::tr( 
"Error: output width or height is larger than 32768 pixel, result will be clipped" ) );
 
  310     image.setDotsPerMeterX( 
static_cast< int >( std::round( resolution / 25.4 * 1000 ) ) );
 
  311     image.setDotsPerMeterY( 
static_cast< int>( std::round( resolution / 25.4 * 1000 ) ) );
 
  312     image.fill( Qt::transparent );
 
  313     QPainter imagePainter( &image );
 
  315     if ( !imagePainter.isActive() )
 
  323 class LayoutContextSettingsRestorer
 
  328     LayoutContextSettingsRestorer( 
QgsLayout *layout )
 
  330       , mPreviousDpi( layout->renderContext().dpi() )
 
  331       , mPreviousFlags( layout->renderContext().flags() )
 
  332       , mPreviousTextFormat( layout->renderContext().textRenderFormat() )
 
  333       , mPreviousExportLayer( layout->renderContext().currentExportLayer() )
 
  334       , mPreviousSimplifyMethod( layout->renderContext().simplifyMethod() )
 
  335       , mExportThemes( layout->renderContext().exportThemes() )
 
  336       , mPredefinedScales( layout->renderContext().predefinedScales() )
 
  341     ~LayoutContextSettingsRestorer()
 
  343       mLayout->renderContext().setDpi( mPreviousDpi );
 
  344       mLayout->renderContext().setFlags( mPreviousFlags );
 
  345       mLayout->renderContext().setTextRenderFormat( mPreviousTextFormat );
 
  347       mLayout->renderContext().setCurrentExportLayer( mPreviousExportLayer );
 
  349       mLayout->renderContext().setSimplifyMethod( mPreviousSimplifyMethod );
 
  350       mLayout->renderContext().setExportThemes( mExportThemes );
 
  351       mLayout->renderContext().setPredefinedScales( mPredefinedScales );
 
  354     LayoutContextSettingsRestorer( 
const LayoutContextSettingsRestorer &other ) = 
delete;
 
  355     LayoutContextSettingsRestorer &operator=( 
const LayoutContextSettingsRestorer &other ) = 
delete;
 
  359     double mPreviousDpi = 0;
 
  360     QgsLayoutRenderContext::Flags mPreviousFlags = QgsLayoutRenderContext::Flags();
 
  362     int mPreviousExportLayer = 0;
 
  364     QStringList mExportThemes;
 
  365     QVector< double > mPredefinedScales;
 
  376   if ( settings.
dpi <= 0 )
 
  377     settings.
dpi = mLayout->renderContext().dpi();
 
  379   mErrorFileName.clear();
 
  381   int worldFilePageNo = -1;
 
  384     worldFilePageNo = referenceMap->page();
 
  387   QFileInfo fi( filePath );
 
  391   pageDetails.
baseName = fi.completeBaseName();
 
  394   LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  396   LayoutContextSettingsRestorer dpiRestorer( mLayout );
 
  398   mLayout->renderContext().setDpi( settings.
dpi );
 
  399   mLayout->renderContext().setFlags( settings.
flags );
 
  403   if ( settings.
pages.empty() )
 
  405     for ( 
int page = 0; page < mLayout->pageCollection()->pageCount(); ++page )
 
  410     for ( 
int page : std::as_const( settings.
pages ) )
 
  412       if ( page >= 0 && page < mLayout->pageCollection()->pageCount() )
 
  417   for ( 
int page : std::as_const( pages ) )
 
  419     if ( !mLayout->pageCollection()->shouldExportPage( page ) )
 
  426     QImage image = createImage( settings, page, bounds, skip );
 
  431     pageDetails.
page = page;
 
  434     if ( image.isNull() )
 
  436       mErrorFileName = outputFilePath;
 
  440     if ( !saveImage( image, outputFilePath, pageDetails.
extension, settings.
exportMetadata ? mLayout->project() : 
nullptr ) )
 
  442       mErrorFileName = outputFilePath;
 
  446     const bool shouldGeoreference = ( page == worldFilePageNo );
 
  447     if ( shouldGeoreference )
 
  449       georeferenceOutputPrivate( outputFilePath, 
nullptr, bounds, settings.
dpi, shouldGeoreference );
 
  454         double a, b, 
c, d, e, f;
 
  455         if ( bounds.isValid() )
 
  460         QFileInfo fi( outputFilePath );
 
  462         QString outputSuffix = fi.suffix();
 
  463         QString worldFileName = fi.absolutePath() + 
'/' + fi.completeBaseName() + 
'.' 
  464                                 + outputSuffix.at( 0 ) + outputSuffix.at( fi.suffix().size() - 1 ) + 
'w';
 
  466         writeWorldFile( worldFileName, a, b, 
c, d, e, f );
 
  471   captureLabelingResults();
 
  482   int total = iterator->
count();
 
  483   double step = total > 0 ? 100.0 / total : 100.0;
 
  485   while ( iterator->
next() )
 
  490         feedback->setProperty( 
"progress", QObject::tr( 
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
 
  492         feedback->setProperty( 
"progress", QObject::tr( 
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
 
  502     QString filePath = iterator->
filePath( baseFilePath, extension );
 
  507         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 ) );
 
  525   if ( !mLayout || mLayout->pageCollection()->pageCount() == 0 )
 
  529   if ( settings.
dpi <= 0 )
 
  530     settings.
dpi = mLayout->renderContext().dpi();
 
  532   mErrorFileName.clear();
 
  534   LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  536   LayoutContextSettingsRestorer contextRestorer( mLayout );
 
  537   ( void )contextRestorer;
 
  538   mLayout->renderContext().setDpi( settings.
dpi );
 
  543     mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
 
  546   std::unique_ptr< QgsLayoutGeoPdfExporter > geoPdfExporter;
 
  548     geoPdfExporter = std::make_unique< QgsLayoutGeoPdfExporter >( mLayout );
 
  550   mLayout->renderContext().setFlags( settings.
flags );
 
  558   mLayout->renderContext().setExportThemes( settings.
exportThemes );
 
  570     const QList<QGraphicsItem *> items = mLayout->items( Qt::AscendingOrder );
 
  572     QList< QgsLayoutGeoPdfExporter::ComponentLayerDetail > pdfComponents;
 
  582       component.
name = layerDetail.name;
 
  583       component.
mapLayerId = layerDetail.mapLayerId;
 
  584       component.
opacity = layerDetail.opacity;
 
  586       component.
group = layerDetail.mapTheme;
 
  587       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' ) ) );
 
  588       pdfComponents << component;
 
  589       preparePrintAsPdf( mLayout, printer, component.
sourcePdfPath );
 
  590       preparePrint( mLayout, printer, 
false );
 
  592       if ( !p.begin( &printer ) )
 
  600       return layerExportResult;
 
  602     result = handleLayeredExport( items, exportFunc );
 
  606     if ( settings.writeGeoPdf )
 
  609       details.
dpi = settings.dpi;
 
  611       QgsLayoutSize pageSize = mLayout->pageCollection()->page( 0 )->sizeWithUnits();
 
  615       if ( settings.exportMetadata )
 
  618         details.
author = mLayout->project()->metadata().author();
 
  621         details.
creationDateTime = mLayout->project()->metadata().creationDateTime();
 
  622         details.
subject = mLayout->project()->metadata().abstract();
 
  623         details.
title = mLayout->project()->metadata().title();
 
  624         details.
keywords = mLayout->project()->metadata().keywords();
 
  627       const QList< QgsMapLayer * > layers = mLayout->project()->mapLayers().values();
 
  633       if ( settings.appendGeoreference )
 
  636         QList< QgsLayoutItemMap * > maps;
 
  637         mLayout->layoutItems( maps );
 
  641           georef.
crs = map->crs();
 
  643           const QPointF topLeft = map->mapToScene( QPointF( 0, 0 ) );
 
  644           const QPointF topRight = map->mapToScene( QPointF( map->rect().width(), 0 ) );
 
  645           const QPointF bottomLeft = map->mapToScene( QPointF( 0, map->rect().height() ) );
 
  646           const QPointF bottomRight = map->mapToScene( QPointF( map->rect().width(), map->rect().height() ) );
 
  659           const QTransform t = map->layoutToMapCoordsTransform();
 
  660           const QgsPointXY topLeftMap = t.map( topLeft );
 
  661           const QgsPointXY topRightMap = t.map( topRight );
 
  662           const QgsPointXY bottomLeftMap = t.map( bottomLeft );
 
  663           const QgsPointXY bottomRightMap = t.map( bottomRight );
 
  675       details.
layerOrder = geoPdfExporter->layerOrder();
 
  680       if ( !geoPdfExporter->finalize( pdfComponents, filePath, details ) )
 
  691     preparePrintAsPdf( mLayout, printer, filePath );
 
  692     preparePrint( mLayout, printer, 
false );
 
  694     if ( !p.begin( &printer ) )
 
  703     bool shouldAppendGeoreference = settings.
appendGeoreference && mLayout && mLayout->referenceMap() && mLayout->referenceMap()->page() == 0;
 
  706       georeferenceOutputPrivate( filePath, 
nullptr, QRectF(), settings.
dpi, shouldAppendGeoreference, settings.
exportMetadata );
 
  709   captureLabelingResults();
 
  725   int total = iterator->
count();
 
  726   double step = total > 0 ? 100.0 / total : 100.0;
 
  729   while ( iterator->
next() )
 
  734         feedback->setProperty( 
"progress", QObject::tr( 
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
 
  736         feedback->setProperty( 
"progress", QObject::tr( 
"Exporting section %1" ).arg( i + 1 ) );
 
  748     LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
 
  750     LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
 
  751     ( void )contextRestorer;
 
  773       preparePrintAsPdf( iterator->
layout(), printer, fileName );
 
  774       preparePrint( iterator->
layout(), printer, 
false );
 
  776       if ( !p.begin( &printer ) )
 
  789         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 ) );
 
  813   int total = iterator->
count();
 
  814   double step = total > 0 ? 100.0 / total : 100.0;
 
  816   while ( iterator->
next() )
 
  821         feedback->setProperty( 
"progress", QObject::tr( 
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
 
  823         feedback->setProperty( 
"progress", QObject::tr( 
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
 
  832     QString filePath = iterator->
filePath( baseFilePath, QStringLiteral( 
"pdf" ) );
 
  839         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 ) );
 
  861   if ( settings.
dpi <= 0 )
 
  862     settings.
dpi = mLayout->renderContext().dpi();
 
  864   mErrorFileName.clear();
 
  866   LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  868   LayoutContextSettingsRestorer contextRestorer( mLayout );
 
  869   ( void )contextRestorer;
 
  870   mLayout->renderContext().setDpi( settings.
dpi );
 
  872   mLayout->renderContext().setFlags( settings.
flags );
 
  879   preparePrint( mLayout, printer, 
true );
 
  881   if ( !p.begin( &printer ) )
 
  890   captureLabelingResults();
 
  905   int total = iterator->
count();
 
  906   double step = total > 0 ? 100.0 / total : 100.0;
 
  909   while ( iterator->
next() )
 
  914         feedback->setProperty( 
"progress", QObject::tr( 
"Printing %1 of %2" ).arg( i + 1 ).arg( total ) );
 
  916         feedback->setProperty( 
"progress", QObject::tr( 
"Printing section %1" ).arg( i + 1 ).arg( total ) );
 
  928     LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
 
  930     LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
 
  931     ( void )contextRestorer;
 
  944       preparePrint( iterator->
layout(), printer, 
true );
 
  946       if ( !p.begin( &printer ) )
 
  980   if ( settings.
dpi <= 0 )
 
  981     settings.
dpi = mLayout->renderContext().dpi();
 
  983   mErrorFileName.clear();
 
  985   LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  987   LayoutContextSettingsRestorer contextRestorer( mLayout );
 
  988   ( void )contextRestorer;
 
  989   mLayout->renderContext().setDpi( settings.
dpi );
 
  991   mLayout->renderContext().setFlags( settings.
flags );
 
  998     mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
 
 1001   QFileInfo fi( filePath );
 
 1004   pageDetails.
baseName = fi.baseName();
 
 1005   pageDetails.
extension = fi.completeSuffix();
 
 1009   for ( 
int i = 0; i < mLayout->pageCollection()->pageCount(); ++i )
 
 1011     if ( !mLayout->pageCollection()->shouldExportPage( i ) )
 
 1016     pageDetails.
page = i;
 
 1023       if ( mLayout->pageCollection()->pageCount() == 1 )
 
 1026         bounds = mLayout->layoutBounds( 
true );
 
 1031         bounds = mLayout->pageItemBounds( i, 
true );
 
 1040       bounds = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
 
 1044     int width = 
static_cast< int >( bounds.width() * settings.
dpi / inchesToLayoutUnits );
 
 1046     int height = 
static_cast< int >( bounds.height() * settings.
dpi / inchesToLayoutUnits );
 
 1047     if ( width == 0 || height == 0 )
 
 1056       const QRectF paperRect = QRectF( pageItem->pos().x(),
 
 1057                                        pageItem->pos().y(),
 
 1058                                        pageItem->rect().width(),
 
 1059                                        pageItem->rect().height() );
 
 1061       QDomNode svgDocRoot;
 
 1062       const QList<QGraphicsItem *> items = mLayout->items( paperRect,
 
 1063                                            Qt::IntersectsItemBoundingRect,
 
 1064                                            Qt::AscendingOrder );
 
 1068         return renderToLayeredSvg( settings, width, height, i, bounds, fileName, layerId, layerDetail.name, svg, svgDocRoot, settings.
exportMetadata );
 
 1070       ExportResult res = handleLayeredExport( items, exportFunc );
 
 1075         appendMetadataToSvg( svg );
 
 1077       QFile out( fileName );
 
 1078       bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
 
 1081         mErrorFileName = fileName;
 
 1085       out.write( svg.toByteArray() );
 
 1091         QSvgGenerator generator;
 
 1094           generator.setTitle( mLayout->project()->metadata().title() );
 
 1095           generator.setDescription( mLayout->project()->metadata().abstract() );
 
 1097         generator.setOutputDevice( &svgBuffer );
 
 1098         generator.setSize( QSize( width, height ) );
 
 1099         generator.setViewBox( QRect( 0, 0, width, height ) );
 
 1100         generator.setResolution( 
static_cast< int >( std::round( settings.
dpi ) ) );
 
 1103         bool createOk = p.begin( &generator );
 
 1106           mErrorFileName = fileName;
 
 1119         svgBuffer.open( QIODevice::ReadOnly );
 
 1123         if ( ! svg.setContent( &svgBuffer, 
false, &errorMsg, &errorLine ) )
 
 1125           mErrorFileName = fileName;
 
 1130           appendMetadataToSvg( svg );
 
 1132         QFile out( fileName );
 
 1133         bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
 
 1136           mErrorFileName = fileName;
 
 1140         out.write( svg.toByteArray() );
 
 1144   captureLabelingResults();
 
 1155   int total = iterator->
count();
 
 1156   double step = total > 0 ? 100.0 / total : 100.0;
 
 1158   while ( iterator->
next() )
 
 1163         feedback->setProperty( 
"progress", QObject::tr( 
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
 
 1165         feedback->setProperty( 
"progress", QObject::tr( 
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
 
 1175     QString filePath = iterator->
filePath( baseFilePath, QStringLiteral( 
"svg" ) );
 
 1182         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 ) );
 
 1201   return mLabelingResults;
 
 1206   QMap<QString, QgsLabelingResults *> res;
 
 1207   std::swap( mLabelingResults, res );
 
 1211 void QgsLayoutExporter::preparePrintAsPdf( 
QgsLayout *layout, QPrinter &printer, 
const QString &filePath )
 
 1213   printer.setOutputFileName( filePath );
 
 1214   printer.setOutputFormat( QPrinter::PdfFormat );
 
 1216   updatePrinterPageSize( 
layout, printer, firstPageToBeExported( 
layout ) );
 
 1225 void QgsLayoutExporter::preparePrint( 
QgsLayout *layout, QPrinter &printer, 
bool setFirstPageSize )
 
 1227   printer.setFullPage( 
true );
 
 1228   printer.setColorMode( QPrinter::Color );
 
 1233   if ( setFirstPageSize )
 
 1235     updatePrinterPageSize( 
layout, printer, firstPageToBeExported( 
layout ) );
 
 1241   if ( mLayout->pageCollection()->pageCount() == 0 )
 
 1244   preparePrint( mLayout, printer, 
true );
 
 1246   if ( !p.begin( &printer ) )
 
 1252   printPrivate( printer, p );
 
 1257 QgsLayoutExporter::ExportResult QgsLayoutExporter::printPrivate( QPrinter &printer, QPainter &painter, 
bool startNewPage, 
double dpi, 
bool rasterize )
 
 1260   int fromPage = ( printer.fromPage() < 1 ) ? 0 : printer.fromPage() - 1;
 
 1261   int toPage = ( printer.toPage() < 1 ) ? mLayout->pageCollection()->pageCount() - 1 : printer.toPage() - 1;
 
 1263   bool pageExported = 
false;
 
 1266     for ( 
int i = fromPage; i <= toPage; ++i )
 
 1268       if ( !mLayout->pageCollection()->shouldExportPage( i ) )
 
 1273       updatePrinterPageSize( mLayout, printer, i );
 
 1274       if ( ( pageExported && i > fromPage ) || startNewPage )
 
 1280       if ( !image.isNull() )
 
 1282         QRectF targetArea( 0, 0, image.width(), image.height() );
 
 1283         painter.drawImage( targetArea, image, targetArea );
 
 1289       pageExported = 
true;
 
 1294     for ( 
int i = fromPage; i <= toPage; ++i )
 
 1296       if ( !mLayout->pageCollection()->shouldExportPage( i ) )
 
 1301       updatePrinterPageSize( mLayout, printer, i );
 
 1303       if ( ( pageExported && i > fromPage ) || startNewPage )
 
 1308       pageExported = 
true;
 
 1314 void QgsLayoutExporter::updatePrinterPageSize( 
QgsLayout *layout, QPrinter &printer, 
int page )
 
 1319   QPageLayout pageLayout( QPageSize( pageSizeMM.
toQSizeF(), QPageSize::Millimeter ),
 
 1320                           QPageLayout::Portrait,
 
 1321                           QMarginsF( 0, 0, 0, 0 ) );
 
 1322   pageLayout.setMode( QPageLayout::FullPageMode );
 
 1323   printer.setPageLayout( pageLayout );
 
 1324   printer.setFullPage( 
true );
 
 1325   printer.setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
 
 1328 QgsLayoutExporter::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 
 1332     QSvgGenerator generator;
 
 1333     if ( includeMetadata )
 
 1336         generator.setTitle( l->name() );
 
 1337       else if ( mLayout->project() )
 
 1338         generator.setTitle( mLayout->project()->title() );
 
 1341     generator.setOutputDevice( &svgBuffer );
 
 1342     generator.setSize( QSize( 
static_cast< int >( std::round( width ) ),
 
 1343                               static_cast< int >( std::round( height ) ) ) );
 
 1344     generator.setViewBox( QRect( 0, 0,
 
 1345                                  static_cast< int >( std::round( width ) ),
 
 1346                                  static_cast< int >( std::round( height ) ) ) );
 
 1347     generator.setResolution( 
static_cast< int >( std::round( settings.dpi ) ) ); 
 
 1349     QPainter svgPainter( &generator );
 
 1350     if ( settings.cropToContents )
 
 1361     svgBuffer.open( QIODevice::ReadOnly );
 
 1365     if ( ! doc.setContent( &svgBuffer, 
false, &errorMsg, &errorLine ) )
 
 1367       mErrorFileName = filename;
 
 1370     if ( 1 == svgLayerId )
 
 1372       svg = QDomDocument( doc.doctype() );
 
 1373       svg.appendChild( svg.importNode( doc.firstChild(), 
false ) );
 
 1374       svgDocRoot = svg.importNode( doc.elementsByTagName( QStringLiteral( 
"svg" ) ).at( 0 ), 
false );
 
 1375       svgDocRoot.toElement().setAttribute( QStringLiteral( 
"xmlns:inkscape" ), QStringLiteral( 
"http://www.inkscape.org/namespaces/inkscape" ) );
 
 1376       svg.appendChild( svgDocRoot );
 
 1378     QDomNode mainGroup = svg.importNode( doc.elementsByTagName( QStringLiteral( 
"g" ) ).at( 0 ), 
true );
 
 1379     mainGroup.toElement().setAttribute( QStringLiteral( 
"id" ), layerName );
 
 1380     mainGroup.toElement().setAttribute( QStringLiteral( 
"inkscape:label" ), layerName );
 
 1381     mainGroup.toElement().setAttribute( QStringLiteral( 
"inkscape:groupmode" ), QStringLiteral( 
"layer" ) );
 
 1382     QDomNode defs = svg.importNode( doc.elementsByTagName( QStringLiteral( 
"defs" ) ).at( 0 ), 
true );
 
 1383     svgDocRoot.appendChild( defs );
 
 1384     svgDocRoot.appendChild( mainGroup );
 
 1389 void QgsLayoutExporter::appendMetadataToSvg( QDomDocument &svg )
 const 
 1392   QDomElement metadataElement = svg.createElement( QStringLiteral( 
"metadata" ) );
 
 1393   QDomElement rdfElement = svg.createElement( QStringLiteral( 
"rdf:RDF" ) );
 
 1394   rdfElement.setAttribute( QStringLiteral( 
"xmlns:rdf" ), QStringLiteral( 
"http://www.w3.org/1999/02/22-rdf-syntax-ns#" ) );
 
 1395   rdfElement.setAttribute( QStringLiteral( 
"xmlns:rdfs" ), QStringLiteral( 
"http://www.w3.org/2000/01/rdf-schema#" ) );
 
 1396   rdfElement.setAttribute( QStringLiteral( 
"xmlns:dc" ), QStringLiteral( 
"http://purl.org/dc/elements/1.1/" ) );
 
 1397   QDomElement descriptionElement = svg.createElement( QStringLiteral( 
"rdf:Description" ) );
 
 1398   QDomElement workElement = svg.createElement( QStringLiteral( 
"cc:Work" ) );
 
 1399   workElement.setAttribute( QStringLiteral( 
"rdf:about" ), QString() );
 
 1401   auto addTextNode = [&workElement, &descriptionElement, &svg]( 
const QString & tag, 
const QString & value )
 
 1404     QDomElement element = svg.createElement( tag );
 
 1405     QDomText t = svg.createTextNode( value );
 
 1406     element.appendChild( t );
 
 1407     workElement.appendChild( element );
 
 1410     descriptionElement.setAttribute( tag, value );
 
 1413   addTextNode( QStringLiteral( 
"dc:format" ), QStringLiteral( 
"image/svg+xml" ) );
 
 1414   addTextNode( QStringLiteral( 
"dc:title" ), metadata.
title() );
 
 1415   addTextNode( QStringLiteral( 
"dc:date" ), metadata.
creationDateTime().toString( Qt::ISODate ) );
 
 1416   addTextNode( QStringLiteral( 
"dc:identifier" ), metadata.
identifier() );
 
 1417   addTextNode( QStringLiteral( 
"dc:description" ), metadata.
abstract() );
 
 1419   auto addAgentNode = [&workElement, &descriptionElement, &svg]( 
const QString & tag, 
const QString & value )
 
 1422     QDomElement inkscapeElement = svg.createElement( tag );
 
 1423     QDomElement agentElement = svg.createElement( QStringLiteral( 
"cc:Agent" ) );
 
 1424     QDomElement titleElement = svg.createElement( QStringLiteral( 
"dc:title" ) );
 
 1425     QDomText t = svg.createTextNode( value );
 
 1426     titleElement.appendChild( t );
 
 1427     agentElement.appendChild( titleElement );
 
 1428     inkscapeElement.appendChild( agentElement );
 
 1429     workElement.appendChild( inkscapeElement );
 
 1432     QDomElement bagElement = svg.createElement( QStringLiteral( 
"rdf:Bag" ) );
 
 1433     QDomElement liElement = svg.createElement( QStringLiteral( 
"rdf:li" ) );
 
 1434     t = svg.createTextNode( value );
 
 1435     liElement.appendChild( t );
 
 1436     bagElement.appendChild( liElement );
 
 1438     QDomElement element = svg.createElement( tag );
 
 1439     element.appendChild( bagElement );
 
 1440     descriptionElement.appendChild( element );
 
 1443   addAgentNode( QStringLiteral( 
"dc:creator" ), metadata.
author() );
 
 1444   addAgentNode( QStringLiteral( 
"dc:publisher" ), QStringLiteral( 
"QGIS %1" ).arg( 
Qgis::version() ) );
 
 1448     QDomElement element = svg.createElement( QStringLiteral( 
"dc:subject" ) );
 
 1449     QDomElement bagElement = svg.createElement( QStringLiteral( 
"rdf:Bag" ) );
 
 1451     for ( 
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
 
 1453       const QStringList words = it.value();
 
 1454       for ( 
const QString &keyword : words )
 
 1456         QDomElement liElement = svg.createElement( QStringLiteral( 
"rdf:li" ) );
 
 1457         QDomText t = svg.createTextNode( keyword );
 
 1458         liElement.appendChild( t );
 
 1459         bagElement.appendChild( liElement );
 
 1462     element.appendChild( bagElement );
 
 1463     workElement.appendChild( element );
 
 1464     descriptionElement.appendChild( element );
 
 1467   rdfElement.appendChild( descriptionElement );
 
 1468   rdfElement.appendChild( workElement );
 
 1469   metadataElement.appendChild( rdfElement );
 
 1470   svg.documentElement().appendChild( metadataElement );
 
 1471   svg.documentElement().setAttribute( QStringLiteral( 
"xmlns:cc" ), QStringLiteral( 
"http://creativecommons.org/ns#" ) );
 
 1474 std::unique_ptr<double[]> QgsLayoutExporter::computeGeoTransform( 
const QgsLayoutItemMap *map, 
const QRectF ®ion, 
double dpi )
 const 
 1477     map = mLayout->referenceMap();
 
 1483     dpi = mLayout->renderContext().dpi();
 
 1486   QRectF exportRegion = region;
 
 1487   if ( !exportRegion.isValid() )
 
 1489     int pageNumber = map->
page();
 
 1492     double pageY = page->pos().y();
 
 1493     QSizeF pageSize = page->rect().size();
 
 1494     exportRegion = QRectF( 0, pageY, pageSize.width(), pageSize.height() );
 
 1498   QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
 
 1501   double outputHeightMM = exportRegion.height();
 
 1502   double outputWidthMM = exportRegion.width();
 
 1506   double mapXCenter = mapExtent.
center().
x();
 
 1507   double mapYCenter = mapExtent.
center().
y();
 
 1509   double sinAlpha = std::sin( alpha );
 
 1510   double cosAlpha = std::cos( alpha );
 
 1513   QPointF mapItemPos = map->pos();
 
 1515   mapItemPos.rx() -= exportRegion.left();
 
 1516   mapItemPos.ry() -= exportRegion.top();
 
 1519   double xRatio = mapExtent.
width() / mapItemSceneRect.width();
 
 1520   double yRatio = mapExtent.
height() / mapItemSceneRect.height();
 
 1521   double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
 
 1522   double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
 
 1523   QgsRectangle paperExtent( xmin, ymax - outputHeightMM * yRatio, xmin + outputWidthMM * xRatio, ymax );
 
 1526   double X0 = paperExtent.xMinimum();
 
 1527   double Y0 = paperExtent.yMaximum();
 
 1532     double X1 = X0 - mapXCenter;
 
 1533     double Y1 = Y0 - mapYCenter;
 
 1534     double X2 = X1 * cosAlpha + Y1 * sinAlpha;
 
 1535     double Y2 = -X1 * sinAlpha + Y1 * cosAlpha;
 
 1536     X0 = X2 + mapXCenter;
 
 1537     Y0 = Y2 + mapYCenter;
 
 1541   int pageWidthPixels = 
static_cast< int >( dpi * outputWidthMM / 25.4 );
 
 1542   int pageHeightPixels = 
static_cast< int >( dpi * outputHeightMM / 25.4 );
 
 1543   double pixelWidthScale = paperExtent.width() / pageWidthPixels;
 
 1544   double pixelHeightScale = paperExtent.height() / pageHeightPixels;
 
 1547   std::unique_ptr<double[]> t( 
new double[6] );
 
 1549   t[1] = cosAlpha * pixelWidthScale;
 
 1550   t[2] = -sinAlpha * pixelWidthScale;
 
 1552   t[4] = -sinAlpha * pixelHeightScale;
 
 1553   t[5] = -cosAlpha * pixelHeightScale;
 
 1558 void QgsLayoutExporter::writeWorldFile( 
const QString &worldFileName, 
double a, 
double b, 
double c, 
double d, 
double e, 
double f )
 const 
 1560   QFile worldFile( worldFileName );
 
 1561   if ( !worldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
 
 1565   QTextStream fout( &worldFile );
 
 1569   fout << QString::number( a, 
'f', 12 ) << 
"\r\n";
 
 1570   fout << QString::number( d, 
'f', 12 ) << 
"\r\n";
 
 1571   fout << QString::number( b, 
'f', 12 ) << 
"\r\n";
 
 1572   fout << QString::number( e, 
'f', 12 ) << 
"\r\n";
 
 1573   fout << QString::number( 
c, 
'f', 12 ) << 
"\r\n";
 
 1574   fout << QString::number( f, 
'f', 12 ) << 
"\r\n";
 
 1579   return georeferenceOutputPrivate( file, map, exportRegion, dpi, 
false );
 
 1582 bool QgsLayoutExporter::georeferenceOutputPrivate( 
const QString &file, 
QgsLayoutItemMap *map, 
const QRectF &exportRegion, 
double dpi, 
bool includeGeoreference, 
bool includeMetadata )
 const 
 1587   if ( !map && includeGeoreference )
 
 1588     map = mLayout->referenceMap();
 
 1590   std::unique_ptr<double[]> t;
 
 1592   if ( map && includeGeoreference )
 
 1595       dpi = mLayout->renderContext().dpi();
 
 1597     t = computeGeoTransform( map, exportRegion, dpi );
 
 1602   CPLSetConfigOption( 
"GDAL_PDF_DPI", QString::number( dpi ).toLocal8Bit().constData() );
 
 1607       GDALSetGeoTransform( outputDS.get(), t.get() );
 
 1609     if ( includeMetadata )
 
 1611       QString creationDateString;
 
 1612       const QDateTime creationDateTime = mLayout->project()->metadata().creationDateTime();
 
 1613       if ( creationDateTime.isValid() )
 
 1615         creationDateString = QStringLiteral( 
"D:%1" ).arg( mLayout->project()->metadata().creationDateTime().toString( QStringLiteral( 
"yyyyMMddHHmmss" ) ) );
 
 1616         if ( creationDateTime.timeZone().isValid() )
 
 1618           int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
 
 1619           creationDateString += ( offsetFromUtc >= 0 ) ? 
'+' : 
'-';
 
 1620           offsetFromUtc = std::abs( offsetFromUtc );
 
 1621           int offsetHours = offsetFromUtc / 3600;
 
 1622           int offsetMins = ( offsetFromUtc % 3600 ) / 60;
 
 1623           creationDateString += QStringLiteral( 
"%1'%2'" ).arg( offsetHours ).arg( offsetMins );
 
 1626       GDALSetMetadataItem( outputDS.get(), 
"CREATION_DATE", creationDateString.toUtf8().constData(), 
nullptr );
 
 1628       GDALSetMetadataItem( outputDS.get(), 
"AUTHOR", mLayout->project()->metadata().author().toUtf8().constData(), 
nullptr );
 
 1629       const QString creator = QStringLiteral( 
"QGIS %1" ).arg( 
Qgis::version() );
 
 1630       GDALSetMetadataItem( outputDS.get(), 
"CREATOR", creator.toUtf8().constData(), 
nullptr );
 
 1631       GDALSetMetadataItem( outputDS.get(), 
"PRODUCER", creator.toUtf8().constData(), 
nullptr );
 
 1632       GDALSetMetadataItem( outputDS.get(), 
"SUBJECT", mLayout->project()->metadata().abstract().toUtf8().constData(), 
nullptr );
 
 1633       GDALSetMetadataItem( outputDS.get(), 
"TITLE", mLayout->project()->metadata().title().toUtf8().constData(), 
nullptr );
 
 1636       QStringList allKeywords;
 
 1637       for ( 
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
 
 1639         allKeywords.append( QStringLiteral( 
"%1: %2" ).arg( it.key(), it.value().join( 
',' ) ) );
 
 1641       const QString keywordString = allKeywords.join( 
';' );
 
 1642       GDALSetMetadataItem( outputDS.get(), 
"KEYWORDS", keywordString.toUtf8().constData(), 
nullptr );
 
 1648   CPLSetConfigOption( 
"GDAL_PDF_DPI", 
nullptr );
 
 1655   if ( items.count() == 1 )
 
 1659       QString name = layoutItem->displayName();
 
 1661       if ( name.startsWith( 
'<' ) && name.endsWith( 
'>' ) )
 
 1662         name = name.mid( 1, name.length() - 2 );
 
 1666   else if ( items.count() > 1 )
 
 1668     QStringList currentLayerItemTypes;
 
 1669     for ( QGraphicsItem *item : items )
 
 1675         if ( !currentLayerItemTypes.contains( itemType ) && !currentLayerItemTypes.contains( itemTypePlural ) )
 
 1676           currentLayerItemTypes << itemType;
 
 1677         else if ( currentLayerItemTypes.contains( itemType ) )
 
 1679           currentLayerItemTypes.replace( currentLayerItemTypes.indexOf( itemType ), itemTypePlural );
 
 1684         if ( !currentLayerItemTypes.contains( QObject::tr( 
"Other" ) ) )
 
 1685           currentLayerItemTypes.append( QObject::tr( 
"Other" ) );
 
 1688     return currentLayerItemTypes.join( QLatin1String( 
", " ) );
 
 1690   return QObject::tr( 
"Layer %1" ).arg( layerId );
 
 1696   LayoutItemHider itemHider( items );
 
 1701   unsigned int layerId = 1;
 
 1703   itemHider.hideAll();
 
 1704   const QList< QGraphicsItem * > itemsToIterate = itemHider.itemsToIterate();
 
 1705   QList< QGraphicsItem * > currentLayerItems;
 
 1706   for ( QGraphicsItem *item : itemsToIterate )
 
 1710     bool canPlaceInExistingLayer = 
false;
 
 1717           switch ( prevItemBehavior )
 
 1720               canPlaceInExistingLayer = 
true;
 
 1724               canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
 
 1729               canPlaceInExistingLayer = 
false;
 
 1737           switch ( prevItemBehavior )
 
 1741               canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
 
 1746               canPlaceInExistingLayer = 
false;
 
 1754           canPlaceInExistingLayer = 
false;
 
 1759           canPlaceInExistingLayer = 
false;
 
 1763       prevType = layoutItem->
type();
 
 1770     if ( canPlaceInExistingLayer )
 
 1772       currentLayerItems << item;
 
 1777       if ( !currentLayerItems.isEmpty() )
 
 1781         ExportResult result = exportFunc( layerId, layerDetails );
 
 1785         currentLayerItems.clear();
 
 1788       itemHider.hideAll();
 
 1793         int layoutItemLayerIdx = 0;
 
 1795         mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
 
 1801           mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
 
 1805           ExportResult result = exportFunc( layerId, layerDetails );
 
 1810           layoutItemLayerIdx++;
 
 1812         layerDetails.mapLayerId.clear();
 
 1814         mLayout->renderContext().setCurrentExportLayer( -1 );
 
 1817         currentLayerItems.clear();
 
 1821         currentLayerItems << item;
 
 1825   if ( !currentLayerItems.isEmpty() )
 
 1828     ExportResult result = exportFunc( layerId, layerDetails );
 
 1843   return simplifyMethod;
 
 1857   int pageNumber = map->
page();
 
 1859   double pageY = page->pos().y();
 
 1860   QSizeF pageSize = page->rect().size();
 
 1861   QRectF pageRect( 0, pageY, pageSize.width(), pageSize.height() );
 
 1877   double destinationHeight = exportRegion.height();
 
 1878   double destinationWidth = exportRegion.width();
 
 1880   QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
 
 1885   double xRatio = mapExtent.
width() / mapItemSceneRect.width();
 
 1886   double yRatio = mapExtent.
height() / mapItemSceneRect.height();
 
 1888   double xCenter = mapExtent.
center().
x();
 
 1889   double yCenter = mapExtent.
center().
y();
 
 1892   QPointF mapItemPos = map->pos();
 
 1894   mapItemPos.rx() -= exportRegion.left();
 
 1895   mapItemPos.ry() -= exportRegion.top();
 
 1897   double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
 
 1898   double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
 
 1899   QgsRectangle paperExtent( xmin, ymax - destinationHeight * yRatio, xmin + destinationWidth * xRatio, ymax );
 
 1901   double X0 = paperExtent.
xMinimum();
 
 1902   double Y0 = paperExtent.
yMinimum();
 
 1905     dpi = mLayout->renderContext().dpi();
 
 1907   int widthPx = 
static_cast< int >( dpi * destinationWidth / 25.4 );
 
 1908   int heightPx = 
static_cast< int >( dpi * destinationHeight / 25.4 );
 
 1910   double Ww = paperExtent.
width() / widthPx;
 
 1911   double Hh = paperExtent.
height() / heightPx;
 
 1920   s[5] = Y0 + paperExtent.
height();
 
 1924   r[0] = std::cos( alpha );
 
 1925   r[1] = -std::sin( alpha );
 
 1926   r[2] = xCenter * ( 1 - std::cos( alpha ) ) + yCenter * std::sin( alpha );
 
 1927   r[3] = std::sin( alpha );
 
 1928   r[4] = std::cos( alpha );
 
 1929   r[5] = - xCenter * std::sin( alpha ) + yCenter * ( 1 - std::cos( alpha ) );
 
 1932   a = r[0] * s[0] + r[1] * s[3];
 
 1933   b = r[0] * s[1] + r[1] * s[4];
 
 1934   c = r[0] * s[2] + r[1] * s[5] + r[2];
 
 1935   d = r[3] * s[0] + r[4] * s[3];
 
 1936   e = r[3] * s[1] + r[4] * s[4];
 
 1937   f = r[3] * s[2] + r[4] * s[5] + r[5];
 
 1945   QList< QgsLayoutItem *> items;
 
 1951     if ( currentItem->isVisible() && currentItem->requiresRasterization() )
 
 1962   QList< QgsLayoutItem *> items;
 
 1968     if ( currentItem->isVisible() && currentItem->containsAdvancedEffects() )
 
 1981     if ( mLayout->pageCollection()->pageCount() == 1 )
 
 1984       bounds = mLayout->layoutBounds( 
true );
 
 1989       bounds = mLayout->pageItemBounds( page, 
true );
 
 1991     if ( bounds.width() <= 0 || bounds.height() <= 0 )
 
 1999     bounds = bounds.adjusted( -settings.
cropMargins.
left() * pixelToLayoutUnits,
 
 2011 int QgsLayoutExporter::firstPageToBeExported( 
QgsLayout *layout )
 
 2014   for ( 
int i = 0; i < pageCount; ++i )
 
 2028   if ( details.
page == 0 )
 
 2038 void QgsLayoutExporter::captureLabelingResults()
 
 2040   qDeleteAll( mLabelingResults );
 
 2041   mLabelingResults.clear();
 
 2043   QList< QgsLayoutItemMap * > maps;
 
 2044   mLayout->layoutItems( maps );
 
 2048     mLabelingResults[ map->
uuid() ] = map->mExportLabelingResults.release();
 
 2052 bool QgsLayoutExporter::saveImage( 
const QImage &image, 
const QString &imageFilename, 
const QString &imageFormat, 
QgsProject *projectForMetadata )
 
 2054   QImageWriter w( imageFilename, imageFormat.toLocal8Bit().constData() );
 
 2055   if ( imageFormat.compare( QLatin1String( 
"tiff" ), Qt::CaseInsensitive ) == 0 || imageFormat.compare( QLatin1String( 
"tif" ), Qt::CaseInsensitive ) == 0 )
 
 2057     w.setCompression( 1 ); 
 
 2059   if ( projectForMetadata )
 
 2061     w.setText( QStringLiteral( 
"Author" ), projectForMetadata->
metadata().
author() );
 
 2062     const QString creator = QStringLiteral( 
"QGIS %1" ).arg( 
Qgis::version() );
 
 2063     w.setText( QStringLiteral( 
"Creator" ), creator );
 
 2064     w.setText( QStringLiteral( 
"Producer" ), creator );
 
 2065     w.setText( QStringLiteral( 
"Subject" ), projectForMetadata->
metadata().
abstract() );
 
 2066     w.setText( QStringLiteral( 
"Created" ), projectForMetadata->
metadata().
creationDateTime().toString( Qt::ISODate ) );
 
 2067     w.setText( QStringLiteral( 
"Title" ), projectForMetadata->
metadata().
title() );
 
 2070     QStringList allKeywords;
 
 2071     for ( 
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
 
 2073       allKeywords.append( QStringLiteral( 
"%1: %2" ).arg( it.key(), it.value().join( 
',' ) ) );
 
 2075     const QString keywordString = allKeywords.join( 
';' );
 
 2076     w.setText( QStringLiteral( 
"Keywords" ), keywordString );
 
 2078   return w.write( image );
 
static QString version()
Version string.
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 bool next()=0
Iterates to next feature, returning false if no more features exist to iterate over.
virtual QgsLayout * layout()=0
Returns the layout associated with the iterator.
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, QgsUnitTypes::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 setTextRenderFormat(QgsRenderContext::TextRenderFormat format)
Sets the text render format, which dictates how text is rendered (e.g.
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 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.
@ 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.
const QgsLayoutMeasurementConverter & measurementConverter() const
Returns the layout measurement converter to be used in the layout.
void setFlags(QgsLayoutRenderContext::Flags flags)
Sets the combination of flags that will be used for rendering 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.
TextRenderFormat
Options for rendering text.
@ TextFormatAlwaysOutlines
Always render text using path objects (AKA outlines/curves).
@ LayoutMillimeters
Millimeters.
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.
QgsRenderContext::TextRenderFormat textRenderFormat
Text rendering format, which controls how text should be rendered in the export (e....
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,...
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...
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.
QgsRenderContext::TextRenderFormat textRenderFormat
Text rendering format, which controls how text should be rendered in the export (e....
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.