Coverage Report

Created: 2026-04-01 07:17

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
39.9M
{
45
39.9M
    gx_image_enum *penum = (gx_image_enum *) info;
46
39.9M
    gx_device *dev;
47
39.9M
    const int y = penum->y;
48
39.9M
    int y_end = min(y + height, penum->rect.h);
49
39.9M
    int width_spp;
50
39.9M
    int num_planes = penum->num_planes;
51
39.9M
    int num_components_per_plane = 1;
52
53
39.9M
#define BCOUNT(plane)   /* bytes per data row */\
54
39.9M
  (((penum->rect.w + (plane).data_x) * penum->spp * penum->bps / num_planes\
55
34.3M
    + 7) >> 3)
56
57
39.9M
    fixed adjust = penum->adjust;
58
39.9M
    ulong offsets[GS_IMAGE_MAX_COMPONENTS];
59
39.9M
    int ignore_data_x;
60
39.9M
    bool bit_planar = penum->num_planes > penum->spp;
61
39.9M
    int code;
62
63
    /* Sanity check */
64
39.9M
    if (penum->pgs != NULL && penum->pgs->level < penum->pgs_level) {
65
1
        code = gs_note_error(gs_error_undefinedresult);
66
1
        goto out;
67
1
    }
68
39.9M
    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
39.9M
    if (check_int_multiply(penum->rect.w, penum->spp, &width_spp) != 0)
78
0
        return gs_note_error(gs_error_undefinedresult);
79
80
39.9M
    dev = setup_image_device(penum);
81
82
    /* Now render complete rows. */
83
84
39.9M
    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
39.9M
        memset(offsets, 0, num_planes * sizeof(offsets[0]));
96
39.9M
    if (num_planes == 1 && penum->plane_depths[0] != penum->bps) {
97
        /* A single plane with multiple components. */
98
6.76M
        num_components_per_plane = penum->plane_depths[0] / penum->bps;
99
6.76M
    }
100
87.2M
    for (; penum->y < y_end; penum->y++) {
101
47.2M
        int px;
102
47.2M
        const byte *buffer;
103
47.2M
        int sourcex;
104
47.2M
        int x_used = penum->used.x;
105
47.2M
        int skip = 0;
106
107
        /* Bump DDA's if it doesn't cause overflow */
108
47.2M
        penum->cur.x = dda_current(penum->dda.row.x);
109
47.2M
        if (max_int - any_abs(penum->dda.row.x.step.dQ) > any_abs(penum->cur.x))
110
47.2M
            dda_next(penum->dda.row.x);
111
47.2M
        penum->cur.y = dda_current(penum->dda.row.y);
112
47.2M
        if (max_int - any_abs(penum->dda.row.y.step.dQ) > any_abs(penum->cur.y))
113
47.2M
            dda_next(penum->dda.row.y);
114
115
47.2M
        if (penum->interpolate == interp_off && penum->skip_next_line && penum->skip_next_line(penum, dev)) {
116
95.6k
            goto mt;
117
47.1M
        } 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
42.3M
            switch (penum->posture) {
123
37.5M
                case image_portrait:
124
37.5M
                    {    /* Precompute integer y and height, */
125
                        /* and check for clipping. */
126
37.5M
                        fixed yc = penum->cur.y,
127
37.5M
                              yn = dda_current(penum->dda.row.y);
128
129
37.5M
                        if (yn < yc) {
130
740k
                            fixed temp = yn;
131
132
740k
                            yn = yc;
133
740k
                            yc = temp;
134
740k
                        }
135
37.5M
                        yc -= adjust;
136
37.5M
                        yn += adjust;
137
37.5M
                        if (penum->interpolate == interp_off)
138
37.5M
                        {
139
37.5M
                            if (yc >= penum->clip_outer.q.y)
140
8.15M
                                goto mt;
141
29.3M
                            if (yn <= penum->clip_outer.p.y)
142
1.72M
                                goto mt;
143
29.3M
                        }
144
27.6M
                        penum->yci = fixed2int_pixround_perfect(yc);
145
27.6M
                        penum->hci = fixed2int_pixround_perfect(yn) - penum->yci;
146
27.6M
                        if (penum->interpolate == interp_off && penum->hci == 0)
147
3.57M
                            goto mt;
148
27.6M
                        if_debug2m('b', penum->memory, "[b]yci=%d, hci=%d\n",
149
24.0M
                                   penum->yci, penum->hci);
150
24.0M
                    }
151
0
                    break;
152
1.29M
                case image_landscape:
153
1.29M
                    {    /* Check for no pixel centers in x. */
154
1.29M
                        fixed xc = penum->cur.x,
155
1.29M
                              xn = dda_current(penum->dda.row.x);
156
157
1.29M
                        if (xn < xc) {
158
4.76k
                            fixed temp = xn;
159
160
4.76k
                            xn = xc;
161
4.76k
                            xc = temp;
162
4.76k
                        }
163
1.29M
                        xc -= adjust;
164
1.29M
                        xn += adjust;
165
1.29M
                        if (penum->interpolate == interp_off)
166
1.29M
                        {
167
1.29M
                            if (xc >= penum->clip_outer.q.x)
168
2.31k
                                goto mt;
169
1.29M
                            if (xn <= penum->clip_outer.p.x)
170
91.7k
                                goto mt;
171
1.29M
                        }
172
1.20M
                        penum->xci = fixed2int_pixround_perfect(xc);
173
1.20M
                        penum->wci = fixed2int_pixround_perfect(xn) - penum->xci;
174
1.20M
                        if (penum->interpolate == interp_off && penum->wci == 0)
175
21.6k
                            goto mt;
176
1.20M
                        if_debug2m('b', penum->memory, "[b]xci=%d, wci=%d\n",
177
1.18M
                                   penum->xci, penum->wci);
178
1.18M
                    }
179
0
                    break;
180
3.50M
                case image_skewed:
181
3.50M
                    ;
182
42.3M
            }
183
42.3M
        }
184
33.6M
        if (0)
185
0
        {
186
13.6M
        mt:
187
13.6M
            skip = 1;
188
13.6M
        }
189
47.2M
        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
47.2M
        } 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
