[gdk-pixbuf] Fix bug 766842



commit ad43d54b11d0b337e8032d9d25b09eb8f8650ace
Author: Daniel Trebbien <dtrebbien gmail com>
Date:   Sun May 29 18:48:13 2016 -0400

    Fix bug 766842
    
    This commit fixes an issue where pixops_composite_nearest_noscale () had
    different behavior than pixops_composite_nearest () for pixels in the
    destination that are not a part of the transformed source image. Per the
    documentation, the pixels at the edges of the source image should be
    replicated to infinity.
    
    Added a test to tests/pixbuf-composite.c
    
    https://bugzilla.gnome.org/show_bug.cgi?id=766842

 gdk-pixbuf/pixops/pixops.c |   55 ++++++++++++++++++++------
 tests/pixbuf-composite.c   |   92 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 132 insertions(+), 15 deletions(-)
---
diff --git a/gdk-pixbuf/pixops/pixops.c b/gdk-pixbuf/pixops/pixops.c
index 6a4a096..11ff241 100644
--- a/gdk-pixbuf/pixops/pixops.c
+++ b/gdk-pixbuf/pixops/pixops.c
@@ -437,21 +437,51 @@ pixops_composite_nearest_noscale (guchar        *dest_buf,
                                  gboolean       src_has_alpha,
                                  int            overall_alpha)
 {
-  int i, j;
-  int x;
+  gint64 i;
+  gint64 x;
+  gint64 xmax, xstart, xstop, y_pos;
+  const guchar *p;
+  unsigned int  a0;
+
+#define INNER_LOOP_NOSCALE(SRC_CHANNELS,DEST_CHANNELS,ASSIGN_PIXEL) \
+      xmax = x + (render_x1 - render_x0);                       \
+      xstart = MIN (0, xmax);                                   \
+      xstop = MIN (src_width, xmax);                            \
+      p = src + CLAMP (x, xstart, xstop) * SRC_CHANNELS;        \
+      while (x < xstart)                                        \
+        {                                                       \
+          ASSIGN_PIXEL;                                         \
+          dest += DEST_CHANNELS;                                \
+          x++;                                                  \
+        }                                                       \
+      p = src + x * SRC_CHANNELS;                               \
+      while (x < xstop)                                         \
+        {                                                       \
+          ASSIGN_PIXEL;                                         \
+          dest += DEST_CHANNELS;                                \
+          x++;                                                  \
+          p += SRC_CHANNELS;                                    \
+        }                                                       \
+      p = src + CLAMP (x, 0, src_width - 1) * SRC_CHANNELS;     \
+      while (x < xmax)                                          \
+        {                                                       \
+          ASSIGN_PIXEL;                                         \
+          dest += DEST_CHANNELS;                                \
+          x++;                                                  \
+        }
 
   for (i = 0; i < (render_y1 - render_y0); i++)
     {
-      const guchar *src  = src_buf + (gsize)(i + render_y0) * src_rowstride;
-      guchar       *dest = dest_buf + (gsize)i * dest_rowstride;
-
-      x = render_x0 * src_channels;
+      const guchar *src;
+      guchar       *dest;
+      y_pos = i + render_y0;
+      y_pos = CLAMP (y_pos, 0, src_height - 1);
+      src  = src_buf + (gsize)y_pos * src_rowstride;
+      dest = dest_buf + (gsize)i * dest_rowstride;
 
-      for (j=0; j < (render_x1 - render_x0); j++)
-       {
-         const guchar *p = src + x;
-         unsigned int  a0;
+      x = render_x0;
 
+      INNER_LOOP_NOSCALE(src_channels, dest_channels,
          if (src_has_alpha)
            a0 = (p[3] * overall_alpha) / 0xff;
          else
@@ -494,11 +524,10 @@ pixops_composite_nearest_noscale (guchar        *dest_buf,
                }
              break;
            }
-         dest += dest_channels;
-         x += src_channels;
-       }
+       );
     }
 }
