Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/jbig2dec/jbig2_image.c
Line
Count
Source
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
    jbig2dec
18
*/
19
20
#ifdef HAVE_CONFIG_H
21
#include "config.h"
22
#endif
23
#include "os_types.h"
24
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>             /* memcpy() */
28
29
#include "jbig2.h"
30
#include "jbig2_priv.h"
31
#include "jbig2_image.h"
32
33
/* allocate a Jbig2Image structure and its associated bitmap */
34
Jbig2Image *
35
jbig2_image_new(Jbig2Ctx *ctx, uint32_t width, uint32_t height)
36
2.45M
{
37
2.45M
    Jbig2Image *image;
38
2.45M
    uint32_t stride;
39
40
2.45M
    if (width == 0 || height == 0) {
41
3
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to create zero sized image");
42
3
        return NULL;
43
3
    }
44
45
2.45M
    image = jbig2_new(ctx, Jbig2Image, 1);
46
2.45M
    if (image == NULL) {
47
0
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate image");
48
0
        return NULL;
49
0
    }
50
51
2.45M
    stride = ((width - 1) >> 3) + 1;    /* generate a byte-aligned stride */
52
53
    /* check for integer multiplication overflow */
54
2.45M
    if (height > (INT32_MAX / stride)) {
55
15
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "integer multiplication overflow (stride=%u, height=%u)", stride, height);
56
15
        jbig2_free(ctx->allocator, image);
57
15
        return NULL;
58
15
    }
59
2.45M
    image->data = jbig2_new(ctx, uint8_t, (size_t) height * stride);
60
2.45M
    if (image->data == NULL) {
61
0
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate image data buffer (stride=%u, height=%u)", stride, height);
62
0
        jbig2_free(ctx->allocator, image);
63
0
        return NULL;
64
0
    }
65
66
2.45M
    image->width = width;
67
2.45M
    image->height = height;
68
2.45M
    image->stride = stride;
69
2.45M
    image->refcount = 1;
70
71
2.45M
    return image;
72
2.45M
}
73
74
/* bump the reference count for an image pointer */
75
Jbig2Image *
76
jbig2_image_reference(Jbig2Ctx *ctx, Jbig2Image *image)
77
132k
{
78
132k
    (void) ctx;
79
132k
    if (image)
80
132k
        image->refcount++;
81
132k
    return image;
82
132k
}
83
84
/* release an image pointer, freeing it it appropriate */
85
void
86
jbig2_image_release(Jbig2Ctx *ctx, Jbig2Image *image)
87
2.58M
{
88
2.58M
    if (image == NULL)
89
774
        return;
90
2.58M
    image->refcount--;
91
2.58M
    if (image->refcount == 0)
92
2.45M
        jbig2_image_free(ctx, image);
93
2.58M
}
94
95
/* free a Jbig2Image structure and its associated memory */
96
void
97
jbig2_image_free(Jbig2Ctx *ctx, Jbig2Image *image)
98
2.45M
{
99
2.45M
    if (image != NULL) {
100
2.45M
        jbig2_free(ctx->allocator, image->data);
101
2.45M
        jbig2_free(ctx->allocator, image);
102
2.45M
    }
103
2.45M
}
104
105
/* resize a Jbig2Image */
106
Jbig2Image *
107
jbig2_image_resize(Jbig2Ctx *ctx, Jbig2Image *image, uint32_t width, uint32_t height, int value)
108
3
{
109
3
    if (width == image->width) {
110
3
        uint8_t *data;
111
112
        /* check for integer multiplication overflow */
113
3
        if (image->height > (INT32_MAX / image->stride)) {
114
0
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "integer multiplication overflow during resize (stride=%u, height=%u)", image->stride, height);
115
0
            return NULL;
116
0
        }
117
        /* use the same stride, just change the length */
118
3
        data = jbig2_renew(ctx, image->data, uint8_t, (size_t) height * image->stride);
119
3
        if (data == NULL) {
120
0
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to reallocate image");
121
0
            return NULL;
122
0
        }
123
3
        image->data = data;
124
3
        if (height > image->height) {
125
3
            const uint8_t fill = value ? 0xFF : 0x00;
126
3
            memset(image->data + (size_t) image->height * image->stride, fill, ((size_t) height - image->height) * image->stride);
127
3
        }
128
3
        image->height = height;
129
130
3
    } else {
131
0
        Jbig2Image *newimage;
132
0
        int code;
133
134
        /* Unoptimized implementation, but it works. */
135
136
0
        newimage = jbig2_image_new(ctx, width, height);
137
0
        if (newimage == NULL) {
138
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate resized image");
139
0
            return NULL;
140
0
        }
141
0
        jbig2_image_clear(ctx, newimage, value);
142
143
0
        code = jbig2_image_compose(ctx, newimage, image, 0, 0, JBIG2_COMPOSE_REPLACE);
144
0
        if (code < 0) {
145
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to compose image buffers when resizing");
146
0
            jbig2_image_release(ctx, newimage);
147
0
            return NULL;
148
0
        }
149
150
        /* if refcount > 1 the original image, its pointer must
151
        be kept, so simply replaces its innards, and throw away
152
        the empty new image shell. */
153
0
        jbig2_free(ctx->allocator, image->data);
154
0
        image->width = newimage->width;
155
0
        image->height = newimage->height;
156
0
        image->stride = newimage->stride;
157
0
        image->data = newimage->data;
158
0
        jbig2_free(ctx->allocator, newimage);
159
0
    }
