Printing feature

This commit is contained in:
Jakub Melka
2020-02-03 19:45:17 +01:00
parent efca4a3cde
commit beaa3425ac
8 changed files with 253 additions and 3 deletions

View File

@ -224,7 +224,8 @@ qt_libraries.files = $$[QT_INSTALL_BINS]/Qt?Widgets$${SUFFIX}.dll \
$$[QT_INSTALL_BINS]/Qt?Gui$${SUFFIX}.dll \ $$[QT_INSTALL_BINS]/Qt?Gui$${SUFFIX}.dll \
$$[QT_INSTALL_BINS]/Qt?Core$${SUFFIX}.dll \ $$[QT_INSTALL_BINS]/Qt?Core$${SUFFIX}.dll \
$$[QT_INSTALL_BINS]/Qt?WinExtras$${SUFFIX}.dll \ $$[QT_INSTALL_BINS]/Qt?WinExtras$${SUFFIX}.dll \
$$[QT_INSTALL_BINS]/Qt?Svg$${SUFFIX}.dll $$[QT_INSTALL_BINS]/Qt?Svg$${SUFFIX}.dll \
$$[QT_INSTALL_BINS]/Qt?PrintSupport$${SUFFIX}.dll
qt_libraries.path = $$DESTDIR/install qt_libraries.path = $$DESTDIR/install
INSTALLS += qt_libraries INSTALLS += qt_libraries
@ -235,3 +236,7 @@ INSTALLS += qt_plugin_platform
qt_plugin_iconengine.files = $$[QT_INSTALL_PLUGINS]/iconengines/qsvgicon$${SUFFIX}.dll qt_plugin_iconengine.files = $$[QT_INSTALL_PLUGINS]/iconengines/qsvgicon$${SUFFIX}.dll
qt_plugin_iconengine.path = $$DESTDIR/install/iconengines qt_plugin_iconengine.path = $$DESTDIR/install/iconengines
INSTALLS += qt_plugin_iconengine INSTALLS += qt_plugin_iconengine
qt_plugin_printsupport.files = $$[QT_INSTALL_PLUGINS]/printsupport/windowsprintersupport$${SUFFIX}.dll
qt_plugin_printsupport.path = $$DESTDIR/install/printsupport
INSTALLS += qt_plugin_printsupport

View File

