From a158d7f14f4b987e9e6380ffe896dbcfd41799ec Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=B8ren=20Sandmann=20Pedersen?= Date: Wed, 26 Nov 2008 13:52:00 -0500 Subject: [PATCH] Add some comments about the linearity of the non-separable blend modes --- pixman/pixman-combine.c.template | 82 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/pixman/pixman-combine.c.template b/pixman/pixman-combine.c.template index 5e86011..ca3f351 100644 --- a/pixman/pixman-combine.c.template +++ b/pixman/pixman-combine.c.template @@ -683,9 +683,7 @@ PdfSeparableBlendMode (Exclusion) * * Lum (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue * - * SetLum (C, l): - * d = l – Lum (C) - * C += d + * ClipColor (C): * l = Lum (C) * min = Cmin * max = Cmax @@ -695,6 +693,11 @@ PdfSeparableBlendMode (Exclusion) * C = l + ( ( ( C – l ) × ( 1 – l ) ) ⁄ ( max – l ) ) * return C * + * SetLum (C, l): + * d = l – Lum (C) + * C += d + * return ClipColor (C) + * * Sat (C) = Max (C) - Min (C) * * SetSat (C, s): @@ -707,6 +710,79 @@ PdfSeparableBlendMode (Exclusion) * return C */ +/* For premultiplied colors, we need to know what happens when C is + * multiplied by a real number. Lum and Sat are linear: + * + * Lum (r × C) = r × Lum (C) Sat (r * C) = r * Sat (C) + * + * If we extend ClipColor with an extra argument a and change + * + * if x >= 1.0 + * + * into + * + * if x >= a + * + * then ClipColor is also linear: + * + * r * ClipColor (C, a) = ClipColor (rC, ra); + * + * for positive r. + * + * Similarly, we can extend SetLum with an extra argument that is just passed + * on to ClipColor: + * + * r * SetLum ( C, l, a) + * + * = r × ClipColor ( C + l - Lum (C), a) + * + * = ClipColor ( r * C + r × l - r * Lum (C), r * a) + * + * = SetLum ( r * C, r * l, r * a) + * + * Finally, SetSat: + * + * r * SetSat (C, s) = SetSat (x * C, r * s) + * + * The above holds for all non-zero x, because they x'es in the fraction for + * C_mid cancel out. Specifically, it holds for x = r: + * + * r * SetSat (C, s) = SetSat (rC, rs) + * + */ + +/* So, for the non-separable PDF blend modes, we have (using s, d for non-premultiplied + * colors, and S, D for premultiplied: + * + * Color: + * + * a_s * a_d * B(s, d) + * = a_s * a_d * SetLum (S/a_s, Lum (D/a_d), 1) + * = SetLum (S * a_d, a_s * Lum (D), a_s * a_d) + * + * + * Luminosity: + * + * a_s * a_d * B(s, d) + * = a_s * a_d * SetLum (D/a_d, Lum(S/a_s), 1) + * = SetLum (a_s * D, a_d * Lum(S), a_s * a_d) + * + * + * Saturation: + * + * a_s * a_d * B(s, d) + * = a_s * a_d * SetLum (SetSat (D/a_d, Sat (S/a_s)), Lum (D/a_d), 1) + * = SetLum (a_s * a_d * SetSat (D/a_d, Sat (S/a_s)), a_s * Lum (D), a_s * a_d) + * = SetLum (SetSat (a_s * D, a_d * Sat (S), a_s * Lum (D), a_s * a_d)) + * + * Hue: + * + * a_s * a_d * B(s, d) + * = a_s * a_d * SetLum (SetSat (S/a_s, Sat (D/a_d)), Lum (D/a_d), 1) + * = a_s * a_d * SetLum (SetSat (a_d * S, a_s * Sat (D)), a_s * Lum (D), a_s * a_d) + * + */ + #define Min(c) (c[0] < c[1] ? (c[0] < c[2] ? c[0] : c[2]) : (c[1] < c[2] ? c[1] : c[2])) #define Max(c) (c[0] > c[1] ? (c[0] > c[2] ? c[0] : c[2]) : (c[1] > c[2] ? c[1] : c[2])) #define Lum(c) ((c[0] * 30 + c[1] * 59 + c[2] * 11) / 100) -- 2.7.4