160
161
3
    return image;
162
3
}
163
164
static inline void
165
template_image_compose_opt(const uint8_t * JBIG2_RESTRICT ss, uint8_t * JBIG2_RESTRICT dd, int early, int late, uint8_t leftmask, uint8_t rightmask, uint32_t bytewidth_, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride, Jbig2ComposeOp op)
166
2.46M
{
167
2.46M
    int i;
168
2.46M
    uint32_t j;
169
2.46M
    int bytewidth = (int)bytewidth_;
170
171
2.46M
    if (bytewidth == 1) {
172
2.10k
        for (j = 0; j < h; j++) {
173
            /* Only 1 byte! */
174
1.98k
            uint8_t v = (((early ? 0 : ss[0]<<8) | (late ? 0 : ss[1]))>>shift);
175
1.98k
            if (op == JBIG2_COMPOSE_OR)
176
1.98k
                *dd |= v & leftmask;
177
0
            else if (op == JBIG2_COMPOSE_AND)
178
0
                *dd &= (v & leftmask) | ~leftmask;
179
0
            else if (op == JBIG2_COMPOSE_XOR)
180
0
                *dd ^= v & leftmask;
181
0
            else if (op == JBIG2_COMPOSE_XNOR)
182
0
                *dd ^= (~v) & leftmask;
183
0
            else /* Replace */
184
0
                *dd = (v & leftmask) | (*dd & ~leftmask);
185
1.98k
            dd += dstride;
186
1.98k
            ss += sstride;
187
1.98k
        }
188
124
        return;
189
124
    }
190
2.46M
    bytewidth -= 2;
191
2.46M
    if (shift == 0) {
192
1.15M
        ss++;
193
295M
        for (j = 0; j < h; j++) {
194
            /* Left byte */
195
294M
            const uint8_t * JBIG2_RESTRICT s = ss;
196
294M
            uint8_t * JBIG2_RESTRICT d = dd;
197
294M
            if (op == JBIG2_COMPOSE_OR)
198
124k
                *d++ |= *s++ & leftmask;
199
294M
            else if (op == JBIG2_COMPOSE_AND)
200
2.08k
                *d++ &= (*s++ & leftmask) | ~leftmask;
201
294M
            else if (op == JBIG2_COMPOSE_XOR)
202
602k
                *d++ ^= *s++ & leftmask;
203
293M
            else if (op == JBIG2_COMPOSE_XNOR)
204
790
                *d++ ^= (~*s++) & leftmask;
205
293M
            else /* Replace */
206
293M
                *d = (*s++ & leftmask) | (*d & ~leftmask), d++;
207
            /* Central run */
208
2.05G
            for (i = bytewidth; i != 0; i--) {
209
1.75G
                if (op == JBIG2_COMPOSE_OR)
210
1.09M
                    *d++ |= *s++;
211
1.75G
                else if (op == JBIG2_COMPOSE_AND)
212
30.8k
                    *d++ &= *s++;
213
1.75G
                else if (op == JBIG2_COMPOSE_XOR)
214
182M
                    *d++ ^= *s++;
215
1.57G
                else if (op == JBIG2_COMPOSE_XNOR)
216
16.7k
                    *d++ ^= ~*s++;
217
1.57G
                else /* Replace */
218
1.57G
                    *d++ = *s++;
219
1.75G
            }
220
            /* Right byte */
221
294M
            if (op == JBIG2_COMPOSE_OR)
222
124k
                *d |= *s & rightmask;
223
294M
            else if (op == JBIG2_COMPOSE_AND)
224
2.08k
                *d &= (*s & rightmask) | ~rightmask;
225
294M
            else if (op == JBIG2_COMPOSE_XOR)
226
602k
                *d ^= *s & rightmask;
227
293M
            else if (op == JBIG2_COMPOSE_XNOR)
228
790
                *d ^= (~*s) & rightmask;
229
293M
            else /* Replace */
230
293M
                *d = (*s & rightmask) | (*d & ~rightmask);
231
294M
            dd += dstride;
232
294M
            ss += sstride;
233
294M
        }
234
1.30M
    } else {
235
333M
        for (j = 0; j < h; j++) {
236
            /* Left byte */
237
331M
            const uint8_t * JBIG2_RESTRICT s = ss;
238
331M
            uint8_t * JBIG2_RESTRICT d = dd;
239
331M
            uint8_t s0, s1, v;
240
331M
            s0 = early ? 0 : *s;
241
331M
            s++;
242
331M
            s1 = *s++;
243
331M
            v = ((s0<<8) | s1)>>shift;
244
331M
            if (op == JBIG2_COMPOSE_OR)
245
61.9k
                *d++ |= v & leftmask;
246
331M
            else if (op == JBIG2_COMPOSE_AND)
247
0
                *d++ &= (v & leftmask) | ~leftmask;
248
331M
            else if (op == JBIG2_COMPOSE_XOR)
249
1.75k
                *d++ ^= v & leftmask;
250
331M
            else if (op == JBIG2_COMPOSE_XNOR)
251
530
                *d++ ^= (~v) & leftmask;
252
331M
            else /* Replace */
253
331M
                *d = (v & leftmask) | (*d & ~leftmask), d++;
254
            /* Central run */
255
9.62G
            for (i = bytewidth; i > 0; i--) {
256
9.29G
                s0 = s1; s1 = *s++;
257
9.29G
                v = ((s0<<8) | s1)>>shift;
258
9.29G
                if (op == JBIG2_COMPOSE_OR)
259
110k
                    *d++ |= v;
260
9.29G
                else if (op == JBIG2_COMPOSE_AND)
261
0
                    *d++ &= v;
262
9.29G
                else if (op == JBIG2_COMPOSE_XOR)
263
12.8k
                    *d++ ^= v;
264
9.29G
                else if (op == JBIG2_COMPOSE_XNOR)
265
12.7k
                    *d++ ^= ~v;
266
9.29G
                else /* Replace */
267
9.29G
                    *d++ = v;
268
9.29G
            }
269
            /* Right byte */
270
331M
            s0 = s1; s1 = (late ? 0 : *s);
271
331M
            v = (((s0<<8) | s1)>>shift);
272
331M
            if (op == JBIG2_COMPOSE_OR)
273
61.9k
                *d |= v & rightmask;
274
331M
            else if (op == JBIG2_COMPOSE_AND)
275
0
                *d &= (v & rightmask) | ~rightmask;
276
331M
            else if (op == JBIG2_COMPOSE_XOR)
277
1.75k
                *d ^= v & rightmask;
278
331M
            else if (op == JBIG2_COMPOSE_XNOR)
279
530
                *d ^= ~v & rightmask;
280
331M
            else /* Replace */
281
331M
                *d = (v & rightmask) | (*d & ~rightmask);
282
331M
            dd += dstride;
283
331M
            ss += sstride;
284
331M
        }
285
1.30M
    }
286
2.46M
}
287
288
static void
289
jbig2_image_compose_opt_OR(const uint8_t *s, uint8_t *d, int early, int late, uint8_t mask, uint8_t rightmask, uint32_t bytewidth, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride)
290
10.1k
{
291
10.1k
    if (early || late)
292
10.0k
        template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_OR);
