Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999, 2000 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: zimage.c,v 1.15 2005/06/15 18:40:08 igor Exp $ */
18
/* Image operators */
19
#include "math_.h"
20
#include "memory_.h"
21
#include "ghost.h"
22
#include "oper.h"
23
#include "gscolor.h"
24
#include "gscspace.h"
25
#include "gscolor2.h"
26
#include "gsmatrix.h"
27
#include "gsimage.h"
28
#include "gxfixed.h"
29
#include "gsstruct.h"
30
#include "gxiparam.h"
31
#include "idict.h"
32
#include "idparam.h"
33
#include "estack.h"		/* for image[mask] */
34
#include "ialloc.h"
35
#include "igstate.h"
36
#include "ilevel.h"
37
#include "store.h"
38
#include "stream.h"
39
#include "ifilter.h"		/* for stream exception handling */
40
#include "iimage.h"
41
 
42
/* Forward references */
43
private int zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
44
				 gx_image_enum_common_t * pie,
45
				 const ref * sources, int npop);
46
private int image_proc_process(i_ctx_t *);
47
private int image_file_continue(i_ctx_t *);
48
private int image_string_continue(i_ctx_t *);
49
private int image_cleanup(i_ctx_t *);
50
 
51
 
52
 
53
/* Extract and check the parameters for a gs_data_image_t. */
54
int
55
data_image_params(const gs_memory_t *mem, 
56
		  const ref *op, gs_data_image_t *pim,
57
		  image_params *pip, bool require_DataSource,
58
		  int num_components, int max_bits_per_component,
59
		  bool has_alpha)
60
{
61
    int code;
62
    int decode_size;
63
    ref *pds;
64
 
65
    check_type(*op, t_dictionary);
66
    check_dict_read(*op);
67
    if ((code = dict_int_param(op, "Width", 0, max_int_in_fixed / 2,
68
			       -1, &pim->Width)) < 0 ||
69
	(code = dict_int_param(op, "Height", 0, max_int_in_fixed / 2,
70
			       -1, &pim->Height)) < 0 ||
71
	(code = dict_matrix_param(mem, op, "ImageMatrix",
72
				  &pim->ImageMatrix)) < 0 ||
73
	(code = dict_bool_param(op, "MultipleDataSources", false,
74
				&pip->MultipleDataSources)) < 0 ||
75
	(code = dict_int_param(op, "BitsPerComponent", 1,
76
			       max_bits_per_component, -1,
77
			       &pim->BitsPerComponent)) < 0 ||
78
	(code = decode_size = dict_floats_param(mem, op, "Decode",
79
						num_components * 2,
80
						&pim->Decode[0], NULL)) < 0 ||
81
	(code = dict_bool_param(op, "Interpolate", false,
82
				&pim->Interpolate)) < 0
83
	)
84
	return code;
85
    pip->pDecode = &pim->Decode[0];
86
    /* Extract and check the data sources. */
87
    if ((code = dict_find_string(op, "DataSource", &pds)) <= 0) {
88
	if (require_DataSource)
89
	    return (code < 0 ? code : gs_note_error(e_rangecheck));
90
	return 1;		/* no data source */
91
    }
92
    if (pip->MultipleDataSources) {
93
	long i, n = num_components + (has_alpha ? 1 : 0);
94
        if (!r_is_array(pds))
95
            return_error(e_typecheck);
96
	if (r_size(pds) != n)
97
	    return_error(e_rangecheck);
98
	for (i = 0; i < n; ++i)
99
	    array_get(mem, pds, i, &pip->DataSource[i]);
100
    } else
101
	pip->DataSource[0] = *pds;
102
    return 0;
103
}
104
 
105
/* Extract and check the parameters for a gs_pixel_image_t. */
106
int
107
pixel_image_params(i_ctx_t *i_ctx_p, const ref *op, gs_pixel_image_t *pim,
108
		   image_params *pip, int max_bits_per_component,
109
		   bool has_alpha)
