Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 2002 Artifex Software Inc.  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: zfsample.c,v 1.9 2003/04/26 18:40:16 dan Exp $ */
18
/* Sample data to create a type 0 function */
19
#include "memory_.h"
20
#include "ghost.h"
21
#include "oper.h"
22
#include "gxcspace.h"
23
#include "estack.h"
24
#include "ialloc.h"
25
#include "idict.h"
26
#include "idparam.h"
27
#include "ifunc.h"
28
#include "ostack.h"
29
#include "store.h"
30
#include "gsfunc0.h"
31
 
32
/*
33
 * We store the data in a string.  Since the max size for a string is 64k,
34
 * we use that as our max data size.
35
 */
36
#define MAX_DATA_SIZE 0x10000
37
/*
38
 * We cannot handle more than  16 inputs.  Otherwise the the data will not
39
 * fit within MAX_DATA_SIZE.
40
 */
41
#define MAX_NUM_INPUTS 16
42
/*
43
 * This value is rather arbitrary.
44
 */
45
#define MAX_NUM_OUTPUTS 128
46
 
47
/* --- Build sampled data function --- */
48
 
49
/*
50
 * This structure is used to hold data required while collecting samples
51
 * for a type 0 function (sampled data).
52
 */
53
struct gs_sampled_data_enum_s {
54
    int indexes[MAX_NUM_INPUTS];
55
    int o_stack_depth;		/* used to verify stack while sampling */
56
    gs_function_t * pfn;
57
};
58
 
59
typedef struct gs_sampled_data_enum_s gs_sampled_data_enum;
60
 
61
 
62
gs_private_st_ptrs1(st_gs_sampled_data_enum, gs_sampled_data_enum,
63
		"gs_sampled_data_enum", gs_sampled_data_enum_enum_ptrs,
64
		gs_sampled_data_enum_reloc_ptrs, pfn);
65
 
66
 
67
/* Forward references */
68
 
69
private int cube_build_func0(const ref * pdict,
70
	gs_function_Sd_params_t * params, gs_memory_t *mem);
71
private int sampled_data_setup(i_ctx_t *i_ctx_p, gs_function_t *pfn,
72
	const ref * pproc, int (*finish_proc)(i_ctx_t *),
73
	gs_memory_t * mem);
74
private int sampled_data_sample(i_ctx_t *i_ctx_p);
75
private int sampled_data_continue(i_ctx_t *i_ctx_p);
76
private int sampled_data_finish(i_ctx_t *i_ctx_p);
77
 
78
private gs_sampled_data_enum * gs_sampled_data_enum_alloc
79
	(gs_memory_t * mem, client_name_t cname);
80
 
81
/*
82
 * Collect data for a type 0 (sampled data) function
83
 * <dict> .buildsampledfunction <function_struct>
84
 *
85
 * The following keys are used from the dictionary:
86
 *    Function (required)
87
 *    Domain (required)
88
 *    Range (required)
89
 *    Size (optional)  If Size is not specified then a default value is determined
90
 *        based upon the number of inputs and outputs.
91
 *    BitsPerSample (required) Only 8, 16, 24, and 32 accepted,
92
 * The remaining keys are ignored.
93
 */
94
private int
95
zbuildsampledfunction(i_ctx_t *i_ctx_p)
96
{
97
    os_ptr op = osp;
98
    const ref * pdict = op;
99
    ref * pfunc;
100
    int code = 0;
101
    gs_function_t *pfn;
102
    gs_function_Sd_params_t params = {0};
103
 
104
    check_type(*pdict, t_dictionary);
105
    /* 
106
     * Check procedure to be sampled.
107
     */
108
    if (dict_find_string(pdict, "Function", &pfunc) <= 0)
109
	return_error(e_rangecheck);
110
    check_proc(*pfunc);
111
    /*
112
     * Set up the hyper cube function data structure.
113
     */
114
    code = cube_build_func0(pdict, &params, imemory);
115
    if (code < 0)
116
	return code;
117
    /*
118
     * This is temporary.  We will call gs_function_Sd_init again after
119
     * we have collected the cube data.  We are doing it now because we need
120
     * a function structure created (along with its GC enumeration stuff)
121
     * that we can use while collecting the cube data.  We will call
122
     * the routine again after the cube data is collected to correctly
123
     * initialize the function.
124
     */
125
    code = gs_function_Sd_init(&pfn, &params, imemory);
126
    if (code < 0)
127
	return code;
128
    /*
129
     * Now setup to collect the sample data.
130
     */
131
    return sampled_data_setup(i_ctx_p, pfn, pfunc, sampled_data_finish, imemory);
132
}
133
 
