Coverage Report

Created: 2026-08-08 08:00

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
1.97M
{
37
1.97M
    Jbig2Image *image;
38
1.97M
    uint32_t stride;
39
40
1.97M
    if (width == 0 || height == 0) {
41
5
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to create zero sized image");
42
5
        return NULL;
43
5
    }
44
45
1.97M
    image = jbig2_new(ctx, Jbig2Image, 1);
46
1.97M
    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
1.97M
    stride = ((width - 1) >> 3) + 1;    /* generate a byte-aligned stride */
52
53
    /* check for integer multiplication overflow */
54
1.97M
    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
1.97M
    image->data = jbig2_new(ctx, uint8_t, (size_t) height * stride);
60
1.97M
    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
1.97M
    image->width = width;
67
1.97M
    image->height = height;
68
1.97M
    image->stride = stride;
69
1.97M
    image->refcount = 1;
70
71
1.97M
    return image;
72
1.97M
}
73
74
/* bump the reference count for an image pointer */
75
Jbig2Image *
76
jbig2_image_reference(Jbig2Ctx *ctx, Jbig2Image *image)
77
1.82k
{
78
1.82k
    (void) ctx;
79
1.82k
    if (image)
80
1.82k
        image->refcount++;
81
1.82k
    return image;
82
1.82k
}
83
84
/* release an image pointer, freeing it it appropriate */
85
void
86
jbig2_image_release(Jbig2Ctx *ctx, Jbig2Image *image)
87
7.11M
{
88
7.11M
    if (image == NULL)
89
5.13M
        return;
90
1.98M
    image->refcount--;
91
1.98M
    if (image->refcount == 0)
92
1.97M
        jbig2_image_free(ctx, image);
93
1.98M
}
94
95
/* free a Jbig2Image structure and its associated memory */
96
void
97
jbig2_image_free(Jbig2Ctx *ctx, Jbig2Image *image)
98
1.97M
{
99
1.97M
    if (image != NULL) {
100
1.97M
        jbig2_free(ctx->allocator, image->data);
101
1.97M
        jbig2_free(ctx->allocator, image);
102
1.97M
    }
103
1.97M
}
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.00M
{
167
2.00M
    int i;
168
2.00M
    uint32_t j;
169
2.00M
    int bytewidth = (int)bytewidth_;
170
171
2.00M
    if (bytewidth == 1) {
172
12.4k
        for (j = 0; j < h; j++) {
173
            /* Only 1 byte! */
174
11.6k
            uint8_t v = (((early ? 0 : ss[0]<<8) | (late ? 0 : ss[1]))>>shift);
175
11.6k
            if (op == JBIG2_COMPOSE_OR)
176
7.46k
                *dd |= v & leftmask;
177
4.23k
            else if (op == JBIG2_COMPOSE_AND)
178
0
                *dd &= (v & leftmask) | ~leftmask;
179
4.23k
            else if (op == JBIG2_COMPOSE_XOR)
180
608
                *dd ^= v & leftmask;
181
3.62k
            else if (op == JBIG2_COMPOSE_XNOR)
182
608
                *dd ^= (~v) & leftmask;
183
3.01k
            else /* Replace */
184
3.01k
                *dd = (v & leftmask) | (*dd & ~leftmask);
185
11.6k
            dd += dstride;
186
11.6k
            ss += sstride;
187
11.6k
        }
188
729
        return;
189
729
    }
190
2.00M
    bytewidth -= 2;
191
2.00M
    if (shift == 0) {
192
828k
        ss++;
193
208M
        for (j = 0; j < h; j++) {
194
            /* Left byte */
195
207M
            const uint8_t * JBIG2_RESTRICT s = ss;
196
207M
            uint8_t * JBIG2_RESTRICT d = dd;
197
207M
            if (op == JBIG2_COMPOSE_OR)
198
225k
                *d++ |= *s++ & leftmask;
199
207M
            else if (op == JBIG2_COMPOSE_AND)
200
2.88k
                *d++ &= (*s++ & leftmask) | ~leftmask;
201
207M
            else if (op == JBIG2_COMPOSE_XOR)
202
655k
                *d++ ^= *s++ & leftmask;
203
206M
            else if (op == JBIG2_COMPOSE_XNOR)
204
790
                *d++ ^= (~*s++) & leftmask;
205
206M
            else /* Replace */
206
206M
                *d = (*s++ & leftmask) | (*d & ~leftmask), d++;
207
            /* Central run */
208
1.75G
            for (i = bytewidth; i != 0; i--) {
209
1.54G
                if (op == JBIG2_COMPOSE_OR)
210
1.96M
                    *d++ |= *s++;
211
1.54G
                else if (op == JBIG2_COMPOSE_AND)
212
43.6k
                    *d++ &= *s++;
213
1.54G
                else if (op == JBIG2_COMPOSE_XOR)
214
198M
                    *d++ ^= *s++;
215
1.34G
                else if (op == JBIG2_COMPOSE_XNOR)
216
16.7k
                    *d++ ^= ~*s++;
217
1.34G
                else /* Replace */
218
1.34G
                    *d++ = *s++;
219
1.54G
            }
220
            /* Right byte */
221
207M
            if (op == JBIG2_COMPOSE_OR)
222
225k
                *d |= *s & rightmask;
223
207M
            else if (op == JBIG2_COMPOSE_AND)
224
2.88k
                *d &= (*s & rightmask) | ~rightmask;
225
207M
            else if (op == JBIG2_COMPOSE_XOR)
226
655k
                *d ^= *s & rightmask;
227
206M
            else if (op == JBIG2_COMPOSE_XNOR)
228
790
                *d ^= (~*s) & rightmask;
229
206M
            else /* Replace */
230
206M
                *d = (*s & rightmask) | (*d & ~rightmask);
231
207M
            dd += dstride;
232
207M
            ss += sstride;
233
207M
        }
234
1.17M
    } else {
235
296M
        for (j = 0; j < h; j++) {
236
            /* Left byte */
237
295M
            const uint8_t * JBIG2_RESTRICT s = ss;
238
295M
            uint8_t * JBIG2_RESTRICT d = dd;
239
295M
            uint8_t s0, s1, v;
240
295M
            s0 = early ? 0 : *s;
241
295M
            s++;
242
295M
            s1 = *s++;
243
295M
            v = ((s0<<8) | s1)>>shift;
244
295M
            if (op == JBIG2_COMPOSE_OR)
245
227k
                *d++ |= v & leftmask;
246
295M
            else if (op == JBIG2_COMPOSE_AND)
247
0
                *d++ &= (v & leftmask) | ~leftmask;
248
295M
            else if (op == JBIG2_COMPOSE_XOR)
249
18.8k
                *d++ ^= v & leftmask;
250
295M
            else if (op == JBIG2_COMPOSE_XNOR)
251
16.9k
                *d++ ^= (~v) & leftmask;
252
295M
            else /* Replace */
253
295M
                *d = (v & leftmask) | (*d & ~leftmask), d++;
254
            /* Central run */
255
8.56G
            for (i = bytewidth; i > 0; i--) {
256
8.27G
                s0 = s1; s1 = *s++;
257
8.27G
                v = ((s0<<8) | s1)>>shift;
258
8.27G
                if (op == JBIG2_COMPOSE_OR)
259
285k
                    *d++ |= v;
260
8.27G
                else if (op == JBIG2_COMPOSE_AND)
261
0
                    *d++ &= v;
262
8.27G
                else if (op == JBIG2_COMPOSE_XOR)
263
36.1k
                    *d++ ^= v;
264
8.27G
                else if (op == JBIG2_COMPOSE_XNOR)
265
40.5k
                    *d++ ^= ~v;
266
8.27G
                else /* Replace */
267
8.27G
                    *d++ = v;
268
8.27G
            }
269
            /* Right byte */
270
295M
            s0 = s1; s1 = (late ? 0 : *s);
271
295M
            v = (((s0<<8) | s1)>>shift);
272
295M
            if (op == JBIG2_COMPOSE_OR)
273
227k
                *d |= v & rightmask;
274
295M
            else if (op == JBIG2_COMPOSE_AND)
275
0
                *d &= (v & rightmask) | ~rightmask;
276
295M
            else if (op == JBIG2_COMPOSE_XOR)
277
18.8k
                *d ^= v & rightmask;
278
295M
            else if (op == JBIG2_COMPOSE_XNOR)
279
16.9k
                *d ^= ~v & rightmask;
280
295M
            else /* Replace */
281
295M
                *d = (v & rightmask) | (*d & ~rightmask);
282
295M
            dd += dstride;
283
295M
            ss += sstride;
284
295M
        }
285
1.17M
    }
286
2.00M
}
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
26.1k
{
291
26.1k
    if (early || late)
292
26.1k
        template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_OR);
