1 /* Copyright (C) 2001-2019 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 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 "gxdevsop.h"
34 #include "gximage.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_gstate * pgs,gx_clip_path * pcpath)155 is_image_visible(const gs_image_common_t * pic, gs_gstate * 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_gstate * pgs,bool uses_color,bool image_is_text,gx_image_enum_common_t ** ppie)204 gs_image_begin_typed(const gs_image_common_t * pic, gs_gstate * pgs,
205                      bool uses_color, bool image_is_text, 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, but this may be for a text object */
216     ensure_tag_is_set(pgs, pgs->device, image_is_text ? GS_TEXT_TAG : GS_IMAGE_TAG);	/* NB: may unset_dev_color */
217 
218     if (uses_color) {
219         code = gx_set_dev_color(pgs);
220         if (code != 0)
221             return code;
222         code = gs_gstate_color_load(pgs);
223         if (code < 0)
224             return code;
225     }
226 
227     if (pgs->overprint || (!pgs->overprint && dev_proc(pgs->device, dev_spec_op)(pgs->device,
228         gxdso_overprint_active, NULL, 0))) {
229         gs_overprint_params_t op_params = { 0 };
230 
231         if_debug0m(gs_debug_flag_overprint, pgs->memory,
232             "[overprint] Image Overprint\n");
233         code = gs_do_set_overprint(pgs);
234         if (code < 0)
235             return code;
236 
237         op_params.op_state = OP_STATE_FILL;
238         gs_gstate_update_overprint(pgs, &op_params);
239 
240         dev = gs_currentdevice(pgs);
241         dev2 = dev;
242     }
243 
244     /* Imagemask with shading color needs a special optimization
245        with converting the image into a clipping.
246        Check for such case after gs_gstate_color_load is done,
247        because it can cause interpreter callout.
248      */
249     if (pic->type->begin_typed_image == &gx_begin_image1) {
250         gs_image_t *image = (gs_image_t *)pic;
251 
252         if(image->ImageMask) {
253             bool transpose = false;
254             gs_matrix_double mat;
255 
256             if((code = gx_image_compute_mat(pgs, NULL, &(image->ImageMatrix), &mat)) < 0)
257                 return code;
258             if ((any_abs(mat.xy) > any_abs(mat.xx)) && (any_abs(mat.yx) > any_abs(mat.yy)))
259                 transpose = true;		/* pure landscape */
260             code = gx_image_fill_masked_start(dev, gs_currentdevicecolor_inline(pgs), transpose,
261                                               pcpath, pgs->memory, pgs->log_op, &dev2);
262             if (code < 0)
263                 return code;
264         }
265         if (dev->interpolate_control < 0) {		/* Force interpolation before begin_typed_image */
266             ((gs_data_image_t *)pic)->Interpolate = true;
267         }
268         else if (dev->interpolate_control == 0) {
269             ((gs_data_image_t *)pic)->Interpolate = false;	/* Suppress interpolation */
270         }
271         if (dev2 != dev) {
272             set_nonclient_dev_color(&dc_temp, 1);
273             pdevc = &dc_temp;
274         }
275     }
276     code = gx_device_begin_typed_image(dev2, (const gs_gstate *)pgs,
277                 NULL, pic, NULL, pdevc, pcpath, pgs->memory, ppie);
278     if (code < 0)
279         return code;
280     code = is_image_visible(pic, pgs, pcpath);
281     if (code < 0)
282         return code;
283     if (!code)
284         (*ppie)->skipping = true;
285     return 0;
286 }
287 
288 /* Allocate an image enumerator. */
289 static void
image_enum_init(gs_image_enum * penum)290 image_enum_init(gs_image_enum * penum)
291 {
292     /* Clean pointers for GC. */
293     penum->info = 0;
294     penum->dev = 0;
295     penum->plane_index = 0;
296     penum->num_planes = 0;
297 }
298 gs_image_enum *
gs_image_enum_alloc(gs_memory_t * mem,client_name_t cname)299 gs_image_enum_alloc(gs_memory_t * mem, client_name_t cname)
300 {
301     gs_image_enum *penum =
302         gs_alloc_struct(mem, gs_image_enum, &st_gs_image_enum, cname);
303 
304     if (penum != 0) {
305         penum->memory = mem;
306         image_enum_init(penum);
307     }
308     return penum;
309 }
310 
311 /* Start processing an ImageType 1 image. */
312 int
gs_image_init(gs_image_enum * penum,const gs_image_t * pim,bool multi,bool image_is_text,gs_gstate * pgs)313 gs_image_init(gs_image_enum * penum, const gs_image_t * pim, bool multi,
314               bool image_is_text, gs_gstate * pgs)
315 {
316     gs_image_t image;
317     gx_image_enum_common_t *pie;
318     int code;
319 
320     image = *pim;
321     if (image.ImageMask) {
322         image.ColorSpace = NULL;
323         if (pgs->in_cachedevice <= 1)
324             image.adjust = false;
325     } else {
326         if (pgs->in_cachedevice)
327             return_error(gs_error_undefined);
328         if (image.ColorSpace == NULL) {
329             /*
330              * Use of a non-current color space is potentially
331              * incorrect, but it appears this case doesn't arise.
332              */
333             image.ColorSpace = gs_cspace_new_DeviceGray(pgs->memory);
334             if (image.ColorSpace == NULL)
335                 return_error(gs_error_VMerror);
336         }
337     }
338     code = gs_image_begin_typed((const gs_image_common_t *)&image, pgs,
339                                 image.ImageMask | image.CombineWithColor,
340                                 image_is_text, &pie);
341     if (code < 0)
342         return code;
343     return gs_image_enum_init(penum, pie, (const gs_data_image_t *)&image,
344                               pgs);
345 }
346 
347 /*
348  * Return the number of bytes of data per row for a given plane.
349  */
350 inline uint
gs_image_bytes_per_plane_row(const gs_image_enum * penum,int plane)351 gs_image_bytes_per_plane_row(const gs_image_enum * penum, int plane)
352 {
353     const gx_image_enum_common_t *pie = penum->info;
354 
355     return (pie->plane_widths[plane] * pie->plane_depths[plane] + 7) >> 3;
356 }
357 
358 /* Cache information when initializing, or after transferring plane data. */
359 static void
cache_planes(gs_image_enum * penum)360 cache_planes(gs_image_enum *penum)
361 {
362     int i;
363 
364     if (penum->wanted_varies) {
365         penum->wanted_varies =
366             !gx_image_planes_wanted(penum->info, penum->wanted);
367         for (i = 0; i < penum->num_planes; ++i)
368             if (penum->wanted[i])
369                 penum->image_planes[i].raster =
370                     gs_image_bytes_per_plane_row(penum, i);
371             else
372                 penum->image_planes[i].data = 0;
373     }
374 }
375 /* Advance to the next wanted plane. */
376 static void
next_plane(gs_image_enum * penum)377 next_plane(gs_image_enum *penum)
378 {
379     int px = penum->plane_index;
380 
381     do {
382         if (++px == penum->num_planes)
383             px = 0;
384     } while (!penum->wanted[px]);
385     penum->plane_index = px;
386 }
387 /*
388  * Initialize plane_index and (if appropriate) wanted and
389  * wanted_varies at the beginning of a group of planes.
390  */
391 static void
begin_planes(gs_image_enum * penum)392 begin_planes(gs_image_enum *penum)
393 {
394     cache_planes(penum);
395     penum->plane_index = -1;
396     next_plane(penum);
397 }
398 
399 int
gs_image_common_init(gs_image_enum * penum,gx_image_enum_common_t * pie,const gs_data_image_t * pim,gx_device * dev)400 gs_image_common_init(gs_image_enum * penum, gx_image_enum_common_t * pie,
401             const gs_data_image_t * pim, gx_device * dev)
402 {
403     /*
404      * HACK : For a compatibility with gs_image_cleanup_and_free_enum,
405      * penum->memory must be initialized in advance
406      * with the memory heap that owns *penum.
407      */
408     int i;
409 
410     if (pim->Width == 0 || pim->Height == 0) {
411         gx_image_end(pie, false);
412         return 1;
413     }
414     image_enum_init(penum);
415     penum->dev = dev;
416     penum->info = pie;
417     penum->num_planes = pie->num_planes;
418     /*
419      * Note that for ImageType 3 InterleaveType 2, penum->height (the
420      * expected number of data rows) differs from pim->Height (the height
421      * of the source image in scan lines).  This doesn't normally cause
422      * any problems, because penum->height is not used to determine when
423      * all the data has been processed: that is up to the plane_data
424      * procedure for the specific image type.
425      */
426     penum->height = pim->Height;
427     for (i = 0; i < pie->num_planes; ++i) {
428         penum->planes[i].pos = 0;
429         penum->planes[i].source.size = 0;	/* for gs_image_next_planes */
430         penum->planes[i].source.data = 0; /* for GC */
431         penum->planes[i].row.data = 0; /* for GC */
432         penum->planes[i].row.size = 0; /* ditto */
433         penum->image_planes[i].data_x = 0; /* just init once, never changes */
434     }
435     /* Initialize the dynamic part of the state. */
436     penum->y = 0;
437     penum->error = false;
438     penum->wanted_varies = true;
439     begin_planes(penum);
440     return 0;
441 }
442 
443 /* Initialize an enumerator for a general image.
444    penum->memory must be initialized in advance.
445 */
446 int
gs_image_enum_init(gs_image_enum * penum,gx_image_enum_common_t * pie,const gs_data_image_t * pim,gs_gstate * pgs)447 gs_image_enum_init(gs_image_enum * penum, gx_image_enum_common_t * pie,
448                    const gs_data_image_t * pim, gs_gstate *pgs)
449 {
450     pgs->device->sgr.stroke_stored = false;
451     return gs_image_common_init(penum, pie, pim,
452                                 (pgs->in_charpath ? NULL :
453                                  gs_currentdevice_inline(pgs)));
454 }
455 
456 /* Return the set of planes wanted. */
457 const byte *
gs_image_planes_wanted(gs_image_enum * penum)458 gs_image_planes_wanted(gs_image_enum *penum)
459 {
460     int i;
461 
462     /*
463      * A plane is wanted at this interface if it is wanted by the
464      * underlying machinery and has no buffered or retained data.
465      */
466     for (i = 0; i < penum->num_planes; ++i)
467         penum->client_wanted[i] =
468             (penum->wanted[i] &&
469              penum->planes[i].pos + penum->planes[i].source.size <
470                penum->image_planes[i].raster);
471     return penum->client_wanted;
472 }
473 
474 /*
475  * Return the enumerator memory used for allocating the row buffers.
476  * Because some PostScript files use save/restore within an image data
477  * reading procedure, this must be a stable allocator.
478  */
479 static gs_memory_t *
gs_image_row_memory(const gs_image_enum * penum)480 gs_image_row_memory(const gs_image_enum *penum)
481 {
482     return gs_memory_stable(penum->memory);
483 }
484 
485 /* Free the row buffers when cleaning up. */
486 static void
free_row_buffers(gs_image_enum * penum,int num_planes,client_name_t cname)487 free_row_buffers(gs_image_enum *penum, int num_planes, client_name_t cname)
488 {
489     int i;
490 
491     for (i = num_planes - 1; i >= 0; --i) {
492         if_debug3m('b', penum->memory, "[b]free plane %d row (0x%lx,%u)\n",
493                    i, (ulong)penum->planes[i].row.data,
494                    penum->planes[i].row.size);
495         gs_free_string(gs_image_row_memory(penum), penum->planes[i].row.data,
496                        penum->planes[i].row.size, cname);
497         penum->planes[i].row.data = 0;
498         penum->planes[i].row.size = 0;
499     }
500 }
501 
502 /* Process the next piece of an image. */
503 int
gs_image_next(gs_image_enum * penum,const byte * dbytes,uint dsize,uint * pused)504 gs_image_next(gs_image_enum * penum, const byte * dbytes, uint dsize,
505               uint * pused)
506 {
507     int px = penum->plane_index;
508     int num_planes = penum->num_planes;
509     int i, code;
510     uint used[GS_IMAGE_MAX_COMPONENTS];
511     gs_const_string plane_data[GS_IMAGE_MAX_COMPONENTS];
512 
513     if (penum->planes[px].source.size != 0)
514         return_error(gs_error_rangecheck);
515     for (i = 0; i < num_planes; i++)
516         plane_data[i].size = 0;
517     plane_data[px].data = dbytes;
518     plane_data[px].size = dsize;
519     penum->error = false;
520     code = gs_image_next_planes(penum, plane_data, used);
521     *pused = used[px];
522     if (code >= 0)
523         next_plane(penum);
524     return code;
525 }
526 
527 int
gs_image_next_planes(gs_image_enum * penum,gs_const_string * plane_data,uint * used)528 gs_image_next_planes(gs_image_enum * penum,
529                      gs_const_string *plane_data /*[num_planes]*/,
530                      uint *used /*[num_planes]*/)
531 {
532     const int num_planes = penum->num_planes;
533     int i;
534     int code = 0;
535 
536 #ifdef DEBUG
537     if (gs_debug_c('b')) {
538         int pi;
539 
540         for (pi = 0; pi < num_planes; ++pi)
541             dmprintf6(penum->memory, "[b]plane %d source=0x%lx,%u pos=%u data=0x%lx,%u\n",
542                      pi, (ulong)penum->planes[pi].source.data,
543                      penum->planes[pi].source.size, penum->planes[pi].pos,
544                      (ulong)plane_data[pi].data, plane_data[pi].size);
545     }
546 #endif
547     for (i = 0; i < num_planes; ++i) {
548         used[i] = 0;
549         if (penum->wanted[i] && plane_data[i].size != 0) {
550             penum->planes[i].source.size = plane_data[i].size;
551             penum->planes[i].source.data = plane_data[i].data;
552         }
553     }
554     for (;;) {
555         /* If wanted can vary, only transfer 1 row at a time. */
556         int h = (penum->wanted_varies ? 1 : max_int);
557 
558         /* Move partial rows from source[] to row[]. */
559         for (i = 0; i < num_planes; ++i) {
560             int pos, size;
561             uint raster;
562 
563             if (!penum->wanted[i])
564                 continue;	/* skip unwanted planes */
565             pos = penum->planes[i].pos;
566             size = penum->planes[i].source.size;
567             raster = penum->image_planes[i].raster;
568             if (size > 0) {
569                 if (pos < raster && (pos != 0 || size < raster)) {
570                     /* Buffer a partial row. */
571                     int copy = min(size, raster - pos);
572                     uint old_size = penum->planes[i].row.size;
573 
574                     /* Make sure the row buffer is fully allocated. */
575                     if (raster > old_size) {
576                         gs_memory_t *mem = gs_image_row_memory(penum);
577                         byte *old_data = penum->planes[i].row.data;
578                         byte *row =
579                             (old_data == 0 ?
580                              gs_alloc_string(mem, raster,
581                                              "gs_image_next(row)") :
582                              gs_resize_string(mem, old_data, old_size, raster,
583                                               "gs_image_next(row)"));
584 
585                         if_debug5m('b', mem, "[b]plane %d row (0x%lx,%u) => (0x%lx,%u)\n",
586                                    i, (ulong)old_data, old_size,
587                                    (ulong)row, raster);
588                         if (row == 0) {
589                             code = gs_note_error(gs_error_VMerror);
590                             free_row_buffers(penum, i, "gs_image_next(row)");
591                             break;
592                         }
593                         penum->planes[i].row.data = row;
594                         penum->planes[i].row.size = raster;
595                     }
596                     memcpy(penum->planes[i].row.data + pos,
597                            penum->planes[i].source.data, copy);
598                     penum->planes[i].source.data += copy;
599                     penum->planes[i].source.size = size -= copy;
600                     penum->planes[i].pos = pos += copy;
601                     used[i] += copy;
602                 }
603             }
604             if (h == 0)
605                 continue;	/* can't transfer any data this cycle */
606             if (pos == raster) {
607                 /*
608                  * This plane will be transferred from the row buffer,
609                  * so we can only transfer one row.
610                  */
611                 h = min(h, 1);
612                 penum->image_planes[i].data = penum->planes[i].row.data;
613             } else if (pos == 0 && size >= raster) {
614                 /* We can transfer 1 or more planes from the source. */
615                 if (raster) {
616                     h = min(h, size / raster);
617                     penum->image_planes[i].data = penum->planes[i].source.data;
618                 }
619                 else
620                     h = 0;
621             } else
622                 h = 0;		/* not enough data in this plane */
623         }
624         if (h == 0 || code != 0)
625             break;
626         /* Pass rows to the device. */
627         if (penum->dev == 0) {
628             /*
629              * ****** NOTE: THE FOLLOWING IS NOT CORRECT FOR ImageType 3
630              * ****** InterleaveType 2, SINCE MASK HEIGHT AND IMAGE HEIGHT
631              * ****** MAY DIFFER (BY AN INTEGER FACTOR).  ALSO, plane_depths[0]
632              * ****** AND plane_widths[0] ARE NOT UPDATED.
633          */
634             if (penum->y + h < penum->height)
635                 code = 0;
636             else
637                 h = penum->height - penum->y, code = 1;
638         } else {
639             code = gx_image_plane_data_rows(penum->info, penum->image_planes,
640                                             h, &h);
641             if_debug2m('b', penum->memory, "[b]used %d, code=%d\n", h, code);
642             penum->error = code < 0;
643         }
644         penum->y += h;
645         /* Update positions and sizes. */
646         if (h == 0)
647             break;
648         for (i = 0; i < num_planes; ++i) {
649             int count;
650 
651             if (!penum->wanted[i])
652                 continue;
653             count = penum->image_planes[i].raster * h;
654             if (penum->planes[i].pos) {
655                 /* We transferred the row from the row buffer. */
656                 penum->planes[i].pos = 0;
657             } else {
658                 /* We transferred the row(s) from the source. */
659                 penum->planes[i].source.data += count;
660                 penum->planes[i].source.size -= count;
661                 used[i] += count;
662             }
663         }
664         cache_planes(penum);
665         if (code > 0)
666             break;
667     }
668     /* Return the retained data pointers. */
669     for (i = 0; i < num_planes; ++i)
670         plane_data[i] = penum->planes[i].source;
671     return code;
672 }
673 
674 /* Clean up after processing an image. */
675 /* Public for ghostpcl. */
676 int
gs_image_cleanup(gs_image_enum * penum,gs_gstate * pgs)677 gs_image_cleanup(gs_image_enum * penum, gs_gstate *pgs)
678 {
679     int code = 0, code1;
680 
681     free_row_buffers(penum, penum->num_planes, "gs_image_cleanup(row)");
682     if (penum->info != 0) {
683         if (dev_proc(penum->info->dev, dev_spec_op)(penum->info->dev,
684                     gxdso_pattern_is_cpath_accum, NULL, 0)) {
685             /* Performing a conversion of imagemask into a clipping path. */
686             gx_device *cdev = penum->info->dev;
687 
688             code = gx_image_end(penum->info, !penum->error); /* Releases penum->info . */
689             code1 = gx_image_fill_masked_end(cdev, penum->dev, gs_currentdevicecolor_inline(pgs));
690             if (code == 0)
691                 code = code1;
692         } else
693             code = gx_image_end(penum->info, !penum->error);
694     }
695     /* Don't free the local enumerator -- the client does that. */
696 
697     return code;
698 }
699 
700 /* Clean up after processing an image and free the enumerator. */
701 int
gs_image_cleanup_and_free_enum(gs_image_enum * penum,gs_gstate * pgs)702 gs_image_cleanup_and_free_enum(gs_image_enum * penum, gs_gstate *pgs)
703 {
704     int code = gs_image_cleanup(penum, pgs);
705 
706     gs_free_object(penum->memory, penum, "gs_image_cleanup_and_free_enum");
707     return code;
708 }
709