Coverage Report

Created: 2025-06-10 07:06

/src/ghostpdl/base/gximage.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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 support */
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gscspace.h"
21
#include "gserrors.h"
22
#include "gsmatrix.h"
23
#include "gsutil.h"
24
#include "gxcolor2.h"   /* for lookup map */
25
#include "gxiparam.h"
26
#include "stream.h"
27
28
/* ---------------- Generic image support ---------------- */
29
30
/* Structure descriptors */
31
public_st_gs_data_image();
32
public_st_gs_pixel_image();
33
34
/* Initialize the common parts of image structures. */
35
void
36
gs_image_common_t_init(gs_image_common_t * pic)
37
55.0k
{
38
55.0k
    gs_make_identity(&pic->ImageMatrix);
39
55.0k
    pic->imagematrices_are_untrustworthy = false;
40
55.0k
}
41
void
42
gs_data_image_t_init(gs_data_image_t * pim, int num_components)
43
55.0k
{
44
55.0k
    int i;
45
46
55.0k
    gs_image_common_t_init((gs_image_common_t *) pim);
47
55.0k
    pim->Width = pim->Height = 0;
48
55.0k
    pim->BitsPerComponent = 1;
49
55.0k
    if (num_components >= 0) {
50
182k
        for (i = 0; i < num_components * 2; i += 2)
51
127k
            pim->Decode[i] = 0, pim->Decode[i + 1] = 1;
52
54.9k
    } else {
53
38
        for (i = 0; i < num_components * -2; i += 2)
54
19
            pim->Decode[i] = 1, pim->Decode[i + 1] = 0;
55
19
    }
56
55.0k
    pim->Interpolate = false;
57
55.0k
    pim->imagematrices_are_untrustworthy = false;
58
55.0k
}
59
void
60
gs_pixel_image_t_init(gs_pixel_image_t * pim,
61
                      gs_color_space * color_space)
62
54.9k
{
63
54.9k
    int num_components;
64
65
54.9k
    if (color_space == 0 ||
66
54.9k
        (num_components =
67
42.8k
         gs_color_space_num_components(color_space)) < 0
68
54.9k
        )
69
12.1k
        num_components = 0;
70
54.9k
    gs_data_image_t_init((gs_data_image_t *) pim, num_components);
71
54.9k
    pim->format = gs_image_format_chunky;
72
54.9k
    pim->ColorSpace = color_space;
73
54.9k
    pim->CombineWithColor = false;
74
54.9k
    pim->override_in_smask = 0;
75
54.9k
}
76
77
/* Initialize the common part of an image-processing enumerator. */
78
int
79
gx_image_enum_common_init(gx_image_enum_common_t * piec,
80
                          const gs_data_image_t * pic,
81
                          const gx_image_enum_procs_t * piep,
82
                          gx_device * dev, int num_components,
83
                          gs_image_format_t format)
84
78.5k
{
85
78.5k
    int bpc = pic->BitsPerComponent;
86
78.5k
    int i;
87
88
78.5k
    piec->image_type = pic->type;
89
78.5k
    piec->procs = piep;
90
78.5k
    piec->dev = dev;
91
78.5k
    piec->id = gs_next_ids(dev->memory, 1);
92
78.5k
    piec->skipping = false;
93
78.5k
    piec->pgs = NULL;
94
95
78.5k
    switch (format) {
96
78.5k
        case gs_image_format_chunky:
97
78.5k
            piec->num_planes = 1;
98
78.5k
            piec->plane_depths[0] = bpc * num_components;
99
78.5k
            break;
100
0
        case gs_image_format_component_planar:
101
0
            piec->num_planes = num_components;
102
0
            for (i = 0; i < num_components; ++i)
103
0
                piec->plane_depths[i] = bpc;
104
0
            break;
105
0
        case gs_image_format_bit_planar:
106
0
            piec->num_planes = bpc * num_components;
107
0
            for (i = 0; i < piec->num_planes; ++i)
108
0
                piec->plane_depths[i] = 1;
109
0
            break;
110
0
        default:
111
0
            return_error(gs_error_rangecheck);
112
78.5k
    }
113
157k
    for (i = 0; i < piec->num_planes; ++i)
114
78.5k
        piec->plane_widths[i] = pic->Width;
115
78.5k
    return 0;
116
78.5k
}
117
118
/* Process the next piece of an image with no source data. */
119
/* This procedure should never be called. */
120
int
121
gx_no_plane_data(gx_image_enum_common_t * info,
122
                 const gx_image_plane_t * planes, int height,
123
                 int *height_used)