134
/* ------- Internal procedures ------- */
135
 
136
 
137
#define bits2bytes(x) ((x) >> 3)	/* Convert bit count to byte count */
138
 
139
/*
140
 * This routine will verify that the requested data hypercube parameters will require
141
 * a data storage size less than or equal to the MAX_DATA_SIZE.
142
 */
143
private bool
144
valid_cube_size(int num_inputs, int num_outputs, int sample_size, const int Size[])
145
{
146
    int i, total_size = num_outputs * sample_size;
147
 
148
    for (i = 0; i < num_inputs; i++) {
149
	if (Size[i] <= 0 || Size[i] > MAX_DATA_SIZE / total_size)
150
	    return false;
151
	total_size *= Size[i];
152
    }
153
    return true;
154
}
155
 
156
/*
157
 * This routine is used to determine a default value for the sampled data size.
158
 * As a default, we will build a hyper cube with each side having the same
159
 * size.  The space requirements for a hypercube grow exponentially with the
160
 * number of dimensions.  Thus we must use fewer points if our functions has
161
 * many inputs.  The values returned were chosen simply to given a reasonable
162
 * tradeoff between keeping storage requirements low but still having enough
163
 * points per side to minimize loss of information.
164
 *
165
 * We do check to see if the data will fit using our initial guess.  If not
166
 * then we decrement the size of each edge until it fits.  We will return a
167
 * e_rangecheck error if the cube can not fit into the maximum  size.
168
 * On exit the Size array contains the cube size (if a valid size was found).
169
 */
170
private int
171
determine_sampled_data_size(int num_inputs, int num_outputs,
172
				int sample_size, int Size[])
173
{
174
    static const int size_list[] = {512, 50, 20, 10, 7, 5, 4, 3};
175
    int i, size;
176
 
177
    /* Start with initial guess at cube size */
178
    if (num_inputs > 0 && num_inputs <= 8)
179
	size = size_list[num_inputs - 1];
180
    else
181
	size = 2;
182
    /*
183
     * Verify that the cube will fit into MAX_DATA_SIZE.  If not then
184
     * decrement the cube size until it will fit.
185
     */
186
    while (true) {
187
        /* Fill Size array with value. */
188
        for (i = 0; i < num_inputs; i++)
189
            Size[i] = size;
190
 
191
	if (valid_cube_size(num_inputs, num_outputs, sample_size, Size))
192
	    return 0;		/* We have a valid size */
193
 
194
	if (size == 2)		/* Cannot have less than 2 points per side */
195
	    return_error(e_rangecheck);
196
	size--;
197
    }
198
}
199
 
200
 
201
/*
202
 * Allocate the enumerator used while collecting sampled data.  This enumerator
203
 * is used to hold the various state data required while sampling.
204
 */
205
private gs_sampled_data_enum *
206
gs_sampled_data_enum_alloc(gs_memory_t * mem, client_name_t cname)
207
{
208
    return gs_alloc_struct(mem, gs_sampled_data_enum,
209
    				&st_gs_sampled_data_enum, cname);
210
}
211
 
212
/*
213
 * This routine will determine the location of a block of data
214
 * in the hyper cube.  Basically this does an index calculation
215
 * for an n dimensional cube.
216
 */
217
private byte *
218
cube_ptr_from_index(gs_function_Sd_params_t * params, int indexes[])
219
{
220
    int i, sum = indexes[params->m - 1];
221
 
222
    for (i = params->m - 2; i >= 0; i--) {
223
	sum *= params->Size[i];
224
	sum += indexes[i];
225
    }
226
    return (byte *)(params->DataSource.data.str.data) + 
227
	sum * params->n * bits2bytes(params->BitsPerSample);
228
}
229
 
230
/*
231
 * This routine will increment the index values for the hypercube.  This
232
 * is used for collecting the data.  If we have incremented the
233
 * last index beyond its last value then we return a true, else false;
234
 */
235
private bool
236
increment_cube_indexes(gs_function_Sd_params_t * params, int indexes[])
237
{
238
    int i = 0;
239
 
240
    while (true) {
241
	/*
242
	 * Increment an index value for an edge and test if we have
243
	 * gone past the final value for the edge.
244
	 */
245
	indexes[i]++;
246
	if (indexes[i] < params->Size[i])
247
	    /*
248
	     * We have not reached the end of the edge.  Exit but
249
	     * indicate that we are not done with the hypercube.
250
	     */
251
	    return false;
252
	/*
253
	 * We have reached the end of one edge of the hypercube and we
254
	 * need to increment the next index.
255
	 */
256
	indexes[i] = 0;
257
	i++;
258
	if (i == params->m)
259
	    /*
260
	     * We have finished the last edge of the hyper cube.
261
	     * We are done.
262
	     */
263
	    return true;
264
    }
265
}
266
 
