shithub: jbig2

Download patch

ref: 0cad58a5a6857aebb665c79706ba33acabc550fd
parent: 033b9666bac46060559b74b2f2a620fde5fc7f32
author: giles <giles@ded80894-8fb9-0310-811b-c03f3676ab4d>
date: Tue Jun 18 09:40:29 EDT 2002

Handle 'page info' segments, and allocate an image buffer based on the page size.
also adds hooks for final compositing and output of the page buffer.
in addition, minor code massage and dead code removal; make the image structure
public.


git-svn-id: http://svn.ghostscript.com/jbig2dec/trunk@72 ded80894-8fb9-0310-811b-c03f3676ab4d

--- a/jbig2.c
+++ b/jbig2.c
@@ -8,7 +8,7 @@
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
         
-    $Id: jbig2.c,v 1.7 2002/06/17 21:06:38 giles Exp $
+    $Id: jbig2.c,v 1.8 2002/06/18 13:40:29 giles Exp $
 */
 
 #include <stdint.h>
@@ -118,6 +118,18 @@
   result->n_results_max = 16;
   result->results = (const Jbig2Result **)jbig2_alloc(allocator, result->n_results_max * sizeof(Jbig2Result *));
 
+  result->current_page = 0;
+  result->max_page_index = 16;
+  result->pages = (Jbig2Page *)jbig2_alloc(allocator, result->max_page_index * sizeof(Jbig2Page));
+  {
+    int index;
+    for (index = 0; index < result->max_page_index; index++) {
+        result->pages[index].state = JBIG2_PAGE_FREE;
+        result->pages[index].number = 0;
+        result->pages[index].image = NULL;
+    }
+  }
+
   return result;
 }
 
@@ -217,7 +229,10 @@
 	      if (ctx->buf_wr_ix - ctx->buf_rd_ix < 13)
 		return 0;
 	      ctx->n_pages = jbig2_get_int32(ctx->buf + ctx->buf_rd_ix + 9);
-              jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates %d pages", ctx->n_pages);
+              if (ctx->n_pages == 1)
+                jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates a single page document");
+              else
+                jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates a %d page document", ctx->n_pages);
 	      ctx->buf_rd_ix += 13;
 	    }
 	  else
--- a/jbig2.h
+++ b/jbig2.h
@@ -8,7 +8,7 @@
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
         
-    $Id: jbig2.h,v 1.6 2002/06/17 21:11:51 giles Exp $
+    $Id: jbig2.h,v 1.7 2002/06/18 13:40:29 giles Exp $
 */
 
 #ifdef __cplusplus
@@ -17,6 +17,7 @@
 
 #include <stdint.h>	// for C99 types -- need a more portable sol'n
 
+/* warning levels */
 typedef enum {
   JBIG2_SEVERITY_DEBUG,
   JBIG2_SEVERITY_INFO,
@@ -28,34 +29,39 @@
   JBIG2_OPTIONS_EMBEDDED = 1
 } Jbig2Options;
 
+/* forward public structure declarations */
 typedef struct _Jbig2Allocator Jbig2Allocator;
 typedef struct _Jbig2Ctx Jbig2Ctx;
 typedef struct _Jbig2GlobalCtx Jbig2GlobalCtx;
 typedef struct _Jbig2SegmentHeader Jbig2SegmentHeader;
-typedef struct _Jbig2PageInfo Jbig2PageInfo;
+typedef struct _Jbig2Image Jbig2Image;
+
+/* private structures */
+typedef struct _Jbig2Page Jbig2Page;
 typedef struct _Jbig2SymbolDictionary Jbig2SymbolDictionary;
 
-struct _Jbig2SegmentHeader {
-  int32_t segment_number;
-  uint8_t flags;
-  int referred_to_segment_count;
-  int32_t page_association;
-  int data_length;
-};
+/*
+   this is the general image structure used by the jbig2dec library
+   images are 1 bpp, packed into word-aligned rows. stride gives
+   the word offset to the next row, while width and height define
+   the size of the image area in pixels.
+*/
 