@ -37,7 +37,7 @@ class PDFPrecompiledPage;
class PDFOptionalContentActivity; class PDFOptionalContentActivity;
/// Renders the PDF page on the painter, or onto an image. /// Renders the PDF page on the painter, or onto an image.
class PDFRenderer class PDFFORQTLIBSHARED_EXPORT PDFRenderer
{ {
public: public:

View File

@ -4,7 +4,7 @@
# #
#------------------------------------------------- #-------------------------------------------------
QT += core gui winextras QT += core gui winextras printsupport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

View File

@ -35,5 +35,6 @@
<file>resources/ui.svg</file> <file>resources/ui.svg</file>
<file>resources/rotate-left.svg</file> <file>resources/rotate-left.svg</file>
<file>resources/rotate-right.svg</file> <file>resources/rotate-right.svg</file>
<file>resources/print.svg</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -37,6 +37,7 @@
#include "pdfexecutionpolicy.h" #include "pdfexecutionpolicy.h"
#include "pdfwidgetutils.h" #include "pdfwidgetutils.h"
#include <QPainter>
#include <QSettings> #include <QSettings>
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
@ -53,6 +54,8 @@
#include <QLabel> #include <QLabel>
#include <QDoubleSpinBox> #include <QDoubleSpinBox>
#include <QDesktopServices> #include <QDesktopServices>
#include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QPrintDialog>
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
@ -109,6 +112,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
ui->actionCopyText->setShortcut(QKeySequence::Copy); ui->actionCopyText->setShortcut(QKeySequence::Copy);
ui->actionRotateRight->setShortcut(QKeySequence("Ctrl+Shift++")); ui->actionRotateRight->setShortcut(QKeySequence("Ctrl+Shift++"));
ui->actionRotateLeft->setShortcut(QKeySequence("Ctrl+Shift+-")); ui->actionRotateLeft->setShortcut(QKeySequence("Ctrl+Shift+-"));
ui->actionPrint->setShortcut(QKeySequence::Print);
for (QAction* action : m_recentFileManager->getActions()) for (QAction* action : m_recentFileManager->getActions())
{ {
@ -806,6 +810,14 @@ void PDFViewerMainWindow::updateActionsAvailability()
const bool isBusy = m_futureWatcher.isRunning() || m_isBusy; const bool isBusy = m_futureWatcher.isRunning() || m_isBusy;
const bool hasDocument = m_pdfDocument; const bool hasDocument = m_pdfDocument;
const bool hasValidDocument = !isBusy && hasDocument; const bool hasValidDocument = !isBusy && hasDocument;
bool canPrint = false;
if (m_pdfDocument)
{
const pdf::PDFObjectStorage& storage = m_pdfDocument->getStorage();
const pdf::PDFSecurityHandler* securityHandler = storage.getSecurityHandler();
canPrint = securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::PrintLowResolution) ||
securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::PrintHighResolution);
}
ui->actionOpen->setEnabled(!isBusy); ui->actionOpen->setEnabled(!isBusy);
ui->actionClose->setEnabled(hasValidDocument); ui->actionClose->setEnabled(hasValidDocument);
@ -817,6 +829,7 @@ void PDFViewerMainWindow::updateActionsAvailability()
ui->actionFitHeight->setEnabled(hasValidDocument); ui->actionFitHeight->setEnabled(hasValidDocument);
ui->actionRendering_Errors->setEnabled(hasValidDocument); ui->actionRendering_Errors->setEnabled(hasValidDocument);
ui->actionFind->setEnabled(hasValidDocument); ui->actionFind->setEnabled(hasValidDocument);
ui->actionPrint->setEnabled(hasValidDocument && canPrint);
setEnabled(!isBusy); setEnabled(!isBusy);
} }
@ -1158,4 +1171,109 @@ void PDFViewerMainWindow::on_actionRotateLeft_triggered()
m_pdfWidget->getDrawWidgetProxy()->performOperation(pdf::PDFDrawWidgetProxy::RotateLeft); m_pdfWidget->getDrawWidgetProxy()->performOperation(pdf::PDFDrawWidgetProxy::RotateLeft);
} }
void PDFViewerMainWindow::on_actionPrint_triggered()
{
// Are we allowed to print in high resolution? If yes, then print in high resolution,
// otherwise print in low resolution. If this action is triggered, then print operation
// should be allowed (at least print in low resolution).
const pdf::PDFObjectStorage& storage = m_pdfDocument->getStorage();
const pdf::PDFSecurityHandler* securityHandler = storage.getSecurityHandler();
QPrinter::PrinterMode printerMode = QPrinter::HighResolution;
if (!securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::PrintHighResolution))
{
printerMode = QPrinter::ScreenResolution;
}
// Run print dialog
QPrinter printer(printerMode);
QPrintDialog printDialog(&printer, this);
printDialog.setOptions(QPrintDialog::PrintPageRange | QPrintDialog::PrintShowPageSize | QPrintDialog::PrintCollateCopies | QPrintDialog::PrintSelection);
printDialog.setOption(QPrintDialog::PrintCurrentPage, m_pdfWidget->getDrawWidget()->getCurrentPages().size() == 1);
printDialog.setMinMax(1, int(m_pdfDocument->getCatalog()->getPageCount()));
if (printDialog.exec() == QPrintDialog::Accepted)
{
std::vector<pdf::PDFInteger> pageIndices;
switch (printDialog.printRange())
{
case QAbstractPrintDialog::AllPages:
{
pageIndices.resize(m_pdfDocument->getCatalog()->getPageCount(), 0);
std::iota(pageIndices.begin(), pageIndices.end(), 0);
break;
}
case QAbstractPrintDialog::Selection:
case QAbstractPrintDialog::CurrentPage:
{
pageIndices = m_pdfWidget->getDrawWidget()->getCurrentPages();
break;
}
case QAbstractPrintDialog::PageRange:
{
const pdf::PDFInteger fromPage = printDialog.fromPage();
const pdf::PDFInteger toPage = printDialog.toPage();
const pdf::PDFInteger pageCount = toPage - fromPage + 1;
if (pageCount > 0)
{
pageIndices.resize(pageCount, 0);
std::iota(pageIndices.begin(), pageIndices.end(), fromPage - 1);
}
break;
}
default:
Q_ASSERT(false);
break;
}
if (pageIndices.empty())
{
// Nothing to be printed
return;
}
pdf::ProgressStartupInfo info;
info.showDialog = true;
info.text = tr("Printing document");
m_progress->start(pageIndices.size(), qMove(info));
printer.setFullPage(true);
QPainter painter(&printer);
const pdf::PDFCatalog* catalog = m_pdfDocument->getCatalog();
pdf::PDFDrawWidgetProxy* proxy = m_pdfWidget->getDrawWidgetProxy();
pdf::PDFOptionalContentActivity optionalContentActivity(m_pdfDocument.data(), pdf::OCUsage::Print, nullptr);
pdf::PDFCMSPointer cms = proxy->getCMSManager()->getCurrentCMS();
pdf::PDFRenderer renderer(m_pdfDocument.get(), proxy->getFontCache(), cms.data(), &optionalContentActivity, proxy->getFeatures(), proxy->getMeshQualitySettings());
const pdf::PDFInteger lastPage = pageIndices.back();
for (const pdf::PDFInteger pageIndex : pageIndices)
{
const pdf::PDFPage* page = catalog->getPage(pageIndex);
Q_ASSERT(page);
QRectF mediaBox = page->getRotatedMediaBox();
QRectF paperRect = printer.paperRect();
QSizeF scaledSize = mediaBox.size().scaled(paperRect.size(), Qt::KeepAspectRatio);
mediaBox.setSize(scaledSize);
mediaBox.moveCenter(paperRect.center());
renderer.render(&painter, mediaBox, pageIndex);
m_progress->step();
if (pageIndex != lastPage)
{
if (!printer.newPage())
{
break;
}
}
}
painter.end();
m_progress->finish();
}
}
} // namespace pdfviewer } // namespace pdfviewer