267
/*
268
 * Fill in the data for a function type 0 parameter object to be used while
269
 * we collect the data for the data cube.  At the end of the process, we
270
 * will create a function type 0 object to be used to calculate values
271
 * as a replacement for the original function.
272
 */
273
private int
274
cube_build_func0(const ref * pdict, gs_function_Sd_params_t * params,
275
							gs_memory_t *mem)
276
{
277
    byte * bytes = 0;
278
    int code, i;
279
    int total_size;
280
 
281
    if ((code = dict_int_param(pdict, "Order", 1, 3, 1, &params->Order)) < 0 ||
282
	(code = dict_int_param(pdict, "BitsPerSample", 1, 32, 0,
283
			       &params->BitsPerSample)) < 0 ||
284
	((code = params->m =
285
	    fn_build_float_array(pdict, "Domain", false, true,
286
		    			&params->Domain, mem)) < 0 ) ||
287
	((code = params->n =
288
	    fn_build_float_array(pdict, "Range", false, true,
289
		    			&params->Range, mem)) < 0) 
290
	) {
291
	goto fail;
292
    }
293
    /*
294
     * The previous logic set the size of m and n to the size of the Domain
295
     * and Range arrays.  This is twice the actual size.  Correct this and
296
     * check for valid values.
297
     */
298
    params->m >>= 1;
299
    params->n >>= 1;
300
    if (params->m == 0 || params->n == 0 ||
301
        params->m > MAX_NUM_INPUTS || params->n > MAX_NUM_OUTPUTS) {
302
	code = gs_note_error(e_rangecheck);
303
        goto fail;
304
    }
305
    /*
306
     * The Size array may or not be specified.  If it is not specified then
307
     * we need to determine a set of default values for the Size array.
308
     */
309
    {
310
	int *ptr = (int *)
311
	    gs_alloc_byte_array(mem, params->m, sizeof(int), "Size");
312
 
313
	if (ptr == NULL) {
314
	    code = gs_note_error(e_VMerror);
315
	    goto fail;
316
	}
317
	params->Size = ptr;
318
	code = dict_ints_param(pdict, "Size", params->m, ptr);
319
        if (code < 0)
320
	    goto fail;
321
        if (code == 0) {
322
	    /*
323
	     * The Size array has not been specified.  Determine a default
324
	     * set of values.
325
	     */
326
            code = determine_sampled_data_size(params->m, params->n,
327
	     			params->BitsPerSample, (int *)params->Size);
328
            if (code < 0)
329
	        goto fail;
330
        }
331
	else {			/* Size array specified - verify valid */
332
	    if (code != params->m || !valid_cube_size(params->m, params->n,
333
	    				params->BitsPerSample, params->Size))
334
	        code = gs_note_error(e_rangecheck);
335
	        goto fail;
336
	}
337
    }
338
    /*
339
     * Determine space required for the sample data storage.
340
     */
341
    total_size = params->n * bits2bytes(params->BitsPerSample);
342
    for (i = 0; i < params->m; i++)
343
	total_size *= params->Size[i];
344
    /*
345
     * Allocate space for the data cube itself.
346
     */
347
    bytes = gs_alloc_byte_array(mem, total_size, 1, "cube_build_func0(bytes)");
348
    if (!bytes) {
349
	code = gs_note_error(e_VMerror);
350
	goto fail;
351
    }
352
    data_source_init_bytes(&params->DataSource,
353
    				(const unsigned char *)bytes, total_size);
354
 
355
    return 0;
356
 
357
fail:
358
    gs_function_Sd_free_params(params, mem);
359
    return (code < 0 ? code : gs_note_error(e_rangecheck));
360
}
361
 
362
/*
363
 * Layout of stuff pushed on estack while collecting the sampled data.
364
 * The data is saved there since it is safe from attack by the procedure
365
 * being sampled and is convient.
366
 *
367
 *      finishing procedure (or 0)
368
 *      procedure being sampled
369
 *      enumeration structure (as bytes)
370
 */
