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, 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 | * |
12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by |
14 | * the Free Software Foundation; either version 2, or (at your option) |
15 | * any later version. |
16 | * |
17 | * This program is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | * GNU General Public License for more details. |
21 | * |
22 | * You should have received a copy of the GNU General Public License |
23 | * along with this program; if not, write to the Free Software |
24 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
25 | */ |
26 | |
27 | #include "poppler-qt6.h" |
28 | |
29 | #include "poppler-annotation-helper.h" |
30 | #include "poppler-annotation-private.h" |
31 | #include "poppler-private.h" |
32 | #include "poppler-converter-private.h" |
33 | #include "poppler-qiodeviceoutstream-private.h" |
34 | |
35 | #include <QFile> |
36 | #include <QUuid> |
37 | |
38 | #include "Array.h" |
39 | #include "Form.h" |
40 | #include <ErrorCodes.h> |
41 | |
42 | namespace Poppler { |
43 | |
44 | class PDFConverterPrivate : public BaseConverterPrivate |
45 | { |
46 | public: |
47 | PDFConverterPrivate(); |
48 | ~PDFConverterPrivate() override; |
49 | |
50 | PDFConverter::PDFOptions opts; |
51 | }; |
52 | |
53 | PDFConverterPrivate::PDFConverterPrivate() : BaseConverterPrivate() { } |
54 | |
55 | PDFConverterPrivate::~PDFConverterPrivate() = default; |
56 | |
57 | PDFConverter::PDFConverter(DocumentData *document) : BaseConverter(*new PDFConverterPrivate()) |
58 | { |
59 | Q_D(PDFConverter); |
60 | d->document = document; |
61 | } |
62 | |
63 | PDFConverter::~PDFConverter() { } |
64 | |
65 | void PDFConverter::setPDFOptions(PDFConverter::PDFOptions options) |
66 | { |
67 | Q_D(PDFConverter); |
68 | d->opts = options; |
69 | } |
70 | |
71 | PDFConverter::PDFOptions PDFConverter::pdfOptions() const |
72 | { |
73 | Q_D(const PDFConverter); |
74 | return d->opts; |
75 | } |
76 | |
77 | bool PDFConverter::convert() |
78 | { |
79 | Q_D(PDFConverter); |
80 | d->lastError = NoError; |
81 | |
82 | if (d->document->locked) { |
83 | d->lastError = FileLockedError; |
84 | return false; |
85 | } |
86 | |
87 | QIODevice *dev = d->openDevice(); |
88 | if (!dev) { |
89 | d->lastError = OpenOutputError; |
90 | return false; |
91 | } |
92 | |
93 | bool deleteFile = false; |
94 | if (QFile *file = qobject_cast<QFile *>(object: dev)) { |
95 | deleteFile = !file->exists(); |
96 | } |
97 | |
98 | int errorCode = errNone; |
99 | QIODeviceOutStream stream(dev); |
100 | if (d->opts & WithChanges) { |
101 | errorCode = d->document->doc->saveAs(outStr: &stream); |
102 | } else { |
103 | errorCode = d->document->doc->saveWithoutChangesAs(outStr: &stream); |
104 | } |
105 | d->closeDevice(); |
106 | if (errorCode != errNone) { |
107 | if (deleteFile) { |
108 | qobject_cast<QFile *>(object: dev)->remove(); |
109 | } |
110 | if (errorCode == errOpenFile) { |
111 | d->lastError = OpenOutputError; |
112 | } else { |
113 | d->lastError = NotSupportedInputFileError; |
114 | } |
115 | } |
116 | |
117 | return (errorCode == errNone); |
118 | } |
119 | |
120 | bool PDFConverter::sign(const NewSignatureData &data) |
121 | { |
122 | Q_D(PDFConverter); |
123 | d->lastError = NoError; |
124 | |
125 | if (d->document->locked) { |
126 | d->lastError = FileLockedError; |
127 | return false; |
128 | } |
129 | |
130 | if (data.signatureText().isEmpty()) { |
131 | qWarning() << "No signature text given" ; |
132 | return false; |
133 | } |
134 | |
135 | ::PDFDoc *doc = d->document->doc; |
136 | ::Page *destPage = doc->getPage(page: data.page() + 1); |
137 | std::unique_ptr<GooString> gSignatureText = std::unique_ptr<GooString>(QStringToUnicodeGooString(s: data.signatureText())); |
138 | std::unique_ptr<GooString> gSignatureLeftText = std::unique_ptr<GooString>(QStringToUnicodeGooString(s: data.signatureLeftText())); |
139 | const auto reason = std::unique_ptr<GooString>(data.reason().isEmpty() ? nullptr : QStringToUnicodeGooString(s: data.reason())); |
140 | const auto location = std::unique_ptr<GooString>(data.location().isEmpty() ? nullptr : QStringToUnicodeGooString(s: data.location())); |
141 | const auto ownerPwd = std::optional<GooString>(data.documentOwnerPassword().constData()); |
142 | const auto userPwd = std::optional<GooString>(data.documentUserPassword().constData()); |
143 | return doc->sign(saveFilename: d->outputFileName.toUtf8().constData(), certNickname: data.certNickname().toUtf8().constData(), password: data.password().toUtf8().constData(), partialFieldName: QStringToGooString(s: data.fieldPartialName()), page: data.page() + 1, |
144 | rect: boundaryToPdfRectangle(pdfPage: destPage, r: data.boundingRectangle(), flags: Annotation::FixedRotation), signatureText: *gSignatureText, signatureTextLeft: *gSignatureLeftText, fontSize: data.fontSize(), leftFontSize: data.leftFontSize(), fontColor: convertQColor(color: data.fontColor()), borderWidth: data.borderWidth(), |
145 | borderColor: convertQColor(color: data.borderColor()), backgroundColor: convertQColor(color: data.backgroundColor()), reason: reason.get(), location: location.get(), imagePath: data.imagePath().toStdString(), ownerPassword: ownerPwd, userPassword: userPwd); |
146 | } |
147 | |
148 | struct PDFConverter::NewSignatureData::NewSignatureDataPrivate |
149 | { |
150 | NewSignatureDataPrivate() = default; |
151 | |
152 | QString certNickname; |
153 | QString password; |
154 | int page; |
155 | QRectF boundingRectangle; |
156 | QString signatureText; |
157 | QString signatureLeftText; |
158 | QString reason; |
159 | QString location; |
160 | double fontSize = 10.0; |
161 | double leftFontSize = 20.0; |
162 | QColor fontColor = Qt::red; |
163 | QColor borderColor = Qt::red; |
164 | double borderWidth = 1.5; |
165 | QColor backgroundColor = QColor(240, 240, 240); |
166 | |
167 | QString partialName = QUuid::createUuid().toString(); |
168 | |
169 | QByteArray documentOwnerPassword; |
170 | QByteArray documentUserPassword; |
171 | |
172 | QString imagePath; |
173 | }; |
174 | |
175 | PDFConverter::NewSignatureData::NewSignatureData() : d(new NewSignatureDataPrivate()) { } |
176 | |
177 | PDFConverter::NewSignatureData::~NewSignatureData() |
178 | { |
179 | delete d; |
180 | } |
181 | |
182 | QString PDFConverter::NewSignatureData::certNickname() const |
183 | { |
184 | return d->certNickname; |
185 | } |
186 | |
187 | void PDFConverter::NewSignatureData::setCertNickname(const QString &certNickname) |
188 | { |
189 | d->certNickname = certNickname; |
190 | } |
191 | |
192 | QString PDFConverter::NewSignatureData::password() const |
193 | { |
194 | return d->password; |
195 | } |
196 | |
197 | void PDFConverter::NewSignatureData::setPassword(const QString &password) |
198 | { |
199 | d->password = password; |
200 | } |
201 | |
202 | int PDFConverter::NewSignatureData::page() const |
203 | { |
204 | return d->page; |
205 | } |
206 | |
207 | void PDFConverter::NewSignatureData::setPage(int page) |
208 | { |
209 | d->page = page; |
210 | } |
211 | |
212 | QRectF PDFConverter::NewSignatureData::boundingRectangle() const |
213 | { |
214 | return d->boundingRectangle; |
215 | } |
216 | |
217 | void PDFConverter::NewSignatureData::setBoundingRectangle(const QRectF &rect) |
218 | { |
219 | d->boundingRectangle = rect; |
220 | } |
221 | |
222 | QString PDFConverter::NewSignatureData::signatureText() const |
223 | { |
224 | return d->signatureText; |
225 | } |
226 | |
227 | void PDFConverter::NewSignatureData::setSignatureText(const QString &text) |
228 | { |
229 | d->signatureText = text; |
230 | } |
231 | |
232 | QString PDFConverter::NewSignatureData::signatureLeftText() const |
233 | { |
234 | return d->signatureLeftText; |
235 | } |
236 | |
237 | void PDFConverter::NewSignatureData::setSignatureLeftText(const QString &text) |
238 | { |
239 | d->signatureLeftText = text; |
240 | } |
241 | |
242 | QString PDFConverter::NewSignatureData::reason() const |
243 | { |
244 | return d->reason; |
245 | } |
246 | |
247 | void PDFConverter::NewSignatureData::setReason(const QString &reason) |
248 | { |
249 | d->reason = reason; |
250 | } |
251 | |
252 | QString PDFConverter::NewSignatureData::location() const |
253 | { |
254 | return d->location; |
255 | } |
256 | |
257 | void PDFConverter::NewSignatureData::setLocation(const QString &location) |
258 | { |
259 | d->location = location; |
260 | } |
261 | |
262 | double PDFConverter::NewSignatureData::fontSize() const |
263 | { |
264 | return d->fontSize; |
265 | } |
266 | |
267 | void PDFConverter::NewSignatureData::setFontSize(double fontSize) |
268 | { |
269 | d->fontSize = fontSize; |
270 | } |
271 | |
272 | double PDFConverter::NewSignatureData::leftFontSize() const |
273 | { |
274 | return d->leftFontSize; |
275 | } |
276 | |
277 | void PDFConverter::NewSignatureData::setLeftFontSize(double fontSize) |
278 | { |
279 | d->leftFontSize = fontSize; |
280 | } |
281 | |
282 | QColor PDFConverter::NewSignatureData::fontColor() const |
283 | { |
284 | return d->fontColor; |
285 | } |
286 | |
287 | void PDFConverter::NewSignatureData::setFontColor(const QColor &color) |
288 | { |
289 | d->fontColor = color; |
290 | } |
291 | |
292 | QColor PDFConverter::NewSignatureData::borderColor() const |
293 | { |
294 | return d->borderColor; |
295 | } |
296 | |
297 | void PDFConverter::NewSignatureData::setBorderColor(const QColor &color) |
298 | { |
299 | d->borderColor = color; |
300 | } |
301 | |
302 | QColor PDFConverter::NewSignatureData::backgroundColor() const |
303 | { |
304 | return d->backgroundColor; |
305 | } |
306 | |
307 | double PDFConverter::NewSignatureData::borderWidth() const |
308 | { |
309 | return d->borderWidth; |
310 | } |
311 | |
312 | void PDFConverter::NewSignatureData::setBorderWidth(double width) |
313 | { |
314 | d->borderWidth = width; |
315 | } |
316 | |
317 | void PDFConverter::NewSignatureData::setBackgroundColor(const QColor &color) |
318 | { |
319 | d->backgroundColor = color; |
320 | } |
321 | |
322 | QString PDFConverter::NewSignatureData::fieldPartialName() const |
323 | { |
324 | return d->partialName; |
325 | } |
326 | |
327 | void PDFConverter::NewSignatureData::setFieldPartialName(const QString &name) |
328 | { |
329 | d->partialName = name; |
330 | } |
331 | |
332 | QByteArray PDFConverter::NewSignatureData::documentOwnerPassword() const |
333 | { |
334 | return d->documentOwnerPassword; |
335 | } |
336 | |
337 | void PDFConverter::NewSignatureData::setDocumentOwnerPassword(const QByteArray &password) |
338 | { |
339 | d->documentOwnerPassword = password; |
340 | } |
341 | |
342 | QByteArray PDFConverter::NewSignatureData::documentUserPassword() const |
343 | { |
344 | return d->documentUserPassword; |
345 | } |
346 | |
347 | void PDFConverter::NewSignatureData::setDocumentUserPassword(const QByteArray &password) |
348 | { |
349 | d->documentUserPassword = password; |
350 | } |
351 | |
352 | QString PDFConverter::NewSignatureData::imagePath() const |
353 | { |
354 | return d->imagePath; |
355 | } |
356 | |
357 | void PDFConverter::NewSignatureData::setImagePath(const QString &path) |
358 | { |
359 | d->imagePath = path; |
360 | } |
361 | } |
362 | |