47.2M
            sourcex = planes[0].data_x;
208
47.2M
            if (!skip)
209
33.6M
                buffer =
210
33.6M
                    (*penum->unpack)(penum->buffer, &sourcex,
211
33.6M
                                     planes[0].data + offsets[0],
212
33.6M
                                     planes[0].data_x, BCOUNT(planes[0]),
213
33.6M
                                     &penum->map[0], penum->spread, num_components_per_plane);
214
13.6M
            else
215
13.6M
                buffer = NULL;
216
217
47.2M
            offsets[0] += planes[0].raster;
218
48.0M
            for (px = 1; px < num_planes; ++px) {
219
735k
                if (!skip)
220
735k
                    (*penum->unpack)(penum->buffer + (px << penum->log2_xbytes),
221
735k
                                     &ignore_data_x,
222
735k
                                     planes[px].data + offsets[px],
223
735k
                                     planes[px].data_x, BCOUNT(planes[px]),
224
735k
                                     &penum->map[px], penum->spread, 1);
225
735k
                offsets[px] += planes[px].raster;
226
735k
            }
227
47.2M
        }
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
47.2M
        if (!skip)
246
33.6M
        {
247
33.6M
            update_strip(penum);
248
33.6M
            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
33.6M
            if_debug2m('b', penum->memory, "[b]pixel0 x=%g, y=%g\n",
258
33.6M
                       fixed2float(dda_current(penum->dda.pixel0.x)),
259
33.6M
                       fixed2float(dda_current(penum->dda.pixel0.y)));
260
33.6M
            code = (*penum->render)(penum, buffer, sourcex + x_used,
261
33.6M
                                    width_spp - x_used * penum->spp, 1, dev);
262
33.6M
            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
33.6M
            penum->prev = penum->cur;
276
33.6M
        }
277
47.2M
    }
278
39.9M
    if (penum->y < penum->rect.h) {
279
38.3M
        code = 0;
280
38.3M
    } else {
281
        /* End of input data.  Render any left-over buffered data. */
282
1.58M
        code = gx_image1_flush(info);
283
1.58M
        if (code >= 0)
284
1.58M
            code = 1;
285
1.58M
    }
286
39.9M
out:
287
    /* Note that caller must call end_image */
288
    /* for both error and normal termination. */
289
39.9M
    *rows_used = penum->y - y;
290
39.9M
    return code;
