Coverage Report

Created: 2026-08-08 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gxidata.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Generic image enumeration and cleanup */
18
#include "gx.h"
19
#include "memory_.h"
20
#include "gserrors.h"
21
#include "gxdevice.h"
22
#include "gxcpath.h"
23
#include "gximage.h"
24
#include "gsicc_cache.h"
25
#include "gxgstate.h"
26
27
#ifdef WITH_CAL
28
#include "cal.h"
29
#endif
30
31
/* Forward declarations */
32
static void update_strip(gx_image_enum *penum);
33
static void repack_bit_planes(const gx_image_plane_t *src_planes,
34
                               const ulong *offsets, int num_planes,
35
                               byte *buffer, int width,
36
                               const sample_lookup_t * ptab, int spread);
37
static gx_device *setup_image_device(const gx_image_enum *penum);
38
39
/* Process the next piece of an ImageType 1 image. */
40
int
41
gx_image1_plane_data(gx_image_enum_common_t * info,
42
                     const gx_image_plane_t * planes, int height,
43
                     int *rows_used)
44
29.2M
{
45
29.2M
    gx_image_enum *penum = (gx_image_enum *) info;
46
29.2M
    gx_device *dev;
47
29.2M
    const int y = penum->y;
48
29.2M
    int y_end = min(y + height, penum->rect.h);
49
29.2M
    int width_spp;
50
29.2M
    int num_planes = penum->num_planes;
51
29.2M
    int num_components_per_plane = 1;
52
53
29.2M
#define BCOUNT(plane)   /* bytes per data row */\
54
29.2M
  (((penum->rect.w + (plane).data_x) * penum->spp * penum->bps / num_planes\
55
25.6M
    + 7) >> 3)
56
57
29.2M
    fixed adjust = penum->adjust;
58
29.2M
    ulong offsets[GS_IMAGE_MAX_COMPONENTS];
59
29.2M
    int ignore_data_x;
60
29.2M
    bool bit_planar = penum->num_planes > penum->spp;
61
29.2M
    int code;
62
63
    /* Sanity check */
64
29.2M
    if (penum->pgs != NULL && penum->pgs->level < penum->pgs_level) {
65
0
        code = gs_note_error(gs_error_undefinedresult);
66
0
        goto out;
67
0
    }
68
29.2M
    if (height == 0) {
69
0
        *rows_used = 0;
70
0
        return 0;
71
0
    }
72
73
    /* width_spp is an 'int' and is passed in various places as an int (or sometimes uint) data type. Since this could
74
     * be (usually is) a 32-bit type we need to ensure we do not overflow an int. We specifically test against 'int'
75
     * rather than '32-bit' in case int isn't 32-bit on this system.
76
     */
77
29.2M
    if (check_int_multiply(penum->rect.w, penum->spp, &width_spp) != 0)
78
0
        return gs_note_error(gs_error_undefinedresult);
79
80
29.2M
    dev = setup_image_device(penum);
81
82
    /* Now render complete rows. */
83
84
29.2M
    if (penum->used.y) {
85
        /*
86
         * Processing was interrupted by an error.  Skip over rows
87
         * already processed.
88
         */
89
0
        int px;
90
91
0
        for (px = 0; px < num_planes; ++px)
92
0
            offsets[px] = (size_t)planes[px].raster * penum->used.y;
93
0
        penum->used.y = 0;
94
0
    } else
95
29.2M
        memset(offsets, 0, num_planes * sizeof(offsets[0]));
96
29.2M
    if (num_planes == 1 && penum->plane_depths[0] != penum->bps) {
97
        /* A single plane with multiple components. */
98
9.38M
        num_components_per_plane = penum->plane_depths[0] / penum->bps;
99
9.38M
    }
100
64.0M
    for (; penum->y < y_end; penum->y++) {
101
34.7M
        int px;
102
34.7M
        const byte *buffer;
103
34.7M
        int sourcex;
104
34.7M
        int x_used = penum->used.x;
105
34.7M
        int skip = 0;
106
107
        /* Bump DDA's if it doesn't cause overflow */
108
34.7M
        penum->cur.x = dda_current(penum->dda.row.x);
109
34.7M
        if (max_int - any_abs(penum->dda.row.x.step.dQ) > any_abs(penum->cur.x))
110
34.7M
            dda_next(penum->dda.row.x);
111
34.7M
        penum->cur.y = dda_current(penum->dda.row.y);
112
34.7M
        if (max_int - any_abs(penum->dda.row.y.step.dQ) > any_abs(penum->cur.y))
113
34.7M
            dda_next(penum->dda.row.y);
114
115
34.7M
        if (penum->interpolate == interp_off && penum->skip_next_line && penum->skip_next_line(penum, dev)) {
116
90.1k
            goto mt;
117
34.7M
        } else if (penum->skip_next_line == NULL) {
118
            /* Previously we skipped these calculations if we were interpolating.
119
             * Bug 706881 shows us that we can't skip this in all cases, because
120
             * the values are needed when halftoning for landscape files at least.
121
             * Easiest to always perform the calculations. */
122
27.7M
            switch (penum->posture) {
123
25.8M
                case image_portrait:
124
25.8M
                    {    /* Precompute integer y and height, */
125
                        /* and check for clipping. */
126
25.8M
                        fixed yc = penum->cur.y,
127
25.8M
                              yn = dda_current(penum->dda.row.y);
128
129
25.8M
                        if (yn < yc) {
130
645k
                            fixed temp = yn;
131
132
645k
                            yn = yc;
133
645k
                            yc = temp;
134
645k
                        }
135
25.8M
                        yc -= adjust;
136
25.8M
                        yn += adjust;
137
25.8M
                        if (penum->interpolate == interp_off)
138
25.8M
                        {
139
25.8M
                            if (yc >= penum->clip_outer.q.y)
140
3.02M
                                goto mt;
141
22.8M
                            if (yn <= penum->clip_outer.p.y)
142
1.56M
                                goto mt;
143
22.8M
                        }
144
21.3M
                        penum->yci = fixed2int_pixround_perfect(yc);
145
21.3M
                        penum->hci = fixed2int_pixround_perfect(yn) - penum->yci;
146
21.3M
                        if (penum->interpolate == interp_off && penum->hci == 0)
147
5.11M
                            goto mt;
148
21.3M
                        if_debug2m('b', penum->memory, "[b]yci=%d, hci=%d\n",
149
16.1M
                                   penum->yci, penum->hci);
150
16.1M
                    }
151
0
                    break;
152
1.07M
                case image_landscape:
153
1.07M
                    {    /* Check for no pixel centers in x. */
154
1.07M
                        fixed xc = penum->cur.x,
155
1.07M
                              xn = dda_current(penum->dda.row.x);
156
157
1.07M
                        if (xn < xc) {
158
4.68k
                            fixed temp = xn;
159
160
4.68k
                            xn = xc;
161
4.68k
                            xc = temp;
162
4.68k
                        }
163
1.07M
                        xc -= adjust;
164
1.07M
                        xn += adjust;
165
1.07M
                        if (penum->interpolate == interp_off)
166
1.07M
                        {
167
1.07M
                            if (xc >= penum->clip_outer.q.x)
168
1.16k
                                goto mt;
169
1.07M
                            if (xn <= penum->clip_outer.p.x)
170
57.4k
                                goto mt;
171
1.07M
                        }
172
1.01M
                        penum->xci = fixed2int_pixround_perfect(xc);
173
1.01M
                        penum->wci = fixed2int_pixround_perfect(xn) - penum->xci;
174
1.01M
                        if (penum->interpolate == interp_off && penum->wci == 0)
175
21.1k
                            goto mt;
176
1.01M
                        if_debug2m('b', penum->memory, "[b]xci=%d, wci=%d\n",
177
997k
                                   penum->xci, penum->wci);
178
997k
                    }
179
0
                    break;
180
792k
                case image_skewed:
181
792k
                    ;
182
27.7M
            }
183
27.7M
        }
184
24.9M
        if (0)
185
0
        {
186
9.87M
        mt:
187
9.87M
            skip = 1;
188
9.87M
        }
189
34.7M
        if (bit_planar) {
190
            /* Repack the bit planes into byte-wide samples. */
191
192
0
            buffer = penum->buffer;
193
0
            sourcex = 0;
194
0
            if (!skip)
195
0
                for (px = 0; px < num_planes; px += penum->bps)
196
0
                    repack_bit_planes(planes, offsets, penum->bps, penum->buffer,
197
0
                                      penum->rect.w, &penum->map[px].table,
198
0
                                      penum->spread);
199
0
            for (px = 0; px < num_planes; ++px)
200
0
                offsets[px] += planes[px].raster;
201
34.7M
        } else {
202
            /*
203
             * Normally, we unpack the data into the buffer, but if
204
             * there is only one plane and we don't need to expand the
205
             * input samples, we may use the data directly.
206
             */
207
34.7M
            sourcex = planes[0].data_x;
208
34.7M
            if (!skip)
209
24.9M
                buffer =
210
24.9M
                    (*penum->unpack)(penum->buffer, &sourcex,
211
24.9M
                                     planes[0].data + offsets[0],
212
24.9M
                                     planes[0].data_x, BCOUNT(planes[0]),
213
24.9M
                                     &penum->map[0], penum->spread, num_components_per_plane);
214
9.87M
            else
215
9.87M
                buffer = NULL;
216
217
34.7M
            offsets[0] += planes[0].raster;
218
35.5M
            for (px = 1; px < num_planes; ++px) {
219
705k
                if (!skip)
220
705k
                    (*penum->unpack)(penum->buffer + (px << penum->log2_xbytes),
221
705k
                                     &ignore_data_x,
222
705k
                                     planes[px].data + offsets[px],
223
705k
                                     planes[px].data_x, BCOUNT(planes[px]),
224
705k
                                     &penum->map[px], penum->spread, 1);
225
705k
                offsets[px] += planes[px].raster;
226
705k
            }
227
34.7M
        }
228
#ifdef DEBUG
229
        if (gs_debug_c('b'))
230
            dmprintf1(dev->memory, "[b]image1 y=%d\n", y);
231
        if (gs_debug_c('B')) {
232
            int i, n = width_spp;
233
            byte *buftemp = (buffer == NULL) ? penum->buffer : (byte *)buffer;
234
235
            if (penum->bps > 8)
236
                n *= 2;
237
            else if (penum->bps == 1 && penum->unpack_bps == 8)
238
                n = (n + 7) / 8;
239
            dmlputs(dev->memory, "[B]row:");
240
            for (i = 0; i < n; i++)
241
                dmprintf1(dev->memory, " %02x", buftemp[i]);
242
            dmputs(dev->memory, "\n");
243
        }
244
#endif
245
34.7M
        if (!skip)
246
24.9M
        {
247
24.9M
            update_strip(penum);
248
24.9M
            if (x_used) {
249
                /*
250
                 * Processing was interrupted by an error.  Skip over pixels
251
                 * already processed.
252
                 */
253
0
                dda_advance(penum->dda.pixel0.x, x_used);
254
0
                dda_advance(penum->dda.pixel0.y, x_used);
255
0
                penum->used.x = 0;
256
0
            }
257
24.9M
            if_debug2m('b', penum->memory, "[b]pixel0 x=%g, y=%g\n",
258
24.9M
                       fixed2float(dda_current(penum->dda.pixel0.x)),
259
24.9M
                       fixed2float(dda_current(penum->dda.pixel0.y)));
260
24.9M
            code = (*penum->render)(penum, buffer, sourcex + x_used,
261
24.9M
                                    width_spp - x_used * penum->spp, 1, dev);
262
24.9M
            if (code < 0) {
263
                /* Error or interrupt, restore original state. */
264
0
                penum->used.x += x_used;
265
0
                if (!penum->used.y) {
266
0
                    dda_previous(penum->dda.row.x);
267
0
                    dda_previous(penum->dda.row.y);
268
0
                    dda_translate(penum->dda.strip.x,
269
0
                                  penum->prev.x - penum->cur.x);
270
0
                    dda_translate(penum->dda.strip.y,
271
0
                                  penum->prev.y - penum->cur.y);
272
0
                }
273
0
                goto out;
274
0
            }
275
24.9M
            penum->prev = penum->cur;
276
24.9M
        }
277
34.7M
    }
278
29.2M
    if (penum->y < penum->rect.h) {
279
27.4M
        code = 0;
280
27.4M
    } else {
281
        /* End of input data.  Render any left-over buffered data. */
282
1.76M
        code = gx_image1_flush(info);
283
1.76M
        if (code >= 0)
284
1.76M
            code = 1;
285
1.76M
    }
286
29.2M
out:
287
    /* Note that caller must call end_image */
288
    /* for both error and normal termination. */
289
29.2M
    *rows_used = penum->y - y;
290
29.2M
    return code;
291
29.2M
}
292
293
/* Flush any buffered data. */
294
int
295
gx_image1_flush(gx_image_enum_common_t * info)
296
3.62M
{
297
3.62M
    gx_image_enum *penum = (gx_image_enum *)info;
298
3.62M
    int width_spp = penum->rect.w * penum->spp;
299
3.62M
    fixed adjust = penum->adjust;
300
301
3.62M
    penum->cur.x = dda_current(penum->dda.row.x);
302
3.62M
    penum->cur.y = dda_current(penum->dda.row.y);
303
3.62M
    switch (penum->posture) {
304
3.37M
        case image_portrait:
305
3.37M
            {
306
3.37M
                fixed yc = penum->cur.y;
307
308
3.37M
                penum->yci = fixed2int_rounded(yc - adjust);
309
3.37M
                penum->hci = fixed2int_rounded(yc + adjust) - penum->yci;
310
3.37M
            }
311
3.37M
            break;
312
200k
        case image_landscape:
313
200k
            {
314
200k
                fixed xc = penum->cur.x;
315
316
200k
                penum->xci = fixed2int_rounded(xc - adjust);
317
200k
                penum->wci = fixed2int_rounded(xc + adjust) - penum->xci;
318
200k
            }
319
200k
            break;
320
48.2k
        case image_skewed:  /* pacify compilers */
321
48.2k
            ;
322
3.62M
    }
323
3.62M
    update_strip(penum);
324
3.62M
    penum->prev = penum->cur;
325
3.62M
    return (*penum->render)(penum, NULL, 0, width_spp, 0,
326
3.62M
                            setup_image_device(penum));
327
3.62M
}
328
329
/* Update the strip DDA when moving to a new row. */
330
static void
331
update_strip(gx_image_enum *penum)
332
28.5M
{
333
334
28.5M
#if 1
335
    /* Old code. */
336
28.5M
    dda_translate(penum->dda.strip.x, penum->cur.x - penum->prev.x);
337
28.5M
    dda_translate(penum->dda.strip.y, penum->cur.y - penum->prev.y);
338
28.5M
    penum->dda.pixel0 = penum->dda.strip;
339
#else
340
    /* A better precision with stromng dda_advance -
341
       doesn't work becauae gx_image1_plane_data
342
       doesn't call it at each step. */
343
    gx_dda_fixed_point temp;
344
345
    temp.x.state = penum->dda.strip.x.state;
346
    temp.y.state = penum->dda.strip.y.state;
347
    temp.x.step = penum->dda.row.x.step;
348
    temp.y.step = penum->dda.row.y.step;
349
    dda_next(temp.x);
350
    dda_next(temp.y);
351
    penum->dda.strip.x.state = temp.x.state;
352
    penum->dda.strip.y.state = temp.y.state;
353
    penum->dda.pixel0 = penum->dda.strip;
354
#endif
355
28.5M
}
356
357
/*
358
 * Repack 1 to 8 individual bit planes into 8-bit samples.
359
 * buffer is aligned, and includes padding to an 8-byte boundary.
360
 * This procedure repacks one row, so the only relevant members of
361
 * src_planes are data and data_x (not raster).
362
 */
