1/*
2 * Copyright (C) 2010-2011, Pino Toscano <pino@kde.org>
3 * Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
4 * Copyright (C) 2017-2019, 2021, Albert Astals Cid <aacid@kde.org>
5 * Copyright (C) 2017, Jeroen Ooms <jeroenooms@gmail.com>
6 * Copyright (C) 2018, Zsombor Hollay-Horvath <hollay.horvath@gmail.com>
7 * Copyright (C) 2018, Adam Reichold <adam.reichold@t-online.de>
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-image.h
26 */
27#include "poppler-image.h"
28
29#include "poppler-image-private.h"
30
31#include <config.h>
32#include "ImgWriter.h"
33#if defined(ENABLE_LIBPNG)
34# include "PNGWriter.h"
35#endif
36#if defined(ENABLE_LIBJPEG)
37# include "JpegWriter.h"
38#endif
39#if defined(ENABLE_LIBTIFF)
40# include "TiffWriter.h"
41#endif
42#include "NetPBMWriter.h"
43
44#include <cstdlib>
45#include <cstring>
46#include <algorithm>
47#include <memory>
48#include <vector>
49
50namespace {
51
52struct FileCloser
53{
54 inline explicit FileCloser(FILE *ff) : f(ff) { }
55 inline ~FileCloser() { (void)close(); }
56 FileCloser(const FileCloser &) = delete;
57 FileCloser &operator=(const FileCloser &) = delete;
58 inline bool close()
59 {
60 if (f) {
61 const int c = fclose(stream: f);
62 f = nullptr;
63 return c == 0;
64 }
65 return true;
66 }
67
68 FILE *f;
69};
70
71int calc_bytes_per_row(int width, poppler::image::format_enum format)
72{
73 switch (format) {
74 case poppler::image::format_invalid:
75 return 0;
76 case poppler::image::format_mono:
77 return (width + 7) >> 3;
78 case poppler::image::format_gray8:
79 return (width + 3) >> 2 << 2;
80 case poppler::image::format_rgb24:
81 case poppler::image::format_bgr24:
82 return (width * 3 + 3) >> 2 << 2;
83 case poppler::image::format_argb32:
84 return width * 4;
85 }
86 return 0;
87}
88
89NetPBMWriter::Format pnm_format(poppler::image::format_enum format)
90{
91 switch (format) {
92 case poppler::image::format_invalid: // unused, anyway
93 case poppler::image::format_mono:
94 return NetPBMWriter::MONOCHROME;
95 case poppler::image::format_gray8:
96 case poppler::image::format_rgb24:
97 case poppler::image::format_bgr24:
98 case poppler::image::format_argb32:
99 return NetPBMWriter::RGB;
100 }
101 return NetPBMWriter::RGB;
102}
103
104}
105
106using namespace poppler;
107
108image_private::image_private(int iwidth, int iheight, image::format_enum iformat) : ref(1), data(nullptr), width(iwidth), height(iheight), bytes_per_row(0), bytes_num(0), format(iformat), own_data(true) { }
109
110image_private::~image_private()
111{
112 if (own_data) {
113 std::free(ptr: data);
114 }
115}
116
117image_private *image_private::create_data(int width, int height, image::format_enum format)
118{
119 if (width <= 0 || height <= 0) {
120 return nullptr;
121 }
122
123 int bpr = calc_bytes_per_row(width, format);
124 if (bpr <= 0) {
125 return nullptr;
126 }
127
128 auto d = std::make_unique<image_private>(args&: width, args&: height, args&: format);
129 d->bytes_num = bpr * height;
130 d->data = reinterpret_cast<char *>(std::malloc(size: d->bytes_num));
131 if (!d->data) {
132 return nullptr;
133 }
134 d->own_data = true;
135 d->bytes_per_row = bpr;
136
137 return d.release();
138}
139
140image_private *image_private::create_data(char *data, int width, int height, image::format_enum format)
141{
142 if (width <= 0 || height <= 0 || !data) {
143 return nullptr;
144 }
145
146 int bpr = calc_bytes_per_row(width, format);
147 if (bpr <= 0) {
148 return nullptr;
149 }
150
151 image_private *d = new image_private(width, height, format);
152 d->bytes_num = bpr * height;
153 d->data = data;
154 d->own_data = false;
155 d->bytes_per_row = bpr;
156
157 return d;
158}
159
160/**
161 \class poppler::image poppler-image.h "poppler/cpp/poppler-image.h"
162
163 A simple representation of image, with direct access to the data.
164
165 This class uses implicit sharing for the internal data, so it can be used as
166 value class. This also means any non-const operation will make sure that the
167 data used by current instance is not shared with other instances (ie
168 \em detaching), copying the shared data.
169
170 \since 0.16
171 */
172
173/**
174 \enum poppler::image::format_enum
175
176 The possible formats for an image.
177
178 format_gray8 and format_bgr24 were introduced in poppler 0.65.
179*/
180
181/**
182 Construct an invalid image.
183 */
184image::image() : d(nullptr) { }
185
186/**
187 Construct a new image.
188
189 It allocates the storage needed for the image data; if the allocation fails,
190 the image is an invalid one.
191
192 \param iwidth the width for the image
193 \param iheight the height for the image
194 \param iformat the format for the bits of the image
195 */
196image::image(int iwidth, int iheight, image::format_enum iformat) : d(image_private::create_data(width: iwidth, height: iheight, format: iformat)) { }
197
198/**
199 Construct a new image.
200
201 It uses the provide data buffer for the image, so you \b must ensure it
202 remains valid for the whole lifetime of the image.
203
204 \param idata the buffer to use for the image
205 \param iwidth the width for the image
206 \param iheight the height for the image
207 \param iformat the format for the bits of the image
208 */
209image::image(char *idata, int iwidth, int iheight, image::format_enum iformat) : d(image_private::create_data(data: idata, width: iwidth, height: iheight, format: iformat)) { }
210
211/**
212 Copy constructor.
213 */
214image::image(const image &img) : d(img.d)
215{
216 if (d) {
217 ++d->ref;
218 }
219}
220
221/**
222 Destructor.
223 */
224image::~image()
225{
226 if (d && !--d->ref) {
227 delete d;
228 }
229}
230
231/**
232 Image validity check.
233
234 \returns whether the image is valid.
235 */
236bool image::is_valid() const
237{
238 return d && d->format != format_invalid;
239}
240
241/**
242 \returns the format of the image
243 */
244image::format_enum image::format() const
245{
246 return d ? d->format : format_invalid;
247}
248
249/**
250 \returns whether the width of the image
251 */
252int image::width() const
253{
254 return d ? d->width : 0;
255}
256
257/**
258 \returns whether the height of the image
259 */
260int image::height() const
261{
262 return d ? d->height : 0;
263}
264
265/**
266 \returns the number of bytes in each row of the image
267 */
268int image::bytes_per_row() const
269{
270 return d ? d->bytes_per_row : 0;
271}
272
273/**
274 Access to the image bits.
275
276 This function will detach and copy the shared data.
277
278 \returns the pointer to the first pixel
279 */
280char *image::data()
281{
282 if (!d) {
283 return nullptr;
284 }
285
286 detach();
287 return d->data;
288}
289
290/**
291 Access to the image bits.
292
293 This function provides const access to the data.
294
295 \returns the pointer to the first pixel
296 */
297const char *image::const_data() const
298{
299 return d ? d->data : nullptr;
300}
301
302/**
303 Copy of a slice of the image.
304
305 \param r the sub-area of this image to copy; if empty, the whole image is
306 copied
307
308 \returns a new image representing the specified part of the current image
309 */
310image image::copy(const rect &r) const
311{
312 if (r.is_empty()) {
313 image img(*this);
314 img.detach();
315 return img;
316 }
317
318 // ### FIXME
319 return *this;
320}
321
322/**
323 Saves the current image to file.
324
325 Using this function it is possible to save the image to the specified
326 \p file_name, in the specified \p out_format and with a resolution of the
327 specified \p dpi.
328
329 Image formats commonly supported are:
330 \li PNG: \c png
331 \li JPEG: \c jpeg, \c jpg
332 \li TIFF: \c tiff
333 \li PNM: \c pnm (with Poppler >= 0.18)
334
335 If an image format is not supported (check the result of
336 supported_image_formats()), the saving fails.
337
338 \returns whether the saving succeeded
339 */
340bool image::save(const std::string &file_name, const std::string &out_format, int dpi) const
341{
342 if (!is_valid() || file_name.empty() || out_format.empty()) {
343 return false;
344 }
345
346 std::string fmt = out_format;
347 std::transform(first: fmt.begin(), last: fmt.end(), result: fmt.begin(), unary_op: tolower);
348
349 std::unique_ptr<ImgWriter> w;
350 const int actual_dpi = dpi == -1 ? 75 : dpi;
351 if (false) {
352 }
353#if defined(ENABLE_LIBPNG)
354 else if (fmt == "png") {
355 w = std::make_unique<PNGWriter>();
356 }
357#endif
358#if defined(ENABLE_LIBJPEG)
359 else if (fmt == "jpeg" || fmt == "jpg") {
360 w = std::make_unique<JpegWriter>();
361 }
362#endif
363#if defined(ENABLE_LIBTIFF)
364 else if (fmt == "tiff") {
365 w = std::make_unique<TiffWriter>();
366 }
367#endif
368 else if (fmt == "pnm") {
369 w = std::make_unique<NetPBMWriter>(args: pnm_format(format: d->format));
370 }
371 if (!w.get()) {
372 return false;
373 }
374 FILE *f = fopen(filename: file_name.c_str(), modes: "wb");
375 if (!f) {
376 return false;
377 }
378 const FileCloser fc(f);
379 if (!w->init(f, width: d->width, height: d->height, hDPI: actual_dpi, vDPI: actual_dpi)) {
380 return false;
381 }
382 switch (d->format) {
383 case format_invalid:
384 return false;
385 case format_mono:
386 return false;
387 case format_gray8: {
388 std::vector<unsigned char> row(3 * d->width);
389 char *hptr = d->data;
390 for (int y = 0; y < d->height; ++y) {
391 unsigned char *rowptr = &row[0];
392 for (int x = 0; x < d->width; ++x, rowptr += 3) {
393 rowptr[0] = *reinterpret_cast<unsigned char *>(hptr + x);
394 rowptr[1] = *reinterpret_cast<unsigned char *>(hptr + x);
395 rowptr[2] = *reinterpret_cast<unsigned char *>(hptr + x);
396 }
397 rowptr = &row[0];
398 if (!w->writeRow(row: &rowptr)) {
399 return false;
400 }
401 hptr += d->bytes_per_row;
402 }
403 break;
404 }
405 case format_bgr24: {
406 std::vector<unsigned char> row(3 * d->width);
407 char *hptr = d->data;
408 for (int y = 0; y < d->height; ++y) {
409 unsigned char *rowptr = &row[0];
410 for (int x = 0; x < d->width; ++x, rowptr += 3) {
411 rowptr[0] = *reinterpret_cast<unsigned char *>(hptr + x * 3 + 2);
412 rowptr[1] = *reinterpret_cast<unsigned char *>(hptr + x * 3 + 1);
413 rowptr[2] = *reinterpret_cast<unsigned char *>(hptr + x * 3);
414 }
415 rowptr = &row[0];
416 if (!w->writeRow(row: &rowptr)) {
417 return false;
418 }
419 hptr += d->bytes_per_row;
420 }
421 break;
422 }
423 case format_rgb24: {
424 char *hptr = d->data;
425 for (int y = 0; y < d->height; ++y) {
426 if (!w->writeRow(row: reinterpret_cast<unsigned char **>(&hptr))) {
427 return false;
428 }
429 hptr += d->bytes_per_row;
430 }
431 break;
432 }
433 case format_argb32: {
434 std::vector<unsigned char> row(3 * d->width);
435 char *hptr = d->data;
436 for (int y = 0; y < d->height; ++y) {
437 unsigned char *rowptr = &row[0];
438 for (int x = 0; x < d->width; ++x, rowptr += 3) {
439 const unsigned int pixel = *reinterpret_cast<unsigned int *>(hptr + x * 4);
440 rowptr[0] = (pixel >> 16) & 0xff;
441 rowptr[1] = (pixel >> 8) & 0xff;
442 rowptr[2] = pixel & 0xff;
443 }
444 rowptr = &row[0];
445 if (!w->writeRow(row: &rowptr)) {
446 return false;
447 }
448 hptr += d->bytes_per_row;
449 }
450 break;
451 }
452 }
453
454 if (!w->close()) {
455 return false;
456 }
457
458 return true;
459}
460
461/**
462 \returns a list of the supported image formats
463 */
464std::vector<std::string> image::supported_image_formats()
465{
466 std::vector<std::string> formats;
467#if defined(ENABLE_LIBPNG)
468 formats.emplace_back(args: "png");
469#endif
470#if defined(ENABLE_LIBJPEG)
471 formats.emplace_back(args: "jpeg");
472 formats.emplace_back(args: "jpg");
473#endif
474#if defined(ENABLE_LIBTIFF)
475 formats.emplace_back(args: "tiff");
476#endif
477 formats.emplace_back(args: "pnm");
478 return formats;
479}
480
481/**
482 Assignment operator.
483 */
484image &image::operator=(const image &img)
485{
486 if (this == &img) {
487 return *this;
488 }
489
490 if (img.d) {
491 ++img.d->ref;
492 }
493 image_private *old_d = d;
494 d = img.d;
495 if (old_d && !--old_d->ref) {
496 delete old_d;
497 }
498 return *this;
499}
500
501void image::detach()
502{
503 if (d->ref == 1) {
504 return;
505 }
506
507 image_private *old_d = d;
508 d = image_private::create_data(width: old_d->width, height: old_d->height, format: old_d->format);
509 if (d) {
510 std::memcpy(dest: d->data, src: old_d->data, n: old_d->bytes_num);
511 --old_d->ref;
512 } else {
513 d = old_d;
514 }
515}
516

source code of poppler/cpp/poppler-image.cpp