1 /*
2  * Copyright (C) 2010, Pino Toscano <pino@kde.org>
3  * Copyright (C) 2015 William Bader <williambader@hotmail.com>
4  * Copyright (C) 2018, Zsombor Hollay-Horvath <hollay.horvath@gmail.com>
5  * Copyright (C) 2019, Julián Unrrein <junrrein@gmail.com>
6  * Copyright (C) 2020, Albert Astals Cid <aacid@kde.org>
7  * Copyright (C) 2021, Hubert Figuiere <hub@figuiere.net>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23 
24 /**
25  \file poppler-page-renderer.h
26  */
27 #include "poppler-page-renderer.h"
28 
29 #include "poppler-document-private.h"
30 #include "poppler-page-private.h"
31 #include "poppler-image.h"
32 
33 #include <config.h>
34 #include <poppler-config.h>
35 
36 #include "PDFDoc.h"
37 #include "SplashOutputDev.h"
38 #include "splash/SplashBitmap.h"
39 
40 using namespace poppler;
41 
42 class poppler::page_renderer_private
43 {
44 public:
page_renderer_private()45     page_renderer_private() : paper_color(0xffffffff), hints(0), image_format(image::format_enum::format_argb32), line_mode(page_renderer::line_mode_enum::line_default) { }
46 
47     static bool conv_color_mode(image::format_enum mode, SplashColorMode &splash_mode);
48     static bool conv_line_mode(page_renderer::line_mode_enum mode, SplashThinLineMode &splash_mode);
49 
50     argb paper_color;
51     unsigned int hints;
52     image::format_enum image_format;
53     page_renderer::line_mode_enum line_mode;
54 };
55 
conv_color_mode(image::format_enum mode,SplashColorMode & splash_mode)56 bool page_renderer_private::conv_color_mode(image::format_enum mode, SplashColorMode &splash_mode)
57 {
58     switch (mode) {
59     case image::format_enum::format_mono:
60         splash_mode = splashModeMono1;
61         break;
62     case image::format_enum::format_gray8:
63         splash_mode = splashModeMono8;
64         break;
65     case image::format_enum::format_rgb24:
66         splash_mode = splashModeRGB8;
67         break;
68     case image::format_enum::format_bgr24:
69         splash_mode = splashModeBGR8;
70         break;
71     case image::format_enum::format_argb32:
72         splash_mode = splashModeXBGR8;
73         break;
74     default:
75         return false;
76     }
77     return true;
78 }
79 
conv_line_mode(page_renderer::line_mode_enum mode,SplashThinLineMode & splash_mode)80 bool page_renderer_private::conv_line_mode(page_renderer::line_mode_enum mode, SplashThinLineMode &splash_mode)
81 {
82     switch (mode) {
83     case page_renderer::line_mode_enum::line_default:
84         splash_mode = splashThinLineDefault;
85         break;
86     case page_renderer::line_mode_enum::line_solid:
87         splash_mode = splashThinLineSolid;
88         break;
89     case page_renderer::line_mode_enum::line_shape:
90         splash_mode = splashThinLineShape;
91         break;
92     default:
93         return false;
94     }
95     return true;
96 }
97 
98 /**
99  \class poppler::page_renderer poppler-page-renderer.h "poppler/cpp/poppler-renderer.h"
100 
101  Simple way to render a page of a PDF %document.
102 
103  \since 0.16
104  */
105 
106 /**
107  \enum poppler::page_renderer::render_hint
108 
109  A flag of an option taken into account when rendering
110 */
111 
112 /**
113  Constructs a new %page renderer.
114  */
page_renderer()115 page_renderer::page_renderer() : d(new page_renderer_private()) { }
116 
117 /**
118  Destructor.
119  */
~page_renderer()120 page_renderer::~page_renderer()
121 {
122     delete d;
123 }
124 
125 /**
126  The color used for the "paper" of the pages.
127 
128  The default color is opaque solid white (0xffffffff).
129 
130  \returns the paper color
131  */
paper_color() const132 argb page_renderer::paper_color() const
133 {
134     return d->paper_color;
135 }
136 
137 /**
138  Set a new color for the "paper".
139 
140  \param c the new color
141  */
set_paper_color(argb c)142 void page_renderer::set_paper_color(argb c)
143 {
144     d->paper_color = c;
145 }
146 
147 /**
148  The hints used when rendering.
149 
150  By default no hint is set.
151 
152  \returns the render hints set
153  */
render_hints() const154 unsigned int page_renderer::render_hints() const
155 {
156     return d->hints;
157 }
158 
159 /**
160  Enable or disable a single render %hint.
161 
162  \param hint the hint to modify
163  \param on whether enable it or not
164  */
set_render_hint(page_renderer::render_hint hint,bool on)165 void page_renderer::set_render_hint(page_renderer::render_hint hint, bool on)
166 {
167     if (on) {
168         d->hints |= hint;
169     } else {
170         d->hints &= ~(int)hint;
171     }
172 }
173 
174 /**
175  Set new render %hints at once.
176 
177  \param hints the new set of render hints
178  */
set_render_hints(unsigned int hints)179 void page_renderer::set_render_hints(unsigned int hints)
180 {
181     d->hints = hints;
182 }
183 
184 /**
185  The image format used when rendering.
186 
187  By default ARGB32 is set.
188 
189  \returns the image format
190 
191  \since 0.65
192  */
image_format() const193 image::format_enum page_renderer::image_format() const
194 {
195     return d->image_format;
196 }
197 
198 /**
199  Set new image format used when rendering.
200 
201  \param format the new image format
202 
203  \since 0.65
204  */
set_image_format(image::format_enum format)205 void page_renderer::set_image_format(image::format_enum format)
206 {
207     d->image_format = format;
208 }
209 
210 /**
211  The line mode used when rendering.
212 
213  By default default mode is set.
214 
215  \returns the line mode
216 
217  \since 0.65
218  */
line_mode() const219 page_renderer::line_mode_enum page_renderer::line_mode() const
220 {
221     return d->line_mode;
222 }
223 
224 /**
225  Set new line mode used when rendering.
226 
227  \param mode the new line mode
228 
229  \since 0.65
230  */
set_line_mode(page_renderer::line_mode_enum mode)231 void page_renderer::set_line_mode(page_renderer::line_mode_enum mode)
232 {
233     d->line_mode = mode;
234 }
235 
236 /**
237  Render the specified page.
238 
239  This functions renders the specified page on an image following the specified
240  parameters, returning it.
241 
242  \param p the page to render
243  \param xres the X resolution, in dot per inch (DPI)
244  \param yres the Y resolution, in dot per inch (DPI)
245  \param x the X top-right coordinate, in pixels
246  \param y the Y top-right coordinate, in pixels
247  \param w the width in pixels of the area to render
248  \param h the height in pixels of the area to render
249  \param rotate the rotation to apply when rendering the page
250 
251  \returns the rendered image, or a null one in case of errors
252 
253  \see can_render
254  */
render_page(const page * p,double xres,double yres,int x,int y,int w,int h,rotation_enum rotate) const255 image page_renderer::render_page(const page *p, double xres, double yres, int x, int y, int w, int h, rotation_enum rotate) const
256 {
257     if (!p) {
258         return image();
259     }
260 
261     page_private *pp = page_private::get(p);
262     PDFDoc *pdfdoc = pp->doc->doc;
263 
264     SplashColorMode colorMode;
265     SplashThinLineMode lineMode;
266 
267     if (!d->conv_color_mode(d->image_format, colorMode) || !d->conv_line_mode(d->line_mode, lineMode)) {
268         return image();
269     }
270 
271     SplashColor bgColor;
272     bgColor[0] = d->paper_color & 0xff;
273     bgColor[1] = (d->paper_color >> 8) & 0xff;
274     bgColor[2] = (d->paper_color >> 16) & 0xff;
275     SplashOutputDev splashOutputDev(colorMode, 4, false, bgColor, true, lineMode);
276     splashOutputDev.setFontAntialias(d->hints & text_antialiasing ? true : false);
277     splashOutputDev.setVectorAntialias(d->hints & antialiasing ? true : false);
278     splashOutputDev.setFreeTypeHinting(d->hints & text_hinting ? true : false, false);
279     splashOutputDev.startDoc(pdfdoc);
280     pdfdoc->displayPageSlice(&splashOutputDev, pp->index + 1, xres, yres, int(rotate) * 90, false, true, false, x, y, w, h, nullptr, nullptr, nullptr, nullptr, true);
281 
282     SplashBitmap *bitmap = splashOutputDev.getBitmap();
283     const int bw = bitmap->getWidth();
284     const int bh = bitmap->getHeight();
285 
286     SplashColorPtr data_ptr = bitmap->getDataPtr();
287 
288     const image img(reinterpret_cast<char *>(data_ptr), bw, bh, d->image_format);
289     return img.copy();
290 }
291 
292 /**
293  Rendering capability test.
294 
295  page_renderer can render only if a render backend ('Splash') is compiled in
296  Poppler.
297 
298  \returns whether page_renderer can render
299  */
can_render()300 bool page_renderer::can_render()
301 {
302     return true;
303 }
304