110
{
111
    int num_components =
112
	gs_color_space_num_components(gs_currentcolorspace(igs));
113
    int code;
114
 
115
    if (num_components < 1)
116
	return_error(e_rangecheck);	/* Pattern space not allowed */
117
    pim->ColorSpace = gs_currentcolorspace(igs);
118
    code = data_image_params(imemory, op, (gs_data_image_t *) pim, pip, true,
119
			     num_components, max_bits_per_component,
120
			     has_alpha);
121
    if (code < 0)
122
	return code;
123
    pim->format =
124
	(pip->MultipleDataSources ? gs_image_format_component_planar :
125
	 gs_image_format_chunky);
126
    return dict_bool_param(op, "CombineWithColor", false,
127
			   &pim->CombineWithColor);
128
}
129
 
130
/* Common setup for all Level 1 and 2 images, and ImageType 4 images. */
131
int
132
zimage_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
133
	     const ref * sources, bool uses_color, int npop)
134
{
135
    gx_image_enum_common_t *pie;
136
    int code =
137
	gs_image_begin_typed((const gs_image_common_t *)pim, igs,
138
			     uses_color, &pie);
139
 
140
    if (code < 0)
141
	return code;
142
    return zimage_data_setup(i_ctx_p, (const gs_pixel_image_t *)pim, pie,
143
			     sources, npop);
144
}
145
 
146
/* Common code for .image1 and .alphaimage operators */
147
int
148
image1_setup(i_ctx_t * i_ctx_p, bool has_alpha)
149
{
150
    os_ptr          op = osp;
151
    gs_image_t      image;
152
    image_params    ip;
153
    int             code;
154
 
155
    gs_image_t_init(&image, gs_currentcolorspace(igs));
156
    code = pixel_image_params( i_ctx_p,
157
                               op,
158
                               (gs_pixel_image_t *)&image,
159
                               &ip,
160
			       (level2_enabled ? 16 : 8),
161
                               has_alpha );
162
    if (code < 0)
163
	return code;
164
 
165
    image.Alpha = (has_alpha ? gs_image_alpha_last : gs_image_alpha_none);
166
    return zimage_setup( i_ctx_p,
167
                         (gs_pixel_image_t *)&image,
168
                         &ip.DataSource[0],
169
			 image.CombineWithColor,
170
                         1 );
171
}
172
 
173
/* <dict> .image1 - */
174
private int
175
zimage1(i_ctx_t *i_ctx_p)
176
{
177
    return image1_setup(i_ctx_p, false);
178
}
179
 
180
/* <dict> .imagemask1 - */
181
private int
182
zimagemask1(i_ctx_t *i_ctx_p)
183
{
184
    os_ptr op = osp;
185
    gs_image_t image;
186
    image_params ip;
187
    int code;
188
 
189
    gs_image_t_init_mask_adjust(&image, false,
190
				gs_incachedevice(igs) != CACHE_DEVICE_NONE);
191
    code = data_image_params(imemory, op, (gs_data_image_t *) & image,
192
			     &ip, true, 1, 1, false);
193
    if (code < 0)
194
	return code;
195
    if (ip.MultipleDataSources)
196
	return_error(e_rangecheck);
197
    return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image, &ip.DataSource[0],
198
			true, 1);
199
}
200
 
201
 
202
/* Common setup for all Level 1 and 2 images, and ImageType 3 and 4 images. */
203
/*
204
 * We push the following on the estack.
205
 *      control mark,
206
 *	num_sources,
207
 *      for I = num_sources-1 ... 0:
208
 *          data source I,
209
 *          aliasing information:
210
 *              if source is not file, 1, except that the topmost value
211
 *		  is used for bookkeeping in the procedure case (see below);
212
 *              if file is referenced by a total of M different sources and
213
 *                this is the occurrence with the lowest I, M;
214
 *              otherwise, -J, where J is the lowest I of the same file as
215
 *                this one;
216
 *      current plane index,
217
 *      num_sources,
218
 *      enumeration structure.
219
 */
220
#define NUM_PUSH(nsource) ((nsource) * 2 + 5)
221
/*
222
 * We can access these values either from the bottom (esp at control mark - 1,
223
 * EBOT macros) or the top (esp = enumeration structure, ETOP macros).
224
 * Note that all macros return pointers.
225
 */
226
#define EBOT_NUM_SOURCES(ep) ((ep) + 2)
227
#define EBOT_SOURCE(ep, i)\
228
  ((ep) + 3 + (EBOT_NUM_SOURCES(ep)->value.intval - 1 - (i)) * 2)
229
#define ETOP_SOURCE(ep, i)\
230
  ((ep) - 4 - (i) * 2)
