Blame jbig2_image.c

Packit 3f21c4
/* Copyright (C) 2001-2012 Artifex Software, Inc.
Packit 3f21c4
   All Rights Reserved.
Packit 3f21c4
Packit 3f21c4
   This software is provided AS-IS with no warranty, either express or
Packit 3f21c4
   implied.
Packit 3f21c4
Packit 3f21c4
   This software is distributed under license and may not be copied,
Packit 3f21c4
   modified or distributed except as expressly authorized under the terms
Packit 3f21c4
   of the license contained in the file LICENSE in this distribution.
Packit 3f21c4
Packit 3f21c4
   Refer to licensing information at http://www.artifex.com or contact
Packit 3f21c4
   Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
Packit 3f21c4
   CA  94903, U.S.A., +1(415)492-9861, for further information.
Packit 3f21c4
*/
Packit 3f21c4
Packit 3f21c4
/*
Packit 3f21c4
    jbig2dec
Packit 3f21c4
*/
Packit 3f21c4
Packit 3f21c4
#ifdef HAVE_CONFIG_H
Packit 3f21c4
#include "config.h"
Packit 3f21c4
#endif
Packit 3f21c4
#include "os_types.h"
Packit 3f21c4
Packit 3f21c4
#include <stdio.h>
Packit 3f21c4
#include <stdlib.h>
Packit 3f21c4
#include <string.h>             /* memcpy() */
Packit 3f21c4
Packit 3f21c4
#include "jbig2.h"
Packit 3f21c4
#include "jbig2_priv.h"
Packit 3f21c4
#include "jbig2_image.h"
Packit 3f21c4
Packit Service 9f36f9
#if !defined (UINT32_MAX)
Packit Service 9f36f9
#define UINT32_MAX  0xffffffffu
Packit Service 9f36f9
#endif
Packit Service 9f36f9
Packit 3f21c4
/* allocate a Jbig2Image structure and its associated bitmap */
Packit 3f21c4
Jbig2Image *
Packit 3f21c4
jbig2_image_new(Jbig2Ctx *ctx, uint32_t width, uint32_t height)
Packit 3f21c4
{
Packit 3f21c4
    Jbig2Image *image;
Packit 3f21c4
    uint32_t stride;
Packit 3f21c4
    int64_t check;
Packit 3f21c4
Packit 3f21c4
    if (width == 0 || height == 0) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1,
Packit 3f21c4
            "zero width (%d) or height (%d) in jbig2_image_new",
Packit 3f21c4
            width, height);
Packit 3f21c4
        return NULL;
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    image = jbig2_new(ctx, Jbig2Image, 1);
Packit 3f21c4
    if (image == NULL) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "could not allocate image structure in jbig2_image_new");
Packit 3f21c4
        return NULL;
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    stride = ((width - 1) >> 3) + 1;    /* generate a byte-aligned stride */
Packit 3f21c4
    /* check for integer multiplication overflow */
Packit 3f21c4
    check = ((int64_t) stride) * ((int64_t) height);
Packit 3f21c4
    if (check != (int)check) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "integer multiplication overflow from stride(%d)*height(%d)", stride, height);
Packit 3f21c4
        jbig2_free(ctx->allocator, image);
Packit 3f21c4
        return NULL;
Packit 3f21c4
    }
Packit 3f21c4
    /* Add 1 to accept runs that exceed image width and clamped to width+1 */
Packit 3f21c4
    image->data = jbig2_new(ctx, uint8_t, (int)check + 1);
Packit 3f21c4
    if (image->data == NULL) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "could not allocate image data buffer! [stride(%d)*height(%d) bytes]", stride, height);
Packit 3f21c4
        jbig2_free(ctx->allocator, image);
Packit 3f21c4
        return NULL;
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    image->width = width;
Packit 3f21c4
    image->height = height;
Packit 3f21c4
    image->stride = stride;
Packit 3f21c4
    image->refcount = 1;
Packit 3f21c4
Packit 3f21c4
    return image;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/* clone an image pointer by bumping its reference count */