124
0
{
125
0
    return_error(gs_error_Fatal);
126
0
}
127
128
/* Clean up after processing an image with no source data. */
129
/* This procedure may be called, but should do nothing. */
130
int
131
gx_ignore_end_image(gx_image_enum_common_t * info, bool draw_last)
132
0
{
133
0
    return 0;
134
0
}
135
136
/* ---------------- Client procedures ---------------- */
137
138
int
139
gx_image_data(gx_image_enum_common_t * info, const byte ** plane_data,
140
              int data_x, uint raster, int height)
141
0
{
142
0
    int num_planes = info->num_planes;
143
0
    gx_image_plane_t planes[GS_IMAGE_MAX_COMPONENTS];
144
0
    int i;
145
146
#ifdef DEBUG
147
    if (num_planes > GS_IMAGE_MAX_COMPONENTS) {
148
        lprintf2("num_planes=%d > GS_IMAGE_MAX_COMPONENTS=%d!\n",
149
                 num_planes, GS_IMAGE_MAX_COMPONENTS);
150
        return_error(gs_error_Fatal);
151
    }
152
#endif
153
0
    for (i = 0; i < num_planes; ++i) {
154
0
        planes[i].data = plane_data[i];
155
0
        planes[i].data_x = data_x;
156
0
        planes[i].raster = raster;
157
0
    }
158
0
    return gx_image_plane_data(info, planes, height);
159
0
}
160
161
int
162
gx_image_plane_data(gx_image_enum_common_t * info,
163
                    const gx_image_plane_t * planes, int height)
164
138k
{
165
138k
    int ignore_rows_used;
166
167
138k
    return gx_image_plane_data_rows(info, planes, height, &ignore_rows_used);
168
138k
}
169
170
int
171
gx_image_plane_data_rows(gx_image_enum_common_t * info,
172
                         const gx_image_plane_t * planes, int height,
173
                         int *rows_used)
174
428k
{
175
428k
    return info->procs->plane_data(info, planes, height, rows_used);
176
428k
}
177
178
int
179
gx_image_flush(gx_image_enum_common_t * info)
180
73.3k
{
181
73.3k
    int (*flush)(gx_image_enum_common_t *) = info->procs->flush;
182
183
73.3k
    return (flush ? flush(info) : 0);
184
73.3k
}
185
186
bool
187
gx_image_planes_wanted(const gx_image_enum_common_t *info, byte *wanted)
188
11.8k
{
189
11.8k
    bool (*planes_wanted)(const gx_image_enum_common_t *, byte *) =
190
11.8k
        info->procs->planes_wanted;
191
192
11.8k
    if (planes_wanted)
193
2.68k
        return planes_wanted(info, wanted);
194
9.15k
    else {
195
9.15k
        memset(wanted, 0xff, info->num_planes);
196
9.15k
        return true;
197
9.15k
    }
198
11.8k
}
199
200
int
201
gx_image_end(gx_image_enum_common_t * info, bool draw_last)
202
38.1k
{
203
38.1k
    return info->procs->end_image(info, draw_last);
204
38.1k
}
205
206
/* ---------------- Serialization ---------------- */
207
208
/*
209
 * Define dummy sput/sget/release procedures for image types that don't
210
 * implement these functions.
211
 */
212
213
int
214
gx_image_no_sput(const gs_image_common_t *pic, stream *s,
215
                 const gs_color_space **ppcs)
216
0
{
217
0
    return_error(gs_error_rangecheck);
218
0
}
219
220
int
221
gx_image_no_sget(gs_image_common_t *pic, stream *s,
222
                 gs_color_space *pcs)
