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
data_image_params(const gs_memory_t * mem,const ref * op,gs_data_image_t * pim,image_params * pip,bool require_DataSource,int num_components,int max_bits_per_component,bool has_alpha)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
pixel_image_params(i_ctx_t * i_ctx_p,const ref * op,gs_pixel_image_t * pim,image_params * pip,int max_bits_per_component,bool has_alpha)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
zimage_setup(i_ctx_t * i_ctx_p,const gs_pixel_image_t * pim,const ref * sources,bool uses_color,int npop)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
image1_setup(i_ctx_t * i_ctx_p,bool has_alpha)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
zimage1(i_ctx_t * i_ctx_p)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
zimagemask1(i_ctx_t * i_ctx_p)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
zimage_data_setup(i_ctx_t * i_ctx_p,const gs_pixel_image_t * pim,gx_image_enum_common_t * pie,const ref * sources,int npop)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
zimage_pop_estack(es_ptr tep)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
image_proc_continue(i_ctx_t * i_ctx_p)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
image_proc_process(i_ctx_t * i_ctx_p)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
image_file_continue(i_ctx_t * i_ctx_p)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
image_string_continue(i_ctx_t * i_ctx_p)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
image_cleanup(i_ctx_t * i_ctx_p)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 };
573