[poppler] 2 commits - poppler/CairoOutputDev.cc poppler/CairoOutputDev.h poppler/Stream.cc poppler/Stream.h

Adrian Johnson ajohnson at kemper.freedesktop.org
Tue Dec 12 10:02:15 UTC 2017


 poppler/CairoOutputDev.cc |   79 +++++++++++++++++++++++++++++++++++++++++++---
 poppler/CairoOutputDev.h  |    5 ++
 poppler/Stream.cc         |   14 +++++---
 poppler/Stream.h          |    6 ++-
 4 files changed, 93 insertions(+), 11 deletions(-)

New commits:
commit f5706275121409887b0e486b896b48cbcccb766a
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 22 10:26:55 2017 +1030

    cairo: limit image size when printing
    
    1 bpp image formats can have very large sizes. Even if the maximum
    cairo image size is not exceeded, it still uses a huge amount of memory
    and is very slow.
    
    This limits the image size when printing to 8192x8192 which is
    sufficient for 300ppi at A2 size. Cairo >= 1.5.10 scales mime images
    to the same dimensions as the cairo image, so the original mime image
    can still be embedded.
    
    Bug 103399

diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 01cc0d0b..09839505 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -69,6 +69,11 @@
 
 // #define LOG_CAIRO
 
+// To limit memory usage and improve performance when printing, limit
+// cairo images to this size. 8192 is sufficient for an A2 sized
+// 300ppi image.
+#define MAX_PRINT_IMAGE_SIZE 8192
+
 #ifdef LOG_CAIRO
 #define LOG(x) (x)
 #else
@@ -3125,7 +3130,22 @@ public:
     bool needsCustomDownscaling = true;
 #endif
 