223
0
{
224
0
    return_error(gs_error_rangecheck);
225
0
}
226
227
void
228
gx_image_default_release(gs_image_common_t *pic, gs_memory_t *mem)
229
0
{
230
0
    gs_free_object(mem, pic, "gx_image_default_release");
231
0
}
232
233
#ifdef DEBUG
234
static void
235
debug_b_print_matrix(const gs_pixel_image_t *pim)
236
{
237
    if_debug6('b', "      ImageMatrix=[%g %g %g %g %g %g]\n",
238
              pim->ImageMatrix.xx, pim->ImageMatrix.xy,
239
              pim->ImageMatrix.yx, pim->ImageMatrix.yy,
240
              pim->ImageMatrix.tx, pim->ImageMatrix.ty);
241
}
242
static void
243
debug_b_print_decode(const gs_pixel_image_t *pim, int num_decode)
244
{
245
    if (gs_debug_c('b')) {
246
        const char *str = "      Decode=[";
247
        int i;
248
249
        for (i = 0; i < num_decode; str = " ", ++i)
250
            dprintf2("%s%g", str, pim->Decode[i]);
251
        dputs("]\n");
252
    }
253
}
254
#else
255
0
#  define debug_b_print_matrix(pim) DO_NOTHING
256
83
#  define debug_b_print_decode(pim, num_decode) DO_NOTHING
257
#endif
258
259
/* Test whether an image has a default ImageMatrix. */
260
bool
261
gx_image_matrix_is_default(const gs_data_image_t *pid)
262
6.97k
{
263
6.97k
    return (is_xxyy(&pid->ImageMatrix) &&
264
6.97k
            pid->ImageMatrix.xx == pid->Width &&
265
6.97k
            pid->ImageMatrix.yy == -pid->Height &&
266
6.97k
            is_fzero(pid->ImageMatrix.tx) &&
267
6.97k
            pid->ImageMatrix.ty == pid->Height);
268
6.97k
}
269
270
/* Put a variable-length uint on a stream. */
271
void
272
sput_variable_uint(stream *s, uint w)
273
20.9k
{
274
22.2k
    for (; w > 0x7f; w >>= 7)
275
1.34k
        sputc(s, (byte)(w | 0x80));
276
20.9k
    sputc(s, (byte)w);
277
20.9k
}
278
279
/*
280
 * Write generic pixel image parameters.  The format is the following,
281
 * encoded as a variable-length uint in the usual way:
282
 *  xxxFEDCCBBBBA
283
 *      A = 0 if standard ImageMatrix, 1 if explicit ImageMatrix
284
 *      BBBB = BitsPerComponent - 1
285
 *      CC = format
286
 *      D = 0 if standard (0..1) Decode, 1 if explicit Decode
287
 *      E = Interpolate
288
 *      F = CombineWithColor
289
 *      xxx = extra information from caller
290
 */
291
25.0k
#define PI_ImageMatrix 0x001
292
25.0k
#define PI_BPC_SHIFT 1
293
22.8k
#define PI_BPC_MASK 0xf
294
25.0k
#define PI_FORMAT_SHIFT 5
295
22.8k
#define PI_FORMAT_MASK 0x3
296
25.0k
#define PI_Decode 0x080
297
22.8k
#define PI_Interpolate 0x100
298
22.8k
#define PI_CombineWithColor 0x200
299
25.0k
#define PI_BITS 10
300
/*
301
 *  Width, encoded as a variable-length uint
302
 *  Height, encoded ditto
303
 *  ImageMatrix (if A = 1), per gs_matrix_store/fetch
304
 *  Decode (if D = 1): blocks of up to 4 components
305
 *      aabbccdd, where each xx is decoded as:
306
 *    00 = default, 01 = swapped default,
307
 *    10 = (0,V), 11 = (U,V)
308
 *      non-defaulted components (up to 8 floats)
309
 */
310
int
311
gx_pixel_image_sput(const gs_pixel_image_t *pim, stream *s,
312
                    const gs_color_space **ppcs, int extra)
313
2.17k
{
314
2.17k
    const gs_color_space *pcs = pim->ColorSpace;
315
2.17k
    int bpc = pim->BitsPerComponent;
316
2.17k
    int num_components = gs_color_space_num_components(pcs);
317
2.17k
    int num_decode;
318
2.17k
    uint control = extra << PI_BITS;
319
2.17k
    float decode_default_1 = 1;
320
2.17k
    int i;
321
2.17k
    uint ignore;
322
323
    /* Construct the control word. */
324
325
2.17k
    if (!gx_image_matrix_is_default((const gs_data_image_t *)pim))
326
0
        control |= PI_ImageMatrix;
327
2.17k
    switch (pim->format) {
328
2.17k
    case gs_image_format_chunky:
329
2.17k
    case gs_image_format_component_planar:
330
2.17k
        switch (bpc) {
331
2.17k
        case 1: case 2: case 4: case 8: case 12: case 16: break;
332
0
        default: return_error(gs_error_rangecheck);
333
2.17k
        }
334
2.17k
        break;
335
2.17k
    case gs_image_format_bit_planar:
336
0
        if (bpc < 1 || bpc > 8)
337
0
            return_error(gs_error_rangecheck);
338
2.17k
    }
339
2.17k
    control |= (bpc - 1) << PI_BPC_SHIFT;
340
2.17k
    control |= pim->format << PI_FORMAT_SHIFT;
341
2.17k
    num_decode = num_components * 2;
342
2.17k
    if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed)
