2 |
- |
1 |
/* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 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: gxht.c,v 1.17 2005/05/23 22:33:22 dan Exp $ */
|
|
|
18 |
/* Halftone rendering for imaging library */
|
|
|
19 |
#include "memory_.h"
|
|
|
20 |
#include "gx.h"
|
|
|
21 |
#include "gserrors.h"
|
|
|
22 |
#include "gsstruct.h"
|
|
|
23 |
#include "gsbitops.h"
|
|
|
24 |
#include "gsutil.h" /* for gs_next_ids */
|
|
|
25 |
#include "gxdcolor.h"
|
|
|
26 |
#include "gxfixed.h"
|
|
|
27 |
#include "gxdevice.h" /* for gzht.h */
|
|
|
28 |
#include "gxistate.h"
|
|
|
29 |
#include "gzht.h"
|
|
|
30 |
#include "gsserial.h"
|
|
|
31 |
|
|
|
32 |
/* Define the sizes of the halftone cache. */
|
|
|
33 |
#define max_cached_tiles_HUGE 5000 /* not used */
|
|
|
34 |
#define max_ht_bits_HUGE 1000000 /* not used */
|
|
|
35 |
#define max_cached_tiles_LARGE 577
|
|
|
36 |
#define max_ht_bits_LARGE 100000
|
|
|
37 |
#define max_cached_tiles_SMALL 25
|
|
|
38 |
#define max_ht_bits_SMALL 1000
|
|
|
39 |
|
|
|
40 |
/* Define the binary halftone device color type. */
|
|
|
41 |
/* The type descriptor must be public for Pattern types. */
|
|
|
42 |
gs_public_st_composite(st_dc_ht_binary, gx_device_color, "dc_ht_binary",
|
|
|
43 |
dc_ht_binary_enum_ptrs, dc_ht_binary_reloc_ptrs);
|
|
|
44 |
private dev_color_proc_save_dc(gx_dc_ht_binary_save_dc);
|
|
|
45 |
private dev_color_proc_get_dev_halftone(gx_dc_ht_binary_get_dev_halftone);
|
|
|
46 |
private dev_color_proc_load(gx_dc_ht_binary_load);
|
|
|
47 |
private dev_color_proc_fill_rectangle(gx_dc_ht_binary_fill_rectangle);
|
|
|
48 |
private dev_color_proc_fill_masked(gx_dc_ht_binary_fill_masked);
|
|
|
49 |
private dev_color_proc_equal(gx_dc_ht_binary_equal);
|
|
|
50 |
private dev_color_proc_write(gx_dc_ht_binary_write);
|
|
|
51 |
private dev_color_proc_read(gx_dc_ht_binary_read);
|
|
|
52 |
const gx_device_color_type_t
|
|
|
53 |
gx_dc_type_data_ht_binary =
|
|
|
54 |
{&st_dc_ht_binary,
|
|
|
55 |
gx_dc_ht_binary_save_dc, gx_dc_ht_binary_get_dev_halftone,
|
|
|
56 |
gx_dc_ht_get_phase,
|
|
|
57 |
gx_dc_ht_binary_load, gx_dc_ht_binary_fill_rectangle,
|
|
|
58 |
gx_dc_ht_binary_fill_masked, gx_dc_ht_binary_equal,
|
|
|
59 |
gx_dc_ht_binary_write, gx_dc_ht_binary_read,
|
|
|
60 |
gx_dc_ht_binary_get_nonzero_comps
|
|
|
61 |
};
|
|
|
62 |
|
|
|
63 |
#undef gx_dc_type_ht_binary
|
|
|
64 |
const gx_device_color_type_t *const gx_dc_type_ht_binary =
|
|
|
65 |
&gx_dc_type_data_ht_binary;
|
|
|
66 |
|
|
|
67 |
#define gx_dc_type_ht_binary (&gx_dc_type_data_ht_binary)
|
|
|
68 |
/* GC procedures */
|
|
|
69 |
private
|
|
|
70 |
ENUM_PTRS_WITH(dc_ht_binary_enum_ptrs, gx_device_color *cptr) return 0;
|
|
|
71 |
ENUM_PTR(0, gx_device_color, colors.binary.b_ht);
|
|
|
72 |
case 1:
|
|
|
73 |
{
|
|
|
74 |
gx_ht_tile *tile = cptr->colors.binary.b_tile;
|
|
|
75 |
|
|
|
76 |
ENUM_RETURN(tile ? tile - tile->index : 0);
|
|
|
77 |
}
|
|
|
78 |
ENUM_PTRS_END
|
|
|
79 |
private RELOC_PTRS_WITH(dc_ht_binary_reloc_ptrs, gx_device_color *cptr)
|
|
|
80 |
{
|
|
|
81 |
gx_ht_tile *tile = cptr->colors.binary.b_tile;
|
|
|
82 |
uint index = tile ? tile->index : 0;
|
|
|
83 |
|
|
|
84 |
RELOC_PTR(gx_device_color, colors.binary.b_ht);
|
|
|
85 |
RELOC_TYPED_OFFSET_PTR(gx_device_color, colors.binary.b_tile, index);
|
|
|
86 |
}
|
|
|
87 |
RELOC_PTRS_END
|
|
|
88 |
#undef cptr
|
|
|
89 |
|
|
|
90 |
/* Other GC procedures */
|
|
|
91 |
private_st_ht_tiles();
|
|
|
92 |
private
|
|
|
93 |
ENUM_PTRS_BEGIN_PROC(ht_tiles_enum_ptrs)
|
|
|
94 |
{
|
|
|
95 |
return 0;
|
|
|
96 |
}
|
|
|
97 |
ENUM_PTRS_END_PROC
|
|
|
98 |
private RELOC_PTRS_BEGIN(ht_tiles_reloc_ptrs)
|
|
|
99 |
{
|
|
|
100 |
/* Reset the bitmap pointers in the tiles. */
|
|
|
101 |
/* We know the first tile points to the base of the bits. */
|
|
|
102 |
gx_ht_tile *ht_tiles = vptr;
|
|
|
103 |
byte *bits = ht_tiles->tiles.data;
|
|
|
104 |
uint diff;
|
|
|
105 |
|
|
|
106 |
if (bits == 0)
|
|
|
107 |
return;
|
|
|
108 |
RELOC_VAR(bits);
|
|
|
109 |
if (size == size_of(gx_ht_tile)) { /* only 1 tile */
|
|
|
110 |
ht_tiles->tiles.data = bits;
|
|
|
111 |
return;
|
|
|
112 |
}
|
|
|
113 |
diff = ht_tiles[1].tiles.data - ht_tiles[0].tiles.data;
|
|
|
114 |
for (; size; ht_tiles++, size -= size_of(gx_ht_tile), bits += diff) {
|
|
|
115 |
ht_tiles->tiles.data = bits;
|
|
|
116 |
}
|
|
|
117 |
}
|
|
|
118 |
RELOC_PTRS_END
|
|
|
119 |
private_st_ht_cache();
|
|
|
120 |
|
|
|
121 |
/* Return the default sizes of the halftone cache. */
|
|
|
122 |
uint
|
|
|
123 |
gx_ht_cache_default_tiles(void)
|
|
|
124 |
{
|
|
|
125 |
#if arch_small_memory
|
|
|
126 |
return max_cached_tiles_SMALL;
|
|
|
127 |
#else
|
|
|
128 |
return (gs_debug_c('.') ? max_cached_tiles_SMALL :
|
|
|
129 |
max_cached_tiles_LARGE);
|
|
|
130 |
#endif
|
|
|
131 |
}
|
|
|
132 |
uint
|
|
|
133 |
gx_ht_cache_default_bits(void)
|
|
|
134 |
{
|
|
|
135 |
#if arch_small_memory
|
|
|
136 |
return max_ht_bits_SMALL;
|
|
|
137 |
#else
|
|
|
138 |
return (gs_debug_c('.') ? max_ht_bits_SMALL :
|
|
|
139 |
max_ht_bits_LARGE);
|
|
|
140 |
#endif
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
/* Allocate a halftone cache. */
|
|
|
144 |
gx_ht_cache *
|
|
|
145 |
gx_ht_alloc_cache(gs_memory_t * mem, uint max_tiles, uint max_bits)
|
|
|
146 |
{
|
|
|
147 |
gx_ht_cache *pcache =
|
|
|
148 |
gs_alloc_struct(mem, gx_ht_cache, &st_ht_cache,
|
|
|
149 |
"alloc_ht_cache(struct)");
|
|
|
150 |
byte *tbits =
|
|
|
151 |
gs_alloc_bytes(mem, max_bits, "alloc_ht_cache(bits)");
|
|
|
152 |
gx_ht_tile *ht_tiles =
|
|
|
153 |
gs_alloc_struct_array(mem, max_tiles, gx_ht_tile, &st_ht_tiles,
|
|
|
154 |
"alloc_ht_cache(ht_tiles)");
|
|
|
155 |
|
|
|
156 |
if (pcache == 0 || tbits == 0 || ht_tiles == 0) {
|
|
|
157 |
gs_free_object(mem, ht_tiles, "alloc_ht_cache(ht_tiles)");
|
|
|
158 |
gs_free_object(mem, tbits, "alloc_ht_cache(bits)");
|
|
|
159 |
gs_free_object(mem, pcache, "alloc_ht_cache(struct)");
|
|
|
160 |
return 0;
|
|
|
161 |
}
|
|
|
162 |
pcache->bits = tbits;
|
|
|
163 |
pcache->bits_size = max_bits;
|
|
|
164 |
pcache->ht_tiles = ht_tiles;
|
|
|
165 |
pcache->num_tiles = max_tiles;
|
|
|
166 |
pcache->order.cache = pcache;
|
|
|
167 |
pcache->order.transfer = 0;
|
|
|
168 |
gx_ht_clear_cache(pcache);
|
|
|
169 |
return pcache;
|
|
|
170 |
}
|
|
|
171 |
|
|
|
172 |
/* Free a halftone cache. */
|
|
|
173 |
void
|
|
|
174 |
gx_ht_free_cache(gs_memory_t * mem, gx_ht_cache * pcache)
|
|
|
175 |
{
|
|
|
176 |
gs_free_object(mem, pcache->ht_tiles, "free_ht_cache(ht_tiles)");
|
|
|
177 |
gs_free_object(mem, pcache->bits, "free_ht_cache(bits)");
|
|
|
178 |
gs_free_object(mem, pcache, "free_ht_cache(struct)");
|
|
|
179 |
}
|
|
|
180 |
|
|
|
181 |
/* Check whether the tile cache corresponds to the current order */
|
|
|
182 |
bool
|
|
|
183 |
gx_check_tile_cache_current(const gs_imager_state * pis)
|
|
|
184 |
{
|
|
|
185 |
/* TO_DO_DEVICEN - this routine is no longer used - delete. */
|
|
|
186 |
return false;
|
|
|
187 |
}
|
|
|
188 |
|
|
|
189 |
/* Make the cache order current, and return whether */
|
|
|
190 |
/* there is room for all possible tiles in the cache. */
|
|
|
191 |
bool
|
|
|
192 |
gx_check_tile_cache(const gs_imager_state * pis)
|
|
|
193 |
{
|
|
|
194 |
/* TO_DO_DEVICEN - this routine is no longer used - delete. */
|
|
|
195 |
return false;
|
|
|
196 |
}
|
|
|
197 |
|
|
|
198 |
/*
|
|
|
199 |
* Determine whether a given (width, y, height) might fit into a single
|
|
|
200 |
* (non-strip) tile. If so, return the byte offset of the appropriate row
|
|
|
201 |
* from the beginning of the tile, and set *ppx to the x phase offset
|
|
|
202 |
* within the tile; if not, return -1.
|
|
|
203 |
*
|
|
|
204 |
* This routine cannot be supported in the DeviceN code.
|
|
|
205 |
*/
|
|
|
206 |
int
|
|
|
207 |
gx_check_tile_size(const gs_imager_state * pis, int w, int y, int h,
|
|
|
208 |
gs_color_select_t select, int *ppx)
|
|
|
209 |
{
|
|
|
210 |
/* TO_DO_DEVICEN - this routine is no longer used - delete. */
|
|
|
211 |
return -1;
|
|
|
212 |
}
|
|
|
213 |
|
|
|
214 |
/* Render a given level into a halftone cache. */
|
|
|
215 |
private int render_ht(gx_ht_tile *, int, const gx_ht_order *,
|
|
|
216 |
gx_bitmap_id);
|
|
|
217 |
private gx_ht_tile *
|
|
|
218 |
gx_render_ht_default(gx_ht_cache * pcache, int b_level)
|
|
|
219 |
{
|
|
|
220 |
const gx_ht_order *porder = &pcache->order;
|
|
|
221 |
int level = porder->levels[b_level];
|
|
|
222 |
gx_ht_tile *bt = &pcache->ht_tiles[level / pcache->levels_per_tile];
|
|
|
223 |
|
|
|
224 |
if (bt->level != level) {
|
|
|
225 |
int code = render_ht(bt, level, porder, pcache->base_id + b_level);
|
|
|
226 |
|
|
|
227 |
if (code < 0)
|
|
|
228 |
return 0;
|
|
|
229 |
}
|
|
|
230 |
return bt;
|
|
|
231 |
}
|
|
|
232 |
/* Faster code if num_tiles == 1. */
|
|
|
233 |
private gx_ht_tile *
|
|
|
234 |
gx_render_ht_1_tile(gx_ht_cache * pcache, int b_level)
|
|
|
235 |
{
|
|
|
236 |
const gx_ht_order *porder = &pcache->order;
|
|
|
237 |
int level = porder->levels[b_level];
|
|
|
238 |
gx_ht_tile *bt = &pcache->ht_tiles[0];
|
|
|
239 |
|
|
|
240 |
if (bt->level != level) {
|
|
|
241 |
int code = render_ht(bt, level, porder, pcache->base_id + b_level);
|
|
|
242 |
|
|
|
243 |
if (code < 0)
|
|
|
244 |
return 0;
|
|
|
245 |
}
|
|
|
246 |
return bt;
|
|
|
247 |
}
|
|
|
248 |
/* Faster code if levels_per_tile == 1. */
|
|
|
249 |
private gx_ht_tile *
|
|
|
250 |
gx_render_ht_1_level(gx_ht_cache * pcache, int b_level)
|
|
|
251 |
{
|
|
|
252 |
const gx_ht_order *porder = &pcache->order;
|
|
|
253 |
int level = porder->levels[b_level];
|
|
|
254 |
gx_ht_tile *bt = &pcache->ht_tiles[level];
|
|
|
255 |
|
|
|
256 |
if (bt->level != level) {
|
|
|
257 |
int code = render_ht(bt, level, porder, pcache->base_id + b_level);
|
|
|
258 |
|
|
|
259 |
if (code < 0)
|
|
|
260 |
return 0;
|
|
|
261 |
}
|
|
|
262 |
return bt;
|
|
|
263 |
}
|
|
|
264 |
|
|
|
265 |
/* save information about the operand binary halftone color */
|
|
|
266 |
private void
|
|
|
267 |
gx_dc_ht_binary_save_dc(const gx_device_color * pdevc,
|
|
|
268 |
gx_device_color_saved * psdc)
|
|
|
269 |
{
|
|
|
270 |
psdc->type = pdevc->type;
|
|
|
271 |
psdc->colors.binary.b_color[0] = pdevc->colors.binary.color[0];
|
|
|
272 |
psdc->colors.binary.b_color[1] = pdevc->colors.binary.color[1];
|
|
|
273 |
psdc->colors.binary.b_level = pdevc->colors.binary.b_level;
|
|
|
274 |
psdc->colors.binary.b_index = pdevc->colors.binary.b_index;
|
|
|
275 |
psdc->phase = pdevc->phase;
|
|
|
276 |
}
|
|
|
277 |
|
|
|
278 |
/* get the halftone used for a binary halftone color */
|
|
|
279 |
private const gx_device_halftone *
|
|
|
280 |
gx_dc_ht_binary_get_dev_halftone(const gx_device_color * pdevc)
|
|
|
281 |
{
|
|
|
282 |
return pdevc->colors.binary.b_ht;
|
|
|
283 |
}
|
|
|
284 |
|
|
|
285 |
/* Load the device color into the halftone cache if needed. */
|
|
|
286 |
private int
|
|
|
287 |
gx_dc_ht_binary_load(gx_device_color * pdevc, const gs_imager_state * pis,
|
|
|
288 |
gx_device * dev, gs_color_select_t select)
|
|
|
289 |
{
|
|
|
290 |
int component_index = pdevc->colors.binary.b_index;
|
|
|
291 |
const gx_ht_order *porder =
|
|
|
292 |
(component_index < 0 ?
|
|
|
293 |
&pdevc->colors.binary.b_ht->order :
|
|
|
294 |
&pdevc->colors.binary.b_ht->components[component_index].corder);
|
|
|
295 |
gx_ht_cache *pcache = porder->cache;
|
|
|
296 |
|
|
|
297 |
if (pcache->order.bit_data != porder->bit_data)
|
|
|
298 |
gx_ht_init_cache(pis->memory, pcache, porder);
|
|
|
299 |
/*
|
|
|
300 |
* We do not load the cache now. Instead we wait until we are ready
|
|
|
301 |
* to actually render the color. This allows multiple colors to be
|
|
|
302 |
* loaded without cache conflicts. (Cache conflicts can occur when
|
|
|
303 |
* if two device colors use the same cache elements. This can occur
|
|
|
304 |
* when the tile size is large enough that we do not have a separate
|
|
|
305 |
* tile for each half tone level.) See gx_dc_ht_binary_load_cache.
|
|
|
306 |
*/
|
|
|
307 |
pdevc->colors.binary.b_tile = NULL;
|
|
|
308 |
return 0;
|
|
|
309 |
}
|
|
|
310 |
|
|
|
311 |
/*
|
|
|
312 |
* Load the half tone tile in the halftone cache.
|
|
|
313 |
*/
|
|
|
314 |
private int
|
|
|
315 |
gx_dc_ht_binary_load_cache(const gx_device_color * pdevc)
|
|
|
316 |
{
|
|
|
317 |
int component_index = pdevc->colors.binary.b_index;
|
|
|
318 |
const gx_ht_order *porder =
|
|
|
319 |
&pdevc->colors.binary.b_ht->components[component_index].corder;
|
|
|
320 |
gx_ht_cache *pcache = porder->cache;
|
|
|
321 |
int b_level = pdevc->colors.binary.b_level;
|
|
|
322 |
int level = porder->levels[b_level];
|
|
|
323 |
gx_ht_tile *bt = &pcache->ht_tiles[level / pcache->levels_per_tile];
|
|
|
324 |
|
|
|
325 |
if (bt->level != level) {
|
|
|
326 |
int code = render_ht(bt, level, porder, pcache->base_id + b_level);
|
|
|
327 |
|
|
|
328 |
if (code < 0)
|
|
|
329 |
return_error(gs_error_Fatal);
|
|
|
330 |
}
|
|
|
331 |
((gx_device_color *)pdevc)->colors.binary.b_tile = bt;
|
|
|
332 |
return 0;
|
|
|
333 |
}
|
|
|
334 |
|
|
|
335 |
/* Fill a rectangle with a binary halftone. */
|
|
|
336 |
/* Note that we treat this as "texture" for RasterOp. */
|
|
|
337 |
private int
|
|
|
338 |
gx_dc_ht_binary_fill_rectangle(const gx_device_color * pdevc, int x, int y,
|
|
|
339 |
int w, int h, gx_device * dev, gs_logical_operation_t lop,
|
|
|
340 |
const gx_rop_source_t * source)
|
|
|
341 |
{
|
|
|
342 |
gx_rop_source_t no_source;
|
|
|
343 |
|
|
|
344 |
/* Load the halftone cache for the color */
|
|
|
345 |
gx_dc_ht_binary_load_cache(pdevc);
|
|
|
346 |
/*
|
|
|
347 |
* Observation of H-P devices and documentation yields confusing
|
|
|
348 |
* evidence about whether white pixels in halftones are always
|
|
|
349 |
* opaque. It appears that for black-and-white devices, these
|
|
|
350 |
* pixels are *not* opaque.
|
|
|
351 |
*/
|
|
|
352 |
if (dev->color_info.depth > 1)
|
|
|
353 |
lop &= ~lop_T_transparent;
|
|
|
354 |
if (source == NULL && lop_no_S_is_T(lop))
|
|
|
355 |
return (*dev_proc(dev, strip_tile_rectangle)) (dev,
|
|
|
356 |
&pdevc->colors.binary.b_tile->tiles,
|
|
|
357 |
x, y, w, h, pdevc->colors.binary.color[0],
|
|
|
358 |
pdevc->colors.binary.color[1],
|
|
|
359 |
pdevc->phase.x, pdevc->phase.y);
|
|
|
360 |
/* Adjust the logical operation per transparent colors. */
|
|
|
361 |
if (pdevc->colors.binary.color[0] == gx_no_color_index)
|
|
|
362 |
lop = rop3_use_D_when_T_0(lop);
|
|
|
363 |
if (pdevc->colors.binary.color[1] == gx_no_color_index)
|
|
|
364 |
lop = rop3_use_D_when_T_1(lop);
|
|
|
365 |
if (source == NULL)
|
|
|
366 |
set_rop_no_source(source, no_source, dev);
|
|
|
367 |
return (*dev_proc(dev, strip_copy_rop)) (dev, source->sdata,
|
|
|
368 |
source->sourcex, source->sraster, source->id,
|
|
|
369 |
(source->use_scolors ? source->scolors : NULL),
|
|
|
370 |
&pdevc->colors.binary.b_tile->tiles,
|
|
|
371 |
pdevc->colors.binary.color,
|
|
|
372 |
x, y, w, h, pdevc->phase.x, pdevc->phase.y,
|
|
|
373 |
lop);
|
|
|
374 |
}
|
|
|
375 |
|
|
|
376 |
private int
|
|
|
377 |
gx_dc_ht_binary_fill_masked(const gx_device_color * pdevc, const byte * data,
|
|
|
378 |
int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h,
|
|
|
379 |
gx_device * dev, gs_logical_operation_t lop, bool invert)
|
|
|
380 |
{
|
|
|
381 |
/*
|
|
|
382 |
* Load the halftone cache for the color. We do not do it earlier
|
|
|
383 |
* because for small halftone caches, each cache tile may be used for
|
|
|
384 |
* for more than one halftone level. This can cause conflicts if more
|
|
|
385 |
* than one device color has been set and they use the same cache
|
|
|
386 |
* entry.
|
|
|
387 |
*/
|
|
|
388 |
int code = gx_dc_ht_binary_load_cache(pdevc);
|
|
|
389 |
|
|
|
390 |
if (code < 0)
|
|
|
391 |
return code;
|
|
|
392 |
return gx_dc_default_fill_masked(pdevc, data, data_x, raster, id,
|
|
|
393 |
x, y, w, h, dev, lop, invert);
|
|
|
394 |
}
|
|
|
395 |
|
|
|
396 |
/* Compare two binary halftones for equality. */
|
|
|
397 |
private bool
|
|
|
398 |
gx_dc_ht_binary_equal(const gx_device_color * pdevc1,
|
|
|
399 |
const gx_device_color * pdevc2)
|
|
|
400 |
{
|
|
|
401 |
return pdevc2->type == pdevc1->type &&
|
|
|
402 |
pdevc1->phase.x == pdevc2->phase.x &&
|
|
|
403 |
pdevc1->phase.y == pdevc2->phase.y &&
|
|
|
404 |
gx_dc_binary_color0(pdevc1) == gx_dc_binary_color0(pdevc2) &&
|
|
|
405 |
gx_dc_binary_color1(pdevc1) == gx_dc_binary_color1(pdevc2) &&
|
|
|
406 |
pdevc1->colors.binary.b_level == pdevc2->colors.binary.b_level;
|
|
|
407 |
}
|
|
|
408 |
|
|
|
409 |
|
|
|
410 |
/*
|
|
|
411 |
* Flags to indicate the pieces of a binary halftone that are included
|
|
|
412 |
* in its string representation. The first byte of the string holds this
|
|
|
413 |
* set of flags.
|
|
|
414 |
*
|
|
|
415 |
* The binary halftone tile is never transmitted as part of the string
|
|
|
416 |
* representation, so there is also no flag bit for it.
|
|
|
417 |
*/
|
|
|
418 |
private const int dc_ht_binary_has_color0 = 0x01;
|
|
|
419 |
private const int dc_ht_binary_has_color1 = 0x02;
|
|
|
420 |
private const int dc_ht_binary_has_level = 0x04;
|
|
|
421 |
private const int dc_ht_binary_has_index = 0x08;
|
|
|
422 |
|
|
|
423 |
|
|
|
424 |
/*
|
|
|
425 |
* Serialize a binany halftone device color.
|
|
|
426 |
*
|
|
|
427 |
* Operands:
|
|
|
428 |
*
|
|
|
429 |
* pdevc pointer to device color to be serialized
|
|
|
430 |
*
|
|
|
431 |
* psdc pointer ot saved version of last serialized color (for
|
|
|
432 |
* this band)
|
|
|
433 |
*
|
|
|
434 |
* dev pointer to the current device, used to retrieve process
|
|
|
435 |
* color model information
|
|
|
436 |
*
|
|
|
437 |
* pdata pointer to buffer in which to write the data
|
|
|
438 |
*
|
|
|
439 |
* psize pointer to a location that, on entry, contains the size of
|
|
|
440 |
* the buffer pointed to by pdata; on return, the size of
|
|
|
441 |
* the data required or actually used will be written here.
|
|
|
442 |
*
|
|
|
443 |
* Returns:
|
|
|
444 |
* 1, with *psize set to 0, if *psdc and *pdevc represent the same color
|
|
|
445 |
*
|
|
|
446 |
* 0, with *psize set to the amount of data written, if everything OK
|
|
|
447 |
*
|
|
|
448 |
* gs_error_rangecheck, with *psize set to the size of buffer required,
|
|
|
449 |
* if *psize was not large enough
|
|
|
450 |
*
|
|
|
451 |
* < 0, != gs_error_rangecheck, in the event of some other error; in this
|
|
|
452 |
* case *psize is not changed.
|
|
|
453 |
*/
|
|
|
454 |
private int
|
|
|
455 |
gx_dc_ht_binary_write(
|
|
|
456 |
const gx_device_color * pdevc,
|
|
|
457 |
const gx_device_color_saved * psdc0,
|
|
|
458 |
const gx_device * dev,
|
|
|
459 |
byte * pdata,
|
|
|
460 |
uint * psize )
|
|
|
461 |
{
|
|
|
462 |
int req_size = 1; /* flag bits */
|
|
|
463 |
int flag_bits = 0;
|
|
|
464 |
uint tmp_size;
|
|
|
465 |
byte * pdata0 = pdata;
|
|
|
466 |
const gx_device_color_saved * psdc = psdc0;
|
|
|
467 |
int code;
|
|
|
468 |
|
|
|
469 |
/* check if operand and saved colors are the same type */
|
|
|
470 |
if (psdc != 0 && psdc->type != pdevc->type)
|
|
|
471 |
psdc = 0;
|
|
|
472 |
|
|
|
473 |
/* check for the information that must be transmitted */
|
|
|
474 |
if ( psdc == 0 ||
|
|
|
475 |
pdevc->colors.binary.color[0] != psdc->colors.binary.b_color[0] ) {
|
|
|
476 |
flag_bits |= dc_ht_binary_has_color0;
|
|
|
477 |
tmp_size = 0;
|
|
|
478 |
(void)gx_dc_write_color( pdevc->colors.binary.color[0],
|
|
|
479 |
dev,
|
|
|
480 |
pdata,
|
|
|
481 |
&tmp_size );
|
|
|
482 |
req_size += tmp_size;
|
|
|
483 |
}
|
|
|
484 |
if ( psdc == 0 ||
|
|
|
485 |
pdevc->colors.binary.color[1] != psdc->colors.binary.b_color[1] ) {
|
|
|
486 |
flag_bits |= dc_ht_binary_has_color1;
|
|
|
487 |
tmp_size = 0;
|
|
|
488 |
(void)gx_dc_write_color( pdevc->colors.binary.color[1],
|
|
|
489 |
dev,
|
|
|
490 |
pdata,
|
|
|
491 |
&tmp_size );
|
|
|
492 |
req_size += tmp_size;
|
|
|
493 |
}
|
|
|
494 |
|
|
|
495 |
if ( psdc == 0 ||
|
|
|
496 |
pdevc->colors.binary.b_level != psdc->colors.binary.b_level ) {
|
|
|
497 |
flag_bits |= dc_ht_binary_has_level;
|
|
|
498 |
req_size += enc_u_sizew(pdevc->colors.binary.b_level);
|
|
|
499 |
}
|
|
|
500 |
|
|
|
501 |
if ( psdc == 0 ||
|
|
|
502 |
pdevc->colors.binary.b_index != psdc->colors.binary.b_index ) {
|
|
|
503 |
flag_bits |= dc_ht_binary_has_index;
|
|
|
504 |
req_size += 1;
|
|
|
505 |
}
|
|
|
506 |
|
|
|
507 |
/* check if there is anything to be done */
|
|
|
508 |
if (flag_bits == 0) {
|
|
|
509 |
*psize = 0;
|
|
|
510 |
return 1;
|
|
|
511 |
}
|
|
|
512 |
|
|
|
513 |
/* check if sufficient space has been provided */
|
|
|
514 |
if (req_size > *psize) {
|
|
|
515 |
*psize = req_size;
|
|
|
516 |
return gs_error_rangecheck;
|
|
|
517 |
}
|
|
|
518 |
|
|
|
519 |
/* write out the flag byte */
|
|
|
520 |
*pdata++ = (byte)flag_bits;
|
|
|
521 |
|
|
|
522 |
/* write out such other parts of the device color as are required */
|
|
|
523 |
if ((flag_bits & dc_ht_binary_has_color0) != 0) {
|
|
|
524 |
tmp_size = req_size - (pdata - pdata0);
|
|
|
525 |
code = gx_dc_write_color( pdevc->colors.binary.color[0],
|
|
|
526 |
dev,
|
|
|
527 |
pdata,
|
|
|
528 |
&tmp_size );
|
|
|
529 |
if (code < 0)
|
|
|
530 |
return code;
|
|
|
531 |
pdata += tmp_size;
|
|
|
532 |
}
|
|
|
533 |
if ((flag_bits & dc_ht_binary_has_color1) != 0) {
|
|
|
534 |
tmp_size = req_size - (pdata - pdata0);
|
|
|
535 |
code = gx_dc_write_color( pdevc->colors.binary.color[1],
|
|
|
536 |
dev,
|
|
|
537 |
pdata,
|
|
|
538 |
&tmp_size );
|
|
|
539 |
if (code < 0)
|
|
|
540 |
return code;
|
|
|
541 |
pdata += tmp_size;
|
|
|
542 |
}
|
|
|
543 |
if ((flag_bits & dc_ht_binary_has_level) != 0)
|
|
|
544 |
enc_u_putw(pdevc->colors.binary.b_level, pdata);
|
|
|
545 |
if ((flag_bits & dc_ht_binary_has_index) != 0)
|
|
|
546 |
*pdata++ = pdevc->colors.binary.b_index;
|
|
|
547 |
|
|
|
548 |
*psize = pdata - pdata0;
|
|
|
549 |
return 0;
|
|
|
550 |
}
|
|
|
551 |
|
|
|
552 |
/*
|
|
|
553 |
* Reconstruct a binary halftone device color from its serial representation.
|
|
|
554 |
*
|
|
|
555 |
* Operands:
|
|
|
556 |
*
|
|
|
557 |
* pdevc pointer to the location in which to write the
|
|
|
558 |
* reconstructed device color
|
|
|
559 |
*
|
|
|
560 |
* pis pointer to the current imager state (to access the
|
|
|
561 |
* current halftone)
|
|
|
562 |
*
|
|
|
563 |
* prior_devc pointer to the current device color (this is provided
|
|
|
564 |
* separately because the device color is not part of the
|
|
|
565 |
* imager state)
|
|
|
566 |
*
|
|
|
567 |
* dev pointer to the current device, used to retrieve process
|
|
|
568 |
* color model information
|
|
|
569 |
*
|
|
|
570 |
* pdata pointer to the buffer to be read
|
|
|
571 |
*
|
|
|
572 |
* size size of the buffer to be read; this should be large
|
|
|
573 |
* enough to hold the entire color description
|
|
|
574 |
*
|
|
|
575 |
* mem pointer to the memory to be used for allocations
|
|
|
576 |
* (ignored here)
|
|
|
577 |
*
|
|
|
578 |
* Returns:
|
|
|
579 |
*
|
|
|
580 |
* # of bytes read if everthing OK, < 0 in the event of an error
|
|
|
581 |
*/
|
|
|
582 |
private int
|
|
|
583 |
gx_dc_ht_binary_read(
|
|
|
584 |
gx_device_color * pdevc,
|
|
|
585 |
const gs_imager_state * pis,
|
|
|
586 |
const gx_device_color * prior_devc,
|
|
|
587 |
const gx_device * dev, /* ignored */
|
|
|
588 |
const byte * pdata,
|
|
|
589 |
uint size,
|
|
|
590 |
gs_memory_t * mem ) /* ignored */
|
|
|
591 |
{
|
|
|
592 |
gx_device_color devc;
|
|
|
593 |
const byte * pdata0 = pdata;
|
|
|
594 |
int code, flag_bits;
|
|
|
595 |
|
|
|
596 |
/* if prior information is available, use it */
|
|
|
597 |
if (prior_devc != 0 && prior_devc->type == gx_dc_type_ht_binary)
|
|
|
598 |
devc = *prior_devc;
|
|
|
599 |
else
|
|
|
600 |
memset(&devc, 0, sizeof(devc)); /* clear pointers */
|
|
|
601 |
devc.type = gx_dc_type_ht_binary;
|
|
|
602 |
|
|
|
603 |
/* the halftone is always taken from the imager state */
|
|
|
604 |
devc.colors.binary.b_ht = pis->dev_ht;
|
|
|
605 |
|
|
|
606 |
/* cache is not porvided until the device color is used */
|
|
|
607 |
devc.colors.binary.b_tile = 0;
|
|
|
608 |
|
|
|
609 |
/* verify the minimum amount of information */
|
|
|
610 |
if (size == 0)
|
|
|
611 |
return_error(gs_error_rangecheck);
|
|
|
612 |
size --;
|
|
|
613 |
flag_bits = *pdata++;
|
|
|
614 |
|
|
|
615 |
/* read the other information provided */
|
|
|
616 |
if ((flag_bits & dc_ht_binary_has_color0) != 0) {
|
|
|
617 |
code = gx_dc_read_color( &devc.colors.binary.color[0],
|
|
|
618 |
dev,
|
|
|
619 |
pdata,
|
|
|
620 |
size );
|
|
|
621 |
if (code < 0)
|
|
|
622 |
return code;
|
|
|
623 |
size -= code;
|
|
|
624 |
pdata += code;
|
|
|
625 |
}
|
|
|
626 |
if ((flag_bits & dc_ht_binary_has_color1) != 0) {
|
|
|
627 |
code = gx_dc_read_color( &devc.colors.binary.color[1],
|
|
|
628 |
dev,
|
|
|
629 |
pdata,
|
|
|
630 |
size );
|
|
|
631 |
if (code < 0)
|
|
|
632 |
return code;
|
|
|
633 |
size -= code;
|
|
|
634 |
pdata += code;
|
|
|
635 |
}
|
|
|
636 |
if ((flag_bits & dc_ht_binary_has_level) != 0) {
|
|
|
637 |
const byte * pdata_start = pdata;
|
|
|
638 |
|
|
|
639 |
if (size < 1)
|
|
|
640 |
return_error(gs_error_rangecheck);
|
|
|
641 |
enc_u_getw(devc.colors.binary.b_level, pdata);
|
|
|
642 |
size -= pdata - pdata_start;
|
|
|
643 |
}
|
|
|
644 |
if ((flag_bits & dc_ht_binary_has_index) != 0) {
|
|
|
645 |
if (size == 0)
|
|
|
646 |
return_error(gs_error_rangecheck);
|
|
|
647 |
--size;
|
|
|
648 |
devc.colors.binary.b_index = *pdata++;
|
|
|
649 |
}
|
|
|
650 |
|
|
|
651 |
/* set the phase as required (select value is arbitrary) */
|
|
|
652 |
/* set the phase as required (select value is arbitrary) */
|
|
|
653 |
color_set_phase_mod( &devc,
|
|
|
654 |
pis->screen_phase[0].x,
|
|
|
655 |
pis->screen_phase[0].y,
|
|
|
656 |
pis->dev_ht->lcm_width,
|
|
|
657 |
pis->dev_ht->lcm_height );
|
|
|
658 |
|
|
|
659 |
/* everything looks good */
|
|
|
660 |
*pdevc = devc;
|
|
|
661 |
return pdata - pdata0;
|
|
|
662 |
}
|
|
|
663 |
|
|
|
664 |
|
|
|
665 |
/*
|
|
|
666 |
* Get the nonzero components of a binary halftone. This is used to
|
|
|
667 |
* distinguish components that are given zero intensity due to halftoning
|
|
|
668 |
* from those for which the original color intensity was in fact zero.
|
|
|
669 |
*
|
|
|
670 |
* Since this device color type involves only a single halftone component,
|
|
|
671 |
* we can reasonably assume that b_level != 0. Hence, we need to check
|
|
|
672 |
* for components with identical intensities in color[0] and color[1].
|
|
|
673 |
*/
|
|
|
674 |
int
|
|
|
675 |
gx_dc_ht_binary_get_nonzero_comps(
|
|
|
676 |
const gx_device_color * pdevc,
|
|
|
677 |
const gx_device * dev,
|
|
|
678 |
gx_color_index * pcomp_bits )
|
|
|
679 |
{
|
|
|
680 |
int code;
|
|
|
681 |
gx_color_value cvals_0[GX_DEVICE_COLOR_MAX_COMPONENTS],
|
|
|
682 |
cvals_1[GX_DEVICE_COLOR_MAX_COMPONENTS];
|
|
|
683 |
|
|
|
684 |
if ( (code = dev_proc(dev, decode_color)( (gx_device *)dev,
|
|
|
685 |
pdevc->colors.binary.color[0],
|
|
|
686 |
cvals_0 )) >= 0 &&
|
|
|
687 |
(code = dev_proc(dev, decode_color)( (gx_device *)dev,
|
|
|
688 |
pdevc->colors.binary.color[1],
|
|
|
689 |
cvals_1 )) >= 0 ) {
|
|
|
690 |
int i, ncomps = dev->color_info.num_components;
|
|
|
691 |
int mask = 0x1, comp_bits = 0;
|
|
|
692 |
|
|
|
693 |
for (i = 0; i < ncomps; i++, mask <<= 1) {
|
|
|
694 |
if (cvals_0[i] != 0 || cvals_1[i] != 0)
|
|
|
695 |
comp_bits |= mask;
|
|
|
696 |
}
|
|
|
697 |
*pcomp_bits = comp_bits;
|
|
|
698 |
code = 0;
|
|
|
699 |
}
|
|
|
700 |
|
|
|
701 |
return code;
|
|
|
702 |
}
|
|
|
703 |
|
|
|
704 |
|
|
|
705 |
/* Initialize the tile cache for a given screen. */
|
|
|
706 |
/* Cache as many different levels as will fit. */
|
|
|
707 |
void
|
|
|
708 |
gx_ht_init_cache(const gs_memory_t *mem, gx_ht_cache * pcache, const gx_ht_order * porder)
|
|
|
709 |
{
|
|
|
710 |
uint width = porder->width;
|
|
|
711 |
uint height = porder->height;
|
|
|
712 |
uint size = width * height + 1;
|
|
|
713 |
int width_unit =
|
|
|
714 |
(width <= ht_mask_bits / 2 ? ht_mask_bits / width * width :
|
|
|
715 |
width);
|
|
|
716 |
int height_unit = height;
|
|
|
717 |
uint raster = porder->raster;
|
|
|
718 |
uint tile_bytes = raster * height;
|
|
|
719 |
uint shift = porder->shift;
|
|
|
720 |
int num_cached;
|
|
|
721 |
int i;
|
|
|
722 |
byte *tbits = pcache->bits;
|
|
|
723 |
|
|
|
724 |
/* Non-monotonic halftones may have more bits than size. */
|
|
|
725 |
if (porder->num_bits >= size)
|
|
|
726 |
size = porder->num_bits + 1;
|
|
|
727 |
/* Make sure num_cached is within bounds */
|
|
|
728 |
num_cached = pcache->bits_size / tile_bytes;
|
|
|
729 |
if (num_cached > size)
|
|
|
730 |
num_cached = size;
|
|
|
731 |
if (num_cached > pcache->num_tiles)
|
|
|
732 |
num_cached = pcache->num_tiles;
|
|
|
733 |
if (num_cached == size &&
|
|
|
734 |
tile_bytes * num_cached <= pcache->bits_size / 2
|
|
|
735 |
) {
|
|
|
736 |
/*
|
|
|
737 |
* We can afford to replicate every tile in the cache,
|
|
|
738 |
* which will reduce breakage when tiling. Since
|
|
|
739 |
* horizontal breakage is more expensive than vertical,
|
|
|
740 |
* and since wide shallow fills are more common than
|
|
|
741 |
* narrow deep fills, we replicate the tile horizontally.
|
|
|
742 |
* We do have to be careful not to replicate the tile
|
|
|
743 |
* to an absurdly large size, however.
|
|
|
744 |
*/
|
|
|
745 |
uint rep_raster =
|
|
|
746 |
((pcache->bits_size / num_cached) / height) &
|
|
|
747 |
~(align_bitmap_mod - 1);
|
|
|
748 |
uint rep_count = rep_raster * 8 / width;
|
|
|
749 |
|
|
|
750 |
/*
|
|
|
751 |
* There's no real value in replicating the tile
|
|
|
752 |
* beyond the point where the byte width of the replicated
|
|
|
753 |
* tile is a multiple of a long.
|
|
|
754 |
*/
|
|
|
755 |
if (rep_count > sizeof(ulong) * 8)
|
|
|
756 |
rep_count = sizeof(ulong) * 8;
|
|
|
757 |
width_unit = width * rep_count;
|
|
|
758 |
raster = bitmap_raster(width_unit);
|
|
|
759 |
tile_bytes = raster * height;
|
|
|
760 |
}
|
|
|
761 |
pcache->base_id = gs_next_ids(mem, porder->num_levels + 1);
|
|
|
762 |
pcache->order = *porder;
|
|
|
763 |
/* The transfer function is irrelevant, and might become dangling. */
|
|
|
764 |
pcache->order.transfer = 0;
|
|
|
765 |
pcache->num_cached = num_cached;
|
|
|
766 |
pcache->levels_per_tile = (size + num_cached - 1) / num_cached;
|
|
|
767 |
pcache->tiles_fit = -1;
|
|
|
768 |
memset(tbits, 0, pcache->bits_size);
|
|
|
769 |
for (i = 0; i < num_cached; i++, tbits += tile_bytes) {
|
|
|
770 |
register gx_ht_tile *bt = &pcache->ht_tiles[i];
|
|
|
771 |
|
|
|
772 |
bt->level = 0;
|
|
|
773 |
bt->index = i;
|
|
|
774 |
bt->tiles.data = tbits;
|
|
|
775 |
bt->tiles.raster = raster;
|
|
|
776 |
bt->tiles.size.x = width_unit;
|
|
|
777 |
bt->tiles.size.y = height_unit;
|
|
|
778 |
bt->tiles.rep_width = width;
|
|
|
779 |
bt->tiles.rep_height = height;
|
|
|
780 |
bt->tiles.shift = bt->tiles.rep_shift = shift;
|
|
|
781 |
}
|
|
|
782 |
pcache->render_ht =
|
|
|
783 |
(pcache->num_tiles == 1 ? gx_render_ht_1_tile :
|
|
|
784 |
pcache->levels_per_tile == 1 ? gx_render_ht_1_level :
|
|
|
785 |
gx_render_ht_default);
|
|
|
786 |
}
|
|
|
787 |
|
|
|
788 |
/*
|
|
|
789 |
* Compute and save the rendering of a given gray level
|
|
|
790 |
* with the current halftone. The cache holds multiple tiles,
|
|
|
791 |
* where each tile covers a range of possible levels.
|
|
|
792 |
* We adjust the tile whose range includes the desired level incrementally;
|
|
|
793 |
* this saves a lot of time for the average image, where gray levels
|
|
|
794 |
* don't change abruptly. Note that the "level" is the number of bits,
|
|
|
795 |
* not the index in the levels vector.
|
|
|
796 |
*/
|
|
|
797 |
private int
|
|
|
798 |
render_ht(gx_ht_tile * pbt, int level /* [1..num_bits-1] */ ,
|
|
|
799 |
const gx_ht_order * porder, gx_bitmap_id new_id)
|
|
|
800 |
{
|
|
|
801 |
byte *data = pbt->tiles.data;
|
|
|
802 |
int code;
|
|
|
803 |
|
|
|
804 |
if_debug7('H', "[H]Halftone cache slot 0x%lx: old=%d, new=%d, w=%d(%d), h=%d(%d):\n",
|
|
|
805 |
(ulong) data, pbt->level, level,
|
|
|
806 |
pbt->tiles.size.x, porder->width,
|
|
|
807 |
pbt->tiles.size.y, porder->num_bits / porder->width);
|
|
|
808 |
#ifdef DEBUG
|
|
|
809 |
if (level < 0 || level > porder->num_bits) {
|
|
|
810 |
lprintf3("Error in render_ht: level=%d, old level=%d, num_bits=%d\n",
|
|
|
811 |
level, pbt->level, porder->num_bits);
|
|
|
812 |
return_error(gs_error_Fatal);
|
|
|
813 |
}
|
|
|
814 |
#endif
|
|
|
815 |
code = porder->procs->render(pbt, level, porder);
|
|
|
816 |
if (code < 0)
|
|
|
817 |
return code;
|
|
|
818 |
pbt->level = level;
|
|
|
819 |
pbt->tiles.id = new_id;
|
|
|
820 |
/*
|
|
|
821 |
* Check whether we want to replicate the tile in the cache.
|
|
|
822 |
* Since we only do this when all the renderings will fit
|
|
|
823 |
* in the cache, we only do it once per level, and it doesn't
|
|
|
824 |
* have to be very efficient.
|
|
|
825 |
*/
|
|
|
826 |
/****** TEST IS WRONG if width > rep_width but tile.raster ==
|
|
|
827 |
****** order raster.
|
|
|
828 |
******/
|
|
|
829 |
if (pbt->tiles.raster > porder->raster)
|
|
|
830 |
bits_replicate_horizontally(data, pbt->tiles.rep_width,
|
|
|
831 |
pbt->tiles.rep_height, porder->raster,
|
|
|
832 |
pbt->tiles.size.x, pbt->tiles.raster);
|
|
|
833 |
if (pbt->tiles.size.y > pbt->tiles.rep_height &&
|
|
|
834 |
pbt->tiles.shift == 0
|
|
|
835 |
)
|
|
|
836 |
bits_replicate_vertically(data, pbt->tiles.rep_height,
|
|
|
837 |
pbt->tiles.raster, pbt->tiles.size.y);
|
|
|
838 |
#ifdef DEBUG
|
|
|
839 |
if (gs_debug_c('H')) {
|
|
|
840 |
const byte *p = pbt->tiles.data;
|
|
|
841 |
int wb = pbt->tiles.raster;
|
|
|
842 |
const byte *ptr = p + wb * pbt->tiles.size.y;
|
|
|
843 |
|
|
|
844 |
while (p < ptr) {
|
|
|
845 |
dprintf8(" %d%d%d%d%d%d%d%d",
|
|
|
846 |
*p >> 7, (*p >> 6) & 1, (*p >> 5) & 1,
|
|
|
847 |
(*p >> 4) & 1, (*p >> 3) & 1, (*p >> 2) & 1,
|
|
|
848 |
(*p >> 1) & 1, *p & 1);
|
|
|
849 |
if ((++p - data) % wb == 0)
|
|
|
850 |
dputc('\n');
|
|
|
851 |
}
|
|
|
852 |
}
|
|
|
853 |
#endif
|
|
|
854 |
return 0;
|
|
|
855 |
}
|