[poppler] 3 commits - CMakeLists.txt config.h.cmake configure.ac poppler/FlateStream.cc poppler/Gfx.cc poppler/Makefile.am poppler/poppler-config.h.in poppler/PSOutputDev.cc poppler/PSOutputDev.h poppler/Stream.cc poppler/Stream.h

Adrian Johnson ajohnson at kemper.freedesktop.org
Thu Feb 25 10:57:44 UTC 2016


 CMakeLists.txt              |   21 +++-
 config.h.cmake              |    5 
 configure.ac                |   97 +++++++++++-------
 poppler/FlateStream.cc      |   14 ++
 poppler/Gfx.cc              |   21 +++-
 poppler/Makefile.am         |   13 ++
 poppler/PSOutputDev.cc      |  226 ++++++++++++++++++++++++++++++++------------
 poppler/PSOutputDev.h       |   13 ++
 poppler/Stream.cc           |  149 ++++++++++++++++++++++++++++-
 poppler/Stream.h            |   40 +++++++
 poppler/poppler-config.h.in |    6 -
 11 files changed, 491 insertions(+), 114 deletions(-)

New commits:
commit 989ceb6bd90cc8a79dd48c58183f1855de269c9b
Author: William Bader <william at newspapersystems.com>
Date:   Thu Feb 25 21:01:16 2016 +1030

    Add support for Flate compression in Level 3 PostScript output.
    
    The changes to the build variables are from Adrian Johnson's DeflateStream
    patches at https://bugs.freedesktop.org/attachment.cgi?id=89776

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d30fa4b..d5474f6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,7 +38,8 @@ option(ENABLE_CPP "Compile poppler cpp wrapper." ON)
 set(ENABLE_LIBOPENJPEG "auto" CACHE STRING "Use libopenjpeg for JPX streams. Possible values: auto, openjpeg1, openjpeg2. 'auto' prefers openjpeg1 over openjpeg2 if both are available. Unset to not use openjpeg.")
 set(ENABLE_CMS "auto" CACHE STRING "Use color management system. Possible values: auto, lcms1, lcms2. 'auto' prefers lcms2 over lcms1 if both are available. Unset to disable color management system.")
 option(ENABLE_LIBCURL "Build libcurl based HTTP support." OFF)
-option(ENABLE_ZLIB "Build with zlib (not totally safe)." OFF)
+option(ENABLE_ZLIB "Build with zlib." ON)
+option(ENABLE_ZLIB_UNCOMPRESS "Use zlib to uncompress flate streams (not totally safe)." OFF)
 option(SPLASH_CMYK "Include support for CMYK rasterization." OFF)
 option(USE_FIXEDPOINT "Use fixed point arithmetic in the Splash backend" OFF)
 option(USE_FLOAT "Use single precision arithmetic in the Splash backend" OFF)
@@ -158,6 +159,10 @@ if(ENABLE_ZLIB)
   endif(ZLIB_FOUND)
   set(ENABLE_ZLIB ${ZLIB_FOUND})
 endif(ENABLE_ZLIB)
+if(ENABLE_ZLIB_UNCOMPRESS AND NOT ENABLE_ZLIB)
+  message("Warning: ENABLE_ZLIB_UNCOMPRESS requires ENABLE_ZLIB")
+  set(ENABLE_ZLIB_UNCOMPRESS FALSE)
+endif(ENABLE_ZLIB_UNCOMPRESS AND NOT ENABLE_ZLIB)
 set(USE_OPENJPEG1 FALSE)
 set(USE_OPENJPEG2 FALSE)
 set(WITH_OPENJPEG FALSE)
@@ -420,10 +425,15 @@ if(JPEG_FOUND)
 endif(JPEG_FOUND)
 if(ENABLE_ZLIB)
   set(poppler_SRCS ${poppler_SRCS}
-    poppler/FlateStream.cc
+    poppler/FlateEncoder.cc
   )
   set(poppler_LIBS ${poppler_LIBS} ${ZLIB_LIBRARIES})
 endif(ENABLE_ZLIB)