343
101
        decode_default_1 = (float)pcs->params.indexed.hival;
344
11.6k
    for (i = 0; i < num_decode; ++i)
345
9.46k
        if (pim->Decode[i] != DECODE_DEFAULT(i, decode_default_1)) {
346
18
            control |= PI_Decode;
347
18
            break;
348
18
        }
349
2.17k
    if (pim->Interpolate)
350
0
        control |= PI_Interpolate;
351
2.17k
    if (pim->CombineWithColor)
352
0
        control |= PI_CombineWithColor;
353
354
    /* Write the encoding on the stream. */
355
356
2.17k
    if_debug3('b', "[b]put control=0x%x, Width=%d, Height=%d\n",
357
2.17k
              control, pim->Width, pim->Height);
358
2.17k
    sput_variable_uint(s, control);
359
2.17k
    sput_variable_uint(s, (uint)pim->Width);
360
2.17k
    sput_variable_uint(s, (uint)pim->Height);
361
2.17k
    if (control & PI_ImageMatrix) {
362
0
        debug_b_print_matrix(pim);
363
0
        sput_matrix(s, &pim->ImageMatrix);
364
0
    }
365
2.17k
    if (control & PI_Decode) {
366
18
        int i;
367
18
        uint dflags = 1;
368
18
        float decode[8];
369
18
        int di = 0;
370
371
18
        debug_b_print_decode(pim, num_decode);
372
36
        for (i = 0; i < num_decode; i += 2) {
373
18
            float u = pim->Decode[i], v = pim->Decode[i + 1];
374
18
            float dv = DECODE_DEFAULT(i + 1, decode_default_1);
375
376
18
            if (dflags >= 0x100) {
377
0
                sputc(s, (byte)(dflags & 0xff));
378
0
                sputs(s, (const byte *)decode, di * sizeof(float), &ignore);
379
0
                dflags = 1;
380
0
                di = 0;
381
0
            }
382
18
            dflags <<= 2;
383
18
            if (u == 0 && v == dv)
384
18
                DO_NOTHING;
385
18
            else if (u == dv && v == 0)
386
15
                dflags += 1;
387
3
            else {
388
3
                if (u != 0) {
389
0
                    dflags++;
390
0
                    decode[di++] = u;
391
0
                }
392
3
                dflags += 2;
393
3
                decode[di++] = v;
394
3
            }
395
18
        }
396
18
        sputc(s, (byte)((dflags << (8 - num_decode)) & 0xff));
397
18
        sputs(s, (const byte *)decode, di * sizeof(float), &ignore);
398
18
    }
399
2.17k
    *ppcs = pcs;
400
2.17k
    return 0;
401
2.17k
}
402
403
/* Set an image's ImageMatrix to the default. */
404
void
405
gx_image_matrix_set_default(gs_data_image_t *pid)
406
28.2k
{
407
28.2k
    pid->ImageMatrix.xx = (float)pid->Width;
408
28.2k
    pid->ImageMatrix.xy = 0;
409
28.2k
    pid->ImageMatrix.yx = 0;
410
28.2k
    pid->ImageMatrix.yy = (float)-pid->Height;
411
28.2k
    pid->ImageMatrix.tx = 0;
412
28.2k
    pid->ImageMatrix.ty = (float)pid->Height;
413
28.2k
}
414
415
/* Get a variable-length uint from a stream. */
416
int
417
sget_variable_uint(stream *s, uint *pw)
418
86.7k
{
419
86.7k
    uint w = 0;
420
86.7k
    int shift = 0;
421
86.7k
    int ch;
422
423
106k
    for (; (ch = sgetc(s)) >= 0x80; shift += 7)
424
19.2k
        w += (ch & 0x7f) << shift;
425
86.7k
    if (ch < 0)
426
0
        return_error(gs_error_ioerror);
427
86.7k
    *pw = w + (ch << shift);
428
86.7k
    return 0;
429
86.7k
}
430
431
/*
432
 * Read generic pixel image parameters.
433
 */
