Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
}