├── .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 |
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 |
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 |
--------------------------------------------------------------------------------