Blame jbig2_halftone.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
/* JBIG2 Pattern Dictionary and Halftone Region decoding */
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 <string.h>             /* memset() */
Packit 3f21c4
Packit 3f21c4
#include "jbig2.h"
Packit 3f21c4
#include "jbig2_priv.h"
Packit 3f21c4
#include "jbig2_arith.h"
Packit 3f21c4
#include "jbig2_generic.h"
Packit 3f21c4
#include "jbig2_mmr.h"
Packit 3f21c4
#include "jbig2_image.h"
Packit 3f21c4
#include "jbig2_halftone.h"
Packit 3f21c4
Packit 3f21c4
/**
Packit 3f21c4
 * jbig2_hd_new: create a new dictionary from a collective bitmap
Packit 3f21c4
 */
Packit 3f21c4
Jbig2PatternDict *
Packit 3f21c4
jbig2_hd_new(Jbig2Ctx *ctx, const Jbig2PatternDictParams *params, Jbig2Image *image)
Packit 3f21c4
{
Packit 3f21c4
    Jbig2PatternDict *new;
Packit 3f21c4
    const int N = params->GRAYMAX + 1;
Packit 3f21c4
    const int HPW = params->HDPW;
Packit 3f21c4
    const int HPH = params->HDPH;
Packit 3f21c4
    int i;
Packit 3f21c4
Packit 3f21c4
    /* allocate a new struct */
Packit 3f21c4
    new = jbig2_new(ctx, Jbig2PatternDict, 1);
Packit 3f21c4
    if (new != NULL) {
Packit 3f21c4
        new->patterns = jbig2_new(ctx, Jbig2Image *, N);
Packit 3f21c4
        if (new->patterns == NULL) {
Packit 3f21c4
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate pattern in collective bitmap dictionary");
Packit 3f21c4
            jbig2_free(ctx->allocator, new);
Packit 3f21c4
            return NULL;
Packit 3f21c4
        }
Packit 3f21c4
        new->n_patterns = N;
Packit 3f21c4
        new->HPW = HPW;
Packit 3f21c4
        new->HPH = HPH;
Packit 3f21c4
Packit 3f21c4
        /* 6.7.5(4) - copy out the individual pattern images */
Packit 3f21c4
        for (i = 0; i < N; i++) {
Packit 3f21c4
            new->patterns[i] = jbig2_image_new(ctx, HPW, HPH);
Packit 3f21c4
            if (new->patterns[i] == NULL) {
Packit 3f21c4
                int j;
Packit 3f21c4
Packit 3f21c4
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to allocate pattern element image");
Packit 3f21c4
                for (j = 0; j < i; j++)
Packit 3f21c4
                    jbig2_free(ctx->allocator, new->patterns[j]);
Packit 3f21c4
                jbig2_free(ctx->allocator, new);
Packit 3f21c4
                return NULL;
Packit 3f21c4
            }
Packit 3f21c4
            /* compose with the REPLACE operator; the source
Packit 3f21c4
               will be clipped to the destintion, selecting the
Packit 3f21c4
               proper sub image */
Packit 3f21c4
            jbig2_image_compose(ctx, new->patterns[i], image, -i * HPW, 0, JBIG2_COMPOSE_REPLACE);
Packit 3f21c4
        }
Packit 3f21c4
    } else {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate collective bitmap dictionary");
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    return new;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/**
Packit 3f21c4
 * jbig2_hd_release: release a pattern dictionary
Packit 3f21c4
 */
Packit 3f21c4
void
Packit 3f21c4
jbig2_hd_release(Jbig2Ctx *ctx, Jbig2PatternDict *dict)
Packit 3f21c4
{
Packit 3f21c4
    int i;
Packit 3f21c4
Packit 3f21c4
    if (dict == NULL)
Packit 3f21c4
        return;
Packit 3f21c4
    for (i = 0; i < dict->n_patterns; i++)
Packit 3f21c4
        if (dict->patterns[i])
Packit 3f21c4
            jbig2_image_release(ctx, dict->patterns[i]);
Packit 3f21c4
    jbig2_free(ctx->allocator, dict->patterns);
Packit 3f21c4
    jbig2_free(ctx->allocator, dict);
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/**
Packit 3f21c4
 * jbig2_decode_pattern_dict: decode pattern dictionary data
Packit 3f21c4
 *
Packit 3f21c4
 * @ctx: jbig2 decoder context
Packit 3f21c4
 * @segment: jbig2 segment (header) structure
Packit 3f21c4
 * @params: parameters from the pattern dictionary header
Packit 3f21c4
 * @data: pointer to text region data to be decoded
Packit 3f21c4
 * @size: length of text region data
Packit 3f21c4
 * @GB_stats: artimetic coding context to use
Packit 3f21c4
 *
Packit 3f21c4
 * Implements the patten dictionary decoding proceedure
Packit 3f21c4
 * described in section 6.7 of the JBIG2 spec.
Packit 3f21c4
 *
Packit 3f21c4
 * returns: a pointer to the resulting dictionary on success
Packit 3f21c4
 * returns: 0 on failure
Packit 3f21c4
 **/
Packit 3f21c4
static Jbig2PatternDict *
Packit 3f21c4
jbig2_decode_pattern_dict(Jbig2Ctx *ctx, Jbig2Segment *segment,
Packit 3f21c4
                          const Jbig2PatternDictParams *params, const byte *data, const size_t size, Jbig2ArithCx *GB_stats)
Packit 3f21c4
{
Packit 3f21c4
    Jbig2PatternDict *hd = NULL;
Packit 3f21c4
    Jbig2Image *image = NULL;
Packit 3f21c4
    Jbig2GenericRegionParams rparams;
Packit 3f21c4
    int code = 0;
Packit 3f21c4
Packit 3f21c4
    /* allocate the collective image */
Packit 3f21c4
    image = jbig2_image_new(ctx, params->HDPW * (params->GRAYMAX + 1), params->HDPH);
Packit 3f21c4
    if (image == NULL) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate collective bitmap for halftone dict!");
Packit 3f21c4
        return NULL;
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /* fill out the generic region decoder parameters */
Packit 3f21c4
    rparams.MMR = params->HDMMR;
Packit 3f21c4
    rparams.GBTEMPLATE = params->HDTEMPLATE;
Packit 3f21c4
    rparams.TPGDON = 0;         /* not used if HDMMR = 1 */
Packit 3f21c4
    rparams.USESKIP = 0;
Packit 3f21c4
    rparams.gbat[0] = -(int8_t) params->HDPW;
Packit 3f21c4
    rparams.gbat[1] = 0;
Packit 3f21c4
    rparams.gbat[2] = -3;
Packit 3f21c4
    rparams.gbat[3] = -1;
Packit 3f21c4
    rparams.gbat[4] = 2;
Packit 3f21c4
    rparams.gbat[5] = -2;
Packit 3f21c4
    rparams.gbat[6] = -2;
Packit 3f21c4
    rparams.gbat[7] = -2;
Packit 3f21c4
Packit 3f21c4
    if (params->HDMMR) {
Packit 3f21c4
        code = jbig2_decode_generic_mmr(ctx, segment, &rparams, data, size, image);
Packit 3f21c4
    } else {
Packit 3f21c4
        Jbig2WordStream *ws = jbig2_word_stream_buf_new(ctx, data, size);
Packit 3f21c4
Packit 3f21c4
        if (ws != NULL) {
Packit 3f21c4
            Jbig2ArithState *as = jbig2_arith_new(ctx, ws);
Packit 3f21c4
Packit 3f21c4
            if (as != NULL) {
Packit 3f21c4
                code = jbig2_decode_generic_region(ctx, segment, &rparams, as, image, GB_stats);
Packit 3f21c4
            } else {
Packit 3f21c4
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for as in halftone dict!");
Packit 3f21c4
            }
Packit 3f21c4
Packit 3f21c4
            jbig2_free(ctx->allocator, as);
Packit 3f21c4
            jbig2_word_stream_buf_free(ctx, ws);
Packit 3f21c4
        } else {
Packit 3f21c4
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for ws in halftone dict!");
Packit 3f21c4
        }
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    if (code == 0)
Packit 3f21c4
        hd = jbig2_hd_new(ctx, params, image);
Packit 3f21c4
    jbig2_image_release(ctx, image);
Packit 3f21c4
Packit 3f21c4
    return hd;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/* 7.4.4 */
Packit 3f21c4
int
Packit 3f21c4
jbig2_pattern_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
Packit 3f21c4
{
Packit 3f21c4
    Jbig2PatternDictParams params;
Packit 3f21c4
    Jbig2ArithCx *GB_stats = NULL;
Packit 3f21c4
    byte flags;
Packit 3f21c4
    int offset = 0;
Packit 3f21c4
Packit 3f21c4
    /* 7.4.4.1 - Data header */
Packit 3f21c4
    if (segment->data_length < 7) {
Packit 3f21c4
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short");
Packit 3f21c4
    }
Packit 3f21c4
    flags = segment_data[0];
Packit 3f21c4
    params.HDMMR = flags & 1;
Packit 3f21c4
    params.HDTEMPLATE = (flags & 6) >> 1;
Packit 3f21c4
    params.HDPW = segment_data[1];
Packit 3f21c4
    params.HDPH = segment_data[2];
Packit 3f21c4
    params.GRAYMAX = jbig2_get_uint32(segment_data + 3);
Packit 3f21c4
    offset += 7;
Packit 3f21c4
Packit 3f21c4
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
Packit 3f21c4
                "pattern dictionary, flags=%02x, %d grays (%dx%d cell)", flags, params.GRAYMAX + 1, params.HDPW, params.HDPH);
Packit 3f21c4
Packit 3f21c4
    if (params.HDMMR && params.HDTEMPLATE) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "HDTEMPLATE is %d when HDMMR is %d, contrary to spec", params.HDTEMPLATE, params.HDMMR);
Packit 3f21c4
    }
Packit 3f21c4
    if (flags & 0xf8) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "Reserved flag bits non-zero");
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /* 7.4.4.2 */
Packit 3f21c4
    if (!params.HDMMR) {
Packit 3f21c4
        /* allocate and zero arithmetic coding stats */
Packit 3f21c4
        int stats_size = jbig2_generic_stats_size(ctx, params.HDTEMPLATE);
Packit 3f21c4
Packit 3f21c4
        GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
Packit 3f21c4
        if (GB_stats == NULL) {
Packit 3f21c4
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate GB_stats in pattern dictionary");
Packit 3f21c4
            return 0;
Packit 3f21c4
        }
Packit 3f21c4
        memset(GB_stats, 0, stats_size);
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    segment->result = jbig2_decode_pattern_dict(ctx, segment, &params, segment_data + offset, segment->data_length - offset, GB_stats);
Packit 3f21c4
Packit 3f21c4
    /* todo: retain GB_stats? */
Packit 3f21c4
    if (!params.HDMMR) {
Packit 3f21c4
        jbig2_free(ctx->allocator, GB_stats);
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    return (segment->result != NULL) ? 0 : -1;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/**
Packit 3f21c4
 * jbig2_decode_gray_scale_image: decode gray-scale image
Packit 3f21c4
 *
Packit 3f21c4
 * @ctx: jbig2 decoder context
Packit 3f21c4
 * @segment: jbig2 segment (header) structure
Packit 3f21c4
 * @data: pointer to text region data to be decoded
Packit 3f21c4
 * @size: length of text region data
Packit 3f21c4
 * @GSMMR: if MMR is used
Packit 3f21c4
 * @GSW: width of gray-scale image
Packit 3f21c4
 * @GSH: height of gray-scale image
Packit 3f21c4
 * @GSBPP: number of bitplanes/Jbig2Images to use
Packit 3f21c4
 * @GSKIP: mask indicating which values should be skipped
Packit 3f21c4
 * @GSTEMPLATE: template used to code the gray-scale bitplanes
Packit 3f21c4
 * @GB_stats: artimetic coding context to use
Packit 3f21c4
 *
Packit 3f21c4
 * Implements the decoding a gray-scale image described in
Packit 3f21c4
 * annex C.5. This is part of the halftone region decoding.
Packit 3f21c4
 *
Packit 3f21c4
 * returns: array of gray-scale values with GSW x GSH width/height
Packit 3f21c4
 *          0 on failure
Packit 3f21c4
 **/
Packit 3f21c4
uint8_t **
Packit 3f21c4
jbig2_decode_gray_scale_image(Jbig2Ctx *ctx, Jbig2Segment *segment,
Packit 3f21c4
                              const byte *data, const size_t size,
Packit 3f21c4
                              bool GSMMR, uint32_t GSW, uint32_t GSH,
Packit 3f21c4
                              uint32_t GSBPP, bool GSUSESKIP, Jbig2Image *GSKIP, int GSTEMPLATE, Jbig2ArithCx *GB_stats)
Packit 3f21c4
{
Packit 3f21c4
    uint8_t **GSVALS = NULL;
Packit 3f21c4
    size_t consumed_bytes = 0;
Packit 3f21c4
    uint32_t i, j, stride, x, y;
Packit 3f21c4
    int code;
Packit 3f21c4
    Jbig2Image **GSPLANES;
Packit 3f21c4
    Jbig2GenericRegionParams rparams;
Packit 3f21c4
    Jbig2WordStream *ws = NULL;
Packit 3f21c4
    Jbig2ArithState *as = NULL;
Packit 3f21c4
Packit 3f21c4
    /* allocate GSPLANES */
Packit 3f21c4
    GSPLANES = jbig2_new(ctx, Jbig2Image *, GSBPP);
Packit 3f21c4
    if (GSPLANES == NULL) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate %d bytes for GSPLANES", GSBPP);
Packit 3f21c4
        return NULL;
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    for (i = 0; i < GSBPP; ++i) {
Packit 3f21c4
        GSPLANES[i] = jbig2_image_new(ctx, GSW, GSH);
Packit 3f21c4
        if (GSPLANES[i] == NULL) {
Packit 3f21c4
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate %dx%d image for GSPLANES", GSW, GSH);
Packit 3f21c4
            /* free already allocated */
Packit 3f21c4
            for (j = i; j > 0;)
Packit 3f21c4
                jbig2_image_release(ctx, GSPLANES[--j]);
Packit 3f21c4
            jbig2_free(ctx->allocator, GSPLANES);
Packit 3f21c4
            return NULL;
Packit 3f21c4
        }
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /* C.5 step 1. Decode GSPLANES[GSBPP-1] */
Packit 3f21c4
    /* fill generic region decoder parameters */
Packit 3f21c4
    rparams.MMR = GSMMR;
Packit 3f21c4
    rparams.GBTEMPLATE = GSTEMPLATE;
Packit 3f21c4
    rparams.TPGDON = 0;
Packit 3f21c4
    rparams.USESKIP = GSUSESKIP;
Packit 3f21c4
    rparams.gbat[0] = (GSTEMPLATE <= 1 ? 3 : 2);
Packit 3f21c4
    rparams.gbat[1] = -1;
Packit 3f21c4
    rparams.gbat[2] = -3;
Packit 3f21c4
    rparams.gbat[3] = -1;
Packit 3f21c4
    rparams.gbat[4] = 2;
Packit 3f21c4
    rparams.gbat[5] = -2;
Packit 3f21c4
    rparams.gbat[6] = -2;
Packit 3f21c4
    rparams.gbat[7] = -2;
Packit 3f21c4
Packit 3f21c4
    if (GSMMR) {
Packit 3f21c4
        code = jbig2_decode_halftone_mmr(ctx, &rparams, data, size, GSPLANES[GSBPP - 1], &consumed_bytes);
Packit 3f21c4
    } else {
Packit 3f21c4
        ws = jbig2_word_stream_buf_new(ctx, data, size);
Packit 3f21c4
        if (ws == NULL) {
Packit 3f21c4
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate ws in jbig2_decode_gray_scale_image");
Packit 3f21c4
            goto cleanup;
Packit 3f21c4
        }
Packit 3f21c4
Packit 3f21c4
        as = jbig2_arith_new(ctx, ws);
Packit 3f21c4
        if (as == NULL) {
Packit 3f21c4
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate as in jbig2_decode_gray_scale_image");
Packit 3f21c4
            goto cleanup;
Packit 3f21c4
        }
Packit 3f21c4
Packit 3f21c4
        code = jbig2_decode_generic_region(ctx, segment, &rparams, as, GSPLANES[GSBPP - 1], GB_stats);
Packit 3f21c4
Packit 3f21c4
    }
Packit 3f21c4
    if (code != 0) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding GSPLANES for halftone image");
Packit 3f21c4
        goto cleanup;
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /* C.5 step 2. Set j = GSBPP-2 */
Packit 3f21c4
    j = GSBPP - 1;
Packit 3f21c4
    /* C.5 step 3. decode loop */
Packit 3f21c4
    while (j > 0) {
Packit 3f21c4
        j--;
Packit 3f21c4
        /*  C.5 step 3. (a) */
Packit 3f21c4
        if (GSMMR) {
Packit 3f21c4
            code = jbig2_decode_halftone_mmr(ctx, &rparams, data + consumed_bytes, size - consumed_bytes, GSPLANES[j], &consumed_bytes);
Packit 3f21c4
        } else {
Packit 3f21c4
            code = jbig2_decode_generic_region(ctx, segment, &rparams, as, GSPLANES[j], GB_stats);
Packit 3f21c4
        }
Packit 3f21c4
        if (code != 0) {
Packit 3f21c4
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding GSPLANES for halftone image");
Packit 3f21c4
            goto cleanup;
Packit 3f21c4
        }
Packit 3f21c4
Packit 3f21c4
        /* C.5 step 3. (b):
Packit 3f21c4
         * for each [x,y]
Packit 3f21c4
         * GSPLANES[j][x][y] = GSPLANES[j+1][x][y] XOR GSPLANES[j][x][y] */
Packit 3f21c4
        stride = GSPLANES[0]->stride;
Packit 3f21c4
        for (i = 0; i < stride * GSH; ++i)
Packit 3f21c4
            GSPLANES[j]->data[i] ^= GSPLANES[j + 1]->data[i];
Packit 3f21c4
Packit 3f21c4
        /*  C.5 step 3. (c) */
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /* allocate GSVALS */
Packit 3f21c4
    GSVALS = jbig2_new(ctx, uint8_t *, GSW);
Packit 3f21c4
    if (GSVALS == NULL) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate GSVALS: %d bytes", GSW);
Packit 3f21c4
        goto cleanup;
Packit 3f21c4
    }
Packit 3f21c4
    for (i = 0; i < GSW; ++i) {
Packit 3f21c4
        GSVALS[i] = jbig2_new(ctx, uint8_t, GSH);
Packit 3f21c4
        if (GSVALS[i] == NULL) {
Packit 3f21c4
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate GSVALS: %d bytes", GSH * GSW);
Packit 3f21c4
            /* free already allocated */
Packit 3f21c4
            for (j = i; j > 0;)
Packit 3f21c4
                jbig2_free(ctx->allocator, GSVALS[--j]);
Packit 3f21c4
            jbig2_free(ctx->allocator, GSVALS);
Packit 3f21c4
            GSVALS = NULL;
Packit 3f21c4
            goto cleanup;
Packit 3f21c4
        }
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /*  C.5 step 4.  */
Packit 3f21c4
    for (x = 0; x < GSW; ++x) {
Packit 3f21c4
        for (y = 0; y < GSH; ++y) {
Packit 3f21c4
            GSVALS[x][y] = 0;
Packit 3f21c4
Packit 3f21c4
            for (j = 0; j < GSBPP; ++j)
Packit 3f21c4
                GSVALS[x][y] += jbig2_image_get_pixel(GSPLANES[j], x, y) << j;
Packit 3f21c4
        }
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
cleanup:
Packit 3f21c4
    /* free memory */
Packit 3f21c4
    if (!GSMMR) {
Packit 3f21c4
        jbig2_free(ctx->allocator, as);
Packit 3f21c4
        jbig2_word_stream_buf_free(ctx, ws);
Packit 3f21c4
    }
Packit 3f21c4
    for (i = 0; i < GSBPP; ++i)
Packit 3f21c4
        jbig2_image_release(ctx, GSPLANES[i]);
Packit 3f21c4
Packit 3f21c4
    jbig2_free(ctx->allocator, GSPLANES);
Packit 3f21c4
Packit 3f21c4
    return GSVALS;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/**
Packit 3f21c4
 * jbig2_decode_ht_region_get_hpats: get pattern dictionary
Packit 3f21c4
 *
Packit 3f21c4
 * @ctx: jbig2 decoder context
Packit 3f21c4
 * @segment: jbig2 halftone region segment
Packit 3f21c4
 *
Packit 3f21c4
 * Returns the first referred pattern dictionary of segment
Packit 3f21c4
 *
Packit 3f21c4
 * returns: pattern dictionary
Packit 3f21c4
 *          0 if search failed
Packit 3f21c4
 **/
Packit 3f21c4
Jbig2PatternDict *
Packit 3f21c4
jbig2_decode_ht_region_get_hpats(Jbig2Ctx *ctx, Jbig2Segment *segment)
Packit 3f21c4
{
Packit 3f21c4
    int index = 0;
Packit 3f21c4
    Jbig2PatternDict *pattern_dict = NULL;
Packit 3f21c4
    Jbig2Segment *rsegment = NULL;
Packit 3f21c4
Packit 3f21c4
    /* loop through all referred segments */
Packit 3f21c4
    while (!pattern_dict && segment->referred_to_segment_count > index) {
Packit 3f21c4
        rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]);
Packit 3f21c4
        if (rsegment) {
Packit 3f21c4
            /* segment type is pattern dictionary and result is not empty */
Packit 3f21c4
            if ((rsegment->flags & 0x3f) == 16 && rsegment->result) {
Packit 3f21c4
                pattern_dict = (Jbig2PatternDict *) rsegment->result;
Packit 3f21c4
                return pattern_dict;
Packit 3f21c4
            }
Packit 3f21c4
        }
Packit 3f21c4
        index++;
Packit 3f21c4
    }
Packit 3f21c4
    return pattern_dict;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/**
Packit 3f21c4
 * jbig2_decode_halftone_region: decode a halftone region
Packit 3f21c4
 *
Packit 3f21c4
 * @ctx: jbig2 decoder context
Packit 3f21c4
 * @segment: jbig2 halftone region segment
Packit 3f21c4
 * @params: parameters
Packit 3f21c4
 * @data: pointer to halftone region data to be decoded
Packit 3f21c4
 * @size: length of halftone region data
Packit 3f21c4
 * @GB_stats: artimetic coding context to use
Packit 3f21c4
 *
Packit 3f21c4
 * Implements the halftone region decoding proceedure
Packit 3f21c4
 * described in section 6.6.5 of the JBIG2 spec.
Packit 3f21c4
 *
Packit 3f21c4
 * returns: 0 on success
Packit 3f21c4
 *         <0 on failure
Packit 3f21c4
 **/
Packit 3f21c4
int
Packit 3f21c4
jbig2_decode_halftone_region(Jbig2Ctx *ctx, Jbig2Segment *segment,
Packit 3f21c4
                             Jbig2HalftoneRegionParams *params, const byte *data, const size_t size, Jbig2Image *image, Jbig2ArithCx *GB_stats)
Packit 3f21c4
{
Packit 3f21c4
    uint32_t HBPP;
Packit 3f21c4
    uint32_t HNUMPATS;
Packit 3f21c4
    uint8_t **GI;
Packit 3f21c4
    Jbig2Image *HSKIP = NULL;
Packit 3f21c4
    Jbig2PatternDict *HPATS;
Packit 3f21c4
    uint32_t i;
Packit 3f21c4
    uint32_t mg, ng;
Packit 3f21c4
    int32_t x, y;
Packit 3f21c4
    uint8_t gray_val;
Packit 3f21c4
Packit 3f21c4
    /* 6.6.5 point 1. Fill bitmap with HDEFPIXEL */
Packit 3f21c4
    memset(image->data, params->HDEFPIXEL, image->stride * image->height);
Packit 3f21c4
Packit 3f21c4
    /* 6.6.5 point 2. compute HSKIP */
Packit 3f21c4
    if (params->HENABLESKIP == 1) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled option HENABLESKIP");
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /* 6.6.5 point 3. set HBPP to ceil(log2(HNUMPATS)):
Packit 3f21c4
     * we need the number of patterns used in this region (HNUMPATS)
Packit 3f21c4
     * get it from referred pattern dictionary */
Packit 3f21c4
Packit 3f21c4
    HPATS = jbig2_decode_ht_region_get_hpats(ctx, segment);
Packit 3f21c4
    if (!HPATS) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "no pattern dictionary found, skipping halftone image");
Packit 3f21c4
        return -1;
Packit 3f21c4
    }
Packit 3f21c4
    HNUMPATS = HPATS->n_patterns;
Packit 3f21c4
Packit 3f21c4
    /* calculate ceil(log2(HNUMPATS)) */
Packit 3f21c4
    HBPP = 0;
Packit 3f21c4
    while (HNUMPATS > (1U << ++HBPP));
Packit 3f21c4
Packit 3f21c4
    /* 6.6.5 point 4. decode gray-scale image as mentioned in annex C */
Packit 3f21c4
    GI = jbig2_decode_gray_scale_image(ctx, segment, data, size,
Packit 3f21c4
                                       params->HMMR, params->HGW, params->HGH, HBPP, params->HENABLESKIP, HSKIP, params->HTEMPLATE, GB_stats);
Packit 3f21c4
Packit 3f21c4
    if (!GI) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to acquire gray-scale image, skipping halftone image");
Packit 3f21c4
        return -1;
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /* 6.6.5 point 5. place patterns with procedure mentioned in 6.6.5.2 */
Packit 3f21c4
    for (mg = 0; mg < params->HGH; ++mg) {
Packit 3f21c4
        for (ng = 0; ng < params->HGW; ++ng) {
Packit 3f21c4
            x = (params->HGX + mg * params->HRY + ng * params->HRX) >> 8;
Packit 3f21c4
            y = (params->HGY + mg * params->HRX - ng * params->HRY) >> 8;
Packit 3f21c4
Packit 3f21c4
            /* prevent pattern index >= HNUMPATS */
Packit 3f21c4
            gray_val = GI[ng][mg];
Packit 3f21c4
            if (gray_val >= HNUMPATS) {
Packit 3f21c4
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "gray-scale image uses value %d which larger than pattern dictionary", gray_val);
Packit 3f21c4
                /* use highest aviable pattern */
Packit 3f21c4
                gray_val = HNUMPATS - 1;
Packit 3f21c4
            }
Packit 3f21c4
            jbig2_image_compose(ctx, image, HPATS->patterns[gray_val], x, y, params->op);
Packit 3f21c4
        }
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /* free GI */
Packit 3f21c4
    for (i = 0; i < params->HGW; ++i) {
Packit 3f21c4
        jbig2_free(ctx->allocator, GI[i]);
Packit 3f21c4
    }
Packit 3f21c4
    jbig2_free(ctx->allocator, GI);
Packit 3f21c4
Packit 3f21c4
    return 0;
Packit 3f21c4
}
Packit 3f21c4
Packit 3f21c4
/**
Packit 3f21c4
 * jbig2_halftone_region: read a halftone region segment header
Packit 3f21c4
 **/
Packit 3f21c4
int
Packit 3f21c4
jbig2_halftone_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
Packit 3f21c4
{
Packit 3f21c4
    int offset = 0;
Packit 3f21c4
    Jbig2RegionSegmentInfo region_info;
Packit 3f21c4
    Jbig2HalftoneRegionParams params;
Packit 3f21c4
    Jbig2Image *image = NULL;
Packit 3f21c4
    Jbig2ArithCx *GB_stats = NULL;
Packit 3f21c4
    int code = 0;
Packit 3f21c4
Packit 3f21c4
    /* 7.4.5.1 */
Packit 3f21c4
    if (segment->data_length < 17)
Packit 3f21c4
        goto too_short;
Packit 3f21c4
    jbig2_get_region_segment_info(&region_info, segment_data);
Packit 3f21c4
    offset += 17;
Packit 3f21c4
Packit 3f21c4
    if (segment->data_length < 18)
Packit 3f21c4
        goto too_short;
Packit 3f21c4
Packit 3f21c4
    /* 7.4.5.1.1 */
Packit 3f21c4
    params.flags = segment_data[offset];
Packit 3f21c4
    params.HMMR = params.flags & 1;
Packit 3f21c4
    params.HTEMPLATE = (params.flags & 6) >> 1;
Packit 3f21c4
    params.HENABLESKIP = (params.flags & 8) >> 3;
Packit 3f21c4
    params.op = (Jbig2ComposeOp)((params.flags & 0x70) >> 4);
Packit 3f21c4
    params.HDEFPIXEL = (params.flags & 0x80) >> 7;
Packit 3f21c4
    offset += 1;
Packit 3f21c4
Packit 3f21c4
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
Packit 3f21c4
                "halftone region: %d x %d @ (%x,%d) flags=%02x", region_info.width, region_info.height, region_info.x, region_info.y, params.flags);
Packit 3f21c4
Packit 3f21c4
    if (params.HMMR && params.HTEMPLATE) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "HTEMPLATE is %d when HMMR is %d, contrary to spec", params.HTEMPLATE, params.HMMR);
Packit 3f21c4
    }
Packit 3f21c4
    if (params.HMMR && params.HENABLESKIP) {
Packit 3f21c4
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "HENABLESKIP is %d when HMMR is %d, contrary to spec", params.HENABLESKIP, params.HMMR);
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    /* Figure 43 */
Packit 3f21c4
    if (segment->data_length - offset < 16)
Packit 3f21c4
        goto too_short;
Packit 3f21c4
    params.HGW = jbig2_get_uint32(segment_data + offset);
Packit 3f21c4
    params.HGH = jbig2_get_uint32(segment_data + offset + 4);
Packit 3f21c4
    params.HGX = jbig2_get_int32(segment_data + offset + 8);
Packit 3f21c4
    params.HGY = jbig2_get_int32(segment_data + offset + 12);
Packit 3f21c4
    offset += 16;
Packit 3f21c4
Packit 3f21c4
    /* Figure 44 */
Packit 3f21c4
    if (segment->data_length - offset < 4)
Packit 3f21c4
        goto too_short;
Packit 3f21c4
    params.HRX = jbig2_get_uint16(segment_data + offset);
Packit 3f21c4
    params.HRY = jbig2_get_uint16(segment_data + offset + 2);
Packit 3f21c4
    offset += 4;
Packit 3f21c4
Packit 3f21c4
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
Packit 3f21c4
                " grid %d x %d @ (%d.%d,%d.%d) vector (%d.%d,%d.%d)",
Packit 3f21c4
                params.HGW, params.HGH,
Packit 3f21c4
                params.HGX >> 8, params.HGX & 0xff, params.HGY >> 8, params.HGY & 0xff, params.HRX >> 8, params.HRX & 0xff, params.HRY >> 8, params.HRY & 0xff);
Packit 3f21c4
Packit 3f21c4
    /* 7.4.5.2.2 */
Packit 3f21c4
    if (!params.HMMR) {
Packit 3f21c4
        /* allocate and zero arithmetic coding stats */
Packit 3f21c4
        int stats_size = jbig2_generic_stats_size(ctx, params.HTEMPLATE);
Packit 3f21c4
Packit 3f21c4
        GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
Packit 3f21c4
        if (GB_stats == NULL) {
Packit 3f21c4
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate GB_stats in halftone region");
Packit 3f21c4
        }
Packit 3f21c4
        memset(GB_stats, 0, stats_size);
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    image = jbig2_image_new(ctx, region_info.width, region_info.height);
Packit 3f21c4
    if (image == NULL) {
Packit 3f21c4
        jbig2_free(ctx->allocator, GB_stats);
Packit 3f21c4
        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to allocate halftone image");
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    code = jbig2_decode_halftone_region(ctx, segment, &params, segment_data + offset, segment->data_length - offset, image, GB_stats);
Packit 3f21c4
Packit 3f21c4
    /* todo: retain GB_stats? */
Packit 3f21c4
    if (!params.HMMR) {
Packit 3f21c4
        jbig2_free(ctx->allocator, GB_stats);
Packit 3f21c4
    }
Packit 3f21c4
Packit 3f21c4
    jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, region_info.x, region_info.y, region_info.op);
Packit 3f21c4
    jbig2_image_release(ctx, image);
Packit 3f21c4
Packit 3f21c4
    return code;
Packit 3f21c4
Packit 3f21c4
too_short:
Packit 3f21c4
    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short");
Packit 3f21c4
}