Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gsimage.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* Image 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
0
#define gs_image_enum_num_ptrs 2
124
125
/* GC procedures */
126
static
127
0
ENUM_PTRS_WITH(gs_image_enum_enum_ptrs, gs_image_enum *eptr)
128
0
{
129
    /* Enumerate the data planes. */
130
0
    index -= gs_image_enum_num_ptrs;
131
0
    if (index < eptr->num_planes)
132
0
        ENUM_RETURN_STRING_PTR(gs_image_enum, planes[index].source);
133
0
    index -= eptr->num_planes;
134
0
    if (index < eptr->num_planes)
135
0
        ENUM_RETURN_STRING_PTR(gs_image_enum, planes[index].row);
136
0
    return 0;
137
0
}
138
0
ENUM_PTR(0, gs_image_enum, dev);
139
0
ENUM_PTR(1, gs_image_enum, info);
140
0
ENUM_PTRS_END
141
0
static RELOC_PTRS_WITH(gs_image_enum_reloc_ptrs, gs_image_enum *eptr)
142
0
{
143
0
    int i;
144
145
0
    RELOC_PTR(gs_image_enum, dev);
146
0
    RELOC_PTR(gs_image_enum, info);
147
0
    for (i = 0; i < eptr->num_planes; i++)
148
0
        RELOC_CONST_STRING_PTR(gs_image_enum, planes[i].source);
149
0
    for (i = 0; i < eptr->num_planes; i++)
150
0
        RELOC_STRING_PTR(gs_image_enum, planes[i].row);
151
0
}
152
0
RELOC_PTRS_END
153
154
static int
155
is_image_visible(const gs_image_common_t * pic, gs_gstate * pgs, gx_clip_path *pcpath)
156
55.4k
{
157
55.4k
    gs_rect image_rect = {{0, 0}, {0, 0}};
158
55.4k
    gs_rect device_rect;
159
55.4k
    gs_int_rect device_int_rect;
160
55.4k
    gs_matrix mat;
161
55.4k
    int code;
162
163
55.4k
    image_rect.q.x = pic->Width;
164
55.4k
    image_rect.q.y = pic->Height;
165
55.4k
    if (pic->ImageMatrix.xx == ctm_only(pgs).xx &&
166
55.4k
        pic->ImageMatrix.xy == ctm_only(pgs).xy &&
167
55.4k
        pic->ImageMatrix.yx == ctm_only(pgs).yx &&
168
55.4k
        pic->ImageMatrix.yy == ctm_only(pgs).yy) {
169
        /* Handle common special case separately to accept singular matrix */
170
8.65k
        mat.xx = mat.yy = 1.;
171
8.65k
        mat.yx = mat.xy = 0.;
172
8.65k
        mat.tx = ctm_only(pgs).tx - pic->ImageMatrix.tx;
173
8.65k
        mat.ty = ctm_only(pgs).ty - pic->ImageMatrix.ty;
174
46.8k
    } else {
175
46.8k
        code = gs_matrix_invert(&pic->ImageMatrix, &mat);
176
46.8k
        if (code < 0)
177
0
            return code;
178
46.8k
        code = gs_matrix_multiply(&mat, &ctm_only(pgs), &mat);
179
46.8k
        if (code < 0)
180
0
            return code;
181
46.8k
    }
182
55.4k
    code = gs_bbox_transform(&image_rect, &mat, &device_rect);
183
55.4k
    if (code < 0)
184
0
        return code;
185
55.4k
    device_int_rect.p.x = (int)floor(device_rect.p.x);
186
55.4k
    device_int_rect.p.y = (int)floor(device_rect.p.y);
187
55.4k
    device_int_rect.q.x = (int)ceil(device_rect.q.x);
188
55.4k
    device_int_rect.q.y = (int)ceil(device_rect.q.y);
189
55.4k
    if (!gx_cpath_rect_visible(pcpath, &device_int_rect))
190
8.73k
        return 0;
191
46.7k
    return 1;
192
55.4k
}
193
194
/* Create an image enumerator given image parameters and a graphics state. */
195
int
196
gs_image_begin_typed(const gs_image_common_t * pic, gs_gstate * pgs,
197
                     bool uses_color, bool image_is_text, gx_image_enum_common_t ** ppie)