+if(ENABLE_ZLIB_UNCOMPRESS)
+  set(poppler_SRCS ${poppler_SRCS}
+    poppler/FlateStream.cc
+  )
+endif(ENABLE_ZLIB_UNCOMPRESS)
 if(ENABLE_LIBCURL)
   set(poppler_SRCS ${poppler_SRCS}
     poppler/CurlCachedFile.cc
@@ -716,7 +726,8 @@ show_end_message("use gtk-doc" "not supported with this CMake build system")
 show_end_message_yesno("use libjpeg" ENABLE_LIBJPEG)
 show_end_message_yesno("use libpng" ENABLE_LIBPNG)
 show_end_message_yesno("use libtiff" ENABLE_LIBTIFF)
-show_end_message_yesno("use zlib" ENABLE_ZLIB)
+show_end_message_yesno("use zlib compress" ENABLE_ZLIB)
+show_end_message_yesno("use zlib uncompress" ENABLE_ZLIB_UNCOMPRESS)
 show_end_message_yesno("use curl" ENABLE_LIBCURL)
 show_end_message_yesno("use libopenjpeg" WITH_OPENJPEG)
 if(USE_OPENJPEG1)
@@ -747,9 +758,9 @@ if(NOT ENABLE_LIBJPEG)
   message("Warning: Using libjpeg is recommended. The internal DCT decoder is unmaintained.")
 endif(NOT ENABLE_LIBJPEG)
 
-if(ENABLE_ZLIB)
+if(ENABLE_ZLIB_UNCOMPRESS)
   message("Warning: Using zlib is not totally safe")
-endif(ENABLE_ZLIB)
+endif(ENABLE_ZLIB_UNCOMPRESS)
 
 if(NOT WITH_OPENJPEG)
   message("Warning: Using libopenjpeg is recommended. The internal JPX decoder is unmaintained.")
diff --git a/config.h.cmake b/config.h.cmake
index 440a13d..60c5120 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -18,9 +18,12 @@
 /* Do not hardcode the library location */
 #cmakedefine ENABLE_RELOCATABLE 1
 
-/* Use zlib instead of builtin zlib decoder. */
+/* Build against zlib. */
 #cmakedefine ENABLE_ZLIB 1
 
+/* Use zlib instead of builtin zlib decoder to uncompress flate streams. */
+#cmakedefine ENABLE_ZLIB_UNCOMPRESS 1
+
 /* Use cairo for rendering. */
 #cmakedefine HAVE_CAIRO 1
 
diff --git a/configure.ac b/configure.ac
index 45575be..879901d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -344,31 +344,53 @@ fi
 AC_CHECK_FUNCS(pread64 lseek64)
 
 dnl Test for zlib
-AC_ARG_ENABLE([zlib],
-  [AS_HELP_STRING([--enable-zlib],[Build with zlib])],
-  [],[enable_zlib="no"])
+AC_ARG_ENABLE(zlib,
+	      AC_HELP_STRING([--disable-zlib],
+			     [Don't build against zlib.]),
+	      enable_zlib=$enableval,
+	      enable_zlib="try")
+
+AC_ARG_ENABLE([zlib_uncompress],
+	      AS_HELP_STRING([--enable-zlib-uncompress],
+			     [Use zlib to uncompress flate streams (not totally safe)]),
+              enable_zlib_uncompress=$enableval,
+              enable_zlib_uncompress="no")
+
 if test x$enable_zlib = xyes; then
-  AC_CHECK_LIB([z], [inflate],,
-	       AC_MSG_ERROR("*** zlib library not found ***"))
-  AC_CHECK_HEADERS([zlib.h],,
-		   AC_MSG_ERROR("*** zlib headers not found ***"))
+   AC_CHECK_LIB([z], [inflate],,
+        AC_MSG_ERROR("*** zlib library not found ***"))
+   AC_CHECK_HEADERS([zlib.h],,
+	AC_MSG_ERROR("*** zlib headers not found ***"))
 elif test x$enable_zlib = xtry; then
-  AC_CHECK_LIB([z], [inflate],
-               [enable_zlib="yes"],
-	       [enable_zlib="no"])
-  AC_CHECK_HEADERS([zlib.h],,
-		   [enable_zlib="no"])
+   AC_CHECK_LIB([z], [inflate],
+	        [enable_zlib="yes"],
+		[enable_zlib="no"])
+   AC_CHECK_HEADERS([zlib.h],,
+		[enable_zlib="no"])
 fi
 
 if test x$enable_zlib = xyes; then
-  ZLIB_LIBS="-lz"
-  AC_SUBST(ZLIB_LIBS)
-  AC_DEFINE(ENABLE_ZLIB)
+    ZLIB_LIBS="-lz"
+    AC_SUBST(ZLIB_LIBS)
+    AC_DEFINE(ENABLE_ZLIB, 1, [Build against zlib.])
+
+    if test x$enable_zlib_uncompress = xyes; then
+        AC_DEFINE(ENABLE_ZLIB_UNCOMPRESS, 1,
+             [Use zlib instead of builtin zlib decoder to uncompress flate streams.])
+    fi
+else
+    if test x$enable_zlib_uncompress = xyes; then
+	echo "  Warning: --enable-zlib-uncompress is incompatible with --disable-zlib."
+    fi
+    enable_zlib_uncompress="no"
 fi
 
 AM_CONDITIONAL(BUILD_ZLIB, test x$enable_zlib = xyes)
 AH_TEMPLATE([ENABLE_ZLIB],
-	    [Use zlib instead of builtin zlib decoder.])
+	    [Build against zlib.])
+AM_CONDITIONAL(BUILD_ZLIB_UNCOMPRESS, test x$enable_zlib_uncompress = xyes)
+AH_TEMPLATE([ENABLE_ZLIB_UNCOMPRESS],
+	    [Use zlib instead of builtin zlib decoder to uncompress flate streams.])
 
 dnl Test for libcurl
 AC_ARG_ENABLE(libcurl,
@@ -989,24 +1011,25 @@ poppler-cpp-uninstalled.pc])
 
 echo ""
 echo "Building poppler with support for:"
-echo "  font configuration: $with_font_configuration"
-echo "  splash output:      $enable_splash_output"
+echo "  font configuration:  $with_font_configuration"
+echo "  splash output:       $enable_splash_output"
 if test x$enable_cmyk = xyes;then
         echo "      with CMYK support"
 fi
-echo "  cairo output:       $use_cairo"
-echo "  qt4 wrapper:        $enable_poppler_qt4"
-echo "  qt5 wrapper:        $enable_poppler_qt5"
-echo "  glib wrapper:       $use_glib"
-echo "    introspection:    $found_introspection"
-echo "  cpp wrapper:        $enable_poppler_cpp"
-echo "  use gtk-doc:        $enable_gtk_doc"
-echo "  use libjpeg:        $enable_libjpeg"
-echo "  use libpng:         $enable_libpng"
-echo "  use libtiff:        $enable_libtiff"
-echo "  use zlib:           $enable_zlib"
-echo "  use libcurl:        $enable_libcurl"
-echo "  use libopenjpeg:    $enable_libopenjpeg"
+echo "  cairo output:        $use_cairo"
+echo "  qt4 wrapper:         $enable_poppler_qt4"
+echo "  qt5 wrapper:         $enable_poppler_qt5"
+echo "  glib wrapper:        $use_glib"
+echo "    introspection:     $found_introspection"
+echo "  cpp wrapper:         $enable_poppler_cpp"
+echo "  use gtk-doc:         $enable_gtk_doc"
+echo "  use libjpeg:         $enable_libjpeg"
+echo "  use libpng:          $enable_libpng"
+echo "  use libtiff:         $enable_libtiff"
+echo "  use zlib compress:   $enable_zlib"
+echo "  use zlib uncompress: $enable_zlib_uncompress"
+echo "  use libcurl:         $enable_libcurl"
+echo "  use libopenjpeg:     $enable_libopenjpeg"
 if test x$enable_libopenjpeg = xyes;then
     if test x$openjpeg1 = xyes;then
         echo "      with openjpeg1"
@@ -1014,7 +1037,7 @@ if test x$enable_libopenjpeg = xyes;then
         echo "      with openjpeg2"
     fi
 fi
-echo "  use cms:            $enable_cms"
+echo "  use cms:             $enable_cms"
 if test x$enable_cms = xyes;then
     if test x$lcms1 = xyes;then
         echo "      with lcms1"
@@ -1023,10 +1046,10 @@ if test x$enable_cms = xyes;then
     fi
 fi
 if test x$enable_build_type != xno;then
-        echo "  build type:         $enable_build_type"
+        echo "  build type:          $enable_build_type"
 fi
-echo "  command line utils: $enable_utils"
-echo "  test data dir:      $TESTDATADIR"
+echo "  command line utils:  $enable_utils"
+echo "  test data dir:       $TESTDATADIR"
 echo ""
 
 if test x$enable_splash_output = xno -a x$enable_cairo_output = xno; then
@@ -1041,8 +1064,8 @@ if test x$enable_libjpeg != xyes; then
 	echo "  Warning: Using libjpeg is recommended. The internal DCT decoder is unmaintained."
 fi
 
-if test x$enable_zlib != xno; then
-	echo "  Warning: Using zlib is not totally safe"
+if test x$enable_zlib_uncompress != xno; then
+	echo "  Warning: Using zlib for decompression is not totally safe"
 fi
 
 if test x$enable_libopenjpeg != xyes; then
diff --git a/poppler/FlateStream.cc b/poppler/FlateStream.cc
index 7990dad..ca63837 100644
--- a/poppler/FlateStream.cc
+++ b/poppler/FlateStream.cc
@@ -8,7 +8,19 @@
 // This file is under the GPLv2 or later license
 //
 //========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "poppler-config.h"
+
+#if ENABLE_ZLIB_UNCOMPRESS
+
 #include "FlateStream.h"
+
 FlateStream::FlateStream(Stream *strA, int predictor, int columns, int colors, int bits) :
   FilterStream(strA)
 {
@@ -126,3 +138,5 @@ GooString *FlateStream::getPSFilter(int psLevel, const char *indent) {
 GBool FlateStream::isBinary(GBool last) {
   return str->isBinary(gTrue);
 }
+
+#endif
diff --git a/poppler/Makefile.am b/poppler/Makefile.am
index 79b6000..90340b8 100644
--- a/poppler/Makefile.am
+++ b/poppler/Makefile.am
@@ -82,14 +82,22 @@ endif
 if BUILD_ZLIB
 
 zlib_sources =					\
-	FlateStream.h				\
-	FlateStream.cc
+	FlateEncoder.h				\
+	FlateEncoder.cc
 
 zlib_libs = 					\
 	$(ZLIB_LIBS)
 
 endif
 
+if BUILD_ZLIB_UNCOMPRESS
+
+zlib_uncompress_sources =			\
+	FlateStream.h				\
+	FlateStream.cc
+
+endif
+
 if BUILD_LIBCURL
 
 libcurl_libs =					\
@@ -200,6 +208,7 @@ libpoppler_la_SOURCES =		\
 	$(splash_sources)	\
 	$(libjpeg_sources)	\
 	$(zlib_sources)		\
+	$(zlib_uncompress_sources) \
 	$(libjpeg2000_sources)	\
 	$(curl_sources)		\
 	Annot.cc		\
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index e565e33..4dc3ddd 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -23,7 +23,7 @@
 // Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2009 Till Kamppeter <till.kamppeter at gmail.com>
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
-// Copyright (C) 2009, 2011, 2012, 2014, 2015 William Bader <williambader at hotmail.com>
+// Copyright (C) 2009, 2011, 2012, 2014-2016 William Bader <williambader at hotmail.com>
 // Copyright (C) 2009 Kovid Goyal <kovid at kovidgoyal.net>
 // Copyright (C) 2009-2011, 2013-2015 Adrian Johnson <ajohnson at redneon.com>
 // Copyright (C) 2012, 2014 Fabio D'Urso <fabiodurso at hotmail.it>
@@ -65,6 +65,12 @@
 #include "Catalog.h"
 #include "Page.h"
 #include "Stream.h"
+#if ENABLE_ZLIB
+#  include "FlateEncoder.h"
+#endif
+#if ENABLE_ZLIB_UNCOMPRESS
+#  include "FlateStream.h"
+#endif
 #include "Annot.h"
 #include "XRef.h"
 #include "PreScanOutputDev.h"
@@ -1244,6 +1250,7 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
   useASCIIHex = gFalse;
   useBinary = gFalse;
   enableLZW = gTrue;
+  enableFlate = gTrue;
   rasterMono = gFalse;
   rasterResolution = 300;
   uncompressPreloadedImages = gFalse;
@@ -2954,7 +2961,7 @@ void PSOutputDev::setupImages(Dict *resDict) {
 }
 
 void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
-  GBool useLZW, useRLE, useCompressed, doUseASCIIHex;
+  GBool useFlate, useLZW, useRLE, useCompressed, doUseASCIIHex;
   GooString *s;
   int c;
   int size, line, col, i;
@@ -2963,29 +2970,29 @@ void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
   // filters
   //~ this does not correctly handle the DeviceN color space
   //~   -- need to use DeviceNRecoder
+
+  useFlate = useLZW = useRLE = gFalse;
+  useCompressed = gFalse;
+  doUseASCIIHex = gFalse;
+
   if (level < psLevel2) {
-    useLZW = useRLE = gFalse;
-    useCompressed = gFalse;
     doUseASCIIHex = gTrue;
   } else {
     if (uncompressPreloadedImages) {
-      useLZW = useRLE = gFalse;
-      useCompressed = gFalse;
+      /* nothing to do */;
     } else {
       s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
       if (s) {
-	useLZW = useRLE = gFalse;
 	useCompressed = gTrue;
 	delete s;
       } else {
-	if (getEnableLZW()) {
+	if (level >= psLevel3 && getEnableFlate()) {
+	  useFlate = gTrue;
+	} else if (getEnableLZW()) {
 	  useLZW = gTrue;
-	  useRLE = gFalse;
 	} else {
 	  useRLE = gTrue;
-	  useLZW = gFalse;
 	}
-	useCompressed = gFalse;
       }
     }
     doUseASCIIHex = useASCIIHex;
@@ -2993,6 +3000,11 @@ void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
   if (useCompressed) {
     str = str->getUndecodedStream();
   }
+#if ENABLE_ZLIB
+  if (useFlate) {
+    str = new FlateEncoder(str);
+  } else
+#endif
   if (useLZW) {
     str = new LZWEncoder(str);
   } else if (useRLE) {
@@ -3240,7 +3252,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
   PreScanOutputDev *scan;
   GBool rasterize;
 #if HAVE_SPLASH
-  GBool useLZW;
+  GBool useFlate, useLZW;
   SplashOutputDev *splashOut;
   SplashColor paperColor;
   PDFRectangle box;
@@ -3280,6 +3292,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
 
 #if HAVE_SPLASH
   // get the rasterization parameters
+  useFlate = getEnableFlate() && level >= psLevel3;
   useLZW = getEnableLZW();
   // start the PS page
   page->makeBox(rasterResolution, rasterResolution, rotateA, useMediaBox, gFalse,
@@ -3591,6 +3604,19 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
         isGray = gFalse;
       }
       str0->reset();
+#if ENABLE_ZLIB
+      if (useFlate) {
+        if (isGray && numComps == 4) {
+	  str = new FlateEncoder(new CMYKGrayEncoder(str0));
+	  numComps = 1;
+        } else if (isGray && numComps == 3) {
+	  str = new FlateEncoder(new RGBGrayEncoder(str0));
+	  numComps = 1;
+        } else {
+	  str = new FlateEncoder(str0);
+        }
+      } else
+#endif
       if (useLZW) {
         if (isGray && numComps == 4) {
 	  str = new LZWEncoder(new CMYKGrayEncoder(str0));
@@ -3639,7 +3665,9 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
       } else {
 	writePS("    /ASCII85Decode filter\n");
       }
-      if (useLZW) {
+      if (useFlate) {
+	writePS("    /FlateDecode filter\n");
+      } else if (useLZW) {
 	writePS("    /LZWDecode filter\n");
       } else {
 	writePS("    /RunLengthDecode filter\n");
@@ -6150,8 +6178,8 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   Stream *str2;
   GooString *s;
   int n, numComps;
-  GBool useLZW, useRLE, useASCII, useCompressed;
-  GBool maskUseLZW, maskUseRLE, maskUseASCII, maskUseCompressed;
+  GBool useFlate, useLZW, useRLE, useASCII, useCompressed;
+  GBool maskUseFlate, maskUseLZW, maskUseRLE, maskUseASCII, maskUseCompressed;
   GooString *maskFilters;
   GfxSeparationColorSpace *sepCS;
   GfxColor color;
@@ -6159,8 +6187,8 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   int c;
   int col, i;
 
-  useLZW = useRLE = useASCII = useCompressed = gFalse; // make gcc happy
-  maskUseLZW = maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
+  useFlate = useLZW = useRLE = useASCII = useCompressed = gFalse;
+  maskUseFlate = maskUseLZW = maskUseRLE = maskUseASCII = maskUseCompressed = gFalse;
   maskFilters = NULL; // make gcc happy
 
   // explicit masking
@@ -6170,23 +6198,18 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
     if ((mode == psModeForm || inType3Char || preloadImagesForms) &&
       uncompressPreloadedImages) {
       s = NULL;
-      maskUseLZW = maskUseRLE = gFalse;
-      maskUseCompressed = gFalse;
-      maskUseASCII = gFalse;
     } else {
       s = maskStr->getPSFilter(3, "  ");
       if (!s) {
-	if (getEnableLZW()) {
+	if (getEnableFlate()) {
+	  maskUseFlate = gTrue;
+	} else if (getEnableLZW()) {
 	  maskUseLZW = gTrue;
-	  maskUseRLE = gFalse;
 	} else {
 	  maskUseRLE = gTrue;
-	  maskUseLZW = gFalse;
 	}
 	maskUseASCII = !(mode == psModeForm || inType3Char || preloadImagesForms);
-	maskUseCompressed = gFalse;
       } else {
-	maskUseLZW = maskUseRLE = gFalse;
 	maskUseASCII = maskStr->isBinary() &&
 	               !(mode == psModeForm || inType3Char || preloadImagesForms);
 	maskUseCompressed = gTrue;
@@ -6197,7 +6220,9 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
       maskFilters->appendf("  /ASCII{0:s}Decode filter\n",
 			   useASCIIHex ? "Hex" : "85");
     }
-    if (maskUseLZW) {
+    if (maskUseFlate) {
+      maskFilters->append("  /FlateDecode filter\n");
+    } else if (maskUseLZW) {
       maskFilters->append("  /LZWDecode filter\n");
     } else if (maskUseRLE) {
       maskFilters->append("  /RunLengthDecode filter\n");
@@ -6216,10 +6241,15 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
       writePS(maskFilters->getCString());
       writePS("pdfMask\n");
 
-      // add LZWEncode/RunLengthEncode and ASCIIHex/85 encode filters
+      // add FlateEncode/LZWEncode/RunLengthEncode and ASCIIHex/85 encode filters
       if (maskUseCompressed) {
 	maskStr = maskStr->getUndecodedStream();
       }
+#if ENABLE_ZLIB
+      if (maskUseFlate) {
+	maskStr = new FlateEncoder(maskStr);
+      } else
+#endif
       if (maskUseLZW) {
 	maskStr = new LZWEncoder(maskStr);
       } else if (maskUseRLE) {
@@ -6243,7 +6273,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
       writePS("%-EOD-\n");
       
       // delete encoders
-      if (maskUseLZW || maskUseRLE || maskUseASCII) {
+      if (maskUseFlate || maskUseLZW || maskUseRLE || maskUseASCII) {
 	delete maskStr;
       }
     }
@@ -6260,6 +6290,11 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
     if (inlineImg) {
       // create an array
       str2 = new FixedLengthEncoder(str, len);
+#if ENABLE_ZLIB
+      if (getEnableFlate()) {
+	str2 = new FlateEncoder(str2);
+      } else
+#endif
       if (getEnableLZW()) {
 	str2 = new LZWEncoder(str2);
       } else {
@@ -6307,7 +6342,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
 	}
       } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
       writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
-      // add an extra entry because the LZWDecode/RunLengthDecode filter may
+      // add an extra entry because the FlateEncode/LZWDecode/RunLengthDecode filter may
       // read past the end
       writePS("<>]\n");
       writePS("0\n");
@@ -6390,28 +6425,28 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   }
 
   // filters
+
+  useFlate = useLZW = useRLE = gFalse;
+  useCompressed = gFalse;
+  useASCII = gFalse;
+
   if ((mode == psModeForm || inType3Char || preloadImagesForms) &&
       uncompressPreloadedImages) {
     s = NULL;
-    useLZW = useRLE = gFalse;
-    useCompressed = gFalse;
-    useASCII = gFalse;
   } else {
     s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
 			 "    ");
     if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
 	inlineImg || !s) {
-      if (getEnableLZW()) {
+      if (getEnableFlate()) {
+	useFlate = gTrue;
+      } else if (getEnableLZW()) {
 	useLZW = gTrue;
-	useRLE = gFalse;
       } else {
 	useRLE = gTrue;
-	useLZW = gFalse;
       }
       useASCII = !(mode == psModeForm || inType3Char || preloadImagesForms);
-      useCompressed = gFalse;
     } else {
-      useLZW = useRLE = gFalse;
       useASCII = str->isBinary() &&
                  !(mode == psModeForm || inType3Char || preloadImagesForms);
       useCompressed = gTrue;
@@ -6421,7 +6456,9 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
     writePSFmt("    /ASCII{0:s}Decode filter\n",
 	       useASCIIHex ? "Hex" : "85");
   }
-  if (useLZW) {
+  if (useFlate) {
+    writePS("    /FlateDecode filter\n");
+  } else if (useLZW) {
     writePS("    /LZWDecode filter\n");
   } else if (useRLE) {
     writePS("    /RunLengthDecode filter\n");
@@ -6499,7 +6536,12 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
       str = str->getUndecodedStream();
     }
 
-    // add LZWEncode/RunLengthEncode and ASCIIHex/85 encode filters
+    // add FlateEncode/LZWEncode/RunLengthEncode and ASCIIHex/85 encode filters
+#if ENABLE_ZLIB
+    if (useFlate) {
+      str = new FlateEncoder(str);
+    } else
+#endif
     if (useLZW) {
       str = new LZWEncoder(str);
     } else if (useRLE) {
@@ -6525,7 +6567,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
     writePS("%-EOD-\n");
 
     // delete encoders
-    if (useLZW || useRLE || useASCII || inlineImg) {
+    if (useFlate || useLZW || useRLE || useASCII || inlineImg) {
       delete str;
     }
   }
diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h
index bd5b075..3aea223 100644
--- a/poppler/PSOutputDev.h
+++ b/poppler/PSOutputDev.h
@@ -20,7 +20,7 @@
 // Copyright (C) 2009-2013 Thomas Freitag <Thomas.Freitag at alfa.de>
 // Copyright (C) 2009 Till Kamppeter <till.kamppeter at gmail.com>
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
-// Copyright (C) 2009, 2011, 2015 William Bader <williambader at hotmail.com>
+// Copyright (C) 2009, 2011, 2015-2016 William Bader <williambader at hotmail.com>
 // Copyright (C) 2010 Hib Eris <hib at hiberis.nl>
 // Copyright (C) 2011, 2014 Adrian Johnson <ajohnson at redneon.com>
 // Copyright (C) 2012 Fabio D'Urso <fabiodurso at hotmail.it>
@@ -321,6 +321,12 @@ public:
   GBool getFontPassthrough() const { return fontPassthrough; }
   GBool getOptimizeColorSpace() const { return optimizeColorSpace; }
   GBool getEnableLZW() const { return enableLZW; };
+  GBool getEnableFlate() const
+#if ENABLE_ZLIB
+    { return enableFlate; }
+#else
+    { return gFalse; }
+#endif
   void setEmbedType1(GBool b) { embedType1 = b; }
   void setEmbedTrueType(GBool b) { embedTrueType = b; }
   void setEmbedCIDPostScript(GBool b) { embedCIDPostScript = b; }
@@ -332,6 +338,7 @@ public:
   void setUseASCIIHex(GBool b) { useASCIIHex = b; }
   void setUseBinary(GBool b) { useBinary = b; }
   void setEnableLZW(GBool b) { enableLZW = b; }
+  void setEnableFlate(GBool b) { enableFlate = b; }
 
 private:
 
@@ -535,6 +542,7 @@ private:
   GBool useASCIIHex;		// use ASCIIHex instead of ASCII85?
   GBool useBinary;		// use binary instead of hex
   GBool enableLZW;		// enable LZW compression
+  GBool enableFlate;		// enable Flate compression
 
 #if OPI_SUPPORT
   int opi13Nest;		// nesting level of OPI 1.3 objects
diff --git a/poppler/Stream.cc b/poppler/Stream.cc
index f2ca60b..bbea4fd 100644
--- a/poppler/Stream.cc
+++ b/poppler/Stream.cc
@@ -70,7 +70,7 @@
 #include "DCTStream.h"
 #endif
 
-#ifdef ENABLE_ZLIB
+#ifdef ENABLE_ZLIB_UNCOMPRESS
 #include "FlateStream.h"
 #endif
 
@@ -3865,7 +3865,7 @@ GBool DCTStream::isBinary(GBool last) {
 
 #endif
 
-#ifndef ENABLE_ZLIB
+#ifndef ENABLE_ZLIB_UNCOMPRESS
 //------------------------------------------------------------------------
 // FlateStream
 //------------------------------------------------------------------------
diff --git a/poppler/Stream.h b/poppler/Stream.h
index 84a8cf9..ed6f7dc 100644
--- a/poppler/Stream.h
+++ b/poppler/Stream.h
@@ -942,7 +942,7 @@ private:
 
 #endif
 
-#ifndef ENABLE_ZLIB
+#ifndef ENABLE_ZLIB_UNCOMPRESS
 //------------------------------------------------------------------------
 // FlateStream
 //------------------------------------------------------------------------
diff --git a/poppler/poppler-config.h.in b/poppler/poppler-config.h.in
index cb77eb7..79d452f 100644
--- a/poppler/poppler-config.h.in
+++ b/poppler/poppler-config.h.in
@@ -81,9 +81,9 @@
 #undef ENABLE_LIBPNG
 #endif
 
-/* Use zlib instead of builtin zlib decoder. */
-#ifndef ENABLE_ZLIB
-#undef ENABLE_ZLIB
+/* Use zlib instead of builtin zlib decoder for uncompressing flate streams. */
+#ifndef ENABLE_ZLIB_UNCOMPRESS
+#undef ENABLE_ZLIB_UNCOMPRESS
 #endif
 
 /* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
commit 91c0be60f3e7a53373ba660702358cf52f74d1b2
Author: William Bader <william at newspapersystems.com>
Date:   Thu Feb 25 20:50:10 2016 +1030

    xpdf304: Merge xpdf-3.04 support for LZW encoding in PSOutputDev and Stream.
    
    Level 2 and Level 3 PostScript now use LZW encoding instead of Run
    Length encoding, which can make some images one tenth the size.
    PSOutputDev provides setEnableLZW() and getEnableLZW() to control
    support for LZW encoding.

diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index 2d01edb..e565e33 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -1243,6 +1243,7 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
   generateOPI = gFalse;
   useASCIIHex = gFalse;
   useBinary = gFalse;
+  enableLZW = gTrue;
   rasterMono = gFalse;
   rasterResolution = 300;
   uncompressPreloadedImages = gFalse;
@@ -2953,7 +2954,7 @@ void PSOutputDev::setupImages(Dict *resDict) {
 }
 
 void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
-  GBool useRLE, useCompressed, doUseASCIIHex;
+  GBool useLZW, useRLE, useCompressed, doUseASCIIHex;
   GooString *s;
   int c;
   int size, line, col, i;
@@ -2963,21 +2964,27 @@ void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
   //~ this does not correctly handle the DeviceN color space
   //~   -- need to use DeviceNRecoder
   if (level < psLevel2) {
-    useRLE = gFalse;
+    useLZW = useRLE = gFalse;
     useCompressed = gFalse;
     doUseASCIIHex = gTrue;
   } else {
     if (uncompressPreloadedImages) {
-      useRLE = gFalse;
+      useLZW = useRLE = gFalse;
       useCompressed = gFalse;
     } else {
       s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
       if (s) {
-	useRLE = gFalse;
+	useLZW = useRLE = gFalse;
 	useCompressed = gTrue;
 	delete s;
       } else {
-	useRLE = gTrue;
+	if (getEnableLZW()) {
+	  useLZW = gTrue;
+	  useRLE = gFalse;
+	} else {
+	  useRLE = gTrue;
+	  useLZW = gFalse;
+	}
 	useCompressed = gFalse;
       }
     }
@@ -2986,7 +2993,9 @@ void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
   if (useCompressed) {
     str = str->getUndecodedStream();
   }
-  if (useRLE) {
+  if (useLZW) {
+    str = new LZWEncoder(str);
+  } else if (useRLE) {
     str = new RunLengthEncoder(str);
   }
   if (doUseASCIIHex) {
@@ -3028,9 +3037,9 @@ void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
     }
   } while (c != (doUseASCIIHex ? '>' : '~') && c != EOF);
   // add one entry for the final line of data; add another entry
-  // because the RunLengthDecode filter may read past the end
+  // because the LZWDecode/RunLengthDecode filter may read past the end
   ++size;
-  if (useRLE) {
+  if (useLZW || useRLE) {
     ++size;
   }
   outerSize = size/65535 + 1;
@@ -3090,7 +3099,7 @@ void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
     }
     if (c == (doUseASCIIHex ? '>' : '~') || c == EOF) {
       writePS((char *)(doUseASCIIHex ? "> put\n" : "~> put\n"));
-      if (useRLE) {
+      if (useLZW || useRLE) {
 	++line;
 	writePSFmt("{0:d} <> put\n", line);
       } else {
@@ -3231,6 +3240,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
   PreScanOutputDev *scan;
   GBool rasterize;
 #if HAVE_SPLASH
+  GBool useLZW;
   SplashOutputDev *splashOut;
   SplashColor paperColor;
   PDFRectangle box;
@@ -3269,6 +3279,8 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
   }
 
 #if HAVE_SPLASH
+  // get the rasterization parameters
+  useLZW = getEnableLZW();
   // start the PS page
   page->makeBox(rasterResolution, rasterResolution, rotateA, useMediaBox, gFalse,
 		sliceX, sliceY, sliceW, sliceH, &box, &crop);
@@ -3579,14 +3591,26 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
         isGray = gFalse;
       }
       str0->reset();
-      if (isGray && numComps == 4) {
-	str = new RunLengthEncoder(new CMYKGrayEncoder(str0));
-	numComps = 1;
-      } else if (isGray && numComps == 3) {
-	str = new RunLengthEncoder(new RGBGrayEncoder(str0));
-	numComps = 1;
+      if (useLZW) {
+        if (isGray && numComps == 4) {
+	  str = new LZWEncoder(new CMYKGrayEncoder(str0));
+	  numComps = 1;
+        } else if (isGray && numComps == 3) {
+	  str = new LZWEncoder(new RGBGrayEncoder(str0));
+	  numComps = 1;
+        } else {
+	  str = new LZWEncoder(str0);
+        }
       } else {
-	str = new RunLengthEncoder(str0);
+        if (isGray && numComps == 4) {
+	  str = new RunLengthEncoder(new CMYKGrayEncoder(str0));
+	  numComps = 1;
+        } else if (isGray && numComps == 3) {
+	  str = new RunLengthEncoder(new RGBGrayEncoder(str0));
+	  numComps = 1;
+        } else {
+	  str = new RunLengthEncoder(str0);
+        }
       }
       if (numComps == 1) {
 	writePS("/DeviceGray setcolorspace\n");
@@ -3615,7 +3639,11 @@ GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
       } else {
 	writePS("    /ASCII85Decode filter\n");
       }
-      writePS("    /RunLengthDecode filter\n");
+      if (useLZW) {
+	writePS("    /LZWDecode filter\n");
+      } else {
+	writePS("    /RunLengthDecode filter\n");
+      }
       writePS(">>\n");
       if (useBinary) {
 	/* nothing to do */;
@@ -4349,7 +4377,7 @@ void PSOutputDev::restoreTextPos(GfxState *state) {
 void PSOutputDev::stroke(GfxState *state) {
   doPath(state->getPath());
   if (inType3Char && t3FillColorOnly) {
-    // if we're construct a cacheable Type 3 glyph, we need to do
+    // if we're constructing a cacheable Type 3 glyph, we need to do
     // everything in the fill color
     writePS("Sf\n");
   } else {
@@ -5651,7 +5679,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
   GBool emitRect, addRect, extendRect;
   GooString *s;
   int n, numComps;
-  GBool useRLE, useASCII, useCompressed;
+  GBool useLZW, useRLE, useASCII, useCompressed;
   GfxSeparationColorSpace *sepCS;
   GfxColor color;
   GfxCMYK cmyk;
@@ -5835,7 +5863,11 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
     if (inlineImg) {
       // create an array
       str2 = new FixedLengthEncoder(str, len);
-      str2 = new RunLengthEncoder(str2);
+      if (getEnableLZW()) {
+	str2 = new LZWEncoder(str2);
+      } else {
+	str2 = new RunLengthEncoder(str2);
+      }
       if (useASCIIHex) {
 	str2 = new ASCIIHexEncoder(str2);
       } else {
@@ -5878,7 +5910,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
 	}
       } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
       writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
-      // add an extra entry because the RunLengthDecode filter may
+      // add an extra entry because the LZWDecode/RunLengthDecode filter may
       // read past the end
       writePS("<>]\n");
       writePS("0\n");
@@ -5956,7 +5988,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
   if ((mode == psModeForm || inType3Char || preloadImagesForms) &&
       uncompressPreloadedImages) {
     s = NULL;
-    useRLE = gFalse;
+    useLZW = useRLE = gFalse;
     useCompressed = gFalse;
     useASCII = gFalse;
   } else {
@@ -5964,11 +5996,17 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
 			 "    ");
     if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
 	inlineImg || !s) {
-      useRLE = gTrue;
+      if (getEnableLZW()) {
+	useLZW = gTrue;
+	useRLE = gFalse;
+      } else {
+	useRLE = gTrue;
+	useLZW = gFalse;
+      }
       useASCII = !(mode == psModeForm || inType3Char || preloadImagesForms);
       useCompressed = gFalse;
     } else {
-      useRLE = gFalse;
+      useLZW = useRLE = gFalse;
       useASCII = str->isBinary() &&
 	         !(mode == psModeForm || inType3Char || preloadImagesForms);
       useCompressed = gTrue;
@@ -5978,7 +6016,9 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
     writePSFmt("    /ASCII{0:s}Decode filter\n",
 	       useASCIIHex ? "Hex" : "85");
   }
-  if (useRLE) {
+  if (useLZW) {
+    writePS("    /LZWDecode filter\n");
+  } else if (useRLE) {
     writePS("    /RunLengthDecode filter\n");
   }
   if (useCompressed) {
@@ -6011,8 +6051,10 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
       str = new DeviceNRecoder(str, width, height, colorMap);
     }
 
-    // add RunLengthEncode and ASCIIHex/85 encode filters
-    if (useRLE) {
+    // add LZWEncode/RunLengthEncode and ASCIIHex/85 encode filters
+    if (useLZW) {
+      str = new LZWEncoder(str);
+    } else if (useRLE) {
       str = new RunLengthEncoder(str);
     }
     if (useASCII) {
@@ -6033,7 +6075,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
 	n = 0;
       } else {
 	// need to read the stream to count characters -- the length
-	// is data-dependent (because of ASCII and RLE filters)
+	// is data-dependent (because of ASCII and LZW/RLE filters)
 	str->reset();
 	n = 0;
 	while ((c = str->getChar()) != EOF) {
@@ -6085,7 +6127,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
 #endif
 
     // delete encoders
-    if (useRLE || useASCII || inlineImg) {
+    if (useLZW || useRLE || useASCII || inlineImg) {
       delete str;
     }
   }
@@ -6108,8 +6150,8 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   Stream *str2;
   GooString *s;
   int n, numComps;
-  GBool useRLE, useASCII, useCompressed;
-  GBool maskUseRLE, maskUseASCII, maskUseCompressed;
+  GBool useLZW, useRLE, useASCII, useCompressed;
+  GBool maskUseLZW, maskUseRLE, maskUseASCII, maskUseCompressed;
   GooString *maskFilters;
   GfxSeparationColorSpace *sepCS;
   GfxColor color;
@@ -6117,8 +6159,8 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   int c;
   int col, i;
 
-  useRLE = useASCII = useCompressed = gFalse; // make gcc happy
-  maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
+  useLZW = useRLE = useASCII = useCompressed = gFalse; // make gcc happy
+  maskUseLZW = maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
   maskFilters = NULL; // make gcc happy
 
   // explicit masking
@@ -6128,17 +6170,23 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
     if ((mode == psModeForm || inType3Char || preloadImagesForms) &&
       uncompressPreloadedImages) {
       s = NULL;
-      maskUseRLE = gFalse;
+      maskUseLZW = maskUseRLE = gFalse;
       maskUseCompressed = gFalse;
       maskUseASCII = gFalse;
     } else {
       s = maskStr->getPSFilter(3, "  ");
       if (!s) {
-	maskUseRLE = gTrue;
+	if (getEnableLZW()) {
+	  maskUseLZW = gTrue;
+	  maskUseRLE = gFalse;
+	} else {
+	  maskUseRLE = gTrue;
+	  maskUseLZW = gFalse;
+	}
 	maskUseASCII = !(mode == psModeForm || inType3Char || preloadImagesForms);
 	maskUseCompressed = gFalse;
       } else {
-	maskUseRLE = gFalse;
+	maskUseLZW = maskUseRLE = gFalse;
 	maskUseASCII = maskStr->isBinary() &&
 	               !(mode == psModeForm || inType3Char || preloadImagesForms);
 	maskUseCompressed = gTrue;
@@ -6149,7 +6197,9 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
       maskFilters->appendf("  /ASCII{0:s}Decode filter\n",
 			   useASCIIHex ? "Hex" : "85");
     }
-    if (maskUseRLE) {
+    if (maskUseLZW) {
+      maskFilters->append("  /LZWDecode filter\n");
+    } else if (maskUseRLE) {
       maskFilters->append("  /RunLengthDecode filter\n");
     }
     if (maskUseCompressed) {
@@ -6166,11 +6216,13 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
       writePS(maskFilters->getCString());
       writePS("pdfMask\n");
 
-      // add RunLengthEncode and ASCIIHex/85 encode filters
+      // add LZWEncode/RunLengthEncode and ASCIIHex/85 encode filters
       if (maskUseCompressed) {
 	maskStr = maskStr->getUndecodedStream();
       }
-      if (maskUseRLE) {
+      if (maskUseLZW) {
+	maskStr = new LZWEncoder(maskStr);
+      } else if (maskUseRLE) {
 	maskStr = new RunLengthEncoder(maskStr);
       }
       if (maskUseASCII) {
@@ -6191,7 +6243,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
       writePS("%-EOD-\n");
       
       // delete encoders
-      if (maskUseRLE || maskUseASCII) {
+      if (maskUseLZW || maskUseRLE || maskUseASCII) {
 	delete maskStr;
       }
     }
@@ -6208,7 +6260,11 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
     if (inlineImg) {
       // create an array
       str2 = new FixedLengthEncoder(str, len);
-      str2 = new RunLengthEncoder(str2);
+      if (getEnableLZW()) {
+	str2 = new LZWEncoder(str2);
+      } else {
+	str2 = new RunLengthEncoder(str2);
+      }
       if (useASCIIHex) {
 	str2 = new ASCIIHexEncoder(str2);
       } else {
@@ -6251,7 +6307,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
 	}
       } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
       writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
-      // add an extra entry because the RunLengthDecode filter may
+      // add an extra entry because the LZWDecode/RunLengthDecode filter may
       // read past the end
       writePS("<>]\n");
       writePS("0\n");
@@ -6337,7 +6393,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
   if ((mode == psModeForm || inType3Char || preloadImagesForms) &&
       uncompressPreloadedImages) {
     s = NULL;
-    useRLE = gFalse;
+    useLZW = useRLE = gFalse;
     useCompressed = gFalse;
     useASCII = gFalse;
   } else {
@@ -6345,11 +6401,17 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
 			 "    ");
     if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
 	inlineImg || !s) {
-      useRLE = gTrue;
+      if (getEnableLZW()) {
+	useLZW = gTrue;
+	useRLE = gFalse;
+      } else {
+	useRLE = gTrue;
+	useLZW = gFalse;
+      }
       useASCII = !(mode == psModeForm || inType3Char || preloadImagesForms);
       useCompressed = gFalse;
     } else {
-      useRLE = gFalse;
+      useLZW = useRLE = gFalse;
       useASCII = str->isBinary() &&
                  !(mode == psModeForm || inType3Char || preloadImagesForms);
       useCompressed = gTrue;
@@ -6359,7 +6421,9 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
     writePSFmt("    /ASCII{0:s}Decode filter\n",
 	       useASCIIHex ? "Hex" : "85");
   }
-  if (useRLE) {
+  if (useLZW) {
+    writePS("    /LZWDecode filter\n");
+  } else if (useRLE) {
     writePS("    /RunLengthDecode filter\n");
   }
   if (useCompressed) {
@@ -6435,8 +6499,10 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
       str = str->getUndecodedStream();
     }
 
-    // add RunLengthEncode and ASCIIHex/85 encode filters
-    if (useRLE) {
+    // add LZWEncode/RunLengthEncode and ASCIIHex/85 encode filters
+    if (useLZW) {
+      str = new LZWEncoder(str);
+    } else if (useRLE) {
       str = new RunLengthEncoder(str);
     }
     if (useASCII) {
@@ -6459,7 +6525,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
     writePS("%-EOD-\n");
 
     // delete encoders
-    if (useRLE || useASCII || inlineImg) {
+    if (useLZW || useRLE || useASCII || inlineImg) {
       delete str;
     }
   }
diff --git a/poppler/PSOutputDev.h b/poppler/PSOutputDev.h
index 7318caf..bd5b075 100644
--- a/poppler/PSOutputDev.h
+++ b/poppler/PSOutputDev.h
@@ -320,6 +320,7 @@ public:
   GBool getEmbedCIDTrueType() const { return embedCIDTrueType; }
   GBool getFontPassthrough() const { return fontPassthrough; }
   GBool getOptimizeColorSpace() const { return optimizeColorSpace; }
+  GBool getEnableLZW() const { return enableLZW; };
   void setEmbedType1(GBool b) { embedType1 = b; }
   void setEmbedTrueType(GBool b) { embedTrueType = b; }
   void setEmbedCIDPostScript(GBool b) { embedCIDPostScript = b; }
@@ -330,6 +331,7 @@ public:
   void setGenerateOPI(GBool b) { generateOPI = b; }
   void setUseASCIIHex(GBool b) { useASCIIHex = b; }
   void setUseBinary(GBool b) { useBinary = b; }
+  void setEnableLZW(GBool b) { enableLZW = b; }
 
 private:
 
@@ -532,6 +534,7 @@ private:
   GBool generateOPI;		// generate PostScript OPI comments?
   GBool useASCIIHex;		// use ASCIIHex instead of ASCII85?
   GBool useBinary;		// use binary instead of hex
+  GBool enableLZW;		// enable LZW compression
 
 #if OPI_SUPPORT
   int opi13Nest;		// nesting level of OPI 1.3 objects
diff --git a/poppler/Stream.cc b/poppler/Stream.cc
index 9617678..f2ca60b 100644
--- a/poppler/Stream.cc
+++ b/poppler/Stream.cc
@@ -5302,6 +5302,151 @@ GBool RunLengthEncoder::fillBuf() {
 }
 
 //------------------------------------------------------------------------
+// LZWEncoder
+//------------------------------------------------------------------------
+
+LZWEncoder::LZWEncoder(Stream *strA):
+  FilterStream(strA)
+{
+  inBufLen = 0;
+  outBufLen = 0;
+}
+
+LZWEncoder::~LZWEncoder() {
+  if (str->isEncoder()) {
+    delete str;
+  }
+}
+
+void LZWEncoder::reset() {
+  int i;
+
+  str->reset();
+
+  // initialize code table
+  for (i = 0; i < 256; ++i) {
+    table[i].byte = i;
+    table[i].next = NULL;
+    table[i].children = NULL;
+  }
+  nextSeq = 258;
+  codeLen = 9;
+
+  // initialize input buffer
+  inBufLen = str->doGetChars(sizeof(inBuf), inBuf);
+
+  // initialize output buffer with a clear-table code
+  outBuf = 256;
+  outBufLen = 9;
+  needEOD = gFalse;
+}
+
+int LZWEncoder::getChar() {
+  int ret;
+
+  if (inBufLen == 0 && !needEOD && outBufLen == 0) {
+    return EOF;
+  }
+  if (outBufLen < 8 && (inBufLen > 0 || needEOD)) {
+    fillBuf();
+  }
+  if (outBufLen >= 8) {
+    ret = (outBuf >> (outBufLen - 8)) & 0xff;
+    outBufLen -= 8;
+  } else {
+    ret = (outBuf << (8 - outBufLen)) & 0xff;
+    outBufLen = 0;
+  }
+  return ret;
+}
+
+int LZWEncoder::lookChar() {
+  if (inBufLen == 0 && !needEOD && outBufLen == 0) {
+    return EOF;
+  }
+  if (outBufLen < 8 && (inBufLen > 0 || needEOD)) {
+    fillBuf();
+  }
+  if (outBufLen >= 8) {
+    return (outBuf >> (outBufLen - 8)) & 0xff;
+  } else {
+    return (outBuf << (8 - outBufLen)) & 0xff;
+  }
+}
+
+// On input, outBufLen < 8.
+// This function generates, at most, 2 12-bit codes
+//   --> outBufLen < 8 + 12 + 12 = 32
+void LZWEncoder::fillBuf() {
+  LZWEncoderNode *p0, *p1;
+  int seqLen, code, i;
+
+  if (needEOD) {
+    outBuf = (outBuf << codeLen) | 257;
+    outBufLen += codeLen;
+    needEOD = gFalse;
+    return;
+  }
+
+  // find longest matching sequence (if any)
+  p0 = table + inBuf[0];
+  seqLen = 1;
+  while (inBufLen > seqLen) {
+    for (p1 = p0->children; p1; p1 = p1->next) {
+      if (p1->byte == inBuf[seqLen]) {
+	break;
+      }
+    }
+    if (!p1) {
+      break;
+    }
+    p0 = p1;
+    ++seqLen;
+  }
+  code = (int)(p0 - table);
+
+  // generate an output code
+  outBuf = (outBuf << codeLen) | code;
+  outBufLen += codeLen;
+
+  // update the table
+  table[nextSeq].byte = seqLen < inBufLen ? inBuf[seqLen] : 0;
+  table[nextSeq].children = NULL;
+  if (table[code].children) {
+    table[nextSeq].next = table[code].children;
+  } else {
+    table[nextSeq].next = NULL;
+  }
+  table[code].children = table + nextSeq;
+  ++nextSeq;
+
+  // update the input buffer
+  memmove(inBuf, inBuf + seqLen, inBufLen - seqLen);
+  inBufLen -= seqLen;
+  inBufLen += str->doGetChars(sizeof(inBuf) - inBufLen, inBuf + inBufLen);
+
+  // increment codeLen; generate clear-table code
+  if (nextSeq == (1 << codeLen)) {
+    ++codeLen;
+    if (codeLen == 13) {
+      outBuf = (outBuf << 12) | 256;
+      outBufLen += 12;
+      for (i = 0; i < 256; ++i) {
+	table[i].next = NULL;
+	table[i].children = NULL;
+      }
+      nextSeq = 258;
+      codeLen = 9;
+    }
+  }
+
+  // generate EOD next time
+  if (inBufLen == 0) {
+    needEOD = gTrue;
+  }
+}
+
+//------------------------------------------------------------------------
 // CMYKGrayEncoder
 //------------------------------------------------------------------------
 
diff --git a/poppler/Stream.h b/poppler/Stream.h
index 00b2925..84a8cf9 100644
--- a/poppler/Stream.h
+++ b/poppler/Stream.h
@@ -1198,6 +1198,44 @@ private:
 };
 
 //------------------------------------------------------------------------
+// LZWEncoder
+//------------------------------------------------------------------------
+
+struct LZWEncoderNode {
+  int byte;
+  LZWEncoderNode *next;		// next sibling
+  LZWEncoderNode *children;	// first child
+};
+
+class LZWEncoder: public FilterStream {
+public:
+
+  LZWEncoder(Stream *strA);
+  virtual ~LZWEncoder();
+  virtual StreamKind getKind() { return strWeird; }
+  virtual void reset();
+  virtual int getChar();
+  virtual int lookChar();
+  virtual GooString *getPSFilter(int psLevel, const char *indent)
+    { return NULL; }
+  virtual GBool isBinary(GBool last = gTrue) { return gTrue; }
+  virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+  LZWEncoderNode table[4096];
+  int nextSeq;
+  int codeLen;
+  Guchar inBuf[4096];
+  int inBufLen;
+  int outBuf;
+  int outBufLen;
+  GBool needEOD;
+
+  void fillBuf();
+};
+
+//------------------------------------------------------------------------
 // CMYKGrayEncoder
 //------------------------------------------------------------------------
 
commit b88e68f9c84d987a814716aab50543bf8a5cb8f8
Author: William Bader <william at newspapersystems.com>
Date:   Thu Feb 25 20:41:48 2016 +1030

    xpdf304: Merge change from poppler/Gfx.cc to avoid attempting a tiling pattern fill
    
    with a singular transform matrix (abs(determinant) < 0.000001).

diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 577c482..bb5f9b1 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -2126,7 +2126,12 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
   btm = baseMatrix;
   ptm = tPat->getMatrix();
   // iCTM = invert CTM
-  det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+  det = ctm[0] * ctm[3] - ctm[1] * ctm[2];
+  if (fabs(det) < 0.000001) {
+    error(errSyntaxError, getPos(), "Singular matrix in tiling pattern fill");
+    return;
+  }
+  det = 1 / det;
   ictm[0] = ctm[3] * det;
   ictm[1] = -ctm[1] * det;
   ictm[2] = -ctm[2] * det;
@@ -2149,7 +2154,12 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
   m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
 
   // construct a (device space) -> (pattern space) transform matrix
-  det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
+  det = m1[0] * m1[3] - m1[1] * m1[2];
+  if (fabs(det) < 0.000001) {
+    error(errSyntaxError, getPos(), "Singular matrix in tiling pattern fill");
+    return;
+  }
+  det = 1 / det;
   imb[0] = m1[3] * det;
   imb[1] = -m1[1] * det;
   imb[2] = -m1[2] * det;
@@ -2335,7 +2345,12 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat,
   btm = baseMatrix;
   ptm = sPat->getMatrix();
   // iCTM = invert CTM
-  det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+  det = ctm[0] * ctm[3] - ctm[1] * ctm[2];
+  if (fabs(det) < 0.000001) {
+    error(errSyntaxError, getPos(), "Singular matrix in shading pattern fill");
+    return;
+  }
+  det = 1 / det;
   ictm[0] = ctm[3] * det;
   ictm[1] = -ctm[1] * det;
   ictm[2] = -ctm[2] * det;


More information about the poppler mailing list