293
12
    else
294
12
        template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_OR);
295
26.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
12
{
300
12
    if (early || late)
301
12
        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
12
}
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
1.35k
{
309
1.35k
    if (early || late)
310
1.35k
        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
1.35k
}
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
1.08k
{
318
1.08k
    if (early || late)
319
1.08k
        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
1.08k
}
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
1.97M
{
327
1.97M
    if (early || late)
328
1.45k
        template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_REPLACE);
329
1.97M
    else
330
1.97M
        template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_REPLACE);
331
1.97M
}
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
4.90M
{
337
4.90M
    uint32_t w, h;
338
4.90M
    uint32_t shift;
339
4.90M
    uint32_t leftbyte;
340
4.90M
    uint8_t *ss;
341
4.90M
    uint8_t *dd;
342
4.90M
    uint8_t leftmask, rightmask;
343
4.90M
    int early = x >= 0;
344
4.90M
    int late;
345
4.90M
    uint32_t bytewidth;
346
4.90M
    uint32_t syoffset = 0;
347
348
4.90M
    (void) ctx;
349
350
4.90M
    if (src == NULL)
351
143
        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
4.90M
    if (
361
4.90M
            (x <= -((int64_t) src->width)) || (x >= (int64_t) dst->width) ||
362
2.01M
            (y <= -((int64_t) src->height)) || (y >= (int64_t) dst->height))
363
2.89M
    {
364
2.89M
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "src image entirely outside dst image in compose_image");
365
2.89M
        return 0;
366
2.89M
    }
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.00M
    w = src->width;
