poppler/CairoOutputDev.cc | 116 ++++++++++++++++++++++++++++------------------ poppler/CairoOutputDev.h | 4 + 2 files changed, 77 insertions(+), 43 deletions(-)
New commits: commit 5453cff5b7cb47cadfdae585a58409117af8c1f1 Author: Carlos Garcia Campos <[email protected]> Date: Sun Feb 28 13:51:22 2010 +0100 [cairo] Select filter for images based on scale factor When rendering images and interpolate flag is disabled or missing, we always interpolate unless scale factor is >= 400% See bugs #25268, #9860 diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index 41a3ff0..5cad4e7 100644 --- a/poppler/CairoOutputDev.cc +++ b/poppler/CairoOutputDev.cc @@ -1456,6 +1456,25 @@ cairo_surface_t *CairoOutputDev::downscaleSurface(cairo_surface_t *orig_surface) } +cairo_filter_t +CairoOutputDev::getFilterForSurface(cairo_surface_t *image, + GBool interpolate) +{ + if (interpolate) + return CAIRO_FILTER_BILINEAR; + + int orig_width = cairo_image_surface_get_width (image); + int orig_height = cairo_image_surface_get_height (image); + int scaled_width, scaled_height; + getScaledSize (orig_width, orig_height, &scaled_width, &scaled_height); + + /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */ + if (scaled_width / orig_width >= 4 || scaled_height / orig_height >= 4) + return CAIRO_FILTER_NEAREST; + + return CAIRO_FILTER_BILINEAR; +} + void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool interpolate, GBool inlineImg) { @@ -1518,6 +1537,7 @@ void CairoOutputDev::drawImageMaskRegular(GfxState *state, Object *ref, Stream * cairo_matrix_t matrix; int invert_bit; int row_stride; + cairo_filter_t filter; /* TODO: Do we want to cache these? */ imgStr = new ImageStream(str, width, 1, 1); @@ -1544,6 +1564,8 @@ void CairoOutputDev::drawImageMaskRegular(GfxState *state, Object *ref, Stream * } } + filter = getFilterForSurface (image, interpolate); + cairo_surface_mark_dirty (image); pattern = cairo_pattern_create_for_surface (image); cairo_surface_destroy (image); @@ -1552,11 +1574,8 @@ void CairoOutputDev::drawImageMaskRegular(GfxState *state, Object *ref, Stream * LOG (printf ("drawImageMask %dx%d\n", width, height)); - /* we should actually be using CAIRO_FILTER_NEAREST here. However, - * cairo doesn't yet do minifaction filtering causing scaled down - * images with CAIRO_FILTER_NEAREST to look really bad */ - cairo_pattern_set_filter (pattern, - interpolate ? CAIRO_FILTER_BEST : CAIRO_FILTER_FAST); + cairo_pattern_set_filter (pattern, filter); + if (!printing) cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); @@ -1897,6 +1916,8 @@ void CairoOutputDev::drawMaskedImage(GfxState *state, Object *ref, Guchar *pix; int x, y; int invert_bit; + cairo_filter_t filter; + cairo_filter_t maskFilter; maskImgStr = new ImageStream(maskStr, maskWidth, 1, 1); maskImgStr->reset(); @@ -1927,6 +1948,8 @@ void CairoOutputDev::drawMaskedImage(GfxState *state, Object *ref, maskImgStr->close(); delete maskImgStr; + maskFilter = getFilterForSurface (maskImage, maskInterpolate); + cairo_surface_mark_dirty (maskImage); maskPattern = cairo_pattern_create_for_surface (maskImage); cairo_surface_destroy (maskImage); @@ -1960,6 +1983,8 @@ void CairoOutputDev::drawMaskedImage(GfxState *state, Object *ref, colorMap->getRGBLine (pix, dest, width); } + filter = getFilterForSurface (image, interpolate); + cairo_surface_mark_dirty (image); pattern = cairo_pattern_create_for_surface (image); cairo_surface_destroy (image); @@ -1968,10 +1993,9 @@ void CairoOutputDev::drawMaskedImage(GfxState *state, Object *ref, LOG (printf ("drawMaskedImage %dx%d\n", width, height)); - cairo_pattern_set_filter (pattern, - interpolate ? CAIRO_FILTER_BILINEAR : CAIRO_FILTER_FAST); - cairo_pattern_set_filter (maskPattern, - maskInterpolate ? CAIRO_FILTER_BILINEAR : CAIRO_FILTER_FAST); + cairo_pattern_set_filter (pattern, filter); + cairo_pattern_set_filter (maskPattern, maskFilter); + if (!printing) { cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); cairo_pattern_set_extend (maskPattern, CAIRO_EXTEND_PAD); @@ -2038,6 +2062,8 @@ void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *s cairo_matrix_t maskMatrix, matrix; Guchar *pix; int y; + cairo_filter_t filter; + cairo_filter_t maskFilter; maskImgStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), @@ -2062,6 +2088,8 @@ void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *s maskImgStr->close(); delete maskImgStr; + maskFilter = getFilterForSurface (maskImage, maskInterpolate); + cairo_surface_mark_dirty (maskImage); maskPattern = cairo_pattern_create_for_surface (maskImage); cairo_surface_destroy (maskImage); @@ -2095,6 +2123,8 @@ void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *s colorMap->getRGBLine (pix, dest, width); } + filter = getFilterForSurface (image, interpolate); + cairo_surface_mark_dirty (image); pattern = cairo_pattern_create_for_surface (image); cairo_surface_destroy (image); @@ -2103,11 +2133,9 @@ void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *s LOG (printf ("drawSoftMaskedImage %dx%d\n", width, height)); - //XXX: should set mask filter - cairo_pattern_set_filter (pattern, - interpolate ? CAIRO_FILTER_BILINEAR : CAIRO_FILTER_FAST); - cairo_pattern_set_filter (maskPattern, - maskInterpolate ? CAIRO_FILTER_BILINEAR : CAIRO_FILTER_FAST); + cairo_pattern_set_filter (pattern, filter); + cairo_pattern_set_filter (maskPattern, maskFilter); + if (!printing) { cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); cairo_pattern_set_extend (maskPattern, CAIRO_EXTEND_PAD); @@ -2193,6 +2221,7 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, unsigned char *buffer; int stride, i; GfxRGB *lookup = NULL; + cairo_filter_t filter = CAIRO_FILTER_BILINEAR; /* TODO: Do we want to cache these? */ imgStr = new ImageStream(str, width, @@ -2286,6 +2315,8 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, image = scaled_surface; width = cairo_image_surface_get_width (image); height = cairo_image_surface_get_height (image); + } else { + filter = getFilterForSurface (image, interpolate); } cairo_surface_mark_dirty (image); @@ -2313,9 +2344,8 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, if (cairo_pattern_status (pattern)) goto cleanup; - cairo_pattern_set_filter (pattern, - interpolate ? - CAIRO_FILTER_BILINEAR : CAIRO_FILTER_FAST); + cairo_pattern_set_filter (pattern, filter); + if (!printing) cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h index 17c060b..02a4955 100644 --- a/poppler/CairoOutputDev.h +++ b/poppler/CairoOutputDev.h @@ -272,6 +272,8 @@ protected: cairo_surface_t *downscaleSurface(cairo_surface_t *orig_surface); void getScaledSize(int orig_width, int orig_height, int *scaledWidth, int *scaledHeight); + cairo_filter_t getFilterForSurface(cairo_surface_t *image, + GBool interpolate); GBool getStreamData (Stream *str, char **buffer, int *length); GfxRGB fill_color, stroke_color; commit e65456cbd5cae2750426aabeb2d66a10537616f0 Author: Carlos Garcia Campos <[email protected]> Date: Sun Feb 28 13:13:13 2010 +0100 [cairo] Refactor scaled size computation into a new method diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index d421431..41a3ff0 100644 --- a/poppler/CairoOutputDev.cc +++ b/poppler/CairoOutputDev.cc @@ -1370,27 +1370,13 @@ get_singular_values (const cairo_matrix_t *matrix, *minor = sqrt (f - delta); } - -cairo_surface_t *CairoOutputDev::downscaleSurface(cairo_surface_t *orig_surface) { - cairo_surface_t *dest_surface; - unsigned char *dest_buffer; - int dest_stride; - unsigned char *orig_buffer; - int orig_width, orig_height; - int orig_stride; - GBool res; - - if (printing) - return NULL; - - - orig_width = cairo_image_surface_get_width (orig_surface); - orig_height = cairo_image_surface_get_height (orig_surface); - +void CairoOutputDev::getScaledSize(int orig_width, + int orig_height, + int *scaledWidth, + int *scaledHeight) { cairo_matrix_t matrix; cairo_get_matrix(cairo, &matrix); - /* this whole computation should be factored out */ double xScale; double yScale; if (orig_width > orig_height) @@ -1399,8 +1385,6 @@ cairo_surface_t *CairoOutputDev::downscaleSurface(cairo_surface_t *orig_surface) get_singular_values (&matrix, &yScale, &xScale); int tx, tx2, ty, ty2; /* the integer co-oridinates of the resulting image */ - int scaledHeight; - int scaledWidth; if (xScale >= 0) { tx = splashRound(matrix.x0 - 0.01); tx2 = splashRound(matrix.x0 + xScale + 0.01) - 1; @@ -1408,13 +1392,13 @@ cairo_surface_t *CairoOutputDev::downscaleSurface(cairo_surface_t *orig_surface) tx = splashRound(matrix.x0 + 0.01) - 1; tx2 = splashRound(matrix.x0 + xScale - 0.01); } - scaledWidth = abs(tx2 - tx) + 1; + *scaledWidth = abs(tx2 - tx) + 1; //scaledWidth = splashRound(fabs(xScale)); - if (scaledWidth == 0) { + if (*scaledWidth == 0) { // technically, this should draw nothing, but it generally seems // better to draw a one-pixel-wide stripe rather than throwing it // away - scaledWidth = 1; + *scaledWidth = 1; } if (yScale >= 0) { ty = splashFloor(matrix.y0 + 0.01); @@ -1423,13 +1407,29 @@ cairo_surface_t *CairoOutputDev::downscaleSurface(cairo_surface_t *orig_surface) ty = splashCeil(matrix.y0 - 0.01); ty2 = splashFloor(matrix.y0 + yScale + 0.01); } - scaledHeight = abs(ty2 - ty); - if (scaledHeight == 0) { - scaledHeight = 1; + *scaledHeight = abs(ty2 - ty); + if (*scaledHeight == 0) { + *scaledHeight = 1; } +} + +cairo_surface_t *CairoOutputDev::downscaleSurface(cairo_surface_t *orig_surface) { + cairo_surface_t *dest_surface; + unsigned char *dest_buffer; + int dest_stride; + unsigned char *orig_buffer; + int orig_width, orig_height; + int orig_stride; + int scaledHeight; + int scaledWidth; + GBool res; + + if (printing) + return NULL; orig_width = cairo_image_surface_get_width (orig_surface); orig_height = cairo_image_surface_get_height (orig_surface); + getScaledSize (orig_width, orig_height, &scaledWidth, &scaledHeight); if (scaledWidth >= orig_width || scaledHeight >= orig_height) return NULL; diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h index e47825e..17c060b 100644 --- a/poppler/CairoOutputDev.h +++ b/poppler/CairoOutputDev.h @@ -270,6 +270,8 @@ public: protected: void doPath(cairo_t *cairo, GfxState *state, GfxPath *path); cairo_surface_t *downscaleSurface(cairo_surface_t *orig_surface); + void getScaledSize(int orig_width, int orig_height, + int *scaledWidth, int *scaledHeight); GBool getStreamData (Stream *str, char **buffer, int *length); GfxRGB fill_color, stroke_color; _______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
