shithub: jbig2

Download patch

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, &params,
+			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(&region_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, &params,
+		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'");