1 /* Copyright (C) 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: gshtx.c,v 1.6 2004/08/04 19:36:12 stefan Exp $ */
18 /* Stand-alone halftone/transfer function related code */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsstruct.h"
23 #include "gsutil.h" /* for gs_next_ids */
24 #include "gxfmap.h"
25 #include "gzstate.h"
26 #include "gzht.h"
27 #include "gshtx.h" /* must come after g*ht.h */
28
29 /*
30 * Procedure to free the set of components when a halftone is released.
31 */
32 private void
free_comps(gs_memory_t * pmem,void * pvht,client_name_t cname)33 free_comps(
34 gs_memory_t * pmem,
35 void *pvht,
36 client_name_t cname
37 )
38 {
39 gs_ht *pht = (gs_ht *) pvht;
40
41 gs_free_object(pmem, pht->params.ht_multiple.components, cname);
42 gs_free_object(pmem, pvht, cname);
43 }
44
45 /*
46 * Stub transfer function, to be applied to components that are not provided
47 * with a transfer function.
48 */
49 private float
null_closure_transfer(floatp val,const gx_transfer_map * pmap_dummy,const void * dummy)50 null_closure_transfer(
51 floatp val,
52 const gx_transfer_map * pmap_dummy, /* NOTUSED */
53 const void *dummy /* NOTUSED */
54 )
55 {
56 return val;
57 }
58
59
60 /*
61 * Build a gs_ht halftone structure.
62 */
63 int
gs_ht_build(gs_ht ** ppht,uint num_comps,gs_memory_t * pmem)64 gs_ht_build(
65 gs_ht ** ppht,
66 uint num_comps,
67 gs_memory_t * pmem
68 )
69 {
70 gs_ht *pht;
71 gs_ht_component *phtc;
72 int i;
73
74 /* must have at least one component */
75 *ppht = 0;
76 if (num_comps == 0)
77 return_error(gs_error_rangecheck);
78
79 /* allocate the halftone and the array of components */
80 rc_alloc_struct_1(pht,
81 gs_ht,
82 &st_gs_ht,
83 pmem,
84 return_error(gs_error_VMerror),
85 "gs_ht_build"
86 );
87 phtc = gs_alloc_struct_array(pmem,
88 num_comps,
89 gs_ht_component,
90 &st_ht_comp_element,
91 "gs_ht_build"
92 );
93 if (phtc == 0) {
94 gs_free_object(pmem, pht, "gs_ht_build");
95 return_error(gs_error_VMerror);
96 }
97 /* initialize the halftone */
98 pht->type = ht_type_multiple;
99 pht->rc.free = free_comps;
100 pht->params.ht_multiple.components = phtc;
101 pht->params.ht_multiple.num_comp = num_comps;
102
103 for (i = 0; i < num_comps; i++) {
104 phtc[i].comp_number = i;
105 phtc[i].cname = 0;
106 phtc[i].type = ht_type_none;
107 }
108
109 *ppht = pht;
110
111 return 0;
112 }
113
114 /*
115 * Set a spot-function halftone component in a gs_ht halftone.
116 */
117 int
gs_ht_set_spot_comp(gs_ht * pht,int comp,floatp freq,floatp angle,float (* spot_func)(floatp,floatp),bool accurate,gs_ht_transfer_proc transfer,const void * client_data)118 gs_ht_set_spot_comp(
119 gs_ht * pht,
120 int comp,
121 floatp freq,
122 floatp angle,
123 float (*spot_func) (floatp, floatp),
124 bool accurate,
125 gs_ht_transfer_proc transfer,
126 const void *client_data
127 )
128 {
129 gs_ht_component *phtc = &(pht->params.ht_multiple.components[comp]);
130
131 if (comp >= pht->params.ht_multiple.num_comp)
132 return_error(gs_error_rangecheck);
133 if (phtc->type != ht_type_none)
134 return_error(gs_error_invalidaccess);
135
136 phtc->type = ht_type_spot;
137 phtc->params.ht_spot.screen.frequency = freq;
138 phtc->params.ht_spot.screen.angle = angle;
139 phtc->params.ht_spot.screen.spot_function = spot_func;
140 phtc->params.ht_spot.accurate_screens = accurate;
141 phtc->params.ht_spot.transfer = gs_mapped_transfer;
142
143 phtc->params.ht_spot.transfer_closure.proc =
144 (transfer == 0 ? null_closure_transfer : transfer);
145 phtc->params.ht_spot.transfer_closure.data = client_data;
146
147 return 0;
148 }
149
150 /*
151 * Set a threshold halftone component in a gs_ht halftone. Note that the
152 * caller is responsible for releasing the threshold data.
153 */
154 int
gs_ht_set_threshold_comp(gs_ht * pht,int comp,int width,int height,const gs_const_string * thresholds,gs_ht_transfer_proc transfer,const void * client_data)155 gs_ht_set_threshold_comp(
156 gs_ht * pht,
157 int comp,
158 int width,
159 int height,
160 const gs_const_string * thresholds,
161 gs_ht_transfer_proc transfer,
162 const void *client_data
163 )
164 {
165 gs_ht_component *phtc = &(pht->params.ht_multiple.components[comp]);
166
167 if (comp >= pht->params.ht_multiple.num_comp)
168 return_error(gs_error_rangecheck);
169 if (phtc->type != ht_type_none)
170 return_error(gs_error_invalidaccess);
171
172 phtc->type = ht_type_threshold;
173 phtc->params.ht_threshold.width = width;
174 phtc->params.ht_threshold.height = height;
175 phtc->params.ht_threshold.thresholds = *thresholds;
176 phtc->params.ht_threshold.transfer = gs_mapped_transfer;
177
178 phtc->params.ht_threshold.transfer_closure.proc =
179 (transfer == 0 ? null_closure_transfer : transfer);
180 phtc->params.ht_threshold.transfer_closure.data = client_data;
181
182 return 0;
183 }
184
185 /*
186 * Increase the reference count of a gs_ht structure by 1.
187 */
188 void
gs_ht_reference(gs_ht * pht)189 gs_ht_reference(
190 gs_ht * pht
191 )
192 {
193 rc_increment(pht);
194 }
195
196 /*
197 * Decrement the reference count of a gs_ht structure by 1. Free the
198 * structure if the reference count reaches 0.
199 */
200 void
gs_ht_release(gs_ht * pht)201 gs_ht_release(
202 gs_ht * pht
203 )
204 {
205 rc_decrement_only(pht, "gs_ht_release");
206 }
207
208
209 /*
210 * Verify that a gs_ht halftone is legitimate.
211 */
212 private int
check_ht(gs_ht * pht)213 check_ht(
214 gs_ht * pht
215 )
216 {
217 int i;
218 int num_comps = pht->params.ht_multiple.num_comp;
219
220 if (pht->type != ht_type_multiple)
221 return_error(gs_error_unregistered);
222 for (i = 0; i < num_comps; i++) {
223 gs_ht_component *phtc = &(pht->params.ht_multiple.components[i]);
224 if ((phtc->type != ht_type_spot) && (phtc->type != ht_type_threshold))
225 return_error(gs_error_unregistered);
226 }
227 return 0;
228 }
229
230 /*
231 * Load a transfer map from a gs_ht_transfer_proc function.
232 */
233 private void
build_transfer_map(gs_ht_component * phtc,gx_transfer_map * pmap)234 build_transfer_map(
235 gs_ht_component * phtc,
236 gx_transfer_map * pmap
237 )
238 {
239 gs_ht_transfer_proc proc;
240 const void *client_info;
241 int i;
242 frac *values = pmap->values;
243
244 if (phtc->type == ht_type_spot) {
245 proc = phtc->params.ht_spot.transfer_closure.proc;
246 client_info = phtc->params.ht_spot.transfer_closure.data;
247 } else {
248 proc = phtc->params.ht_threshold.transfer_closure.proc;
249 client_info = phtc->params.ht_threshold.transfer_closure.data;
250 }
251
252 for (i = 0; i < transfer_map_size; i++) {
253 float fval =
254 proc(i * (1 / (double)(transfer_map_size - 1)), pmap, client_info);
255
256 values[i] =
257 (fval <= 0.0 ? frac_0 : fval >= 1.0 ? frac_1 :
258 float2frac(fval));
259 }
260 }
261
262 /*
263 * Allocate the order and transfer maps required by a halftone, and perform
264 * some elementary initialization. This will also build the component index
265 * to order index map.
266 */
267 private gx_ht_order_component *
alloc_ht_order(const gs_ht * pht,gs_memory_t * pmem,byte * comp2order)268 alloc_ht_order(
269 const gs_ht * pht,
270 gs_memory_t * pmem,
271 byte * comp2order
272 )
273 {
274 int num_comps = pht->params.ht_multiple.num_comp;
275 gx_ht_order_component *pocs = gs_alloc_struct_array(
276 pmem,
277 pht->params.ht_multiple.num_comp,
278 gx_ht_order_component,
279 &st_ht_order_component_element,
280 "alloc_ht_order"
281 );
282 int inext = 0;
283 int i;
284
285 if (pocs == 0)
286 return 0;
287 pocs->corder.transfer = 0;
288
289 for (i = 0; i < num_comps; i++) {
290 gs_ht_component *phtc = &(pht->params.ht_multiple.components[i]);
291 gx_transfer_map *pmap = gs_alloc_struct(pmem,
292 gx_transfer_map,
293 &st_transfer_map,
294 "alloc_ht_order"
295 );
296
297 if (pmap == 0) {
298 int j;
299
300 for (j = 0; j < inext; j++)
301 gs_free_object(pmem, pocs[j].corder.transfer, "alloc_ht_order");
302 gs_free_object(pmem, pocs, "alloc_ht_order");
303 return 0;
304 }
305 pmap->proc = gs_mapped_transfer;
306 pmap->id = gs_next_ids(pmem, 1);
307 pocs[inext].corder.levels = 0;
308 pocs[inext].corder.bit_data = 0;
309 pocs[inext].corder.cache = 0;
310 pocs[inext].corder.transfer = pmap;
311 pocs[inext].cname = phtc->cname;
312 pocs[inext].comp_number = phtc->comp_number;
313 comp2order[i] = inext++;
314 }
315
316 return pocs;
317 }
318
319 /*
320 * Build the halftone order for one component.
321 */
322 private int
build_component(gs_ht_component * phtc,gx_ht_order * porder,gs_state * pgs,gs_memory_t * pmem)323 build_component(
324 gs_ht_component * phtc,
325 gx_ht_order * porder,
326 gs_state * pgs,
327 gs_memory_t * pmem
328 )
329 {
330 if (phtc->type == ht_type_spot) {
331 gs_screen_enum senum;
332 int code;
333
334 code = gx_ht_process_screen_memory(&senum,
335 pgs,
336 &phtc->params.ht_spot.screen,
337 phtc->params.ht_spot.accurate_screens,
338 pmem
339 );
340 if (code < 0)
341 return code;
342
343 /* avoid wiping out the transfer structure pointer */
344 senum.order.transfer = porder->transfer;
345 *porder = senum.order;
346
347 } else { /* ht_type_threshold */
348 int code;
349 gx_transfer_map *transfer = porder->transfer;
350
351 porder->params.M = phtc->params.ht_threshold.width;
352 porder->params.N = 0;
353 porder->params.R = 1;
354 porder->params.M1 = phtc->params.ht_threshold.height;
355 porder->params.N1 = 0;
356 porder->params.R1 = 1;
357 code = gx_ht_alloc_threshold_order(porder,
358 phtc->params.ht_threshold.width,
359 phtc->params.ht_threshold.height,
360 256,
361 pmem
362 );
363 if (code < 0)
364 return code;
365 gx_ht_construct_threshold_order(
366 porder,
367 phtc->params.ht_threshold.thresholds.data
368 );
369 /*
370 * gx_ht_construct_threshold_order wipes out transfer map pointer,
371 * restore it here.
372 */
373 porder->transfer = transfer;
374 }
375
376 build_transfer_map(phtc, porder->transfer);
377 return 0;
378 }
379
380 /*
381 * Free an order array and all elements it points to.
382 */
383 private void
free_order_array(gx_ht_order_component * pocs,int num_comps,gs_memory_t * pmem)384 free_order_array(
385 gx_ht_order_component * pocs,
386 int num_comps,
387 gs_memory_t * pmem
388 )
389 {
390 int i;
391
392 for (i = 0; i < num_comps; i++)
393 gx_ht_order_release(&(pocs[i].corder), pmem, true);
394 gs_free_object(pmem, pocs, "gs_ht_install");
395 }
396
397
398 /*
399 * Install a gs_ht halftone as the current halftone in the graphic state.
400 */
401 int
gs_ht_install(gs_state * pgs,gs_ht * pht)402 gs_ht_install(
403 gs_state * pgs,
404 gs_ht * pht
405 )
406 {
407 int code = 0;
408 gs_memory_t *pmem = pht->rc.memory;
409 gx_device_halftone dev_ht;
410 gx_ht_order_component *pocs;
411 byte comp2order[32]; /* ample component to order map */
412 int num_comps = pht->params.ht_multiple.num_comp;
413 int i;
414
415 /* perform so sanity checks (must have one default component) */
416 if ((code = check_ht(pht)) != 0)
417 return code;
418
419 /* allocate the halftone order structure and transfer maps */
420 if ((pocs = alloc_ht_order(pht, pmem, comp2order)) == 0)
421 return_error(gs_error_VMerror);
422
423 /* build all of the order for each component */
424 for (i = 0; i < num_comps; i++) {
425 int j = comp2order[i];
426
427 code = build_component(&(pht->params.ht_multiple.components[i]),
428 &(pocs[j].corder),
429 pgs,
430 pmem
431 );
432
433 if ((code >= 0) && (j != 0)) {
434 gx_ht_cache *pcache;
435
436 pcache = gx_ht_alloc_cache(pmem,
437 4,
438 pocs[j].corder.raster *
439 (pocs[j].corder.num_bits /
440 pocs[j].corder.width) * 4
441 );
442
443 if (pcache == 0)
444 code = gs_note_error(gs_error_VMerror);
445 else {
446 pocs[j].corder.cache = pcache;
447 gx_ht_init_cache(pmem, pcache, &(pocs[j].corder));
448 }
449 }
450 if (code < 0)
451 break;
452 }
453
454 if (code < 0) {
455 free_order_array(pocs, num_comps, pmem);
456 return code;
457 }
458 /* initialize the device halftone structure */
459 dev_ht.rc.memory = pmem;
460 dev_ht.order = pocs[0].corder; /* Default */
461 if (num_comps == 1) {
462 /* we have only a Default; we don't need components. */
463 gs_free_object(pmem, pocs, "gs_ht_install");
464 dev_ht.components = 0;
465 } else {
466 dev_ht.components = pocs;
467 dev_ht.num_comp = num_comps;
468 }
469
470 /* at last, actually install the halftone in the graphic state */
471 if ((code = gx_ht_install(pgs, (gs_halftone *) pht, &dev_ht)) < 0)
472 gx_device_halftone_release(&dev_ht, pmem);
473 return code;
474 }
475
476 /* ---------------- Mask-defined halftones ---------------- */
477
478 /*
479 * Create a halftone order from an array of explicit masks. This is
480 * silly, because the rendering machinery actually wants masks, but doing
481 * it right seems to require too many changes in existing code.
482 */
483 private int
create_mask_bits(const byte * mask1,const byte * mask2,int width,int height,gx_ht_bit * bits)484 create_mask_bits(const byte * mask1, const byte * mask2,
485 int width, int height, gx_ht_bit * bits)
486 {
487 /*
488 * We do this with the slowest, simplest possible algorithm....
489 */
490 int width_bytes = (width + 7) >> 3;
491 int x, y;
492 int count = 0;
493
494 for (y = 0; y < height; ++y)
495 for (x = 0; x < width; ++x) {
496 int offset = y * width_bytes + (x >> 3);
497 byte bit_mask = 0x80 >> (x & 7);
498
499 if ((mask1[offset] ^ mask2[offset]) & bit_mask) {
500 if (bits)
501 gx_ht_construct_bit(&bits[count], width, y * width + x);
502 ++count;
503 }
504 }
505 return count;
506 }
507 private int
create_mask_order(gx_ht_order * porder,gs_state * pgs,const gs_client_order_halftone * phcop,gs_memory_t * mem)508 create_mask_order(gx_ht_order * porder, gs_state * pgs,
509 const gs_client_order_halftone * phcop,
510 gs_memory_t * mem)
511 {
512 int width_bytes = (phcop->width + 7) >> 3;
513 const byte *masks = (const byte *)phcop->client_data;
514 int bytes_per_mask = width_bytes * phcop->height;
515 const byte *prev_mask;
516 int num_levels = phcop->num_levels;
517 int num_bits = 0;
518 int i;
519 int code;
520
521 /* Do a first pass to compute how many bits entries will be needed. */
522 for (prev_mask = masks, num_bits = 0, i = 0;
523 i < num_levels - 1;
524 ++i, prev_mask += bytes_per_mask
525 )
526 num_bits += create_mask_bits(prev_mask, prev_mask + bytes_per_mask,
527 phcop->width, phcop->height, NULL);
528 code = gx_ht_alloc_client_order(porder, phcop->width, phcop->height,
529 num_levels, num_bits, mem);
530 if (code < 0)
531 return code;
532 /* Fill in the bits and levels entries. */
533 for (prev_mask = masks, num_bits = 0, i = 0;
534 i < num_levels - 1;
535 ++i, prev_mask += bytes_per_mask
536 ) {
537 porder->levels[i] = num_bits;
538 num_bits += create_mask_bits(prev_mask, prev_mask + bytes_per_mask,
539 phcop->width, phcop->height,
540 ((gx_ht_bit *)porder->bit_data) +
541 num_bits);
542 }
543 porder->levels[num_levels - 1] = num_bits;
544 return 0;
545 }
546
547 /* Define the client-order halftone procedure structure. */
548 private const gs_client_order_ht_procs_t mask_order_procs =
549 {
550 create_mask_order
551 };
552
553 /*
554 * Define a halftone by an explicit set of masks. We translate these
555 * internally into a threshold array, since that's what the halftone
556 * rendering machinery knows how to deal with.
557 */
558 int
gs_ht_set_mask_comp(gs_ht * pht,int component_index,int width,int height,int num_levels,const byte * masks,gs_ht_transfer_proc transfer,const void * client_data)559 gs_ht_set_mask_comp(gs_ht * pht,
560 int component_index,
561 int width, int height, int num_levels,
562 const byte * masks, /* width x height x num_levels bits */
563 gs_ht_transfer_proc transfer,
564 const void *client_data)
565 {
566 gs_ht_component *phtc =
567 &(pht->params.ht_multiple.components[component_index]);
568
569 if (component_index >= pht->params.ht_multiple.num_comp)
570 return_error(gs_error_rangecheck);
571 if (phtc->type != ht_type_none)
572 return_error(gs_error_invalidaccess);
573
574 phtc->type = ht_type_client_order;
575 phtc->params.client_order.width = width;
576 phtc->params.client_order.height = height;
577 phtc->params.client_order.num_levels = num_levels;
578 phtc->params.client_order.procs = &mask_order_procs;
579 phtc->params.client_order.client_data = masks;
580 phtc->params.client_order.transfer_closure.proc =
581 (transfer == 0 ? null_closure_transfer : transfer);
582 phtc->params.client_order.transfer_closure.data = client_data;
583
584 return 0;
585
586 }
587