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