-struct _Jbig2PageInfo {
-	uint32_t	height, width;	/* in pixels */
-	uint32_t	x_resolution,
-                        y_resolution;	/* in pixels per meter */
-	uint16_t	stripe_size;
-	int		striped;
-	uint8_t		flags;
+struct _Jbig2Image {
+        int             width, height, stride;
+        uint32_t        *data;
 };
 
+Jbig2Image*     jbig2_image_new(Jbig2Ctx *ctx, int width, int height);
+void            jbig2_image_free(Jbig2Ctx *ctx, Jbig2Image *image);
+
+
+/* error callback */
 typedef int (*Jbig2ErrorCallback) (void *data,
 				  const char *msg, Jbig2Severity severity,
 				  int32_t seg_idx);
 
+/* dynamic memory callbacks */
 struct _Jbig2Allocator {
   void *(*alloc) (Jbig2Allocator *allocator, size_t size);
   void (*free) (Jbig2Allocator *allocator, void *p);
@@ -62,21 +68,33 @@
   void *(*realloc) (Jbig2Allocator *allocator, void *p, size_t size);
 };
 
+/* decoder context */
 Jbig2Ctx *jbig2_ctx_new (Jbig2Allocator *allocator,
 			 Jbig2Options options,
 			 Jbig2GlobalCtx *global_ctx,
 			 Jbig2ErrorCallback error_callback,
 			 void *error_callback_data);
+void jbig2_ctx_free (Jbig2Ctx *ctx);
 
+/* global context for embedded streams */
+Jbig2GlobalCtx *jbig2_make_global_ctx (Jbig2Ctx *ctx);
+void jbig2_global_ctx_free (Jbig2GlobalCtx *global_ctx);
+
+/* submit data to the decoder */
 int jbig2_write (Jbig2Ctx *ctx, const unsigned char *data, size_t size);
 
-/* get_bits */
+/* get the next available decoded page image */
+Jbig2Image *jbig2_get_page(Jbig2Ctx *ctx);
 
-void jbig2_ctx_free (Jbig2Ctx *ctx);
+/* segment header routines */
 
-Jbig2GlobalCtx *jbig2_make_global_ctx (Jbig2Ctx *ctx);
-
-void jbig2_global_ctx_free (Jbig2GlobalCtx *global_ctx);
+struct _Jbig2SegmentHeader {
+  int32_t segment_number;
+  uint8_t flags;
+  int referred_to_segment_count;
+  int32_t page_association;
+  int data_length;
+};
 
 Jbig2SegmentHeader *jbig2_parse_segment_header (Jbig2Ctx *ctx, uint8_t *buf, size_t buf_size,
 			    size_t *p_header_size);
--- a/jbig2_image.h
+++ b/jbig2_image.h
@@ -8,27 +8,12 @@
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
 
-    $Id: jbig2_image.h,v 1.4 2002/06/17 16:30:20 giles Exp $
+    $Id: jbig2_image.h,v 1.5 2002/06/18 13:40:29 giles Exp $
 */
 
 
 #ifndef _JBIG2_IMAGE_H
 #define _JBIG2_IMAGE_H
-
-/*
-   this is the general image structure used by the jbig2dec library
-   images are 1 bpp, packed into word-aligned rows. stride gives
-   the word offset to the next row, while width and height define
-   the size of the image area in pixels.
-*/
-
-typedef struct _Jbig2Image {
-	int		width, height, stride;
-	uint32_t	*data;
-} Jbig2Image;
-
-Jbig2Image*	jbig2_image_new(Jbig2Ctx *ctx, int width, int height);
-void		jbig2_image_free(Jbig2Ctx *ctx, Jbig2Image *image);
 
 /* routines for dumping the image data in various formats */
 /* FIXME: should these be in the client instead? */
--- a/jbig2_page.c
+++ b/jbig2_page.c
@@ -1,7 +1,7 @@
 /*
     jbig2dec
     
-    Copyright (c) 2001 artofcode LLC.
+    Copyright (c) 2001-2002 artofcode LLC.
     
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -8,7 +8,7 @@
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
 
-    $Id: jbig2_page.c,v 1.2 2002/06/15 16:02:55 giles Exp $
+    $Id: jbig2_page.c,v 1.3 2002/06/18 13:40:29 giles Exp $
 */
 
 #include <stdio.h>
@@ -17,65 +17,160 @@
 #include "jbig2.h"
 #include "jbig2_priv.h"
 
-/* parse the page info segment data starting at ctx->offset
-   a pointer to a new Jbig2PageInfo struct is returned
+/* dump the page struct info */
+static void
+dump_page_info(Jbig2Ctx *ctx, Jbig2SegmentHeader *sh, Jbig2Page *page)
+{
+    if (page->x_resolution == 0) {
+        jbig2_error(ctx, JBIG2_SEVERITY_INFO, sh->segment_number,
+            "page %d image is %dx%d (unknown res)", page->number,
+            page->width, page->height);
+    } else if (page->x_resolution == page->y_resolution) {
+        jbig2_error(ctx, JBIG2_SEVERITY_INFO, sh->segment_number,
+            "page %d image is %dx%d (%d ppm)", page->number,
+            page->width, page->height,
+            page->x_resolution);
+    } else {
+        jbig2_error(ctx, JBIG2_SEVERITY_INFO, sh->segment_number,
+            "page %d image is %dx%d (%dx%d ppm)", page->number,
+            page->width, page->height,
+            page->x_resolution, page->y_resolution);
+    }
+    if (page->striped) {
+        jbig2_error(ctx, JBIG2_SEVERITY_INFO, sh->segment_number,
+            "\tmaximum stripe size: %d", page->stripe_size);
+    }
+}
 
-   the ctx->offset pointer is not advanced; the caller must
-   take care of that, using the data_length field of the
-   segment header.
-*/
-static Jbig2PageInfo *
-jbig2_read_page_info (Jbig2Ctx *ctx) {
-  Jbig2PageInfo *info = (Jbig2PageInfo *)jbig2_alloc(ctx->allocator, sizeof(Jbig2PageInfo));
-  int offset = ctx->buf_rd_ix;
+/**
+ * jbig2_read_page_info: parse page info segment
+ *
+ * parse the page info segment data and fill out a corresponding
+ * Jbig2Page struct is returned, including allocating an image
+ * buffer for the page (or the first stripe)
+ **/
+int
+jbig2_read_page_info (Jbig2Ctx *ctx, Jbig2SegmentHeader *sh, const byte *segment_data)
+{
+    Jbig2Page *page;
 
-	if (info == NULL) {
-		printf("unable to allocate memory to parse page info segment\n");
-		return NULL;
-	}
-	
-	info->width = get_int32(ctx, offset);
-	info->height = get_int32(ctx, offset + 4);
-	offset += 8;
-	
-	info->x_resolution = get_int32(ctx, offset);
-	info->y_resolution = get_int32(ctx, offset + 4);
-	offset += 8;
-	
-	get_bytes(ctx, &(info->flags), 1, offset++);
-	
-	{
-	int16_t striping = get_int16(ctx, offset);
-	if (striping & 0x8000) {
-		info->striped = TRUE;
-		info->stripe_size = striping & 0x7FFF;
-	} else {
-		info->striped = FALSE;
-		info->stripe_size = 0;	/* would info->height be better? */
-	}
-	offset += 2;
-	}
-	
-	return info;
-}
+    /* a new page info segment implies the previous page is finished */
+    page = &(ctx->pages[ctx->current_page]);
+    if ((page->number != 0) && 
+            (page->state == JBIG2_PAGE_NEW) || (page->state == JBIG2_PAGE_FREE)) {
+        page->state = JBIG2_PAGE_COMPLETE;
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number,
+            "unexpected page info segment, marking previous page finished");
+    }
+        
+    /* find a free page */
+    {
+        int index, j;
+        index = ctx->current_page;
+        while (ctx->pages[index].state != JBIG2_PAGE_FREE) {
+            index++;
+            if (index >= ctx->max_page_index) { // FIXME: should also look for freed pages?
+                /* grow the list */
+                jbig2_realloc(ctx->allocator, ctx->pages, (ctx->max_page_index <<= 2) * sizeof(Jbig2Page));
+                for (j=index; j < ctx->max_page_index; j++) {
+                    /* note to raph: and look, it gets worse! */
+                    ctx->pages[j].state = JBIG2_PAGE_FREE;
+                    ctx->pages[j].number = 0;
+                    ctx->pages[j].image = NULL;
+
+                }
+            }
+        }
+        page = &(ctx->pages[index]);
+        ctx->current_page = index;
+        page->state = JBIG2_PAGE_NEW;
+        page->number = sh->page_association;
+    }
+    
+    // FIXME: would be nice if we tried to work around this
+    if (sh->data_length < 19) {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, sh->segment_number,
+            "segment too short");
+        return NULL;
+    }
+    
+    /* 7.4.8.x */
+    page->width = jbig2_get_int32(segment_data);
+    page->height = jbig2_get_int32(segment_data + 4);
+    
+    page->x_resolution = jbig2_get_int32(segment_data + 8);
+    page->y_resolution = jbig2_get_int32(segment_data + 12);
+    page->flags = segment_data[16];
 