-    if (!needsCustomDownscaling || printing || scaledWidth >= width || scaledHeight >= height) {
+    if (printing) {
+      if (width > MAX_PRINT_IMAGE_SIZE || height > MAX_PRINT_IMAGE_SIZE) {
+	if (width > height) {
+	  scaledWidth = MAX_PRINT_IMAGE_SIZE;
+	  scaledHeight = MAX_PRINT_IMAGE_SIZE * (double)height/width;
+	} else {
+	  scaledHeight = MAX_PRINT_IMAGE_SIZE;
+	  scaledWidth = MAX_PRINT_IMAGE_SIZE * (double)width/height;
+	}
+	needsCustomDownscaling = true;
+      } else {
+	needsCustomDownscaling = false;
+      }
+    }
+
+    if (!needsCustomDownscaling || scaledWidth >= width || scaledHeight >= height) {
       // No downscaling. Create cairo image containing the source image data.
       unsigned char *buffer;
       ptrdiff_t stride;
@@ -3255,8 +3275,17 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   if (width == widthA && height == heightA)
     filter = getFilterForSurface (image, interpolate);
 
-  if (!inlineImg) /* don't read stream twice if it is an inline image */
-    setMimeData(state, str, ref, colorMap, image, heightA);
+  if (!inlineImg) { /* don't read stream twice if it is an inline image */
+    // cairo 1.15.10 allows mime image data to have different size to cairo image
+    // mime image size will be scaled to same size as cairo image
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 15, 10)
+    bool requireSameSize = false;
+#else
+    bool requireSameSize = true;
+#endif
+    if (!requireSameSize || (width == widthA && height == heightA))
+      setMimeData(state, str, ref, colorMap, image, heightA);
+  }
 
   pattern = cairo_pattern_create_for_surface (image);
   cairo_surface_destroy (image);
commit 3f13dd5f04984be1912b4537ffbfacd892750915
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 22 09:37:01 2017 +1030

    cairo: support embedding CCITT image data
    
    Bug 103399

diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index cc8a161b..01cc0d0b 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -2761,7 +2761,7 @@ void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *s
 
   cairo_surface_mark_dirty (image);
 
-  setMimeData(state, str, ref, colorMap, image);
+  setMimeData(state, str, ref, colorMap, image, height);
 
   pattern = cairo_pattern_create_for_surface (image);
   cairo_surface_destroy (image);
@@ -2935,8 +2935,38 @@ GBool CairoOutputDev::setMimeDataForJBIG2Globals(Stream  *str,
 }
 #endif
 
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 15, 10)
+GBool CairoOutputDev::setMimeDataForCCITTParams(Stream  *str,
+						cairo_surface_t *image, int height)
+{
+  CCITTFaxStream *ccittStr = static_cast<CCITTFaxStream *>(str);
+
+  GooString params;
+  params.appendf("Columns={0:d}", ccittStr->getColumns());
+  params.appendf(" Rows={0:d}", height);
+  params.appendf(" K={0:d}", ccittStr->getEncoding());
+  params.appendf(" EndOfLine={0:d}", ccittStr->getEndOfLine() ? 1 : 0);
+  params.appendf(" EncodedByteAlign={0:d}", ccittStr->getEncodedByteAlign() ? 1 : 0);
+  params.appendf(" EndOfBlock={0:d}", ccittStr->getEndOfBlock() ? 1 : 0);
+  params.appendf(" BlackIs1={0:d}", ccittStr->getBlackIs1() ? 1 : 0);
+  params.appendf(" DamagedRowsBeforeError={0:d}", ccittStr->getDamagedRowsBeforeError());
+
+  char *p = strdup(params.getCString());
+  if (cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
+                                   (const unsigned char*)p,
+                                   params.getLength(),
+                                   gfree, (void*)p))
+  {
+    gfree (p);
+    return gFalse;
+  }
+
+  return gTrue;
+}
+#endif
+
 void CairoOutputDev::setMimeData(GfxState *state, Stream *str, Object *ref,
-				 GfxImageColorMap *colorMap, cairo_surface_t *image)
+				 GfxImageColorMap *colorMap, cairo_surface_t *image, int height)
 {
   char *strBuffer;
   int len;
@@ -2960,6 +2990,11 @@ void CairoOutputDev::setMimeData(GfxState *state, Stream *str, Object *ref,
       mime_type = CAIRO_MIME_TYPE_JBIG2;
       break;
 #endif
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 15, 10)
+    case strCCITTFax:
+      mime_type = CAIRO_MIME_TYPE_CCITT_FAX;
+      break;
+#endif
     default:
       return;
   }
@@ -3002,6 +3037,11 @@ void CairoOutputDev::setMimeData(GfxState *state, Stream *str, Object *ref,
     return;
 #endif
 
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 15, 10)
+  if (strKind == strCCITTFax && !setMimeDataForCCITTParams(str, image, height))
+    return;
+#endif
+
   if (getStreamData (str->getNextStream(), &strBuffer, &len)) {
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
@@ -3216,7 +3256,7 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
     filter = getFilterForSurface (image, interpolate);
 
   if (!inlineImg) /* don't read stream twice if it is an inline image */
-    setMimeData(state, str, ref, colorMap, image);
+    setMimeData(state, str, ref, colorMap, image, heightA);
 
   pattern = cairo_pattern_create_for_surface (image);
   cairo_surface_destroy (image);
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index 1fee8121..83ed1abf 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -283,12 +283,15 @@ protected:
 				     GBool interpolate);
   GBool getStreamData (Stream *str, char **buffer, int *length);
   void setMimeData(GfxState *state, Stream *str, Object *ref,
-		   GfxImageColorMap *colorMap, cairo_surface_t *image);
+		   GfxImageColorMap *colorMap, cairo_surface_t *image, int height);
   void fillToStrokePathClip(GfxState *state);
   void alignStrokeCoords(GfxSubpath *subpath, int i, double *x, double *y);
 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 14, 0)
   GBool setMimeDataForJBIG2Globals (Stream *str, cairo_surface_t *image);
 #endif
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 15, 10)
+  GBool setMimeDataForCCITTParams(Stream  *str, cairo_surface_t *image, int height);
+#endif
   static void setContextAntialias(cairo_t *cr, cairo_antialias_t antialias);
 
   GfxRGB fill_color, stroke_color;