View File

@ -96,6 +96,8 @@ private slots:
void on_actionRotateLeft_triggered(); void on_actionRotateLeft_triggered();
void on_actionPrint_triggered();
private: private:
void onActionOpenTriggered(); void onActionOpenTriggered();
void onActionCloseTriggered(); void onActionCloseTriggered();

View File

@ -31,6 +31,7 @@
<addaction name="actionClose"/> <addaction name="actionClose"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionSend_by_E_Mail"/> <addaction name="actionSend_by_E_Mail"/>
<addaction name="actionPrint"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionProperties"/> <addaction name="actionProperties"/>
<addaction name="separator"/> <addaction name="separator"/>
@ -440,6 +441,15 @@
<string>Rotate Left</string> <string>Rotate Left</string>
</property> </property>
</action> </action>
<action name="actionPrint">
<property name="icon">
<iconset resource="pdfforqtviewer.qrc">
<normaloff>:/resources/print.svg</normaloff>:/resources/print.svg</iconset>
</property>
<property name="text">
<string>Print</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources> <resources>

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30mm"
height="30mm"
viewBox="0 0 30 30"
version="1.1"
id="svg5291"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="print.svg">
<defs
id="defs5285" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:cx="43.479195"
inkscape:cy="22.801583"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2035"
inkscape:window-x="-13"
inkscape:window-y="-13"
inkscape:window-maximized="1" />
<metadata
id="metadata5288">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Jakub Melka</dc:title>
</cc:Agent>
</dc:creator>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Vrstva 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-267)">
<rect
style="fill:#000000;fill-opacity:0.9948007;stroke:#000000;stroke-width:0.37699473;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="rect831"
width="23.085983"
height="7.656455"
x="4.1268063"
y="279.67856" />
<rect
style="fill:none;fill-opacity:0.9948007;stroke:#000000;stroke-width:0.7492165;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="rect833"
width="14.933595"
height="2.2713938"
x="8.1247196"
y="287.44482" />
<rect
style="fill:none;fill-opacity:0.9948007;stroke:#000000;stroke-width:0.72756678;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="rect837"
width="17.304916"
height="5.3208041"
x="6.9582481"
y="274.62485" />
<rect
style="fill:#ffffff;fill-opacity:0.9948007;stroke:none;stroke-width:1.1373328;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="rect841"
width="1.508518"
height="1.3341492"
x="4.8337612"
y="280.19043" />
<rect
style="fill:#ffffff;fill-opacity:0.9948007;stroke:none;stroke-width:1.1373328;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="rect841-0"
width="1.508518"
height="1.3341492"
x="6.8714461"
y="280.19043" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB