[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