1/* Copyright (C) 2001-2019 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., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, 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#if !defined (INT32_MAX)
34#define INT32_MAX 0x7fffffff
35#endif
36
37/* allocate a Jbig2Image structure and its associated bitmap */
38Jbig2Image *
39jbig2_image_new(Jbig2Ctx *ctx, uint32_t width, uint32_t height)
40{
41 Jbig2Image *image;
42 uint32_t stride;
43
44 if (width == 0 || height == 0) {
45 jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to create zero sized image");
46 return NULL;
47 }
48
49 image = jbig2_new(ctx, Jbig2Image, 1);
50 if (image == NULL) {
51 jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate image");
52 return NULL;
53 }
54
55 stride = ((width - 1) >> 3) + 1; /* generate a byte-aligned stride */
56
57 /* check for integer multiplication overflow */
58 if (height > (INT32_MAX / stride)) {
59 jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "integer multiplication overflow (stride=%u, height=%u)", stride, height);
60 jbig2_free(ctx->allocator, image);
61 return NULL;
62 }
63 image->data = jbig2_new(ctx, uint8_t, (size_t) height * stride);
64 if (image->data == NULL) {
65 jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate image data buffer (stride=%u, height=%u)", stride, height);
66 jbig2_free(ctx->allocator, image);
67 return NULL;
68 }
69
70 image->width = width;
71 image->height = height;
72 image->stride = stride;
73 image->refcount = 1;
74
75 return image;
76}
77
78/* bump the reference count for an image pointer */
79Jbig2Image *
80jbig2_image_reference(Jbig2Ctx *ctx, Jbig2Image *image)
81{
82 if (image)
83 image->refcount++;
84 return image;
85}
86
87/* release an image pointer, freeing it it appropriate */
88void
89jbig2_image_release(Jbig2Ctx *ctx, Jbig2Image *image)
90{
91 if (image == NULL)
92 return;
93 image->refcount--;
94 if (image->refcount == 0)
95 jbig2_image_free(ctx, image);
96}
97
98/* free a Jbig2Image structure and its associated memory */
99void
100jbig2_image_free(Jbig2Ctx *ctx, Jbig2Image *image)
101{
102 if (image != NULL) {
103 jbig2_free(ctx->allocator, image->data);
104 jbig2_free(ctx->allocator, image);
105 }
106}
107
108/* resize a Jbig2Image */
109Jbig2Image *
110jbig2_image_resize(Jbig2Ctx *ctx, Jbig2Image *image, uint32_t width, uint32_t height, int value)
111{
112 if (width == image->width) {
113 uint8_t *data;
114
115 /* check for integer multiplication overflow */
116 if (image->height > (INT32_MAX / image->stride)) {
117 jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "integer multiplication overflow during resize (stride=%u, height=%u)", image->stride, height);
118 return NULL;
119 }
120 /* use the same stride, just change the length */
121 data = jbig2_renew(ctx, image->data, uint8_t, (size_t) height * image->stride);
122 if (data == NULL) {
123 jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to reallocate image");
124 return NULL;
125 }
126 image->data = data;
127 if (height > image->height) {
128 const uint8_t fill = value ? 0xFF : 0x00;
129 memset(image->data + (size_t) image->height * image->stride, fill, ((size_t) height - image->height) * image->stride);
130 }
131 image->height = height;
132
133 } else {
134 Jbig2Image *newimage;
135 int code;
136
137 /* Unoptimized implementation, but it works. */
138
139 newimage = jbig2_image_new(ctx, width, height);
140 if (newimage == NULL) {
141 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to allocate resized image");
142 return NULL;
143 }
144 jbig2_image_clear(ctx, newimage, value);
145
146 code = jbig2_image_compose(ctx, newimage, image, 0, 0, JBIG2_COMPOSE_REPLACE);
147 if (code < 0) {
148 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to compose image buffers when resizing");
149 jbig2_image_release(ctx, newimage);
150 return NULL;
151 }
152
153 /* if refcount > 1 the original image, its pointer must
154 be kept, so simply replaces its innards, and throw away
155 the empty new image shell. */
156 jbig2_free(ctx->allocator, image->data);
157 image->width = newimage->width;
158 image->height = newimage->height;
159 image->stride = newimage->stride;
160 image->data = newimage->data;
161 jbig2_free(ctx->allocator, newimage);
162 }
163
164 return image;
165}
166
167/* composite one jbig2_image onto another
168 slow but general version */
169static int
170jbig2_image_compose_unopt(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int y, Jbig2ComposeOp op)
171{
172 uint32_t i, j;
173 uint32_t sw = src->width;
174 uint32_t sh = src->height;
175 uint32_t sx = 0;
176 uint32_t sy = 0;
177
178 /* clip to the dst image boundaries */
179 if (x < 0) {
180 sx += -x;
181 if (sw < (uint32_t) -x)
182 sw = 0;
183 else
184 sw -= -x;
185 x = 0;
186 }
187 if (y < 0) {
188 sy += -y;
189 if (sh < (uint32_t) -y)
190 sh = 0;
191 else
192 sh -= -y;
193 y = 0;
194 }
195 if ((uint32_t) x + sw >= dst->width) {
196 if (dst->width >= (uint32_t) x)
197 sw = dst->width - x;
198 else
199 sw = 0;
200 }
201 if ((uint32_t) y + sh >= dst->height) {
202 if (dst->height >= (uint32_t) y)
203 sh = dst->height - y;
204 else
205 sh = 0;
206 }
207
208 switch (op) {
209 case JBIG2_COMPOSE_OR:
210 for (j = 0; j < sh; j++) {
211 for (i = 0; i < sw; i++) {
212 jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy) | jbig2_image_get_pixel(dst, i + x, j + y));
213 }
214 }
215 break;
216 case JBIG2_COMPOSE_AND:
217 for (j = 0; j < sh; j++) {
218 for (i = 0; i < sw; i++) {
219 jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy) & jbig2_image_get_pixel(dst, i + x, j + y));
220 }
221 }
222 break;
223 case JBIG2_COMPOSE_XOR:
224 for (j = 0; j < sh; j++) {
225 for (i = 0; i < sw; i++) {
226 jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy) ^ jbig2_image_get_pixel(dst, i + x, j + y));
227 }
228 }
229 break;
230 case JBIG2_COMPOSE_XNOR:
231 for (j = 0; j < sh; j++) {
232 for (i = 0; i < sw; i++) {
233 jbig2_image_set_pixel(dst, i + x, j + y, (jbig2_image_get_pixel(src, i + sx, j + sy) == jbig2_image_get_pixel(dst, i + x, j + y)));
234 }
235 }
236 break;
237 case JBIG2_COMPOSE_REPLACE:
238 for (j = 0; j < sh; j++) {
239 for (i = 0; i < sw; i++) {
240 jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy));
241 }
242 }
243 break;
244 }
245
246 return 0;
247}
248
249/* composite one jbig2_image onto another */
250int
251jbig2_image_compose(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int y, Jbig2ComposeOp op)
252{
253 uint32_t i, j;
254 uint32_t w, h;
255 uint32_t leftbyte, rightbyte;
256 uint32_t shift;
257 uint8_t *s, *ss;
258 uint8_t *d, *dd;
259 uint8_t mask, rightmask;
260
261 if (src == NULL)
262 return 0;
263
264 /* The optimized code for the OR operator below doesn't
265 handle the source image partially placed outside the
266 destination (above and/or to the left). The affected
267 intersection of the destination is computed correctly,
268 however the correct subset of the source image is not
269 chosen. Instead the upper left corner of the source image
270 is always used.
271
272 In the unoptimized version that handles all operators
273 (including OR) the correct subset of the source image is
274 chosen.
275
276 The workaround is to check whether the x/y coordinates to
277 the composition operator are negative and in this case use
278 the unoptimized implementation.
279
280 TODO: Fix the optimized OR implementation if possible. */
281 if (op != JBIG2_COMPOSE_OR || x < 0 || y < 0) {
282 /* hand off the the general routine */
283 return jbig2_image_compose_unopt(ctx, dst, src, x, y, op);
284 }
285
286 /* optimized code for the prevalent OR operator */
287
288 /* clip */
289 w = src->width;
290 h = src->height;
291 ss = src->data;
292
293 if (x < 0) {
294 if (w < (uint32_t) -x)
295 w = 0;
296 else
297 w += x;
298 x = 0;
299 }
300 if (y < 0) {
301 if (h < (uint32_t) -y)
302 h = 0;
303 else
304 h += y;
305 y = 0;
306 }
307 w = ((uint32_t) x + w < dst->width) ? w : ((dst->width >= (uint32_t) x) ? dst->width - (uint32_t) x : 0);
308 h = ((uint32_t) y + h < dst->height) ? h : ((dst->height >= (uint32_t) y) ? dst->height - (uint32_t) y : 0);
309#ifdef JBIG2_DEBUG
310 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "compositing %dx%d at (%d, %d) after clipping", w, h, x, y);
311#endif
312
313 /* check for zero clipping region */
314 if ((w <= 0) || (h <= 0)) {
315#ifdef JBIG2_DEBUG
316 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "zero clipping region");
317#endif
318 return 0;
319 }
320
321 leftbyte = (uint32_t) x >> 3;
322 rightbyte = ((uint32_t) x + w - 1) >> 3;
323 shift = x & 7;
324
325 /* general OR case */
326 s = ss;
327 d = dd = dst->data + y * dst->stride + leftbyte;
328 if (d < dst->data ||
329 leftbyte > dst->stride ||
330 d - leftbyte + (size_t) h * dst->stride > dst->data + (size_t) dst->height * dst->stride ||
331 s - leftbyte + (size_t) (h - 1) * src->stride + rightbyte > src->data + (size_t) src->height * src->stride) {
332 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "preventing heap overflow in jbig2_image_compose");
333 }
334 if (leftbyte == rightbyte) {
335 mask = 0x100 - (0x100 >> w);
336 for (j = 0; j < h; j++) {
337 *d |= (*s & mask) >> shift;
338 d += dst->stride;
339 s += src->stride;
340 }
341 } else if (shift == 0) {
342 rightmask = (w & 7) ? 0x100 - (1 << (8 - (w & 7))) : 0xFF;
343 for (j = 0; j < h; j++) {
344 for (i = leftbyte; i < rightbyte; i++)
345 *d++ |= *s++;
346 *d |= *s & rightmask;
347 d = (dd += dst->stride);
348 s = (ss += src->stride);
349 }
350 } else {
351 bool overlap = (((w + 7) >> 3) < ((x + w + 7) >> 3) - (x >> 3));
352
353 mask = 0x100 - (1 << shift);
354 if (overlap)
355 rightmask = (0x100 - (0x100 >> ((x + w) & 7))) >> (8 - shift);
356 else
357 rightmask = 0x100 - (0x100 >> (w & 7));
358 for (j = 0; j < h; j++) {
359 *d++ |= (*s & mask) >> shift;
360 for (i = leftbyte; i < rightbyte - 1; i++) {
361 *d |= ((*s++ & ~mask) << (8 - shift));
362 *d++ |= ((*s & mask) >> shift);
363 }
364 if (overlap)
365 *d |= (*s & rightmask) << (8 - shift);
366 else
367 *d |= ((s[0] & ~mask) << (8 - shift)) | ((s[1] & rightmask) >> shift);
368 d = (dd += dst->stride);
369 s = (ss += src->stride);
370 }
371 }
372
373 return 0;
374}
375
376/* initialize an image bitmap to a constant value */
377void
378jbig2_image_clear(Jbig2Ctx *ctx, Jbig2Image *image, int value)
379{
380 const uint8_t fill = value ? 0xFF : 0x00;
381
382 memset(image->data, fill, image->stride * image->height);
383}
384
385/* look up a pixel value in an image.
386 returns 0 outside the image frame for the convenience of
387 the template code
388*/
389int
390jbig2_image_get_pixel(Jbig2Image *image, int x, int y)
391{
392 const int w = image->width;
393 const int h = image->height;
394 const int byte = (x >> 3) + y * image->stride;
395 const int bit = 7 - (x & 7);
396
397 if ((x < 0) || (x >= w))
398 return 0;
399 if ((y < 0) || (y >= h))
400 return 0;
401
402 return ((image->data[byte] >> bit) & 1);
403}
404
405/* set an individual pixel value in an image */
406void
407jbig2_image_set_pixel(Jbig2Image *image, int x, int y, bool value)
408{
409 const int w = image->width;
410 const int h = image->height;
411 int scratch, mask;
412 int bit, byte;
413
414 if ((x < 0) || (x >= w))
415 return;
416 if ((y < 0) || (y >= h))
417 return;
418
419 byte = (x >> 3) + y * image->stride;
420 bit = 7 - (x & 7);
421 mask = (1 << bit) ^ 0xff;
422
423 scratch = image->data[byte] & mask;
424 image->data[byte] = scratch | (value << bit);
425}
426