Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qpdfiohandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include <QLoggingCategory>
6#include <QPainter>
7#include <QtPdf/private/qpdffile_p.h>
8#include <QtPdf/private/qtpdfglobal_p.h>
9
11
12Q_PDF_LOGGING_CATEGORY(qLcPdf, "qt.imageformat.pdf")
13
14QPdfIOHandler::QPdfIOHandler()
15{
16}
17
18QPdfIOHandler::~QPdfIOHandler()
19{
20 if (m_ownsDocument)
21 delete m_doc;
22}
23
24bool QPdfIOHandler::canRead() const
25{
26 if (!device())
27 return false;
28 if (m_loaded)
29 return true;
30 if (QPdfIOHandler::canRead(device())) {
31 setFormat("pdf");
32 return true;
33 }
34 return false;
35}
36
37bool QPdfIOHandler::canRead(QIODevice *device)
38{
39 char buf[6];
40 if (device->peek(buf, 6) != 6)
41 return false;
42 return (!qstrncmp(buf, "%PDF-", 5) || Q_UNLIKELY(!qstrncmp(buf, "\012%PDF-", 6)));
43}
44
45int QPdfIOHandler::currentImageNumber() const
46{
47 return m_page;
48}
49
50QRect QPdfIOHandler::currentImageRect() const
51{
52 return QRect(QPoint(0, 0), m_doc->pagePointSize(m_page).toSize());
53}
54
55int QPdfIOHandler::imageCount() const
56{
57 int ret = 0;
58 if (const_cast<QPdfIOHandler *>(this)->load(device()))
59 ret = m_doc->pageCount();
60 qCDebug(qLcPdf) << ret;
61 return ret;
62}
63
64bool QPdfIOHandler::read(QImage *image)
65{
66 if (load(device())) {
67 if (m_doc.isNull() || m_page >= m_doc->pageCount())
68 return false;
69 if (m_page < 0)
70 m_page = 0;
71 const bool xform = (m_clipRect.isValid() || m_scaledSize.isValid() || m_scaledClipRect.isValid());
72 QSize pageSize = m_doc->pagePointSize(m_page).toSize();
73 QSize finalSize = pageSize;
74 QRectF bounds;
75 if (xform && !finalSize.isEmpty()) {
76 bounds = QRectF(QPointF(0,0), QSizeF(finalSize));
77 QPoint tr1, tr2;
78 QSizeF sc(1, 1);
79 if (m_clipRect.isValid()) {
80 tr1 = -m_clipRect.topLeft();
81 finalSize = m_clipRect.size();
82 }
83 if (m_scaledSize.isValid()) {
84 sc = QSizeF(qreal(m_scaledSize.width()) / finalSize.width(),
85 qreal(m_scaledSize.height()) / finalSize.height());
86 finalSize = m_scaledSize;
87 pageSize = m_scaledSize;
88 }
89 if (m_scaledClipRect.isValid()) {
90 tr2 = -m_scaledClipRect.topLeft();
91 finalSize = m_scaledClipRect.size();
92 }
93 QTransform t;
94 t.translate(tr2.x(), tr2.y());
95 t.scale(sc.width(), sc.height());
96 t.translate(tr1.x(), tr1.y());
97 bounds = t.mapRect(bounds);
98 }
99 qCDebug(qLcPdf) << m_page << finalSize;
100 if (image->size() != finalSize || !image->reinterpretAsFormat(QImage::Format_ARGB32_Premultiplied)) {
101 *image = QImage(finalSize, QImage::Format_ARGB32_Premultiplied);
102 if (!finalSize.isEmpty() && image->isNull()) {
103 // avoid QTBUG-68229
104 qWarning("QPdfIOHandler: QImage allocation failed (size %i x %i)", finalSize.width(), finalSize.height());
105 return false;
106 }
107 }
108 if (!finalSize.isEmpty()) {
109 QPdfDocumentRenderOptions options;
110 if (m_scaledClipRect.isValid())
111 options.setScaledClipRect(m_scaledClipRect);
112 options.setScaledSize(pageSize);
113 image->fill(m_backColor.rgba());
114 QPainter p(image);
115 if (!m_doc.isNull()) {
116 QImage pageImage = m_doc->render(m_page, finalSize, options);
117 p.drawImage(0, 0, pageImage);
118 p.end();
119 }
120 }
121 return true;
122 }
123
124 return false;
125}
126
127QVariant QPdfIOHandler::option(ImageOption option) const
128{
129 switch (option) {
130 case ImageFormat:
131 return QImage::Format_ARGB32_Premultiplied;
132 case Size:
133 const_cast<QPdfIOHandler *>(this)->load(device());
134 return m_doc->pagePointSize(qMax(0, m_page));
135 case ClipRect:
136 return m_clipRect;
137 case ScaledSize:
138 return m_scaledSize;
139 case ScaledClipRect:
140 return m_scaledClipRect;
141 case BackgroundColor:
142 return m_backColor;
143 case Name:
144 return m_doc->metaData(QPdfDocument::MetaDataField::Title);
145 default:
146 break;
147 }
148 return QVariant();
149}
150
151void QPdfIOHandler::setOption(ImageOption option, const QVariant & value)
152{
153 switch (option) {
154 case ClipRect:
155 m_clipRect = value.toRect();
156 break;
157 case ScaledSize:
158 m_scaledSize = value.toSize();
159 break;
160 case ScaledClipRect:
161 m_scaledClipRect = value.toRect();
162 break;
163 case BackgroundColor:
164 m_backColor = value.value<QColor>();
165 break;
166 default:
167 break;
168 }
169}
170
171bool QPdfIOHandler::supportsOption(ImageOption option) const
172{
173 switch (option)
174 {
175 case ImageFormat:
176 case Size:
177 case ClipRect:
178 case ScaledSize:
179 case ScaledClipRect:
180 case BackgroundColor:
181 case Name:
182 return true;
183 default:
184 break;
185 }
186 return false;
187}
188
189bool QPdfIOHandler::jumpToImage(int frame)
190{
191 qCDebug(qLcPdf) << frame;
192 if (frame < 0 || frame >= imageCount())
193 return false;
194 m_page = frame;
195 return true;
196}
197
198bool QPdfIOHandler::jumpToNextImage()
199{
200 return jumpToImage(m_page + 1);
201}
202
203bool QPdfIOHandler::load(QIODevice *device)
204{
205 if (m_loaded)
206 return true;
207 if (format().isEmpty())
208 if (!canRead())
209 return false;
210
211 QPdfFile *pdfFile = qobject_cast<QPdfFile *>(device);
212 if (pdfFile) {
213 m_doc = pdfFile->document();
214 m_ownsDocument = false;
215 qCDebug(qLcPdf) << "loading via QPdfFile, reusing document instance" << m_doc;
216 } else {
217 m_doc = new QPdfDocument();
218 m_ownsDocument = true;
219 m_doc->load(device);
220 qCDebug(qLcPdf) << "loading via new document instance" << m_doc;
221 }
222 m_loaded = (m_doc->error() == QPdfDocument::Error::None);
223
224 return m_loaded;
225}
226
227QT_END_NAMESPACE