1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include <qpdfwriter.h>
41 
42 #ifndef QT_NO_PDF
43 
44 #include "qpagedpaintdevice_p.h"
45 #include <QtCore/private/qobject_p.h>
46 #include "private/qpdf_p.h"
47 #include <QtCore/qfile.h>
48 
49 QT_BEGIN_NAMESPACE
50 
51 class QPdfWriterPrivate : public QObjectPrivate
52 {
53 public:
QPdfWriterPrivate()54     QPdfWriterPrivate()
55         : QObjectPrivate()
56     {
57         engine = new QPdfEngine();
58         output = nullptr;
59         pdfVersion = QPdfWriter::PdfVersion_1_4;
60     }
~QPdfWriterPrivate()61     ~QPdfWriterPrivate()
62     {
63         delete engine;
64         delete output;
65     }
66 
67     QPdfEngine *engine;
68     QFile *output;
69     QPdfWriter::PdfVersion pdfVersion;
70 };
71 
72 class QPdfPagedPaintDevicePrivate : public QPagedPaintDevicePrivate
73 {
74 public:
QPdfPagedPaintDevicePrivate(QPdfWriterPrivate * d)75     QPdfPagedPaintDevicePrivate(QPdfWriterPrivate *d)
76         : QPagedPaintDevicePrivate(), pd(d)
77     {}
78 
~QPdfPagedPaintDevicePrivate()79     ~QPdfPagedPaintDevicePrivate()
80     {}
81 
setPageLayout(const QPageLayout & newPageLayout)82     bool setPageLayout(const QPageLayout &newPageLayout) override
83     {
84         // Try to set the paint engine page layout
85         pd->engine->setPageLayout(newPageLayout);
86         return pageLayout().isEquivalentTo(newPageLayout);
87     }
88 
setPageSize(const QPageSize & pageSize)89     bool setPageSize(const QPageSize &pageSize) override
90     {
91         // Try to set the paint engine page size
92         pd->engine->setPageSize(pageSize);
93         return pageLayout().pageSize().isEquivalentTo(pageSize);
94     }
95 
setPageOrientation(QPageLayout::Orientation orientation)96     bool setPageOrientation(QPageLayout::Orientation orientation) override
97     {
98         // Set the print engine value
99         pd->engine->setPageOrientation(orientation);
100         return pageLayout().orientation() == orientation;
101     }
102 
setPageMargins(const QMarginsF & margins,QPageLayout::Unit units)103     bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override
104     {
105         // Try to set engine margins
106         pd->engine->setPageMargins(margins, units);
107         return pageLayout().margins() == margins && pageLayout().units() == units;
108     }
109 
pageLayout() const110     QPageLayout pageLayout() const override
111     {
112         return pd->engine->pageLayout();
113     }
114 
115     QPdfWriterPrivate *pd;
116 };
117 
118 /*! \class QPdfWriter
119     \inmodule QtGui
120 
121     \brief The QPdfWriter class is a class to generate PDFs
122     that can be used as a paint device.
123 
124     \ingroup painting
125 
126     QPdfWriter generates PDF out of a series of drawing commands using QPainter.
127     The newPage() method can be used to create several pages.
128   */
129 
130 /*!
131   Constructs a PDF writer that will write the pdf to \a filename.
132   */
QPdfWriter(const QString & filename)133 QPdfWriter::QPdfWriter(const QString &filename)
134     : QObject(*new QPdfWriterPrivate),
135       QPagedPaintDevice(new QPdfPagedPaintDevicePrivate(d_func()))
136 {
137     Q_D(QPdfWriter);
138 
139     d->engine->setOutputFilename(filename);
140 }
141 
142 /*!
143   Constructs a PDF writer that will write the pdf to \a device.
144   */
QPdfWriter(QIODevice * device)145 QPdfWriter::QPdfWriter(QIODevice *device)
146     : QObject(*new QPdfWriterPrivate),
147       QPagedPaintDevice(new QPdfPagedPaintDevicePrivate(d_func()))
148 {
149     Q_D(QPdfWriter);
150 
151     d->engine->d_func()->outDevice = device;
152 }
153 
154 /*!
155   Destroys the pdf writer.
156   */
~QPdfWriter()157 QPdfWriter::~QPdfWriter()
158 {
159 
160 }
161 
162 /*!
163     \since 5.10
164 
165     Sets the PDF version for this writer to \a version.
166 
167     If \a version is the same value as currently set then no change will be made.
168 */
setPdfVersion(PdfVersion version)169 void QPdfWriter::setPdfVersion(PdfVersion version)
170 {
171     Q_D(QPdfWriter);
172 
173     if (d->pdfVersion == version)
174         return;
175 
176     d->pdfVersion = version;
177     d->engine->setPdfVersion(static_cast<QPdfEngine::PdfVersion>(static_cast<int>(version)));
178 }
179 
180 /*!
181     \since 5.10
182 
183     Returns the PDF version for this writer. The default is \c PdfVersion_1_4.
184 */
pdfVersion() const185 QPdfWriter::PdfVersion QPdfWriter::pdfVersion() const
186 {
187     Q_D(const QPdfWriter);
188     return d->pdfVersion;
189 }
190 
191 /*!
192   Returns the title of the document.
193   */
title() const194 QString QPdfWriter::title() const
195 {
196     Q_D(const QPdfWriter);
197     return d->engine->d_func()->title;
198 }
199 
200 /*!
201   Sets the title of the document being created to \a title.
202   */
setTitle(const QString & title)203 void QPdfWriter::setTitle(const QString &title)
204 {
205     Q_D(QPdfWriter);
206     d->engine->d_func()->title = title;
207 }
208 
209 /*!
210   Returns the creator of the document.
211   */
creator() const212 QString QPdfWriter::creator() const
213 {
214     Q_D(const QPdfWriter);
215     return d->engine->d_func()->creator;
216 }
217 
218 /*!
219   Sets the creator of the document to \a creator.
220   */
setCreator(const QString & creator)221 void QPdfWriter::setCreator(const QString &creator)
222 {
223     Q_D(QPdfWriter);
224     d->engine->d_func()->creator = creator;
225 }
226 
227 /*!
228   \reimp
229   */
paintEngine() const230 QPaintEngine *QPdfWriter::paintEngine() const
231 {
232     Q_D(const QPdfWriter);
233 
234     return d->engine;
235 }
236 
237 /*!
238     \since 5.3
239 
240     Sets the PDF \a resolution in DPI.
241 
242     This setting affects the coordinate system as returned by, for
243     example QPainter::viewport().
244 
245     \sa resolution()
246 */
247 
setResolution(int resolution)248 void QPdfWriter::setResolution(int resolution)
249 {
250     Q_D(const QPdfWriter);
251     if (resolution > 0)
252         d->engine->setResolution(resolution);
253 }
254 
255 /*!
256     \since 5.3
257 
258     Returns the resolution of the PDF in DPI.
259 
260     \sa setResolution()
261 */
262 
resolution() const263 int QPdfWriter::resolution() const
264 {
265     Q_D(const QPdfWriter);
266     return d->engine->resolution();
267 }
268 
269 /*!
270     \since 5.15
271 
272     Sets the document metadata. This metadata is not influenced by the setTitle / setCreator methods,
273     so is up to the user to keep it consistent.
274     \a xmpMetadata contains XML formatted metadata to embed into the PDF file.
275 
276     \sa documentXmpMetadata()
277 */
278 
setDocumentXmpMetadata(const QByteArray & xmpMetadata)279 void QPdfWriter::setDocumentXmpMetadata(const QByteArray &xmpMetadata)
280 {
281     Q_D(const QPdfWriter);
282     d->engine->setDocumentXmpMetadata(xmpMetadata);
283 }
284 
285 /*!
286     \since 5.15
287 
288     Gets the document metadata, as it was provided with a call to setDocumentXmpMetadata. It will not
289     return the default metadata.
290 
291     \sa setDocumentXmpMetadata()
292 */
293 
documentXmpMetadata() const294 QByteArray QPdfWriter::documentXmpMetadata() const
295 {
296     Q_D(const QPdfWriter);
297     return d->engine->documentXmpMetadata();
298 }
299 
300 /*!
301     \since 5.15
302 
303     Adds \a fileName attachment to the PDF with (optional) \a mimeType.
304     \a data contains the raw file data to embed into the PDF file.
305 */
306 
addFileAttachment(const QString & fileName,const QByteArray & data,const QString & mimeType)307 void QPdfWriter::addFileAttachment(const QString &fileName, const QByteArray &data, const QString &mimeType)
308 {
309     Q_D(QPdfWriter);
310     d->engine->addFileAttachment(fileName, data, mimeType);
311 }
312 
313 // Defined in QPagedPaintDevice but non-virtual, add QPdfWriter specific doc here
314 #ifdef Q_QDOC
315 /*!
316     \fn bool QPdfWriter::setPageLayout(const QPageLayout &newPageLayout)
317     \since 5.3
318 
319     Sets the PDF page layout to \a newPageLayout.
320 
321     You should call this before calling QPainter::begin(), or immediately
322     before calling newPage() to apply the new page layout to a new page.
323     You should not call any painting methods between a call to setPageLayout()
324     and newPage() as the wrong paint metrics may be used.
325 
326     Returns true if the page layout was successfully set to \a newPageLayout.
327 
328     \sa pageLayout()
329 */
330 
331 /*!
332     \fn bool QPdfWriter::setPageSize(const QPageSize &pageSize)
333     \since 5.3
334 
335     Sets the PDF page size to \a pageSize.
336 
337     To get the current QPageSize use pageLayout().pageSize().
338 
339     You should call this before calling QPainter::begin(), or immediately
340     before calling newPage() to apply the new page size to a new page.
341     You should not call any painting methods between a call to setPageSize()
342     and newPage() as the wrong paint metrics may be used.
343 
344     Returns true if the page size was successfully set to \a pageSize.
345 
346     \sa pageLayout()
347 */
348 
349 /*!
350     \fn bool QPdfWriter::setPageOrientation(QPageLayout::Orientation orientation)
351     \since 5.3
352 
353     Sets the PDF page \a orientation.
354 
355     The page orientation is used to define the orientation of the
356     page size when obtaining the page rect.
357 
358     You should call this before calling QPainter::begin(), or immediately
359     before calling newPage() to apply the new orientation to a new page.
360     You should not call any painting methods between a call to setPageOrientation()
361     and newPage() as the wrong paint metrics may be used.
362 
363     To get the current QPageLayout::Orientation use pageLayout().orientation().
364 
365     Returns true if the page orientation was successfully set to \a orientation.
366 
367     \sa pageLayout()
368 */
369 
370 /*!
371     \fn bool QPdfWriter::setPageMargins(const QMarginsF &margins)
372     \since 5.3
373 
374     Set the PDF page \a margins in the current page layout units.
375 
376     You should call this before calling QPainter::begin(), or immediately
377     before calling newPage() to apply the new margins to a new page.
378     You should not call any painting methods between a call to setPageMargins()
379     and newPage() as the wrong paint metrics may be used.
380 
381     To get the current page margins use pageLayout().margins().
382 
383     Returns true if the page margins were successfully set to \a margins.
384 
385     \sa pageLayout()
386 */
387 
388 /*!
389     \fn bool QPdfWriter::setPageMargins(const QMarginsF &margins, QPageLayout::Unit units)
390     \since 5.3
391 
392     Set the PDF page \a margins defined in the given \a units.
393 
394     You should call this before calling QPainter::begin(), or immediately
395     before calling newPage() to apply the new margins to a new page.
396     You should not call any painting methods between a call to setPageMargins()
397     and newPage() as the wrong paint metrics may be used.
398 
399     To get the current page margins use pageLayout().margins().
400 
401     Returns true if the page margins were successfully set to \a margins.
402 
403     \sa pageLayout()
404 */
405 
406 /*!
407     \fn QPageLayout QPdfWriter::pageLayout() const
408     \since 5.3
409 
410     Returns the current page layout.  Use this method to access the current
411     QPageSize, QPageLayout::Orientation, QMarginsF, fullRect() and paintRect().
412 
413     Note that you cannot use the setters on the returned object, you must either
414     call the individual QPdfWriter methods or use setPageLayout().
415 
416     \sa setPageLayout(), setPageSize(), setPageOrientation(), setPageMargins()
417 */
418 #endif
419 
420 #if QT_DEPRECATED_SINCE(5, 14)
421 QT_WARNING_PUSH
422 QT_WARNING_DISABLE_DEPRECATED
423 /*!
424     \reimp
425 
426     \obsolete Use setPageSize(QPageSize(id)) instead
427 
428     \sa setPageSize()
429 */
430 
setPageSize(PageSize size)431 void QPdfWriter::setPageSize(PageSize size)
432 {
433     setPageSize(QPageSize(QPageSize::PageSizeId(size)));
434 }
435 
436 /*!
437     \reimp
438 
439     \obsolete Use setPageSize(QPageSize(size, QPageSize::Millimeter)) instead
440 
441     \sa setPageSize()
442 */
443 
setPageSizeMM(const QSizeF & size)444 void QPdfWriter::setPageSizeMM(const QSizeF &size)
445 {
446     setPageSize(QPageSize(size, QPageSize::Millimeter));
447 }
448 QT_WARNING_POP
449 #endif
450 
451 /*!
452     \internal
453 
454     Returns the metric for the given \a id.
455 */
metric(PaintDeviceMetric id) const456 int QPdfWriter::metric(PaintDeviceMetric id) const
457 {
458     Q_D(const QPdfWriter);
459     return d->engine->metric(id);
460 }
461 
462 /*!
463   \reimp
464 */
newPage()465 bool QPdfWriter::newPage()
466 {
467     Q_D(QPdfWriter);
468 
469     return d->engine->newPage();
470 }
471 
472 
473 #if QT_DEPRECATED_SINCE(5, 14)
474 QT_WARNING_PUSH
475 QT_WARNING_DISABLE_DEPRECATED
476 /*!
477     \reimp
478 
479     \obsolete Use setPageMargins(QMarginsF(l, t, r, b), QPageLayout::Millimeter) instead
480 
481     \sa setPageMargins()
482   */
setMargins(const Margins & m)483 void QPdfWriter::setMargins(const Margins &m)
484 {
485     setPageMargins(QMarginsF(m.left, m.top, m.right, m.bottom), QPageLayout::Millimeter);
486 }
487 QT_WARNING_POP
488 #endif
489 
490 QT_END_NAMESPACE
491 
492 #endif // QT_NO_PDF
493