From ee9bccdb5d743123197ce47536bcbb9c9d4391e1 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 18 Aug 2013 15:50:39 +0930 Subject: [PATCH 1/5] Refactor ImageOutputDev to facilitate adding more output formats - Move PPM/PBM code into a NetPBMWriter class so PNGWriter and TiffWritersupport be added. - Create generic WriteRawIMage function for writing jpeg files so support for jpeg2000/jbig2 can be added. --- CMakeLists.txt | 1 + goo/Makefile.am | 2 + goo/NetPBMWriter.cc | 84 ++++++++++++++++ goo/NetPBMWriter.h | 52 ++++++++++ utils/ImageOutputDev.cc | 261 +++++++++++++++++++++--------------------------- utils/ImageOutputDev.h | 15 +-- 6 files changed, 262 insertions(+), 153 deletions(-) create mode 100644 goo/NetPBMWriter.cc create mode 100644 goo/NetPBMWriter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0da8c6d..1e03c5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -264,6 +264,7 @@ set(poppler_SRCS goo/GooString.cc goo/gmem.cc goo/FixedPoint.cc + goo/NetPBMWriter.cc goo/PNGWriter.cc goo/TiffWriter.cc goo/JpegWriter.cc diff --git a/goo/Makefile.am b/goo/Makefile.am index 0764e79..a48b20e 100644 --- a/goo/Makefile.am +++ b/goo/Makefile.am @@ -13,6 +13,7 @@ poppler_goo_include_HEADERS = \ gmem.h \ gfile.h \ FixedPoint.h \ + NetPBMWriter.h \ PNGWriter.h \ JpegWriter.h \ TiffWriter.h \ @@ -55,6 +56,7 @@ libgoo_la_SOURCES = \ GooString.cc \ gmem.cc \ FixedPoint.cc \ + NetPBMWriter.cc \ PNGWriter.cc \ JpegWriter.cc \ TiffWriter.cc \ diff --git a/goo/NetPBMWriter.cc b/goo/NetPBMWriter.cc new file mode 100644 index 0000000..fca00b2 --- /dev/null +++ b/goo/NetPBMWriter.cc @@ -0,0 +1,84 @@ +//======================================================================== +// +// NetPBMWriter.h +// +// Copyright 1998-2003 Glyph & Cog, LLC +// +//======================================================================== +// +//======================================================================== +// +// 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) 2005, 2007, 2011 Albert Astals Cid +// Copyright (C) 2006 Rainer Keller +// Copyright (C) 2008 Timothy Lee +// Copyright (C) 2008 Vasile Gaburici +// Copyright (C) 2009 Carlos Garcia Campos +// Copyright (C) 2009 William Bader +// Copyright (C) 2010 Jakob Voss +// Copyright (C) 2012, 2013 Adrian Johnson +// Copyright (C) 2013 Thomas Fischer +// +// 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 "poppler-config.h" + +#include "NetPBMWriter.h" + +// Writer for the NetPBM formats (PBM and PPM) +// This format is documented at: +// http://netpbm.sourceforge.net/doc/pbm.html +// http://netpbm.sourceforge.net/doc/ppm.html + +NetPBMWriter::NetPBMWriter(Format formatA) : format(formatA) +{ +} + +bool NetPBMWriter::init(FILE *f, int widthA, int heightA, int hDPI, int vDPI) +{ + file = f; + width = widthA; + if (format == MONOCHROME) { + fprintf(file, "P4\n"); + fprintf(file, "%d %d\n", widthA, heightA); + } else { + fprintf(file, "P6\n"); + fprintf(file, "%d %d\n", widthA, heightA); + fprintf(file, "255\n"); + } + return true; +} + +bool NetPBMWriter::writePointers(unsigned char **rowPointers, int rowCount) +{ + for (int i = 0; i < rowCount; i++) + writeRow(&rowPointers[i]); + return true; +} + +bool NetPBMWriter::writeRow(unsigned char **row) +{ + if (format == MONOCHROME) { + // PBM uses 0 = white, 1 = black so we need to invert the colors + int size = (width + 7)/8; + for (int i = 0; i < size; i++) + fputc((*row)[i] ^ 0xff, file); + } else { + fwrite(*row, 1, width*3, file); + } + return true; +} + + +bool NetPBMWriter::close() +{ + return true; +} + diff --git a/goo/NetPBMWriter.h b/goo/NetPBMWriter.h new file mode 100644 index 0000000..21a19ee --- /dev/null +++ b/goo/NetPBMWriter.h @@ -0,0 +1,52 @@ +//======================================================================== +// +// NetPBMWriter.h +// +// This file is licensed under the GPLv2 or later +// +// Copyright (C) 2009 Stefan Thomas +// Copyright (C) 2009, 2011 Albert Astals Cid +// Copyright (C) 2010, 2013 Adrian Johnson +// Copyright (C) 2010 Brian Cameron +// Copyright (C) 2011 Thomas Freitag +// +//======================================================================== + +#ifndef NETPBMWRITER_H +#define NETPBMWRITER_H + +#include "poppler-config.h" + +#include "ImgWriter.h" + +// Writer for the NetPBM formats (PBM and PPM) +// This format is documented at: +// http://netpbm.sourceforge.net/doc/pbm.html +// http://netpbm.sourceforge.net/doc/ppm.html + +class NetPBMWriter : public ImgWriter +{ +public: + + /* RGB - 3 bytes/pixel + * MONOCHROME - 8 pixels/byte + */ + enum Format { RGB, MONOCHROME }; + + NetPBMWriter(Format formatA = RGB); + ~NetPBMWriter() {}; + + bool init(FILE *f, int width, int height, int hDPI, int vDPI); + + bool writePointers(unsigned char **rowPointers, int rowCount); + bool writeRow(unsigned char **row); + + bool close(); + +private: + FILE *file; + Format format; + int width; +}; + +#endif diff --git a/utils/ImageOutputDev.cc b/utils/ImageOutputDev.cc index e61e8e9..897c116 100644 --- a/utils/ImageOutputDev.cc +++ b/utils/ImageOutputDev.cc @@ -41,6 +41,7 @@ #include #include #include "goo/gmem.h" +#include "goo/NetPBMWriter.h" #include "Error.h" #include "GfxState.h" #include "Object.h" @@ -274,177 +275,145 @@ void ImageOutputDev::listImage(GfxState *state, Object *ref, Stream *str, ++imgNum; } -void ImageOutputDev::writeMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool interpolate, GBool inlineImg) { +void ImageOutputDev::writeRawImage(Stream *str, const char *ext) { FILE *f; int c; - int size, i; - // dump JPEG file - if (dumpJPEG && str->getKind() == strDCT && !inlineImg) { + // open the image file + setFilename(ext); + ++imgNum; + if (!(f = fopen(fileName, "wb"))) { + error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); + return; + } - // open the image file - setFilename("jpg"); - ++imgNum; - if (!(f = fopen(fileName, "wb"))) { - error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); - return; - } + // initialize stream + str = str->getNextStream(); + str->reset(); - // initialize stream - str = str->getNextStream(); - str->reset(); + // copy the stream + while ((c = str->getChar()) != EOF) + fputc(c, f); - // copy the stream - while ((c = str->getChar()) != EOF) - fputc(c, f); + str->close(); + fclose(f); +} - str->close(); - fclose(f); +void ImageOutputDev::writeImageFile(ImgWriter *writer, ImageFormat format, const char *ext, + Stream *str, int width, int height, GfxImageColorMap *colorMap) { + FILE *f; + ImageStream *imgStr; + unsigned char *row; + unsigned char *rowp; + Guchar *p; + GfxRGB rgb; + GfxGray gray; + Guchar zero = 0; + int invert_bits = 0xff; - // dump PBM file - } else { + setFilename(ext); + ++imgNum; + if (!(f = fopen(fileName, "wb"))) { + error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); + return; + } - // open the image file and write the PBM header - setFilename("pbm"); - ++imgNum; - if (!(f = fopen(fileName, "wb"))) { - error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); - return; - } - fprintf(f, "P4\n"); - fprintf(f, "%d %d\n", width, height); + if (!writer->init(f, width, height, 72, 72)) { + error(errIO, -1, "Error writing '{0:s}'", fileName); + return; + } + if (format != imgMonochrome) { + // initialize stream + imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); + } else { // initialize stream str->reset(); + } + + row = (unsigned char *) gmallocn(width, sizeof(unsigned int)); + + // if 0 comes out as 0 in the color map, the we _flip_ stream bits + // otherwise we pass through stream bits unmolested + if (colorMap) { + colorMap->getGray(&zero, &gray); + if (colToByte(gray) == 0) + invert_bits = 0x00; + } - // copy the stream - size = height * ((width + 7) / 8); - for (i = 0; i < size; ++i) { - fputc(str->getChar(), f); + // for each line... + for (int y = 0; y < height; y++) { + switch (format) { + case imgRGB: + p = imgStr->getLine(); + rowp = row; + for (int x = 0; x < width; ++x) { + if (p) { + colorMap->getRGB(p, &rgb); + *rowp++ = colToByte(rgb.r); + *rowp++ = colToByte(rgb.g); + *rowp++ = colToByte(rgb.b); + p += colorMap->getNumPixelComps(); + } else { + *rowp++ = 0; + *rowp++ = 0; + *rowp++ = 0; + } + } + writer->writeRow(&row); + break; + + case imgMonochrome: + int size = (width + 7)/8; + for (int x = 0; x < size; x++) + row[x] = str->getChar() ^ invert_bits; + writer->writeRow(&row); + break; } + } - str->close(); - fclose(f); + gfree(row); + if (format != imgMonochrome) { + imgStr->close(); + delete imgStr; } + str->close(); + writer->close(); + fclose(f); } void ImageOutputDev::writeImage(GfxState *state, Object *ref, Stream *str, int width, int height, - GfxImageColorMap *colorMap, - GBool interpolate, int *maskColors, GBool inlineImg) { - FILE *f; - ImageStream *imgStr; - Guchar *p; - Guchar zero = 0; - GfxGray gray; - GfxRGB rgb; - int x, y; - int c; - int size, i; - int pbm_mask = 0xff; + GfxImageColorMap *colorMap, GBool inlineImg) { + ImageFormat format; - // dump JPEG file if (dumpJPEG && str->getKind() == strDCT && (colorMap->getNumPixelComps() == 1 || colorMap->getNumPixelComps() == 3) && !inlineImg) { - // open the image file - setFilename("jpg"); - ++imgNum; - if (!(f = fopen(fileName, "wb"))) { - error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); - return; - } + // dump JPEG file + writeRawImage(str, "jpg"); - // initialize stream - str = str->getNextStream(); - str->reset(); - - // copy the stream - while ((c = str->getChar()) != EOF) - fputc(c, 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 - setFilename("pbm"); - ++imgNum; - if (!(f = fopen(fileName, "wb"))) { - error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); - return; - } - fprintf(f, "P4\n"); - fprintf(f, "%d %d\n", width, height); - - // initialize stream - str->reset(); - - // if 0 comes out as 0 in the color map, the we _flip_ stream bits - // otherwise we pass through stream bits unmolested - colorMap->getGray(&zero, &gray); - if(colToByte(gray)) - pbm_mask = 0; - - // copy the stream - size = height * ((width + 7) / 8); - for (i = 0; i < size; ++i) { - fputc(str->getChar() ^ pbm_mask, f); - } - - str->close(); - fclose(f); - - // dump PPM file } else { + ImgWriter *writer; - // open the image file and write the PPM header - setFilename("ppm"); - ++imgNum; - if (!(f = fopen(fileName, "wb"))) { - error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); - return; + // dump PBM file + if (!colorMap || (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1)) { + writer = new NetPBMWriter(NetPBMWriter::MONOCHROME); + format = imgMonochrome; + } else { + writer = new NetPBMWriter(NetPBMWriter::RGB); + format = imgRGB; } - 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); - 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; + writeImageFile(writer, format, + format == imgRGB ? "ppm" : "pbm", + str, width, height, colorMap); - fclose(f); + delete writer; } } @@ -463,7 +432,7 @@ void ImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, if (listImages) listImage(state, ref, str, width, height, NULL, interpolate, inlineImg, imgStencil); else - writeMask(state, ref, str, width, height, invert, interpolate, inlineImg); + writeImage(state, ref, str, width, height, NULL, inlineImg); } void ImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, @@ -473,7 +442,7 @@ void ImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, if (listImages) listImage(state, ref, str, width, height, colorMap, interpolate, inlineImg, imgImage); else - writeImage(state, ref, str, width, height, colorMap, interpolate, maskColors, inlineImg); + writeImage(state, ref, str, width, height, colorMap, inlineImg); } void ImageOutputDev::drawMaskedImage( @@ -484,9 +453,8 @@ void ImageOutputDev::drawMaskedImage( listImage(state, ref, str, width, height, colorMap, interpolate, gFalse, imgImage); listImage(state, ref, str, maskWidth, maskHeight, NULL, maskInterpolate, gFalse, imgMask); } else { - drawImage(state, ref, str, width, height, colorMap, interpolate, NULL, gFalse); - drawImageMask(state, ref, maskStr, maskWidth, maskHeight, maskInvert, - maskInterpolate, gFalse); + writeImage(state, ref, str, width, height, colorMap, gFalse); + writeImage(state, ref, maskStr, maskWidth, maskHeight, NULL, gFalse); } } @@ -499,8 +467,7 @@ void ImageOutputDev::drawSoftMaskedImage( listImage(state, ref, str, width, height, colorMap, interpolate, gFalse, imgImage); listImage(state, ref, maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate, gFalse, imgSmask); } else { - drawImage(state, ref, str, width, height, colorMap, interpolate, NULL, gFalse); - drawImage(state, ref, maskStr, maskWidth, maskHeight, - maskColorMap, maskInterpolate, NULL, gFalse); + writeImage(state, ref, str, width, height, colorMap, gFalse); + writeImage(state, ref, maskStr, maskWidth, maskHeight, maskColorMap, gFalse); } } diff --git a/utils/ImageOutputDev.h b/utils/ImageOutputDev.h index 878bdb9..5d8536c 100644 --- a/utils/ImageOutputDev.h +++ b/utils/ImageOutputDev.h @@ -36,6 +36,7 @@ #include #include "goo/gtypes.h" +#include "goo/ImgWriter.h" #include "OutputDev.h" class GfxState; @@ -52,6 +53,10 @@ public: imgMask, imgSmask }; + enum ImageFormat { + imgRGB, + imgMonochrome + }; // Create an OutputDev which will write images to files named // -NNN. or -PPP-NNN., if @@ -128,13 +133,11 @@ private: GfxImageColorMap *colorMap, GBool interpolate, GBool inlineImg, ImageType imageType); - void writeMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool interpolate, GBool inlineImg); void writeImage(GfxState *state, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - GBool interpolate, int *maskColors, GBool inlineImg); - + int width, int height, GfxImageColorMap *colorMap, GBool inlineImg); + void writeRawImage(Stream *str, const char *ext); + void writeImageFile(ImgWriter *writer, ImageFormat format, const char *ext, + Stream *str, int width, int height, GfxImageColorMap *colorMap); char *fileRoot; // root of output file names char *fileName; // buffer for output file names -- 1.8.1.2