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 <[email protected]> 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 <[email protected]> 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 _______________________________________________ poppler mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/poppler
