1 /* Copyright (C) 1992, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gxicolor.c,v 1.9 2003/08/18 21:21:57 dan Exp $ */
18 /* Color image rendering */
19 #include "gx.h"
20 #include "memory_.h"
21 #include "gpcheck.h"
22 #include "gserrors.h"
23 #include "gxfixed.h"
24 #include "gxfrac.h"
25 #include "gxarith.h"
26 #include "gxmatrix.h"
27 #include "gsccolor.h"
28 #include "gspaint.h"
29 #include "gzstate.h"
30 #include "gxdevice.h"
31 #include "gxcmap.h"
32 #include "gxdcconv.h"
33 #include "gxdcolor.h"
34 #include "gxistate.h"
35 #include "gxdevmem.h"
36 #include "gxcpath.h"
37 #include "gximage.h"
38
39 typedef union {
40 byte v[GS_IMAGE_MAX_COLOR_COMPONENTS];
41 #define BYTES_PER_BITS32 4
42 #define BITS32_PER_COLOR_SAMPLES\
43 ((GS_IMAGE_MAX_COLOR_COMPONENTS + BYTES_PER_BITS32 - 1) / BYTES_PER_BITS32)
44 bits32 all[BITS32_PER_COLOR_SAMPLES]; /* for fast comparison */
45 } color_samples;
46
47 /* ------ Strategy procedure ------ */
48
49 /* Check the prototype. */
50 iclass_proc(gs_image_class_4_color);
51
52 private irender_proc(image_render_color);
53 irender_proc_t
gs_image_class_4_color(gx_image_enum * penum)54 gs_image_class_4_color(gx_image_enum * penum)
55 {
56 if (penum->use_mask_color) {
57 /*
58 * Scale the mask colors to match the scaling of each sample to
59 * a full byte, and set up the quick-filter parameters.
60 */
61 int i;
62 color_samples mask, test;
63 bool exact = penum->spp <= BYTES_PER_BITS32;
64
65 memset(&mask, 0, sizeof(mask));
66 memset(&test, 0, sizeof(test));
67 for (i = 0; i < penum->spp; ++i) {
68 byte v0, v1;
69 byte match = 0xff;
70
71 gx_image_scale_mask_colors(penum, i);
72 v0 = (byte)penum->mask_color.values[2 * i];
73 v1 = (byte)penum->mask_color.values[2 * i + 1];
74 while ((v0 & match) != (v1 & match))
75 match <<= 1;
76 mask.v[i] = match;
77 test.v[i] = v0 & match;
78 exact &= (v0 == match && (v1 | match) == 0xff);
79 }
80 penum->mask_color.mask = mask.all[0];
81 penum->mask_color.test = test.all[0];
82 penum->mask_color.exact = exact;
83 } else {
84 penum->mask_color.mask = 0;
85 penum->mask_color.test = ~0;
86 }
87 return &image_render_color;
88 }
89
90 /* ------ Rendering procedures ------ */
91
92 /* Test whether a color is transparent. */
93 private bool
mask_color_matches(const byte * v,const gx_image_enum * penum,int num_components)94 mask_color_matches(const byte *v, const gx_image_enum *penum,
95 int num_components)
96 {
97 int i;
98
99 for (i = num_components * 2, v += num_components - 1; (i -= 2) >= 0; --v)
100 if (*v < penum->mask_color.values[i] ||
101 *v > penum->mask_color.values[i + 1]
102 )
103 return false;
104 return true;
105 }
106
107 /* Render a color image with 8 or fewer bits per sample. */
108 private int
image_render_color(gx_image_enum * penum_orig,const byte * buffer,int data_x,uint w,int h,gx_device * dev)109 image_render_color(gx_image_enum *penum_orig, const byte *buffer, int data_x,
110 uint w, int h, gx_device * dev)
111 {
112 const gx_image_enum *const penum = penum_orig; /* const within proc */
113 gx_image_clue *const clues = penum_orig->clues; /* not const */
114 const gs_imager_state *pis = penum->pis;
115 gs_logical_operation_t lop = penum->log_op;
116 gx_dda_fixed_point pnext;
117 image_posture posture = penum->posture;
118 fixed xprev, yprev;
119 fixed pdyx, pdyy; /* edge of parallelogram */
120 int vci, vdi;
121 const gs_color_space *pcs = penum->pcs;
122 cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
123 cs_proc_remap_concrete_color((*remap_concrete_color)) =
124 pcs->type->remap_concrete_color;
125 gs_client_color cc;
126 bool device_color = penum->device_color;
127 const gx_color_map_procs *cmap_procs = gx_get_cmap_procs(pis, dev);
128 bits32 mask = penum->mask_color.mask;
129 bits32 test = penum->mask_color.test;
130 gx_image_clue *pic = &clues[0];
131 #define pdevc (&pic->dev_color)
132 gx_image_clue *pic_next = &clues[1];
133 #define pdevc_next (&pic_next->dev_color)
134 gx_image_clue empty_clue;
135 gx_image_clue clue_temp;
136 int spp = penum->spp;
137 const byte *psrc_initial = buffer + data_x * spp;
138 const byte *psrc = psrc_initial;
139 const byte *rsrc = psrc + spp; /* psrc + spp at start of run */
140 fixed xrun; /* x ditto */
141 fixed yrun; /* y ditto */
142 int irun; /* int x/rrun */
143 color_samples run; /* run value */
144 color_samples next; /* next sample value */
145 const byte *bufend = psrc + w;
146 bool use_cache = spp * penum->bps <= 12;
147 int code = 0, mcode = 0;
148
149 if (h == 0)
150 return 0;
151 pnext = penum->dda.pixel0;
152 xrun = xprev = dda_current(pnext.x);
153 yrun = yprev = dda_current(pnext.y);
154 pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
155 pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
156 switch (posture) {
157 case image_portrait:
158 vci = penum->yci, vdi = penum->hci;
159 irun = fixed2int_var_rounded(xrun);
160 break;
161 case image_landscape:
162 default: /* we don't handle skew -- treat as landscape */
163 vci = penum->xci, vdi = penum->wci;
164 irun = fixed2int_var_rounded(yrun);
165 break;
166 }
167
168 if_debug5('b', "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n",
169 penum->y, data_x, w, fixed2float(xprev), fixed2float(yprev));
170 memset(&run, 0, sizeof(run));
171 memset(&next, 0, sizeof(next));
172 /* Ensure that we don't get any false dev_color_eq hits. */
173 if (use_cache) {
174 set_nonclient_dev_color(&empty_clue.dev_color, gx_no_color_index);
175 pic = &empty_clue;
176 }
177 cs_full_init_color(&cc, pcs);
178 run.v[0] = ~psrc[0]; /* force remap */
179 while (psrc < bufend) {
180 dda_next(pnext.x);
181 dda_next(pnext.y);
182 #define CLUE_HASH3(penum, next)\
183 &clues[(next.v[0] + (next.v[1] << 2) + (next.v[2] << 4)) & 255];
184 #define CLUE_HASH4(penum, next)\
185 &clues[(next.v[0] + (next.v[1] << 2) + (next.v[2] << 4) +\
186 (next.v[3] << 6)) & 255]
187
188 if (spp == 4) { /* may be CMYK or RGBA */
189 next.v[0] = psrc[0];
190 next.v[1] = psrc[1];
191 next.v[2] = psrc[2];
192 next.v[3] = psrc[3];
193 psrc += 4;
194 map4: if (next.all[0] == run.all[0])
195 goto inc;
196 if (use_cache) {
197 pic_next = CLUE_HASH4(penum, next);
198 if (pic_next->key == next.all[0])
199 goto f;
200 /*
201 * If we are really unlucky, pic_next == pic,
202 * so mapping this color would clobber the one
203 * we're about to use for filling the run.
204 */
205 if (pic_next == pic) {
206 clue_temp = *pic;
207 pic = &clue_temp;
208 }
209 pic_next->key = next.all[0];
210 }
211 /* Check for transparent color. */
212 if ((next.all[0] & mask) == test &&
213 (penum->mask_color.exact ||
214 mask_color_matches(next.v, penum, 4))
215 ) {
216 color_set_null(pdevc_next);
217 goto mapped;
218 }
219 if (device_color) {
220 frac frac_color[4];
221
222 if (penum->alpha) {
223 /*
224 * We do not have support for DeviceN color and alpha.
225 */
226 cmap_procs->map_rgb_alpha
227 (byte2frac(next.v[0]), byte2frac(next.v[1]),
228 byte2frac(next.v[2]), byte2frac(next.v[3]),
229 pdevc_next, pis, dev,
230 gs_color_select_source);
231 goto mapped;
232 }
233 /*
234 * We can call the remap concrete_color for the colorspace
235 * directly since device_color is only true if the colorspace
236 * is concrete.
237 */
238 frac_color[0] = byte2frac(next.v[0]);
239 frac_color[1] = byte2frac(next.v[1]);
240 frac_color[2] = byte2frac(next.v[2]);
241 frac_color[3] = byte2frac(next.v[3]);
242 remap_concrete_color(frac_color, pcs, pdevc_next, pis,
243 dev, gs_color_select_source);
244 goto mapped;
245 }
246 decode_sample(next.v[3], cc, 3);
247 if_debug1('B', "[B]cc[3]=%g\n", cc.paint.values[3]);
248 do3: decode_sample(next.v[0], cc, 0);
249 decode_sample(next.v[1], cc, 1);
250 decode_sample(next.v[2], cc, 2);
251 if_debug3('B', "[B]cc[0..2]=%g,%g,%g\n",
252 cc.paint.values[0], cc.paint.values[1],
253 cc.paint.values[2]);
254 } else if (spp == 3) { /* may be RGB */
255 next.v[0] = psrc[0];
256 next.v[1] = psrc[1];
257 next.v[2] = psrc[2];
258 psrc += 3;
259 if (next.all[0] == run.all[0])
260 goto inc;
261 if (use_cache) {
262 pic_next = CLUE_HASH3(penum, next);
263 if (pic_next->key == next.all[0])
264 goto f;
265 /* See above re the following check. */
266 if (pic_next == pic) {
267 clue_temp = *pic;
268 pic = &clue_temp;
269 }
270 pic_next->key = next.all[0];
271 }
272 /* Check for transparent color. */
273 if ((next.all[0] & mask) == test &&
274 (penum->mask_color.exact ||
275 mask_color_matches(next.v, penum, 3))
276 ) {
277 color_set_null(pdevc_next);
278 goto mapped;
279 }
280 if (device_color) {
281 frac frac_color[3];
282 /*
283 * We can call the remap concrete_color for the colorspace
284 * directly since device_color is only true if the colorspace
285 * is concrete.
286 */
287 frac_color[0] = byte2frac(next.v[0]);
288 frac_color[1] = byte2frac(next.v[1]);
289 frac_color[2] = byte2frac(next.v[2]);
290 remap_concrete_color(frac_color, pcs, pdevc_next, pis,
291 dev, gs_color_select_source);
292 goto mapped;
293 }
294 goto do3;
295 } else if (penum->alpha) {
296 if (spp == 2) { /* might be Gray + alpha */
297 next.v[2] = next.v[1] = next.v[0] = psrc[0];
298 next.v[3] = psrc[1];
299 psrc += 2;
300 goto map4;
301 } else if (spp == 5) { /* might be CMYK + alpha */
302 /* Convert CMYK to RGB. */
303 frac rgb[3];
304
305 color_cmyk_to_rgb(byte2frac(psrc[0]), byte2frac(psrc[1]),
306 byte2frac(psrc[2]), byte2frac(psrc[3]),
307 pis, rgb);
308 /*
309 * It seems silly to do all this converting between
310 * fracs and bytes, but that's what the current
311 * APIs require.
312 */
313 next.v[0] = frac2byte(rgb[0]);
314 next.v[1] = frac2byte(rgb[1]);
315 next.v[2] = frac2byte(rgb[2]);
316 next.v[3] = psrc[4];
317 psrc += 5;
318 goto map4;
319 }
320 } else { /* DeviceN */
321 int i;
322
323 use_cache = false; /* should do in initialization */
324 if (!memcmp(psrc, run.v, spp)) {
325 psrc += spp;
326 goto inc;
327 }
328 memcpy(next.v, psrc, spp);
329 psrc += spp;
330 if ((next.all[0] & mask) == test &&
331 (penum->mask_color.exact ||
332 mask_color_matches(next.v, penum, spp))
333 ) {
334 color_set_null(pdevc_next);
335 goto mapped;
336 }
337 for (i = 0; i < spp; ++i)
338 decode_sample(next.v[i], cc, i);
339 #ifdef DEBUG
340 if (gs_debug_c('B')) {
341 dprintf2("[B]cc[0..%d]=%g", spp - 1,
342 cc.paint.values[0]);
343 for (i = 1; i < spp; ++i)
344 dprintf1(",%g", cc.paint.values[i]);
345 dputs("\n");
346 }
347 #endif
348 }
349 mcode = remap_color(&cc, pcs, pdevc_next, pis, dev,
350 gs_color_select_source);
351 if (mcode < 0)
352 goto fill;
353 mapped: if (pic == pic_next)
354 goto fill;
355 f: if_debug7('B', "[B]0x%x,0x%x,0x%x,0x%x -> %ld,%ld,0x%lx\n",
356 next.v[0], next.v[1], next.v[2], next.v[3],
357 pdevc_next->colors.binary.color[0],
358 pdevc_next->colors.binary.color[1],
359 (ulong) pdevc_next->type);
360 /* Even though the supplied colors don't match, */
361 /* the device colors might. */
362 if (dev_color_eq(*pdevc, *pdevc_next))
363 goto set;
364 fill: /* Fill the region between */
365 /* xrun/irun and xprev */
366 /*
367 * Note; This section is nearly a copy of a simlar section below
368 * for processing the last image pixel in the loop. This would have been
369 * made into a subroutine except for complications about the number of
370 * variables that would have been needed to be passed to the routine.
371 */
372 switch (posture) {
373 case image_portrait:
374 { /* Rectangle */
375 int xi = irun;
376 int wi = (irun = fixed2int_var_rounded(xprev)) - xi;
377
378 if (wi < 0)
379 xi += wi, wi = -wi;
380 if (wi > 0)
381 code = gx_fill_rectangle_device_rop(xi, vci, wi, vdi,
382 pdevc, dev, lop);
383 }
384 break;
385 case image_landscape:
386 { /* 90 degree rotated rectangle */
387 int yi = irun;
388 int hi = (irun = fixed2int_var_rounded(yprev)) - yi;
389
390 if (hi < 0)
391 yi += hi, hi = -hi;
392 if (hi > 0)
393 code = gx_fill_rectangle_device_rop(vci, yi, vdi, hi,
394 pdevc, dev, lop);
395 }
396 break;
397 default:
398 { /* Parallelogram */
399 code = (*dev_proc(dev, fill_parallelogram))
400 (dev, xrun, yrun, xprev - xrun, yprev - yrun, pdyx, pdyy,
401 pdevc, lop);
402 xrun = xprev;
403 yrun = yprev;
404 }
405 }
406 if (code < 0)
407 goto err;
408 rsrc = psrc;
409 if ((code = mcode) < 0) {
410 /* Invalidate any partially built cache entry. */
411 if (use_cache)
412 pic_next->key = ~next.all[0];
413 goto err;
414 }
415 if (use_cache)
416 pic = pic_next;
417 else {
418 gx_image_clue *ptemp = pic;
419
420 pic = pic_next;
421 pic_next = ptemp;
422 }
423 set: run = next;
424 inc: xprev = dda_current(pnext.x);
425 yprev = dda_current(pnext.y); /* harmless if no skew */
426 }
427 /* Fill the last run. */
428 /*
429 * Note; This section is nearly a copy of a simlar section above
430 * for processing an image pixel in the loop. This would have been
431 * made into a subroutine except for complications about the number
432 * variables that would have been needed to be passed to the routine.
433 */
434 switch (posture) {
435 case image_portrait:
436 { /* Rectangle */
437 int xi = irun;
438 int wi = (irun = fixed2int_var_rounded(xprev)) - xi;
439
440 if (wi < 0)
441 xi += wi, wi = -wi;
442 if (wi > 0)
443 code = gx_fill_rectangle_device_rop(xi, vci, wi, vdi,
444 pdevc, dev, lop);
445 }
446 break;
447 case image_landscape:
448 { /* 90 degree rotated rectangle */
449 int yi = irun;
450 int hi = (irun = fixed2int_var_rounded(yprev)) - yi;
451
452 if (hi < 0)
453 yi += hi, hi = -hi;
454 if (hi > 0)
455 code = gx_fill_rectangle_device_rop(vci, yi, vdi, hi,
456 pdevc, dev, lop);
457 }
458 break;
459 default:
460 { /* Parallelogram */
461 code = (*dev_proc(dev, fill_parallelogram))
462 (dev, xrun, yrun, xprev - xrun, yprev - yrun, pdyx, pdyy,
463 pdevc, lop);
464 }
465 }
466 return (code < 0 ? code : 1);
467 /* Save position if error, in case we resume. */
468 err:
469 penum_orig->used.x = (rsrc - spp - psrc_initial) / spp;
470 penum_orig->used.y = 0;
471 return code;
472 }
473