xref: /plan9/sys/src/cmd/gs/src/gxicolor.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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