From 7cbfe3ba214006dda5fa6d21871ef6fc61067005 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 23 Nov 2008 15:42:53 +0100 Subject: [PATCH] rework blend-mode documentation to match current code better --- pixman/pixman-combine.c.template | 222 ++++++++++++++++++++++----------------- 1 file changed, 127 insertions(+), 95 deletions(-) diff --git a/pixman/pixman-combine.c.template b/pixman/pixman-combine.c.template index 41e174c..78eac3d 100644 --- a/pixman/pixman-combine.c.template +++ b/pixman/pixman-combine.c.template @@ -336,12 +336,32 @@ fbCombineSaturateU (pixman_implementation_t *imp, pixman_op_t op, } } - -/* Multiply +/* + * PDF blend modes: + * The following blend modes have been taken from the PDF ISO 32000 + * specification, which at this point in time is available from + * http://www.adobe.com/devnet/acrobat/pdfs/PDF32000_2008.pdf + * The relevant chapters are 11.3.5 and 11.3.6. + * The formula for computing the final pixel color given in 11.3.6 is: + * αr × Cr = (1 – αs) × αb × Cb + (1 – αb) × αs × Cs + αb × αs × B(Cb, Cs) + * with B() being the blend function. + * Note that OVER is a special case of this operation, using B(Cb, Cs) = Cs + * + * These blend modes should match the SVG filter draft specification, as + * it has been designed to mirror ISO 32000. Note that at the current point + * no released draft exists that shows this, as the formulas have not been + * updated yet after the release of ISO 32000. * - * Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - * Da' = Sa.Da + Sa.(1 - Da) + Da.(1 - Sa) - * = Sa + Da - Sa.Da + * The default implementation here uses the PdfSeparableBlendMode and + * PdfNonSeparableBlendMode macros, which take the blend function as an + * argument. Note that this implementation operates on premultiplied colors, + * while the PDF specification does not. Therefore the code uses the formula + * ar.Cra = (1 – as) . Dca + (1 – ad) . Sca + B(Dca, ad, Sca, as) + */ + +/* + * Multiply + * B(Dca, ad, Sca, as) = Dca.Sca */ static void @@ -463,11 +483,9 @@ fbCombine ## name ## C (pixman_implementation_t *imp, pixman_op_t op, \ } \ } -/* Screen - * - * Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) - * = Sca + Dca - Sca.Dca - * Da' = Sa + Da - Sa.Da +/* + * Screen + * B(Dca, ad, Sca, as) = Dca.sa + Sca.da - Dca.Sca */ static inline comp4_t @@ -478,13 +496,13 @@ BlendScreen (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) PdfSeparableBlendMode (Screen) -/* Overlay - * - * if 2.Dca < Da - * Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) +/* + * Overlay + * B(Dca, ab, Sca, as) = + * if 2.Dca < Da + * 2.Sca.Dca * otherwise - * Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) - * Da' = Sa + Da - Sa.Da + * Sa.Da - 2.(Da - Dca).(Sa - Sca) */ static inline comp4_t @@ -501,10 +519,9 @@ BlendOverlay (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) PdfSeparableBlendMode (Overlay) -/* Darken - * - * Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - * Da' = Sa + Da - Sa.Da +/* + * Darken + * B(Dca, ab, Sca, as) = min (Sca.Da, Dca.Sa) */ static inline comp4_t @@ -519,10 +536,9 @@ BlendDarken (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) PdfSeparableBlendMode (Darken) -/* Lighten - * - * Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - * Da' = Sa + Da - Sa.Da +/* + * Lighten + * B(Dca, ab, Sca, as) = max (Sca.Da, Dca.Sa) */ static inline comp4_t @@ -537,14 +553,13 @@ BlendLighten (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) PdfSeparableBlendMode (Lighten) -/* Color dodge - * - * if Sca == Sa - * Dca' = (Dca != 0).Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) - * otherwise - * Dca' = Da.Sa. min (Dca / Da / (1 - Sca/Sa)) - * - * Da' = Sa + Da - Sa.Da +/* + * Color dodge + * B(Dca, ab, Sca, as) = + * if Sca == Sa + * (Dca != 0).Sa.Da + * otherwise + * Da.Sa. min (Dca / Da / (1 - Sca/Sa)) */ static inline comp4_t @@ -560,38 +575,36 @@ BlendColorDodge (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) PdfSeparableBlendMode (ColorDodge) -/* Color burn - * - * if Sca. == 0 - * Dca' = (Da == Dca).SaDa + Sca.(1 - Da) + Dca.(1 - Sa) - * otherwise - * Dca' = Sa.Da.(1 - min (1, (1 - Dca/Da).Sa / Sca)) + Sca.(1 - Da) + Dca.(1 - Sa) - * - * Da' = Sa + Da - Sa.Da +/* + * Color burn + * B(Dca, ab, Sca, as) = + * if Sca. == 0 + * (Da == Dca).SaDa + * otherwise + * Sa.Da.(1 - min (1, (1 - Dca/Da).Sa / Sca)) */ static inline comp4_t BlendColorBurn (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) { if (sca == 0) { - return (da == dca) ? DivOne (sa * da) : 0; + return (da == dca) ? DivOne (sa * da) : 0; } else { - comp4_t sada = sa * da; - comp4_t rca = (da - dca) * sa * sa / sca; - return DivOne (rca > sada ? 0 : sada - rca); + comp4_t sada = sa * da; + comp4_t rca = (da - dca) * sa * sa / sca; + return DivOne (rca > sada ? 0 : sada - rca); } } PdfSeparableBlendMode (ColorBurn) -/* Hard light - * - * if 2.Sca < Sa - * Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - * otherwise - * Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) - * - * Da' = Sa + Da - Sa.Da +/* + * Hard light + * B(Dca, ab, Sca, as) = + * if 2.Sca < Sa + * 2.Sca.Dca + * otherwise + * Sa.Da - 2.(Da - Dca).(Sa - Sca) */ static inline comp4_t BlendHardLight (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) @@ -604,38 +617,15 @@ BlendHardLight (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) PdfSeparableBlendMode (HardLight) -/* Soft light - * - * original definition (taken from PDF spec): - * - * if (Sc <= 0.5) - * Dc' = Dc - ( 1 - 2 . Sc ) . Dc . ( 1 - Dc ) - * else - * Dc' = Dc + ( 2 . Sc - 1 ) . ( F(Dc) - Dc ) - * - * with - * if (x < 0.25) - * F(x) = ( ( 16 . x - 12 ) . x + 4 ) . x - * else - * F(x) = SQRT (x) - * - * ==> - * - * if (Sc <= 0.5) - * Dc' = Dc - ( 1 - 2 . Sc ) . Dc . ( 1 - Dc ) - * otherwise if (Dc < 0.25) - * Dc' = Dc + ( 2 . Sc - 1 ) . ( ((16 . Dc - 12) . Dc + 4) - Dc ) - * otherwise - * Dc' = Dc + ( 2 . Sc - 1 ) . ( SQRT(Dc) - Dc ) - * - * ==> - * - * if (2.Sca <= Sa) - * Dca' = Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) - * otherwise if Dca.4 <= Da - * Dca' = Dca.(Sa + (2.Sca - Sa).((16.Dca/Da - 12).Dca/Da + 3) + Sc.(1 - Da) + Dca.(1 - Sa) - * otherwise - * Dca' = (Dca.Sa + (SQRT (Dca/Da).Da - Dca).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) +/* + * Soft light + * B(Dca, ab, Sca, as) = + * if (2.Sca <= Sa) + * Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa)) + * otherwise if Dca.4 <= Da + * Dca.(Sa + (2.Sca - Sa).((16.Dca/Da - 12).Dca/Da + 3) + * otherwise + * (Dca.Sa + (SQRT (Dca/Da).Da - Dca).(2.Sca - Sa)) */ static inline comp4_t @@ -664,12 +654,9 @@ BlendSoftLight (comp4_t dca_org, comp4_t da_org, comp4_t sca_org, comp4_t sa_org PdfSeparableBlendMode (SoftLight) -/* Difference - * - * Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa) - * = Sca + Dca - 2.min(Sca.Da, Dca.Sa) - * - * Da' = Sa + Da - Sa.Da +/* + * Difference + * B(Dca, ab, Sca, as) = abs (Dca.Sa - Sca.Da) */ static inline comp4_t @@ -686,11 +673,9 @@ BlendDifference (comp4_t dca, comp4_t da, comp4_t sca, comp4_t sa) PdfSeparableBlendMode (Difference) -/* Exclusion - * - * Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) - * - * Da' = Sa + Da - Sa.Da +/* + * Exclusion + * B(Dca, ab, Sca, as) = (Sca.Da + Dca.Sa - 2.Sca.Dca) */ /* This can be made faster by writing it directly and not using @@ -772,6 +757,37 @@ fbCombineSubtractC (pixman_implementation_t *imp, pixman_op_t op, #undef Subtract +/* + * PDF nonseperable blend modes are implemented using the following functions + * to operate in HSL space, with Cmax, Cmid, Cmin referring to the max, mid + * and min value of the red, green and blue components. + * + * Lum (C) = 0.3 × Cred + 0.59 × Cgreen + 0.11 × Cblue + * + * SetLum (C, l): + * d = l – Lum (C) + * C += d + * l = Lum (C) + * min = Cmin + * max = Cmax + * if n < 0.0 + * C = l + ( ( ( C – l ) × l ) ⁄ ( l – min ) ) + * if x > 1.0 + * C = l + ( ( ( C – l ) × ( 1 – l ) ) ⁄ ( max – l ) ) + * return C + * + * Sat (C) = Max (C) - Min (C) + * + * SetSat (C, s): + * if Cmax > Cmin + * Cmid = ( ( ( Cmid – Cmin ) × s ) ⁄ ( Cmax – Cmin ) ) + * Cmax = s + * else + * Cmid = Cmax = 0.0 + * Cmin = 0.0 + * return C + */ + #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) @@ -947,6 +963,10 @@ SetSat (comp4_t dest[3], comp4_t src[3], comp4_t sat) if (Max (dest) > 255 * 255) while (1); \ } +/* + * Hue: + * B(Cb, Cs) = SetLum (SetSat (Cs, Sat (Cb)), Lum (Cb)) + */ static inline void BlendHSLHue (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp4_t sa) { @@ -959,6 +979,10 @@ BlendHSLHue (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp4_t sa) PdfNonSeparableBlendMode (HSLHue) +/* + * Saturation: + * B(Cb, Cs) = SetLum (SetSat (Cb, Sat (Cs)), Lum (Cb)) + */ static inline void BlendHSLSaturation (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp4_t sa) { @@ -971,6 +995,10 @@ BlendHSLSaturation (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp PdfNonSeparableBlendMode (HSLSaturation) +/* + * Color: + * B(Cb, Cs) = SetLum (Cs, Lum (Cb)) + */ static inline void BlendHSLColor (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp4_t sa) { @@ -982,6 +1010,10 @@ BlendHSLColor (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp4_t s PdfNonSeparableBlendMode (HSLColor) +/* + * Luminosity: + * B(Cb, Cs) = SetLum (Cb, Lum (Cs)) + */ static inline void BlendHSLLuminosity (comp4_t c[3], comp4_t dc[3], comp4_t da, comp4_t sc[3], comp4_t sa) { -- 2.7.4