diff options
Diffstat (limited to 'examples/pdf/pdfviewer')
18 files changed, 989 insertions, 0 deletions
diff --git a/examples/pdf/pdfviewer/images/busy.png b/examples/pdf/pdfviewer/images/busy.png Binary files differnew file mode 100644 index 0000000..69056c4 --- /dev/null +++ b/examples/pdf/pdfviewer/images/busy.png diff --git a/examples/pdf/pdfviewer/images/fileopen.png b/examples/pdf/pdfviewer/images/fileopen.png Binary files differnew file mode 100644 index 0000000..33e0d63 --- /dev/null +++ b/examples/pdf/pdfviewer/images/fileopen.png diff --git a/examples/pdf/pdfviewer/images/go-next-24.png b/examples/pdf/pdfviewer/images/go-next-24.png Binary files differnew file mode 100644 index 0000000..9a55ef3 --- /dev/null +++ b/examples/pdf/pdfviewer/images/go-next-24.png diff --git a/examples/pdf/pdfviewer/images/go-previous-24.png b/examples/pdf/pdfviewer/images/go-previous-24.png Binary files differnew file mode 100644 index 0000000..2ea769e --- /dev/null +++ b/examples/pdf/pdfviewer/images/go-previous-24.png diff --git a/examples/pdf/pdfviewer/images/zoom-in-24.png b/examples/pdf/pdfviewer/images/zoom-in-24.png Binary files differnew file mode 100644 index 0000000..d29b142 --- /dev/null +++ b/examples/pdf/pdfviewer/images/zoom-in-24.png diff --git a/examples/pdf/pdfviewer/images/zoom-in-32.png b/examples/pdf/pdfviewer/images/zoom-in-32.png Binary files differnew file mode 100644 index 0000000..34d70af --- /dev/null +++ b/examples/pdf/pdfviewer/images/zoom-in-32.png diff --git a/examples/pdf/pdfviewer/images/zoom-out-24.png b/examples/pdf/pdfviewer/images/zoom-out-24.png Binary files differnew file mode 100644 index 0000000..1970347 --- /dev/null +++ b/examples/pdf/pdfviewer/images/zoom-out-24.png diff --git a/examples/pdf/pdfviewer/images/zoom-out-32.png b/examples/pdf/pdfviewer/images/zoom-out-32.png Binary files differnew file mode 100644 index 0000000..b832206 --- /dev/null +++ b/examples/pdf/pdfviewer/images/zoom-out-32.png diff --git a/examples/pdf/pdfviewer/main.cpp b/examples/pdf/pdfviewer/main.cpp new file mode 100644 index 0000000..20fa6f8 --- /dev/null +++ b/examples/pdf/pdfviewer/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include <QApplication> +#include <QUrl> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + QStringList args = a.arguments(); + w.show(); + if (args.length() > 1) + w.open(QUrl::fromLocalFile(args[1])); + + return a.exec(); +} diff --git a/examples/pdf/pdfviewer/mainwindow.cpp b/examples/pdf/pdfviewer/mainwindow.cpp new file mode 100644 index 0000000..d865a8b --- /dev/null +++ b/examples/pdf/pdfviewer/mainwindow.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include "sequentialpagewidget.h" + +#include <QFileDialog> +#include <QLineEdit> +#include <QMessageBox> +#include <QPdfDocument> +#include <QScroller> +#include <QtMath> + +const qreal zoomMultiplier = qSqrt(2.0); + +Q_LOGGING_CATEGORY(lcExample, "qt.examples.pdfviewer") + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) + , m_pageWidget(new SequentialPageWidget(this)) + , m_zoomEdit(new QLineEdit(this)) + , m_pageEdit(new QLineEdit(this)) + , m_document(new QPdfDocument(this)) +{ + ui->setupUi(this); + ui->scrollArea->setWidget(m_pageWidget); + m_zoomEdit->setMaximumWidth(50); + m_zoomEdit->setAlignment(Qt::AlignHCenter); + ui->mainToolBar->insertWidget(ui->actionZoom_In, m_zoomEdit); + m_pageEdit->setMaximumWidth(50); + m_pageEdit->setAlignment(Qt::AlignHCenter); + ui->mainToolBar->insertWidget(ui->actionGo, m_pageEdit); + connect(m_pageWidget, SIGNAL(showingPageRange(int,int)), + this, SLOT(showingPageRange(int,int)), Qt::QueuedConnection); + connect(m_pageWidget, SIGNAL(zoomChanged(qreal)), + this, SLOT(zoomChanged(qreal))); + connect(m_zoomEdit, SIGNAL(returnPressed()), this, SLOT(zoomEdited())); + connect(m_pageEdit, SIGNAL(returnPressed()), this, SLOT(on_actionGo_triggered())); + + QScroller::grabGesture(ui->scrollArea); + + m_pageWidget->setDocument(m_document); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::open(const QUrl &docLocation) +{ + if (docLocation.isLocalFile()) { + m_document->load(docLocation.toLocalFile()); + } else { + qCDebug(lcExample) << docLocation << "is not a valid local file"; + QMessageBox::critical(this, tr("Failed to open"), tr("%1 is not a valid local file").arg(docLocation.toString())); + } + qCDebug(lcExample) << docLocation; + ui->scrollArea->ensureVisible(0, 0, 0, 0); +} + +void MainWindow::showingPageRange(int start, int end) +{ + ui->statusBar->clearMessage(); + if (start == end) + ui->statusBar->showMessage(tr("showing page %1").arg(start)); + else + ui->statusBar->showMessage(tr("showing pages %1 to %2").arg(start).arg(end)); + m_pageEdit->setText(QString::number(end)); +} + +void MainWindow::zoomChanged(qreal factor) +{ + m_zoomEdit->setText(tr("%1%").arg(factor * 100., 0, 'f', 0)); +} + +void MainWindow::zoomEdited() +{ + bool ok = false; + qreal factor = m_zoomEdit->text().remove(QChar('%')).toDouble(&ok); + if (ok) + m_pageWidget->setZoom(factor / 100.); +} + +void MainWindow::on_actionOpen_triggered() +{ + QUrl toOpen = QFileDialog::getOpenFileUrl(this, tr("Choose a PDF"), QUrl(), "Portable Documents (*.pdf)"); + if (toOpen.isValid()) + open(toOpen); +} + +void MainWindow::on_actionQuit_triggered() +{ + QApplication::quit(); +} + +void MainWindow::on_actionAbout_triggered() +{ + QMessageBox::about(this, tr("About PdfViewer"), + tr("An example using QPdfDocument")); +} + +void MainWindow::on_actionAbout_Qt_triggered() +{ + QMessageBox::aboutQt(this); +} + +void MainWindow::on_actionZoom_In_triggered() +{ + m_pageWidget->setZoom(m_pageWidget->zoom() * zoomMultiplier); +} + +void MainWindow::on_actionZoom_Out_triggered() +{ + m_pageWidget->setZoom(m_pageWidget->zoom() / zoomMultiplier); +} + +void MainWindow::on_actionGo_triggered() +{ + bool ok = false; + int page = m_pageEdit->text().toInt(&ok); + if (!ok) return; + ui->scrollArea->ensureVisible(0, m_pageWidget->yForPage(page)); +} + +void MainWindow::on_actionPrevious_Page_triggered() +{ + ui->scrollArea->ensureVisible(0, m_pageWidget->yForPage(m_pageWidget->topPageShowing() - 1)); +} + +void MainWindow::on_actionNext_Page_triggered() +{ + ui->scrollArea->ensureVisible(0, m_pageWidget->yForPage(m_pageWidget->bottomPageShowing() + 1)); +} diff --git a/examples/pdf/pdfviewer/mainwindow.h b/examples/pdf/pdfviewer/mainwindow.h new file mode 100644 index 0000000..dedc812 --- /dev/null +++ b/examples/pdf/pdfviewer/mainwindow.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QLoggingCategory> +#include <QMainWindow> + +Q_DECLARE_LOGGING_CATEGORY(lcExample) + +namespace Ui { +class MainWindow; +} + +class QLineEdit; +class QPdfDocument; +class SequentialPageWidget; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +public slots: + void open(const QUrl &docLocation); + +private slots: + void showingPageRange(int start, int end); + void zoomChanged(qreal factor); + void zoomEdited(); + + // action handlers + void on_actionOpen_triggered(); + void on_actionQuit_triggered(); + void on_actionAbout_triggered(); + void on_actionAbout_Qt_triggered(); + void on_actionZoom_In_triggered(); + void on_actionZoom_Out_triggered(); + void on_actionGo_triggered(); + void on_actionPrevious_Page_triggered(); + void on_actionNext_Page_triggered(); + +private: + Ui::MainWindow *ui; + SequentialPageWidget *m_pageWidget; + QLineEdit *m_zoomEdit; + QLineEdit *m_pageEdit; + + QPdfDocument *m_document; +}; + +#endif // MAINWINDOW_H diff --git a/examples/pdf/pdfviewer/mainwindow.ui b/examples/pdf/pdfviewer/mainwindow.ui new file mode 100644 index 0000000..7070619 --- /dev/null +++ b/examples/pdf/pdfviewer/mainwindow.ui @@ -0,0 +1,173 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QScrollArea" name="scrollArea"> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>380</width> + <height>200</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"/> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menuBar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>19</height> + </rect> + </property> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>File</string> + </property> + <addaction name="actionOpen"/> + <addaction name="actionQuit"/> + </widget> + <widget class="QMenu" name="menuHelp"> + <property name="title"> + <string>Help</string> + </property> + <addaction name="actionAbout"/> + <addaction name="actionAbout_Qt"/> + </widget> + <widget class="QMenu" name="menuView"> + <property name="title"> + <string>View</string> + </property> + <addaction name="actionZoom_In"/> + <addaction name="actionZoom_Out"/> + <addaction name="actionPrevious_Page"/> + <addaction name="actionNext_Page"/> + </widget> + <addaction name="menuFile"/> + <addaction name="menuView"/> + <addaction name="menuHelp"/> + </widget> + <widget class="QToolBar" name="mainToolBar"> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="actionOpen"/> + <addaction name="separator"/> + <addaction name="actionZoom_Out"/> + <addaction name="actionZoom_In"/> + <addaction name="separator"/> + <addaction name="actionGo"/> + </widget> + <widget class="QStatusBar" name="statusBar"/> + <action name="actionOpen"> + <property name="icon"> + <iconset resource="resources.qrc"> + <normaloff>:/icons/images/fileopen.png</normaloff>:/icons/images/fileopen.png</iconset> + </property> + <property name="text"> + <string>Open...</string> + </property> + <property name="shortcut"> + <string>Ctrl+O</string> + </property> + </action> + <action name="actionQuit"> + <property name="text"> + <string>Quit</string> + </property> + <property name="shortcut"> + <string>Ctrl+Q</string> + </property> + </action> + <action name="actionAbout"> + <property name="text"> + <string>About</string> + </property> + </action> + <action name="actionAbout_Qt"> + <property name="text"> + <string>About Qt</string> + </property> + </action> + <action name="actionZoom_In"> + <property name="icon"> + <iconset resource="resources.qrc"> + <normaloff>:/icons/images/zoom-in-24.png</normaloff>:/icons/images/zoom-in-24.png</iconset> + </property> + <property name="text"> + <string>Zoom In</string> + </property> + <property name="shortcut"> + <string>Ctrl+=</string> + </property> + </action> + <action name="actionZoom_Out"> + <property name="icon"> + <iconset resource="resources.qrc"> + <normaloff>:/icons/images/zoom-out-24.png</normaloff>:/icons/images/zoom-out-24.png</iconset> + </property> + <property name="text"> + <string>Zoom Out</string> + </property> + <property name="shortcut"> + <string>Ctrl+-</string> + </property> + </action> + <action name="actionGo"> + <property name="text"> + <string>Go</string> + </property> + <property name="toolTip"> + <string>Go to Page</string> + </property> + </action> + <action name="actionPrevious_Page"> + <property name="text"> + <string>Previous Page</string> + </property> + <property name="shortcut"> + <string>PgUp</string> + </property> + </action> + <action name="actionNext_Page"> + <property name="text"> + <string>Next Page</string> + </property> + <property name="shortcut"> + <string>PgDown</string> + </property> + </action> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources> + <include location="resources.qrc"/> + </resources> + <connections/> +</ui> diff --git a/examples/pdf/pdfviewer/pagerenderer.cpp b/examples/pdf/pdfviewer/pagerenderer.cpp new file mode 100644 index 0000000..c8f2456 --- /dev/null +++ b/examples/pdf/pdfviewer/pagerenderer.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pagerenderer.h" + +#include <QElapsedTimer> +#include <QLoggingCategory> +#include <QPainter> +#include <QPdfDocument> +#include <QUrl> + +Q_DECLARE_LOGGING_CATEGORY(lcExample) + +PageRenderer::PageRenderer(QObject *parent) + : QThread(parent) + , m_document(nullptr) + , m_page(0) + , m_zoom(1.) + , m_minRenderTime(1000000000.) + , m_maxRenderTime(0.) + , m_totalRenderTime(0.) + , m_totalPagesRendered(0) +{ +} + +void PageRenderer::setDocument(QPdfDocument *document) +{ + m_document = document; +} + +void PageRenderer::requestPage(int page, qreal zoom, Priority priority) +{ + // TODO maybe queue up the requests + m_page = page; + m_zoom = zoom; + start(priority); +} + +void PageRenderer::run() +{ + renderPage(m_page, m_zoom); +} + +void PageRenderer::renderPage(int page, qreal zoom) +{ + if (!m_document || m_document->status() != QPdfDocument::Ready) + return; + + const QSizeF size = m_document->pageSize(page) * m_zoom; + + QElapsedTimer timer; + timer.start(); + + const QImage &img = m_document->render(page, size); + + const qreal secs = timer.nsecsElapsed() / 1000000000.0; + if (secs < m_minRenderTime) + m_minRenderTime = secs; + + if (secs > m_maxRenderTime) + m_maxRenderTime = secs; + + m_totalRenderTime += secs; + ++m_totalPagesRendered; + + emit pageReady(page, zoom, img); + + qCDebug(lcExample) << "page" << page << "zoom" << m_zoom << "size" << size << "in" << secs << + "secs; min" << m_minRenderTime << + "avg" << m_totalRenderTime / m_totalPagesRendered << + "max" << m_maxRenderTime; +} diff --git a/examples/pdf/pdfviewer/pagerenderer.h b/examples/pdf/pdfviewer/pagerenderer.h new file mode 100644 index 0000000..5feccaa --- /dev/null +++ b/examples/pdf/pdfviewer/pagerenderer.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PAGECACHE_H +#define PAGECACHE_H + +#include <QImage> +#include <QThread> + +class QPdfDocument; + +class PageRenderer : public QThread +{ + Q_OBJECT + +public: + explicit PageRenderer(QObject *parent = nullptr); + +public slots: + void setDocument(QPdfDocument *document); + + void requestPage(int page, qreal zoom, Priority priority = QThread::NormalPriority); + +signals: + void pageReady(int page, qreal zoom, QImage image); + +protected: + void run() override; + +private: + void renderPage(int page, qreal zoom); + +private: + QPdfDocument *m_document; + + // current request only + int m_page; + qreal m_zoom; + + // performance statistics + qreal m_minRenderTime; + qreal m_maxRenderTime; + qreal m_totalRenderTime; + int m_totalPagesRendered; +}; + +#endif // PAGECACHE_H diff --git a/examples/pdf/pdfviewer/pdfviewer.pro b/examples/pdf/pdfviewer/pdfviewer.pro new file mode 100644 index 0000000..10cacce --- /dev/null +++ b/examples/pdf/pdfviewer/pdfviewer.pro @@ -0,0 +1,21 @@ +QT += core gui widgets pdf +TARGET = pdfviewer +TEMPLATE = app + +SOURCES += main.cpp\ + mainwindow.cpp \ + sequentialpagewidget.cpp \ + pagerenderer.cpp + +HEADERS += mainwindow.h \ + sequentialpagewidget.h \ + pagerenderer.h + +FORMS += mainwindow.ui + +RESOURCES += \ + resources.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/pdf/pdfviewer +INSTALLS += target + diff --git a/examples/pdf/pdfviewer/resources.qrc b/examples/pdf/pdfviewer/resources.qrc new file mode 100644 index 0000000..02d9655 --- /dev/null +++ b/examples/pdf/pdfviewer/resources.qrc @@ -0,0 +1,12 @@ +<RCC> + <qresource prefix="/icons"> + <file>images/fileopen.png</file> + <file>images/go-next-24.png</file> + <file>images/go-previous-24.png</file> + <file>images/zoom-in-24.png</file> + <file>images/zoom-in-32.png</file> + <file>images/zoom-out-24.png</file> + <file>images/zoom-out-32.png</file> + <file>images/busy.png</file> + </qresource> +</RCC> diff --git a/examples/pdf/pdfviewer/sequentialpagewidget.cpp b/examples/pdf/pdfviewer/sequentialpagewidget.cpp new file mode 100644 index 0000000..904bc17 --- /dev/null +++ b/examples/pdf/pdfviewer/sequentialpagewidget.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "sequentialpagewidget.h" +#include "pagerenderer.h" +#include <QPaintEvent> +#include <QPainter> +#include <QPdfDocument> +#include <QGuiApplication> +#include <QScreen> +#include <QLoggingCategory> +#include <QElapsedTimer> + +Q_DECLARE_LOGGING_CATEGORY(lcExample) + +SequentialPageWidget::SequentialPageWidget(QWidget *parent) + : QWidget(parent) + , m_pageCacheLimit(20) + , m_pageRenderer(new PageRenderer()) + , m_background(Qt::darkGray) + , m_placeholderIcon(":icons/images/busy.png") + , m_placeholderBackground(Qt::white) + , m_pageSpacing(3) + , m_topPageShowing(0) + , m_zoom(1.) + , m_screenResolution(QGuiApplication::primaryScreen()->logicalDotsPerInch() / 72.0) + , m_document(nullptr) +{ + connect(m_pageRenderer, SIGNAL(pageReady(int, qreal, QImage)), this, SLOT(pageLoaded(int, qreal, QImage)), Qt::QueuedConnection); + grabGesture(Qt::SwipeGesture); +} + +SequentialPageWidget::~SequentialPageWidget() +{ + delete m_pageRenderer; +} + +void SequentialPageWidget::setDocument(QPdfDocument *document) +{ + m_pageRenderer->setDocument(document); + + m_document = document; + connect(m_document, &QPdfDocument::statusChanged, this, &SequentialPageWidget::documentStatusChanged); + + documentStatusChanged(); +} + +void SequentialPageWidget::setZoom(qreal factor) +{ + m_zoom = factor; + emit zoomChanged(factor); + invalidate(); +} + +QSizeF SequentialPageWidget::pageSize(int page) +{ +// if (!m_pageSizes.length() <= page) +// return QSizeF(); + return m_pageSizes[page] * m_screenResolution * m_zoom; +} + +void SequentialPageWidget::invalidate() +{ + QSizeF totalSize(0, m_pageSpacing); + for (int page = 0; page < pageCount(); ++page) { + QSizeF size = pageSize(page); + totalSize.setHeight(totalSize.height() + size.height()); + if (size.width() > totalSize.width()) + totalSize.setWidth(size.width()); + } + m_totalSize = totalSize.toSize(); + setMinimumSize(m_totalSize); + emit zoomChanged(m_zoom); + qCDebug(lcExample) << "total size" << m_totalSize; + m_pageCache.clear(); + update(); +} + +void SequentialPageWidget::documentStatusChanged() +{ + m_pageSizes.clear(); + m_topPageShowing = 0; + + if (m_document->status() == QPdfDocument::Ready) { + for (int page = 0; page < m_document->pageCount(); ++page) + m_pageSizes.append(m_document->pageSize(page)); + } + + invalidate(); +} + +void SequentialPageWidget::pageLoaded(int page, qreal zoom, QImage image) +{ + Q_UNUSED(zoom) + if (m_cachedPagesLRU.length() > m_pageCacheLimit) + m_pageCache.remove(m_cachedPagesLRU.takeFirst()); + m_pageCache.insert(page, image); + m_cachedPagesLRU.append(page); + update(); +} + +int SequentialPageWidget::pageCount() +{ + return m_pageSizes.count(); +} + +void SequentialPageWidget::paintEvent(QPaintEvent * event) +{ + QPainter painter(this); + painter.fillRect(event->rect(), m_background); + + if (m_pageSizes.isEmpty()) + return; + + // Find the first page that needs to be rendered + int page = 0; + int y = 0; + while (page < pageCount()) { + QSizeF size = pageSize(page); + int height = size.toSize().height(); + if (y + height >= event->rect().top()) + break; + y += height + m_pageSpacing; + ++page; + } + y += m_pageSpacing; + m_topPageShowing = page; + + // Actually render pages + while (y < event->rect().bottom() && page < pageCount()) { + QSizeF size = pageSize(page); + if (m_pageCache.contains(page)) { + const QImage &img = m_pageCache[page]; + painter.fillRect((width() - img.width()) / 2, y, size.width(), size.height(), Qt::white); + painter.drawImage((width() - img.width()) / 2, y, img); + } else { + painter.fillRect((width() - size.width()) / 2, y, size.width(), size.height(), m_placeholderBackground); + painter.drawPixmap((size.width() - m_placeholderIcon.width()) / 2, + (size.height() - m_placeholderIcon.height()) / 2, m_placeholderIcon); + m_pageRenderer->requestPage(page, m_screenResolution * m_zoom); + } + y += size.height() + m_pageSpacing; + ++page; + } + m_bottomPageShowing = page - 1; + emit showingPageRange(m_topPageShowing, m_bottomPageShowing); +} + +qreal SequentialPageWidget::yForPage(int endPage) +{ + // TODO maybe put this loop into a page iterator class + int y = m_pageSpacing; + for (int page = 0; page < pageCount() && page < endPage; ++page) { + QSizeF size = pageSize(page); + int height = size.toSize().height(); + y += height + m_pageSpacing; + } + return y; +} diff --git a/examples/pdf/pdfviewer/sequentialpagewidget.h b/examples/pdf/pdfviewer/sequentialpagewidget.h new file mode 100644 index 0000000..85f3571 --- /dev/null +++ b/examples/pdf/pdfviewer/sequentialpagewidget.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SEQUENTIALPAGEWIDGET_H +#define SEQUENTIALPAGEWIDGET_H + +#include <QWidget> + +class QPdfDocument; +class PageRenderer; + +class SequentialPageWidget : public QWidget +{ + Q_OBJECT +public: + explicit SequentialPageWidget(QWidget *parent = 0); + ~SequentialPageWidget(); + + void paintEvent(QPaintEvent * event); + qreal zoom() { return m_zoom; } + qreal yForPage(int page); + int topPageShowing() { return m_topPageShowing; } + int bottomPageShowing() { return m_bottomPageShowing; } + + void setDocument(QPdfDocument *document); + +public slots: + void setZoom(qreal factor); + void invalidate(); + +signals: + void showingPageRange(int start, int end); + void zoomChanged(qreal factor); + +private slots: + void documentStatusChanged(); + void pageLoaded(int page, qreal zoom, QImage image); + +private: + int pageCount(); + QSizeF pageSize(int page); + void render(int page); + +private: + QHash<int, QImage> m_pageCache; + QVector<int> m_cachedPagesLRU; + int m_pageCacheLimit; + QVector<QSizeF> m_pageSizes; + PageRenderer *m_pageRenderer; + QBrush m_background; + QPixmap m_placeholderIcon; + QBrush m_placeholderBackground; + int m_pageSpacing; + int m_topPageShowing; + int m_bottomPageShowing; + QSize m_totalSize; + qreal m_zoom; + qreal m_screenResolution; // pixels per point + + QPdfDocument *m_document; +}; + +#endif // SEQUENTIALPAGEWIDGET_H |