-/* dump the page info struct */
-static void
-dump_page_info(Jbig2PageInfo *info)
-{
-    FILE *out = stderr;
+    /* 7.4.8.6 */
+    {
+        int16_t striping = jbig2_get_int16(segment_data +17);
+        if (striping & 0x8000) {
+            page->striped = TRUE;
+            page->stripe_size = striping & 0x7FFF;
+        } else {
+            page->striped = FALSE;
+            page->stripe_size = 0;	/* would page->height be better? */
+        }
+    }
+    if (page->height == 0xFFFFFFFF && page->striped == FALSE) {
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number,
+            "height is unspecified but page is not markes as striped");
+        page->striped = TRUE;
+    }
     
-    fprintf(out, "image is %dx%d ", info->width, info->height);
-    if (info->x_resolution == 0) {
-        fprintf(out, "(unknown res) ");
-    } else if (info->x_resolution == info->y_resolution) {
-        fprintf(out, "(%d ppm) ", info->x_resolution);
+    if (sh->data_length > 19) {
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number,
+            "extra data in segment");
+    }
+    
+    dump_page_info(ctx, sh, page);
+
+    /* allocate an approprate page image buffer */
+    /* 7.4.8.2 */
+    if (page->height == 0xFFFFFFFF) {
+        page->image = jbig2_image_new(ctx, page->width, page->stripe_size);
     } else {
-        fprintf(out, "(%dx%d ppm) ", info->x_resolution, info->y_resolution);
+        page->image = jbig2_image_new(ctx, page->width, page->height);
     }
