summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Trebbien <dtrebbien@gmail.com>2016-05-29 18:48:13 -0400
committerMatthias Clasen <mclasen@redhat.com>2016-05-31 13:30:01 -0400
commitad43d54b11d0b337e8032d9d25b09eb8f8650ace (patch)
tree39bb1bc2b9a2579fd11400a664d618626d677cc6
parent0a4b7c51705351fdcd8b838897395bb1ef36eef3 (diff)
downloadgdk-pixbuf-ad43d54b11d0b337e8032d9d25b09eb8f8650ace.tar.gz
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
-rw-r--r--gdk-pixbuf/pixops/pixops.c55
-rw-r--r--tests/pixbuf-composite.c92
2 files changed, 132 insertions, 15 deletions
diff --git a/gdk-pixbuf/pixops/pixops.c b/gdk-pixbuf/pixops/pixops.c
index 6a4a09629..11ff2415a 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 e8b70fd93..3bd201fab 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 ();
}