1 /* poppler-ps-converter.cc: qt interface to poppler
2 * Copyright (C) 2007, 2009, 2010, 2015, 2020, 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 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
24 */
25
26 #include "poppler-qt6.h"
27
28 #include "poppler-private.h"
29 #include "poppler-converter-private.h"
30
31 #include "PSOutputDev.h"
32
outputToQIODevice(void * stream,const char * data,int len)33 static void outputToQIODevice(void *stream, const char *data, int len)
34 {
35 static_cast<QIODevice *>(stream)->write(data, len);
36 }
37
38 namespace Poppler {
39
40 class PSConverterPrivate : public BaseConverterPrivate
41 {
42 public:
43 PSConverterPrivate();
44 ~PSConverterPrivate() override;
45
46 QList<int> pageList;
47 QString title;
48 double hDPI;
49 double vDPI;
50 int rotate;
51 int paperWidth;
52 int paperHeight;
53 int marginRight;
54 int marginBottom;
55 int marginLeft;
56 int marginTop;
57 PSConverter::PSOptions opts;
58 void (*pageConvertedCallback)(int page, void *payload);
59 void *pageConvertedPayload;
60 };
61
PSConverterPrivate()62 PSConverterPrivate::PSConverterPrivate()
63 : BaseConverterPrivate(),
64 hDPI(72),
65 vDPI(72),
66 rotate(0),
67 paperWidth(-1),
68 paperHeight(-1),
69 marginRight(0),
70 marginBottom(0),
71 marginLeft(0),
72 marginTop(0),
73 opts(PSConverter::Printing),
74 pageConvertedCallback(nullptr),
75 pageConvertedPayload(nullptr)
76 {
77 }
78
79 PSConverterPrivate::~PSConverterPrivate() = default;
80
PSConverter(DocumentData * document)81 PSConverter::PSConverter(DocumentData *document) : BaseConverter(*new PSConverterPrivate())
82 {
83 Q_D(PSConverter);
84 d->document = document;
85 }
86
~PSConverter()87 PSConverter::~PSConverter() { }
88
setPageList(const QList<int> & pageList)89 void PSConverter::setPageList(const QList<int> &pageList)
90 {
91 Q_D(PSConverter);
92 d->pageList = pageList;
93 }
94
setTitle(const QString & title)95 void PSConverter::setTitle(const QString &title)
96 {
97 Q_D(PSConverter);
98 d->title = title;
99 }
100
setHDPI(double hDPI)101 void PSConverter::setHDPI(double hDPI)
102 {
103 Q_D(PSConverter);
104 d->hDPI = hDPI;
105 }
106
setVDPI(double vDPI)107 void PSConverter::setVDPI(double vDPI)
108 {
109 Q_D(PSConverter);
110 d->vDPI = vDPI;
111 }
112
setRotate(int rotate)113 void PSConverter::setRotate(int rotate)
114 {
115 Q_D(PSConverter);
116 d->rotate = rotate;
117 }
118
setPaperWidth(int paperWidth)119 void PSConverter::setPaperWidth(int paperWidth)
120 {
121 Q_D(PSConverter);
122 d->paperWidth = paperWidth;
123 }
124
setPaperHeight(int paperHeight)125 void PSConverter::setPaperHeight(int paperHeight)
126 {
127 Q_D(PSConverter);
128 d->paperHeight = paperHeight;
129 }
130
setRightMargin(int marginRight)131 void PSConverter::setRightMargin(int marginRight)
132 {
133 Q_D(PSConverter);
134 d->marginRight = marginRight;
135 }
136
setBottomMargin(int marginBottom)137 void PSConverter::setBottomMargin(int marginBottom)
138 {
139 Q_D(PSConverter);
140 d->marginBottom = marginBottom;
141 }
142
setLeftMargin(int marginLeft)143 void PSConverter::setLeftMargin(int marginLeft)
144 {
145 Q_D(PSConverter);
146 d->marginLeft = marginLeft;
147 }
148
setTopMargin(int marginTop)149 void PSConverter::setTopMargin(int marginTop)
150 {
151 Q_D(PSConverter);
152 d->marginTop = marginTop;
153 }
154
setStrictMargins(bool strictMargins)155 void PSConverter::setStrictMargins(bool strictMargins)
156 {
157 Q_D(PSConverter);
158 if (strictMargins)
159 d->opts |= StrictMargins;
160 else
161 d->opts &= ~StrictMargins;
162 }
163
setForceRasterize(bool forceRasterize)164 void PSConverter::setForceRasterize(bool forceRasterize)
165 {
166 Q_D(PSConverter);
167 if (forceRasterize)
168 d->opts |= ForceRasterization;
169 else
170 d->opts &= ~ForceRasterization;
171 }
172
setPSOptions(PSConverter::PSOptions options)173 void PSConverter::setPSOptions(PSConverter::PSOptions options)
174 {
175 Q_D(PSConverter);
176 d->opts = options;
177 }
178
psOptions() const179 PSConverter::PSOptions PSConverter::psOptions() const
180 {
181 Q_D(const PSConverter);
182 return d->opts;
183 }
184
setPageConvertedCallback(void (* callback)(int page,void * payload),void * payload)185 void PSConverter::setPageConvertedCallback(void (*callback)(int page, void *payload), void *payload)
186 {
187 Q_D(PSConverter);
188 d->pageConvertedCallback = callback;
189 d->pageConvertedPayload = payload;
190 }
191
annotDisplayDecideCbk(Annot * annot,void * user_data)192 static bool annotDisplayDecideCbk(Annot *annot, void *user_data)
193 {
194 if (annot->getType() == Annot::typeWidget)
195 return true; // Never hide forms
196 else
197 return *(bool *)user_data;
198 }
199
convert()200 bool PSConverter::convert()
201 {
202 Q_D(PSConverter);
203 d->lastError = NoError;
204
205 Q_ASSERT(!d->pageList.isEmpty());
206 Q_ASSERT(d->paperWidth != -1);
207 Q_ASSERT(d->paperHeight != -1);
208
209 if (d->document->locked) {
210 d->lastError = FileLockedError;
211 return false;
212 }
213
214 QIODevice *dev = d->openDevice();
215 if (!dev) {
216 d->lastError = OpenOutputError;
217 return false;
218 }
219
220 QByteArray pstitle8Bit = d->title.toLocal8Bit();
221 char *pstitlechar;
222 if (!d->title.isEmpty())
223 pstitlechar = pstitle8Bit.data();
224 else
225 pstitlechar = nullptr;
226
227 std::vector<int> pages;
228 foreach (int page, d->pageList) {
229 pages.push_back(page);
230 }
231
232 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,
233 d->paperWidth - d->marginRight, d->paperHeight - d->marginTop, (d->opts & ForceRasterization) ? psAlwaysRasterize : psRasterizeWhenNeeded);
234
235 if (d->opts & StrictMargins) {
236 double xScale = ((double)d->paperWidth - (double)d->marginLeft - (double)d->marginRight) / (double)d->paperWidth;
237 double yScale = ((double)d->paperHeight - (double)d->marginBottom - (double)d->marginTop) / (double)d->paperHeight;
238 psOut->setScale(xScale, yScale);
239 }
240
241 if (psOut->isOk()) {
242 bool isPrinting = (d->opts & Printing) ? true : false;
243 bool showAnnotations = (d->opts & HideAnnotations) ? false : true;
244 foreach (int page, d->pageList) {
245 d->document->doc->displayPage(psOut, page, d->hDPI, d->vDPI, d->rotate, false, true, isPrinting, nullptr, nullptr, annotDisplayDecideCbk, &showAnnotations, true);
246 if (d->pageConvertedCallback)
247 (*d->pageConvertedCallback)(page, d->pageConvertedPayload);
248 }
249 delete psOut;
250 d->closeDevice();
251 return true;
252 } else {
253 delete psOut;
254 d->closeDevice();
255 return false;
256 }
257 }
258
259 }
260