From 316e9d0e2fee36de8bcdbeaa86b24392d7d2ef08 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Sun, 22 Oct 2017 10:26:55 +1030 Subject: [PATCH 2/2] 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 use 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 --- poppler/CairoOutputDev.cc | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index 8beef9fa..e817f608 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; int 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.9 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, 9) + bool requireSameSize = false; +#else + bool requireSameSize = true; +#endif + if (!requireSameSize || (width == widthA and height == heightA)) + setMimeData(state, str, ref, colorMap, image, heightA); + } pattern = cairo_pattern_create_for_surface (image); cairo_surface_destroy (image); -- 2.11.0