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