198
55.6k
{
199
55.6k
    gx_device *dev = gs_currentdevice(pgs);
200
55.6k
    gx_clip_path *pcpath;
201
55.6k
    int code = gx_effective_clip_path(pgs, &pcpath);
202
55.6k
    gx_device *dev2 = dev;
203
55.6k
    gx_device_color dc_temp, *pdevc = gs_currentdevicecolor_inline(pgs);
204
205
55.6k
    if (code < 0)
206
0
        return code;
207
    /* Processing an image object operation, but this may be for a text object */
208
55.6k
    ensure_tag_is_set(pgs, pgs->device, image_is_text ? GS_TEXT_TAG : GS_IMAGE_TAG);  /* NB: may unset_dev_color */
209
210
55.6k
    if (uses_color) {
211
16.4k
        code = gx_set_dev_color(pgs);
212
16.4k
        if (code != 0)
213
2
            return code;
214
16.4k
        code = gs_gstate_color_load(pgs);
215
16.4k
        if (code < 0)
216
0
            return code;
217
16.4k
    }
218
219
55.6k
    if (pgs->overprint || (!pgs->overprint && dev_proc(pgs->device, dev_spec_op)(pgs->device,
220
55.5k
        gxdso_overprint_active, NULL, 0))) {
221
32
        gs_overprint_params_t op_params = { 0 };
222
223
32
        if_debug0m(gs_debug_flag_overprint, pgs->memory,
224
32
            "[overprint] Image Overprint\n");
225
32
        code = gs_do_set_overprint(pgs);
226
32
        if (code < 0)
227
0
            return code;
228
229
32
        op_params.op_state = OP_STATE_FILL;
230
32
        gs_gstate_update_overprint(pgs, &op_params);
231
232
32
        dev = gs_currentdevice(pgs);
233
32
        dev2 = dev;
234
32
    }
235
236
    /* Imagemask with shading color needs a special optimization
237
       with converting the image into a clipping.
238
       Check for such case after gs_gstate_color_load is done,
239
       because it can cause interpreter callout.
240
     */
241
55.6k
    if (pic->type->begin_typed_image == &gx_begin_image1) {
242
55.0k
        gs_image_t *image = (gs_image_t *)pic;
243
244
55.0k
        if(image->ImageMask) {
245
16.4k
            bool transpose = false;
246
16.4k
            gs_matrix_double mat;
247
248
16.4k
            if((code = gx_image_compute_mat(pgs, NULL, &(image->ImageMatrix), &mat)) < 0)
249
0
                return code;
250
16.4k
            if ((any_abs(mat.xy) > any_abs(mat.xx)) && (any_abs(mat.yx) > any_abs(mat.yy)))
251
121
                transpose = true;   /* pure landscape */
252
16.4k
            code = gx_image_fill_masked_start(dev, gs_currentdevicecolor_inline(pgs), transpose,
253
16.4k
                                              pcpath, pgs->memory, pgs->log_op, &dev2);
254
16.4k
            if (code < 0)
255
0
                return code;
256
16.4k
        }
257
55.0k
        if (dev->interpolate_control < 0) {   /* Force interpolation before begin_typed_image */
258
941
            ((gs_data_image_t *)pic)->Interpolate = true;
259
941
        }
260
54.0k
        else if (dev->interpolate_control == 0) {
261
54.0k
            ((gs_data_image_t *)pic)->Interpolate = false; /* Suppress interpolation */
262
54.0k
        }
263
55.0k
        if (dev2 != dev) {
264
90
            set_nonclient_dev_color(&dc_temp, 1);
265
90
            pdevc = &dc_temp;
266
90
        }
267
55.0k
    }
268
55.6k
    code = gx_device_begin_typed_image(dev2, (const gs_gstate *)pgs,
269
55.6k
                NULL, pic, NULL, pdevc, pcpath, pgs->memory, ppie);
270
55.6k
    if (code < 0)
271
148
        return code;
272
55.4k
    code = is_image_visible(pic, pgs, pcpath);
273
55.4k
    if (code < 0)
274
0
        return code;
275
55.4k
    if (!code)
276
8.73k
        (*ppie)->skipping = true;
277
55.4k
    return 0;
278
55.4k
}
279
280
/* Allocate an image enumerator. */
281
static void
282
image_enum_init(gs_image_enum * penum)
283
110k
{
284
    /* Clean pointers for GC. */
285
110k
    penum->info = 0;
286
110k
    penum->dev = 0;
287
110k
    penum->plane_index = 0;
288
110k
    penum->num_planes = 0;
289
110k
}
290
gs_image_enum *
291
gs_image_enum_alloc(gs_memory_t * mem, client_name_t cname)
292
55.6k
{
293
55.6k
    gs_image_enum *penum =
294
55.6k
        gs_alloc_struct(mem, gs_image_enum, &st_gs_image_enum, cname);
295
296
55.6k
    if (penum != 0) {
297
55.6k
        penum->memory = mem;
298
55.6k
        image_enum_init(penum);
299
55.6k
    }
300
55.6k
    return penum;
301
55.6k
}
302
303
/* Start processing an ImageType 1 image. */
304
int
305
gs_image_init(gs_image_enum * penum, const gs_image_t * pim, bool multi,
306
              bool image_is_text, gs_gstate * pgs)
