1 //========================================================================
5 //========================================================================
7 //========================================================================
9 // Modified under the Poppler project - http://poppler.freedesktop.org
11 // All changes made under the Poppler project to this file are licensed
12 // under GPL version 2 or later
14 // Copyright (C) 2006, 2009, 2010, 2012, 2015 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 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 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>
25 // To see a description of the changes please see the Changelog file that
26 // came with your tarball or type make ChangeLog if you are building from git
28 //========================================================================
32 #ifdef USE_GCC_PRAGMAS
33 #pragma implementation
41 #include "SplashErrorCodes.h"
42 #include "SplashBitmap.h"
43 #include "poppler/Error.h"
44 #include "goo/JpegWriter.h"
45 #include "goo/PNGWriter.h"
46 #include "goo/TiffWriter.h"
47 #include "goo/ImgWriter.h"
48 #include "goo/GooList.h"
50 //------------------------------------------------------------------------
52 //------------------------------------------------------------------------
54 SplashBitmap::SplashBitmap(int widthA
, int heightA
, int rowPadA
,
55 SplashColorMode modeA
, GBool alphaA
,
56 GBool topDown
, GooList
*separationListA
) {
64 rowSize
= (width
+ 7) >> 3;
78 if (width
> 0 && width
<= INT_MAX
/ 3) {
85 if (width
> 0 && width
<= INT_MAX
/ 4) {
93 if (width
> 0 && width
<= INT_MAX
/ 4) {
99 case splashModeDeviceN8
:
100 if (width
> 0 && width
<= INT_MAX
/ 4) {
101 rowSize
= width
* (SPOT_NCOMPS
+ 4);
109 rowSize
+= rowPad
- 1;
110 rowSize
-= rowSize
% rowPad
;
112 data
= (SplashColorPtr
)gmallocn_checkoverflow(rowSize
, height
);
115 data
+= (height
- 1) * rowSize
;
119 alpha
= (Guchar
*)gmallocn(width
, height
);
126 separationList
= new GooList();
127 if (separationListA
!= NULL
)
128 for (int i
= 0; i
< separationListA
->getLength(); i
++)
129 separationList
->append(((GfxSeparationColorSpace
*) separationListA
->get(i
))->copy());
132 SplashBitmap
*SplashBitmap::copy(SplashBitmap
*src
) {
133 SplashBitmap
*result
= new SplashBitmap(src
->getWidth(), src
->getHeight(), src
->getRowPad(),
134 src
->getMode(), src
->getAlphaPtr() != NULL
, src
->getRowSize() >= 0, src
->getSeparationList());
135 Guchar
*dataSource
= src
->getDataPtr();
136 Guchar
*dataDest
= result
->getDataPtr();
137 int amount
= src
->getRowSize();
139 dataSource
= dataSource
+ (src
->getHeight() - 1) * amount
;
140 dataDest
= dataDest
+ (src
->getHeight() - 1) * amount
;
141 amount
*= -src
->getHeight();
143 amount
*= src
->getHeight();
145 memcpy(dataDest
, dataSource
, amount
);
146 if (src
->getAlphaPtr() != NULL
) {
147 memcpy(result
->getAlphaPtr(), src
->getAlphaPtr(), src
->getWidth() * src
->getHeight());
152 SplashBitmap::~SplashBitmap() {
155 gfree(data
+ (height
- 1) * rowSize
);
161 deleteGooList(separationList
, GfxSeparationColorSpace
);
165 SplashError
SplashBitmap::writePNMFile(char *fileName
) {
169 if (!(f
= fopen(fileName
, "wb"))) {
170 return splashErrOpenFile
;
173 e
= this->writePNMFile(f
);
180 SplashError
SplashBitmap::writePNMFile(FILE *f
) {
181 SplashColorPtr row
, p
;
186 case splashModeMono1
:
187 fprintf(f
, "P4\n%d %d\n", width
, height
);
189 for (y
= 0; y
< height
; ++y
) {
191 for (x
= 0; x
< width
; x
+= 8) {
199 case splashModeMono8
:
200 fprintf(f
, "P5\n%d %d\n255\n", width
, height
);
202 for (y
= 0; y
< height
; ++y
) {
203 fwrite(row
, 1, width
, f
);
209 fprintf(f
, "P6\n%d %d\n255\n", width
, height
);
211 for (y
= 0; y
< height
; ++y
) {
212 fwrite(row
, 1, 3 * width
, f
);
217 case splashModeXBGR8
:
218 fprintf(f
, "P6\n%d %d\n255\n", width
, height
);
220 for (y
= 0; y
< height
; ++y
) {
222 for (x
= 0; x
< width
; ++x
) {
223 fputc(splashBGR8R(p
), f
);
224 fputc(splashBGR8G(p
), f
);
225 fputc(splashBGR8B(p
), f
);
234 fprintf(f
, "P6\n%d %d\n255\n", width
, height
);
236 for (y
= 0; y
< height
; ++y
) {
238 for (x
= 0; x
< width
; ++x
) {
239 fputc(splashBGR8R(p
), f
);
240 fputc(splashBGR8G(p
), f
);
241 fputc(splashBGR8B(p
), f
);
249 case splashModeCMYK8
:
250 case splashModeDeviceN8
:
251 // PNM doesn't support CMYK
252 error(errInternal
, -1, "unsupported SplashBitmap mode");
253 return splashErrGeneric
;
260 SplashError
SplashBitmap::writeAlphaPGMFile(char *fileName
) {
264 return splashErrModeMismatch
;
266 if (!(f
= fopen(fileName
, "wb"))) {
267 return splashErrOpenFile
;
269 fprintf(f
, "P5\n%d %d\n255\n", width
, height
);
270 fwrite(alpha
, 1, width
* height
, f
);
275 void SplashBitmap::getPixel(int x
, int y
, SplashColorPtr pixel
) {
278 if (y
< 0 || y
>= height
|| x
< 0 || x
>= width
|| !data
) {
282 case splashModeMono1
:
283 p
= &data
[y
* rowSize
+ (x
>> 3)];
284 pixel
[0] = (p
[0] & (0x80 >> (x
& 7))) ? 0xff : 0x00;
286 case splashModeMono8
:
287 p
= &data
[y
* rowSize
+ x
];
291 p
= &data
[y
* rowSize
+ 3 * x
];
296 case splashModeXBGR8
:
297 p
= &data
[y
* rowSize
+ 4 * x
];
304 p
= &data
[y
* rowSize
+ 3 * x
];
310 case splashModeCMYK8
:
311 p
= &data
[y
* rowSize
+ 4 * x
];
317 case splashModeDeviceN8
:
318 p
= &data
[y
* rowSize
+ (SPOT_NCOMPS
+ 4) * x
];
319 for (int cp
= 0; cp
< SPOT_NCOMPS
+ 4; cp
++)
326 Guchar
SplashBitmap::getAlpha(int x
, int y
) {
327 return alpha
[y
* width
+ x
];
330 SplashColorPtr
SplashBitmap::takeData() {
331 SplashColorPtr data2
;
338 SplashError
SplashBitmap::writeImgFile(SplashImageFileFormat format
, char *fileName
, int hDPI
, int vDPI
, const char *compressionString
) {
342 if (!(f
= fopen(fileName
, "wb"))) {
343 return splashErrOpenFile
;
346 e
= writeImgFile(format
, f
, hDPI
, vDPI
, compressionString
);
352 SplashError
SplashBitmap::writeImgFile(SplashImageFileFormat format
, FILE *f
, int hDPI
, int vDPI
, const char *compressionString
) {
358 case splashFormatPng
:
359 writer
= new PNGWriter();
363 #ifdef ENABLE_LIBJPEG
365 case splashFormatJpegCMYK
:
366 writer
= new JpegWriter(JpegWriter::CMYK
);
369 case splashFormatJpeg
:
370 writer
= new JpegWriter();
374 #ifdef ENABLE_LIBTIFF
375 case splashFormatTiff
:
377 case splashModeMono1
:
378 writer
= new TiffWriter(TiffWriter::MONOCHROME
);
380 case splashModeMono8
:
381 writer
= new TiffWriter(TiffWriter::GRAY
);
385 writer
= new TiffWriter(TiffWriter::RGB
);
388 case splashModeCMYK8
:
389 case splashModeDeviceN8
:
390 writer
= new TiffWriter(TiffWriter::CMYK
);
394 fprintf(stderr
, "TiffWriter: Mode %d not supported\n", mode
);
395 writer
= new TiffWriter();
398 ((TiffWriter
*)writer
)->setCompressionString(compressionString
);
404 // Not the greatest error message, but users of this function should
405 // have already checked whether their desired format is compiled in.
406 error(errInternal
, -1, "Support for this image type not compiled in");
407 return splashErrGeneric
;
410 e
= writeImgFile(writer
, f
, hDPI
, vDPI
);
415 #include "poppler/GfxState_helpers.h"
417 void SplashBitmap::getRGBLine(int yl
, SplashColorPtr line
) {
419 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
;
421 for (int x
= 0; x
< width
; x
++) {
422 getPixel(x
, yl
, col
);
423 c
= byteToDbl(col
[0]);
424 m
= byteToDbl(col
[1]);
425 y
= byteToDbl(col
[2]);
426 k
= byteToDbl(col
[3]);
428 if (separationList
->getLength() > 0) {
429 for (int i
= 0; i
< separationList
->getLength(); i
++) {
433 input
.c
[0] = byteToCol(col
[i
+4]);
434 GfxSeparationColorSpace
*sepCS
= (GfxSeparationColorSpace
*)separationList
->get(i
);
435 sepCS
->getCMYK(&input
, &cmyk
);
436 col
[0] = colToByte(cmyk
.c
);
437 col
[1] = colToByte(cmyk
.m
);
438 col
[2] = colToByte(cmyk
.y
);
439 col
[3] = colToByte(cmyk
.k
);
440 c
+= byteToDbl(col
[0]);
441 m
+= byteToDbl(col
[1]);
442 y
+= byteToDbl(col
[2]);
443 k
+= byteToDbl(col
[3]);
456 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
457 *line
++ = dblToByte(clip01(r
));
458 *line
++ = dblToByte(clip01(g
));
459 *line
++ = dblToByte(clip01(b
));
463 void SplashBitmap::getXBGRLine(int yl
, SplashColorPtr line
) {
465 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
;
467 for (int x
= 0; x
< width
; x
++) {
468 getPixel(x
, yl
, col
);
469 c
= byteToDbl(col
[0]);
470 m
= byteToDbl(col
[1]);
471 y
= byteToDbl(col
[2]);
472 k
= byteToDbl(col
[3]);
474 if (separationList
->getLength() > 0) {
475 for (int i
= 0; i
< separationList
->getLength(); i
++) {
479 input
.c
[0] = byteToCol(col
[i
+4]);
480 GfxSeparationColorSpace
*sepCS
= (GfxSeparationColorSpace
*)separationList
->get(i
);
481 sepCS
->getCMYK(&input
, &cmyk
);
482 col
[0] = colToByte(cmyk
.c
);
483 col
[1] = colToByte(cmyk
.m
);
484 col
[2] = colToByte(cmyk
.y
);
485 col
[3] = colToByte(cmyk
.k
);
486 c
+= byteToDbl(col
[0]);
487 m
+= byteToDbl(col
[1]);
488 y
+= byteToDbl(col
[2]);
489 k
+= byteToDbl(col
[3]);
502 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
503 *line
++ = dblToByte(clip01(b
));
504 *line
++ = dblToByte(clip01(g
));
505 *line
++ = dblToByte(clip01(r
));
510 GBool
SplashBitmap::convertToXBGR() {
511 if (mode
== splashModeXBGR8
)
514 int newrowSize
= width
* 4;
515 SplashColorPtr newdata
= (SplashColorPtr
)gmallocn_checkoverflow(newrowSize
, height
);
516 if (newdata
!= NULL
) {
517 for (int y
= 0; y
< height
; y
++) {
518 unsigned char *row
= newdata
+ y
* newrowSize
;
522 gfree(data
+ (height
- 1) * rowSize
);
527 rowSize
= newrowSize
;
528 mode
= splashModeXBGR8
;
530 return newdata
!= NULL
;
534 void SplashBitmap::getCMYKLine(int yl
, SplashColorPtr line
) {
537 for (int x
= 0; x
< width
; x
++) {
538 getPixel(x
, yl
, col
);
539 if (separationList
->getLength() > 0) {
541 c
= byteToDbl(col
[0]);
542 m
= byteToDbl(col
[1]);
543 y
= byteToDbl(col
[2]);
544 k
= byteToDbl(col
[3]);
545 for (int i
= 0; i
< separationList
->getLength(); i
++) {
549 input
.c
[0] = byteToCol(col
[i
+4]);
550 GfxSeparationColorSpace
*sepCS
= (GfxSeparationColorSpace
*)separationList
->get(i
);
551 sepCS
->getCMYK(&input
, &cmyk
);
552 col
[0] = colToByte(cmyk
.c
);
553 col
[1] = colToByte(cmyk
.m
);
554 col
[2] = colToByte(cmyk
.y
);
555 col
[3] = colToByte(cmyk
.k
);
556 c
+= byteToDbl(col
[0]);
557 m
+= byteToDbl(col
[1]);
558 y
+= byteToDbl(col
[2]);
559 k
+= byteToDbl(col
[3]);
562 col
[0] = dblToByte(clip01(c
));
563 col
[1] = dblToByte(clip01(m
));
564 col
[2] = dblToByte(clip01(y
));
565 col
[3] = dblToByte(clip01(k
));
575 SplashError
SplashBitmap::writeImgFile(ImgWriter
*writer
, FILE *f
, int hDPI
, int vDPI
) {
576 if (mode
!= splashModeRGB8
&& mode
!= splashModeMono8
&& mode
!= splashModeMono1
&& mode
!= splashModeXBGR8
&& mode
!= splashModeBGR8
578 && mode
!= splashModeCMYK8
&& mode
!= splashModeDeviceN8
581 error(errInternal
, -1, "unsupported SplashBitmap mode");
582 return splashErrGeneric
;
585 if (!writer
->init(f
, width
, height
, hDPI
, vDPI
)) {
586 return splashErrGeneric
;
591 case splashModeCMYK8
:
592 if (writer
->supportCMYK()) {
594 unsigned char **row_pointers
= new unsigned char*[height
];
597 for (int y
= 0; y
< height
; ++y
) {
598 row_pointers
[y
] = row
;
601 if (!writer
->writePointers(row_pointers
, height
)) {
602 delete[] row_pointers
;
603 return splashErrGeneric
;
605 delete[] row_pointers
;
607 unsigned char *row
= new unsigned char[3 * width
];
608 for (int y
= 0; y
< height
; y
++) {
610 if (!writer
->writeRow(&row
)) {
612 return splashErrGeneric
;
618 case splashModeDeviceN8
:
619 if (writer
->supportCMYK()) {
620 unsigned char *row
= new unsigned char[4 * width
];
621 for (int y
= 0; y
< height
; y
++) {
623 if (!writer
->writeRow(&row
)) {
625 return splashErrGeneric
;
630 unsigned char *row
= new unsigned char[3 * width
];
631 for (int y
= 0; y
< height
; y
++) {
633 if (!writer
->writeRow(&row
)) {
635 return splashErrGeneric
;
645 unsigned char **row_pointers
= new unsigned char*[height
];
648 for (int y
= 0; y
< height
; ++y
) {
649 row_pointers
[y
] = row
;
652 if (!writer
->writePointers(row_pointers
, height
)) {
653 delete[] row_pointers
;
654 return splashErrGeneric
;
656 delete[] row_pointers
;
662 unsigned char *row
= new unsigned char[3 * width
];
663 for (int y
= 0; y
< height
; y
++) {
664 // Convert into a PNG row
665 for (int x
= 0; x
< width
; x
++) {
666 row
[3*x
] = data
[y
* rowSize
+ x
* 3 + 2];
667 row
[3*x
+1] = data
[y
* rowSize
+ x
* 3 + 1];
668 row
[3*x
+2] = data
[y
* rowSize
+ x
* 3];
671 if (!writer
->writeRow(&row
)) {
673 return splashErrGeneric
;
680 case splashModeXBGR8
:
682 unsigned char *row
= new unsigned char[3 * width
];
683 for (int y
= 0; y
< height
; y
++) {
684 // Convert into a PNG row
685 for (int x
= 0; x
< width
; x
++) {
686 row
[3*x
] = data
[y
* rowSize
+ x
* 4 + 2];
687 row
[3*x
+1] = data
[y
* rowSize
+ x
* 4 + 1];
688 row
[3*x
+2] = data
[y
* rowSize
+ x
* 4];
691 if (!writer
->writeRow(&row
)) {
693 return splashErrGeneric
;
700 case splashModeMono8
:
702 unsigned char *row
= new unsigned char[3 * width
];
703 for (int y
= 0; y
< height
; y
++) {
704 // Convert into a PNG row
705 for (int x
= 0; x
< width
; x
++) {
706 row
[3*x
] = data
[y
* rowSize
+ x
];
707 row
[3*x
+1] = data
[y
* rowSize
+ x
];
708 row
[3*x
+2] = data
[y
* rowSize
+ x
];
711 if (!writer
->writeRow(&row
)) {
713 return splashErrGeneric
;
720 case splashModeMono1
:
722 unsigned char *row
= new unsigned char[3 * width
];
723 for (int y
= 0; y
< height
; y
++) {
724 // Convert into a PNG row
725 for (int x
= 0; x
< width
; x
++) {
726 getPixel(x
, y
, &row
[3*x
]);
727 row
[3*x
+1] = row
[3*x
];
728 row
[3*x
+2] = row
[3*x
];
731 if (!writer
->writeRow(&row
)) {
733 return splashErrGeneric
;
745 if (!writer
->close()) {
746 return splashErrGeneric
;