[babl] Add code to handle N-components



commit 6e83f2cdf03db496731d9375f90ba05320ac6fb5
Author: �yvind Kolås <pippin gimp org>
Date:   Mon Jun 28 00:42:02 2010 +0100

    Add code to handle N-components
    
    Added a new API call, babl_format_n (). This allows constructing a babl
    format with an arbitrary number of components all of the same type. At
    the moment. The model used for such formats is "Y", at the moment
    conversions are only well defined for such formats to other n-component
    formats with the same number of components.

 babl/babl-classes.h        |    2 +-
 babl/babl-fish-reference.c |  135 ++++++++++++++++++++++++++++++++++++++------
 babl/babl-format.c         |   56 +++++++++++++++++-
 babl/babl.h                |   12 ++++-
 tests/Makefile.am          |    1 +
 tests/n_components.c       |  116 +++++++++++++++++++++++++++++++++++++
 6 files changed, 299 insertions(+), 23 deletions(-)
---
diff --git a/babl/babl-classes.h b/babl/babl-classes.h
index 0427c30..fa25c4e 100644
--- a/babl/babl-classes.h
+++ b/babl/babl-classes.h
@@ -67,7 +67,7 @@ enum {
 
 
 /* This union can be used for convenient access to any field without
- * the need to case if the variable already is of the type Babl*
+ * the need to cast if the variable already is of the type Babl*
  */
 typedef union _Babl
 {
diff --git a/babl/babl-fish-reference.c b/babl/babl-fish-reference.c
index 0b1cc27..5fbc837 100644
--- a/babl/babl-fish-reference.c
+++ b/babl/babl-fish-reference.c
@@ -201,6 +201,79 @@ convert_from_double (BablFormat *destination_fmt,
 }
 
 
+static void
+ncomponent_convert_to_double (BablFormat *source_fmt,
+                              BablImage  *source,
+                              char       *source_buf,
+                              char       *source_double_buf,
+                              int         n)
+{
+  BablImage *src_img;
+  BablImage *dst_img;
+
+  src_img = (BablImage *) babl_image_new (
+    babl_component_from_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+  dst_img = (BablImage *) babl_image_new (
+    babl_component_from_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+
+  dst_img->type[0]  = (BablType *) babl_type_from_id (BABL_DOUBLE);
+  dst_img->pitch[0] = (dst_img->type[0]->bits / 8);
+  dst_img->stride[0] = 0;
+
+  src_img->data[0]   = source_buf;
+  src_img->type[0] = source_fmt->type[0];
+  src_img->pitch[0] = source_fmt->type[0]->bits / 8;
+  src_img->stride[0] = 0;
+
+  dst_img->data[0] = source_double_buf;
+
+  babl_process (
+    assert_conversion_find (src_img->type[0], dst_img->type[0]),
+    src_img, dst_img,
+    n * source_fmt->components);
+  babl_free (src_img);
+  babl_free (dst_img);
+}
+
+static void
+ncomponent_convert_from_double (BablFormat *destination_fmt,
+                                char       *destination_double_buf,
+                                BablImage  *destination,
+                                char       *destination_buf,
+                                int         n)
+{
+  BablImage *src_img;
+  BablImage *dst_img;
+
+  src_img = (BablImage *) babl_image_new (
+    babl_component_from_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+  dst_img = (BablImage *) babl_image_new (
+    babl_component_from_id (BABL_LUMINANCE), NULL, 1, 0, NULL);
+
+  src_img->type[0]   = (BablType *) babl_type_from_id (BABL_DOUBLE);
+  src_img->pitch[0]  = (src_img->type[0]->bits / 8);
+  src_img->stride[0] = 0;
+
+  dst_img->data[0]  = destination_buf;
+  dst_img->type[0]  = (BablType *) babl_type_from_id (BABL_DOUBLE);
+  dst_img->pitch[0] = destination_fmt->type[0]->bits/8;
+  dst_img->stride[0] = 0;
+
+  dst_img->type[0] = destination_fmt->type[0];
+  src_img->data[0] = destination_double_buf;
+
+  babl_process (
+    assert_conversion_find (src_img->type[0], dst_img->type[0]),
+    src_img, dst_img,
+    n * destination_fmt->components);
+
+  dst_img->data[0] += dst_img->type[0]->bits / 8;
+  babl_free (src_img);
+  babl_free (dst_img);
+}
+
+
+
 static int
 process_same_model (Babl      *babl,
                     BablImage *source,
@@ -217,24 +290,51 @@ process_same_model (Babl      *babl,
     }
 
   double_buf = babl_malloc (sizeof (double) * n *
-                            BABL (babl->fish.source)->format.model->components);
+                            BABL (babl->fish.source)->format.components);
 
-  convert_to_double (
-    (BablFormat *) BABL (babl->fish.source),
-    BABL_IS_BABL (source) ? source : NULL,
-    BABL_IS_BABL (source) ? NULL : (char *) source,
-    double_buf,
-    n
-  );
+  if (
+      (BABL (babl->fish.source)->format.components ==
+       BABL (babl->fish.destination)->format.components)
+      && (BABL (babl->fish.source)->format.model->components !=
+          BABL (babl->fish.source)->format.components))
+    {
+      /* FIXME: should recursively invoke babl and look up an appropriate fish
+       * for the conversion and multiply n by the number of components.
+       */
+      ncomponent_convert_to_double (
+        (BablFormat *) BABL (babl->fish.source),
+        BABL_IS_BABL (source) ? source : NULL,
+        BABL_IS_BABL (source) ? NULL : (char *) source,
+        double_buf,
+        n
+      );
 
-  convert_from_double (
-    (BablFormat *) BABL (babl->fish.destination),
-    double_buf,
-    BABL_IS_BABL (destination) ? destination : NULL,
-    BABL_IS_BABL (destination) ? NULL : (char *) destination,
-    n
-  );
+      ncomponent_convert_from_double (
+        (BablFormat *) BABL (babl->fish.destination),
+        double_buf,
+        BABL_IS_BABL (destination) ? destination : NULL,
+        BABL_IS_BABL (destination) ? NULL : (char *) destination,
+        n
+      );
+    }
+  else
+    {
+      convert_to_double (
+        (BablFormat *) BABL (babl->fish.source),
+        BABL_IS_BABL (source) ? source : NULL,
+        BABL_IS_BABL (source) ? NULL : (char *) source,
+        double_buf,
+        n
+      );
 
+      convert_from_double (
+        (BablFormat *) BABL (babl->fish.destination),
+        double_buf,
+        BABL_IS_BABL (destination) ? destination : NULL,
+        BABL_IS_BABL (destination) ? NULL : (char *) destination,
+        n
+      );
+    }
   babl_free (double_buf);
   return 0;
 }
@@ -252,6 +352,7 @@ babl_fish_reference_process (Babl      *babl,
   Babl *rgba_image;
   Babl *destination_image;
 
+
   if (BABL (babl->fish.source)->format.model ==
       BABL (babl->fish.destination)->format.model)
     return process_same_model (babl, source, destination, n);
diff --git a/babl/babl-format.c b/babl/babl-format.c
index 4c75d3c..186d15a 100644
--- a/babl/babl-format.c
+++ b/babl/babl-format.c
@@ -116,7 +116,6 @@ format_new (const char     *name,
 }
 
 
-
 static char *
 create_name (BablModel      *model,
              int             components,
@@ -185,6 +184,58 @@ create_name (BablModel      *model,
   return babl_strdup (buf);
 }
 
+
+static char *
+ncomponents_create_name (Babl *type,
+                         int   components)
+{
+  char buf[512];
+  sprintf (buf, "%s[%i] ", type->instance.name, components);
+  return babl_strdup (buf);
+}
+
+Babl *
+babl_format_n (Babl *btype,
+               int   components)
+{
+  int            i;
+  Babl          *babl;
+  int            id         = 0;
+  int            planar     = 0;
+  BablModel     *model      = (BablModel *)babl_model ("Y");
+  BablComponent *component [components];
+  BablSampling  *sampling  [components];
+  BablType      *type      [components];
+  char          *name       = NULL;
+
+  for (i = 0; i<components; i++)
+    {
+      component[i] = model->component[0];
+      type[i] = &btype->type;
+      sampling[i] = (BablSampling *) babl_sampling (1, 1);
+    }
+
+  name = ncomponents_create_name (btype, components);
+  babl = babl_db_exist (db, id, name);
+  if (babl)
+    {
+      /* There is an instance already registered by the required id/name,
+       * returning the preexistent one instead.
+       */
+      babl_free (name);
+      return babl;
+    }
+
+  babl = format_new (name,
+                     id,
+                     planar, components, model,
+                     component, sampling, type);
+
+  babl_db_insert (db, babl);
+  babl_free (name);
+  return babl;
+}
+
 Babl *
 babl_format_new (void *first_arg,
                  ...)
@@ -322,9 +373,6 @@ babl_format_new (void *first_arg,
                      planar, components, model,
                      component, sampling, type);
 
-  /* Since there is not an already registered instance by the required
-   * id/name, inserting newly created class into database.
-   */
   babl_db_insert (db, babl);
   babl_free (name);
   return babl;
diff --git a/babl/babl.h b/babl/babl.h
index 44276a4..1ad2ea7 100644
--- a/babl/babl.h
+++ b/babl/babl.h
@@ -153,7 +153,7 @@ Babl * babl_model_new      (void *first_arg,
                             ...) BABL_ARG_NULL_TERMINATED;
 
 /**
- * Defines a new color format in babl. Provided BablType and|or
+ * Defines a new pixel format in babl. Provided BablType and|or
  * BablSampling is valid for the following components as well. If no
  * name is provided a (long) descriptive name is used.
  *
@@ -172,6 +172,16 @@ Babl * babl_model_new      (void *first_arg,
 Babl * babl_format_new     (void *first_arg,
                             ...) BABL_ARG_NULL_TERMINATED;
 
+/*
+ * Defines a new pixel format in babl. With the specified data storage
+ * type and the given number of components. At the moment behavior of 
+ * conversions are only well defined to other babl_format_n derived formats
+ * with the same number of components.
+ */
+Babl *
+babl_format_n (Babl *type,
+               int   components);
+
 /**
  * Defines a new conversion between either two formats, two models or
  * two types in babl.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9fa34e2..e8fdd1d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -10,6 +10,7 @@ TESTS =				\
 	sanity			\
 	babl_class_name		\
 	types			\
+	n_components		\
 	models			\
 	$(CONCURRENCY_STRESS_TEST)
 
diff --git a/tests/n_components.c b/tests/n_components.c
new file mode 100644
index 0000000..0cfeb11
--- /dev/null
+++ b/tests/n_components.c
@@ -0,0 +1,116 @@
+/* babl - dynamically extendable universal pixel conversion library.
+ * Copyright (C) 2005, �yvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "config.h"
+#include <math.h>
+#include "babl-internal.h"
+
+#define PIXELS       7
+#define COMPONENTS   2048
+#define TOLERANCE    0
+
+float source_buf [PIXELS * COMPONENTS] =
+{
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+   0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 
+  /* the rest of the input buffer is nulls */
+}; 
+
+unsigned char reference_buf [PIXELS * COMPONENTS] =
+{ 
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153,
+  /* the rest of the reference buffer is nulls */
+};
+
+unsigned char destination_buf [PIXELS * COMPONENTS];
+
+static int
+test (void)
+{
+  int   components;
+  int   OK = 1;
+
+  for (components = 1; components < 2048; components ++)
+  {
+    Babl *fish;
+    Babl *src_fmt;
+    Babl *dst_fmt;
+    int   i;
+
+    src_fmt = babl_format_n (babl_type ("float"), components);
+    dst_fmt = babl_format_n (babl_type ("u8"), components);
+
+    fish = babl_fish (src_fmt, dst_fmt);
+
+    babl_process (fish, source_buf, destination_buf, PIXELS);
+
+    for (i = 0; i < PIXELS * components; i++)
+      {
+        if (abs (destination_buf[i] - reference_buf[i]) > TOLERANCE)
+          {
+            babl_log ("%i-components, pixel %i component %i is %i should be %i",
+                      components, i / components, i % components, destination_buf[i], reference_buf[i]);
+            OK = 0;
+          }
+      }
+  }
+  if (!OK)
+    return -1;
+  return 0;
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+  babl_init ();
+  if (test ())
+    return -1;
+  babl_exit ();
+  return 0;
+}



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