Packit 3f21c4
Jbig2Image *
Packit 3f21c4
jbig2_image_clone(Jbig2Ctx *ctx, Jbig2Image *image)
Packit 3f21c4
{
Packit 3f21c4
    if (image)
Packit 3f21c4
        image->refcount++;
Packit 3f21c4
    return image;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/* release an image pointer, freeing it it appropriate */
Packit 3f21c4
void
Packit 3f21c4
jbig2_image_release(Jbig2Ctx *ctx, Jbig2Image *image)
Packit 3f21c4
{
Packit 3f21c4
    if (image == NULL)
Packit 3f21c4
        return;
Packit 3f21c4
    image->refcount--;
Packit 3f21c4
    if (!image->refcount)
Packit 3f21c4
        jbig2_image_free(ctx, image);
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/* free a Jbig2Image structure and its associated memory */
Packit 3f21c4
void
Packit 3f21c4
jbig2_image_free(Jbig2Ctx *ctx, Jbig2Image *image)
Packit 3f21c4
{
Packit 3f21c4
    if (image)
Packit 3f21c4
        jbig2_free(ctx->allocator, image->data);
Packit 3f21c4
    jbig2_free(ctx->allocator, image);
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/* resize a Jbig2Image */
Packit 3f21c4
Jbig2Image *
Packit 3f21c4
jbig2_image_resize(Jbig2Ctx *ctx, Jbig2Image *image, uint32_t width, uint32_t height)
Packit 3f21c4
{
Packit 3f21c4
    if (width == image->width) {
Packit 3f21c4
        /* check for integer multiplication overflow */
Packit 3f21c4
        int64_t check = ((int64_t) image->stride) * ((int64_t) height);
Packit 3f21c4
Packit 3f21c4
        if (check != (int)check) {
Packit 3f21c4
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "integer multiplication overflow during resize stride(%d)*height(%d)", image->stride, height);
Packit 3f21c4
            return NULL;
Packit 3f21c4
        }
Packit 3f21c4
        /* use the same stride, just change the length */
Packit 3f21c4
        image->data = jbig2_renew(ctx, image->data, uint8_t, (int)check);
Packit 3f21c4
        if (image->data == NULL) {
Packit 3f21c4
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "could not resize image buffer!");
Packit 3f21c4
            return NULL;
Packit 3f21c4
        }
Packit 3f21c4
        if (height > image->height) {
Packit 3f21c4
            memset(image->data + image->height * image->stride, 0, (height - image->height) * image->stride);
Packit 3f21c4
        }
Packit 3f21c4
        image->height = height;
Packit 3f21c4
Packit 3f21c4
    } else {
Packit 3f21c4
        /* we must allocate a new image buffer and copy */
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "jbig2_image_resize called with a different width (NYI)");
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    return NULL;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/* composite one jbig2_image onto another
Packit 3f21c4
   slow but general version */
Packit 3f21c4
static int
Packit 3f21c4
jbig2_image_compose_unopt(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int y, Jbig2ComposeOp op)
Packit 3f21c4
{
Packit 3f21c4
    uint32_t i, j;
Packit 3f21c4
    uint32_t sw = src->width;
Packit 3f21c4
    uint32_t sh = src->height;
Packit 3f21c4
    uint32_t sx = 0;
Packit 3f21c4
    uint32_t sy = 0;
Packit 3f21c4
Packit 3f21c4
    /* clip to the dst image boundaries */
Packit 3f21c4
    if (x < 0) {
Packit 3f21c4
        sx += -x;
Packit 3f21c4
        if (sw < (uint32_t)-x)
Packit 3f21c4
            sw = 0;
Packit 3f21c4
        else
Packit 3f21c4
            sw -= -x;
Packit 3f21c4
        x = 0;
Packit 3f21c4
    }
Packit 3f21c4
    if (y < 0) {
Packit 3f21c4
        sy += -y;
Packit 3f21c4
        if (sh < (uint32_t)-y)
Packit 3f21c4
            sh = 0;
Packit 3f21c4
        else
Packit 3f21c4
            sh -= -y;
Packit 3f21c4
        y = 0;
Packit 3f21c4
    }
Packit 3f21c4
    if ((uint32_t)x + sw >= dst->width) {
Packit 3f21c4
        if (dst->width >= (uint32_t)x)
Packit 3f21c4
            sw = dst->width - x;
Packit 3f21c4
        else
Packit 3f21c4
            sw = 0;
Packit 3f21c4
    }
Packit 3f21c4
    if ((uint32_t)y + sh >= dst->height) {
Packit 3f21c4
        if (dst->height >= (uint32_t)y)
Packit 3f21c4
            sh = dst->height - y;
Packit 3f21c4
        else
Packit 3f21c4
            sh = 0;
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    switch (op) {
Packit 3f21c4
    case JBIG2_COMPOSE_OR:
Packit 3f21c4
        for (j = 0; j < sh; j++) {
Packit 3f21c4
            for (i = 0; i < sw; i++) {
Packit 3f21c4
                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));
Packit 3f21c4
            }
Packit 3f21c4
        }
Packit 3f21c4
        break;
Packit 3f21c4
    case JBIG2_COMPOSE_AND:
Packit 3f21c4
        for (j = 0; j < sh; j++) {
Packit 3f21c4
            for (i = 0; i < sw; i++) {
Packit 3f21c4
                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));
Packit 3f21c4
            }
Packit 3f21c4
        }
Packit 3f21c4
        break;
Packit 3f21c4
    case JBIG2_COMPOSE_XOR:
Packit 3f21c4
        for (j = 0; j < sh; j++) {
Packit 3f21c4
            for (i = 0; i < sw; i++) {
Packit 3f21c4
                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));
Packit 3f21c4
            }
