diff options
author | Darin Adler <darin@src.gnome.org> | 2000-05-04 14:53:48 +0000 |
---|---|---|
committer | Darin Adler <darin@src.gnome.org> | 2000-05-04 14:53:48 +0000 |
commit | 24fa8a64bcd200b1c2f15ffb9d8d5c34e279601f (patch) | |
tree | 8d83b25348c9d5413f741aad41997db13dcd06bd | |
parent | fec650eb382ba8cd7dfec4a9b1976eedb335e17e (diff) | |
download | gtk+-24fa8a64bcd200b1c2f15ffb9d8d5c34e279601f.tar.gz |
Added some tests of composite to highlight problems in the old
* gdk-pixbuf/.cvsignore:
* gdk-pixbuf/Makefile.am:
* gdk-pixbuf/test-gdk-pixbuf.c (store_pixel), (fill_with_pixel),
(load_pixel), (simple_composite_test_one),
(simple_composite_test_one_type), (simple_composite_test), (main):
Added some tests of composite to highlight problems in the old
implementation. These tests run without any user interaction.
Just do "make check".
* gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest),
(composite_pixel), (composite_line): Fix composite to do a textbook
"A over B" composite. This was clearly the intent, and it was easy
to fix the code to do it. (Note to those that read my earlier tries
at a patch; this version fixes typos that were present in all
my patch attempts. I checked the final version by adding more tests.)
-rw-r--r-- | gdk-pixbuf/.cvsignore | 1 | ||||
-rw-r--r-- | gdk-pixbuf/ChangeLog | 18 | ||||
-rw-r--r-- | gdk-pixbuf/Makefile.am | 5 | ||||
-rw-r--r-- | gdk-pixbuf/pixops/pixops.c | 89 | ||||
-rw-r--r-- | gdk-pixbuf/test-gdk-pixbuf.c | 205 |
5 files changed, 255 insertions, 63 deletions
diff --git a/gdk-pixbuf/.cvsignore b/gdk-pixbuf/.cvsignore index e80ab794d8..da164a845d 100644 --- a/gdk-pixbuf/.cvsignore +++ b/gdk-pixbuf/.cvsignore @@ -5,6 +5,7 @@ Makefile .libs *.la *.lo +test-gdk-pixbuf testpixbuf testpixbuf-drawable testpixbuf-scale diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog index f51b3517c0..d41d8e664f 100644 --- a/gdk-pixbuf/ChangeLog +++ b/gdk-pixbuf/ChangeLog @@ -1,3 +1,21 @@ +2000-05-04 Darin Adler <darin@eazel.com> + + * gdk-pixbuf/.cvsignore: + * gdk-pixbuf/Makefile.am: + * gdk-pixbuf/test-gdk-pixbuf.c (store_pixel), (fill_with_pixel), + (load_pixel), (simple_composite_test_one), + (simple_composite_test_one_type), (simple_composite_test), (main): + Added some tests of composite to highlight problems in the old + implementation. These tests run without any user interaction. + Just do "make check". + + * gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest), + (composite_pixel), (composite_line): Fix composite to do a textbook + "A over B" composite. This was clearly the intent, and it was easy + to fix the code to do it. (Note to those that read my earlier tries + at a patch; this version fixes typos that were present in all + my patch attempts. I checked the final version by adding more tests.) + 2000-04-22 05:27:43 2000 Owen Taylor <otaylor@redhat.com> * gdk-pixbuf/pixops/pixops.c (pixops_scale_nearest): Properly diff --git a/gdk-pixbuf/Makefile.am b/gdk-pixbuf/Makefile.am index 35db1b7f3d..924f289f70 100644 --- a/gdk-pixbuf/Makefile.am +++ b/gdk-pixbuf/Makefile.am @@ -138,7 +138,8 @@ extra_sources = $(libpixbufloader_png_la_SOURCES) \ builtin_libraries = endif -noinst_PROGRAMS = testpixbuf testpixbuf-drawable testanimation testpixbuf-scale +noinst_PROGRAMS = test-gdk-pixbuf testpixbuf testpixbuf-drawable testanimation testpixbuf-scale +TESTS = test-gdk-pixbuf DEPS = libgdk_pixbuf.la INCLUDES = -I$(top_srcdir) -I$(top_builddir) \ @@ -150,11 +151,13 @@ AM_CPPFLAGS = "-DPIXBUF_LIBDIR=\"$(libexecdir)\"" LDADDS = libgdk_pixbuf.la $(GLIB_LIBS) $(GTK_LIBS) $(STATIC_LIB_DEPS) if INSIDE_GNOME_LIBS +test_gdk_pixbuf_LDADD = $(LDADDS) -lgmodule testpixbuf_LDADD = $(LDADDS) -lgmodule testpixbuf_drawable_LDADD = $(LDADDS) testpixbuf_scale_LDADD = $(LDADDS) testanimation_LDADD = $(LDADDS) -lgmodule else +test_gdk_pixbuf_LDADD = $(LDADDS) $(GNOME_LIBS) -lgmodule testpixbuf_LDADD = $(LDADDS) $(GNOME_LIBS) -lgmodule testpixbuf_drawable_LDADD = $(LDADDS) $(GNOME_LIBS) testpixbuf_scale_LDADD = $(LDADDS) $(GNOME_LIBS) diff --git a/gdk-pixbuf/pixops/pixops.c b/gdk-pixbuf/pixops/pixops.c index d9592659d0..00652d5c67 100644 --- a/gdk-pixbuf/pixops/pixops.c +++ b/gdk-pixbuf/pixops/pixops.c @@ -171,36 +171,23 @@ pixops_composite_nearest (guchar *dest_buf, unsigned int a0; if (src_has_alpha) - a0 = (p[3] * overall_alpha + 0xff) >> 8; + a0 = (p[3] * overall_alpha) / 0xff; else a0 = overall_alpha; if (dest_has_alpha) { - unsigned int a1 = dest[3]; - unsigned int total = a0 + a1; - - if (total) - { - dest[0] = (a0 * src[0] + a1 * dest[0]) / (total); - dest[1] = (a0 * src[1] + a1 * dest[1]) / (total); - dest[2] = (a0 * src[2] + a1 * dest[2]) / (total); - dest[3] = total - ((a0 * a1 + 0xff) >> 8); - } - else - { - dest[0] = 0; - dest[1] = 0; - dest[2] = 0; - dest[3] = 0; - } + dest[0] = (a0 * src[0] + (0xff - a0) * dest[0]) / 0xff; + dest[1] = (a0 * src[1] + (0xff - a0) * dest[1]) / 0xff; + dest[2] = (a0 * src[2] + (0xff - a0) * dest[2]) / 0xff; + dest[3] = (0xff * a0 + (0xff - a0) * dest[3]) / 0xff; } else { - dest[0] = dest[0] + ((a0 * (p[0] - dest[0]) + 0xff) >> 8); - dest[1] = dest[1] + ((a0 * (p[1] - dest[1]) + 0xff) >> 8); - dest[2] = dest[2] + ((a0 * (p[2] - dest[2]) + 0xff) >> 8); - + dest[0] = (a0 * p[0] + (0xff - a0) * dest[0]) / 0xff; + dest[1] = (a0 * p[1] + (0xff - a0) * dest[1]) / 0xff; + dest[2] = (a0 * p[2] + (0xff - a0) * dest[2]) / 0xff; + if (dest_channels == 4) dest[3] = 0xff; } @@ -309,29 +296,18 @@ composite_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha { if (dest_has_alpha) { - unsigned int w = (((1 << 16) - a) * dest[3]) >> 8; - unsigned int total = a + w; - - if (total) - { - dest[0] = (r + w * dest[0]) / total; - dest[1] = (g + w * dest[1]) / total; - dest[2] = (b + w * dest[2]) / total; - dest[3] = (r * w) >> 16; - } - else - { - dest[0] = 0; - dest[1] = 0; - dest[2] = 0; - dest[3] = 0; - } + unsigned int w = (0xff0000 - a) * dest[3]; + + dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000; + dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000; + dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000; + dest[3] = (0xff * a + (0xff0000 - a) * dest[3]) / 0xff0000; } else { - dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24; - dest[1] = ((0xff0000 - a) * dest[1] + g) >> 24; - dest[2] = ((0xff0000 - a) * dest[2] + b) >> 24; + dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000; + dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000; + dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000; } } @@ -366,7 +342,7 @@ composite_line (int *weights, int n_x, int n_y, ta = q[3] * line_weights[j]; else ta = 0xff * line_weights[j]; - + r += ta * q[0]; g += ta * q[1]; b += ta * q[2]; @@ -378,29 +354,18 @@ composite_line (int *weights, int n_x, int n_y, if (dest_has_alpha) { - unsigned int w = (((1 << 16) - a) * dest[3]) >> 8; - unsigned int total = a + w; + unsigned int w = (0xff0000 - a) * dest[3]; - if (total) - { - dest[0] = (r + w * dest[0]) / total; - dest[1] = (r + w * dest[1]) / total; - dest[2] = (r + w * dest[2]) / total; - dest[3] = (r * w) >> 16; - } - else - { - dest[0] = 0; - dest[1] = 0; - dest[2] = 0; - dest[3] = 0; - } + dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000; + dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000; + dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000; + dest[3] = (0xff * a + (0xff0000 - a) * dest[3]) / 0xff0000; } else { - dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24; - dest[1] = ((0xff0000 - a) * dest[1] + g) >> 24; - dest[2] = ((0xff0000 - a) * dest[2] + b) >> 24; + dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000; + dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000; + dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000; } dest += dest_channels; diff --git a/gdk-pixbuf/test-gdk-pixbuf.c b/gdk-pixbuf/test-gdk-pixbuf.c index 5b96dddd0d..b75f2e65e1 100644 --- a/gdk-pixbuf/test-gdk-pixbuf.c +++ b/gdk-pixbuf/test-gdk-pixbuf.c @@ -1,3 +1,5 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + /* GdkPixbuf library - test program * * Copyright (C) 1999 The Free Software Foundation @@ -27,7 +29,210 @@ +static void +store_pixel (guchar *pixels, + int pixel, + gboolean alpha) +{ + if (alpha) { + pixels[0] = pixel >> 24; + pixels[1] = pixel >> 16; + pixels[2] = pixel >> 8; + pixels[3] = pixel; + } else { + pixels[0] = pixel >> 16; + pixels[1] = pixel >> 8; + pixels[2] = pixel; + } +} + +static void +fill_with_pixel (GdkPixbuf *pixbuf, + int pixel) +{ + int x, y; + + for (x = 0; x < gdk_pixbuf_get_width (pixbuf); x++) { + for (y = 0; y < gdk_pixbuf_get_height (pixbuf); y++) { + store_pixel (gdk_pixbuf_get_pixels (pixbuf) + + y * gdk_pixbuf_get_rowstride (pixbuf) + + x * gdk_pixbuf_get_n_channels (pixbuf), + pixel, + gdk_pixbuf_get_has_alpha (pixbuf)); + } + } +} + +static int +load_pixel (const guchar *pixels, + gboolean alpha) +{ + if (alpha) + return (((((pixels[0] << 8) | pixels[1]) << 8) | pixels[2]) << 8) | pixels[3]; + else + return (((pixels[0] << 8) | pixels[1]) << 8) | pixels[2]; +} + +static gboolean +simple_composite_test_one (GdkInterpType type, + int source_pixel, + gboolean source_alpha, + int destination_pixel, + gboolean destination_alpha, + int expected_result) +{ + GdkPixbuf *source_pixbuf; + GdkPixbuf *destination_pixbuf; + int result_pixel; + + source_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, source_alpha, 8, 32, 32); + destination_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, destination_alpha, 8, 32, 32); + + fill_with_pixel (source_pixbuf, source_pixel); + fill_with_pixel (destination_pixbuf, destination_pixel); + + gdk_pixbuf_composite (source_pixbuf, destination_pixbuf, + 0, 0, 32, 32, 0, 0, 1, 1, type, 0xFF); + + result_pixel = load_pixel (gdk_pixbuf_get_pixels (destination_pixbuf) + + 16 * gdk_pixbuf_get_rowstride (destination_pixbuf) + + 16 * gdk_pixbuf_get_n_channels (destination_pixbuf), + destination_alpha); + + gdk_pixbuf_unref (source_pixbuf); + gdk_pixbuf_unref (destination_pixbuf); + + if (result_pixel != expected_result) { + char *interpolation_type, *source_string, *destination_string, *result_string, *expected_string; + + switch (type) { + case GDK_INTERP_NEAREST: interpolation_type = "GDK_INTERP_NEAREST"; break; + case GDK_INTERP_TILES: interpolation_type = "GDK_INTERP_TILES"; break; + case GDK_INTERP_BILINEAR: interpolation_type = "GDK_INTERP_BILINEAR"; break; + case GDK_INTERP_HYPER: interpolation_type = "GDK_INTERP_HYPER"; break; + default: interpolation_type = "???"; + } + + if (source_alpha) { + source_string = g_strdup_printf ("0x%08X", source_pixel); + } else { + source_string = g_strdup_printf ("0x%06X", source_pixel); + } + + if (destination_alpha) { + destination_string = g_strdup_printf ("0x%08X", destination_pixel); + result_string = g_strdup_printf ("0x%08X", result_pixel); + expected_string = g_strdup_printf ("0x%08X", expected_result); + } else { + destination_string = g_strdup_printf ("0x%06X", destination_pixel); + result_string = g_strdup_printf ("0x%06X", result_pixel); + expected_string = g_strdup_printf ("0x%06X", expected_result); + } + + g_message ("simple_composite_test (%s): composite %s on top of %s, expected %s, got %s", + interpolation_type, + source_string, destination_string, expected_string, result_string); + return FALSE; + } + + return TRUE; +} + +static gboolean +simple_composite_test_one_type (GdkInterpType type) +{ + gboolean success; + + success = TRUE; + + /* There are only a few trivial cases in here. + * But these were enough to expose the problems in the old composite code. + */ + + /* Non-alpha into non-alpha. */ + success &= simple_composite_test_one (type, 0x000000, FALSE, 0x000000, FALSE, 0x000000); + success &= simple_composite_test_one (type, 0x000000, FALSE, 0xFFFFFF, FALSE, 0x000000); + success &= simple_composite_test_one (type, 0xFF0000, FALSE, 0x000000, FALSE, 0xFF0000); + success &= simple_composite_test_one (type, 0x00FF00, FALSE, 0x000000, FALSE, 0x00FF00); + success &= simple_composite_test_one (type, 0x0000FF, FALSE, 0x000000, FALSE, 0x0000FF); + success &= simple_composite_test_one (type, 0x000000, FALSE, 0xFF0000, FALSE, 0x000000); + success &= simple_composite_test_one (type, 0x000000, FALSE, 0x00FF00, FALSE, 0x000000); + success &= simple_composite_test_one (type, 0x000000, FALSE, 0x0000FF, FALSE, 0x000000); + success &= simple_composite_test_one (type, 0x00FF00, FALSE, 0xFFFFFF, FALSE, 0x00FF00); + success &= simple_composite_test_one (type, 0xFFFFFF, FALSE, 0xFFFFFF, FALSE, 0xFFFFFF); + + /* Alpha into non-alpha. */ + success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x000000, FALSE, 0x000000); + success &= simple_composite_test_one (type, 0x00000000, TRUE, 0xFFFFFF, FALSE, 0xFFFFFF); + success &= simple_composite_test_one (type, 0x0000007F, TRUE, 0xFFFFFF, FALSE, 0x808080); + success &= simple_composite_test_one (type, 0x00000080, TRUE, 0xFFFFFF, FALSE, 0x7F7F7F); + success &= simple_composite_test_one (type, 0x000000FF, TRUE, 0xFFFFFF, FALSE, 0x000000); + success &= simple_composite_test_one (type, 0x000000FF, TRUE, 0xFFFFFF, FALSE, 0x000000); + success &= simple_composite_test_one (type, 0xFF0000FF, TRUE, 0x000000, FALSE, 0xFF0000); + success &= simple_composite_test_one (type, 0x00FF00FF, TRUE, 0x000000, FALSE, 0x00FF00); + success &= simple_composite_test_one (type, 0x0000FFFF, TRUE, 0x000000, FALSE, 0x0000FF); + success &= simple_composite_test_one (type, 0x00000000, TRUE, 0xFF0000, FALSE, 0xFF0000); + success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x00FF00, FALSE, 0x00FF00); + success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x0000FF, FALSE, 0x0000FF); + success &= simple_composite_test_one (type, 0x00FF0080, TRUE, 0xFFFFFF, FALSE, 0x7FFF7F); + success &= simple_composite_test_one (type, 0xFFFFFFFF, TRUE, 0xFFFFFF, FALSE, 0xFFFFFF); + + /* Non-alpha into alpha. */ + success &= simple_composite_test_one (type, 0x000000, FALSE, 0x00000000, TRUE, 0x000000FF); + success &= simple_composite_test_one (type, 0x000000, FALSE, 0xFFFFFFFF, TRUE, 0x000000FF); + success &= simple_composite_test_one (type, 0xFF0000, FALSE, 0x00000000, TRUE, 0xFF0000FF); + success &= simple_composite_test_one (type, 0x00FF00, FALSE, 0x00000000, TRUE, 0x00FF00FF); + success &= simple_composite_test_one (type, 0x0000FF, FALSE, 0x00000000, TRUE, 0x0000FFFF); + success &= simple_composite_test_one (type, 0x000000, FALSE, 0xFF0000FF, TRUE, 0x000000FF); + success &= simple_composite_test_one (type, 0x000000, FALSE, 0x00FF00FF, TRUE, 0x000000FF); + success &= simple_composite_test_one (type, 0x000000, FALSE, 0x0000FFFF, TRUE, 0x000000FF); + success &= simple_composite_test_one (type, 0x00FF00, FALSE, 0xFFFFFF00, TRUE, 0x00FF00FF); + success &= simple_composite_test_one (type, 0xFFFFFF, FALSE, 0xFFFFFFFF, TRUE, 0xFFFFFFFF); + + /* Alpha into alpha. */ + success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x00000000, TRUE, 0x00000000); + success &= simple_composite_test_one (type, 0x00000000, TRUE, 0xFFFFFFFF, TRUE, 0xFFFFFFFF); + success &= simple_composite_test_one (type, 0x0000007F, TRUE, 0xFFFFFFFF, TRUE, 0x808080FF); + success &= simple_composite_test_one (type, 0x00000080, TRUE, 0xFFFFFFFF, TRUE, 0x7F7F7FFF); + success &= simple_composite_test_one (type, 0x000000FF, TRUE, 0xFFFFFFFF, TRUE, 0x000000FF); + success &= simple_composite_test_one (type, 0xFF0000FF, TRUE, 0x00000000, TRUE, 0xFF0000FF); + success &= simple_composite_test_one (type, 0x00FF00FF, TRUE, 0x00000000, TRUE, 0x00FF00FF); + success &= simple_composite_test_one (type, 0x0000FFFF, TRUE, 0x00000000, TRUE, 0x0000FFFF); + success &= simple_composite_test_one (type, 0x00000000, TRUE, 0xFF0000FF, TRUE, 0xFF0000FF); + success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x00FF00FF, TRUE, 0x00FF00FF); + success &= simple_composite_test_one (type, 0x00000000, TRUE, 0x0000FFFF, TRUE, 0x0000FFFF); + success &= simple_composite_test_one (type, 0x00FF0080, TRUE, 0xFFFFFF00, TRUE, 0x7FFF7F80); + success &= simple_composite_test_one (type, 0xFFFFFFFF, TRUE, 0xFFFFFFFF, TRUE, 0xFFFFFFFF); + + return success; +} + +static gboolean +simple_composite_test (void) +{ + gboolean success; + + success = TRUE; + + success &= simple_composite_test_one_type (GDK_INTERP_NEAREST); + success &= simple_composite_test_one_type (GDK_INTERP_TILES); + success &= simple_composite_test_one_type (GDK_INTERP_BILINEAR); + success &= simple_composite_test_one_type (GDK_INTERP_HYPER); + + return success; +} + int main (int argc, char **argv) { + int result; + + result = EXIT_SUCCESS; + + /* Run some tests. */ + if (!simple_composite_test ()) { + result = EXIT_FAILURE; + } + + return result; } |