ref: 720e508d03bae14bf0e412abb37ad08ecde72e46
parent: 3fb9f08036565d4bd4147283e2e685217b6e4b55
author: giles <giles@ded80894-8fb9-0310-811b-c03f3676ab4d>
date: Thu Aug 4 03:05:05 EDT 2005
Work-in-progress commit of halftone dictionary implementation. This is enabled in the scons build, but not the standard one. git-svn-id: http://svn.ghostscript.com/jbig2dec/trunk@423 ded80894-8fb9-0310-811b-c03f3676ab4d
--- a/SConstruct
+++ b/SConstruct
@@ -2,7 +2,9 @@
env = Environment(CPPDEFINES = {'HAVE_STDINT_H' : None,
'PACKAGE' : '\\"jbig2dec\\"',
- 'VERSION' : '\\"0.8\\"'})
+ 'VERSION' : '\\"0.8\\"',
+ 'JBIG2_HALFTONE' : None})
+env.Append(CCFLAGS = ' -g')
lib_sources = Split("""jbig2.c
jbig2_arith.c jbig2_arith_int.c jbig2_arith_iaid.c
@@ -9,6 +11,7 @@
jbig2_huffman.c jbig2_metadata.c
jbig2_segment.c jbig2_page.c
jbig2_symbol_dict.c jbig2_text.c
+ jbig2_halftone.c
jbig2_generic.c jbig2_refinement.c jbig2_mmr.c
jbig2_image.c jbig2_image_pbm.c""")
@@ -30,9 +33,3 @@
env.Program('jbig2dec', jbig2dec_sources, LIBS=['jbig2dec'], LIBPATH='.')
-# self tests
-test = env.Copy(CPPDEFINES = ['TEST', 'HAVE_STDINT_H'])
-test_sha1 = test.Program(test.Object('test_sha1', 'sha1.c'))
-test_alias = test.Alias('test', [test_sha1, 'test_jbig2dec.py', 'jbig2dec'])
-test.Command(test_alias, [], ["./test_jbig2dec.py", "./test_sha1"])
-test.AlwaysBuild('test')
--- /dev/null
+++ b/jbig2_halftone.c
@@ -1,0 +1,364 @@
+/*
+ jbig2dec
+
+ Copyright (C) 2005 artofcode LLC.
+
+ 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 information on commercial licensing, go to
+ http://www.artifex.com/licensing/ or contact
+ Artifex Software, Inc., 101 Lucas Valley Road #110,
+ San Rafael, CA 94903, U.S.A., +1(415)492-9861.
+
+ $Id: jbig2_text.c 420 2005-07-27 23:55:54Z giles $
+*/
+
+/* 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"
+
+
+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;
+
+ /* 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");
+}
--- a/jbig2_segment.c
+++ b/jbig2_segment.c
@@ -239,7 +239,15 @@
case 6: /* immediate text region */
case 7: /* immediate lossless text region */
return jbig2_parse_text_region(ctx, segment, segment_data);
+#ifdef JBIG2_HALFTONE
case 16:
+ return jbig2_pattern_dictionary(ctx, segment, segment_data);
+ case 20: /* intermediate halftone region */
+ case 22: /* immediate halftone region */
+ case 23: /* immediate lossless halftone region */
+ return jbig2_halftone_region(ctx, segment, segment_data);
+#else
+ case 16:
return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
"unhandled segment type 'pattern dictionary'");
case 20:
@@ -251,6 +259,7 @@
case 23:
return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
"unhandled segment type 'immediate lossless halftone region'");
+#endif
case 36:
return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
"unhandled segment type 'intermediate generic region'");