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 setup procedures for Ghostscript library */
18 #include "memory_.h"
19 #include "math_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsstruct.h"
23 #include "gscspace.h"
24 #include "gsmatrix.h"		/* for gsiparam.h */
25 #include "gsimage.h"
26 #include "gxarith.h"		/* for igcd */
27 #include "gxdevice.h"
28 #include "gxiparam.h"
29 #include "gxpath.h"		/* for gx_effective_clip_path */
30 #include "gximask.h"
31 #include "gzstate.h"
32 #include "gsutil.h"
33 #include "vdtrace.h"
34 #include "gxdevsop.h"
35 
36 /*
37   The main internal invariant for the gs_image machinery is
38   straightforward.  The state consists primarily of N plane buffers
39   (planes[]).
40 */
41 typedef struct image_enum_plane_s {
42 /*
43   The state of each plane consists of:
44 
45   - A row buffer, aligned and (logically) large enough to hold one scan line
46     for that plane.  (It may have to be reallocated if the plane width or
47     depth changes.)  A row buffer is "full" if it holds exactly a full scan
48     line.
49 */
50     gs_string row;
51 /*
52   - A position within the row buffer, indicating how many initial bytes are
53     occupied.
54 */
55     uint pos;
56 /*
57   - A (retained) source string, which may be empty (size = 0).
58 */
59     gs_const_string source;
60 } image_enum_plane_t;
61 /*
62   The possible states for each plane do not depend on the state of any other
63   plane.  Either:
64 
65   - pos = 0, source.size = 0.
66 
67   - If the underlying image processor says the plane is currently wanted,
68     either:
69 
70     - pos = 0, source.size >= one full row of data for this plane.  This
71       case allows us to avoid copying the data from the source string to the
72       row buffer if the client is providing data in blocks of at least one
73       scan line.
74 
75     - pos = full, source.size may have any value.
76 
77     - pos > 0, pos < full, source.size = 0;
78 
79   - If the underlying image processor says the plane is not currently
80     wanted:
81 
82     - pos = 0, source.size may have any value.
83 
84   This invariant holds at the beginning and end of each call on
85   gs_image_next_planes.  Note that for each plane, the "plane wanted" status
86   and size of a full row may change after each call of plane_data.  As
87   documented in gxiparam.h, we assume that a call of plane_data can only
88   change a plane's status from "wanted" to "not wanted", or change the width
89   or depth of a wanted plane, if data for that plane was actually supplied
90   (and used).
91 */
92 
93 /* Define the enumeration state for this interface layer. */
94 /*typedef struct gs_image_enum_s gs_image_enum; *//* in gsimage.h */
95 struct gs_image_enum_s {
96     /* The following are set at initialization time. */
97     gs_memory_t *memory;
98     gx_device *dev;		/* if 0, just skip over the data */
99     gx_image_enum_common_t *info;	/* driver bookkeeping structure */
100     int num_planes;
101     int height;
102     bool wanted_varies;
103     /* The following are updated dynamically. */
104     int plane_index;		/* index of next plane of data, */
105                                 /* only needed for gs_image_next */
106     int y;
107     bool error;
108     byte wanted[GS_IMAGE_MAX_COMPONENTS]; /* cache gx_image_planes_wanted */
109     byte client_wanted[GS_IMAGE_MAX_COMPONENTS]; /* see gsimage.h */
110     image_enum_plane_t planes[GS_IMAGE_MAX_COMPONENTS]; /* see above */
111     /*
112      * To reduce setup for transferring complete rows, we maintain a
113      * partially initialized parameter array for gx_image_plane_data_rows.
114      * The data member is always set just before calling
115      * gx_image_plane_data_rows; the data_x and raster members are reset
116      * when needed.
117      */
118     gx_image_plane_t image_planes[GS_IMAGE_MAX_COMPONENTS];
119 };
120 
121 gs_private_st_composite(st_gs_image_enum, gs_image_enum, "gs_image_enum",
122                         gs_image_enum_enum_ptrs, gs_image_enum_reloc_ptrs);
123 #define gs_image_enum_num_ptrs 2
124 
125 /* GC procedures */
126 static
ENUM_PTRS_WITH(gs_image_enum_enum_ptrs,gs_image_enum * eptr)127 ENUM_PTRS_WITH(gs_image_enum_enum_ptrs, gs_image_enum *eptr)
128 {
129     /* Enumerate the data planes. */
130     index -= gs_image_enum_num_ptrs;
131     if (index < eptr->num_planes)
132         ENUM_RETURN_STRING_PTR(gs_image_enum, planes[index].source);
133     index -= eptr->num_planes;
134     if (index < eptr->num_planes)
135         ENUM_RETURN_STRING_PTR(gs_image_enum, planes[index].row);
136     return 0;
137 }
138 ENUM_PTR(0, gs_image_enum, dev);
139 ENUM_PTR(1, gs_image_enum, info);
140 ENUM_PTRS_END
RELOC_PTRS_WITH(gs_image_enum_reloc_ptrs,gs_image_enum * eptr)141 static RELOC_PTRS_WITH(gs_image_enum_reloc_ptrs, gs_image_enum *eptr)
142 {
143     int i;
144 
145     RELOC_PTR(gs_image_enum, dev);
146     RELOC_PTR(gs_image_enum, info);
147     for (i = 0; i < eptr->num_planes; i++)
148         RELOC_CONST_STRING_PTR(gs_image_enum, planes[i].source);
149     for (i = 0; i < eptr->num_planes; i++)
150         RELOC_STRING_PTR(gs_image_enum, planes[i].row);
151 }
152 RELOC_PTRS_END
153 
154 static int
is_image_visible(const gs_image_common_t * pic,gs_state * pgs,gx_clip_path * pcpath)155 is_image_visible(const gs_image_common_t * pic, gs_state * pgs, gx_clip_path *pcpath)
156 {
157     /* HACK : We need the source image size here,
158        but gs_image_common_t doesn't pass it.
159        We would like to move Width, Height to gs_image_common,
160        but gs_image2_t appears to have those fields of double type.
161      */
162     if (pic->type->begin_typed_image == gx_begin_image1) {
163         gs_image1_t *pim = (gs_image1_t *) pic;
164         gs_rect image_rect = {{0, 0}, {0, 0}};
165         gs_rect device_rect;
166         gs_int_rect device_int_rect;
167         gs_matrix mat;
168         int code;
169 
170         image_rect.q.x = pim->Width;
171         image_rect.q.y = pim->Height;
172         if (pic->ImageMatrix.xx == ctm_only(pgs).xx &&
173             pic->ImageMatrix.xy == ctm_only(pgs).xy &&
174             pic->ImageMatrix.yx == ctm_only(pgs).yx &&
175             pic->ImageMatrix.yy == ctm_only(pgs).yy) {
176             /* Handle common special case separately to accept singular matrix */
177             mat.xx = mat.yy = 1.;
178             mat.yx = mat.xy = 0.;
179             mat.tx = ctm_only(pgs).tx - pic->ImageMatrix.tx;
180             mat.ty = ctm_only(pgs).ty - pic->ImageMatrix.ty;
181         } else {
182             code = gs_matrix_invert(&pic->ImageMatrix, &mat);
183             if (code < 0)
184                 return code;
185             code = gs_matrix_multiply(&mat, &ctm_only(pgs), &mat);
186             if (code < 0)
187                 return code;
188         }
189         code = gs_bbox_transform(&image_rect, &mat, &device_rect);
190         if (code < 0)
191             return code;
192         device_int_rect.p.x = (int)floor(device_rect.p.x);
193         device_int_rect.p.y = (int)floor(device_rect.p.y);
194         device_int_rect.q.x = (int)ceil(device_rect.q.x);
195         device_int_rect.q.y = (int)ceil(device_rect.q.y);
196         if (!gx_cpath_rect_visible(pcpath, &device_int_rect))
197             return 0;
198     }
199     return 1;
200 }
201 
202 /* Create an image enumerator given image parameters and a graphics state. */
203 int
gs_image_begin_typed(const gs_image_common_t * pic,gs_state * pgs,bool uses_color,gx_image_enum_common_t ** ppie)204 gs_image_begin_typed(const gs_image_common_t * pic, gs_state * pgs,
205                      bool uses_color, gx_image_enum_common_t ** ppie)
206 {
207     gx_device *dev = gs_currentdevice(pgs);
208     gx_clip_path *pcpath;
209     int code = gx_effective_clip_path(pgs, &pcpath);
210     gx_device *dev2 = dev;
211     gx_device_color dc_temp, *pdevc = gs_currentdevicecolor_inline(pgs);
212 
213     if (code < 0)
214         return code;
215     /* Processing an image object operation */
216     dev_proc(pgs->device, set_graphics_type_tag)(pgs->device, GS_IMAGE_TAG);
217 
218     if (uses_color) {
219         code = gx_set_dev_color(pgs);
220         if (code != 0)
221             return code;
222         code = gs_state_color_load(pgs);
223         if (code < 0)
224             return code;
225     }
226     /* Imagemask with shading color needs a special optimization
227        with converting the image into a clipping.
228        Check for such case after gs_state_color_load is done,
229        because it can cause interpreter callout.
230      */
231     if (pic->type->begin_typed_image == &gx_begin_image1) {
232         gs_image_t *image = (gs_image_t *)pic;
233 
234         if(image->ImageMask) {
235             code = gx_image_fill_masked_start(dev, gs_currentdevicecolor_inline(pgs), pcpath, pgs->memory, &dev2);
236             if (code < 0)
237                 return code;
238         }
239         if (dev2 != dev) {
240             set_nonclient_dev_color(&dc_temp, 1);
241             pdevc = &dc_temp;
242         }
243     }
244     code = gx_device_begin_typed_image(dev2, (const gs_imager_state *)pgs,
245                 NULL, pic, NULL, pdevc, pcpath, pgs->memory, ppie);
246     if (code < 0)
247         return code;
248     code = is_image_visible(pic, pgs, pcpath);
249     if (code < 0)
250         return code;
251     if (!code)
252         (*ppie)->skipping = true;
253     return 0;
254 }
255 
256 /* Allocate an image enumerator. */
257 static void
image_enum_init(gs_image_enum * penum)258 image_enum_init(gs_image_enum * penum)
259 {
260     /* Clean pointers for GC. */
261     penum->info = 0;
262     penum->dev = 0;
263     penum->plane_index = 0;
264     penum->num_planes = 0;
265 }
266 gs_image_enum *
gs_image_enum_alloc(gs_memory_t * mem,client_name_t cname)267 gs_image_enum_alloc(gs_memory_t * mem, client_name_t cname)
268 {
269     gs_image_enum *penum =
270         gs_alloc_struct(mem, gs_image_enum, &st_gs_image_enum, cname);
271 
272     if (penum != 0) {
273         penum->memory = mem;
274         image_enum_init(penum);
275     }
276     return penum;
277 }
278 
279 /* Start processing an ImageType 1 image. */
280 int
gs_image_init(gs_image_enum * penum,const gs_image_t * pim,bool multi,gs_state * pgs)281 gs_image_init(gs_image_enum * penum, const gs_image_t * pim, bool multi,
282               gs_state * pgs)
283 {
284     gs_image_t image;
285     gx_image_enum_common_t *pie;
286     int code;
287 
288     image = *pim;
289     if (image.ImageMask) {
290         image.ColorSpace = NULL;
291         if (pgs->in_cachedevice <= 1)
292             image.adjust = false;
293     } else {
294         if (pgs->in_cachedevice)
295             return_error(gs_error_undefined);
296         if (image.ColorSpace == NULL) {
297             /*
298              * Use of a non-current color space is potentially
299              * incorrect, but it appears this case doesn't arise.
300              */
301             image.ColorSpace = gs_cspace_new_DeviceGray(pgs->memory);
302         }
303     }
304     code = gs_image_begin_typed((const gs_image_common_t *)&image, pgs,
305                                 image.ImageMask | image.CombineWithColor,
306                                 &pie);
307     if (code < 0)
308         return code;
309     return gs_image_enum_init(penum, pie, (const gs_data_image_t *)&image,
310                               pgs);
311 }
312 
313 /*
314  * Return the number of bytes of data per row for a given plane.
315  */
316 inline uint
gs_image_bytes_per_plane_row(const gs_image_enum * penum,int plane)317 gs_image_bytes_per_plane_row(const gs_image_enum * penum, int plane)
318 {
319     const gx_image_enum_common_t *pie = penum->info;
320 
321     return (pie->plane_widths[plane] * pie->plane_depths[plane] + 7) >> 3;
322 }
323 
324 /* Cache information when initializing, or after transferring plane data. */
325 static void
cache_planes(gs_image_enum * penum)326 cache_planes(gs_image_enum *penum)
327 {
328     int i;
329 
330     if (penum->wanted_varies) {
331         penum->wanted_varies =
332             !gx_image_planes_wanted(penum->info, penum->wanted);
333         for (i = 0; i < penum->num_planes; ++i)
334             if (penum->wanted[i])
335                 penum->image_planes[i].raster =
336                     gs_image_bytes_per_plane_row(penum, i);
337             else
338                 penum->image_planes[i].data = 0;
339     }
340 }
341 /* Advance to the next wanted plane. */
342 static void
next_plane(gs_image_enum * penum)343 next_plane(gs_image_enum *penum)
344 {
345     int px = penum->plane_index;
346 
347     do {
348         if (++px == penum->num_planes)
349             px = 0;
350     } while (!penum->wanted[px]);
351     penum->plane_index = px;
352 }
353 /*
354  * Initialize plane_index and (if appropriate) wanted and
355  * wanted_varies at the beginning of a group of planes.
356  */
357 static void
begin_planes(gs_image_enum * penum)358 begin_planes(gs_image_enum *penum)
359 {
360     cache_planes(penum);
361     penum->plane_index = -1;
362     next_plane(penum);
363 }
364 
365 int
gs_image_common_init(gs_image_enum * penum,gx_image_enum_common_t * pie,const gs_data_image_t * pim,gx_device * dev)366 gs_image_common_init(gs_image_enum * penum, gx_image_enum_common_t * pie,
367             const gs_data_image_t * pim, gx_device * dev)
368 {
369     /*
370      * HACK : For a compatibility with gs_image_cleanup_and_free_enum,
371      * penum->memory must be initialized in advance
372      * with the memory heap that owns *penum.
373      */
374     int i;
375 
376     if (pim->Width == 0 || pim->Height == 0) {
377         gx_image_end(pie, false);
378         return 1;
379     }
380     image_enum_init(penum);
381     penum->dev = dev;
382     penum->info = pie;
383     penum->num_planes = pie->num_planes;
384     /*
385      * Note that for ImageType 3 InterleaveType 2, penum->height (the
386      * expected number of data rows) differs from pim->Height (the height
387      * of the source image in scan lines).  This doesn't normally cause
388      * any problems, because penum->height is not used to determine when
389      * all the data has been processed: that is up to the plane_data
390      * procedure for the specific image type.
391      */
392     penum->height = pim->Height;
393     for (i = 0; i < pie->num_planes; ++i) {
394         penum->planes[i].pos = 0;
395         penum->planes[i].source.size = 0;	/* for gs_image_next_planes */
396         penum->planes[i].source.data = 0; /* for GC */
397         penum->planes[i].row.data = 0; /* for GC */
398         penum->planes[i].row.size = 0; /* ditto */
399         penum->image_planes[i].data_x = 0; /* just init once, never changes */
400     }
401     /* Initialize the dynamic part of the state. */
402     penum->y = 0;
403     penum->error = false;
404     penum->wanted_varies = true;
405     begin_planes(penum);
406     return 0;
407 }
408 
409 /* Initialize an enumerator for a general image.
410    penum->memory must be initialized in advance.
411 */
412 int
gs_image_enum_init(gs_image_enum * penum,gx_image_enum_common_t * pie,const gs_data_image_t * pim,gs_state * pgs)413 gs_image_enum_init(gs_image_enum * penum, gx_image_enum_common_t * pie,
414                    const gs_data_image_t * pim, gs_state *pgs)
415 {
416     pgs->device->sgr.stroke_stored = false;
417     return gs_image_common_init(penum, pie, pim,
418                                 (pgs->in_charpath ? NULL :
419                                  gs_currentdevice_inline(pgs)));
420 }
421 
422 /* Return the set of planes wanted. */
423 const byte *
gs_image_planes_wanted(gs_image_enum * penum)424 gs_image_planes_wanted(gs_image_enum *penum)
425 {
426     int i;
427 
428     /*
429      * A plane is wanted at this interface if it is wanted by the
430      * underlying machinery and has no buffered or retained data.
431      */
432     for (i = 0; i < penum->num_planes; ++i)
433         penum->client_wanted[i] =
434             (penum->wanted[i] &&
435              penum->planes[i].pos + penum->planes[i].source.size <
436                penum->image_planes[i].raster);
437     return penum->client_wanted;
438 }
439 
440 /*
441  * Return the enumerator memory used for allocating the row buffers.
442  * Because some PostScript files use save/restore within an image data
443  * reading procedure, this must be a stable allocator.
444  */
445 static gs_memory_t *
gs_image_row_memory(const gs_image_enum * penum)446 gs_image_row_memory(const gs_image_enum *penum)
447 {
448     return gs_memory_stable(penum->memory);
449 }
450 
451 /* Free the row buffers when cleaning up. */
452 static void
free_row_buffers(gs_image_enum * penum,int num_planes,client_name_t cname)453 free_row_buffers(gs_image_enum *penum, int num_planes, client_name_t cname)
454 {
455     int i;
456 
457     for (i = num_planes - 1; i >= 0; --i) {
458         if_debug3('b', "[b]free plane %d row (0x%lx,%u)\n",
459                   i, (ulong)penum->planes[i].row.data,
460                   penum->planes[i].row.size);
461         gs_free_string(gs_image_row_memory(penum), penum->planes[i].row.data,
462                        penum->planes[i].row.size, cname);
463         penum->planes[i].row.data = 0;
464         penum->planes[i].row.size = 0;
465     }
466 }
467 
468 /* Process the next piece of an image. */
469 int
gs_image_next(gs_image_enum * penum,const byte * dbytes,uint dsize,uint * pused)470 gs_image_next(gs_image_enum * penum, const byte * dbytes, uint dsize,
471               uint * pused)
472 {
473     int px = penum->plane_index;
474     int num_planes = penum->num_planes;
475     int i, code;
476     uint used[GS_IMAGE_MAX_COMPONENTS];
477     gs_const_string plane_data[GS_IMAGE_MAX_COMPONENTS];
478 
479     if (penum->planes[px].source.size != 0)
480         return_error(gs_error_rangecheck);
481     for (i = 0; i < num_planes; i++)
482         plane_data[i].size = 0;
483     plane_data[px].data = dbytes;
484     plane_data[px].size = dsize;
485     penum->error = false;
486     code = gs_image_next_planes(penum, plane_data, used);
487     *pused = used[px];
488     if (code >= 0)
489         next_plane(penum);
490     return code;
491 }
492 
493 int
gs_image_next_planes(gs_image_enum * penum,gs_const_string * plane_data,uint * used)494 gs_image_next_planes(gs_image_enum * penum,
495                      gs_const_string *plane_data /*[num_planes]*/,
496                      uint *used /*[num_planes]*/)
497 {
498     const int num_planes = penum->num_planes;
499     int i;
500     int code = 0;
501 
502 #ifdef DEBUG
503     vd_get_dc('i');
504     vd_set_shift(0, 0);
505     vd_set_scale(0.01);
506     vd_set_origin(0, 0);
507     if (gs_debug_c('b')) {
508         int pi;
509 
510         for (pi = 0; pi < num_planes; ++pi)
511             dprintf6("[b]plane %d source=0x%lx,%u pos=%u data=0x%lx,%u\n",
512                      pi, (ulong)penum->planes[pi].source.data,
513                      penum->planes[pi].source.size, penum->planes[pi].pos,
514                      (ulong)plane_data[pi].data, plane_data[pi].size);
515     }
516 #endif
517     for (i = 0; i < num_planes; ++i) {
518         used[i] = 0;
519         if (penum->wanted[i] && plane_data[i].size != 0) {
520             penum->planes[i].source.size = plane_data[i].size;
521             penum->planes[i].source.data = plane_data[i].data;
522         }
523     }
524     for (;;) {
525         /* If wanted can vary, only transfer 1 row at a time. */
526         int h = (penum->wanted_varies ? 1 : max_int);
527 
528         /* Move partial rows from source[] to row[]. */
529         for (i = 0; i < num_planes; ++i) {
530             int pos, size;
531             uint raster;
532 
533             if (!penum->wanted[i])
534                 continue;	/* skip unwanted planes */
535             pos = penum->planes[i].pos;
536             size = penum->planes[i].source.size;
537             raster = penum->image_planes[i].raster;
538             if (size > 0) {
539                 if (pos < raster && (pos != 0 || size < raster)) {
540                     /* Buffer a partial row. */
541                     int copy = min(size, raster - pos);
542                     uint old_size = penum->planes[i].row.size;
543 
544                     /* Make sure the row buffer is fully allocated. */
545                     if (raster > old_size) {
546                         gs_memory_t *mem = gs_image_row_memory(penum);
547                         byte *old_data = penum->planes[i].row.data;
548                         byte *row =
549                             (old_data == 0 ?
550                              gs_alloc_string(mem, raster,
551                                              "gs_image_next(row)") :
552                              gs_resize_string(mem, old_data, old_size, raster,
553                                               "gs_image_next(row)"));
554 
555                         if_debug5('b', "[b]plane %d row (0x%lx,%u) => (0x%lx,%u)\n",
556                                   i, (ulong)old_data, old_size,
557                                   (ulong)row, raster);
558                         if (row == 0) {
559                             code = gs_note_error(gs_error_VMerror);
560                             free_row_buffers(penum, i, "gs_image_next(row)");
561                             break;
562                         }
563                         penum->planes[i].row.data = row;
564                         penum->planes[i].row.size = raster;
565                     }
566                     memcpy(penum->planes[i].row.data + pos,
567                            penum->planes[i].source.data, copy);
568                     penum->planes[i].source.data += copy;
569                     penum->planes[i].source.size = size -= copy;
570                     penum->planes[i].pos = pos += copy;
571                     used[i] += copy;
572                 }
573             }
574             if (h == 0)
575                 continue;	/* can't transfer any data this cycle */
576             if (pos == raster) {
577                 /*
578                  * This plane will be transferred from the row buffer,
579                  * so we can only transfer one row.
580                  */
581                 h = min(h, 1);
582                 penum->image_planes[i].data = penum->planes[i].row.data;
583             } else if (pos == 0 && size >= raster) {
584                 /* We can transfer 1 or more planes from the source. */
585                 h = min(h, size / raster);
586                 penum->image_planes[i].data = penum->planes[i].source.data;
587             } else
588                 h = 0;		/* not enough data in this plane */
589         }
590         if (h == 0 || code != 0)
591             break;
592         /* Pass rows to the device. */
593         if (penum->dev == 0) {
594             /*
595              * ****** NOTE: THE FOLLOWING IS NOT CORRECT FOR ImageType 3
596              * ****** InterleaveType 2, SINCE MASK HEIGHT AND IMAGE HEIGHT
597              * ****** MAY DIFFER (BY AN INTEGER FACTOR).  ALSO, plane_depths[0]
598              * ****** AND plane_widths[0] ARE NOT UPDATED.
599          */
600             if (penum->y + h < penum->height)
601                 code = 0;
602             else
603                 h = penum->height - penum->y, code = 1;
604         } else {
605             code = gx_image_plane_data_rows(penum->info, penum->image_planes,
606                                             h, &h);
607             if_debug2('b', "[b]used %d, code=%d\n", h, code);
608             penum->error = code < 0;
609         }
610         penum->y += h;
611         /* Update positions and sizes. */
612         if (h == 0)
613             break;
614         for (i = 0; i < num_planes; ++i) {
615             int count;
616 
617             if (!penum->wanted[i])
618                 continue;
619             count = penum->image_planes[i].raster * h;
620             if (penum->planes[i].pos) {
621                 /* We transferred the row from the row buffer. */
622                 penum->planes[i].pos = 0;
623             } else {
624                 /* We transferred the row(s) from the source. */
625                 penum->planes[i].source.data += count;
626                 penum->planes[i].source.size -= count;
627                 used[i] += count;
628             }
629         }
630         cache_planes(penum);
631         if (code > 0)
632             break;
633     }
634     /* Return the retained data pointers. */
635     for (i = 0; i < num_planes; ++i)
636         plane_data[i] = penum->planes[i].source;
637     vd_release_dc;
638     return code;
639 }
640 
641 /* Clean up after processing an image. */
642 /* Public for ghostpcl. */
643 int
gs_image_cleanup(gs_image_enum * penum,gs_state * pgs)644 gs_image_cleanup(gs_image_enum * penum, gs_state *pgs)
645 {
646     int code = 0, code1;
647 
648     free_row_buffers(penum, penum->num_planes, "gs_image_cleanup(row)");
649     if (penum->info != 0) {
650         if (dev_proc(penum->info->dev, dev_spec_op)(penum->info->dev,
651                     gxdso_pattern_is_cpath_accum, NULL, 0)) {
652             /* Performing a conversion of imagemask into a clipping path. */
653             gx_device *cdev = penum->info->dev;
654 
655             code = gx_image_end(penum->info, !penum->error); /* Releases penum->info . */
656             code1 = gx_image_fill_masked_end(cdev, penum->dev, gs_currentdevicecolor_inline(pgs));
657             if (code == 0)
658                 code = code1;
659         } else
660             code = gx_image_end(penum->info, !penum->error);
661     }
662     /* Don't free the local enumerator -- the client does that. */
663 
664     return code;
665 }
666 
667 /* Clean up after processing an image and free the enumerator. */
668 int
gs_image_cleanup_and_free_enum(gs_image_enum * penum,gs_state * pgs)669 gs_image_cleanup_and_free_enum(gs_image_enum * penum, gs_state *pgs)
670 {
671     int code = gs_image_cleanup(penum, pgs);
672 
673     gs_free_object(penum->memory, penum, "gs_image_cleanup_and_free_enum");
674     return code;
675 }
676