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