293
8
    else
294
8
        template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_OR);
295
10.1k
}
296
297
static void
298
jbig2_image_compose_opt_AND(const uint8_t *s, uint8_t *d, int early, int late, uint8_t mask, uint8_t rightmask, uint32_t bytewidth, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride)
299
10
{
300
10
    if (early || late)
301
10
        template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_AND);
302
0
    else
303
0
        template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_AND);
304
10
}
305
306
static void
307
jbig2_image_compose_opt_XOR(const uint8_t *s, uint8_t *d, int early, int late, uint8_t mask, uint8_t rightmask, uint32_t bytewidth, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride)
308
248
{
309
248
    if (early || late)
310
248
        template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XOR);
311
0
    else
312
0
        template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XOR);
313
248
}
314
315
static void
316
jbig2_image_compose_opt_XNOR(const uint8_t *s, uint8_t *d, int early, int late, uint8_t mask, uint8_t rightmask, uint32_t bytewidth, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride)
317
12
{
318
12
    if (early || late)
319
12
        template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XNOR);
320
0
    else
321
0
        template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XNOR);
322
12
}
323
324
static void
325
jbig2_image_compose_opt_REPLACE(const uint8_t *s, uint8_t *d, int early, int late, uint8_t mask, uint8_t rightmask, uint32_t bytewidth, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride)
326
2.45M
{
327
2.45M
    if (early || late)
328
278
        template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_REPLACE);
