[poppler] 2 commits - goo/JpegWriter.cc goo/JpegWriter.h splash/SplashBitmap.cc splash/SplashBitmap.h utils/pdftocairo.1 utils/pdftocairo.cc utils/pdftoppm.1 utils/pdftoppm.cc

Adrian Johnson ajohnson at kemper.freedesktop.org
Wed Aug 16 21:32:00 UTC 2017


 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 <ajohnson at redneon.com>
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, &params);
     } else if (jpegcmyk) {
-      bitmap->writeImgFile(splashFormatJpegCMYK, ppmFile, x_resolution, y_resolution);
+      bitmap->writeImgFile(splashFormatJpegCMYK, ppmFile, x_resolution, y_resolution, &params);
     } else if (tiff) {
-      bitmap->writeImgFile(splashFormatTiff, ppmFile, x_resolution, y_resolution, TiffCompressionStr);
+      bitmap->writeImgFile(splashFormatTiff, ppmFile, x_resolution, y_resolution, &params);
     } 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, &params);
     } else if (tiff) {
-      bitmap->writeImgFile(splashFormatTiff, stdout, x_resolution, y_resolution, TiffCompressionStr);
+      bitmap->writeImgFile(splashFormatTiff, stdout, x_resolution, y_resolution, &params);
     } 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 <ajohnson at redneon.com>
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);


More information about the poppler mailing list