1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
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, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: gxi12bit.c 8517 2008-02-04 22:18:08Z leonardo $ */
15 /* 12-bit image procedures */
16 #include "gx.h"
17 #include "memory_.h"
18 #include "gpcheck.h"
19 #include "gserrors.h"
20 #include "gxfixed.h"
21 #include "gxfrac.h"
22 #include "gxarith.h"
23 #include "gxmatrix.h"
24 #include "gsccolor.h"
25 #include "gspaint.h"
26 #include "gxdevice.h"
27 #include "gxcmap.h"
28 #include "gxdcolor.h"
29 #include "gxistate.h"
30 #include "gxdevmem.h"
31 #include "gxcpath.h"
32 #include "gximage.h"
33 #include "vdtrace.h"
34 
35 /* ---------------- Unpacking procedures ---------------- */
36 
37 static const byte *
sample_unpack_12(byte * bptr,int * pdata_x,const byte * data,int data_x,uint dsize,const sample_map * ignore_smap,int spread,int ignore_num_components_per_plane)38 sample_unpack_12(byte * bptr, int *pdata_x, const byte * data,
39 		 int data_x, uint dsize, const sample_map *ignore_smap, int spread,
40 		 int ignore_num_components_per_plane)
41 {
42     /* Assuming an identity map for all components. */
43     register frac *bufp = (frac *) bptr;
44     uint dskip = (data_x >> 1) * 3;
45     const byte *psrc = data + dskip;
46 #define inc_bufp(bp, n) bp = (frac *)((byte *)(bp) + (n))
47     uint sample;
48     int left = dsize - dskip;
49 
50     if ((data_x & 1) && left > 0)
51 	switch (left) {
52 	    default:
53 		sample = ((uint) (psrc[1] & 0xf) << 8) + psrc[2];
54 		*bufp = bits2frac(sample, 12);
55 		inc_bufp(bufp, spread);
56 		psrc += 3;
57 		left -= 3;
58 		break;
59 	    case 2:		/* xxxxxxxx xxxxdddd */
60 		*bufp = (psrc[1] & 0xf) * (frac_1 / 15);
61 	    case 1:		/* xxxxxxxx */
62 		left = 0;
63 	}
64     while (left >= 3) {
65 	sample = ((uint) * psrc << 4) + (psrc[1] >> 4);
66 	*bufp = bits2frac(sample, 12);
67 	inc_bufp(bufp, spread);
68 	sample = ((uint) (psrc[1] & 0xf) << 8) + psrc[2];
69 	*bufp = bits2frac(sample, 12);
70 	inc_bufp(bufp, spread);
71 	psrc += 3;
72 	left -= 3;
73     }
74     /* Handle trailing bytes. */
75     switch (left) {
76 	case 2:		/* dddddddd ddddxxxx */
77 	    sample = ((uint) * psrc << 4) + (psrc[1] >> 4);
78 	    *bufp = bits2frac(sample, 12);
79 	    inc_bufp(bufp, spread);
80 	    *bufp = (psrc[1] & 0xf) * (frac_1 / 15);
81 	    break;
82 	case 1:		/* dddddddd */
83 	    sample = (uint) * psrc << 4;
84 	    *bufp = bits2frac(sample, 12);
85 	    break;
86 	case 0:		/* Nothing more to do. */
87 	    ;
88     }
89     *pdata_x = 0;
90     return bptr;
91 }
92 
93 const sample_unpack_proc_t sample_unpack_12_proc = sample_unpack_12;
94 
95 /* ------ Strategy procedure ------ */
96 
97 /* Check the prototype. */
98 iclass_proc(gs_image_class_2_fracs);
99 
100 /* Use special (slow) logic for 12-bit source values. */
101 static irender_proc(image_render_frac);
102 irender_proc_t
gs_image_class_2_fracs(gx_image_enum * penum)103 gs_image_class_2_fracs(gx_image_enum * penum)
104 {
105     if (penum->bps > 8) {
106 	if (penum->use_mask_color) {
107 	    /* Convert color mask values to fracs. */
108 	    int i;
109 
110 	    for (i = 0; i < penum->spp * 2; ++i)
111 		penum->mask_color.values[i] =
112 		    bits2frac(penum->mask_color.values[i], 12);
113 	}
114 	if_debug0('b', "[b]render=frac\n");
115 	return &image_render_frac;
116     }
117     return 0;
118 }
119 
120 /* ---------------- Rendering procedures ---------------- */
121 
122 /* ------ Rendering for 12-bit samples ------ */
123 
124 #define FRACS_PER_LONG (arch_sizeof_long / arch_sizeof_frac)
125 typedef union {
126     frac v[GS_IMAGE_MAX_COLOR_COMPONENTS];
127 #define LONGS_PER_COLOR_FRACS\
128   ((GS_IMAGE_MAX_COLOR_COMPONENTS + FRACS_PER_LONG - 1) / FRACS_PER_LONG)
129     long all[LONGS_PER_COLOR_FRACS];	/* for fast comparison */
130 } color_fracs;
131 
132 #define LONGS_PER_4_FRACS ((arch_sizeof_frac * 4 + arch_sizeof_long - 1) / arch_sizeof_long)
133 #if LONGS_PER_4_FRACS == 1
134 #  define COLOR_FRACS_4_EQ(f1, f2)\
135      ((f1).all[0] == (f2).all[0])
136 #else
137 #if LONGS_PER_4_FRACS == 2
138 #  define COLOR_FRACS_4_EQ(f1, f2)\
139      ((f1).all[0] == (f2).all[0] && (f1).all[1] == (f2).all[1])
140 #endif
141 #endif
142 
143 /* Test whether a color is transparent. */
144 static bool
mask_color12_matches(const frac * v,const gx_image_enum * penum,int num_components)145 mask_color12_matches(const frac *v, const gx_image_enum *penum,
146 		   int num_components)
147 {
148     int i;
149 
150     for (i = num_components * 2, v += num_components - 1; (i -= 2) >= 0; --v)
151 	if (*v < penum->mask_color.values[i] ||
152 	    *v > penum->mask_color.values[i + 1]
153 	    )
154 	    return false;
155     return true;
156 }
157 
158 /* Render an image with more than 8 bits per sample. */
159 /* The samples have been expanded into fracs. */
160 static int
image_render_frac(gx_image_enum * penum,const byte * buffer,int data_x,uint w,int h,gx_device * dev)161 image_render_frac(gx_image_enum * penum, const byte * buffer, int data_x,
162 		  uint w, int h, gx_device * dev)
163 {
164     const gs_imager_state *pis = penum->pis;
165     gs_logical_operation_t lop = penum->log_op;
166     gx_dda_fixed_point pnext;
167     image_posture posture = penum->posture;
168     fixed xl, ytf;
169     fixed pdyx, pdyy;		/* edge of parallelogram */
170     int yt = penum->yci, iht = penum->hci;
171     const gs_color_space *pcs = penum->pcs;
172     cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
173     gs_client_color cc;
174     bool device_color = penum->device_color;
175     const gx_color_map_procs *cmap_procs = gx_get_cmap_procs(pis, dev);
176     cmap_proc_rgb((*map_rgb)) = cmap_procs->map_rgb;
177     cmap_proc_cmyk((*map_cmyk)) = cmap_procs->map_cmyk;
178     bool use_mask_color = penum->use_mask_color;
179     gx_device_color devc1, devc2;
180     gx_device_color *pdevc = &devc1;
181     gx_device_color *pdevc_next = &devc2;
182     int spp = penum->spp;
183     const frac *psrc_initial = (const frac *)buffer + data_x * spp;
184     const frac *psrc = psrc_initial;
185     const frac *rsrc = psrc + spp; /* psrc + spp at start of run */
186     fixed xrun;			/* x at start of run */
187     int irun;			/* int xrun */
188     fixed yrun;			/* y ditto */
189     color_fracs run;		/* run value */
190     color_fracs next;		/* next sample value */
191     const frac *bufend = psrc + w;
192     int code = 0, mcode = 0;
193 
194     if (h == 0)
195 	return 0;
196     pnext = penum->dda.pixel0;
197     xrun = xl = dda_current(pnext.x);
198     irun = fixed2int_var_rounded(xrun);
199     yrun = ytf = dda_current(pnext.y);
200     pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
201     pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
202     if_debug5('b', "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n",
203 	      penum->y, data_x, w, fixed2float(xl), fixed2float(ytf));
204     memset(&run, 0, sizeof(run));
205     memset(&next, 0, sizeof(next));
206     /* Ensure that we don't get any false dev_color_eq hits. */
207     set_nonclient_dev_color(&devc1, gx_no_color_index);
208     set_nonclient_dev_color(&devc2, gx_no_color_index);
209     cs_full_init_color(&cc, pcs);
210     run.v[0] = ~psrc[0];	/* force remap */
211 
212     while (psrc < bufend) {
213 	next.v[0] = psrc[0];
214 	switch (spp) {
215 	    case 4:		/* may be CMYK */
216 		next.v[1] = psrc[1];
217 		next.v[2] = psrc[2];
218 		next.v[3] = psrc[3];
219 		psrc += 4;
220 		if (COLOR_FRACS_4_EQ(next, run))
221 		    goto inc;
222 		if (use_mask_color && mask_color12_matches(next.v, penum, 4)) {
223 		    color_set_null(pdevc_next);
224 		    goto f;
225 		}
226 		if (device_color) {
227 		    (*map_cmyk) (next.v[0], next.v[1],
228 				 next.v[2], next.v[3],
229 				 pdevc_next, pis, dev,
230 				 gs_color_select_source);
231 		    goto f;
232 		}
233 		decode_frac(next.v[0], cc, 0);
234 		decode_frac(next.v[1], cc, 1);
235 		decode_frac(next.v[2], cc, 2);
236 		decode_frac(next.v[3], cc, 3);
237 		if_debug4('B', "[B]cc[0..3]=%g,%g,%g,%g\n",
238 			  cc.paint.values[0], cc.paint.values[1],
239 			  cc.paint.values[2], cc.paint.values[3]);
240 		if_debug1('B', "[B]cc[3]=%g\n",
241 			  cc.paint.values[3]);
242 		break;
243 	    case 3:		/* may be RGB */
244 		next.v[1] = psrc[1];
245 		next.v[2] = psrc[2];
246 		psrc += 3;
247 		if (COLOR_FRACS_4_EQ(next, run))
248 		    goto inc;
249 		if (use_mask_color && mask_color12_matches(next.v, penum, 3)) {
250 		    color_set_null(pdevc_next);
251 		    goto f;
252 		}
253 		if (device_color) {
254 		    (*map_rgb) (next.v[0], next.v[1],
255 				next.v[2], pdevc_next, pis, dev,
256 				gs_color_select_source);
257 		    goto f;
258 		}
259 		decode_frac(next.v[0], cc, 0);
260 		decode_frac(next.v[1], cc, 1);
261 		decode_frac(next.v[2], cc, 2);
262 		if_debug3('B', "[B]cc[0..2]=%g,%g,%g\n",
263 			  cc.paint.values[0], cc.paint.values[1],
264 			  cc.paint.values[2]);
265 		break;
266 	    case 1:		/* may be Gray */
267 		psrc++;
268 		if (next.v[0] == run.v[0])
269 		    goto inc;
270 		if (use_mask_color && mask_color12_matches(next.v, penum, 1)) {
271 		    color_set_null(pdevc_next);
272 		    goto f;
273 		}
274 		if (device_color) {
275 		    (*map_rgb) (next.v[0], next.v[0],
276 				next.v[0], pdevc_next, pis, dev,
277 				gs_color_select_source);
278 		    goto f;
279 		}
280 		decode_frac(next.v[0], cc, 0);
281 		if_debug1('B', "[B]cc[0]=%g\n",
282 			  cc.paint.values[0]);
283 		break;
284 	    default:		/* DeviceN */
285 		{
286 		    int i;
287 
288 		    for (i = 1; i < spp; ++i)
289 			next.v[i] = psrc[i];
290 		    psrc += spp;
291 		    if (!memcmp(next.v, run.v, spp * sizeof(next.v[0])))
292 			goto inc;
293 		    if (use_mask_color &&
294 			mask_color12_matches(next.v, penum, spp)
295 			) {
296 			color_set_null(pdevc_next);
297 			goto f;
298 		    }
299 		    for (i = 0; i < spp; ++i)
300 			decode_frac(next.v[i], cc, i);
301 #ifdef DEBUG
302 		    if (gs_debug_c('B')) {
303 			dprintf2("[B]cc[0..%d]=%g", spp - 1,
304 				 cc.paint.values[0]);
305 			for (i = 1; i < spp; ++i)
306 			    dprintf1(",%g", cc.paint.values[i]);
307 			dputs("\n");
308 		    }
309 #endif
310 		}
311 		break;
312 	}
313 	mcode = remap_color(&cc, pcs, pdevc_next, pis, dev,
314 			   gs_color_select_source);
315 	if (mcode < 0)
316 	    goto fill;
317 f:
318 	if (sizeof(pdevc_next->colors.binary.color[0]) <= sizeof(ulong))
319 	    if_debug7('B', "[B]0x%x,0x%x,0x%x,0x%x -> 0x%lx,0x%lx,0x%lx\n",
320 		  next.v[0], next.v[1], next.v[2], next.v[3],
321 		  (ulong)pdevc_next->colors.binary.color[0],
322 		  (ulong)pdevc_next->colors.binary.color[1],
323 		  (ulong)pdevc_next->type);
324 	else
325 	    if_debug9('B', "[B]0x%x,0x%x,0x%x,0x%x -> 0x%08lx%08lx,0x%08lx%08lx,0x%lx\n",
326 		  next.v[0], next.v[1], next.v[2], next.v[3],
327 		  (ulong)(pdevc_next->colors.binary.color[0] >>
328 			8 * (sizeof(pdevc_next->colors.binary.color[0]) - sizeof(ulong))),
329 		  (ulong)pdevc_next->colors.binary.color[0],
330 		  (ulong)(pdevc_next->colors.binary.color[1] >>
331 			8 * (sizeof(pdevc_next->colors.binary.color[1]) - sizeof(ulong))),
332 		  (ulong)pdevc_next->colors.binary.color[1],
333 		  (ulong)pdevc_next->type);
334 /* NB: sizeof gx_color_index is 4 or 8 bytes! */
335 
336 
337 	/* Even though the supplied colors don't match, */
338 	/* the device colors might. */
339 	if (!dev_color_eq(devc1, devc2)) {
340 	    /* Fill the region between xrun/irun and xl */
341 	    gx_device_color *ptemp;
342 
343 fill:
344 	    if (posture != image_portrait) {	/* Parallelogram */
345 		code = (*dev_proc(dev, fill_parallelogram))
346 		    (dev, xrun, yrun,
347 		     xl - xrun, ytf - yrun, pdyx, pdyy,
348 		     pdevc, lop);
349 	    } else {		/* Rectangle */
350 		int xi = irun;
351 		int wi = (irun = fixed2int_var_rounded(xl)) - xi;
352 
353 		if (wi < 0)
354 		    xi += wi, wi = -wi;
355 		code = gx_fill_rectangle_device_rop(xi, yt,
356 						  wi, iht, pdevc, dev, lop);
357 		vd_set_scale(0.01);
358 		vd_rect(int2fixed(xi), int2fixed(yt), int2fixed(xi + wi), int2fixed(yt + iht),
359 		    1, (int)pdevc->colors.pure);
360 	    }
361 	    if (code < 0)
362 		goto err;
363 	    rsrc = psrc;
364 	    if ((code = mcode) < 0)
365 		goto err;
366 	    ptemp = pdevc;
367 	    pdevc = pdevc_next;
368 	    pdevc_next = ptemp;
369 	    xrun = xl;
370 	    yrun = ytf;
371 	}
372 	run = next;
373 inc:
374 	xl = dda_next(pnext.x);
375 	ytf = dda_next(pnext.y);
376     }
377     /* Fill the final run. */
378     if (posture != image_portrait) {
379 	code = (*dev_proc(dev, fill_parallelogram))
380 	    (dev, xrun, yrun, xl - xrun, ytf - yrun, pdyx, pdyy, pdevc, lop);
381 	/*vd_quad(xrun, yrun, xl, ytf, xl + pdyx, ytf + pdyy, xrun + pdyx, yrun + pdyy,
382 		1, (int)pdevc->colors.pure); */
383     } else {
384 	/* Same code as above near 'fill:' : */
385 	int xi = irun;
386 	int wi = (irun = fixed2int_var_rounded(xl)) - xi;
387 
388 	if (wi < 0)
389 	    xi += wi, wi = -wi;
390 	code = gx_fill_rectangle_device_rop(xi, yt,
391 					  wi, iht, pdevc, dev, lop);
392 	vd_set_scale(0.01);
393 	vd_rect(int2fixed(xi), int2fixed(yt), int2fixed(xi + wi), int2fixed(yt + iht),
394 	    1, (int)pdevc->colors.pure);
395     }
396     return (code < 0 ? code : 1);
397 
398     /* Save position if error, in case we resume. */
399 err:
400     penum->used.x = (rsrc - spp - psrc_initial) / spp;
401     penum->used.y = 0;
402     return code;
403 }
404