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
34static void outputToQIODevice(void *stream, const char *data, size_t len)
35{
36 static_cast<QIODevice *>(stream)->write(data, len);
37}
38
39namespace Poppler {
40
41class PSConverterPrivate : public BaseConverterPrivate
42{
43public:
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
63PSConverterPrivate::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
80PSConverterPrivate::~PSConverterPrivate() = default;
81
82PSConverter::PSConverter(DocumentData *document) : BaseConverter(*new PSConverterPrivate())
83{
84 Q_D(PSConverter);
85 d->document = document;
86}
87
88PSConverter::~PSConverter() { }
89
90void PSConverter::setPageList(const QList<int> &pageList)
91{
92 Q_D(PSConverter);
93 d->pageList = pageList;
94}
95
96void PSConverter::setTitle(const QString &title)
97{
98 Q_D(PSConverter);
99 d->title = title;
100}
101
102void PSConverter::setHDPI(double hDPI)
103{
104 Q_D(PSConverter);
105 d->hDPI = hDPI;
106}
107
108void PSConverter::setVDPI(double vDPI)
109{
110 Q_D(PSConverter);
111 d->vDPI = vDPI;
112}
113
114void PSConverter::setRotate(int rotate)
115{
116 Q_D(PSConverter);
117 d->rotate = rotate;
118}
119
120void PSConverter::setPaperWidth(int paperWidth)
121{
122 Q_D(PSConverter);
123 d->paperWidth = paperWidth;
124}
125
126void PSConverter::setPaperHeight(int paperHeight)
127{
128 Q_D(PSConverter);
129 d->paperHeight = paperHeight;
130}
131
132void PSConverter::setRightMargin(int marginRight)
133{
134 Q_D(PSConverter);
135 d->marginRight = marginRight;
136}
137
138void PSConverter::setBottomMargin(int marginBottom)
139{
140 Q_D(PSConverter);
141 d->marginBottom = marginBottom;
142}
143
144void PSConverter::setLeftMargin(int marginLeft)
145{
146 Q_D(PSConverter);
147 d->marginLeft = marginLeft;
148}
149
150void PSConverter::setTopMargin(int marginTop)
151{
152 Q_D(PSConverter);
153 d->marginTop = marginTop;
154}
155
156void 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
166void 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
176void 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
186void PSConverter::setPSOptions(PSConverter::PSOptions options)
187{
188 Q_D(PSConverter);
189 d->opts = options;
190}
191
192PSConverter::PSOptions PSConverter::psOptions() const
193{
194 Q_D(const PSConverter);
195 return d->opts;
196}
197
198void 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
205static 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
214bool 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

source code of poppler/qt6/src/poppler-ps-converter.cc