371
#define estack_storage 3
372
#define esp_finish_proc (*real_opproc(esp - 2))
373
#define sample_proc esp[-1]
374
#define senum r_ptr(esp, gs_sampled_data_enum)
375
/*
376
 * Sone invalid tint transform functions pop more items off of the stack
377
 * then they are supposed to use.  This is a violation of the PLRM however
378
 * this is done by Adobe and we have to handle the situation.  This is
379
 * a kludge but we set aside some unused stack space below the input
380
 * variables.  The tint transform can trash this without causing any
381
 * real problems.
382
 */
383
#define O_STACK_PAD 3
384
 
385
/*
386
 * Set up to collect the data for the sampled function.  This is used for
387
 * those alternate tint transforms that cannot be converted into a
388
 * type 4 function.
389
 */
390
private int
391
sampled_data_setup(i_ctx_t *i_ctx_p, gs_function_t *pfn,
392
	const ref * pproc, int (*finish_proc)(i_ctx_t *), gs_memory_t * mem)
393
{
394
    os_ptr op = osp;
395
    gs_sampled_data_enum *penum;
396
    int i;
397
    gs_function_Sd_params_t * params = (gs_function_Sd_params_t *)&pfn->params;
398
 
399
    check_estack(estack_storage + 1);		/* Verify space on estack */
400
    check_ostack(params->m + O_STACK_PAD);	/* and the operand stack */
401
    check_ostack(params->n + O_STACK_PAD);
402
 
403
    /*
404
     * Allocate space for the enumerator data structure.
405
     */
406
    penum = gs_sampled_data_enum_alloc(imemory, "zbuildsampledfuntion(params)");
407
    if (penum == NULL)
408
	return_error(e_VMerror);
409
 
410
    /* Initialize data in the enumeration structure */
411
 
412
    penum->pfn = pfn;
413
    for(i=0; i< params->m; i++)
414
        penum->indexes[i] = 0;
415
    /*
416
     * Save stack depth for checking the correct number of values on stack
417
     * after the function, which is being sampled, is called.
418
     */
419
    penum->o_stack_depth = ref_stack_count(&o_stack);
420
    /*
421
     * Note:  As previously mentioned, we are putting some spare (unused) stack
422
     * space under the input values in case the function unbalances the stack.
423
     * It is possible for the function to pop or change values on the stack
424
     * outside of the input values.  (This has been found to happen with some
425
     * proc sets from Adobe.)
426
     */
427
    push(O_STACK_PAD);
428
    for (i = 0; i < O_STACK_PAD; i++) 		/* Set space = null */
429
	make_null(op - i);
430
 
431
    /* Push everything on the estack */
432
 
433
    esp += estack_storage;
434
    make_op_estack(esp - 2, finish_proc);	/* Finish proc onto estack */
435
    sample_proc = *pproc;			/* Save function to be sampled */
436
    make_istruct(esp, 0, penum);		/* Color cube enumeration structure */
437
    push_op_estack(sampled_data_sample);	/* Start sampling data */
438
    return o_push_estack;
439
}
440
 
441
/*
442
 * Set up to collect the next sampled data value.
443
 */
444
private int
445
sampled_data_sample(i_ctx_t *i_ctx_p)
446
{
447
    os_ptr op = osp;
448
    gs_sampled_data_enum *penum = senum;
449
    ref proc;
450
    gs_function_Sd_params_t * params =
451
    			(gs_function_Sd_params_t *)&penum->pfn->params;
452
    int num_inputs = params->m;
453
    int i;
454
 
455
    /* Put set of input values onto the stack. */
456
    push(num_inputs);
457
    for (i = 0; i < num_inputs; i++) {
458
	double dmin = params->Domain[2 * i];
459
	double dmax = params->Domain[2 * i + 1];
460
 
461
	make_real(op - num_inputs + i + 1, (float) (
462
	    penum->indexes[i] * (dmax - dmin)/(params->Size[i] - 1) + dmin));
463
    }
464
 
465
    proc = sample_proc;			    /* Get procedure from storage */
466
    push_op_estack(sampled_data_continue);  /* Put 'save' routine on estack, after sample proc */
467
    *++esp = proc;			    /* Put procedure to be executed */
468
    return o_push_estack;
469
}
470
 
471
/* 
472
 * Continuation procedure for processing sampled values.
473
 */
