ref: 1fde432da43cbe5bc34f3a95ee5d2f2466090e52
dir: /jbig2_halftone.c/
/* jbig2dec Copyright (C) 2005 Artifex Software, Inc. 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. For further licensing information refer to http://artifex.com/ or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861. */ /* JBIG2 Pattern Dictionary and Halftone Region decoding */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include <string.h> /* memset() */ #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" #include "jbig2_generic.h" #include "jbig2_mmr.h" typedef struct { int n_patterns; Jbig2Image **patterns; int HPW, HPH; } Jbig2PatternDict; /* Table 24 */ typedef struct { bool HDMMR; uint32_t HDPW; uint32_t HDPH; uint32_t GRAYMAX; int HDTEMPLATE; } Jbig2PatternDictParams; /* Table 33 */ typedef struct { byte flags; uint32_t HGW; uint32_t HGH; int32_t HGX; int32_t HGY; uint16_t HRX; uint16_t HRY; bool HMMR; int HTEMPLATE; bool HENABLESKIP; Jbig2ComposeOp op; bool HDEFPIXEL; } Jbig2HalftoneRegionParams; /** * jbig2_hd_new: create a new dictionary from a collective bitmap */ Jbig2PatternDict * jbig2_hd_new(Jbig2Ctx *ctx, const Jbig2PatternDictParams *params, Jbig2Image *image) { Jbig2PatternDict *new; const int N = params->GRAYMAX + 1; const int HPW = params->HDPW; const int HPH = params->HDPH; int i; /* allocate a new struct */ new = (Jbig2PatternDict *)jbig2_alloc(ctx->allocator, sizeof(Jbig2PatternDict)); if (new != NULL) { new->patterns = (Jbig2Image **)jbig2_alloc(ctx->allocator, N*sizeof(Jbig2Image*)); if (new->patterns == NULL) { jbig2_free(ctx->allocator, new); return NULL; } new->n_patterns = N; new->HPW = HPW; new->HPH = HPH; /* 6.7.5(4) - copy out the individual pattern images */ for (i = 0; i < N; i++) { new->patterns[i] = jbig2_image_new(ctx, HPW, HPH); /* compose with the REPLACE operator; the source will be clipped to the destintion, selecting the proper sub image */ jbig2_image_compose(ctx, new->patterns[i], image, -i * HPW, 0, JBIG2_COMPOSE_REPLACE); } } return new; } /** * jbig2_hd_release: release a pattern dictionary */ void jbig2_hd_release(Jbig2Ctx *ctx, Jbig2PatternDict *dict) { int i; if (dict == NULL) return; for (i = 0; i < dict->n_patterns; i++) if (dict->patterns[i]) jbig2_image_release(ctx, dict->patterns[i]); jbig2_free(ctx->allocator, dict->patterns); jbig2_free(ctx->allocator, dict); } /** * jbig2_decode_pattern_dict: decode pattern dictionary data * * @ctx: jbig2 decoder context * @segment: jbig2 segment (header) structure * @params: parameters from the pattern dictionary header * @data: pointer to text region data to be decoded * @size: length of text region data * @GB_stats: artimetic coding context to use * * Implements the patten dictionary decoding proceedure * described in section 6.7 of the JBIG2 spec. * * returns: a pointer to the resulting dictionary on success * returns: 0 on failure **/ static Jbig2PatternDict * jbig2_decode_pattern_dict(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2PatternDictParams *params, const byte *data, const size_t size, Jbig2ArithCx *GB_stats) { Jbig2PatternDict *hd = NULL; uint32_t GRAY; Jbig2Image *image; Jbig2GenericRegionParams rparams; int code; /* allocate the collective image */ image = jbig2_image_new(ctx, params->HDPW * (params->GRAYMAX + 1), params->HDPH); if (image == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate collective bitmap for halftone dict!\n"); return NULL; } /* fill out the generic region decoder parameters */ rparams.MMR = params->HDMMR; rparams.GBTEMPLATE = params->HDTEMPLATE; rparams.TPGDON = 0; /* not used if HDMMR = 1 */ rparams.USESKIP = 0; rparams.gbat[0] = -params->HDPW; rparams.gbat[1] = 0; rparams.gbat[2] = -3; rparams.gbat[3] = -1; rparams.gbat[4] = 2; rparams.gbat[5] = -2; rparams.gbat[6] = -2; rparams.gbat[7] = -2; if (params->HDMMR) { code = jbig2_decode_generic_mmr(ctx, segment, &rparams, data, size, image); } else { Jbig2WordStream *ws = jbig2_word_stream_buf_new(ctx, data, size); Jbig2ArithState *as = jbig2_arith_new(ctx, ws); code = jbig2_decode_generic_region(ctx, segment, &rparams, as, image, GB_stats); jbig2_free(ctx->allocator, as); jbig2_word_stream_buf_free(ctx, ws); } if (code != 0) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "error decoding collective pattern dictionary bitmap!"); } hd = jbig2_hd_new(ctx, params, image); jbig2_image_release(ctx, image); return hd; } /* 7.4.4 */ int jbig2_pattern_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) { Jbig2PatternDictParams params; Jbig2ArithCx *GB_stats = NULL; byte flags; int offset = 0; /* 7.4.4.1 - Data header */ if (segment->data_length < 7) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); } flags = segment_data[0]; params.HDMMR = flags & 1; params.HDTEMPLATE = (flags & 6) >> 1; params.HDPW = segment_data[1]; params.HDPH = segment_data[2]; params.GRAYMAX = jbig2_get_int32(segment_data + 3); offset += 7; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "pattern dictionary, flags=%02x, %d grays (%dx%d cell)", flags, params.GRAYMAX + 1, params.HDPW, params.HDPH); if (params.HDMMR && params.HDTEMPLATE) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "HDTEMPLATE is %d when HDMMR is %d, contrary to spec", params.HDTEMPLATE, params.HDMMR); } if (flags & 0xf8) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "Reserved flag bits non-zero"); } /* 7.4.4.2 */ if (!params.HDMMR) { /* allocate and zero arithmetic coding stats */ int stats_size = jbig2_generic_stats_size(ctx, params.HDTEMPLATE); GB_stats = jbig2_alloc(ctx->allocator, stats_size); memset(GB_stats, 0, stats_size); } segment->result = jbig2_decode_pattern_dict(ctx, segment, ¶ms, segment_data + offset, segment->data_length - offset, GB_stats); /* todo: retain GB_stats? */ if (!params.HDMMR) { jbig2_free(ctx->allocator, GB_stats); } return (segment->result != NULL) ? 0 : 1; } /** * jbig2_decode_halftone_region: decode a halftone region **/ int jbig2_decode_halftone_region(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2HalftoneRegionParams *params, const byte *data, const size_t size, Jbig2Image *image, Jbig2ArithCx *GB_stats) { int code = 0; /* todo: implement */ return code; } /** * jbig2_halftone_region: read a halftone region segment header **/ int jbig2_halftone_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) { int offset = 0; Jbig2RegionSegmentInfo region_info; Jbig2HalftoneRegionParams params; Jbig2Image *image; Jbig2ArithCx *GB_stats; int code; /* 7.4.5.1 */ if (segment->data_length < 17) goto too_short; jbig2_get_region_segment_info(®ion_info, segment_data); offset += 17; if (segment->data_length < 18) goto too_short; /* 7.4.5.1.1 */ params.flags = segment_data[offset]; params.HMMR = params.flags & 1; params.HTEMPLATE = (params.flags & 6) >> 1; params.HENABLESKIP = (params.flags & 8) >> 3; params.op = (params.flags & 0x70) >> 4; params.HDEFPIXEL = (params.flags &0x80) >> 7; offset += 1; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "halftone region: %d x %d @ (%x,%d) flags=%02x", region_info.width, region_info.height, region_info.x, region_info.y, params.flags); if (params.HMMR && params.HTEMPLATE) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "HTEMPLATE is %d when HMMR is %d, contrary to spec", params.HTEMPLATE, params.HMMR); } if (params.HMMR && params.HENABLESKIP) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "HENABLESKIP is %d when HMMR is %d, contrary to spec", params.HENABLESKIP, params.HMMR); } /* Figure 43 */ if (segment->data_length - offset < 16) goto too_short; params.HGW = jbig2_get_int32(segment_data + offset); params.HGH = jbig2_get_int32(segment_data + offset + 4); params.HGX = jbig2_get_int32(segment_data + offset + 8); params.HGY = jbig2_get_int32(segment_data + offset + 12); offset += 16; /* Figure 44 */ if (segment->data_length - offset < 4) goto too_short; params.HRX = jbig2_get_int16(segment_data + offset); params.HRY = jbig2_get_int16(segment_data + offset + 2); offset += 4; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " grid %d x %d @ (%d.%d,%d.%d) vector (%d.%d,%d.%d)", params.HGW, params.HGH, params.HGX >> 8, params.HGX & 0xff, params.HGY >> 8, params.HGY & 0xff, params.HRX >> 8, params.HRX & 0xff, params.HRY >> 8, params.HRY & 0xff); /* 7.4.5.2.2 */ if (!params.HMMR) { /* allocate and zero arithmetic coding stats */ int stats_size = jbig2_generic_stats_size(ctx, params.HTEMPLATE); GB_stats = jbig2_alloc(ctx->allocator, stats_size); memset(GB_stats, 0, stats_size); } image = jbig2_image_new(ctx, region_info.width, region_info.height); code = jbig2_decode_halftone_region(ctx, segment, ¶ms, segment_data + offset, segment->data_length - offset, image, GB_stats); /* todo: retain GB_stats? */ if (!params.HMMR) { jbig2_free(ctx->allocator, GB_stats); } return code; too_short: return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); }