| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- /* Copyright (C) 2001-2023 Artifex Software, Inc.
- All Rights Reserved.
- This software is provided AS-IS with no warranty, either express or
- implied.
- This software is distributed under license and may not be copied,
- modified or distributed except as expressly authorized under the terms
- of the license contained in the file LICENSE in this distribution.
- Refer to licensing information at http://www.artifex.com or contact
- Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
- CA 94129, USA, for further information.
- */
- /*
- jbig2dec
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "os_types.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h> /* memcpy() */
- #include "jbig2.h"
- #include "jbig2_priv.h"
- #include "jbig2_image.h"
- /* allocate a Jbig2Image structure and its associated bitmap */
- Jbig2Image *
- jbig2_image_new(Jbig2Ctx *ctx, uint32_t width, uint32_t height)
- {
- Jbig2Image *image;
- uint32_t stride;
- if (width == 0 || height == 0) {
- jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to create zero sized image");
- return NULL;
- }
- image = jbig2_new(ctx, Jbig2Image, 1);
- if (image == NULL) {
- jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate image");
- return NULL;
- }
- stride = ((width - 1) >> 3) + 1; /* generate a byte-aligned stride */
- /* check for integer multiplication overflow */
- if (height > (INT32_MAX / stride)) {
- jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "integer multiplication overflow (stride=%u, height=%u)", stride, height);
- jbig2_free(ctx->allocator, image);
- return NULL;
- }
- image->data = jbig2_new(ctx, uint8_t, (size_t) height * stride);
- if (image->data == NULL) {
- jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate image data buffer (stride=%u, height=%u)", stride, height);
- jbig2_free(ctx->allocator, image);
- return NULL;
- }
- image->width = width;
- image->height = height;
- image->stride = stride;
- image->refcount = 1;
- return image;
- }
- /* bump the reference count for an image pointer */
- Jbig2Image *
- jbig2_image_reference(Jbig2Ctx *ctx, Jbig2Image *image)
- {
- if (image)
- image->refcount++;
- return image;
- }
- /* release an image pointer, freeing it it appropriate */
- void
- jbig2_image_release(Jbig2Ctx *ctx, Jbig2Image *image)
- {
- if (image == NULL)
- return;
- image->refcount--;
- if (image->refcount == 0)
- jbig2_image_free(ctx, image);
- }
- /* free a Jbig2Image structure and its associated memory */
- void
- jbig2_image_free(Jbig2Ctx *ctx, Jbig2Image *image)
- {
- if (image != NULL) {
- jbig2_free(ctx->allocator, image->data);
- jbig2_free(ctx->allocator, image);
- }
- }
- /* resize a Jbig2Image */
- Jbig2Image *
- jbig2_image_resize(Jbig2Ctx *ctx, Jbig2Image *image, uint32_t width, uint32_t height, int value)
- {
- if (width == image->width) {
- uint8_t *data;
- /* check for integer multiplication overflow */
- if (image->height > (INT32_MAX / image->stride)) {
- jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "integer multiplication overflow during resize (stride=%u, height=%u)", image->stride, height);
- return NULL;
- }
- /* use the same stride, just change the length */
- data = jbig2_renew(ctx, image->data, uint8_t, (size_t) height * image->stride);
- if (data == NULL) {
- jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to reallocate image");
- return NULL;
- }
- image->data = data;
- if (height > image->height) {
- const uint8_t fill = value ? 0xFF : 0x00;
- memset(image->data + (size_t) image->height * image->stride, fill, ((size_t) height - image->height) * image->stride);
- }
- image->height = height;
- } else {
- Jbig2Image *newimage;
- int code;
- /* Unoptimized implementation, but it works. */
- newimage = jbig2_image_new(ctx, width, height);
- if (newimage == NULL) {
- jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to allocate resized image");
- return NULL;
- }
- jbig2_image_clear(ctx, newimage, value);
- code = jbig2_image_compose(ctx, newimage, image, 0, 0, JBIG2_COMPOSE_REPLACE);
- if (code < 0) {
- jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to compose image buffers when resizing");
- jbig2_image_release(ctx, newimage);
- return NULL;
- }
- /* if refcount > 1 the original image, its pointer must
- be kept, so simply replaces its innards, and throw away
- the empty new image shell. */
- jbig2_free(ctx->allocator, image->data);
- image->width = newimage->width;
- image->height = newimage->height;
- image->stride = newimage->stride;
- image->data = newimage->data;
- jbig2_free(ctx->allocator, newimage);
- }
- return image;
- }
- static inline void
- 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)
- {
- int i;
- uint32_t j;
- int bytewidth = (int)bytewidth_;
- if (bytewidth == 1) {
- for (j = 0; j < h; j++) {
- /* Only 1 byte! */
- uint8_t v = (((early ? 0 : ss[0]<<8) | (late ? 0 : ss[1]))>>shift);
- if (op == JBIG2_COMPOSE_OR)
- *dd |= v & leftmask;
- else if (op == JBIG2_COMPOSE_AND)
- *dd &= (v & leftmask) | ~leftmask;
- else if (op == JBIG2_COMPOSE_XOR)
- *dd ^= v & leftmask;
- else if (op == JBIG2_COMPOSE_XNOR)
- *dd ^= (~v) & leftmask;
- else /* Replace */
- *dd = (v & leftmask) | (*dd & ~leftmask);
- dd += dstride;
- ss += sstride;
- }
- return;
- }
- bytewidth -= 2;
- if (shift == 0) {
- ss++;
- for (j = 0; j < h; j++) {
- /* Left byte */
- const uint8_t * JBIG2_RESTRICT s = ss;
- uint8_t * JBIG2_RESTRICT d = dd;
- if (op == JBIG2_COMPOSE_OR)
- *d++ |= *s++ & leftmask;
- else if (op == JBIG2_COMPOSE_AND)
- *d++ &= (*s++ & leftmask) | ~leftmask;
- else if (op == JBIG2_COMPOSE_XOR)
- *d++ ^= *s++ & leftmask;
- else if (op == JBIG2_COMPOSE_XNOR)
- *d++ ^= (~*s++) & leftmask;
- else /* Replace */
- *d = (*s++ & leftmask) | (*d & ~leftmask), d++;
- /* Central run */
- for (i = bytewidth; i != 0; i--) {
- if (op == JBIG2_COMPOSE_OR)
- *d++ |= *s++;
- else if (op == JBIG2_COMPOSE_AND)
- *d++ &= *s++;
- else if (op == JBIG2_COMPOSE_XOR)
- *d++ ^= *s++;
- else if (op == JBIG2_COMPOSE_XNOR)
- *d++ ^= ~*s++;
- else /* Replace */
- *d++ = *s++;
- }
- /* Right byte */
- if (op == JBIG2_COMPOSE_OR)
- *d |= *s & rightmask;
- else if (op == JBIG2_COMPOSE_AND)
- *d &= (*s & rightmask) | ~rightmask;
- else if (op == JBIG2_COMPOSE_XOR)
- *d ^= *s & rightmask;
- else if (op == JBIG2_COMPOSE_XNOR)
- *d ^= (~*s) & rightmask;
- else /* Replace */
- *d = (*s & rightmask) | (*d & ~rightmask);
- dd += dstride;
- ss += sstride;
- }
- } else {
- for (j = 0; j < h; j++) {
- /* Left byte */
- const uint8_t * JBIG2_RESTRICT s = ss;
- uint8_t * JBIG2_RESTRICT d = dd;
- uint8_t s0, s1, v;
- s0 = early ? 0 : *s;
- s++;
- s1 = *s++;
- v = ((s0<<8) | s1)>>shift;
- if (op == JBIG2_COMPOSE_OR)
- *d++ |= v & leftmask;
- else if (op == JBIG2_COMPOSE_AND)
- *d++ &= (v & leftmask) | ~leftmask;
- else if (op == JBIG2_COMPOSE_XOR)
- *d++ ^= v & leftmask;
- else if (op == JBIG2_COMPOSE_XNOR)
- *d++ ^= (~v) & leftmask;
- else /* Replace */
- *d = (v & leftmask) | (*d & ~leftmask), d++;
- /* Central run */
- for (i = bytewidth; i > 0; i--) {
- s0 = s1; s1 = *s++;
- v = ((s0<<8) | s1)>>shift;
- if (op == JBIG2_COMPOSE_OR)
- *d++ |= v;
- else if (op == JBIG2_COMPOSE_AND)
- *d++ &= v;
- else if (op == JBIG2_COMPOSE_XOR)
- *d++ ^= v;
- else if (op == JBIG2_COMPOSE_XNOR)
- *d++ ^= ~v;
- else /* Replace */
- *d++ = v;
- }
- /* Right byte */
- s0 = s1; s1 = (late ? 0 : *s);
- v = (((s0<<8) | s1)>>shift);
- if (op == JBIG2_COMPOSE_OR)
- *d |= v & rightmask;
- else if (op == JBIG2_COMPOSE_AND)
- *d &= (v & rightmask) | ~rightmask;
- else if (op == JBIG2_COMPOSE_XOR)
- *d ^= v & rightmask;
- else if (op == JBIG2_COMPOSE_XNOR)
- *d ^= ~v & rightmask;
- else /* Replace */
- *d = (v & rightmask) | (*d & ~rightmask);
- dd += dstride;
- ss += sstride;
- }
- }
- }
- static void
- 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)
- {
- if (early || late)
- template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_OR);
- else
- template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_OR);
- }
- static void
- 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)
- {
- if (early || late)
- template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_AND);
- else
- template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_AND);
- }
- static void
- 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)
- {
- if (early || late)
- template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XOR);
- else
- template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XOR);
- }
- static void
- 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)
- {
- if (early || late)
- template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XNOR);
- else
- template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XNOR);
- }
- static void
- 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)
- {
- if (early || late)
- template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_REPLACE);
- else
- template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_REPLACE);
- }
- /* composite one jbig2_image onto another */
- int
- jbig2_image_compose(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int y, Jbig2ComposeOp op)
- {
- uint32_t w, h;
- uint32_t shift;
- uint32_t leftbyte;
- uint8_t *ss;
- uint8_t *dd;
- uint8_t leftmask, rightmask;
- int early = x >= 0;
- int late;
- uint32_t bytewidth;
- uint32_t syoffset = 0;
- if (src == NULL)
- return 0;
- if ((UINT32_MAX - src->width < (uint32_t) (x > 0 ? x : -x)) ||
- (UINT32_MAX - src->height < (uint32_t) (y > 0 ? y : -y)))
- {
- #ifdef JBIG2_DEBUG
- jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "overflow in compose_image");
- #endif
- return 0;
- }
- /* This code takes a src image and combines it onto dst at offset (x,y), with operation op. */
- /* Data is packed msb first within a byte, so with bits numbered: 01234567.
- * Second byte is: 89abcdef. So to combine into a run, we use:
- * (s[0]<<8) | s[1] == 0123456789abcdef.
- * To read from src into dst at offset 3, we need to read:
- * read: 0123456789abcdef...
- * write: 0123456798abcdef...
- * In general, to read from src and write into dst at offset x, we need to shift
- * down by (x&7) bits to allow for bit alignment. So shift = x&7.
- * So the 'central' part of our runs will see us doing:
- * *d++ op= ((s[0]<<8)|s[1])>>shift;
- * with special cases on the left and right edges of the run to mask.
- * With the left hand edge, we have to be careful not to 'underread' the start of
- * the src image; this is what the early flag is about. Similarly we have to be
- * careful not to read off the right hand edge; this is what the late flag is for.
- */
- /* clip */
- w = src->width;
- h = src->height;
- shift = (x & 7);
- ss = src->data - early;
- if (x < 0) {
- if (w < (uint32_t) -x)
- w = 0;
- else
- w += x;
- ss += (-x-1)>>3;
- x = 0;
- }
- if (y < 0) {
- if (h < (uint32_t) -y)
- h = 0;
- else
- h += y;
- syoffset = -y * src->stride;
- y = 0;
- }
- if ((uint32_t)x + w > dst->width)
- {
- if (dst->width < (uint32_t)x)
- w = 0;
- else
- w = dst->width - x;
- }
- if ((uint32_t)y + h > dst->height)
- {
- if (dst->height < (uint32_t)y)
- h = 0;
- else
- h = dst->height - y;
- }
- #ifdef JBIG2_DEBUG
- jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "compositing %dx%d at (%d, %d) after clipping", w, h, x, y);
- #endif
- /* check for zero clipping region */
- if ((w <= 0) || (h <= 0)) {
- #ifdef JBIG2_DEBUG
- jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "zero clipping region");
- #endif
- return 0;
- }
- leftbyte = (uint32_t) x >> 3;
- dd = dst->data + y * dst->stride + leftbyte;
- bytewidth = (((uint32_t) x + w - 1) >> 3) - leftbyte + 1;
- leftmask = 255>>(x&7);
- rightmask = (((x+w)&7) == 0) ? 255 : ~(255>>((x+w)&7));
- if (bytewidth == 1)
- leftmask &= rightmask;
- late = (ss + bytewidth >= src->data + ((src->width+7)>>3));
- ss += syoffset;
- switch(op)
- {
- case JBIG2_COMPOSE_OR:
- jbig2_image_compose_opt_OR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
- break;
- case JBIG2_COMPOSE_AND:
- jbig2_image_compose_opt_AND(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
- break;
- case JBIG2_COMPOSE_XOR:
- jbig2_image_compose_opt_XOR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
- break;
- case JBIG2_COMPOSE_XNOR:
- jbig2_image_compose_opt_XNOR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
- break;
- case JBIG2_COMPOSE_REPLACE:
- jbig2_image_compose_opt_REPLACE(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride);
- break;
- }
- return 0;
- }
- /* initialize an image bitmap to a constant value */
- void
- jbig2_image_clear(Jbig2Ctx *ctx, Jbig2Image *image, int value)
- {
- const uint8_t fill = value ? 0xFF : 0x00;
- memset(image->data, fill, image->stride * image->height);
- }
- /* look up a pixel value in an image.
- returns 0 outside the image frame for the convenience of
- the template code
- */
- int
- jbig2_image_get_pixel(Jbig2Image *image, int x, int y)
- {
- const int w = image->width;
- const int h = image->height;
- const int byte = (x >> 3) + y * image->stride;
- const int bit = 7 - (x & 7);
- if ((x < 0) || (x >= w))
- return 0;
- if ((y < 0) || (y >= h))
- return 0;
- return ((image->data[byte] >> bit) & 1);
- }
- /* set an individual pixel value in an image */
- void
- jbig2_image_set_pixel(Jbig2Image *image, int x, int y, bool value)
- {
- const int w = image->width;
- const int h = image->height;
- int scratch, mask;
- int bit, byte;
- if ((x < 0) || (x >= w))
- return;
- if ((y < 0) || (y >= h))
- return;
- byte = (x >> 3) + y * image->stride;
- bit = 7 - (x & 7);
- mask = (1 << bit) ^ 0xff;
- scratch = image->data[byte] & mask;
- image->data[byte] = scratch | (value << bit);
- }
|