Coverage Report

Created: 2026-02-14 07:09

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