231
#define ETOP_PLANE_INDEX(ep) ((ep) - 2)
232
#define ETOP_NUM_SOURCES(ep) ((ep) - 1)
233
private int
234
zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
235
		  gx_image_enum_common_t * pie, const ref * sources, int npop)
236
{
237
    int num_sources = pie->num_planes;
238
    int inumpush = NUM_PUSH(num_sources);
239
    int code;
240
    gs_image_enum *penum;
241
    int px;
242
    const ref *pp;
243
 
244
    check_estack(inumpush + 2);	/* stuff above, + continuation + proc */
245
    make_int(EBOT_NUM_SOURCES(esp), num_sources);
246
    /*
247
     * Note that the data sources may be procedures, strings, or (Level
248
     * 2 only) files.  (The Level 1 reference manual says that Level 1
249
     * requires procedures, but Adobe Level 1 interpreters also accept
250
     * strings.)  The sources must all be of the same type.
251
     *
252
     * The Adobe documentation explicitly says that if two or more of the
253
     * data sources are the same or inter-dependent files, the result is not
254
     * defined.  We don't have a problem with the bookkeeping for
255
     * inter-dependent files, since each one has its own buffer, but we do
256
     * have to be careful if two or more sources are actually the same file.
257
     * That is the reason for the aliasing information described above.
258
     */
259
    for (px = 0, pp = sources; px < num_sources; px++, pp++) {
260
	es_ptr ep = EBOT_SOURCE(esp, px);
261
 
262
	make_int(ep + 1, 1);	/* default is no aliasing */
263
	switch (r_type(pp)) {
264
	    case t_file:
265
		if (!level2_enabled)
266
		    return_error(e_typecheck);
267
		/* Check for aliasing. */
268
		{
269
		    int pi;
270
 
271
		    for (pi = 0; pi < px; ++pi)
272
			if (sources[pi].value.pfile == pp->value.pfile) {
273
			    /* Record aliasing */
274
			    make_int(ep + 1, -pi);
275
			    EBOT_SOURCE(esp, pi)[1].value.intval++;
276
			    break;
277
			}
278
		}
279
		/* falls through */
280
	    case t_string:
281
		if (r_type(pp) != r_type(sources)) {
282
    		    if (pie != NULL)
283
		        gx_image_end(pie, false);    /* Clean up pie */
284
		    return_error(e_typecheck);
285
		}
286
		check_read(*pp);
287
		break;
288
	    default:
289
		if (!r_is_proc(sources)) {
290
    		    if (pie != NULL)
291
		        gx_image_end(pie, false);    /* Clean up pie */
292
		    return_error(e_typecheck);
293
		}
294
		check_proc(*pp);
295
	}
296
	*ep = *pp;
297
    }
298
    /* Always place the image enumerator into local memory,
299
       because pie may have local objects inherited from igs,
300
       which may be local when the current allocation mode is global. 
301
       Bug 688140. */
302
    if ((penum = gs_image_enum_alloc(imemory_local, "image_setup")) == 0)
303
	return_error(e_VMerror);
304
    code = gs_image_enum_init(penum, pie, (const gs_data_image_t *)pim, igs);
305
    if (code != 0) {		/* error, or empty image */
306
	int code1 = gs_image_cleanup_and_free_enum(penum);
307
 
308
	if (code >= 0)		/* empty image */
309
	    pop(npop);
310
	if (code >= 0 && code1 < 0)
311
	    code = code1;
312
	return code;
313
    }
314
    push_mark_estack(es_other, image_cleanup);
315
    esp += inumpush - 1;
316
    make_int(ETOP_PLANE_INDEX(esp), 0);
317
    make_int(ETOP_NUM_SOURCES(esp), num_sources);
318
    make_struct(esp, avm_local, penum);
319
    switch (r_type(sources)) {
320
	case t_file:
321
	    push_op_estack(image_file_continue);
322
	    break;
323
	case t_string:
324
	    push_op_estack(image_string_continue);
325
	    break;
326
	default:		/* procedure */
327
	    push_op_estack(image_proc_process);
328
	    break;
329
    }
330
    pop(npop);
331
    return o_push_estack;
332
}
333
/* Pop all the control information off the e-stack. */
334
private es_ptr
335
zimage_pop_estack(es_ptr tep)
336
{
337
    return tep - NUM_PUSH(ETOP_NUM_SOURCES(tep)->value.intval);
338
}
339
 