Packit 3f21c4
        }
Packit 3f21c4
        break;
Packit 3f21c4
    case JBIG2_COMPOSE_XNOR:
Packit 3f21c4
        for (j = 0; j < sh; j++) {
Packit 3f21c4
            for (i = 0; i < sw; i++) {
Packit 3f21c4
                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)));
Packit 3f21c4
            }
Packit 3f21c4
        }
Packit 3f21c4
        break;
Packit 3f21c4
    case JBIG2_COMPOSE_REPLACE:
Packit 3f21c4
        for (j = 0; j < sh; j++) {
Packit 3f21c4
            for (i = 0; i < sw; i++) {
Packit 3f21c4
                jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy));
Packit 3f21c4
            }
Packit 3f21c4
        }
Packit 3f21c4
        break;
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    return 0;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/* composite one jbig2_image onto another */
Packit 3f21c4
int
Packit 3f21c4
jbig2_image_compose(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int y, Jbig2ComposeOp op)
Packit 3f21c4
{
Packit 3f21c4
    uint32_t i, j;
Packit 3f21c4
    uint32_t w, h;
Packit 3f21c4
    uint32_t leftbyte, rightbyte;
Packit 3f21c4
    uint32_t shift;
Packit 3f21c4
    uint8_t *s, *ss;
Packit 3f21c4
    uint8_t *d, *dd;
Packit 3f21c4
    uint8_t mask, rightmask;
Packit 3f21c4
Packit Service 9f36f9
    if ((UINT32_MAX - src->width  < (x > 0 ? x : -x)) ||
Packit Service 9f36f9
        (UINT32_MAX - src->height < (y > 0 ? y : -y)))
Packit Service 9f36f9
    {
Packit Service 9f36f9
#ifdef JBIG2_DEBUG
Packit Service 9f36f9
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "overflow in compose_image");
Packit Service 9f36f9
#endif
Packit Service 9f36f9
        return 0;
Packit Service 9f36f9
    }
