Skip to content

Commit

Permalink
[layouts] Use QPdfWriter to export layouts to PDF
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn committed Mar 30, 2023
1 parent 97d68a3 commit 4419761
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 71 deletions.
1 change: 1 addition & 0 deletions python/core/auto_generated/layout/qgslayoutexporter.sip.in
Expand Up @@ -9,6 +9,7 @@




class QgsLayoutExporter
{
%Docstring(signature="appended")
Expand Down
118 changes: 59 additions & 59 deletions src/core/layout/qgslayoutexporter.cpp
Expand Up @@ -526,7 +526,6 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToImage( QgsAbstractLay

QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( const QString &filePath, const QgsLayoutExporter::PdfExportSettings &s )
{
#ifndef QT_NO_PRINTER
if ( !mLayout || mLayout->pageCollection()->pageCount() == 0 )
return PrintError;

Expand Down Expand Up @@ -582,7 +581,6 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( const QString &f
auto exportFunc = [this, &subSettings, &pdfComponents, &geoPdfExporter, &settings, &baseDir, &baseFileName]( unsigned int layerId, const QgsLayoutItem::ExportLayerDetail & layerDetail )->QgsLayoutExporter::ExportResult
{
ExportResult layerExportResult = Success;
QPrinter printer;
QgsLayoutGeoPdfExporter::ComponentLayerDetail component;
component.name = layerDetail.name;
component.mapLayerId = layerDetail.mapLayerId;
Expand All @@ -591,16 +589,17 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( const QString &f
component.group = layerDetail.mapTheme;
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' ) ) );
pdfComponents << component;
preparePrintAsPdf( mLayout, printer, component.sourcePdfPath );
preparePrint( mLayout, printer, false );
QPdfWriter printer = QPdfWriter( component.sourcePdfPath );
preparePrintAsPdf( mLayout, &printer, component.sourcePdfPath );
preparePrint( mLayout, &printer, false );
QPainter p;
if ( !p.begin( &printer ) )
{
//error beginning print
return FileError;
}
p.setRenderHint( QPainter::LosslessImageRendering, mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagLosslessImageRendering );
layerExportResult = printPrivate( printer, p, false, subSettings.dpi, subSettings.rasterizeWholeImage );
layerExportResult = printPrivate( &printer, p, false, subSettings.dpi, subSettings.rasterizeWholeImage );
p.end();
return layerExportResult;
};
Expand Down Expand Up @@ -692,17 +691,17 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( const QString &f
}
else
{
QPrinter printer;
preparePrintAsPdf( mLayout, printer, filePath );
preparePrint( mLayout, printer, false );
QPdfWriter printer = QPdfWriter( filePath );
preparePrintAsPdf( mLayout, &printer, filePath );
preparePrint( mLayout, &printer, false );
QPainter p;
if ( !p.begin( &printer ) )
{
//error beginning print
return FileError;
}
p.setRenderHint( QPainter::LosslessImageRendering, mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagLosslessImageRendering );
result = printPrivate( printer, p, false, settings.dpi, settings.rasterizeWholeImage );
result = printPrivate( &printer, p, false, settings.dpi, settings.rasterizeWholeImage );
p.end();

bool shouldAppendGeoreference = settings.appendGeoreference && mLayout && mLayout->referenceMap() && mLayout->referenceMap()->page() == 0;
Expand All @@ -713,22 +712,18 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( const QString &f
}
captureLabelingResults();
return result;
#else
return PrintError;
#endif
}

QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( QgsAbstractLayoutIterator *iterator, const QString &fileName, const QgsLayoutExporter::PdfExportSettings &s, QString &error, QgsFeedback *feedback )
{
#ifndef QT_NO_PRINTER
error.clear();

if ( !iterator->beginRender() )
return IteratorError;

PdfExportSettings settings = s;

QPrinter printer;
QPdfWriter printer = QPdfWriter( fileName );
QPainter p;

int total = iterator->count();
Expand Down Expand Up @@ -779,8 +774,8 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( QgsAbstractLayou

if ( first )
{
preparePrintAsPdf( iterator->layout(), printer, fileName );
preparePrint( iterator->layout(), printer, false );
preparePrintAsPdf( iterator->layout(), &printer, fileName );
preparePrint( iterator->layout(), &printer, false );

if ( !p.begin( &printer ) )
{
Expand All @@ -792,7 +787,7 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( QgsAbstractLayou

QgsLayoutExporter exporter( iterator->layout() );

ExportResult result = exporter.printPrivate( printer, p, !first, settings.dpi, settings.rasterizeWholeImage );
ExportResult result = exporter.printPrivate( &printer, p, !first, settings.dpi, settings.rasterizeWholeImage );
if ( result != Success )
{
if ( result == FileError )
Expand All @@ -811,14 +806,10 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( QgsAbstractLayou

iterator->endRender();
return Success;
#else
return PrintError;
#endif
}

QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdfs( QgsAbstractLayoutIterator *iterator, const QString &baseFilePath, const QgsLayoutExporter::PdfExportSettings &settings, QString &error, QgsFeedback *feedback )
{
#ifndef QT_NO_PRINTER
error.clear();

if ( !iterator->beginRender() )
Expand Down Expand Up @@ -864,9 +855,6 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdfs( QgsAbstractLayo

iterator->endRender();
return Success;
#else
return PrintError;
#endif
}

#ifndef QT_NO_PRINTER
Expand Down Expand Up @@ -894,15 +882,15 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::print( QPrinter &printer, con
// in items missing from the output
mLayout->renderContext().setFlag( QgsLayoutRenderContext::FlagUseAdvancedEffects, !settings.rasterizeWholeImage );

preparePrint( mLayout, printer, true );
preparePrint( mLayout, &printer, true );
QPainter p;
if ( !p.begin( &printer ) )
{
//error beginning print
return PrintError;
}
p.setRenderHint( QPainter::LosslessImageRendering, mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagLosslessImageRendering );
ExportResult result = printPrivate( printer, p, false, settings.dpi, settings.rasterizeWholeImage );
ExportResult result = printPrivate( &printer, p, false, settings.dpi, settings.rasterizeWholeImage );
p.end();

captureLabelingResults();
Expand Down Expand Up @@ -959,7 +947,7 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::print( QgsAbstractLayoutItera

if ( first )
{
preparePrint( iterator->layout(), printer, true );
preparePrint( iterator->layout(), &printer, true );

if ( !p.begin( &printer ) )
{
Expand All @@ -971,7 +959,7 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::print( QgsAbstractLayoutItera

QgsLayoutExporter exporter( iterator->layout() );

ExportResult result = exporter.printPrivate( printer, p, !first, settings.dpi, settings.rasterizeWholeImage );
ExportResult result = exporter.printPrivate( &printer, p, !first, settings.dpi, settings.rasterizeWholeImage );
if ( result != Success )
{
iterator->endRender();
Expand Down Expand Up @@ -1228,8 +1216,7 @@ QMap<QString, QgsLabelingResults *> QgsLayoutExporter::takeLabelingResults()
return res;
}

#ifndef QT_NO_PRINTER
void QgsLayoutExporter::preparePrintAsPdf( QgsLayout *layout, QPrinter &printer, const QString &filePath )
void QgsLayoutExporter::preparePrintAsPdf( QgsLayout *layout, QPagedPaintDevice *device, const QString &filePath )
{
QFileInfo fi( filePath );
QDir dir;
Expand All @@ -1238,10 +1225,7 @@ void QgsLayoutExporter::preparePrintAsPdf( QgsLayout *layout, QPrinter &printer,
dir.mkpath( fi.absolutePath() );
}

printer.setOutputFileName( filePath );
printer.setOutputFormat( QPrinter::PdfFormat );

updatePrinterPageSize( layout, printer, firstPageToBeExported( layout ) );
updatePrinterPageSize( layout, device, firstPageToBeExported( layout ) );

// TODO: add option for this in layout
// May not work on Windows or non-X11 Linux. Works fine on Mac using QPrinter::NativeFormat
Expand All @@ -1250,47 +1234,60 @@ void QgsLayoutExporter::preparePrintAsPdf( QgsLayout *layout, QPrinter &printer,
#if defined(HAS_KDE_QT5_PDF_TRANSFORM_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
// paint engine hack not required, fixed upstream
#else
QgsPaintEngineHack::fixEngineFlags( printer.paintEngine() );
QgsPaintEngineHack::fixEngineFlags( device->paintEngine() );
#endif
}

void QgsLayoutExporter::preparePrint( QgsLayout *layout, QPrinter &printer, bool setFirstPageSize )
void QgsLayoutExporter::preparePrint( QgsLayout *layout, QPagedPaintDevice *device, bool setFirstPageSize )
{
printer.setFullPage( true );
printer.setColorMode( QPrinter::Color );

//set user-defined resolution
printer.setResolution( static_cast< int>( std::round( layout->renderContext().dpi() ) ) );
if ( QPrinter *printer = dynamic_cast<QPrinter *>( device ) )

This comment has been minimized.

Copy link
@PeterPetrik

PeterPetrik May 29, 2023

Contributor

This line does not compile on builds with QT_NO_PRINTER (e.g. iOS) (@nirvn )

{
printer->setFullPage( true );
printer->setColorMode( QPrinter::Color );
//set user-defined resolution
printer->setResolution( static_cast< int>( std::round( layout->renderContext().dpi() ) ) );
}
else if ( QPdfWriter *pdf = dynamic_cast<QPdfWriter *>( device ) )
{
pdf->setResolution( static_cast< int>( std::round( layout->renderContext().dpi() ) ) );
}

if ( setFirstPageSize )
{
updatePrinterPageSize( layout, printer, firstPageToBeExported( layout ) );
updatePrinterPageSize( layout, device, firstPageToBeExported( layout ) );
}
}

QgsLayoutExporter::ExportResult QgsLayoutExporter::print( QPrinter &printer )
QgsLayoutExporter::ExportResult QgsLayoutExporter::print( QPagedPaintDevice *device )
{
if ( mLayout->pageCollection()->pageCount() == 0 )
return PrintError;

preparePrint( mLayout, printer, true );
preparePrint( mLayout, device, true );
QPainter p;
if ( !p.begin( &printer ) )
if ( !p.begin( device ) )
{
//error beginning print
return PrintError;
}

printPrivate( printer, p );
printPrivate( device, p );
p.end();
return Success;
}

QgsLayoutExporter::ExportResult QgsLayoutExporter::printPrivate( QPrinter &printer, QPainter &painter, bool startNewPage, double dpi, bool rasterize )
QgsLayoutExporter::ExportResult QgsLayoutExporter::printPrivate( QPagedPaintDevice *device, QPainter &painter, bool startNewPage, double dpi, bool rasterize )
{
//layout starts page numbering at 0
int fromPage = ( printer.fromPage() < 1 ) ? 0 : printer.fromPage() - 1;
int toPage = ( printer.toPage() < 1 ) ? mLayout->pageCollection()->pageCount() - 1 : printer.toPage() - 1;
// layout starts page numbering at 0
int fromPage = 0;
int toPage = mLayout->pageCollection()->pageCount() - 1;
if ( QPrinter *printer = dynamic_cast<QPrinter *>( device ) )
{
if ( printer->fromPage() >= 1 )
fromPage = printer->fromPage() - 1;
if ( printer->toPage() >= 1 )
toPage = printer->toPage() - 1;
}

bool pageExported = false;
if ( rasterize )
Expand All @@ -1302,10 +1299,10 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::printPrivate( QPrinter &print
continue;
}

updatePrinterPageSize( mLayout, printer, i );
updatePrinterPageSize( mLayout, device, i );
if ( ( pageExported && i > fromPage ) || startNewPage )
{
printer.newPage();
device->newPage();
}

QImage image = renderPageToImage( i, QSize(), dpi );
Expand All @@ -1330,11 +1327,11 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::printPrivate( QPrinter &print
continue;
}

updatePrinterPageSize( mLayout, printer, i );
updatePrinterPageSize( mLayout, device, i );

if ( ( pageExported && i > fromPage ) || startNewPage )
{
printer.newPage();
device->newPage();
}
renderPage( &painter, i );
pageExported = true;
Expand All @@ -1343,7 +1340,7 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::printPrivate( QPrinter &print
return Success;
}

void QgsLayoutExporter::updatePrinterPageSize( QgsLayout *layout, QPrinter &printer, int page )
void QgsLayoutExporter::updatePrinterPageSize( QgsLayout *layout, QPagedPaintDevice *device, int page )
{
QgsLayoutSize pageSize = layout->pageCollection()->page( page )->sizeWithUnits();
QgsLayoutSize pageSizeMM = layout->renderContext().measurementConverter().convert( pageSize, Qgis::LayoutUnit::Millimeters );
Expand All @@ -1352,11 +1349,14 @@ void QgsLayoutExporter::updatePrinterPageSize( QgsLayout *layout, QPrinter &prin
QPageLayout::Portrait,
QMarginsF( 0, 0, 0, 0 ) );
pageLayout.setMode( QPageLayout::FullPageMode );
printer.setPageLayout( pageLayout );
printer.setFullPage( true );
printer.setPageMargins( QMarginsF( 0, 0, 0, 0 ) );
device->setPageLayout( pageLayout );
device->setPageMargins( QMarginsF( 0, 0, 0, 0 ) );

if ( QPrinter *printer = dynamic_cast<QPrinter *>( device ) )
{
printer->setFullPage( true );
}
}
#endif // QT_NO_PRINTER

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
{
Expand Down
23 changes: 11 additions & 12 deletions src/core/layout/qgslayoutexporter.h
Expand Up @@ -21,6 +21,8 @@
#include "qgslayoutrendercontext.h"
#include "qgslayoutreportcontext.h"
#include "qgslayoutitem.h"

#include <QPdfWriter>
#include <QPointer>
#include <QSize>
#include <QRectF>
Expand Down Expand Up @@ -721,32 +723,29 @@ class CORE_EXPORT QgsLayoutExporter
//! Write a world file
void writeWorldFile( const QString &fileName, double a, double b, double c, double d, double e, double f ) const;

#ifndef QT_NO_PRINTER

/**
* Prepare a \a printer for printing a layout as a PDF, to the destination \a filePath.
* Prepare a \a device for printing a layout as a PDF, to the destination \a filePath.
*/
static void preparePrintAsPdf( QgsLayout *layout, QPrinter &printer, const QString &filePath );
static void preparePrintAsPdf( QgsLayout *layout, QPagedPaintDevice *device, const QString &filePath );

static void preparePrint( QgsLayout *layout, QPrinter &printer, bool setFirstPageSize = false );
static void preparePrint( QgsLayout *layout, QPagedPaintDevice *device, bool setFirstPageSize = false );

/**
* Convenience function that prepares the printer and prints.
* Convenience function that prepares the \a device and prints.
*/
ExportResult print( QPrinter &printer );
ExportResult print( QPagedPaintDevice *device );

/**
* Print on a preconfigured printer
* \param printer QPrinter destination
* Print on a preconfigured device
* \param device QPagedPaintDevice destination
* \param painter QPainter source
* \param startNewPage set to TRUE to begin the print on a new page
* \param dpi set to a value > 0 to manually override the layout's default dpi
* \param rasterize set to TRUE to force print as a raster image
*/
ExportResult printPrivate( QPrinter &printer, QPainter &painter, bool startNewPage = false, double dpi = -1, bool rasterize = false );
ExportResult printPrivate( QPagedPaintDevice *device, QPainter &painter, bool startNewPage = false, double dpi = -1, bool rasterize = false );

static void updatePrinterPageSize( QgsLayout *layout, QPrinter &printer, int page );
#endif
static void updatePrinterPageSize( QgsLayout *layout, QPagedPaintDevice *device, int page );

ExportResult renderToLayeredSvg( const SvgExportSettings &settings, double width, double height, int page, const QRectF &bounds,
const QString &filename, unsigned int svgLayerId, const QString &layerName,
Expand Down

0 comments on commit 4419761

Please sign in to comment.