-    if (info->striped) {
-        fprintf(out, "\tmaximum stripe size: %d\n", info->stripe_size);
+    if (page->image == NULL) {
+        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, sh->segment_number,
+            "failed to allocate buffer for page image");
+        jbig2_free(ctx->allocator, page);
+        return NULL;
     } else {
-        fprintf(out, "\tno striping\n");
+        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, sh->segment_number,
+            "allocated %dx%d page image (%d bytes)",
+            page->image->width, page->image->height,
+            page->image->stride*page->image->height);
     }
+    
+    return 0;
 }
+
+/**
+ * jbig2_complete_page: complete a page image
+ *
+ * called upon seeing an 'end of page' segment, this routine
+ * marks a page as completed. final compositing and output
+ * of the page image will also happen from here (NYI)
+ **/
+int
+jbig2_complete_page (Jbig2Ctx *ctx, Jbig2SegmentHeader *sh, const byte *segment_data)
+{
+    uint32_t page_number = ctx->pages[ctx->current_page].number;
+    
+    if (sh->page_association != page_number) {
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number,
+            "end of page marker for page %d doesn't match current page number %d",
+            sh->page_association, page_number);
+    }
+    
+    ctx->pages[ctx->current_page].state = JBIG2_PAGE_COMPLETE;
+    jbig2_error(ctx, JBIG2_SEVERITY_INFO, sh->segment_number,
+        "end of page %d", page_number);
+
+    // FIXME: write out the page image
+    
+    return 0;
+}
\ No newline at end of file
--- a/jbig2_priv.h
+++ b/jbig2_priv.h
@@ -66,6 +66,12 @@
   int n_results;
   int n_results_max;
   const Jbig2Result **results;