Packit Service 9f36f9
Packit 3f21c4
    if (op != JBIG2_COMPOSE_OR) {
Packit 3f21c4
        /* hand off the the general routine */
Packit 3f21c4
        return jbig2_image_compose_unopt(ctx, dst, src, x, y, op);
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /* clip */
Packit 3f21c4
    w = src->width;
Packit 3f21c4
    h = src->height;
Packit 3f21c4
    ss = src->data;
Packit 3f21c4
Packit 3f21c4
    if (x < 0) {
Packit 3f21c4
        if (w < (uint32_t)-x)
Packit 3f21c4
            w = 0;
Packit 3f21c4
        else
Packit 3f21c4
            w += x;
Packit 3f21c4
        x = 0;
Packit 3f21c4
    }
Packit 3f21c4
    if (y < 0) {
Packit 3f21c4
        if (h < (uint32_t)-y)
Packit 3f21c4
            h = 0;
Packit 3f21c4
        else
Packit 3f21c4
            h += y;
Packit 3f21c4
        y = 0;
Packit 3f21c4
    }
Packit 3f21c4
    w = ((uint32_t)x + w < dst->width) ? w : ((dst->width >= (uint32_t)x) ? dst->width - (uint32_t)x : 0);
Packit 3f21c4
    h = ((uint32_t)y + h < dst->height) ? h : ((dst->height >= (uint32_t)y) ? dst->height - (uint32_t)y : 0);
Packit 3f21c4
#ifdef JBIG2_DEBUG
Packit 3f21c4
    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "compositing %dx%d at (%d, %d) after clipping\n", w, h, x, y);
Packit 3f21c4
#endif
Packit 3f21c4
Packit 3f21c4
    /* check for zero clipping region */
Packit 3f21c4
    if ((w <= 0) || (h <= 0)) {
Packit 3f21c4
#ifdef JBIG2_DEBUG
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "zero clipping region");
Packit 3f21c4
#endif
Packit 3f21c4
        return 0;
Packit 3f21c4
    }
Packit 3f21c4
#if 0
Packit 3f21c4
    /* special case complete/strip replacement */
Packit 3f21c4
    /* disabled because it's only safe to do when the destination
Packit 3f21c4
       buffer is all-blank. */
Packit 3f21c4
    if ((x == 0) && (w == src->width)) {
Packit 3f21c4
        memcpy(dst->data + y * dst->stride, src->data, h * src->stride);
Packit 3f21c4
        return 0;
Packit 3f21c4
    }
Packit 3f21c4
#endif
Packit 3f21c4
Packit 3f21c4
    leftbyte = (uint32_t)x >> 3;
Packit 3f21c4
    rightbyte = ((uint32_t)x + w - 1) >> 3;
Packit 3f21c4
    shift = x & 7;
Packit 3f21c4
Packit 3f21c4
    /* general OR case */
Packit 3f21c4
    s = ss;
Packit 3f21c4
    d = dd = dst->data + y * dst->stride + leftbyte;
Packit 3f21c4
    if (d < dst->data || leftbyte > dst->stride || d - leftbyte + h * dst->stride > dst->data + dst->height * dst->stride ||
Packit 3f21c4
        s - leftbyte + (h - 1) * src->stride + rightbyte > src->data + src->height * src->stride) {
Packit 3f21c4
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "preventing heap overflow in jbig2_image_compose");
Packit 3f21c4
    }
