/src/mupdf/source/fitz/draw-blend.c
Line | Count | Source |
1 | | // Copyright (C) 2004-2025 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | |
25 | | #include "draw-imp.h" |
26 | | #include "pixmap-imp.h" |
27 | | |
28 | | #include <string.h> |
29 | | #include <math.h> |
30 | | #include <assert.h> |
31 | | |
32 | | /* PDF 1.4 blend modes. These are slow. */ |
33 | | |
34 | | /* Define PARANOID_PREMULTIPLY to check premultiplied values are |
35 | | * properly in range. */ |
36 | | #undef PARANOID_PREMULTIPLY |
37 | | |
38 | | /* |
39 | | |
40 | | Some notes on the transparency maths: |
41 | | |
42 | | Compositing equation: |
43 | | ===================== |
44 | | |
45 | | In section 7.2.2 (page 517) of pdf_reference17.pdf, it says: |
46 | | |
47 | | Cr = (1 - As/Ar) * Cb + As/Ar * [ (1-Ab) * Cs + Ab * B(Cb,Cs) ] |
48 | | |
49 | | It says that this is a simplified version of the more general form. |
50 | | |
51 | | This equation is then restated in section 7.2.2 and it says: |
52 | | |
53 | | The formula shown above is a simplification of the following formula: |
54 | | |
55 | | Ar * Cr = [(1-As)*Ab*Cb] + [(1-Ab)*As*Cs] + [Ab*As*B(Cb, Cs)] |
56 | | |
57 | | At first glance this always appears to be a mistake to me, as it looks |
58 | | like they have make a mistake in the division. |
59 | | |
60 | | However, if we consider the result alpha equation: |
61 | | |
62 | | Ar = Union(Ab, As) = Ab + As - Ab * As |
63 | | |
64 | | we can rearrange that to give: |
65 | | |
66 | | Ar - As = (1 - As) * Ab |
67 | | |
68 | | 1 - As/Ar = (1 - As) * Ab / Ar |
69 | | |
70 | | So substituting into the first equation above, we get: |
71 | | |
72 | | Cr = ((1 - As) * Ab/Ar) * Cb + As/Ar * [ (1-Ab) * Cs + Ab * B(Cb,Cs) ] |
73 | | |
74 | | And thus: |
75 | | |
76 | | Ar * Cr = (1 - As) * Ab * Cb + As * [ (1-Ab)*Cs + Ab * B(Cb,Cs) ] |
77 | | |
78 | | as required. |
79 | | |
80 | | Alpha blending on top of compositing: |
81 | | ===================================== |
82 | | |
83 | | Suppose we have a group to blend using blend mode B, and we want |
84 | | to apply alpha too. Let's apply the blending first to get an |
85 | | intermediate result (Ir), then apply the alpha to that to get the |
86 | | result (Cr): |
87 | | |
88 | | Ir = (1 - As/Ar) * Cb + As/Ar * [ (1-Ab) * Cs + Ab * B(Cb,Cs) ] |
89 | | |
90 | | Cr = (1-alpha) * Cb + alpha * Ir |
91 | | = Cb - alpha * Cb + alpha * Cb - alpha * Cb * As / Ar + alpha * As / Ar * [ (1 - Ab) * Cs + Ab * B(Cb, Cs) ] |
92 | | = Cb - alpha * Cb * As / Ar + alpha * As / Ar * [ (1 - Ab) * Cs + Ab * B(Cb, Cs) ] |
93 | | = Cb * (1 - alpha * As / Ar) + alpha * As / Ar * [ (1 - Ab) * Cs + Ab * B(Cb, Cs) ] |
94 | | |
95 | | We want premultiplied results, so: |
96 | | |
97 | | Ar*Cr = Cb * (Ar - alpha * As) + alpha * As * (1 - Ab) * Cs + alpha * As * Ab * B(Cb, Cs) ] |
98 | | |
99 | | In the same way, for the alpha values: |
100 | | |
101 | | Ia = Union(Ab, As) = Ab + As - As*Ab |
102 | | Ar = (1-alpha) * Ab + alpha * Ia |
103 | | = Ab - alpha * Ab + alpha * Ab + alpha * As - alpha * As * Ab |
104 | | = Ab + alpha * As - alpha * As * Ab |
105 | | = Union(Ab, alpha * As) |
106 | | |
107 | | */ |
108 | | |
109 | | typedef unsigned char byte; |
110 | | |
111 | | static const char *fz_blendmode_names[] = |
112 | | { |
113 | | "Normal", |
114 | | "Multiply", |
115 | | "Screen", |
116 | | "Overlay", |
117 | | "Darken", |
118 | | "Lighten", |
119 | | "ColorDodge", |
120 | | "ColorBurn", |
121 | | "HardLight", |
122 | | "SoftLight", |
123 | | "Difference", |
124 | | "Exclusion", |
125 | | "Hue", |
126 | | "Saturation", |
127 | | "Color", |
128 | | "Luminosity", |
129 | | }; |
130 | | |
131 | | int fz_lookup_blendmode(const char *name) |
132 | 0 | { |
133 | 0 | int i; |
134 | 0 | for (i = 0; i < (int)nelem(fz_blendmode_names); i++) |
135 | 0 | if (!strcmp(name, fz_blendmode_names[i])) |
136 | 0 | return i; |
137 | 0 | return FZ_BLEND_NORMAL; |
138 | 0 | } |
139 | | |
140 | | const char *fz_blendmode_name(int blendmode) |
141 | 0 | { |
142 | 0 | if (blendmode >= 0 && blendmode < (int)nelem(fz_blendmode_names)) |
143 | 0 | return fz_blendmode_names[blendmode]; |
144 | 0 | return "Normal"; |
145 | 0 | } |
146 | | |
147 | | /* Separable blend modes */ |
148 | | |
149 | | static inline int fz_screen_byte(int b, int s) |
150 | 0 | { |
151 | 0 | return b + s - fz_mul255(b, s); |
152 | 0 | } |
153 | | |
154 | | static inline int fz_hard_light_byte(int b, int s) |
155 | 0 | { |
156 | 0 | int s2 = s << 1; |
157 | 0 | if (s <= 127) |
158 | 0 | return fz_mul255(b, s2); |
159 | 0 | else |
160 | 0 | return fz_screen_byte(b, s2 - 255); |
161 | 0 | } |
162 | | |
163 | | static inline int fz_overlay_byte(int b, int s) |
164 | 0 | { |
165 | 0 | return fz_hard_light_byte(s, b); /* note swapped order */ |
166 | 0 | } |
167 | | |
168 | | static inline int fz_darken_byte(int b, int s) |
169 | 0 | { |
170 | 0 | return fz_mini(b, s); |
171 | 0 | } |
172 | | |
173 | | static inline int fz_lighten_byte(int b, int s) |
174 | 0 | { |
175 | 0 | return fz_maxi(b, s); |
176 | 0 | } |
177 | | |
178 | | static inline int fz_color_dodge_byte(int b, int s) |
179 | 0 | { |
180 | 0 | s = 255 - s; |
181 | 0 | if (b <= 0) |
182 | 0 | return 0; |
183 | 0 | else if (b >= s) |
184 | 0 | return 255; |
185 | 0 | else |
186 | 0 | return (0x1fe * b + s) / (s << 1); |
187 | 0 | } |
188 | | |
189 | | static inline int fz_color_burn_byte(int b, int s) |
190 | 0 | { |
191 | 0 | b = 255 - b; |
192 | 0 | if (b <= 0) |
193 | 0 | return 255; |
194 | 0 | else if (b >= s) |
195 | 0 | return 0; |
196 | 0 | else |
197 | 0 | return 0xff - (0x1fe * b + s) / (s << 1); |
198 | 0 | } |
199 | | |
200 | | static inline int fz_soft_light_byte(int b, int s) |
201 | 0 | { |
202 | 0 | if (s < 128) { |
203 | 0 | return b - fz_mul255(fz_mul255((255 - (s<<1)), b), 255 - b); |
204 | 0 | } |
205 | 0 | else { |
206 | 0 | int dbd; |
207 | 0 | if (b < 64) |
208 | 0 | dbd = fz_mul255(fz_mul255((b << 4) - 3060, b) + 1020, b); |
209 | 0 | else |
210 | 0 | dbd = (int)sqrtf(255.0f * b); |
211 | 0 | return b + fz_mul255(((s<<1) - 255), (dbd - b)); |
212 | 0 | } |
213 | 0 | } |
214 | | |
215 | | static inline int fz_difference_byte(int b, int s) |
216 | 0 | { |
217 | 0 | return fz_absi(b - s); |
218 | 0 | } |
219 | | |
220 | | static inline int fz_exclusion_byte(int b, int s) |
221 | 0 | { |
222 | 0 | return b + s - (fz_mul255(b, s)<<1); |
223 | 0 | } |
224 | | |
225 | | /* Non-separable blend modes */ |
226 | | |
227 | | static void |
228 | | fz_luminosity_rgb(unsigned char *rd, unsigned char *gd, unsigned char *bd, int rb, int gb, int bb, int rs, int gs, int bs) |
229 | 0 | { |
230 | 0 | int delta, scale; |
231 | 0 | int r, g, b, y; |
232 | | |
233 | | /* 0.3f, 0.59f, 0.11f in fixed point */ |
234 | 0 | delta = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8; |
235 | 0 | r = rb + delta; |
236 | 0 | g = gb + delta; |
237 | 0 | b = bb + delta; |
238 | |
|
239 | 0 | if ((r | g | b) & 0x100) |
240 | 0 | { |
241 | 0 | y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8; |
242 | 0 | if (delta > 0) |
243 | 0 | { |
244 | 0 | int max; |
245 | 0 | max = fz_maxi(r, fz_maxi(g, b)); |
246 | 0 | scale = (max == y ? 0 : ((255 - y) << 16) / (max - y)); |
247 | 0 | } |
248 | 0 | else |
249 | 0 | { |
250 | 0 | int min; |
251 | 0 | min = fz_mini(r, fz_mini(g, b)); |
252 | 0 | scale = (y == min ? 0 : (y << 16) / (y - min)); |
253 | 0 | } |
254 | 0 | r = y + (((r - y) * scale + 0x8000) >> 16); |
255 | 0 | g = y + (((g - y) * scale + 0x8000) >> 16); |
256 | 0 | b = y + (((b - y) * scale + 0x8000) >> 16); |
257 | 0 | } |
258 | |
|
259 | 0 | *rd = fz_clampi(r, 0, 255); |
260 | 0 | *gd = fz_clampi(g, 0, 255); |
261 | 0 | *bd = fz_clampi(b, 0, 255); |
262 | 0 | } |
263 | | |
264 | | static void |
265 | | fz_saturation_rgb(unsigned char *rd, unsigned char *gd, unsigned char *bd, int rb, int gb, int bb, int rs, int gs, int bs) |
266 | 0 | { |
267 | 0 | int minb, maxb; |
268 | 0 | int mins, maxs; |
269 | 0 | int y; |
270 | 0 | int scale; |
271 | 0 | int r, g, b; |
272 | |
|
273 | 0 | minb = fz_mini(rb, fz_mini(gb, bb)); |
274 | 0 | maxb = fz_maxi(rb, fz_maxi(gb, bb)); |
275 | 0 | if (minb == maxb) |
276 | 0 | { |
277 | | /* backdrop has zero saturation, avoid divide by 0 */ |
278 | 0 | gb = fz_clampi(gb, 0, 255); |
279 | 0 | *rd = gb; |
280 | 0 | *gd = gb; |
281 | 0 | *bd = gb; |
282 | 0 | return; |
283 | 0 | } |
284 | | |
285 | 0 | mins = fz_mini(rs, fz_mini(gs, bs)); |
286 | 0 | maxs = fz_maxi(rs, fz_maxi(gs, bs)); |
287 | |
|
288 | 0 | scale = ((maxs - mins) << 16) / (maxb - minb); |
289 | 0 | y = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8; |
290 | 0 | r = y + ((((rb - y) * scale) + 0x8000) >> 16); |
291 | 0 | g = y + ((((gb - y) * scale) + 0x8000) >> 16); |
292 | 0 | b = y + ((((bb - y) * scale) + 0x8000) >> 16); |
293 | |
|
294 | 0 | if ((r | g | b) & 0x100) |
295 | 0 | { |
296 | 0 | int scalemin, scalemax; |
297 | 0 | int min, max; |
298 | |
|
299 | 0 | min = fz_mini(r, fz_mini(g, b)); |
300 | 0 | max = fz_maxi(r, fz_maxi(g, b)); |
301 | |
|
302 | 0 | if (min < 0) |
303 | 0 | scalemin = (y << 16) / (y - min); |
304 | 0 | else |
305 | 0 | scalemin = 0x10000; |
306 | |
|
307 | 0 | if (max > 255) |
308 | 0 | scalemax = ((255 - y) << 16) / (max - y); |
309 | 0 | else |
310 | 0 | scalemax = 0x10000; |
311 | |
|
312 | 0 | scale = fz_mini(scalemin, scalemax); |
313 | 0 | r = y + (((r - y) * scale + 0x8000) >> 16); |
314 | 0 | g = y + (((g - y) * scale + 0x8000) >> 16); |
315 | 0 | b = y + (((b - y) * scale + 0x8000) >> 16); |
316 | 0 | } |
317 | |
|
318 | 0 | *rd = fz_clampi(r, 0, 255); |
319 | 0 | *gd = fz_clampi(g, 0, 255); |
320 | 0 | *bd = fz_clampi(b, 0, 255); |
321 | 0 | } |
322 | | |
323 | | static void |
324 | | fz_color_rgb(unsigned char *rr, unsigned char *rg, unsigned char *rb, int br, int bg, int bb, int sr, int sg, int sb) |
325 | 0 | { |
326 | 0 | fz_luminosity_rgb(rr, rg, rb, sr, sg, sb, br, bg, bb); |
327 | 0 | } |
328 | | |
329 | | static void |
330 | | fz_hue_rgb(unsigned char *rr, unsigned char *rg, unsigned char *rb, int br, int bg, int bb, int sr, int sg, int sb) |
331 | 0 | { |
332 | 0 | unsigned char tr, tg, tb; |
333 | 0 | fz_luminosity_rgb(&tr, &tg, &tb, sr, sg, sb, br, bg, bb); |
334 | 0 | fz_saturation_rgb(rr, rg, rb, tr, tg, tb, br, bg, bb); |
335 | 0 | } |
336 | | |
337 | | /* Blending loops */ |
338 | | |
339 | | static inline void |
340 | | fz_blend_separable(byte * FZ_RESTRICT bp, int bal, const byte * FZ_RESTRICT sp, int sal, int n1, int w, int blendmode, int complement, int first_spot) |
341 | 0 | { |
342 | 0 | int k; |
343 | 0 | do |
344 | 0 | { |
345 | 0 | int sa = (sal ? sp[n1] : 255); |
346 | |
|
347 | 0 | if (sa != 0) |
348 | 0 | { |
349 | 0 | int ba = (bal ? bp[n1] : 255); |
350 | 0 | if (ba == 0) |
351 | 0 | { |
352 | 0 | memcpy(bp, sp, n1 + (sal && bal)); |
353 | 0 | if (bal && !sal) |
354 | 0 | bp[n1+1] = 255; |
355 | 0 | } |
356 | 0 | else |
357 | 0 | { |
358 | 0 | int saba = fz_mul255(sa, ba); |
359 | | |
360 | | /* ugh, division to get non-premul components */ |
361 | 0 | int invsa = sa ? 255 * 256 / sa : 0; |
362 | 0 | int invba = ba ? 255 * 256 / ba : 0; |
363 | | |
364 | | /* Process colorants */ |
365 | 0 | for (k = 0; k < first_spot; k++) |
366 | 0 | { |
367 | 0 | int sc = (sp[k] * invsa) >> 8; |
368 | 0 | int bc = (bp[k] * invba) >> 8; |
369 | 0 | int rc; |
370 | |
|
371 | 0 | if (complement) |
372 | 0 | { |
373 | 0 | sc = 255 - sc; |
374 | 0 | bc = 255 - bc; |
375 | 0 | } |
376 | |
|
377 | 0 | switch (blendmode) |
378 | 0 | { |
379 | 0 | default: |
380 | 0 | case FZ_BLEND_NORMAL: rc = sc; break; |
381 | 0 | case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break; |
382 | 0 | case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break; |
383 | 0 | case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break; |
384 | 0 | case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break; |
385 | 0 | case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break; |
386 | 0 | case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break; |
387 | 0 | case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break; |
388 | 0 | case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break; |
389 | 0 | case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break; |
390 | 0 | case FZ_BLEND_DIFFERENCE: rc = fz_difference_byte(bc, sc); break; |
391 | 0 | case FZ_BLEND_EXCLUSION: rc = fz_exclusion_byte(bc, sc); break; |
392 | 0 | } |
393 | | |
394 | 0 | if (complement) |
395 | 0 | { |
396 | 0 | rc = 255 - rc; |
397 | 0 | } |
398 | |
|
399 | 0 | bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, rc); |
400 | 0 | } |
401 | | |
402 | | /* spots */ |
403 | 0 | for (; k < n1; k++) |
404 | 0 | { |
405 | 0 | int sc = 255 - ((sp[k] * invsa) >> 8); |
406 | 0 | int bc = 255 - ((bp[k] * invba) >> 8); |
407 | 0 | int rc; |
408 | |
|
409 | 0 | switch (blendmode) |
410 | 0 | { |
411 | 0 | default: |
412 | 0 | case FZ_BLEND_NORMAL: |
413 | 0 | case FZ_BLEND_DIFFERENCE: |
414 | 0 | case FZ_BLEND_EXCLUSION: |
415 | 0 | rc = sc; break; |
416 | 0 | case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break; |
417 | 0 | case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break; |
418 | 0 | case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break; |
419 | 0 | case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break; |
420 | 0 | case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break; |
421 | 0 | case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break; |
422 | 0 | case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break; |
423 | 0 | case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break; |
424 | 0 | case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break; |
425 | 0 | } |
426 | 0 | bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, 255 - rc); |
427 | 0 | } |
428 | | |
429 | 0 | if (bal) |
430 | 0 | bp[k] = ba + sa - saba; |
431 | 0 | } |
432 | 0 | } |
433 | 0 | sp += n1 + sal; |
434 | 0 | bp += n1 + bal; |
435 | 0 | } |
436 | 0 | while (--w); |
437 | 0 | } |
438 | | |
439 | | static inline void |
440 | | fz_blend_nonseparable_gray(byte * FZ_RESTRICT bp, int bal, const byte * FZ_RESTRICT sp, int sal, int n, int w, int blendmode, int first_spot) |
441 | 0 | { |
442 | 0 | do |
443 | 0 | { |
444 | 0 | int sa = (sal ? sp[n] : 255); |
445 | |
|
446 | 0 | if (sa != 0) |
447 | 0 | { |
448 | 0 | int ba = (bal ? bp[n] : 255); |
449 | 0 | if (ba == 0) |
450 | 0 | { |
451 | 0 | memcpy(bp, sp, n + (sal && bal)); |
452 | 0 | if (bal && !sal) |
453 | 0 | bp [n + 1] = 255; |
454 | 0 | } |
455 | 0 | else |
456 | 0 | { |
457 | 0 | int saba = fz_mul255(sa, ba); |
458 | | |
459 | | /* ugh, division to get non-premul components */ |
460 | 0 | int invsa = 255 * 256 / sa; |
461 | 0 | int invba = 255 * 256 / ba; |
462 | 0 | int k; |
463 | |
|
464 | 0 | switch (blendmode) |
465 | 0 | { |
466 | 0 | default: |
467 | 0 | case FZ_BLEND_HUE: |
468 | 0 | case FZ_BLEND_SATURATION: |
469 | 0 | case FZ_BLEND_COLOR: |
470 | 0 | { |
471 | 0 | int bg = (bp[0] * invba) >> 8; |
472 | 0 | bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, bg); |
473 | 0 | break; |
474 | 0 | } |
475 | 0 | case FZ_BLEND_LUMINOSITY: |
476 | 0 | { |
477 | 0 | int sg = (sp[0] * invsa) >> 8; |
478 | 0 | bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, sg); |
479 | 0 | break; |
480 | 0 | } |
481 | 0 | } |
482 | | |
483 | | /* Normal blend for spots */ |
484 | 0 | for (k = first_spot; k < n; k++) |
485 | 0 | { |
486 | 0 | int sc = (sp[k] * invsa) >> 8; |
487 | 0 | bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, sc); |
488 | 0 | } |
489 | 0 | if (bal) |
490 | 0 | bp[n] = ba + sa - saba; |
491 | 0 | } |
492 | 0 | } |
493 | 0 | sp += n + sal; |
494 | 0 | bp += n + bal; |
495 | 0 | } while (--w); |
496 | 0 | } |
497 | | |
498 | | static inline void |
499 | | fz_blend_nonseparable(byte * FZ_RESTRICT bp, int bal, const byte * FZ_RESTRICT sp, int sal, int n, int w, int blendmode, int complement, int first_spot) |
500 | 0 | { |
501 | 0 | do |
502 | 0 | { |
503 | 0 | unsigned char rr, rg, rb; |
504 | |
|
505 | 0 | int sa = (sal ? sp[n] : 255); |
506 | |
|
507 | 0 | if (sa != 0) |
508 | 0 | { |
509 | 0 | int ba = (bal ? bp[n] : 255); |
510 | 0 | if (ba == 0) |
511 | 0 | { |
512 | 0 | memcpy(bp, sp, n + (sal && bal)); |
513 | 0 | if (bal && !sal) |
514 | 0 | bp [n + 1] = 255; |
515 | 0 | } |
516 | 0 | else |
517 | 0 | { |
518 | 0 | int k; |
519 | 0 | int saba = fz_mul255(sa, ba); |
520 | | |
521 | | /* ugh, division to get non-premul components */ |
522 | 0 | int invsa = 255 * 256 / sa; |
523 | 0 | int invba = 255 * 256 / ba; |
524 | |
|
525 | 0 | int sr = (sp[0] * invsa) >> 8; |
526 | 0 | int sg = (sp[1] * invsa) >> 8; |
527 | 0 | int sb = (sp[2] * invsa) >> 8; |
528 | |
|
529 | 0 | int br = (bp[0] * invba) >> 8; |
530 | 0 | int bg = (bp[1] * invba) >> 8; |
531 | 0 | int bb = (bp[2] * invba) >> 8; |
532 | | |
533 | | /* CMYK */ |
534 | 0 | if (complement) |
535 | 0 | { |
536 | 0 | sr = 255 - sr; |
537 | 0 | sg = 255 - sg; |
538 | 0 | sb = 255 - sb; |
539 | 0 | br = 255 - br; |
540 | 0 | bg = 255 - bg; |
541 | 0 | bb = 255 - bb; |
542 | 0 | } |
543 | |
|
544 | 0 | switch (blendmode) |
545 | 0 | { |
546 | 0 | default: |
547 | 0 | case FZ_BLEND_HUE: |
548 | 0 | fz_hue_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); |
549 | 0 | break; |
550 | 0 | case FZ_BLEND_SATURATION: |
551 | 0 | fz_saturation_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); |
552 | 0 | break; |
553 | 0 | case FZ_BLEND_COLOR: |
554 | 0 | fz_color_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); |
555 | 0 | break; |
556 | 0 | case FZ_BLEND_LUMINOSITY: |
557 | 0 | fz_luminosity_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); |
558 | 0 | break; |
559 | 0 | } |
560 | | |
561 | | /* CMYK */ |
562 | 0 | if (complement) |
563 | 0 | { |
564 | 0 | rr = 255 - rr; |
565 | 0 | rg = 255 - rg; |
566 | 0 | rb = 255 - rb; |
567 | 0 | bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, rr); |
568 | 0 | bp[1] = fz_mul255(255 - sa, bp[1]) + fz_mul255(255 - ba, sp[1]) + fz_mul255(saba, rg); |
569 | 0 | bp[2] = fz_mul255(255 - sa, bp[2]) + fz_mul255(255 - ba, sp[2]) + fz_mul255(saba, rb); |
570 | |
|
571 | 0 | switch (blendmode) |
572 | 0 | { |
573 | 0 | default: |
574 | 0 | case FZ_BLEND_HUE: |
575 | 0 | case FZ_BLEND_SATURATION: |
576 | 0 | case FZ_BLEND_COLOR: |
577 | 0 | k = (bp[3] * invba) >> 8; |
578 | 0 | break; |
579 | 0 | case FZ_BLEND_LUMINOSITY: |
580 | 0 | k = (sp[3] * invsa) >> 8; |
581 | 0 | break; |
582 | 0 | } |
583 | 0 | bp[3] = fz_mul255(255 - sa, bp[3]) + fz_mul255(255 - ba, sp[3]) + fz_mul255(saba, k); |
584 | 0 | } |
585 | 0 | else |
586 | 0 | { |
587 | 0 | bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, rr); |
588 | 0 | bp[1] = fz_mul255(255 - sa, bp[1]) + fz_mul255(255 - ba, sp[1]) + fz_mul255(saba, rg); |
589 | 0 | bp[2] = fz_mul255(255 - sa, bp[2]) + fz_mul255(255 - ba, sp[2]) + fz_mul255(saba, rb); |
590 | 0 | } |
591 | | |
592 | 0 | if (bal) |
593 | 0 | bp[n] = ba + sa - saba; |
594 | | |
595 | | /* Normal blend for spots */ |
596 | 0 | for (k = first_spot; k < n; k++) |
597 | 0 | { |
598 | 0 | int sc = (sp[k] * invsa) >> 8; |
599 | 0 | bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, sc); |
600 | 0 | } |
601 | 0 | } |
602 | 0 | } |
603 | 0 | sp += n + sal; |
604 | 0 | bp += n + bal; |
605 | 0 | } |
606 | 0 | while (--w); |
607 | 0 | } |
608 | | |
609 | | static inline void |
610 | | fz_blend_separable_nonisolated(byte * FZ_RESTRICT bp, int bal, const byte * FZ_RESTRICT sp, int sal, int n1, int w, int blendmode, int complement, const byte * FZ_RESTRICT hp, int alpha, int first_spot) |
611 | 0 | { |
612 | 0 | int k; |
613 | |
|
614 | 0 | if (sal == 0 && alpha == 255 && blendmode == 0) |
615 | 0 | { |
616 | | /* In this case, the uncompositing and the recompositing |
617 | | * cancel one another out, and it's just a simple copy. */ |
618 | | /* FIXME: Maybe we can avoid using the shape plane entirely |
619 | | * and just copy? */ |
620 | 0 | do |
621 | 0 | { |
622 | 0 | int ha = fz_mul255(*hp++, alpha); /* ha = shape_alpha */ |
623 | | /* If ha == 0 then leave everything unchanged */ |
624 | 0 | if (ha != 0) |
625 | 0 | { |
626 | 0 | for (k = 0; k < n1; k++) |
627 | 0 | bp[k] = sp[k]; |
628 | 0 | if (bal) |
629 | 0 | bp[k] = 255; |
630 | 0 | } |
631 | |
|
632 | 0 | sp += n1; |
633 | 0 | bp += n1 + bal; |
634 | 0 | } |
635 | 0 | while (--w); |
636 | 0 | return; |
637 | 0 | } |
638 | 0 | do |
639 | 0 | { |
640 | 0 | int ha = *hp++; |
641 | 0 | int haa = fz_mul255(ha, alpha); /* ha = shape_alpha */ |
642 | | /* If haa == 0 then leave everything unchanged */ |
643 | 0 | while (haa != 0) /* Use while, so we can break out */ |
644 | 0 | { |
645 | 0 | int sa, ba, bahaa, ra, ra0, invsa, invba, scale; |
646 | 0 | sa = (sal ? sp[n1] : 255); |
647 | 0 | if (sa == 0) |
648 | 0 | break; /* No change! */ |
649 | 0 | invsa = 255 * 256 / sa; |
650 | 0 | ba = (bal ? bp[n1] : 255); |
651 | 0 | if (ba == 0) |
652 | 0 | { |
653 | | /* Just copy pixels (allowing for change in |
654 | | * premultiplied alphas) */ |
655 | 0 | for (k = 0; k < n1; k++) |
656 | 0 | bp[k] = fz_mul255((sp[k] * invsa) >> 8, haa); |
657 | 0 | if (bal) |
658 | 0 | bp[n1] = haa; |
659 | 0 | break; |
660 | 0 | } |
661 | 0 | invba = 255 * 256 / ba; |
662 | | |
663 | | /* Because we are in a non-isolated group, we need to |
664 | | * do some 'uncomposition' magic before we blend. |
665 | | * My attempts to understand what is going on here have |
666 | | * utterly failed, so I've resorted (after much patient |
667 | | * help from Michael) to copying what the gs code does. |
668 | | * This seems to be an implementation of the equations |
669 | | * given on page 236 (section 7.3.3) of pdf_reference17. |
670 | | * My understanding is that this is "composition" when |
671 | | * we actually want to do "decomposition", hence my |
672 | | * confusion. It appears to work though. |
673 | | */ |
674 | 0 | scale = (512 * ba + ha) / (ha*2) - FZ_EXPAND(ba); |
675 | |
|
676 | 0 | sa = haa; |
677 | | |
678 | | /* Calculate result_alpha - a combination of the |
679 | | * background alpha, and 'shape' */ |
680 | 0 | bahaa = fz_mul255(ba, haa); |
681 | 0 | ra0 = ba - bahaa; |
682 | 0 | ra = ra0 + haa; |
683 | 0 | if (bal) |
684 | 0 | bp[n1] = ra; |
685 | |
|
686 | 0 | if (ra == 0) |
687 | 0 | break; |
688 | | |
689 | | /* Process colorants */ |
690 | 0 | for (k = 0; k < first_spot; k++) |
691 | 0 | { |
692 | | /* Read pixels (and convert to non-premultiplied form) */ |
693 | 0 | int sc = (sp[k] * invsa) >> 8; |
694 | 0 | int bc = (bp[k] * invba) >> 8; |
695 | 0 | int rc; |
696 | |
|
697 | 0 | if (complement) |
698 | 0 | { |
699 | 0 | sc = 255 - sc; |
700 | 0 | bc = 255 - bc; |
701 | 0 | } |
702 | | |
703 | | /* Uncomposite (see above) */ |
704 | 0 | sc = sc + (((sc-bc) * scale)>>8); |
705 | 0 | sc = fz_clampi(sc, 0, 255); |
706 | |
|
707 | 0 | switch (blendmode) |
708 | 0 | { |
709 | 0 | default: |
710 | 0 | case FZ_BLEND_NORMAL: rc = sc; break; |
711 | 0 | case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break; |
712 | 0 | case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break; |
713 | 0 | case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break; |
714 | 0 | case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break; |
715 | 0 | case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break; |
716 | 0 | case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break; |
717 | 0 | case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break; |
718 | 0 | case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break; |
719 | 0 | case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break; |
720 | 0 | case FZ_BLEND_DIFFERENCE: rc = fz_difference_byte(bc, sc); break; |
721 | 0 | case FZ_BLEND_EXCLUSION: rc = fz_exclusion_byte(bc, sc); break; |
722 | 0 | } |
723 | | |
724 | | /* From the notes at the top: |
725 | | * |
726 | | * Ar * Cr = Cb * (Ar - alpha * As) + alpha * As * (1 - Ab) * Cs + alpha * As * Ab * B(Cb, Cs) ] |
727 | | * |
728 | | * And: |
729 | | * |
730 | | * Ar = ba + haa - bahaa |
731 | | * |
732 | | * In our 0..255 world, with our current variables: |
733 | | * |
734 | | * ra.rc = bc * (ra - haa) + haa * (255 - ba) * sc + bahaa * B(Cb, Cs) |
735 | | * = bc * ra0 + haa * (255 - ba) * sc + bahaa * B(Cb, Cs) |
736 | | */ |
737 | | |
738 | 0 | if (bahaa != 255) |
739 | 0 | rc = fz_mul255(bahaa, rc); |
740 | 0 | if (ba != 255) |
741 | 0 | { |
742 | 0 | int t = fz_mul255(255 - ba, haa); |
743 | 0 | rc += fz_mul255(t, sc); |
744 | 0 | } |
745 | 0 | if (ra0 != 0) |
746 | 0 | rc += fz_mul255(ra0, bc); |
747 | |
|
748 | 0 | if (complement) |
749 | 0 | rc = ra - rc; |
750 | |
|
751 | 0 | bp[k] = fz_clampi(rc, 0, ra); |
752 | 0 | } |
753 | | |
754 | | /* Spots */ |
755 | 0 | for (; k < n1; k++) |
756 | 0 | { |
757 | 0 | int sc = 255 - ((sp[k] * invsa + 128) >> 8); |
758 | 0 | int bc = 255 - ((bp[k] * invba + 128) >> 8); |
759 | 0 | int rc; |
760 | |
|
761 | 0 | sc = sc + (((sc-bc) * scale)>>8); |
762 | | |
763 | | /* Non-white preserving use Normal */ |
764 | 0 | switch (blendmode) |
765 | 0 | { |
766 | 0 | default: |
767 | 0 | case FZ_BLEND_NORMAL: |
768 | 0 | case FZ_BLEND_DIFFERENCE: |
769 | 0 | case FZ_BLEND_EXCLUSION: |
770 | 0 | rc = sc; break; |
771 | 0 | case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break; |
772 | 0 | case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break; |
773 | 0 | case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break; |
774 | 0 | case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break; |
775 | 0 | case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break; |
776 | 0 | case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break; |
777 | 0 | case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break; |
778 | 0 | case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break; |
779 | 0 | case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break; |
780 | 0 | } |
781 | | |
782 | 0 | if (bahaa != 255) |
783 | 0 | rc = fz_mul255(bahaa, rc); |
784 | 0 | if (ba != 255) |
785 | 0 | { |
786 | 0 | int t = fz_mul255(255 - ba, haa); |
787 | 0 | rc += fz_mul255(t, sc); |
788 | 0 | } |
789 | 0 | if (ra0 != 0) |
790 | 0 | rc += fz_mul255(ra0, bc); |
791 | |
|
792 | 0 | bp[k] = ra - rc; |
793 | 0 | } |
794 | 0 | break; |
795 | 0 | } |
796 | | |
797 | 0 | sp += n1 + sal; |
798 | 0 | bp += n1 + bal; |
799 | 0 | } |
800 | 0 | while (--w); |
801 | 0 | } |
802 | | |
803 | | static inline void |
804 | | fz_blend_nonseparable_nonisolated_gray(byte * FZ_RESTRICT bp, int bal, const byte * FZ_RESTRICT sp, int sal, int n, int w, int blendmode, const byte * FZ_RESTRICT hp, int alpha, int first_spot) |
805 | 0 | { |
806 | 0 | do |
807 | 0 | { |
808 | 0 | int ha = *hp++; |
809 | 0 | int haa = fz_mul255(ha, alpha); |
810 | 0 | if (haa != 0) |
811 | 0 | { |
812 | 0 | int ba = (bal ? bp[n] : 255); |
813 | |
|
814 | 0 | if (ba == 0 && alpha == 255) |
815 | 0 | { |
816 | 0 | memcpy(bp, sp, n + (sal && bal)); |
817 | 0 | if (bal && !sal) |
818 | 0 | bp[n+1] = 255; |
819 | 0 | } |
820 | 0 | else |
821 | 0 | { |
822 | 0 | int sa = (sal ? sp[n] : 255); |
823 | 0 | int bahaa = fz_mul255(ba, haa); |
824 | 0 | int k; |
825 | | |
826 | | /* Calculate result_alpha */ |
827 | 0 | int ra = ba - bahaa + haa; |
828 | 0 | if (bal) |
829 | 0 | bp[n] = ra; |
830 | 0 | if (ra != 0) |
831 | 0 | { |
832 | 0 | int invha = ha ? 255 * 256 / ha : 0; |
833 | | |
834 | | /* ugh, division to get non-premul components */ |
835 | 0 | int invsa = sa ? 255 * 256 / sa : 0; |
836 | 0 | int invba = ba ? 255 * 256 / ba : 0; |
837 | |
|
838 | 0 | int sg = (sp[0] * invsa) >> 8; |
839 | 0 | int bg = (bp[0] * invba) >> 8; |
840 | | |
841 | | /* Uncomposite */ |
842 | 0 | sg = (((sg - bg)*invha) >> 8) + bg; |
843 | 0 | sg = fz_clampi(sg, 0, 255); |
844 | |
|
845 | 0 | switch (blendmode) |
846 | 0 | { |
847 | 0 | default: |
848 | 0 | case FZ_BLEND_HUE: |
849 | 0 | case FZ_BLEND_SATURATION: |
850 | 0 | case FZ_BLEND_COLOR: |
851 | 0 | bp[0] = fz_mul255(ra, bg); |
852 | 0 | break; |
853 | 0 | case FZ_BLEND_LUMINOSITY: |
854 | 0 | bp[0] = fz_mul255(ra, sg); |
855 | 0 | break; |
856 | 0 | } |
857 | | |
858 | | /* Normal blend for spots */ |
859 | 0 | for (k = first_spot; k < n; k++) |
860 | 0 | { |
861 | 0 | int sc = (sp[k] * invsa + 128) >> 8; |
862 | 0 | int bc = (bp[k] * invba + 128) >> 8; |
863 | 0 | int rc; |
864 | |
|
865 | 0 | sc = (((sc - bc) * invha + 128) >> 8) + bc; |
866 | 0 | sc = fz_clampi(sc, 0, 255); |
867 | 0 | rc = bc + fz_mul255(sa, fz_mul255(255 - ba, sc) + fz_mul255(ba, sc) - bc); |
868 | 0 | rc = fz_clampi(rc, 0, 255); |
869 | 0 | bp[k] = fz_mul255(rc, ra); |
870 | 0 | } |
871 | 0 | } |
872 | 0 | } |
873 | 0 | } |
874 | 0 | sp += n + sal; |
875 | 0 | bp += n + bal; |
876 | 0 | } while (--w); |
877 | 0 | } |
878 | | |
879 | | static inline void |
880 | | fz_blend_nonseparable_nonisolated(byte * FZ_RESTRICT bp, int bal, const byte * FZ_RESTRICT sp, int sal, int n, int w, int blendmode, int complement, const byte * FZ_RESTRICT hp, int alpha, int first_spot) |
881 | 0 | { |
882 | 0 | do |
883 | 0 | { |
884 | 0 | int ha = *hp++; |
885 | 0 | int haa = fz_mul255(ha, alpha); |
886 | 0 | if (haa != 0) |
887 | 0 | { |
888 | 0 | int sa = (sal ? sp[n] : 255); |
889 | 0 | int ba = (bal ? bp[n] : 255); |
890 | |
|
891 | 0 | if (ba == 0 && alpha == 255) |
892 | 0 | { |
893 | 0 | memcpy(bp, sp, n + (sal && bal)); |
894 | 0 | if (bal && !sal) |
895 | 0 | bp[n] = 255; |
896 | 0 | } |
897 | 0 | else |
898 | 0 | { |
899 | 0 | int bahaa = fz_mul255(ba, haa); |
900 | | |
901 | | /* Calculate result_alpha */ |
902 | 0 | int ra0 = ba - bahaa; |
903 | 0 | int ra = ra0 + haa; |
904 | |
|
905 | 0 | if (bal) |
906 | 0 | bp[n] = ra; |
907 | |
|
908 | 0 | if (ra != 0) |
909 | 0 | { |
910 | | /* Because we are a non-isolated group, we |
911 | | * need to 'uncomposite' before we blend |
912 | | * (recomposite). We assume that normal |
913 | | * blending has been done inside the group, |
914 | | * so: ra.rc = (1-ha).bc + ha.sc |
915 | | * A bit of rearrangement, and that gives us |
916 | | * that: sc = (ra.rc - bc)/ha + bc |
917 | | * Now, the result of the blend was stored in |
918 | | * src, so: */ |
919 | 0 | int invha = ha ? 255 * 256 / ha : 0; |
920 | 0 | int k; |
921 | 0 | unsigned char rr, rg, rb; |
922 | | |
923 | | /* ugh, division to get non-premul components */ |
924 | 0 | int invsa = sa ? 255 * 256 / sa : 0; |
925 | 0 | int invba = ba ? 255 * 256 / ba : 0; |
926 | |
|
927 | 0 | int sr = (sp[0] * invsa) >> 8; |
928 | 0 | int sg = (sp[1] * invsa) >> 8; |
929 | 0 | int sb = (sp[2] * invsa) >> 8; |
930 | |
|
931 | 0 | int br = (bp[0] * invba) >> 8; |
932 | 0 | int bg = (bp[1] * invba) >> 8; |
933 | 0 | int bb = (bp[2] * invba) >> 8; |
934 | |
|
935 | 0 | if (complement) |
936 | 0 | { |
937 | 0 | sr = 255 - sr; |
938 | 0 | sg = 255 - sg; |
939 | 0 | sb = 255 - sb; |
940 | 0 | br = 255 - br; |
941 | 0 | bg = 255 - bg; |
942 | 0 | bb = 255 - bb; |
943 | 0 | } |
944 | | |
945 | | /* Uncomposite */ |
946 | 0 | sr = (((sr - br)*invha) >> 8) + br; |
947 | 0 | sr = fz_clampi(sr, 0, 255); |
948 | 0 | sg = (((sg - bg)*invha) >> 8) + bg; |
949 | 0 | sg = fz_clampi(sg, 0, 255); |
950 | 0 | sb = (((sb - bb)*invha) >> 8) + bb; |
951 | 0 | sb = fz_clampi(sb, 0, 255); |
952 | |
|
953 | 0 | switch (blendmode) |
954 | 0 | { |
955 | 0 | default: |
956 | 0 | case FZ_BLEND_HUE: |
957 | 0 | fz_hue_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); |
958 | 0 | break; |
959 | 0 | case FZ_BLEND_SATURATION: |
960 | 0 | fz_saturation_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); |
961 | 0 | break; |
962 | 0 | case FZ_BLEND_COLOR: |
963 | 0 | fz_color_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); |
964 | 0 | break; |
965 | 0 | case FZ_BLEND_LUMINOSITY: |
966 | 0 | fz_luminosity_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb); |
967 | 0 | break; |
968 | 0 | } |
969 | | |
970 | | /* From the notes at the top: |
971 | | * |
972 | | * Ar * Cr = Cb * (Ar - alpha * As) + alpha * As * (1 - Ab) * Cs + alpha * As * Ab * B(Cb, Cs) ] |
973 | | * |
974 | | * And: |
975 | | * |
976 | | * Ar = ba + haa - bahaa |
977 | | * |
978 | | * In our 0..255 world, with our current variables: |
979 | | * |
980 | | * ra.rc = bc * (ra - haa) + haa * (255 - ba) * sc + bahaa * B(Cb, Cs) |
981 | | * = bc * ra0 + haa * (255 - ba) * sc + bahaa * B(Cb, Cs) |
982 | | */ |
983 | | |
984 | 0 | if (bahaa != 255) |
985 | 0 | { |
986 | 0 | rr = fz_mul255(bahaa, rr); |
987 | 0 | rg = fz_mul255(bahaa, rg); |
988 | 0 | rb = fz_mul255(bahaa, rb); |
989 | 0 | } |
990 | 0 | if (ba != 255) |
991 | 0 | { |
992 | 0 | int t = fz_mul255(255 - ba, haa); |
993 | 0 | rr += fz_mul255(t, sr); |
994 | 0 | rg += fz_mul255(t, sg); |
995 | 0 | rb += fz_mul255(t, sb); |
996 | 0 | } |
997 | 0 | if (ra0 != 0) |
998 | 0 | { |
999 | 0 | rr += fz_mul255(ra0, br); |
1000 | 0 | rg += fz_mul255(ra0, bg); |
1001 | 0 | rb += fz_mul255(ra0, bb); |
1002 | 0 | } |
1003 | | |
1004 | | /* CMYK */ |
1005 | 0 | if (complement) |
1006 | 0 | { |
1007 | 0 | int sk, bk, rk; |
1008 | | |
1009 | | /* Care must be taking when inverting here, as r = alpha * col. |
1010 | | * We want to store alpha * (255 - col) = alpha * 255 - alpha * col |
1011 | | */ |
1012 | 0 | rr = ra - rr; |
1013 | 0 | rg = ra - rg; |
1014 | 0 | rb = ra - rb; |
1015 | |
|
1016 | 0 | sk = sa ? (sp[3] * invsa) >> 8 : 255; |
1017 | 0 | bk = ba ? (bp[3] * invba) >> 8 : 255; |
1018 | |
|
1019 | 0 | bk = fz_clampi(bk, 0, 255); |
1020 | 0 | sk = fz_clampi(sk, 0, 255); |
1021 | |
|
1022 | 0 | if (blendmode == FZ_BLEND_LUMINOSITY) |
1023 | 0 | rk = sk; |
1024 | 0 | else |
1025 | 0 | rk = bk; |
1026 | |
|
1027 | 0 | if (bahaa != 255) |
1028 | 0 | rk = fz_mul255(bahaa, rk); |
1029 | |
|
1030 | 0 | if (ba != 255) |
1031 | 0 | { |
1032 | 0 | int t = fz_mul255(255 - ba, haa); |
1033 | 0 | rk += fz_mul255(t, sk); |
1034 | 0 | } |
1035 | |
|
1036 | 0 | if (ra0 != 0) |
1037 | 0 | rk += fz_mul255(ra0, bk); |
1038 | |
|
1039 | 0 | bp[3] = rk; |
1040 | 0 | } |
1041 | |
|
1042 | 0 | bp[0] = rr; |
1043 | 0 | bp[1] = rg; |
1044 | 0 | bp[2] = rb; |
1045 | | |
1046 | | /* Normal blend for spots */ |
1047 | 0 | for (k = first_spot; k < n; k++) |
1048 | 0 | { |
1049 | 0 | int sc = (sp[k] * invsa + 128) >> 8; |
1050 | 0 | int bc = (bp[k] * invba + 128) >> 8; |
1051 | 0 | int rc; |
1052 | |
|
1053 | 0 | sc = (((sc - bc) * invha + 128) >> 8) + bc; |
1054 | 0 | sc = fz_clampi(sc, 0, 255); |
1055 | 0 | rc = bc + fz_mul255(ha, fz_mul255(255 - ba, sc) + fz_mul255(ba, sc) - bc); |
1056 | 0 | rc = fz_clampi(rc, 0, 255); |
1057 | 0 | bp[k] = fz_mul255(rc, ra); |
1058 | 0 | } |
1059 | 0 | } |
1060 | 0 | } |
1061 | 0 | } |
1062 | 0 | sp += n + sal; |
1063 | 0 | bp += n + bal; |
1064 | 0 | } |
1065 | 0 | while (--w); |
1066 | 0 | } |
1067 | | |
1068 | | #ifdef PARANOID_PREMULTIPLY |
1069 | | static void |
1070 | | verify_premultiply(fz_context *ctx, const fz_pixmap * FZ_RESTRICT dst) |
1071 | | { |
1072 | | unsigned char *dp = dst->samples; |
1073 | | int w = dst->w; |
1074 | | int h = dst->h; |
1075 | | int n = dst->n; |
1076 | | int x, y, i; |
1077 | | int s = dst->stride - n * w; |
1078 | | |
1079 | | for (y = h; y > 0; y--) |
1080 | | { |
1081 | | for (x = w; x > 0; x--) |
1082 | | { |
1083 | | int a = dp[n-1]; |
1084 | | for (i = n-1; i > 0; i--) |
1085 | | if (*dp++ > a) |
1086 | | abort(); |
1087 | | dp++; |
1088 | | } |
1089 | | dp += s; |
1090 | | } |
1091 | | } |
1092 | | #endif |
1093 | | |
1094 | | void |
1095 | | fz_blend_pixmap(fz_context *ctx, fz_pixmap * FZ_RESTRICT dst, fz_pixmap * FZ_RESTRICT src, int alpha, int blendmode, int isolated, const fz_pixmap * FZ_RESTRICT shape) |
1096 | 0 | { |
1097 | 0 | unsigned char *sp; |
1098 | 0 | unsigned char *dp; |
1099 | 0 | fz_irect bbox; |
1100 | 0 | int x, y, w, h, n; |
1101 | 0 | int da, sa; |
1102 | 0 | int complement; |
1103 | | |
1104 | | /* TODO: fix this hack! */ |
1105 | 0 | if (isolated && alpha < 255) |
1106 | 0 | { |
1107 | 0 | unsigned char *sp2; |
1108 | 0 | int nn; |
1109 | 0 | h = src->h; |
1110 | 0 | sp2 = src->samples; |
1111 | 0 | nn = src->w * src->n; |
1112 | 0 | while (h--) |
1113 | 0 | { |
1114 | 0 | n = nn; |
1115 | 0 | while (n--) |
1116 | 0 | { |
1117 | 0 | *sp2 = fz_mul255(*sp2, alpha); |
1118 | 0 | sp2++; |
1119 | 0 | } |
1120 | 0 | sp2 += src->stride - nn; |
1121 | 0 | } |
1122 | 0 | } |
1123 | |
|
1124 | 0 | bbox = fz_intersect_irect(fz_pixmap_bbox(ctx, src), fz_pixmap_bbox(ctx, dst)); |
1125 | |
|
1126 | 0 | x = bbox.x0; |
1127 | 0 | y = bbox.y0; |
1128 | 0 | w = fz_irect_width(bbox); |
1129 | 0 | h = fz_irect_height(bbox); |
1130 | 0 | if (w == 0 || h == 0) |
1131 | 0 | return; |
1132 | | |
1133 | 0 | complement = fz_colorspace_is_subtractive(ctx, src->colorspace); |
1134 | 0 | n = src->n; |
1135 | 0 | sp = src->samples + (y - src->y) * (size_t)src->stride + (x - src->x) * (size_t)src->n; |
1136 | 0 | sa = src->alpha; |
1137 | 0 | dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x - dst->x) * (size_t)dst->n; |
1138 | 0 | da = dst->alpha; |
1139 | |
|
1140 | 0 | if (n == 1) |
1141 | 0 | sa = da = 0; |
1142 | |
|
1143 | | #ifdef PARANOID_PREMULTIPLY |
1144 | | if (sa) |
1145 | | verify_premultiply(ctx, src); |
1146 | | if (da) |
1147 | | verify_premultiply(ctx, dst); |
1148 | | #endif |
1149 | |
|
1150 | 0 | n -= sa; |
1151 | 0 | assert(n == dst->n - da); |
1152 | |
|
1153 | 0 | if (!isolated) |
1154 | 0 | { |
1155 | 0 | const unsigned char *hp = shape->samples + (y - shape->y) * (size_t)shape->stride + (x - shape->x); |
1156 | |
|
1157 | 0 | while (h--) |
1158 | 0 | { |
1159 | 0 | if (blendmode >= FZ_BLEND_HUE) |
1160 | 0 | { |
1161 | 0 | if (complement || src->s > 0) |
1162 | 0 | if ((n - src->s) == 1) |
1163 | 0 | fz_blend_nonseparable_nonisolated_gray(dp, da, sp, sa, n, w, blendmode, hp, alpha, 1); |
1164 | 0 | else |
1165 | 0 | fz_blend_nonseparable_nonisolated(dp, da, sp, sa, n, w, blendmode, complement, hp, alpha, n - src->s); |
1166 | 0 | else |
1167 | 0 | if (da) |
1168 | 0 | if (sa) |
1169 | 0 | if (n == 1) |
1170 | 0 | fz_blend_nonseparable_nonisolated_gray(dp, 1, sp, 1, 1, w, blendmode, hp, alpha, 1); |
1171 | 0 | else |
1172 | 0 | fz_blend_nonseparable_nonisolated(dp, 1, sp, 1, n, w, blendmode, complement, hp, alpha, n); |
1173 | 0 | else |
1174 | 0 | if (n == 1) |
1175 | 0 | fz_blend_nonseparable_nonisolated_gray(dp, 1, sp, 0, 1, w, blendmode, hp, alpha, 1); |
1176 | 0 | else |
1177 | 0 | fz_blend_nonseparable_nonisolated(dp, 1, sp, 0, n, w, blendmode, complement, hp, alpha, n); |
1178 | 0 | else |
1179 | 0 | if (sa) |
1180 | 0 | if (n == 1) |
1181 | 0 | fz_blend_nonseparable_nonisolated_gray(dp, 0, sp, 1, 1, w, blendmode, hp, alpha, 1); |
1182 | 0 | else |
1183 | 0 | fz_blend_nonseparable_nonisolated(dp, 0, sp, 1, n, w, blendmode, complement, hp, alpha, n); |
1184 | 0 | else |
1185 | 0 | if (n == 1) |
1186 | 0 | fz_blend_nonseparable_nonisolated_gray(dp, 0, sp, 0, 1, w, blendmode, hp, alpha, 1); |
1187 | 0 | else |
1188 | 0 | fz_blend_nonseparable_nonisolated(dp, 0, sp, 0, n, w, blendmode, complement, hp, alpha, n); |
1189 | 0 | } |
1190 | 0 | else |
1191 | 0 | { |
1192 | 0 | if (complement || src->s > 0) |
1193 | 0 | fz_blend_separable_nonisolated(dp, da, sp, sa, n, w, blendmode, complement, hp, alpha, n - src->s); |
1194 | 0 | else |
1195 | 0 | if (da) |
1196 | 0 | if (sa) |
1197 | 0 | fz_blend_separable_nonisolated(dp, 1, sp, 1, n, w, blendmode, 0, hp, alpha, n); |
1198 | 0 | else |
1199 | 0 | fz_blend_separable_nonisolated(dp, 1, sp, 0, n, w, blendmode, 0, hp, alpha, n); |
1200 | 0 | else |
1201 | 0 | if (sa) |
1202 | 0 | fz_blend_separable_nonisolated(dp, 0, sp, 1, n, w, blendmode, 0, hp, alpha, n); |
1203 | 0 | else |
1204 | 0 | fz_blend_separable_nonisolated(dp, 0, sp, 0, n, w, blendmode, 0, hp, alpha, n); |
1205 | 0 | } |
1206 | 0 | sp += src->stride; |
1207 | 0 | dp += dst->stride; |
1208 | 0 | hp += shape->stride; |
1209 | 0 | } |
1210 | 0 | } |
1211 | 0 | else |
1212 | 0 | { |
1213 | 0 | while (h--) |
1214 | 0 | { |
1215 | 0 | if (blendmode >= FZ_BLEND_HUE) |
1216 | 0 | { |
1217 | 0 | if (complement || src->s > 0) |
1218 | 0 | if ((n - src->s) == 1) |
1219 | 0 | fz_blend_nonseparable_gray(dp, da, sp, sa, n, w, blendmode, 1); |
1220 | 0 | else |
1221 | 0 | fz_blend_nonseparable(dp, da, sp, sa, n, w, blendmode, complement, n - src->s); |
1222 | 0 | else |
1223 | 0 | if (da) |
1224 | 0 | if (sa) |
1225 | 0 | if (n == 1) |
1226 | 0 | fz_blend_nonseparable_gray(dp, 1, sp, 1, 1, w, blendmode, 1); |
1227 | 0 | else |
1228 | 0 | fz_blend_nonseparable(dp, 1, sp, 1, n, w, blendmode, complement, n); |
1229 | 0 | else |
1230 | 0 | if (n == 1) |
1231 | 0 | fz_blend_nonseparable_gray(dp, 1, sp, 0, 1, w, blendmode, 1); |
1232 | 0 | else |
1233 | 0 | fz_blend_nonseparable(dp, 1, sp, 0, n, w, blendmode, complement, n); |
1234 | 0 | else |
1235 | 0 | if (sa) |
1236 | 0 | if (n == 1) |
1237 | 0 | fz_blend_nonseparable_gray(dp, 0, sp, 1, 1, w, blendmode, 1); |
1238 | 0 | else |
1239 | 0 | fz_blend_nonseparable(dp, 0, sp, 1, n, w, blendmode, complement, n); |
1240 | 0 | else |
1241 | 0 | if (n == 1) |
1242 | 0 | fz_blend_nonseparable_gray(dp, 0, sp, 0, 1, w, blendmode, 1); |
1243 | 0 | else |
1244 | 0 | fz_blend_nonseparable(dp, 0, sp, 0, n, w, blendmode, complement, n); |
1245 | 0 | } |
1246 | 0 | else |
1247 | 0 | { |
1248 | 0 | if (complement || src->s > 0) |
1249 | 0 | fz_blend_separable(dp, da, sp, sa, n, w, blendmode, complement, n - src->s); |
1250 | 0 | else |
1251 | 0 | if (da) |
1252 | 0 | if (sa) |
1253 | 0 | fz_blend_separable(dp, 1, sp, 1, n, w, blendmode, 0, n); |
1254 | 0 | else |
1255 | 0 | fz_blend_separable(dp, 1, sp, 0, n, w, blendmode, 0, n); |
1256 | 0 | else |
1257 | 0 | if (sa) |
1258 | 0 | fz_blend_separable(dp, 0, sp, 1, n, w, blendmode, 0, n); |
1259 | 0 | else |
1260 | 0 | fz_blend_separable(dp, 0, sp, 0, n, w, blendmode, 0, n); |
1261 | 0 | } |
1262 | 0 | sp += src->stride; |
1263 | 0 | dp += dst->stride; |
1264 | 0 | } |
1265 | 0 | } |
1266 | |
|
1267 | | #ifdef PARANOID_PREMULTIPLY |
1268 | | if (da) |
1269 | | verify_premultiply(ctx, dst); |
1270 | | #endif |
1271 | 0 | } |
1272 | | |
1273 | | static inline void |
1274 | | fz_blend_knockout(byte * FZ_RESTRICT bp, int bal, const byte * FZ_RESTRICT sp, int sal, int n1, int w, const byte * FZ_RESTRICT hp) |
1275 | 0 | { |
1276 | 0 | int k; |
1277 | 0 | do |
1278 | 0 | { |
1279 | 0 | int ha = *hp++; |
1280 | |
|
1281 | 0 | if (ha != 0) |
1282 | 0 | { |
1283 | 0 | int sa = (sal ? sp[n1] : 255); |
1284 | 0 | int ba = (bal ? bp[n1] : 255); |
1285 | 0 | if (ba == 0 && ha == 0xFF) |
1286 | 0 | { |
1287 | 0 | memcpy(bp, sp, n1); |
1288 | 0 | if (bal) |
1289 | 0 | bp[n1] = sa; |
1290 | 0 | } |
1291 | 0 | else |
1292 | 0 | { |
1293 | 0 | int hasa = fz_mul255(ha, sa); |
1294 | | /* ugh, division to get non-premul components */ |
1295 | 0 | int invsa = sa ? 255 * 256 / sa : 0; |
1296 | 0 | int invba = ba ? 255 * 256 / ba : 0; |
1297 | 0 | int ra = hasa + fz_mul255(255-ha, ba); |
1298 | | |
1299 | | /* Process colorants + spots */ |
1300 | 0 | for (k = 0; k < n1; k++) |
1301 | 0 | { |
1302 | 0 | int sc = (sp[k] * invsa) >> 8; |
1303 | 0 | int bc = (bp[k] * invba) >> 8; |
1304 | 0 | int rc = fz_mul255(255 - ha, bc) + fz_mul255(ha, sc); |
1305 | |
|
1306 | 0 | bp[k] = fz_mul255(ra, rc); |
1307 | 0 | } |
1308 | |
|
1309 | 0 | if (bal) |
1310 | 0 | bp[k] = ra; |
1311 | 0 | } |
1312 | 0 | } |
1313 | 0 | sp += n1 + sal; |
1314 | 0 | bp += n1 + bal; |
1315 | 0 | } |
1316 | 0 | while (--w); |
1317 | 0 | } |
1318 | | |
1319 | | void |
1320 | | fz_blend_pixmap_knockout(fz_context *ctx, fz_pixmap * FZ_RESTRICT dst, fz_pixmap * FZ_RESTRICT src, const fz_pixmap * FZ_RESTRICT shape) |
1321 | 0 | { |
1322 | 0 | unsigned char *sp; |
1323 | 0 | unsigned char *dp; |
1324 | 0 | fz_irect sbox, dbox, bbox; |
1325 | 0 | int x, y, w, h, n; |
1326 | 0 | int da, sa; |
1327 | 0 | const unsigned char *hp; |
1328 | |
|
1329 | 0 | dbox = fz_pixmap_bbox_no_ctx(dst); |
1330 | 0 | sbox = fz_pixmap_bbox_no_ctx(src); |
1331 | 0 | bbox = fz_intersect_irect(dbox, sbox); |
1332 | |
|
1333 | 0 | x = bbox.x0; |
1334 | 0 | y = bbox.y0; |
1335 | 0 | w = fz_irect_width(bbox); |
1336 | 0 | h = fz_irect_height(bbox); |
1337 | 0 | if (w == 0 || h == 0) |
1338 | 0 | return; |
1339 | | |
1340 | 0 | n = src->n; |
1341 | 0 | sp = src->samples + (y - src->y) * (size_t)src->stride + (x - src->x) * (size_t)src->n; |
1342 | 0 | sa = src->alpha; |
1343 | 0 | dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x - dst->x) * (size_t)dst->n; |
1344 | 0 | da = dst->alpha; |
1345 | 0 | hp = shape->samples + (y - shape->y) * (size_t)shape->stride + (x - shape->x); |
1346 | |
|
1347 | | #ifdef PARANOID_PREMULTIPLY |
1348 | | if (sa) |
1349 | | verify_premultiply(ctx, src); |
1350 | | if (da) |
1351 | | verify_premultiply(ctx, dst); |
1352 | | #endif |
1353 | |
|
1354 | 0 | n -= sa; |
1355 | 0 | assert(n == dst->n - da); |
1356 | |
|
1357 | 0 | while (h--) |
1358 | 0 | { |
1359 | 0 | fz_blend_knockout(dp, da, sp, sa, n, w, hp); |
1360 | 0 | sp += src->stride; |
1361 | 0 | dp += dst->stride; |
1362 | 0 | hp += shape->stride; |
1363 | 0 | } |
1364 | |
|
1365 | | #ifdef PARANOID_PREMULTIPLY |
1366 | | if (da) |
1367 | | verify_premultiply(ctx, dst); |
1368 | | #endif |
1369 | 0 | } |