2 |
- |
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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 |
}
|