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

Carlos Garcia Campos carlosgc at kemper.freedesktop.org
Sun Feb 28 04:57:58 PST 2010


 poppler/CairoOutputDev.cc |  116 ++++++++++++++++++++++++++++------------------
 poppler/CairoOutputDev.h  |    4 +
 2 files changed, 77 insertions(+), 43 deletions(-)

New commits:
commit 5453cff5b7cb47cadfdae585a58409117af8c1f1
Author: Carlos Garcia Campos <carlosgc at gnome.org>
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 <carlosgc at gnome.org>
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;


More information about the poppler mailing list