mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Printing feature
This commit is contained in:
@ -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
|
||||||
|
@ -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:
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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>
|
||||||
|
114
PdfForQtViewer/resources/print.svg
Normal file
114
PdfForQtViewer/resources/print.svg
Normal 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 |
Reference in New Issue
Block a user