363
static void
364
repack_bit_planes(const gx_image_plane_t *src_planes, const ulong *offsets,
365
                  int num_planes, byte *buffer, int width,
366
                  const sample_lookup_t * ptab, int spread)
367
0
{
368
0
    gx_image_plane_t planes[8];
369
0
    byte *zeros = 0;
370
0
    byte *dest = buffer;
371
0
    int any_data_x = 0;
372
0
    bool direct = (spread == 1 && ptab->lookup8[0] == 0 &&
373
0
                   ptab->lookup8[255] == 255);
374
0
    int pi, x;
375
0
    gx_image_plane_t *pp;
376
377
    /*
378
     * Set up the row pointers, taking data_x and null planes into account.
379
     * If there are any null rows, we need to create a block of zeros in
380
     * order to avoid tests in the loop.
381
     */
382
0
    for (pi = 0, pp = planes; pi < num_planes; ++pi, ++pp)
383
0
        if (src_planes[pi].data == 0) {
384
0
            if (!zeros) {
385
0
                zeros = buffer + width - ((width + 7) >> 3);
386
0
            }
387
0
            pp->data = zeros;
388
0
            pp->data_x = 0;
389
0
        } else {
390
0
            int dx = src_planes[pi].data_x;
391
392
0
            pp->data = src_planes[pi].data + (dx >> 3) + offsets[pi];
393
0
            any_data_x |= (pp->data_x = dx & 7);
394
0
        }
395
0
    if (zeros)
396
0
        memset(zeros, 0, buffer + width - zeros);
397
398
    /*
399
     * Now process the data, in blocks of one input byte column
400
     * (8 output bytes).
401
     */
402
0
    for (x = 0; x < width; x += 8) {
403
0
        bits32 w0 = 0, w1 = 0;
404
#if ARCH_IS_BIG_ENDIAN
405
        static const bits32 expand[16] = {
406
            0x00000000, 0x00000001, 0x00000100, 0x00000101,
407
            0x00010000, 0x00010001, 0x00010100, 0x00010101,
408
            0x01000000, 0x01000001, 0x01000100, 0x01000101,
409
            0x01010000, 0x01010001, 0x01010100, 0x01010101
410
        };
411
#else
412
0
        static const bits32 expand[16] = {
413
0
            0x00000000, 0x01000000, 0x00010000, 0x01010000,
414
0
            0x00000100, 0x01000100, 0x00010100, 0x01010100,
415
0
            0x00000001, 0x01000001, 0x00010001, 0x01010001,
416
0
            0x00000101, 0x01000101, 0x00010101, 0x01010101
417
0
        };
418
0
#endif
419
420
0
        if (any_data_x) {
421
0
            for (pi = 0, pp = planes; pi < num_planes; ++pi, ++pp) {
422
0
                uint b = *(pp->data++);
423
0
                int dx = pp->data_x;
424
425
0
                if (dx) {
426
0
                    b <<= dx;
427
0
                    if (x + 8 - dx < width)
428
0
                        b += *pp->data >> (8 - dx);
429
0
                }
430
0
                w0 = (w0 << 1) | expand[b >> 4];
431
0
                w1 = (w1 << 1) | expand[b & 0xf];
432
0
            }
433
0
        } else {
434
0
            for (pi = 0, pp = planes; pi < num_planes; ++pi, ++pp) {
435
0
                uint b = *(pp->data++);
436
437
0
                w0 = (w0 << 1) | expand[b >> 4];
438
0
                w1 = (w1 << 1) | expand[b & 0xf];
439
0
            }
440
0
        }
441
        /*
442
         * We optimize spread == 1 and identity ptab together, although
443
         * we could subdivide these 2 cases into 4 if we wanted.
444
         */
445
0
        if (direct) {
446
0
            ((bits32 *)dest)[0] = w0;
447
0
            ((bits32 *)dest)[1] = w1;
448
0
            dest += 8;
449
0
        } else {
450
0
#define MAP_BYTE(v) (ptab->lookup8[(byte)(v)])
451
0
            dest[0] = MAP_BYTE(w0 >> 24); dest += spread;
452
0
            dest[1] = MAP_BYTE(w0 >> 16); dest += spread;
453
0
            dest[2] = MAP_BYTE(w0 >> 8); dest += spread;
454
0
            dest[3] = MAP_BYTE(w0); dest += spread;
455
0
            dest[4] = MAP_BYTE(w1 >> 24); dest += spread;
456
0
            dest[5] = MAP_BYTE(w1 >> 16); dest += spread;
457
0
            dest[6] = MAP_BYTE(w1 >> 8); dest += spread;
458
0
            dest[7] = MAP_BYTE(w1); dest += spread;
459
0
#undef MAP_BYTE
460
0
        }
461
0
    }
462
0
}
463
464
/* Set up the device for drawing an image. */
465
static gx_device *
466
setup_image_device(const gx_image_enum *penum)
467
32.8M
{
468
32.8M
    gx_device *dev = penum->dev;
469
470
32.8M
    if (penum->clip_dev) {
471
14.4M
        gx_device_clip *cdev = penum->clip_dev;
472
473
14.4M
        gx_device_set_target((gx_device_forward *)cdev, dev);
474
14.4M
        dev = (gx_device *) cdev;
475
14.4M
    }
476
32.8M
    if (penum->rop_dev) {
477
9.48k
        gx_device_rop_texture *rtdev = penum->rop_dev;
478
479
9.48k
        gx_device_set_target((gx_device_forward *)rtdev, dev);
480
9.48k
        dev = (gx_device *) rtdev;
481
9.48k
    }
482
32.8M
    return dev;
483
32.8M
}
484
485
/* Clean up by releasing the buffers. */
486
/* Currently we ignore draw_last. */
487
int
488
gx_image1_end_image(gx_image_enum_common_t * info, bool draw_last)
489
1.80M
{
490
1.80M
    gx_image_enum *penum = (gx_image_enum *) info;
491
1.80M
    gs_memory_t *mem = penum->memory;
492
1.80M
    stream_image_scale_state *scaler = penum->scaler;
493
494
1.80M
    if_debug2m('b', penum->memory, "[b]%send_image, y=%d\n",
495
1.80M
               (penum->y < penum->rect.h ? "premature " : ""), penum->y);
496
1.80M
    if (draw_last) {
497
1.79M
        int code = gx_image_flush(info);
498
499
1.79M
        if (code < 0)
500
0
            return code;
501
1.79M
    }
502
503
1.80M
    if (penum->tpr_state != NULL) {
504
480k
        transform_pixel_region_data data;
505
480k
        gx_device *dev = penum->dev;
506
480k
        if (penum->clip_dev)
507
57.4k
            dev = (gx_device *)penum->clip_dev;
508
480k
        if (penum->rop_dev)
509
0
            dev = (gx_device *)penum->rop_dev;
510
480k
        data.state = penum->tpr_state;
511
480k
        dev_proc(dev, transform_pixel_region)(dev, transform_pixel_region_end, &data);
512
480k
    }
513
    /* release the reference to the target */
514
1.80M
    if ( penum->rop_dev )
515
484
        gx_device_set_target((gx_device_forward *)penum->rop_dev, NULL);
516
    /* it is not clear (to me) why these are freed explicitly instead
517
       of using reference counting */
518
1.80M
    gs_free_object(mem, penum->rop_dev, "image RasterOp");
519
520
    /* We do now reference count the clip device, see bug #706771 */
521
1.80M
    rc_decrement(penum->clip_dev, "gx_image1_end_image");
522
1.80M
    penum->clip_dev = NULL;
523
524
1.80M
    if (scaler != 0) {
525
0
        (*scaler->templat->release) ((stream_state *) scaler);
526
0
        gs_free_object(mem, scaler, "image scaler state");
527
0
    }
528
1.80M
    if (penum->icc_link != NULL) {
529
1.07M
        gsicc_release_link(penum->icc_link);
530
1.07M
    }
531
1.80M
    if (penum->color_cache != NULL) {
532
1.97k
        gs_free_object(mem, penum->color_cache->device_contone,
533
1.97k
                        "device_contone");
534
1.97k
        gs_free_object(mem, penum->color_cache->is_transparent,
535
1.97k
                       "image is_transparent");
536
1.97k
        gs_free_object(mem, penum->color_cache, "image color cache");
537
1.97k
    }
538
1.80M
    if (penum->thresh_buffer != NULL) {
539
157k
        gs_free_object(mem, penum->thresh_buffer, "image thresh_buffer");
540
157k
    }
541
1.80M
    if (penum->ht_buffer != NULL) {
542
157k
        gs_free_object(mem, penum->ht_buffer, "image ht_buffer");
543
157k
    }
544
1.80M
    if (penum->clues != NULL) {
545
819k
        gs_free_object(mem,penum->clues, "image clues");
546
819k
    }
547
548
    /* decrement this ref that was incremented in gx_image_enum_begin() */
549
1.80M
    rc_decrement_only(penum->pcs, "pcs");
550
1.80M
    penum->pcs = NULL;
551
552
1.80M
    gs_free_object(mem, penum->line, "image line");
553
1.80M
    gs_free_object(mem, penum->buffer, "image buffer");
554
555
#ifdef WITH_CAL
556
    if (penum->cal_ht != NULL) {
557
        cal_halftone_fin(penum->cal_ht, mem->non_gc_memory);
558
    }
559
#endif
560
1.80M
    gx_image_free_enum(&info);
561
1.80M
    return 0;
562
1.80M
}