//======================================================================== // // 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 Albert Astals Cid // Copyright (C) 2007 Ilmari Heikkinen // Copyright (C) 2009 Shen Liang // Copyright (C) 2009 Stefan Thomas // Copyright (C) 2010 Adrian Johnson // Copyright (C) 2010 Harry Roberts // // 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 #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include "goo/gmem.h" #include "SplashErrorCodes.h" #include "SplashBitmap.h" #include "poppler/Error.h" #include "goo/JpegWriter.h" #include "goo/PNGWriter.h" #include "goo/ImgWriter.h" //------------------------------------------------------------------------ // SplashBitmap //------------------------------------------------------------------------ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, GBool alphaA, GBool topDown) { width = widthA; height = heightA; mode = modeA; 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; #endif } if (rowSize > 0) { rowSize += rowPad - 1; rowSize -= rowSize % rowPad; } data = (SplashColorPtr)gmallocn(rowSize, height); if (!topDown) { data += (height - 1) * rowSize; rowSize = -rowSize; } if (alphaA) { alpha = (Guchar *)gmallocn(width, height); } else { alpha = NULL; } } SplashBitmap::~SplashBitmap() { if (rowSize < 0) { gfree(data + (height - 1) * rowSize); } else { gfree(data); } gfree(alpha); } 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) { p = row; for (x = 0; x < width; ++x) { fputc(*p, f); ++p; } row += rowSize; } break; case splashModeRGB8: 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(splashRGB8R(p), f); fputc(splashRGB8G(p), f); fputc(splashRGB8B(p), f); p += 3; } 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: // PNM doesn't support CMYK error(-1, "unsupported SplashBitmap mode"); return splashErrGeneric; break; #endif } return splashOk; } void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { SplashColorPtr p; if (y < 0 || y >= height || x < 0 || x >= width) { 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; #endif } } Guchar SplashBitmap::getAlpha(int x, int y) { return alpha[y * width + x]; } SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI) { FILE *f; SplashError e; if (!(f = fopen(fileName, "wb"))) { return splashErrOpenFile; } e = writeImgFile(format, f, hDPI, vDPI); fclose(f); return e; } SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI) { ImgWriter *writer; SplashError e; switch (format) { #ifdef ENABLE_LIBPNG case splashFormatPng: writer = new PNGWriter(); break; #endif #ifdef ENABLE_LIBJPEG case splashFormatJpeg: writer = new JpegWriter(); 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(-1, "Support for this image type not compiled in"); return splashErrGeneric; } e = writeImgFile(writer, f, hDPI, vDPI); delete writer; return e; } SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI) { if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8) { error(-1, "unsupported SplashBitmap mode"); return splashErrGeneric; } if (!writer->init(f, width, height, hDPI, vDPI)) { return splashErrGeneric; } switch (mode) { 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 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; }