+#undef INNER_LOOP_NOSCALE
 
 static void
 pixops_composite_color_nearest (guchar        *dest_buf,
diff --git a/tests/pixbuf-composite.c b/tests/pixbuf-composite.c
index e8b70fd..3bd201f 100644
--- a/tests/pixbuf-composite.c
+++ b/tests/pixbuf-composite.c
@@ -22,7 +22,7 @@
 #include "test-common.h"
 
 static void
-test_composite (void)
+test_composite1 (void)
 {
   GdkPixbuf *red, *green, *out, *ref, *sub;
 
@@ -54,12 +54,100 @@ test_composite (void)
   g_object_unref (sub);
 }
 
+/*
+ * Test for Bug 766842
+ * https://bugzilla.gnome.org/show_bug.cgi?id=766842
+ */
+static void
+test_composite2 (void)
+{
+  GdkPixbuf *src, *dest;
+  guchar *pixels, *p;
+
+  src = gdk_pixbuf_new_from_file ("test-image.png", NULL);
+
+  {
+    GdkPixbuf *tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                     TRUE,
+                                     gdk_pixbuf_get_bits_per_sample (src),
+                                     gdk_pixbuf_get_width (src),
+                                     gdk_pixbuf_get_height (src));
+    gdk_pixbuf_fill (tmp, 0x00ccccff);
+    gdk_pixbuf_composite (src, tmp,
+                          0, 0, gdk_pixbuf_get_width (tmp), gdk_pixbuf_get_height (tmp),
+                          0., 0., 1., 1.,
+                          GDK_INTERP_NEAREST, 255);
+    g_object_unref (src);
+    src = tmp;
+  }
+
+  pixels = gdk_pixbuf_get_pixels (src);
+  p = pixels;
+  p[0] = 0xff;
+  p[1] = 0x00;
+  p[2] = 0xff;
+  p = pixels + (gsize)((gdk_pixbuf_get_height (src) - 1) * gdk_pixbuf_get_rowstride (src)) + 
(gsize)((gdk_pixbuf_get_width (src) - 1) * gdk_pixbuf_get_n_channels (src));
+  p[0] = 0xff;
+  p[1] = 0xff;
+  p[2] = 0x00;
+
+  dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                         TRUE,
+                         gdk_pixbuf_get_bits_per_sample (src),
+                         gdk_pixbuf_get_width (src) + 80,
+                         gdk_pixbuf_get_height (src) + 80);
+  gdk_pixbuf_fill (dest, 0xffffffff);
+  gdk_pixbuf_composite (src, dest,
+                        0, 0, gdk_pixbuf_get_width (dest), gdk_pixbuf_get_height (dest),
+                        10.0, 10.0, 1.0, 1.0,
+                        GDK_INTERP_NEAREST, 255);
+
+  pixels = gdk_pixbuf_get_pixels (dest);
+  p = pixels;
+  g_assert_cmpint (p[0], ==, 0xff);
+  g_assert_cmpint (p[1], ==, 0x00);
+  g_assert_cmpint (p[2], ==, 0xff);
+  p = pixels + (gsize)((gdk_pixbuf_get_height (dest) - 1) * gdk_pixbuf_get_rowstride (dest)) + 
(gsize)((gdk_pixbuf_get_width (dest) - 1) * gdk_pixbuf_get_n_channels (dest));
+  g_assert_cmpint (p[0], ==, 0xff);
+  g_assert_cmpint (p[1], ==, 0xff);
+  g_assert_cmpint (p[2], ==, 0x00);
+
+  g_object_unref (dest);
+
+  /* now try compositing into a pixbuf that is 1px less in width and height */
+  dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                         TRUE,
+                         gdk_pixbuf_get_bits_per_sample (src),
+                         gdk_pixbuf_get_width (src) - 1,
+                         gdk_pixbuf_get_height (src) - 1);
+  gdk_pixbuf_fill (dest, 0xffffffff);
+  gdk_pixbuf_composite (src, dest,
+                        0, 0, gdk_pixbuf_get_width (dest), gdk_pixbuf_get_height (dest),
+                        -1.0, -2.0, 1.0, 1.0,
+                        GDK_INTERP_NEAREST, 255);
+
+  pixels = gdk_pixbuf_get_pixels (dest);
+  p = pixels + (gsize)((gdk_pixbuf_get_height (dest) - 2) * gdk_pixbuf_get_rowstride (dest)) + 
(gsize)((gdk_pixbuf_get_width (dest) - 1) * gdk_pixbuf_get_n_channels (dest));
+  g_assert_cmpint (p[0], ==, 0xff);
+  g_assert_cmpint (p[1], ==, 0xff);
+  g_assert_cmpint (p[2], ==, 0x00);
+  p = pixels + (gsize)((gdk_pixbuf_get_height (dest) - 1) * gdk_pixbuf_get_rowstride (dest)) + 
(gsize)((gdk_pixbuf_get_width (dest) - 1) * gdk_pixbuf_get_n_channels (dest));
+  g_assert_cmpint (p[0], ==, 0xff);
+  g_assert_cmpint (p[1], ==, 0xff);
+  g_assert_cmpint (p[2], ==, 0x00);
+
+  g_object_unref (dest);
+
+  g_object_unref (src);
+}
+
 int
 main (int argc, char *argv[])
 {
   g_test_init (&argc, &argv, NULL);
 
-  g_test_add_func ("/pixbuf/composite", test_composite);
+  g_test_add_func ("/pixbuf/composite1", test_composite1);
+  g_test_add_func ("/pixbuf/composite2", test_composite2);
 
   return g_test_run ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]