diff options
Diffstat (limited to 'Build/source/libs/poppler/poppler-src/splash/SplashBitmap.cc')
-rw-r--r-- | Build/source/libs/poppler/poppler-src/splash/SplashBitmap.cc | 795 |
1 files changed, 795 insertions, 0 deletions
diff --git a/Build/source/libs/poppler/poppler-src/splash/SplashBitmap.cc b/Build/source/libs/poppler/poppler-src/splash/SplashBitmap.cc new file mode 100644 index 00000000000..7c14b3161b1 --- /dev/null +++ b/Build/source/libs/poppler/poppler-src/splash/SplashBitmap.cc @@ -0,0 +1,795 @@ +//======================================================================== +// +// SplashBitmap.cc +// +//======================================================================== + +//======================================================================== +// +// Modified under the Poppler project - http://poppler.freedesktop.org +// +// All changes made under the Poppler project to this file are licensed +// under GPL version 2 or later +// +// Copyright (C) 2006, 2009, 2010, 2012, 2015 Albert Astals Cid <aacid@kde.org> +// Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen@gmail.com> +// Copyright (C) 2009 Shen Liang <shenzhuxi@gmail.com> +// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com> +// Copyright (C) 2010, 2012 Adrian Johnson <ajohnson@redneon.com> +// Copyright (C) 2010 Harry Roberts <harry.roberts@midnight-labs.org> +// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com> +// Copyright (C) 2010, 2015 William Bader <williambader@hotmail.com> +// Copyright (C) 2011-2013 Thomas Freitag <Thomas.Freitag@alfa.de> +// Copyright (C) 2012 Anthony Wesley <awesley@smartnetworks.com.au> +// Copyright (C) 2015 Adam Reichold <adamreichold@myopera.com> +// +// To see a description of the changes please see the Changelog file that +// came with your tarball or type make ChangeLog if you are building from git +// +//======================================================================== + +#include <config.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include "goo/gmem.h" +#include "SplashErrorCodes.h" +#include "SplashBitmap.h" +#include "poppler/Error.h" +#include "goo/JpegWriter.h" +#include "goo/PNGWriter.h" +#include "goo/TiffWriter.h" +#include "goo/ImgWriter.h" +#include "goo/GooList.h" + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA, + SplashColorMode modeA, GBool alphaA, + GBool topDown, GooList *separationListA) { + width = widthA; + height = heightA; + mode = modeA; + rowPad = rowPadA; + switch (mode) { + case splashModeMono1: + if (width > 0) { + rowSize = (width + 7) >> 3; + } else { + rowSize = -1; + } + break; + case splashModeMono8: + if (width > 0) { + rowSize = width; + } else { + rowSize = -1; + } + break; + case splashModeRGB8: + case splashModeBGR8: + if (width > 0 && width <= INT_MAX / 3) { + rowSize = width * 3; + } else { + rowSize = -1; + } + break; + case splashModeXBGR8: + if (width > 0 && width <= INT_MAX / 4) { + rowSize = width * 4; + } else { + rowSize = -1; + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + if (width > 0 && width <= INT_MAX / 4) { + rowSize = width * 4; + } else { + rowSize = -1; + } + break; + case splashModeDeviceN8: + if (width > 0 && width <= INT_MAX / 4) { + rowSize = width * (SPOT_NCOMPS + 4); + } else { + rowSize = -1; + } + break; +#endif + } + if (rowSize > 0) { + rowSize += rowPad - 1; + rowSize -= rowSize % rowPad; + } + data = (SplashColorPtr)gmallocn_checkoverflow(rowSize, height); + if (data != NULL) { + if (!topDown) { + data += (height - 1) * rowSize; + rowSize = -rowSize; + } + if (alphaA) { + alpha = (Guchar *)gmallocn(width, height); + } else { + alpha = NULL; + } + } else { + alpha = NULL; + } + separationList = new GooList(); + if (separationListA != NULL) + for (int i = 0; i < separationListA->getLength(); i++) + separationList->append(((GfxSeparationColorSpace *) separationListA->get(i))->copy()); +} + +SplashBitmap *SplashBitmap::copy(SplashBitmap *src) { + SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(), + src->getMode(), src->getAlphaPtr() != NULL, src->getRowSize() >= 0, src->getSeparationList()); + Guchar *dataSource = src->getDataPtr(); + Guchar *dataDest = result->getDataPtr(); + int amount = src->getRowSize(); + if (amount < 0) { + dataSource = dataSource + (src->getHeight() - 1) * amount; + dataDest = dataDest + (src->getHeight() - 1) * amount; + amount *= -src->getHeight(); + } else { + amount *= src->getHeight(); + } + memcpy(dataDest, dataSource, amount); + if (src->getAlphaPtr() != NULL) { + memcpy(result->getAlphaPtr(), src->getAlphaPtr(), src->getWidth() * src->getHeight()); + } + return result; +} + +SplashBitmap::~SplashBitmap() { + if (data) { + if (rowSize < 0) { + gfree(data + (height - 1) * rowSize); + } else { + gfree(data); + } + } + gfree(alpha); + deleteGooList(separationList, GfxSeparationColorSpace); +} + + +SplashError SplashBitmap::writePNMFile(char *fileName) { + FILE *f; + SplashError e; + + if (!(f = fopen(fileName, "wb"))) { + return splashErrOpenFile; + } + + e = this->writePNMFile(f); + + fclose(f); + return e; +} + + +SplashError SplashBitmap::writePNMFile(FILE *f) { + SplashColorPtr row, p; + int x, y; + + switch (mode) { + + case splashModeMono1: + fprintf(f, "P4\n%d %d\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; x += 8) { + fputc(*p ^ 0xff, f); + ++p; + } + row += rowSize; + } + break; + + case splashModeMono8: + fprintf(f, "P5\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + fwrite(row, 1, width, f); + row += rowSize; + } + break; + + case splashModeRGB8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + fwrite(row, 1, 3 * width, f); + row += rowSize; + } + break; + + case splashModeXBGR8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashBGR8R(p), f); + fputc(splashBGR8G(p), f); + fputc(splashBGR8B(p), f); + p += 4; + } + row += rowSize; + } + break; + + + case splashModeBGR8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashBGR8R(p), f); + fputc(splashBGR8G(p), f); + fputc(splashBGR8B(p), f); + p += 3; + } + row += rowSize; + } + break; + +#if SPLASH_CMYK + case splashModeCMYK8: + case splashModeDeviceN8: + // PNM doesn't support CMYK + error(errInternal, -1, "unsupported SplashBitmap mode"); + return splashErrGeneric; + break; +#endif + } + return splashOk; +} + +SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) { + FILE *f; + + if (!alpha) { + return splashErrModeMismatch; + } + if (!(f = fopen(fileName, "wb"))) { + return splashErrOpenFile; + } + fprintf(f, "P5\n%d %d\n255\n", width, height); + fwrite(alpha, 1, width * height, f); + fclose(f); + return splashOk; +} + +void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { + SplashColorPtr p; + + if (y < 0 || y >= height || x < 0 || x >= width || !data) { + return; + } + switch (mode) { + case splashModeMono1: + p = &data[y * rowSize + (x >> 3)]; + pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00; + break; + case splashModeMono8: + p = &data[y * rowSize + x]; + pixel[0] = p[0]; + break; + case splashModeRGB8: + p = &data[y * rowSize + 3 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + break; + case splashModeXBGR8: + p = &data[y * rowSize + 4 * x]; + pixel[0] = p[2]; + pixel[1] = p[1]; + pixel[2] = p[0]; + pixel[3] = p[3]; + break; + case splashModeBGR8: + p = &data[y * rowSize + 3 * x]; + pixel[0] = p[2]; + pixel[1] = p[1]; + pixel[2] = p[0]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + p = &data[y * rowSize + 4 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + pixel[3] = p[3]; + break; + case splashModeDeviceN8: + p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x]; + for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++) + pixel[cp] = p[cp]; + break; +#endif + } +} + +Guchar SplashBitmap::getAlpha(int x, int y) { + return alpha[y * width + x]; +} + +SplashColorPtr SplashBitmap::takeData() { + SplashColorPtr data2; + + data2 = data; + data = NULL; + return data2; +} + +SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, const char *compressionString) { + FILE *f; + SplashError e; + + if (!(f = fopen(fileName, "wb"))) { + return splashErrOpenFile; + } + + e = writeImgFile(format, f, hDPI, vDPI, compressionString); + + fclose(f); + return e; +} + +SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, const char *compressionString) { + ImgWriter *writer; + SplashError e; + + switch (format) { + #ifdef ENABLE_LIBPNG + case splashFormatPng: + writer = new PNGWriter(); + break; + #endif + + #ifdef ENABLE_LIBJPEG + #if SPLASH_CMYK + case splashFormatJpegCMYK: + writer = new JpegWriter(JpegWriter::CMYK); + break; + #endif + case splashFormatJpeg: + writer = new JpegWriter(); + break; + #endif + + #ifdef ENABLE_LIBTIFF + case splashFormatTiff: + switch (mode) { + case splashModeMono1: + writer = new TiffWriter(TiffWriter::MONOCHROME); + break; + case splashModeMono8: + writer = new TiffWriter(TiffWriter::GRAY); + break; + case splashModeRGB8: + case splashModeBGR8: + writer = new TiffWriter(TiffWriter::RGB); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + case splashModeDeviceN8: + writer = new TiffWriter(TiffWriter::CMYK); + break; +#endif + default: + fprintf(stderr, "TiffWriter: Mode %d not supported\n", mode); + writer = new TiffWriter(); + } + if (writer) { + ((TiffWriter *)writer)->setCompressionString(compressionString); + } + break; + #endif + + default: + // Not the greatest error message, but users of this function should + // have already checked whether their desired format is compiled in. + error(errInternal, -1, "Support for this image type not compiled in"); + return splashErrGeneric; + } + + e = writeImgFile(writer, f, hDPI, vDPI); + delete writer; + return e; +} + +#include "poppler/GfxState_helpers.h" + +void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) { + SplashColor col; + double c, m, y, k, c1, m1, y1, k1, r, g, b; + + for (int x = 0; x < width; x++) { + getPixel(x, yl, col); + c = byteToDbl(col[0]); + m = byteToDbl(col[1]); + y = byteToDbl(col[2]); + k = byteToDbl(col[3]); +#if SPLASH_CMYK + if (separationList->getLength() > 0) { + for (int i = 0; i < separationList->getLength(); i++) { + if (col[i+4] > 0) { + GfxCMYK cmyk; + GfxColor input; + input.c[0] = byteToCol(col[i+4]); + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + sepCS->getCMYK(&input, &cmyk); + col[0] = colToByte(cmyk.c); + col[1] = colToByte(cmyk.m); + col[2] = colToByte(cmyk.y); + col[3] = colToByte(cmyk.k); + c += byteToDbl(col[0]); + m += byteToDbl(col[1]); + y += byteToDbl(col[2]); + k += byteToDbl(col[3]); + } + } + if (c > 1) c = 1; + if (m > 1) m = 1; + if (y > 1) y = 1; + if (k > 1) k = 1; + } +#endif + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); + *line++ = dblToByte(clip01(r)); + *line++ = dblToByte(clip01(g)); + *line++ = dblToByte(clip01(b)); + } +} + +void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line, ConversionMode conversionMode) { + SplashColor col; + double c, m, y, k, c1, m1, y1, k1, r, g, b; + + for (int x = 0; x < width; x++) { + getPixel(x, yl, col); + c = byteToDbl(col[0]); + m = byteToDbl(col[1]); + y = byteToDbl(col[2]); + k = byteToDbl(col[3]); +#if SPLASH_CMYK + if (separationList->getLength() > 0) { + for (int i = 0; i < separationList->getLength(); i++) { + if (col[i+4] > 0) { + GfxCMYK cmyk; + GfxColor input; + input.c[0] = byteToCol(col[i+4]); + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + sepCS->getCMYK(&input, &cmyk); + col[0] = colToByte(cmyk.c); + col[1] = colToByte(cmyk.m); + col[2] = colToByte(cmyk.y); + col[3] = colToByte(cmyk.k); + c += byteToDbl(col[0]); + m += byteToDbl(col[1]); + y += byteToDbl(col[2]); + k += byteToDbl(col[3]); + } + } + if (c > 1) c = 1; + if (m > 1) m = 1; + if (y > 1) y = 1; + if (k > 1) k = 1; + } +#endif + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b); + + if (conversionMode == conversionAlphaPremultiplied) { + const double a = getAlpha(x, yl) / 255.0; + + *line++ = dblToByte(clip01(b * a)); + *line++ = dblToByte(clip01(g * a)); + *line++ = dblToByte(clip01(r * a)); + } else { + *line++ = dblToByte(clip01(b)); + *line++ = dblToByte(clip01(g)); + *line++ = dblToByte(clip01(r)); + } + + if (conversionMode != conversionOpaque) { + *line++ = getAlpha(x, yl); + } else { + *line++ = 255; + } + } +} + +static inline Guchar div255(int x) { + return (Guchar)((x + (x >> 8) + 0x80) >> 8); +} + +GBool SplashBitmap::convertToXBGR(ConversionMode conversionMode) { + if (mode == splashModeXBGR8) { + if (conversionMode != conversionOpaque) { + // Copy the alpha channel into the fourth component so that XBGR becomes ABGR. + const SplashColorPtr dbegin = data; + const SplashColorPtr dend = data + rowSize * height; + + Guchar *const abegin = alpha; + Guchar *const aend = alpha + width * height; + + SplashColorPtr d = dbegin; + Guchar *a = abegin; + + if (conversionMode == conversionAlphaPremultiplied) { + for (; d < dend && a < aend; d += 4, a += 1) { + d[0] = div255(d[0] * *a); + d[1] = div255(d[1] * *a); + d[2] = div255(d[2] * *a); + d[3] = *a; + } + } else { + for (d += 3; d < dend && a < aend; d += 4, a += 1) { + *d = *a; + } + } + } + + return gTrue; + } + + int newrowSize = width * 4; + SplashColorPtr newdata = (SplashColorPtr)gmallocn_checkoverflow(newrowSize, height); + if (newdata != NULL) { + for (int y = 0; y < height; y++) { + unsigned char *row = newdata + y * newrowSize; + getXBGRLine(y, row, conversionMode); + } + if (rowSize < 0) { + gfree(data + (height - 1) * rowSize); + } else { + gfree(data); + } + data = newdata; + rowSize = newrowSize; + mode = splashModeXBGR8; + } + return newdata != NULL; +} + +#if SPLASH_CMYK +void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line) { + SplashColor col; + + for (int x = 0; x < width; x++) { + getPixel(x, yl, col); + if (separationList->getLength() > 0) { + double c, m, y, k; + c = byteToDbl(col[0]); + m = byteToDbl(col[1]); + y = byteToDbl(col[2]); + k = byteToDbl(col[3]); + for (int i = 0; i < separationList->getLength(); i++) { + if (col[i+4] > 0) { + GfxCMYK cmyk; + GfxColor input; + input.c[0] = byteToCol(col[i+4]); + GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i); + sepCS->getCMYK(&input, &cmyk); + col[0] = colToByte(cmyk.c); + col[1] = colToByte(cmyk.m); + col[2] = colToByte(cmyk.y); + col[3] = colToByte(cmyk.k); + c += byteToDbl(col[0]); + m += byteToDbl(col[1]); + y += byteToDbl(col[2]); + k += byteToDbl(col[3]); + } + } + col[0] = dblToByte(clip01(c)); + col[1] = dblToByte(clip01(m)); + col[2] = dblToByte(clip01(y)); + col[3] = dblToByte(clip01(k)); + } + *line++ = col[0]; + *line++ = col[1]; + *line++ = col[2]; + *line++ = col[3]; + } +} +#endif + +SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI) { + if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8 && mode != splashModeBGR8 +#if SPLASH_CMYK + && mode != splashModeCMYK8 && mode != splashModeDeviceN8 +#endif + ) { + error(errInternal, -1, "unsupported SplashBitmap mode"); + return splashErrGeneric; + } + + if (!writer->init(f, width, height, hDPI, vDPI)) { + return splashErrGeneric; + } + + switch (mode) { +#if SPLASH_CMYK + case splashModeCMYK8: + if (writer->supportCMYK()) { + SplashColorPtr row; + unsigned char **row_pointers = new unsigned char*[height]; + row = data; + + for (int y = 0; y < height; ++y) { + row_pointers[y] = row; + row += rowSize; + } + if (!writer->writePointers(row_pointers, height)) { + delete[] row_pointers; + return splashErrGeneric; + } + delete[] row_pointers; + } else { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + getRGBLine(y, row); + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; + case splashModeDeviceN8: + if (writer->supportCMYK()) { + unsigned char *row = new unsigned char[4 * width]; + for (int y = 0; y < height; y++) { + getCMYKLine(y, row); + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } else { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + getRGBLine(y, row); + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; +#endif + case splashModeRGB8: + { + SplashColorPtr row; + unsigned char **row_pointers = new unsigned char*[height]; + row = data; + + for (int y = 0; y < height; ++y) { + row_pointers[y] = row; + row += rowSize; + } + if (!writer->writePointers(row_pointers, height)) { + delete[] row_pointers; + return splashErrGeneric; + } + delete[] row_pointers; + } + break; + + case splashModeBGR8: + { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + // Convert into a PNG row + for (int x = 0; x < width; x++) { + row[3*x] = data[y * rowSize + x * 3 + 2]; + row[3*x+1] = data[y * rowSize + x * 3 + 1]; + row[3*x+2] = data[y * rowSize + x * 3]; + } + + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; + + case splashModeXBGR8: + { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + // Convert into a PNG row + for (int x = 0; x < width; x++) { + row[3*x] = data[y * rowSize + x * 4 + 2]; + row[3*x+1] = data[y * rowSize + x * 4 + 1]; + row[3*x+2] = data[y * rowSize + x * 4]; + } + + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; + + case splashModeMono8: + { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + // Convert into a PNG row + for (int x = 0; x < width; x++) { + row[3*x] = data[y * rowSize + x]; + row[3*x+1] = data[y * rowSize + x]; + row[3*x+2] = data[y * rowSize + x]; + } + + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; + + case splashModeMono1: + { + unsigned char *row = new unsigned char[3 * width]; + for (int y = 0; y < height; y++) { + // Convert into a PNG row + for (int x = 0; x < width; x++) { + getPixel(x, y, &row[3*x]); + row[3*x+1] = row[3*x]; + row[3*x+2] = row[3*x]; + } + + if (!writer->writeRow(&row)) { + delete[] row; + return splashErrGeneric; + } + } + delete[] row; + } + break; + + default: + // can't happen + break; + } + + if (!writer->close()) { + return splashErrGeneric; + } + + return splashOk; +} |