307
8.64k
{
308
8.64k
    gs_image_t image;
309
8.64k
    gx_image_enum_common_t *pie;
310
8.64k
    int code;
311
312
8.64k
    image = *pim;
313
8.64k
    if (image.ImageMask) {
314
8.64k
        image.ColorSpace = NULL;
315
8.64k
        if (pgs->in_cachedevice <= 1)
316
8.64k
            image.adjust = false;
317
8.64k
    } else {
318
0
        if (pgs->in_cachedevice)
319
0
            return_error(gs_error_undefined);
320
0
        if (image.ColorSpace == NULL) {
321
            /*
322
             * Use of a non-current color space is potentially
323
             * incorrect, but it appears this case doesn't arise.
324
             */
325
0
            image.ColorSpace = gs_cspace_new_DeviceGray(pgs->memory);
326
0
            if (image.ColorSpace == NULL)
327
0
                return_error(gs_error_VMerror);
328
0
        }
329
0
    }
330
8.64k
    code = gs_image_begin_typed((const gs_image_common_t *)&image, pgs,
331
8.64k
                                image.ImageMask | image.CombineWithColor,
332
8.64k
                                image_is_text, &pie);
333
8.64k
    if (code < 0)
334
0
        return code;
335
8.64k
    return gs_image_enum_init(penum, pie, (const gs_data_image_t *)&image,
336
8.64k
                              pgs);
337
8.64k
}
338
339
/*
340
 * Return the number of bytes of data per row for a given plane.
341
 */
342
inline uint
343
gs_image_bytes_per_plane_row(const gs_image_enum * penum, int plane)
344
239k
{
345
239k
    const gx_image_enum_common_t *pie = penum->info;
346
347
239k
    return (pie->plane_widths[plane] * pie->plane_depths[plane] + 7) >> 3;
348
239k
}
349
350
/* Cache information when initializing, or after transferring plane data. */
351
static void
352
cache_planes(gs_image_enum *penum)
353
3.75M
{
354
3.75M
    int i;
355
356
3.75M
    if (penum->wanted_varies) {
357
148k
        penum->wanted_varies =
358
148k
            !gx_image_planes_wanted(penum->info, penum->wanted);
359
390k
        for (i = 0; i < penum->num_planes; ++i)
360
241k
            if (penum->wanted[i])
361
239k
                penum->image_planes[i].raster =
362
239k
                    gs_image_bytes_per_plane_row(penum, i);
363
2.59k
            else
364
2.59k
                penum->image_planes[i].data = 0;
365
148k
    }
366
3.75M
}
367
/* Advance to the next wanted plane. */
368
static void
369
next_plane(gs_image_enum *penum)
370
1.92M
{
371
1.92M
    int px = penum->plane_index;
372
373
1.92M
    do {
374
1.92M
        if (++px == penum->num_planes)
375
1.86M
            px = 0;
376
1.92M
    } while (!penum->wanted[px]);
377
1.92M
    penum->plane_index = px;
378
1.92M
}
379
/*
380
 * Initialize plane_index and (if appropriate) wanted and
381
 * wanted_varies at the beginning of a group of planes.
382
 */
