1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2 All Rights Reserved.
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 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16 /* PDF 1.4 blending functions */
17
18 #include "memory_.h"
19 #include "gx.h"
20 #include "gstparam.h"
21 #include "gxblend.h"
22 #include "gxcolor2.h"
23 #include "gsicc_cache.h"
24 #include "gsicc_manage.h"
25
26 typedef int art_s32;
27
28 #if RAW_DUMP
29 extern unsigned int global_index;
30 extern unsigned int clist_band_count;
31 #endif
32
33 /* This function is used for mapping the SMask source to a
34 monochrome luminosity value which basically is the alpha value
35 Note, that separation colors are not allowed here. Everything
36 must be in CMYK, RGB or monochrome. */
37
38 /* Note, data is planar */
39
40 void
smask_luminosity_mapping(int num_rows,int num_cols,int n_chan,int row_stride,int plane_stride,byte * src,const byte * dst,bool isadditive,gs_transparency_mask_subtype_t SMask_SubType)41 smask_luminosity_mapping(int num_rows, int num_cols, int n_chan, int row_stride,
42 int plane_stride, byte *src, const byte *dst, bool isadditive,
43 gs_transparency_mask_subtype_t SMask_SubType)
44 {
45 int x,y;
46 int mask_alpha_offset,mask_C_offset,mask_M_offset,mask_Y_offset,mask_K_offset;
47 int mask_R_offset,mask_G_offset,mask_B_offset;
48 byte *dstptr;
49
50 #if RAW_DUMP
51 dump_raw_buffer(num_rows, row_stride, n_chan,
52 plane_stride, row_stride,
53 "Raw_Mask", src);
54
55 global_index++;
56 #endif
57 dstptr = dst;
58 /* If subtype is Luminosity then we should just grab the Y channel */
59 if ( SMask_SubType == TRANSPARENCY_MASK_Luminosity ){
60 memcpy(dst, &(src[plane_stride]), plane_stride);
61 return;
62 }
63 /* If we are alpha type, then just grab that */
64 /* We need to optimize this so that we are only drawing alpha in the rect fills */
65 if ( SMask_SubType == TRANSPARENCY_MASK_Alpha ){
66 mask_alpha_offset = (n_chan - 1) * plane_stride;
67 memcpy(dst, &(src[mask_alpha_offset]), plane_stride);
68 return;
69 }
70 /* To avoid the if statement inside this loop,
71 decide on additive or subractive now */
72 if (isadditive || n_chan == 2) {
73 /* Now we need to split Gray from RGB */
74 if( n_chan == 2 ) {
75 /* Gray Scale case */
76 mask_alpha_offset = (n_chan - 1) * plane_stride;
77 mask_R_offset = 0;
78 for ( y = 0; y < num_rows; y++ ) {
79 for ( x = 0; x < num_cols; x++ ){
80 /* With the current design this will indicate if
81 we ever did a fill at this pixel. if not then move on.
82 This could have some serious optimization */
83 if (src[x + mask_alpha_offset] != 0x00) {
84 dstptr[x] = src[x + mask_R_offset];
85 }
86 }
87 dstptr += row_stride;
88 mask_alpha_offset += row_stride;
89 mask_R_offset += row_stride;
90 }
91 } else {
92 /* RGB case */
93 mask_R_offset = 0;
94 mask_G_offset = plane_stride;
95 mask_B_offset = 2 * plane_stride;
96 mask_alpha_offset = (n_chan - 1) * plane_stride;
97 for ( y = 0; y < num_rows; y++ ) {
98 for ( x = 0; x < num_cols; x++ ){
99 /* With the current design this will indicate if
100 we ever did a fill at this pixel. if not then move on */
101 if (src[x + mask_alpha_offset] != 0x00) {
102 /* Get luminosity of Device RGB value */
103 float temp;
104 temp = ( 0.30 * src[x + mask_R_offset] +
105 0.59 * src[x + mask_G_offset] +
106 0.11 * src[x + mask_B_offset] );
107 temp = temp * (1.0 / 255.0 ); /* May need to be optimized */
108 dstptr[x] = float_color_to_byte_color(temp);
109 }
110 }
111 dstptr += row_stride;
112 mask_alpha_offset += row_stride;
113 mask_R_offset += row_stride;
114 mask_G_offset += row_stride;
115 mask_B_offset += row_stride;
116 }
117 }
118 } else {
119 /* CMYK case */
120 mask_alpha_offset = (n_chan - 1) * plane_stride;
121 mask_C_offset = 0;
122 mask_M_offset = plane_stride;
123 mask_Y_offset = 2 * plane_stride;
124 mask_K_offset = 3 * plane_stride;
125 for ( y = 0; y < num_rows; y++ ){
126 for ( x = 0; x < num_cols; x++ ){
127 /* With the current design this will indicate if
128 we ever did a fill at this pixel. if not then move on */
129 if (src[x + mask_alpha_offset] != 0x00){
130 /* PDF spec says to use Y = 0.30 (1 - C)(1 - K) +
131 0.59 (1 - M)(1 - K) + 0.11 (1 - Y)(1 - K) */
132 /* For device CMYK */
133 float temp;
134 temp = ( 0.30 * ( 0xff - src[x + mask_C_offset]) +
135 0.59 * ( 0xff - src[x + mask_M_offset]) +
136 0.11 * ( 0xff - src[x + mask_Y_offset]) ) *
137 ( 0xff - src[x + mask_K_offset]);
138 temp = temp * (1.0 / 65025.0 ); /* May need to be optimized */
139 dstptr[x] = float_color_to_byte_color(temp);
140 }
141 }
142 dstptr += row_stride;
143 mask_alpha_offset += row_stride;
144 mask_C_offset += row_stride;
145 mask_M_offset += row_stride;
146 mask_Y_offset += row_stride;
147 mask_K_offset += row_stride;
148 }
149 }
150 }
151
152 /* soft mask gray buffer should be blended with its transparency planar data
153 during the pop for a luminosity case if we have a soft mask within a soft
154 mask. This situation is detected in the code so that we only do this
155 blending in those rare situations */
156 void
smask_blend(byte * src,int width,int height,int rowstride,int planestride)157 smask_blend(byte *src, int width, int height, int rowstride,
158 int planestride)
159 {
160 int x, y;
161 int position;
162 byte comp, a;
163 int tmp;
164 byte bg = 0;
165
166 for (y = 0; y < height; y++) {
167 position = y * rowstride;
168 for (x = 0; x < width; x++) {
169 a = src[position + planestride];
170 if ((a + 1) & 0xfe) {
171 a ^= 0xff;
172 comp = src[position];
173 tmp = ((bg - comp) * a) + 0x80;
174 comp += (tmp + (tmp >> 8)) >> 8;
175 src[position] = comp;
176 } else if (a == 0) {
177 src[position] = 0;
178 }
179 position+=1;
180 }
181 }
182 }
183
smask_copy(int num_rows,int num_cols,int row_stride,byte * src,const byte * dst)184 void smask_copy(int num_rows, int num_cols, int row_stride,
185 byte *src, const byte *dst)
186 {
187 int y;
188 byte *dstptr,*srcptr;
189
190 dstptr = dst;
191 srcptr = src;
192 for ( y = 0; y < num_rows; y++ ) {
193 memcpy(dstptr,srcptr,num_cols);
194 dstptr += row_stride;
195 srcptr += row_stride;
196 }
197 }
198
smask_icc(gx_device * dev,int num_rows,int num_cols,int n_chan,int row_stride,int plane_stride,byte * src,const byte * dst,gsicc_link_t * icclink)199 void smask_icc(gx_device *dev, int num_rows, int num_cols, int n_chan,
200 int row_stride, int plane_stride, byte *src, const byte *dst,
201 gsicc_link_t *icclink)
202 {
203 gsicc_bufferdesc_t input_buff_desc;
204 gsicc_bufferdesc_t output_buff_desc;
205
206 #if RAW_DUMP
207 dump_raw_buffer(num_rows, row_stride, n_chan,
208 plane_stride, row_stride,
209 "Raw_Mask_ICC", src);
210 global_index++;
211 #endif
212 /* Set up the buffer descriptors. Note that pdf14 always has
213 the alpha channels at the back end (last planes).
214 We will just handle that here and let the CMM know
215 nothing about it */
216
217 gsicc_init_buffer(&input_buff_desc, n_chan-1, 1,
218 false, false, true, plane_stride, row_stride,
219 num_rows, num_cols);
220 gsicc_init_buffer(&output_buff_desc, 1, 1,
221 false, false, true, plane_stride,
222 row_stride, num_rows, num_cols);
223 /* Transform the data */
224 (icclink->procs.map_buffer)(dev, icclink, &input_buff_desc, &output_buff_desc,
225 (void*) src, (void*) dst);
226 }
227
228 void
art_blend_luminosity_rgb_8(int n_chan,byte * dst,const byte * backdrop,const byte * src)229 art_blend_luminosity_rgb_8(int n_chan, byte *dst, const byte *backdrop,
230 const byte *src)
231 {
232 int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
233 int rs = src[0], gs = src[1], bs = src[2];
234 int delta_y;
235 int r, g, b;
236
237 /*
238 * From section 7.4 of the PDF 1.5 specification, for RGB, the luminosity
239 * is: Y = 0.30 R + 0.59 G + 0.11 B)
240 */
241 delta_y = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
242 r = rb + delta_y;
243 g = gb + delta_y;
244 b = bb + delta_y;
245 if ((r | g | b) & 0x100) {
246 int y;
247 int scale;
248
249 y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8;
250 if (delta_y > 0) {
251 int max;
252
253 max = r > g ? r : g;
254 max = b > max ? b : max;
255 scale = ((255 - y) << 16) / (max - y);
256 } else {
257 int min;
258
259 min = r < g ? r : g;
260 min = b < min ? b : min;
261 scale = (y << 16) / (y - min);
262 }
263 r = y + (((r - y) * scale + 0x8000) >> 16);
264 g = y + (((g - y) * scale + 0x8000) >> 16);
265 b = y + (((b - y) * scale + 0x8000) >> 16);
266 }
267 dst[0] = r;
268 dst[1] = g;
269 dst[2] = b;
270 }
271
272 void
art_blend_luminosity_custom_8(int n_chan,byte * dst,const byte * backdrop,const byte * src)273 art_blend_luminosity_custom_8(int n_chan, byte *dst, const byte *backdrop,
274 const byte *src)
275 {
276 int delta_y = 0, test = 0;
277 int r[ART_MAX_CHAN];
278 int i;
279
280 /*
281 * Since we do not know the details of the blending color space, we are
282 * simply using the average as the luminosity. First we need the
283 * delta luminosity values.
284 */
285 for (i = 0; i < n_chan; i++)
286 delta_y += src[i] - backdrop[i];
287 delta_y = (delta_y + n_chan / 2) / n_chan;
288 for (i = 0; i < n_chan; i++) {
289 r[i] = backdrop[i] + delta_y;
290 test |= r[i];
291 }
292
293 if (test & 0x100) {
294 int y;
295 int scale;
296
297 /* Assume that the luminosity is simply the average of the backdrop. */
298 y = src[0];
299 for (i = 1; i < n_chan; i++)
300 y += src[i];
301 y = (y + n_chan / 2) / n_chan;
302
303 if (delta_y > 0) {
304 int max;
305
306 max = r[0];
307 for (i = 1; i < n_chan; i++)
308 max = max(max, r[i]);
309 scale = ((255 - y) << 16) / (max - y);
310 } else {
311 int min;
312
313 min = r[0];
314 for (i = 1; i < n_chan; i++)
315 min = min(min, r[i]);
316 scale = (y << 16) / (y - min);
317 }
318 for (i = 0; i < n_chan; i++)
319 r[i] = y + (((r[i] - y) * scale + 0x8000) >> 16);
320 }
321 for (i = 0; i < n_chan; i++)
322 dst[i] = r[i];
323 }
324
325 /*
326 * The PDF 1.4 spec. does not give the details of the math involved in the
327 * luminosity blending. All we are given is:
328 * "Creates a color with the luminance of the source color and the hue
329 * and saturation of the backdrop color. This produces an inverse
330 * effect to that of the Color mode."
331 * From section 7.4 of the PDF 1.5 specification, which is duscussing soft
332 * masks, we are given that, for CMYK, the luminosity is:
333 * Y = 0.30 (1 - C)(1 - K) + 0.59 (1 - M)(1 - K) + 0.11 (1 - Y)(1 - K)
334 * However the results of this equation do not match the results seen from
335 * Illustrator CS. Very different results are obtained if process gray
336 * (.5, .5, .5, 0) is blended over pure cyan, versus gray (0, 0, 0, .5) over
337 * the same pure cyan. The first gives a medium cyan while the later gives a
338 * medium gray. This routine seems to match Illustrator's actions. C, M and Y
339 * are treated similar to RGB in the previous routine and black is treated
340 * separately.
341 *
342 * Our component values have already been complemented, i.e. (1 - X).
343 */
344 void
art_blend_luminosity_cmyk_8(int n_chan,byte * dst,const byte * backdrop,const byte * src)345 art_blend_luminosity_cmyk_8(int n_chan, byte *dst, const byte *backdrop,
346 const byte *src)
347 {
348 int i;
349
350 /* Treat CMY the same as RGB. */
351 art_blend_luminosity_rgb_8(3, dst, backdrop, src);
352 for (i = 3; i < n_chan; i++)
353 dst[i] = src[i];
354 }
355
356 void
art_blend_saturation_rgb_8(int n_chan,byte * dst,const byte * backdrop,const byte * src)357 art_blend_saturation_rgb_8(int n_chan, byte *dst, const byte *backdrop,
358 const byte *src)
359 {
360 int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
361 int rs = src[0], gs = src[1], bs = src[2];
362 int minb, maxb;
363 int mins, maxs;
364 int y;
365 int scale;
366 int r, g, b;
367
368 minb = rb < gb ? rb : gb;
369 minb = minb < bb ? minb : bb;
370 maxb = rb > gb ? rb : gb;
371 maxb = maxb > bb ? maxb : bb;
372 if (minb == maxb) {
373 /* backdrop has zero saturation, avoid divide by 0 */
374 dst[0] = gb;
375 dst[1] = gb;
376 dst[2] = gb;
377 return;
378 }
379
380 mins = rs < gs ? rs : gs;
381 mins = mins < bs ? mins : bs;
382 maxs = rs > gs ? rs : gs;
383 maxs = maxs > bs ? maxs : bs;
384
385 scale = ((maxs - mins) << 16) / (maxb - minb);
386 y = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
387 r = y + ((((rb - y) * scale) + 0x8000) >> 16);
388 g = y + ((((gb - y) * scale) + 0x8000) >> 16);
389 b = y + ((((bb - y) * scale) + 0x8000) >> 16);
390
391 if ((r | g | b) & 0x100) {
392 int scalemin, scalemax;
393 int min, max;
394
395 min = r < g ? r : g;
396 min = min < b ? min : b;
397 max = r > g ? r : g;
398 max = max > b ? max : b;
399
400 if (min < 0)
401 scalemin = (y << 16) / (y - min);
402 else
403 scalemin = 0x10000;
404
405 if (max > 255)
406 scalemax = ((255 - y) << 16) / (max - y);
407 else
408 scalemax = 0x10000;
409
410 scale = scalemin < scalemax ? scalemin : scalemax;
411 r = y + (((r - y) * scale + 0x8000) >> 16);
412 g = y + (((g - y) * scale + 0x8000) >> 16);
413 b = y + (((b - y) * scale + 0x8000) >> 16);
414 }
415
416 dst[0] = r;
417 dst[1] = g;
418 dst[2] = b;
419 }
420
421 void
art_blend_saturation_custom_8(int n_chan,byte * dst,const byte * backdrop,const byte * src)422 art_blend_saturation_custom_8(int n_chan, byte *dst, const byte *backdrop,
423 const byte *src)
424 {
425 int minb, maxb;
426 int mins, maxs;
427 int y;
428 int scale;
429 int r[ART_MAX_CHAN];
430 int test = 0;
431 int temp, i;
432
433 /* Determine min and max of the backdrop */
434 minb = maxb = temp = backdrop[0];
435 for (i = 1; i < n_chan; i++) {
436 temp = backdrop[i];
437 minb = min(minb, temp);
438 maxb = max(maxb, temp);
439 }
440
441 if (minb == maxb) {
442 /* backdrop has zero saturation, avoid divide by 0 */
443 for (i = 0; i < n_chan; i++)
444 dst[i] = temp;
445 return;
446 }
447
448 /* Determine min and max of the source */
449 mins = maxs = src[0];
450 for (i = 1; i < n_chan; i++) {
451 temp = src[i];
452 mins = min(minb, temp);
453 maxs = max(minb, temp);
454 }
455
456 scale = ((maxs - mins) << 16) / (maxb - minb);
457
458 /* Assume that the saturation is simply the average of the backdrop. */
459 y = backdrop[0];
460 for (i = 1; i < n_chan; i++)
461 y += backdrop[i];
462 y = (y + n_chan / 2) / n_chan;
463
464 /* Calculate the saturated values */
465 for (i = 0; i < n_chan; i++) {
466 r[i] = y + ((((backdrop[i] - y) * scale) + 0x8000) >> 16);
467 test |= r[i];
468 }
469
470 if (test & 0x100) {
471 int scalemin, scalemax;
472 int min, max;
473
474 /* Determine min and max of our blended values */
475 min = max = temp = r[0];
476 for (i = 1; i < n_chan; i++) {
477 temp = src[i];
478 min = min(min, temp);
479 max = max(max, temp);
480 }
481
482 if (min < 0)
483 scalemin = (y << 16) / (y - min);
484 else
485 scalemin = 0x10000;
486
487 if (max > 255)
488 scalemax = ((255 - y) << 16) / (max - y);
489 else
490 scalemax = 0x10000;
491
492 scale = scalemin < scalemax ? scalemin : scalemax;
493 for (i = 0; i < n_chan; i++)
494 r[i] = y + (((r[i] - y) * scale + 0x8000) >> 16);
495 }
496
497 for (i = 0; i < n_chan; i++)
498 dst[i] = r[i];
499 }
500
501 /* Our component values have already been complemented, i.e. (1 - X). */
502 void
art_blend_saturation_cmyk_8(int n_chan,byte * dst,const byte * backdrop,const byte * src)503 art_blend_saturation_cmyk_8(int n_chan, byte *dst, const byte *backdrop,
504 const byte *src)
505 {
506 int i;
507
508 /* Treat CMY the same as RGB */
509 art_blend_saturation_rgb_8(3, dst, backdrop, src);
510 for (i = 3; i < n_chan; i++)
511 dst[i] = backdrop[i];
512 }
513
514 /* This array consists of floor ((x - x * x / 255.0) * 65536 / 255 +
515 0.5) for x in [0..255]. */
516 const unsigned int art_blend_sq_diff_8[256] = {
517 0, 256, 510, 762, 1012, 1260, 1506, 1750, 1992, 2231, 2469, 2705,
518 2939, 3171, 3401, 3628, 3854, 4078, 4300, 4519, 4737, 4953, 5166,
519 5378, 5588, 5795, 6001, 6204, 6406, 6606, 6803, 6999, 7192, 7384,
520 7573, 7761, 7946, 8129, 8311, 8490, 8668, 8843, 9016, 9188, 9357,
521 9524, 9690, 9853, 10014, 10173, 10331, 10486, 10639, 10790, 10939,
522 11086, 11232, 11375, 11516, 11655, 11792, 11927, 12060, 12191, 12320,
523 12447, 12572, 12695, 12816, 12935, 13052, 13167, 13280, 13390, 13499,
524 13606, 13711, 13814, 13914, 14013, 14110, 14205, 14297, 14388, 14477,
525 14564, 14648, 14731, 14811, 14890, 14967, 15041, 15114, 15184, 15253,
526 15319, 15384, 15446, 15507, 15565, 15622, 15676, 15729, 15779, 15827,
527 15874, 15918, 15960, 16001, 16039, 16075, 16110, 16142, 16172, 16200,
528 16227, 16251, 16273, 16293, 16311, 16327, 16341, 16354, 16364, 16372,
529 16378, 16382, 16384, 16384, 16382, 16378, 16372, 16364, 16354, 16341,
530 16327, 16311, 16293, 16273, 16251, 16227, 16200, 16172, 16142, 16110,
531 16075, 16039, 16001, 15960, 15918, 15874, 15827, 15779, 15729, 15676,
532 15622, 15565, 15507, 15446, 15384, 15319, 15253, 15184, 15114, 15041,
533 14967, 14890, 14811, 14731, 14648, 14564, 14477, 14388, 14297, 14205,
534 14110, 14013, 13914, 13814, 13711, 13606, 13499, 13390, 13280, 13167,
535 13052, 12935, 12816, 12695, 12572, 12447, 12320, 12191, 12060, 11927,
536 11792, 11655, 11516, 11375, 11232, 11086, 10939, 10790, 10639, 10486,
537 10331, 10173, 10014, 9853, 9690, 9524, 9357, 9188, 9016, 8843, 8668,
538 8490, 8311, 8129, 7946, 7761, 7573, 7384, 7192, 6999, 6803, 6606,
539 6406, 6204, 6001, 5795, 5588, 5378, 5166, 4953, 4737, 4519, 4300,
540 4078, 3854, 3628, 3401, 3171, 2939, 2705, 2469, 2231, 1992, 1750,
541 1506, 1260, 1012, 762, 510, 256, 0
542 };
543
544 /* This array consists of SoftLight (x, 255) - x, for values of x in
545 the range [0..255] (normalized to [0..255 range). The original
546 values were directly sampled from Adobe Illustrator 9. I've fit a
547 quadratic spline to the SoftLight (x, 1) function as follows
548 (normalized to [0..1] range):
549
550 Anchor point (0, 0)
551 Control point (0.0755, 0.302)
552 Anchor point (0.18, 0.4245)
553 Control point (0.4263, 0.7131)
554 Anchor point (1, 1)
555
556 I don't believe this is _exactly_ the function that Adobe uses,
557 but it really should be close enough for all practical purposes. */
558 const byte art_blend_soft_light_8[256] = {
559 0, 3, 6, 9, 11, 14, 16, 19, 21, 23, 26, 28, 30, 32, 33, 35, 37, 39,
560 40, 42, 43, 45, 46, 47, 48, 49, 51, 52, 53, 53, 54, 55, 56, 57, 57,
561 58, 58, 59, 60, 60, 60, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 63,
562 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
563 64, 64, 64, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 62, 62, 62,
564 62, 62, 62, 62, 61, 61, 61, 61, 61, 61, 60, 60, 60, 60, 60, 59, 59,
565 59, 59, 59, 58, 58, 58, 58, 57, 57, 57, 57, 56, 56, 56, 56, 55, 55,
566 55, 55, 54, 54, 54, 54, 53, 53, 53, 52, 52, 52, 51, 51, 51, 51, 50,
567 50, 50, 49, 49, 49, 48, 48, 48, 47, 47, 47, 46, 46, 46, 45, 45, 45,
568 44, 44, 43, 43, 43, 42, 42, 42, 41, 41, 40, 40, 40, 39, 39, 39, 38,
569 38, 37, 37, 37, 36, 36, 35, 35, 35, 34, 34, 33, 33, 33, 32, 32, 31,
570 31, 31, 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26, 25, 25, 25, 24,
571 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16,
572 16, 15, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7,
573 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0
574 };
575
576 void
art_blend_pixel_8(byte * dst,const byte * backdrop,const byte * src,int n_chan,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs)577 art_blend_pixel_8(byte *dst, const byte *backdrop,
578 const byte *src, int n_chan, gs_blend_mode_t blend_mode,
579 const pdf14_nonseparable_blending_procs_t * pblend_procs)
580 {
581 int i;
582 byte b, s;
583 bits32 t;
584
585 switch (blend_mode) {
586 case BLEND_MODE_Normal:
587 case BLEND_MODE_Compatible: /* todo */
588 memcpy(dst, src, n_chan);
589 break;
590 case BLEND_MODE_Multiply:
591 for (i = 0; i < n_chan; i++) {
592 t = ((bits32) backdrop[i]) * ((bits32) src[i]);
593 t += 0x80;
594 t += (t >> 8);
595 dst[i] = t >> 8;
596 }
597 break;
598 case BLEND_MODE_Screen:
599 for (i = 0; i < n_chan; i++) {
600 t =
601 ((bits32) (0xff - backdrop[i])) *
602 ((bits32) (0xff - src[i]));
603 t += 0x80;
604 t += (t >> 8);
605 dst[i] = 0xff - (t >> 8);
606 }
607 break;
608 case BLEND_MODE_Overlay:
609 for (i = 0; i < n_chan; i++) {
610 b = backdrop[i];
611 s = src[i];
612 if (b < 0x80)
613 t = 2 * ((bits32) b) * ((bits32) s);
614 else
615 t = 0xfe01 -
616 2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
617 t += 0x80;
618 t += (t >> 8);
619 dst[i] = t >> 8;
620 }
621 break;
622 case BLEND_MODE_SoftLight:
623 for (i = 0; i < n_chan; i++) {
624 b = backdrop[i];
625 s = src[i];
626 if (s < 0x80) {
627 t = (0xff - (s << 1)) * art_blend_sq_diff_8[b];
628 t += 0x8000;
629 dst[i] = b - (t >> 16);
630 } else {
631 t =
632 ((s << 1) -
633 0xff) * ((bits32) (art_blend_soft_light_8[b]));
634 t += 0x80;
635 t += (t >> 8);
636 dst[i] = b + (t >> 8);
637 }
638 }
639 break;
640 case BLEND_MODE_HardLight:
641 for (i = 0; i < n_chan; i++) {
642 b = backdrop[i];
643 s = src[i];
644 if (s < 0x80)
645 t = 2 * ((bits32) b) * ((bits32) s);
646 else
647 t = 0xfe01 -
648 2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
649 t += 0x80;
650 t += (t >> 8);
651 dst[i] = t >> 8;
652 }
653 break;
654 case BLEND_MODE_ColorDodge:
655 for (i = 0; i < n_chan; i++) {
656 b = backdrop[i];
657 s = 0xff - src[i];
658 if (b == 0)
659 dst[i] = 0;
660 else if (b >= s)
661 dst[i] = 0xff;
662 else
663 dst[i] = (0x1fe * b + s) / (s << 1);
664 }
665 break;
666 case BLEND_MODE_ColorBurn:
667 for (i = 0; i < n_chan; i++) {
668 b = 0xff - backdrop[i];
669 s = src[i];
670 if (b == 0)
671 dst[i] = 0xff;
672 else if (b >= s)
673 dst[i] = 0;
674 else
675 dst[i] = 0xff - (0x1fe * b + s) / (s << 1);
676 }
677 break;
678 case BLEND_MODE_Darken:
679 for (i = 0; i < n_chan; i++) {
680 b = backdrop[i];
681 s = src[i];
682 dst[i] = b < s ? b : s;
683 }
684 break;
685 case BLEND_MODE_Lighten:
686 for (i = 0; i < n_chan; i++) {
687 b = backdrop[i];
688 s = src[i];
689 dst[i] = b > s ? b : s;
690 }
691 break;
692 case BLEND_MODE_Difference:
693 for (i = 0; i < n_chan; i++) {
694 art_s32 tmp;
695
696 tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
697 dst[i] = tmp < 0 ? -tmp : tmp;
698 }
699 break;
700 case BLEND_MODE_Exclusion:
701 for (i = 0; i < n_chan; i++) {
702 b = backdrop[i];
703 s = src[i];
704 t = ((bits32) (0xff - b)) * ((bits32) s) +
705 ((bits32) b) * ((bits32) (0xff - s));
706 t += 0x80;
707 t += (t >> 8);
708 dst[i] = t >> 8;
709 }
710 break;
711 case BLEND_MODE_Luminosity:
712 pblend_procs->blend_luminosity(n_chan, dst, backdrop, src);
713 break;
714 case BLEND_MODE_Color:
715 pblend_procs->blend_luminosity(n_chan, dst, src, backdrop);
716 break;
717 case BLEND_MODE_Saturation:
718 pblend_procs->blend_saturation(n_chan, dst, backdrop, src);
719 break;
720 case BLEND_MODE_Hue:
721 {
722 byte tmp[4];
723
724 pblend_procs->blend_luminosity(n_chan, tmp, src, backdrop);
725 pblend_procs->blend_saturation(n_chan, dst, tmp, backdrop);
726 }
727 break;
728 default:
729 dlprintf1("art_blend_pixel_8: blend mode %d not implemented\n",
730 blend_mode);
731 memcpy(dst, src, n_chan);
732 break;
733 }
734 }
735
736 void
art_blend_pixel(ArtPixMaxDepth * dst,const ArtPixMaxDepth * backdrop,const ArtPixMaxDepth * src,int n_chan,gs_blend_mode_t blend_mode)737 art_blend_pixel(ArtPixMaxDepth* dst, const ArtPixMaxDepth *backdrop,
738 const ArtPixMaxDepth* src, int n_chan,
739 gs_blend_mode_t blend_mode)
740 {
741 int i;
742 ArtPixMaxDepth b, s;
743 bits32 t;
744
745 switch (blend_mode) {
746 case BLEND_MODE_Normal:
747 case BLEND_MODE_Compatible: /* todo */
748 memcpy(dst, src, n_chan * sizeof(ArtPixMaxDepth));
749 break;
750 case BLEND_MODE_Multiply:
751 for (i = 0; i < n_chan; i++) {
752 t = ((bits32) backdrop[i]) * ((bits32) src[i]);
753 t += 0x8000;
754 t += (t >> 16);
755 dst[i] = t >> 16;
756 }
757 break;
758 case BLEND_MODE_Screen:
759 for (i = 0; i < n_chan; i++) {
760 t =
761 ((bits32) (0xffff - backdrop[i])) *
762 ((bits32) (0xffff - src[i]));
763 t += 0x8000;
764 t += (t >> 16);
765 dst[i] = 0xffff - (t >> 16);
766 }
767 break;
768 case BLEND_MODE_Overlay:
769 for (i = 0; i < n_chan; i++) {
770 b = backdrop[i];
771 s = src[i];
772 if (b < 0x8000)
773 t = 2 * ((bits32) b) * ((bits32) s);
774 else
775 t = 0xfffe0001u -
776 2 * ((bits32) (0xffff - b)) * ((bits32) (0xffff - s));
777 t += 0x8000;
778 t += (t >> 16);
779 dst[i] = t >> 16;
780 }
781 break;
782 case BLEND_MODE_HardLight:
783 for (i = 0; i < n_chan; i++) {
784 b = backdrop[i];
785 s = src[i];
786 if (s < 0x8000)
787 t = 2 * ((bits32) b) * ((bits32) s);
788 else
789 t = 0xfffe0001u -
790 2 * ((bits32) (0xffff - b)) * ((bits32) (0xffff - s));
791 t += 0x8000;
792 t += (t >> 16);
793 dst[i] = t >> 16;
794 }
795 break;
796 case BLEND_MODE_ColorDodge:
797 for (i = 0; i < n_chan; i++) {
798 b = backdrop[i];
799 s = src[i];
800 if (b == 0)
801 dst[i] = 0;
802 else if (s >= b)
803 dst[i] = 0xffff;
804 else
805 dst[i] = (0x1fffe * s + b) / (b << 1);
806 }
807 break;
808 case BLEND_MODE_ColorBurn:
809 for (i = 0; i < n_chan; i++) {
810 b = 0xffff - backdrop[i];
811 s = src[i];
812 if (b == 0)
813 dst[i] = 0xffff;
814 else if (b >= s)
815 dst[i] = 0;
816 else
817 dst[i] = 0xffff - (0x1fffe * b + s) / (s << 1);
818 }
819 break;
820 case BLEND_MODE_Darken:
821 for (i = 0; i < n_chan; i++) {
822 b = backdrop[i];
823 s = src[i];
824 dst[i] = b < s ? b : s;
825 }
826 break;
827 case BLEND_MODE_Lighten:
828 for (i = 0; i < n_chan; i++) {
829 b = backdrop[i];
830 s = src[i];
831 dst[i] = b > s ? b : s;
832 }
833 break;
834 case BLEND_MODE_Difference:
835 for (i = 0; i < n_chan; i++) {
836 art_s32 tmp;
837
838 tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
839 dst[i] = tmp < 0 ? -tmp : tmp;
840 }
841 break;
842 case BLEND_MODE_Exclusion:
843 for (i = 0; i < n_chan; i++) {
844 b = backdrop[i];
845 s = src[i];
846 t = ((bits32) (0xffff - b)) * ((bits32) s) +
847 ((bits32) b) * ((bits32) (0xffff - s));
848 t += 0x8000;
849 t += (t >> 16);
850 dst[i] = t >> 16;
851 }
852 break;
853 default:
854 dlprintf1("art_blend_pixel: blend mode %d not implemented\n",
855 blend_mode);
856 memcpy(dst, src, n_chan);
857 break;
858 }
859 }
860
861 byte
art_pdf_union_8(byte alpha1,byte alpha2)862 art_pdf_union_8(byte alpha1, byte alpha2)
863 {
864 int tmp;
865
866 tmp = (0xff - alpha1) * (0xff - alpha2) + 0x80;
867 return 0xff - ((tmp + (tmp >> 8)) >> 8);
868 }
869
870 byte
art_pdf_union_mul_8(byte alpha1,byte alpha2,byte alpha_mask)871 art_pdf_union_mul_8(byte alpha1, byte alpha2, byte alpha_mask)
872 {
873 int tmp;
874
875 if (alpha_mask == 0xff) {
876 tmp = (0xff - alpha1) * (0xff - alpha2) + 0x80;
877 return 0xff - ((tmp + (tmp >> 8)) >> 8);
878 } else {
879 tmp = alpha2 * alpha_mask + 0x80;
880 tmp = (tmp + (tmp >> 8)) >> 8;
881 tmp = (0xff - alpha1) * (0xff - tmp) + 0x80;
882 return 0xff - ((tmp + (tmp >> 8)) >> 8);
883 }
884 }
885
886 void
art_pdf_composite_pixel_alpha_8(byte * dst,const byte * src,int n_chan,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs)887 art_pdf_composite_pixel_alpha_8(byte *dst, const byte *src, int n_chan,
888 gs_blend_mode_t blend_mode,
889 const pdf14_nonseparable_blending_procs_t * pblend_procs)
890 {
891 byte a_b, a_s;
892 unsigned int a_r;
893 int tmp;
894 int src_scale;
895 int c_b, c_s;
896 int i;
897
898 a_s = src[n_chan];
899 if (a_s == 0) {
900 /* source alpha is zero, avoid all computations and possible
901 divide by zero errors. */
902 return;
903 }
904
905 a_b = dst[n_chan];
906 if (a_b == 0) {
907 /* backdrop alpha is zero, just copy source pixels and avoid
908 computation. */
909
910 memcpy (dst, src, n_chan + 1);
911
912 return;
913 }
914
915 /* Result alpha is Union of backdrop and source alpha */
916 tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
917 a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
918 /* todo: verify that a_r is nonzero in all cases */
919
920 /* Compute a_s / a_r in 16.16 format */
921 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
922
923 if (blend_mode == BLEND_MODE_Normal) {
924 /* Do simple compositing of source over backdrop */
925 for (i = 0; i < n_chan; i++) {
926 c_s = src[i];
927 c_b = dst[i];
928 tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
929 dst[i] = tmp >> 16;
930 }
931 } else {
932 /* Do compositing with blending */
933 byte blend[ART_MAX_CHAN];
934
935 art_blend_pixel_8(blend, dst, src, n_chan, blend_mode, pblend_procs);
936 for (i = 0; i < n_chan; i++) {
937 int c_bl; /* Result of blend function */
938 int c_mix; /* Blend result mixed with source color */
939
940 c_s = src[i];
941 c_b = dst[i];
942 c_bl = blend[i];
943 tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
944 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
945 tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
946 dst[i] = tmp >> 16;
947 }
948 }
949 dst[n_chan] = a_r;
950 }
951
952 #if 0
953 /**
954 * art_pdf_composite_pixel_knockout_8: Composite two pixels with knockout.
955 * @dst: Where to store resulting pixel, also immediate backdrop.
956 * @backdrop: Initial backdrop color.
957 * @src: Source pixel color.
958 * @n_chan: Number of channels.
959 * @blend_mode: Blend mode.
960 *
961 * Composites two pixels using the compositing operation specialized
962 * for knockout groups (Section 5.5). A few things to keep in mind:
963 *
964 * 1. This is a reference implementation, not a high-performance one.
965 *
966 * 2. All pixels are assumed to have a single alpha channel.
967 *
968 * 3. Zero is black, one is white.
969 *
970 * Also note that src and dst are expected to be allocated aligned to
971 * 32 bit boundaries, ie bytes from [0] to [(n_chan + 3) & -4] may
972 * be accessed.
973 *
974 * All pixel values have both alpha and shape channels, ie with those
975 * included the total number of channels is @n_chan + 2.
976 *
977 * An invariant: shape >= alpha.
978 **/
979 void
980 art_pdf_composite_pixel_knockout_8(byte *dst,
981 const byte *backdrop, const byte *src,
982 int n_chan, gs_blend_mode_t blend_mode)
983 {
984 int i;
985 byte ct[ART_MAX_CHAN + 1];
986 byte src_shape;
987 byte backdrop_alpha;
988 byte dst_alpha;
989 bits32 src_opacity;
990 bits32 backdrop_weight, t_weight;
991 int tmp;
992
993 if (src[n_chan] == 0)
994 return;
995 if (src[n_chan + 1] == 255 && blend_mode == BLEND_MODE_Normal ||
996 dst[n_chan] == 0) {
997
998 memcpy (dst, src, n_chan + 2);
999
1000 return;
1001 }
1002
1003 src_shape = src[n_chan + 1]; /* $fs_i$ */
1004 src_opacity = (255 * src[n_chan] + 0x80) / src_shape; /* $qs_i$ */
1005 #if 0
1006 for (i = 0; i < (n_chan + 3) >> 2; i++) {
1007 ((bits32 *) src_tmp)[i] = ((const bits32 *)src[i]);
1008 }
1009 src_tmp[n_chan] = src_opacity;
1010
1011 for (i = 0; i <= n_chan >> 2; i++) {
1012 ((bits32 *) tmp)[i] = ((bits32 *) backdrop[i]);
1013 }
1014 #endif
1015
1016 backdrop_scale = if (blend_mode == BLEND_MODE_Normal) {
1017 /* Do simple compositing of source over backdrop */
1018 for (i = 0; i < n_chan; i++) {
1019 c_s = src[i];
1020 c_b = dst[i];
1021 tmp = (c_b << 16) + ct_scale * (c_s - c_b) + 0x8000;
1022 ct[i] = tmp >> 16;
1023 }
1024 } else {
1025 /* Do compositing with blending */
1026 byte blend[ART_MAX_CHAN];
1027
1028 art_blend_pixel_8(blend, backdrop, src, n_chan, blend_mode, pblend_procs);
1029 for (i = 0; i < n_chan; i++) {
1030 int c_bl; /* Result of blend function */
1031 int c_mix; /* Blend result mixed with source color */
1032
1033 c_s = src[i];
1034 c_b = dst[i];
1035 c_bl = blend[i];
1036 tmp = a_b * (((int)c_bl) - ((int)c_s)) + 0x80;
1037 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
1038 tmp = (c_b << 16) + ct_scale * (c_mix - c_b) + 0x8000;
1039 ct[i] = tmp >> 16;
1040 }
1041 }
1042
1043 /* do weighted average of $Ct$ using relative alpha contribution as weight */
1044 backdrop_alpha = backdrop[n_chan];
1045 tmp = (0xff - blend_alpha) * (0xff - backdrop_alpha) + 0x80;
1046 dst_alpha = 0xff - (((tmp >> 8) + tmp) >> 8);
1047 dst[n_chan] = dst_alpha;
1048 t_weight = ((blend_alpha << 16) + 0x8000) / dst_alpha;
1049 for (i = 0; i < n_chan; i++) {
1050
1051 }
1052 }
1053 #endif
1054
1055 void
art_pdf_uncomposite_group_8(byte * dst,const byte * backdrop,const byte * src,byte src_alpha_g,int n_chan)1056 art_pdf_uncomposite_group_8(byte *dst,
1057 const byte *backdrop,
1058 const byte *src, byte src_alpha_g, int n_chan)
1059 {
1060 byte backdrop_alpha = backdrop[n_chan];
1061 int i;
1062 int tmp;
1063 int scale;
1064
1065 dst[n_chan] = src_alpha_g;
1066
1067 if (src_alpha_g == 0)
1068 return;
1069
1070 scale = (backdrop_alpha * 255 * 2 + src_alpha_g) / (src_alpha_g << 1) -
1071 backdrop_alpha;
1072 for (i = 0; i < n_chan; i++) {
1073 int si, di;
1074
1075 si = src[i];
1076 di = backdrop[i];
1077 tmp = (si - di) * scale + 0x80;
1078 tmp = si + ((tmp + (tmp >> 8)) >> 8);
1079
1080 /* todo: it should be possible to optimize these cond branches */
1081 if (tmp < 0)
1082 tmp = 0;
1083 if (tmp > 255)
1084 tmp = 255;
1085 dst[i] = tmp;
1086 }
1087
1088 }
1089
1090 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,const pdf14_nonseparable_blending_procs_t * pblend_procs)1091 art_pdf_recomposite_group_8(byte *dst, byte *dst_alpha_g,
1092 const byte *src, byte src_alpha_g, int n_chan,
1093 byte alpha, gs_blend_mode_t blend_mode,
1094 const pdf14_nonseparable_blending_procs_t * pblend_procs)
1095 {
1096 byte dst_alpha;
1097 int i;
1098 int tmp;
1099 int scale;
1100
1101 if (src_alpha_g == 0)
1102 return;
1103
1104 if (blend_mode == BLEND_MODE_Normal && alpha == 255) {
1105 /* In this case, uncompositing and recompositing cancel each
1106 other out. Note: if the reason that alpha == 255 is that
1107 there is no constant mask and no soft mask, then this
1108 operation should be optimized away at a higher level. */
1109
1110 memcpy(dst, src, n_chan + 1);
1111 if (dst_alpha_g != NULL) {
1112 tmp = (255 - *dst_alpha_g) * (255 - src_alpha_g) + 0x80;
1113 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
1114 }
1115 return;
1116 } else {
1117 /* "interesting" blend mode */
1118 byte ca[ART_MAX_CHAN + 1]; /* $C, \alpha$ */
1119
1120 dst_alpha = dst[n_chan];
1121 if (src_alpha_g == 255 || dst_alpha == 0) {
1122 memcpy(ca, src, n_chan + 3);
1123 } else {
1124 /* Uncomposite the color. In other words, solve
1125 "src = (ca, src_alpha_g) over dst" for ca */
1126
1127 /* todo (maybe?): replace this code with call to
1128 art_pdf_uncomposite_group_8() to reduce code
1129 duplication. */
1130
1131 scale = (dst_alpha * 255 * 2 + src_alpha_g) / (src_alpha_g << 1) -
1132 dst_alpha;
1133 for (i = 0; i < n_chan; i++) {
1134 int si, di;
1135
1136 si = src[i];
1137 di = dst[i];
1138 tmp = (si - di) * scale + 0x80;
1139 tmp = si + ((tmp + (tmp >> 8)) >> 8);
1140
1141 /* todo: it should be possible to optimize these cond branches */
1142 if (tmp < 0)
1143 tmp = 0;
1144 if (tmp > 255)
1145 tmp = 255;
1146 ca[i] = tmp;
1147 }
1148 }
1149
1150 tmp = src_alpha_g * alpha + 0x80;
1151 tmp = (tmp + (tmp >> 8)) >> 8;
1152 ca[n_chan] = tmp;
1153 if (dst_alpha_g != NULL) {
1154 tmp = (255 - *dst_alpha_g) * (255 - tmp) + 0x80;
1155 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
1156 }
1157 art_pdf_composite_pixel_alpha_8(dst, ca, n_chan,
1158 blend_mode, pblend_procs);
1159 }
1160 /* todo: optimize BLEND_MODE_Normal buf alpha != 255 case */
1161 }
1162
1163 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,const pdf14_nonseparable_blending_procs_t * pblend_procs)1164 art_pdf_composite_group_8(byte *dst, byte *dst_alpha_g,
1165 const byte *src, int n_chan, byte alpha, gs_blend_mode_t blend_mode,
1166 const pdf14_nonseparable_blending_procs_t * pblend_procs)
1167 {
1168 byte src_alpha; /* $\alpha g_n$ */
1169 byte src_tmp[ART_MAX_CHAN + 1];
1170 int tmp;
1171
1172 if (alpha == 255) {
1173 art_pdf_composite_pixel_alpha_8(dst, src, n_chan,
1174 blend_mode, pblend_procs);
1175 if (dst_alpha_g != NULL) {
1176 tmp = (255 - *dst_alpha_g) * (255 - src[n_chan]) + 0x80;
1177 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
1178 }
1179 } else {
1180 src_alpha = src[n_chan];
1181 if (src_alpha == 0)
1182 return;
1183 memcpy(src_tmp, src, n_chan + 3);
1184 tmp = src_alpha * alpha + 0x80;
1185 src_tmp[n_chan] = (tmp + (tmp >> 8)) >> 8;
1186 art_pdf_composite_pixel_alpha_8(dst, src_tmp, n_chan,
1187 blend_mode, pblend_procs);
1188 if (dst_alpha_g != NULL) {
1189 tmp = (255 - *dst_alpha_g) * (255 - src_tmp[n_chan]) + 0x80;
1190 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
1191 }
1192 }
1193 }
1194
1195 /* A very simple case. Knockout isolated group going to a parent that is not
1196 a knockout. Simply copy over everwhere where we have a non-zero alpha value */
1197 void
art_pdf_knockoutisolated_group_8(byte * dst,const byte * src,int n_chan)1198 art_pdf_knockoutisolated_group_8(byte *dst, const byte *src, int n_chan)
1199 {
1200 byte src_alpha;
1201
1202 src_alpha = src[n_chan];
1203 if (src_alpha == 0)
1204 return;
1205
1206 memcpy (dst, src, n_chan + 1);
1207 }
1208
1209 void
art_pdf_composite_knockout_simple_8(byte * dst,byte * dst_shape,byte * dst_tag,const byte * src,byte tag,int n_chan,byte opacity)1210 art_pdf_composite_knockout_simple_8(byte *dst,
1211 byte *dst_shape,
1212 byte *dst_tag,
1213 const byte *src,
1214 byte tag,
1215 int n_chan, byte opacity)
1216 {
1217 byte src_shape = src[n_chan];
1218 int i;
1219
1220 if (src_shape == 0)
1221 return;
1222 else if (src_shape == 255) {
1223 memcpy (dst, src, n_chan + 3);
1224 dst[n_chan] = opacity;
1225 if (dst_shape != NULL)
1226 *dst_shape = 255;
1227 } else {
1228 /* Use src_shape to interpolate (in premultiplied alpha space)
1229 between dst and (src, opacity). */
1230 int dst_alpha = dst[n_chan];
1231 byte result_alpha;
1232 int tmp;
1233
1234 tmp = (opacity - dst_alpha) * src_shape + 0x80;
1235 result_alpha = dst_alpha + ((tmp + (tmp >> 8)) >> 8);
1236
1237 if (result_alpha != 0)
1238 for (i = 0; i < n_chan; i++) {
1239 /* todo: optimize this - can strength-reduce so that
1240 inner loop is a single interpolation */
1241 tmp = dst[i] * dst_alpha * (255 - src_shape) +
1242 ((int)src[i]) * opacity * src_shape + (result_alpha << 7);
1243 dst[i] = tmp / (result_alpha * 255);
1244 }
1245 dst[n_chan] = result_alpha;
1246
1247 /* union in dst_shape if non-null */
1248 if (dst_shape != NULL) {
1249 tmp = (255 - *dst_shape) * (255 - src_shape) + 0x80;
1250 *dst_shape = 255 - ((tmp + (tmp >> 8)) >> 8);
1251 }
1252 }
1253 }
1254
1255 void
art_pdf_composite_knockout_isolated_8(byte * dst,byte * dst_shape,byte * dst_tag,const byte * src,int n_chan,byte shape,byte tag,byte alpha_mask,byte shape_mask)1256 art_pdf_composite_knockout_isolated_8(byte *dst,
1257 byte *dst_shape,
1258 byte *dst_tag,
1259 const byte *src,
1260 int n_chan,
1261 byte shape,
1262 byte tag,
1263 byte alpha_mask, byte shape_mask)
1264 {
1265 int tmp;
1266 int i;
1267
1268 if (shape == 0)
1269 return;
1270 else if ((shape & shape_mask) == 255) {
1271
1272 memcpy(dst, src, n_chan + 3);
1273 tmp = src[n_chan] * alpha_mask + 0x80;
1274 dst[n_chan] = (tmp + (tmp >> 8)) >> 8;
1275 if (dst_shape != NULL)
1276 *dst_shape = 255;
1277 if (dst_tag != NULL)
1278 *dst_tag = tag;
1279 } else {
1280 /* Use src_shape to interpolate (in premultiplied alpha space)
1281 between dst and (src, opacity). */
1282 byte src_shape, src_alpha;
1283 int dst_alpha = dst[n_chan];
1284 byte result_alpha;
1285 int tmp;
1286
1287 tmp = shape * shape_mask + 0x80;
1288 src_shape = (tmp + (tmp >> 8)) >> 8;
1289
1290 tmp = src[n_chan] * alpha_mask + 0x80;
1291 src_alpha = (tmp + (tmp >> 8)) >> 8;
1292
1293 tmp = (src_alpha - dst_alpha) * src_shape + 0x80;
1294 result_alpha = dst_alpha + ((tmp + (tmp >> 8)) >> 8);
1295
1296 if (result_alpha != 0)
1297 for (i = 0; i < n_chan; i++) {
1298 /* todo: optimize this - can strength-reduce so that
1299 inner loop is a single interpolation */
1300 tmp = dst[i] * dst_alpha * (255 - src_shape) +
1301 ((int)src[i]) * src_alpha * src_shape +
1302 (result_alpha << 7);
1303 dst[i] = tmp / (result_alpha * 255);
1304 }
1305 dst[n_chan] = result_alpha;
1306
1307 /* union in dst_shape if non-null */
1308 if (dst_shape != NULL) {
1309 tmp = (255 - *dst_shape) * (255 - src_shape) + 0x80;
1310 *dst_shape = 255 - ((tmp + (tmp >> 8)) >> 8);
1311 }
1312 if (dst_tag != NULL) {
1313 *dst_tag = (*dst_tag | tag) & ~GS_UNTOUCHED_TAG;
1314 }
1315 }
1316 }
1317
1318 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,const pdf14_nonseparable_blending_procs_t * pblend_procs)1319 art_pdf_composite_knockout_8(byte *dst,
1320 byte *dst_alpha_g, const byte *backdrop, const byte *src,
1321 int n_chan, byte shape, byte alpha_mask,
1322 byte shape_mask, gs_blend_mode_t blend_mode,
1323 const pdf14_nonseparable_blending_procs_t * pblend_procs)
1324 {
1325 /* This implementation follows the Adobe spec pretty closely, rather
1326 than trying to do anything clever. For example, in the case of a
1327 Normal blend_mode when the top group is non-isolated, uncompositing
1328 and recompositing is more work than needed. So be it. Right now,
1329 I'm more worried about manageability than raw performance. */
1330 byte alpha_t;
1331 byte src_alpha, src_shape;
1332 byte src_opacity;
1333 byte ct[ART_MAX_CHAN];
1334 byte backdrop_alpha;
1335 byte alpha_g_i_1, alpha_g_i, alpha_i;
1336 int tmp;
1337 int i;
1338 int scale_b;
1339 int scale_src;
1340
1341 if (shape == 0 || shape_mask == 0)
1342 return;
1343
1344 tmp = shape * shape_mask + 0x80;
1345 /* $f s_i$ */
1346 src_shape = (tmp + (tmp >> 8)) >> 8;
1347
1348 tmp = src[n_chan] * alpha_mask + 0x80;
1349 src_alpha = (tmp + (tmp >> 8)) >> 8;
1350
1351 /* $q s_i$ */
1352 src_opacity = (src_alpha * 510 + src_shape) / (2 * src_shape);
1353
1354 /* $\alpha t$, \alpha g_b is always zero for knockout groups */
1355 alpha_t = src_opacity;
1356
1357 /* $\alpha b$ */
1358 backdrop_alpha = backdrop[n_chan];
1359
1360 tmp = (0xff - src_opacity) * backdrop_alpha;
1361 /* $(1 - q s_i) \cdot alpha_b$ scaled by 2^16 */
1362 scale_b = tmp + (tmp >> 7) + (tmp >> 14);
1363
1364 /* $q s_i$ scaled by 2^16 */
1365 scale_src = (src_opacity << 8) + (src_opacity) + (src_opacity >> 7);
1366
1367 /* Do simple compositing of source over backdrop */
1368 if (blend_mode == BLEND_MODE_Normal) {
1369 for (i = 0; i < n_chan; i++) {
1370 int c_s;
1371 int c_b;
1372
1373 c_s = src[i];
1374 c_b = backdrop[i];
1375 tmp = (c_b << 16) * scale_b + (c_s - c_b) + scale_src + 0x8000;
1376 ct[i] = tmp >> 16;
1377 }
1378 } else {
1379 byte blend[ART_MAX_CHAN];
1380
1381 art_blend_pixel_8(blend, backdrop, src, n_chan,
1382 blend_mode, pblend_procs);
1383 for (i = 0; i < n_chan; i++) {
1384 int c_s;
1385 int c_b;
1386 int c_bl; /* Result of blend function */
1387 int c_mix; /* Blend result mixed with source color */
1388
1389 c_s = src[i];
1390 c_b = backdrop[i];
1391 c_bl = blend[i];
1392 tmp = backdrop_alpha * (c_bl - ((int)c_s)) + 0x80;
1393 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
1394 tmp = (c_b << 16) * scale_b + (c_mix - c_b) + scale_src + 0x8000;
1395 ct[i] = tmp >> 16;
1396 }
1397 }
1398
1399 /* $\alpha g_{i - 1}$ */
1400 alpha_g_i_1 = *dst_alpha_g;
1401
1402 tmp = src_shape * (((int)alpha_t) - alpha_g_i_1) + 0x80;
1403 /* $\alpha g_i$ */
1404 alpha_g_i = alpha_g_i_1 + ((tmp + (tmp >> 8)) >> 8);
1405
1406 tmp = (0xff - backdrop_alpha) * (0xff - alpha_g_i) + 0x80;
1407 /* $\alpha_i$ */
1408 alpha_i = 0xff - ((tmp + (tmp >> 8)) >> 8);
1409
1410 if (alpha_i > 0) {
1411 int scale_dst;
1412 int scale_t;
1413 byte dst_alpha;
1414
1415 /* $f s_i / \alpha_i$ scaled by 2^16 */
1416 scale_t = ((src_shape << 17) + alpha_i) / (2 * alpha_i);
1417
1418 /* $\alpha_{i - 1}$ */
1419 dst_alpha = dst[n_chan];
1420
1421 tmp = (1 - src_shape) * dst_alpha;
1422 tmp = (tmp << 9) + (tmp << 1) + (tmp >> 7) + alpha_i;
1423 scale_dst = tmp / (2 * alpha_i);
1424
1425 for (i = 0; i < n_chan; i++) {
1426 tmp = dst[i] * scale_dst + ct[i] * scale_t + 0x8000;
1427 /* todo: clamp? */
1428 dst[i] = tmp >> 16;
1429 }
1430 }
1431 dst[n_chan] = alpha_i;
1432 *dst_alpha_g = alpha_g_i;
1433 }
1434
1435 #if RAW_DUMP
1436 /* Debug dump of buffer data from pdf14 device. Saved in
1437 planar form with global indexing and tag information in
1438 file name */
1439 void
dump_raw_buffer(int num_rows,int width,int n_chan,int plane_stride,int rowstride,char filename[],byte * Buffer)1440 dump_raw_buffer(int num_rows, int width, int n_chan,
1441 int plane_stride, int rowstride,
1442 char filename[],byte *Buffer)
1443 {
1444 char full_file_name[50];
1445 FILE *fid;
1446 int z,y;
1447 byte *buff_ptr;
1448 int max_bands;
1449
1450 /* clist_band_count is incremented at every pdf14putimage */
1451 /* Useful for catching this thing and only dumping */
1452 /* during a particular band if we have a large file */
1453 /* if (clist_band_count != 65) return; */
1454 buff_ptr = Buffer;
1455 #if RAW_DUMP_AS_PAM
1456 /* FIXME: GRAY + ALPHA + SHAPE + TAGS will be interpreted as RGB + ALPHA */
1457 if ((n_chan == 2) || (n_chan == 3)) {
1458 int x;
1459 sprintf(full_file_name,"%02d)%s.pam",global_index,filename);
1460 fid = fopen(full_file_name,"wb");
1461 fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE GRAYSCALE_ALPHA\nENDHDR\n",
1462 width, num_rows);
1463 for(y=0; y<num_rows; y++)
1464 for(x=0; x<width; x++)
1465 for(z=0; z<2; z++)
1466 fputc(Buffer[z*plane_stride + y*rowstride + x], fid);
1467 fclose(fid);
1468 if (n_chan == 3) {
1469 sprintf(full_file_name,"%02d)%s_shape.pam",global_index,filename);
1470 fid = fopen(full_file_name,"wb");
1471 fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 1\nMAXVAL 255\nTUPLTYPE GRAYSCALE\nENDHDR\n",
1472 width, num_rows);
1473 for(y=0; y<num_rows; y++)
1474 for(x=0; x<width; x++)
1475 fputc(Buffer[2*plane_stride + y*rowstride + x], fid);
1476 fclose(fid);
1477 }
1478 }
1479 if ((n_chan == 4) || (n_chan == 5) || (n_chan == 6)) {
1480 int x;
1481 sprintf(full_file_name,"%02d)%s.pam",global_index,filename);
1482 fid = fopen(full_file_name,"wb");
1483 fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n",
1484 width, num_rows);
1485 for(y=0; y<num_rows; y++)
1486 for(x=0; x<width; x++)
1487 for(z=0; z<4; z++)
1488 fputc(Buffer[z*plane_stride + y*rowstride + x], fid);
1489 fclose(fid);
1490 if (n_chan > 4) {
1491 sprintf(full_file_name,"%02d)%s_shape.pam",global_index,filename);
1492 fid = fopen(full_file_name,"wb");
1493 fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 1\nMAXVAL 255\nTUPLTYPE GRAYSCALE\nENDHDR\n",
1494 width, num_rows);
1495 for(y=0; y<num_rows; y++)
1496 for(x=0; x<width; x++)
1497 fputc(Buffer[4*plane_stride + y*rowstride + x], fid);
1498 fclose(fid);
1499 }
1500 if (n_chan == 6) {
1501 sprintf(full_file_name,"%02d)%s_tags.pam",global_index,filename);
1502 fid = fopen(full_file_name,"wb");
1503 fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 1\nMAXVAL 255\nTUPLTYPE GRAYSCALE\nENDHDR\n",
1504 width, num_rows);
1505 for(y=0; y<num_rows; y++)
1506 for(x=0; x<width; x++)
1507 fputc(Buffer[5*plane_stride + y*rowstride + x], fid);
1508 fclose(fid);
1509 }
1510 return;
1511 }
1512 #endif
1513 max_bands = ( n_chan < 57 ? n_chan : 56); /* Photoshop handles at most 56 bands */
1514 sprintf(full_file_name,"%02d)%s_%dx%dx%d.raw",global_index,filename,width,num_rows,max_bands);
1515 fid = fopen(full_file_name,"wb");
1516
1517 for (z = 0; z < max_bands; ++z) {
1518 /* grab pointer to the next plane */
1519 buff_ptr = &(Buffer[z*plane_stride]);
1520 for ( y = 0; y < num_rows; y++ ) {
1521 /* write out each row */
1522 fwrite(buff_ptr,sizeof(unsigned char),width,fid);
1523 buff_ptr += rowstride;
1524 }
1525 }
1526 fclose(fid);
1527 }
1528 #endif
1529