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