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 */
}
```
parent e396e75b
Pipeline #88081 failed with stage
in 7 minutes
......@@ -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
}
......
......@@ -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;
......
......@@ -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);
......
......@@ -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
......
......@@ -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++;
}
......
......@@ -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);