340
/*
341
 * Continuation for procedure data source.  We use the topmost aliasing slot
342
 * to remember whether we've just called the procedure (1) or whether we're
343
 * returning from a RemapColor callout (0).
344
 */
345
private int
346
image_proc_continue(i_ctx_t *i_ctx_p)
347
{
348
    os_ptr op = osp;
349
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
350
    int px = ETOP_PLANE_INDEX(esp)->value.intval;
351
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
352
    uint size, used[gs_image_max_planes];
353
    gs_const_string plane_data[gs_image_max_planes];
354
    const byte *wanted;
355
    int i, code;
356
 
357
    if (!r_has_type_attrs(op, t_string, a_read)) {
358
	check_op(1);
359
	/* Procedure didn't return a (readable) string.  Quit. */
360
	esp = zimage_pop_estack(esp);
361
	image_cleanup(i_ctx_p);
362
	return_error(!r_has_type(op, t_string) ? e_typecheck : e_invalidaccess);
363
    }
364
    size = r_size(op);
365
    if (size == 0 && ETOP_SOURCE(esp, 0)[1].value.intval == 0)
366
	code = 1;
367
    else {
368
	for (i = 0; i < num_sources; i++)
369
	    plane_data[i].size = 0;
370
	plane_data[px].data = op->value.bytes;
371
	plane_data[px].size = size;
372
	code = gs_image_next_planes(penum, plane_data, used);
373
	if (code == e_RemapColor) {
374
	    op->value.bytes += used[px]; /* skip used data */
375
	    r_dec_size(op, used[px]);
376
	    ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* RemapColor callout */
377
	    return code;
378
	}
379
    }
380
    if (code) {			/* Stop now. */
381
	esp = zimage_pop_estack(esp);
382
	pop(1);
383
	image_cleanup(i_ctx_p);
384
	return (code < 0 ? code : o_pop_estack);
385
    }
386
    pop(1);
387
    wanted = gs_image_planes_wanted(penum);
388
    do {
389
	if (++px == num_sources)
390
	    px = 0;
391
    } while (!wanted[px]);
392
    ETOP_PLANE_INDEX(esp)->value.intval = px;
393
    return image_proc_process(i_ctx_p);
394
}
395
private int
396
image_proc_process(i_ctx_t *i_ctx_p)
397
{
398
    int px = ETOP_PLANE_INDEX(esp)->value.intval;
399
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
400
    const byte *wanted = gs_image_planes_wanted(penum);
401
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
402
    const ref *pp;
403
 
404
    ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* procedure callout */
405
    while (!wanted[px]) {
406
	if (++px == num_sources)
407
	    px = 0;
408
	ETOP_PLANE_INDEX(esp)->value.intval = px;
409
    }
410
    pp = ETOP_SOURCE(esp, px);
411
    push_op_estack(image_proc_continue);
412
    *++esp = *pp;
413
    return o_push_estack;
414
}
415
 
