1//========================================================================
2//
3// SplashBitmap.cc
4//
5//========================================================================
6
7//========================================================================
8//
9// Modified under the Poppler project - http://poppler.freedesktop.org
10//
11// All changes made under the Poppler project to this file are licensed
12// under GPL version 2 or later
13//
14// Copyright (C) 2006, 2009, 2010, 2012, 2015, 2018, 2019, 2021, 2022 Albert Astals Cid <aacid@kde.org>
15// Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen@gmail.com>
16// Copyright (C) 2009 Shen Liang <shenzhuxi@gmail.com>
17// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
18// Copyright (C) 2010, 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
19// Copyright (C) 2010 Harry Roberts <harry.roberts@midnight-labs.org>
20// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
21// Copyright (C) 2010, 2015, 2019 William Bader <williambader@hotmail.com>
22// Copyright (C) 2011-2013 Thomas Freitag <Thomas.Freitag@alfa.de>
23// Copyright (C) 2012 Anthony Wesley <awesley@smartnetworks.com.au>
24// Copyright (C) 2015, 2018 Adam Reichold <adamreichold@myopera.com>
25// Copyright (C) 2016 Kenji Uno <ku@digitaldolphins.jp>
26// Copyright (C) 2018 Martin Packman <gzlist@googlemail.com>
27// Copyright (C) 2019 Christian Persch <chpe@src.gnome.org>
28// Copyright (C) 2019 Oliver Sander <oliver.sander@tu-dresden.de>
29//
30// To see a description of the changes please see the Changelog file that
31// came with your tarball or type make ChangeLog if you are building from git
32//
33//========================================================================
34
35#include <config.h>
36
37#include <cstdio>
38#include <cstring>
39#include <cstdlib>
40#include <climits>
41#include "goo/gfile.h"
42#include "goo/gmem.h"
43#include "SplashErrorCodes.h"
44#include "SplashBitmap.h"
45#include "poppler/Error.h"
46#include "poppler/GfxState.h"
47#include "goo/JpegWriter.h"
48#include "goo/PNGWriter.h"
49#include "goo/TiffWriter.h"
50#include "goo/ImgWriter.h"
51
52//------------------------------------------------------------------------
53// SplashBitmap
54//------------------------------------------------------------------------
55
56SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, SplashColorMode modeA, bool alphaA, bool topDown, const std::vector<GfxSeparationColorSpace *> *separationListA)
57{
58 width = widthA;
59 height = heightA;
60 mode = modeA;
61 rowPad = rowPadA;
62 switch (mode) {
63 case splashModeMono1:
64 if (width > 0) {
65 rowSize = (width + 7) >> 3;
66 } else {
67 rowSize = -1;
68 }
69 break;
70 case splashModeMono8:
71 if (width > 0) {
72 rowSize = width;
73 } else {
74 rowSize = -1;
75 }
76 break;
77 case splashModeRGB8:
78 case splashModeBGR8:
79 if (width > 0 && width <= INT_MAX / 3) {
80 rowSize = width * 3;
81 } else {
82 rowSize = -1;
83 }
84 break;
85 case splashModeXBGR8:
86 if (width > 0 && width <= INT_MAX / 4) {
87 rowSize = width * 4;
88 } else {
89 rowSize = -1;
90 }
91 break;
92 case splashModeCMYK8:
93 if (width > 0 && width <= INT_MAX / 4) {
94 rowSize = width * 4;
95 } else {
96 rowSize = -1;
97 }
98 break;
99 case splashModeDeviceN8:
100 if (width > 0 && width <= static_cast<int>(INT_MAX / splashMaxColorComps)) {
101 rowSize = width * splashMaxColorComps;
102 } else {
103 rowSize = -1;
104 }
105 break;
106 }
107 if (rowSize > 0) {
108 rowSize += rowPad - 1;
109 rowSize -= rowSize % rowPad;
110 }
111 data = (SplashColorPtr)gmallocn_checkoverflow(count: rowSize, size: height);
112 if (data != nullptr) {
113 if (!topDown) {
114 data += (height - 1) * rowSize;
115 rowSize = -rowSize;
116 }
117 if (alphaA) {
118 alpha = (unsigned char *)gmallocn_checkoverflow(count: width, size: height);
119 } else {
120 alpha = nullptr;
121 }
122 } else {
123 alpha = nullptr;
124 }
125 separationList = new std::vector<GfxSeparationColorSpace *>();
126 if (separationListA != nullptr) {
127 for (const GfxSeparationColorSpace *separation : *separationListA) {
128 separationList->push_back(x: (GfxSeparationColorSpace *)separation->copy());
129 }
130 }
131}
132
133SplashBitmap *SplashBitmap::copy(const SplashBitmap *src)
134{
135 SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(), src->getMode(), src->getAlphaPtr() != nullptr, src->getRowSize() >= 0, src->getSeparationList());
136 SplashColorConstPtr dataSource = src->getDataPtr();
137 unsigned char *dataDest = result->getDataPtr();
138 int amount = src->getRowSize();
139 if (amount < 0) {
140 dataSource = dataSource + (src->getHeight() - 1) * amount;
141 dataDest = dataDest + (src->getHeight() - 1) * amount;
142 amount *= -src->getHeight();
143 } else {
144 amount *= src->getHeight();
145 }
146 memcpy(dest: dataDest, src: dataSource, n: amount);
147 if (src->getAlphaPtr() != nullptr) {
148 memcpy(dest: result->getAlphaPtr(), src: src->getAlphaPtr(), n: src->getWidth() * src->getHeight());
149 }
150 return result;
151}
152
153SplashBitmap::~SplashBitmap()
154{
155 if (data) {
156 if (rowSize < 0) {
157 gfree(p: data + (height - 1) * rowSize);
158 } else {
159 gfree(p: data);
160 }
161 }
162 gfree(p: alpha);
163 for (auto entry : *separationList) {
164 delete entry;
165 }
166 delete separationList;
167}
168
169SplashError SplashBitmap::writePNMFile(char *fileName)
170{
171 FILE *f;
172 SplashError e;
173
174 if (!(f = openFile(path: fileName, mode: "wb"))) {
175 return splashErrOpenFile;
176 }
177
178 e = this->writePNMFile(f);
179
180 fclose(stream: f);
181 return e;
182}
183
184SplashError SplashBitmap::writePNMFile(FILE *f)
185{
186 SplashColorPtr row, p;
187 int x, y;
188
189 switch (mode) {
190
191 case splashModeMono1:
192 fprintf(stream: f, format: "P4\n%d %d\n", width, height);
193 row = data;
194 for (y = 0; y < height; ++y) {
195 p = row;
196 for (x = 0; x < width; x += 8) {
197 fputc(c: *p ^ 0xff, stream: f);
198 ++p;
199 }
200 row += rowSize;
201 }
202 break;
203
204 case splashModeMono8:
205 fprintf(stream: f, format: "P5\n%d %d\n255\n", width, height);
206 row = data;
207 for (y = 0; y < height; ++y) {
208 fwrite(ptr: row, size: 1, n: width, s: f);
209 row += rowSize;
210 }
211 break;
212
213 case splashModeRGB8:
214 fprintf(stream: f, format: "P6\n%d %d\n255\n", width, height);
215 row = data;
216 for (y = 0; y < height; ++y) {
217 fwrite(ptr: row, size: 1, n: 3 * width, s: f);
218 row += rowSize;
219 }
220 break;
221
222 case splashModeXBGR8:
223 fprintf(stream: f, format: "P6\n%d %d\n255\n", width, height);
224 row = data;
225 for (y = 0; y < height; ++y) {
226 p = row;
227 for (x = 0; x < width; ++x) {
228 fputc(c: splashBGR8R(bgr8: p), stream: f);
229 fputc(c: splashBGR8G(bgr8: p), stream: f);
230 fputc(c: splashBGR8B(bgr8: p), stream: f);
231 p += 4;
232 }
233 row += rowSize;
234 }
235 break;
236
237 case splashModeBGR8:
238 fprintf(stream: f, format: "P6\n%d %d\n255\n", width, height);
239 row = data;
240 for (y = 0; y < height; ++y) {
241 p = row;
242 for (x = 0; x < width; ++x) {
243 fputc(c: splashBGR8R(bgr8: p), stream: f);
244 fputc(c: splashBGR8G(bgr8: p), stream: f);
245 fputc(c: splashBGR8B(bgr8: p), stream: f);
246 p += 3;
247 }
248 row += rowSize;
249 }
250 break;
251
252 case splashModeCMYK8:
253 case splashModeDeviceN8:
254 // PNM doesn't support CMYK
255 error(category: errInternal, pos: -1, msg: "unsupported SplashBitmap mode");
256 return splashErrGeneric;
257 break;
258 }
259 return splashOk;
260}
261
262SplashError SplashBitmap::writeAlphaPGMFile(char *fileName)
263{
264 FILE *f;
265
266 if (!alpha) {
267 return splashErrModeMismatch;
268 }
269 if (!(f = openFile(path: fileName, mode: "wb"))) {
270 return splashErrOpenFile;
271 }
272 fprintf(stream: f, format: "P5\n%d %d\n255\n", width, height);
273 fwrite(ptr: alpha, size: 1, n: width * height, s: f);
274 fclose(stream: f);
275 return splashOk;
276}
277
278void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel)
279{
280 SplashColorPtr p;
281
282 if (y < 0 || y >= height || x < 0 || x >= width || !data) {
283 return;
284 }
285 switch (mode) {
286 case splashModeMono1:
287 p = &data[y * rowSize + (x >> 3)];
288 pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00;
289 break;
290 case splashModeMono8:
291 p = &data[y * rowSize + x];
292 pixel[0] = p[0];
293 break;
294 case splashModeRGB8:
295 p = &data[y * rowSize + 3 * x];
296 pixel[0] = p[0];
297 pixel[1] = p[1];
298 pixel[2] = p[2];
299 break;
300 case splashModeXBGR8:
301 p = &data[y * rowSize + 4 * x];
302 pixel[0] = p[2];
303 pixel[1] = p[1];
304 pixel[2] = p[0];
305 pixel[3] = p[3];
306 break;
307 case splashModeBGR8:
308 p = &data[y * rowSize + 3 * x];
309 pixel[0] = p[2];
310 pixel[1] = p[1];
311 pixel[2] = p[0];
312 break;
313 case splashModeCMYK8:
314 p = &data[y * rowSize + 4 * x];
315 pixel[0] = p[0];
316 pixel[1] = p[1];
317 pixel[2] = p[2];
318 pixel[3] = p[3];
319 break;
320 case splashModeDeviceN8:
321 p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x];
322 for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++) {
323 pixel[cp] = p[cp];
324 }
325 break;
326 }
327}
328
329unsigned char SplashBitmap::getAlpha(int x, int y)
330{
331 return alpha[y * width + x];
332}
333
334SplashColorPtr SplashBitmap::takeData()
335{
336 SplashColorPtr data2;
337
338 data2 = data;
339 data = nullptr;
340 return data2;
341}
342
343SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, const char *fileName, double hDPI, double vDPI, WriteImgParams *params)
344{
345 FILE *f;
346 SplashError e;
347
348 if (!(f = openFile(path: fileName, mode: "wb"))) {
349 return splashErrOpenFile;
350 }
351
352 e = writeImgFile(format, f, hDPI, vDPI, params);
353
354 fclose(stream: f);
355 return e;
356}
357
358void SplashBitmap::setJpegParams(ImgWriter *writer, WriteImgParams *params)
359{
360#ifdef ENABLE_LIBJPEG
361 if (params) {
362 static_cast<JpegWriter *>(writer)->setProgressive(params->jpegProgressive);
363 static_cast<JpegWriter *>(writer)->setOptimize(params->jpegOptimize);
364 if (params->jpegQuality >= 0) {
365 static_cast<JpegWriter *>(writer)->setQuality(params->jpegQuality);
366 }
367 }
368#endif
369}
370
371SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, double hDPI, double vDPI, WriteImgParams *params)
372{
373 ImgWriter *writer;
374 SplashError e;
375
376 SplashColorMode imageWriterFormat = splashModeRGB8;
377
378 switch (format) {
379#ifdef ENABLE_LIBPNG
380 case splashFormatPng:
381 writer = new PNGWriter();
382 break;
383#endif
384
385#ifdef ENABLE_LIBJPEG
386 case splashFormatJpegCMYK:
387 writer = new JpegWriter(JpegWriter::CMYK);
388 setJpegParams(writer, params);
389 break;
390 case splashFormatJpeg:
391 writer = new JpegWriter();
392 setJpegParams(writer, params);
393 break;
394#endif
395
396#ifdef ENABLE_LIBTIFF
397 case splashFormatTiff:
398 switch (mode) {
399 case splashModeMono1:
400 writer = new TiffWriter(TiffWriter::MONOCHROME);
401 imageWriterFormat = splashModeMono1;
402 break;
403 case splashModeMono8:
404 writer = new TiffWriter(TiffWriter::GRAY);
405 imageWriterFormat = splashModeMono8;
406 break;
407 case splashModeRGB8:
408 case splashModeBGR8:
409 writer = new TiffWriter(TiffWriter::RGB);
410 break;
411 case splashModeCMYK8:
412 case splashModeDeviceN8:
413 writer = new TiffWriter(TiffWriter::CMYK);
414 break;
415 default:
416 fprintf(stderr, format: "TiffWriter: Mode %d not supported\n", mode);
417 writer = new TiffWriter();
418 }
419 if (writer && params) {
420 ((TiffWriter *)writer)->setCompressionString(params->tiffCompression.c_str());
421 }
422 break;
423#endif
424
425 default:
426 // Not the greatest error message, but users of this function should
427 // have already checked whether their desired format is compiled in.
428 error(category: errInternal, pos: -1, msg: "Support for this image type not compiled in");
429 return splashErrGeneric;
430 }
431
432 e = writeImgFile(writer, f, hDPI, vDPI, imageWriterFormat);
433 delete writer;
434 return e;
435}
436
437#include "poppler/GfxState_helpers.h"
438
439void SplashBitmap::getRGBLine(int yl, SplashColorPtr line)
440{
441 SplashColor col;
442 double c, m, y, k, c1, m1, y1, k1, r, g, b;
443
444 for (int x = 0; x < width; x++) {
445 getPixel(x, y: yl, pixel: col);
446 c = byteToDbl(x: col[0]);
447 m = byteToDbl(x: col[1]);
448 y = byteToDbl(x: col[2]);
449 k = byteToDbl(x: col[3]);
450 if (separationList->size() > 0) {
451 for (std::size_t i = 0; i < separationList->size(); i++) {
452 if (col[i + 4] > 0) {
453 GfxCMYK cmyk;
454 GfxColor input;
455 input.c[0] = byteToCol(x: col[i + 4]);
456 GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]);
457 sepCS->getCMYK(color: &input, cmyk: &cmyk);
458 col[0] = colToByte(x: cmyk.c);
459 col[1] = colToByte(x: cmyk.m);
460 col[2] = colToByte(x: cmyk.y);
461 col[3] = colToByte(x: cmyk.k);
462 c += byteToDbl(x: col[0]);
463 m += byteToDbl(x: col[1]);
464 y += byteToDbl(x: col[2]);
465 k += byteToDbl(x: col[3]);
466 }
467 }
468 if (c > 1) {
469 c = 1;
470 }
471 if (m > 1) {
472 m = 1;
473 }
474 if (y > 1) {
475 y = 1;
476 }
477 if (k > 1) {
478 k = 1;
479 }
480 }
481 c1 = 1 - c;
482 m1 = 1 - m;
483 y1 = 1 - y;
484 k1 = 1 - k;
485 cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
486 *line++ = dblToByte(x: clip01(x: r));
487 *line++ = dblToByte(x: clip01(x: g));
488 *line++ = dblToByte(x: clip01(x: b));
489 }
490}
491
492void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line, ConversionMode conversionMode)
493{
494 SplashColor col;
495 double c, m, y, k, c1, m1, y1, k1, r, g, b;
496
497 for (int x = 0; x < width; x++) {
498 getPixel(x, y: yl, pixel: col);
499 c = byteToDbl(x: col[0]);
500 m = byteToDbl(x: col[1]);
501 y = byteToDbl(x: col[2]);
502 k = byteToDbl(x: col[3]);
503 if (separationList->size() > 0) {
504 for (std::size_t i = 0; i < separationList->size(); i++) {
505 if (col[i + 4] > 0) {
506 GfxCMYK cmyk;
507 GfxColor input;
508 input.c[0] = byteToCol(x: col[i + 4]);
509 GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]);
510 sepCS->getCMYK(color: &input, cmyk: &cmyk);
511 col[0] = colToByte(x: cmyk.c);
512 col[1] = colToByte(x: cmyk.m);
513 col[2] = colToByte(x: cmyk.y);
514 col[3] = colToByte(x: cmyk.k);
515 c += byteToDbl(x: col[0]);
516 m += byteToDbl(x: col[1]);
517 y += byteToDbl(x: col[2]);
518 k += byteToDbl(x: col[3]);
519 }
520 }
521 if (c > 1) {
522 c = 1;
523 }
524 if (m > 1) {
525 m = 1;
526 }
527 if (y > 1) {
528 y = 1;
529 }
530 if (k > 1) {
531 k = 1;
532 }
533 }
534 c1 = 1 - c;
535 m1 = 1 - m;
536 y1 = 1 - y;
537 k1 = 1 - k;
538 cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
539
540 if (conversionMode == conversionAlphaPremultiplied) {
541 const double a = getAlpha(x, y: yl) / 255.0;
542
543 *line++ = dblToByte(x: clip01(x: b * a));
544 *line++ = dblToByte(x: clip01(x: g * a));
545 *line++ = dblToByte(x: clip01(x: r * a));
546 } else {
547 *line++ = dblToByte(x: clip01(x: b));
548 *line++ = dblToByte(x: clip01(x: g));
549 *line++ = dblToByte(x: clip01(x: r));
550 }
551
552 if (conversionMode != conversionOpaque) {
553 *line++ = getAlpha(x, y: yl);
554 } else {
555 *line++ = 255;
556 }
557 }
558}
559
560static inline unsigned char div255(int x)
561{
562 return (unsigned char)((x + (x >> 8) + 0x80) >> 8);
563}
564
565bool SplashBitmap::convertToXBGR(ConversionMode conversionMode)
566{
567 if (mode == splashModeXBGR8) {
568 if (conversionMode != conversionOpaque) {
569 // Copy the alpha channel into the fourth component so that XBGR becomes ABGR.
570 const SplashColorPtr dbegin = data;
571 const SplashColorPtr dend = data + rowSize * height;
572
573 unsigned char *const abegin = alpha;
574 unsigned char *const aend = alpha + width * height;
575
576 SplashColorPtr d = dbegin;
577 unsigned char *a = abegin;
578
579 if (conversionMode == conversionAlphaPremultiplied) {
580 for (; d < dend && a < aend; d += 4, a += 1) {
581 d[0] = div255(x: d[0] * *a);
582 d[1] = div255(x: d[1] * *a);
583 d[2] = div255(x: d[2] * *a);
584 d[3] = *a;
585 }
586 } else {
587 for (d += 3; d < dend && a < aend; d += 4, a += 1) {
588 *d = *a;
589 }
590 }
591 }
592
593 return true;
594 }
595
596 int newrowSize = width * 4;
597 SplashColorPtr newdata = (SplashColorPtr)gmallocn_checkoverflow(count: newrowSize, size: height);
598 if (newdata != nullptr) {
599 for (int y = 0; y < height; y++) {
600 unsigned char *row = newdata + y * newrowSize;
601 getXBGRLine(yl: y, line: row, conversionMode);
602 }
603 if (rowSize < 0) {
604 gfree(p: data + (height - 1) * rowSize);
605 } else {
606 gfree(p: data);
607 }
608 data = newdata;
609 rowSize = newrowSize;
610 mode = splashModeXBGR8;
611 }
612 return newdata != nullptr;
613}
614
615void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line)
616{
617 SplashColor col;
618
619 for (int x = 0; x < width; x++) {
620 getPixel(x, y: yl, pixel: col);
621 if (separationList->size() > 0) {
622 double c, m, y, k;
623 c = byteToDbl(x: col[0]);
624 m = byteToDbl(x: col[1]);
625 y = byteToDbl(x: col[2]);
626 k = byteToDbl(x: col[3]);
627 for (std::size_t i = 0; i < separationList->size(); i++) {
628 if (col[i + 4] > 0) {
629 GfxCMYK cmyk;
630 GfxColor input;
631 input.c[0] = byteToCol(x: col[i + 4]);
632 GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)((*separationList)[i]);
633 sepCS->getCMYK(color: &input, cmyk: &cmyk);
634 col[0] = colToByte(x: cmyk.c);
635 col[1] = colToByte(x: cmyk.m);
636 col[2] = colToByte(x: cmyk.y);
637 col[3] = colToByte(x: cmyk.k);
638 c += byteToDbl(x: col[0]);
639 m += byteToDbl(x: col[1]);
640 y += byteToDbl(x: col[2]);
641 k += byteToDbl(x: col[3]);
642 }
643 }
644 col[0] = dblToByte(x: clip01(x: c));
645 col[1] = dblToByte(x: clip01(x: m));
646 col[2] = dblToByte(x: clip01(x: y));
647 col[3] = dblToByte(x: clip01(x: k));
648 }
649 *line++ = col[0];
650 *line++ = col[1];
651 *line++ = col[2];
652 *line++ = col[3];
653 }
654}
655
656SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, double hDPI, double vDPI, SplashColorMode imageWriterFormat)
657{
658 if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8 && mode != splashModeBGR8 && mode != splashModeCMYK8 && mode != splashModeDeviceN8) {
659 error(category: errInternal, pos: -1, msg: "unsupported SplashBitmap mode");
660 return splashErrGeneric;
661 }
662
663 if (!writer->init(f, width, height, hDPI, vDPI)) {
664 return splashErrGeneric;
665 }
666
667 switch (mode) {
668 case splashModeCMYK8:
669 if (writer->supportCMYK()) {
670 SplashColorPtr row;
671 unsigned char **row_pointers = new unsigned char *[height];
672 row = data;
673
674 for (int y = 0; y < height; ++y) {
675 row_pointers[y] = row;
676 row += rowSize;
677 }
678 if (!writer->writePointers(rowPointers: row_pointers, rowCount: height)) {
679 delete[] row_pointers;
680 return splashErrGeneric;
681 }
682 delete[] row_pointers;
683 } else {
684 unsigned char *row = new unsigned char[3 * width];
685 for (int y = 0; y < height; y++) {
686 getRGBLine(yl: y, line: row);
687 if (!writer->writeRow(row: &row)) {
688 delete[] row;
689 return splashErrGeneric;
690 }
691 }
692 delete[] row;
693 }
694 break;
695 case splashModeDeviceN8:
696 if (writer->supportCMYK()) {
697 unsigned char *row = new unsigned char[4 * width];
698 for (int y = 0; y < height; y++) {
699 getCMYKLine(yl: y, line: row);
700 if (!writer->writeRow(row: &row)) {
701 delete[] row;
702 return splashErrGeneric;
703 }
704 }
705 delete[] row;
706 } else {
707 unsigned char *row = new unsigned char[3 * width];
708 for (int y = 0; y < height; y++) {
709 getRGBLine(yl: y, line: row);
710 if (!writer->writeRow(row: &row)) {
711 delete[] row;
712 return splashErrGeneric;
713 }
714 }
715 delete[] row;
716 }
717 break;
718 case splashModeRGB8: {
719 SplashColorPtr row;
720 unsigned char **row_pointers = new unsigned char *[height];
721 row = data;
722
723 for (int y = 0; y < height; ++y) {
724 row_pointers[y] = row;
725 row += rowSize;
726 }
727 if (!writer->writePointers(rowPointers: row_pointers, rowCount: height)) {
728 delete[] row_pointers;
729 return splashErrGeneric;
730 }
731 delete[] row_pointers;
732 } break;
733
734 case splashModeBGR8: {
735 unsigned char *row = new unsigned char[3 * width];
736 for (int y = 0; y < height; y++) {
737 // Convert into a PNG row
738 for (int x = 0; x < width; x++) {
739 row[3 * x] = data[y * rowSize + x * 3 + 2];
740 row[3 * x + 1] = data[y * rowSize + x * 3 + 1];
741 row[3 * x + 2] = data[y * rowSize + x * 3];
742 }
743
744 if (!writer->writeRow(row: &row)) {
745 delete[] row;
746 return splashErrGeneric;
747 }
748 }
749 delete[] row;
750 } break;
751
752 case splashModeXBGR8: {
753 unsigned char *row = new unsigned char[3 * width];
754 for (int y = 0; y < height; y++) {
755 // Convert into a PNG row
756 for (int x = 0; x < width; x++) {
757 row[3 * x] = data[y * rowSize + x * 4 + 2];
758 row[3 * x + 1] = data[y * rowSize + x * 4 + 1];
759 row[3 * x + 2] = data[y * rowSize + x * 4];
760 }
761
762 if (!writer->writeRow(row: &row)) {
763 delete[] row;
764 return splashErrGeneric;
765 }
766 }
767 delete[] row;
768 } break;
769
770 case splashModeMono8: {
771 if (imageWriterFormat == splashModeMono8) {
772 SplashColorPtr row;
773 unsigned char **row_pointers = new unsigned char *[height];
774 row = data;
775
776 for (int y = 0; y < height; ++y) {
777 row_pointers[y] = row;
778 row += rowSize;
779 }
780 if (!writer->writePointers(rowPointers: row_pointers, rowCount: height)) {
781 delete[] row_pointers;
782 return splashErrGeneric;
783 }
784 delete[] row_pointers;
785 } else if (imageWriterFormat == splashModeRGB8) {
786 unsigned char *row = new unsigned char[3 * width];
787 for (int y = 0; y < height; y++) {
788 // Convert into a PNG row
789 for (int x = 0; x < width; x++) {
790 row[3 * x] = data[y * rowSize + x];
791 row[3 * x + 1] = data[y * rowSize + x];
792 row[3 * x + 2] = data[y * rowSize + x];
793 }
794
795 if (!writer->writeRow(row: &row)) {
796 delete[] row;
797 return splashErrGeneric;
798 }
799 }
800 delete[] row;
801 } else {
802 // only splashModeMono8 or splashModeRGB8
803 return splashErrGeneric;
804 }
805 } break;
806
807 case splashModeMono1: {
808 if (imageWriterFormat == splashModeMono1) {
809 SplashColorPtr row;
810 unsigned char **row_pointers = new unsigned char *[height];
811 row = data;
812
813 for (int y = 0; y < height; ++y) {
814 row_pointers[y] = row;
815 row += rowSize;
816 }
817 if (!writer->writePointers(rowPointers: row_pointers, rowCount: height)) {
818 delete[] row_pointers;
819 return splashErrGeneric;
820 }
821 delete[] row_pointers;
822 } else if (imageWriterFormat == splashModeRGB8) {
823 unsigned char *row = new unsigned char[3 * width];
824 for (int y = 0; y < height; y++) {
825 // Convert into a PNG row
826 for (int x = 0; x < width; x++) {
827 getPixel(x, y, pixel: &row[3 * x]);
828 row[3 * x + 1] = row[3 * x];
829 row[3 * x + 2] = row[3 * x];
830 }
831
832 if (!writer->writeRow(row: &row)) {
833 delete[] row;
834 return splashErrGeneric;
835 }
836 }
837 delete[] row;
838 } else {
839 // only splashModeMono1 or splashModeRGB8
840 return splashErrGeneric;
841 }
842 } break;
843
844 default:
845 // can't happen
846 break;
847 }
848
849 if (!writer->close()) {
850 return splashErrGeneric;
851 }
852
853 return splashOk;
854}
855

source code of poppler/splash/SplashBitmap.cc