[babl] babl: symmetric conversions between associated and separate alpha.



commit a4d607843d3cab18745d547fc8a46dec51dcea5e
Author: Øyvind Kolås <pippin gimp org>
Date:   Thu Jun 13 17:00:23 2019 +0200

    babl: symmetric conversions between associated and separate alpha.
    
    Provide symmetric, color data preserving conversions between associated and
    separate alpha for alpha values near and equal to 0.0 at single precision
    floating point. Thus these symmetric conversions also augment associated alpha
    to always maintain color information.
    
    This is achieved by clamping the alpha used when computing the color
    components when multiplying/dividing components between separate and
    associated alpha to BABL_ALPHA_FLOOR and -BABL_ALPHA_FLOOR for values
    near 0.0, the alpha value is copied unmodified between pixels; the main
    improvement of this commit.
    
    In the implementation BABL_ALPHA_FLOOR is 1/65536 = 0.00001526.. small
    enough that it vanishing in rounding for 16bit integer alpha but large
    enough to retain color data.
    
    The following table illustrates what corresponding values are between the
    two alpha encodings supported. We here usea BABL_ALPHA_FLOOR of 0.01 instead
    of 0.00001526 to make it easier to see what happens.
    
    ```
    "RGBA float"                     "RaGaBaA float"
    separate alpha                   associated alpha
    non-premultiplied                pre-multiplied alpha
    
        R       G      B      A         Ra     Ga     Ba     A
      10.000   1.000  0.100  0.000     0.100  0.010  0.001  0.000
      10.000   1.000  0.100  0.005     0.100  0.010  0.001  0.005
    __10.000___1.000__0.100__0.010_____0.100__0.010__0.001__0.010__
      10.000   1.000  0.100  0.020     0.200  0.020  0.002  0.020
      10.000   1.000  0.100  0.200     2.000  0.200  0.020  0.200
      10.000   1.000  0.100  0.400     4.000  0.400  0.040  0.400
    
    1000.000 100.000 10.000  0.000    10.000  1.000  0.100  0.000
    1000.000 100.000 10.000  0.005    10.000  1.000  0.100  0.005
    1000.000_100.000_10.000__0.010____10.000__1.000__0.100__0.010___
     500.000  50.000  5.000  0.020    10.000  1.000  0.100  0.020
      50.000   5.000  0.500  0.200    10.000  1.000  0.100  0.200
      25.000   2.500  0.250  0.400    10.000  1.000  0.100  0.400
    ```
    
    GEGL lets each operation compute with it's preferred encoding - for some
    operations like blurs this is associated alpha, for others like color
    adjustments it is separate alpha, perhaps even in CIE Lab based encodings
    rather than RGB. An earlier iteration of this approach was already in use in
    babl making un-erase mode and similar features in GIMP-2.10 work correctly
    after blurring, the previous implementation did not preserve the
    alpha value.
    
    Just the core of the implementation follows:
    
    ```
     #define BABL_ALPHA_FLOOR_F  (1.0f/65536.0f)
    
    static inline float
    babl_epsilon_for_zero_float (float value)
    {
     if (value <= BABL_ALPHA_FLOOR_F)
     {
       /* for performance one could directly retun BABL_ALPHA_FLOOR_F here
          and dropping handling negative values consistently. */
       if (value >= 0.0f)
         return BABL_ALPHA_FLOOR_F;
       else if (value >= -BABL_ALPHA_FLOOR_F)
         return -BABL_ALPHA_FLOOR_F;
     }
     return value;  /* most common case, return input value */
    }
    
    static inline void
    separate_to_associated_rgba (const float *separate_rgba,
                                       float *associated_rgba)
    {
      float alpha = babl_epsilon_for_zero_float (separate_rgba[3]);
    
      associated_rgba[0] = separate_rgba[0] * alpha;
      associated_rgba[1] = separate_rgba[1] * alpha;
      associated_rgba[2] = separate_rgba[2] * alpha;
      associated_rgba[3] = separate_rgba[3]; /* direct copy */
    }
    
    static inline void
    associated_to_separate_rgba (const float *associated_rgba,
                                       float *separate_rgba)
    {
      float alpha = babl_epsilon_for_zero_float (associated_rgba[3]);
      float reciprocal_alpha = 1.0f / alpha; /* the conditional normally in
                                                this conversion to avoid
                                                division by zero is handled by
                                                epsilon_for_zero */
      separate_rgba[0] = associated_rgba[0] * reciprocal_alpha;
      separate_rgba[1] = associated_rgba[1] * reciprocal_alpha;
      separate_rgba[2] = associated_rgba[2] * reciprocal_alpha;
    
      separate_rgba[3] = associated_rgba[3]; /* direct copy */
    }
    ```

 babl/babl.h                  |   3 +-
 babl/base/model-gray.c       | 188 ++++++++++---------------------------------
 babl/base/model-rgb.c        | 156 ++++++++---------------------------
 babl/base/util.h             |  45 +++++++++--
 extensions/double.c          |  14 +---
 extensions/fast-float.c      |  14 +---
 extensions/float.c           |  28 ++-----
 extensions/gegl-fixups.c     |  45 ++++-------
 extensions/sse2-float.c      |  59 +++++---------
 extensions/two-table.c       |  15 +---
 tests/Makefile.am            |   1 +
 tests/transparent_symmetry.c | 109 +++++++++++++++++++++++++
 12 files changed, 276 insertions(+), 401 deletions(-)
---
diff --git a/babl/babl.h b/babl/babl.h
index d5741d2..b4b9464 100644
--- a/babl/babl.h
+++ b/babl/babl.h
@@ -648,7 +648,8 @@ int babl_space_is_cmyk (const Babl *space);
  * it can also be used as a generic alpha zero epsilon in GEGL
  *
  */
-#define BABL_ALPHA_FLOOR (1/65536.0)
+#define BABL_ALPHA_FLOOR   (1/65536.0)
+#define BABL_ALPHA_FLOOR_F (1/65536.0f)
 
 #ifdef __cplusplus
 }