416
/* Continue processing data from an image with file data sources. */
417
private int
418
image_file_continue(i_ctx_t *i_ctx_p)
419
{
420
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
421
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
422
 
423
    for (;;) {
424
	uint min_avail = max_int;
425
	gs_const_string plane_data[gs_image_max_planes];
426
	int code;
427
	int px;
428
	const ref *pp;
429
	bool at_eof = false;
430
 
431
	/*
432
	 * Do a first pass through the files to ensure that at least
433
	 * one has data available in its buffer.
434
	 */
435
 
436
	for (px = 0, pp = ETOP_SOURCE(esp, 0); px < num_sources;
437
	     ++px, pp -= 2
438
	    ) {
439
	    int num_aliases = pp[1].value.intval;
440
	    stream *s = pp->value.pfile;
441
	    int min_left;
442
	    uint avail;
443
 
444
	    if (num_aliases <= 0)
445
		num_aliases = ETOP_SOURCE(esp, -num_aliases)[1].value.intval;
446
	    while ((avail = sbufavailable(s)) <=
447
		   (min_left = sbuf_min_left(s)) + num_aliases - 1) {
448
		int next = s->end_status;
449
 
450
		switch (next) {
451
		case 0:
452
		    s_process_read_buf(s);
453
		    continue;
454
		case EOFC:
455
		    at_eof = true;
456
		    break;	/* with no data available */
457
		case INTC:
458
		case CALLC:
459
		    return
460
			s_handle_read_exception(i_ctx_p, next, pp,
461
						NULL, 0, image_file_continue);
462
		default:
463
		    /* case ERRC: */
464
		    return_error(e_ioerror);
465
		}
466
		break;		/* for EOFC */
467
	    }
468
	    /*
469
	     * Note that in the EOF case, we can get here with no data
470
	     * available.
471
	     */
472
	    if (avail >= min_left)
473
		avail = (avail - min_left) / num_aliases; /* may be 0 */
474
	    if (avail < min_avail)
475
		min_avail = avail;
476
	    plane_data[px].data = sbufptr(s);
477
	    plane_data[px].size = avail;
478
	}
479
 
480
	/*
481
	 * Now pass the available buffered data to the image processor.
482
	 * Even if there is no available data, we must call
483
	 * gs_image_next_planes one more time to finish processing any
484
	 * retained data.
485
	 */
486
 
487
	{
488
	    int pi;
489
	    uint used[gs_image_max_planes];
490
 
491
	    code = gs_image_next_planes(penum, plane_data, used);
492
	    /* Now that used has been set, update the streams. */
493
	    for (pi = 0, pp = ETOP_SOURCE(esp, 0); pi < num_sources;
494
		 ++pi, pp -= 2
495
		 )
496
		sbufskip(pp->value.pfile, used[pi]);
497
	    if (code == e_RemapColor)
498
		return code;
499
	}
500
	if (at_eof)
501
	    code = 1;
502
	if (code) {
503
	    int code1;
504
 
505
	    esp = zimage_pop_estack(esp);
506
	    code1 = image_cleanup(i_ctx_p);
507
	    return (code < 0 ? code : code1 < 0 ? code1 : o_pop_estack);
508
	}
509
    }
510
}
511
 
512
/* Process data from an image with string data sources. */
513
/* This may still encounter a RemapColor callback. */
514
private int
515
image_string_continue(i_ctx_t *i_ctx_p)
516
{
517
    gs_image_enum *penum = r_ptr(esp, gs_image_enum);
518
    int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
519
    gs_const_string sources[gs_image_max_planes];
520
    uint used[gs_image_max_planes];
521
 
522
    /* Pass no data initially, to find out how much is retained. */
523
    memset(sources, 0, sizeof(sources[0]) * num_sources);
524
    for (;;) {
525
	int px;
526
	int code = gs_image_next_planes(penum, sources, used);
527
 
528
	if (code == e_RemapColor)
529
	    return code;
530
    stop_now:
531
	if (code) {		/* Stop now. */
532
	    esp -= NUM_PUSH(num_sources);
533
	    image_cleanup(i_ctx_p);
534
	    return (code < 0 ? code : o_pop_estack);
535
	}
536
	for (px = 0; px < num_sources; ++px)
537
	    if (sources[px].size == 0) {
538
		const ref *psrc = ETOP_SOURCE(esp, px);
539
		uint size = r_size(psrc);
540
 
541
		if (size == 0) {	    /* empty source */
542
		    code = 1;
543
		    goto stop_now;
544
                }
545
		sources[px].data = psrc->value.bytes;
546
		sources[px].size = size;
547
	    }
548
    }
549
}
550
 
551
/* Clean up after enumerating an image */
552
private int
553
image_cleanup(i_ctx_t *i_ctx_p)
554
{
555
    es_ptr ep_top = esp + NUM_PUSH(EBOT_NUM_SOURCES(esp)->value.intval);
556
    gs_image_enum *penum = r_ptr(ep_top, gs_image_enum);
557
 
558
    return gs_image_cleanup_and_free_enum(penum);
559
}
560
 
561
/* ------ Initialization procedure ------ */
562
 
563
const op_def zimage_op_defs[] =
564
{
565
    {"1.image1", zimage1},
566
    {"1.imagemask1", zimagemask1},
567
		/* Internal operators */
568
    {"1%image_proc_continue", image_proc_continue},
569
    {"0%image_file_continue", image_file_continue},
570
    {"0%image_string_continue", image_string_continue},
571
    op_def_end(0)
572
};