387
2.00M
    h = src->height;
388
2.00M
    shift = (uint32_t) (x & 7);
389
2.00M
    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.00M
    if (x < 0) {
399
1.97M
        uint32_t negx = (uint32_t) (-x);
400
1.97M
        w -= negx;
401
1.97M
        ss += (negx-1)>>3;
402
1.97M
        x = 0;
403
1.97M
    }
404
2.00M
    if (y < 0) {
405
587
        uint32_t negy = (uint32_t) (-y);
406
587
        h -= negy;
407
587
        syoffset = negy * src->stride;
408
587
        y = 0;
409
587
    }
410
411
    /* clip right/bottom */
412
2.00M
    if ((uint32_t)x + w > dst->width)
413
1.97M
        w = dst->width - ((uint32_t) x);
414
2.00M
    if ((uint32_t)y + h > dst->height)
415
510
        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.00M
    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.00M
    leftbyte = (uint32_t) x >> 3;
430
2.00M
    dd = dst->data + y * dst->stride + leftbyte;
431
2.00M
    bytewidth = (((uint32_t) x + w - 1) >> 3) - leftbyte + 1;
432
2.00M
    leftmask = 255>>(x&7);
433
2.00M
    rightmask = (((x+w)&7) == 0) ? 255 : ~(255>>((x+w)&7));
434
2.00M
    if (bytewidth == 1)
435
767
        leftmask &= rightmask;
436
2.00M
    late = (ss + bytewidth >= src->data + ((src->width+7)>>3));
437
2.00M
    ss += syoffset;
438
439
2.00M
    switch(op)
440
2.00M
    {
441
26.1k
    case JBIG2_COMPOSE_OR:
442
26.1k
        jbig2_image_compose_opt_OR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
443
26.1k
        break;
444
12
    case JBIG2_COMPOSE_AND:
445
12
        jbig2_image_compose_opt_AND(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
446
12
        break;
447
1.35k
    case JBIG2_COMPOSE_XOR:
448
1.35k
        jbig2_image_compose_opt_XOR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
449
1.35k
        break;
450
1.08k
    case JBIG2_COMPOSE_XNOR:
451
1.08k
        jbig2_image_compose_opt_XNOR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
452
1.08k
        break;
453
1.97M
    case JBIG2_COMPOSE_REPLACE:
454
1.97M
        jbig2_image_compose_opt_REPLACE(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
455
1.97M
        break;
456
2.00M
    }
457
458
2.00M
    return 0;
459
2.00M
}
460
461
/* initialize an image bitmap to a constant value */
462
void
463
jbig2_image_clear(Jbig2Ctx *ctx, Jbig2Image *image, int value)
464
570
{
465
570
    const uint8_t fill = value ? 0xFF : 0x00;
466
467
570
    (void) ctx;
468
469
570
    memset(image->data, fill, image->stride * image->height);
470
570
}
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
72.8M
{
479
72.8M
    const int64_t w = image->width;
480
72.8M
    const int64_t h = image->height;
481
72.8M
    size_t sx, sy;
482
72.8M
    size_t byte;
483
72.8M
    int bit;
484
485
72.8M
    if ((x < 0) || (x >= w))
486
228k
        return 0;
487
72.5M
    if ((y < 0) || (y >= h))
488
717k
        return 0;
489
490
71.8M
    sx = (size_t) x;
491
71.8M
    sy = (size_t) y;
492
493
71.8M
    byte = (sx >> 3) + sy * image->stride;
494
71.8M
    bit = 7 - ((int) (sx & 7));
495
496
71.8M
    return ((image->data[byte] >> bit) & 1);
497
72.5M
}
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
3.67M
{
503
3.67M
    const int64_t w = image->width;
504
3.67M
    const int64_t h = image->height;
505
3.67M
    uint8_t scratch, mask;
506
3.67M
    size_t sx, sy;
507
3.67M
    size_t byte;
508
3.67M
    int bit;
509
510
3.67M
    if ((x < 0) || (x >= w))
511
0
        return;
512
3.67M
    if ((y < 0) || (y >= h))
513
0
        return;
514
515
3.67M
    sx = (size_t) x;
516
3.67M
    sy = (size_t) y;
517
518
3.67M
    byte = (sx >> 3) + sy * image->stride;
519
3.67M
    bit = 7 - ((int) (sx & 7));
520
3.67M
    mask = (uint8_t) ((1 << bit) ^ 0xff);
521
522
3.67M
    scratch = image->data[byte] & mask;
523
3.67M
    image->data[byte] = scratch | (value << bit);
524
3.67M
}