1 /*
2 Copyright (C) 2001 artofcode LLC.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 For more information about licensing, please refer to
12 http://www.ghostscript.com/licensing/. For information on
13 commercial licensing, go to http://www.artifex.com/licensing/ or
14 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
15 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
16
17 Author: Raph Levien <raph@artofcode.com>
18 */
19 /* $Id: gxblend.c,v 1.6 2004/08/18 04:48:56 dan Exp $ */
20 /* PDF 1.4 blending functions */
21
22 #include "memory_.h"
23 #include "gx.h"
24 #include "gstparam.h"
25 #include "gxblend.h"
26
27 typedef int art_s32;
28
29 static void
art_blend_luminosity_rgb_8(byte * dst,const byte * backdrop,const byte * src)30 art_blend_luminosity_rgb_8(byte *dst, const byte *backdrop,
31 const byte *src)
32 {
33 int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
34 int rs = src[0], gs = src[1], bs = src[2];
35 int delta_y;
36 int r, g, b;
37
38 /*
39 * From section 7.4 of the PDF 1.5 specification, for RGB, the luminosity
40 * is: Y = 0.30 R + 0.59 G + 0.11 B)
41 */
42 delta_y = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
43 r = rb + delta_y;
44 g = gb + delta_y;
45 b = bb + delta_y;
46 if ((r | g | b) & 0x100) {
47 int y;
48 int scale;
49
50 y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8;
51 if (delta_y > 0) {
52 int max;
53
54 max = r > g ? r : g;
55 max = b > max ? b : max;
56 scale = ((255 - y) << 16) / (max - y);
57 } else {
58 int min;
59
60 min = r < g ? r : g;
61 min = b < min ? b : min;
62 scale = (y << 16) / (y - min);
63 }
64 r = y + (((r - y) * scale + 0x8000) >> 16);
65 g = y + (((g - y) * scale + 0x8000) >> 16);
66 b = y + (((b - y) * scale + 0x8000) >> 16);
67 }
68 dst[0] = r;
69 dst[1] = g;
70 dst[2] = b;
71 }
72
73 /*
74 * The PDF 1.4 spec. does not give the details of the math involved in the
75 * luminosity blending. All we are given is:
76 * "Creates a color with the luminance of the source color and the hue
77 * and saturation of the backdrop color. This produces an inverse
78 * effect to that of the Color mode."
79 * From section 7.4 of the PDF 1.5 specification, which is duscussing soft
80 * masks, we are given that, for CMYK, the luminosity is:
81 * Y = 0.30 (1 - C)(1 - K) + 0.59 (1 - M)(1 - K) + 0.11 (1 - Y)(1 - K)
82 * However the results of this equation do not match the results seen from
83 * Illustrator CS. Very different results are obtained if process gray
84 * (.5, .5, .5, 0) is blended over pure cyan, versus gray (0, 0, 0, .5) over
85 * the same pure cyan. The first gives a medium cyan while the later gives a
86 * medium gray. This routine seems to match Illustrator's actions. C, M and Y
87 * are treated similar to RGB in the previous routine and black is treated
88 * separately.
89 *
90 * Our component values have already been complemented, i.e. (1 - X).
91 */
92 static void
art_blend_luminosity_cmyk_8(byte * dst,const byte * backdrop,const byte * src)93 art_blend_luminosity_cmyk_8(byte *dst, const byte *backdrop,
94 const byte *src)
95 {
96 /* Treat CMY the same as RGB. */
97 art_blend_luminosity_rgb_8(dst, backdrop, src);
98 dst[3] = src[3];
99 }
100
101 static void
art_blend_saturation_rgb_8(byte * dst,const byte * backdrop,const byte * src)102 art_blend_saturation_rgb_8(byte *dst, const byte *backdrop,
103 const byte *src)
104 {
105 int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
106 int rs = src[0], gs = src[1], bs = src[2];
107 int minb, maxb;
108 int mins, maxs;
109 int y;
110 int scale;
111 int r, g, b;
112
113 minb = rb < gb ? rb : gb;
114 minb = minb < bb ? minb : bb;
115 maxb = rb > gb ? rb : gb;
116 maxb = maxb > bb ? maxb : bb;
117 if (minb == maxb) {
118 /* backdrop has zero saturation, avoid divide by 0 */
119 dst[0] = gb;
120 dst[1] = gb;
121 dst[2] = gb;
122 return;
123 }
124
125 mins = rs < gs ? rs : gs;
126 mins = mins < bs ? mins : bs;
127 maxs = rs > gs ? rs : gs;
128 maxs = maxs > bs ? maxs : bs;
129
130 scale = ((maxs - mins) << 16) / (maxb - minb);
131 y = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
132 r = y + ((((rb - y) * scale) + 0x8000) >> 16);
133 g = y + ((((gb - y) * scale) + 0x8000) >> 16);
134 b = y + ((((bb - y) * scale) + 0x8000) >> 16);
135
136 if ((r | g | b) & 0x100) {
137 int scalemin, scalemax;
138 int min, max;
139
140 min = r < g ? r : g;
141 min = min < b ? min : b;
142 max = r > g ? r : g;
143 max = max > b ? max : b;
144
145 if (min < 0)
146 scalemin = (y << 16) / (y - min);
147 else
148 scalemin = 0x10000;
149
150 if (max > 255)
151 scalemax = ((255 - y) << 16) / (max - y);
152 else
153 scalemax = 0x10000;
154
155 scale = scalemin < scalemax ? scalemin : scalemax;
156 r = y + (((r - y) * scale + 0x8000) >> 16);
157 g = y + (((g - y) * scale + 0x8000) >> 16);
158 b = y + (((b - y) * scale + 0x8000) >> 16);
159 }
160
161 dst[0] = r;
162 dst[1] = g;
163 dst[2] = b;
164 }
165
166 /* Our component values have already been complemented, i.e. (1 - X). */
167 static void
art_blend_saturation_cmyk_8(byte * dst,const byte * backdrop,const byte * src)168 art_blend_saturation_cmyk_8(byte *dst, const byte *backdrop,
169 const byte *src)
170 {
171 /* Treat CMY the same as RGB */
172 art_blend_saturation_rgb_8(dst, backdrop, src);
173 dst[3] = backdrop[3];
174 }
175
176 /* This array consists of floor ((x - x * x / 255.0) * 65536 / 255 +
177 0.5) for x in [0..255]. */
178 const unsigned int art_blend_sq_diff_8[256] = {
179 0, 256, 510, 762, 1012, 1260, 1506, 1750, 1992, 2231, 2469, 2705,
180 2939, 3171, 3401, 3628, 3854, 4078, 4300, 4519, 4737, 4953, 5166,
181 5378, 5588, 5795, 6001, 6204, 6406, 6606, 6803, 6999, 7192, 7384,
182 7573, 7761, 7946, 8129, 8311, 8490, 8668, 8843, 9016, 9188, 9357,
183 9524, 9690, 9853, 10014, 10173, 10331, 10486, 10639, 10790, 10939,
184 11086, 11232, 11375, 11516, 11655, 11792, 11927, 12060, 12191, 12320,
185 12447, 12572, 12695, 12816, 12935, 13052, 13167, 13280, 13390, 13499,
186 13606, 13711, 13814, 13914, 14013, 14110, 14205, 14297, 14388, 14477,
187 14564, 14648, 14731, 14811, 14890, 14967, 15041, 15114, 15184, 15253,
188 15319, 15384, 15446, 15507, 15565, 15622, 15676, 15729, 15779, 15827,
189 15874, 15918, 15960, 16001, 16039, 16075, 16110, 16142, 16172, 16200,
190 16227, 16251, 16273, 16293, 16311, 16327, 16341, 16354, 16364, 16372,
191 16378, 16382, 16384, 16384, 16382, 16378, 16372, 16364, 16354, 16341,
192 16327, 16311, 16293, 16273, 16251, 16227, 16200, 16172, 16142, 16110,
193 16075, 16039, 16001, 15960, 15918, 15874, 15827, 15779, 15729, 15676,
194 15622, 15565, 15507, 15446, 15384, 15319, 15253, 15184, 15114, 15041,
195 14967, 14890, 14811, 14731, 14648, 14564, 14477, 14388, 14297, 14205,
196 14110, 14013, 13914, 13814, 13711, 13606, 13499, 13390, 13280, 13167,
197 13052, 12935, 12816, 12695, 12572, 12447, 12320, 12191, 12060, 11927,
198 11792, 11655, 11516, 11375, 11232, 11086, 10939, 10790, 10639, 10486,
199 10331, 10173, 10014, 9853, 9690, 9524, 9357, 9188, 9016, 8843, 8668,
200 8490, 8311, 8129, 7946, 7761, 7573, 7384, 7192, 6999, 6803, 6606,
201 6406, 6204, 6001, 5795, 5588, 5378, 5166, 4953, 4737, 4519, 4300,
202 4078, 3854, 3628, 3401, 3171, 2939, 2705, 2469, 2231, 1992, 1750,
203 1506, 1260, 1012, 762, 510, 256, 0
204 };
205
206 /* This array consists of SoftLight (x, 255) - x, for values of x in
207 the range [0..255] (normalized to [0..255 range). The original
208 values were directly sampled from Adobe Illustrator 9. I've fit a
209 quadratic spline to the SoftLight (x, 1) function as follows
210 (normalized to [0..1] range):
211
212 Anchor point (0, 0)
213 Control point (0.0755, 0.302)
214 Anchor point (0.18, 0.4245)
215 Control point (0.4263, 0.7131)
216 Anchor point (1, 1)
217
218 I don't believe this is _exactly_ the function that Adobe uses,
219 but it really should be close enough for all practical purposes. */
220 const byte art_blend_soft_light_8[256] = {
221 0, 3, 6, 9, 11, 14, 16, 19, 21, 23, 26, 28, 30, 32, 33, 35, 37, 39,
222 40, 42, 43, 45, 46, 47, 48, 49, 51, 52, 53, 53, 54, 55, 56, 57, 57,
223 58, 58, 59, 60, 60, 60, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 63,
224 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
225 64, 64, 64, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 62, 62, 62,
226 62, 62, 62, 62, 61, 61, 61, 61, 61, 61, 60, 60, 60, 60, 60, 59, 59,
227 59, 59, 59, 58, 58, 58, 58, 57, 57, 57, 57, 56, 56, 56, 56, 55, 55,
228 55, 55, 54, 54, 54, 54, 53, 53, 53, 52, 52, 52, 51, 51, 51, 51, 50,
229 50, 50, 49, 49, 49, 48, 48, 48, 47, 47, 47, 46, 46, 46, 45, 45, 45,
230 44, 44, 43, 43, 43, 42, 42, 42, 41, 41, 40, 40, 40, 39, 39, 39, 38,
231 38, 37, 37, 37, 36, 36, 35, 35, 35, 34, 34, 33, 33, 33, 32, 32, 31,
232 31, 31, 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26, 25, 25, 25, 24,
233 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16,
234 16, 15, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7,
235 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0
236 };
237
238 void
art_blend_pixel_8(byte * dst,const byte * backdrop,const byte * src,int n_chan,gs_blend_mode_t blend_mode)239 art_blend_pixel_8(byte *dst, const byte *backdrop,
240 const byte *src, int n_chan, gs_blend_mode_t blend_mode)
241 {
242 int i;
243 byte b, s;
244 bits32 t;
245
246 switch (blend_mode) {
247 case BLEND_MODE_Normal:
248 case BLEND_MODE_Compatible: /* todo */
249 memcpy(dst, src, n_chan);
250 break;
251 case BLEND_MODE_Multiply:
252 for (i = 0; i < n_chan; i++) {
253 t = ((bits32) backdrop[i]) * ((bits32) src[i]);
254 t += 0x80;
255 t += (t >> 8);
256 dst[i] = t >> 8;
257 }
258 break;
259 case BLEND_MODE_Screen:
260 for (i = 0; i < n_chan; i++) {
261 t =
262 ((bits32) (0xff - backdrop[i])) *
263 ((bits32) (0xff - src[i]));
264 t += 0x80;
265 t += (t >> 8);
266 dst[i] = 0xff - (t >> 8);
267 }
268 break;
269 case BLEND_MODE_Overlay:
270 for (i = 0; i < n_chan; i++) {
271 b = backdrop[i];
272 s = src[i];
273 if (b < 0x80)
274 t = 2 * ((bits32) b) * ((bits32) s);
275 else
276 t = 0xfe01 -
277 2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
278 t += 0x80;
279 t += (t >> 8);
280 dst[i] = t >> 8;
281 }
282 break;
283 case BLEND_MODE_SoftLight:
284 for (i = 0; i < n_chan; i++) {
285 b = backdrop[i];
286 s = src[i];
287 if (s < 0x80) {
288 t = (0xff - (s << 1)) * art_blend_sq_diff_8[b];
289 t += 0x8000;
290 dst[i] = b - (t >> 16);
291 } else {
292 t =
293 ((s << 1) -
294 0xff) * ((bits32) (art_blend_soft_light_8[b]));
295 t += 0x80;
296 t += (t >> 8);
297 dst[i] = b + (t >> 8);
298 }
299 }
300 break;
301 case BLEND_MODE_HardLight:
302 for (i = 0; i < n_chan; i++) {
303 b = backdrop[i];
304 s = src[i];
305 if (s < 0x80)
306 t = 2 * ((bits32) b) * ((bits32) s);
307 else
308 t = 0xfe01 -
309 2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
310 t += 0x80;
311 t += (t >> 8);
312 dst[i] = t >> 8;
313 }
314 break;
315 case BLEND_MODE_ColorDodge:
316 for (i = 0; i < n_chan; i++) {
317 b = backdrop[i];
318 s = 0xff - src[i];
319 if (b == 0)
320 dst[i] = 0;
321 else if (b >= s)
322 dst[i] = 0xff;
323 else
324 dst[i] = (0x1fe * b + s) / (s << 1);
325 }
326 break;
327 case BLEND_MODE_ColorBurn:
328 for (i = 0; i < n_chan; i++) {
329 b = 0xff - backdrop[i];
330 s = src[i];
331 if (b == 0)
332 dst[i] = 0xff;
333 else if (b >= s)
334 dst[i] = 0;
335 else
336 dst[i] = 0xff - (0x1fe * b + s) / (s << 1);
337 }
338 break;
339 case BLEND_MODE_Darken:
340 for (i = 0; i < n_chan; i++) {
341 b = backdrop[i];
342 s = src[i];
343 dst[i] = b < s ? b : s;
344 }
345 break;
346 case BLEND_MODE_Lighten:
347 for (i = 0; i < n_chan; i++) {
348 b = backdrop[i];
349 s = src[i];
350 dst[i] = b > s ? b : s;
351 }
352 break;
353 case BLEND_MODE_Difference:
354 for (i = 0; i < n_chan; i++) {
355 art_s32 tmp;
356
357 tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
358 dst[i] = tmp < 0 ? -tmp : tmp;
359 }
360 break;
361 case BLEND_MODE_Exclusion:
362 for (i = 0; i < n_chan; i++) {
363 b = backdrop[i];
364 s = src[i];
365 t = ((bits32) (0xff - b)) * ((bits32) s) +
366 ((bits32) b) * ((bits32) (0xff - s));
367 t += 0x80;
368 t += (t >> 8);
369 dst[i] = t >> 8;
370 }
371 break;
372 case BLEND_MODE_Luminosity:
373 switch (n_chan) {
374 case 1: /* DeviceGray */
375 dlprintf(
376 "art_blend_pixel_8: DeviceGray luminosity blend mode not implemented\n");
377 break;
378 case 3: /* DeviceRGB */
379 art_blend_luminosity_rgb_8(dst, backdrop, src);
380 break;
381 case 4: /* DeviceCMYK */
382 art_blend_luminosity_cmyk_8(dst, backdrop, src);
383 break;
384 default: /* Should not happen */
385 break;
386 }
387 break;
388 case BLEND_MODE_Color:
389 switch (n_chan) {
390 case 1: /* DeviceGray */
391 dlprintf(
392 "art_blend_pixel_8: DeviceGray color blend mode not implemented\n");
393 break;
394 case 3: /* DeviceRGB */
395 art_blend_luminosity_rgb_8(dst, src, backdrop);
396 break;
397 case 4: /* DeviceCMYK */
398 art_blend_luminosity_cmyk_8(dst, src, backdrop);
399 break;
400 default: /* Should not happen */
401 break;
402 }
403 break;
404 case BLEND_MODE_Saturation:
405 switch (n_chan) {
406 case 1: /* DeviceGray */
407 dlprintf(
408 "art_blend_pixel_8: DeviceGray saturation blend mode not implemented\n");
409 break;
410 case 3: /* DeviceRGB */
411 art_blend_saturation_rgb_8(dst, backdrop, src);
412 break;
413 case 4: /* DeviceCMYK */
414 art_blend_saturation_cmyk_8(dst, backdrop, src);
415 break;
416 default: /* Should not happen */
417 break;
418 }
419 break;
420 case BLEND_MODE_Hue:
421 {
422 byte tmp[4];
423
424 switch (n_chan) {
425 case 1: /* DeviceGray */
426 dlprintf(
427 "art_blend_pixel_8: DeviceGray hue blend mode not implemented\n");
428 break;
429 case 3: /* DeviceRGB */
430 art_blend_luminosity_rgb_8(tmp, src, backdrop);
431 art_blend_saturation_rgb_8(dst, tmp, backdrop);
432 break;
433 case 4: /* DeviceCMYK */
434 art_blend_luminosity_cmyk_8(tmp, src, backdrop);
435 art_blend_saturation_cmyk_8(dst, tmp, backdrop);
436 break;
437 default: /* Should not happen */
438 break;
439 }
440 }
441 break;
442 default:
443 dlprintf1("art_blend_pixel_8: blend mode %d not implemented\n",
444 blend_mode);
445 memcpy(dst, src, n_chan);
446 break;
447 }
448 }
449
450 void
art_blend_pixel(ArtPixMaxDepth * dst,const ArtPixMaxDepth * backdrop,const ArtPixMaxDepth * src,int n_chan,gs_blend_mode_t blend_mode)451 art_blend_pixel(ArtPixMaxDepth* dst, const ArtPixMaxDepth *backdrop,
452 const ArtPixMaxDepth* src, int n_chan,
453 gs_blend_mode_t blend_mode)
454 {
455 int i;
456 ArtPixMaxDepth b, s;
457 bits32 t;
458
459 switch (blend_mode) {
460 case BLEND_MODE_Normal:
461 case BLEND_MODE_Compatible: /* todo */
462 memcpy(dst, src, n_chan * sizeof(ArtPixMaxDepth));
463 break;
464 case BLEND_MODE_Multiply:
465 for (i = 0; i < n_chan; i++) {
466 t = ((bits32) backdrop[i]) * ((bits32) src[i]);
467 t += 0x8000;
468 t += (t >> 16);
469 dst[i] = t >> 16;
470 }
471 break;
472 case BLEND_MODE_Screen:
473 for (i = 0; i < n_chan; i++) {
474 t =
475 ((bits32) (0xffff - backdrop[i])) *
476 ((bits32) (0xffff - src[i]));
477 t += 0x8000;
478 t += (t >> 16);
479 dst[i] = 0xffff - (t >> 16);
480 }
481 break;
482 case BLEND_MODE_Overlay:
483 for (i = 0; i < n_chan; i++) {
484 b = backdrop[i];
485 s = src[i];
486 if (b < 0x8000)
487 t = 2 * ((bits32) b) * ((bits32) s);
488 else
489 t = 0xfffe0001u -
490 2 * ((bits32) (0xffff - b)) * ((bits32) (0xffff - s));
491 t += 0x8000;
492 t += (t >> 16);
493 dst[i] = t >> 16;
494 }
495 break;
496 case BLEND_MODE_HardLight:
497 for (i = 0; i < n_chan; i++) {
498 b = backdrop[i];
499 s = src[i];
500 if (s < 0x8000)
501 t = 2 * ((bits32) b) * ((bits32) s);
502 else
503 t = 0xfffe0001u -
504 2 * ((bits32) (0xffff - b)) * ((bits32) (0xffff - s));
505 t += 0x8000;
506 t += (t >> 16);
507 dst[i] = t >> 16;
508 }
509 break;
510 case BLEND_MODE_ColorDodge:
511 for (i = 0; i < n_chan; i++) {
512 b = backdrop[i];
513 s = src[i];
514 if (b == 0)
515 dst[i] = 0;
516 else if (s >= b)
517 dst[i] = 0xffff;
518 else
519 dst[i] = (0x1fffe * s + b) / (b << 1);
520 }
521 break;
522 case BLEND_MODE_ColorBurn:
523 for (i = 0; i < n_chan; i++) {
524 b = 0xffff - backdrop[i];
525 s = src[i];
526 if (b == 0)
527 dst[i] = 0xffff;
528 else if (b >= s)
529 dst[i] = 0;
530 else
531 dst[i] = 0xffff - (0x1fffe * b + s) / (s << 1);
532 }
533 case BLEND_MODE_Darken:
534 for (i = 0; i < n_chan; i++) {
535 b = backdrop[i];
536 s = src[i];
537 dst[i] = b < s ? b : s;
538 }
539 break;
540 case BLEND_MODE_Lighten:
541 for (i = 0; i < n_chan; i++) {
542 b = backdrop[i];
543 s = src[i];
544 dst[i] = b > s ? b : s;
545 }
546 break;
547 case BLEND_MODE_Difference:
548 for (i = 0; i < n_chan; i++) {
549 art_s32 tmp;
550
551 tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
552 dst[i] = tmp < 0 ? -tmp : tmp;
553 }
554 break;
555 case BLEND_MODE_Exclusion:
556 for (i = 0; i < n_chan; i++) {
557 b = backdrop[i];
558 s = src[i];
559 t = ((bits32) (0xffff - b)) * ((bits32) s) +
560 ((bits32) b) * ((bits32) (0xffff - s));
561 t += 0x8000;
562 t += (t >> 16);
563 dst[i] = t >> 16;
564 }
565 break;
566 default:
567 dlprintf1("art_blend_pixel: blend mode %d not implemented\n",
568 blend_mode);
569 memcpy(dst, src, n_chan);
570 break;
571 }
572 }
573
574 byte
art_pdf_union_8(byte alpha1,byte alpha2)575 art_pdf_union_8(byte alpha1, byte alpha2)
576 {
577 int tmp;
578
579 tmp = (0xff - alpha1) * (0xff - alpha2) + 0x80;
580 return 0xff - ((tmp + (tmp >> 8)) >> 8);
581 }
582
583 byte
art_pdf_union_mul_8(byte alpha1,byte alpha2,byte alpha_mask)584 art_pdf_union_mul_8(byte alpha1, byte alpha2, byte alpha_mask)
585 {
586 int tmp;
587
588 if (alpha_mask == 0xff) {
589 tmp = (0xff - alpha1) * (0xff - alpha2) + 0x80;
590 return 0xff - ((tmp + (tmp >> 8)) >> 8);
591 } else {
592 tmp = alpha2 * alpha_mask + 0x80;
593 tmp = (tmp + (tmp >> 8)) >> 8;
594 tmp = (0xff - alpha1) * (0xff - tmp) + 0x80;
595 return 0xff - ((tmp + (tmp >> 8)) >> 8);
596 }
597 }
598
599 void
art_pdf_composite_pixel_alpha_8(byte * dst,const byte * src,int n_chan,gs_blend_mode_t blend_mode)600 art_pdf_composite_pixel_alpha_8(byte *dst, const byte *src, int n_chan,
601 gs_blend_mode_t blend_mode)
602 {
603 byte a_b, a_s;
604 unsigned int a_r;
605 int tmp;
606 int src_scale;
607 int c_b, c_s;
608 int i;
609
610 a_s = src[n_chan];
611 if (a_s == 0) {
612 /* source alpha is zero, avoid all computations and possible
613 divide by zero errors. */
614 return;
615 }
616
617 a_b = dst[n_chan];
618 if (a_b == 0) {
619 /* backdrop alpha is zero, just copy source pixels and avoid
620 computation. */
621
622 /* this idiom is faster than memcpy (dst, src, n_chan + 1); for
623 expected small values of n_chan. */
624 for (i = 0; i <= n_chan >> 2; i++) {
625 ((bits32 *) dst)[i] = ((const bits32 *)src)[i];
626 }
627
628 return;
629 }
630
631 /* Result alpha is Union of backdrop and source alpha */
632 tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
633 a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
634 /* todo: verify that a_r is nonzero in all cases */
635
636 /* Compute a_s / a_r in 16.16 format */
637 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
638
639 if (blend_mode == BLEND_MODE_Normal) {
640 /* Do simple compositing of source over backdrop */
641 for (i = 0; i < n_chan; i++) {
642 c_s = src[i];
643 c_b = dst[i];
644 tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
645 dst[i] = tmp >> 16;
646 }
647 } else {
648 /* Do compositing with blending */
649 byte blend[ART_MAX_CHAN];
650
651 art_blend_pixel_8(blend, dst, src, n_chan, blend_mode);
652 for (i = 0; i < n_chan; i++) {
653 int c_bl; /* Result of blend function */
654 int c_mix; /* Blend result mixed with source color */
655
656 c_s = src[i];
657 c_b = dst[i];
658 c_bl = blend[i];
659 tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
660 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
661 tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
662 dst[i] = tmp >> 16;
663 }
664 }
665 dst[n_chan] = a_r;
666 }
667
668 #if 0
669 /**
670 * art_pdf_composite_pixel_knockout_8: Composite two pixels with knockout.
671 * @dst: Where to store resulting pixel, also immediate backdrop.
672 * @backdrop: Initial backdrop color.
673 * @src: Source pixel color.
674 * @n_chan: Number of channels.
675 * @blend_mode: Blend mode.
676 *
677 * Composites two pixels using the compositing operation specialized
678 * for knockout groups (Section 5.5). A few things to keep in mind:
679 *
680 * 1. This is a reference implementation, not a high-performance one.
681 *
682 * 2. All pixels are assumed to have a single alpha channel.
683 *
684 * 3. Zero is black, one is white.
685 *
686 * Also note that src and dst are expected to be allocated aligned to
687 * 32 bit boundaries, ie bytes from [0] to [(n_chan + 3) & -4] may
688 * be accessed.
689 *
690 * All pixel values have both alpha and shape channels, ie with those
691 * included the total number of channels is @n_chan + 2.
692 *
693 * An invariant: shape >= alpha.
694 **/
695 void
696 art_pdf_composite_pixel_knockout_8(byte *dst,
697 const byte *backdrop, const byte *src,
698 int n_chan, gs_blend_mode_t blend_mode)
699 {
700 int i;
701 byte ct[ART_MAX_CHAN + 1];
702 byte src_shape;
703 byte backdrop_alpha;
704 byte dst_alpha;
705 bits32 src_opacity;
706 bits32 backdrop_weight, t_weight;
707 int tmp;
708
709 if (src[n_chan] == 0)
710 return;
711 if (src[n_chan + 1] == 255 && blend_mode == BLEND_MODE_Normal ||
712 dst[n_chan] == 0) {
713 /* this idiom is faster than memcpy (dst, src, n_chan + 2); for
714 expected small values of n_chan. */
715 for (i = 0; i <= (n_chan + 1) >> 2; i++) {
716 ((bits32 *) dst)[i] = ((const bits32 *)src[i]);
717 }
718
719 return;
720 }
721
722
723 src_shape = src[n_chan + 1]; /* $fs_i$ */
724 src_opacity = (255 * src[n_chan] + 0x80) / src_shape; /* $qs_i$ */
725 #if 0
726 for (i = 0; i < (n_chan + 3) >> 2; i++) {
727 ((bits32 *) src_tmp)[i] = ((const bits32 *)src[i]);
728 }
729 src_tmp[n_chan] = src_opacity;
730
731 for (i = 0; i <= n_chan >> 2; i++) {
732 ((bits32 *) tmp)[i] = ((bits32 *) backdrop[i]);
733 }
734 #endif
735
736 backdrop_scale = if (blend_mode == BLEND_MODE_Normal) {
737 /* Do simple compositing of source over backdrop */
738 for (i = 0; i < n_chan; i++) {
739 c_s = src[i];
740 c_b = dst[i];
741 tmp = (c_b << 16) + ct_scale * (c_s - c_b) + 0x8000;
742 ct[i] = tmp >> 16;
743 }
744 } else {
745 /* Do compositing with blending */
746 byte blend[ART_MAX_CHAN];
747
748 art_blend_pixel_8(blend, backdrop, src, n_chan, blend_mode);
749 for (i = 0; i < n_chan; i++) {
750 int c_bl; /* Result of blend function */
751 int c_mix; /* Blend result mixed with source color */
752
753 c_s = src[i];
754 c_b = dst[i];
755 c_bl = blend[i];
756 tmp = a_b * (((int)c_bl) - ((int)c_s)) + 0x80;
757 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
758 tmp = (c_b << 16) + ct_scale * (c_mix - c_b) + 0x8000;
759 ct[i] = tmp >> 16;
760 }
761 }
762
763 /* do weighted average of $Ct$ using relative alpha contribution as weight */
764 backdrop_alpha = backdrop[n_chan];
765 tmp = (0xff - blend_alpha) * (0xff - backdrop_alpha) + 0x80;
766 dst_alpha = 0xff - (((tmp >> 8) + tmp) >> 8);
767 dst[n_chan] = dst_alpha;
768 t_weight = ((blend_alpha << 16) + 0x8000) / dst_alpha;
769 for (i = 0; i < n_chan; i++) {
770
771 }
772 }
773 #endif
774
775 void
art_pdf_uncomposite_group_8(byte * dst,const byte * backdrop,const byte * src,byte src_alpha_g,int n_chan)776 art_pdf_uncomposite_group_8(byte *dst,
777 const byte *backdrop,
778 const byte *src, byte src_alpha_g, int n_chan)
779 {
780 byte backdrop_alpha = backdrop[n_chan];
781 int i;
782 int tmp;
783 int scale;
784
785 dst[n_chan] = src_alpha_g;
786
787 if (src_alpha_g == 0)
788 return;
789
790 scale = (backdrop_alpha * 255 * 2 + src_alpha_g) / (src_alpha_g << 1) -
791 backdrop_alpha;
792 for (i = 0; i < n_chan; i++) {
793 int si, di;
794
795 si = src[i];
796 di = backdrop[i];
797 tmp = (si - di) * scale + 0x80;
798 tmp = si + ((tmp + (tmp >> 8)) >> 8);
799
800 /* todo: it should be possible to optimize these cond branches */
801 if (tmp < 0)
802 tmp = 0;
803 if (tmp > 255)
804 tmp = 255;
805 dst[i] = tmp;
806 }
807
808 }
809
810 void
art_pdf_recomposite_group_8(byte * dst,byte * dst_alpha_g,const byte * src,byte src_alpha_g,int n_chan,byte alpha,gs_blend_mode_t blend_mode)811 art_pdf_recomposite_group_8(byte *dst, byte *dst_alpha_g,
812 const byte *src, byte src_alpha_g,
813 int n_chan,
814 byte alpha, gs_blend_mode_t blend_mode)
815 {
816 byte dst_alpha;
817 int i;
818 int tmp;
819 int scale;
820
821 if (src_alpha_g == 0)
822 return;
823
824 if (blend_mode == BLEND_MODE_Normal && alpha == 255) {
825 /* In this case, uncompositing and recompositing cancel each
826 other out. Note: if the reason that alpha == 255 is that
827 there is no constant mask and no soft mask, then this
828 operation should be optimized away at a higher level. */
829 for (i = 0; i <= n_chan >> 2; i++)
830 ((bits32 *) dst)[i] = ((const bits32 *)src)[i];
831 if (dst_alpha_g != NULL) {
832 tmp = (255 - *dst_alpha_g) * (255 - src_alpha_g) + 0x80;
833 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
834 }
835 return;
836 } else {
837 /* "interesting" blend mode */
838 byte ca[ART_MAX_CHAN + 1]; /* $C, \alpha$ */
839
840 dst_alpha = dst[n_chan];
841 if (src_alpha_g == 255 || dst_alpha == 0) {
842 for (i = 0; i < (n_chan + 3) >> 2; i++)
843 ((bits32 *) ca)[i] = ((const bits32 *)src)[i];
844 } else {
845 /* Uncomposite the color. In other words, solve
846 "src = (ca, src_alpha_g) over dst" for ca */
847
848 /* todo (maybe?): replace this code with call to
849 art_pdf_uncomposite_group_8() to reduce code
850 duplication. */
851
852 scale = (dst_alpha * 255 * 2 + src_alpha_g) / (src_alpha_g << 1) -
853 dst_alpha;
854 for (i = 0; i < n_chan; i++) {
855 int si, di;
856
857 si = src[i];
858 di = dst[i];
859 tmp = (si - di) * scale + 0x80;
860 tmp = si + ((tmp + (tmp >> 8)) >> 8);
861
862 /* todo: it should be possible to optimize these cond branches */
863 if (tmp < 0)
864 tmp = 0;
865 if (tmp > 255)
866 tmp = 255;
867 ca[i] = tmp;
868 }
869 }
870
871 tmp = src_alpha_g * alpha + 0x80;
872 tmp = (tmp + (tmp >> 8)) >> 8;
873 ca[n_chan] = tmp;
874 if (dst_alpha_g != NULL) {
875 tmp = (255 - *dst_alpha_g) * (255 - tmp) + 0x80;
876 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
877 }
878 art_pdf_composite_pixel_alpha_8(dst, ca, n_chan, blend_mode);
879 }
880 /* todo: optimize BLEND_MODE_Normal buf alpha != 255 case */
881 }
882
883 void
art_pdf_composite_group_8(byte * dst,byte * dst_alpha_g,const byte * src,int n_chan,byte alpha,gs_blend_mode_t blend_mode)884 art_pdf_composite_group_8(byte *dst, byte *dst_alpha_g,
885 const byte *src,
886 int n_chan, byte alpha, gs_blend_mode_t blend_mode)
887 {
888 byte src_alpha; /* $\alpha g_n$ */
889 byte src_tmp[ART_MAX_CHAN + 1];
890 int i;
891 int tmp;
892
893 if (alpha == 255) {
894 art_pdf_composite_pixel_alpha_8(dst, src, n_chan, blend_mode);
895 if (dst_alpha_g != NULL) {
896 tmp = (255 - *dst_alpha_g) * (255 - src[n_chan]) + 0x80;
897 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
898 }
899 } else {
900 src_alpha = src[n_chan];
901 if (src_alpha == 0)
902 return;
903 for (i = 0; i < (n_chan + 3) >> 2; i++)
904 ((bits32 *) src_tmp)[i] = ((const bits32 *)src)[i];
905 tmp = src_alpha * alpha + 0x80;
906 src_tmp[n_chan] = (tmp + (tmp >> 8)) >> 8;
907 art_pdf_composite_pixel_alpha_8(dst, src_tmp, n_chan, blend_mode);
908 if (dst_alpha_g != NULL) {
909 tmp = (255 - *dst_alpha_g) * (255 - src_tmp[n_chan]) + 0x80;
910 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
911 }
912 }
913 }
914
915 void
art_pdf_composite_knockout_simple_8(byte * dst,byte * dst_shape,const byte * src,int n_chan,byte opacity)916 art_pdf_composite_knockout_simple_8(byte *dst,
917 byte *dst_shape,
918 const byte *src,
919 int n_chan, byte opacity)
920 {
921 byte src_shape = src[n_chan];
922 int i;
923
924 if (src_shape == 0)
925 return;
926 else if (src_shape == 255) {
927 for (i = 0; i < (n_chan + 3) >> 2; i++)
928 ((bits32 *) dst)[i] = ((const bits32 *)src)[i];
929 dst[n_chan] = opacity;
930 if (dst_shape != NULL)
931 *dst_shape = 255;
932 } else {
933 /* Use src_shape to interpolate (in premultiplied alpha space)
934 between dst and (src, opacity). */
935 int dst_alpha = dst[n_chan];
936 byte result_alpha;
937 int tmp;
938
939 tmp = (opacity - dst_alpha) * src_shape + 0x80;
940 result_alpha = dst_alpha + ((tmp + (tmp >> 8)) >> 8);
941
942 if (result_alpha != 0)
943 for (i = 0; i < n_chan; i++) {
944 /* todo: optimize this - can strength-reduce so that
945 inner loop is a single interpolation */
946 tmp = dst[i] * dst_alpha * (255 - src_shape) +
947 ((int)src[i]) * opacity * src_shape + (result_alpha << 7);
948 dst[i] = tmp / (result_alpha * 255);
949 }
950 dst[n_chan] = result_alpha;
951
952 /* union in dst_shape if non-null */
953 if (dst_shape != NULL) {
954 tmp = (255 - *dst_shape) * (255 - src_shape) + 0x80;
955 *dst_shape = 255 - ((tmp + (tmp >> 8)) >> 8);
956 }
957 }
958 }
959
960 void
art_pdf_composite_knockout_isolated_8(byte * dst,byte * dst_shape,const byte * src,int n_chan,byte shape,byte alpha_mask,byte shape_mask)961 art_pdf_composite_knockout_isolated_8(byte *dst,
962 byte *dst_shape,
963 const byte *src,
964 int n_chan,
965 byte shape,
966 byte alpha_mask, byte shape_mask)
967 {
968 int tmp;
969 int i;
970
971 if (shape == 0)
972 return;
973 else if ((shape & shape_mask) == 255) {
974 for (i = 0; i < (n_chan + 3) >> 2; i++)
975 ((bits32 *) dst)[i] = ((const bits32 *)src)[i];
976 tmp = src[n_chan] * alpha_mask + 0x80;
977 dst[n_chan] = (tmp + (tmp >> 8)) >> 8;
978 if (dst_shape != NULL)
979 *dst_shape = 255;
980 } else {
981 /* Use src_shape to interpolate (in premultiplied alpha space)
982 between dst and (src, opacity). */
983 byte src_shape, src_alpha;
984 int dst_alpha = dst[n_chan];
985 byte result_alpha;
986 int tmp;
987
988 tmp = shape * shape_mask + 0x80;
989 src_shape = (tmp + (tmp >> 8)) >> 8;
990
991 tmp = src[n_chan] * alpha_mask + 0x80;
992 src_alpha = (tmp + (tmp >> 8)) >> 8;
993
994 tmp = (src_alpha - dst_alpha) * src_shape + 0x80;
995 result_alpha = dst_alpha + ((tmp + (tmp >> 8)) >> 8);
996
997 if (result_alpha != 0)
998 for (i = 0; i < n_chan; i++) {
999 /* todo: optimize this - can strength-reduce so that
1000 inner loop is a single interpolation */
1001 tmp = dst[i] * dst_alpha * (255 - src_shape) +
1002 ((int)src[i]) * src_alpha * src_shape +
1003 (result_alpha << 7);
1004 dst[i] = tmp / (result_alpha * 255);
1005 }
1006 dst[n_chan] = result_alpha;
1007
1008 /* union in dst_shape if non-null */
1009 if (dst_shape != NULL) {
1010 tmp = (255 - *dst_shape) * (255 - src_shape) + 0x80;
1011 *dst_shape = 255 - ((tmp + (tmp >> 8)) >> 8);
1012 }
1013 }
1014 }
1015
1016 void
art_pdf_composite_knockout_8(byte * dst,byte * dst_alpha_g,const byte * backdrop,const byte * src,int n_chan,byte shape,byte alpha_mask,byte shape_mask,gs_blend_mode_t blend_mode)1017 art_pdf_composite_knockout_8(byte *dst,
1018 byte *dst_alpha_g,
1019 const byte *backdrop,
1020 const byte *src,
1021 int n_chan,
1022 byte shape,
1023 byte alpha_mask,
1024 byte shape_mask, gs_blend_mode_t blend_mode)
1025 {
1026 /* This implementation follows the Adobe spec pretty closely, rather
1027 than trying to do anything clever. For example, in the case of a
1028 Normal blend_mode when the top group is non-isolated, uncompositing
1029 and recompositing is more work than needed. So be it. Right now,
1030 I'm more worried about manageability than raw performance. */
1031 byte alpha_t;
1032 byte src_alpha, src_shape;
1033 byte src_opacity;
1034 byte ct[ART_MAX_CHAN];
1035 byte backdrop_alpha;
1036 byte alpha_g_i_1, alpha_g_i, alpha_i;
1037 int tmp;
1038 int i;
1039 int scale_b;
1040 int scale_src;
1041
1042 if (shape == 0 || shape_mask == 0)
1043 return;
1044
1045 tmp = shape * shape_mask + 0x80;
1046 /* $f s_i$ */
1047 src_shape = (tmp + (tmp >> 8)) >> 8;
1048
1049 tmp = src[n_chan] * alpha_mask + 0x80;
1050 src_alpha = (tmp + (tmp >> 8)) >> 8;
1051
1052 /* $q s_i$ */
1053 src_opacity = (src_alpha * 510 + src_shape) / (2 * src_shape);
1054
1055 /* $\alpha t$, \alpha g_b is always zero for knockout groups */
1056 alpha_t = src_opacity;
1057
1058 /* $\alpha b$ */
1059 backdrop_alpha = backdrop[n_chan];
1060
1061 tmp = (0xff - src_opacity) * backdrop_alpha;
1062 /* $(1 - q s_i) \cdot alpha_b$ scaled by 2^16 */
1063 scale_b = tmp + (tmp >> 7) + (tmp >> 14);
1064
1065 /* $q s_i$ scaled by 2^16 */
1066 scale_src = (src_opacity << 8) + (src_opacity) + (src_opacity >> 7);
1067
1068 /* Do simple compositing of source over backdrop */
1069 if (blend_mode == BLEND_MODE_Normal) {
1070 for (i = 0; i < n_chan; i++) {
1071 int c_s;
1072 int c_b;
1073
1074 c_s = src[i];
1075 c_b = backdrop[i];
1076 tmp = (c_b << 16) * scale_b + (c_s - c_b) + scale_src + 0x8000;
1077 ct[i] = tmp >> 16;
1078 }
1079 } else {
1080 byte blend[ART_MAX_CHAN];
1081
1082 art_blend_pixel_8(blend, backdrop, src, n_chan, blend_mode);
1083 for (i = 0; i < n_chan; i++) {
1084 int c_s;
1085 int c_b;
1086 int c_bl; /* Result of blend function */
1087 int c_mix; /* Blend result mixed with source color */
1088
1089 c_s = src[i];
1090 c_b = backdrop[i];
1091 c_bl = blend[i];
1092 tmp = backdrop_alpha * (c_bl - ((int)c_s)) + 0x80;
1093 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
1094 tmp = (c_b << 16) * scale_b + (c_mix - c_b) + scale_src + 0x8000;
1095 ct[i] = tmp >> 16;
1096 }
1097 }
1098
1099 /* $\alpha g_{i - 1}$ */
1100 alpha_g_i_1 = *dst_alpha_g;
1101
1102 tmp = src_shape * (((int)alpha_t) - alpha_g_i_1) + 0x80;
1103 /* $\alpha g_i$ */
1104 alpha_g_i = alpha_g_i_1 + ((tmp + (tmp >> 8)) >> 8);
1105
1106 tmp = (0xff - backdrop_alpha) * (0xff - alpha_g_i) + 0x80;
1107 /* $\alpha_i$ */
1108 alpha_i = 0xff - ((tmp + (tmp >> 8)) >> 8);
1109
1110 if (alpha_i > 0) {
1111 int scale_dst;
1112 int scale_t;
1113 byte dst_alpha;
1114
1115 /* $f s_i / \alpha_i$ scaled by 2^16 */
1116 scale_t = ((src_shape << 17) + alpha_i) / (2 * alpha_i);
1117
1118 /* $\alpha_{i - 1}$ */
1119 dst_alpha = dst[n_chan];
1120
1121 tmp = (1 - src_shape) * dst_alpha;
1122 tmp = (tmp << 9) + (tmp << 1) + (tmp >> 7) + alpha_i;
1123 scale_dst = tmp / (2 * alpha_i);
1124
1125 for (i = 0; i < n_chan; i++) {
1126 tmp = dst[i] * scale_dst + ct[i] * scale_t + 0x8000;
1127 /* todo: clamp? */
1128 dst[i] = tmp >> 16;
1129 }
1130 }
1131 dst[n_chan] = alpha_i;
1132 *dst_alpha_g = alpha_g_i;
1133 }
1134