383
static void
384
begin_planes(gs_image_enum *penum)
385
55.3k
{
386
55.3k
    cache_planes(penum);
387
55.3k
    penum->plane_index = -1;
388
55.3k
    next_plane(penum);
389
55.3k
}
390
391
int
392
gs_image_common_init(gs_image_enum * penum, gx_image_enum_common_t * pie,
393
            const gs_data_image_t * pim, gx_device * dev)
394
55.4k
{
395
    /*
396
     * HACK : For a compatibility with gs_image_cleanup_and_free_enum,
397
     * penum->memory must be initialized in advance
398
     * with the memory heap that owns *penum.
399
     */
400
55.4k
    int i;
401
402
55.4k
    if (pim->Width == 0 || pim->Height == 0) {
403
147
        gx_device *cdev = pie->dev;
404
405
147
        gx_image_end(pie, false);
406
147
        if (dev_proc(cdev, dev_spec_op)(cdev,
407
147
                    gxdso_pattern_is_cpath_accum, NULL, 0))
408
11
            gx_device_retain((gx_device *)cdev, false);
409
147
        return 1;
410
147
    }
411
55.3k
    image_enum_init(penum);
412
55.3k
    penum->dev = dev;
413
55.3k
    penum->info = pie;
414
55.3k
    penum->num_planes = pie->num_planes;
415
    /*
416
     * Note that for ImageType 3 InterleaveType 2, penum->height (the
417
     * expected number of data rows) differs from pim->Height (the height
418
     * of the source image in scan lines).  This doesn't normally cause
419
     * any problems, because penum->height is not used to determine when
420
     * all the data has been processed: that is up to the plane_data
421
     * procedure for the specific image type.
422
     */
423
55.3k
    penum->height = pim->Height;
424
111k
    for (i = 0; i < pie->num_planes; ++i) {
425
55.8k
        penum->planes[i].pos = 0;
426
55.8k
        penum->planes[i].source.size = 0; /* for gs_image_next_planes */
427
55.8k
        penum->planes[i].source.data = 0; /* for GC */
428
55.8k
        penum->planes[i].row.data = 0; /* for GC */
429
55.8k
        penum->planes[i].row.size = 0; /* ditto */
430
55.8k
        penum->image_planes[i].data_x = 0; /* just init once, never changes */
431
55.8k
    }
432
    /* Initialize the dynamic part of the state. */
433
55.3k
    penum->y = 0;
434
55.3k
    penum->error = false;
435
55.3k
    penum->wanted_varies = true;
436
55.3k
    begin_planes(penum);
437
55.3k
    return 0;
438
55.4k
}
439
440
/* Initialize an enumerator for a general image.
441
   penum->memory must be initialized in advance.
442
*/
443
int
444
gs_image_enum_init(gs_image_enum * penum, gx_image_enum_common_t * pie,
445
                   const gs_data_image_t * pim, gs_gstate *pgs)
