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