From 29f723a9369ae76e1aa04e221597ec89745a46cb Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 16 Jul 2017 12:23:28 +0930 Subject: [PATCH 2/2] pdftoppm: add -jpegopt for setting jpeg compression parameters Bug 45727 --- splash/SplashBitmap.cc | 25 ++++++++++++---- splash/SplashBitmap.h | 15 ++++++++-- utils/pdftoppm.1 | 15 ++++++++++ utils/pdftoppm.cc | 80 ++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 120 insertions(+), 15 deletions(-) diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc index e9b2be42..aae87025 100644 --- a/splash/SplashBitmap.cc +++ b/splash/SplashBitmap.cc @@ -337,7 +337,7 @@ SplashColorPtr SplashBitmap::takeData() { return data2; } -SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, const char *compressionString) { +SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, WriteImgParams* params) { FILE *f; SplashError e; @@ -345,13 +345,24 @@ SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileN return splashErrOpenFile; } - e = writeImgFile(format, f, hDPI, vDPI, compressionString); - + e = writeImgFile(format, f, hDPI, vDPI, params); + fclose(f); return e; } -SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, const char *compressionString) { +void SplashBitmap::setJpegParams(ImgWriter *writer, WriteImgParams* params) +{ +#ifdef ENABLE_LIBJPEG + if (params) { + static_cast(writer)->setProgressive(params->jpegProgressive); + if (params->jpegQuality >= 0) + static_cast(writer)->setQuality(params->jpegQuality); + } +#endif +} + +SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, WriteImgParams* params) { ImgWriter *writer; SplashError e; @@ -368,10 +379,12 @@ SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, in #if SPLASH_CMYK case splashFormatJpegCMYK: writer = new JpegWriter(JpegWriter::CMYK); + setJpegParams(writer, params); break; #endif case splashFormatJpeg: writer = new JpegWriter(); + setJpegParams(writer, params); break; #endif @@ -400,8 +413,8 @@ SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, in fprintf(stderr, "TiffWriter: Mode %d not supported\n", mode); writer = new TiffWriter(); } - if (writer) { - ((TiffWriter *)writer)->setCompressionString(compressionString); + if (writer && params) { + ((TiffWriter *)writer)->setCompressionString(params->tiffCompression.getCString()); } break; #endif diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h index 6858f90f..be667f17 100644 --- a/splash/SplashBitmap.h +++ b/splash/SplashBitmap.h @@ -72,9 +72,16 @@ public: SplashError writePNMFile(char *fileName); SplashError writePNMFile(FILE *f); SplashError writeAlphaPGMFile(char *fileName); - - SplashError writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, const char *compressionString = ""); - SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, const char *compressionString = ""); + + struct WriteImgParams + { + int jpegQuality = -1; + GBool jpegProgressive = gFalse; + GooString tiffCompression; + }; + + SplashError writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, WriteImgParams* params = NULL); + SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, WriteImgParams* params = NULL); SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI, SplashColorMode imageWriterFormat); enum ConversionMode @@ -112,6 +119,8 @@ private: GooList *separationList; // list of spot colorants and their mapping functions friend class Splash; + + void setJpegParams(ImgWriter *writer, WriteImgParams* params); }; #endif diff --git a/utils/pdftoppm.1 b/utils/pdftoppm.1 index e16ca7d9..b489e025 100644 --- a/utils/pdftoppm.1 +++ b/utils/pdftoppm.1 @@ -92,6 +92,11 @@ Generates a PNG file instead a PPM file. .B \-jpeg Generates a JPEG file instead a PPM file. .TP +.BI \-jpegopt " jpeg-options" +When used with \-jpeg, takes a list of options to control the jpeg compression. See +.B JPEG OPTIONS +for the available options. +.TP .B \-tiff Generates a TIFF file instead a PPM file. .TP @@ -156,6 +161,16 @@ Error related to PDF permissions. .TP 99 Other error. +.SH JPEG OPTIONS +When JPEG output is specified, the \-jpegopt option can be used to control the JPEG compression parameters. +It takes a string of the form "=[,=]". Currently the available options are: +.TP +.BI quality +Selects the JPEG quality value. The value must be an integer between 0 and 100. +.TP +.BI progressive +Select progressive JPEG output. The possible values are "y", "n", +indicating progressive (yes) or non-progressive (no), respectively. .SH AUTHOR The pdftoppm software and documentation are copyright 1996-2011 Glyph & Cog, LLC. diff --git a/utils/pdftoppm.cc b/utils/pdftoppm.cc index 3574595b..8da5327b 100644 --- a/utils/pdftoppm.cc +++ b/utils/pdftoppm.cc @@ -87,6 +87,9 @@ static GBool png = gFalse; static GBool jpeg = gFalse; static GBool jpegcmyk = gFalse; static GBool tiff = gFalse; +static GooString jpegOpt; +static int jpegQuality = -1; +static bool jpegProgressive = false; #if SPLASH_CMYK static GBool overprint = gFalse; #endif @@ -160,6 +163,8 @@ static const ArgDesc argDesc[] = { {"-jpegcmyk",argFlag, &jpegcmyk, 0, "generate a CMYK JPEG file"}, #endif + {"-jpegopt", argGooString, &jpegOpt, 0, + "jpeg options, with format =[,=]*"}, #endif #if SPLASH_CMYK {"-overprint",argFlag, &overprint, 0, @@ -208,6 +213,58 @@ static const ArgDesc argDesc[] = { {NULL} }; +static GBool parseJpegOptions() +{ + //jpegOpt format is: =,=,... + const char *nextOpt = jpegOpt.getCString(); + while (nextOpt && *nextOpt) + { + const char *comma = strchr(nextOpt, ','); + GooString opt; + if (comma) { + opt.Set(nextOpt, comma - nextOpt); + nextOpt = comma + 1; + } else { + opt.Set(nextOpt); + nextOpt = NULL; + } + //here opt is "= " + const char *equal = strchr(opt.getCString(), '='); + if (!equal) { + fprintf(stderr, "Unknown jpeg option \"%s\"\n", opt.getCString()); + return gFalse; + } + int iequal = equal - opt.getCString(); + GooString value(&opt, iequal + 1, opt.getLength() - iequal - 1); + opt.del(iequal, opt.getLength() - iequal); + //here opt is "" and value is "" + + if (opt.cmp("quality") == 0) { + if (!isInt(value.getCString())) { + fprintf(stderr, "Invalid jpeg quality\n"); + return gFalse; + } + jpegQuality = atoi(value.getCString()); + if (jpegQuality < 0 || jpegQuality > 100) { + fprintf(stderr, "jpeg quality must be between 0 and 100\n"); + return gFalse; + } + } else if (opt.cmp("progressive") == 0) { + jpegProgressive = gFalse; + if (value.cmp("y") == 0) { + jpegProgressive = gTrue; + } else if (value.cmp("n") != 0) { + fprintf(stderr, "jpeg progressive option must be \"y\" or \"n\"\n"); + return gFalse; + } + } else { + fprintf(stderr, "Unknown jpeg option \"%s\"\n", opt.getCString()); + return gFalse; + } + } + return gTrue; +} + static void savePageSlice(PDFDoc *doc, SplashOutputDev *splashOut, int pg, int x, int y, int w, int h, @@ -225,16 +282,21 @@ static void savePageSlice(PDFDoc *doc, ); SplashBitmap *bitmap = splashOut->getBitmap(); - + + SplashBitmap::WriteImgParams params; + params.jpegQuality = jpegQuality; + params.jpegProgressive = jpegProgressive; + params.tiffCompression.Set(TiffCompressionStr); + if (ppmFile != NULL) { if (png) { bitmap->writeImgFile(splashFormatPng, ppmFile, x_resolution, y_resolution); } else if (jpeg) { - bitmap->writeImgFile(splashFormatJpeg, ppmFile, x_resolution, y_resolution); + bitmap->writeImgFile(splashFormatJpeg, ppmFile, x_resolution, y_resolution, ¶ms); } else if (jpegcmyk) { - bitmap->writeImgFile(splashFormatJpegCMYK, ppmFile, x_resolution, y_resolution); + bitmap->writeImgFile(splashFormatJpegCMYK, ppmFile, x_resolution, y_resolution, ¶ms); } else if (tiff) { - bitmap->writeImgFile(splashFormatTiff, ppmFile, x_resolution, y_resolution, TiffCompressionStr); + bitmap->writeImgFile(splashFormatTiff, ppmFile, x_resolution, y_resolution, ¶ms); } else { bitmap->writePNMFile(ppmFile); } @@ -246,9 +308,9 @@ static void savePageSlice(PDFDoc *doc, if (png) { bitmap->writeImgFile(splashFormatPng, stdout, x_resolution, y_resolution); } else if (jpeg) { - bitmap->writeImgFile(splashFormatJpeg, stdout, x_resolution, y_resolution); + bitmap->writeImgFile(splashFormatJpeg, stdout, x_resolution, y_resolution, ¶ms); } else if (tiff) { - bitmap->writeImgFile(splashFormatTiff, stdout, x_resolution, y_resolution, TiffCompressionStr); + bitmap->writeImgFile(splashFormatTiff, stdout, x_resolution, y_resolution, ¶ms); } else { bitmap->writePNMFile(stdout); } @@ -372,6 +434,12 @@ int main(int argc, char *argv[]) { } } + if (jpegOpt.getLength() > 0) { + if (!jpeg) + fprintf(stderr, "Warning: -jpegopt only valid with jpeg output.\n"); + parseJpegOptions(); + } + // read config file globalParams = new GlobalParams(); if (enableFreeTypeStr[0]) { -- 2.11.0