446
55.4k
{
447
55.4k
    pgs->device->sgr.stroke_stored = false;
448
55.4k
    return gs_image_common_init(penum, pie, pim,
449
55.4k
                                (pgs->in_charpath ? NULL :
450
55.4k
                                 gs_currentdevice_inline(pgs)));
451
55.4k
}
452
453
/* Return the set of planes wanted. */
454
const byte *
455
gs_image_planes_wanted(gs_image_enum *penum)
456
35.3k
{
457
35.3k
    int i;
458
459
    /*
460
     * A plane is wanted at this interface if it is wanted by the
461
     * underlying machinery and has no buffered or retained data.
462
     */
463
81.5k
    for (i = 0; i < penum->num_planes; ++i)
464
46.2k
        penum->client_wanted[i] =
465
46.2k
            (penum->wanted[i] &&
466
46.2k
             penum->planes[i].pos + penum->planes[i].source.size <
467
46.2k
               penum->image_planes[i].raster);
468
35.3k
    return penum->client_wanted;
469
35.3k
}
470
471
/*
472
 * Return the enumerator memory used for allocating the row buffers.
473
 * Because some PostScript files use save/restore within an image data
474
 * reading procedure, this must be a stable allocator.
475
 */
476
static gs_memory_t *
477
gs_image_row_memory(const gs_image_enum *penum)
478
140k
{
479
140k
    return gs_memory_stable(penum->memory);
480
140k
}
481
482
/* Free the row buffers when cleaning up. */
483
static void
484
free_row_buffers(gs_image_enum *penum, int num_planes, client_name_t cname)
485
55.6k
{
486
55.6k
    int i;
487
488
111k
    for (i = num_planes - 1; i >= 0; --i) {
489
55.8k
        if_debug3m('b', penum->memory, "[b]free plane %d row ("PRI_INTPTR",%u)\n",
490
55.8k
                   i, (intptr_t)penum->planes[i].row.data,
491
55.8k
                   penum->planes[i].row.size);
492
55.8k
        gs_free_string(gs_image_row_memory(penum), penum->planes[i].row.data,
493
55.8k
                       penum->planes[i].row.size, cname);
494
55.8k
        penum->planes[i].row.data = 0;
495
55.8k
        penum->planes[i].row.size = 0;
496
55.8k
    }
497
55.6k
}
498
499
/* Process the next piece of an image. */
500
int
501
gs_image_next(gs_image_enum * penum, const byte * dbytes, uint dsize,
502
              uint * pused)
503
1.86M
{
504
1.86M
    int px = penum->plane_index;
505
1.86M
    int num_planes = penum->num_planes;
506
1.86M
    int i, code;
507
1.86M
    uint used[GS_IMAGE_MAX_COMPONENTS];
508
1.86M
    gs_const_string plane_data[GS_IMAGE_MAX_COMPONENTS];
509
510
1.86M
    if (penum->planes[px].source.size != 0)
511
0
        return_error(gs_error_rangecheck);
512
3.73M
    for (i = 0; i < num_planes; i++)
513
1.86M
        plane_data[i].size = 0;
514
1.86M
    plane_data[px].data = dbytes;
515
1.86M
    plane_data[px].size = dsize;
516
1.86M
    penum->error = false;
517
1.86M
    code = gs_image_next_planes(penum, plane_data, used);
518
1.86M
    *pused = used[px];
519
1.86M
    if (code >= 0)
520
1.86M
        next_plane(penum);
521
1.86M
    return code;
522
1.86M
}
523
524
int
525
gs_image_next_planes(gs_image_enum * penum,
526
                     gs_const_string *plane_data /*[num_planes]*/,
527
                     uint *used /*[num_planes]*/)
