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