diff --git a/generators/poppler/generator_pdf.cpp b/generators/poppler/generator_pdf.cpp --- a/generators/poppler/generator_pdf.cpp +++ b/generators/poppler/generator_pdf.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -76,8 +77,26 @@ class PDFOptionsPage : public QWidget { Q_OBJECT +public slots: + void enableOrDisableScaleMode() + { + m_scaleMode->setEnabled ( m_forceRaster->isChecked() ); + + if ( m_forceRaster->isChecked() ) { + m_scaleMode->setToolTip( i18n( "Scaling mode for the printed pages" ) ); + } else { + m_scaleMode->setToolTip( i18n( "Select rasterization to enable this!" ) ); + } + } public: + enum ScaleMode { + FitToPrintableArea, + FitToPage, + None + }; + Q_ENUM(ScaleMode) + PDFOptionsPage() { setWindowTitle( i18n( "PDF Options" ) ); @@ -90,8 +109,26 @@ m_forceRaster->setToolTip(i18n("Rasterize into an image before printing")); m_forceRaster->setWhatsThis(i18n("Forces the rasterization of each page into an image before printing it. This usually gives somewhat worse results, but is useful when printing documents that appear to print incorrectly.")); layout->addWidget(m_forceRaster); + + QWidget* formWidget = new QWidget(this); + QFormLayout* printBackendLayout = new QFormLayout(formWidget); + + m_scaleMode = new QComboBox; + m_scaleMode->insertItem(FitToPrintableArea, i18n("Fit to printable area"), FitToPrintableArea); + m_scaleMode->insertItem(FitToPage, i18n("Fit to full page"), FitToPage); + m_scaleMode->insertItem(None, i18n("None; print original size"), None); + m_scaleMode->setToolTip(i18n("Select rasterization to enable this!")); + printBackendLayout->addRow(i18n("Scale mode:"), m_scaleMode); + + layout->addWidget(formWidget); + layout->addStretch(1); + // Enable scaleMode only if the file is to be rasterized before printing + m_scaleMode->setEnabled( false ); + + connect( m_forceRaster, &QCheckBox::stateChanged, this, &PDFOptionsPage::enableOrDisableScaleMode ); + #if defined(Q_OS_WIN) && !defined HAVE_POPPLER_0_60 m_printAnnots->setVisible( false ); #endif @@ -118,9 +155,15 @@ m_forceRaster->setChecked( forceRaster ); } + ScaleMode scaleMode() const + { + return m_scaleMode->currentData().value(); + } + private: QCheckBox *m_printAnnots; QCheckBox *m_forceRaster; + QComboBox *m_scaleMode; }; @@ -1291,11 +1334,13 @@ { bool printAnnots = true; bool forceRasterize = false; + PDFOptionsPage::ScaleMode scaleMode = PDFOptionsPage::FitToPrintableArea; if ( pdfOptionsPage ) { printAnnots = pdfOptionsPage->printAnnots(); forceRasterize = pdfOptionsPage->printForceRaster(); + scaleMode = pdfOptionsPage->scaleMode(); } #ifdef Q_OS_WIN @@ -1317,6 +1362,11 @@ if ( forceRasterize && printAnnots) { #endif + + // If requested, scale to full page instead of the printable area + if ( scaleMode == PDFOptionsPage::FitToPage ) + printer.setFullPage( true ); + QPainter painter; painter.begin(&printer); @@ -1333,13 +1383,30 @@ Poppler::Page *pp = pdfdoc->page( page ); if (pp) { + QSizeF pageSize = pp->pageSizeF(); // Unit is 'points' (i.e., 1/72th of an inch) + QRect painterWindow = painter.window(); // Unit is 'QPrinter::DevicePixel' + + // Default: no scaling at all, but we need to go from DevicePixel units to 'points' + // Warning: We compute the horizontal scaling, and later assume that the vertical scaling will be the same. + double scaling = printer.paperRect(QPrinter::DevicePixel).width() / printer.paperRect(QPrinter::Point).width(); + + if ( scaleMode != PDFOptionsPage::None ) + { + // Get the two scaling factors needed to fit the page onto paper horizontally or vertically + auto horizontalScaling = painterWindow.width() / pageSize.width(); + auto verticalScaling = painterWindow.height() / pageSize.height(); + + // We use the smaller of the two for both directions, to keep the aspect ratio + scaling = std::min(horizontalScaling, verticalScaling); + } + #ifdef Q_OS_WIN QImage img = pp->renderToImage( printer.physicalDpiX(), printer.physicalDpiY() ); #else // UNIX: Same resolution as the postscript rasterizer; see discussion at https://git.reviewboard.kde.org/r/130218/ QImage img = pp->renderToImage( 300, 300 ); #endif - painter.drawImage( painter.window(), img, QRectF(0, 0, img.width(), img.height()) ); + painter.drawImage( QRectF( QPointF( 0, 0 ), scaling * pp->pageSizeF() ), img ); delete pp; } userMutex()->unlock();