329
2.45M
    else
330
2.45M
        template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_REPLACE);
331
2.45M
}
332
333
/* composite one jbig2_image onto another */
334
int
335
jbig2_image_compose(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int64_t x, int64_t y, Jbig2ComposeOp op)
336
2.59M
{
337
2.59M
    uint32_t w, h;
338
2.59M
    uint32_t shift;
339
2.59M
    uint32_t leftbyte;
340
2.59M
    uint8_t *ss;
341
2.59M
    uint8_t *dd;
342
2.59M
    uint8_t leftmask, rightmask;
343
2.59M
    int early = x >= 0;
344
2.59M
    int late;
345
2.59M
    uint32_t bytewidth;
346
2.59M
    uint32_t syoffset = 0;
347
348
2.59M
    (void) ctx;
349
350
2.59M
    if (src == NULL)
351
140
        return 0;
352
353
    /* Detect if src image has no overlap with the dst image.
354
     * Because the widths/heights are of type uint32_t their theoretical
355
     * maximum size is UINT32_MAX. Therefore this check also rejects any
356
     * x/y values outside the range [-UINT32_MAX + 1, UINT32_MAX - 1].
357
     * And after this if-statement x/y must necessarily fall within this
358
     * closed range.
359
     */
360
2.59M
    if (
361
2.59M
            (x <= -((int64_t) src->width)) || (x >= (int64_t) dst->width) ||
362
2.46M
            (y <= -((int64_t) src->height)) || (y >= (int64_t) dst->height))
363
133k
    {
364
133k
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "src image entirely outside dst image in compose_image");
365
133k
        return 0;
366
133k
    }
367
368
    /* This code takes a src image and combines it onto dst at offset (x,y), with operation op. */
369
370
    /* Data is packed msb first within a byte, so with bits numbered: 01234567.
371
     * Second byte is: 89abcdef. So to combine into a run, we use:
372
     *       (s[0]<<8) | s[1] == 0123456789abcdef.
373
     * To read from src into dst at offset 3, we need to read:
374
     *    read:      0123456789abcdef...
375
     *    write:  0123456798abcdef...
376
     * In general, to read from src and write into dst at offset x, we need to shift
377
     * down by (x&7) bits to allow for bit alignment. So shift = x&7.
378
     * So the 'central' part of our runs will see us doing:
379
     *   *d++ op= ((s[0]<<8)|s[1])>>shift;
380
     * with special cases on the left and right edges of the run to mask.
381
     * With the left hand edge, we have to be careful not to 'underread' the start of
382
     * the src image; this is what the early flag is about. Similarly we have to be
383
     * careful not to read off the right hand edge; this is what the late flag is for.
384
     */
385
386
2.46M
    w = src->width;
387
2.46M
    h = src->height;
388
2.46M
    shift = (uint32_t) (x & 7);
389
2.46M
    ss = src->data - early;
390
391
    /* Since we know that x/y are now limited to [-UINT32_MAX + 1, UINT32_MAX - 1],
392
     * we know that we can't accidentally negate an INT64_MIN. Moreover, we know
393
     * that their negated values fit within an uint32_t, so casting to uint32_t is
394
     * safe.
395
     */
396
397
    /* clip left/top */
398
2.46M
    if (x < 0) {
399
2.45M
        uint32_t negx = (uint32_t) (-x);
400
2.45M
        w -= negx;
401
2.45M
        ss += (negx-1)>>3;
402
2.45M
        x = 0;
403
2.45M
    }
404
2.46M
    if (y < 0) {
405
149
        uint32_t negy = (uint32_t) (-y);
406
149
        h -= negy;
407
149
        syoffset = negy * src->stride;
408
149
        y = 0;
409
149
    }
410
411
    /* clip right/bottom */
412
2.46M
    if ((uint32_t)x + w > dst->width)
413
2.45M
        w = dst->width - ((uint32_t) x);
