comparison mupdf-source/source/fitz/draw-blend.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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 {
133 int i;
134 for (i = 0; i < (int)nelem(fz_blendmode_names); i++)
135 if (!strcmp(name, fz_blendmode_names[i]))
136 return i;
137 return FZ_BLEND_NORMAL;
138 }
139
140 const char *fz_blendmode_name(int blendmode)
141 {
142 if (blendmode >= 0 && blendmode < (int)nelem(fz_blendmode_names))
143 return fz_blendmode_names[blendmode];
144 return "Normal";
145 }
146
147 /* Separable blend modes */
148
149 static inline int fz_screen_byte(int b, int s)
150 {
151 return b + s - fz_mul255(b, s);
152 }
153
154 static inline int fz_hard_light_byte(int b, int s)
155 {
156 int s2 = s << 1;
157 if (s <= 127)
158 return fz_mul255(b, s2);
159 else
160 return fz_screen_byte(b, s2 - 255);
161 }
162
163 static inline int fz_overlay_byte(int b, int s)
164 {
165 return fz_hard_light_byte(s, b); /* note swapped order */
166 }
167
168 static inline int fz_darken_byte(int b, int s)
169 {
170 return fz_mini(b, s);
171 }
172
173 static inline int fz_lighten_byte(int b, int s)
174 {
175 return fz_maxi(b, s);
176 }
177
178 static inline int fz_color_dodge_byte(int b, int s)
179 {
180 s = 255 - s;
181 if (b <= 0)
182 return 0;
183 else if (b >= s)
184 return 255;
185 else
186 return (0x1fe * b + s) / (s << 1);
187 }
188
189 static inline int fz_color_burn_byte(int b, int s)
190 {
191 b = 255 - b;
192 if (b <= 0)
193 return 255;
194 else if (b >= s)
195 return 0;
196 else
197 return 0xff - (0x1fe * b + s) / (s << 1);
198 }
199
200 static inline int fz_soft_light_byte(int b, int s)
201 {
202 if (s < 128) {
203 return b - fz_mul255(fz_mul255((255 - (s<<1)), b), 255 - b);
204 }
205 else {
206 int dbd;
207 if (b < 64)
208 dbd = fz_mul255(fz_mul255((b << 4) - 3060, b) + 1020, b);
209 else
210 dbd = (int)sqrtf(255.0f * b);
211 return b + fz_mul255(((s<<1) - 255), (dbd - b));
212 }
213 }
214
215 static inline int fz_difference_byte(int b, int s)
216 {
217 return fz_absi(b - s);
218 }
219
220 static inline int fz_exclusion_byte(int b, int s)
221 {
222 return b + s - (fz_mul255(b, s)<<1);
223 }
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 {
230 int delta, scale;
231 int r, g, b, y;
232
233 /* 0.3f, 0.59f, 0.11f in fixed point */
234 delta = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
235 r = rb + delta;
236 g = gb + delta;
237 b = bb + delta;
238
239 if ((r | g | b) & 0x100)
240 {
241 y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8;
242 if (delta > 0)
243 {
244 int max;
245 max = fz_maxi(r, fz_maxi(g, b));
246 scale = (max == y ? 0 : ((255 - y) << 16) / (max - y));
247 }
248 else
249 {
250 int min;
251 min = fz_mini(r, fz_mini(g, b));
252 scale = (y == min ? 0 : (y << 16) / (y - min));
253 }
254 r = y + (((r - y) * scale + 0x8000) >> 16);
255 g = y + (((g - y) * scale + 0x8000) >> 16);
256 b = y + (((b - y) * scale + 0x8000) >> 16);
257 }
258
259 *rd = fz_clampi(r, 0, 255);
260 *gd = fz_clampi(g, 0, 255);
261 *bd = fz_clampi(b, 0, 255);
262 }
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 {
267 int minb, maxb;
268 int mins, maxs;
269 int y;
270 int scale;
271 int r, g, b;
272
273 minb = fz_mini(rb, fz_mini(gb, bb));
274 maxb = fz_maxi(rb, fz_maxi(gb, bb));
275 if (minb == maxb)
276 {
277 /* backdrop has zero saturation, avoid divide by 0 */
278 gb = fz_clampi(gb, 0, 255);
279 *rd = gb;
280 *gd = gb;
281 *bd = gb;
282 return;
283 }
284
285 mins = fz_mini(rs, fz_mini(gs, bs));
286 maxs = fz_maxi(rs, fz_maxi(gs, bs));
287
288 scale = ((maxs - mins) << 16) / (maxb - minb);
289 y = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
290 r = y + ((((rb - y) * scale) + 0x8000) >> 16);
291 g = y + ((((gb - y) * scale) + 0x8000) >> 16);
292 b = y + ((((bb - y) * scale) + 0x8000) >> 16);
293
294 if ((r | g | b) & 0x100)
295 {
296 int scalemin, scalemax;
297 int min, max;
298
299 min = fz_mini(r, fz_mini(g, b));
300 max = fz_maxi(r, fz_maxi(g, b));
301
302 if (min < 0)
303 scalemin = (y << 16) / (y - min);
304 else
305 scalemin = 0x10000;
306
307 if (max > 255)
308 scalemax = ((255 - y) << 16) / (max - y);
309 else
310 scalemax = 0x10000;
311
312 scale = fz_mini(scalemin, scalemax);
313 r = y + (((r - y) * scale + 0x8000) >> 16);
314 g = y + (((g - y) * scale + 0x8000) >> 16);
315 b = y + (((b - y) * scale + 0x8000) >> 16);
316 }
317
318 *rd = fz_clampi(r, 0, 255);
319 *gd = fz_clampi(g, 0, 255);
320 *bd = fz_clampi(b, 0, 255);
321 }
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 {
326 fz_luminosity_rgb(rr, rg, rb, sr, sg, sb, br, bg, bb);
327 }
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 {
332 unsigned char tr, tg, tb;
333 fz_luminosity_rgb(&tr, &tg, &tb, sr, sg, sb, br, bg, bb);
334 fz_saturation_rgb(rr, rg, rb, tr, tg, tb, br, bg, bb);
335 }
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 {
342 int k;
343 do
344 {
345 int sa = (sal ? sp[n1] : 255);
346
347 if (sa != 0)
348 {
349 int ba = (bal ? bp[n1] : 255);
350 if (ba == 0)
351 {
352 memcpy(bp, sp, n1 + (sal && bal));
353 if (bal && !sal)
354 bp[n1+1] = 255;
355 }
356 else
357 {
358 int saba = fz_mul255(sa, ba);
359
360 /* ugh, division to get non-premul components */
361 int invsa = sa ? 255 * 256 / sa : 0;
362 int invba = ba ? 255 * 256 / ba : 0;
363
364 /* Process colorants */
365 for (k = 0; k < first_spot; k++)
366 {
367 int sc = (sp[k] * invsa) >> 8;
368 int bc = (bp[k] * invba) >> 8;
369 int rc;
370
371 if (complement)
372 {
373 sc = 255 - sc;
374 bc = 255 - bc;
375 }
376
377 switch (blendmode)
378 {
379 default:
380 case FZ_BLEND_NORMAL: rc = sc; break;
381 case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break;
382 case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break;
383 case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break;
384 case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break;
385 case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break;
386 case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break;
387 case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break;
388 case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break;
389 case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break;
390 case FZ_BLEND_DIFFERENCE: rc = fz_difference_byte(bc, sc); break;
391 case FZ_BLEND_EXCLUSION: rc = fz_exclusion_byte(bc, sc); break;
392 }
393
394 if (complement)
395 {
396 rc = 255 - rc;
397 }
398
399 bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, rc);
400 }
401
402 /* spots */
403 for (; k < n1; k++)
404 {
405 int sc = 255 - ((sp[k] * invsa) >> 8);
406 int bc = 255 - ((bp[k] * invba) >> 8);
407 int rc;
408
409 switch (blendmode)
410 {
411 default:
412 case FZ_BLEND_NORMAL:
413 case FZ_BLEND_DIFFERENCE:
414 case FZ_BLEND_EXCLUSION:
415 rc = sc; break;
416 case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break;
417 case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break;
418 case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break;
419 case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break;
420 case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break;
421 case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break;
422 case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break;
423 case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break;
424 case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break;
425 }
426 bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, 255 - rc);
427 }
428
429 if (bal)
430 bp[k] = ba + sa - saba;
431 }
432 }
433 sp += n1 + sal;
434 bp += n1 + bal;
435 }
436 while (--w);
437 }
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 {
442 do
443 {
444 int sa = (sal ? sp[n] : 255);
445
446 if (sa != 0)
447 {
448 int ba = (bal ? bp[n] : 255);
449 if (ba == 0)
450 {
451 memcpy(bp, sp, n + (sal && bal));
452 if (bal && !sal)
453 bp [n + 1] = 255;
454 }
455 else
456 {
457 int saba = fz_mul255(sa, ba);
458
459 /* ugh, division to get non-premul components */
460 int invsa = 255 * 256 / sa;
461 int invba = 255 * 256 / ba;
462 int k;
463
464 switch (blendmode)
465 {
466 default:
467 case FZ_BLEND_HUE:
468 case FZ_BLEND_SATURATION:
469 case FZ_BLEND_COLOR:
470 {
471 int bg = (bp[0] * invba) >> 8;
472 bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, bg);
473 break;
474 }
475 case FZ_BLEND_LUMINOSITY:
476 {
477 int sg = (sp[0] * invsa) >> 8;
478 bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, sg);
479 break;
480 }
481 }
482
483 /* Normal blend for spots */
484 for (k = first_spot; k < n; k++)
485 {
486 int sc = (sp[k] * invsa) >> 8;
487 bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, sc);
488 }
489 if (bal)
490 bp[n] = ba + sa - saba;
491 }
492 }
493 sp += n + sal;
494 bp += n + bal;
495 } while (--w);
496 }
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 {
501 do
502 {
503 unsigned char rr, rg, rb;
504
505 int sa = (sal ? sp[n] : 255);
506
507 if (sa != 0)
508 {
509 int ba = (bal ? bp[n] : 255);
510 if (ba == 0)
511 {
512 memcpy(bp, sp, n + (sal && bal));
513 if (bal && !sal)
514 bp [n + 1] = 255;
515 }
516 else
517 {
518 int k;
519 int saba = fz_mul255(sa, ba);
520
521 /* ugh, division to get non-premul components */
522 int invsa = 255 * 256 / sa;
523 int invba = 255 * 256 / ba;
524
525 int sr = (sp[0] * invsa) >> 8;
526 int sg = (sp[1] * invsa) >> 8;
527 int sb = (sp[2] * invsa) >> 8;
528
529 int br = (bp[0] * invba) >> 8;
530 int bg = (bp[1] * invba) >> 8;
531 int bb = (bp[2] * invba) >> 8;
532
533 /* CMYK */
534 if (complement)
535 {
536 sr = 255 - sr;
537 sg = 255 - sg;
538 sb = 255 - sb;
539 br = 255 - br;
540 bg = 255 - bg;
541 bb = 255 - bb;
542 }
543
544 switch (blendmode)
545 {
546 default:
547 case FZ_BLEND_HUE:
548 fz_hue_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
549 break;
550 case FZ_BLEND_SATURATION:
551 fz_saturation_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
552 break;
553 case FZ_BLEND_COLOR:
554 fz_color_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
555 break;
556 case FZ_BLEND_LUMINOSITY:
557 fz_luminosity_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
558 break;
559 }
560
561 /* CMYK */
562 if (complement)
563 {
564 rr = 255 - rr;
565 rg = 255 - rg;
566 rb = 255 - rb;
567 bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, rr);
568 bp[1] = fz_mul255(255 - sa, bp[1]) + fz_mul255(255 - ba, sp[1]) + fz_mul255(saba, rg);
569 bp[2] = fz_mul255(255 - sa, bp[2]) + fz_mul255(255 - ba, sp[2]) + fz_mul255(saba, rb);
570
571 switch (blendmode)
572 {
573 default:
574 case FZ_BLEND_HUE:
575 case FZ_BLEND_SATURATION:
576 case FZ_BLEND_COLOR:
577 k = (bp[3] * invba) >> 8;
578 break;
579 case FZ_BLEND_LUMINOSITY:
580 k = (sp[3] * invsa) >> 8;
581 break;
582 }
583 bp[3] = fz_mul255(255 - sa, bp[3]) + fz_mul255(255 - ba, sp[3]) + fz_mul255(saba, k);
584 }
585 else
586 {
587 bp[0] = fz_mul255(255 - sa, bp[0]) + fz_mul255(255 - ba, sp[0]) + fz_mul255(saba, rr);
588 bp[1] = fz_mul255(255 - sa, bp[1]) + fz_mul255(255 - ba, sp[1]) + fz_mul255(saba, rg);
589 bp[2] = fz_mul255(255 - sa, bp[2]) + fz_mul255(255 - ba, sp[2]) + fz_mul255(saba, rb);
590 }
591
592 if (bal)
593 bp[n] = ba + sa - saba;
594
595 /* Normal blend for spots */
596 for (k = first_spot; k < n; k++)
597 {
598 int sc = (sp[k] * invsa) >> 8;
599 bp[k] = fz_mul255(255 - sa, bp[k]) + fz_mul255(255 - ba, sp[k]) + fz_mul255(saba, sc);
600 }
601 }
602 }
603 sp += n + sal;
604 bp += n + bal;
605 }
606 while (--w);
607 }
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 {
612 int k;
613
614 if (sal == 0 && alpha == 255 && blendmode == 0)
615 {
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 do
621 {
622 int ha = fz_mul255(*hp++, alpha); /* ha = shape_alpha */
623 /* If ha == 0 then leave everything unchanged */
624 if (ha != 0)
625 {
626 for (k = 0; k < n1; k++)
627 bp[k] = sp[k];
628 if (bal)
629 bp[k] = 255;
630 }
631
632 sp += n1;
633 bp += n1 + bal;
634 }
635 while (--w);
636 return;
637 }
638 do
639 {
640 int ha = *hp++;
641 int haa = fz_mul255(ha, alpha); /* ha = shape_alpha */
642 /* If haa == 0 then leave everything unchanged */
643 while (haa != 0) /* Use while, so we can break out */
644 {
645 int sa, ba, bahaa, ra, ra0, invsa, invba, scale;
646 sa = (sal ? sp[n1] : 255);
647 if (sa == 0)
648 break; /* No change! */
649 invsa = 255 * 256 / sa;
650 ba = (bal ? bp[n1] : 255);
651 if (ba == 0)
652 {
653 /* Just copy pixels (allowing for change in
654 * premultiplied alphas) */
655 for (k = 0; k < n1; k++)
656 bp[k] = fz_mul255((sp[k] * invsa) >> 8, haa);
657 if (bal)
658 bp[n1] = haa;
659 break;
660 }
661 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 scale = (512 * ba + ha) / (ha*2) - FZ_EXPAND(ba);
675
676 sa = haa;
677
678 /* Calculate result_alpha - a combination of the
679 * background alpha, and 'shape' */
680 bahaa = fz_mul255(ba, haa);
681 ra0 = ba - bahaa;
682 ra = ra0 + haa;
683 if (bal)
684 bp[n1] = ra;
685
686 if (ra == 0)
687 break;
688
689 /* Process colorants */
690 for (k = 0; k < first_spot; k++)
691 {
692 /* Read pixels (and convert to non-premultiplied form) */
693 int sc = (sp[k] * invsa) >> 8;
694 int bc = (bp[k] * invba) >> 8;
695 int rc;
696
697 if (complement)
698 {
699 sc = 255 - sc;
700 bc = 255 - bc;
701 }
702
703 /* Uncomposite (see above) */
704 sc = sc + (((sc-bc) * scale)>>8);
705 sc = fz_clampi(sc, 0, 255);
706
707 switch (blendmode)
708 {
709 default:
710 case FZ_BLEND_NORMAL: rc = sc; break;
711 case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break;
712 case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break;
713 case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break;
714 case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break;
715 case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break;
716 case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break;
717 case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break;
718 case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break;
719 case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break;
720 case FZ_BLEND_DIFFERENCE: rc = fz_difference_byte(bc, sc); break;
721 case FZ_BLEND_EXCLUSION: rc = fz_exclusion_byte(bc, sc); break;
722 }
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 if (bahaa != 255)
739 rc = fz_mul255(bahaa, rc);
740 if (ba != 255)
741 {
742 int t = fz_mul255(255 - ba, haa);
743 rc += fz_mul255(t, sc);
744 }
745 if (ra0 != 0)
746 rc += fz_mul255(ra0, bc);
747
748 if (complement)
749 rc = ra - rc;
750
751 bp[k] = fz_clampi(rc, 0, ra);
752 }
753
754 /* Spots */
755 for (; k < n1; k++)
756 {
757 int sc = 255 - ((sp[k] * invsa + 128) >> 8);
758 int bc = 255 - ((bp[k] * invba + 128) >> 8);
759 int rc;
760
761 sc = sc + (((sc-bc) * scale)>>8);
762
763 /* Non-white preserving use Normal */
764 switch (blendmode)
765 {
766 default:
767 case FZ_BLEND_NORMAL:
768 case FZ_BLEND_DIFFERENCE:
769 case FZ_BLEND_EXCLUSION:
770 rc = sc; break;
771 case FZ_BLEND_MULTIPLY: rc = fz_mul255(bc, sc); break;
772 case FZ_BLEND_SCREEN: rc = fz_screen_byte(bc, sc); break;
773 case FZ_BLEND_OVERLAY: rc = fz_overlay_byte(bc, sc); break;
774 case FZ_BLEND_DARKEN: rc = fz_darken_byte(bc, sc); break;
775 case FZ_BLEND_LIGHTEN: rc = fz_lighten_byte(bc, sc); break;
776 case FZ_BLEND_COLOR_DODGE: rc = fz_color_dodge_byte(bc, sc); break;
777 case FZ_BLEND_COLOR_BURN: rc = fz_color_burn_byte(bc, sc); break;
778 case FZ_BLEND_HARD_LIGHT: rc = fz_hard_light_byte(bc, sc); break;
779 case FZ_BLEND_SOFT_LIGHT: rc = fz_soft_light_byte(bc, sc); break;
780 }
781
782 if (bahaa != 255)
783 rc = fz_mul255(bahaa, rc);
784 if (ba != 255)
785 {
786 int t = fz_mul255(255 - ba, haa);
787 rc += fz_mul255(t, sc);
788 }
789 if (ra0 != 0)
790 rc += fz_mul255(ra0, bc);
791
792 bp[k] = ra - rc;
793 }
794 break;
795 }
796
797 sp += n1 + sal;
798 bp += n1 + bal;
799 }
800 while (--w);
801 }
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 {
806 do
807 {
808 int ha = *hp++;
809 int haa = fz_mul255(ha, alpha);
810 if (haa != 0)
811 {
812 int ba = (bal ? bp[n] : 255);
813
814 if (ba == 0 && alpha == 255)
815 {
816 memcpy(bp, sp, n + (sal && bal));
817 if (bal && !sal)
818 bp[n+1] = 255;
819 }
820 else
821 {
822 int sa = (sal ? sp[n] : 255);
823 int bahaa = fz_mul255(ba, haa);
824 int k;
825
826 /* Calculate result_alpha */
827 int ra = ba - bahaa + haa;
828 if (bal)
829 bp[n] = ra;
830 if (ra != 0)
831 {
832 int invha = ha ? 255 * 256 / ha : 0;
833
834 /* ugh, division to get non-premul components */
835 int invsa = sa ? 255 * 256 / sa : 0;
836 int invba = ba ? 255 * 256 / ba : 0;
837
838 int sg = (sp[0] * invsa) >> 8;
839 int bg = (bp[0] * invba) >> 8;
840
841 /* Uncomposite */
842 sg = (((sg - bg)*invha) >> 8) + bg;
843 sg = fz_clampi(sg, 0, 255);
844
845 switch (blendmode)
846 {
847 default:
848 case FZ_BLEND_HUE:
849 case FZ_BLEND_SATURATION:
850 case FZ_BLEND_COLOR:
851 bp[0] = fz_mul255(ra, bg);
852 break;
853 case FZ_BLEND_LUMINOSITY:
854 bp[0] = fz_mul255(ra, sg);
855 break;
856 }
857
858 /* Normal blend for spots */
859 for (k = first_spot; k < n; k++)
860 {
861 int sc = (sp[k] * invsa + 128) >> 8;
862 int bc = (bp[k] * invba + 128) >> 8;
863 int rc;
864
865 sc = (((sc - bc) * invha + 128) >> 8) + bc;
866 sc = fz_clampi(sc, 0, 255);
867 rc = bc + fz_mul255(sa, fz_mul255(255 - ba, sc) + fz_mul255(ba, sc) - bc);
868 rc = fz_clampi(rc, 0, 255);
869 bp[k] = fz_mul255(rc, ra);
870 }
871 }
872 }
873 }
874 sp += n + sal;
875 bp += n + bal;
876 } while (--w);
877 }
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 {
882 do
883 {
884 int ha = *hp++;
885 int haa = fz_mul255(ha, alpha);
886 if (haa != 0)
887 {
888 int sa = (sal ? sp[n] : 255);
889 int ba = (bal ? bp[n] : 255);
890
891 if (ba == 0 && alpha == 255)
892 {
893 memcpy(bp, sp, n + (sal && bal));
894 if (bal && !sal)
895 bp[n] = 255;
896 }
897 else
898 {
899 int bahaa = fz_mul255(ba, haa);
900
901 /* Calculate result_alpha */
902 int ra0 = ba - bahaa;
903 int ra = ra0 + haa;
904
905 if (bal)
906 bp[n] = ra;
907
908 if (ra != 0)
909 {
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 int invha = ha ? 255 * 256 / ha : 0;
920 int k;
921 unsigned char rr, rg, rb;
922
923 /* ugh, division to get non-premul components */
924 int invsa = sa ? 255 * 256 / sa : 0;
925 int invba = ba ? 255 * 256 / ba : 0;
926
927 int sr = (sp[0] * invsa) >> 8;
928 int sg = (sp[1] * invsa) >> 8;
929 int sb = (sp[2] * invsa) >> 8;
930
931 int br = (bp[0] * invba) >> 8;
932 int bg = (bp[1] * invba) >> 8;
933 int bb = (bp[2] * invba) >> 8;
934
935 if (complement)
936 {
937 sr = 255 - sr;
938 sg = 255 - sg;
939 sb = 255 - sb;
940 br = 255 - br;
941 bg = 255 - bg;
942 bb = 255 - bb;
943 }
944
945 /* Uncomposite */
946 sr = (((sr - br)*invha) >> 8) + br;
947 sr = fz_clampi(sr, 0, 255);
948 sg = (((sg - bg)*invha) >> 8) + bg;
949 sg = fz_clampi(sg, 0, 255);
950 sb = (((sb - bb)*invha) >> 8) + bb;
951 sb = fz_clampi(sb, 0, 255);
952
953 switch (blendmode)
954 {
955 default:
956 case FZ_BLEND_HUE:
957 fz_hue_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
958 break;
959 case FZ_BLEND_SATURATION:
960 fz_saturation_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
961 break;
962 case FZ_BLEND_COLOR:
963 fz_color_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
964 break;
965 case FZ_BLEND_LUMINOSITY:
966 fz_luminosity_rgb(&rr, &rg, &rb, br, bg, bb, sr, sg, sb);
967 break;
968 }
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 if (bahaa != 255)
985 {
986 rr = fz_mul255(bahaa, rr);
987 rg = fz_mul255(bahaa, rg);
988 rb = fz_mul255(bahaa, rb);
989 }
990 if (ba != 255)
991 {
992 int t = fz_mul255(255 - ba, haa);
993 rr += fz_mul255(t, sr);
994 rg += fz_mul255(t, sg);
995 rb += fz_mul255(t, sb);
996 }
997 if (ra0 != 0)
998 {
999 rr += fz_mul255(ra0, br);
1000 rg += fz_mul255(ra0, bg);
1001 rb += fz_mul255(ra0, bb);
1002 }
1003
1004 /* CMYK */
1005 if (complement)
1006 {
1007 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 rr = ra - rr;
1013 rg = ra - rg;
1014 rb = ra - rb;
1015
1016 sk = sa ? (sp[3] * invsa) >> 8 : 255;
1017 bk = ba ? (bp[3] * invba) >> 8 : 255;
1018
1019 bk = fz_clampi(bk, 0, 255);
1020 sk = fz_clampi(sk, 0, 255);
1021
1022 if (blendmode == FZ_BLEND_LUMINOSITY)
1023 rk = sk;
1024 else
1025 rk = bk;
1026
1027 if (bahaa != 255)
1028 rk = fz_mul255(bahaa, rk);
1029
1030 if (ba != 255)
1031 {
1032 int t = fz_mul255(255 - ba, haa);
1033 rk += fz_mul255(t, sk);
1034 }
1035
1036 if (ra0 != 0)
1037 rk += fz_mul255(ra0, bk);
1038
1039 bp[3] = rk;
1040 }
1041
1042 bp[0] = rr;
1043 bp[1] = rg;
1044 bp[2] = rb;
1045
1046 /* Normal blend for spots */
1047 for (k = first_spot; k < n; k++)
1048 {
1049 int sc = (sp[k] * invsa + 128) >> 8;
1050 int bc = (bp[k] * invba + 128) >> 8;
1051 int rc;
1052
1053 sc = (((sc - bc) * invha + 128) >> 8) + bc;
1054 sc = fz_clampi(sc, 0, 255);
1055 rc = bc + fz_mul255(ha, fz_mul255(255 - ba, sc) + fz_mul255(ba, sc) - bc);
1056 rc = fz_clampi(rc, 0, 255);
1057 bp[k] = fz_mul255(rc, ra);
1058 }
1059 }
1060 }
1061 }
1062 sp += n + sal;
1063 bp += n + bal;
1064 }
1065 while (--w);
1066 }
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 {
1097 unsigned char *sp;
1098 unsigned char *dp;
1099 fz_irect bbox;
1100 int x, y, w, h, n;
1101 int da, sa;
1102 int complement;
1103
1104 /* TODO: fix this hack! */
1105 if (isolated && alpha < 255)
1106 {
1107 unsigned char *sp2;
1108 int nn;
1109 h = src->h;
1110 sp2 = src->samples;
1111 nn = src->w * src->n;
1112 while (h--)
1113 {
1114 n = nn;
1115 while (n--)
1116 {
1117 *sp2 = fz_mul255(*sp2, alpha);
1118 sp2++;
1119 }
1120 sp2 += src->stride - nn;
1121 }
1122 }
1123
1124 bbox = fz_intersect_irect(fz_pixmap_bbox(ctx, src), fz_pixmap_bbox(ctx, dst));
1125
1126 x = bbox.x0;
1127 y = bbox.y0;
1128 w = fz_irect_width(bbox);
1129 h = fz_irect_height(bbox);
1130 if (w == 0 || h == 0)
1131 return;
1132
1133 complement = fz_colorspace_is_subtractive(ctx, src->colorspace);
1134 n = src->n;
1135 sp = src->samples + (y - src->y) * (size_t)src->stride + (x - src->x) * (size_t)src->n;
1136 sa = src->alpha;
1137 dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x - dst->x) * (size_t)dst->n;
1138 da = dst->alpha;
1139
1140 if (n == 1)
1141 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 n -= sa;
1151 assert(n == dst->n - da);
1152
1153 if (!isolated)
1154 {
1155 const unsigned char *hp = shape->samples + (y - shape->y) * (size_t)shape->stride + (x - shape->x);
1156
1157 while (h--)
1158 {
1159 if (blendmode >= FZ_BLEND_HUE)
1160 {
1161 if (complement || src->s > 0)
1162 if ((n - src->s) == 1)
1163 fz_blend_nonseparable_nonisolated_gray(dp, da, sp, sa, n, w, blendmode, hp, alpha, 1);
1164 else
1165 fz_blend_nonseparable_nonisolated(dp, da, sp, sa, n, w, blendmode, complement, hp, alpha, n - src->s);
1166 else
1167 if (da)
1168 if (sa)
1169 if (n == 1)
1170 fz_blend_nonseparable_nonisolated_gray(dp, 1, sp, 1, 1, w, blendmode, hp, alpha, 1);
1171 else
1172 fz_blend_nonseparable_nonisolated(dp, 1, sp, 1, n, w, blendmode, complement, hp, alpha, n);
1173 else
1174 if (n == 1)
1175 fz_blend_nonseparable_nonisolated_gray(dp, 1, sp, 0, 1, w, blendmode, hp, alpha, 1);
1176 else
1177 fz_blend_nonseparable_nonisolated(dp, 1, sp, 0, n, w, blendmode, complement, hp, alpha, n);
1178 else
1179 if (sa)
1180 if (n == 1)
1181 fz_blend_nonseparable_nonisolated_gray(dp, 0, sp, 1, 1, w, blendmode, hp, alpha, 1);
1182 else
1183 fz_blend_nonseparable_nonisolated(dp, 0, sp, 1, n, w, blendmode, complement, hp, alpha, n);
1184 else
1185 if (n == 1)
1186 fz_blend_nonseparable_nonisolated_gray(dp, 0, sp, 0, 1, w, blendmode, hp, alpha, 1);
1187 else
1188 fz_blend_nonseparable_nonisolated(dp, 0, sp, 0, n, w, blendmode, complement, hp, alpha, n);
1189 }
1190 else
1191 {
1192 if (complement || src->s > 0)
1193 fz_blend_separable_nonisolated(dp, da, sp, sa, n, w, blendmode, complement, hp, alpha, n - src->s);
1194 else
1195 if (da)
1196 if (sa)
1197 fz_blend_separable_nonisolated(dp, 1, sp, 1, n, w, blendmode, 0, hp, alpha, n);
1198 else
1199 fz_blend_separable_nonisolated(dp, 1, sp, 0, n, w, blendmode, 0, hp, alpha, n);
1200 else
1201 if (sa)
1202 fz_blend_separable_nonisolated(dp, 0, sp, 1, n, w, blendmode, 0, hp, alpha, n);
1203 else
1204 fz_blend_separable_nonisolated(dp, 0, sp, 0, n, w, blendmode, 0, hp, alpha, n);
1205 }
1206 sp += src->stride;
1207 dp += dst->stride;
1208 hp += shape->stride;
1209 }
1210 }
1211 else
1212 {
1213 while (h--)
1214 {
1215 if (blendmode >= FZ_BLEND_HUE)
1216 {
1217 if (complement || src->s > 0)
1218 if ((n - src->s) == 1)
1219 fz_blend_nonseparable_gray(dp, da, sp, sa, n, w, blendmode, 1);
1220 else
1221 fz_blend_nonseparable(dp, da, sp, sa, n, w, blendmode, complement, n - src->s);
1222 else
1223 if (da)
1224 if (sa)
1225 if (n == 1)
1226 fz_blend_nonseparable_gray(dp, 1, sp, 1, 1, w, blendmode, 1);
1227 else
1228 fz_blend_nonseparable(dp, 1, sp, 1, n, w, blendmode, complement, n);
1229 else
1230 if (n == 1)
1231 fz_blend_nonseparable_gray(dp, 1, sp, 0, 1, w, blendmode, 1);
1232 else
1233 fz_blend_nonseparable(dp, 1, sp, 0, n, w, blendmode, complement, n);
1234 else
1235 if (sa)
1236 if (n == 1)
1237 fz_blend_nonseparable_gray(dp, 0, sp, 1, 1, w, blendmode, 1);
1238 else
1239 fz_blend_nonseparable(dp, 0, sp, 1, n, w, blendmode, complement, n);
1240 else
1241 if (n == 1)
1242 fz_blend_nonseparable_gray(dp, 0, sp, 0, 1, w, blendmode, 1);
1243 else
1244 fz_blend_nonseparable(dp, 0, sp, 0, n, w, blendmode, complement, n);
1245 }
1246 else
1247 {
1248 if (complement || src->s > 0)
1249 fz_blend_separable(dp, da, sp, sa, n, w, blendmode, complement, n - src->s);
1250 else
1251 if (da)
1252 if (sa)
1253 fz_blend_separable(dp, 1, sp, 1, n, w, blendmode, 0, n);
1254 else
1255 fz_blend_separable(dp, 1, sp, 0, n, w, blendmode, 0, n);
1256 else
1257 if (sa)
1258 fz_blend_separable(dp, 0, sp, 1, n, w, blendmode, 0, n);
1259 else
1260 fz_blend_separable(dp, 0, sp, 0, n, w, blendmode, 0, n);
1261 }
1262 sp += src->stride;
1263 dp += dst->stride;
1264 }
1265 }
1266
1267 #ifdef PARANOID_PREMULTIPLY
1268 if (da)
1269 verify_premultiply(ctx, dst);
1270 #endif
1271 }
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 {
1276 int k;
1277 do
1278 {
1279 int ha = *hp++;
1280
1281 if (ha != 0)
1282 {
1283 int sa = (sal ? sp[n1] : 255);
1284 int ba = (bal ? bp[n1] : 255);
1285 if (ba == 0 && ha == 0xFF)
1286 {
1287 memcpy(bp, sp, n1);
1288 if (bal)
1289 bp[n1] = sa;
1290 }
1291 else
1292 {
1293 int hasa = fz_mul255(ha, sa);
1294 /* ugh, division to get non-premul components */
1295 int invsa = sa ? 255 * 256 / sa : 0;
1296 int invba = ba ? 255 * 256 / ba : 0;
1297 int ra = hasa + fz_mul255(255-ha, ba);
1298
1299 /* Process colorants + spots */
1300 for (k = 0; k < n1; k++)
1301 {
1302 int sc = (sp[k] * invsa) >> 8;
1303 int bc = (bp[k] * invba) >> 8;
1304 int rc = fz_mul255(255 - ha, bc) + fz_mul255(ha, sc);
1305
1306 bp[k] = fz_mul255(ra, rc);
1307 }
1308
1309 if (bal)
1310 bp[k] = ra;
1311 }
1312 }
1313 sp += n1 + sal;
1314 bp += n1 + bal;
1315 }
1316 while (--w);
1317 }
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 {
1322 unsigned char *sp;
1323 unsigned char *dp;
1324 fz_irect sbox, dbox, bbox;
1325 int x, y, w, h, n;
1326 int da, sa;
1327 const unsigned char *hp;
1328
1329 dbox = fz_pixmap_bbox_no_ctx(dst);
1330 sbox = fz_pixmap_bbox_no_ctx(src);
1331 bbox = fz_intersect_irect(dbox, sbox);
1332
1333 x = bbox.x0;
1334 y = bbox.y0;
1335 w = fz_irect_width(bbox);
1336 h = fz_irect_height(bbox);
1337 if (w == 0 || h == 0)
1338 return;
1339
1340 n = src->n;
1341 sp = src->samples + (y - src->y) * (size_t)src->stride + (x - src->x) * (size_t)src->n;
1342 sa = src->alpha;
1343 dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x - dst->x) * (size_t)dst->n;
1344 da = dst->alpha;
1345 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 n -= sa;
1355 assert(n == dst->n - da);
1356
1357 while (h--)
1358 {
1359 fz_blend_knockout(dp, da, sp, sa, n, w, hp);
1360 sp += src->stride;
1361 dp += dst->stride;
1362 hp += shape->stride;
1363 }
1364
1365 #ifdef PARANOID_PREMULTIPLY
1366 if (da)
1367 verify_premultiply(ctx, dst);
1368 #endif
1369 }