]> Pileus Git - ~andy/gtk/commitdiff
Added some tests of composite to highlight problems in the old
authorDarin Adler <darin@src.gnome.org>
Thu, 4 May 2000 14:53:48 +0000 (14:53 +0000)
committerDarin Adler <darin@src.gnome.org>
Thu, 4 May 2000 14:53:48 +0000 (14:53 +0000)
* 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.)

gdk-pixbuf/.cvsignore
gdk-pixbuf/ChangeLog
gdk-pixbuf/Makefile.am
gdk-pixbuf/pixops/pixops.c
gdk-pixbuf/test-gdk-pixbuf.c

index e80ab794d81f4726c4bfcd456e81e65e34568193..da164a845db1c1747ffbd79d9f52d0a1cd32b52e 100644 (file)
@@ -5,6 +5,7 @@ Makefile
 .libs
 *.la
 *.lo
+test-gdk-pixbuf
 testpixbuf
 testpixbuf-drawable
 testpixbuf-scale
index f51b3517c0095ef14901c77a51d2aa6a95943b26..d41d8e664f1788e1f9c4220a08f0972081ee5505 100644 (file)
@@ -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
index 35db1b7f3d639822acd5e99441354fb11cda89ea..924f289f7009fc9fb283d07921f899a2e03b2c31 100644 (file)
@@ -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)
index d9592659d00d9feb6389a6d75b465f16f66c6677..00652d5c67f09bb3d822a6174e2e474c95abb8c4 100644 (file)
@@ -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;
index 5b96dddd0d6b1fad703a24c43caf4dd817ed568c..b75f2e65e181ba4fb3197138c29d645912daf9c9 100644 (file)
@@ -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
 
 \f
 
+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;
 }