├── .gitignore ├── .gitmodules ├── .qmake.conf ├── LICENSE.FDL ├── LICENSE.GPLv3 ├── LICENSE.LGPLv3 ├── examples ├── examples.pro └── pdf │ ├── pdf.pro │ └── pdfviewer │ ├── images │ ├── busy.png │ ├── fileopen.png │ ├── go-next-24.png │ ├── go-previous-24.png │ ├── zoom-in-24.png │ ├── zoom-in-32.png │ ├── zoom-out-24.png │ └── zoom-out-32.png │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── mainwindow.ui │ ├── pageselector.cpp │ ├── pageselector.h │ ├── pdfviewer.pro │ ├── resources.qrc │ ├── zoomselector.cpp │ └── zoomselector.h ├── qpdf.pro ├── src ├── 3rdparty │ └── gyp2pri.py ├── lib │ └── lib.pro ├── pdf │ ├── doc │ │ └── qtpdf.qdocconf │ ├── jsbridge.cpp │ ├── pdf.pro │ ├── qpdfbookmarkmodel.cpp │ ├── qpdfbookmarkmodel.h │ ├── qpdfdocument.cpp │ ├── qpdfdocument.h │ ├── qpdfdocument_p.h │ ├── qpdfdocumentrenderoptions.h │ ├── qpdfdocumentrenderoptions.qdoc │ ├── qpdfnamespace.h │ ├── qpdfnamespace.qdoc │ ├── qpdfpagenavigation.cpp │ ├── qpdfpagenavigation.h │ ├── qpdfpagerenderer.cpp │ ├── qpdfpagerenderer.h │ └── qtpdfglobal.h ├── pdfwidgets │ ├── pdfwidgets.pro │ ├── qpdfview.cpp │ ├── qpdfview.h │ ├── qpdfview_p.h │ └── qtpdfwidgetsglobal.h └── src.pro ├── sync.profile └── tests ├── auto ├── auto.pro ├── cmake │ └── cmake.pro ├── qpdfbookmarkmodel │ ├── pdf-sample.bookmarks.pdf │ ├── pdf-sample.bookmarks_pages.pdf │ ├── qpdfbookmarkmodel.pro │ └── tst_qpdfbookmarkmodel.cpp ├── qpdfdocument │ ├── pdf-sample.metadata.pdf │ ├── pdf-sample.protected.pdf │ ├── qpdfdocument.pro │ └── tst_qpdfdocument.cpp ├── qpdfpagenavigation │ ├── pdf-sample.pagenavigation.pdf │ ├── qpdfpagenavigation.pro │ └── tst_qpdfpagenavigation.cpp └── qpdfpagerenderer │ ├── pdf-sample.pagerenderer.pdf │ ├── qpdfpagerenderer.pro │ └── tst_qpdfpagerenderer.cpp └── tests.pro /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated in the Qt build system 2 | # ---------------------------------------------------------------------------- 3 | 4 | config.tests/*/*/* 5 | !config.tests/*/*/*[.]* 6 | config.tests/*/*/*[.]app 7 | 8 | callgrind.out.* 9 | pcviewer.cfg 10 | *~ 11 | *.a 12 | *.la 13 | *.core 14 | *.moc 15 | *.o 16 | *.obj 17 | *.orig 18 | *.swp 19 | *.rej 20 | *.so 21 | *.pbxuser 22 | *.mode1 23 | *.mode1v3 24 | *_pch.h.cpp 25 | *_resource.rc 26 | .#* 27 | *.*# 28 | core 29 | .qmake.cache 30 | .qmake.vars 31 | *.prl 32 | tags 33 | .DS_Store 34 | *.debug 35 | Makefile* 36 | !qmake/Makefile.win32* 37 | !qmake/Makefile.unix 38 | *.prl 39 | *.app 40 | *.pro.user 41 | *.qmlproject.user 42 | *.gcov 43 | bin/Qt*.dll 44 | bin/assistant* 45 | bin/designer* 46 | bin/dumpcpp* 47 | bin/idc* 48 | bin/linguist* 49 | bin/lrelease* 50 | bin/lupdate* 51 | bin/lconvert* 52 | bin/moc* 53 | bin/makeqpf* 54 | bin/pixeltool* 55 | bin/qmake* 56 | bin/qdoc3* 57 | bin/qt3to4* 58 | bin/qttracereplay* 59 | bin/rcc* 60 | bin/uic* 61 | bin/patternist* 62 | bin/phonon* 63 | bin/qcollectiongenerator* 64 | bin/qdbus* 65 | bin/qhelpconverter* 66 | bin/qhelpgenerator* 67 | bin/qtconfig* 68 | bin/xmlpatterns* 69 | bin/cetest* 70 | bin/collectiongenerator 71 | bin/helpconverter 72 | bin/helpgenerator 73 | bin/kmap2qmap* 74 | bin/qlalr* 75 | bin/qmlconv* 76 | bin/qmldebugger* 77 | bin/qml* 78 | bin/qttracereplay* 79 | configure.cache 80 | config.status 81 | mkspecs/default 82 | mkspecs/qconfig.pri 83 | moc_*.cpp 84 | qmake/qmake.exe 85 | qmake/Makefile.bak 86 | src/corelib/global/qconfig.cpp 87 | src/corelib/global/qconfig.h 88 | src/corelib/global/qconfig.h.qmake 89 | ui_*.h 90 | tests/auto/qprocess/test*/*.exe 91 | tests/auto/qtcpsocket/stressTest/*.exe 92 | tests/auto/qprocess/fileWriterProcess/*.exe 93 | tests/auto/qmake/testdata/quotedfilenames/*.exe 94 | tests/auto/compilerwarnings/*.exe 95 | tests/auto/qmake/testdata/quotedfilenames/test.cpp 96 | tests/auto/qprocess/fileWriterProcess.txt 97 | .com.apple.timemachine.supported 98 | tests/auto/qlibrary/libmylib.so* 99 | tests/auto/qresourceengine/runtime_resource.rcc 100 | tools/qtestlib/chart/chart* 101 | tools/qtestlib/updater/updater* 102 | tools/qmleasing/qmleasing 103 | tools/qmltestrunner/qmltestrunner 104 | tools/activeqt/testcon/testcon.tlb 105 | translations/*.qm 106 | translations/*_untranslated.ts 107 | qrc_*.cpp 108 | 109 | # Test generated files 110 | QObject.log 111 | tst_* 112 | !tst_*.* 113 | tst_*.log 114 | tst_*.debug 115 | tst_*~ 116 | 117 | # xemacs temporary files 118 | *.flc 119 | 120 | # Vim temporary files 121 | .*.swp 122 | 123 | # Visual Studio generated files 124 | *.ib_pdb_index 125 | *.idb 126 | *.ilk 127 | *.pdb 128 | *.dll 129 | *.exp 130 | *.sln 131 | *.suo 132 | *.vcproj 133 | *vcproj.*.*.user 134 | *.ncb 135 | *.vcxproj 136 | *.vcxproj.filters 137 | *.vcxproj.user 138 | 139 | # MinGW generated files 140 | *.Debug 141 | *.Release 142 | 143 | # WebKit temp files 144 | src/3rdparty/webkit/WebCore/mocinclude.tmp 145 | src/3rdparty/webkit/includes.txt 146 | src/3rdparty/webkit/includes2.txt 147 | 148 | # Symlinks generated by configure 149 | tools/qvfb/qvfbhdr.h 150 | tools/qvfb/qlock_p.h 151 | tools/qvfb/qlock.cpp 152 | tools/qvfb/qwssignalhandler.cpp 153 | tools/qvfb/qwssignalhandler_p.h 154 | .DS_Store 155 | .pch 156 | .rcc 157 | *.app 158 | config.status 159 | config.tests/unix/cups/cups 160 | config.tests/unix/getaddrinfo/getaddrinfo 161 | config.tests/unix/getifaddrs/getifaddrs 162 | config.tests/unix/iconv/iconv 163 | config.tests/unix/ipv6/ipv6 164 | config.tests/unix/ipv6ifname/ipv6ifname 165 | config.tests/unix/largefile/largefile 166 | config.tests/unix/nis/nis 167 | config.tests/unix/odbc/odbc 168 | config.tests/unix/openssl/openssl 169 | config.tests/unix/stl/stl 170 | config.tests/unix/zlib/zlib 171 | config.tests/unix/3dnow/3dnow 172 | config.tests/unix/mmx/mmx 173 | config.tests/unix/sse/sse 174 | config.tests/unix/sse2/sse2 175 | 176 | 177 | 178 | # Directories to ignore 179 | # --------------------- 180 | 181 | debug 182 | imports/* 183 | examples/tools/plugandpaint/plugins 184 | include/* 185 | include/*/* 186 | lib/* 187 | !lib/fonts 188 | !lib/README 189 | plugins/*/* 190 | release 191 | tmp 192 | doc-build 193 | doc/html/* 194 | doc/qch 195 | doc-build 196 | doc/qtqml 197 | doc/qtquick 198 | .rcc 199 | .pch 200 | .metadata 201 | 202 | # Symbian build system generated files 203 | # --------------------- 204 | 205 | ABLD.BAT 206 | bld.inf* 207 | *.mmp 208 | *.mk 209 | *.rss 210 | *.loc 211 | !s60main.rss 212 | *.pkg 213 | plugin_commonu.def 214 | *.qtplugin 215 | *.sis 216 | *.sisx 217 | *.lst 218 | *.exe 219 | *.mif 220 | *.rsc 221 | *.sym 222 | *.lib 223 | 224 | # runonphone crash dumps 225 | d_exc_*.txt 226 | d_exc_*.stk 227 | 228 | # Generated by abldfast.bat from devtools. 229 | .abldsteps.* 230 | 231 | # Carbide project files 232 | # --------------------- 233 | .project 234 | .cproject 235 | .make.cache 236 | *.d 237 | 238 | qtc-debugging-helper 239 | src/corelib/lib 240 | src/network/lib 241 | src/xml/lib/ 242 | 243 | .pc/ 244 | 245 | # INTEGRITY generated files 246 | *.gpj 247 | *.int 248 | *.ael 249 | *.dla 250 | *.dnm 251 | *.dep 252 | *.map 253 | work 254 | 255 | #generated version headers 256 | src/qmltest/qtquicktestversion.h 257 | src/qtquick1/qtquick1version.h 258 | src/qmldevtools/qtqmldevtoolsversion.h 259 | src/quick/qtquickversion.h 260 | src/qml/qtqmlversion.h 261 | 262 | tests/auto/*/*.o 263 | tests/auto/*/*.moc 264 | tests/auto/*/*/*.o 265 | tests/auto/*/*/*.moc 266 | 267 | # Generated static plugin import sources 268 | *_plugin_import.cpp 269 | 270 | # Compiled python code 271 | *.pyc 272 | 273 | src/qml/RegExpJitTables.h 274 | src/qml/udis86_itab.c 275 | src/qml/udis86_itab.h 276 | 277 | src/lib/pdfium.pri 278 | src/lib/agg.pri 279 | src/lib/freetype.pri 280 | src/lib/lcms2.pri 281 | src/lib/libjpeg.pri 282 | src/lib/libopenjpeg.pri 283 | src/lib/zlib.pri 284 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/3rdparty/pdfium"] 2 | path = src/3rdparty/pdfium 3 | url = https://pdfium.googlesource.com/pdfium 4 | -------------------------------------------------------------------------------- /.qmake.conf: -------------------------------------------------------------------------------- 1 | load(qt_build_config) 2 | 3 | CONFIG += warning_clean 4 | 5 | MODULE_VERSION = 5.9.0 6 | 7 | # Resolve root directories for sources 8 | QTPDF_ROOT = $$PWD 9 | 10 | -------------------------------------------------------------------------------- /LICENSE.LGPLv3: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | 3 | The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd. 4 | Contact: http://www.qt.io/licensing/ 5 | 6 | You may use, distribute and copy the Qt Toolkit under the terms of 7 | GNU Lesser General Public License version 3, which is displayed below. 8 | This license makes reference to the version 3 of the GNU General 9 | Public License, which you can find in the LICENSE.GPLv3 file. 10 | 11 | ------------------------------------------------------------------------- 12 | 13 | GNU LESSER GENERAL PUBLIC LICENSE 14 | Version 3, 29 June 2007 15 | 16 | Copyright © 2007 Free Software Foundation, Inc. 17 | Everyone is permitted to copy and distribute verbatim copies of this 18 | licensedocument, but changing it is not allowed. 19 | 20 | This version of the GNU Lesser General Public License incorporates 21 | the terms and conditions of version 3 of the GNU General Public 22 | License, supplemented by the additional permissions listed below. 23 | 24 | 0. Additional Definitions. 25 | 26 | As used herein, “this License” refers to version 3 of the GNU Lesser 27 | General Public License, and the “GNU GPL” refers to version 3 of the 28 | GNU General Public License. 29 | 30 | “The Library” refers to a covered work governed by this License, 31 | other than an Application or a Combined Work as defined below. 32 | 33 | An “Application” is any work that makes use of an interface provided 34 | by the Library, but which is not otherwise based on the Library. 35 | Defining a subclass of a class defined by the Library is deemed a mode 36 | of using an interface provided by the Library. 37 | 38 | A “Combined Work” is a work produced by combining or linking an 39 | Application with the Library. The particular version of the Library 40 | with which the Combined Work was made is also called the “Linked 41 | Version”. 42 | 43 | The “Minimal Corresponding Source” for a Combined Work means the 44 | Corresponding Source for the Combined Work, excluding any source code 45 | for portions of the Combined Work that, considered in isolation, are 46 | based on the Application, and not on the Linked Version. 47 | 48 | The “Corresponding Application Code” for a Combined Work means the 49 | object code and/or source code for the Application, including any data 50 | and utility programs needed for reproducing the Combined Work from the 51 | Application, but excluding the System Libraries of the Combined Work. 52 | 53 | 1. Exception to Section 3 of the GNU GPL. 54 | 55 | You may convey a covered work under sections 3 and 4 of this License 56 | without being bound by section 3 of the GNU GPL. 57 | 58 | 2. Conveying Modified Versions. 59 | 60 | If you modify a copy of the Library, and, in your modifications, a 61 | facility refers to a function or data to be supplied by an Application 62 | that uses the facility (other than as an argument passed when the 63 | facility is invoked), then you may convey a copy of the modified 64 | version: 65 | 66 | a) under this License, provided that you make a good faith effort 67 | to ensure that, in the event an Application does not supply the 68 | function or data, the facility still operates, and performs 69 | whatever part of its purpose remains meaningful, or 70 | 71 | b) under the GNU GPL, with none of the additional permissions of 72 | this License applicable to that copy. 73 | 74 | 3. Object Code Incorporating Material from Library Header Files. 75 | 76 | The object code form of an Application may incorporate material from 77 | a header file that is part of the Library. You may convey such object 78 | code under terms of your choice, provided that, if the incorporated 79 | material is not limited to numerical parameters, data structure 80 | layouts and accessors, or small macros, inline functions and templates 81 | (ten or fewer lines in length), you do both of the following: 82 | 83 | a) Give prominent notice with each copy of the object code that 84 | the Library is used in it and that the Library and its use are 85 | covered by this License. 86 | 87 | b) Accompany the object code with a copy of the GNU GPL and this 88 | license document. 89 | 90 | 4. Combined Works. 91 | 92 | You may convey a Combined Work under terms of your choice that, taken 93 | together, effectively do not restrict modification of the portions of 94 | the Library contained in the Combined Work and reverse engineering for 95 | debugging such modifications, if you also do each of the following: 96 | 97 | a) Give prominent notice with each copy of the Combined Work that 98 | the Library is used in it and that the Library and its use are 99 | covered by this License. 100 | 101 | b) Accompany the Combined Work with a copy of the GNU GPL and this 102 | license document. 103 | 104 | c) For a Combined Work that displays copyright notices during 105 | execution, include the copyright notice for the Library among 106 | these notices, as well as a reference directing the user to the 107 | copies of the GNU GPL and this license document. 108 | 109 | d) Do one of the following: 110 | 111 | 0) Convey the Minimal Corresponding Source under the terms of 112 | this License, and the Corresponding Application Code in a form 113 | suitable for, and under terms that permit, the user to 114 | recombine or relink the Application with a modified version of 115 | the Linked Version to produce a modified Combined Work, in the 116 | manner specified by section 6 of the GNU GPL for conveying 117 | Corresponding Source. 118 | 119 | 1) Use a suitable shared library mechanism for linking with 120 | the Library. A suitable mechanism is one that (a) uses at run 121 | time a copy of the Library already present on the user's 122 | computer system, and (b) will operate properly with a modified 123 | version of the Library that is interface-compatible with the 124 | Linked Version. 125 | 126 | e) Provide Installation Information, but only if you would 127 | otherwise be required to provide such information under section 6 128 | of the GNU GPL, and only to the extent that such information is 129 | necessary to install and execute a modified version of the 130 | Combined Work produced by recombining or relinking the Application 131 | with a modified version of the Linked Version. (If you use option 132 | 4d0, the Installation Information must accompany the Minimal 133 | Corresponding Source and Corresponding Application Code. If you 134 | use option 4d1, you must provide the Installation Information in 135 | the manner specified by section 6 of the GNU GPL for conveying 136 | Corresponding Source.) 137 | 138 | 5. Combined Libraries. 139 | 140 | You may place library facilities that are a work based on the Library 141 | side by side in a single library together with other library 142 | facilities that are not Applications and are not covered by this 143 | License, and convey such a combined library under terms of your 144 | choice, if you do both of the following: 145 | 146 | a) Accompany the combined library with a copy of the same work 147 | based on the Library, uncombined with any other library 148 | facilities, conveyed under the terms of this License. 149 | 150 | b) Give prominent notice with the combined library that part of 151 | it is a work based on the Library, and explaining where to find 152 | the accompanying uncombined form of the same work. 153 | 154 | 6. Revised Versions of the GNU Lesser General Public License. 155 | 156 | The Free Software Foundation may publish revised and/or new versions 157 | of the GNU Lesser General Public License from time to time. Such new 158 | versions will be similar in spirit to the present version, but may 159 | differ in detail to address new problems or concerns. 160 | 161 | Each version is given a distinguishing version number. If the Library 162 | as you received it specifies that a certain numbered version of the 163 | GNU Lesser General Public License “or any later version” applies to 164 | it, you have the option of following the terms and conditions either 165 | of that published version or of any later version published by the 166 | Free Software Foundation. If the Library as you received it does not 167 | specify a version number of the GNU Lesser General Public License, 168 | you may choose any version of the GNU Lesser General Public License 169 | ever published by the Free Software Foundation. 170 | 171 | If the Library as you received it specifies that a proxy can decide 172 | whether future versions of the GNU Lesser General Public License shall 173 | apply, that proxy's public statement of acceptance of any version is 174 | permanent authorization for you to choose that version for the Library. 175 | -------------------------------------------------------------------------------- /examples/examples.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS += pdf 3 | -------------------------------------------------------------------------------- /examples/pdf/pdf.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS += pdfviewer 3 | -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/images/busy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/examples/pdf/pdfviewer/images/busy.png -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/images/fileopen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/examples/pdf/pdfviewer/images/fileopen.png -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/images/go-next-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/examples/pdf/pdfviewer/images/go-next-24.png -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/images/go-previous-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/examples/pdf/pdfviewer/images/go-previous-24.png -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/images/zoom-in-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/examples/pdf/pdfviewer/images/zoom-in-24.png -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/images/zoom-in-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/examples/pdf/pdfviewer/images/zoom-in-32.png -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/images/zoom-out-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/examples/pdf/pdfviewer/images/zoom-out-24.png -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/images/zoom-out-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/examples/pdf/pdfviewer/images/zoom-out-32.png -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/main.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "mainwindow.h" 38 | #include 39 | #include 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | QApplication a(argc, argv); 44 | MainWindow w; 45 | QStringList args = a.arguments(); 46 | w.show(); 47 | if (args.length() > 1) 48 | w.open(QUrl::fromLocalFile(args[1])); 49 | 50 | return a.exec(); 51 | } 52 | -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "mainwindow.h" 38 | #include "ui_mainwindow.h" 39 | 40 | #include "pageselector.h" 41 | #include "zoomselector.h" 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | const qreal zoomMultiplier = qSqrt(2.0); 51 | 52 | Q_LOGGING_CATEGORY(lcExample, "qt.examples.pdfviewer") 53 | 54 | MainWindow::MainWindow(QWidget *parent) 55 | : QMainWindow(parent) 56 | , ui(new Ui::MainWindow) 57 | , m_zoomSelector(new ZoomSelector(this)) 58 | , m_pageSelector(new PageSelector(this)) 59 | , m_document(new QPdfDocument(this)) 60 | { 61 | ui->setupUi(this); 62 | 63 | m_zoomSelector->setMaximumWidth(150); 64 | ui->mainToolBar->insertWidget(ui->actionZoom_In, m_zoomSelector); 65 | 66 | m_pageSelector->setMaximumWidth(150); 67 | ui->mainToolBar->addWidget(m_pageSelector); 68 | 69 | m_pageSelector->setPageNavigation(ui->pdfView->pageNavigation()); 70 | 71 | connect(m_zoomSelector, &ZoomSelector::zoomModeChanged, ui->pdfView, &QPdfView::setZoomMode); 72 | connect(m_zoomSelector, &ZoomSelector::zoomFactorChanged, ui->pdfView, &QPdfView::setZoomFactor); 73 | m_zoomSelector->reset(); 74 | 75 | QPdfBookmarkModel *bookmarkModel = new QPdfBookmarkModel(this); 76 | bookmarkModel->setDocument(m_document); 77 | 78 | ui->bookmarkView->setModel(bookmarkModel); 79 | connect(ui->bookmarkView, SIGNAL(activated(QModelIndex)), this, SLOT(bookmarkSelected(QModelIndex))); 80 | 81 | ui->tabWidget->setTabEnabled(1, false); // disable 'Pages' tab for now 82 | 83 | ui->pdfView->setDocument(m_document); 84 | 85 | connect(ui->pdfView, &QPdfView::zoomFactorChanged, 86 | m_zoomSelector, &ZoomSelector::setZoomFactor); 87 | } 88 | 89 | MainWindow::~MainWindow() 90 | { 91 | delete ui; 92 | } 93 | 94 | void MainWindow::open(const QUrl &docLocation) 95 | { 96 | if (docLocation.isLocalFile()) { 97 | m_document->load(docLocation.toLocalFile()); 98 | const auto documentTitle = m_document->metaData(QPdfDocument::Title).toString(); 99 | setWindowTitle(!documentTitle.isEmpty() ? documentTitle : QStringLiteral("PDF Viewer")); 100 | } else { 101 | qCDebug(lcExample) << docLocation << "is not a valid local file"; 102 | QMessageBox::critical(this, tr("Failed to open"), tr("%1 is not a valid local file").arg(docLocation.toString())); 103 | } 104 | qCDebug(lcExample) << docLocation; 105 | } 106 | 107 | void MainWindow::bookmarkSelected(const QModelIndex &index) 108 | { 109 | if (!index.isValid()) 110 | return; 111 | 112 | const int page = index.data(QPdfBookmarkModel::PageNumberRole).toInt(); 113 | ui->pdfView->pageNavigation()->setCurrentPage(page); 114 | } 115 | 116 | void MainWindow::on_actionOpen_triggered() 117 | { 118 | QUrl toOpen = QFileDialog::getOpenFileUrl(this, tr("Choose a PDF"), QUrl(), "Portable Documents (*.pdf)"); 119 | if (toOpen.isValid()) 120 | open(toOpen); 121 | } 122 | 123 | void MainWindow::on_actionQuit_triggered() 124 | { 125 | QApplication::quit(); 126 | } 127 | 128 | void MainWindow::on_actionAbout_triggered() 129 | { 130 | QMessageBox::about(this, tr("About PdfViewer"), 131 | tr("An example using QPdfDocument")); 132 | } 133 | 134 | void MainWindow::on_actionAbout_Qt_triggered() 135 | { 136 | QMessageBox::aboutQt(this); 137 | } 138 | 139 | void MainWindow::on_actionZoom_In_triggered() 140 | { 141 | ui->pdfView->setZoomFactor(ui->pdfView->zoomFactor() * zoomMultiplier); 142 | } 143 | 144 | void MainWindow::on_actionZoom_Out_triggered() 145 | { 146 | ui->pdfView->setZoomFactor(ui->pdfView->zoomFactor() / zoomMultiplier); 147 | } 148 | 149 | void MainWindow::on_actionPrevious_Page_triggered() 150 | { 151 | ui->pdfView->pageNavigation()->goToPreviousPage(); 152 | } 153 | 154 | void MainWindow::on_actionNext_Page_triggered() 155 | { 156 | ui->pdfView->pageNavigation()->goToNextPage(); 157 | } 158 | 159 | void MainWindow::on_actionContinuous_triggered() 160 | { 161 | ui->pdfView->setPageMode(ui->actionContinuous->isChecked() ? QPdfView::MultiPage : QPdfView::SinglePage); 162 | } 163 | -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/mainwindow.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef MAINWINDOW_H 38 | #define MAINWINDOW_H 39 | 40 | #include 41 | #include 42 | 43 | Q_DECLARE_LOGGING_CATEGORY(lcExample) 44 | 45 | QT_BEGIN_NAMESPACE 46 | namespace Ui { 47 | class MainWindow; 48 | } 49 | 50 | class QPdfDocument; 51 | class QPdfView; 52 | QT_END_NAMESPACE 53 | 54 | class PageSelector; 55 | class ZoomSelector; 56 | 57 | class MainWindow : public QMainWindow 58 | { 59 | Q_OBJECT 60 | 61 | public: 62 | explicit MainWindow(QWidget *parent = nullptr); 63 | ~MainWindow(); 64 | 65 | public slots: 66 | void open(const QUrl &docLocation); 67 | 68 | private slots: 69 | void bookmarkSelected(const QModelIndex &index); 70 | 71 | // action handlers 72 | void on_actionOpen_triggered(); 73 | void on_actionQuit_triggered(); 74 | void on_actionAbout_triggered(); 75 | void on_actionAbout_Qt_triggered(); 76 | void on_actionZoom_In_triggered(); 77 | void on_actionZoom_Out_triggered(); 78 | void on_actionPrevious_Page_triggered(); 79 | void on_actionNext_Page_triggered(); 80 | void on_actionContinuous_triggered(); 81 | 82 | private: 83 | Ui::MainWindow *ui; 84 | ZoomSelector *m_zoomSelector; 85 | PageSelector *m_pageSelector; 86 | 87 | QPdfDocument *m_document; 88 | }; 89 | 90 | #endif // MAINWINDOW_H 91 | -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 700 10 | 600 11 | 12 | 13 | 14 | PDF Viewer 15 | 16 | 17 | true 18 | 19 | 20 | 21 | 22 | 0 23 | 24 | 25 | 0 26 | 27 | 28 | 0 29 | 30 | 31 | 0 32 | 33 | 34 | 0 35 | 36 | 37 | 38 | 39 | 40 | 0 41 | 42 | 43 | 0 44 | 45 | 46 | 0 47 | 48 | 49 | 0 50 | 51 | 52 | 0 53 | 54 | 55 | 56 | 57 | Qt::Horizontal 58 | 59 | 60 | 61 | 62 | 0 63 | 0 64 | 65 | 66 | 67 | QTabWidget::West 68 | 69 | 70 | 0 71 | 72 | 73 | false 74 | 75 | 76 | 77 | Bookmarks 78 | 79 | 80 | 81 | 0 82 | 83 | 84 | 2 85 | 86 | 87 | 2 88 | 89 | 90 | 2 91 | 92 | 93 | 2 94 | 95 | 96 | 97 | 98 | 99 | 0 100 | 0 101 | 102 | 103 | 104 | true 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | Pages 113 | 114 | 115 | 116 | 117 | 118 | 119 | 10 120 | 0 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 0 135 | 0 136 | 700 137 | 22 138 | 139 | 140 | 141 | 142 | File 143 | 144 | 145 | 146 | 147 | 148 | 149 | Help 150 | 151 | 152 | 153 | 154 | 155 | 156 | View 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | false 172 | 173 | 174 | false 175 | 176 | 177 | TopToolBarArea 178 | 179 | 180 | false 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | :/icons/images/fileopen.png:/icons/images/fileopen.png 193 | 194 | 195 | Open... 196 | 197 | 198 | Ctrl+O 199 | 200 | 201 | 202 | 203 | Quit 204 | 205 | 206 | Ctrl+Q 207 | 208 | 209 | 210 | 211 | About 212 | 213 | 214 | 215 | 216 | About Qt 217 | 218 | 219 | 220 | 221 | 222 | :/icons/images/zoom-in-24.png:/icons/images/zoom-in-24.png 223 | 224 | 225 | Zoom In 226 | 227 | 228 | Ctrl+= 229 | 230 | 231 | 232 | 233 | 234 | :/icons/images/zoom-out-24.png:/icons/images/zoom-out-24.png 235 | 236 | 237 | Zoom Out 238 | 239 | 240 | Ctrl+- 241 | 242 | 243 | 244 | 245 | Previous Page 246 | 247 | 248 | PgUp 249 | 250 | 251 | 252 | 253 | Next Page 254 | 255 | 256 | PgDown 257 | 258 | 259 | 260 | 261 | true 262 | 263 | 264 | Continuous 265 | 266 | 267 | 268 | 269 | 270 | 271 | QPdfView 272 | QWidget 273 |
qpdfview.h
274 | 1 275 |
276 |
277 | 278 | 279 | 280 | 281 |
282 | -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/pageselector.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "pageselector.h" 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | PageSelector::PageSelector(QWidget *parent) 46 | : QWidget(parent) 47 | , m_pageNavigation(nullptr) 48 | { 49 | QHBoxLayout *layout = new QHBoxLayout(this); 50 | 51 | m_previousPageButton = new QToolButton(this); 52 | m_previousPageButton->setText("<"); 53 | m_previousPageButton->setEnabled(false); 54 | 55 | m_pageNumberEdit = new QLineEdit(this); 56 | m_pageNumberEdit->setAlignment(Qt::AlignRight); 57 | 58 | m_pageCountLabel = new QLabel(this); 59 | m_pageCountLabel->setText("0"); 60 | 61 | m_nextPageButton = new QToolButton(this); 62 | m_nextPageButton->setText(">"); 63 | m_nextPageButton->setEnabled(false); 64 | 65 | layout->addWidget(m_previousPageButton); 66 | layout->addWidget(m_pageNumberEdit); 67 | layout->addWidget(m_pageCountLabel); 68 | layout->addWidget(m_nextPageButton); 69 | } 70 | 71 | void PageSelector::setPageNavigation(QPdfPageNavigation *pageNavigation) 72 | { 73 | m_pageNavigation = pageNavigation; 74 | 75 | connect(m_previousPageButton, &QToolButton::clicked, m_pageNavigation, &QPdfPageNavigation::goToPreviousPage); 76 | connect(m_pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged, m_previousPageButton, &QToolButton::setEnabled); 77 | 78 | connect(m_pageNavigation, &QPdfPageNavigation::currentPageChanged, this, &PageSelector::onCurrentPageChanged); 79 | connect(m_pageNavigation, &QPdfPageNavigation::pageCountChanged, this, [this](int pageCount){ m_pageCountLabel->setText(QString::fromLatin1("/ %1").arg(pageCount)); }); 80 | 81 | connect(m_pageNumberEdit, &QLineEdit::editingFinished, this, &PageSelector::pageNumberEdited); 82 | 83 | connect(m_nextPageButton, &QToolButton::clicked, m_pageNavigation, &QPdfPageNavigation::goToNextPage); 84 | connect(m_pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged, m_nextPageButton, &QToolButton::setEnabled); 85 | 86 | onCurrentPageChanged(m_pageNavigation->currentPage()); 87 | } 88 | 89 | void PageSelector::onCurrentPageChanged(int page) 90 | { 91 | if (m_pageNavigation->pageCount() == 0) 92 | m_pageNumberEdit->setText(QString::number(0)); 93 | else 94 | m_pageNumberEdit->setText(QString::number(page + 1)); 95 | } 96 | 97 | void PageSelector::pageNumberEdited() 98 | { 99 | if (!m_pageNavigation) 100 | return; 101 | 102 | const QString text = m_pageNumberEdit->text(); 103 | 104 | bool ok = false; 105 | const int pageNumber = text.toInt(&ok); 106 | 107 | if (!ok) 108 | onCurrentPageChanged(m_pageNavigation->currentPage()); 109 | else 110 | m_pageNavigation->setCurrentPage(qBound(0, pageNumber - 1, m_pageNavigation->pageCount() - 1)); 111 | } 112 | -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/pageselector.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef PAGESELECTOR_H 38 | #define PAGESELECTOR_H 39 | 40 | #include 41 | 42 | QT_BEGIN_NAMESPACE 43 | class QLabel; 44 | class QLineEdit; 45 | class QPdfDocument; 46 | class QPdfPageNavigation; 47 | class QToolButton; 48 | QT_END_NAMESPACE 49 | 50 | class PageSelector : public QWidget 51 | { 52 | Q_OBJECT 53 | 54 | public: 55 | explicit PageSelector(QWidget *parent = nullptr); 56 | 57 | void setPageNavigation(QPdfPageNavigation *pageNavigation); 58 | 59 | private slots: 60 | void onCurrentPageChanged(int page); 61 | void pageNumberEdited(); 62 | 63 | private: 64 | QPdfPageNavigation *m_pageNavigation; 65 | 66 | QLineEdit *m_pageNumberEdit; 67 | QLabel *m_pageCountLabel; 68 | QToolButton *m_previousPageButton; 69 | QToolButton *m_nextPageButton; 70 | }; 71 | 72 | #endif // PAGESELECTOR_H 73 | -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/pdfviewer.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | TARGET = pdfviewer 3 | QT += core gui widgets pdfwidgets 4 | 5 | SOURCES += \ 6 | main.cpp \ 7 | mainwindow.cpp \ 8 | pageselector.cpp \ 9 | zoomselector.cpp 10 | 11 | HEADERS += \ 12 | mainwindow.h \ 13 | pageselector.h \ 14 | zoomselector.h 15 | 16 | FORMS += \ 17 | mainwindow.ui 18 | 19 | RESOURCES += \ 20 | resources.qrc 21 | 22 | target.path = $$[QT_INSTALL_EXAMPLES]/pdf/pdfviewer 23 | INSTALLS += target 24 | -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/fileopen.png 4 | images/go-next-24.png 5 | images/go-previous-24.png 6 | images/zoom-in-24.png 7 | images/zoom-in-32.png 8 | images/zoom-out-24.png 9 | images/zoom-out-32.png 10 | images/busy.png 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/zoomselector.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "zoomselector.h" 38 | 39 | #include 40 | 41 | ZoomSelector::ZoomSelector(QWidget *parent) 42 | : QComboBox(parent) 43 | { 44 | setEditable(true); 45 | 46 | addItem(QLatin1String("Fit Width")); 47 | addItem(QLatin1String("Fit Page")); 48 | addItem(QLatin1String("12%")); 49 | addItem(QLatin1String("25%")); 50 | addItem(QLatin1String("33%")); 51 | addItem(QLatin1String("50%")); 52 | addItem(QLatin1String("66%")); 53 | addItem(QLatin1String("75%")); 54 | addItem(QLatin1String("100%")); 55 | addItem(QLatin1String("125%")); 56 | addItem(QLatin1String("150%")); 57 | addItem(QLatin1String("200%")); 58 | addItem(QLatin1String("400%")); 59 | 60 | connect(this, static_cast(&QComboBox::currentIndexChanged), 61 | this, &ZoomSelector::onCurrentTextChanged); 62 | 63 | connect(lineEdit(), &QLineEdit::editingFinished, 64 | this, [this](){onCurrentTextChanged(lineEdit()->text()); }); 65 | } 66 | 67 | void ZoomSelector::setZoomFactor(qreal zoomFactor) 68 | { 69 | setCurrentText(QString::number(qRound(zoomFactor * 100)) + QLatin1String("%")); 70 | } 71 | 72 | void ZoomSelector::reset() 73 | { 74 | setCurrentIndex(8); // 100% 75 | } 76 | 77 | void ZoomSelector::onCurrentTextChanged(const QString &text) 78 | { 79 | if (text == QLatin1String("Fit Width")) { 80 | emit zoomModeChanged(QPdfView::FitToWidth); 81 | } else if (text == QLatin1String("Fit Page")) { 82 | emit zoomModeChanged(QPdfView::FitInView); 83 | } else { 84 | qreal factor = 1.0; 85 | 86 | QString withoutPercent(text); 87 | withoutPercent.remove(QLatin1Char('%')); 88 | 89 | bool ok = false; 90 | const int zoomLevel = withoutPercent.toInt(&ok); 91 | if (ok) 92 | factor = zoomLevel / 100.0; 93 | 94 | emit zoomModeChanged(QPdfView::CustomZoom); 95 | emit zoomFactorChanged(factor); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /examples/pdf/pdfviewer/zoomselector.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef ZOOMSELECTOR_H 38 | #define ZOOMSELECTOR_H 39 | 40 | #include 41 | #include 42 | 43 | class ZoomSelector : public QComboBox 44 | { 45 | Q_OBJECT 46 | 47 | public: 48 | explicit ZoomSelector(QWidget *parent = nullptr); 49 | 50 | public slots: 51 | void setZoomFactor(qreal zoomFactor); 52 | 53 | void reset(); 54 | 55 | signals: 56 | void zoomModeChanged(QPdfView::ZoomMode zoomMode); 57 | void zoomFactorChanged(qreal zoomFactor); 58 | 59 | private slots: 60 | void onCurrentTextChanged(const QString &text); 61 | }; 62 | 63 | #endif // ZOOMSELECTOR_H 64 | -------------------------------------------------------------------------------- /qpdf.pro: -------------------------------------------------------------------------------- 1 | load(qt_parts) 2 | # Upstream PDFium has not been ported to various platforms yet. 3 | requires(!qnx:!uikit:!winphone:!winrt:!win32-g++:!integrity) 4 | -------------------------------------------------------------------------------- /src/3rdparty/gyp2pri.py: -------------------------------------------------------------------------------- 1 | import sys, ast, os, argparse 2 | 3 | class Gyp(object): 4 | def __init__(self, fileName, gypVariables): 5 | self.fileName = fileName 6 | self.gypVariables = gypVariables 7 | with open(fileName, "r") as f: 8 | self.variables = ast.literal_eval(f.read()) 9 | 10 | def target(self, name): 11 | for t in self.variables["targets"]: 12 | if t["target_name"] == name: 13 | return t; 14 | 15 | for condition in self.variables["conditions"] or []: 16 | check = condition[0] 17 | vars = condition[1] 18 | try: 19 | if eval(check, None, self.gypVariables): 20 | for t in vars["targets"] or []: 21 | if t["target_name"] == name: 22 | return t; 23 | except: pass 24 | return None 25 | 26 | def target_defaults(self): 27 | return self.variables["target_defaults"] 28 | 29 | class ProFileSection(object): 30 | sourceExtensions = [ ".cpp", ".cc", ".c" ] 31 | headerExtensions = [ ".h", ".hh" ] 32 | skippingExtensions = [ ".rc" ] 33 | skippingFiles = [ "makefile" ] 34 | 35 | def __init__(self, scope): 36 | self.sources = [] 37 | self.headers = [] 38 | self.defines = [] 39 | self.includes = [] 40 | self.config = [] 41 | self.scope = scope 42 | 43 | def addSource(self, fileName): 44 | extension = os.path.splitext(fileName)[1] 45 | baseName = os.path.basename(fileName) 46 | if extension in ProFile.headerExtensions: 47 | self.headers.append(fileName) 48 | elif extension in ProFile.sourceExtensions: 49 | self.sources.append(fileName) 50 | elif baseName in ProFile.skippingFiles: 51 | return 52 | elif extension in ProFile.skippingExtensions: 53 | return 54 | else: 55 | raise Exception("Unknown source %s" % fileName) 56 | 57 | def addSources(self, sources, baseDirectory = None): 58 | for source in sources: 59 | path = source 60 | if baseDirectory: 61 | path = baseDirectory + "/" + path 62 | self.addSource(path) 63 | 64 | def addDefine(self, define): 65 | self.defines.append(define) 66 | 67 | def addDefines(self, defines): 68 | for macro in defines: 69 | self.addDefine(macro) 70 | 71 | def addConfig(self, cfg): 72 | self.config.append(cfg) 73 | 74 | def addInclude(self, path): 75 | path = path.replace("<(DEPTH)", "") 76 | self.includes.append("$$PWD/" + path) 77 | 78 | def generate(self): 79 | result = "" 80 | if self.defines: 81 | result += "DEFINES += \\\n " 82 | result += " \\\n ".join(self.defines) 83 | result += "\n\n" 84 | if self.config: 85 | result += "CONFIG += \\\n " 86 | result += " \\\n ".join(self.config) 87 | result += "\n\n" 88 | if self.includes: 89 | result += "INCLUDEPATH += \\\n " 90 | result += " \\\n ".join(self.includes) 91 | result += "\n\n" 92 | result += "SOURCES += \\\n " 93 | result += " \\\n ".join(self.sources) 94 | result += "\n\n" 95 | result += "HEADERS += \\\n " 96 | result += " \\\n ".join(self.headers) 97 | result += "\n\n" 98 | return result 99 | 100 | class ProFile(ProFileSection): 101 | def __init__(self): 102 | ProFileSection.__init__(self, "") 103 | self.scopes = [] 104 | 105 | def addScope(self, section): 106 | self.scopes.append(section) 107 | 108 | def generate(self): 109 | result = "# This is a generated file, do not edit!\n" 110 | result += ProFileSection.generate(self) 111 | for section in self.scopes: 112 | result += section.scope + " {\n" 113 | result += section.generate() 114 | result += "\n}\n" 115 | return result 116 | 117 | def addDependencies(gyp, proFile, gypTarget, variables): 118 | for dep in gypTarget.get("dependencies") or []: 119 | target = None 120 | baseDir = None 121 | for key, value in variables.iteritems(): 122 | name = "<(" + key + ")" 123 | replacement = value 124 | dep = dep.replace(name, replacement) 125 | if ".gyp:" in dep: 126 | targetFileName = dep[:dep.index(":")] 127 | fileName = os.path.dirname(gyp.fileName) + "/" + targetFileName 128 | subDep = dep[dep.index(":") + 1:] 129 | target = Gyp(fileName, variables).target(subDep) 130 | baseDir = os.path.relpath(os.path.dirname(fileName), os.path.dirname(gyp.fileName)) 131 | else: 132 | target = gyp.target(dep) 133 | if not target: 134 | return 135 | if target["target_name"] == "javascript": 136 | continue 137 | if target["target_name"] == "jsapi": 138 | continue 139 | pro.addSources(target["sources"], baseDir) 140 | 141 | if "conditions" in target: 142 | for condition in target["conditions"]: 143 | if condition[0] == "OS==\"win\"": 144 | scope = ProFileSection("win32") 145 | scope.addSources(condition[1]["sources"]) 146 | pro.addScope(scope) 147 | 148 | addDependencies(gyp, proFile, target, variables) 149 | 150 | optionParser = argparse.ArgumentParser() 151 | optionParser.add_argument("--gyp-var", action="append") 152 | optionParser.add_argument("input") 153 | optionParser.add_argument("mainTarget") 154 | optionParser.add_argument("output") 155 | config = optionParser.parse_args() 156 | 157 | variables = {} 158 | for var in config.gyp_var or []: 159 | key, value = var.split("=") 160 | variables[key] = value 161 | 162 | gyp = Gyp(config.input, variables) 163 | 164 | mainTarget = gyp.target(config.mainTarget) 165 | 166 | pro = ProFile() 167 | 168 | pro.addSources(mainTarget["sources"]) 169 | 170 | addDependencies(gyp, pro, mainTarget, variables) 171 | 172 | target_defaults = gyp.target_defaults() 173 | pro.addDefines(target_defaults["defines"]) 174 | if "include_dirs" in target_defaults: 175 | for path in target_defaults["include_dirs"]: 176 | pro.addInclude(os.path.relpath(os.path.dirname(gyp.fileName) + "/" + path, os.path.dirname(config.output))) 177 | 178 | with open(config.output, "w") as f: 179 | f.write(pro.generate()) 180 | -------------------------------------------------------------------------------- /src/lib/lib.pro: -------------------------------------------------------------------------------- 1 | TARGET = qtpdfium 2 | 3 | CONFIG += staticlib hide_symbols warn_off rtti_off exceptions_off c++11 4 | 5 | DEFINES += NOMINMAX 6 | 7 | load(qt_helper_lib) 8 | 9 | unix:!mac: CONFIG -= debug_and_release 10 | 11 | VPATH += $$QTPDF_ROOT/src/3rdparty/pdfium 12 | VPATH += $$QTPDF_ROOT/src/3rdparty/pdfium/third_party 13 | 14 | system(python $$QTPDF_ROOT/src/3rdparty/gyp2pri.py --gyp-var libjpeg_gyp_path=third_party/third_party.gyp --gyp-var pdf_use_skia=0 $$QTPDF_ROOT/src/3rdparty/pdfium/pdfium.gyp pdfium $$OUT_PWD/pdfium.pri) 15 | system(python $$QTPDF_ROOT/src/3rdparty/gyp2pri.py $$QTPDF_ROOT/src/3rdparty/pdfium/third_party/third_party.gyp fx_freetype $$OUT_PWD/freetype.pri) 16 | 17 | include($$OUT_PWD/pdfium.pri) 18 | 19 | DEFINES += FT2_BUILD_LIBRARY 20 | include($$OUT_PWD/freetype.pri) 21 | 22 | win32: LIBS_PRIVATE += -ladvapi32 -lgdi32 -luser32 23 | mac: LIBS_PRIVATE += -framework AppKit -framework CoreFoundation 24 | -------------------------------------------------------------------------------- /src/pdf/doc/qtpdf.qdocconf: -------------------------------------------------------------------------------- 1 | include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) 2 | 3 | project = QtPdf 4 | description = Qt Pdf Reference Documentation 5 | version = $QT_VERSION 6 | 7 | qhp.projects = QtPdf 8 | 9 | qhp.QtPdf.file = qtpdf.qhp 10 | qhp.QtPdf.namespace = org.qt-project.qtpdf.$QT_VERSION_TAG 11 | qhp.QtPdf.virtualFolder = qtpdf 12 | qhp.QtPdf.indexTitle = Qt PDF 13 | qhp.QtPdf.indexRoot = 14 | 15 | qhp.QtPdf.filterAttributes = qtpdf $QT_VERSION qtrefdoc 16 | qhp.QtPdf.customFilters.Qt.name = QtPdf $QT_VERSION 17 | qhp.QtPdf.customFilters.Qt.filterAttributes = qtpdf $QT_VERSION 18 | qhp.QtPdf.subprojects = classes 19 | qhp.QtPdf.subprojects.classes.title = C++ Classes 20 | qhp.QtPdf.subprojects.classes.indexTitle = Qt PDF C++ Classes 21 | qhp.QtPdf.subprojects.classes.selectors = class fake:headerfile 22 | qhp.QtPdf.subprojects.classes.sortPages = true 23 | 24 | depends += qtcore \ 25 | qtwidgets \ 26 | qtgui \ 27 | qtdoc \ 28 | qmake 29 | 30 | headerdirs += .. 31 | 32 | sourcedirs += .. 33 | 34 | exampledirs += ../../../examples/pdf \ 35 | snippets/ 36 | 37 | imagedirs += images 38 | 39 | navigation.landingpage = "Qt PDF" 40 | navigation.cppclassespage = "Qt PDF C++ Classes" 41 | -------------------------------------------------------------------------------- /src/pdf/jsbridge.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "fpdfsdk/javascript/JS_Runtime_Stub.cpp" 38 | 39 | -------------------------------------------------------------------------------- /src/pdf/pdf.pro: -------------------------------------------------------------------------------- 1 | TARGET = QtPdf 2 | QT += gui core core-private 3 | QT_PRIVATE += network 4 | TEMPLATE = lib 5 | CONFIG += c++11 6 | CONFIG -= precompile_header # Not supported by upstream header files 7 | win32: DEFINES += NOMINMAX 8 | INCLUDEPATH += $$QTPDF_ROOT/src/3rdparty/pdfium/fpdfsdk/include 9 | INCLUDEPATH += $$QTPDF_ROOT/src/3rdparty/pdfium 10 | INCLUDEPATH += $$QTPDF_ROOT/src/3rdparty/pdfium/third_party/freetype/include 11 | load(qt_module) 12 | 13 | LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lqtpdfium$$qtPlatformTargetSuffix() 14 | 15 | QMAKE_DOCS = $$PWD/doc/qtpdf.qdocconf 16 | 17 | gcc { 18 | QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter 19 | } 20 | 21 | msvc { 22 | QMAKE_CXXFLAGS_WARN_ON += -wd"4100" 23 | } 24 | 25 | SOURCES += \ 26 | jsbridge.cpp \ 27 | qpdfbookmarkmodel.cpp \ 28 | qpdfdocument.cpp \ 29 | qpdfpagenavigation.cpp \ 30 | qpdfpagerenderer.cpp 31 | 32 | HEADERS += \ 33 | qpdfbookmarkmodel.h \ 34 | qpdfdocument.h \ 35 | qpdfdocument_p.h \ 36 | qpdfdocumentrenderoptions.h \ 37 | qpdfnamespace.h \ 38 | qpdfpagenavigation.h \ 39 | qpdfpagerenderer.h \ 40 | qtpdfglobal.h 41 | -------------------------------------------------------------------------------- /src/pdf/qpdfbookmarkmodel.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "qpdfbookmarkmodel.h" 38 | 39 | #include "qpdfdocument.h" 40 | #include "qpdfdocument_p.h" 41 | 42 | #include "public/fpdf_doc.h" 43 | #include "public/fpdfview.h" 44 | 45 | #include 46 | #include 47 | #include 48 | 49 | QT_BEGIN_NAMESPACE 50 | 51 | class BookmarkNode 52 | { 53 | public: 54 | explicit BookmarkNode(BookmarkNode *parentNode = nullptr) 55 | : m_parentNode(parentNode) 56 | , m_level(0) 57 | , m_pageNumber(0) 58 | { 59 | } 60 | 61 | ~BookmarkNode() 62 | { 63 | clear(); 64 | } 65 | 66 | void clear() 67 | { 68 | qDeleteAll(m_childNodes); 69 | m_childNodes.clear(); 70 | } 71 | 72 | void appendChild(BookmarkNode *child) 73 | { 74 | m_childNodes.append(child); 75 | } 76 | 77 | BookmarkNode *child(int row) const 78 | { 79 | return m_childNodes.at(row); 80 | } 81 | 82 | int childCount() const 83 | { 84 | return m_childNodes.count(); 85 | } 86 | 87 | int row() const 88 | { 89 | if (m_parentNode) 90 | return m_parentNode->m_childNodes.indexOf(const_cast(this)); 91 | 92 | return 0; 93 | } 94 | 95 | BookmarkNode *parentNode() const 96 | { 97 | return m_parentNode; 98 | } 99 | 100 | QString title() const 101 | { 102 | return m_title; 103 | } 104 | 105 | void setTitle(const QString &title) 106 | { 107 | m_title = title; 108 | } 109 | 110 | int level() const 111 | { 112 | return m_level; 113 | } 114 | 115 | void setLevel(int level) 116 | { 117 | m_level = level; 118 | } 119 | 120 | int pageNumber() const 121 | { 122 | return m_pageNumber; 123 | } 124 | 125 | void setPageNumber(int pageNumber) 126 | { 127 | m_pageNumber = pageNumber; 128 | } 129 | 130 | private: 131 | QVector m_childNodes; 132 | BookmarkNode *m_parentNode; 133 | 134 | QString m_title; 135 | int m_level; 136 | int m_pageNumber; 137 | }; 138 | 139 | 140 | class QPdfBookmarkModelPrivate : public QAbstractItemModelPrivate 141 | { 142 | public: 143 | QPdfBookmarkModelPrivate() 144 | : QAbstractItemModelPrivate() 145 | , m_rootNode(new BookmarkNode(nullptr)) 146 | , m_document(nullptr) 147 | , m_structureMode(QPdfBookmarkModel::TreeMode) 148 | { 149 | } 150 | 151 | void rebuild() 152 | { 153 | Q_Q(QPdfBookmarkModel); 154 | 155 | const bool documentAvailable = (m_document && m_document->status() == QPdfDocument::Ready); 156 | 157 | if (documentAvailable) { 158 | q->beginResetModel(); 159 | m_rootNode->clear(); 160 | QPdfMutexLocker lock; 161 | appendChildNode(m_rootNode.data(), nullptr, 0, m_document->d->doc); 162 | lock.unlock(); 163 | q->endResetModel(); 164 | } else { 165 | if (m_rootNode->childCount() == 0) { 166 | return; 167 | } else { 168 | q->beginResetModel(); 169 | m_rootNode->clear(); 170 | q->endResetModel(); 171 | } 172 | } 173 | } 174 | 175 | void appendChildNode(BookmarkNode *parentBookmarkNode, FPDF_BOOKMARK parentBookmark, int level, FPDF_DOCUMENT document) 176 | { 177 | FPDF_BOOKMARK bookmark = FPDFBookmark_GetFirstChild(document, parentBookmark); 178 | 179 | while (bookmark) { 180 | BookmarkNode *childBookmarkNode = nullptr; 181 | 182 | if (m_structureMode == QPdfBookmarkModel::TreeMode) { 183 | childBookmarkNode = new BookmarkNode(parentBookmarkNode); 184 | parentBookmarkNode->appendChild(childBookmarkNode); 185 | } else if (m_structureMode == QPdfBookmarkModel::ListMode) { 186 | childBookmarkNode = new BookmarkNode(m_rootNode.data()); 187 | m_rootNode->appendChild(childBookmarkNode); 188 | } 189 | 190 | const unsigned long titleLength = FPDFBookmark_GetTitle(bookmark, nullptr, 0); 191 | 192 | QVector titleBuffer(titleLength); 193 | FPDFBookmark_GetTitle(bookmark, titleBuffer.data(), titleBuffer.length()); 194 | 195 | const FPDF_DEST dest = FPDFBookmark_GetDest(document, bookmark); 196 | const int pageNumber = FPDFDest_GetPageIndex(document, dest); 197 | 198 | childBookmarkNode->setTitle(QString::fromUtf16(titleBuffer.data())); 199 | childBookmarkNode->setLevel(level); 200 | childBookmarkNode->setPageNumber(pageNumber); 201 | 202 | // recurse down 203 | appendChildNode(childBookmarkNode, bookmark, level + 1, document); 204 | 205 | bookmark = FPDFBookmark_GetNextSibling(document, bookmark); 206 | } 207 | } 208 | 209 | void _q_documentStatusChanged() 210 | { 211 | rebuild(); 212 | } 213 | 214 | Q_DECLARE_PUBLIC(QPdfBookmarkModel) 215 | 216 | QScopedPointer m_rootNode; 217 | QPointer m_document; 218 | QPdfBookmarkModel::StructureMode m_structureMode; 219 | }; 220 | 221 | 222 | QPdfBookmarkModel::QPdfBookmarkModel(QObject *parent) 223 | : QAbstractItemModel(*new QPdfBookmarkModelPrivate, parent) 224 | { 225 | } 226 | 227 | QPdfDocument* QPdfBookmarkModel::document() const 228 | { 229 | Q_D(const QPdfBookmarkModel); 230 | 231 | return d->m_document; 232 | } 233 | 234 | void QPdfBookmarkModel::setDocument(QPdfDocument *document) 235 | { 236 | Q_D(QPdfBookmarkModel); 237 | 238 | if (d->m_document == document) 239 | return; 240 | 241 | if (d->m_document) 242 | disconnect(d->m_document, SIGNAL(statusChanged(QPdfDocument::Status)), this, SLOT(_q_documentStatusChanged())); 243 | 244 | d->m_document = document; 245 | emit documentChanged(d->m_document); 246 | 247 | if (d->m_document) 248 | connect(d->m_document, SIGNAL(statusChanged(QPdfDocument::Status)), this, SLOT(_q_documentStatusChanged())); 249 | 250 | d->rebuild(); 251 | } 252 | 253 | QPdfBookmarkModel::StructureMode QPdfBookmarkModel::structureMode() const 254 | { 255 | Q_D(const QPdfBookmarkModel); 256 | 257 | return d->m_structureMode; 258 | } 259 | 260 | void QPdfBookmarkModel::setStructureMode(StructureMode mode) 261 | { 262 | Q_D(QPdfBookmarkModel); 263 | 264 | if (d->m_structureMode == mode) 265 | return; 266 | 267 | d->m_structureMode = mode; 268 | emit structureModeChanged(d->m_structureMode); 269 | 270 | d->rebuild(); 271 | } 272 | 273 | int QPdfBookmarkModel::columnCount(const QModelIndex &parent) const 274 | { 275 | return 1; 276 | } 277 | 278 | QHash QPdfBookmarkModel::roleNames() const 279 | { 280 | QHash names; 281 | 282 | names[TitleRole] = "title"; 283 | names[LevelRole] = "level"; 284 | names[PageNumberRole] = "pageNumber"; 285 | 286 | return names; 287 | } 288 | 289 | QVariant QPdfBookmarkModel::data(const QModelIndex &index, int role) const 290 | { 291 | if (!index.isValid()) 292 | return QVariant(); 293 | 294 | const BookmarkNode *node = static_cast(index.internalPointer()); 295 | switch (role) { 296 | case TitleRole: 297 | return node->title(); 298 | case LevelRole: 299 | return node->level(); 300 | case PageNumberRole: 301 | return node->pageNumber(); 302 | default: 303 | return QVariant(); 304 | } 305 | } 306 | 307 | QModelIndex QPdfBookmarkModel::index(int row, int column, const QModelIndex &parent) const 308 | { 309 | Q_D(const QPdfBookmarkModel); 310 | 311 | if (!hasIndex(row, column, parent)) 312 | return QModelIndex(); 313 | 314 | BookmarkNode *parentNode; 315 | 316 | if (!parent.isValid()) 317 | parentNode = d->m_rootNode.data(); 318 | else 319 | parentNode = static_cast(parent.internalPointer()); 320 | 321 | BookmarkNode *childNode = parentNode->child(row); 322 | if (childNode) 323 | return createIndex(row, column, childNode); 324 | else 325 | return QModelIndex(); 326 | } 327 | 328 | QModelIndex QPdfBookmarkModel::parent(const QModelIndex &index) const 329 | { 330 | Q_D(const QPdfBookmarkModel); 331 | 332 | if (!index.isValid()) 333 | return QModelIndex(); 334 | 335 | const BookmarkNode *childNode = static_cast(index.internalPointer()); 336 | BookmarkNode *parentNode = childNode->parentNode(); 337 | 338 | if (parentNode == d->m_rootNode.data()) 339 | return QModelIndex(); 340 | 341 | return createIndex(parentNode->row(), 0, parentNode); 342 | } 343 | 344 | int QPdfBookmarkModel::rowCount(const QModelIndex &parent) const 345 | { 346 | Q_D(const QPdfBookmarkModel); 347 | 348 | if (parent.column() > 0) 349 | return 0; 350 | 351 | BookmarkNode *parentNode = nullptr; 352 | 353 | if (!parent.isValid()) 354 | parentNode = d->m_rootNode.data(); 355 | else 356 | parentNode = static_cast(parent.internalPointer()); 357 | 358 | return parentNode->childCount(); 359 | } 360 | 361 | QT_END_NAMESPACE 362 | 363 | #include "moc_qpdfbookmarkmodel.cpp" 364 | -------------------------------------------------------------------------------- /src/pdf/qpdfbookmarkmodel.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QPDFBOOKMARKMODEL_H 38 | #define QPDFBOOKMARKMODEL_H 39 | 40 | #include "qtpdfglobal.h" 41 | 42 | #include 43 | 44 | QT_BEGIN_NAMESPACE 45 | 46 | class QPdfDocument; 47 | class QPdfBookmarkModelPrivate; 48 | 49 | class Q_PDF_EXPORT QPdfBookmarkModel : public QAbstractItemModel 50 | { 51 | Q_OBJECT 52 | 53 | Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged) 54 | Q_PROPERTY(StructureMode structureMode READ structureMode WRITE setStructureMode NOTIFY structureModeChanged) 55 | 56 | public: 57 | enum StructureMode 58 | { 59 | TreeMode, 60 | ListMode 61 | }; 62 | Q_ENUM(StructureMode) 63 | 64 | enum Role 65 | { 66 | TitleRole = Qt::DisplayRole, 67 | LevelRole = Qt::UserRole, 68 | PageNumberRole 69 | }; 70 | Q_ENUM(Role) 71 | 72 | explicit QPdfBookmarkModel(QObject *parent = nullptr); 73 | 74 | QPdfDocument* document() const; 75 | void setDocument(QPdfDocument *document); 76 | 77 | StructureMode structureMode() const; 78 | void setStructureMode(StructureMode mode); 79 | 80 | QVariant data(const QModelIndex &index, int role) const override; 81 | QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; 82 | QModelIndex parent(const QModelIndex &index) const override; 83 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 84 | int columnCount(const QModelIndex &parent = QModelIndex()) const override; 85 | QHash roleNames() const override; 86 | 87 | Q_SIGNALS: 88 | void documentChanged(QPdfDocument *document); 89 | void structureModeChanged(QPdfBookmarkModel::StructureMode structureMode); 90 | 91 | private: 92 | Q_DECLARE_PRIVATE(QPdfBookmarkModel) 93 | 94 | Q_PRIVATE_SLOT(d_func(), void _q_documentStatusChanged()) 95 | }; 96 | 97 | QT_END_NAMESPACE 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /src/pdf/qpdfdocument.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "qpdfdocument.h" 38 | #include "qpdfdocument_p.h" 39 | 40 | #include "public/fpdf_doc.h" 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | QT_BEGIN_NAMESPACE 48 | 49 | // The library is not thread-safe at all, it has a lot of global variables. 50 | Q_GLOBAL_STATIC_WITH_ARGS(QMutex, pdfMutex, (QMutex::Recursive)); 51 | static int libraryRefCount; 52 | 53 | QPdfMutexLocker::QPdfMutexLocker() 54 | : QMutexLocker(pdfMutex()) 55 | { 56 | } 57 | 58 | QPdfDocumentPrivate::QPdfDocumentPrivate() 59 | : avail(nullptr) 60 | , doc(nullptr) 61 | , loadComplete(false) 62 | , status(QPdfDocument::Null) 63 | , lastError(QPdfDocument::NoError) 64 | , pageCount(0) 65 | { 66 | asyncBuffer.setData(QByteArray()); 67 | asyncBuffer.open(QIODevice::ReadWrite); 68 | 69 | const QPdfMutexLocker lock; 70 | 71 | if (libraryRefCount == 0) 72 | FPDF_InitLibrary(); 73 | ++libraryRefCount; 74 | 75 | // FPDF_FILEACCESS setup 76 | m_Param = this; 77 | m_GetBlock = fpdf_GetBlock; 78 | 79 | // FX_FILEAVAIL setup 80 | FX_FILEAVAIL::version = 1; 81 | IsDataAvail = fpdf_IsDataAvail; 82 | 83 | // FX_DOWNLOADHINTS setup 84 | FX_DOWNLOADHINTS::version = 1; 85 | AddSegment = fpdf_AddSegment; 86 | } 87 | 88 | QPdfDocumentPrivate::~QPdfDocumentPrivate() 89 | { 90 | q->close(); 91 | 92 | const QPdfMutexLocker lock; 93 | 94 | if (!--libraryRefCount) 95 | FPDF_DestroyLibrary(); 96 | } 97 | 98 | void QPdfDocumentPrivate::clear() 99 | { 100 | QPdfMutexLocker lock; 101 | 102 | if (doc) 103 | FPDF_CloseDocument(doc); 104 | doc = nullptr; 105 | 106 | if (avail) 107 | FPDFAvail_Destroy(avail); 108 | avail = nullptr; 109 | lock.unlock(); 110 | 111 | if (pageCount != 0) { 112 | pageCount = 0; 113 | emit q->pageCountChanged(pageCount); 114 | } 115 | 116 | loadComplete = false; 117 | 118 | asyncBuffer.close(); 119 | asyncBuffer.setData(QByteArray()); 120 | asyncBuffer.open(QIODevice::ReadWrite); 121 | 122 | if (sequentialSourceDevice) 123 | sequentialSourceDevice->disconnect(q); 124 | } 125 | 126 | void QPdfDocumentPrivate::updateLastError() 127 | { 128 | if (doc) { 129 | lastError = QPdfDocument::NoError; 130 | return; 131 | } 132 | 133 | QPdfMutexLocker lock; 134 | const unsigned long error = FPDF_GetLastError(); 135 | lock.unlock(); 136 | 137 | switch (error) { 138 | case FPDF_ERR_SUCCESS: lastError = QPdfDocument::NoError; break; 139 | case FPDF_ERR_UNKNOWN: lastError = QPdfDocument::UnknownError; break; 140 | case FPDF_ERR_FILE: lastError = QPdfDocument::FileNotFoundError; break; 141 | case FPDF_ERR_FORMAT: lastError = QPdfDocument::InvalidFileFormatError; break; 142 | case FPDF_ERR_PASSWORD: lastError = QPdfDocument::IncorrectPasswordError; break; 143 | case FPDF_ERR_SECURITY: lastError = QPdfDocument::UnsupportedSecuritySchemeError; break; 144 | default: 145 | Q_UNREACHABLE(); 146 | } 147 | } 148 | 149 | void QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnership) 150 | { 151 | if (transferDeviceOwnership) 152 | ownDevice.reset(newDevice); 153 | else 154 | ownDevice.reset(); 155 | 156 | if (newDevice->isSequential()) { 157 | sequentialSourceDevice = newDevice; 158 | device = &asyncBuffer; 159 | QNetworkReply *reply = qobject_cast(sequentialSourceDevice); 160 | 161 | if (!reply) { 162 | setStatus(QPdfDocument::Error); 163 | qWarning() << "QPdfDocument: Loading from sequential devices only supported with QNetworkAccessManager."; 164 | return; 165 | } 166 | 167 | if (reply->isFinished() && reply->error() != QNetworkReply::NoError) { 168 | setStatus(QPdfDocument::Error); 169 | return; 170 | } 171 | 172 | QObject::connect(reply, &QNetworkReply::finished, q, [this, reply](){ 173 | if (reply->error() != QNetworkReply::NoError || reply->bytesAvailable() == 0) { 174 | this->setStatus(QPdfDocument::Error); 175 | } 176 | }); 177 | 178 | if (reply->header(QNetworkRequest::ContentLengthHeader).isValid()) 179 | _q_tryLoadingWithSizeFromContentHeader(); 180 | else 181 | QObject::connect(reply, SIGNAL(metaDataChanged()), q, SLOT(_q_tryLoadingWithSizeFromContentHeader())); 182 | } else { 183 | device = newDevice; 184 | initiateAsyncLoadWithTotalSizeKnown(device->size()); 185 | checkComplete(); 186 | } 187 | } 188 | 189 | void QPdfDocumentPrivate::_q_tryLoadingWithSizeFromContentHeader() 190 | { 191 | if (avail) 192 | return; 193 | 194 | const QNetworkReply *networkReply = qobject_cast(sequentialSourceDevice); 195 | if (!networkReply) { 196 | setStatus(QPdfDocument::Error); 197 | return; 198 | } 199 | 200 | const QVariant contentLength = networkReply->header(QNetworkRequest::ContentLengthHeader); 201 | if (!contentLength.isValid()) { 202 | setStatus(QPdfDocument::Error); 203 | return; 204 | } 205 | 206 | QObject::connect(sequentialSourceDevice, SIGNAL(readyRead()), q, SLOT(_q_copyFromSequentialSourceDevice())); 207 | 208 | initiateAsyncLoadWithTotalSizeKnown(contentLength.toULongLong()); 209 | 210 | if (sequentialSourceDevice->bytesAvailable()) 211 | _q_copyFromSequentialSourceDevice(); 212 | } 213 | 214 | void QPdfDocumentPrivate::initiateAsyncLoadWithTotalSizeKnown(quint64 totalSize) 215 | { 216 | // FPDF_FILEACCESS setup 217 | m_FileLen = totalSize; 218 | 219 | const QPdfMutexLocker lock; 220 | 221 | avail = FPDFAvail_Create(this, this); 222 | } 223 | 224 | void QPdfDocumentPrivate::_q_copyFromSequentialSourceDevice() 225 | { 226 | if (loadComplete) 227 | return; 228 | 229 | const QByteArray data = sequentialSourceDevice->read(sequentialSourceDevice->bytesAvailable()); 230 | if (data.isEmpty()) 231 | return; 232 | 233 | asyncBuffer.seek(asyncBuffer.size()); 234 | asyncBuffer.write(data); 235 | 236 | checkComplete(); 237 | } 238 | 239 | void QPdfDocumentPrivate::tryLoadDocument() 240 | { 241 | QPdfMutexLocker lock; 242 | 243 | if (!FPDFAvail_IsDocAvail(avail, this)) 244 | return; 245 | 246 | Q_ASSERT(!doc); 247 | 248 | doc = FPDFAvail_GetDocument(avail, password); 249 | lock.unlock(); 250 | 251 | updateLastError(); 252 | 253 | if (lastError == QPdfDocument::IncorrectPasswordError) { 254 | FPDF_CloseDocument(doc); 255 | doc = nullptr; 256 | 257 | setStatus(QPdfDocument::Error); 258 | emit q->passwordRequired(); 259 | } 260 | } 261 | 262 | void QPdfDocumentPrivate::checkComplete() 263 | { 264 | if (!avail || loadComplete) 265 | return; 266 | 267 | if (!doc) 268 | tryLoadDocument(); 269 | 270 | if (!doc) 271 | return; 272 | 273 | loadComplete = true; 274 | 275 | QPdfMutexLocker lock; 276 | 277 | const int newPageCount = FPDF_GetPageCount(doc); 278 | for (int i = 0; i < newPageCount; ++i) { 279 | int result = PDF_DATA_NOTAVAIL; 280 | while (result == PDF_DATA_NOTAVAIL) { 281 | result = FPDFAvail_IsPageAvail(avail, i, this); 282 | } 283 | 284 | if (result == PDF_DATA_ERROR) 285 | loadComplete = false; 286 | } 287 | 288 | lock.unlock(); 289 | 290 | if (loadComplete) { 291 | if (newPageCount != pageCount) { 292 | pageCount = newPageCount; 293 | emit q->pageCountChanged(pageCount); 294 | } 295 | 296 | setStatus(QPdfDocument::Ready); 297 | } 298 | } 299 | 300 | void QPdfDocumentPrivate::setStatus(QPdfDocument::Status documentStatus) 301 | { 302 | if (status == documentStatus) 303 | return; 304 | 305 | status = documentStatus; 306 | emit q->statusChanged(status); 307 | } 308 | 309 | FPDF_BOOL QPdfDocumentPrivate::fpdf_IsDataAvail(_FX_FILEAVAIL *pThis, size_t offset, size_t size) 310 | { 311 | QPdfDocumentPrivate *d = static_cast(pThis); 312 | return offset + size <= static_cast(d->device->size()); 313 | } 314 | 315 | int QPdfDocumentPrivate::fpdf_GetBlock(void *param, unsigned long position, unsigned char *pBuf, unsigned long size) 316 | { 317 | QPdfDocumentPrivate *d = static_cast(reinterpret_cast(param)); 318 | d->device->seek(position); 319 | return qMax(qint64(0), d->device->read(reinterpret_cast(pBuf), size)); 320 | 321 | } 322 | 323 | void QPdfDocumentPrivate::fpdf_AddSegment(_FX_DOWNLOADHINTS *pThis, size_t offset, size_t size) 324 | { 325 | Q_UNUSED(pThis); 326 | Q_UNUSED(offset); 327 | Q_UNUSED(size); 328 | } 329 | 330 | /*! 331 | \class QPdfDocument 332 | \since 5.10 333 | \inmodule QtPdf 334 | 335 | \brief The QPdfDocument class loads a PDF document and renders pages from it. 336 | */ 337 | 338 | /*! 339 | Constructs a new document with parent object \a parent. 340 | */ 341 | QPdfDocument::QPdfDocument(QObject *parent) 342 | : QObject(parent) 343 | , d(new QPdfDocumentPrivate) 344 | { 345 | d->q = this; 346 | } 347 | 348 | /*! 349 | Destroys the document. 350 | */ 351 | QPdfDocument::~QPdfDocument() 352 | { 353 | } 354 | 355 | QPdfDocument::DocumentError QPdfDocument::load(const QString &fileName) 356 | { 357 | close(); 358 | 359 | d->setStatus(QPdfDocument::Loading); 360 | 361 | QScopedPointer f(new QFile(fileName)); 362 | if (!f->open(QIODevice::ReadOnly)) { 363 | d->lastError = FileNotFoundError; 364 | d->setStatus(QPdfDocument::Error); 365 | } else { 366 | d->load(f.take(), /*transfer ownership*/true); 367 | } 368 | return d->lastError; 369 | } 370 | 371 | /*! 372 | \enum QPdfDocument::Status 373 | 374 | This enum describes the current status of the document. 375 | 376 | \value Null The initial status after the document has been created or after it has been closed. 377 | \value Loading The status after load() has been called and before the document is fully loaded. 378 | \value Ready The status when the document is fully loaded and its data can be accessed. 379 | \value Unloading The status after close() has been called on an open document. 380 | At this point the document is still valid and all its data can be accessed. 381 | \value Error The status after Loading, if loading has failed. 382 | 383 | \sa QPdfDocument::status() 384 | */ 385 | 386 | /*! 387 | Returns the current status of the document. 388 | */ 389 | QPdfDocument::Status QPdfDocument::status() const 390 | { 391 | return d->status; 392 | } 393 | 394 | void QPdfDocument::load(QIODevice *device) 395 | { 396 | close(); 397 | 398 | d->setStatus(QPdfDocument::Loading); 399 | 400 | d->load(device, /*transfer ownership*/false); 401 | } 402 | 403 | void QPdfDocument::setPassword(const QString &password) 404 | { 405 | const QByteArray newPassword = password.toUtf8(); 406 | 407 | if (d->password == newPassword) 408 | return; 409 | 410 | d->password = newPassword; 411 | emit passwordChanged(); 412 | } 413 | 414 | QString QPdfDocument::password() const 415 | { 416 | return QString::fromUtf8(d->password); 417 | } 418 | 419 | /*! 420 | \enum QPdfDocument::MetaDataField 421 | 422 | This enum describes the available fields of meta data. 423 | 424 | \value Title The document's title as QString. 425 | \value Author The name of the person who created the document as QString. 426 | \value Subject The subject of the document as QString. 427 | \value Keywords Keywords associated with the document as QString. 428 | \value Creator If the document was converted to PDF from another format, 429 | the name of the conforming product that created the original document 430 | from which it was converted as QString. 431 | \value Producer If the document was converted to PDF from another format, 432 | the name of the conforming product that converted it to PDF as QString. 433 | \value CreationDate The date and time the document was created as QDateTime. 434 | \value ModificationDate The date and time the document was most recently modified as QDateTime. 435 | 436 | \sa QPdfDocument::metaData() 437 | */ 438 | 439 | /*! 440 | Returns the meta data of the document for the given \a field. 441 | */ 442 | QVariant QPdfDocument::metaData(MetaDataField field) const 443 | { 444 | if (!d->doc) 445 | return QString(); 446 | 447 | QByteArray fieldName; 448 | switch (field) { 449 | case Title: 450 | fieldName = "Title"; 451 | break; 452 | case Subject: 453 | fieldName = "Subject"; 454 | break; 455 | case Author: 456 | fieldName = "Author"; 457 | break; 458 | case Keywords: 459 | fieldName = "Keywords"; 460 | break; 461 | case Producer: 462 | fieldName = "Producer"; 463 | break; 464 | case Creator: 465 | fieldName = "Creator"; 466 | break; 467 | case CreationDate: 468 | fieldName = "CreationDate"; 469 | break; 470 | case ModificationDate: 471 | fieldName = "ModDate"; 472 | break; 473 | } 474 | 475 | QPdfMutexLocker lock; 476 | const unsigned long len = FPDF_GetMetaText(d->doc, fieldName.constData(), nullptr, 0); 477 | 478 | QVector buf(len); 479 | FPDF_GetMetaText(d->doc, fieldName.constData(), buf.data(), buf.length()); 480 | lock.unlock(); 481 | 482 | QString text = QString::fromUtf16(buf.data()); 483 | 484 | switch (field) { 485 | case Title: // fall through 486 | case Subject: 487 | case Author: 488 | case Keywords: 489 | case Producer: 490 | case Creator: 491 | return text; 492 | case CreationDate: // fall through 493 | case ModificationDate: 494 | // convert a "D:YYYYMMDDHHmmSSOHH'mm'" into "YYYY-MM-DDTHH:mm:ss+HH:mm" 495 | if (text.startsWith(QLatin1String("D:"))) 496 | text = text.mid(2); 497 | text.insert(4, QLatin1Char('-')); 498 | text.insert(7, QLatin1Char('-')); 499 | text.insert(10, QLatin1Char('T')); 500 | text.insert(13, QLatin1Char(':')); 501 | text.insert(16, QLatin1Char(':')); 502 | text.replace(QLatin1Char('\''), QLatin1Char(':')); 503 | if (text.endsWith(QLatin1Char(':'))) 504 | text.chop(1); 505 | 506 | return QDateTime::fromString(text, Qt::ISODate); 507 | } 508 | 509 | return QVariant(); 510 | } 511 | 512 | QPdfDocument::DocumentError QPdfDocument::error() const 513 | { 514 | return d->lastError; 515 | } 516 | 517 | /*! 518 | Closes the document. 519 | */ 520 | void QPdfDocument::close() 521 | { 522 | if (!d->doc) 523 | return; 524 | 525 | d->setStatus(Unloading); 526 | 527 | d->clear(); 528 | 529 | if (!d->password.isEmpty()) { 530 | d->password.clear(); 531 | emit passwordChanged(); 532 | } 533 | 534 | d->setStatus(Null); 535 | } 536 | 537 | /*! 538 | Returns the amount of pages for the loaded document or \c 0 if 539 | no document is loaded. 540 | */ 541 | int QPdfDocument::pageCount() const 542 | { 543 | return d->pageCount; 544 | } 545 | 546 | QSizeF QPdfDocument::pageSize(int page) const 547 | { 548 | QSizeF result; 549 | if (!d->doc) 550 | return result; 551 | 552 | const QPdfMutexLocker lock; 553 | 554 | FPDF_GetPageSizeByIndex(d->doc, page, &result.rwidth(), &result.rheight()); 555 | return result; 556 | } 557 | 558 | /*! 559 | Renders the \a page into a QImage of size \a imageSize according to the 560 | provided \a renderOptions. 561 | 562 | Returns the rendered page or an empty image in case of an error. 563 | 564 | Note: If the \a imageSize does not match the aspect ratio of the page in the 565 | PDF document, the page is rendered scaled, so that it covers the 566 | complete \a imageSize. 567 | */ 568 | QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions renderOptions) 569 | { 570 | if (!d->doc) 571 | return QImage(); 572 | 573 | const QPdfMutexLocker lock; 574 | 575 | FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page); 576 | if (!pdfPage) 577 | return QImage(); 578 | 579 | QImage result(imageSize, QImage::Format_ARGB32); 580 | result.fill(Qt::transparent); 581 | FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(result.width(), result.height(), FPDFBitmap_BGRA, result.bits(), result.bytesPerLine()); 582 | 583 | int rotation = 0; 584 | switch (renderOptions.rotation()) { 585 | case QPdf::Rotate0: 586 | rotation = 0; 587 | break; 588 | case QPdf::Rotate90: 589 | rotation = 1; 590 | break; 591 | case QPdf::Rotate180: 592 | rotation = 2; 593 | break; 594 | case QPdf::Rotate270: 595 | rotation = 3; 596 | break; 597 | } 598 | 599 | const QPdf::RenderFlags renderFlags = renderOptions.renderFlags(); 600 | int flags = 0; 601 | if (renderFlags & QPdf::RenderAnnotations) 602 | flags |= FPDF_ANNOT; 603 | if (renderFlags & QPdf::RenderOptimizedForLcd) 604 | flags |= FPDF_LCD_TEXT; 605 | if (renderFlags & QPdf::RenderGrayscale) 606 | flags |= FPDF_GRAYSCALE; 607 | if (renderFlags & QPdf::RenderForceHalftone) 608 | flags |= FPDF_RENDER_FORCEHALFTONE; 609 | if (renderFlags & QPdf::RenderTextAliased) 610 | flags |= FPDF_RENDER_NO_SMOOTHTEXT; 611 | if (renderFlags & QPdf::RenderImageAliased) 612 | flags |= FPDF_RENDER_NO_SMOOTHIMAGE; 613 | if (renderFlags & QPdf::RenderPathAliased) 614 | flags |= FPDF_RENDER_NO_SMOOTHPATH; 615 | 616 | FPDF_RenderPageBitmap(bitmap, pdfPage, 0, 0, result.width(), result.height(), rotation, flags); 617 | 618 | FPDFBitmap_Destroy(bitmap); 619 | 620 | FPDF_ClosePage(pdfPage); 621 | 622 | return result; 623 | } 624 | 625 | QT_END_NAMESPACE 626 | 627 | #include "moc_qpdfdocument.cpp" 628 | -------------------------------------------------------------------------------- /src/pdf/qpdfdocument.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QPDFDOCUMENT_H 38 | #define QPDFDOCUMENT_H 39 | 40 | #include "qtpdfglobal.h" 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | QT_BEGIN_NAMESPACE 47 | 48 | class QPdfDocumentPrivate; 49 | class QNetworkReply; 50 | 51 | class Q_PDF_EXPORT QPdfDocument : public QObject 52 | { 53 | Q_OBJECT 54 | 55 | Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged FINAL) 56 | Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged FINAL) 57 | Q_PROPERTY(Status status READ status NOTIFY statusChanged FINAL) 58 | 59 | public: 60 | enum Status { 61 | Null, 62 | Loading, 63 | Ready, 64 | Unloading, 65 | Error 66 | }; 67 | Q_ENUM(Status) 68 | 69 | enum DocumentError { 70 | NoError, 71 | UnknownError, 72 | FileNotFoundError, 73 | InvalidFileFormatError, 74 | IncorrectPasswordError, 75 | UnsupportedSecuritySchemeError 76 | }; 77 | Q_ENUM(DocumentError) 78 | 79 | enum MetaDataField { 80 | Title, 81 | Subject, 82 | Author, 83 | Keywords, 84 | Producer, 85 | Creator, 86 | CreationDate, 87 | ModificationDate 88 | }; 89 | Q_ENUM(MetaDataField) 90 | 91 | explicit QPdfDocument(QObject *parent = nullptr); 92 | ~QPdfDocument(); 93 | 94 | DocumentError load(const QString &fileName); 95 | 96 | Status status() const; 97 | 98 | void load(QIODevice *device); 99 | void setPassword(const QString &password); 100 | QString password() const; 101 | 102 | QVariant metaData(MetaDataField field) const; 103 | 104 | DocumentError error() const; 105 | 106 | void close(); 107 | 108 | int pageCount() const; 109 | 110 | QSizeF pageSize(int page) const; 111 | 112 | QImage render(int page, QSize imageSize, QPdfDocumentRenderOptions options = QPdfDocumentRenderOptions()); 113 | 114 | Q_SIGNALS: 115 | void passwordChanged(); 116 | void passwordRequired(); 117 | void statusChanged(QPdfDocument::Status status); 118 | void pageCountChanged(int pageCount); 119 | 120 | private: 121 | friend class QPdfBookmarkModelPrivate; 122 | 123 | Q_PRIVATE_SLOT(d, void _q_tryLoadingWithSizeFromContentHeader()) 124 | Q_PRIVATE_SLOT(d, void _q_copyFromSequentialSourceDevice()) 125 | QScopedPointer d; 126 | }; 127 | 128 | QT_END_NAMESPACE 129 | 130 | #endif // QPDFDOCUMENT_H 131 | -------------------------------------------------------------------------------- /src/pdf/qpdfdocument_p.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QPDFDOCUMENT_P_H 38 | #define QPDFDOCUMENT_P_H 39 | 40 | #include "qpdfdocument.h" 41 | 42 | #include "public/fpdfview.h" 43 | #include "public/fpdf_dataavail.h" 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | QT_BEGIN_NAMESPACE 51 | 52 | class QPdfMutexLocker : public QMutexLocker 53 | { 54 | public: 55 | QPdfMutexLocker(); 56 | }; 57 | 58 | class QPdfDocumentPrivate: public FPDF_FILEACCESS, public FX_FILEAVAIL, public FX_DOWNLOADHINTS 59 | { 60 | public: 61 | QPdfDocumentPrivate(); 62 | ~QPdfDocumentPrivate(); 63 | 64 | QPdfDocument *q; 65 | 66 | FPDF_AVAIL avail; 67 | FPDF_DOCUMENT doc; 68 | bool loadComplete; 69 | 70 | QPointer device; 71 | QScopedPointer ownDevice; 72 | QBuffer asyncBuffer; 73 | QPointer sequentialSourceDevice; 74 | QByteArray password; 75 | 76 | QPdfDocument::Status status; 77 | QPdfDocument::DocumentError lastError; 78 | int pageCount; 79 | 80 | void clear(); 81 | 82 | void load(QIODevice *device, bool ownDevice); 83 | void loadAsync(QIODevice *device); 84 | 85 | void _q_tryLoadingWithSizeFromContentHeader(); 86 | void initiateAsyncLoadWithTotalSizeKnown(quint64 totalSize); 87 | void _q_copyFromSequentialSourceDevice(); 88 | void tryLoadDocument(); 89 | void checkComplete(); 90 | void setStatus(QPdfDocument::Status status); 91 | 92 | static FPDF_BOOL fpdf_IsDataAvail(struct _FX_FILEAVAIL* pThis, size_t offset, size_t size); 93 | static int fpdf_GetBlock(void* param, unsigned long position, unsigned char* pBuf, unsigned long size); 94 | static void fpdf_AddSegment(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size); 95 | void updateLastError(); 96 | }; 97 | 98 | QT_END_NAMESPACE 99 | 100 | #endif // QPDFDOCUMENT_P_H 101 | -------------------------------------------------------------------------------- /src/pdf/qpdfdocumentrenderoptions.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QPDFDOCUMENTRENDEROPTIONS_H 38 | #define QPDFDOCUMENTRENDEROPTIONS_H 39 | 40 | #include "qpdfnamespace.h" 41 | 42 | #include 43 | 44 | QT_BEGIN_NAMESPACE 45 | 46 | class QPdfDocumentRenderOptions 47 | { 48 | public: 49 | Q_DECL_CONSTEXPR QPdfDocumentRenderOptions() Q_DECL_NOTHROW : data(0) {} 50 | 51 | Q_DECL_CONSTEXPR QPdf::Rotation rotation() const Q_DECL_NOTHROW { return static_cast(bits.rotation); } 52 | Q_DECL_RELAXED_CONSTEXPR void setRotation(QPdf::Rotation _rotation) Q_DECL_NOTHROW { bits.rotation = _rotation; } 53 | 54 | Q_DECL_CONSTEXPR QPdf::RenderFlags renderFlags() const Q_DECL_NOTHROW { return static_cast(bits.renderFlags); } 55 | Q_DECL_RELAXED_CONSTEXPR void setRenderFlags(QPdf::RenderFlags _renderFlags) Q_DECL_NOTHROW { bits.renderFlags = _renderFlags; } 56 | 57 | private: 58 | friend Q_DECL_CONSTEXPR inline bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) Q_DECL_NOTHROW; 59 | 60 | 61 | struct Bits { 62 | quint32 renderFlags : 8; 63 | quint32 rotation : 3; 64 | quint32 reserved : 21; 65 | quint32 reserved2 : 32; 66 | }; 67 | 68 | union { 69 | Bits bits; 70 | quint64 data; 71 | }; 72 | }; 73 | 74 | Q_DECLARE_TYPEINFO(QPdfDocumentRenderOptions, Q_PRIMITIVE_TYPE); 75 | 76 | Q_DECL_CONSTEXPR inline bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) Q_DECL_NOTHROW 77 | { 78 | return lhs.data == rhs.data; 79 | } 80 | 81 | Q_DECL_CONSTEXPR inline bool operator!=(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) Q_DECL_NOTHROW 82 | { 83 | return !operator==(lhs, rhs); 84 | } 85 | 86 | QT_END_NAMESPACE 87 | 88 | Q_DECLARE_METATYPE(QPdfDocumentRenderOptions) 89 | 90 | #endif // QPDFDOCUMENTRENDEROPTIONS_H 91 | -------------------------------------------------------------------------------- /src/pdf/qpdfdocumentrenderoptions.qdoc: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "qpdfdocumentrenderoptions.h" 38 | 39 | QT_BEGIN_NAMESPACE 40 | 41 | /*! 42 | \class QPdfDocumentRenderOptions 43 | \since 5.10 44 | \inmodule QtPdf 45 | 46 | \brief The QPdfDocumentRenderOptions class holds the options to render a page from a PDF document. 47 | 48 | \sa QPdfDocument 49 | */ 50 | 51 | /*! 52 | \fn QPdfDocumentRenderOptions::QPdfDocumentRenderOptions() 53 | 54 | Constructs a QPdfDocumentRenderOptions object. 55 | */ 56 | 57 | /*! 58 | \fn QPdf::Rotation QPdfDocumentRenderOptions::rotation() const 59 | 60 | Returns the rotation used for rendering a page from a PDF document. 61 | 62 | \sa setRotation() 63 | */ 64 | 65 | /*! 66 | \fn void QPdfDocumentRenderOptions::setRotation(QPdf::Rotation rotation) 67 | 68 | Sets the \a rotation used for rendering a page from a PDF document. 69 | 70 | \sa rotation() 71 | */ 72 | 73 | /*! 74 | \fn QPdf::RenderFlags QPdfDocumentRenderOptions::renderFlags() const 75 | 76 | Returns the special flags used for rendering a page from a PDF document. 77 | 78 | \sa setRenderFlags() 79 | */ 80 | 81 | /*! 82 | \fn void QPdfDocumentRenderOptions::setRenderFlags(QPdf::RenderFlags flags) 83 | 84 | Sets the special \a flags used for rendering a page from a PDF document. 85 | 86 | \sa renderFlags() 87 | */ 88 | 89 | /*! 90 | \fn bool operator!=(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) 91 | \relates QPdfDocumentRenderOptions 92 | 93 | Returns \c true if the options \a lhs and \a rhs are different, otherwise 94 | returns \c false. 95 | */ 96 | 97 | /*! 98 | \fn bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) 99 | \relates QPdfDocumentRenderOptions 100 | 101 | Returns \c true if the options \a lhs and \a rhs are equal, 102 | otherwise returns \c false. 103 | */ 104 | 105 | QT_END_NAMESPACE 106 | -------------------------------------------------------------------------------- /src/pdf/qpdfnamespace.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QPDFNAMESPACE_H 38 | #define QPDFNAMESPACE_H 39 | 40 | #include 41 | 42 | namespace QPdf { 43 | Q_NAMESPACE 44 | 45 | enum Rotation { 46 | Rotate0, 47 | Rotate90, 48 | Rotate180, 49 | Rotate270 50 | }; 51 | Q_ENUM_NS(Rotation) 52 | 53 | enum RenderFlag { 54 | NoRenderFlags = 0x000, 55 | RenderAnnotations = 0x001, 56 | RenderOptimizedForLcd = 0x002, 57 | RenderGrayscale = 0x004, 58 | RenderForceHalftone = 0x008, 59 | RenderTextAliased = 0x010, 60 | RenderImageAliased = 0x020, 61 | RenderPathAliased = 0x040 62 | }; 63 | Q_FLAG_NS(RenderFlag) 64 | Q_DECLARE_FLAGS(RenderFlags, RenderFlag) 65 | } 66 | 67 | Q_DECLARE_OPERATORS_FOR_FLAGS(QPdf::RenderFlags) 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/pdf/qpdfnamespace.qdoc: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | /*! 38 | \namespace QPdf 39 | \inmodule QtPdf 40 | \keyword QPdf Namespace 41 | 42 | \brief The QPdf namespace contains miscellaneous identifiers 43 | used throughout the QtPdf module. 44 | */ 45 | 46 | /*! 47 | \enum QPdf::Rotation 48 | 49 | This enum describes the rotation of the page for rendering. 50 | 51 | \value Rotate0 Do not rotate (the default) 52 | \value Rotate90 Rotate 90 degrees clockwise 53 | \value Rotate180 Rotate 180 degrees 54 | \value Rotate270 Rotate 270 degrees clockwise 55 | 56 | \sa QPdfDocument::render() 57 | */ 58 | /*! 59 | \enum QPdf::RenderFlag 60 | 61 | This enum is used to describe how a page should be rendered. 62 | 63 | \value NoRenderFlags The default value, representing no flags. 64 | \value RenderAnnotations The page is rendered with annotations. 65 | \value RenderOptimizedForLcd The text of the page is rendered optimized for LCD display. 66 | \value RenderGrayscale The page is rendered grayscale. 67 | \value RenderForceHalftone Always use halftones for rendering if the output image is stretched. 68 | \value RenderTextAliased Anti-aliasing is disabled for rendering text. 69 | \value RenderImageAliased Anti-aliasing is disabled for rendering images. 70 | \value RenderPathAliased Anti-aliasing is disabled for rendering paths. 71 | 72 | \sa QPdfDocument::render() 73 | */ 74 | 75 | -------------------------------------------------------------------------------- /src/pdf/qpdfpagenavigation.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "qpdfpagenavigation.h" 38 | 39 | #include "qpdfdocument.h" 40 | 41 | #include 42 | 43 | #include 44 | 45 | QT_BEGIN_NAMESPACE 46 | 47 | class QPdfPageNavigationPrivate : public QObjectPrivate 48 | { 49 | public: 50 | QPdfPageNavigationPrivate() 51 | : QObjectPrivate() 52 | { 53 | } 54 | 55 | void update() 56 | { 57 | Q_Q(QPdfPageNavigation); 58 | 59 | const bool documentAvailable = m_document && m_document->status() == QPdfDocument::Ready; 60 | 61 | if (documentAvailable) { 62 | const int newPageCount = m_document->pageCount(); 63 | if (m_pageCount != newPageCount) { 64 | m_pageCount = newPageCount; 65 | emit q->pageCountChanged(m_pageCount); 66 | } 67 | } else { 68 | if (m_pageCount != 0) { 69 | m_pageCount = 0; 70 | emit q->pageCountChanged(m_pageCount); 71 | } 72 | } 73 | 74 | if (m_currentPage != 0) { 75 | m_currentPage = 0; 76 | emit q->currentPageChanged(m_currentPage); 77 | } 78 | 79 | updatePrevNext(); 80 | } 81 | 82 | void updatePrevNext() 83 | { 84 | Q_Q(QPdfPageNavigation); 85 | 86 | const bool hasPreviousPage = m_currentPage > 0; 87 | const bool hasNextPage = m_currentPage < (m_pageCount - 1); 88 | 89 | if (m_canGoToPreviousPage != hasPreviousPage) { 90 | m_canGoToPreviousPage = hasPreviousPage; 91 | emit q->canGoToPreviousPageChanged(m_canGoToPreviousPage); 92 | } 93 | 94 | if (m_canGoToNextPage != hasNextPage) { 95 | m_canGoToNextPage = hasNextPage; 96 | emit q->canGoToNextPageChanged(m_canGoToNextPage); 97 | } 98 | } 99 | 100 | void documentStatusChanged() 101 | { 102 | update(); 103 | } 104 | 105 | Q_DECLARE_PUBLIC(QPdfPageNavigation) 106 | 107 | QPointer m_document = nullptr; 108 | int m_currentPage = 0; 109 | int m_pageCount = 0; 110 | bool m_canGoToPreviousPage = false; 111 | bool m_canGoToNextPage = false; 112 | 113 | QMetaObject::Connection m_documentStatusChangedConnection; 114 | }; 115 | 116 | /*! 117 | \class QPdfPageNavigation 118 | \since 5.10 119 | \inmodule QtPdf 120 | 121 | \brief The QPdfPageNavigation class handles the navigation through a PDF document. 122 | 123 | \sa QPdfDocument 124 | */ 125 | 126 | 127 | /*! 128 | Constructs a page navigation object with parent object \a parent. 129 | */ 130 | QPdfPageNavigation::QPdfPageNavigation(QObject *parent) 131 | : QObject(*new QPdfPageNavigationPrivate, parent) 132 | { 133 | } 134 | 135 | /*! 136 | Destroys the page navigation object. 137 | */ 138 | QPdfPageNavigation::~QPdfPageNavigation() 139 | { 140 | } 141 | 142 | /*! 143 | \property QPdfPageNavigation::document 144 | \brief the document instance on which this object navigates 145 | 146 | By default, this property is \c nullptr. 147 | 148 | \sa document(), setDocument(), QPdfDocument 149 | */ 150 | 151 | /*! 152 | Returns the document on which this object navigates, or a \c nullptr 153 | if none has set before. 154 | 155 | \sa QPdfDocument 156 | */ 157 | QPdfDocument* QPdfPageNavigation::document() const 158 | { 159 | Q_D(const QPdfPageNavigation); 160 | 161 | return d->m_document; 162 | } 163 | 164 | /*! 165 | Sets the \a document this object navigates on. 166 | 167 | After a new document has been set, the currentPage will be \c 0. 168 | 169 | \sa QPdfDocument 170 | */ 171 | void QPdfPageNavigation::setDocument(QPdfDocument *document) 172 | { 173 | Q_D(QPdfPageNavigation); 174 | 175 | if (d->m_document == document) 176 | return; 177 | 178 | if (d->m_document) 179 | disconnect(d->m_documentStatusChangedConnection); 180 | 181 | d->m_document = document; 182 | emit documentChanged(d->m_document); 183 | 184 | if (d->m_document) 185 | d->m_documentStatusChangedConnection = connect(d->m_document.data(), &QPdfDocument::statusChanged, this, [d](){ d->documentStatusChanged(); }); 186 | 187 | d->update(); 188 | } 189 | 190 | /*! 191 | \property QPdfPageNavigation::currentPage 192 | \brief the current page number in the document 193 | 194 | \sa currentPage(), setCurrentPage() 195 | */ 196 | 197 | /*! 198 | Returns the current page number or \c 0 if there is no document set. 199 | 200 | After a document has been loaded, the currentPage will always be \c 0. 201 | */ 202 | int QPdfPageNavigation::currentPage() const 203 | { 204 | Q_D(const QPdfPageNavigation); 205 | 206 | return d->m_currentPage; 207 | } 208 | 209 | /*! 210 | \fn void QPdfPageNavigation::setCurrentPage(int page) 211 | 212 | Sets the current \a page number. 213 | */ 214 | void QPdfPageNavigation::setCurrentPage(int newPage) 215 | { 216 | Q_D(QPdfPageNavigation); 217 | 218 | if (newPage < 0 || newPage >= d->m_pageCount) 219 | return; 220 | 221 | if (d->m_currentPage == newPage) 222 | return; 223 | 224 | d->m_currentPage = newPage; 225 | emit currentPageChanged(d->m_currentPage); 226 | 227 | d->updatePrevNext(); 228 | } 229 | 230 | /*! 231 | \property QPdfPageNavigation::pageCount 232 | \brief the number of pages in the document 233 | 234 | \sa pageCount() 235 | */ 236 | 237 | /*! 238 | Returns the number of pages in the document or \c 0 if there 239 | is no document set. 240 | */ 241 | int QPdfPageNavigation::pageCount() const 242 | { 243 | Q_D(const QPdfPageNavigation); 244 | 245 | return d->m_pageCount; 246 | } 247 | 248 | /*! 249 | \property QPdfPageNavigation::canGoToPreviousPage 250 | \brief whether there is a page before the current page 251 | 252 | \sa canGoToPreviousPage(), goToPreviousPage() 253 | */ 254 | 255 | /*! 256 | Returns whether there is a page before the current one. 257 | */ 258 | bool QPdfPageNavigation::canGoToPreviousPage() const 259 | { 260 | Q_D(const QPdfPageNavigation); 261 | 262 | return d->m_canGoToPreviousPage; 263 | } 264 | 265 | /*! 266 | \property QPdfPageNavigation::canGoToNextPage 267 | \brief whether there is a page after the current page 268 | 269 | \sa canGoToNextPage(), goToNextPage() 270 | */ 271 | 272 | /*! 273 | Returns whether there is a page after the current one. 274 | */ 275 | bool QPdfPageNavigation::canGoToNextPage() const 276 | { 277 | Q_D(const QPdfPageNavigation); 278 | 279 | return d->m_canGoToNextPage; 280 | } 281 | 282 | /*! 283 | Changes the current page to the previous page. 284 | 285 | If there is no previous page in the document, nothing happens. 286 | 287 | \sa canGoToPreviousPage 288 | */ 289 | void QPdfPageNavigation::goToPreviousPage() 290 | { 291 | Q_D(QPdfPageNavigation); 292 | 293 | if (d->m_currentPage > 0) 294 | setCurrentPage(d->m_currentPage - 1); 295 | } 296 | 297 | /*! 298 | Changes the current page to the next page. 299 | 300 | If there is no next page in the document, nothing happens. 301 | 302 | \sa canGoToNextPage 303 | */ 304 | void QPdfPageNavigation::goToNextPage() 305 | { 306 | Q_D(QPdfPageNavigation); 307 | 308 | if (d->m_currentPage < d->m_pageCount - 1) 309 | setCurrentPage(d->m_currentPage + 1); 310 | } 311 | 312 | QT_END_NAMESPACE 313 | 314 | #include "moc_qpdfpagenavigation.cpp" 315 | -------------------------------------------------------------------------------- /src/pdf/qpdfpagenavigation.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QPDFPAGENAVIGATION_H 38 | #define QPDFPAGENAVIGATION_H 39 | 40 | #include "qtpdfglobal.h" 41 | 42 | #include 43 | 44 | QT_BEGIN_NAMESPACE 45 | 46 | class QPdfDocument; 47 | class QPdfPageNavigationPrivate; 48 | 49 | class Q_PDF_EXPORT QPdfPageNavigation : public QObject 50 | { 51 | Q_OBJECT 52 | 53 | Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged) 54 | 55 | Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged) 56 | Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged) 57 | Q_PROPERTY(bool canGoToPreviousPage READ canGoToPreviousPage NOTIFY canGoToPreviousPageChanged) 58 | Q_PROPERTY(bool canGoToNextPage READ canGoToNextPage NOTIFY canGoToNextPageChanged) 59 | 60 | public: 61 | explicit QPdfPageNavigation(QObject *parent = nullptr); 62 | ~QPdfPageNavigation(); 63 | 64 | QPdfDocument* document() const; 65 | void setDocument(QPdfDocument *document); 66 | 67 | int currentPage() const; 68 | void setCurrentPage(int currentPage); 69 | 70 | int pageCount() const; 71 | 72 | bool canGoToPreviousPage() const; 73 | bool canGoToNextPage() const; 74 | 75 | public Q_SLOTS: 76 | void goToPreviousPage(); 77 | void goToNextPage(); 78 | 79 | Q_SIGNALS: 80 | void documentChanged(QPdfDocument *document); 81 | void currentPageChanged(int currentPage); 82 | void pageCountChanged(int pageCount); 83 | void canGoToPreviousPageChanged(bool canGo); 84 | void canGoToNextPageChanged(bool canGo); 85 | 86 | private: 87 | Q_DECLARE_PRIVATE(QPdfPageNavigation) 88 | }; 89 | 90 | QT_END_NAMESPACE 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /src/pdf/qpdfpagerenderer.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "qpdfpagerenderer.h" 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | QT_BEGIN_NAMESPACE 46 | 47 | class RenderWorker : public QObject 48 | { 49 | Q_OBJECT 50 | 51 | public: 52 | RenderWorker(); 53 | ~RenderWorker(); 54 | 55 | void setDocument(QPdfDocument *document); 56 | 57 | public Q_SLOTS: 58 | void requestPage(quint64 requestId, int page, QSize imageSize, 59 | QPdfDocumentRenderOptions options); 60 | 61 | Q_SIGNALS: 62 | void pageRendered(int page, QSize imageSize, const QImage &image, 63 | QPdfDocumentRenderOptions options, quint64 requestId); 64 | 65 | private: 66 | QPointer m_document; 67 | QMutex m_mutex; 68 | }; 69 | 70 | class QPdfPageRendererPrivate : public QObjectPrivate 71 | { 72 | Q_DECLARE_PUBLIC(QPdfPageRenderer) 73 | 74 | public: 75 | QPdfPageRendererPrivate(); 76 | ~QPdfPageRendererPrivate(); 77 | 78 | void handleNextRequest(); 79 | void requestFinished(int page, QSize imageSize, const QImage &image, 80 | QPdfDocumentRenderOptions options, quint64 requestId); 81 | 82 | QPdfPageRenderer::RenderMode m_renderMode = QPdfPageRenderer::SingleThreadedRenderMode; 83 | QPointer m_document; 84 | 85 | struct PageRequest 86 | { 87 | quint64 id; 88 | int pageNumber; 89 | QSize imageSize; 90 | QPdfDocumentRenderOptions options; 91 | }; 92 | 93 | QVector m_requests; 94 | QVector m_pendingRequests; 95 | quint64 m_requestIdCounter = 1; 96 | 97 | QThread *m_renderThread = nullptr; 98 | QScopedPointer m_renderWorker; 99 | }; 100 | 101 | Q_DECLARE_TYPEINFO(QPdfPageRendererPrivate::PageRequest, Q_PRIMITIVE_TYPE); 102 | 103 | 104 | RenderWorker::RenderWorker() 105 | : m_document(nullptr) 106 | { 107 | } 108 | 109 | RenderWorker::~RenderWorker() 110 | { 111 | } 112 | 113 | void RenderWorker::setDocument(QPdfDocument *document) 114 | { 115 | const QMutexLocker locker(&m_mutex); 116 | 117 | if (m_document == document) 118 | return; 119 | 120 | m_document = document; 121 | } 122 | 123 | void RenderWorker::requestPage(quint64 requestId, int pageNumber, QSize imageSize, 124 | QPdfDocumentRenderOptions options) 125 | { 126 | const QMutexLocker locker(&m_mutex); 127 | 128 | if (!m_document || m_document->status() != QPdfDocument::Ready) 129 | return; 130 | 131 | const QImage image = m_document->render(pageNumber, imageSize, options); 132 | 133 | emit pageRendered(pageNumber, imageSize, image, options, requestId); 134 | } 135 | 136 | 137 | QPdfPageRendererPrivate::QPdfPageRendererPrivate() 138 | : QObjectPrivate() 139 | , m_renderWorker(new RenderWorker) 140 | { 141 | } 142 | 143 | QPdfPageRendererPrivate::~QPdfPageRendererPrivate() 144 | { 145 | if (m_renderThread) { 146 | m_renderThread->quit(); 147 | m_renderThread->wait(); 148 | } 149 | } 150 | 151 | void QPdfPageRendererPrivate::handleNextRequest() 152 | { 153 | if (m_requests.isEmpty()) 154 | return; 155 | 156 | const PageRequest request = m_requests.takeFirst(); 157 | m_pendingRequests.append(request); 158 | 159 | QMetaObject::invokeMethod(m_renderWorker.data(), "requestPage", Qt::QueuedConnection, 160 | Q_ARG(quint64, request.id), Q_ARG(int, request.pageNumber), 161 | Q_ARG(QSize, request.imageSize), Q_ARG(QPdfDocumentRenderOptions, 162 | request.options)); 163 | } 164 | 165 | void QPdfPageRendererPrivate::requestFinished(int page, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions options, quint64 requestId) 166 | { 167 | const auto it = std::find_if(m_pendingRequests.begin(), m_pendingRequests.end(), 168 | [page, imageSize, options](const PageRequest &request){ return request.pageNumber == page && request.imageSize == imageSize && request.options == options; }); 169 | 170 | if (it != m_pendingRequests.end()) 171 | m_pendingRequests.erase(it); 172 | } 173 | 174 | /*! 175 | \class QPdfPageRenderer 176 | \since 5.11 177 | \inmodule QtPdf 178 | 179 | \brief The QPdfPageRenderer class encapsulates the rendering of pages of a PDF document. 180 | 181 | The QPdfPageRenderer contains a queue that collects all render requests that are invoked through 182 | requestPage(). Depending on the configured RenderMode the QPdfPageRenderer processes this queue 183 | in the main UI thread on next event loop invocation (SingleThreadedRenderMode) or in a separate worker thread 184 | (MultiThreadedRenderMode) and emits the result through the pageRendered() signal for each request once 185 | the rendering is done. 186 | 187 | \sa QPdfDocument 188 | */ 189 | 190 | 191 | /*! 192 | Constructs a page renderer object with parent object \a parent. 193 | */ 194 | QPdfPageRenderer::QPdfPageRenderer(QObject *parent) 195 | : QObject(*new QPdfPageRendererPrivate(), parent) 196 | { 197 | Q_D(QPdfPageRenderer); 198 | 199 | qRegisterMetaType(); 200 | 201 | connect(d->m_renderWorker.data(), &RenderWorker::pageRendered, this, 202 | [this,d](int page, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions options, quint64 requestId) { 203 | d->requestFinished(page, imageSize, image, options, requestId); 204 | emit pageRendered(page, imageSize, image, options, requestId); 205 | d->handleNextRequest(); 206 | }); 207 | } 208 | 209 | /*! 210 | Destroys the page renderer object. 211 | */ 212 | QPdfPageRenderer::~QPdfPageRenderer() 213 | { 214 | } 215 | 216 | /*! 217 | \enum QPdfPageRenderer::RenderMode 218 | 219 | This enum describes how the pages are rendered. 220 | 221 | \value MultiThreadedRenderMode All pages are rendered in a separate worker thread. 222 | \value SingleThreadedRenderMode All pages are rendered in the main UI thread (default). 223 | 224 | \sa renderMode(), setRenderMode() 225 | */ 226 | 227 | /*! 228 | \property QPdfPageRenderer::renderMode 229 | \brief the mode the renderer renders the pages 230 | 231 | By default, this property is \c QPdfPageRenderer::SingleThreaded. 232 | 233 | \sa setRenderMode(), RenderMode 234 | */ 235 | 236 | /*! 237 | Returns the mode of how the pages are rendered. 238 | 239 | \sa RenderMode 240 | */ 241 | QPdfPageRenderer::RenderMode QPdfPageRenderer::renderMode() const 242 | { 243 | Q_D(const QPdfPageRenderer); 244 | 245 | return d->m_renderMode; 246 | } 247 | 248 | /*! 249 | Sets the mode of how the pages are rendered. 250 | 251 | \sa RenderMode 252 | */ 253 | void QPdfPageRenderer::setRenderMode(RenderMode mode) 254 | { 255 | Q_D(QPdfPageRenderer); 256 | 257 | if (d->m_renderMode == mode) 258 | return; 259 | 260 | d->m_renderMode = mode; 261 | emit renderModeChanged(d->m_renderMode); 262 | 263 | if (d->m_renderMode == MultiThreadedRenderMode) { 264 | d->m_renderThread = new QThread; 265 | d->m_renderWorker->moveToThread(d->m_renderThread); 266 | d->m_renderThread->start(); 267 | } else { 268 | d->m_renderThread->quit(); 269 | d->m_renderThread->wait(); 270 | delete d->m_renderThread; 271 | d->m_renderThread = nullptr; 272 | 273 | // pulling the object from another thread should be fine, once that thread is deleted 274 | d->m_renderWorker->moveToThread(this->thread()); 275 | } 276 | } 277 | 278 | /*! 279 | \property QPdfPageRenderer::document 280 | \brief the document instance this object renders the pages from 281 | 282 | By default, this property is \c nullptr. 283 | 284 | \sa document(), setDocument(), QPdfDocument 285 | */ 286 | 287 | /*! 288 | Returns the document this objects renders the pages from, or a \c nullptr 289 | if none has been set before. 290 | 291 | \sa QPdfDocument 292 | */ 293 | QPdfDocument* QPdfPageRenderer::document() const 294 | { 295 | Q_D(const QPdfPageRenderer); 296 | 297 | return d->m_document; 298 | } 299 | 300 | /*! 301 | Sets the \a document this object renders the pages from. 302 | 303 | \sa QPdfDocument 304 | */ 305 | void QPdfPageRenderer::setDocument(QPdfDocument *document) 306 | { 307 | Q_D(QPdfPageRenderer); 308 | 309 | if (d->m_document == document) 310 | return; 311 | 312 | d->m_document = document; 313 | emit documentChanged(d->m_document); 314 | 315 | d->m_renderWorker->setDocument(d->m_document); 316 | } 317 | 318 | /*! 319 | Requests the renderer to render the page \a pageNumber into a QImage of size \a imageSize 320 | according to the provided \a options. 321 | 322 | Once the rendering is done the pageRendered() signal is emitted with the result as parameters. 323 | 324 | The return value is an ID that uniquely identifies the render request. If a request with the 325 | same parameters is still in the queue, the ID of that queued request is returned. 326 | */ 327 | quint64 QPdfPageRenderer::requestPage(int pageNumber, QSize imageSize, 328 | QPdfDocumentRenderOptions options) 329 | { 330 | Q_D(QPdfPageRenderer); 331 | 332 | if (!d->m_document || d->m_document->status() != QPdfDocument::Ready) 333 | return 0; 334 | 335 | for (const auto request : qAsConst(d->m_pendingRequests)) { 336 | if (request.pageNumber == pageNumber 337 | && request.imageSize == imageSize 338 | && request.options == options) 339 | return request.id; 340 | } 341 | 342 | const auto id = d->m_requestIdCounter++; 343 | 344 | QPdfPageRendererPrivate::PageRequest request; 345 | request.id = id; 346 | request.pageNumber = pageNumber; 347 | request.imageSize = imageSize; 348 | request.options = options; 349 | 350 | d->m_requests.append(request); 351 | 352 | d->handleNextRequest(); 353 | 354 | return id; 355 | } 356 | 357 | QT_END_NAMESPACE 358 | 359 | #include "qpdfpagerenderer.moc" 360 | -------------------------------------------------------------------------------- /src/pdf/qpdfpagerenderer.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QPDFPAGERENDERER_H 38 | #define QPDFPAGERENDERER_H 39 | 40 | #include "qtpdfglobal.h" 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | QT_BEGIN_NAMESPACE 47 | 48 | class QPdfDocument; 49 | class QPdfPageRendererPrivate; 50 | 51 | class Q_PDF_EXPORT QPdfPageRenderer : public QObject 52 | { 53 | Q_OBJECT 54 | 55 | Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged) 56 | Q_PROPERTY(RenderMode renderMode READ renderMode WRITE setRenderMode NOTIFY renderModeChanged) 57 | 58 | public: 59 | enum RenderMode 60 | { 61 | MultiThreadedRenderMode, 62 | SingleThreadedRenderMode 63 | }; 64 | Q_ENUM(RenderMode) 65 | 66 | explicit QPdfPageRenderer(QObject *parent = nullptr); 67 | ~QPdfPageRenderer(); 68 | 69 | RenderMode renderMode() const; 70 | void setRenderMode(RenderMode mode); 71 | 72 | QPdfDocument* document() const; 73 | void setDocument(QPdfDocument *document); 74 | 75 | quint64 requestPage(int pageNumber, QSize imageSize, 76 | QPdfDocumentRenderOptions options = QPdfDocumentRenderOptions()); 77 | 78 | Q_SIGNALS: 79 | void documentChanged(QPdfDocument *document); 80 | void renderModeChanged(RenderMode renderMode); 81 | 82 | void pageRendered(int pageNumber, QSize imageSize, const QImage &image, 83 | QPdfDocumentRenderOptions options, quint64 requestId); 84 | 85 | private: 86 | Q_DECLARE_PRIVATE(QPdfPageRenderer) 87 | }; 88 | 89 | QT_END_NAMESPACE 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/pdf/qtpdfglobal.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QTPDFGLOBAL_H 38 | #define QTPDFGLOBAL_H 39 | 40 | #include 41 | 42 | QT_BEGIN_NAMESPACE 43 | 44 | #ifndef Q_PDF_EXPORT 45 | # ifndef QT_STATIC 46 | # if defined(QT_BUILD_PDF_LIB) 47 | # define Q_PDF_EXPORT Q_DECL_EXPORT 48 | # else 49 | # define Q_PDF_EXPORT Q_DECL_IMPORT 50 | # endif 51 | # else 52 | # define Q_PDF_EXPORT 53 | # endif 54 | #endif 55 | 56 | QT_END_NAMESPACE 57 | 58 | #endif // QTPDFGLOBAL_H 59 | 60 | -------------------------------------------------------------------------------- /src/pdfwidgets/pdfwidgets.pro: -------------------------------------------------------------------------------- 1 | TARGET = QtPdfWidgets 2 | QT = core gui widgets widgets-private pdf 3 | 4 | SOURCES += \ 5 | qpdfview.cpp 6 | 7 | HEADERS += \ 8 | qpdfview.h \ 9 | qpdfview_p.h \ 10 | qtpdfwidgetsglobal.h 11 | 12 | load(qt_module) 13 | -------------------------------------------------------------------------------- /src/pdfwidgets/qpdfview.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include "qpdfview.h" 38 | #include "qpdfview_p.h" 39 | 40 | #include "qpdfpagerenderer.h" 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | QT_BEGIN_NAMESPACE 50 | 51 | QPdfViewPrivate::QPdfViewPrivate() 52 | : QAbstractScrollAreaPrivate() 53 | , m_document(nullptr) 54 | , m_pageNavigation(nullptr) 55 | , m_pageRenderer(nullptr) 56 | , m_pageMode(QPdfView::SinglePage) 57 | , m_zoomMode(QPdfView::CustomZoom) 58 | , m_zoomFactor(1.0) 59 | , m_pageSpacing(3) 60 | , m_documentMargins(6, 6, 6, 6) 61 | , m_blockPageScrolling(false) 62 | , m_pageCacheLimit(20) 63 | , m_screenResolution(QGuiApplication::primaryScreen()->logicalDotsPerInch() / 72.0) 64 | { 65 | } 66 | 67 | void QPdfViewPrivate::init() 68 | { 69 | Q_Q(QPdfView); 70 | 71 | m_pageNavigation = new QPdfPageNavigation(q); 72 | m_pageRenderer = new QPdfPageRenderer(q); 73 | m_pageRenderer->setRenderMode(QPdfPageRenderer::MultiThreadedRenderMode); 74 | } 75 | 76 | void QPdfViewPrivate::documentStatusChanged() 77 | { 78 | updateDocumentLayout(); 79 | invalidatePageCache(); 80 | } 81 | 82 | void QPdfViewPrivate::currentPageChanged(int currentPage) 83 | { 84 | Q_Q(QPdfView); 85 | 86 | if (m_blockPageScrolling) 87 | return; 88 | 89 | q->verticalScrollBar()->setValue(yPositionForPage(currentPage)); 90 | 91 | if (m_pageMode == QPdfView::SinglePage) 92 | invalidateDocumentLayout(); 93 | } 94 | 95 | void QPdfViewPrivate::calculateViewport() 96 | { 97 | Q_Q(QPdfView); 98 | 99 | const int x = q->horizontalScrollBar()->value(); 100 | const int y = q->verticalScrollBar()->value(); 101 | const int width = q->viewport()->width(); 102 | const int height = q->viewport()->height(); 103 | 104 | setViewport(QRect(x, y, width, height)); 105 | } 106 | 107 | void QPdfViewPrivate::setViewport(QRect viewport) 108 | { 109 | if (m_viewport == viewport) 110 | return; 111 | 112 | const QSize oldSize = m_viewport.size(); 113 | 114 | m_viewport = viewport; 115 | 116 | if (oldSize != m_viewport.size()) { 117 | updateDocumentLayout(); 118 | 119 | if (m_zoomMode != QPdfView::CustomZoom) { 120 | invalidatePageCache(); 121 | } 122 | } 123 | 124 | if (m_pageMode == QPdfView::MultiPage) { 125 | // An imaginary, 2px height line at the upper half of the viewport, which is used to 126 | // determine which page is currently located there -> we propagate that as 'current' page 127 | // to the QPdfPageNavigation object 128 | const QRect currentPageLine(m_viewport.x(), m_viewport.y() + m_viewport.height() * 0.4, m_viewport.width(), 2); 129 | 130 | int currentPage = 0; 131 | for (auto it = m_documentLayout.pageGeometries.cbegin(); it != m_documentLayout.pageGeometries.cend(); ++it) { 132 | const QRect pageGeometry = it.value(); 133 | if (pageGeometry.intersects(currentPageLine)) { 134 | currentPage = it.key(); 135 | break; 136 | } 137 | } 138 | 139 | if (currentPage != m_pageNavigation->currentPage()) { 140 | m_blockPageScrolling = true; 141 | m_pageNavigation->setCurrentPage(currentPage); 142 | m_blockPageScrolling = false; 143 | } 144 | } 145 | } 146 | 147 | void QPdfViewPrivate::updateScrollBars() 148 | { 149 | Q_Q(QPdfView); 150 | 151 | const QSize p = q->viewport()->size(); 152 | const QSize v = m_documentLayout.documentSize; 153 | 154 | q->horizontalScrollBar()->setRange(0, v.width() - p.width()); 155 | q->horizontalScrollBar()->setPageStep(p.width()); 156 | q->verticalScrollBar()->setRange(0, v.height() - p.height()); 157 | q->verticalScrollBar()->setPageStep(p.height()); 158 | } 159 | 160 | void QPdfViewPrivate::pageRendered(int pageNumber, QSize imageSize, const QImage &image, quint64 requestId) 161 | { 162 | Q_Q(QPdfView); 163 | 164 | Q_UNUSED(imageSize) 165 | Q_UNUSED(requestId) 166 | 167 | if (!m_cachedPagesLRU.contains(pageNumber)) { 168 | if (m_cachedPagesLRU.length() > m_pageCacheLimit) 169 | m_pageCache.remove(m_cachedPagesLRU.takeFirst()); 170 | 171 | m_cachedPagesLRU.append(pageNumber); 172 | } 173 | 174 | m_pageCache.insert(pageNumber, image); 175 | 176 | q->viewport()->update(); 177 | } 178 | 179 | void QPdfViewPrivate::invalidateDocumentLayout() 180 | { 181 | updateDocumentLayout(); 182 | invalidatePageCache(); 183 | } 184 | 185 | void QPdfViewPrivate::invalidatePageCache() 186 | { 187 | Q_Q(QPdfView); 188 | 189 | m_pageCache.clear(); 190 | q->viewport()->update(); 191 | } 192 | 193 | QPdfViewPrivate::DocumentLayout QPdfViewPrivate::calculateDocumentLayout() const 194 | { 195 | // The DocumentLayout describes a virtual layout where all pages are positioned inside 196 | // - For SinglePage mode, this is just an area as large as the current page surrounded 197 | // by the m_documentMargins. 198 | // - For MultiPage mode, this is the area that is covered by all pages which are placed 199 | // below each other, with m_pageSpacing inbetween and surrounded by m_documentMargins 200 | 201 | DocumentLayout documentLayout; 202 | 203 | if (!m_document || m_document->status() != QPdfDocument::Ready) 204 | return documentLayout; 205 | 206 | QHash pageGeometries; 207 | 208 | const int pageCount = m_document->pageCount(); 209 | 210 | int totalWidth = 0; 211 | 212 | const int startPage = (m_pageMode == QPdfView::SinglePage ? m_pageNavigation->currentPage() : 0); 213 | const int endPage = (m_pageMode == QPdfView::SinglePage ? m_pageNavigation->currentPage() + 1 : pageCount); 214 | 215 | // calculate page sizes 216 | for (int page = startPage; page < endPage; ++page) { 217 | QSize pageSize; 218 | if (m_zoomMode == QPdfView::CustomZoom) { 219 | pageSize = QSizeF(m_document->pageSize(page) * m_screenResolution * m_zoomFactor).toSize(); 220 | } else if (m_zoomMode == QPdfView::FitToWidth) { 221 | pageSize = QSizeF(m_document->pageSize(page) * m_screenResolution).toSize(); 222 | const qreal factor = (qreal(m_viewport.width() - m_documentMargins.left() - m_documentMargins.right()) / qreal(pageSize.width())); 223 | pageSize *= factor; 224 | } else if (m_zoomMode == QPdfView::FitInView) { 225 | const QSize viewportSize(m_viewport.size() + QSize(-m_documentMargins.left() - m_documentMargins.right(), -m_pageSpacing)); 226 | 227 | pageSize = QSizeF(m_document->pageSize(page) * m_screenResolution).toSize(); 228 | pageSize = pageSize.scaled(viewportSize, Qt::KeepAspectRatio); 229 | } 230 | 231 | totalWidth = qMax(totalWidth, pageSize.width()); 232 | 233 | pageGeometries[page] = QRect(QPoint(0, 0), pageSize); 234 | } 235 | 236 | totalWidth += m_documentMargins.left() + m_documentMargins.right(); 237 | 238 | int pageY = m_documentMargins.top(); 239 | 240 | // calculate page positions 241 | for (int page = startPage; page < endPage; ++page) { 242 | const QSize pageSize = pageGeometries[page].size(); 243 | 244 | // center horizontal inside the viewport 245 | const int pageX = (qMax(totalWidth, m_viewport.width()) - pageSize.width()) / 2; 246 | 247 | pageGeometries[page].moveTopLeft(QPoint(pageX, pageY)); 248 | 249 | pageY += pageSize.height() + m_pageSpacing; 250 | } 251 | 252 | pageY += m_documentMargins.bottom(); 253 | 254 | documentLayout.pageGeometries = pageGeometries; 255 | 256 | // calculate overall document size 257 | documentLayout.documentSize = QSize(totalWidth, pageY); 258 | 259 | return documentLayout; 260 | } 261 | 262 | qreal QPdfViewPrivate::yPositionForPage(int pageNumber) const 263 | { 264 | const auto it = m_documentLayout.pageGeometries.constFind(pageNumber); 265 | if (it == m_documentLayout.pageGeometries.cend()) 266 | return 0.0; 267 | 268 | return (*it).y(); 269 | } 270 | 271 | void QPdfViewPrivate::updateDocumentLayout() 272 | { 273 | m_documentLayout = calculateDocumentLayout(); 274 | 275 | updateScrollBars(); 276 | } 277 | 278 | 279 | QPdfView::QPdfView(QWidget *parent) 280 | : QAbstractScrollArea(*new QPdfViewPrivate(), parent) 281 | { 282 | Q_D(QPdfView); 283 | 284 | d->init(); 285 | 286 | connect(d->m_pageNavigation, &QPdfPageNavigation::currentPageChanged, this, [d](int page){ d->currentPageChanged(page); }); 287 | 288 | connect(d->m_pageRenderer, &QPdfPageRenderer::pageRendered, 289 | this, [d](int pageNumber, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions, quint64 requestId){ d->pageRendered(pageNumber, imageSize, image, requestId); }); 290 | 291 | verticalScrollBar()->setSingleStep(20); 292 | horizontalScrollBar()->setSingleStep(20); 293 | 294 | QScroller::grabGesture(this); 295 | 296 | d->calculateViewport(); 297 | } 298 | 299 | /*! 300 | \internal 301 | */ 302 | QPdfView::QPdfView(QPdfViewPrivate &dd, QWidget *parent) 303 | : QAbstractScrollArea(dd, parent) 304 | { 305 | } 306 | 307 | QPdfView::~QPdfView() 308 | { 309 | } 310 | 311 | void QPdfView::setDocument(QPdfDocument *document) 312 | { 313 | Q_D(QPdfView); 314 | 315 | if (d->m_document == document) 316 | return; 317 | 318 | if (d->m_document) 319 | disconnect(d->m_documentStatusChangedConnection); 320 | 321 | d->m_document = document; 322 | emit documentChanged(d->m_document); 323 | 324 | if (d->m_document) 325 | d->m_documentStatusChangedConnection = connect(d->m_document.data(), &QPdfDocument::statusChanged, this, [d](){ d->documentStatusChanged(); }); 326 | 327 | d->m_pageNavigation->setDocument(d->m_document); 328 | d->m_pageRenderer->setDocument(d->m_document); 329 | 330 | d->documentStatusChanged(); 331 | } 332 | 333 | QPdfDocument *QPdfView::document() const 334 | { 335 | Q_D(const QPdfView); 336 | 337 | return d->m_document; 338 | } 339 | 340 | QPdfPageNavigation *QPdfView::pageNavigation() const 341 | { 342 | Q_D(const QPdfView); 343 | 344 | return d->m_pageNavigation; 345 | } 346 | 347 | QPdfView::PageMode QPdfView::pageMode() const 348 | { 349 | Q_D(const QPdfView); 350 | 351 | return d->m_pageMode; 352 | } 353 | 354 | void QPdfView::setPageMode(PageMode mode) 355 | { 356 | Q_D(QPdfView); 357 | 358 | if (d->m_pageMode == mode) 359 | return; 360 | 361 | d->m_pageMode = mode; 362 | d->invalidateDocumentLayout(); 363 | 364 | emit pageModeChanged(d->m_pageMode); 365 | } 366 | 367 | QPdfView::ZoomMode QPdfView::zoomMode() const 368 | { 369 | Q_D(const QPdfView); 370 | 371 | return d->m_zoomMode; 372 | } 373 | 374 | void QPdfView::setZoomMode(ZoomMode mode) 375 | { 376 | Q_D(QPdfView); 377 | 378 | if (d->m_zoomMode == mode) 379 | return; 380 | 381 | d->m_zoomMode = mode; 382 | d->invalidateDocumentLayout(); 383 | 384 | emit zoomModeChanged(d->m_zoomMode); 385 | } 386 | 387 | qreal QPdfView::zoomFactor() const 388 | { 389 | Q_D(const QPdfView); 390 | 391 | return d->m_zoomFactor; 392 | } 393 | 394 | void QPdfView::setZoomFactor(qreal factor) 395 | { 396 | Q_D(QPdfView); 397 | 398 | if (d->m_zoomFactor == factor) 399 | return; 400 | 401 | d->m_zoomFactor = factor; 402 | d->invalidateDocumentLayout(); 403 | 404 | emit zoomFactorChanged(d->m_zoomFactor); 405 | } 406 | 407 | int QPdfView::pageSpacing() const 408 | { 409 | Q_D(const QPdfView); 410 | 411 | return d->m_pageSpacing; 412 | } 413 | 414 | void QPdfView::setPageSpacing(int spacing) 415 | { 416 | Q_D(QPdfView); 417 | 418 | if (d->m_pageSpacing == spacing) 419 | return; 420 | 421 | d->m_pageSpacing = spacing; 422 | d->invalidateDocumentLayout(); 423 | 424 | emit pageSpacingChanged(d->m_pageSpacing); 425 | } 426 | 427 | QMargins QPdfView::documentMargins() const 428 | { 429 | Q_D(const QPdfView); 430 | 431 | return d->m_documentMargins; 432 | } 433 | 434 | void QPdfView::setDocumentMargins(QMargins margins) 435 | { 436 | Q_D(QPdfView); 437 | 438 | if (d->m_documentMargins == margins) 439 | return; 440 | 441 | d->m_documentMargins = margins; 442 | d->invalidateDocumentLayout(); 443 | 444 | emit documentMarginsChanged(d->m_documentMargins); 445 | } 446 | 447 | void QPdfView::paintEvent(QPaintEvent *event) 448 | { 449 | Q_D(QPdfView); 450 | 451 | QPainter painter(viewport()); 452 | painter.fillRect(event->rect(), palette().brush(QPalette::Dark)); 453 | painter.translate(-d->m_viewport.x(), -d->m_viewport.y()); 454 | 455 | for (auto it = d->m_documentLayout.pageGeometries.cbegin(); it != d->m_documentLayout.pageGeometries.cend(); ++it) { 456 | const QRect pageGeometry = it.value(); 457 | if (pageGeometry.intersects(d->m_viewport)) { // page needs to be painted 458 | painter.fillRect(pageGeometry, Qt::white); 459 | 460 | const int page = it.key(); 461 | const auto pageIt = d->m_pageCache.constFind(page); 462 | if (pageIt != d->m_pageCache.cend()) { 463 | const QImage &img = pageIt.value(); 464 | painter.drawImage(pageGeometry.topLeft(), img); 465 | } else { 466 | d->m_pageRenderer->requestPage(page, pageGeometry.size()); 467 | } 468 | } 469 | } 470 | } 471 | 472 | void QPdfView::resizeEvent(QResizeEvent *event) 473 | { 474 | Q_D(QPdfView); 475 | 476 | QAbstractScrollArea::resizeEvent(event); 477 | 478 | d->updateScrollBars(); 479 | d->calculateViewport(); 480 | } 481 | 482 | void QPdfView::scrollContentsBy(int dx, int dy) 483 | { 484 | Q_D(QPdfView); 485 | 486 | QAbstractScrollArea::scrollContentsBy(dx, dy); 487 | 488 | d->calculateViewport(); 489 | } 490 | 491 | QT_END_NAMESPACE 492 | 493 | #include "moc_qpdfview.cpp" 494 | -------------------------------------------------------------------------------- /src/pdfwidgets/qpdfview.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QPDFVIEW_H 38 | #define QPDFVIEW_H 39 | 40 | #include 41 | #include 42 | 43 | QT_BEGIN_NAMESPACE 44 | 45 | class QPdfDocument; 46 | class QPdfPageNavigation; 47 | class QPdfViewPrivate; 48 | 49 | class Q_PDF_WIDGETS_EXPORT QPdfView : public QAbstractScrollArea 50 | { 51 | Q_OBJECT 52 | 53 | Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged) 54 | 55 | Q_PROPERTY(PageMode pageMode READ pageMode WRITE setPageMode NOTIFY pageModeChanged) 56 | Q_PROPERTY(ZoomMode zoomMode READ zoomMode WRITE setZoomMode NOTIFY zoomModeChanged) 57 | Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged) 58 | 59 | Q_PROPERTY(int pageSpacing READ pageSpacing WRITE setPageSpacing NOTIFY pageSpacingChanged) 60 | Q_PROPERTY(QMargins documentMargins READ documentMargins WRITE setDocumentMargins NOTIFY documentMarginsChanged) 61 | 62 | public: 63 | enum PageMode 64 | { 65 | SinglePage, 66 | MultiPage 67 | }; 68 | Q_ENUM(PageMode) 69 | 70 | enum ZoomMode 71 | { 72 | CustomZoom, 73 | FitToWidth, 74 | FitInView 75 | }; 76 | Q_ENUM(ZoomMode) 77 | 78 | explicit QPdfView(QWidget *parent = nullptr); 79 | ~QPdfView(); 80 | 81 | void setDocument(QPdfDocument *document); 82 | QPdfDocument *document() const; 83 | 84 | QPdfPageNavigation *pageNavigation() const; 85 | 86 | PageMode pageMode() const; 87 | ZoomMode zoomMode() const; 88 | qreal zoomFactor() const; 89 | 90 | int pageSpacing() const; 91 | void setPageSpacing(int spacing); 92 | 93 | QMargins documentMargins() const; 94 | void setDocumentMargins(QMargins margins); 95 | 96 | public Q_SLOTS: 97 | void setPageMode(PageMode mode); 98 | void setZoomMode(ZoomMode mode); 99 | void setZoomFactor(qreal factor); 100 | 101 | Q_SIGNALS: 102 | void documentChanged(QPdfDocument *document); 103 | void pageModeChanged(PageMode pageMode); 104 | void zoomModeChanged(ZoomMode zoomMode); 105 | void zoomFactorChanged(qreal zoomFactor); 106 | void pageSpacingChanged(int pageSpacing); 107 | void documentMarginsChanged(QMargins documentMargins); 108 | 109 | protected: 110 | explicit QPdfView(QPdfViewPrivate &, QWidget *); 111 | 112 | void paintEvent(QPaintEvent *event) override; 113 | void resizeEvent(QResizeEvent *event) override; 114 | void scrollContentsBy(int dx, int dy) override; 115 | 116 | private: 117 | Q_DECLARE_PRIVATE(QPdfView) 118 | }; 119 | 120 | QT_END_NAMESPACE 121 | 122 | #endif // QPDFVIEW_H 123 | -------------------------------------------------------------------------------- /src/pdfwidgets/qpdfview_p.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QPDFVIEW_P_H 38 | #define QPDFVIEW_P_H 39 | 40 | // 41 | // W A R N I N G 42 | // ------------- 43 | // 44 | // This file is not part of the Qt API. It exists purely as an 45 | // implementation detail. This header file may change from version to 46 | // version without notice, or even be removed. 47 | // 48 | // We mean it. 49 | // 50 | 51 | #include "qpdfview.h" 52 | 53 | #include 54 | #include 55 | 56 | QT_BEGIN_NAMESPACE 57 | 58 | class QPdfPageRenderer; 59 | 60 | class QPdfViewPrivate : public QAbstractScrollAreaPrivate 61 | { 62 | Q_DECLARE_PUBLIC(QPdfView) 63 | 64 | public: 65 | QPdfViewPrivate(); 66 | void init(); 67 | 68 | void documentStatusChanged(); 69 | void currentPageChanged(int currentPage); 70 | void calculateViewport(); 71 | void setViewport(QRect viewport); 72 | void updateScrollBars(); 73 | 74 | void pageRendered(int pageNumber, QSize imageSize, const QImage &image, quint64 requestId); 75 | void invalidateDocumentLayout(); 76 | void invalidatePageCache(); 77 | 78 | qreal yPositionForPage(int page) const; 79 | 80 | struct DocumentLayout 81 | { 82 | QSize documentSize; 83 | QHash pageGeometries; 84 | }; 85 | 86 | DocumentLayout calculateDocumentLayout() const; 87 | void updateDocumentLayout(); 88 | 89 | QPointer m_document; 90 | QPdfPageNavigation* m_pageNavigation; 91 | QPdfPageRenderer *m_pageRenderer; 92 | 93 | QPdfView::PageMode m_pageMode; 94 | QPdfView::ZoomMode m_zoomMode; 95 | qreal m_zoomFactor; 96 | 97 | int m_pageSpacing; 98 | QMargins m_documentMargins; 99 | 100 | bool m_blockPageScrolling; 101 | 102 | QMetaObject::Connection m_documentStatusChangedConnection; 103 | 104 | QRect m_viewport; 105 | 106 | QHash m_pageCache; 107 | QVector m_cachedPagesLRU; 108 | int m_pageCacheLimit; 109 | 110 | DocumentLayout m_documentLayout; 111 | 112 | qreal m_screenResolution; // pixels per point 113 | }; 114 | 115 | Q_DECLARE_TYPEINFO(QPdfViewPrivate::DocumentLayout, Q_MOVABLE_TYPE); 116 | 117 | QT_END_NAMESPACE 118 | 119 | #endif // QPDFVIEW_P_H 120 | -------------------------------------------------------------------------------- /src/pdfwidgets/qtpdfwidgetsglobal.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #ifndef QTPDFWIDGETSGLOBAL_H 38 | #define QTPDFWIDGETSGLOBAL_H 39 | 40 | #include 41 | 42 | QT_BEGIN_NAMESPACE 43 | 44 | #ifndef Q_PDF_WIDGETS_EXPORT 45 | # ifndef QT_STATIC 46 | # if defined(QT_BUILD_PDFWIDGETS_LIB) 47 | # define Q_PDF_WIDGETS_EXPORT Q_DECL_EXPORT 48 | # else 49 | # define Q_PDF_WIDGETS_EXPORT Q_DECL_IMPORT 50 | # endif 51 | # else 52 | # define Q_PDF_WIDGETS_EXPORT 53 | # endif 54 | #endif 55 | 56 | QT_END_NAMESPACE 57 | 58 | #endif // QTPDFWIDGETSGLOBAL_H 59 | 60 | -------------------------------------------------------------------------------- /src/src.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | src_pdf.subdir = pdf 4 | src_pdf.depends = lib 5 | 6 | SUBDIRS = lib src_pdf 7 | 8 | qtHaveModule(widgets) { 9 | src_pdfwidgets.subdir = pdfwidgets 10 | src_pdfwidgets.depends = src_pdf 11 | 12 | SUBDIRS += src_pdfwidgets 13 | } 14 | -------------------------------------------------------------------------------- /sync.profile: -------------------------------------------------------------------------------- 1 | %modules = ( # path to module name map 2 | "QtPdf" => "$basedir/src/pdf", 3 | "QtPdfWidgets" => "$basedir/src/pdfwidgets", 4 | ); 5 | # Module dependencies. 6 | # Every module that is required to build this module should have one entry. 7 | # Each of the module version specifiers can take one of the following values: 8 | # - A specific Git revision. 9 | # - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch) 10 | # - an empty string to use the same branch under test (dependencies will become "refs/heads/master" if we are in the master branch) 11 | # 12 | %dependencies = ( 13 | "qtbase" => "", 14 | ); 15 | -------------------------------------------------------------------------------- /tests/auto/auto.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS = \ 4 | qpdfbookmarkmodel \ 5 | qpdfpagenavigation \ 6 | qpdfpagerenderer 7 | 8 | qtHaveModule(printsupport): SUBDIRS += qpdfdocument 9 | -------------------------------------------------------------------------------- /tests/auto/cmake/cmake.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/tests/auto/cmake/cmake.pro -------------------------------------------------------------------------------- /tests/auto/qpdfbookmarkmodel/pdf-sample.bookmarks.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/tests/auto/qpdfbookmarkmodel/pdf-sample.bookmarks.pdf -------------------------------------------------------------------------------- /tests/auto/qpdfbookmarkmodel/pdf-sample.bookmarks_pages.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/tests/auto/qpdfbookmarkmodel/pdf-sample.bookmarks_pages.pdf -------------------------------------------------------------------------------- /tests/auto/qpdfbookmarkmodel/qpdfbookmarkmodel.pro: -------------------------------------------------------------------------------- 1 | CONFIG += testcase 2 | TARGET = tst_qpdfbookmarkmodel 3 | QT += pdf testlib network 4 | macos:CONFIG -= app_bundle 5 | SOURCES += tst_qpdfbookmarkmodel.cpp 6 | -------------------------------------------------------------------------------- /tests/auto/qpdfbookmarkmodel/tst_qpdfbookmarkmodel.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the test suite of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | 38 | #include 39 | 40 | #include 41 | #include 42 | 43 | class tst_QPdfBookmarkModel: public QObject 44 | { 45 | Q_OBJECT 46 | 47 | public: 48 | tst_QPdfBookmarkModel() 49 | { 50 | qRegisterMetaType(); 51 | } 52 | 53 | private slots: 54 | void emptyModel(); 55 | void setEmptyDocument(); 56 | void setEmptyDocumentAndLoad(); 57 | void setLoadedDocument(); 58 | void unloadDocument(); 59 | void testTreeStructure(); 60 | void testListStructure(); 61 | void testPageNumberRole(); 62 | }; 63 | 64 | void tst_QPdfBookmarkModel::emptyModel() 65 | { 66 | QPdfBookmarkModel model; 67 | 68 | QVERIFY(!model.document()); 69 | QCOMPARE(model.structureMode(), QPdfBookmarkModel::TreeMode); 70 | QCOMPARE(model.rowCount(), 0); 71 | QCOMPARE(model.columnCount(), 1); 72 | QCOMPARE(model.index(0, 0).isValid(), false); 73 | } 74 | 75 | void tst_QPdfBookmarkModel::setEmptyDocument() 76 | { 77 | QPdfDocument document; 78 | QPdfBookmarkModel model; 79 | 80 | model.setDocument(&document); 81 | 82 | QCOMPARE(model.document(), &document); 83 | QCOMPARE(model.structureMode(), QPdfBookmarkModel::TreeMode); 84 | QCOMPARE(model.rowCount(), 0); 85 | QCOMPARE(model.columnCount(), 1); 86 | QCOMPARE(model.index(0, 0).isValid(), false); 87 | } 88 | 89 | void tst_QPdfBookmarkModel::setEmptyDocumentAndLoad() 90 | { 91 | QPdfDocument document; 92 | QPdfBookmarkModel model; 93 | 94 | model.setDocument(&document); 95 | 96 | QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset())); 97 | QSignalSpy modelResetSpy(&model, SIGNAL(modelReset())); 98 | 99 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks.pdf")), QPdfDocument::NoError); 100 | 101 | QCOMPARE(modelAboutToBeResetSpy.count(), 1); 102 | QCOMPARE(modelResetSpy.count(), 1); 103 | 104 | QCOMPARE(model.rowCount(), 3); 105 | } 106 | 107 | void tst_QPdfBookmarkModel::setLoadedDocument() 108 | { 109 | QPdfDocument document; 110 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks.pdf")), QPdfDocument::NoError); 111 | 112 | QPdfBookmarkModel model; 113 | 114 | QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset())); 115 | QSignalSpy modelResetSpy(&model, SIGNAL(modelReset())); 116 | 117 | model.setDocument(&document); 118 | 119 | QCOMPARE(modelAboutToBeResetSpy.count(), 1); 120 | QCOMPARE(modelResetSpy.count(), 1); 121 | 122 | QCOMPARE(model.rowCount(), 3); 123 | } 124 | 125 | void tst_QPdfBookmarkModel::unloadDocument() 126 | { 127 | QPdfDocument document; 128 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks.pdf")), QPdfDocument::NoError); 129 | 130 | QPdfBookmarkModel model; 131 | model.setDocument(&document); 132 | 133 | QCOMPARE(model.rowCount(), 3); 134 | 135 | QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset())); 136 | QSignalSpy modelResetSpy(&model, SIGNAL(modelReset())); 137 | 138 | document.close(); 139 | 140 | QCOMPARE(modelAboutToBeResetSpy.count(), 1); 141 | QCOMPARE(modelResetSpy.count(), 1); 142 | 143 | QCOMPARE(model.rowCount(), 0); 144 | } 145 | 146 | void tst_QPdfBookmarkModel::testTreeStructure() 147 | { 148 | QPdfDocument document; 149 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks.pdf")), QPdfDocument::NoError); 150 | 151 | QPdfBookmarkModel model; 152 | model.setDocument(&document); 153 | 154 | QCOMPARE(model.rowCount(), 3); 155 | 156 | const QModelIndex index1 = model.index(0, 0); 157 | QCOMPARE(index1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1")); 158 | QCOMPARE(index1.data(QPdfBookmarkModel::LevelRole).toInt(), 0); 159 | QCOMPARE(model.rowCount(index1), 2); 160 | 161 | const QModelIndex index1_1 = model.index(0, 0, index1); 162 | QCOMPARE(index1_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1.1")); 163 | QCOMPARE(index1_1.data(QPdfBookmarkModel::LevelRole).toInt(), 1); 164 | QCOMPARE(model.rowCount(index1_1), 0); 165 | 166 | const QModelIndex index1_2 = model.index(1, 0, index1); 167 | QCOMPARE(index1_2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1.2")); 168 | QCOMPARE(index1_2.data(QPdfBookmarkModel::LevelRole).toInt(), 1); 169 | QCOMPARE(model.rowCount(index1_2), 0); 170 | 171 | const QModelIndex index2 = model.index(1, 0); 172 | QCOMPARE(index2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2")); 173 | QCOMPARE(index2.data(QPdfBookmarkModel::LevelRole).toInt(), 0); 174 | QCOMPARE(model.rowCount(index2), 2); 175 | 176 | const QModelIndex index2_1 = model.index(0, 0, index2); 177 | QCOMPARE(index2_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.1")); 178 | QCOMPARE(index2_1.data(QPdfBookmarkModel::LevelRole).toInt(), 1); 179 | QCOMPARE(model.rowCount(index2_1), 1); 180 | 181 | const QModelIndex index2_1_1 = model.index(0, 0, index2_1); 182 | QCOMPARE(index2_1_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.1.1")); 183 | QCOMPARE(index2_1_1.data(QPdfBookmarkModel::LevelRole).toInt(), 2); 184 | QCOMPARE(model.rowCount(index2_1_1), 0); 185 | 186 | const QModelIndex index2_2 = model.index(1, 0, index2); 187 | QCOMPARE(index2_2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.2")); 188 | QCOMPARE(index2_2.data(QPdfBookmarkModel::LevelRole).toInt(), 1); 189 | QCOMPARE(model.rowCount(index2_2), 0); 190 | 191 | const QModelIndex index3 = model.index(2, 0); 192 | QCOMPARE(index3.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 3")); 193 | QCOMPARE(index3.data(QPdfBookmarkModel::LevelRole).toInt(), 0); 194 | QCOMPARE(model.rowCount(index3), 0); 195 | 196 | const QModelIndex index4 = model.index(3, 0); 197 | QCOMPARE(index4, QModelIndex()); 198 | } 199 | 200 | void tst_QPdfBookmarkModel::testListStructure() 201 | { 202 | QPdfDocument document; 203 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks.pdf")), QPdfDocument::NoError); 204 | 205 | QPdfBookmarkModel model; 206 | model.setDocument(&document); 207 | 208 | QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset())); 209 | QSignalSpy modelResetSpy(&model, SIGNAL(modelReset())); 210 | 211 | model.setStructureMode(QPdfBookmarkModel::ListMode); 212 | 213 | QCOMPARE(modelAboutToBeResetSpy.count(), 1); 214 | QCOMPARE(modelResetSpy.count(), 1); 215 | 216 | QCOMPARE(model.rowCount(), 8); 217 | 218 | const QModelIndex index1 = model.index(0, 0); 219 | QCOMPARE(index1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1")); 220 | QCOMPARE(index1.data(QPdfBookmarkModel::LevelRole).toInt(), 0); 221 | QCOMPARE(model.rowCount(index1), 0); 222 | 223 | const QModelIndex index1_1 = model.index(1, 0); 224 | QCOMPARE(index1_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1.1")); 225 | QCOMPARE(index1_1.data(QPdfBookmarkModel::LevelRole).toInt(), 1); 226 | QCOMPARE(model.rowCount(index1_1), 0); 227 | 228 | const QModelIndex index1_2 = model.index(2, 0); 229 | QCOMPARE(index1_2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1.2")); 230 | QCOMPARE(index1_2.data(QPdfBookmarkModel::LevelRole).toInt(), 1); 231 | QCOMPARE(model.rowCount(index1_2), 0); 232 | 233 | const QModelIndex index2 = model.index(3, 0); 234 | QCOMPARE(index2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2")); 235 | QCOMPARE(index2.data(QPdfBookmarkModel::LevelRole).toInt(), 0); 236 | QCOMPARE(model.rowCount(index2), 0); 237 | 238 | const QModelIndex index2_1 = model.index(4, 0); 239 | QCOMPARE(index2_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.1")); 240 | QCOMPARE(index2_1.data(QPdfBookmarkModel::LevelRole).toInt(), 1); 241 | QCOMPARE(model.rowCount(index2_1), 0); 242 | 243 | const QModelIndex index2_1_1 = model.index(5, 0); 244 | QCOMPARE(index2_1_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.1.1")); 245 | QCOMPARE(index2_1_1.data(QPdfBookmarkModel::LevelRole).toInt(), 2); 246 | QCOMPARE(model.rowCount(index2_1_1), 0); 247 | 248 | const QModelIndex index2_2 = model.index(6, 0); 249 | QCOMPARE(index2_2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.2")); 250 | QCOMPARE(index2_2.data(QPdfBookmarkModel::LevelRole).toInt(), 1); 251 | QCOMPARE(model.rowCount(index2_2), 0); 252 | 253 | const QModelIndex index3 = model.index(7, 0); 254 | QCOMPARE(index3.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 3")); 255 | QCOMPARE(index3.data(QPdfBookmarkModel::LevelRole).toInt(), 0); 256 | QCOMPARE(model.rowCount(index3), 0); 257 | 258 | const QModelIndex index4 = model.index(8, 0); 259 | QCOMPARE(index4, QModelIndex()); 260 | } 261 | 262 | void tst_QPdfBookmarkModel::testPageNumberRole() 263 | { 264 | QPdfDocument document; 265 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks_pages.pdf")), QPdfDocument::NoError); 266 | 267 | QPdfBookmarkModel model; 268 | model.setDocument(&document); 269 | 270 | QCOMPARE(model.rowCount(), 3); 271 | 272 | const QModelIndex index1 = model.index(0, 0); 273 | QCOMPARE(index1.data(QPdfBookmarkModel::PageNumberRole).toInt(), 0); 274 | 275 | const QModelIndex index2 = model.index(1, 0); 276 | QCOMPARE(index2.data(QPdfBookmarkModel::PageNumberRole).toInt(), 1); 277 | 278 | const QModelIndex index2_1 = model.index(0, 0, index2); 279 | QCOMPARE(index2_1.data(QPdfBookmarkModel::PageNumberRole).toInt(), 1); 280 | 281 | const QModelIndex index3 = model.index(2, 0); 282 | QCOMPARE(index3.data(QPdfBookmarkModel::PageNumberRole).toInt(), 2); 283 | } 284 | 285 | QTEST_MAIN(tst_QPdfBookmarkModel) 286 | 287 | #include "tst_qpdfbookmarkmodel.moc" 288 | -------------------------------------------------------------------------------- /tests/auto/qpdfdocument/pdf-sample.metadata.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/tests/auto/qpdfdocument/pdf-sample.metadata.pdf -------------------------------------------------------------------------------- /tests/auto/qpdfdocument/pdf-sample.protected.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/tests/auto/qpdfdocument/pdf-sample.protected.pdf -------------------------------------------------------------------------------- /tests/auto/qpdfdocument/qpdfdocument.pro: -------------------------------------------------------------------------------- 1 | CONFIG += testcase 2 | TARGET = tst_qpdfdocument 3 | QT += pdf printsupport testlib network 4 | macx:CONFIG -= app_bundle 5 | SOURCES += tst_qpdfdocument.cpp 6 | 7 | -------------------------------------------------------------------------------- /tests/auto/qpdfdocument/tst_qpdfdocument.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the test suite of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | class tst_QPdfDocument: public QObject 49 | { 50 | Q_OBJECT 51 | 52 | public: 53 | tst_QPdfDocument() 54 | { 55 | qRegisterMetaType(); 56 | } 57 | 58 | private slots: 59 | void pageCount(); 60 | void loadFromIODevice(); 61 | void loadAsync(); 62 | void password(); 63 | void close(); 64 | void loadAfterClose(); 65 | void closeOnDestroy(); 66 | void status(); 67 | void passwordClearedOnClose(); 68 | void metaData(); 69 | }; 70 | 71 | struct TemporaryPdf: public QTemporaryFile 72 | { 73 | TemporaryPdf(); 74 | QPageLayout pageLayout; 75 | }; 76 | 77 | 78 | TemporaryPdf::TemporaryPdf() 79 | { 80 | open(); 81 | pageLayout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF()); 82 | 83 | { 84 | QPrinter printer; 85 | printer.setOutputFormat(QPrinter::PdfFormat); 86 | printer.setOutputFileName(fileName()); 87 | printer.setPageLayout(pageLayout); 88 | 89 | { 90 | QPainter painter(&printer); 91 | painter.drawText(100, 100, QStringLiteral("Hello Page 1")); 92 | printer.newPage(); 93 | painter.drawText(100, 100, QStringLiteral("Hello Page 2")); 94 | } 95 | } 96 | 97 | seek(0); 98 | } 99 | 100 | void tst_QPdfDocument::pageCount() 101 | { 102 | TemporaryPdf tempPdf; 103 | 104 | QPdfDocument doc; 105 | QSignalSpy pageCountChangedSpy(&doc, SIGNAL(pageCountChanged(int))); 106 | 107 | QCOMPARE(doc.pageCount(), 0); 108 | QCOMPARE(doc.load(tempPdf.fileName()), QPdfDocument::NoError); 109 | QCOMPARE(doc.pageCount(), 2); 110 | QCOMPARE(pageCountChangedSpy.count(), 1); 111 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount()); 112 | 113 | QCOMPARE(doc.pageSize(0).toSize(), tempPdf.pageLayout.fullRectPoints().size()); 114 | } 115 | 116 | void tst_QPdfDocument::loadFromIODevice() 117 | { 118 | TemporaryPdf tempPdf; 119 | QPdfDocument doc; 120 | QSignalSpy statusChangedSpy(&doc, SIGNAL(statusChanged(QPdfDocument::Status))); 121 | QSignalSpy pageCountChangedSpy(&doc, SIGNAL(pageCountChanged(int))); 122 | doc.load(&tempPdf); 123 | QCOMPARE(statusChangedSpy.count(), 2); 124 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Loading); 125 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Ready); 126 | QCOMPARE(doc.error(), QPdfDocument::NoError); 127 | QCOMPARE(doc.pageCount(), 2); 128 | QCOMPARE(pageCountChangedSpy.count(), 1); 129 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount()); 130 | } 131 | 132 | void tst_QPdfDocument::loadAsync() 133 | { 134 | TemporaryPdf tempPdf; 135 | 136 | QNetworkAccessManager nam; 137 | 138 | QUrl url = QUrl::fromLocalFile(tempPdf.fileName()); 139 | QScopedPointer reply(nam.get(QNetworkRequest(url))); 140 | 141 | QPdfDocument doc; 142 | QSignalSpy statusChangedSpy(&doc, SIGNAL(statusChanged(QPdfDocument::Status))); 143 | QSignalSpy pageCountChangedSpy(&doc, SIGNAL(pageCountChanged(int))); 144 | 145 | doc.load(reply.data()); 146 | 147 | QCOMPARE(statusChangedSpy.count(), 2); 148 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Loading); 149 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Ready); 150 | QCOMPARE(doc.pageCount(), 2); 151 | QCOMPARE(pageCountChangedSpy.count(), 1); 152 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount()); 153 | } 154 | 155 | void tst_QPdfDocument::password() 156 | { 157 | QPdfDocument doc; 158 | QSignalSpy passwordChangedSpy(&doc, SIGNAL(passwordChanged())); 159 | 160 | QCOMPARE(doc.pageCount(), 0); 161 | QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::IncorrectPasswordError); 162 | QCOMPARE(passwordChangedSpy.count(), 0); 163 | doc.setPassword(QStringLiteral("WrongPassword")); 164 | QCOMPARE(passwordChangedSpy.count(), 1); 165 | QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::IncorrectPasswordError); 166 | QCOMPARE(doc.status(), QPdfDocument::Error); 167 | doc.setPassword(QStringLiteral("Qt")); 168 | QCOMPARE(passwordChangedSpy.count(), 2); 169 | QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::NoError); 170 | QCOMPARE(doc.pageCount(), 1); 171 | } 172 | 173 | void tst_QPdfDocument::close() 174 | { 175 | TemporaryPdf tempPdf; 176 | QPdfDocument doc; 177 | 178 | QSignalSpy statusChangedSpy(&doc, SIGNAL(statusChanged(QPdfDocument::Status))); 179 | QSignalSpy pageCountChangedSpy(&doc, SIGNAL(pageCountChanged(int))); 180 | 181 | doc.load(&tempPdf); 182 | 183 | QCOMPARE(statusChangedSpy.count(), 2); 184 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Loading); 185 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Ready); 186 | QCOMPARE(pageCountChangedSpy.count(), 1); 187 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount()); 188 | 189 | statusChangedSpy.clear(); 190 | pageCountChangedSpy.clear(); 191 | 192 | doc.close(); 193 | QCOMPARE(statusChangedSpy.count(), 2); 194 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Unloading); 195 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Null); 196 | QCOMPARE(doc.pageCount(), 0); 197 | QCOMPARE(pageCountChangedSpy.count(), 1); 198 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount()); 199 | } 200 | 201 | void tst_QPdfDocument::loadAfterClose() 202 | { 203 | TemporaryPdf tempPdf; 204 | QPdfDocument doc; 205 | 206 | QSignalSpy statusChangedSpy(&doc, SIGNAL(statusChanged(QPdfDocument::Status))); 207 | QSignalSpy pageCountChangedSpy(&doc, SIGNAL(pageCountChanged(int))); 208 | 209 | doc.load(&tempPdf); 210 | QCOMPARE(statusChangedSpy.count(), 2); 211 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Loading); 212 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Ready); 213 | QCOMPARE(pageCountChangedSpy.count(), 1); 214 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount()); 215 | statusChangedSpy.clear(); 216 | pageCountChangedSpy.clear(); 217 | 218 | doc.close(); 219 | QCOMPARE(statusChangedSpy.count(), 2); 220 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Unloading); 221 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Null); 222 | QCOMPARE(pageCountChangedSpy.count(), 1); 223 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount()); 224 | statusChangedSpy.clear(); 225 | pageCountChangedSpy.clear(); 226 | 227 | doc.load(&tempPdf); 228 | QCOMPARE(statusChangedSpy.count(), 2); 229 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Loading); 230 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Ready); 231 | QCOMPARE(doc.error(), QPdfDocument::NoError); 232 | QCOMPARE(doc.pageCount(), 2); 233 | QCOMPARE(pageCountChangedSpy.count(), 1); 234 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount()); 235 | } 236 | 237 | void tst_QPdfDocument::closeOnDestroy() 238 | { 239 | TemporaryPdf tempPdf; 240 | 241 | // deleting an open document should automatically close it 242 | { 243 | QPdfDocument *doc = new QPdfDocument; 244 | 245 | doc->load(&tempPdf); 246 | 247 | QSignalSpy statusChangedSpy(doc, SIGNAL(statusChanged(QPdfDocument::Status))); 248 | QSignalSpy pageCountChangedSpy(doc, SIGNAL(pageCountChanged(int))); 249 | 250 | delete doc; 251 | 252 | QCOMPARE(statusChangedSpy.count(), 2); 253 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Unloading); 254 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Null); 255 | QCOMPARE(pageCountChangedSpy.count(), 1); 256 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), 0); 257 | } 258 | 259 | // deleting a closed document should not emit any signal 260 | { 261 | QPdfDocument *doc = new QPdfDocument; 262 | doc->load(&tempPdf); 263 | doc->close(); 264 | 265 | QSignalSpy statusChangedSpy(doc, SIGNAL(statusChanged(QPdfDocument::Status))); 266 | QSignalSpy pageCountChangedSpy(doc, SIGNAL(pageCountChanged(int))); 267 | 268 | delete doc; 269 | 270 | QCOMPARE(statusChangedSpy.count(), 0); 271 | QCOMPARE(pageCountChangedSpy.count(), 0); 272 | } 273 | } 274 | 275 | void tst_QPdfDocument::status() 276 | { 277 | TemporaryPdf tempPdf; 278 | 279 | QPdfDocument doc; 280 | QCOMPARE(doc.status(), QPdfDocument::Null); 281 | 282 | QSignalSpy statusChangedSpy(&doc, SIGNAL(statusChanged(QPdfDocument::Status))); 283 | 284 | // open existing document 285 | doc.load(&tempPdf); 286 | QCOMPARE(statusChangedSpy.count(), 2); 287 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Loading); 288 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Ready); 289 | statusChangedSpy.clear(); 290 | 291 | QCOMPARE(doc.status(), QPdfDocument::Ready); 292 | 293 | // close document 294 | doc.close(); 295 | 296 | QCOMPARE(statusChangedSpy.count(), 2); 297 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Unloading); 298 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Null); 299 | statusChangedSpy.clear(); 300 | 301 | QCOMPARE(doc.status(), QPdfDocument::Null); 302 | 303 | // try to open non-existing document 304 | doc.load(QFINDTESTDATA("does-not-exist.pdf")); 305 | QCOMPARE(statusChangedSpy.count(), 2); 306 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Loading); 307 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Error); 308 | QCOMPARE(doc.status(), QPdfDocument::Error); 309 | statusChangedSpy.clear(); 310 | 311 | // try to open non-existing document asynchronously 312 | QNetworkAccessManager accessManager; 313 | 314 | const QUrl url("http://doesnotexist.qt.io"); 315 | QScopedPointer reply(accessManager.get(QNetworkRequest(url))); 316 | 317 | doc.load(reply.data()); 318 | 319 | QTime stopWatch; 320 | stopWatch.start(); 321 | forever { 322 | QCoreApplication::instance()->processEvents(); 323 | if (statusChangedSpy.count() == 2) 324 | break; 325 | 326 | if (stopWatch.elapsed() >= 30000) 327 | break; 328 | } 329 | 330 | QCOMPARE(statusChangedSpy.count(), 2); 331 | QCOMPARE(statusChangedSpy[0][0].value(), QPdfDocument::Loading); 332 | QCOMPARE(statusChangedSpy[1][0].value(), QPdfDocument::Error); 333 | statusChangedSpy.clear(); 334 | } 335 | 336 | void tst_QPdfDocument::passwordClearedOnClose() 337 | { 338 | TemporaryPdf tempPdf; 339 | QPdfDocument doc; 340 | 341 | QSignalSpy passwordChangedSpy(&doc, SIGNAL(passwordChanged())); 342 | 343 | doc.setPassword(QStringLiteral("Qt")); 344 | QCOMPARE(passwordChangedSpy.count(), 1); 345 | QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::NoError); 346 | passwordChangedSpy.clear(); 347 | 348 | doc.close(); // password is cleared on close 349 | QCOMPARE(passwordChangedSpy.count(), 1); 350 | passwordChangedSpy.clear(); 351 | 352 | doc.load(&tempPdf); 353 | doc.close(); // signal is not emitted if password didn't change 354 | QCOMPARE(passwordChangedSpy.count(), 0); 355 | } 356 | 357 | void tst_QPdfDocument::metaData() 358 | { 359 | QPdfDocument doc; 360 | 361 | // a closed document does not return any meta data 362 | QCOMPARE(doc.metaData(QPdfDocument::Title).toString(), QString()); 363 | QCOMPARE(doc.metaData(QPdfDocument::Subject).toString(), QString()); 364 | QCOMPARE(doc.metaData(QPdfDocument::Author).toString(), QString()); 365 | QCOMPARE(doc.metaData(QPdfDocument::Keywords).toString(), QString()); 366 | QCOMPARE(doc.metaData(QPdfDocument::Producer).toString(), QString()); 367 | QCOMPARE(doc.metaData(QPdfDocument::Creator).toString(), QString()); 368 | QCOMPARE(doc.metaData(QPdfDocument::CreationDate).toDateTime(), QDateTime()); 369 | QCOMPARE(doc.metaData(QPdfDocument::ModificationDate).toDateTime(), QDateTime()); 370 | 371 | QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.metadata.pdf")), QPdfDocument::NoError); 372 | 373 | // check for proper meta data from sample document 374 | QCOMPARE(doc.metaData(QPdfDocument::Title).toString(), QString::fromLatin1("Qt PDF Unit Test Document")); 375 | QCOMPARE(doc.metaData(QPdfDocument::Subject).toString(), QString::fromLatin1("A test for meta data access")); 376 | QCOMPARE(doc.metaData(QPdfDocument::Author).toString(), QString::fromLatin1("John Doe")); 377 | QCOMPARE(doc.metaData(QPdfDocument::Keywords).toString(), QString::fromLatin1("meta data keywords")); 378 | QCOMPARE(doc.metaData(QPdfDocument::Producer).toString(), QString::fromLatin1("LibreOffice 5.1")); 379 | QCOMPARE(doc.metaData(QPdfDocument::Creator).toString(), QString::fromLatin1("Writer")); 380 | QCOMPARE(doc.metaData(QPdfDocument::CreationDate).toDateTime(), QDateTime(QDate(2016, 8, 7), QTime(7, 3, 6), Qt::UTC)); 381 | QCOMPARE(doc.metaData(QPdfDocument::ModificationDate).toDateTime(), QDateTime(QDate(2016, 8, 8), QTime(8, 3, 6), Qt::UTC)); 382 | } 383 | 384 | QTEST_MAIN(tst_QPdfDocument) 385 | 386 | #include "tst_qpdfdocument.moc" 387 | 388 | -------------------------------------------------------------------------------- /tests/auto/qpdfpagenavigation/pdf-sample.pagenavigation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/tests/auto/qpdfpagenavigation/pdf-sample.pagenavigation.pdf -------------------------------------------------------------------------------- /tests/auto/qpdfpagenavigation/qpdfpagenavigation.pro: -------------------------------------------------------------------------------- 1 | CONFIG += testcase 2 | TARGET = tst_qpdfpagenavigation 3 | QT += pdf testlib network 4 | macos:CONFIG -= app_bundle 5 | SOURCES += tst_qpdfpagenavigation.cpp 6 | -------------------------------------------------------------------------------- /tests/auto/qpdfpagenavigation/tst_qpdfpagenavigation.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 The Qt Company Ltd. 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the test suite of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | 38 | #include 39 | 40 | #include 41 | #include 42 | 43 | class tst_QPdfPageNavigation: public QObject 44 | { 45 | Q_OBJECT 46 | 47 | private slots: 48 | void defaultValues(); 49 | void setEmptyDocument(); 50 | void setEmptyDocumentAndLoad(); 51 | void setLoadedDocument(); 52 | void unloadDocument(); 53 | void navigate(); 54 | }; 55 | 56 | void tst_QPdfPageNavigation::defaultValues() 57 | { 58 | QPdfPageNavigation pageNavigation; 59 | 60 | QCOMPARE(pageNavigation.document(), nullptr); 61 | QCOMPARE(pageNavigation.currentPage(), 0); 62 | QCOMPARE(pageNavigation.pageCount(), 0); 63 | QCOMPARE(pageNavigation.canGoToPreviousPage(), false); 64 | QCOMPARE(pageNavigation.canGoToNextPage(), false); 65 | } 66 | 67 | void tst_QPdfPageNavigation::setEmptyDocument() 68 | { 69 | QPdfDocument document; 70 | QPdfPageNavigation pageNavigation; 71 | 72 | pageNavigation.setDocument(&document); 73 | 74 | QCOMPARE(pageNavigation.document(), &document); 75 | QCOMPARE(pageNavigation.currentPage(), 0); 76 | QCOMPARE(pageNavigation.pageCount(), 0); 77 | QCOMPARE(pageNavigation.canGoToPreviousPage(), false); 78 | QCOMPARE(pageNavigation.canGoToNextPage(), false); 79 | } 80 | 81 | void tst_QPdfPageNavigation::setEmptyDocumentAndLoad() 82 | { 83 | QPdfDocument document; 84 | QPdfPageNavigation pageNavigation; 85 | 86 | pageNavigation.setDocument(&document); 87 | 88 | QSignalSpy currentPageChangedSpy(&pageNavigation, &QPdfPageNavigation::currentPageChanged); 89 | QSignalSpy pageCountChangedSpy(&pageNavigation, &QPdfPageNavigation::pageCountChanged); 90 | QSignalSpy canGoToPreviousPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged); 91 | QSignalSpy canGoToNextPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged); 92 | 93 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagenavigation.pdf")), QPdfDocument::NoError); 94 | 95 | QCOMPARE(currentPageChangedSpy.count(), 0); // current page stays '0' 96 | QCOMPARE(pageCountChangedSpy.count(), 1); 97 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), 3); 98 | QCOMPARE(canGoToPreviousPageChangedSpy.count(), 0); // still no previous page available 99 | QCOMPARE(canGoToNextPageChangedSpy.count(), 1); 100 | QCOMPARE(canGoToNextPageChangedSpy[0][0].toBool(), true); 101 | } 102 | 103 | void tst_QPdfPageNavigation::setLoadedDocument() 104 | { 105 | QPdfDocument document; 106 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagenavigation.pdf")), QPdfDocument::NoError); 107 | 108 | QPdfPageNavigation pageNavigation; 109 | 110 | QSignalSpy currentPageChangedSpy(&pageNavigation, &QPdfPageNavigation::currentPageChanged); 111 | QSignalSpy pageCountChangedSpy(&pageNavigation, &QPdfPageNavigation::pageCountChanged); 112 | QSignalSpy canGoToPreviousPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged); 113 | QSignalSpy canGoToNextPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged); 114 | 115 | pageNavigation.setDocument(&document); 116 | 117 | QCOMPARE(currentPageChangedSpy.count(), 0); // current page stays '0' 118 | QCOMPARE(pageCountChangedSpy.count(), 1); 119 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), 3); 120 | QCOMPARE(canGoToPreviousPageChangedSpy.count(), 0); // still no previous page available 121 | QCOMPARE(canGoToNextPageChangedSpy.count(), 1); 122 | QCOMPARE(canGoToNextPageChangedSpy[0][0].toBool(), true); 123 | } 124 | 125 | void tst_QPdfPageNavigation::unloadDocument() 126 | { 127 | QPdfDocument document; 128 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagenavigation.pdf")), QPdfDocument::NoError); 129 | 130 | QPdfPageNavigation pageNavigation; 131 | pageNavigation.setDocument(&document); 132 | 133 | QSignalSpy currentPageChangedSpy(&pageNavigation, &QPdfPageNavigation::currentPageChanged); 134 | QSignalSpy pageCountChangedSpy(&pageNavigation, &QPdfPageNavigation::pageCountChanged); 135 | QSignalSpy canGoToPreviousPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged); 136 | QSignalSpy canGoToNextPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged); 137 | 138 | document.close(); 139 | 140 | QCOMPARE(currentPageChangedSpy.count(), 0); // current page stays '0' 141 | QCOMPARE(pageCountChangedSpy.count(), 1); 142 | QCOMPARE(pageCountChangedSpy[0][0].toInt(), 0); 143 | QCOMPARE(canGoToPreviousPageChangedSpy.count(), 0); // still no previous page available 144 | QCOMPARE(canGoToNextPageChangedSpy.count(), 1); 145 | QCOMPARE(canGoToNextPageChangedSpy[0][0].toBool(), false); 146 | } 147 | 148 | void tst_QPdfPageNavigation::navigate() 149 | { 150 | QPdfDocument document; 151 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagenavigation.pdf")), QPdfDocument::NoError); 152 | 153 | QPdfPageNavigation pageNavigation; 154 | pageNavigation.setDocument(&document); 155 | 156 | QSignalSpy currentPageChangedSpy(&pageNavigation, &QPdfPageNavigation::currentPageChanged); 157 | QSignalSpy canGoToPreviousPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged); 158 | QSignalSpy canGoToNextPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged); 159 | 160 | QCOMPARE(pageNavigation.currentPage(), 0); 161 | 162 | // try to go to previous page while there is none 163 | QCOMPARE(pageNavigation.canGoToPreviousPage(), false); 164 | pageNavigation.goToPreviousPage(); 165 | QCOMPARE(canGoToPreviousPageChangedSpy.count(), 0); 166 | QCOMPARE(pageNavigation.currentPage(), 0); 167 | QCOMPARE(pageNavigation.canGoToPreviousPage(), false); 168 | 169 | // try to go to next page 170 | QCOMPARE(pageNavigation.canGoToNextPage(), true); 171 | pageNavigation.goToNextPage(); 172 | QCOMPARE(canGoToPreviousPageChangedSpy.count(), 1); 173 | QCOMPARE(canGoToNextPageChangedSpy.count(), 0); 174 | QCOMPARE(currentPageChangedSpy.count(), 1); 175 | QCOMPARE(pageNavigation.currentPage(), 1); 176 | QCOMPARE(pageNavigation.canGoToPreviousPage(), true); 177 | 178 | currentPageChangedSpy.clear(); 179 | canGoToPreviousPageChangedSpy.clear(); 180 | canGoToNextPageChangedSpy.clear(); 181 | 182 | // try to go to last page 183 | pageNavigation.setCurrentPage(2); 184 | QCOMPARE(canGoToPreviousPageChangedSpy.count(), 0); 185 | QCOMPARE(canGoToNextPageChangedSpy.count(), 1); 186 | QCOMPARE(currentPageChangedSpy.count(), 1); 187 | QCOMPARE(pageNavigation.currentPage(), 2); 188 | QCOMPARE(pageNavigation.canGoToNextPage(), false); 189 | 190 | // check that invalid requests are ignored 191 | pageNavigation.setCurrentPage(-1); 192 | QCOMPARE(pageNavigation.currentPage(), 2); 193 | 194 | pageNavigation.setCurrentPage(3); 195 | QCOMPARE(pageNavigation.currentPage(), 2); 196 | } 197 | 198 | QTEST_MAIN(tst_QPdfPageNavigation) 199 | 200 | #include "tst_qpdfpagenavigation.moc" 201 | -------------------------------------------------------------------------------- /tests/auto/qpdfpagerenderer/pdf-sample.pagerenderer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt-labs/qtpdf/ed87172a58bc82394569fbf059b04d2895208787/tests/auto/qpdfpagerenderer/pdf-sample.pagerenderer.pdf -------------------------------------------------------------------------------- /tests/auto/qpdfpagerenderer/qpdfpagerenderer.pro: -------------------------------------------------------------------------------- 1 | CONFIG += testcase 2 | TARGET = tst_qpdfpagerenderer 3 | QT += pdf testlib network 4 | macos:CONFIG -= app_bundle 5 | SOURCES += tst_qpdfpagerenderer.cpp 6 | -------------------------------------------------------------------------------- /tests/auto/qpdfpagerenderer/tst_qpdfpagerenderer.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König 4 | ** Contact: http://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the QtPDF module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL3$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see http://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at http://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or later as published by the Free 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in 29 | ** the packaging of this file. Please review the following information to 30 | ** ensure the GNU General Public License version 2.0 requirements will be 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. 32 | ** 33 | ** $QT_END_LICENSE$ 34 | ** 35 | ****************************************************************************/ 36 | 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | class tst_QPdfPageRenderer: public QObject 43 | { 44 | Q_OBJECT 45 | 46 | private slots: 47 | void defaultValues(); 48 | void withNoDocument(); 49 | void withEmptyDocument(); 50 | void withLoadedDocumentSingleThreaded(); 51 | void withLoadedDocumentMultiThreaded(); 52 | void switchingRenderMode(); 53 | }; 54 | 55 | void tst_QPdfPageRenderer::defaultValues() 56 | { 57 | QPdfPageRenderer pageRenderer; 58 | 59 | QCOMPARE(pageRenderer.document(), nullptr); 60 | QCOMPARE(pageRenderer.renderMode(), QPdfPageRenderer::SingleThreadedRenderMode); 61 | } 62 | 63 | void tst_QPdfPageRenderer::withNoDocument() 64 | { 65 | QPdfPageRenderer pageRenderer; 66 | 67 | const QSize imageSize(100, 100); 68 | const quint64 requestId = pageRenderer.requestPage(0, imageSize); 69 | 70 | QCOMPARE(requestId, quint64(0)); 71 | } 72 | 73 | void tst_QPdfPageRenderer::withEmptyDocument() 74 | { 75 | QPdfDocument document; 76 | QPdfPageRenderer pageRenderer; 77 | 78 | pageRenderer.setDocument(&document); 79 | 80 | const QSize imageSize(100, 100); 81 | const quint64 requestId = pageRenderer.requestPage(0, imageSize); 82 | 83 | QCOMPARE(requestId, quint64(0)); 84 | } 85 | 86 | void tst_QPdfPageRenderer::withLoadedDocumentSingleThreaded() 87 | { 88 | QPdfDocument document; 89 | QPdfPageRenderer pageRenderer; 90 | pageRenderer.setDocument(&document); 91 | 92 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagerenderer.pdf")), QPdfDocument::NoError); 93 | 94 | QSignalSpy pageRenderedSpy(&pageRenderer, &QPdfPageRenderer::pageRendered); 95 | 96 | const QSize imageSize(100, 100); 97 | const quint64 requestId = pageRenderer.requestPage(0, imageSize); 98 | 99 | QCOMPARE(requestId, quint64(1)); 100 | QTRY_COMPARE(pageRenderedSpy.count(), 1); 101 | QCOMPARE(pageRenderedSpy[0][0].toInt(), 0); 102 | QCOMPARE(pageRenderedSpy[0][1].toSize(), imageSize); 103 | QCOMPARE(pageRenderedSpy[0][2].value().size(), imageSize); 104 | QCOMPARE(pageRenderedSpy[0][4].toULongLong(), requestId); 105 | } 106 | 107 | void tst_QPdfPageRenderer::withLoadedDocumentMultiThreaded() 108 | { 109 | QPdfDocument document; 110 | 111 | QPdfPageRenderer pageRenderer; 112 | pageRenderer.setDocument(&document); 113 | pageRenderer.setRenderMode(QPdfPageRenderer::MultiThreadedRenderMode); 114 | 115 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagerenderer.pdf")), QPdfDocument::NoError); 116 | 117 | QSignalSpy pageRenderedSpy(&pageRenderer, &QPdfPageRenderer::pageRendered); 118 | 119 | const QSize imageSize(100, 100); 120 | const quint64 requestId = pageRenderer.requestPage(0, imageSize); 121 | 122 | QCOMPARE(requestId, quint64(1)); 123 | QTRY_COMPARE(pageRenderedSpy.count(), 1); 124 | QCOMPARE(pageRenderedSpy[0][0].toInt(), 0); 125 | QCOMPARE(pageRenderedSpy[0][1].toSize(), imageSize); 126 | QCOMPARE(pageRenderedSpy[0][2].value().size(), imageSize); 127 | QCOMPARE(pageRenderedSpy[0][4].toULongLong(), requestId); 128 | } 129 | 130 | void tst_QPdfPageRenderer::switchingRenderMode() 131 | { 132 | QPdfDocument document; 133 | QPdfPageRenderer pageRenderer; 134 | pageRenderer.setDocument(&document); 135 | 136 | QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagerenderer.pdf")), QPdfDocument::NoError); 137 | 138 | QSignalSpy pageRenderedSpy(&pageRenderer, &QPdfPageRenderer::pageRendered); 139 | 140 | // render single threaded 141 | const QSize imageSize(100, 100); 142 | const quint64 firstRequestId = pageRenderer.requestPage(0, imageSize); 143 | 144 | QTRY_COMPARE(pageRenderedSpy.count(), 1); 145 | QCOMPARE(pageRenderedSpy[0][0].toInt(), 0); 146 | QCOMPARE(pageRenderedSpy[0][1].toSize(), imageSize); 147 | QCOMPARE(pageRenderedSpy[0][2].value().size(), imageSize); 148 | QCOMPARE(pageRenderedSpy[0][4].toULongLong(), firstRequestId); 149 | 150 | const QImage image = pageRenderedSpy[0][2].value(); 151 | 152 | pageRenderedSpy.clear(); 153 | 154 | // switch to multi threaded 155 | pageRenderer.setRenderMode(QPdfPageRenderer::MultiThreadedRenderMode); 156 | 157 | const quint64 secondRequestId = pageRenderer.requestPage(0, imageSize); 158 | 159 | QVERIFY(firstRequestId != secondRequestId); 160 | QTRY_COMPARE(pageRenderedSpy.count(), 1); 161 | QCOMPARE(pageRenderedSpy[0][0].toInt(), 0); 162 | QCOMPARE(pageRenderedSpy[0][1].toSize(), imageSize); 163 | QCOMPARE(pageRenderedSpy[0][2].value(), image); 164 | QCOMPARE(pageRenderedSpy[0][2].value().size(), imageSize); 165 | QCOMPARE(pageRenderedSpy[0][4].toULongLong(), secondRequestId); 166 | 167 | pageRenderedSpy.clear(); 168 | 169 | // switch back to single threaded 170 | pageRenderer.setRenderMode(QPdfPageRenderer::SingleThreadedRenderMode); 171 | 172 | const quint64 thirdRequestId = pageRenderer.requestPage(0, imageSize); 173 | 174 | QTRY_COMPARE(pageRenderedSpy.count(), 1); 175 | QCOMPARE(pageRenderedSpy[0][0].toInt(), 0); 176 | QCOMPARE(pageRenderedSpy[0][1].toSize(), imageSize); 177 | QCOMPARE(pageRenderedSpy[0][2].value(), image); 178 | QCOMPARE(pageRenderedSpy[0][2].value().size(), imageSize); 179 | QCOMPARE(pageRenderedSpy[0][4].toULongLong(), thirdRequestId); 180 | } 181 | 182 | QTEST_MAIN(tst_QPdfPageRenderer) 183 | 184 | #include "tst_qpdfpagerenderer.moc" 185 | -------------------------------------------------------------------------------- /tests/tests.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = auto 3 | --------------------------------------------------------------------------------