Removed -D__MORPHOS__ from the makefiles.
[AROS-Contrib.git] / vpdf / poppler / splash / SplashBitmap.cc
blob0a2549dfc43acb210b3f3e6f3d08abccdec6c598
1 //========================================================================
2 //
3 // SplashBitmap.cc
4 //
5 //========================================================================
7 //========================================================================
8 //
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 //========================================================================
30 #include <config.h>
32 #ifdef USE_GCC_PRAGMAS
33 #pragma implementation
34 #endif
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <limits.h>
40 #include "goo/gmem.h"
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 //------------------------------------------------------------------------
51 // SplashBitmap
52 //------------------------------------------------------------------------
54 SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA,
55 SplashColorMode modeA, GBool alphaA,
56 GBool topDown, GooList *separationListA) {
57 width = widthA;
58 height = heightA;
59 mode = modeA;
60 rowPad = rowPadA;
61 switch (mode) {
62 case splashModeMono1:
63 if (width > 0) {
64 rowSize = (width + 7) >> 3;
65 } else {
66 rowSize = -1;
68 break;
69 case splashModeMono8:
70 if (width > 0) {
71 rowSize = width;
72 } else {
73 rowSize = -1;
75 break;
76 case splashModeRGB8:
77 case splashModeBGR8:
78 if (width > 0 && width <= INT_MAX / 3) {
79 rowSize = width * 3;
80 } else {
81 rowSize = -1;
83 break;
84 case splashModeXBGR8:
85 if (width > 0 && width <= INT_MAX / 4) {
86 rowSize = width * 4;
87 } else {
88 rowSize = -1;
90 break;
91 #if SPLASH_CMYK
92 case splashModeCMYK8:
93 if (width > 0 && width <= INT_MAX / 4) {
94 rowSize = width * 4;
95 } else {
96 rowSize = -1;
98 break;
99 case splashModeDeviceN8:
100 if (width > 0 && width <= INT_MAX / 4) {
101 rowSize = width * (SPOT_NCOMPS + 4);
102 } else {
103 rowSize = -1;
105 break;
106 #endif
108 if (rowSize > 0) {
109 rowSize += rowPad - 1;
110 rowSize -= rowSize % rowPad;
112 data = (SplashColorPtr)gmallocn_checkoverflow(rowSize, height);
113 if (data != NULL) {
114 if (!topDown) {
115 data += (height - 1) * rowSize;
116 rowSize = -rowSize;
118 if (alphaA) {
119 alpha = (Guchar *)gmallocn(width, height);
120 } else {
121 alpha = NULL;
123 } else {
124 alpha = NULL;
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();
138 if (amount < 0) {
139 dataSource = dataSource + (src->getHeight() - 1) * amount;
140 dataDest = dataDest + (src->getHeight() - 1) * amount;
141 amount *= -src->getHeight();
142 } else {
143 amount *= src->getHeight();
145 memcpy(dataDest, dataSource, amount);
146 if (src->getAlphaPtr() != NULL) {
147 memcpy(result->getAlphaPtr(), src->getAlphaPtr(), src->getWidth() * src->getHeight());
149 return result;
152 SplashBitmap::~SplashBitmap() {
153 if (data) {
154 if (rowSize < 0) {
155 gfree(data + (height - 1) * rowSize);
156 } else {
157 gfree(data);
160 gfree(alpha);
161 deleteGooList(separationList, GfxSeparationColorSpace);
165 SplashError SplashBitmap::writePNMFile(char *fileName) {
166 FILE *f;
167 SplashError e;
169 if (!(f = fopen(fileName, "wb"))) {
170 return splashErrOpenFile;
173 e = this->writePNMFile(f);
175 fclose(f);
176 return e;
180 SplashError SplashBitmap::writePNMFile(FILE *f) {
181 SplashColorPtr row, p;
182 int x, y;
184 switch (mode) {
186 case splashModeMono1:
187 fprintf(f, "P4\n%d %d\n", width, height);
188 row = data;
189 for (y = 0; y < height; ++y) {
190 p = row;
191 for (x = 0; x < width; x += 8) {
192 fputc(*p ^ 0xff, f);
193 ++p;
195 row += rowSize;
197 break;
199 case splashModeMono8:
200 fprintf(f, "P5\n%d %d\n255\n", width, height);
201 row = data;
202 for (y = 0; y < height; ++y) {
203 fwrite(row, 1, width, f);
204 row += rowSize;
206 break;
208 case splashModeRGB8:
209 fprintf(f, "P6\n%d %d\n255\n", width, height);
210 row = data;
211 for (y = 0; y < height; ++y) {
212 fwrite(row, 1, 3 * width, f);
213 row += rowSize;
215 break;
217 case splashModeXBGR8:
218 fprintf(f, "P6\n%d %d\n255\n", width, height);
219 row = data;
220 for (y = 0; y < height; ++y) {
221 p = row;
222 for (x = 0; x < width; ++x) {
223 fputc(splashBGR8R(p), f);
224 fputc(splashBGR8G(p), f);
225 fputc(splashBGR8B(p), f);
226 p += 4;
228 row += rowSize;
230 break;
233 case splashModeBGR8:
234 fprintf(f, "P6\n%d %d\n255\n", width, height);
235 row = data;
236 for (y = 0; y < height; ++y) {
237 p = row;
238 for (x = 0; x < width; ++x) {
239 fputc(splashBGR8R(p), f);
240 fputc(splashBGR8G(p), f);
241 fputc(splashBGR8B(p), f);
242 p += 3;
244 row += rowSize;
246 break;
248 #if SPLASH_CMYK
249 case splashModeCMYK8:
250 case splashModeDeviceN8:
251 // PNM doesn't support CMYK
252 error(errInternal, -1, "unsupported SplashBitmap mode");
253 return splashErrGeneric;
254 break;
255 #endif
257 return splashOk;
260 SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) {
261 FILE *f;
263 if (!alpha) {
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);
271 fclose(f);
272 return splashOk;
275 void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) {
276 SplashColorPtr p;
278 if (y < 0 || y >= height || x < 0 || x >= width) {
279 return;
281 switch (mode) {
282 case splashModeMono1:
283 p = &data[y * rowSize + (x >> 3)];
284 pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00;
285 break;
286 case splashModeMono8:
287 p = &data[y * rowSize + x];
288 pixel[0] = p[0];
289 break;
290 case splashModeRGB8:
291 p = &data[y * rowSize + 3 * x];
292 pixel[0] = p[0];
293 pixel[1] = p[1];
294 pixel[2] = p[2];
295 break;
296 case splashModeXBGR8:
297 p = &data[y * rowSize + 4 * x];
298 pixel[0] = p[2];
299 pixel[1] = p[1];
300 pixel[2] = p[0];
301 pixel[3] = p[3];
302 break;
303 case splashModeBGR8:
304 p = &data[y * rowSize + 3 * x];
305 pixel[0] = p[2];
306 pixel[1] = p[1];
307 pixel[2] = p[0];
308 break;
309 #if SPLASH_CMYK
310 case splashModeCMYK8:
311 p = &data[y * rowSize + 4 * x];
312 pixel[0] = p[0];
313 pixel[1] = p[1];
314 pixel[2] = p[2];
315 pixel[3] = p[3];
316 break;
317 case splashModeDeviceN8:
318 p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x];
319 for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++)
320 pixel[cp] = p[cp];
321 break;
322 #endif
326 Guchar SplashBitmap::getAlpha(int x, int y) {
327 return alpha[y * width + x];
330 SplashColorPtr SplashBitmap::takeData() {
331 SplashColorPtr data2;
333 data2 = data;
334 data = NULL;
335 return data2;
338 SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, const char *compressionString) {
339 FILE *f;
340 SplashError e;
342 if (!(f = fopen(fileName, "wb"))) {
343 return splashErrOpenFile;
346 e = writeImgFile(format, f, hDPI, vDPI, compressionString);
348 fclose(f);
349 return e;
352 SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, const char *compressionString) {
353 #if !defined(__MORPHOS__) && !defined(__AROS__)
355 ImgWriter *writer;
356 SplashError e;
358 switch (format) {
359 #ifdef ENABLE_LIBPNG
360 case splashFormatPng:
361 writer = new PNGWriter();
362 break;
363 #endif
365 #ifdef ENABLE_LIBJPEG
366 #ifdef SPLASH_CMYK
367 case splashFormatJpegCMYK:
368 writer = new JpegWriter(JpegWriter::CMYK);
369 break;
370 #endif
371 case splashFormatJpeg:
372 writer = new JpegWriter();
373 break;
374 #endif
376 #ifdef ENABLE_LIBTIFF
377 case splashFormatTiff:
378 switch (mode) {
379 case splashModeMono1:
380 writer = new TiffWriter(TiffWriter::MONOCHROME);
381 break;
382 case splashModeMono8:
383 writer = new TiffWriter(TiffWriter::GRAY);
384 break;
385 case splashModeRGB8:
386 case splashModeBGR8:
387 writer = new TiffWriter(TiffWriter::RGB);
388 break;
389 #if SPLASH_CMYK
390 case splashModeCMYK8:
391 case splashModeDeviceN8:
392 writer = new TiffWriter(TiffWriter::CMYK);
393 break;
394 #endif
395 default:
396 fprintf(stderr, "TiffWriter: Mode %d not supported\n", mode);
397 writer = new TiffWriter();
399 if (writer) {
400 ((TiffWriter *)writer)->setCompressionString(compressionString);
402 break;
403 #endif
405 default:
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);
413 delete writer;
414 return e;
415 #else
416 return splashErrGeneric;
417 #endif
420 #include "poppler/GfxState_helpers.h"
422 void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) {
423 SplashColor col;
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]);
432 #if SPLASH_CMYK
433 if (separationList->getLength() > 0) {
434 for (int i = 0; i < separationList->getLength(); i++) {
435 if (col[i+4] > 0) {
436 GfxCMYK cmyk;
437 GfxColor input;
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]);
451 if (c > 1) c = 1;
452 if (m > 1) m = 1;
453 if (y > 1) y = 1;
454 if (k > 1) k = 1;
456 #endif
457 c1 = 1 - c;
458 m1 = 1 - m;
459 y1 = 1 - y;
460 k1 = 1 - k;
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) {
469 SplashColor col;
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]);
478 #if SPLASH_CMYK
479 if (separationList->getLength() > 0) {
480 for (int i = 0; i < separationList->getLength(); i++) {
481 if (col[i+4] > 0) {
482 GfxCMYK cmyk;
483 GfxColor input;
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]);
497 if (c > 1) c = 1;
498 if (m > 1) m = 1;
499 if (y > 1) y = 1;
500 if (k > 1) k = 1;
502 #endif
503 c1 = 1 - c;
504 m1 = 1 - m;
505 y1 = 1 - y;
506 k1 = 1 - k;
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));
511 *line++ = 255;
515 GBool SplashBitmap::convertToXBGR() {
516 if (mode == splashModeXBGR8)
517 return gTrue;
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;
524 getXBGRLine(y, row);
526 if (rowSize < 0) {
527 gfree(data + (height - 1) * rowSize);
528 } else {
529 gfree(data);
531 data = newdata;
532 rowSize = newrowSize;
533 mode = splashModeXBGR8;
535 return newdata != NULL;
538 #if SPLASH_CMYK
539 void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line) {
540 SplashColor col;
542 for (int x = 0; x < width; x++) {
543 getPixel(x, yl, col);
544 if (separationList->getLength() > 0) {
545 double c, m, y, k;
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++) {
551 if (col[i+4] > 0) {
552 GfxCMYK cmyk;
553 GfxColor input;
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));
572 *line++ = col[0];
573 *line++ = col[1];
574 *line++ = col[2];
575 *line++ = col[3];
578 #endif
580 SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI) {
581 if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8 && mode != splashModeBGR8
582 #if SPLASH_CMYK
583 && mode != splashModeCMYK8 && mode != splashModeDeviceN8
584 #endif
586 error(errInternal, -1, "unsupported SplashBitmap mode");
587 return splashErrGeneric;
590 if (!writer->init(f, width, height, hDPI, vDPI)) {
591 return splashErrGeneric;
594 switch (mode) {
595 #if SPLASH_CMYK
596 case splashModeCMYK8:
597 if (writer->supportCMYK()) {
598 SplashColorPtr row;
599 unsigned char **row_pointers = new unsigned char*[height];
600 row = data;
602 for (int y = 0; y < height; ++y) {
603 row_pointers[y] = row;
604 row += rowSize;
606 if (!writer->writePointers(row_pointers, height)) {
607 delete[] row_pointers;
608 return splashErrGeneric;
610 delete[] row_pointers;
611 } else {
612 unsigned char *row = new unsigned char[3 * width];
613 for (int y = 0; y < height; y++) {
614 getRGBLine(y, row);
615 if (!writer->writeRow(&row)) {
616 delete[] row;
617 return splashErrGeneric;
620 delete[] row;
622 break;
623 case splashModeDeviceN8:
624 if (writer->supportCMYK()) {
625 unsigned char *row = new unsigned char[4 * width];
626 for (int y = 0; y < height; y++) {
627 getCMYKLine(y, row);
628 if (!writer->writeRow(&row)) {
629 delete[] row;
630 return splashErrGeneric;
633 delete[] row;
634 } else {
635 unsigned char *row = new unsigned char[3 * width];
636 for (int y = 0; y < height; y++) {
637 getRGBLine(y, row);
638 if (!writer->writeRow(&row)) {
639 delete[] row;
640 return splashErrGeneric;
643 delete[] row;
645 break;
646 #endif
647 case splashModeRGB8:
649 SplashColorPtr row;
650 unsigned char **row_pointers = new unsigned char*[height];
651 row = data;
653 for (int y = 0; y < height; ++y) {
654 row_pointers[y] = row;
655 row += rowSize;
657 if (!writer->writePointers(row_pointers, height)) {
658 delete[] row_pointers;
659 return splashErrGeneric;
661 delete[] row_pointers;
663 break;
665 case splashModeBGR8:
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)) {
677 delete[] row;
678 return splashErrGeneric;
681 delete[] row;
683 break;
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)) {
697 delete[] row;
698 return splashErrGeneric;
701 delete[] row;
703 break;
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)) {
717 delete[] row;
718 return splashErrGeneric;
721 delete[] row;
723 break;
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)) {
737 delete[] row;
738 return splashErrGeneric;
741 delete[] row;
743 break;
745 default:
746 // can't happen
747 break;
750 if (!writer->close()) {
751 return splashErrGeneric;
754 return splashOk;