xref: /plan9/sys/src/cmd/gs/src/gximono.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 2000 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: gximono.c,v 1.11 2003/12/04 12:35:35 igor Exp $ */
18 /* General mono-component image rendering */
19 #include "gx.h"
20 #include "memory_.h"
21 #include "gpcheck.h"
22 #include "gserrors.h"
23 #include "gxfixed.h"
24 #include "gxarith.h"
25 #include "gxmatrix.h"
26 #include "gsccolor.h"
27 #include "gspaint.h"
28 #include "gsutil.h"
29 #include "gxdevice.h"
30 #include "gxcmap.h"
31 #include "gxdcolor.h"
32 #include "gxistate.h"
33 #include "gxdevmem.h"
34 #include "gdevmem.h"		/* for mem_mono_device */
35 #include "gxcpath.h"
36 #include "gximage.h"
37 #include "gzht.h"
38 
39 /* ------ Strategy procedure ------ */
40 
41 /* Check the prototype. */
42 iclass_proc(gs_image_class_3_mono);
43 
44 private irender_proc(image_render_mono);
45 irender_proc_t
gs_image_class_3_mono(gx_image_enum * penum)46 gs_image_class_3_mono(gx_image_enum * penum)
47 {
48     if (penum->spp == 1) {
49 	/*
50 	 * Use the slow loop for imagemask with a halftone or a non-default
51 	 * logical operation.
52 	 */
53 	penum->slow_loop =
54 	    (penum->masked && !color_is_pure(&penum->icolor1)) ||
55 	    penum->use_rop;
56 	/* We can bypass X clipping for portrait mono-component images. */
57 	if (!(penum->slow_loop || penum->posture != image_portrait))
58 	    penum->clip_image &= ~(image_clip_xmin | image_clip_xmax);
59 	if_debug0('b', "[b]render=mono\n");
60 	/* Precompute values needed for rasterizing. */
61 	penum->dxx =
62 	    float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2);
63 	/*
64 	 * Scale the mask colors to match the scaling of each sample to a
65 	 * full byte.  Also, if black or white is transparent, reset icolor0
66 	 * or icolor1, which are used directly in the fast case loop.
67 	 */
68 	if (penum->use_mask_color) {
69 	    gx_image_scale_mask_colors(penum, 0);
70 	    if (penum->mask_color.values[0] <= 0)
71 		color_set_null(&penum->icolor0);
72 	    if (penum->mask_color.values[1] >= 255)
73 		color_set_null(&penum->icolor1);
74 	}
75 	return &image_render_mono;
76     }
77     return 0;
78 }
79 
80 /*
81  * Rendering procedure for general mono-component images, dealing with
82  * multiple bit-per-sample images, general transformations, arbitrary
83  * single-component color spaces (DeviceGray, DevicePixel, CIEBasedA,
84  * Separation, Indexed), and color masking. This procedure handles a
85  * single scan line.
86  */
87 private int
image_render_mono(gx_image_enum * penum,const byte * buffer,int data_x,uint w,int h,gx_device * dev)88 image_render_mono(gx_image_enum * penum, const byte * buffer, int data_x,
89 		  uint w, int h, gx_device * dev)
90 {
91     const gs_imager_state *pis = penum->pis;
92     gs_logical_operation_t lop = penum->log_op;
93     const bool masked = penum->masked;
94     const gs_color_space *pcs = NULL;	/* only set for non-masks */
95     cs_proc_remap_color((*remap_color)) = NULL;	/* ditto */
96     gs_client_color cc;
97     gx_device_color *pdevc = &penum->icolor1;	/* color for masking */
98     bool tiles_fit;
99     uint mask_base = penum->mask_color.values[0];
100     uint mask_limit =
101 	(penum->use_mask_color ?
102 	 penum->mask_color.values[1] - mask_base + 1 : 0);
103 /*
104  * Free variables of IMAGE_SET_GRAY:
105  *   Read: penum, pis, dev, tiles_fit, mask_base, mask_limit
106  *   Set: pdevc, code, cc
107  */
108 #define IMAGE_SET_GRAY(sample_value)\
109   BEGIN\
110     pdevc = &penum->clues[sample_value].dev_color;\
111     if (!color_is_set(pdevc)) {\
112 	if ((uint)(sample_value - mask_base) < mask_limit)\
113 	    color_set_null(pdevc);\
114 	else {\
115 	    decode_sample(sample_value, cc, 0);\
116 	    code = (*remap_color)(&cc, pcs, pdevc, pis, dev, gs_color_select_source);\
117 	    if (code < 0)\
118 		goto err;\
119 	}\
120     } else if (!color_is_pure(pdevc)) {\
121 	if (!tiles_fit) {\
122 	    code = gx_color_load_select(pdevc, pis, dev, gs_color_select_source);\
123 	    if (code < 0)\
124 		goto err;\
125 	}\
126     }\
127   END
128     gx_dda_fixed_point next;	/* (y not used in fast loop) */
129     gx_dda_step_fixed dxx2, dxx3, dxx4;		/* (not used in all loops) */
130     const byte *psrc_initial = buffer + data_x;
131     const byte *psrc = psrc_initial;
132     const byte *rsrc = psrc;	/* psrc at start of run */
133     const byte *endp = psrc + w;
134     const byte *stop = endp;
135     fixed xrun;			/* x at start of run */
136     byte run;		/* run value */
137     int htrun = (masked ? 255 : -2);		/* halftone run value */
138     int code = 0;
139 
140     if (h == 0)
141 	return 0;
142     /*
143      * Make sure the cache setup matches the graphics state.  Also determine
144      * whether all tiles fit in the cache.  We may bypass the latter check
145      * for masked images with a pure color.
146      */
147 
148     /* TO_DO_DEVICEN - The gx_check_tile_cache_current() routine is bogus */
149 
150     if (pis == 0 || !gx_check_tile_cache_current(pis)) {
151         image_init_clues(penum, penum->bps, penum->spp);
152     }
153     tiles_fit = (pis && penum->device_color ? gx_check_tile_cache(pis) : false);
154     next = penum->dda.pixel0;
155     xrun = dda_current(next.x);
156     if (!masked) {
157 	pcs = penum->pcs;	/* (may not be set for masks) */
158         remap_color = pcs->type->remap_color;
159     }
160     run = *psrc;
161     /* Find the last transition in the input. */
162     {
163 	byte last = stop[-1];
164 
165 	while (stop > psrc && stop[-1] == last)
166 	    --stop;
167     }
168     if (penum->slow_loop || penum->posture != image_portrait) {
169 
170 	/**************************************************************
171 	 * Slow case (skewed, rotated, or imagemask with a halftone). *
172 	 **************************************************************/
173 
174 	fixed yrun;
175 	const fixed pdyx = dda_current(penum->dda.row.x) - penum->cur.x;
176 	const fixed pdyy = dda_current(penum->dda.row.y) - penum->cur.y;
177 	dev_proc_fill_parallelogram((*fill_pgram)) =
178 	    dev_proc(dev, fill_parallelogram);
179 
180 #define xl dda_current(next.x)
181 #define ytf dda_current(next.y)
182 	yrun = ytf;
183 	if (masked) {
184 
185 	    /**********************
186 	     * Slow case, masked. *
187 	     **********************/
188 
189 	    pdevc = &penum->icolor1;
190 	    code = gx_color_load(pdevc, pis, dev);
191 	    if (code < 0)
192 		return code;
193 	    if (stop <= psrc)
194 		goto last;
195 	    if (penum->posture == image_portrait) {
196 
197 		/********************************
198 		 * Slow case, masked, portrait. *
199 		 ********************************/
200 
201 		/*
202 		 * We don't have to worry about the Y DDA, and the fill
203 		 * regions are rectangles.  Calculate multiples of the DDA
204 		 * step.
205 		 */
206 		fixed ax =
207 		    (penum->matrix.xx < 0 ? -penum->adjust : penum->adjust);
208 		fixed ay =
209 		    (pdyy < 0 ? -penum->adjust : penum->adjust);
210 		fixed dyy = pdyy + (ay << 1);
211 
212 		yrun -= ay;
213 		dda_translate(next.x, -ax);
214 		ax <<= 1;
215 		dxx2 = next.x.step;
216 		dda_step_add(dxx2, next.x.step);
217 		dxx3 = dxx2;
218 		dda_step_add(dxx3, next.x.step);
219 		dxx4 = dxx3;
220 		dda_step_add(dxx4, next.x.step);
221 		for (;;) {	/* Skip a run of zeros. */
222 		    while (!psrc[0])
223 			if (!psrc[1]) {
224 			    if (!psrc[2]) {
225 				if (!psrc[3]) {
226 				    psrc += 4;
227 				    dda_state_next(next.x.state, dxx4);
228 				    continue;
229 				}
230 				psrc += 3;
231 				dda_state_next(next.x.state, dxx3);
232 				break;
233 			    }
234 			    psrc += 2;
235 			    dda_state_next(next.x.state, dxx2);
236 			    break;
237 			} else {
238 			    ++psrc;
239 			    dda_next(next.x);
240 			    break;
241 			}
242 		    xrun = xl;
243 		    if (psrc >= stop)
244 			break;
245 		    for (; *psrc; ++psrc)
246 			dda_next(next.x);
247 		    code = (*fill_pgram)(dev, xrun, yrun,
248 					 xl - xrun + ax, fixed_0, fixed_0, dyy,
249 					 pdevc, lop);
250 		    if (code < 0)
251 			goto err;
252 		    rsrc = psrc;
253 		    if (psrc >= stop)
254 			break;
255 		}
256 
257 	    } else if (penum->posture == image_landscape) {
258 
259 		/*********************************
260 		 * Slow case, masked, landscape. *
261 		 *********************************/
262 
263 		/*
264 		 * We don't have to worry about the X DDA.  However, we do
265 		 * have to take adjustment into account.  We don't bother to
266 		 * optimize this as heavily as the portrait case.
267 		 */
268 		fixed ax =
269 		    (pdyx < 0 ? -penum->adjust : penum->adjust);
270 		fixed dyx = pdyx + (ax << 1);
271 		fixed ay =
272 		    (penum->matrix.xy < 0 ? -penum->adjust : penum->adjust);
273 
274 		xrun -= ax;
275 		dda_translate(next.y, -ay);
276 		ay <<= 1;
277 		for (;;) {
278 		    for (; !*psrc; ++psrc)
279 			dda_next(next.y);
280 		    yrun = ytf;
281 		    if (psrc >= stop)
282 			break;
283 		    for (; *psrc; ++psrc)
284 			dda_next(next.y);
285 		    code = (*fill_pgram)(dev, xrun, yrun, fixed_0,
286 					 ytf - yrun + ay, dyx, fixed_0,
287 					 pdevc, lop);
288 		    if (code < 0)
289 			goto err;
290 		    rsrc = psrc;
291 		    if (psrc >= stop)
292 			break;
293 		}
294 
295 	    } else {
296 
297 		/**************************************
298 		 * Slow case, masked, not orthogonal. *
299 		 **************************************/
300 
301 		for (;;) {
302 		    for (; !*psrc; ++psrc) {
303 			dda_next(next.x);
304 			dda_next(next.y);
305 		    }
306 		    yrun = ytf;
307 		    xrun = xl;
308 		    if (psrc >= stop)
309 			break;
310 		    for (; *psrc; ++psrc) {
311 			dda_next(next.x);
312 			dda_next(next.y);
313 		    }
314 		    code = (*fill_pgram)(dev, xrun, yrun, xl - xrun,
315 					 ytf - yrun, pdyx, pdyy, pdevc, lop);
316 		    if (code < 0)
317 			goto err;
318 		    rsrc = psrc;
319 		    if (psrc >= stop)
320 			break;
321 		}
322 
323 	    }
324 
325 	} else if (penum->posture == image_portrait ||
326 		   penum->posture == image_landscape
327 	    ) {
328 
329 	    /**************************************
330 	     * Slow case, not masked, orthogonal. *
331 	     **************************************/
332 
333 	    /* In this case, we can fill runs quickly. */
334 	    /****** DOESN'T DO ADJUSTMENT ******/
335 	    if (stop <= psrc)
336 		goto last;
337 	    for (;;) {
338 		if (*psrc != run) {
339 		    if (run != htrun) {
340 			htrun = run;
341 			IMAGE_SET_GRAY(run);
342 		    }
343 		    code = (*fill_pgram)(dev, xrun, yrun, xl - xrun,
344 					 ytf - yrun, pdyx, pdyy,
345 					 pdevc, lop);
346 		    if (code < 0)
347 			goto err;
348 		    yrun = ytf;
349 		    xrun = xl;
350 		    rsrc = psrc;
351 		    if (psrc >= stop)
352 			break;
353 		    run = *psrc;
354 		}
355 		psrc++;
356 		dda_next(next.x);
357 		dda_next(next.y);
358 	    }
359 	} else {
360 
361 	    /******************************************
362 	     * Slow case, not masked, not orthogonal. *
363 	     ******************************************/
364 
365 	    /*
366 	     * Since we have to check for the end after every pixel
367 	     * anyway, we may as well avoid the last-run code.
368 	     */
369 	    stop = endp;
370 	    for (;;) {
371 		/* We can't skip large constant regions quickly, */
372 		/* because this leads to rounding errors. */
373 		/* Just fill the region between xrun and xl. */
374 		if (run != htrun) {
375 		    htrun = run;
376 		    IMAGE_SET_GRAY(run);
377 		}
378 		code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
379 				      ytf - yrun, pdyx, pdyy, pdevc, lop);
380 		if (code < 0)
381 		    goto err;
382 		yrun = ytf;
383 		xrun = xl;
384 		rsrc = psrc;
385 		if (psrc >= stop)
386 		    break;
387 		run = *psrc++;
388 		dda_next(next.x);
389 		dda_next(next.y);	/* harmless if no skew */
390 	    }
391 
392 	}
393 	/* Fill the last run. */
394       last:if (stop < endp && (*stop || !masked)) {
395 	    if (!masked) {
396 		IMAGE_SET_GRAY(*stop);
397 	    }
398 	    dda_advance(next.x, endp - stop);
399 	    dda_advance(next.y, endp - stop);
400 	    code = (*fill_pgram) (dev, xrun, yrun, xl - xrun,
401 				  ytf - yrun, pdyx, pdyy, pdevc, lop);
402 	}
403 #undef xl
404 #undef ytf
405 
406     } else {
407 
408 	/**********************************************************
409 	 * Fast case: no skew, and not imagemask with a halftone. *
410 	 **********************************************************/
411 
412 	const fixed adjust = penum->adjust;
413 	const fixed dxx = penum->dxx;
414 	fixed xa = (dxx >= 0 ? adjust : -adjust);
415 	const int yt = penum->yci, iht = penum->hci;
416 
417 	dev_proc_fill_rectangle((*fill_proc)) =
418 	    dev_proc(dev, fill_rectangle);
419 	int xmin = fixed2int_pixround(penum->clip_outer.p.x);
420 	int xmax = fixed2int_pixround(penum->clip_outer.q.x);
421 
422 #define xl dda_current(next.x)
423 	/* Fold the adjustment into xrun and xl, */
424 	/* including the +0.5-epsilon for rounding. */
425 	xrun = xrun - xa + (fixed_half - fixed_epsilon);
426 	dda_translate(next.x, xa + (fixed_half - fixed_epsilon));
427 	xa <<= 1;
428 	/* Calculate multiples of the DDA step. */
429 	dxx2 = next.x.step;
430 	dda_step_add(dxx2, next.x.step);
431 	dxx3 = dxx2;
432 	dda_step_add(dxx3, next.x.step);
433 	dxx4 = dxx3;
434 	dda_step_add(dxx4, next.x.step);
435 	if (stop > psrc)
436 	    for (;;) {		/* Skip large constant regions quickly, */
437 		/* but don't slow down transitions too much. */
438 	      skf:if (psrc[0] == run) {
439 		    if (psrc[1] == run) {
440 			if (psrc[2] == run) {
441 			    if (psrc[3] == run) {
442 				psrc += 4;
443 				dda_state_next(next.x.state, dxx4);
444 				goto skf;
445 			    } else {
446 				psrc += 4;
447 				dda_state_next(next.x.state, dxx3);
448 			    }
449 			} else {
450 			    psrc += 3;
451 			    dda_state_next(next.x.state, dxx2);
452 			}
453 		    } else {
454 			psrc += 2;
455 			dda_next(next.x);
456 		    }
457 		} else
458 		    psrc++;
459 		{		/* Now fill the region between xrun and xl. */
460 		    int xi = fixed2int_var(xrun);
461 		    int wi = fixed2int_var(xl) - xi;
462 		    int xei;
463 
464 		    if (wi <= 0) {
465 			if (wi == 0)
466 			    goto mt;
467 			xi += wi, wi = -wi;
468 		    }
469 		    if ((xei = xi + wi) > xmax || xi < xmin) {	/* Do X clipping */
470 			if (xi < xmin)
471 			    wi -= xmin - xi, xi = xmin;
472 			if (xei > xmax)
473 			    wi -= xei - xmax;
474 			if (wi <= 0)
475 			    goto mt;
476 		    }
477 		    switch (run) {
478 			case 0:
479 			    if (masked)
480 				goto mt;
481 			    if (!color_is_pure(&penum->icolor0))
482 				goto ht;
483 			    code = (*fill_proc) (dev, xi, yt, wi, iht,
484 						 penum->icolor0.colors.pure);
485 			    break;
486 			case 255:	/* just for speed */
487 			    if (!color_is_pure(&penum->icolor1))
488 				goto ht;
489 			    code = (*fill_proc) (dev, xi, yt, wi, iht,
490 						 penum->icolor1.colors.pure);
491 			    break;
492 			default:
493 			  ht:	/* Use halftone if needed */
494 			    if (run != htrun) {
495 				IMAGE_SET_GRAY(run);
496 				htrun = run;
497 			    }
498                             code = gx_fill_rectangle_device_rop(xi, yt, wi, iht,
499                                                                  pdevc, dev, lop);
500 
501 		    }
502 		    if (code < 0)
503 			goto err;
504 		  mt:xrun = xl - xa;	/* original xa << 1 */
505 		    rsrc = psrc - 1;
506 		    if (psrc > stop) {
507 			--psrc;
508 			break;
509 		    }
510 		    run = psrc[-1];
511 		}
512 		dda_next(next.x);
513 	    }
514 	/* Fill the last run. */
515 	if (*stop != 0 || !masked) {
516 	    int xi = fixed2int_var(xrun);
517 	    int wi, xei;
518 
519 	    dda_advance(next.x, endp - stop);
520 	    wi = fixed2int_var(xl) - xi;
521 	    if (wi <= 0) {
522 		if (wi == 0)
523 		    goto lmt;
524 		xi += wi, wi = -wi;
525 	    }
526 	    if ((xei = xi + wi) > xmax || xi < xmin) {	/* Do X clipping */
527 		if (xi < xmin)
528 		    wi -= xmin - xi, xi = xmin;
529 		if (xei > xmax)
530 		    wi -= xei - xmax;
531 		if (wi <= 0)
532 		    goto lmt;
533 	    }
534 	    IMAGE_SET_GRAY(*stop);
535 	    code = gx_fill_rectangle_device_rop(xi, yt, wi, iht,
536 						pdevc, dev, lop);
537 	  lmt:;
538 	}
539 
540     }
541 #undef xl
542     if (code >= 0)
543 	return 1;
544     /* Save position if error, in case we resume. */
545 err:
546     penum->used.x = rsrc - psrc_initial;
547     penum->used.y = 0;
548     return code;
549 }
550