414
2.46M
    if ((uint32_t)y + h > dst->height)
415
117
        h = dst->height - ((uint32_t) y);
416
#ifdef JBIG2_DEBUG
417
    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "compositing %ux%u at (%u, %u) after clipping",
418
        w, h, (uint32_t) x, (uint32_t) y);
419
#endif
420
421
    /* check for zero clipping region */
422
2.46M
    if ((w <= 0) || (h <= 0)) {
423
#ifdef JBIG2_DEBUG
424
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "zero clipping region");
425
#endif
426
0
        return 0;
427
0
    }
428
429
2.46M
    leftbyte = (uint32_t) x >> 3;
430
2.46M
    dd = dst->data + y * dst->stride + leftbyte;
431
2.46M
    bytewidth = (((uint32_t) x + w - 1) >> 3) - leftbyte + 1;
432
2.46M
    leftmask = 255>>(x&7);
433
2.46M
    rightmask = (((x+w)&7) == 0) ? 255 : ~(255>>((x+w)&7));
434
2.46M
    if (bytewidth == 1)
435
124
        leftmask &= rightmask;
436
2.46M
    late = (ss + bytewidth >= src->data + ((src->width+7)>>3));
437
2.46M
    ss += syoffset;
438
439
2.46M
    switch(op)
440
2.46M
    {
441
10.1k
    case JBIG2_COMPOSE_OR:
442
10.1k
        jbig2_image_compose_opt_OR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
443
10.1k
        break;
444
10
    case JBIG2_COMPOSE_AND:
445
10
        jbig2_image_compose_opt_AND(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
446
10
        break;
447
248
    case JBIG2_COMPOSE_XOR:
448
248
        jbig2_image_compose_opt_XOR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
449
248
        break;
450
12
    case JBIG2_COMPOSE_XNOR:
451
12
        jbig2_image_compose_opt_XNOR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
452
12
        break;
453
2.45M
    case JBIG2_COMPOSE_REPLACE:
454
2.45M
        jbig2_image_compose_opt_REPLACE(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
455
2.45M
        break;
456
2.46M
    }
457
458
2.46M
    return 0;
459
2.46M
}
460
461
/* initialize an image bitmap to a constant value */
462
void
463
jbig2_image_clear(Jbig2Ctx *ctx, Jbig2Image *image, int value)
464
455
{
465
455
    const uint8_t fill = value ? 0xFF : 0x00;
466
467
455
    (void) ctx;
468
469
455
    memset(image->data, fill, image->stride * image->height);
470
455
}
471
472
/* look up a pixel value in an image.
473
   returns 0 outside the image frame for the convenience of
474
   the template code
475
*/
476
int
477
jbig2_image_get_pixel(Jbig2Image *image, int64_t x, int64_t y)
478
9.67M
{
479
9.67M
    const int64_t w = image->width;
480
9.67M
    const int64_t h = image->height;
481
9.67M
    size_t sx, sy;
482
9.67M
    size_t byte;
483
9.67M
    int bit;
484
485
9.67M
    if ((x < 0) || (x >= w))
486
165k
        return 0;
487
9.51M
    if ((y < 0) || (y >= h))
488
192k
        return 0;
489
490
9.31M
    sx = (size_t) x;
491
9.31M
    sy = (size_t) y;
492
493
9.31M
    byte = (sx >> 3) + sy * image->stride;
494
9.31M
    bit = 7 - ((int) (sx & 7));
495
496
9.31M
    return ((image->data[byte] >> bit) & 1);
497
9.51M
}
498
499
/* set an individual pixel value in an image */
500
void
501
jbig2_image_set_pixel(Jbig2Image *image, int64_t x, int64_t y, bool value)
502
412k
{
503
412k
    const int64_t w = image->width;
504
412k
    const int64_t h = image->height;
505
412k
    uint8_t scratch, mask;
506
412k
    size_t sx, sy;
507
412k
    size_t byte;
508
412k
    int bit;
509
510
412k
    if ((x < 0) || (x >= w))
511
0
        return;
512
412k
    if ((y < 0) || (y >= h))
513
0
        return;
514
515
412k
    sx = (size_t) x;
516
412k
    sy = (size_t) y;
517
518
412k
    byte = (sx >> 3) + sy * image->stride;
519
412k
    bit = 7 - ((int) (sx & 7));
520
412k
    mask = (uint8_t) ((1 << bit) ^ 0xff);
521
522
412k
    scratch = image->data[byte] & mask;
523
412k
    image->data[byte] = scratch | (value << bit);
524
412k
}