291
39.9M
}
292
293
/* Flush any buffered data. */
294
int
295
gx_image1_flush(gx_image_enum_common_t * info)
296
3.26M
{
297
3.26M
    gx_image_enum *penum = (gx_image_enum *)info;
298
3.26M
    int width_spp = penum->rect.w * penum->spp;
299
3.26M
    fixed adjust = penum->adjust;
300
301
3.26M
    penum->cur.x = dda_current(penum->dda.row.x);
302
3.26M
    penum->cur.y = dda_current(penum->dda.row.y);
303
3.26M
    switch (penum->posture) {
304
2.82M
        case image_portrait:
305
2.82M
            {
306
2.82M
                fixed yc = penum->cur.y;
307
308
2.82M
                penum->yci = fixed2int_rounded(yc - adjust);
309
2.82M
                penum->hci = fixed2int_rounded(yc + adjust) - penum->yci;
310
2.82M
            }
311
2.82M
            break;
312
237k
        case image_landscape:
313
237k
            {
314
237k
                fixed xc = penum->cur.x;
315
316
237k
                penum->xci = fixed2int_rounded(xc - adjust);
317
237k
                penum->wci = fixed2int_rounded(xc + adjust) - penum->xci;
318
237k
            }
319
237k
            break;
320
199k
        case image_skewed:  /* pacify compilers */
321
199k
            ;
322
3.26M
    }
323
3.26M
    update_strip(penum);
324
3.26M
    penum->prev = penum->cur;
325
3.26M
    return (*penum->render)(penum, NULL, 0, width_spp, 0,
326
3.26M
                            setup_image_device(penum));
327
3.26M
}
328
329
/* Update the strip DDA when moving to a new row. */
330
static void
331
update_strip(gx_image_enum *penum)
332
36.8M
{
333
334
36.8M
#if 1
335
    /* Old code. */
336
36.8M
    dda_translate(penum->dda.strip.x, penum->cur.x - penum->prev.x);
337
36.8M
    dda_translate(penum->dda.strip.y, penum->cur.y - penum->prev.y);
338
36.8M
    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
36.8M
}
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
43.1M
{
468
43.1M
    gx_device *dev = penum->dev;
469
470
43.1M
    if (penum->clip_dev) {
471
27.0M
        gx_device_clip *cdev = penum->clip_dev;
472
473
27.0M
        gx_device_set_target((gx_device_forward *)cdev, dev);
474
27.0M
        dev = (gx_device *) cdev;
475
27.0M
    }
476
43.1M
    if (penum->rop_dev) {
477
7.98k
        gx_device_rop_texture *rtdev = penum->rop_dev;
478
479
7.98k
        gx_device_set_target((gx_device_forward *)rtdev, dev);
480
7.98k
        dev = (gx_device *) rtdev;
481
7.98k
    }
482
43.1M
    return dev;
483
43.1M
}
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.61M
{
490
1.61M
    gx_image_enum *penum = (gx_image_enum *) info;
491
1.61M
    gs_memory_t *mem = penum->memory;
492
1.61M
    stream_image_scale_state *scaler = penum->scaler;
493
494
1.61M
    if_debug2m('b', penum->memory, "[b]%send_image, y=%d\n",
495
1.61M
               (penum->y < penum->rect.h ? "premature " : ""), penum->y);
496
1.61M
    if (draw_last) {
497
1.60M
        int code = gx_image_flush(info);
498
499
1.60M
        if (code < 0)
500
0
            return code;
501
1.60M
    }
502
503
1.61M
    if (penum->tpr_state != NULL) {
504
446k
        transform_pixel_region_data data;
505
446k
        gx_device *dev = penum->dev;
506
446k
        if (penum->clip_dev)
507
62.7k
            dev = (gx_device *)penum->clip_dev;
508
446k
        if (penum->rop_dev)
509
0
            dev = (gx_device *)penum->rop_dev;
510
446k
        data.state = penum->tpr_state;
511
446k
        dev_proc(dev, transform_pixel_region)(dev, transform_pixel_region_end, &data);
512
446k
    }
513
    /* release the reference to the target */
514
1.61M
    if ( penum->rop_dev )
515
274
        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.61M
    gs_free_object(mem, penum->rop_dev, "image RasterOp");
519
520
    /* We do now reference count the clip device, see bug #706771 */
521
1.61M
    rc_decrement(penum->clip_dev, "gx_image1_end_image");
522
1.61M
    penum->clip_dev = NULL;
523
524
1.61M
    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.61M
    if (penum->icc_link != NULL) {
529
750k
        gsicc_release_link(penum->icc_link);
530
750k
    }
531
1.61M
    if (penum->color_cache != NULL) {
532
1.74k
        gs_free_object(mem, penum->color_cache->device_contone,
533
1.74k
                        "device_contone");
534
1.74k
        gs_free_object(mem, penum->color_cache->is_transparent,
535
1.74k
                       "image is_transparent");
536
1.74k
        gs_free_object(mem, penum->color_cache, "image color cache");
537
1.74k
    }
538
1.61M
    if (penum->thresh_buffer != NULL) {
539
123k
        gs_free_object(mem, penum->thresh_buffer, "image thresh_buffer");
540
123k
    }
541
1.61M
    if (penum->ht_buffer != NULL) {
542
123k
        gs_free_object(mem, penum->ht_buffer, "image ht_buffer");
543
123k
    }
544
1.61M
    if (penum->clues != NULL) {
545
938k
        gs_free_object(mem,penum->clues, "image clues");
546
938k
    }
547
548
    /* decrement this ref that was incremented in gx_image_enum_begin() */
549
1.61M
    rc_decrement_only(penum->pcs, "pcs");
550
1.61M
    penum->pcs = NULL;
551
552
1.61M
    gs_free_object(mem, penum->line, "image line");
553
1.61M
    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.61M
    gx_image_free_enum(&info);
561
1.61M
    return 0;
562
1.61M
}