# Re: color space conversions and alpha compositing

• From: Alex Danilo <alex@abbra.com>
• Date: Fri, 18 Feb 2011 16:23:56 +1100
• To: Cameron McCormack <cam@mcc.id.au>
• Message-Id: <WBSSGL.4I9BC2E4H6F1@abbra.com>
```Hi Cam,

I think you got the equations for linearRGB->sRGB wrong
by the look of things (good ol' Wikipedia...)

--Original Message--:
>I am reviewing my test painting-render-02-b.svg for correctness.  The
>test involves alpha compositing when color-interpolation="linearRGB".
>
>I will run through a worked example here, and hopefully someone can tell
>me if I am doing it right.
>
>Let’s perform alpha compositing where the background pixel is (0,0,0,1),
>opaque black, and the foreground pixel to be composited into the
>background is (1,1,1,0.5), half opaque white.  (I’m using component
>values in the range [0, 1].)
>
>For the sRGB ↔ linearRGB conversions I’m using the formulae on
>http://en.wikipedia.org/wiki/SRGB#Specification_of_the_transformation:
>
>  R_s = R_linear ≤ 0.0031308 ? 12.92 * R_linear
>                             : min(1.055 * pow(R_linear, 1 / 2.4), 1)
>  G_s = G_linear ≤ 0.0031308 ? 12.92 * G_linear
>                             : min(1.055 * pow(G_linear, 1 / 2.4), 1)
>  B_s = B_linear ≤ 0.0031308 ? 12.92 * B_linear
>                             : min(1.055 * pow(B_linear, 1 / 2.4), 1)
>  A_s = A_linear

These terms should have a '- 0.055' for the larger value case.

>and
>
>  R_linear = R_s ≤ 0.04045 ? R_s / 12.92
>                           : pow((R_s + 0.055) / 1.055, 2.4)
>  G_linear = G_s ≤ 0.04045 ? R_s / 12.92
>                           : pow((G_s + 0.055) / 1.055, 2.4)
>  B_linear = B_s ≤ 0.04045 ? B_s / 12.92
>                           : pow((B_s + 0.055) / 1.055, 2.4)
>  A_linear = A_s
>
>and for the compositing itself the formulae at
>
>  R_result = min((1 - A_fg) * R_bg + R_fg, 1)
>  G_result = min((1 - A_fg) * G_bg + G_fg, 1)
>  B_result = min((1 - A_fg) * B_bg + B_fg, 1)
>  A_result = 1 - (1 - A_fg) * (1 - A_bg)
>
>For the unpremultiplied ↔ premultiplied alpha conversions I’m doing
>
>  R_pre = R * A
>  G_pre = G * A
>  B_pre = B * A
>  A_pre = A
>
>and
>
>  R = R_pre / A
>  G = R_pre / A
>  B = R_pre / A
>  A = A_pre
>
>
>
>  bg = (0, 0, 0, 1)
>  fg = (1, 1, 1, 0.5)
>
>Convert them to linearRGB space:
>
>  bg_linear = (0, 0, 0, 1)
>  fg_linear = (1, 1, 1, 0.5)    i.e., the same values
>
>Since the alpha compositing is done with premultiplied colours, we
>multiply the alpha in:
>
>  bg_linear_pre = (0, 0, 0, 1)
>  fg_linear_pre = (0.5, 0.5, 0.5, 0.5)
>
>Do the alpha blending:
>
>  result_linear_pre = (0.5, 0.5, 0.5, 1)
>
>Unpremultiply:

You never unpremultiply. See: http://www.soe.ucsc.edu/classes/cmps160/Spring05/blinn_theory.pdf
as a nice reference. Basically the intermediate bit plane always holds premultiplied colours.
So, if you had 'enable-background="new"' on a group element, the intermediate
backing store after all compositing would consist of premultiplied values and per-pixel alpha.

>  result_linear = (0.5, 0.5, 0.5, 1)
>
>Convert to sRGB:
>
>  result = (0.790357, 0.790357, 0.790357, 1)

The result with the corrected equation is 0.73535...

which also handily multiplies by 255 to give 187 or 0xBB just like the viewers that
support linearRGB compositing get.

>I think in this particular example, the order of the colour space
>conversion and the alpha multiplication/division doesn’t matter, since
>you get the same result.  Is that true in general, though?

No, not in general. sRGB is non-linear. So you will get a different
some nice pictures of composited images.

>Is my method above correct?

Almost, just need to correct the equations.

Cheers,
Alex

>--
>Cameron McCormack ≝ http://mcc.id.au/
>
>
>
```

Received on Friday, 18 February 2011 05:24:44 UTC