comparison mupdf-source/thirdparty/jbig2dec/jbig2_image.c @ 2:b50eed0cc0ef upstream

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