xref: /plan9/sys/src/cmd/gs/src/gxhtbit.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1999, 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: gxhtbit.c,v 1.5 2002/02/21 22:24:53 giles Exp $ */
18 /* Halftone bit updating for imaging library */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsbitops.h"
23 #include "gscdefs.h"
24 #include "gxbitmap.h"
25 #include "gxhttile.h"
26 #include "gxtmap.h"
27 #include "gxdht.h"
28 #include "gxdhtres.h"
29 
30 extern_gx_device_halftone_list();
31 
32 /*
33  * Construct a standard-representation order from a threshold array.
34  */
35 private int
construct_ht_order_default(gx_ht_order * porder,const byte * thresholds)36 construct_ht_order_default(gx_ht_order *porder, const byte *thresholds)
37 {
38     gx_ht_bit *bits = (gx_ht_bit *)porder->bit_data;
39     uint i;
40 
41     for (i = 0; i < porder->num_bits; i++)
42 	bits[i].mask = max(1, thresholds[i]);
43     gx_ht_complete_threshold_order(porder);
44     return 0;
45 }
46 
47 /*
48  * Construct a short-representation order from a threshold array.
49  * Uses porder->width, num_levels, num_bits, levels, bit_data;
50  * sets porder->levels[], bit_data[].
51  */
52 private int
construct_ht_order_short(gx_ht_order * porder,const byte * thresholds)53 construct_ht_order_short(gx_ht_order *porder, const byte *thresholds)
54 {
55     uint size = porder->num_bits;
56     uint i;
57     ushort *bits = (ushort *)porder->bit_data;
58     uint *levels = porder->levels;
59     uint num_levels = porder->num_levels;
60 
61     memset(levels, 0, num_levels * sizeof(*levels));
62     /* Count the number of threshold elements with each value. */
63     for (i = 0; i < size; i++) {
64 	uint value = max(1, thresholds[i]);
65 
66 	if (value + 1 < num_levels)
67 	    levels[value + 1]++;
68     }
69     for (i = 2; i < num_levels; ++i)
70 	levels[i] += levels[i - 1];
71     /* Now construct the actual order. */
72     {
73 	uint width = porder->width;
74 	uint padding = bitmap_raster(width) * 8 - width;
75 
76 	for (i = 0; i < size; i++) {
77 	    uint value = max(1, thresholds[i]);
78 
79 	    /* Adjust the bit index to account for padding. */
80 	    bits[levels[value]++] = i + (i / width * padding);
81 	}
82     }
83 
84     /* Check whether this is a predefined halftone. */
85     {
86 	const gx_dht_proc *phtrp = gx_device_halftone_list;
87 
88 	for (; *phtrp; ++phtrp) {
89 	    const gx_device_halftone_resource_t *const *pphtr = (*phtrp)();
90 	    const gx_device_halftone_resource_t *phtr;
91 
92 	    while ((phtr = *pphtr++) != 0) {
93 		if (phtr->Width == porder->width &&
94 		    phtr->Height == porder->height &&
95 		    phtr->elt_size == sizeof(ushort) &&
96 		    !memcmp(phtr->levels, levels, num_levels * sizeof(*levels)) &&
97 		    !memcmp(phtr->bit_data, porder->bit_data,
98 			    size * phtr->elt_size)
99 		    ) {
100 		    /*
101 		     * This is a predefined halftone.  Free the levels and
102 		     * bit_data arrays, replacing them with the built-in ones.
103 		     */
104 		    if (porder->data_memory) {
105 			gs_free_object(porder->data_memory, porder->bit_data,
106 				       "construct_ht_order_short(bit_data)");
107 			gs_free_object(porder->data_memory, porder->levels,
108 				       "construct_ht_order_short(levels)");
109 		    }
110 		    porder->data_memory = 0;
111 		    porder->levels = (uint *)phtr->levels; /* actually const */
112 		    porder->bit_data = (void *)phtr->bit_data; /* actually const */
113 		    goto out;
114 		}
115 	    }
116 	}
117     }
118  out:
119     return 0;
120 }
121 
122 /* Return the bit coordinate using the standard representation. */
123 private int
ht_bit_index_default(const gx_ht_order * porder,uint index,gs_int_point * ppt)124 ht_bit_index_default(const gx_ht_order *porder, uint index, gs_int_point *ppt)
125 {
126     const gx_ht_bit *phtb = &((const gx_ht_bit *)porder->bit_data)[index];
127     uint offset = phtb->offset;
128     int bit = 0;
129 
130     while (!(((const byte *)&phtb->mask)[bit >> 3] & (0x80 >> (bit & 7))))
131 	++bit;
132     ppt->x = (offset % porder->raster * 8) + bit;
133     ppt->y = offset / porder->raster;
134     return 0;
135 }
136 
137 /* Return the bit coordinate using the short representation. */
138 private int
ht_bit_index_short(const gx_ht_order * porder,uint index,gs_int_point * ppt)139 ht_bit_index_short(const gx_ht_order *porder, uint index, gs_int_point *ppt)
140 {
141     uint bit_index = ((const ushort *)porder->bit_data)[index];
142     uint bit_raster = porder->raster * 8;
143 
144     ppt->x = bit_index % bit_raster;
145     ppt->y = bit_index / bit_raster;
146     return 0;
147 }
148 
149 /* Update a halftone tile using the default order representation. */
150 private int
render_ht_default(gx_ht_tile * pbt,int level,const gx_ht_order * porder)151 render_ht_default(gx_ht_tile *pbt, int level, const gx_ht_order *porder)
152 {
153     int old_level = pbt->level;
154     register const gx_ht_bit *p =
155 	(const gx_ht_bit *)porder->bit_data + old_level;
156     register byte *data = pbt->tiles.data;
157 
158     /*
159      * Invert bits between the two levels.  Note that we can use the same
160      * loop to turn bits either on or off, using xor.  The Borland compiler
161      * generates truly dreadful code if we don't use a temporary, and it
162      * doesn't hurt better compilers, so we always use one.
163      */
164 #define INVERT_DATA(i)\
165      BEGIN\
166        ht_mask_t *dp = (ht_mask_t *)&data[p[i].offset];\
167        *dp ^= p[i].mask;\
168      END
169 #ifdef DEBUG
170 #  define INVERT(i)\
171      BEGIN\
172        if_debug3('H', "[H]invert level=%d offset=%u mask=0x%x\n",\
173 	         (int)(p + i - (const gx_ht_bit *)porder->bit_data),\
174 		 p[i].offset, p[i].mask);\
175        INVERT_DATA(i);\
176      END
177 #else
178 #  define INVERT(i) INVERT_DATA(i)
179 #endif
180   sw:switch (level - old_level) {
181 	default:
182 	    if (level > old_level) {
183 		INVERT(0); INVERT(1); INVERT(2); INVERT(3);
184 		p += 4; old_level += 4;
185 	    } else {
186 		INVERT(-1); INVERT(-2); INVERT(-3); INVERT(-4);
187 		p -= 4; old_level -= 4;
188 	    }
189 	    goto sw;
190 	case 7: INVERT(6);
191 	case 6: INVERT(5);
192 	case 5: INVERT(4);
193 	case 4: INVERT(3);
194 	case 3: INVERT(2);
195 	case 2: INVERT(1);
196 	case 1: INVERT(0);
197 	case 0: break;		/* Shouldn't happen! */
198 	case -7: INVERT(-7);
199 	case -6: INVERT(-6);
200 	case -5: INVERT(-5);
201 	case -4: INVERT(-4);
202 	case -3: INVERT(-3);
203 	case -2: INVERT(-2);
204 	case -1: INVERT(-1);
205     }
206 #undef INVERT_DATA
207 #undef INVERT
208     return 0;
209 }
210 
211 /* Update a halftone tile using the short representation. */
212 private int
render_ht_short(gx_ht_tile * pbt,int level,const gx_ht_order * porder)213 render_ht_short(gx_ht_tile *pbt, int level, const gx_ht_order *porder)
214 {
215     int old_level = pbt->level;
216     register const ushort *p = (const ushort *)porder->bit_data + old_level;
217     register byte *data = pbt->tiles.data;
218 
219     /* Invert bits between the two levels. */
220 #define INVERT_DATA(i)\
221      BEGIN\
222        uint bit_index = p[i];\
223        byte *dp = &data[bit_index >> 3];\
224        *dp ^= 0x80 >> (bit_index & 7);\
225      END
226 #ifdef DEBUG
227 #  define INVERT(i)\
228      BEGIN\
229        if_debug3('H', "[H]invert level=%d offset=%u mask=0x%x\n",\
230 	         (int)(p + i - (const ushort *)porder->bit_data),\
231 		 p[i] >> 3, 0x80 >> (p[i] & 7));\
232        INVERT_DATA(i);\
233      END
234 #else
235 #  define INVERT(i) INVERT_DATA(i)
236 #endif
237   sw:switch (level - old_level) {
238 	default:
239 	    if (level > old_level) {
240 		INVERT(0); INVERT(1); INVERT(2); INVERT(3);
241 		p += 4; old_level += 4;
242 	    } else {
243 		INVERT(-1); INVERT(-2); INVERT(-3); INVERT(-4);
244 		p -= 4; old_level -= 4;
245 	    }
246 	    goto sw;
247 	case 7: INVERT(6);
248 	case 6: INVERT(5);
249 	case 5: INVERT(4);
250 	case 4: INVERT(3);
251 	case 3: INVERT(2);
252 	case 2: INVERT(1);
253 	case 1: INVERT(0);
254 	case 0: break;		/* Shouldn't happen! */
255 	case -7: INVERT(-7);
256 	case -6: INVERT(-6);
257 	case -5: INVERT(-5);
258 	case -4: INVERT(-4);
259 	case -3: INVERT(-3);
260 	case -2: INVERT(-2);
261 	case -1: INVERT(-1);
262     }
263 #undef INVERT_DATA
264 #undef INVERT
265     return 0;
266 }
267 
268 /* Define the procedure vectors for the order data implementations. */
269 const gx_ht_order_procs_t ht_order_procs_table[2] = {
270     { sizeof(gx_ht_bit), construct_ht_order_default, ht_bit_index_default,
271       render_ht_default },
272     { sizeof(ushort), construct_ht_order_short, ht_bit_index_short,
273       render_ht_short }
274 };
275