1 | /* poppler-ps-converter.cc: qt interface to poppler |
2 | * Copyright (C) 2007, 2009, 2010, 2015, 2020, 2022, Albert Astals Cid <aacid@kde.org> |
3 | * Copyright (C) 2008, Pino Toscano <pino@kde.org> |
4 | * Copyright (C) 2010 Hib Eris <hib@hiberis.nl> |
5 | * Copyright (C) 2011 Glad Deschrijver <glad.deschrijver@gmail.com> |
6 | * Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it> |
7 | * Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> |
8 | * Copyright (C) 2014 Adrian Johnson <ajohnson@redneon.com> |
9 | * Copyright (C) 2020 William Bader <williambader@hotmail.com> |
10 | * Copyright (C) 2023 Kevin Ottens <kevin.ottens@enioka.com>. Work sponsored by De Bortoli Wines |
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-private.h" |
30 | #include "poppler-converter-private.h" |
31 | |
32 | #include "PSOutputDev.h" |
33 | |
34 | static void outputToQIODevice(void *stream, const char *data, size_t len) |
35 | { |
36 | static_cast<QIODevice *>(stream)->write(data, len); |
37 | } |
38 | |
39 | namespace Poppler { |
40 | |
41 | class PSConverterPrivate : public BaseConverterPrivate |
42 | { |
43 | public: |
44 | PSConverterPrivate(); |
45 | ~PSConverterPrivate() override; |
46 | |
47 | QList<int> pageList; |
48 | QString title; |
49 | double hDPI; |
50 | double vDPI; |
51 | int rotate; |
52 | int paperWidth; |
53 | int paperHeight; |
54 | int marginRight; |
55 | int marginBottom; |
56 | int marginLeft; |
57 | int marginTop; |
58 | PSConverter::PSOptions opts; |
59 | void (*pageConvertedCallback)(int page, void *payload); |
60 | void *pageConvertedPayload; |
61 | }; |
62 | |
63 | PSConverterPrivate::PSConverterPrivate() |
64 | : BaseConverterPrivate(), |
65 | hDPI(72), |
66 | vDPI(72), |
67 | rotate(0), |
68 | paperWidth(-1), |
69 | paperHeight(-1), |
70 | marginRight(0), |
71 | marginBottom(0), |
72 | marginLeft(0), |
73 | marginTop(0), |
74 | opts(PSConverter::Printing), |
75 | pageConvertedCallback(nullptr), |
76 | pageConvertedPayload(nullptr) |
77 | { |
78 | } |
79 | |
80 | PSConverterPrivate::~PSConverterPrivate() = default; |
81 | |
82 | PSConverter::PSConverter(DocumentData *document) : BaseConverter(*new PSConverterPrivate()) |
83 | { |
84 | Q_D(PSConverter); |
85 | d->document = document; |
86 | } |
87 | |
88 | PSConverter::~PSConverter() { } |
89 | |
90 | void PSConverter::setPageList(const QList<int> &pageList) |
91 | { |
92 | Q_D(PSConverter); |
93 | d->pageList = pageList; |
94 | } |
95 | |
96 | void PSConverter::setTitle(const QString &title) |
97 | { |
98 | Q_D(PSConverter); |
99 | d->title = title; |
100 | } |
101 | |
102 | void PSConverter::setHDPI(double hDPI) |
103 | { |
104 | Q_D(PSConverter); |
105 | d->hDPI = hDPI; |
106 | } |
107 | |
108 | void PSConverter::setVDPI(double vDPI) |
109 | { |
110 | Q_D(PSConverter); |
111 | d->vDPI = vDPI; |
112 | } |
113 | |
114 | void PSConverter::setRotate(int rotate) |
115 | { |
116 | Q_D(PSConverter); |
117 | d->rotate = rotate; |
118 | } |
119 | |
120 | void PSConverter::setPaperWidth(int paperWidth) |
121 | { |
122 | Q_D(PSConverter); |
123 | d->paperWidth = paperWidth; |
124 | } |
125 | |
126 | void PSConverter::setPaperHeight(int paperHeight) |
127 | { |
128 | Q_D(PSConverter); |
129 | d->paperHeight = paperHeight; |
130 | } |
131 | |
132 | void PSConverter::setRightMargin(int marginRight) |
133 | { |
134 | Q_D(PSConverter); |
135 | d->marginRight = marginRight; |
136 | } |
137 | |
138 | void PSConverter::setBottomMargin(int marginBottom) |
139 | { |
140 | Q_D(PSConverter); |
141 | d->marginBottom = marginBottom; |
142 | } |
143 | |
144 | void PSConverter::setLeftMargin(int marginLeft) |
145 | { |
146 | Q_D(PSConverter); |
147 | d->marginLeft = marginLeft; |
148 | } |
149 | |
150 | void PSConverter::setTopMargin(int marginTop) |
151 | { |
152 | Q_D(PSConverter); |
153 | d->marginTop = marginTop; |
154 | } |
155 | |
156 | void PSConverter::setStrictMargins(bool strictMargins) |
157 | { |
158 | Q_D(PSConverter); |
159 | if (strictMargins) { |
160 | d->opts |= StrictMargins; |
161 | } else { |
162 | d->opts &= ~StrictMargins; |
163 | } |
164 | } |
165 | |
166 | void PSConverter::setForceOverprintPreview(bool forceOverprintPreview) |
167 | { |
168 | Q_D(PSConverter); |
169 | if (forceOverprintPreview) { |
170 | d->opts |= ForceOverprintPreview; |
171 | } else { |
172 | d->opts &= ~ForceOverprintPreview; |
173 | } |
174 | } |
175 | |
176 | void PSConverter::setForceRasterize(bool forceRasterize) |
177 | { |
178 | Q_D(PSConverter); |
179 | if (forceRasterize) { |
180 | d->opts |= ForceRasterization; |
181 | } else { |
182 | d->opts &= ~ForceRasterization; |
183 | } |
184 | } |
185 | |
186 | void PSConverter::setPSOptions(PSConverter::PSOptions options) |
187 | { |
188 | Q_D(PSConverter); |
189 | d->opts = options; |
190 | } |
191 | |
192 | PSConverter::PSOptions PSConverter::psOptions() const |
193 | { |
194 | Q_D(const PSConverter); |
195 | return d->opts; |
196 | } |
197 | |
198 | void PSConverter::setPageConvertedCallback(void (*callback)(int page, void *payload), void *payload) |
199 | { |
200 | Q_D(PSConverter); |
201 | d->pageConvertedCallback = callback; |
202 | d->pageConvertedPayload = payload; |
203 | } |
204 | |
205 | static bool annotDisplayDecideCbk(Annot *annot, void *user_data) |
206 | { |
207 | if (annot->getType() == Annot::typeWidget) { |
208 | return true; // Never hide forms |
209 | } else { |
210 | return *(bool *)user_data; |
211 | } |
212 | } |
213 | |
214 | bool PSConverter::convert() |
215 | { |
216 | Q_D(PSConverter); |
217 | d->lastError = NoError; |
218 | |
219 | Q_ASSERT(!d->pageList.isEmpty()); |
220 | Q_ASSERT(d->paperWidth != -1); |
221 | Q_ASSERT(d->paperHeight != -1); |
222 | |
223 | if (d->document->locked) { |
224 | d->lastError = FileLockedError; |
225 | return false; |
226 | } |
227 | |
228 | QIODevice *dev = d->openDevice(); |
229 | if (!dev) { |
230 | d->lastError = OpenOutputError; |
231 | return false; |
232 | } |
233 | |
234 | QByteArray pstitle8Bit = d->title.toLocal8Bit(); |
235 | char *pstitlechar; |
236 | if (!d->title.isEmpty()) { |
237 | pstitlechar = pstitle8Bit.data(); |
238 | } else { |
239 | pstitlechar = nullptr; |
240 | } |
241 | |
242 | std::vector<int> pages; |
243 | foreach (int page, d->pageList) { |
244 | pages.push_back(x: page); |
245 | } |
246 | |
247 | PSOutputDev *psOut = new PSOutputDev(outputToQIODevice, dev, pstitlechar, d->document->doc, pages, (d->opts & PrintToEPS) ? psModeEPS : psModePS, d->paperWidth, d->paperHeight, false, false, d->marginLeft, d->marginBottom, |
248 | d->paperWidth - d->marginRight, d->paperHeight - d->marginTop, (d->opts & ForceRasterization) ? psAlwaysRasterize : psRasterizeWhenNeeded); |
249 | if (d->opts & ForceOverprintPreview) { |
250 | psOut->setForceRasterize(psAlwaysRasterize); |
251 | psOut->setOverprintPreview(true); |
252 | } |
253 | |
254 | if (d->opts & StrictMargins) { |
255 | double xScale = ((double)d->paperWidth - (double)d->marginLeft - (double)d->marginRight) / (double)d->paperWidth; |
256 | double yScale = ((double)d->paperHeight - (double)d->marginBottom - (double)d->marginTop) / (double)d->paperHeight; |
257 | psOut->setScale(x: xScale, y: yScale); |
258 | } |
259 | |
260 | if (psOut->isOk()) { |
261 | bool isPrinting = (d->opts & Printing) ? true : false; |
262 | bool showAnnotations = (d->opts & HideAnnotations) ? false : true; |
263 | foreach (int page, d->pageList) { |
264 | d->document->doc->displayPage(out: psOut, page, hDPI: d->hDPI, vDPI: d->vDPI, rotate: d->rotate, useMediaBox: false, crop: true, printing: isPrinting, abortCheckCbk: nullptr, abortCheckCbkData: nullptr, annotDisplayDecideCbk, annotDisplayDecideCbkData: &showAnnotations, copyXRef: true); |
265 | if (d->pageConvertedCallback) { |
266 | (*d->pageConvertedCallback)(page, d->pageConvertedPayload); |
267 | } |
268 | } |
269 | delete psOut; |
270 | d->closeDevice(); |
271 | return true; |
272 | } else { |
273 | delete psOut; |
274 | d->closeDevice(); |
275 | return false; |
276 | } |
277 | } |
278 | |
279 | } |
280 | |