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