17dd7cddfSDavid du Colombier /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999, 2000 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: zimage.c,v 1.15 2005/06/15 18:40:08 igor Exp $ */
187dd7cddfSDavid du Colombier /* Image operators */
19*593dc095SDavid du Colombier #include "math_.h"
207dd7cddfSDavid du Colombier #include "memory_.h"
217dd7cddfSDavid du Colombier #include "ghost.h"
227dd7cddfSDavid du Colombier #include "oper.h"
23*593dc095SDavid du Colombier #include "gscolor.h"
24*593dc095SDavid du Colombier #include "gscspace.h"
25*593dc095SDavid du Colombier #include "gscolor2.h"
26*593dc095SDavid du Colombier #include "gsmatrix.h"
27*593dc095SDavid du Colombier #include "gsimage.h"
28*593dc095SDavid du Colombier #include "gxfixed.h"
297dd7cddfSDavid du Colombier #include "gsstruct.h"
30*593dc095SDavid du Colombier #include "gxiparam.h"
31*593dc095SDavid du Colombier #include "idict.h"
32*593dc095SDavid du Colombier #include "idparam.h"
33*593dc095SDavid du Colombier #include "estack.h" /* for image[mask] */
347dd7cddfSDavid du Colombier #include "ialloc.h"
357dd7cddfSDavid du Colombier #include "igstate.h"
367dd7cddfSDavid du Colombier #include "ilevel.h"
377dd7cddfSDavid du Colombier #include "store.h"
387dd7cddfSDavid du Colombier #include "stream.h"
397dd7cddfSDavid du Colombier #include "ifilter.h" /* for stream exception handling */
407dd7cddfSDavid du Colombier #include "iimage.h"
417dd7cddfSDavid du Colombier
427dd7cddfSDavid du Colombier /* Forward references */
43*593dc095SDavid du Colombier private int zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
44*593dc095SDavid du Colombier gx_image_enum_common_t * pie,
45*593dc095SDavid du Colombier const ref * sources, int npop);
46*593dc095SDavid du Colombier private int image_proc_process(i_ctx_t *);
47*593dc095SDavid du Colombier private int image_file_continue(i_ctx_t *);
48*593dc095SDavid du Colombier private int image_string_continue(i_ctx_t *);
49*593dc095SDavid du Colombier private int image_cleanup(i_ctx_t *);
507dd7cddfSDavid du Colombier
51*593dc095SDavid du Colombier
52*593dc095SDavid du Colombier
53*593dc095SDavid du Colombier /* Extract and check the parameters for a gs_data_image_t. */
547dd7cddfSDavid du Colombier 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*593dc095SDavid du Colombier data_image_params(const gs_memory_t *mem,
56*593dc095SDavid du Colombier const ref *op, gs_data_image_t *pim,
57*593dc095SDavid du Colombier image_params *pip, bool require_DataSource,
58*593dc095SDavid du Colombier int num_components, int max_bits_per_component,
59*593dc095SDavid du Colombier bool has_alpha)
607dd7cddfSDavid du Colombier {
617dd7cddfSDavid du Colombier int code;
62*593dc095SDavid du Colombier int decode_size;
63*593dc095SDavid du Colombier ref *pds;
647dd7cddfSDavid du Colombier
65*593dc095SDavid du Colombier check_type(*op, t_dictionary);
66*593dc095SDavid du Colombier check_dict_read(*op);
67*593dc095SDavid du Colombier if ((code = dict_int_param(op, "Width", 0, max_int_in_fixed / 2,
68*593dc095SDavid du Colombier -1, &pim->Width)) < 0 ||
69*593dc095SDavid du Colombier (code = dict_int_param(op, "Height", 0, max_int_in_fixed / 2,
70*593dc095SDavid du Colombier -1, &pim->Height)) < 0 ||
71*593dc095SDavid du Colombier (code = dict_matrix_param(mem, op, "ImageMatrix",
72*593dc095SDavid du Colombier &pim->ImageMatrix)) < 0 ||
73*593dc095SDavid du Colombier (code = dict_bool_param(op, "MultipleDataSources", false,
74*593dc095SDavid du Colombier &pip->MultipleDataSources)) < 0 ||
75*593dc095SDavid du Colombier (code = dict_int_param(op, "BitsPerComponent", 1,
76*593dc095SDavid du Colombier max_bits_per_component, -1,
77*593dc095SDavid du Colombier &pim->BitsPerComponent)) < 0 ||
78*593dc095SDavid du Colombier (code = decode_size = dict_floats_param(mem, op, "Decode",
79*593dc095SDavid du Colombier num_components * 2,
80*593dc095SDavid du Colombier &pim->Decode[0], NULL)) < 0 ||
81*593dc095SDavid du Colombier (code = dict_bool_param(op, "Interpolate", false,
82*593dc095SDavid du Colombier &pim->Interpolate)) < 0
83*593dc095SDavid du Colombier )
847dd7cddfSDavid du Colombier return code;
85*593dc095SDavid du Colombier pip->pDecode = &pim->Decode[0];
86*593dc095SDavid du Colombier /* Extract and check the data sources. */
87*593dc095SDavid du Colombier if ((code = dict_find_string(op, "DataSource", &pds)) <= 0) {
88*593dc095SDavid du Colombier if (require_DataSource)
89*593dc095SDavid du Colombier return (code < 0 ? code : gs_note_error(e_rangecheck));
90*593dc095SDavid du Colombier return 1; /* no data source */
91*593dc095SDavid du Colombier }
92*593dc095SDavid du Colombier if (pip->MultipleDataSources) {
93*593dc095SDavid du Colombier long i, n = num_components + (has_alpha ? 1 : 0);
94*593dc095SDavid du Colombier if (!r_is_array(pds))
95*593dc095SDavid du Colombier return_error(e_typecheck);
96*593dc095SDavid du Colombier if (r_size(pds) != n)
97*593dc095SDavid du Colombier return_error(e_rangecheck);
98*593dc095SDavid du Colombier for (i = 0; i < n; ++i)
99*593dc095SDavid du Colombier array_get(mem, pds, i, &pip->DataSource[i]);
100*593dc095SDavid du Colombier } else
101*593dc095SDavid du Colombier pip->DataSource[0] = *pds;
102*593dc095SDavid du Colombier return 0;
103*593dc095SDavid du Colombier }
104*593dc095SDavid du Colombier
105*593dc095SDavid du Colombier /* Extract and check the parameters for a gs_pixel_image_t. */
106*593dc095SDavid du Colombier 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*593dc095SDavid du Colombier pixel_image_params(i_ctx_t *i_ctx_p, const ref *op, gs_pixel_image_t *pim,
108*593dc095SDavid du Colombier image_params *pip, int max_bits_per_component,
109*593dc095SDavid du Colombier bool has_alpha)
110*593dc095SDavid du Colombier {
111*593dc095SDavid du Colombier int num_components =
112*593dc095SDavid du Colombier gs_color_space_num_components(gs_currentcolorspace(igs));
113*593dc095SDavid du Colombier int code;
114*593dc095SDavid du Colombier
115*593dc095SDavid du Colombier if (num_components < 1)
116*593dc095SDavid du Colombier return_error(e_rangecheck); /* Pattern space not allowed */
117*593dc095SDavid du Colombier pim->ColorSpace = gs_currentcolorspace(igs);
118*593dc095SDavid du Colombier code = data_image_params(imemory, op, (gs_data_image_t *) pim, pip, true,
119*593dc095SDavid du Colombier num_components, max_bits_per_component,
120*593dc095SDavid du Colombier has_alpha);
121*593dc095SDavid du Colombier if (code < 0)
122*593dc095SDavid du Colombier return code;
123*593dc095SDavid du Colombier pim->format =
124*593dc095SDavid du Colombier (pip->MultipleDataSources ? gs_image_format_component_planar :
125*593dc095SDavid du Colombier gs_image_format_chunky);
126*593dc095SDavid du Colombier return dict_bool_param(op, "CombineWithColor", false,
127*593dc095SDavid du Colombier &pim->CombineWithColor);
1287dd7cddfSDavid du Colombier }
1297dd7cddfSDavid du Colombier
1307dd7cddfSDavid du Colombier /* Common setup for all Level 1 and 2 images, and ImageType 4 images. */
1317dd7cddfSDavid du Colombier int
zimage_setup(i_ctx_t * i_ctx_p,const gs_pixel_image_t * pim,const ref * sources,bool uses_color,int npop)1327dd7cddfSDavid du Colombier zimage_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
1337dd7cddfSDavid du Colombier const ref * sources, bool uses_color, int npop)
1347dd7cddfSDavid du Colombier {
1357dd7cddfSDavid du Colombier gx_image_enum_common_t *pie;
1367dd7cddfSDavid du Colombier int code =
1377dd7cddfSDavid du Colombier gs_image_begin_typed((const gs_image_common_t *)pim, igs,
1387dd7cddfSDavid du Colombier uses_color, &pie);
1397dd7cddfSDavid du Colombier
1407dd7cddfSDavid du Colombier if (code < 0)
1417dd7cddfSDavid du Colombier return code;
1427dd7cddfSDavid du Colombier return zimage_data_setup(i_ctx_p, (const gs_pixel_image_t *)pim, pie,
1437dd7cddfSDavid du Colombier sources, npop);
1447dd7cddfSDavid du Colombier }
1457dd7cddfSDavid du Colombier
146*593dc095SDavid du Colombier /* Common code for .image1 and .alphaimage operators */
147*593dc095SDavid du Colombier int
image1_setup(i_ctx_t * i_ctx_p,bool has_alpha)148*593dc095SDavid du Colombier image1_setup(i_ctx_t * i_ctx_p, bool has_alpha)
149*593dc095SDavid du Colombier {
150*593dc095SDavid du Colombier os_ptr op = osp;
151*593dc095SDavid du Colombier gs_image_t image;
152*593dc095SDavid du Colombier image_params ip;
153*593dc095SDavid du Colombier int code;
154*593dc095SDavid du Colombier
155*593dc095SDavid du Colombier gs_image_t_init(&image, gs_currentcolorspace(igs));
156*593dc095SDavid du Colombier code = pixel_image_params( i_ctx_p,
157*593dc095SDavid du Colombier op,
158*593dc095SDavid du Colombier (gs_pixel_image_t *)&image,
159*593dc095SDavid du Colombier &ip,
160*593dc095SDavid du Colombier (level2_enabled ? 16 : 8),
161*593dc095SDavid du Colombier has_alpha );
162*593dc095SDavid du Colombier if (code < 0)
163*593dc095SDavid du Colombier return code;
164*593dc095SDavid du Colombier
165*593dc095SDavid du Colombier image.Alpha = (has_alpha ? gs_image_alpha_last : gs_image_alpha_none);
166*593dc095SDavid du Colombier return zimage_setup( i_ctx_p,
167*593dc095SDavid du Colombier (gs_pixel_image_t *)&image,
168*593dc095SDavid du Colombier &ip.DataSource[0],
169*593dc095SDavid du Colombier image.CombineWithColor,
170*593dc095SDavid du Colombier 1 );
171*593dc095SDavid du Colombier }
172*593dc095SDavid du Colombier
173*593dc095SDavid du Colombier /* <dict> .image1 - */
174*593dc095SDavid du Colombier private int
zimage1(i_ctx_t * i_ctx_p)175*593dc095SDavid du Colombier zimage1(i_ctx_t *i_ctx_p)
176*593dc095SDavid du Colombier {
177*593dc095SDavid du Colombier return image1_setup(i_ctx_p, false);
178*593dc095SDavid du Colombier }
179*593dc095SDavid du Colombier
180*593dc095SDavid du Colombier /* <dict> .imagemask1 - */
181*593dc095SDavid du Colombier private int
zimagemask1(i_ctx_t * i_ctx_p)182*593dc095SDavid du Colombier zimagemask1(i_ctx_t *i_ctx_p)
183*593dc095SDavid du Colombier {
184*593dc095SDavid du Colombier os_ptr op = osp;
185*593dc095SDavid du Colombier gs_image_t image;
186*593dc095SDavid du Colombier image_params ip;
187*593dc095SDavid du Colombier int code;
188*593dc095SDavid du Colombier
189*593dc095SDavid du Colombier gs_image_t_init_mask_adjust(&image, false,
190*593dc095SDavid du Colombier gs_incachedevice(igs) != CACHE_DEVICE_NONE);
191*593dc095SDavid du Colombier code = data_image_params(imemory, op, (gs_data_image_t *) & image,
192*593dc095SDavid du Colombier &ip, true, 1, 1, false);
193*593dc095SDavid du Colombier if (code < 0)
194*593dc095SDavid du Colombier return code;
195*593dc095SDavid du Colombier if (ip.MultipleDataSources)
196*593dc095SDavid du Colombier return_error(e_rangecheck);
197*593dc095SDavid du Colombier return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image, &ip.DataSource[0],
198*593dc095SDavid du Colombier true, 1);
199*593dc095SDavid du Colombier }
200*593dc095SDavid du Colombier
201*593dc095SDavid du Colombier
2027dd7cddfSDavid du Colombier /* Common setup for all Level 1 and 2 images, and ImageType 3 and 4 images. */
2037dd7cddfSDavid du Colombier /*
2047dd7cddfSDavid du Colombier * We push the following on the estack.
2057dd7cddfSDavid du Colombier * control mark,
2067dd7cddfSDavid du Colombier * num_sources,
2077dd7cddfSDavid du Colombier * for I = num_sources-1 ... 0:
2087dd7cddfSDavid du Colombier * data source I,
2097dd7cddfSDavid du Colombier * aliasing information:
2107dd7cddfSDavid du Colombier * if source is not file, 1, except that the topmost value
2117dd7cddfSDavid du Colombier * is used for bookkeeping in the procedure case (see below);
2127dd7cddfSDavid du Colombier * if file is referenced by a total of M different sources and
2137dd7cddfSDavid du Colombier * this is the occurrence with the lowest I, M;
2147dd7cddfSDavid du Colombier * otherwise, -J, where J is the lowest I of the same file as
2157dd7cddfSDavid du Colombier * this one;
2167dd7cddfSDavid du Colombier * current plane index,
2177dd7cddfSDavid du Colombier * num_sources,
2187dd7cddfSDavid du Colombier * enumeration structure.
2197dd7cddfSDavid du Colombier */
2207dd7cddfSDavid du Colombier #define NUM_PUSH(nsource) ((nsource) * 2 + 5)
2217dd7cddfSDavid du Colombier /*
2227dd7cddfSDavid du Colombier * We can access these values either from the bottom (esp at control mark - 1,
2237dd7cddfSDavid du Colombier * EBOT macros) or the top (esp = enumeration structure, ETOP macros).
2247dd7cddfSDavid du Colombier * Note that all macros return pointers.
2257dd7cddfSDavid du Colombier */
2267dd7cddfSDavid du Colombier #define EBOT_NUM_SOURCES(ep) ((ep) + 2)
2277dd7cddfSDavid du Colombier #define EBOT_SOURCE(ep, i)\
2287dd7cddfSDavid du Colombier ((ep) + 3 + (EBOT_NUM_SOURCES(ep)->value.intval - 1 - (i)) * 2)
2297dd7cddfSDavid du Colombier #define ETOP_SOURCE(ep, i)\
2307dd7cddfSDavid du Colombier ((ep) - 4 - (i) * 2)
2317dd7cddfSDavid du Colombier #define ETOP_PLANE_INDEX(ep) ((ep) - 2)
2327dd7cddfSDavid du Colombier #define ETOP_NUM_SOURCES(ep) ((ep) - 1)
233*593dc095SDavid du Colombier 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)2347dd7cddfSDavid du Colombier zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim,
2357dd7cddfSDavid du Colombier gx_image_enum_common_t * pie, const ref * sources, int npop)
2367dd7cddfSDavid du Colombier {
2377dd7cddfSDavid du Colombier int num_sources = pie->num_planes;
2387dd7cddfSDavid du Colombier int inumpush = NUM_PUSH(num_sources);
2397dd7cddfSDavid du Colombier int code;
2407dd7cddfSDavid du Colombier gs_image_enum *penum;
2417dd7cddfSDavid du Colombier int px;
2427dd7cddfSDavid du Colombier const ref *pp;
2437dd7cddfSDavid du Colombier
2447dd7cddfSDavid du Colombier check_estack(inumpush + 2); /* stuff above, + continuation + proc */
2457dd7cddfSDavid du Colombier make_int(EBOT_NUM_SOURCES(esp), num_sources);
2467dd7cddfSDavid du Colombier /*
2477dd7cddfSDavid du Colombier * Note that the data sources may be procedures, strings, or (Level
2487dd7cddfSDavid du Colombier * 2 only) files. (The Level 1 reference manual says that Level 1
2497dd7cddfSDavid du Colombier * requires procedures, but Adobe Level 1 interpreters also accept
2507dd7cddfSDavid du Colombier * strings.) The sources must all be of the same type.
2517dd7cddfSDavid du Colombier *
2527dd7cddfSDavid du Colombier * The Adobe documentation explicitly says that if two or more of the
2537dd7cddfSDavid du Colombier * data sources are the same or inter-dependent files, the result is not
2547dd7cddfSDavid du Colombier * defined. We don't have a problem with the bookkeeping for
2557dd7cddfSDavid du Colombier * inter-dependent files, since each one has its own buffer, but we do
2567dd7cddfSDavid du Colombier * have to be careful if two or more sources are actually the same file.
2577dd7cddfSDavid du Colombier * That is the reason for the aliasing information described above.
2587dd7cddfSDavid du Colombier */
2597dd7cddfSDavid du Colombier for (px = 0, pp = sources; px < num_sources; px++, pp++) {
2607dd7cddfSDavid du Colombier es_ptr ep = EBOT_SOURCE(esp, px);
2617dd7cddfSDavid du Colombier
2627dd7cddfSDavid du Colombier make_int(ep + 1, 1); /* default is no aliasing */
2637dd7cddfSDavid du Colombier switch (r_type(pp)) {
2647dd7cddfSDavid du Colombier case t_file:
2657dd7cddfSDavid du Colombier if (!level2_enabled)
2667dd7cddfSDavid du Colombier return_error(e_typecheck);
2677dd7cddfSDavid du Colombier /* Check for aliasing. */
2687dd7cddfSDavid du Colombier {
2697dd7cddfSDavid du Colombier int pi;
2707dd7cddfSDavid du Colombier
2717dd7cddfSDavid du Colombier for (pi = 0; pi < px; ++pi)
2727dd7cddfSDavid du Colombier if (sources[pi].value.pfile == pp->value.pfile) {
2737dd7cddfSDavid du Colombier /* Record aliasing */
2747dd7cddfSDavid du Colombier make_int(ep + 1, -pi);
2753ff48bf5SDavid du Colombier EBOT_SOURCE(esp, pi)[1].value.intval++;
2767dd7cddfSDavid du Colombier break;
2777dd7cddfSDavid du Colombier }
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier /* falls through */
2807dd7cddfSDavid du Colombier case t_string:
281*593dc095SDavid du Colombier if (r_type(pp) != r_type(sources)) {
282*593dc095SDavid du Colombier if (pie != NULL)
283*593dc095SDavid du Colombier gx_image_end(pie, false); /* Clean up pie */
2847dd7cddfSDavid du Colombier return_error(e_typecheck);
285*593dc095SDavid du Colombier }
2867dd7cddfSDavid du Colombier check_read(*pp);
2877dd7cddfSDavid du Colombier break;
2887dd7cddfSDavid du Colombier default:
289*593dc095SDavid du Colombier if (!r_is_proc(sources)) {
290*593dc095SDavid du Colombier if (pie != NULL)
291*593dc095SDavid du Colombier gx_image_end(pie, false); /* Clean up pie */
2927dd7cddfSDavid du Colombier return_error(e_typecheck);
293*593dc095SDavid du Colombier }
2947dd7cddfSDavid du Colombier check_proc(*pp);
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier *ep = *pp;
2977dd7cddfSDavid du Colombier }
298*593dc095SDavid du Colombier /* Always place the image enumerator into local memory,
299*593dc095SDavid du Colombier because pie may have local objects inherited from igs,
300*593dc095SDavid du Colombier which may be local when the current allocation mode is global.
301*593dc095SDavid du Colombier Bug 688140. */
302*593dc095SDavid du Colombier if ((penum = gs_image_enum_alloc(imemory_local, "image_setup")) == 0)
3037dd7cddfSDavid du Colombier return_error(e_VMerror);
3047dd7cddfSDavid du Colombier code = gs_image_enum_init(penum, pie, (const gs_data_image_t *)pim, igs);
3057dd7cddfSDavid du Colombier if (code != 0) { /* error, or empty image */
306*593dc095SDavid du Colombier int code1 = gs_image_cleanup_and_free_enum(penum);
307*593dc095SDavid du Colombier
3087dd7cddfSDavid du Colombier if (code >= 0) /* empty image */
3097dd7cddfSDavid du Colombier pop(npop);
310*593dc095SDavid du Colombier if (code >= 0 && code1 < 0)
311*593dc095SDavid du Colombier code = code1;
3127dd7cddfSDavid du Colombier return code;
3137dd7cddfSDavid du Colombier }
3147dd7cddfSDavid du Colombier push_mark_estack(es_other, image_cleanup);
3157dd7cddfSDavid du Colombier esp += inumpush - 1;
3167dd7cddfSDavid du Colombier make_int(ETOP_PLANE_INDEX(esp), 0);
3177dd7cddfSDavid du Colombier make_int(ETOP_NUM_SOURCES(esp), num_sources);
318*593dc095SDavid du Colombier make_struct(esp, avm_local, penum);
3197dd7cddfSDavid du Colombier switch (r_type(sources)) {
3207dd7cddfSDavid du Colombier case t_file:
3217dd7cddfSDavid du Colombier push_op_estack(image_file_continue);
3227dd7cddfSDavid du Colombier break;
3237dd7cddfSDavid du Colombier case t_string:
3247dd7cddfSDavid du Colombier push_op_estack(image_string_continue);
3257dd7cddfSDavid du Colombier break;
3267dd7cddfSDavid du Colombier default: /* procedure */
3277dd7cddfSDavid du Colombier push_op_estack(image_proc_process);
3287dd7cddfSDavid du Colombier break;
3297dd7cddfSDavid du Colombier }
3307dd7cddfSDavid du Colombier pop(npop);
3317dd7cddfSDavid du Colombier return o_push_estack;
3327dd7cddfSDavid du Colombier }
3337dd7cddfSDavid du Colombier /* Pop all the control information off the e-stack. */
3347dd7cddfSDavid du Colombier private es_ptr
zimage_pop_estack(es_ptr tep)3357dd7cddfSDavid du Colombier zimage_pop_estack(es_ptr tep)
3367dd7cddfSDavid du Colombier {
3377dd7cddfSDavid du Colombier return tep - NUM_PUSH(ETOP_NUM_SOURCES(tep)->value.intval);
3387dd7cddfSDavid du Colombier }
3397dd7cddfSDavid du Colombier
3407dd7cddfSDavid du Colombier /*
3417dd7cddfSDavid du Colombier * Continuation for procedure data source. We use the topmost aliasing slot
3427dd7cddfSDavid du Colombier * to remember whether we've just called the procedure (1) or whether we're
3437dd7cddfSDavid du Colombier * returning from a RemapColor callout (0).
3447dd7cddfSDavid du Colombier */
3457dd7cddfSDavid du Colombier private int
image_proc_continue(i_ctx_t * i_ctx_p)3467dd7cddfSDavid du Colombier image_proc_continue(i_ctx_t *i_ctx_p)
3477dd7cddfSDavid du Colombier {
3487dd7cddfSDavid du Colombier os_ptr op = osp;
3497dd7cddfSDavid du Colombier gs_image_enum *penum = r_ptr(esp, gs_image_enum);
3507dd7cddfSDavid du Colombier int px = ETOP_PLANE_INDEX(esp)->value.intval;
3517dd7cddfSDavid du Colombier int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
3527dd7cddfSDavid du Colombier uint size, used[gs_image_max_planes];
3537dd7cddfSDavid du Colombier gs_const_string plane_data[gs_image_max_planes];
3547dd7cddfSDavid du Colombier const byte *wanted;
3557dd7cddfSDavid du Colombier int i, code;
3567dd7cddfSDavid du Colombier
3577dd7cddfSDavid du Colombier if (!r_has_type_attrs(op, t_string, a_read)) {
3587dd7cddfSDavid du Colombier check_op(1);
3597dd7cddfSDavid du Colombier /* Procedure didn't return a (readable) string. Quit. */
3607dd7cddfSDavid du Colombier esp = zimage_pop_estack(esp);
3617dd7cddfSDavid du Colombier image_cleanup(i_ctx_p);
3627dd7cddfSDavid du Colombier return_error(!r_has_type(op, t_string) ? e_typecheck : e_invalidaccess);
3637dd7cddfSDavid du Colombier }
3647dd7cddfSDavid du Colombier size = r_size(op);
3657dd7cddfSDavid du Colombier if (size == 0 && ETOP_SOURCE(esp, 0)[1].value.intval == 0)
3667dd7cddfSDavid du Colombier code = 1;
3677dd7cddfSDavid du Colombier else {
3687dd7cddfSDavid du Colombier for (i = 0; i < num_sources; i++)
3697dd7cddfSDavid du Colombier plane_data[i].size = 0;
3707dd7cddfSDavid du Colombier plane_data[px].data = op->value.bytes;
3717dd7cddfSDavid du Colombier plane_data[px].size = size;
3727dd7cddfSDavid du Colombier code = gs_image_next_planes(penum, plane_data, used);
3737dd7cddfSDavid du Colombier if (code == e_RemapColor) {
3747dd7cddfSDavid du Colombier op->value.bytes += used[px]; /* skip used data */
3757dd7cddfSDavid du Colombier r_dec_size(op, used[px]);
3767dd7cddfSDavid du Colombier ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* RemapColor callout */
3777dd7cddfSDavid du Colombier return code;
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier }
3807dd7cddfSDavid du Colombier if (code) { /* Stop now. */
3817dd7cddfSDavid du Colombier esp = zimage_pop_estack(esp);
3827dd7cddfSDavid du Colombier pop(1);
3837dd7cddfSDavid du Colombier image_cleanup(i_ctx_p);
3847dd7cddfSDavid du Colombier return (code < 0 ? code : o_pop_estack);
3857dd7cddfSDavid du Colombier }
3867dd7cddfSDavid du Colombier pop(1);
3877dd7cddfSDavid du Colombier wanted = gs_image_planes_wanted(penum);
3887dd7cddfSDavid du Colombier do {
3897dd7cddfSDavid du Colombier if (++px == num_sources)
3907dd7cddfSDavid du Colombier px = 0;
3917dd7cddfSDavid du Colombier } while (!wanted[px]);
3927dd7cddfSDavid du Colombier ETOP_PLANE_INDEX(esp)->value.intval = px;
3937dd7cddfSDavid du Colombier return image_proc_process(i_ctx_p);
3947dd7cddfSDavid du Colombier }
3957dd7cddfSDavid du Colombier private int
image_proc_process(i_ctx_t * i_ctx_p)3967dd7cddfSDavid du Colombier image_proc_process(i_ctx_t *i_ctx_p)
3977dd7cddfSDavid du Colombier {
3987dd7cddfSDavid du Colombier int px = ETOP_PLANE_INDEX(esp)->value.intval;
3997dd7cddfSDavid du Colombier gs_image_enum *penum = r_ptr(esp, gs_image_enum);
4007dd7cddfSDavid du Colombier const byte *wanted = gs_image_planes_wanted(penum);
4017dd7cddfSDavid du Colombier int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
4027dd7cddfSDavid du Colombier const ref *pp;
4037dd7cddfSDavid du Colombier
4047dd7cddfSDavid du Colombier ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* procedure callout */
4057dd7cddfSDavid du Colombier while (!wanted[px]) {
4067dd7cddfSDavid du Colombier if (++px == num_sources)
4077dd7cddfSDavid du Colombier px = 0;
4087dd7cddfSDavid du Colombier ETOP_PLANE_INDEX(esp)->value.intval = px;
4097dd7cddfSDavid du Colombier }
4107dd7cddfSDavid du Colombier pp = ETOP_SOURCE(esp, px);
4117dd7cddfSDavid du Colombier push_op_estack(image_proc_continue);
4127dd7cddfSDavid du Colombier *++esp = *pp;
4137dd7cddfSDavid du Colombier return o_push_estack;
4147dd7cddfSDavid du Colombier }
4157dd7cddfSDavid du Colombier
4167dd7cddfSDavid du Colombier /* Continue processing data from an image with file data sources. */
4177dd7cddfSDavid du Colombier private int
image_file_continue(i_ctx_t * i_ctx_p)4187dd7cddfSDavid du Colombier image_file_continue(i_ctx_t *i_ctx_p)
4197dd7cddfSDavid du Colombier {
4207dd7cddfSDavid du Colombier gs_image_enum *penum = r_ptr(esp, gs_image_enum);
4217dd7cddfSDavid du Colombier int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
4227dd7cddfSDavid du Colombier
4237dd7cddfSDavid du Colombier for (;;) {
4247dd7cddfSDavid du Colombier uint min_avail = max_int;
4257dd7cddfSDavid du Colombier gs_const_string plane_data[gs_image_max_planes];
4267dd7cddfSDavid du Colombier int code;
4277dd7cddfSDavid du Colombier int px;
4287dd7cddfSDavid du Colombier const ref *pp;
4297dd7cddfSDavid du Colombier bool at_eof = false;
4307dd7cddfSDavid du Colombier
4317dd7cddfSDavid du Colombier /*
4327dd7cddfSDavid du Colombier * Do a first pass through the files to ensure that at least
4337dd7cddfSDavid du Colombier * one has data available in its buffer.
4347dd7cddfSDavid du Colombier */
4357dd7cddfSDavid du Colombier
4367dd7cddfSDavid du Colombier for (px = 0, pp = ETOP_SOURCE(esp, 0); px < num_sources;
4377dd7cddfSDavid du Colombier ++px, pp -= 2
4387dd7cddfSDavid du Colombier ) {
4397dd7cddfSDavid du Colombier int num_aliases = pp[1].value.intval;
4407dd7cddfSDavid du Colombier stream *s = pp->value.pfile;
4417dd7cddfSDavid du Colombier int min_left;
4427dd7cddfSDavid du Colombier uint avail;
4437dd7cddfSDavid du Colombier
4447dd7cddfSDavid du Colombier if (num_aliases <= 0)
4453ff48bf5SDavid du Colombier num_aliases = ETOP_SOURCE(esp, -num_aliases)[1].value.intval;
4467dd7cddfSDavid du Colombier while ((avail = sbufavailable(s)) <=
4477dd7cddfSDavid du Colombier (min_left = sbuf_min_left(s)) + num_aliases - 1) {
4487dd7cddfSDavid du Colombier int next = s->end_status;
4497dd7cddfSDavid du Colombier
4507dd7cddfSDavid du Colombier switch (next) {
4517dd7cddfSDavid du Colombier case 0:
4527dd7cddfSDavid du Colombier s_process_read_buf(s);
4537dd7cddfSDavid du Colombier continue;
4547dd7cddfSDavid du Colombier case EOFC:
4557dd7cddfSDavid du Colombier at_eof = true;
4567dd7cddfSDavid du Colombier break; /* with no data available */
4577dd7cddfSDavid du Colombier case INTC:
4587dd7cddfSDavid du Colombier case CALLC:
4597dd7cddfSDavid du Colombier return
4607dd7cddfSDavid du Colombier s_handle_read_exception(i_ctx_p, next, pp,
4617dd7cddfSDavid du Colombier NULL, 0, image_file_continue);
4627dd7cddfSDavid du Colombier default:
4637dd7cddfSDavid du Colombier /* case ERRC: */
4647dd7cddfSDavid du Colombier return_error(e_ioerror);
4657dd7cddfSDavid du Colombier }
4667dd7cddfSDavid du Colombier break; /* for EOFC */
4677dd7cddfSDavid du Colombier }
4687dd7cddfSDavid du Colombier /*
4697dd7cddfSDavid du Colombier * Note that in the EOF case, we can get here with no data
4707dd7cddfSDavid du Colombier * available.
4717dd7cddfSDavid du Colombier */
4727dd7cddfSDavid du Colombier if (avail >= min_left)
4737dd7cddfSDavid du Colombier avail = (avail - min_left) / num_aliases; /* may be 0 */
4747dd7cddfSDavid du Colombier if (avail < min_avail)
4757dd7cddfSDavid du Colombier min_avail = avail;
4767dd7cddfSDavid du Colombier plane_data[px].data = sbufptr(s);
4777dd7cddfSDavid du Colombier plane_data[px].size = avail;
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier
4807dd7cddfSDavid du Colombier /*
4817dd7cddfSDavid du Colombier * Now pass the available buffered data to the image processor.
4827dd7cddfSDavid du Colombier * Even if there is no available data, we must call
4837dd7cddfSDavid du Colombier * gs_image_next_planes one more time to finish processing any
4847dd7cddfSDavid du Colombier * retained data.
4857dd7cddfSDavid du Colombier */
4867dd7cddfSDavid du Colombier
4877dd7cddfSDavid du Colombier {
4887dd7cddfSDavid du Colombier int pi;
4897dd7cddfSDavid du Colombier uint used[gs_image_max_planes];
4907dd7cddfSDavid du Colombier
4917dd7cddfSDavid du Colombier code = gs_image_next_planes(penum, plane_data, used);
4927dd7cddfSDavid du Colombier /* Now that used has been set, update the streams. */
4937dd7cddfSDavid du Colombier for (pi = 0, pp = ETOP_SOURCE(esp, 0); pi < num_sources;
4947dd7cddfSDavid du Colombier ++pi, pp -= 2
4957dd7cddfSDavid du Colombier )
4967dd7cddfSDavid du Colombier sbufskip(pp->value.pfile, used[pi]);
4977dd7cddfSDavid du Colombier if (code == e_RemapColor)
4987dd7cddfSDavid du Colombier return code;
4997dd7cddfSDavid du Colombier }
5007dd7cddfSDavid du Colombier if (at_eof)
5017dd7cddfSDavid du Colombier code = 1;
5027dd7cddfSDavid du Colombier if (code) {
503*593dc095SDavid du Colombier int code1;
504*593dc095SDavid du Colombier
5057dd7cddfSDavid du Colombier esp = zimage_pop_estack(esp);
506*593dc095SDavid du Colombier code1 = image_cleanup(i_ctx_p);
507*593dc095SDavid du Colombier return (code < 0 ? code : code1 < 0 ? code1 : o_pop_estack);
5087dd7cddfSDavid du Colombier }
5097dd7cddfSDavid du Colombier }
5107dd7cddfSDavid du Colombier }
5117dd7cddfSDavid du Colombier
5127dd7cddfSDavid du Colombier /* Process data from an image with string data sources. */
5137dd7cddfSDavid du Colombier /* This may still encounter a RemapColor callback. */
5147dd7cddfSDavid du Colombier private int
image_string_continue(i_ctx_t * i_ctx_p)5157dd7cddfSDavid du Colombier image_string_continue(i_ctx_t *i_ctx_p)
5167dd7cddfSDavid du Colombier {
5177dd7cddfSDavid du Colombier gs_image_enum *penum = r_ptr(esp, gs_image_enum);
5187dd7cddfSDavid du Colombier int num_sources = ETOP_NUM_SOURCES(esp)->value.intval;
5197dd7cddfSDavid du Colombier gs_const_string sources[gs_image_max_planes];
5207dd7cddfSDavid du Colombier uint used[gs_image_max_planes];
5217dd7cddfSDavid du Colombier
5227dd7cddfSDavid du Colombier /* Pass no data initially, to find out how much is retained. */
5237dd7cddfSDavid du Colombier memset(sources, 0, sizeof(sources[0]) * num_sources);
5247dd7cddfSDavid du Colombier for (;;) {
5257dd7cddfSDavid du Colombier int px;
5267dd7cddfSDavid du Colombier int code = gs_image_next_planes(penum, sources, used);
5277dd7cddfSDavid du Colombier
5287dd7cddfSDavid du Colombier if (code == e_RemapColor)
5297dd7cddfSDavid du Colombier return code;
5303ff48bf5SDavid du Colombier stop_now:
5317dd7cddfSDavid du Colombier if (code) { /* Stop now. */
5327dd7cddfSDavid du Colombier esp -= NUM_PUSH(num_sources);
5337dd7cddfSDavid du Colombier image_cleanup(i_ctx_p);
5347dd7cddfSDavid du Colombier return (code < 0 ? code : o_pop_estack);
5357dd7cddfSDavid du Colombier }
5367dd7cddfSDavid du Colombier for (px = 0; px < num_sources; ++px)
5377dd7cddfSDavid du Colombier if (sources[px].size == 0) {
5387dd7cddfSDavid du Colombier const ref *psrc = ETOP_SOURCE(esp, px);
5393ff48bf5SDavid du Colombier uint size = r_size(psrc);
5407dd7cddfSDavid du Colombier
5413ff48bf5SDavid du Colombier if (size == 0) { /* empty source */
5423ff48bf5SDavid du Colombier code = 1;
5433ff48bf5SDavid du Colombier goto stop_now;
5443ff48bf5SDavid du Colombier }
5457dd7cddfSDavid du Colombier sources[px].data = psrc->value.bytes;
5463ff48bf5SDavid du Colombier sources[px].size = size;
5477dd7cddfSDavid du Colombier }
5487dd7cddfSDavid du Colombier }
5497dd7cddfSDavid du Colombier }
5507dd7cddfSDavid du Colombier
5517dd7cddfSDavid du Colombier /* Clean up after enumerating an image */
5527dd7cddfSDavid du Colombier private int
image_cleanup(i_ctx_t * i_ctx_p)5537dd7cddfSDavid du Colombier image_cleanup(i_ctx_t *i_ctx_p)
5547dd7cddfSDavid du Colombier {
5557dd7cddfSDavid du Colombier es_ptr ep_top = esp + NUM_PUSH(EBOT_NUM_SOURCES(esp)->value.intval);
5567dd7cddfSDavid du Colombier gs_image_enum *penum = r_ptr(ep_top, gs_image_enum);
5577dd7cddfSDavid du Colombier
558*593dc095SDavid du Colombier return gs_image_cleanup_and_free_enum(penum);
5597dd7cddfSDavid du Colombier }
5607dd7cddfSDavid du Colombier
5617dd7cddfSDavid du Colombier /* ------ Initialization procedure ------ */
5627dd7cddfSDavid du Colombier
5637dd7cddfSDavid du Colombier const op_def zimage_op_defs[] =
5647dd7cddfSDavid du Colombier {
565*593dc095SDavid du Colombier {"1.image1", zimage1},
566*593dc095SDavid du Colombier {"1.imagemask1", zimagemask1},
5677dd7cddfSDavid du Colombier /* Internal operators */
5687dd7cddfSDavid du Colombier {"1%image_proc_continue", image_proc_continue},
5697dd7cddfSDavid du Colombier {"0%image_file_continue", image_file_continue},
5707dd7cddfSDavid du Colombier {"0%image_string_continue", image_string_continue},
5717dd7cddfSDavid du Colombier op_def_end(0)
5727dd7cddfSDavid du Colombier };
573