434
int
435
gx_pixel_image_sget(gs_pixel_image_t *pim, stream *s,
436
                    gs_color_space *pcs)
437
22.8k
{
438
22.8k
    uint control;
439
22.8k
    float decode_default_1 = 1;
440
22.8k
    int num_components, num_decode;
441
22.8k
    int i;
442
22.8k
    int code;
443
22.8k
    uint ignore;
444
445
22.8k
    if ((code = sget_variable_uint(s, &control)) < 0 ||
446
22.8k
        (code = sget_variable_uint(s, (uint *)&pim->Width)) < 0 ||
447
22.8k
        (code = sget_variable_uint(s, (uint *)&pim->Height)) < 0
448
22.8k
        )
449
0
        return code;
450
22.8k
    if_debug3('b', "[b]get control=0x%x, Width=%d, Height=%d\n",
451
22.8k
              control, pim->Width, pim->Height);
452
22.8k
    if (control & PI_ImageMatrix) {
453
0
        if ((code = sget_matrix(s, &pim->ImageMatrix)) < 0)
454
0
            return code;
455
0
        debug_b_print_matrix(pim);
456
0
    } else
457
22.8k
        gx_image_matrix_set_default((gs_data_image_t *)pim);
458
22.8k
    pim->BitsPerComponent = ((control >> PI_BPC_SHIFT) & PI_BPC_MASK) + 1;
459
22.8k
    pim->format = (control >> PI_FORMAT_SHIFT) & PI_FORMAT_MASK;
460
22.8k
    pim->ColorSpace = pcs;
461
22.8k
    num_components = gs_color_space_num_components(pcs);
462
22.8k
    num_decode = num_components * 2;
463
22.8k
    if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed)
464
399
        decode_default_1 = (float)pcs->params.indexed.hival;
465
22.8k
    if (control & PI_Decode) {
466
65
        uint dflags = 0x10000;
467
65
        float *dp = pim->Decode;
468
469
130
        for (i = 0; i < num_decode; i += 2, dp += 2, dflags <<= 2) {
470
65
            if (dflags >= 0x10000) {
471
65
                dflags = sgetc(s) + 0x100;
472
65
                if (dflags < 0x100)
473
0
                    return_error(gs_error_ioerror);
474
65
            }
475
65
            switch (dflags & 0xc0) {
476
0
            case 0x00:
477
0
                dp[0] = 0, dp[1] = DECODE_DEFAULT(i + 1, decode_default_1);
478
0
                break;
479
48
            case 0x40:
480
48
                dp[0] = DECODE_DEFAULT(i + 1, decode_default_1), dp[1] = 0;
481
48
                break;
482
17
            case 0x80:
483
17
                dp[0] = 0;
484
17
                if (sgets(s, (byte *)(dp + 1), sizeof(float), &ignore) < 0)
485
0
                    return_error(gs_error_ioerror);
486
17
                break;
487
17
            case 0xc0:
488
0
                if (sgets(s, (byte *)dp, sizeof(float) * 2, &ignore) < 0)
489
0
                    return_error(gs_error_ioerror);
490
0
                break;
491
65
            }
492
65
        }
493
65
        debug_b_print_decode(pim, num_decode);
494
22.7k
    } else {
495
106k
        for (i = 0; i < num_decode; ++i)
496
84.1k
            pim->Decode[i] = DECODE_DEFAULT(i, decode_default_1);
497
22.7k
    }
498
22.8k
    pim->Interpolate = (control & PI_Interpolate) != 0;
499
22.8k
    pim->CombineWithColor = (control & PI_CombineWithColor) != 0;
500
22.8k
    return control >> PI_BITS;
501
22.8k
}
502
503
/*
504
 * Release a pixel image object.  Currently this just frees the object.
505
 */
506
void
507
gx_pixel_image_release(gs_pixel_image_t *pic, gs_memory_t *mem)
508
0
{
509
0
    gx_image_default_release((gs_image_common_t *)pic, mem);
510
0
}