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 @@ -82,16 +82,24 @@ public slots: void enableOrDisableScaleMode() { - m_scaleMode->setEnabled ( m_forceRaster->isChecked() ); + bool enableScaleModes = m_forceRaster->isChecked() || printBackend() == PDFOptionsPage::QPrinterBackend; - if ( m_forceRaster->isChecked() ) { + m_scaleMode->setEnabled ( enableScaleModes ); + + if ( enableScaleModes ) { m_scaleMode->setToolTip( i18n( "Scaling mode for the printed pages" ) ); } else { - m_scaleMode->setToolTip( i18n( "Select rasterization to enable this!" ) ); + m_scaleMode->setToolTip( i18n( "Select rasterization or QPrinter printing to enable this!" ) ); } } public: + enum PrintBackend { + CUPSBackend, + QPrinterBackend + }; + Q_ENUM(PrintBackend) + enum ScaleMode { FitToPrintableArea, FitToPage, @@ -112,8 +120,29 @@ 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); + m_printBackend = new QComboBox; + // Windows can only print with the QPrinter backend, because the CUPS backend + // is UNIX-specific. +#if !defined(Q_OS_WIN) + m_printBackend->insertItem(CUPSBackend, i18n("CUPS"), CUPSBackend); + m_printBackend->setItemData(CUPSBackend, xi18n("Print using the CUPS printing system.This will convert your PDF file to PostScript first,and then send the PostScript file to the printer."), Qt::ToolTipRole); + m_printBackend->setItemData(CUPSBackend, xi18n("Print using the CUPS printing system.This will convert your PDF file to PostScript first,and then send the PostScript file to the printer."), Qt::WhatsThisRole); +#endif + + // Print using the platform-independent Qt infrastructure. By necessity, + // this uses a backend of the Poppler PDF library that is called 'Arthur'. + // This Arthur backend is still somewhat immature, and you may see misrenderings + // of your PDF document. In fact, the backend is so bad before poppler 0.60 + // that we'd rather not expose the QPrinter option at all for older poppler versions. + // On Windows we have no choice, because there the CUPS backend will not work. + // On the positive side, QPrinter printing allows more printing options. +#if defined(Q_OS_WIN) || HAVE_POPPLER_0_60 + m_printBackend->insertItem(QPrinterBackend, i18n("QPrinter (experimental)"), QPrinterBackend); + m_printBackend->setItemData(QPrinterBackend, i18n("Print with Qt (experimental, you may see rendering artifacts)"), Qt::ToolTipRole); +#endif QWidget* formWidget = new QWidget(this); QFormLayout* printBackendLayout = new QFormLayout(formWidget); + printBackendLayout->addRow(i18n("Print backend:"), m_printBackend); m_scaleMode = new QComboBox; m_scaleMode->insertItem(FitToPrintableArea, i18n("Fit to printable area"), FitToPrintableArea); @@ -129,6 +158,7 @@ // Enable scaleMode only if the file is to be rasterized before printing m_scaleMode->setEnabled( false ); + connect( m_printBackend, QOverload::of( &QComboBox::currentIndexChanged ), this, &PDFOptionsPage::enableOrDisableScaleMode ); connect( m_forceRaster, &QCheckBox::stateChanged, this, &PDFOptionsPage::enableOrDisableScaleMode ); #if defined(Q_OS_WIN) && !defined HAVE_POPPLER_0_60 @@ -157,6 +187,11 @@ m_forceRaster->setChecked( forceRaster ); } + PrintBackend printBackend() const + { + return m_printBackend->currentData().value(); + } + ScaleMode scaleMode() const { return m_scaleMode->currentData().value(); @@ -165,6 +200,7 @@ private: QCheckBox *m_printAnnots; QCheckBox *m_forceRaster; + QComboBox *m_printBackend; QComboBox *m_scaleMode; }; @@ -1336,33 +1372,21 @@ { bool printAnnots = true; bool forceRasterize = false; + PDFOptionsPage::PrintBackend printBackend = PDFOptionsPage::CUPSBackend; PDFOptionsPage::ScaleMode scaleMode = PDFOptionsPage::FitToPrintableArea; if ( pdfOptionsPage ) { printAnnots = pdfOptionsPage->printAnnots(); forceRasterize = pdfOptionsPage->printForceRaster(); + printBackend = pdfOptionsPage->printBackend(); scaleMode = pdfOptionsPage->scaleMode(); } -#ifdef Q_OS_WIN - // Windows can only print by rasterization, because that is - // currently the only way Okular implements printing without using UNIX-specific - // tools like 'lpr'. - forceRasterize = true; -#ifndef HAVE_POPPLER_0_60 - // The Document::HideAnnotations flags was introduced in poppler 0.60 - printAnnots = true; -#endif -#endif - -#ifdef HAVE_POPPLER_0_60 - if ( forceRasterize ) + if ( forceRasterize || printBackend == PDFOptionsPage::QPrinterBackend ) { +#ifdef HAVE_POPPLER_0_60 pdfdoc->setRenderHint(Poppler::Document::HideAnnotations, !printAnnots); -#else - if ( forceRasterize && printAnnots) - { #endif // If requested, scale to full page instead of the printable area @@ -1388,9 +1412,12 @@ 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' + // We need to convert 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(); + double unitsConversion = printer.paperRect(QPrinter::DevicePixel).width() / printer.paperRect(QPrinter::Point).width(); + + // Default: no scaling at all + double scaling = 1.0; if ( scaleMode != PDFOptionsPage::None ) { @@ -1399,16 +1426,34 @@ 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); + scaling = std::min(horizontalScaling, verticalScaling) / unitsConversion; } + if ( forceRasterize ) + { #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( QRectF( QPointF( 0, 0 ), scaling * pp->pageSizeF() ), img ); + painter.drawImage( QRectF( QPointF( 0, 0 ), unitsConversion * scaling * pp->pageSizeF() ), img ); + } else + { + QRect viewport; + viewport.setWidth(scaling * painter.window().width()); + viewport.setHeight(scaling * painter.window().height()); + painter.setViewport(viewport); + + // temporarily switch to poppler's Arthur backend. + // It is the only one that implements renderToPainter. + auto actualRenderBackend = pdfdoc->renderBackend(); + pdfdoc->setRenderBackend( Poppler::Document::ArthurBackend ); + + pp->renderToPainter( &painter, printer.logicalDpiX(), printer.logicalDpiY() ); + + pdfdoc->setRenderBackend( actualRenderBackend ); + } } userMutex()->unlock(); }