diff --git a/poppler/Stream.cc b/poppler/Stream.cc
index da1d9267..2dbd6c82 100644
--- a/poppler/Stream.cc
+++ b/poppler/Stream.cc
@@ -214,7 +214,7 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursio
   int bits;
   int early;
   int encoding;
-  GBool endOfLine, byteAlign, endOfBlock, black;
+  GBool endOfLine, byteAlign, endOfBlock, black, damagedRowsBeforeError;
   int columns, rows;
   Object globals, obj;
 
@@ -256,7 +256,8 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursio
     rows = 0;
     endOfBlock = gTrue;
     black = gFalse;
-    if (params->isDict()) {
+    damagedRowsBeforeError = 0;
+  if (params->isDict()) {
       obj = params->dictLookup("K", recursion);
       if (obj.isInt()) {
 	encoding = obj.getInt();
@@ -285,9 +286,13 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params, int recursio
       if (obj.isBool()) {
 	black = obj.getBool();
       }
+      obj = params->dictLookup("DamagedRowsBeforeError", recursion);
+      if (obj.isInt()) {
+	damagedRowsBeforeError = obj.getInt();
+      }
     }
     str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign,
-			     columns, rows, endOfBlock, black);
+			     columns, rows, endOfBlock, black, damagedRowsBeforeError);
   } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) {
 #ifdef HAVE_DCT_DECODER
     int colorXform = -1;
@@ -1641,12 +1646,13 @@ GBool RunLengthStream::fillBuf() {
 
 CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
 			       GBool byteAlignA, int columnsA, int rowsA,
-			       GBool endOfBlockA, GBool blackA):
+			       GBool endOfBlockA, GBool blackA, int damagedRowsBeforeErrorA):
     FilterStream(strA) {
   encoding = encodingA;
   endOfLine = endOfLineA;
   byteAlign = byteAlignA;
   columns = columnsA;
+  damagedRowsBeforeError = damagedRowsBeforeErrorA;
   if (columns < 1) {
     columns = 1;
   } else if (columns > INT_MAX - 2) {
diff --git a/poppler/Stream.h b/poppler/Stream.h
index 152dbb0f..36988ccc 100644
--- a/poppler/Stream.h
+++ b/poppler/Stream.h
@@ -794,7 +794,7 @@ public:
 
   CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
 		 GBool byteAlignA, int columnsA, int rowsA,
-		 GBool endOfBlockA, GBool blackA);
+		 GBool endOfBlockA, GBool blackA, int damagedRowsBeforeErrorA);
   ~CCITTFaxStream();
   StreamKind getKind() override { return strCCITTFax; }
   void reset() override;
@@ -808,8 +808,11 @@ public:
 
   int getEncoding() { return encoding; }
   GBool getEndOfLine() { return endOfLine; }
+  GBool getEncodedByteAlign() { return byteAlign; }
+  GBool getEndOfBlock() { return endOfBlock; }
   int getColumns() { return columns; }
   GBool getBlackIs1() { return black; }
+  int getDamagedRowsBeforeError() { return damagedRowsBeforeError; }
 
 private:
 
@@ -821,6 +824,7 @@ private:
   int rows;			// 'Rows' parameter
   GBool endOfBlock;		// 'EndOfBlock' parameter
   GBool black;			// 'BlackIs1' parameter
+  int damagedRowsBeforeError;   // 'DamagedRowsBeforeError' parameter
   GBool eof;			// true if at eof
   GBool nextLine2D;		// true if next line uses 2D encoding
   int row;			// current row


More information about the poppler mailing list