goo/JpegWriter.cc | 10 ++++++ goo/JpegWriter.h | 2 + splash/SplashBitmap.cc | 25 +++++++++++---- splash/SplashBitmap.h | 15 +++++++-- utils/pdftocairo.1 | 17 +++++++++- utils/pdftocairo.cc | 71 +++++++++++++++++++++++++++++++++++++++++++ utils/pdftoppm.1 | 15 +++++++++ utils/pdftoppm.cc | 80 +++++++++++++++++++++++++++++++++++++++++++++---- 8 files changed, 219 insertions(+), 16 deletions(-)
New commits: commit b9030a069756c84669ed6f408399cc7e2ce4fd10 Author: Adrian Johnson <[email protected]> Date: Sun Jul 16 12:23:28 2017 +0930 pdftoppm: add -jpegopt for setting jpeg compression parameters Bug 45727 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<JpegWriter*>(writer)->setProgressive(params->jpegProgressive); + if (params->jpegQuality >= 0) + static_cast<JpegWriter*>(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..9802bd30 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 = nullptr); + SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, WriteImgParams* params = nullptr); 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 "<opt>=<val>[,<opt>=<val>]". 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 <opt1>=<val1>[,<optN>=<valN>]*"}, #endif #if SPLASH_CMYK {"-overprint",argFlag, &overprint, 0, @@ -208,6 +213,58 @@ static const ArgDesc argDesc[] = { {NULL} }; +static GBool parseJpegOptions() +{ + //jpegOpt format is: <opt1>=<val1>,<opt2>=<val2>,... + 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 "<optN>=<valN> " + 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 "<optN>" and value is "<valN>" + + 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]) { commit dd54243f00557e84dba887403912d12463c8b1e9 Author: Adrian Johnson <[email protected]> Date: Sat Jul 15 21:26:29 2017 +0930 pdftocairo: add -jpegopt for setting jpeg compression parameters Bug 45727 diff --git a/goo/JpegWriter.cc b/goo/JpegWriter.cc index 9b7c5051..a9959f09 100644 --- a/goo/JpegWriter.cc +++ b/goo/JpegWriter.cc @@ -64,6 +64,16 @@ JpegWriter::~JpegWriter() delete priv; } +void JpegWriter::setQuality(int quality) +{ + priv->quality = quality; +} + +void JpegWriter::setProgressive(bool progressive) +{ + priv->progressive = progressive; +} + bool JpegWriter::init(FILE *f, int width, int height, int hDPI, int vDPI) { // Setup error handler diff --git a/goo/JpegWriter.h b/goo/JpegWriter.h index 7d0cf58e..aa3fb622 100644 --- a/goo/JpegWriter.h +++ b/goo/JpegWriter.h @@ -39,6 +39,8 @@ public: JpegWriter(Format format = RGB); ~JpegWriter(); + void setQuality(int quality); + void setProgressive(bool progressive); bool init(FILE *f, int width, int height, int hDPI, int vDPI) override; bool writePointers(unsigned char **rowPointers, int rowCount) override; diff --git a/utils/pdftocairo.1 b/utils/pdftocairo.1 index 997093c1..3a60b73e 100644 --- a/utils/pdftocairo.1 +++ b/utils/pdftocairo.1 @@ -75,7 +75,7 @@ at the top left (SVG) or bottom left (PDF, PS, EPS). Generates a PNG file(s) .TP .BI \-jpeg -Generates a JPEG file(s) +Generates a JPEG file(s). See also \-jpegopt. .TP .BI \-tiff Generates a TIFF file(s) @@ -199,6 +199,11 @@ Use a transparent page color instead of white (PNG and TIFF only). .BI \-icc " icc-file" Use the specified ICC file as the output profile (PNG only). The profile will be embedded in the PNG 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 \-level2 Generate Level 2 PostScript (PS only). .TP @@ -295,6 +300,16 @@ Error related to ICC profile. .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 "<opt>=<val>[,<opt>=<val>]". 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 WINDOWS PRINTER OPTIONS In Windows, you can use the \-print option to print directly to a system printer. Additionally, you can use the \-printopt option to configure the printer. It takes a string of the form "<opt>=<val>[,<opt>=<val>]". Currently the available options are: diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc index 91b77a55..9aacfb8d 100644 --- a/utils/pdftocairo.cc +++ b/utils/pdftocairo.cc @@ -128,6 +128,10 @@ static GBool quiet = gFalse; static GBool printVersion = gFalse; static GBool printHelp = gFalse; +static GooString jpegOpt; +static int jpegQuality = -1; +static bool jpegProgressive = false; + static GooString printer; static GooString printOpt; #ifdef CAIRO_HAS_WIN32_SURFACE @@ -142,6 +146,8 @@ static const ArgDesc argDesc[] = { #if ENABLE_LIBJPEG {"-jpeg", argFlag, &jpeg, 0, "generate a JPEG file"}, + {"-jpegopt", argGooString, &jpegOpt, 0, + "jpeg options, with format <opt1>=<val1>[,<optN>=<valN>]*"}, #endif #if ENABLE_LIBTIFF {"-tiff", argFlag, &tiff, 0, @@ -321,6 +327,58 @@ static GBool parseAntialiasOption(GooString *antialias, cairo_antialias_t *antia return gFalse; } +static GBool parseJpegOptions() +{ + //jpegOpt format is: <opt1>=<val1>,<opt2>=<val2>,... + 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 "<optN>=<valN> " + 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 "<optN>" and value is "<valN>" + + 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 writePageImage(GooString *filename) { ImgWriter *writer = 0; @@ -365,6 +423,10 @@ static void writePageImage(GooString *filename) writer = new JpegWriter(JpegWriter::GRAY); else writer = new JpegWriter(JpegWriter::RGB); + + static_cast<JpegWriter*>(writer)->setProgressive(jpegProgressive); + if (jpegQuality >= 0) + static_cast<JpegWriter*>(writer)->setQuality(jpegQuality); #endif } else if (tiff) { #if ENABLE_LIBTIFF @@ -979,6 +1041,15 @@ int main(int argc, char *argv[]) { exit(99); } + if (jpegOpt.getLength() > 0) { + if (!jpeg) { + fprintf(stderr, "Error: -jpegopt may only be used with jpeg output.\n"); + exit(99); + } + if (!parseJpegOptions()) + exit(99); + } + if (strlen(tiffCompressionStr) > 0 && !tiff) { fprintf(stderr, "Error: -tiffcompression may only be used with tiff output.\n"); exit(99); _______________________________________________ poppler mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/poppler