+  
+  /* list of decoded pages, including the one in progress,
+     currently stored as a contiguous, 0-indexed array. */
+  int current_page;
+  int max_page_index;
+  Jbig2Page *pages;
 };
 
 int32_t
@@ -73,6 +79,35 @@
 
 int16_t
 jbig2_get_int16 (const byte *buf);
+
+/* the page structure handles decoded page
+   results. it's allocated by a 'page info'
+   segement and marked complete by an 'end of page'
+   segment.
+*/
+
+typedef enum {
+    JBIG2_PAGE_FREE,
+    JBIG2_PAGE_NEW,
+    JBIG2_PAGE_COMPLETE,
+    JBIG2_PAGE_RETURNED
+} Jbig2PageState;
+
+struct _Jbig2Page {
+    Jbig2PageState state;
+    uint32_t number;
+    uint32_t height, width;	/* in pixels */
+    uint32_t x_resolution,
+             y_resolution;	/* in pixels per meter */
+    uint16_t stripe_size;
+    bool striped;
+    uint8_t flags;
+    Jbig2Image *image;
+};
+
+int jbig2_read_page_info (Jbig2Ctx *ctx, Jbig2SegmentHeader *sh, const byte *segment_data);
+int jbig2_complete_page (Jbig2Ctx *ctx, Jbig2SegmentHeader *sh, const byte *segment_data);
+
 
 /* The word stream design is a compromise between simplicity and
    trying to amortize the number of method calls. Each ::get_next_word
--- a/jbig2_segment.c
+++ b/jbig2_segment.c
@@ -8,7 +8,7 @@
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
 
-    $Id: jbig2_segment.c,v 1.3 2002/06/18 09:46:45 giles Exp $
+    $Id: jbig2_segment.c,v 1.4 2002/06/18 13:40:29 giles Exp $
 */
 
 #include <stdio.h>
@@ -146,17 +146,16 @@
       return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number,
         "unhandled segment type 'immediate lossless generic refinement region'");
     case 48:
-      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number,
-        "unhandled segment type 'page info'");
+      return jbig2_read_page_info(ctx, sh, segment_data);
     case 49:
-      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number,
-        "unhandled segment type 'end of page'");
+      return jbig2_complete_page(ctx, sh, segment_data);
     case 50:
       return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number,
         "unhandled segment type 'end of stripe'");
     case 51:
-      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number,
-        "unhandled segment type 'end of file'");
+      ctx->state = JBIG2_FILE_EOF;
+      return jbig2_error(ctx, JBIG2_SEVERITY_INFO, sh->segment_number,
+        "end of file");
     case 52:
       return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number,
         "unhandled segment type 'profile'");
--- a/jbig2dec.c
+++ b/jbig2dec.c
@@ -8,7 +8,7 @@
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
 
-    $Id: jbig2dec.c,v 1.20 2002/06/15 16:02:55 giles Exp $
+    $Id: jbig2dec.c,v 1.21 2002/06/18 13:40:29 giles Exp $
 */
 
 #include <stdio.h>
@@ -236,8 +236,8 @@
     switch (severity) {
         case JBIG2_SEVERITY_DEBUG: string = "DEBUG"; break;;
         case JBIG2_SEVERITY_INFO: string = "info"; break;;
-        case JBIG2_SEVERITY_WARNING: string = "warning"; break;;
-        case JBIG2_SEVERITY_FATAL: string = "fatal error"; break;;
+        case JBIG2_SEVERITY_WARNING: string = "WARNING"; break;;
+        case JBIG2_SEVERITY_FATAL: string = "FATAL ERROR"; break;;
         default: string = "unknown message"; break;;
     }