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 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
) {
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
) {
353 #if !defined(__MORPHOS__) && !defined(__AROS__)
360 case splashFormatPng
:
361 writer
= new PNGWriter();
365 #ifdef ENABLE_LIBJPEG
367 case splashFormatJpegCMYK
:
368 writer
= new JpegWriter(JpegWriter::CMYK
);
371 case splashFormatJpeg
:
372 writer
= new JpegWriter();
376 #ifdef ENABLE_LIBTIFF
377 case splashFormatTiff
:
379 case splashModeMono1
:
380 writer
= new TiffWriter(TiffWriter::MONOCHROME
);
382 case splashModeMono8
:
383 writer
= new TiffWriter(TiffWriter::GRAY
);
387 writer
= new TiffWriter(TiffWriter::RGB
);
390 case splashModeCMYK8
:
391 case splashModeDeviceN8
:
392 writer
= new TiffWriter(TiffWriter::CMYK
);
396 fprintf(stderr
, "TiffWriter: Mode %d not supported\n", mode
);
397 writer
= new TiffWriter();
400 ((TiffWriter
*)writer
)->setCompressionString(compressionString
);
406 // Not the greatest error message, but users of this function should
407 // have already checked whether their desired format is compiled in.
408 error(errInternal
, -1, "Support for this image type not compiled in");
409 return splashErrGeneric
;
412 e
= writeImgFile(writer
, f
, hDPI
, vDPI
);
416 return splashErrGeneric
;
420 #include "poppler/GfxState_helpers.h"
422 void SplashBitmap::getRGBLine(int yl
, SplashColorPtr line
) {
424 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
;
426 for (int x
= 0; x
< width
; x
++) {
427 getPixel(x
, yl
, col
);
428 c
= byteToDbl(col
[0]);
429 m
= byteToDbl(col
[1]);
430 y
= byteToDbl(col
[2]);
431 k
= byteToDbl(col
[3]);
433 if (separationList
->getLength() > 0) {
434 for (int i
= 0; i
< separationList
->getLength(); i
++) {
438 input
.c
[0] = byteToCol(col
[i
+4]);
439 GfxSeparationColorSpace
*sepCS
= (GfxSeparationColorSpace
*)separationList
->get(i
);
440 sepCS
->getCMYK(&input
, &cmyk
);
441 col
[0] = colToByte(cmyk
.c
);
442 col
[1] = colToByte(cmyk
.m
);
443 col
[2] = colToByte(cmyk
.y
);
444 col
[3] = colToByte(cmyk
.k
);
445 c
+= byteToDbl(col
[0]);
446 m
+= byteToDbl(col
[1]);
447 y
+= byteToDbl(col
[2]);
448 k
+= byteToDbl(col
[3]);
461 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
462 *line
++ = dblToByte(clip01(r
));
463 *line
++ = dblToByte(clip01(g
));
464 *line
++ = dblToByte(clip01(b
));
468 void SplashBitmap::getXBGRLine(int yl
, SplashColorPtr line
) {
470 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
;
472 for (int x
= 0; x
< width
; x
++) {
473 getPixel(x
, yl
, col
);
474 c
= byteToDbl(col
[0]);
475 m
= byteToDbl(col
[1]);
476 y
= byteToDbl(col
[2]);
477 k
= byteToDbl(col
[3]);
479 if (separationList
->getLength() > 0) {
480 for (int i
= 0; i
< separationList
->getLength(); i
++) {
484 input
.c
[0] = byteToCol(col
[i
+4]);
485 GfxSeparationColorSpace
*sepCS
= (GfxSeparationColorSpace
*)separationList
->get(i
);
486 sepCS
->getCMYK(&input
, &cmyk
);
487 col
[0] = colToByte(cmyk
.c
);
488 col
[1] = colToByte(cmyk
.m
);
489 col
[2] = colToByte(cmyk
.y
);
490 col
[3] = colToByte(cmyk
.k
);
491 c
+= byteToDbl(col
[0]);
492 m
+= byteToDbl(col
[1]);
493 y
+= byteToDbl(col
[2]);
494 k
+= byteToDbl(col
[3]);
507 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
508 *line
++ = dblToByte(clip01(b
));
509 *line
++ = dblToByte(clip01(g
));
510 *line
++ = dblToByte(clip01(r
));
515 GBool
SplashBitmap::convertToXBGR() {
516 if (mode
== splashModeXBGR8
)
519 int newrowSize
= width
* 4;
520 SplashColorPtr newdata
= (SplashColorPtr
)gmallocn_checkoverflow(newrowSize
, height
);
521 if (newdata
!= NULL
) {
522 for (int y
= 0; y
< height
; y
++) {
523 unsigned char *row
= newdata
+ y
* newrowSize
;
527 gfree(data
+ (height
- 1) * rowSize
);
532 rowSize
= newrowSize
;
533 mode
= splashModeXBGR8
;
535 return newdata
!= NULL
;
539 void SplashBitmap::getCMYKLine(int yl
, SplashColorPtr line
) {
542 for (int x
= 0; x
< width
; x
++) {
543 getPixel(x
, yl
, col
);
544 if (separationList
->getLength() > 0) {
546 c
= byteToDbl(col
[0]);
547 m
= byteToDbl(col
[1]);
548 y
= byteToDbl(col
[2]);
549 k
= byteToDbl(col
[3]);
550 for (int i
= 0; i
< separationList
->getLength(); i
++) {
554 input
.c
[0] = byteToCol(col
[i
+4]);
555 GfxSeparationColorSpace
*sepCS
= (GfxSeparationColorSpace
*)separationList
->get(i
);
556 sepCS
->getCMYK(&input
, &cmyk
);
557 col
[0] = colToByte(cmyk
.c
);
558 col
[1] = colToByte(cmyk
.m
);
559 col
[2] = colToByte(cmyk
.y
);
560 col
[3] = colToByte(cmyk
.k
);
561 c
+= byteToDbl(col
[0]);
562 m
+= byteToDbl(col
[1]);
563 y
+= byteToDbl(col
[2]);
564 k
+= byteToDbl(col
[3]);
567 col
[0] = dblToByte(clip01(c
));
568 col
[1] = dblToByte(clip01(m
));
569 col
[2] = dblToByte(clip01(y
));
570 col
[3] = dblToByte(clip01(k
));
580 SplashError
SplashBitmap::writeImgFile(ImgWriter
*writer
, FILE *f
, int hDPI
, int vDPI
) {
581 if (mode
!= splashModeRGB8
&& mode
!= splashModeMono8
&& mode
!= splashModeMono1
&& mode
!= splashModeXBGR8
&& mode
!= splashModeBGR8
583 && mode
!= splashModeCMYK8
&& mode
!= splashModeDeviceN8
586 error(errInternal
, -1, "unsupported SplashBitmap mode");
587 return splashErrGeneric
;
590 if (!writer
->init(f
, width
, height
, hDPI
, vDPI
)) {
591 return splashErrGeneric
;
596 case splashModeCMYK8
:
597 if (writer
->supportCMYK()) {
599 unsigned char **row_pointers
= new unsigned char*[height
];
602 for (int y
= 0; y
< height
; ++y
) {
603 row_pointers
[y
] = row
;
606 if (!writer
->writePointers(row_pointers
, height
)) {
607 delete[] row_pointers
;
608 return splashErrGeneric
;
610 delete[] row_pointers
;
612 unsigned char *row
= new unsigned char[3 * width
];
613 for (int y
= 0; y
< height
; y
++) {
615 if (!writer
->writeRow(&row
)) {
617 return splashErrGeneric
;
623 case splashModeDeviceN8
:
624 if (writer
->supportCMYK()) {
625 unsigned char *row
= new unsigned char[4 * width
];
626 for (int y
= 0; y
< height
; y
++) {
628 if (!writer
->writeRow(&row
)) {
630 return splashErrGeneric
;
635 unsigned char *row
= new unsigned char[3 * width
];
636 for (int y
= 0; y
< height
; y
++) {
638 if (!writer
->writeRow(&row
)) {
640 return splashErrGeneric
;
650 unsigned char **row_pointers
= new unsigned char*[height
];
653 for (int y
= 0; y
< height
; ++y
) {
654 row_pointers
[y
] = row
;
657 if (!writer
->writePointers(row_pointers
, height
)) {
658 delete[] row_pointers
;
659 return splashErrGeneric
;
661 delete[] row_pointers
;
667 unsigned char *row
= new unsigned char[3 * width
];
668 for (int y
= 0; y
< height
; y
++) {
669 // Convert into a PNG row
670 for (int x
= 0; x
< width
; x
++) {
671 row
[3*x
] = data
[y
* rowSize
+ x
* 3 + 2];
672 row
[3*x
+1] = data
[y
* rowSize
+ x
* 3 + 1];
673 row
[3*x
+2] = data
[y
* rowSize
+ x
* 3];
676 if (!writer
->writeRow(&row
)) {
678 return splashErrGeneric
;
685 case splashModeXBGR8
:
687 unsigned char *row
= new unsigned char[3 * width
];
688 for (int y
= 0; y
< height
; y
++) {
689 // Convert into a PNG row
690 for (int x
= 0; x
< width
; x
++) {
691 row
[3*x
] = data
[y
* rowSize
+ x
* 4 + 2];
692 row
[3*x
+1] = data
[y
* rowSize
+ x
* 4 + 1];
693 row
[3*x
+2] = data
[y
* rowSize
+ x
* 4];
696 if (!writer
->writeRow(&row
)) {
698 return splashErrGeneric
;
705 case splashModeMono8
:
707 unsigned char *row
= new unsigned char[3 * width
];
708 for (int y
= 0; y
< height
; y
++) {
709 // Convert into a PNG row
710 for (int x
= 0; x
< width
; x
++) {
711 row
[3*x
] = data
[y
* rowSize
+ x
];
712 row
[3*x
+1] = data
[y
* rowSize
+ x
];
713 row
[3*x
+2] = data
[y
* rowSize
+ x
];
716 if (!writer
->writeRow(&row
)) {
718 return splashErrGeneric
;
725 case splashModeMono1
:
727 unsigned char *row
= new unsigned char[3 * width
];
728 for (int y
= 0; y
< height
; y
++) {
729 // Convert into a PNG row
730 for (int x
= 0; x
< width
; x
++) {
731 getPixel(x
, y
, &row
[3*x
]);
732 row
[3*x
+1] = row
[3*x
];
733 row
[3*x
+2] = row
[3*x
];
736 if (!writer
->writeRow(&row
)) {
738 return splashErrGeneric
;
750 if (!writer
->close()) {
751 return splashErrGeneric
;