/src/poppler/qt6/src/poppler-pdf-converter.cc
Line | Count | Source |
1 | | /* poppler-pdf-converter.cc: qt interface to poppler |
2 | | * Copyright (C) 2008, Pino Toscano <pino@kde.org> |
3 | | * Copyright (C) 2008, 2009, 2020-2022, 2024, 2025, Albert Astals Cid <aacid@kde.org> |
4 | | * Copyright (C) 2020, Thorsten Behrens <Thorsten.Behrens@CIB.de> |
5 | | * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by Technische Universität Dresden |
6 | | * Copyright (C) 2021, Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. |
7 | | * Copyright (C) 2021, Zachary Travis <ztravis@everlaw.com> |
8 | | * Copyright (C) 2021, Georgiy Sgibnev <georgiy@sgibnev.com>. Work sponsored by lab50.net. |
9 | | * Copyright (C) 2022, Martin <martinbts@gmx.net> |
10 | | * Copyright (C) 2022, Felix Jung <fxjung@posteo.de> |
11 | | * Copyright (C) 2024, 2026, g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk> |
12 | | * |
13 | | * This program is free software; you can redistribute it and/or modify |
14 | | * it under the terms of the GNU General Public License as published by |
15 | | * the Free Software Foundation; either version 2, or (at your option) |
16 | | * any later version. |
17 | | * |
18 | | * This program is distributed in the hope that it will be useful, |
19 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | | * GNU General Public License for more details. |
22 | | * |
23 | | * You should have received a copy of the GNU General Public License |
24 | | * along with this program; if not, write to the Free Software |
25 | | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
26 | | */ |
27 | | |
28 | | #include "poppler-converter.h" |
29 | | #include "poppler-qt6.h" |
30 | | |
31 | | #include "poppler-annotation-helper.h" |
32 | | #include "poppler-annotation-private.h" |
33 | | #include "poppler-private.h" |
34 | | #include "poppler-converter-private.h" |
35 | | #include "poppler-qiodeviceoutstream-private.h" |
36 | | |
37 | | #include <QFile> |
38 | | #include <QUuid> |
39 | | |
40 | | #include "Form.h" |
41 | | #include <ErrorCodes.h> |
42 | | |
43 | | namespace Poppler { |
44 | | |
45 | | class PDFConverterPrivate : public BaseConverterPrivate |
46 | | { |
47 | | public: |
48 | | PDFConverterPrivate(); |
49 | | ~PDFConverterPrivate() override; |
50 | | |
51 | | PDFConverter::PDFOptions opts; |
52 | | }; |
53 | | |
54 | 0 | PDFConverterPrivate::PDFConverterPrivate() = default; |
55 | | |
56 | 0 | PDFConverterPrivate::~PDFConverterPrivate() = default; |
57 | | |
58 | 0 | PDFConverter::PDFConverter(DocumentData *document) : BaseConverter(*new PDFConverterPrivate()) |
59 | 0 | { |
60 | 0 | Q_D(PDFConverter); |
61 | 0 | d->document = document; |
62 | 0 | } |
63 | | |
64 | 0 | PDFConverter::~PDFConverter() = default; |
65 | | |
66 | | void PDFConverter::setPDFOptions(PDFConverter::PDFOptions options) |
67 | 0 | { |
68 | 0 | Q_D(PDFConverter); |
69 | 0 | d->opts = options; |
70 | 0 | } |
71 | | |
72 | | PDFConverter::PDFOptions PDFConverter::pdfOptions() const |
73 | 0 | { |
74 | 0 | Q_D(const PDFConverter); |
75 | 0 | return d->opts; |
76 | 0 | } |
77 | | |
78 | | bool PDFConverter::convert() |
79 | 0 | { |
80 | 0 | Q_D(PDFConverter); |
81 | 0 | d->lastError = NoError; |
82 | |
|
83 | 0 | if (d->document->locked) { |
84 | 0 | d->lastError = FileLockedError; |
85 | 0 | return false; |
86 | 0 | } |
87 | | |
88 | 0 | QIODevice *dev = d->openDevice(); |
89 | 0 | if (!dev) { |
90 | 0 | d->lastError = OpenOutputError; |
91 | 0 | return false; |
92 | 0 | } |
93 | | |
94 | 0 | bool deleteFile = false; |
95 | 0 | if (auto *file = qobject_cast<QFile *>(dev)) { |
96 | 0 | deleteFile = !file->exists(); |
97 | 0 | } |
98 | |
|
99 | 0 | int errorCode = errNone; |
100 | 0 | QIODeviceOutStream stream(dev); |
101 | 0 | if (d->opts & WithChanges) { |
102 | 0 | errorCode = d->document->doc->saveAs(&stream); |
103 | 0 | } else { |
104 | 0 | errorCode = d->document->doc->saveWithoutChangesAs(&stream); |
105 | 0 | } |
106 | 0 | d->closeDevice(); |
107 | 0 | if (errorCode != errNone) { |
108 | 0 | if (deleteFile) { |
109 | 0 | qobject_cast<QFile *>(dev)->remove(); |
110 | 0 | } |
111 | 0 | if (errorCode == errOpenFile) { |
112 | 0 | d->lastError = OpenOutputError; |
113 | 0 | } else { |
114 | 0 | d->lastError = NotSupportedInputFileError; |
115 | 0 | } |
116 | 0 | } |
117 | |
|
118 | 0 | return (errorCode == errNone); |
119 | 0 | } |
120 | | |
121 | | bool PDFConverter::sign(const NewSignatureData &data) |
122 | 0 | { |
123 | 0 | Q_D(PDFConverter); |
124 | 0 | d->lastError = NoError; |
125 | |
|
126 | 0 | if (d->document->locked) { |
127 | 0 | d->lastError = FileLockedError; |
128 | 0 | return false; |
129 | 0 | } |
130 | | |
131 | 0 | if (data.signatureText().isEmpty()) { |
132 | 0 | qWarning() << "No signature text given"; |
133 | 0 | return false; |
134 | 0 | } |
135 | | |
136 | 0 | ::PDFDoc *doc = d->document->doc.get(); |
137 | 0 | ::Page *destPage = doc->getPage(data.page() + 1); |
138 | 0 | std::unique_ptr<GooString> gSignatureText = std::unique_ptr<GooString>(QStringToUnicodeGooString(data.signatureText())); |
139 | 0 | std::unique_ptr<GooString> gSignatureLeftText = std::unique_ptr<GooString>(QStringToUnicodeGooString(data.signatureLeftText())); |
140 | 0 | const auto reason = std::unique_ptr<GooString>(data.reason().isEmpty() ? nullptr : QStringToUnicodeGooString(data.reason())); |
141 | 0 | const auto location = std::unique_ptr<GooString>(data.location().isEmpty() ? nullptr : QStringToUnicodeGooString(data.location())); |
142 | 0 | const auto ownerPwd = std::optional<GooString>(data.documentOwnerPassword().constData()); |
143 | 0 | const auto userPwd = std::optional<GooString>(data.documentUserPassword().constData()); |
144 | 0 | auto failure = doc->sign(d->outputFileName.toUtf8().constData(), data.certNickname().toUtf8().constData(), data.password().toUtf8().constData(), QStringToGooString(data.fieldPartialName()), data.page() + 1, |
145 | 0 | boundaryToPdfRectangle(destPage, data.boundingRectangle(), Annotation::FixedRotation), *gSignatureText, *gSignatureLeftText, data.fontSize(), data.leftFontSize(), convertQColor(data.fontColor()), |
146 | 0 | data.borderWidth(), convertQColor(data.borderColor()), convertQColor(data.backgroundColor()), reason.get(), location.get(), data.imagePath().toStdString(), ownerPwd, userPwd); |
147 | 0 | if (failure) { |
148 | 0 | d->lastSigningErrorDetails = fromPopplerCore(failure.value().message); |
149 | 0 | d->lastSigningResult = GenericSigningError; // catch all |
150 | 0 | switch (failure.value().type) { |
151 | 0 | case CryptoSign::SigningError::GenericError: |
152 | 0 | d->lastSigningResult = GenericSigningError; |
153 | 0 | break; |
154 | 0 | case CryptoSign::SigningError::InternalError: |
155 | 0 | d->lastSigningResult = InternalError; |
156 | 0 | break; |
157 | 0 | case CryptoSign::SigningError::KeyMissing: |
158 | 0 | d->lastSigningResult = KeyMissing; |
159 | 0 | break; |
160 | 0 | case CryptoSign::SigningError::UserCancelled: |
161 | 0 | d->lastSigningResult = UserCancelled; |
162 | |
|
163 | 0 | break; |
164 | 0 | case CryptoSign::SigningError::WriteFailed: |
165 | 0 | d->lastSigningResult = WriteFailed; |
166 | 0 | break; |
167 | 0 | case CryptoSign::SigningError::BadPassphrase: |
168 | |
|
169 | 0 | d->lastSigningResult = BadPassphrase; |
170 | 0 | break; |
171 | 0 | } |
172 | 0 | return false; |
173 | 0 | } |
174 | 0 | d->lastSigningErrorDetails = {}; |
175 | 0 | d->lastSigningResult = SigningSuccess; |
176 | 0 | return true; |
177 | 0 | } |
178 | | |
179 | | PDFConverter::SigningResult PDFConverter::lastSigningResult() const |
180 | 0 | { |
181 | 0 | Q_D(const PDFConverter); |
182 | 0 | return d->lastSigningResult; |
183 | 0 | } |
184 | | |
185 | | Poppler::ErrorString PDFConverter::lastSigningErrorDetails() const |
186 | 0 | { |
187 | 0 | Q_D(const PDFConverter); |
188 | 0 | return d->lastSigningErrorDetails; |
189 | 0 | } |
190 | | |
191 | | struct PDFConverter::NewSignatureData::NewSignatureDataPrivate |
192 | | { |
193 | 0 | NewSignatureDataPrivate() = default; |
194 | | |
195 | | QString certNickname; |
196 | | QString password; |
197 | | int page; |
198 | | QRectF boundingRectangle; |
199 | | QString signatureText; |
200 | | QString signatureLeftText; |
201 | | QString reason; |
202 | | QString location; |
203 | | double fontSize = 10.0; |
204 | | double leftFontSize = 20.0; |
205 | | QColor fontColor = Qt::red; |
206 | | QColor borderColor = Qt::red; |
207 | | double borderWidth = 1.5; |
208 | | QColor backgroundColor = QColor(240, 240, 240); |
209 | | |
210 | | QString partialName = QUuid::createUuid().toString(); |
211 | | |
212 | | QByteArray documentOwnerPassword; |
213 | | QByteArray documentUserPassword; |
214 | | |
215 | | QString imagePath; |
216 | | }; |
217 | | |
218 | 0 | PDFConverter::NewSignatureData::NewSignatureData() : d(new NewSignatureDataPrivate()) { } |
219 | | |
220 | | PDFConverter::NewSignatureData::~NewSignatureData() |
221 | 0 | { |
222 | 0 | delete d; |
223 | 0 | } |
224 | | |
225 | | QString PDFConverter::NewSignatureData::certNickname() const |
226 | 0 | { |
227 | 0 | return d->certNickname; |
228 | 0 | } |
229 | | |
230 | | void PDFConverter::NewSignatureData::setCertNickname(const QString &certNickname) |
231 | 0 | { |
232 | 0 | d->certNickname = certNickname; |
233 | 0 | } |
234 | | |
235 | | QString PDFConverter::NewSignatureData::password() const |
236 | 0 | { |
237 | 0 | return d->password; |
238 | 0 | } |
239 | | |
240 | | void PDFConverter::NewSignatureData::setPassword(const QString &password) |
241 | 0 | { |
242 | 0 | d->password = password; |
243 | 0 | } |
244 | | |
245 | | int PDFConverter::NewSignatureData::page() const |
246 | 0 | { |
247 | 0 | return d->page; |
248 | 0 | } |
249 | | |
250 | | void PDFConverter::NewSignatureData::setPage(int page) |
251 | 0 | { |
252 | 0 | d->page = page; |
253 | 0 | } |
254 | | |
255 | | QRectF PDFConverter::NewSignatureData::boundingRectangle() const |
256 | 0 | { |
257 | 0 | return d->boundingRectangle; |
258 | 0 | } |
259 | | |
260 | | void PDFConverter::NewSignatureData::setBoundingRectangle(const QRectF &rect) |
261 | 0 | { |
262 | 0 | d->boundingRectangle = rect; |
263 | 0 | } |
264 | | |
265 | | QString PDFConverter::NewSignatureData::signatureText() const |
266 | 0 | { |
267 | 0 | return d->signatureText; |
268 | 0 | } |
269 | | |
270 | | void PDFConverter::NewSignatureData::setSignatureText(const QString &text) |
271 | 0 | { |
272 | 0 | d->signatureText = text; |
273 | 0 | } |
274 | | |
275 | | QString PDFConverter::NewSignatureData::signatureLeftText() const |
276 | 0 | { |
277 | 0 | return d->signatureLeftText; |
278 | 0 | } |
279 | | |
280 | | void PDFConverter::NewSignatureData::setSignatureLeftText(const QString &text) |
281 | 0 | { |
282 | 0 | d->signatureLeftText = text; |
283 | 0 | } |
284 | | |
285 | | QString PDFConverter::NewSignatureData::reason() const |
286 | 0 | { |
287 | 0 | return d->reason; |
288 | 0 | } |
289 | | |
290 | | void PDFConverter::NewSignatureData::setReason(const QString &reason) |
291 | 0 | { |
292 | 0 | d->reason = reason; |
293 | 0 | } |
294 | | |
295 | | QString PDFConverter::NewSignatureData::location() const |
296 | 0 | { |
297 | 0 | return d->location; |
298 | 0 | } |
299 | | |
300 | | void PDFConverter::NewSignatureData::setLocation(const QString &location) |
301 | 0 | { |
302 | 0 | d->location = location; |
303 | 0 | } |
304 | | |
305 | | double PDFConverter::NewSignatureData::fontSize() const |
306 | 0 | { |
307 | 0 | return d->fontSize; |
308 | 0 | } |
309 | | |
310 | | void PDFConverter::NewSignatureData::setFontSize(double fontSize) |
311 | 0 | { |
312 | 0 | d->fontSize = fontSize; |
313 | 0 | } |
314 | | |
315 | | double PDFConverter::NewSignatureData::leftFontSize() const |
316 | 0 | { |
317 | 0 | return d->leftFontSize; |
318 | 0 | } |
319 | | |
320 | | void PDFConverter::NewSignatureData::setLeftFontSize(double fontSize) |
321 | 0 | { |
322 | 0 | d->leftFontSize = fontSize; |
323 | 0 | } |
324 | | |
325 | | QColor PDFConverter::NewSignatureData::fontColor() const |
326 | 0 | { |
327 | 0 | return d->fontColor; |
328 | 0 | } |
329 | | |
330 | | void PDFConverter::NewSignatureData::setFontColor(const QColor &color) |
331 | 0 | { |
332 | 0 | d->fontColor = color; |
333 | 0 | } |
334 | | |
335 | | QColor PDFConverter::NewSignatureData::borderColor() const |
336 | 0 | { |
337 | 0 | return d->borderColor; |
338 | 0 | } |
339 | | |
340 | | void PDFConverter::NewSignatureData::setBorderColor(const QColor &color) |
341 | 0 | { |
342 | 0 | d->borderColor = color; |
343 | 0 | } |
344 | | |
345 | | QColor PDFConverter::NewSignatureData::backgroundColor() const |
346 | 0 | { |
347 | 0 | return d->backgroundColor; |
348 | 0 | } |
349 | | |
350 | | double PDFConverter::NewSignatureData::borderWidth() const |
351 | 0 | { |
352 | 0 | return d->borderWidth; |
353 | 0 | } |
354 | | |
355 | | void PDFConverter::NewSignatureData::setBorderWidth(double width) |
356 | 0 | { |
357 | 0 | d->borderWidth = width; |
358 | 0 | } |
359 | | |
360 | | void PDFConverter::NewSignatureData::setBackgroundColor(const QColor &color) |
361 | 0 | { |
362 | 0 | d->backgroundColor = color; |
363 | 0 | } |
364 | | |
365 | | QString PDFConverter::NewSignatureData::fieldPartialName() const |
366 | 0 | { |
367 | 0 | return d->partialName; |
368 | 0 | } |
369 | | |
370 | | void PDFConverter::NewSignatureData::setFieldPartialName(const QString &name) |
371 | 0 | { |
372 | 0 | d->partialName = name; |
373 | 0 | } |
374 | | |
375 | | QByteArray PDFConverter::NewSignatureData::documentOwnerPassword() const |
376 | 0 | { |
377 | 0 | return d->documentOwnerPassword; |
378 | 0 | } |
379 | | |
380 | | void PDFConverter::NewSignatureData::setDocumentOwnerPassword(const QByteArray &password) |
381 | 0 | { |
382 | 0 | d->documentOwnerPassword = password; |
383 | 0 | } |
384 | | |
385 | | QByteArray PDFConverter::NewSignatureData::documentUserPassword() const |
386 | 0 | { |
387 | 0 | return d->documentUserPassword; |
388 | 0 | } |
389 | | |
390 | | void PDFConverter::NewSignatureData::setDocumentUserPassword(const QByteArray &password) |
391 | 0 | { |
392 | 0 | d->documentUserPassword = password; |
393 | 0 | } |
394 | | |
395 | | QString PDFConverter::NewSignatureData::imagePath() const |
396 | 0 | { |
397 | 0 | return d->imagePath; |
398 | 0 | } |
399 | | |
400 | | void PDFConverter::NewSignatureData::setImagePath(const QString &path) |
401 | 0 | { |
402 | 0 | d->imagePath = path; |
403 | 0 | } |
404 | | } |