Packit 3f21c4
    if (leftbyte == rightbyte) {
Packit 3f21c4
        mask = 0x100 - (0x100 >> w);
Packit 3f21c4
        for (j = 0; j < h; j++) {
Packit 3f21c4
            *d |= (*s & mask) >> shift;
Packit 3f21c4
            d += dst->stride;
Packit 3f21c4
            s += src->stride;
Packit 3f21c4
        }
Packit 3f21c4
    } else if (shift == 0) {
Packit 3f21c4
        rightmask = (w & 7) ? 0x100 - (1 << (8 - (w & 7))) : 0xFF;
Packit 3f21c4
        for (j = 0; j < h; j++) {
Packit 3f21c4
            for (i = leftbyte; i < rightbyte; i++)
Packit 3f21c4
                *d++ |= *s++;
Packit 3f21c4
            *d |= *s & rightmask;
Packit 3f21c4
            d = (dd += dst->stride);
Packit 3f21c4
            s = (ss += src->stride);
Packit 3f21c4
        }
Packit 3f21c4
    } else {
Packit 3f21c4
        bool overlap = (((w + 7) >> 3) < ((x + w + 7) >> 3) - (x >> 3));
Packit 3f21c4
Packit 3f21c4
        mask = 0x100 - (1 << shift);
Packit 3f21c4
        if (overlap)
Packit 3f21c4
            rightmask = (0x100 - (0x100 >> ((x + w) & 7))) >> (8 - shift);
Packit 3f21c4
        else
Packit 3f21c4
            rightmask = 0x100 - (0x100 >> (w & 7));
Packit 3f21c4
        for (j = 0; j < h; j++) {
Packit 3f21c4
            *d++ |= (*s & mask) >> shift;
Packit 3f21c4
            for (i = leftbyte; i < rightbyte - 1; i++) {
Packit 3f21c4
                *d |= ((*s++ & ~mask) << (8 - shift));
Packit 3f21c4
                *d++ |= ((*s & mask) >> shift);
Packit 3f21c4
            }
Packit 3f21c4
            if (overlap)
Packit 3f21c4
                *d |= (*s & rightmask) << (8 - shift);
Packit 3f21c4
            else
Packit 3f21c4
                *d |= ((s[0] & ~mask) << (8 - shift)) | ((s[1] & rightmask) >> shift);
Packit 3f21c4
            d = (dd += dst->stride);
Packit 3f21c4
            s = (ss += src->stride);
Packit 3f21c4
        }
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    return 0;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/* initialize an image bitmap to a constant value */
Packit 3f21c4
void
Packit 3f21c4
jbig2_image_clear(Jbig2Ctx *ctx, Jbig2Image *image, int value)
Packit 3f21c4
{
Packit 3f21c4
    const uint8_t fill = value ? 0xFF : 0x00;
Packit 3f21c4
Packit 3f21c4
    memset(image->data, fill, image->stride * image->height);
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/* look up a pixel value in an image.
Packit 3f21c4
   returns 0 outside the image frame for the convenience of
Packit 3f21c4
   the template code
Packit 3f21c4
*/
Packit 3f21c4
int
Packit 3f21c4
jbig2_image_get_pixel(Jbig2Image *image, int x, int y)
Packit 3f21c4
{
Packit 3f21c4
    const int w = image->width;
Packit 3f21c4
    const int h = image->height;
Packit 3f21c4
    const int byte = (x >> 3) + y * image->stride;
Packit 3f21c4
    const int bit = 7 - (x & 7);
Packit 3f21c4
Packit 3f21c4
    if ((x < 0) || (x >= w))
Packit 3f21c4
        return 0;
Packit 3f21c4
    if ((y < 0) || (y >= h))
Packit 3f21c4
        return 0;
Packit 3f21c4
Packit 3f21c4
    return ((image->data[byte] >> bit) & 1);
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/* set an individual pixel value in an image */
Packit 3f21c4
int
Packit 3f21c4
jbig2_image_set_pixel(Jbig2Image *image, int x, int y, bool value)
Packit 3f21c4
{
Packit 3f21c4
    const int w = image->width;
Packit 3f21c4
    const int h = image->height;
Packit 3f21c4
    int scratch, mask;
Packit 3f21c4
    int bit, byte;
Packit 3f21c4
Packit 3f21c4
    if ((x < 0) || (x >= w))
Packit 3f21c4
        return 0;
Packit 3f21c4
    if ((y < 0) || (y >= h))
Packit 3f21c4
        return 0;
Packit 3f21c4
Packit 3f21c4
    byte = (x >> 3) + y * image->stride;
Packit 3f21c4
    bit = 7 - (x & 7);
Packit 3f21c4
    mask = (1 << bit) ^ 0xff;
Packit 3f21c4
Packit 3f21c4
    scratch = image->data[byte] & mask;
Packit 3f21c4
    image->data[byte] = scratch | (value << bit);
Packit 3f21c4
Packit 3f21c4
    return 1;
Packit 3f21c4
}