diff --git a/babl/base/model-gray.c b/babl/base/model-gray.c
index 37136d0..2031b22 100644
--- a/babl/base/model-gray.c
+++ b/babl/base/model-gray.c
@@ -467,16 +467,9 @@ gray_alpha_premultiplied_to_rgba (Babl  *conversion,
   while (n--)
     {
       double luminance = *(double *) src[0];
-      double alpha;
-      alpha = *(double *) src[1];
-      if (alpha == 0)
-        luminance = 0;
-      else
-      {
-        luminance = luminance / alpha;
-        if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-          alpha = 0.0;
-      }
+      double alpha = *(double *) src[1];
+      double used_alpha = babl_epsilon_for_zero (alpha);
+      luminance = luminance / used_alpha;
 
       *(double *) dst[0] = luminance;
       *(double *) dst[1] = luminance;
@@ -513,19 +506,13 @@ rgba_to_gray_alpha_premultiplied (Babl  *conversion,
       double blue  = *(double *) src[2];
       double luminance;
       double alpha = *(double *) src[3];
-      if (alpha <= BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-         else if (alpha >= -BABL_ALPHA_FLOOR)
-           alpha = -BABL_ALPHA_FLOOR;
-      }
+      double used_alpha = babl_epsilon_for_zero (alpha);
 
       luminance = red * RGB_LUMINANCE_RED +
                   green * RGB_LUMINANCE_GREEN +
                   blue * RGB_LUMINANCE_BLUE;
 
-      luminance *= alpha;
+      luminance *= used_alpha;
 
       *(double *) dst[0] = luminance;
       *(double *) dst[1] = alpha;
@@ -549,17 +536,11 @@ non_premultiplied_to_premultiplied (Babl  *conversion,
     {
       int    band;
       double alpha = *(double *) src[src_bands-1];
-      if (alpha < BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-        else if (alpha >= -BABL_ALPHA_FLOOR)
-          alpha = -BABL_ALPHA_FLOOR;
-      }
+      double used_alpha = babl_epsilon_for_zero (alpha);
 
       for (band = 0; band < src_bands - 1; band++)
         {
-          *(double *) dst[band] = *(double *) src[band] * alpha;
+          *(double *) dst[band] = *(double *) src[band] * used_alpha;
         }
       *(double *) dst[dst_bands - 1] = alpha;
 
@@ -582,18 +563,13 @@ premultiplied_to_non_premultiplied (Babl  *conversion,
   while (n--)
     {
       int    band;
-      double alpha;
-      alpha = *(double *) src[src_bands-1];
+      double alpha = *(double *) src[src_bands-1];
+      double used_alpha = babl_epsilon_for_zero (alpha);
 
       for (band = 0; band < src_bands - 1; band++)
         {
-          if (alpha == 0.0)
-            *(double *) dst[band] = 0;
-          else
-            *(double *) dst[band] = *(double *) src[band] / alpha;
+          *(double *) dst[band] = *(double *) src[band] / used_alpha;
         }
-      if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-        alpha = 0.0;
       *(double *) dst[dst_bands - 1] = alpha;
 
       BABL_PLANAR_STEP
@@ -622,20 +598,14 @@ rgba2gray_perceptual_premultiplied (Babl *conversion,
       double luminance;
       double luma;
       double alpha = ((double *) src)[3];
-      if (alpha < BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-        else if (alpha >= -BABL_ALPHA_FLOOR)
-          alpha = -BABL_ALPHA_FLOOR;
-      }
+      double used_alpha = babl_epsilon_for_zero (alpha);
 
       luminance = red * RGB_LUMINANCE_RED +
                   green * RGB_LUMINANCE_GREEN +
                   blue * RGB_LUMINANCE_BLUE;
       luma = babl_trc_from_linear (trc, luminance);
 
-      ((double *) dst)[0] = luma * alpha;
+      ((double *) dst)[0] = luma * used_alpha;
       ((double *) dst)[1] = alpha;
 
       src += 4 * sizeof (double);
@@ -663,20 +633,14 @@ rgba2gray_nonlinear_premultiplied (Babl *conversion,
       double luminance;
       double luma;
       double alpha = ((double *) src)[3];
-      if (alpha < BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-        else if (alpha >= -BABL_ALPHA_FLOOR)
-          alpha = -BABL_ALPHA_FLOOR;
-      }
+      double used_alpha = babl_epsilon_for_zero (alpha);
 
       luminance = red * RGB_LUMINANCE_RED +
                   green * RGB_LUMINANCE_GREEN +
                   blue * RGB_LUMINANCE_BLUE;
       luma = babl_trc_from_linear (trc, luminance);
 
-      ((double *) dst)[0] = luma * alpha;
+      ((double *) dst)[0] = luma * used_alpha;
       ((double *) dst)[1] = alpha;
 
       src += 4 * sizeof (double);
@@ -697,18 +661,12 @@ gray_perceptual_premultiplied2rgba (Babl *conversion,
     {
       double luma  = ((double *) src)[0];
       double luminance;
-      double alpha;
-      alpha = ((double *) src)[1];
-      if (alpha == 0.0)
-        luma = 0.0;
-      else
-        luma = luma / alpha;
+      double alpha = ((double *) src)[1];
+      double used_alpha = babl_epsilon_for_zero (alpha);
+      luma = luma / used_alpha;
 
       luminance = babl_trc_to_linear (trc, luma);
 
-      if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-        alpha = 0.0;
-
       ((double *) dst)[0] = luminance;
       ((double *) dst)[1] = luminance;
       ((double *) dst)[2] = luminance;
@@ -732,18 +690,11 @@ gray_nonlinear_premultiplied2rgba (Babl *conversion,
     {
       double luma  = ((double *) src)[0];
       double luminance;
-      double alpha;
-      alpha = ((double *) src)[1];
-      if (alpha == 0.0)
-        luma = 0.0;
-      else
-        luma = luma / alpha;
-
+      double alpha = ((double *) src)[1];
+      double used_alpha = babl_epsilon_for_zero (alpha);
+      luma = luma / used_alpha;
       luminance = babl_trc_to_linear (trc, luma);
 
-      if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-        alpha = 0.0;
-
       ((double *) dst)[0] = luminance;
       ((double *) dst)[1] = luminance;
       ((double *) dst)[2] = luminance;
@@ -1349,16 +1300,9 @@ gray_alpha_premultiplied_to_rgba_float (Babl  *conversion,
   while (n--)
     {
       float luminance = *(float *) src[0];
-      float alpha;
-      alpha = *(float *) src[1];
-      if (alpha == 0)
-        luminance = 0.0f;
-      else
-      {
-        luminance = luminance / alpha;
-        if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-          alpha = 0.0f;
-      }
+      float alpha = *(float *) src[1];
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
+      luminance = luminance / used_alpha;
 
       *(float *) dst[0] = luminance;
       *(float *) dst[1] = luminance;
@@ -1395,19 +1339,13 @@ rgba_to_gray_alpha_premultiplied_float (Babl  *conversion,
       float blue  = *(float *) src[2];
       float luminance;
       float alpha = *(float *) src[3];
-      if (alpha <= BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-         else if (alpha >= -BABL_ALPHA_FLOOR)
-           alpha = -BABL_ALPHA_FLOOR;
-      }
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
 
       luminance = red * RGB_LUMINANCE_RED +
                   green * RGB_LUMINANCE_GREEN +
                   blue * RGB_LUMINANCE_BLUE;
 
-      luminance *= alpha;
+      luminance *= used_alpha;
 
       *(float *) dst[0] = luminance;
       *(float *) dst[1] = alpha;
@@ -1431,27 +1369,11 @@ non_premultiplied_to_premultiplied_float (Babl  *conversion,
     {
       int    band;
       float alpha = *(float *) src[src_bands-1];
-      if (alpha < BABL_ALPHA_FLOOR)
-      {
-        int non_zero_components = 0;
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-        else if (alpha >= -BABL_ALPHA_FLOOR)
-          alpha = -BABL_ALPHA_FLOOR;
-
-        for (band = 0; band < src_bands - 1; band++)
-        {
-          if (*(float *) src[band] != 0.0f)
-            non_zero_components++;
-        }
-        if (non_zero_components)
-          alpha = 0.0f;
-
-      }
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
 
       for (band = 0; band < src_bands - 1; band++)
         {
-          *(float *) dst[band] = *(float *) src[band] * alpha;
+          *(float *) dst[band] = *(float *) src[band] * used_alpha;
         }
       *(float *) dst[dst_bands - 1] = alpha;
 
@@ -1474,18 +1396,13 @@ premultiplied_to_non_premultiplied_float (Babl  *conversion,
   while (n--)
     {
       int    band;
-      float alpha;
-      alpha = *(float *) src[src_bands-1];
+      float alpha = *(float *) src[src_bands-1];
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
 
       for (band = 0; band < src_bands - 1; band++)
         {
-          if (alpha == 0.0f)
-            *(float *) dst[band] = 0.0f;
-          else
-            *(float *) dst[band] = *(float *) src[band] / alpha;
+          *(float *) dst[band] = *(float *) src[band] / used_alpha;
         }
-      if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-        alpha = 0.0f;
       *(float *) dst[dst_bands - 1] = alpha;
 
       BABL_PLANAR_STEP
@@ -1512,20 +1429,14 @@ rgba2gray_nonlinear_premultiplied_float (Babl *conversion,
       float luminance;
       float luma;
       float alpha = ((float *) src)[3];
-      if (alpha < BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-        else if (alpha >= -BABL_ALPHA_FLOOR)
-          alpha = -BABL_ALPHA_FLOOR;
-      }
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
 
       luminance = red * RGB_LUMINANCE_RED +
                   green * RGB_LUMINANCE_GREEN +
                   blue * RGB_LUMINANCE_BLUE;
       luma = babl_trc_from_linear (trc, luminance);
 
-      ((float *) dst)[0] = luma * alpha;
+      ((float *) dst)[0] = luma * used_alpha;
       ((float *) dst)[1] = alpha;
 
       src += 4 * sizeof (float);
@@ -1546,18 +1457,12 @@ gray_nonlinear_premultiplied2rgba_float (Babl *conversion,
     {
       float luma  = ((float *) src)[0];
       float luminance;
-      float alpha;
-      alpha = ((float *) src)[1];
-      if (alpha == 0.0f)
-        luma = 0.0f;
-      else
-        luma = luma / alpha;
+      float alpha = ((float *) src)[1];
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
 
+      luma = luma / used_alpha;
       luminance = babl_trc_to_linear (trc, luma);
 
-      if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-        alpha = 0.0f;
-
       ((float *) dst)[0] = luminance;
       ((float *) dst)[1] = luminance;
       ((float *) dst)[2] = luminance;
@@ -1588,20 +1493,14 @@ rgba2gray_perceptual_premultiplied_float (Babl *conversion,
       float luminance;
       float luma;
       float alpha = ((float *) src)[3];
-      if (alpha < BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-        else if (alpha >= -BABL_ALPHA_FLOOR)
-          alpha = -BABL_ALPHA_FLOOR;
-      }
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
 
       luminance = red * RGB_LUMINANCE_RED +
                   green * RGB_LUMINANCE_GREEN +
                   blue * RGB_LUMINANCE_BLUE;
       luma = babl_trc_from_linear (trc, luminance);
 
-      ((float *) dst)[0] = luma * alpha;
+      ((float *) dst)[0] = luma * used_alpha;
       ((float *) dst)[1] = alpha;
 
       src += 4 * sizeof (float);
@@ -1621,17 +1520,12 @@ gray_perceptual_premultiplied2rgba_float (Babl *conversion,
     {
       float luma  = ((float *) src)[0];
       float luminance;
-      float alpha;
-      alpha = ((float *) src)[1];
-      if (alpha == 0.0f)
-        luma = 0.0f;
-      else
-        luma = luma / alpha;
+      float alpha = ((float *) src)[1];
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
 
-      luminance = babl_trc_to_linear (trc, luma);
+      luma = luma / used_alpha;
 
-      if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-        alpha = 0.0f;
+      luminance = babl_trc_to_linear (trc, luma);
 
       ((float *) dst)[0] = luminance;
       ((float *) dst)[1] = luminance;
diff --git a/babl/base/model-rgb.c b/babl/base/model-rgb.c
index a89117c..cdf628e 100644
--- a/babl/base/model-rgb.c
+++ b/babl/base/model-rgb.c
@@ -334,8 +334,6 @@ g3_nonlinear_to_linear (Babl  *conversion,
 }
 
 
-
-
 static void
 non_premultiplied_to_premultiplied (Babl  *conversion,
                                     int    src_bands,
@@ -354,17 +352,11 @@ non_premultiplied_to_premultiplied (Babl  *conversion,
       double alpha = *(double *) src[src_bands - 1];
       int    band;
 
-      if (alpha < BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0)
-          alpha = BABL_ALPHA_FLOOR;
-        else if (alpha >= -BABL_ALPHA_FLOOR)
-          alpha = -BABL_ALPHA_FLOOR;
-      }
+      double used_alpha = babl_epsilon_for_zero (alpha);
 
       for (band = 0; band < src_bands - 1; band++)
         {
-          *(double *) dst[band] = *(double *) src[band] * alpha;
+          *(double *) dst[band] = *(double *) src[band] * used_alpha;
         }
       *(double *) dst[dst_bands - 1] = alpha;
 
@@ -390,19 +382,10 @@ premultiplied_to_non_premultiplied (Babl  *conversion,
   BABL_PLANAR_SANITY
   while (n--)
     {
-      double alpha;
-      double recip_alpha;
+      double alpha = *(double *) src[src_bands - 1];
       int    band;
-
-      alpha = *(double *) src[src_bands - 1];
-      if (alpha == 0.0)
-         recip_alpha = 0.0;
-      else
-      {
-        recip_alpha  = 1.0 / alpha;
-        if (alpha == BABL_ALPHA_FLOOR)
-          alpha = 0.0; // making 0 round-trip to zero, causing discontinuity
-      }
+      double used_alpha = babl_epsilon_for_zero (alpha);
+      double recip_alpha = 1.0 / used_alpha;
 
       for (band = 0; band < src_bands - 1; band++)
         *(double *) dst[band] = *(double *) src[band] * recip_alpha;
@@ -426,17 +409,11 @@ rgba2rgba_nonlinear_premultiplied (Babl *conversion,
   while (n--)
     {
       double alpha = ((double *) src)[3];
-      if (alpha <= BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-           alpha = BABL_ALPHA_FLOOR;
-         else if (alpha >= -BABL_ALPHA_FLOOR)
-           alpha = -BABL_ALPHA_FLOOR;
-      }
-
-      ((double *) dst)[0] = babl_trc_from_linear (trc[0], ((double *) src)[0]) * alpha;
-      ((double *) dst)[1] = babl_trc_from_linear (trc[1], ((double *) src)[1]) * alpha;
-      ((double *) dst)[2] = babl_trc_from_linear (trc[2], ((double *) src)[2]) * alpha;
+      double used_alpha = babl_epsilon_for_zero (alpha);
+
+      ((double *) dst)[0] = babl_trc_from_linear (trc[0], ((double *) src)[0]) * used_alpha;
+      ((double *) dst)[1] = babl_trc_from_linear (trc[1], ((double *) src)[1]) * used_alpha;
+      ((double *) dst)[2] = babl_trc_from_linear (trc[2], ((double *) src)[2]) * used_alpha;
       ((double *) dst)[3] = alpha;
       src                += 4 * sizeof (double);
       dst                += 4 * sizeof (double);
@@ -458,18 +435,9 @@ rgba_nonlinear_premultiplied2rgba (Babl *conversion,
 
   while (n--)
     {
-      double alpha, reciprocal;
-      alpha = ((double *) src)[3];
-      if (alpha == 0.0)
-      {
-        reciprocal= 0.0f;
-      }
-      else
-      {
-        reciprocal= 1.0 / alpha;
-        if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-          alpha = 0;
-      }
+      double alpha      = ((double *) src)[3];
+      double used_alpha = babl_epsilon_for_zero (alpha);
+      double reciprocal = 1.0 / used_alpha;
 
       ((double *) dst)[0] = babl_trc_to_linear (trc[0], ((double *) src)[0] * reciprocal);
       ((double *) dst)[1] = babl_trc_to_linear (trc[1], ((double *) src)[1] * reciprocal);
@@ -604,18 +572,11 @@ rgba2rgba_perceptual_premultiplied (Babl *conversion,
   while (n--)
     {
       double alpha = ((double *) src)[3];
+      double used_alpha = babl_epsilon_for_zero (alpha);
 
-      if (alpha <= BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-        else if (alpha >= -BABL_ALPHA_FLOOR)
-           alpha = -BABL_ALPHA_FLOOR;
-      }
-
-      ((double *) dst)[0] = babl_trc_from_linear (trc, ((double *) src)[0]) * alpha;
-      ((double *) dst)[1] = babl_trc_from_linear (trc, ((double *) src)[1]) * alpha;
-      ((double *) dst)[2] = babl_trc_from_linear (trc, ((double *) src)[2]) * alpha;
+      ((double *) dst)[0] = babl_trc_from_linear (trc, ((double *) src)[0]) * used_alpha;
+      ((double *) dst)[1] = babl_trc_from_linear (trc, ((double *) src)[1]) * used_alpha;
+      ((double *) dst)[2] = babl_trc_from_linear (trc, ((double *) src)[2]) * used_alpha;
       ((double *) dst)[3] = alpha;
       src                += 4 * sizeof (double);
       dst                += 4 * sizeof (double);
@@ -634,18 +595,10 @@ rgba_perceptual_premultiplied2rgba (Babl *conversion,
 
   while (n--)
     {
-      double alpha, reciprocal;
-      alpha = ((double *) src)[3];
-      if (alpha == 0)
-      {
-        reciprocal = 0.0;
-      }
-      else
-      {
-         reciprocal = 1.0/alpha;
-         if(alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-           alpha = 0.0;
-      }
+      double alpha = ((double *) src)[3];
+      double used_alpha = babl_epsilon_for_zero (alpha);
+      double reciprocal = 1.0/used_alpha;
+
       ((double *) dst)[0] = babl_trc_to_linear (trc, ((double *) src)[0] * reciprocal);
       ((double *) dst)[1] = babl_trc_to_linear (trc, ((double *) src)[1] * reciprocal);
       ((double *) dst)[2] = babl_trc_to_linear (trc, ((double *) src)[2] * reciprocal);
@@ -1195,25 +1148,12 @@ non_premultiplied_to_premultiplied_float (Babl  *conversion,
   while (n--)
     {
       float alpha = *(float *) src[src_bands - 1];
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
       int    band;
 
-      if (alpha < BABL_ALPHA_FLOOR)
-      {
-        int non_zero_components = 0;
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-        else if (alpha >= -BABL_ALPHA_FLOOR)
-          alpha = -BABL_ALPHA_FLOOR;
-        for (band = 0 ; band< src_bands-1; band++)
-          if (*(float *) src[band] != 0.0f)
-            non_zero_components++;
-        if (non_zero_components == 0)
-          alpha = 0.0f;
-      }
-
       for (band = 0; band < src_bands - 1; band++)
         {
-          *(float *) dst[band] = *(float *) src[band] * alpha;
+          *(float *) dst[band] = *(float *) src[band] * used_alpha;
         }
       *(float *) dst[dst_bands - 1] = alpha;
 
@@ -1237,19 +1177,10 @@ premultiplied_to_non_premultiplied_float (Babl  *conversion,
   BABL_PLANAR_SANITY
   while (n--)
     {
-      float alpha;
-      float recip_alpha;
       int    band;
-
-      alpha = *(float *) src[src_bands - 1];
-      if (alpha == 0.0f)
-         recip_alpha = 0.0f;
-      else
-      {
-        recip_alpha  = 1.0f / alpha;
-        if (alpha == BABL_ALPHA_FLOOR)
-          alpha = 0.0f; // making 0 round-trip to zero, causing discontinuity
-      }
+      float alpha = *(float *) src[src_bands - 1];
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
+      float recip_alpha  = 1.0f / used_alpha;
 
       for (band = 0; band < src_bands - 1; band++)
         *(float *) dst[band] = *(float *) src[band] * recip_alpha;
@@ -1273,21 +1204,11 @@ rgba2rgba_nonlinear_premultiplied_float (Babl *conversion,
   while (n--)
     {
       float alpha = ((float *) src)[3];
-      if (alpha <= BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-           alpha = BABL_ALPHA_FLOOR;
-         else if (alpha >= -BABL_ALPHA_FLOOR)
-           alpha = -BABL_ALPHA_FLOOR;
-        if (((float *) src)[0] == 0.0 &&
-            ((float *) src)[1] == 0.0 &&
-            ((float *) src)[2] == 0.0)
-           alpha = 0.0;
-      }
-
-      ((float *) dst)[0] = babl_trc_from_linear (trc[0], ((float *) src)[0]) * alpha;
-      ((float *) dst)[1] = babl_trc_from_linear (trc[1], ((float *) src)[1]) * alpha;
-      ((float *) dst)[2] = babl_trc_from_linear (trc[2], ((float *) src)[2]) * alpha;
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
+
+      ((float *) dst)[0] = babl_trc_from_linear (trc[0], ((float *) src)[0]) * used_alpha;
+      ((float *) dst)[1] = babl_trc_from_linear (trc[1], ((float *) src)[1]) * used_alpha;
+      ((float *) dst)[2] = babl_trc_from_linear (trc[2], ((float *) src)[2]) * used_alpha;
       ((float *) dst)[3] = alpha;
       src  += 4 * sizeof (float);
       dst  += 4 * sizeof (float);
@@ -1307,18 +1228,9 @@ rgba_nonlinear_premultiplied2rgba_float (Babl *conversion,
 
   while (n--)
     {
-      float alpha, reciprocal;
-      alpha = ((float *) src)[3];
-      if (alpha == 0.0)
-      {
-        reciprocal= 0.0f;
-      }
-      else
-      {
-        reciprocal= 1.0 / alpha;
-        if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-          alpha = 0;
-      }
+      float alpha = ((float *) src)[3];
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
+      float reciprocal= 1.0f / used_alpha;
 
       ((float *) dst)[0] = babl_trc_to_linear (trc[0], ((float *) src)[0] * reciprocal);
       ((float *) dst)[1] = babl_trc_to_linear (trc[1], ((float *) src)[1] * reciprocal);
diff --git a/babl/base/util.h b/babl/base/util.h
index b16840e..123e556 100644
--- a/babl/base/util.h
+++ b/babl/base/util.h
@@ -22,13 +22,7 @@
 #include <assert.h>
 #include <math.h>
 #include "pow-24.h"
-
-/* Alpha threshold used in the reference implementation for
- * un-pre-multiplication of color data, deprecated in favor of the following
- *
- * 0.01 / (2^16 - 1)
- */
-#define BABL_ALPHA_THRESHOLD 0.000000152590219
+#include <babl.h>
 
 
 #define BABL_PLANAR_SANITY  \
@@ -53,6 +47,43 @@
   }
 
 
+#if 1
+
+static inline double
+babl_epsilon_for_zero (double value)
+{
+ if (value <= BABL_ALPHA_FLOOR)
+ {
+   if (value >= 0.0)
+     return BABL_ALPHA_FLOOR;
+   else if (value >= -BABL_ALPHA_FLOOR)
+     return -BABL_ALPHA_FLOOR;
+ }
+ return value;
+}
+
+static inline float
+babl_epsilon_for_zero_float (float value)
+{
+ if (value <= BABL_ALPHA_FLOOR_F)
+ {
+   if (value >= 0.0f)
+     return BABL_ALPHA_FLOOR_F;
+   else if (value >= -BABL_ALPHA_FLOOR_F)
+     return -BABL_ALPHA_FLOOR_F;
+ }
+ return value;
+}
+
+#else
+
+#define babl_alpha_avoid_zero(a) \
+  (a)<=BABL_ALPHA_FLOOR?(a)>=0.0?BABL_ALPHA_FLOOR:(a)>=-BABL_ALPHA_FLOOR?-BABL_ALPHA_FLOOR:(a):(a)
+
+#endif
+
+
+
 #define BABL_USE_SRGB_GAMMA
 
 #ifdef BABL_USE_SRGB_GAMMA
diff --git a/extensions/double.c b/extensions/double.c
index 07f533b..fe29cd9 100644
--- a/extensions/double.c
+++ b/extensions/double.c
@@ -43,16 +43,10 @@ conv_rgbaD_linear_rgbAD_gamma (const Babl    *conversion,
    while (n--)
      {
        double alpha = fsrc[3];
-       if (alpha <= BABL_ALPHA_FLOOR)
-       {
-         if (alpha >= 0.0f)
-           alpha = BABL_ALPHA_FLOOR;
-         else if (alpha >= -BABL_ALPHA_FLOOR)
-           alpha = -BABL_ALPHA_FLOOR;
-       }
-       *fdst++ = babl_trc_from_linear (trc[0], *fsrc++) * alpha;
-       *fdst++ = babl_trc_from_linear (trc[1], *fsrc++) * alpha;
-       *fdst++ = babl_trc_from_linear (trc[2], *fsrc++) * alpha;
+       double used_alpha = babl_epsilon_for_zero (alpha);
+       *fdst++ = babl_trc_from_linear (trc[0], *fsrc++) * used_alpha;
+       *fdst++ = babl_trc_from_linear (trc[1], *fsrc++) * used_alpha;
+       *fdst++ = babl_trc_from_linear (trc[2], *fsrc++) * used_alpha;
        *fdst++ = alpha;
        fsrc++;
      }
diff --git a/extensions/fast-float.c b/extensions/fast-float.c
index 965a9eb..8730046 100644
--- a/extensions/fast-float.c
+++ b/extensions/fast-float.c
@@ -310,16 +310,10 @@ conv_rgbaF_linear_rgbAF_gamma (const Babl    *conversion,
        }
        else
        {
-         if (alpha < BABL_ALPHA_FLOOR)
-         {
-           if (alpha >= 0.0f)
-             alpha = BABL_ALPHA_FLOOR;
-           else if (alpha >= -BABL_ALPHA_FLOOR)
-             alpha = -BABL_ALPHA_FLOOR;
-         }
-         *fdst++ = linear_to_gamma_2_2_lut (red)   * alpha;
-         *fdst++ = linear_to_gamma_2_2_lut (green) * alpha;
-         *fdst++ = linear_to_gamma_2_2_lut (blue)  * alpha;
+         float used_alpha = babl_epsilon_for_zero_float (alpha);
+         *fdst++ = linear_to_gamma_2_2_lut (red)   * used_alpha;
+         *fdst++ = linear_to_gamma_2_2_lut (green) * used_alpha;
+         *fdst++ = linear_to_gamma_2_2_lut (blue)  * used_alpha;
          *fdst++ = alpha;
        }
      }
diff --git a/extensions/float.c b/extensions/float.c
index f688e66..b25870f 100644
--- a/extensions/float.c
+++ b/extensions/float.c
@@ -44,16 +44,10 @@ conv_rgbaF_linear_rgbAF_nonlinear (const Babl    *conversion,
    while (n--)
      {
        float alpha = fsrc[3];
-       if (alpha < BABL_ALPHA_FLOOR)
-       {
-         if (alpha >= 0.0f)
-           alpha = BABL_ALPHA_FLOOR;
-         else if (alpha >= -BABL_ALPHA_FLOOR)
-           alpha = -BABL_ALPHA_FLOOR;
-       }
-       *fdst++ = babl_trc_from_linear (trc[0], *fsrc++) * alpha;
-       *fdst++ = babl_trc_from_linear (trc[1], *fsrc++) * alpha;
-       *fdst++ = babl_trc_from_linear (trc[2], *fsrc++) * alpha;
+       float used_alpha = babl_alpha_avoid_zero (alpha);
+       *fdst++ = babl_trc_from_linear (trc[0], *fsrc++) * used_alpha;
+       *fdst++ = babl_trc_from_linear (trc[1], *fsrc++) * used_alpha;
+       *fdst++ = babl_trc_from_linear (trc[2], *fsrc++) * used_alpha;
        *fdst++ = alpha;
        fsrc++;
      }
@@ -72,16 +66,10 @@ conv_rgbaF_linear_rgbAF_perceptual (const Babl    *conversion,
    while (n--)
      {
        float alpha = fsrc[3];
-       if (alpha < BABL_ALPHA_FLOOR)
-       {
-         if (alpha >= 0.0f)
-           alpha = BABL_ALPHA_FLOOR;
-         else if (alpha >= -BABL_ALPHA_FLOOR)
-           alpha = -BABL_ALPHA_FLOOR;
-       }
-       *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++) * alpha;
-       *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++) * alpha;
-       *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++) * alpha;
+       float used_alpha = babl_alpha_avoid_zero (alpha);
+       *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++) * used_alpha;
+       *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++) * used_alpha;
+       *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++) * used_alpha;
        *fdst++ = alpha;
        fsrc++;
      }
diff --git a/extensions/gegl-fixups.c b/extensions/gegl-fixups.c
index 38a0cf5..e38d73f 100644
--- a/extensions/gegl-fixups.c
+++ b/extensions/gegl-fixups.c
@@ -410,16 +410,10 @@ conv_rgbaF_rgbAF (const Babl    *conversion,
   while (n--)
     {
       float alpha = src[3];
-      if (alpha < BABL_ALPHA_FLOOR)
-      {
-        if (alpha >= 0.0f)
-          alpha = BABL_ALPHA_FLOOR;
-        else if (alpha >= -BABL_ALPHA_FLOOR)
-          alpha = -BABL_ALPHA_FLOOR;
-      }
-      dst[0] = src[0] * alpha;
-      dst[1] = src[1] * alpha;
-      dst[2] = src[2] * alpha;
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
+      dst[0] = src[0] * used_alpha;
+      dst[1] = src[1] * used_alpha;
+      dst[2] = src[2] * used_alpha;
       dst[3] = alpha;
       src   += 4;
       dst   += 4;
@@ -439,17 +433,13 @@ conv_rgbAF_rgbaF (const Babl    *conversion,
   while (n--)
     {
       float alpha = src[3];
-      float recip;
-      if (alpha == 0.0f)
-        recip = 0.0f;
-      else
-        recip = 1.0f/alpha;
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
+      float recip = 1.0f/used_alpha;
 
       dst[0] = src[0] * recip;
       dst[1] = src[1] * recip;
       dst[2] = src[2] * recip;
-      if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-        alpha = 0.0f;
+
       dst[3] = alpha;
       src   += 4;
       dst   += 4;
@@ -470,20 +460,13 @@ conv_rgbAF_lrgba8 (const Babl    *conversion,
   while (n--)
     {
       float alpha = src[3];
-      if (alpha == 0.0f)
-        {
-          dst[0] = dst[1] = dst[2] = dst[3] = 0;
-        }
-      else
-        {
-          float recip = (1.0/alpha);
-          if (alpha == BABL_ALPHA_FLOOR || alpha == -BABL_ALPHA_FLOOR)
-            alpha = 0.0f;
-          dst[0] = table_F_8[gggl_float_to_index16 (src[0] * recip)];
-          dst[1] = table_F_8[gggl_float_to_index16 (src[1] * recip)];
-          dst[2] = table_F_8[gggl_float_to_index16 (src[2] * recip)];
-          dst[3] = table_F_8[gggl_float_to_index16 (alpha)];
-        }
+      float used_alpha = babl_epsilon_for_zero_float (alpha);
+      float recip = (1.0f/used_alpha);
+
+      dst[0] = table_F_8[gggl_float_to_index16 (src[0] * recip)];
+      dst[1] = table_F_8[gggl_float_to_index16 (src[1] * recip)];
+      dst[2] = table_F_8[gggl_float_to_index16 (src[2] * recip)];
+      dst[3] = table_F_8[gggl_float_to_index16 (alpha)];
       src   += 4;
       dst   += 4;
     }
diff --git a/extensions/sse2-float.c b/extensions/sse2-float.c
index e12fb9a..6acec08 100644
--- a/extensions/sse2-float.c
+++ b/extensions/sse2-float.c
@@ -35,12 +35,12 @@
 
 #define Q(a) { a, a, a, a }
 
-static const float BABL_ALPHA_THRESHOLD_FLOAT = (float)BABL_ALPHA_THRESHOLD;
+static const float BABL_ALPHA_FLOOR_FLOAT = (float)BABL_ALPHA_FLOOR;
 
 static void
 conv_rgbaF_linear_rgbAF_linear (const Babl  *conversion,
-                                const float *src,  
-                                float       *dst, 
+                                const float *src,
+                                float       *dst,
                                 long         samples)
 {
   long i = 0;
@@ -56,21 +56,9 @@ conv_rgbaF_linear_rgbAF_linear (const Babl  *conversion,
         {
           float alpha0 = ((float *)s)[3];
           float alpha1 = ((float *)s)[7];
+          float used_alpha0 = babl_epsilon_for_zero_float (alpha0);
+          float used_alpha1 = babl_epsilon_for_zero_float (alpha1);
 
-          if (alpha0 < BABL_ALPHA_FLOOR)
-          {
-            if (alpha0 >= 0.0f)
-              alpha0 = BABL_ALPHA_FLOOR;
-            else
-              alpha0 = -BABL_ALPHA_FLOOR;
-          }
-          if (alpha1 < BABL_ALPHA_FLOOR)
-          {
-            if (alpha1 >= 0.0f)
-              alpha1 = BABL_ALPHA_FLOOR;
-            else
-              alpha1 = -BABL_ALPHA_FLOOR;
-          }
          {
           __v4sf rbaa0, rbaa1;
         
@@ -79,13 +67,16 @@ conv_rgbaF_linear_rgbAF_linear (const Babl  *conversion,
 
 
           /* Expand alpha */
-          __v4sf aaaa0 = (__v4sf)_mm_set1_ps(alpha0);
-          __v4sf aaaa1 = (__v4sf)_mm_set1_ps(alpha1);
+          __v4sf aaaa0 = (__v4sf)_mm_set1_ps(used_alpha0);
+          __v4sf aaaa1 = (__v4sf)_mm_set1_ps(used_alpha1);
           
           /* Premultiply */
           rgba0 = rgba0 * aaaa0;
           rgba1 = rgba1 * aaaa1;
-          
+    
+          aaaa0 = (__v4sf)_mm_set1_ps(alpha0);
+          aaaa1 = (__v4sf)_mm_set1_ps(alpha1);
+
           /* Shuffle the original alpha value back in */
           rbaa0 = _mm_shuffle_ps(rgba0, aaaa0, _MM_SHUFFLE(0, 0, 2, 0));
           rbaa1 = _mm_shuffle_ps(rgba1, aaaa1, _MM_SHUFFLE(0, 0, 2, 0));
@@ -106,16 +97,10 @@ conv_rgbaF_linear_rgbAF_linear (const Babl  *conversion,
   while (remainder--)
   {
     float a = src[3];
-    if (a <= BABL_ALPHA_FLOOR)
-    {
-      if (a >= 0.0f)
-        a = BABL_ALPHA_FLOOR;
-      else if (a >= -BABL_ALPHA_FLOOR)
-        a = -BABL_ALPHA_FLOOR;
-    }
-    dst[0] = src[0] * a;
-    dst[1] = src[1] * a;
-    dst[2] = src[2] * a;
+    float used_alpha = babl_epsilon_for_zero_float (a);
+    dst[0] = src[0] * used_alpha;
+    dst[1] = src[1] * used_alpha;
+    dst[2] = src[2] * used_alpha;
     dst[3] = a;
     
     src += 4;
@@ -143,16 +128,11 @@ conv_rgbAF_linear_rgbaF_linear_shuffle (const Babl  *conversion,
           __v4sf pre_rgba0, rgba0, rbaa0, raaaa0;
           
           float alpha0 = ((float *)s)[3];
+          float used_alpha0 = babl_epsilon_for_zero_float (alpha0);
           pre_rgba0 = *s;
           
-          if (alpha0 == 0.0f)
           {
-            /* Zero RGB */
-            rgba0 = _mm_setzero_ps();
-          }
-          else
-          {
-            float recip0 = 1.0f/alpha0;
+            float recip0 = 1.0f/used_alpha0;
             
             /* Expand reciprocal */
             raaaa0 = _mm_load1_ps(&recip0);
@@ -165,9 +145,6 @@ conv_rgbAF_linear_rgbaF_linear_shuffle (const Babl  *conversion,
           rbaa0 = _mm_shuffle_ps(rgba0, pre_rgba0, _MM_SHUFFLE(3, 3, 2, 0));
           rgba0 = _mm_shuffle_ps(rgba0, rbaa0, _MM_SHUFFLE(2, 1, 1, 0));
 
-          if (alpha0 == BABL_ALPHA_FLOOR || alpha0 == -BABL_ALPHA_FLOOR)
-            ((float *)d)[3] = 0.0f;
-
           s++;
           *d++ = rgba0;
         }
@@ -209,7 +186,7 @@ conv_rgbAF_linear_rgbaF_linear_spin (const Babl  *conversion,
       const long    n = samples;
       const __v4sf *s = (const __v4sf*) src;
             __v4sf *d = (__v4sf*)dst;
-      const __v4sf zero = _mm_set_ss (BABL_ALPHA_THRESHOLD_FLOAT);
+      const __v4sf zero = _mm_set_ss (BABL_ALPHA_FLOOR_FLOAT);
       const __v4sf one = _mm_set_ss(1.0f);
 
       for ( ; i < n; i += 1)
diff --git a/extensions/two-table.c b/extensions/two-table.c
index 292a88a..efdfa70 100644
--- a/extensions/two-table.c
+++ b/extensions/two-table.c
@@ -92,18 +92,9 @@ conv_rgbafloat_linear_rgbu8_gamma (const Babl    *conversion,
 
   while (n--)
     {
-      if (src[3] <= BABL_ALPHA_FLOOR)
-        {
-          dst[0] = 0;
-          dst[1] = 0;
-          dst[2] = 0;
-        }
-      else
-        {
-          dst[0] = conv_float_u8_two_table_map (src[0]);
-          dst[1] = conv_float_u8_two_table_map (src[1]);
-          dst[2] = conv_float_u8_two_table_map (src[2]);
-        }
+      dst[0] = conv_float_u8_two_table_map (src[0]);
+      dst[1] = conv_float_u8_two_table_map (src[1]);
+      dst[2] = conv_float_u8_two_table_map (src[2]);
       src += 4;
       dst += 3;
     }
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e81fd62..918851a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -27,6 +27,7 @@ C_TESTS =                             \
        models                  \
        cairo-RGB24             \
        transparent             \
+       transparent_symmetry    \
        $(CONCURRENCY_STRESS_TESTS)
 
 TESTS = \
diff --git a/tests/transparent_symmetry.c b/tests/transparent_symmetry.c
new file mode 100644
index 0000000..90a0974
--- /dev/null
+++ b/tests/transparent_symmetry.c
@@ -0,0 +1,109 @@
+/* babl - dynamically extendable universal pixel conversion library.
+ * Copyright (C) 2005, 2017 Ø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
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include <math.h>
+#include "babl-internal.h"
+
+#define TOLERANCE    0.000001
+#define PIXELS       10
+
+float source_buf [PIXELS * 4] =
+{ 10.0, 1.0, 0.1, 1.0,
+  10.0, 1.0, 0.1, 0.5,
+  10.0, 1.0, 0.1, 0.1,
+  10.0, 1.0, 0.1, 0.01,
+  10.0, 1.0, 0.1, -0.01,
+  10.0, 1.0, 0.1, 1.5,
+  10.0, 1.0, 0.0001, 0.000001,
+  10.0, 1.0, 0.1, -0.00001,
+  10.0, 1.0, 0.1, 0.0,
+  10.0, 1.0, 0.1, -0.5,
+};
+
+float bounce_buf [PIXELS * 4];
+float destination_buf [PIXELS * 4];
+
+static int
+test (void)
+{
+  int i;
+  int OK = 1;
+
+  babl_process (babl_fish ("RGBA float", "RaGaBaA float"),
+                source_buf, bounce_buf,
+                PIXELS);
+  babl_process (babl_fish ("RaGaBaA float", "RGBA float"),
+                bounce_buf, destination_buf,
+                PIXELS);
+
+  for (i = 0; i < PIXELS; i++)
+    {
+      for (int c = 0; c < 4; c++)
+      {
+      if (fabs (destination_buf[i*4+c] - source_buf[i*4+c]) > TOLERANCE)
+        {
+          babl_log ("separate alpha %i.%i: %.9f!=%.9f(ref)  ", i, c, destination_buf[i*4+c],
+                                                  source_buf[i*4+c]);
+          OK = 0;
+        }
+     //   fprintf (stdout, "%.19f ", destination_buf[i*4+c]);
+      }
+    //  fprintf (stdout, "\n");
+    }
+
+  fprintf (stdout, "\n");
+
+  babl_process (babl_fish ("RaGaBaA float", "RGBA float"),
+                source_buf, bounce_buf,
+                PIXELS);
+  babl_process (babl_fish ("RGBA float", "RaGaBaA float"),
+                bounce_buf, destination_buf,
+                PIXELS);
+
+  for (i = 0; i < PIXELS; i++)
+    {
+      for (int c = 0; c < 4; c++)
+      {
+      if (fabs (destination_buf[i*4+c] - source_buf[i*4+c]) > TOLERANCE)
+        {
+          babl_log ("associatd-alpha %i.%i: %.9f!=%.9f(ref)  ", i, c, destination_buf[i*4+c],
+                                                  source_buf[i*4+c]);
+          OK = 0;
+        }
+      //  fprintf (stdout, "%.19f ", destination_buf[i*4+c]);
+      }
+    //  fprintf (stdout, "\n");
+    }
+
+
+  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]