-
Øyvind "pippin" Kolås authored
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 */ } ```
a4d60784