[babl] extensions: Add the HSL color space



commit 0600fb9a5769556273c6f8c83d0cc5e3fe775e0a
Author: Téo Mazars <teo mazars ensimag fr>
Date:   Mon Jun 24 22:55:35 2013 +0200

    extensions: Add the HSL color space
    
    Needed at least as legacy

 extensions/HSL.c       |  286 ++++++++++++++++++++++++++++++++++++++++++++++++
 extensions/Makefile.am |    2 +
 tests/Makefile.am      |    1 +
 tests/hsl.c            |  111 +++++++++++++++++++
 4 files changed, 400 insertions(+), 0 deletions(-)
---
diff --git a/extensions/HSL.c b/extensions/HSL.c
new file mode 100644
index 0000000..5426474
--- /dev/null
+++ b/extensions/HSL.c
@@ -0,0 +1,286 @@
+/* babl - dynamically extendable universal pixel conversion library.
+ *
+ * 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 <string.h>
+
+#include "babl.h"
+#include "base/util.h"
+
+#define MIN(a,b) ((a > b) ? b : a)
+#define MAX(a,b) ((a < b) ? b : a)
+
+static long  rgba_to_hsla     (char   *src,
+                               char   *dst,
+                               long    samples);
+static long  hsla_to_rgba     (char   *src,
+                               char   *dst,
+                               long    samples);
+static long  rgba_to_hsl      (char   *src,
+                               char   *dst,
+                               long    samples);
+static long  hsl_to_rgba      (char   *src,
+                               char   *dst,
+                               long    samples);
+static void  rgb_to_hsl_step  (double *src,
+                               double *dst);
+static void  hsl_to_rgb_step  (double *src,
+                               double *dst);
+static inline double hue2cpn  (double  p,
+                               double  q,
+                               double  hue);
+int init (void);
+
+
+int
+init (void)
+{
+  babl_component_new ("hue", NULL);
+  babl_component_new ("saturation", NULL);
+  babl_component_new ("lightness", NULL);
+  babl_component_new ("alpha", NULL);
+
+  babl_model_new ("name", "HSLA",
+                  babl_component ("hue"),
+                  babl_component ("saturation"),
+                  babl_component ("lightness"),
+                  babl_component ("alpha"),
+                  NULL);
+  babl_model_new ("name", "HSL",
+                  babl_component ("hue"),
+                  babl_component ("saturation"),
+                  babl_component ("lightness"),
+                  NULL);
+
+
+  babl_conversion_new (babl_model ("RGBA"),
+                       babl_model ("HSLA"),
+                       "linear", rgba_to_hsla,
+                       NULL);
+  babl_conversion_new (babl_model ("RGBA"),
+                       babl_model ("HSL"),
+                       "linear", rgba_to_hsl,
+                       NULL);
+  babl_conversion_new (babl_model ("HSLA"),
+                       babl_model ("RGBA"),
+                       "linear", hsla_to_rgba,
+                       NULL);
+  babl_conversion_new (babl_model ("HSL"),
+                       babl_model ("RGBA"),
+                       "linear", hsl_to_rgba,
+                       NULL);
+
+  babl_format_new ("name", "HSLA float",
+                   babl_model ("HSLA"),
+                   babl_type ("float"),
+                   babl_component ("hue"),
+                   babl_component ("saturation"),
+                   babl_component ("lightness"),
+                   babl_component ("alpha"),
+                   NULL);
+  babl_format_new ("name", "HSL float",
+                   babl_model ("HSL"),
+                   babl_type ("float"),
+                   babl_component ("hue"),
+                   babl_component ("saturation"),
+                   babl_component ("lightness"),
+                   NULL);
+  return 0;
+}
+
+
+static inline void
+rgb_to_hsl_step (double* src,
+                 double* dst)
+{
+
+  double min, max;
+  double hue, saturation, lightness;
+  int cpn_max;
+
+  double red   = linear_to_gamma_2_2 (src[0]);
+  double green = linear_to_gamma_2_2 (src[1]);
+  double blue  = linear_to_gamma_2_2 (src[2]);
+
+  max = MAX (red, MAX (green, blue));
+  min = MIN (red, MIN (green, blue));
+
+  if (max == red)
+    cpn_max = 0;
+  else if (max == green)
+    cpn_max = 1;
+  else
+    cpn_max = 2;
+
+  lightness = (max + min) / 2.0;
+
+  if (max == min)
+    {
+      hue = saturation = 0;
+    }
+  else
+    {
+      double diff = max - min;
+      double sum  = max + min;
+      saturation = lightness > 0.5 ? diff / (2.0 - sum) : diff / sum;
+      switch (cpn_max)
+        {
+        case 0: hue = (green - blue)  / diff + (green < blue ? 6.0 : 0.0); break;
+        case 1: hue = (blue  - red)   / diff + 2.0; break;
+        case 2: hue = (red   - green) / diff + 4.0; break;
+        default: break;
+        }
+      hue /= 6.0;
+    }
+
+  dst[0] = hue;
+  dst[1] = saturation;
+  dst[2] = lightness;
+}
+
+
+static long
+rgba_to_hsla (char *src,
+              char *dst,
+              long  samples)
+{
+  long n = samples;
+
+  while (n--)
+    {
+      double alpha = ((double *) src)[3];
+
+      rgb_to_hsl_step ((double *) src, (double *) dst);
+
+      ((double *) dst)[3] = alpha;
+
+      src += 4 * sizeof (double);
+      dst += 4 * sizeof (double);
+    }
+
+  return samples;
+}
+
+
+static long
+rgba_to_hsl (char *src,
+             char *dst,
+             long  samples)
+{
+  long n = samples;
+
+  while (n--)
+    {
+      rgb_to_hsl_step ((double *) src, (double *) dst);
+
+      src += 4 * sizeof (double);
+      dst += 3 * sizeof (double);
+    }
+
+  return samples;
+}
+
+
+static inline double
+hue2cpn (double p, double q, double hue)
+{
+  if (hue < 0.0) hue += 1.0;
+  if (hue > 1.0) hue -= 1.0;
+  if (hue < 1.0 / 6.0) return p + (q - p) * 6.0 * hue;
+  if (hue < 1.0 / 2.0) return q;
+  if (hue < 2.0 / 3.0) return p + (q - p) * (2.0 / 3.0 - hue) * 6.0;
+  return p;
+}
+
+
+static void
+hsl_to_rgb_step (double *src,
+                 double *dst)
+{
+  double hue        = src[0];
+  double saturation = src[1];
+  double lightness  = src[2];
+
+  double red = 0, green = 0, blue = 0;
+
+  if (saturation < 1e-7)
+    {
+      red = green = blue = lightness;
+    }
+  else
+    {
+      double q = lightness < 0.5 ?
+        lightness * (1 + saturation) :
+        lightness + saturation - lightness * saturation;
+
+      double p = 2 * lightness - q;
+
+      red   = hue2cpn (p, q, hue + 1.0/3.0);
+      green = hue2cpn (p, q, hue);
+      blue  = hue2cpn (p, q, hue - 1.0/3.0);
+    }
+
+  dst[0] = gamma_2_2_to_linear (red);
+  dst[1] = gamma_2_2_to_linear (green);
+  dst[2] = gamma_2_2_to_linear (blue);
+}
+
+
+static long
+hsla_to_rgba (char *src,
+              char *dst,
+              long  samples)
+{
+  long n = samples;
+
+  while (n--)
+    {
+      double alpha = ((double *) src)[3];
+
+      hsl_to_rgb_step ((double *) src, (double *) dst);
+
+      ((double *) dst)[3] = alpha;
+
+      src += 4 * sizeof (double);
+      dst += 4 * sizeof (double);
+    }
+
+  return samples;
+}
+
+
+static long
+hsl_to_rgba (char *src,
+             char *dst,
+             long  samples)
+{
+  long n = samples;
+
+  while (n--)
+    {
+      hsl_to_rgb_step ((double *) src, (double *) dst);
+
+      ((double *) dst)[3] = 1.0;
+
+      src += 3 * sizeof (double);
+      dst += 4 * sizeof (double);
+    }
+
+  return samples;
+}
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index b657117..dca87c0 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -25,6 +25,7 @@ ext_LTLIBRARIES = \
        float.la        \
        fast-float.la   \
        naive-CMYK.la   \
+       HSL.la          \
        HSV.la          \
        simple.la       \
        sse2-float.la   \
@@ -41,6 +42,7 @@ gggl_la_SOURCES = gggl.c
 gimp_8bit_la_SOURCES = gimp-8bit.c
 grey_la_SOURCES = grey.c
 naive_CMYK_la_SOURCES = naive-CMYK.c
+HSL_la_SOURCES = HSL.c
 HSV_la_SOURCES = HSV.c
 sse2_float_la_SOURCES = sse2-float.c
 sse2_int8_la_SOURCES = sse2-int8.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3a38e51..5f7e5b2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -12,6 +12,7 @@ C_TESTS =                             \
        extract \
        floatclamp \
        float-to-8bit \
+       hsl    \
        hsva   \
        types                   \
        palette \
diff --git a/tests/hsl.c b/tests/hsl.c
new file mode 100644
index 0000000..4b24db2
--- /dev/null
+++ b/tests/hsl.c
@@ -0,0 +1,111 @@
+/* babl - dynamically extendable universal pixel conversion library.
+ *
+ * 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 <math.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "babl.h"
+
+#define CHECK_CONV(test_name, componenttype, src_fmt, dst_fmt, src_pix, expected_pix) \
+  {                                                                     \
+    const Babl *fish;                                                   \
+    int i;                                                              \
+    fish = babl_fish (src_fmt, dst_fmt);                                \
+    if (!fish)                                                          \
+      {                                                                 \
+        printf ("  %s failed to make fish\n", test_name);               \
+        OK = 0;                                                         \
+      }                                                                 \
+    for (i = 0; i < sizeof(src_pix)/sizeof(src_pix[0]); i ++)           \
+      {                                                                 \
+        int c;                                                          \
+        componenttype result[10];                                       \
+        babl_process (fish, src_pix[i], result, 1);                     \
+        for (c = 0; c < sizeof(expected_pix[i])/sizeof(expected_pix[i][0]); c++) \
+          if (fabs(result[c] - expected_pix[i][c]) > 0.001)             \
+            {                                                           \
+              printf (" %s failed #%i[%i]  got %lf expected %lf\n",     \
+                      test_name, i, c, result[c], expected_pix[i][c]);  \
+              OK = 0;                                                   \
+            }                                                           \
+      }                                                                 \
+  }
+
+
+int
+main (int    argc,
+      char **argv)
+{
+  int OK = 1;
+
+  float rgba[][4] = {{1.0     , 1.0     , 1.0     , 1.0},
+                     {0.214041, 0.214041, 0.214041, 1.0},
+                     {0.0     , 0.0     , 0.0     , 1.0},
+                     {1.0     , 0.0     , 0.0     , 1.0},
+                     {0.522519, 0.522519, 0.0     , 1.0},
+                     {0.0     , 0.214041, 0.0     , 1.0},
+                     {0.214041, 1.0     , 1.0     , 1.0},
+                     {0.214041, 0.214041, 1.0     , 1.0},
+                     {0.522520, 0.050876, 0.522521, 1.0},
+                     {0.353069, 0.372000, 0.017878, 1.0},
+                     {0.052772, 0.010679, 0.823194, 1.0},
+                     {0.012693, 0.414530, 0.052934, 1.0},
+                     {0.870621, 0.579515, 0.004228, 1.0},
+                     {0.453672, 0.029212, 0.781390, 1.0},
+                     {0.850554, 0.181933, 0.081839, 1.0},
+                     {0.995195, 0.941644, 0.244979, 1.0},
+                     {0.009836, 0.595745, 0.308242, 1.0},
+                     {0.036595, 0.019338, 0.315257, 1.0},
+                     {0.209470, 0.207646, 0.478434, 1.0}};
+
+  float hsla[][4] = {{0.0,       0.0  ,   1.0  , 1.0},
+                     {0.0,       0.0  ,   0.500, 1.0},
+                     {0.0,       0.0  ,   0.0  , 1.0},
+                     {0.0,       1.0  ,   0.500, 1.0},
+                     {0.166667,  1.0  ,   0.375, 1.0},
+                     {0.333333,  1.0  ,   0.250, 1.0},
+                     {0.5,       1.0  ,   0.750, 1.0},
+                     {0.666666,  1.0  ,   0.750, 1.0},
+                     {0.833333,  0.500,   0.500, 1.0},
+                     {0.171666,  0.638,   0.393, 1.0},
+                     {0.6975,    0.832,   0.511, 1.0},
+                     {0.374722,  0.707,   0.396, 1.0},
+                     {0.1375,    0.893,   0.497, 1.0},
+                     {0.788028,  0.775,   0.542, 1.0},
+                     {0.039837,  0.817,   0.624, 1.0},
+                     {0.158083,  0.991,   0.765, 1.0},
+                     {0.451149,  0.779,   0.447, 1.0},
+                     {0.689732,  0.601,   0.373, 1.0},
+                     {0.668129,  0.290,   0.607, 1.0}};
+
+  babl_init ();
+
+  CHECK_CONV ("rgba to hsla ", float,
+              babl_format ("RGBA float"),
+              babl_format ("HSLA float"),
+              rgba, hsla);
+
+  CHECK_CONV ("hsla to rgba ", float,
+              babl_format ("HSLA float"),
+              babl_format ("RGBA float"),
+              hsla, rgba);
+
+  babl_exit ();
+
+  return !OK;
+}


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