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