1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Image operators */
18 #include "math_.h"
19 #include "memory_.h"
20 #include "stat_.h" /* get system header early to avoid name clash on Cygwin */
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 #include "gxcspace.h"
42 
43 /* Forward references */
44 static int zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
45                                  gx_image_enum_common_t * pie,
46                                  const ref * sources, int npop);
47 static int image_proc_process(i_ctx_t *);
48 static int image_file_continue(i_ctx_t *);
49 static int image_string_continue(i_ctx_t *);
50 static int image_cleanup(i_ctx_t *);
51 
52 /* Extract and check the parameters for a gs_data_image_t. */
53 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,bool islab)54 data_image_params(const gs_memory_t *mem,
55                   const ref *op, gs_data_image_t *pim,
56                   image_params *pip, bool require_DataSource,
57                   int num_components, int max_bits_per_component,
58                   bool has_alpha, bool islab)
59 {
60     int code;
61     int decode_size;
62     ref *pds;
63 
64     check_type(*op, t_dictionary);
65     check_dict_read(*op);
66     if ((code = dict_int_param(op, "Width", 0, max_int_in_fixed / 2,
67                                -1, &pim->Width)) < 0 ||
68         (code = dict_int_param(op, "Height", 0, max_int_in_fixed / 2,
69                                -1, &pim->Height)) < 0 ||
70         (code = dict_matrix_param(mem, op, "ImageMatrix",
71                                   &pim->ImageMatrix)) < 0 ||
72         (code = dict_bool_param(op, "MultipleDataSources", false,
73                                 &pip->MultipleDataSources)) < 0 ||
74         (code = dict_int_param(op, "BitsPerComponent", 1,
75                                max_bits_per_component, -1,
76                                &pim->BitsPerComponent)) < 0 ||
77         (code = dict_bool_param(op, "Interpolate", false,
78                                 &pim->Interpolate)) < 0
79         )
80         return code;
81 
82     /* Decode size pulled out of here to catch case of Lab color space which
83        has a 4 entry range.  We also do NOT want to do Lab decoding IF range
84        is the common -128 127 for a and b. Otherwise we end up doing multiple
85        decode operations, since ICC flow will expect encoded data.
86        That is resolved later.  Also discovered that PDF write will stick
87        6 entry range in wich appears to be OK as far as AR is concerned so
88        we have to handle that too. */
89     if (islab) {
90         /* Note that it is possible that only the ab range values are there
91            or the lab values.  I have seen both cases.... */
92         code = decode_size = dict_floats_param(mem, op, "Decode", 4,
93                                                     &pim->Decode[2], NULL);
94         if (code < 0) {
95             /* Try for all three */
96             code = decode_size = dict_floats_param(mem, op, "Decode", 6,
97                                                         &pim->Decode[0], NULL);
98         } else {
99             /* Set the range on the L */
100             pim->Decode[0] = 0;
101             pim->Decode[1] = 100.0;
102         }
103         if (code < 0) return code;
104     } else {
105         code = decode_size = dict_floats_param(mem, op, "Decode",
106                                                     num_components * 2,
107                                                     &pim->Decode[0], NULL);
108         if (code < 0) return code;
109     }
110     pip->pDecode = &pim->Decode[0];
111     /* Extract and check the data sources. */
112     if ((code = dict_find_string(op, "DataSource", &pds)) <= 0) {
113         if (require_DataSource)
114             return (code < 0 ? code : gs_note_error(e_rangecheck));
115         return 1;		/* no data source */
116     }
117     if (pip->MultipleDataSources) {
118         ref *ds = pip->DataSource;
119         long i, n = num_components + (has_alpha ? 1 : 0);
120         if (!r_is_array(pds))
121             return_error(e_typecheck);
122         if (r_size(pds) != n)
123             return_error(e_rangecheck);
124         for (i = 0; i < n; ++i)
125             array_get(mem, pds, i, &ds[i]);
126         if (r_type(&ds[0]) == t_string) {
127             /* We don't have a problem with the strings of different length
128              * but Adobe does and CET tast 12-02.ps reports this as an error.
129              */
130             if (has_alpha)
131                 n--;
132             for (i = 1; i < n; ++i) {
133                 if (r_type(&ds[i]) == t_string && r_size(&ds[i]) != r_size(&ds[0])) {
134                     return_error(e_rangecheck);
135                 }
136             }
137         }
138     } else
139         pip->DataSource[0] = *pds;
140     return 0;
141 }
142 
143 /* Extract and check the parameters for a gs_pixel_image_t. */
144 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,gs_color_space * csp)145 pixel_image_params(i_ctx_t *i_ctx_p, const ref *op, gs_pixel_image_t *pim,
146                    image_params *pip, int max_bits_per_component,
147                    bool has_alpha, gs_color_space *csp)
148 {
149     bool islab = false;
150     int num_components =
151         gs_color_space_num_components(csp);
152     int code;
153 
154     if (num_components < 1)
155         return_error(e_rangecheck);	/* Pattern space not allowed */
156     pim->ColorSpace = csp;
157 
158     if (pim->ColorSpace->cmm_icc_profile_data != NULL)
159         islab = pim->ColorSpace->cmm_icc_profile_data->islab;
160 
161     code = data_image_params(imemory, op, (gs_data_image_t *) pim, pip, true,
162                              num_components, max_bits_per_component,
163                              has_alpha, islab);
164     if (code < 0)
165         return code;
166     pim->format =
167         (pip->MultipleDataSources ? gs_image_format_component_planar :
168          gs_image_format_chunky);
169     return dict_bool_param(op, "CombineWithColor", false,
170                            &pim->CombineWithColor);
171 }
172 
173 /* Common setup for all Level 1 and 2 images, and ImageType 4 images. */
174 int
zimage_setup(i_ctx_t * i_ctx_p,const gs_pixel_image_t * pim,const ref * sources,bool uses_color,int npop)175 zimage_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
176              const ref * sources, bool uses_color, int npop)
177 {
178     gx_image_enum_common_t *pie;
179     int code =
180         gs_image_begin_typed((const gs_image_common_t *)pim, igs,
181                              uses_color, &pie);
182 
183     if (code < 0)
184         return code;
185     return zimage_data_setup(i_ctx_p, (const gs_pixel_image_t *)pim, pie,
186                              sources, npop);
187 }
188 
189 /* Common code for .image1 and .alphaimage operators */
190 int
image1_setup(i_ctx_t * i_ctx_p,bool has_alpha)191 image1_setup(i_ctx_t * i_ctx_p, bool has_alpha)
192 {
193     os_ptr          op = osp;
194     gs_image_t      image;
195     image_params    ip;
196     int             code;
197     gs_color_space *csp = gs_currentcolorspace(igs);
198 
199     /* Adobe interpreters accept sampled images when the current color
200      * space is a pattern color space using the base color space instead
201      * of the pattern space. CET 12-07a-12
202      * If all conditions are not met the pattern color space goes through
203      * triggering a rangecheck error.
204      */
205     if (gs_currentcpsimode(imemory) && gs_color_space_num_components(csp) < 1) {
206        gs_color_space *bsp = csp->base_space;
207        if (bsp)
208          csp = bsp;
209     }
210 
211     gs_image_t_init(&image, csp);
212     code = pixel_image_params( i_ctx_p,
213                                op,
214                                (gs_pixel_image_t *)&image,
215                                &ip,
216                                (level2_enabled ? 16 : 8),
217                                has_alpha, csp);
218     if (code < 0)
219         return code;
220 
221     image.Alpha = (has_alpha ? gs_image_alpha_last : gs_image_alpha_none);
222         /* swap Width, Height, and ImageMatrix so that it comes out the same */
223         /* This is only for performance, so only do it for non-skew cases */
224     if (image.Width == 1 && image.Height > 1 && image.BitsPerComponent == 8 &&
225         image.ImageMatrix.xy == 0.0 && image.ImageMatrix.yx == 0.0 &&
226         image.ImageMatrix.tx == 0.0) {
227         float ftmp;
228         int   itemp;
229 
230         itemp = image.Width;
231         image.Width = image.Height;
232         image.Height = itemp;
233 
234         image.ImageMatrix.xy = image.ImageMatrix.xx;
235         image.ImageMatrix.yx = image.ImageMatrix.yy;
236         image.ImageMatrix.xx = 0.0;
237         image.ImageMatrix.yy = 0.0;
238         ftmp = image.ImageMatrix.tx;
239         image.ImageMatrix.tx = image.ImageMatrix.ty;
240         image.ImageMatrix.ty = ftmp;
241     }
242     return zimage_setup( i_ctx_p,
243                          (gs_pixel_image_t *)&image,
244                          &ip.DataSource[0],
245                          image.CombineWithColor,
246                          1 );
247 }
248 
249 /* <dict> .image1 - */
250 static int
zimage1(i_ctx_t * i_ctx_p)251 zimage1(i_ctx_t *i_ctx_p)
252 {
253     return image1_setup(i_ctx_p, false);
254 }
255 
256 /* <dict> .imagemask1 - */
257 static int
zimagemask1(i_ctx_t * i_ctx_p)258 zimagemask1(i_ctx_t *i_ctx_p)
259 {
260     os_ptr op = osp;
261     gs_image_t image;
262     image_params ip;
263     int code;
264 
265     gs_image_t_init_mask_adjust(&image, false,
266                                 gs_incachedevice(igs) != CACHE_DEVICE_NONE);
267     code = data_image_params(imemory, op, (gs_data_image_t *) & image,
268                              &ip, true, 1, 1, false, false);
269     if (code < 0)
270         return code;
271     return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image, &ip.DataSource[0],
272                         true, 1);
273 }
274 
275 /* Common setup for all Level 1 and 2 images, and ImageType 3 and 4 images. */
276 /*
277  * We push the following on the estack.
278  *      control mark,
279  *	num_sources,
280  *      for I = num_sources-1 ... 0:
281  *          data source I,
282  *          aliasing information:
283  *              if source is not file, 1, except that the topmost value
284  *		  is used for bookkeeping in the procedure case (see below);
285  *              if file is referenced by a total of M different sources and
286  *                this is the occurrence with the lowest I, M;
287  *              otherwise, -J, where J is the lowest I of the same file as
288  *                this one;
289  *      current plane index,
290  *      num_sources,
291  *      enumeration structure.
292  */
293 #define NUM_PUSH(nsource) ((nsource) * 2 + 5)
294 /*
295  * We can access these values either from the bottom (esp at control mark - 1,
296  * EBOT macros) or the top (esp = enumeration structure, ETOP macros).
297  * Note that all macros return pointers.
298  */
299 #define EBOT_NUM_SOURCES(ep) ((ep) + 2)
300 #define EBOT_SOURCE(ep, i)\
301   ((ep) + 3 + (EBOT_NUM_SOURCES(ep)->value.intval - 1 - (i)) * 2)
302 #define ETOP_SOURCE(ep, i)\
303   ((ep) - 4 - (i) * 2)
304 #define ETOP_PLANE_INDEX(ep) ((ep) - 2)
305 #define ETOP_NUM_SOURCES(ep) ((ep) - 1)
306 static 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)307 zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
308                   gx_image_enum_common_t * pie, const ref * sources, int npop)
309 {
310     int num_sources = pie->num_planes;
311     int inumpush = NUM_PUSH(num_sources);
312     int code;
313     gs_image_enum *penum;
314     int px;
315     const ref *pp;
316     bool string_sources = true;
317 
318     check_estack(inumpush + 2);	/* stuff above, + continuation + proc */
319     make_int(EBOT_NUM_SOURCES(esp), num_sources);
320     /*
321      * Note that the data sources may be procedures, strings, or (Level
322      * 2 only) files.  (The Level 1 reference manual says that Level 1
323      * requires procedures, but Adobe Level 1 interpreters also accept
324      * strings.)  The sources must all be of the same type.
325      *
326      * The Adobe documentation explicitly says that if two or more of the
327      * data sources are the same or inter-dependent files, the result is not
328      * defined.  We don't have a problem with the bookkeeping for
329      * inter-dependent files, since each one has its own buffer, but we do
330      * have to be careful if two or more sources are actually the same file.
331      * That is the reason for the aliasing information described above.
332      */
333     for (px = 0, pp = sources; px < num_sources; px++, pp++) {
334         es_ptr ep = EBOT_SOURCE(esp, px);
335 
336         make_int(ep + 1, 1);	/* default is no aliasing */
337         switch (r_type(pp)) {
338             case t_file:
339                 if (!level2_enabled)
340                     return_error(e_typecheck);
341                 /* Check for aliasing. */
342                 {
343                     int pi;
344 
345                     for (pi = 0; pi < px; ++pi)
346                         if (sources[pi].value.pfile == pp->value.pfile) {
347                             /* Record aliasing */
348                             make_int(ep + 1, -pi);
349                             EBOT_SOURCE(esp, pi)[1].value.intval++;
350                             break;
351                         }
352                 }
353                 string_sources = false;
354                 /* falls through */
355             case t_string:
356                 if (r_type(pp) != r_type(sources)) {
357                     gx_image_end(pie, false);    /* Clean up pie */
358                     return_error(e_typecheck);
359                 }
360                 check_read(*pp);
361                 break;
362             default:
363                 if (!r_is_proc(sources)) {
364                     static const char ds[] = "DataSource";
365                     gx_image_end(pie, false);    /* Clean up pie */
366                     gs_errorinfo_put_pair(i_ctx_p, ds, sizeof(ds) - 1, pp);
367                     return_error(e_typecheck);
368                 }
369                 check_proc(*pp);
370                 string_sources = false;
371         }
372         *ep = *pp;
373     }
374     /* Always place the image enumerator into local memory,
375        because pie may have local objects inherited from igs,
376        which may be local when the current allocation mode is global.
377        Bug 688140. */
378     if ((penum = gs_image_enum_alloc(imemory_local, "image_setup")) == 0)
379         return_error(e_VMerror);
380     code = gs_image_enum_init(penum, pie, (const gs_data_image_t *)pim, igs);
381     if (code != 0 || (pie->skipping && string_sources)) {		/* error, or empty image */
382         int code1 = gs_image_cleanup_and_free_enum(penum, igs);
383 
384         if (code >= 0)		/* empty image */
385             pop(npop);
386         if (code >= 0 && code1 < 0)
387             code = code1;
388         return code;
389     }
390     push_mark_estack(es_other, image_cleanup);
391     esp += inumpush - 1;
392     make_int(ETOP_PLANE_INDEX(esp), 0);
393     make_int(ETOP_NUM_SOURCES(esp), num_sources);
394     make_struct(esp, avm_local, penum);
395     switch (r_type(sources)) {
396         case t_file:
397             push_op_estack(image_file_continue);
398             break;
399         case t_string:
400             push_op_estack(image_string_continue);
401             break;
402         default:		/* procedure */
403             push_op_estack(image_proc_process);
404             break;
405     }
406     pop(npop);
407     return o_push_estack;
408 }
409 /* Pop all the control information off the e-stack. */
410 static es_ptr
zimage_pop_estack(es_ptr tep)411 zimage_pop_estack(es_ptr tep)
412 {
413     return tep - NUM_PUSH(ETOP_NUM_SOURCES(tep)->value.intval);
414 }
415 
416 /*
417  * Continuation for procedure data source.  We use the topmost aliasing slot
418  * to remember whether we've just called the procedure (1) or whether we're
419  * returning from a RemapColor callout (0).
420  */
421 static int
image_proc_continue(i_ctx_t * i_ctx_p)422 image_proc_continue(i_ctx_t *i_ctx_p)
423 {
424     os_ptr op = osp;
425     gs_image_enum *penum = r_ptr(esp, gs_image_enum);
426     int px = ETOP_PLANE_INDEX(esp)->value.intval;
427     int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
428     uint size, used[GS_IMAGE_MAX_COMPONENTS];
429     gs_const_string plane_data[GS_IMAGE_MAX_COMPONENTS];
430     const byte *wanted;
431     int i, code;
432 
433     if (!r_has_type_attrs(op, t_string, a_read)) {
434         check_op(1);
435         /* Procedure didn't return a (readable) string.  Quit. */
436         esp = zimage_pop_estack(esp);
437         image_cleanup(i_ctx_p);
438         return_error(!r_has_type(op, t_string) ? e_typecheck : e_invalidaccess);
439     }
440     size = r_size(op);
441     if (size == 0 && ETOP_SOURCE(esp, 0)[1].value.intval == 0)
442         code = 1;
443     else {
444         for (i = 0; i < num_sources; i++)
445             plane_data[i].size = 0;
446         plane_data[px].data = op->value.bytes;
447         plane_data[px].size = size;
448         code = gs_image_next_planes(penum, plane_data, used);
449         if (code == e_RemapColor) {
450             op->value.bytes += used[px]; /* skip used data */
451             r_dec_size(op, used[px]);
452             ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* RemapColor callout */
453             return code;
454         }
455     }
456     if (code) {			/* Stop now. */
457         esp = zimage_pop_estack(esp);
458         pop(1);
459         image_cleanup(i_ctx_p);
460         return (code < 0 ? code : o_pop_estack);
461     }
462     pop(1);
463     wanted = gs_image_planes_wanted(penum);
464     do {
465         if (++px == num_sources)
466             px = 0;
467     } while (!wanted[px]);
468     ETOP_PLANE_INDEX(esp)->value.intval = px;
469     return image_proc_process(i_ctx_p);
470 }
471 static int
image_proc_process(i_ctx_t * i_ctx_p)472 image_proc_process(i_ctx_t *i_ctx_p)
473 {
474     int px = ETOP_PLANE_INDEX(esp)->value.intval;
475     gs_image_enum *penum = r_ptr(esp, gs_image_enum);
476     const byte *wanted = gs_image_planes_wanted(penum);
477     int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
478     const ref *pp;
479 
480     ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* procedure callout */
481     while (!wanted[px]) {
482         if (++px == num_sources)
483             px = 0;
484         ETOP_PLANE_INDEX(esp)->value.intval = px;
485     }
486     pp = ETOP_SOURCE(esp, px);
487     push_op_estack(image_proc_continue);
488     *++esp = *pp;
489     return o_push_estack;
490 }
491 
492 /* Continue processing data from an image with file data sources. */
493 static int
image_file_continue(i_ctx_t * i_ctx_p)494 image_file_continue(i_ctx_t *i_ctx_p)
495 {
496     gs_image_enum *penum = r_ptr(esp, gs_image_enum);
497     int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
498 
499     for (;;) {
500         uint min_avail = max_int;
501         gs_const_string plane_data[GS_IMAGE_MAX_COMPONENTS];
502         int code;
503         int px;
504         const ref *pp;
505         int at_eof_count = 0;
506         int total_used;
507 
508         /*
509          * Do a first pass through the files to ensure that at least
510          * one has data available in its buffer.
511          */
512 
513         for (px = 0, pp = ETOP_SOURCE(esp, 0); px < num_sources;
514              ++px, pp -= 2
515             ) {
516             int num_aliases = pp[1].value.intval;
517             stream *s = pp->value.pfile;
518             int min_left;
519             uint avail;
520 
521             if (num_aliases <= 0)
522                 num_aliases = ETOP_SOURCE(esp, -num_aliases)[1].value.intval;
523             while ((avail = sbufavailable(s)) <=
524                    (min_left = sbuf_min_left(s)) + num_aliases - 1) {
525                 int next = s->end_status;
526 
527                 switch (next) {
528                 case 0:
529                     s_process_read_buf(s);
530                     continue;
531                 case EOFC:
532                     at_eof_count++;
533                     break;	/* with no data available */
534                 case INTC:
535                 case CALLC:
536                     return
537                         s_handle_read_exception(i_ctx_p, next, pp,
538                                                 NULL, 0, image_file_continue);
539                 default:
540                     /* case ERRC: */
541                     return_error(e_ioerror);
542                 }
543                 break;		/* for EOFC */
544             }
545             /*
546              * Note that in the EOF case, we can get here with no data
547              * available.
548              */
549             if (avail >= min_left)
550                 avail = (avail - min_left) / num_aliases; /* may be 0 */
551             if (avail < min_avail)
552                 min_avail = avail;
553             plane_data[px].data = sbufptr(s);
554             plane_data[px].size = avail;
555         }
556 
557         /*
558          * Now pass the available buffered data to the image processor.
559          * Even if there is no available data, we must call
560          * gs_image_next_planes one more time to finish processing any
561          * retained data.
562          */
563 
564         {
565             int pi;
566             uint used[GS_IMAGE_MAX_COMPONENTS];
567 
568             code = gs_image_next_planes(penum, plane_data, used);
569             /* Now that used has been set, update the streams. */
570             total_used = 0;
571             for (pi = 0, pp = ETOP_SOURCE(esp, 0); pi < num_sources;
572                  ++pi, pp -= 2 ) {
573                 sbufskip(pp->value.pfile, used[pi]);
574                 total_used += used[pi];
575             }
576             if (code == e_RemapColor)
577                 return code;
578         }
579         if (at_eof_count >= num_sources || (at_eof_count && total_used == 0))
580             code = 1;
581         if (code) {
582             int code1;
583 
584             esp = zimage_pop_estack(esp);
585             code1 = image_cleanup(i_ctx_p);
586             return (code < 0 ? code : code1 < 0 ? code1 : o_pop_estack);
587         }
588     }
589 }
590 
591 /* Process data from an image with string data sources. */
592 /* This may still encounter a RemapColor callback. */
593 static int
image_string_continue(i_ctx_t * i_ctx_p)594 image_string_continue(i_ctx_t *i_ctx_p)
595 {
596     gs_image_enum *penum = r_ptr(esp, gs_image_enum);
597     int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
598     gs_const_string sources[GS_IMAGE_MAX_COMPONENTS];
599     uint used[GS_IMAGE_MAX_COMPONENTS];
600 
601     /* Pass no data initially, to find out how much is retained. */
602     memset(sources, 0, sizeof(sources[0]) * num_sources);
603     for (;;) {
604         int px;
605         int code = gs_image_next_planes(penum, sources, used);
606 
607         if (code == e_RemapColor)
608             return code;
609     stop_now:
610         if (code) {		/* Stop now. */
611             esp -= NUM_PUSH(num_sources);
612             image_cleanup(i_ctx_p);
613             return (code < 0 ? code : o_pop_estack);
614         }
615         for (px = 0; px < num_sources; ++px)
616             if (sources[px].size == 0) {
617                 const ref *psrc = ETOP_SOURCE(esp, px);
618                 uint size = r_size(psrc);
619 
620                 if (size == 0) {	    /* empty source */
621                     code = 1;
622                     goto stop_now;
623                 }
624                 sources[px].data = psrc->value.bytes;
625                 sources[px].size = size;
626             }
627     }
628 }
629 
630 /* Clean up after enumerating an image */
631 static int
image_cleanup(i_ctx_t * i_ctx_p)632 image_cleanup(i_ctx_t *i_ctx_p)
633 {
634     es_ptr ep_top = esp + NUM_PUSH(EBOT_NUM_SOURCES(esp)->value.intval);
635     gs_image_enum *penum = r_ptr(ep_top, gs_image_enum);
636 
637     return gs_image_cleanup_and_free_enum(penum, igs);
638 }
639 
640 /* ------ Initialization procedure ------ */
641 
642 const op_def zimage_op_defs[] =
643 {
644     {"1.image1", zimage1},
645     {"1.imagemask1", zimagemask1},
646                 /* Internal operators */
647     {"1%image_proc_continue", image_proc_continue},
648     {"0%image_file_continue", image_file_continue},
649     {"0%image_string_continue", image_string_continue},
650     op_def_end(0)
651 };
652