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