Coverage Report

Created: 2026-07-24 07:44

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