474
private int
475
sampled_data_continue(i_ctx_t *i_ctx_p)
476
{
477
    os_ptr op = osp;
478
    gs_sampled_data_enum *penum = senum;
479
    gs_function_Sd_params_t * params =
480
	    (gs_function_Sd_params_t *)&penum->pfn->params;
481
    int i, j, num_out = params->n;
482
    int code = 0;
483
    byte * data_ptr;
484
    double sampled_data_value_max = (double)((1 << params->BitsPerSample) - 1);
485
    int bps = bits2bytes(params->BitsPerSample);
486
 
487
    /*
488
     * Check to make sure that the procedure produced the correct number of
489
     * values.  If not, move the stack back to where it belongs and abort
490
     */
491
    if (num_out + O_STACK_PAD + penum->o_stack_depth != ref_stack_count(&o_stack)) {
492
	int stack_depth_adjust = ref_stack_count(&o_stack) - penum->o_stack_depth;
493
 
494
	if (stack_depth_adjust >= 0)
495
	    pop(stack_depth_adjust);
496
	else {
497
	    /*
498
	     * If we get to here then there were major problems.  The function
499
	     * removed too many items off of the stack.  We had placed extra
500
	     * (unused) stack stack space to allow for this but the function
501
	     * exceeded even that.  Data on the stack may have been lost.
502
	     * The only thing that we can do is move the stack pointer back and
503
	     * hope.  (We have not seen real Postscript files that have this
504
	     * problem.)
505
	     */
506
	    push(-stack_depth_adjust);
507
	}
508
	ifree_object(penum->pfn, "sampled_data_continue(pfn)");
509
	ifree_object(penum, "sampled_data_continue((enum)");
510
	return_error(e_undefinedresult);
511
    }
512
 
513
    /* Save data from the given function */
514
    data_ptr = cube_ptr_from_index(params, penum->indexes);
515
    for (i=0; i < num_out; i++) {
516
	ulong cv;
517
        double value;
518
	double rmin = params->Range[2 * i];
519
	double rmax = params->Range[2 * i + 1];
520
 
521
        code = real_param(op + i - num_out + 1, &value);
522
        if (code < 0)
523
	    return code;
524
	if (value < rmin)
525
	    value = rmin;
526
	else if (value > rmax)
527
	    value = rmax;
528
	value = (value - rmin) / (rmax - rmin);		/* Convert to 0 to 1.0 */
529
	cv = (int) (value * sampled_data_value_max + 0.5);
530
	for (j = 0; j < bps; j++)
531
	    data_ptr[bps * i + j] = (byte)(cv >> ((bps - 1 - j) * 8));	/* MSB first */
532
    }
533
    pop(num_out);		    /* Move op to base of result values */
534
 
535
    /* Check if we are done collecting data. */
536
 
537
    if (increment_cube_indexes(params, penum->indexes)) {
538
	pop(O_STACK_PAD);	    /* Remove spare stack space */
539
	/* Execute the closing procedure, if given */
540
	code = 0;
541
	if (esp_finish_proc != 0)
542
	    code = esp_finish_proc(i_ctx_p);
543
 
544
	return code;
545
    }
546
 
547
    /* Now get the data for the next location */
548
 
549
    return sampled_data_sample(i_ctx_p);
550
}
551
 
552
/*
553
 * We have collected all of the sample data.  Create a type 0 function stucture.
554
 */
555
private int
556
sampled_data_finish(i_ctx_t *i_ctx_p)
557
{
558
    os_ptr op = osp;
559
    gs_sampled_data_enum *penum = senum;
560
    /* Build a type 0 function using the given parameters */
561
    gs_function_Sd_params_t * params =
562
	(gs_function_Sd_params_t *)&penum->pfn->params;
563
    gs_function_t * pfn;
564
    ref cref;			/* closure */
565
    int code = gs_function_Sd_init(&pfn, params, imemory);
566
 
567
    if (code < 0)
568
	return code;
569
 
570
    code = ialloc_ref_array(&cref, a_executable | a_execute, 2,
571
			    "sampled_data_finish(cref)");
572
    if (code < 0)
573
	return code;
574
 
575
    make_istruct_new(cref.value.refs, a_executable | a_execute, pfn);
576
    make_oper_new(cref.value.refs + 1, 0, zexecfunction);
577
    ref_assign(op, &cref);
578
 
579
    esp -= estack_storage;
580
    ifree_object(penum->pfn, "sampled_data_finish(pfn)");
581
    ifree_object(penum, "sampled_data_finish(enum)");
582
    return o_pop_estack;
583
}
584
 
585
 
586
/* ------ Initialization procedure ------ */
587
 
588
const op_def zfsample_op_defs[] =
589
{
590
    op_def_begin_level2(),
591
    {"1.buildsampledfunction", zbuildsampledfunction},
592
    op_def_end(0)
593
};