//======================================================================== // // ImageOutputDev.cc // // Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include #include "gmem.h" #include "gmempp.h" #include "config.h" #include "Error.h" #include "GfxState.h" #include "Object.h" #include "Stream.h" #include "ImageOutputDev.h" ImageOutputDev::ImageOutputDev(char *fileRootA, GBool dumpJPEGA, GBool dumpRawA, GBool listA) { fileRoot = copyString(fileRootA); dumpJPEG = dumpJPEGA; dumpRaw = dumpRawA; list = listA; imgNum = 0; curPageNum = 0; ok = gTrue; } ImageOutputDev::~ImageOutputDev() { gfree(fileRoot); } void ImageOutputDev::startPage(int pageNum, GfxState *state) { curPageNum = pageNum; } void ImageOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *strRef, int paintType, int tilingType, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep) { // do nothing -- this avoids the potentially slow loop in Gfx.cc } void ImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg, GBool interpolate) { GString *fileName; FILE *f; char buf[4096]; int size, n, i; // dump raw file if (dumpRaw && !inlineImg) { // open the image file fileName = GString::format("{0:s}-{1:04d}.{2:s}", fileRoot, imgNum, getRawFileExtension(str)); ++imgNum; if (!(f = openFile(fileName->getCString(), "wb"))) { error(errIO, -1, "Couldn't open image file '{0:t}'", fileName); delete fileName; return; } // initialize stream str = getRawStream(str); str->reset(); // copy the stream while ((n = str->getBlock(buf, sizeof(buf))) > 0) { fwrite(buf, 1, n, f); } str->close(); fclose(f); // dump JPEG file } else if (dumpJPEG && str->getKind() == strDCT && !inlineImg) { // open the image file fileName = GString::format("{0:s}-{1:04d}.jpg", fileRoot, imgNum); ++imgNum; if (!(f = openFile(fileName->getCString(), "wb"))) { error(errIO, -1, "Couldn't open image file '{0:t}'", fileName); delete fileName; return; } // initialize stream str = ((DCTStream *)str)->getRawStream(); str->reset(); // copy the stream while ((n = str->getBlock(buf, sizeof(buf))) > 0) { fwrite(buf, 1, n, f); } str->close(); fclose(f); // dump PBM file } else { // open the image file and write the PBM header fileName = GString::format("{0:s}-{1:04d}.pbm", fileRoot, imgNum); ++imgNum; if (!(f = openFile(fileName->getCString(), "wb"))) { error(errIO, -1, "Couldn't open image file '{0:t}'", fileName); delete fileName; return; } fprintf(f, "P4\n"); fprintf(f, "%d %d\n", width, height); // initialize stream str->reset(); // copy the stream size = height * ((width + 7) / 8); while (size > 0) { i = size < (int)sizeof(buf) ? size : (int)sizeof(buf); n = str->getBlock(buf, i); fwrite(buf, 1, n, f); if (n < i) { break; } size -= n; } str->close(); fclose(f); } if (list) { writeImageInfo(fileName, width, height, state, NULL); } delete fileName; } void ImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg, GBool interpolate) { GfxColorSpaceMode csMode; GString *fileName; FILE *f; ImageStream *imgStr; Guchar *p; GfxRGB rgb; GfxGray gray; int x, y; char buf[4096]; int size, n, i, j; csMode = colorMap->getColorSpace()->getMode(); if (csMode == csIndexed) { csMode = ((GfxIndexedColorSpace *)colorMap->getColorSpace()) ->getBase()->getMode(); } // dump raw file if (dumpRaw && !inlineImg) { // open the image file fileName = GString::format("{0:s}-{1:04d}.{2:s}", fileRoot, imgNum, getRawFileExtension(str)); ++imgNum; if (!(f = openFile(fileName->getCString(), "wb"))) { error(errIO, -1, "Couldn't open image file '{0:t}'", fileName); delete fileName; return; } // initialize stream str = getRawStream(str); str->reset(); // copy the stream while ((n = str->getBlock(buf, sizeof(buf))) > 0) { fwrite(buf, 1, n, f); } str->close(); fclose(f); // dump JPEG file } else if (dumpJPEG && str->getKind() == strDCT && (colorMap->getNumPixelComps() == 1 || colorMap->getNumPixelComps() == 3) && !inlineImg) { // open the image file fileName = GString::format("{0:s}-{1:04d}.jpg", fileRoot, imgNum); ++imgNum; if (!(f = openFile(fileName->getCString(), "wb"))) { error(errIO, -1, "Couldn't open image file '{0:t}'", fileName); delete fileName; return; } // initialize stream str = ((DCTStream *)str)->getRawStream(); str->reset(); // copy the stream while ((n = str->getBlock(buf, sizeof(buf))) > 0) { fwrite(buf, 1, n, f); } str->close(); fclose(f); // dump PBM file } else if (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1) { // open the image file and write the PBM header fileName = GString::format("{0:s}-{1:04d}.pbm", fileRoot, imgNum); ++imgNum; if (!(f = openFile(fileName->getCString(), "wb"))) { error(errIO, -1, "Couldn't open image file '{0:t}'", fileName); delete fileName; return; } fprintf(f, "P4\n"); fprintf(f, "%d %d\n", width, height); // initialize stream str->reset(); // copy the stream size = height * ((width + 7) / 8); while (size > 0) { i = size < (int)sizeof(buf) ? size : (int)sizeof(buf); n = str->getBlock(buf, i); for (j = 0; j < n; ++j) { buf[j] = (char)(buf[j] ^ 0xff); } fwrite(buf, 1, n, f); if (n < i) { break; } size -= n; } str->close(); fclose(f); // dump PGM file } else if (colorMap->getNumPixelComps() == 1 && (csMode == csDeviceGray || csMode == csCalGray)) { // open the image file and write the PGM header fileName = GString::format("{0:s}-{1:04d}.pgm", fileRoot, imgNum); ++imgNum; if (!(f = openFile(fileName->getCString(), "wb"))) { error(errIO, -1, "Couldn't open image file '{0:t}'", fileName); delete fileName; return; } fprintf(f, "P5\n"); fprintf(f, "%d %d\n", width, height); fprintf(f, "255\n"); // initialize stream imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgStr->reset(); // for each line... for (y = 0; y < height; ++y) { // write the line if ((p = imgStr->getLine())) { for (x = 0; x < width; ++x) { colorMap->getGray(p, &gray, state->getRenderingIntent()); fputc(colToByte(gray), f); ++p; } } else { for (x = 0; x < width; ++x) { fputc(0, f); } } } imgStr->close(); delete imgStr; fclose(f); // dump PPM file } else { // open the image file and write the PPM header fileName = GString::format("{0:s}-{1:04d}.ppm", fileRoot, imgNum); ++imgNum; if (!(f = openFile(fileName->getCString(), "wb"))) { error(errIO, -1, "Couldn't open image file '{0:t}'", fileName); delete fileName; return; } fprintf(f, "P6\n"); fprintf(f, "%d %d\n", width, height); fprintf(f, "255\n"); // initialize stream imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgStr->reset(); // for each line... for (y = 0; y < height; ++y) { // write the line if ((p = imgStr->getLine())) { for (x = 0; x < width; ++x) { colorMap->getRGB(p, &rgb, state->getRenderingIntent()); fputc(colToByte(rgb.r), f); fputc(colToByte(rgb.g), f); fputc(colToByte(rgb.b), f); p += colorMap->getNumPixelComps(); } } else { for (x = 0; x < width; ++x) { fputc(0, f); fputc(0, f); fputc(0, f); } } } imgStr->close(); delete imgStr; fclose(f); } if (list) { writeImageInfo(fileName, width, height, state, colorMap); } delete fileName; } void ImageOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Object *maskRef, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GBool interpolate) { drawImage(state, ref, str, width, height, colorMap, NULL, gFalse, interpolate); drawImageMask(state, maskRef, maskStr, maskWidth, maskHeight, maskInvert, gFalse, interpolate); } void ImageOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Object *maskRef, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap, double *matte, GBool interpolate) { drawImage(state, ref, str, width, height, colorMap, NULL, gFalse, interpolate); drawImage(state, maskRef, maskStr, maskWidth, maskHeight, maskColorMap, NULL, gFalse, interpolate); } Stream *ImageOutputDev::getRawStream(Stream *str) { switch (str->getKind()) { case strLZW: case strRunLength: case strCCITTFax: case strDCT: case strFlate: case strJBIG2: case strJPX: return ((FilterStream *)str)->getNextStream(); default: return str; } } const char *ImageOutputDev::getRawFileExtension(Stream *str) { switch (str->getKind()) { case strLZW: return "lzw"; case strRunLength: return "rle"; case strCCITTFax: return "fax"; case strDCT: return "jpg"; case strFlate: return "flate"; case strJBIG2: return "jb2"; case strJPX: return "jpx"; default: return "unknown"; } } void ImageOutputDev::writeImageInfo(GString *fileName, int width, int height, GfxState *state, GfxImageColorMap *colorMap) { const char *mode; double hdpi, vdpi, x0, y0, x1, y1; int bpc; // this works for 0/90/180/270-degree rotations, along with // horizontal/vertical flips state->transformDelta(1, 0, &x0, &y0); state->transformDelta(0, 1, &x1, &y1); x0 = fabs(x0); y0 = fabs(y0); x1 = fabs(x1); y1 = fabs(y1); if (x0 > y0) { hdpi = (72 * width) / x0; vdpi = (72 * height) / y1; } else { hdpi = (72 * height) / x1; vdpi = (72 * width) / y0; } if (colorMap) { mode = GfxColorSpace::getColorSpaceModeName( colorMap->getColorSpace()->getMode()); bpc = colorMap->getBits(); } else { mode = NULL; bpc = 1; } printf("%s: page=%d width=%d height=%d hdpi=%.2f vdpi=%.2f %s%s bpc=%d\n", fileName->getCString(), curPageNum, width, height, hdpi, vdpi, mode ? "colorspace=" : "mask", mode ? mode : "", bpc); }