31#include <QImageWriter> 
   33#include <QSvgGenerator> 
   42class LayoutContextPreviewSettingRestorer
 
   46    LayoutContextPreviewSettingRestorer( 
QgsLayout *layout )
 
   48      , mPreviousSetting( layout->renderContext().mIsPreviewRender )
 
   50      mLayout->renderContext().mIsPreviewRender = 
false;
 
   53    ~LayoutContextPreviewSettingRestorer()
 
   55      mLayout->renderContext().mIsPreviewRender = mPreviousSetting;
 
   58    LayoutContextPreviewSettingRestorer( 
const LayoutContextPreviewSettingRestorer &other ) = 
delete;
 
   59    LayoutContextPreviewSettingRestorer &operator=( 
const LayoutContextPreviewSettingRestorer &other ) = 
delete;
 
   63    bool mPreviousSetting = 
false;
 
   73      const QList< QgsLayoutGuide * > guides = mLayout->guides().guides();
 
   76        mPrevVisibility.insert( guide, guide->item()->isVisible() );
 
   77        guide->item()->setVisible( 
false );
 
   83      for ( 
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
 
   85        it.key()->item()->setVisible( it.value() );
 
   89    LayoutGuideHider( 
const LayoutGuideHider &other ) = 
delete;
 
   90    LayoutGuideHider &operator=( 
const LayoutGuideHider &other ) = 
delete;
 
   94    QHash< QgsLayoutGuide *, bool > mPrevVisibility;
 
  100    explicit LayoutItemHider( 
const QList<QGraphicsItem *> &items )
 
  102      mItemsToIterate.reserve( items.count() );
 
  103      for ( QGraphicsItem *item : items )
 
  105        const bool isVisible = item->isVisible();
 
  106        mPrevVisibility[item] = isVisible;
 
  108          mItemsToIterate.append( item );
 
  110          layoutItem->setProperty( 
"wasVisible", isVisible );
 
  118      for ( 
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
 
  126      for ( 
auto it = mPrevVisibility.constBegin(); it != mPrevVisibility.constEnd(); ++it )
 
  128        it.key()->setVisible( it.value() );
 
  130          layoutItem->setProperty( 
"wasVisible", QVariant() );
 
  134    QList< QGraphicsItem * > itemsToIterate()
 const { 
return mItemsToIterate; }
 
  136    LayoutItemHider( 
const LayoutItemHider &other ) = 
delete;
 
  137    LayoutItemHider &operator=( 
const LayoutItemHider &other ) = 
delete;
 
  141    QList<QGraphicsItem * > mItemsToIterate;
 
  142    QHash<QGraphicsItem *, bool> mPrevVisibility;
 
  155  qDeleteAll( mLabelingResults );
 
  168  if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
 
  179  LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  182  QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
 
  191  if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
 
  202  LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  205  QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
 
  207  const double imageAspectRatio = 
static_cast< double >( imageSize.width() ) / imageSize.height();
 
  208  const double paperAspectRatio = paperRect.width() / paperRect.height();
 
  209  if ( imageSize.isValid() && ( !
qgsDoubleNear( imageAspectRatio, paperAspectRatio, 0.008 ) ) )
 
  214    QgsMessageLog::logMessage( QObject::tr( 
"Ignoring custom image size because aspect ratio %1 does not match paper ratio %2" ).arg( QString::number( imageAspectRatio, 
'g', 3 ), QString::number( paperAspectRatio, 
'g', 3 ) ), QStringLiteral( 
"Layout" ), Qgis::MessageLevel::Warning );
 
  222class LayoutItemCacheSettingRestorer
 
  226    LayoutItemCacheSettingRestorer( 
QgsLayout *layout )
 
  229      const QList< QGraphicsItem * > items = mLayout->items();
 
  230      for ( QGraphicsItem *item : items )
 
  232        mPrevCacheMode.insert( item, item->cacheMode() );
 
  233        item->setCacheMode( QGraphicsItem::NoCache );
 
  237    ~LayoutItemCacheSettingRestorer()
 
  239      for ( 
auto it = mPrevCacheMode.constBegin(); it != mPrevCacheMode.constEnd(); ++it )
 
  241        it.key()->setCacheMode( it.value() );
 
  245    LayoutItemCacheSettingRestorer( 
const LayoutItemCacheSettingRestorer &other ) = 
delete;
 
  246    LayoutItemCacheSettingRestorer &operator=( 
const LayoutItemCacheSettingRestorer &other ) = 
delete;
 
  250    QHash< QGraphicsItem *, QGraphicsItem::CacheMode > mPrevCacheMode;
 
  257  QPaintDevice *paintDevice = painter->device();
 
  258  if ( !paintDevice || !mLayout )
 
  263  LayoutItemCacheSettingRestorer cacheRestorer( mLayout );
 
  264  ( void )cacheRestorer;
 
  265  LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  267  LayoutGuideHider guideHider( mLayout );
 
  272  mLayout->render( painter, QRectF( 0, 0, paintDevice->width(), paintDevice->height() ), region );
 
  280  LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  283  double resolution = mLayout->renderContext().dpi();
 
  284  double oneInchInLayoutUnits = mLayout->convertToLayoutUnits( 
QgsLayoutMeasurement( 1, Qgis::LayoutUnit::Inches ) );
 
  285  if ( imageSize.isValid() )
 
  289    resolution = ( imageSize.width() / region.width()
 
  290                   + imageSize.height() / region.height() ) / 2.0 * oneInchInLayoutUnits;
 
  298  int width = imageSize.isValid() ? imageSize.width()
 
  299              : 
static_cast< int >( resolution * region.width() / oneInchInLayoutUnits );
 
  300  int height = imageSize.isValid() ? imageSize.height()
 
  301               : 
static_cast< int >( resolution * region.height() / oneInchInLayoutUnits );
 
  303  QImage image( QSize( width, height ), QImage::Format_ARGB32 );
 
  304  if ( !image.isNull() )
 
  307    if ( width > 32768 || height > 32768 )
 
  308      QgsMessageLog::logMessage( QObject::tr( 
"Error: output width or height is larger than 32768 pixel, result will be clipped" ) );
 
  309    image.setDotsPerMeterX( 
static_cast< int >( std::round( resolution / 25.4 * 1000 ) ) );
 
  310    image.setDotsPerMeterY( 
static_cast< int>( std::round( resolution / 25.4 * 1000 ) ) );
 
  311    image.fill( Qt::transparent );
 
  312    QPainter imagePainter( &image );
 
  314    if ( !imagePainter.isActive() )
 
  322class LayoutContextSettingsRestorer
 
  327    LayoutContextSettingsRestorer( 
QgsLayout *layout )
 
  329      , mPreviousDpi( layout->renderContext().dpi() )
 
  330      , mPreviousFlags( layout->renderContext().flags() )
 
  331      , mPreviousTextFormat( layout->renderContext().textRenderFormat() )
 
  332      , mPreviousExportLayer( layout->renderContext().currentExportLayer() )
 
  333      , mPreviousSimplifyMethod( layout->renderContext().simplifyMethod() )
 
  334      , mExportThemes( layout->renderContext().exportThemes() )
 
  335      , mPredefinedScales( layout->renderContext().predefinedScales() )
 
  340    ~LayoutContextSettingsRestorer()
 
  342      mLayout->renderContext().setDpi( mPreviousDpi );
 
  343      mLayout->renderContext().setFlags( mPreviousFlags );
 
  344      mLayout->renderContext().setTextRenderFormat( mPreviousTextFormat );
 
  346      mLayout->renderContext().setCurrentExportLayer( mPreviousExportLayer );
 
  348      mLayout->renderContext().setSimplifyMethod( mPreviousSimplifyMethod );
 
  349      mLayout->renderContext().setExportThemes( mExportThemes );
 
  350      mLayout->renderContext().setPredefinedScales( mPredefinedScales );
 
  353    LayoutContextSettingsRestorer( 
const LayoutContextSettingsRestorer &other ) = 
delete;
 
  354    LayoutContextSettingsRestorer &operator=( 
const LayoutContextSettingsRestorer &other ) = 
delete;
 
  358    double mPreviousDpi = 0;
 
  359    QgsLayoutRenderContext::Flags mPreviousFlags = QgsLayoutRenderContext::Flags();
 
  361    int mPreviousExportLayer = 0;
 
  363    QStringList mExportThemes;
 
  364    QVector< double > mPredefinedScales;
 
  375  if ( settings.
dpi <= 0 )
 
  376    settings.
dpi = mLayout->renderContext().dpi();
 
  378  mErrorFileName.clear();
 
  380  int worldFilePageNo = -1;
 
  383    worldFilePageNo = referenceMap->page();
 
  386  QFileInfo fi( filePath );
 
  388  if ( !dir.exists( fi.absolutePath() ) )
 
  390    dir.mkpath( fi.absolutePath() );
 
  395  pageDetails.
baseName = fi.completeBaseName();
 
  398  LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  400  LayoutContextSettingsRestorer dpiRestorer( mLayout );
 
  402  mLayout->renderContext().setDpi( settings.
dpi );
 
  403  mLayout->renderContext().setFlags( settings.
flags );
 
  407  if ( settings.
pages.empty() )
 
  409    for ( 
int page = 0; page < mLayout->pageCollection()->pageCount(); ++page )
 
  414    for ( 
int page : std::as_const( settings.
pages ) )
 
  416      if ( page >= 0 && page < mLayout->pageCollection()->pageCount() )
 
  421  for ( 
int page : std::as_const( pages ) )
 
  423    if ( !mLayout->pageCollection()->shouldExportPage( page ) )
 
  430    QImage image = createImage( settings, page, bounds, skip );
 
  435    pageDetails.
page = page;
 
  438    if ( image.isNull() )
 
  440      mErrorFileName = outputFilePath;
 
  444    if ( !saveImage( image, outputFilePath, pageDetails.
extension, settings.
exportMetadata ? mLayout->project() : 
nullptr ) )
 
  446      mErrorFileName = outputFilePath;
 
  450    const bool shouldGeoreference = ( page == worldFilePageNo );
 
  451    if ( shouldGeoreference )
 
  453      georeferenceOutputPrivate( outputFilePath, 
nullptr, bounds, settings.
dpi, shouldGeoreference );
 
  458        double a, b, 
c, d, e, f;
 
  459        if ( bounds.isValid() )
 
  464        QFileInfo fi( outputFilePath );
 
  466        QString outputSuffix = fi.suffix();
 
  467        QString worldFileName = fi.absolutePath() + 
'/' + fi.completeBaseName() + 
'.' 
  468                                + outputSuffix.at( 0 ) + outputSuffix.at( fi.suffix().size() - 1 ) + 
'w';
 
  470        writeWorldFile( worldFileName, a, b, 
c, d, e, f );
 
  475  captureLabelingResults();
 
  486  int total = iterator->
count();
 
  487  double step = total > 0 ? 100.0 / total : 100.0;
 
  489  while ( iterator->
next() )
 
  494        feedback->setProperty( 
"progress", QObject::tr( 
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
 
  496        feedback->setProperty( 
"progress", QObject::tr( 
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
 
  506    QString filePath = iterator->
filePath( baseFilePath, extension );
 
  511        error = QObject::tr( 
"Cannot write to %1. This file may be open in another application or may be an invalid path." ).arg( QDir::toNativeSeparators( filePath ) );
 
  529  if ( !mLayout || mLayout->pageCollection()->pageCount() == 0 )
 
  533  if ( settings.
dpi <= 0 )
 
  534    settings.
dpi = mLayout->renderContext().dpi();
 
  536  mErrorFileName.clear();
 
  538  LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  540  LayoutContextSettingsRestorer contextRestorer( mLayout );
 
  541  ( void )contextRestorer;
 
  542  mLayout->renderContext().setDpi( settings.
dpi );
 
  547    mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
 
  550  std::unique_ptr< QgsLayoutGeoPdfExporter > geoPdfExporter;
 
  552    geoPdfExporter = std::make_unique< QgsLayoutGeoPdfExporter >( mLayout );
 
  554  mLayout->renderContext().setFlags( settings.
flags );
 
  562  mLayout->renderContext().setExportThemes( settings.
exportThemes );
 
  574    const QList<QGraphicsItem *> items = mLayout->items( Qt::AscendingOrder );
 
  576    QList< QgsLayoutGeoPdfExporter::ComponentLayerDetail > pdfComponents;
 
  585      component.
name = layerDetail.name;
 
  586      component.
mapLayerId = layerDetail.mapLayerId;
 
  587      component.
opacity = layerDetail.opacity;
 
  589      component.
group = layerDetail.mapTheme;
 
  590      component.
sourcePdfPath = settings.writeGeoPdf ? geoPdfExporter->generateTemporaryFilepath( QStringLiteral( 
"layer_%1.pdf" ).arg( layerId ) ) : baseDir.filePath( QStringLiteral( 
"%1_%2.pdf" ).arg( baseFileName ).arg( layerId, 4, 10, QChar( 
'0' ) ) );
 
  591      pdfComponents << component;
 
  593      preparePrintAsPdf( mLayout, &printer, component.
sourcePdfPath );
 
  594      preparePrint( mLayout, &printer, 
false );
 
  596      if ( !p.begin( &printer ) )
 
  604      return layerExportResult;
 
  606    result = handleLayeredExport( items, exportFunc );
 
  610    if ( settings.writeGeoPdf )
 
  613      details.
dpi = settings.dpi;
 
  615      QgsLayoutSize pageSize = mLayout->pageCollection()->page( 0 )->sizeWithUnits();
 
  616      QgsLayoutSize pageSizeMM = mLayout->renderContext().measurementConverter().convert( pageSize, Qgis::LayoutUnit::Millimeters );
 
  619      if ( settings.exportMetadata )
 
  622        details.
author = mLayout->project()->metadata().author();
 
  625        details.
creationDateTime = mLayout->project()->metadata().creationDateTime();
 
  626        details.
subject = mLayout->project()->metadata().abstract();
 
  627        details.
title = mLayout->project()->metadata().title();
 
  628        details.
keywords = mLayout->project()->metadata().keywords();
 
  631      const QList< QgsMapLayer * > layers = mLayout->project()->mapLayers().values();
 
  637      if ( settings.appendGeoreference )
 
  640        QList< QgsLayoutItemMap * > maps;
 
  641        mLayout->layoutItems( maps );
 
  645          georef.
crs = map->crs();
 
  647          const QPointF topLeft = map->mapToScene( QPointF( 0, 0 ) );
 
  648          const QPointF topRight = map->mapToScene( QPointF( map->rect().width(), 0 ) );
 
  649          const QPointF bottomLeft = map->mapToScene( QPointF( 0, map->rect().height() ) );
 
  650          const QPointF bottomRight = map->mapToScene( QPointF( map->rect().width(), map->rect().height() ) );
 
  651          const QgsLayoutPoint topLeftMm = mLayout->convertFromLayoutUnits( topLeft, Qgis::LayoutUnit::Millimeters );
 
  652          const QgsLayoutPoint topRightMm = mLayout->convertFromLayoutUnits( topRight, Qgis::LayoutUnit::Millimeters );
 
  653          const QgsLayoutPoint bottomLeftMm = mLayout->convertFromLayoutUnits( bottomLeft, Qgis::LayoutUnit::Millimeters );
 
  654          const QgsLayoutPoint bottomRightMm = mLayout->convertFromLayoutUnits( bottomRight, Qgis::LayoutUnit::Millimeters );
 
  663          const QTransform t = map->layoutToMapCoordsTransform();
 
  664          const QgsPointXY topLeftMap = t.map( topLeft );
 
  665          const QgsPointXY topRightMap = t.map( topRight );
 
  666          const QgsPointXY bottomLeftMap = t.map( bottomLeft );
 
  667          const QgsPointXY bottomRightMap = t.map( bottomRight );
 
  679      details.
layerOrder = geoPdfExporter->layerOrder();
 
  684      if ( !geoPdfExporter->finalize( pdfComponents, filePath, details ) )
 
  694    QPdfWriter printer = QPdfWriter( filePath );
 
  695    preparePrintAsPdf( mLayout, &printer, filePath );
 
  696    preparePrint( mLayout, &printer, 
false );
 
  698    if ( !p.begin( &printer ) )
 
  707    bool shouldAppendGeoreference = settings.
appendGeoreference && mLayout && mLayout->referenceMap() && mLayout->referenceMap()->page() == 0;
 
  710      georeferenceOutputPrivate( filePath, 
nullptr, QRectF(), settings.
dpi, shouldAppendGeoreference, settings.
exportMetadata );
 
  713  captureLabelingResults();
 
  726  QPdfWriter printer = QPdfWriter( fileName );
 
  729  int total = iterator->
count();
 
  730  double step = total > 0 ? 100.0 / total : 100.0;
 
  733  while ( iterator->
next() )
 
  738        feedback->setProperty( 
"progress", QObject::tr( 
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
 
  740        feedback->setProperty( 
"progress", QObject::tr( 
"Exporting section %1" ).arg( i + 1 ) );
 
  752    LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
 
  754    LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
 
  755    ( void )contextRestorer;
 
  777      preparePrintAsPdf( iterator->
layout(), &printer, fileName );
 
  778      preparePrint( iterator->
layout(), &printer, 
false );
 
  780      if ( !p.begin( &printer ) )
 
  794        error = QObject::tr( 
"Cannot write to %1. This file may be open in another application or may be an invalid path." ).arg( QDir::toNativeSeparators( fileName ) );
 
  818  int total = iterator->
count();
 
  819  double step = total > 0 ? 100.0 / total : 100.0;
 
  821  while ( iterator->
next() )
 
  826        feedback->setProperty( 
"progress", QObject::tr( 
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
 
  828        feedback->setProperty( 
"progress", QObject::tr( 
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
 
  837    QString filePath = iterator->
filePath( baseFilePath, QStringLiteral( 
"pdf" ) );
 
  844        error = QObject::tr( 
"Cannot write to %1. This file may be open in another application or may be an invalid path." ).arg( QDir::toNativeSeparators( filePath ) );
 
  867  if ( settings.
dpi <= 0 )
 
  868    settings.
dpi = mLayout->renderContext().dpi();
 
  870  mErrorFileName.clear();
 
  872  LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  874  LayoutContextSettingsRestorer contextRestorer( mLayout );
 
  875  ( void )contextRestorer;
 
  876  mLayout->renderContext().setDpi( settings.
dpi );
 
  878  mLayout->renderContext().setFlags( settings.
flags );
 
  885  preparePrint( mLayout, &printer, 
true );
 
  887  if ( !p.begin( &printer ) )
 
  896  captureLabelingResults();
 
  911  int total = iterator->
count();
 
  912  double step = total > 0 ? 100.0 / total : 100.0;
 
  915  while ( iterator->
next() )
 
  920        feedback->setProperty( 
"progress", QObject::tr( 
"Printing %1 of %2" ).arg( i + 1 ).arg( total ) );
 
  922        feedback->setProperty( 
"progress", QObject::tr( 
"Printing section %1" ).arg( i + 1 ).arg( total ) );
 
  934    LayoutContextPreviewSettingRestorer restorer( iterator->
layout() );
 
  936    LayoutContextSettingsRestorer contextRestorer( iterator->
layout() );
 
  937    ( void )contextRestorer;
 
  950      preparePrint( iterator->
layout(), &printer, 
true );
 
  952      if ( !p.begin( &printer ) )
 
  988  if ( settings.
dpi <= 0 )
 
  989    settings.
dpi = mLayout->renderContext().dpi();
 
  991  mErrorFileName.clear();
 
  993  LayoutContextPreviewSettingRestorer restorer( mLayout );
 
  995  LayoutContextSettingsRestorer contextRestorer( mLayout );
 
  996  ( void )contextRestorer;
 
  997  mLayout->renderContext().setDpi( settings.
dpi );
 
  999  mLayout->renderContext().setFlags( settings.
flags );
 
 1006    mLayout->renderContext().setSimplifyMethod( createExportSimplifyMethod() );
 
 1009  QFileInfo fi( filePath );
 
 1012  pageDetails.
baseName = fi.baseName();
 
 1013  pageDetails.
extension = fi.completeSuffix();
 
 1015  double inchesToLayoutUnits = mLayout->convertToLayoutUnits( 
QgsLayoutMeasurement( 1, Qgis::LayoutUnit::Inches ) );
 
 1017  for ( 
int i = 0; i < mLayout->pageCollection()->pageCount(); ++i )
 
 1019    if ( !mLayout->pageCollection()->shouldExportPage( i ) )
 
 1024    pageDetails.
page = i;
 
 1031      if ( mLayout->pageCollection()->pageCount() == 1 )
 
 1034        bounds = mLayout->layoutBounds( 
true );
 
 1039        bounds = mLayout->pageItemBounds( i, 
true );
 
 1048      bounds = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
 
 1052    int width = 
static_cast< int >( bounds.width() * settings.
dpi / inchesToLayoutUnits );
 
 1054    int height = 
static_cast< int >( bounds.height() * settings.
dpi / inchesToLayoutUnits );
 
 1055    if ( width == 0 || height == 0 )
 
 1064      const QRectF paperRect = QRectF( pageItem->pos().x(),
 
 1065                                       pageItem->pos().y(),
 
 1066                                       pageItem->rect().width(),
 
 1067                                       pageItem->rect().height() );
 
 1069      QDomNode svgDocRoot;
 
 1070      const QList<QGraphicsItem *> items = mLayout->items( paperRect,
 
 1071                                           Qt::IntersectsItemBoundingRect,
 
 1072                                           Qt::AscendingOrder );
 
 1076        return renderToLayeredSvg( settings, width, height, i, bounds, fileName, layerId, layerDetail.name, svg, svgDocRoot, settings.
exportMetadata );
 
 1078      ExportResult res = handleLayeredExport( items, exportFunc );
 
 1083        appendMetadataToSvg( svg );
 
 1085      QFile out( fileName );
 
 1086      bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
 
 1089        mErrorFileName = fileName;
 
 1093      out.write( svg.toByteArray() );
 
 1099        QSvgGenerator generator;
 
 1102          generator.setTitle( mLayout->project()->metadata().title() );
 
 1103          generator.setDescription( mLayout->project()->metadata().abstract() );
 
 1105        generator.setOutputDevice( &svgBuffer );
 
 1106        generator.setSize( QSize( width, height ) );
 
 1107        generator.setViewBox( QRect( 0, 0, width, height ) );
 
 1108        generator.setResolution( 
static_cast< int >( std::round( settings.
dpi ) ) );
 
 1111        bool createOk = p.begin( &generator );
 
 1114          mErrorFileName = fileName;
 
 1127        svgBuffer.open( QIODevice::ReadOnly );
 
 1131        if ( ! svg.setContent( &svgBuffer, 
false, &errorMsg, &errorLine ) )
 
 1133          mErrorFileName = fileName;
 
 1138          appendMetadataToSvg( svg );
 
 1140        QFile out( fileName );
 
 1141        bool openOk = out.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate );
 
 1144          mErrorFileName = fileName;
 
 1148        out.write( svg.toByteArray() );
 
 1152  captureLabelingResults();
 
 1163  int total = iterator->
count();
 
 1164  double step = total > 0 ? 100.0 / total : 100.0;
 
 1166  while ( iterator->
next() )
 
 1171        feedback->setProperty( 
"progress", QObject::tr( 
"Exporting %1 of %2" ).arg( i + 1 ).arg( total ) );
 
 1173        feedback->setProperty( 
"progress", QObject::tr( 
"Exporting section %1" ).arg( i + 1 ).arg( total ) );
 
 1183    QString filePath = iterator->
filePath( baseFilePath, QStringLiteral( 
"svg" ) );
 
 1190        error = QObject::tr( 
"Cannot write to %1. This file may be open in another application or may be an invalid path." ).arg( QDir::toNativeSeparators( filePath ) );
 
 1209  return mLabelingResults;
 
 1214  QMap<QString, QgsLabelingResults *> res;
 
 1215  std::swap( mLabelingResults, res );
 
 1219void QgsLayoutExporter::preparePrintAsPdf( 
QgsLayout *layout, QPagedPaintDevice *device, 
const QString &filePath )
 
 1221  QFileInfo fi( filePath );
 
 1223  if ( !dir.exists( fi.absolutePath() ) )
 
 1225    dir.mkpath( fi.absolutePath() );
 
 1228  updatePrinterPageSize( 
layout, device, firstPageToBeExported( 
layout ) );
 
 1234#if defined(HAS_KDE_QT5_PDF_TRANSFORM_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0) 
 1241void QgsLayoutExporter::preparePrint( 
QgsLayout *layout, QPagedPaintDevice *device, 
bool setFirstPageSize )
 
 1243  if ( QPdfWriter *pdf = 
dynamic_cast<QPdfWriter *
>( device ) )
 
 1247#ifndef QT_NO_PRINTER 
 1248  else if ( QPrinter *printer = 
dynamic_cast<QPrinter *
>( device ) )
 
 1250    printer->setFullPage( 
true );
 
 1251    printer->setColorMode( QPrinter::Color );
 
 1257  if ( setFirstPageSize )
 
 1259    updatePrinterPageSize( 
layout, device, firstPageToBeExported( 
layout ) );
 
 1265  if ( mLayout->pageCollection()->pageCount() == 0 )
 
 1268  preparePrint( mLayout, device, 
true );
 
 1270  if ( !p.begin( device ) )
 
 1276  printPrivate( device, p );
 
 1281QgsLayoutExporter::ExportResult QgsLayoutExporter::printPrivate( QPagedPaintDevice *device, QPainter &painter, 
bool startNewPage, 
double dpi, 
bool rasterize )
 
 1285  int toPage = mLayout->pageCollection()->pageCount() - 1;
 
 1287#ifndef QT_NO_PRINTER 
 1288  if ( QPrinter *printer = 
dynamic_cast<QPrinter *
>( device ) )
 
 1290    if ( printer->fromPage() >= 1 )
 
 1291      fromPage = printer->fromPage() - 1;
 
 1292    if ( printer->toPage() >= 1 )
 
 1293      toPage = printer->toPage() - 1;
 
 1297  bool pageExported = 
false;
 
 1300    for ( 
int i = fromPage; i <= toPage; ++i )
 
 1302      if ( !mLayout->pageCollection()->shouldExportPage( i ) )
 
 1307      updatePrinterPageSize( mLayout, device, i );
 
 1308      if ( ( pageExported && i > fromPage ) || startNewPage )
 
 1314      if ( !image.isNull() )
 
 1316        QRectF targetArea( 0, 0, image.width(), image.height() );
 
 1317        painter.drawImage( targetArea, image, targetArea );
 
 1323      pageExported = 
true;
 
 1328    for ( 
int i = fromPage; i <= toPage; ++i )
 
 1330      if ( !mLayout->pageCollection()->shouldExportPage( i ) )
 
 1335      updatePrinterPageSize( mLayout, device, i );
 
 1337      if ( ( pageExported && i > fromPage ) || startNewPage )
 
 1342      pageExported = 
true;
 
 1348void QgsLayoutExporter::updatePrinterPageSize( 
QgsLayout *layout, QPagedPaintDevice *device, 
int page )
 
 1353  QPageLayout pageLayout( QPageSize( pageSizeMM.
toQSizeF(), QPageSize::Millimeter ),
 
 1354                          QPageLayout::Portrait,
 
 1355                          QMarginsF( 0, 0, 0, 0 ) );
 
 1356  pageLayout.setMode( QPageLayout::FullPageMode );
 
 1357  device->setPageLayout( pageLayout );
 
 1358  device->setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
 
 1360#ifndef QT_NO_PRINTER 
 1361  if ( QPrinter *printer = 
dynamic_cast<QPrinter *
>( device ) )
 
 1363    printer->setFullPage( 
true );
 
 1368QgsLayoutExporter::ExportResult QgsLayoutExporter::renderToLayeredSvg( 
const SvgExportSettings &settings, 
double width, 
double height, 
int page, 
const QRectF &bounds, 
const QString &filename, 
unsigned int svgLayerId, 
const QString &layerName, QDomDocument &svg, QDomNode &svgDocRoot, 
bool includeMetadata )
 const 
 1372    QSvgGenerator generator;
 
 1373    if ( includeMetadata )
 
 1376        generator.setTitle( l->name() );
 
 1377      else if ( mLayout->project() )
 
 1378        generator.setTitle( mLayout->project()->title() );
 
 1381    generator.setOutputDevice( &svgBuffer );
 
 1382    generator.setSize( QSize( 
static_cast< int >( std::round( width ) ),
 
 1383                              static_cast< int >( std::round( height ) ) ) );
 
 1384    generator.setViewBox( QRect( 0, 0,
 
 1385                                 static_cast< int >( std::round( width ) ),
 
 1386                                 static_cast< int >( std::round( height ) ) ) );
 
 1387    generator.setResolution( 
static_cast< int >( std::round( settings.dpi ) ) ); 
 
 1389    QPainter svgPainter( &generator );
 
 1390    if ( settings.cropToContents )
 
 1401    svgBuffer.open( QIODevice::ReadOnly );
 
 1405    if ( ! doc.setContent( &svgBuffer, 
false, &errorMsg, &errorLine ) )
 
 1407      mErrorFileName = filename;
 
 1410    if ( 1 == svgLayerId )
 
 1412      svg = QDomDocument( doc.doctype() );
 
 1413      svg.appendChild( svg.importNode( doc.firstChild(), 
false ) );
 
 1414      svgDocRoot = svg.importNode( doc.elementsByTagName( QStringLiteral( 
"svg" ) ).at( 0 ), 
false );
 
 1415      svgDocRoot.toElement().setAttribute( QStringLiteral( 
"xmlns:inkscape" ), QStringLiteral( 
"http://www.inkscape.org/namespaces/inkscape" ) );
 
 1416      svg.appendChild( svgDocRoot );
 
 1418    QDomNode mainGroup = svg.importNode( doc.elementsByTagName( QStringLiteral( 
"g" ) ).at( 0 ), 
true );
 
 1419    mainGroup.toElement().setAttribute( QStringLiteral( 
"id" ), layerName );
 
 1420    mainGroup.toElement().setAttribute( QStringLiteral( 
"inkscape:label" ), layerName );
 
 1421    mainGroup.toElement().setAttribute( QStringLiteral( 
"inkscape:groupmode" ), QStringLiteral( 
"layer" ) );
 
 1422    QDomNode defs = svg.importNode( doc.elementsByTagName( QStringLiteral( 
"defs" ) ).at( 0 ), 
true );
 
 1423    svgDocRoot.appendChild( defs );
 
 1424    svgDocRoot.appendChild( mainGroup );
 
 1429void QgsLayoutExporter::appendMetadataToSvg( QDomDocument &svg )
 const 
 1432  QDomElement metadataElement = svg.createElement( QStringLiteral( 
"metadata" ) );
 
 1433  QDomElement rdfElement = svg.createElement( QStringLiteral( 
"rdf:RDF" ) );
 
 1434  rdfElement.setAttribute( QStringLiteral( 
"xmlns:rdf" ), QStringLiteral( 
"http://www.w3.org/1999/02/22-rdf-syntax-ns#" ) );
 
 1435  rdfElement.setAttribute( QStringLiteral( 
"xmlns:rdfs" ), QStringLiteral( 
"http://www.w3.org/2000/01/rdf-schema#" ) );
 
 1436  rdfElement.setAttribute( QStringLiteral( 
"xmlns:dc" ), QStringLiteral( 
"http://purl.org/dc/elements/1.1/" ) );
 
 1437  QDomElement descriptionElement = svg.createElement( QStringLiteral( 
"rdf:Description" ) );
 
 1438  QDomElement workElement = svg.createElement( QStringLiteral( 
"cc:Work" ) );
 
 1439  workElement.setAttribute( QStringLiteral( 
"rdf:about" ), QString() );
 
 1441  auto addTextNode = [&workElement, &descriptionElement, &svg]( 
const QString & tag, 
const QString & value )
 
 1444    QDomElement element = svg.createElement( tag );
 
 1445    QDomText t = svg.createTextNode( value );
 
 1446    element.appendChild( t );
 
 1447    workElement.appendChild( element );
 
 1450    descriptionElement.setAttribute( tag, value );
 
 1453  addTextNode( QStringLiteral( 
"dc:format" ), QStringLiteral( 
"image/svg+xml" ) );
 
 1454  addTextNode( QStringLiteral( 
"dc:title" ), metadata.
title() );
 
 1455  addTextNode( QStringLiteral( 
"dc:date" ), metadata.
creationDateTime().toString( Qt::ISODate ) );
 
 1456  addTextNode( QStringLiteral( 
"dc:identifier" ), metadata.
identifier() );
 
 1457  addTextNode( QStringLiteral( 
"dc:description" ), metadata.
abstract() );
 
 1459  auto addAgentNode = [&workElement, &descriptionElement, &svg]( 
const QString & tag, 
const QString & value )
 
 1462    QDomElement inkscapeElement = svg.createElement( tag );
 
 1463    QDomElement agentElement = svg.createElement( QStringLiteral( 
"cc:Agent" ) );
 
 1464    QDomElement titleElement = svg.createElement( QStringLiteral( 
"dc:title" ) );
 
 1465    QDomText t = svg.createTextNode( value );
 
 1466    titleElement.appendChild( t );
 
 1467    agentElement.appendChild( titleElement );
 
 1468    inkscapeElement.appendChild( agentElement );
 
 1469    workElement.appendChild( inkscapeElement );
 
 1472    QDomElement bagElement = svg.createElement( QStringLiteral( 
"rdf:Bag" ) );
 
 1473    QDomElement liElement = svg.createElement( QStringLiteral( 
"rdf:li" ) );
 
 1474    t = svg.createTextNode( value );
 
 1475    liElement.appendChild( t );
 
 1476    bagElement.appendChild( liElement );
 
 1478    QDomElement element = svg.createElement( tag );
 
 1479    element.appendChild( bagElement );
 
 1480    descriptionElement.appendChild( element );
 
 1483  addAgentNode( QStringLiteral( 
"dc:creator" ), metadata.
author() );
 
 1484  addAgentNode( QStringLiteral( 
"dc:publisher" ), QStringLiteral( 
"QGIS %1" ).arg( 
Qgis::version() ) );
 
 1488    QDomElement element = svg.createElement( QStringLiteral( 
"dc:subject" ) );
 
 1489    QDomElement bagElement = svg.createElement( QStringLiteral( 
"rdf:Bag" ) );
 
 1491    for ( 
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
 
 1493      const QStringList words = it.value();
 
 1494      for ( 
const QString &keyword : words )
 
 1496        QDomElement liElement = svg.createElement( QStringLiteral( 
"rdf:li" ) );
 
 1497        QDomText t = svg.createTextNode( keyword );
 
 1498        liElement.appendChild( t );
 
 1499        bagElement.appendChild( liElement );
 
 1502    element.appendChild( bagElement );
 
 1503    workElement.appendChild( element );
 
 1504    descriptionElement.appendChild( element );
 
 1507  rdfElement.appendChild( descriptionElement );
 
 1508  rdfElement.appendChild( workElement );
 
 1509  metadataElement.appendChild( rdfElement );
 
 1510  svg.documentElement().appendChild( metadataElement );
 
 1511  svg.documentElement().setAttribute( QStringLiteral( 
"xmlns:cc" ), QStringLiteral( 
"http://creativecommons.org/ns#" ) );
 
 1514std::unique_ptr<double[]> QgsLayoutExporter::computeGeoTransform( 
const QgsLayoutItemMap *map, 
const QRectF ®ion, 
double dpi )
 const 
 1517    map = mLayout->referenceMap();
 
 1523    dpi = mLayout->renderContext().dpi();
 
 1526  QRectF exportRegion = region;
 
 1527  if ( !exportRegion.isValid() )
 
 1529    int pageNumber = map->
page();
 
 1532    double pageY = page->pos().y();
 
 1533    QSizeF pageSize = page->rect().size();
 
 1534    exportRegion = QRectF( 0, pageY, pageSize.width(), pageSize.height() );
 
 1538  QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
 
 1541  double outputHeightMM = exportRegion.height();
 
 1542  double outputWidthMM = exportRegion.width();
 
 1546  double mapXCenter = mapExtent.
center().
x();
 
 1547  double mapYCenter = mapExtent.
center().
y();
 
 1549  double sinAlpha = std::sin( alpha );
 
 1550  double cosAlpha = std::cos( alpha );
 
 1553  QPointF mapItemPos = map->pos();
 
 1555  mapItemPos.rx() -= exportRegion.left();
 
 1556  mapItemPos.ry() -= exportRegion.top();
 
 1559  double xRatio = mapExtent.
width() / mapItemSceneRect.width();
 
 1560  double yRatio = mapExtent.
height() / mapItemSceneRect.height();
 
 1561  double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
 
 1562  double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
 
 1563  QgsRectangle paperExtent( xmin, ymax - outputHeightMM * yRatio, xmin + outputWidthMM * xRatio, ymax );
 
 1566  double X0 = paperExtent.xMinimum();
 
 1567  double Y0 = paperExtent.yMaximum();
 
 1572    double X1 = X0 - mapXCenter;
 
 1573    double Y1 = Y0 - mapYCenter;
 
 1574    double X2 = X1 * cosAlpha + Y1 * sinAlpha;
 
 1575    double Y2 = -X1 * sinAlpha + Y1 * cosAlpha;
 
 1576    X0 = X2 + mapXCenter;
 
 1577    Y0 = Y2 + mapYCenter;
 
 1581  int pageWidthPixels = 
static_cast< int >( dpi * outputWidthMM / 25.4 );
 
 1582  int pageHeightPixels = 
static_cast< int >( dpi * outputHeightMM / 25.4 );
 
 1583  double pixelWidthScale = paperExtent.width() / pageWidthPixels;
 
 1584  double pixelHeightScale = paperExtent.height() / pageHeightPixels;
 
 1587  std::unique_ptr<double[]> t( 
new double[6] );
 
 1589  t[1] = cosAlpha * pixelWidthScale;
 
 1590  t[2] = -sinAlpha * pixelWidthScale;
 
 1592  t[4] = -sinAlpha * pixelHeightScale;
 
 1593  t[5] = -cosAlpha * pixelHeightScale;
 
 1598void QgsLayoutExporter::writeWorldFile( 
const QString &worldFileName, 
double a, 
double b, 
double c, 
double d, 
double e, 
double f )
 const 
 1600  QFile worldFile( worldFileName );
 
 1601  if ( !worldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
 
 1605  QTextStream fout( &worldFile );
 
 1609  fout << QString::number( a, 
'f', 12 ) << 
"\r\n";
 
 1610  fout << QString::number( d, 
'f', 12 ) << 
"\r\n";
 
 1611  fout << QString::number( b, 
'f', 12 ) << 
"\r\n";
 
 1612  fout << QString::number( e, 
'f', 12 ) << 
"\r\n";
 
 1613  fout << QString::number( 
c, 
'f', 12 ) << 
"\r\n";
 
 1614  fout << QString::number( f, 
'f', 12 ) << 
"\r\n";
 
 1619  return georeferenceOutputPrivate( file, map, exportRegion, dpi, 
false );
 
 1622bool QgsLayoutExporter::georeferenceOutputPrivate( 
const QString &file, 
QgsLayoutItemMap *map, 
const QRectF &exportRegion, 
double dpi, 
bool includeGeoreference, 
bool includeMetadata )
 const 
 1627  if ( !map && includeGeoreference )
 
 1628    map = mLayout->referenceMap();
 
 1630  std::unique_ptr<double[]> t;
 
 1632  if ( map && includeGeoreference )
 
 1635      dpi = mLayout->renderContext().dpi();
 
 1637    t = computeGeoTransform( map, exportRegion, dpi );
 
 1642  CPLSetConfigOption( 
"GDAL_PDF_DPI", QString::number( dpi ).toUtf8().constData() );
 
 1647      GDALSetGeoTransform( outputDS.get(), t.get() );
 
 1649    if ( includeMetadata )
 
 1651      QString creationDateString;
 
 1652      const QDateTime creationDateTime = mLayout->project()->metadata().creationDateTime();
 
 1653      if ( creationDateTime.isValid() )
 
 1655        creationDateString = QStringLiteral( 
"D:%1" ).arg( mLayout->project()->metadata().creationDateTime().toString( QStringLiteral( 
"yyyyMMddHHmmss" ) ) );
 
 1656        if ( creationDateTime.timeZone().isValid() )
 
 1658          int offsetFromUtc = creationDateTime.timeZone().offsetFromUtc( creationDateTime );
 
 1659          creationDateString += ( offsetFromUtc >= 0 ) ? 
'+' : 
'-';
 
 1660          offsetFromUtc = std::abs( offsetFromUtc );
 
 1661          int offsetHours = offsetFromUtc / 3600;
 
 1662          int offsetMins = ( offsetFromUtc % 3600 ) / 60;
 
 1663          creationDateString += QStringLiteral( 
"%1'%2'" ).arg( offsetHours ).arg( offsetMins );
 
 1666      GDALSetMetadataItem( outputDS.get(), 
"CREATION_DATE", creationDateString.toUtf8().constData(), 
nullptr );
 
 1668      GDALSetMetadataItem( outputDS.get(), 
"AUTHOR", mLayout->project()->metadata().author().toUtf8().constData(), 
nullptr );
 
 1669      const QString creator = QStringLiteral( 
"QGIS %1" ).arg( 
Qgis::version() );
 
 1670      GDALSetMetadataItem( outputDS.get(), 
"CREATOR", creator.toUtf8().constData(), 
nullptr );
 
 1671      GDALSetMetadataItem( outputDS.get(), 
"PRODUCER", creator.toUtf8().constData(), 
nullptr );
 
 1672      GDALSetMetadataItem( outputDS.get(), 
"SUBJECT", mLayout->project()->metadata().abstract().toUtf8().constData(), 
nullptr );
 
 1673      GDALSetMetadataItem( outputDS.get(), 
"TITLE", mLayout->project()->metadata().title().toUtf8().constData(), 
nullptr );
 
 1676      QStringList allKeywords;
 
 1677      for ( 
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
 
 1679        allKeywords.append( QStringLiteral( 
"%1: %2" ).arg( it.key(), it.value().join( 
',' ) ) );
 
 1681      const QString keywordString = allKeywords.join( 
';' );
 
 1682      GDALSetMetadataItem( outputDS.get(), 
"KEYWORDS", keywordString.toUtf8().constData(), 
nullptr );
 
 1688  CPLSetConfigOption( 
"GDAL_PDF_DPI", 
nullptr );
 
 1695  if ( items.count() == 1 )
 
 1699      QString name = layoutItem->displayName();
 
 1701      if ( name.startsWith( 
'<' ) && name.endsWith( 
'>' ) )
 
 1702        name = name.mid( 1, name.length() - 2 );
 
 1706  else if ( items.count() > 1 )
 
 1708    QStringList currentLayerItemTypes;
 
 1709    for ( QGraphicsItem *item : items )
 
 1715        if ( !currentLayerItemTypes.contains( itemType ) && !currentLayerItemTypes.contains( itemTypePlural ) )
 
 1716          currentLayerItemTypes << itemType;
 
 1717        else if ( currentLayerItemTypes.contains( itemType ) )
 
 1719          currentLayerItemTypes.replace( currentLayerItemTypes.indexOf( itemType ), itemTypePlural );
 
 1724        if ( !currentLayerItemTypes.contains( QObject::tr( 
"Other" ) ) )
 
 1725          currentLayerItemTypes.append( QObject::tr( 
"Other" ) );
 
 1728    return currentLayerItemTypes.join( QLatin1String( 
", " ) );
 
 1730  return QObject::tr( 
"Layer %1" ).arg( layerId );
 
 1736  LayoutItemHider itemHider( items );
 
 1741  unsigned int layerId = 1;
 
 1743  itemHider.hideAll();
 
 1744  const QList< QGraphicsItem * > itemsToIterate = itemHider.itemsToIterate();
 
 1745  QList< QGraphicsItem * > currentLayerItems;
 
 1746  for ( QGraphicsItem *item : itemsToIterate )
 
 1750    bool canPlaceInExistingLayer = 
false;
 
 1757          switch ( prevItemBehavior )
 
 1760              canPlaceInExistingLayer = 
true;
 
 1764              canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
 
 1769              canPlaceInExistingLayer = 
false;
 
 1777          switch ( prevItemBehavior )
 
 1781              canPlaceInExistingLayer = prevType == -1 || prevType == layoutItem->
type();
 
 1786              canPlaceInExistingLayer = 
false;
 
 1794          canPlaceInExistingLayer = 
false;
 
 1799          canPlaceInExistingLayer = 
false;
 
 1803      prevType = layoutItem->
type();
 
 1810    if ( canPlaceInExistingLayer )
 
 1812      currentLayerItems << item;
 
 1817      if ( !currentLayerItems.isEmpty() )
 
 1821        ExportResult result = exportFunc( layerId, layerDetails );
 
 1825        currentLayerItems.clear();
 
 1828      itemHider.hideAll();
 
 1833        int layoutItemLayerIdx = 0;
 
 1835        mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
 
 1841          mLayout->renderContext().setCurrentExportLayer( layoutItemLayerIdx );
 
 1845          ExportResult result = exportFunc( layerId, layerDetails );
 
 1850          layoutItemLayerIdx++;
 
 1852        layerDetails.mapLayerId.clear();
 
 1854        mLayout->renderContext().setCurrentExportLayer( -1 );
 
 1857        currentLayerItems.clear();
 
 1861        currentLayerItems << item;
 
 1865  if ( !currentLayerItems.isEmpty() )
 
 1868    ExportResult result = exportFunc( layerId, layerDetails );
 
 1883  return simplifyMethod;
 
 1897  int pageNumber = map->
page();
 
 1899  double pageY = page->pos().y();
 
 1900  QSizeF pageSize = page->rect().size();
 
 1901  QRectF pageRect( 0, pageY, pageSize.width(), pageSize.height() );
 
 1917  double destinationHeight = exportRegion.height();
 
 1918  double destinationWidth = exportRegion.width();
 
 1920  QRectF mapItemSceneRect = map->mapRectToScene( map->rect() );
 
 1925  double xRatio = mapExtent.
width() / mapItemSceneRect.width();
 
 1926  double yRatio = mapExtent.
height() / mapItemSceneRect.height();
 
 1928  double xCenter = mapExtent.
center().
x();
 
 1929  double yCenter = mapExtent.
center().
y();
 
 1932  QPointF mapItemPos = map->pos();
 
 1934  mapItemPos.rx() -= exportRegion.left();
 
 1935  mapItemPos.ry() -= exportRegion.top();
 
 1937  double xmin = mapExtent.
xMinimum() - mapItemPos.x() * xRatio;
 
 1938  double ymax = mapExtent.
yMaximum() + mapItemPos.y() * yRatio;
 
 1939  QgsRectangle paperExtent( xmin, ymax - destinationHeight * yRatio, xmin + destinationWidth * xRatio, ymax );
 
 1941  double X0 = paperExtent.
xMinimum();
 
 1942  double Y0 = paperExtent.
yMinimum();
 
 1945    dpi = mLayout->renderContext().dpi();
 
 1947  int widthPx = 
static_cast< int >( dpi * destinationWidth / 25.4 );
 
 1948  int heightPx = 
static_cast< int >( dpi * destinationHeight / 25.4 );
 
 1950  double Ww = paperExtent.
width() / widthPx;
 
 1951  double Hh = paperExtent.
height() / heightPx;
 
 1960  s[5] = Y0 + paperExtent.
height();
 
 1964  r[0] = std::cos( alpha );
 
 1965  r[1] = -std::sin( alpha );
 
 1966  r[2] = xCenter * ( 1 - std::cos( alpha ) ) + yCenter * std::sin( alpha );
 
 1967  r[3] = std::sin( alpha );
 
 1968  r[4] = std::cos( alpha );
 
 1969  r[5] = - xCenter * std::sin( alpha ) + yCenter * ( 1 - std::cos( alpha ) );
 
 1972  a = r[0] * s[0] + r[1] * s[3];
 
 1973  b = r[0] * s[1] + r[1] * s[4];
 
 1974  c = r[0] * s[2] + r[1] * s[5] + r[2];
 
 1975  d = r[3] * s[0] + r[4] * s[3];
 
 1976  e = r[3] * s[1] + r[4] * s[4];
 
 1977  f = r[3] * s[2] + r[4] * s[5] + r[5];
 
 1985  QList< QgsLayoutItem *> items;
 
 1991    if ( currentItem->isVisible() && currentItem->requiresRasterization() )
 
 2002  QList< QgsLayoutItem *> items;
 
 2008    if ( currentItem->isVisible() && currentItem->containsAdvancedEffects() )
 
 2021    if ( mLayout->pageCollection()->pageCount() == 1 )
 
 2024      bounds = mLayout->layoutBounds( 
true );
 
 2029      bounds = mLayout->pageItemBounds( page, 
true );
 
 2031    if ( bounds.width() <= 0 || bounds.height() <= 0 )
 
 2038    double pixelToLayoutUnits = mLayout->convertToLayoutUnits( 
QgsLayoutMeasurement( 1, Qgis::LayoutUnit::Pixels ) );
 
 2039    bounds = bounds.adjusted( -settings.
cropMargins.
left() * pixelToLayoutUnits,
 
 2051int QgsLayoutExporter::firstPageToBeExported( 
QgsLayout *layout )
 
 2054  for ( 
int i = 0; i < pageCount; ++i )
 
 2068  if ( details.
page == 0 )
 
 2078void QgsLayoutExporter::captureLabelingResults()
 
 2080  qDeleteAll( mLabelingResults );
 
 2081  mLabelingResults.clear();
 
 2083  QList< QgsLayoutItemMap * > maps;
 
 2084  mLayout->layoutItems( maps );
 
 2088    mLabelingResults[ map->
uuid() ] = map->mExportLabelingResults.release();
 
 2092bool QgsLayoutExporter::saveImage( 
const QImage &image, 
const QString &imageFilename, 
const QString &imageFormat, 
QgsProject *projectForMetadata )
 
 2094  QImageWriter w( imageFilename, imageFormat.toLocal8Bit().constData() );
 
 2095  if ( imageFormat.compare( QLatin1String( 
"tiff" ), Qt::CaseInsensitive ) == 0 || imageFormat.compare( QLatin1String( 
"tif" ), Qt::CaseInsensitive ) == 0 )
 
 2097    w.setCompression( 1 ); 
 
 2099  if ( projectForMetadata )
 
 2101    w.setText( QStringLiteral( 
"Author" ), projectForMetadata->
metadata().
author() );
 
 2102    const QString creator = QStringLiteral( 
"QGIS %1" ).arg( 
Qgis::version() );
 
 2103    w.setText( QStringLiteral( 
"Creator" ), creator );
 
 2104    w.setText( QStringLiteral( 
"Producer" ), creator );
 
 2105    w.setText( QStringLiteral( 
"Subject" ), projectForMetadata->
metadata().
abstract() );
 
 2106    w.setText( QStringLiteral( 
"Created" ), projectForMetadata->
metadata().
creationDateTime().toString( Qt::ISODate ) );
 
 2107    w.setText( QStringLiteral( 
"Title" ), projectForMetadata->
metadata().
title() );
 
 2110    QStringList allKeywords;
 
 2111    for ( 
auto it = keywords.constBegin(); it != keywords.constEnd(); ++it )
 
 2113      allKeywords.append( QStringLiteral( 
"%1: %2" ).arg( it.key(), it.value().join( 
',' ) ) );
 
 2115    const QString keywordString = allKeywords.join( 
';' );
 
 2116    w.setText( QStringLiteral( 
"Keywords" ), keywordString );
 
 2118  return w.write( image );
 
static QString version()
Version string.
 
TextRenderFormat
Options for rendering text.
 
An abstract base class for QgsLayout based classes which can be exported by QgsLayoutExporter.
 
virtual bool endRender()=0
Ends the render, performing any required cleanup tasks.
 
virtual QgsLayout * layout()=0
Returns the layout associated with the iterator.
 
virtual bool next()=0
Iterates to next feature, returning false if no more features exist to iterate over.
 
virtual bool beginRender()=0
Called when rendering begins, before iteration commences.
 
virtual QString filePath(const QString &baseFilePath, const QString &extension)=0
Returns the file path for the current feature, based on a specified base file path and extension.
 
virtual int count() const =0
Returns the number of features to iterate over.
 
static QgsLayoutItemRegistry * layoutItemRegistry()
Returns the application's layout item registry, used for layout item types.
 
@ WKT_PREFERRED_GDAL
Preferred format for conversion of CRS to WKT for use with the GDAL library.
 
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
 
Base class for feedback objects to be used for cancellation of something running in a worker thread.
 
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
 
void setProgress(double progress)
Sets the current progress for the feedback object.
 
Handles rendering and exports of layouts to various formats.
 
ExportResult exportToSvg(const QString &filePath, const QgsLayoutExporter::SvgExportSettings &settings)
Exports the layout as an SVG to the filePath, using the specified export settings.
 
ExportResult exportToImage(const QString &filePath, const QgsLayoutExporter::ImageExportSettings &settings)
Exports the layout to the filePath, using the specified export settings.
 
ExportResult exportToPdf(const QString &filePath, const QgsLayoutExporter::PdfExportSettings &settings)
Exports the layout as a PDF to the filePath, using the specified export settings.
 
virtual ~QgsLayoutExporter()
 
QImage renderRegionToImage(const QRectF ®ion, QSize imageSize=QSize(), double dpi=-1) const
Renders a region of the layout to an image.
 
QMap< QString, QgsLabelingResults * > takeLabelingResults()
Takes the labeling results for all map items included in the export.
 
static bool requiresRasterization(const QgsLayout *layout)
Returns true if the specified layout contains visible items which have settings that require rasteriz...
 
QgsLayout * layout() const
Returns the layout linked to this exporter.
 
bool georeferenceOutput(const QString &file, QgsLayoutItemMap *referenceMap=nullptr, const QRectF &exportRegion=QRectF(), double dpi=-1) const
Georeferences a file (image of PDF) exported from the layout.
 
virtual QString generateFileName(const PageExportDetails &details) const
Generates the file name for a page during export.
 
ExportResult
Result codes for exporting layouts.
 
@ Canceled
Export was canceled.
 
@ MemoryError
Unable to allocate memory required to export.
 
@ PrintError
Could not start printing to destination device.
 
@ IteratorError
Error iterating over layout.
 
@ FileError
Could not write to destination file, likely due to a lock held by another application.
 
@ Success
Export was successful.
 
@ SvgLayerError
Could not create layered SVG file.
 
QImage renderPageToImage(int page, QSize imageSize=QSize(), double dpi=-1) const
Renders a full page to an image.
 
static ExportResult exportToPdfs(QgsAbstractLayoutIterator *iterator, const QString &baseFilePath, const QgsLayoutExporter::PdfExportSettings &settings, QString &error, QgsFeedback *feedback=nullptr)
Exports a layout iterator to multiple PDF files, with the specified export settings.
 
void computeWorldFileParameters(double &a, double &b, double &c, double &d, double &e, double &f, double dpi=-1) const
Compute world file parameters.
 
void renderPage(QPainter *painter, int page) const
Renders a full page to a destination painter.
 
ExportResult print(QPrinter &printer, const QgsLayoutExporter::PrintExportSettings &settings)
Prints the layout to a printer, using the specified export settings.
 
QMap< QString, QgsLabelingResults * > labelingResults()
Returns the labeling results for all map items included in the export.
 
static bool containsAdvancedEffects(const QgsLayout *layout)
Returns true if the specified layout contains visible items which have settings such as opacity which...
 
void renderRegion(QPainter *painter, const QRectF ®ion) const
Renders a region from the layout to a painter.
 
QgsLayoutExporter(QgsLayout *layout)
Constructor for QgsLayoutExporter, for the specified layout.
 
Contains the configuration for a single snap guide used by a layout.
 
Layout graphical items for displaying a map.
 
double mapRotation(QgsLayoutObject::PropertyValueType valueType=QgsLayoutObject::EvaluatedValue) const
Returns the rotation used for drawing the map within the layout item, in degrees clockwise.
 
QgsRectangle extent() const
Returns the current map extent.
 
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
 
Item representing the paper in a layout.
 
QgsLayoutItemAbstractMetadata * itemMetadata(int type) const
Returns the metadata for the specified item type.
 
Base class for graphical items within a QgsLayout.
 
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
 
virtual QgsLayoutItem::ExportLayerDetail exportLayerDetails() const
Returns the details for the specified current export layer.
 
virtual bool nextExportPart()
Moves to the next export part for a multi-layered export item, during a multi-layered export.
 
virtual void startLayeredExport()
Starts a multi-layer export operation.
 
int page() const
Returns the page the item is currently on, with the first page returning 0.
 
int type() const override
Returns a unique graphics item type identifier.
 
virtual void stopLayeredExport()
Stops a multi-layer export operation.
 
virtual QString uuid() const
Returns the item identification string.
 
ExportLayerBehavior
Behavior of item when exporting to layered outputs.
 
@ ItemContainsSubLayers
Item contains multiple sublayers which must be individually exported.
 
@ MustPlaceInOwnLayer
Item must be placed in its own individual layer.
 
@ CanGroupWithItemsOfSameType
Item can only be placed on layers with other items of the same type, but multiple items of this type ...
 
@ CanGroupWithAnyOtherItem
Item can be placed on a layer with any other item (default behavior)
 
virtual ExportLayerBehavior exportLayerBehavior() const
Returns the behavior of this item during exporting to layered exports (e.g.
 
QgsLayoutMeasurement convert(QgsLayoutMeasurement measurement, Qgis::LayoutUnit targetUnits) const
Converts a measurement from one unit to another.
 
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
 
int pageCount() const
Returns the number of pages in the collection.
 
bool shouldExportPage(int page) const
Returns whether the specified page number should be included in exports of the layouts.
 
QgsLayoutItemPage * page(int pageNumber)
Returns a specific page (by pageNumber) from the collection.
 
This class provides a method of storing points, consisting of an x and y coordinate,...
 
double x() const
Returns x coordinate of point.
 
double y() const
Returns y coordinate of point.
 
void setDpi(double dpi)
Sets the dpi for outputting the layout.
 
void setSimplifyMethod(const QgsVectorSimplifyMethod &method)
Sets the simplification setting to use when rendering vector layers.
 
void setTextRenderFormat(Qgis::TextRenderFormat format)
Sets the text render format, which dictates how text is rendered (e.g.
 
QgsLayoutRenderContext::Flags flags() const
Returns the current combination of flags used for rendering the layout.
 
void setFlag(QgsLayoutRenderContext::Flag flag, bool on=true)
Enables or disables a particular rendering flag for the layout.
 
double dpi() const
Returns the dpi for outputting the layout.
 
@ FlagRenderLabelsByMapLayer
When rendering map items to multi-layered exports, render labels belonging to different layers into s...
 
@ FlagUseAdvancedEffects
Enable advanced effects such as blend modes.
 
@ FlagLosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
 
@ FlagAntialiasing
Use antialiasing when drawing items.
 
@ FlagForceVectorOutput
Force output in vector format where possible, even if items require rasterization to keep their corre...
 
void setPredefinedScales(const QVector< qreal > &scales)
Sets the list of predefined scales to use with the layout.
 
void setFlags(QgsLayoutRenderContext::Flags flags)
Sets the combination of flags that will be used for rendering the layout.
 
const QgsLayoutMeasurementConverter & measurementConverter() const
Returns the layout measurement converter to be used in the layout.
 
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
 
QSizeF toQSizeF() const
Converts the layout size to a QSizeF.
 
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
 
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout's render context, which stores information relating to the current ...
 
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout's page collection, which stores and manages page items in the layout.
 
void layoutItems(QList< T * > &itemList) const
Returns a list of layout items of a specific type.
 
Line string geometry type, with support for z-dimension and m-values.
 
Base class for all map layer types.
 
double top() const
Returns the top margin.
 
double right() const
Returns the right margin.
 
double bottom() const
Returns the bottom margin.
 
double left() const
Returns the left margin.
 
Interface for master layout type objects, such as print layouts and reports.
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
 
static void fixEngineFlags(QPaintEngine *engine)
 
A class to represent a 2D point.
 
void setExteriorRing(QgsCurve *ring) override
Sets the exterior ring of the polygon.
 
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
 
QgsProjectMetadata metadata
 
A rectangle specified with double values.
 
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
 
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
 
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
 
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
 
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
 
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
 
This class contains information how to simplify geometries fetched from a vector layer.
 
void setSimplifyHints(SimplifyHints simplifyHints)
Sets the simplification hints of the vector layer managed.
 
void setThreshold(float threshold)
Sets the simplification threshold of the vector layer managed.
 
void setSimplifyAlgorithm(SimplifyAlgorithm simplifyAlgorithm)
Sets the local simplification algorithm of the vector layer managed.
 
void setForceLocalOptimization(bool localOptimization)
Sets where the simplification executes, after fetch the geometries from provider, or when supported,...
 
@ GeometrySimplification
The geometries can be simplified using the current map2pixel context state.
 
@ SnappedToGridGlobal
Snap to a global grid based on the tolerance. Good for consistent results for incoming vertices,...
 
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
 
#define Q_NOWARN_DEPRECATED_POP
 
#define Q_NOWARN_DEPRECATED_PUSH
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
 
QString nameForLayerWithItems(const QList< QGraphicsItem * > &items, unsigned int layerId)
 
Contains details of a particular input component to be used during PDF composition.
 
QString sourcePdfPath
File path to the (already created) PDF to use as the source for this component layer.
 
QString mapLayerId
Associated map layer ID, or an empty string if this component layer is not associated with a map laye...
 
QPainter::CompositionMode compositionMode
Component composition mode.
 
QString group
Optional group name, for arranging layers in top-level groups.
 
QString name
User-friendly name for the generated PDF layer.
 
double opacity
Component opacity.
 
Contains details of a control point used during georeferencing GeoPDF outputs.
 
QgsAbstractMetadataBase::KeywordMap keywords
Metadata keyword map.
 
bool useIso32000ExtensionFormatGeoreferencing
true if ISO3200 extension format georeferencing should be used.
 
QMap< QString, QString > layerIdToPdfLayerTreeNameMap
Optional map of map layer ID to custom layer tree name to show in the created PDF file.
 
bool useOgcBestPracticeFormatGeoreferencing
true if OGC "best practice" format georeferencing should be used.
 
QDateTime creationDateTime
Metadata creation datetime.
 
QSizeF pageSizeMm
Page size, in millimeters.
 
QList< QgsAbstractGeoPdfExporter::GeoReferencedSection > georeferencedSections
List of georeferenced sections.
 
QString author
Metadata author tag.
 
QMap< QString, bool > initialLayerVisibility
Optional map of map layer ID to initial visibility state.
 
QString producer
Metadata producer tag.
 
QString creator
Metadata creator tag.
 
QMap< QString, QString > customLayerTreeGroups
Optional map of map layer ID to custom logical layer tree group in created PDF file.
 
bool includeFeatures
true if feature vector information (such as attributes) should be exported.
 
QStringList layerOrder
Optional list of layer IDs, in the order desired to appear in the generated GeoPDF file.
 
QString subject
Metadata subject tag.
 
QString title
Metadata title tag.
 
QgsCoordinateReferenceSystem crs
Coordinate reference system for georeferenced section.
 
QgsPolygon pageBoundsPolygon
Bounds of the georeferenced section on the page, in millimeters, as a free-form polygon.
 
QList< QgsAbstractGeoPdfExporter::ControlPoint > controlPoints
List of control points corresponding to this georeferenced section.
 
Contains settings relating to exporting layouts to raster images.
 
QgsMargins cropMargins
Crop to content margins, in pixels.
 
QList< int > pages
List of specific pages to export, or an empty list to export all pages.
 
bool generateWorldFile
Set to true to generate an external world file alongside exported images.
 
QSize imageSize
Manual size in pixels for output image.
 
bool exportMetadata
Indicates whether image export should include metadata generated from the layout's project's metadata...
 
QgsLayoutRenderContext::Flags flags
Layout context flags, which control how the export will be created.
 
bool cropToContents
Set to true if image should be cropped so only parts of the layout containing items are exported.
 
double dpi
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
 
QVector< qreal > predefinedMapScales
A list of predefined scales to use with the layout.
 
Contains details of a page being exported by the class.
 
QString baseName
Base part of filename (i.e. file name without extension or '.')
 
QString extension
File suffix/extension (without the leading '.')
 
QString directory
Target folder.
 
int page
Page number, where 0 = first page.
 
Contains settings relating to exporting layouts to PDF.
 
bool forceVectorOutput
Set to true to force vector object exports, even when the resultant appearance will differ from the l...
 
bool rasterizeWholeImage
Set to true to force whole layout to be rasterized while exporting.
 
QStringList exportThemes
Optional list of map themes to export as GeoPDF layer groups.
 
bool exportMetadata
Indicates whether PDF export should include metadata generated from the layout's project's metadata.
 
bool appendGeoreference
Indicates whether PDF export should append georeference data.
 
QgsLayoutRenderContext::Flags flags
Layout context flags, which control how the export will be created.
 
bool writeGeoPdf
true if GeoPDF files should be created, instead of normal PDF files.
 
double dpi
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
 
QVector< qreal > predefinedMapScales
A list of predefined scales to use with the layout.
 
bool exportLayersAsSeperateFiles
true if individual layers from the layout should be rendered to separate PDF files.
 
bool simplifyGeometries
Indicates whether vector geometries should be simplified to avoid redundant extraneous detail,...
 
Qgis::TextRenderFormat textRenderFormat
Text rendering format, which controls how text should be rendered in the export (e....
 
Contains settings relating to printing layouts.
 
QVector< qreal > predefinedMapScales
A list of predefined scales to use with the layout.
 
double dpi
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
 
QgsLayoutRenderContext::Flags flags
Layout context flags, which control how the export will be created.
 
bool rasterizeWholeImage
Set to true to force whole layout to be rasterized while exporting.
 
Contains settings relating to exporting layouts to SVG.
 
bool forceVectorOutput
Set to true to force vector object exports, even when the resultant appearance will differ from the l...
 
Qgis::TextRenderFormat textRenderFormat
Text rendering format, which controls how text should be rendered in the export (e....
 
bool exportAsLayers
Set to true to export as a layered SVG file.
 
bool simplifyGeometries
Indicates whether vector geometries should be simplified to avoid redundant extraneous detail,...
 
bool exportMetadata
Indicates whether SVG export should include RDF metadata generated from the layout's project's metada...
 
double dpi
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
 
QgsLayoutRenderContext::Flags flags
Layout context flags, which control how the export will be created.
 
QVector< qreal > predefinedMapScales
A list of predefined scales to use with the layout.
 
bool exportLabelsToSeparateLayers
Set to true to export labels to separate layers (grouped by map layer) in layered SVG exports.
 
bool cropToContents
Set to true if image should be cropped so only parts of the layout containing items are exported.
 
QgsMargins cropMargins
Crop to content margins, in layout units.
 
Contains details of a particular export layer relating to a layout item.
 
QString name
User-friendly name for the export layer.