528
3.58M
{
529
3.58M
    const int num_planes = penum->num_planes;
530
3.58M
    int i;
531
3.58M
    int code = 0;
532
533
#ifdef DEBUG
534
    if (gs_debug_c('b')) {
535
        int pi;
536
537
        for (pi = 0; pi < num_planes; ++pi)
538
            dmprintf6(penum->memory, "[b]plane %d source="PRI_INTPTR",%u pos=%u data="PRI_INTPTR",%u\n",
539
                     pi, (intptr_t)penum->planes[pi].source.data,
540
                     penum->planes[pi].source.size, penum->planes[pi].pos,
541
                     (intptr_t)plane_data[pi].data, plane_data[pi].size);
542
    }
543
#endif
544
7.22M
    for (i = 0; i < num_planes; ++i) {
545
3.64M
        used[i] = 0;
546
3.64M
        if (penum->wanted[i] && plane_data[i].size != 0) {
547
3.63M
            penum->planes[i].source.size = plane_data[i].size;
548
3.63M
            penum->planes[i].source.data = plane_data[i].data;
549
3.63M
        }
550
3.64M
    }
551
7.23M
    for (;;) {
552
        /* If wanted can vary, only transfer 1 row at a time. */
553
7.23M
        int h = (penum->wanted_varies ? 1 : max_int);
554
555
        /* Move partial rows from source[] to row[]. */
556
14.6M
        for (i = 0; i < num_planes; ++i) {
557
7.38M
            int pos, size;
558
7.38M
            uint raster;
559
560
7.38M
            if (!penum->wanted[i])
561
2.60k
                continue;  /* skip unwanted planes */
562
7.38M
            pos = penum->planes[i].pos;
563
7.38M
            size = penum->planes[i].source.size;
564
7.38M
            raster = penum->image_planes[i].raster;
565
7.38M
            if (size > 0) {
566
4.83M
                if (pos < raster && (pos != 0 || size < raster)) {
567
                    /* Buffer a partial row. */
568
1.79M
                    int copy = min(size, raster - pos);
569
1.79M
                    uint old_size = penum->planes[i].row.size;
570
571
                    /* Make sure the row buffer is fully allocated. */
572
1.79M
                    if (raster > old_size) {
573
28.2k
                        gs_memory_t *mem = gs_image_row_memory(penum);
574
28.2k
                        byte *old_data = penum->planes[i].row.data;
575
28.2k
                        byte *row =
576
28.2k
                            (old_data == 0 ?
577
28.2k
                             gs_alloc_string(mem, raster,
578
28.2k
                                             "gs_image_next(row)") :
579
28.2k
                             gs_resize_string(mem, old_data, old_size, raster,
580
28.2k
                                              "gs_image_next(row)"));
581
582
28.2k
                        if_debug5m('b', mem, "[b]plane %d row ("PRI_INTPTR",%u) => ("PRI_INTPTR",%u)\n",
583
28.2k
                                   i, (intptr_t)old_data, old_size,
584
28.2k
                                   (intptr_t)row, raster);
585
28.2k
                        if (row == 0) {
586
0
                            code = gs_note_error(gs_error_VMerror);
587
0
                            free_row_buffers(penum, i, "gs_image_next(row)");
588
0
                            break;
589
0
                        }
590
28.2k
                        penum->planes[i].row.data = row;
591
28.2k
                        penum->planes[i].row.size = raster;
592
28.2k
                    }
593
1.79M
                    memcpy(penum->planes[i].row.data + pos,
594
1.79M
                           penum->planes[i].source.data, copy);
595
1.79M
                    penum->planes[i].source.data += copy;
596
1.79M
                    penum->planes[i].source.size = size -= copy;
597
1.79M
                    penum->planes[i].pos = pos += copy;
598
1.79M
                    used[i] += copy;
599
1.79M
                }
600
4.83M
            }
601
7.38M
            if (h == 0)
602
2.82k
                continue;  /* can't transfer any data this cycle */
603
7.37M
            if (pos == raster) {
604
                /*
605
                 * This plane will be transferred from the row buffer,
606
                 * so we can only transfer one row.
607
                 */
608
800k
                h = min(h, 1);
609
800k
                penum->image_planes[i].data = penum->planes[i].row.data;
610
6.57M
            } else if (pos == 0 && size >= raster) {
611
                /* We can transfer 1 or more planes from the source. */
612
3.03M
                if (raster) {
613
3.03M
                    h = min(h, size / raster);
614
3.03M
                    penum->image_planes[i].data = penum->planes[i].source.data;
615
3.03M
                }
616
0
                else
617
0
                    h = 0;
618
3.03M
            } else
619
3.53M
                h = 0;   /* not enough data in this plane */
620
7.37M
        }
621
7.23M
        if (h == 0 || code != 0)
622
3.53M
            break;
623
        /* Pass rows to the device. */
624
3.69M
        if (penum->dev == 0) {
625
            /*
626
             * ****** NOTE: THE FOLLOWING IS NOT CORRECT FOR ImageType 3
627
             * ****** InterleaveType 2, SINCE MASK HEIGHT AND IMAGE HEIGHT
628
             * ****** MAY DIFFER (BY AN INTEGER FACTOR).  ALSO, plane_depths[0]
629
             * ****** AND plane_widths[0] ARE NOT UPDATED.
630
         */
631
0
            if (penum->y + h < penum->height)
632
0
                code = 0;
633
0
            else
634
0
                h = penum->height - penum->y, code = 1;
635
3.69M
        } else {
636
3.69M
            code = gx_image_plane_data_rows(penum->info, penum->image_planes,
637
3.69M
                                            h, &h);
638
3.69M
            if_debug2m('b', penum->memory, "[b]used %d, code=%d\n", h, code);
639
3.69M
            penum->error = code < 0;
640
3.69M
        }
641
3.69M
        penum->y += h;
642
        /* Update positions and sizes. */
643
3.69M
        if (h == 0)
644
0
            break;
645
7.48M
        for (i = 0; i < num_planes; ++i) {
646
3.79M
            int count;
647
648
3.79M
            if (!penum->wanted[i])
649
2.58k
                continue;
650
3.78M
            count = penum->image_planes[i].raster * h;
651
3.78M
            if (penum->planes[i].pos) {
652
                /* We transferred the row from the row buffer. */
653
800k
                penum->planes[i].pos = 0;
654
2.98M
            } else {
655
                /* We transferred the row(s) from the source. */
656
2.98M
                penum->planes[i].source.data += count;
657
2.98M
                penum->planes[i].source.size -= count;
658
2.98M
                used[i] += count;
659
2.98M
            }
660
3.78M
        }
661
3.69M
        cache_planes(penum);
662
3.69M
        if (code > 0)
663
49.0k
            break;
664
3.69M
    }
665
    /* Return the retained data pointers. */
666
7.22M
    for (i = 0; i < num_planes; ++i)
667
3.64M
        plane_data[i] = penum->planes[i].source;
668
3.58M
    return code;
669
3.58M
}
670
671
/* Clean up after processing an image. */
672
/* Public for ghostpcl. */
673
int
674
gs_image_cleanup(gs_image_enum * penum, gs_gstate *pgs)
675
55.6k
{
676
55.6k
    int code = 0, code1;
677
678
55.6k
    free_row_buffers(penum, penum->num_planes, "gs_image_cleanup(row)");
679
55.6k
    if (penum->info != 0) {
680
55.3k
        if (dev_proc(penum->info->dev, dev_spec_op)(penum->info->dev,
681
55.3k
                    gxdso_pattern_is_cpath_accum, NULL, 0)) {
682
            /* Performing a conversion of imagemask into a clipping path. */
683
79
            gx_device *cdev = penum->info->dev;
684
685
79
            code = gx_image_end(penum->info, !penum->error); /* Releases penum->info . */
686
79
            code1 = gx_image_fill_masked_end(cdev, penum->dev, gs_currentdevicecolor_inline(pgs));
687
79
            if (code == 0)
688
79
                code = code1;
689
79
        } else
690
55.2k
            code = gx_image_end(penum->info, !penum->error);
691
55.3k
    }
692
    /* Don't free the local enumerator -- the client does that. */
693
694
55.6k
    return code;
695
55.6k
}
696
697
/* Clean up after processing an image and free the enumerator. */
698
int
699
gs_image_cleanup_and_free_enum(gs_image_enum * penum, gs_gstate *pgs)
700
55.6k
{
701
55.6k
    int code;
702
703
55.6k
    if (penum == NULL)
704
0
            return 0;
705
55.6k
    code = gs_image_cleanup(penum, pgs);
706
707
55.6k
    gs_free_object(penum->memory, penum, "gs_image_cleanup_and_free_enum");
708
55.6k
    return code;
709
55.6k
}