Пример #1
0
/**
 * jbig2_page_info: parse page info segment
 *
 * Parse the page info segment data and fill out a corresponding
 * Jbig2Page struct and ready it for subsequent rendered data,
 * including allocating an image buffer for the page (or the first stripe)
 **/
int
jbig2_page_info (Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
{
    Jbig2Page *page;

    /* 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, 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) {
                /* grow the list */
		ctx->pages = jbig2_renew(ctx, ctx->pages, Jbig2Page,
                    (ctx->max_page_index <<= 2));
                for (j=index; j < ctx->max_page_index; j++) {
                    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 = segment->page_association;
    }

    /* FIXME: would be nice if we tried to work around this */
    if (segment->data_length < 19) {
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
            "segment too short");
    }

    /* 7.4.8.x */
    page->width = jbig2_get_uint32(segment_data);
    page->height = jbig2_get_uint32(segment_data + 4);

    page->x_resolution = jbig2_get_uint32(segment_data + 8);
    page->y_resolution = jbig2_get_uint32(segment_data + 12);
    page->flags = segment_data[16];

    /* 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, segment->number,
            "height is unspecified but page is not markes as striped");
        page->striped = TRUE;
    }
    page->end_row = 0;

    if (segment->data_length > 19) {
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
            "extra data in segment");
    }

    dump_page_info(ctx, segment, 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 {
        page->image = jbig2_image_new(ctx, page->width, page->height);
    }
    if (page->image == NULL) {
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
            "failed to allocate buffer for page image");
    } else {
	/* 8.2 (3) fill the page with the default pixel value */
	jbig2_image_clear(ctx, page->image, (page->flags & 4));
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
            "allocated %dx%d page image (%d bytes)",
            page->image->width, page->image->height,
            page->image->stride*page->image->height);
    }

    return 0;
}
Пример #2
0
/**
 * jbig2_parse_text_region: read a text region segment header
 **/
int
jbig2_parse_text_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
{
    int offset = 0;
    Jbig2RegionSegmentInfo region_info;
    Jbig2TextRegionParams params;
    Jbig2Image *image;
    Jbig2SymbolDict **dicts;
    int n_dicts;
    uint16_t flags;
    uint16_t huffman_flags = 0;
    Jbig2ArithCx *GR_stats = NULL;
    int code = 0;
    Jbig2WordStream *ws = NULL; 
    Jbig2ArithState *as = NULL; 
    
    /* 7.4.1 */
    if (segment->data_length < 17)
        goto too_short;
    jbig2_get_region_segment_info(&region_info, segment_data);
    offset += 17;
    
    /* 7.4.3.1.1 */
    flags = jbig2_get_int16(segment_data + offset);
    offset += 2;

    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
	"text region header flags 0x%04x", flags);
    
    params.SBHUFF = flags & 0x0001;
    params.SBREFINE = flags & 0x0002;
    params.LOGSBSTRIPS = (flags & 0x000c) >> 2;
    params.SBSTRIPS = 1 << params.LOGSBSTRIPS;
    params.REFCORNER = (flags & 0x0030) >> 4;
    params.TRANSPOSED = flags & 0x0040;
    params.SBCOMBOP = (flags & 0x0180) >> 7;
    params.SBDEFPIXEL = flags & 0x0200;
    /* SBDSOFFSET is a signed 5 bit integer */
    params.SBDSOFFSET = (flags & 0x7C00) >> 10;
    if (params.SBDSOFFSET > 0x0f) params.SBDSOFFSET -= 0x20;
    params.SBRTEMPLATE = flags & 0x8000;

    if (params.SBDSOFFSET) {
      jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
	"text region has SBDSOFFSET %d", params.SBDSOFFSET);
    }

    if (params.SBHUFF)	/* Huffman coding */
      {
        /* 7.4.3.1.2 */
        huffman_flags = jbig2_get_int16(segment_data + offset);
        offset += 2;
        
        if (huffman_flags & 0x8000)
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
                "reserved bit 15 of text region huffman flags is not zero");
      }
    else	/* arithmetic coding */
      {
        /* 7.4.3.1.3 */
        if ((params.SBREFINE) && !(params.SBRTEMPLATE))
          {
            params.sbrat[0] = segment_data[offset];
            params.sbrat[1] = segment_data[offset + 1];
            params.sbrat[2] = segment_data[offset + 2];
            params.sbrat[3] = segment_data[offset + 3];
            offset += 4;
	  }
      }
    
    /* 7.4.3.1.4 */
    params.SBNUMINSTANCES = jbig2_get_int32(segment_data + offset);
    offset += 4;
    
    if (params.SBHUFF) {
        /* 7.4.3.1.5 - Symbol ID Huffman table */
	/* ...this is handled in the segment body decoder */	

        /* 7.4.3.1.6 - Other Huffman table selection */
	switch (huffman_flags & 0x0003) {
	  case 0: /* Table B.6 */
	    params.SBHUFFFS = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_F);
	    break;
	  case 1: /* Table B.7 */
	    params.SBHUFFFS = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_G);
	    break;
	  case 3: /* Custom table from referred segment */
	    /* We handle this case later by leaving the table as NULL */
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region uses custom FS huffman table (NYI)");
	    break;
	  case 2: /* invalid */
	  default:
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region specified invalid FS huffman table");
	    break;
	}
	switch ((huffman_flags & 0x000c) >> 2) {
	  case 0: /* Table B.8 */
	    params.SBHUFFDS = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_H);
	    break;
	  case 1: /* Table B.9 */
	    params.SBHUFFDS = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_I);
	    break;
	  case 2: /* Table B.10 */
	    params.SBHUFFDS = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_J);
	    break;
	  case 3: /* Custom table from referred segment */
	    /* We handle this case later by leaving the table as NULL */
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region uses custom DS huffman table (NYI)");
	    break;
	}
	switch ((huffman_flags & 0x0030) >> 4) {
	  case 0: /* Table B.11 */
	    params.SBHUFFDT = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_K);
	    break;
	  case 1: /* Table B.12 */
	    params.SBHUFFDT = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_L);
	    break;
	  case 2: /* Table B.13 */
	    params.SBHUFFDT = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_M);
	    break;
	  case 3: /* Custom table from referred segment */
	    /* We handle this case later by leaving the table as NULL */
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region uses custom DT huffman table (NYI)");
	    break;
	}
	switch ((huffman_flags & 0x00c0) >> 6) {
	  case 0: /* Table B.14 */
	    params.SBHUFFRDW = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_N);
	    break;
	  case 1: /* Table B.15 */
	    params.SBHUFFRDW = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_O);
	    break;
	  case 3: /* Custom table from referred segment */
	    /* We handle this case later by leaving the table as NULL */
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region uses custom RDW huffman table (NYI)");
	    break;
	  case 2: /* invalid */
	  default:
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region specified invalid RDW huffman table");
	    break;
	}
	switch ((huffman_flags & 0x0300) >> 8) {
	  case 0: /* Table B.14 */
	    params.SBHUFFRDH = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_N);
	    break;
	  case 1: /* Table B.15 */
	    params.SBHUFFRDH = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_O);
	    break;
	  case 3: /* Custom table from referred segment */
	    /* We handle this case later by leaving the table as NULL */
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region uses custom RDH huffman table (NYI)");
	    break;
	  case 2: /* invalid */
	  default:
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region specified invalid RDH huffman table");
	    break;
	}
        switch ((huffman_flags & 0x0c00) >> 10) {
	  case 0: /* Table B.14 */
	    params.SBHUFFRDX = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_N);
	    break;
	  case 1: /* Table B.15 */
	    params.SBHUFFRDX = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_O);
	    break;
	  case 3: /* Custom table from referred segment */
	    /* We handle this case later by leaving the table as NULL */
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region uses custom RDX huffman table (NYI)");
	    break;
	  case 2: /* invalid */
	  default:
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region specified invalid RDX huffman table");
	    break;
	}
	switch ((huffman_flags & 0x3000) >> 12) {
	  case 0: /* Table B.14 */
	    params.SBHUFFRDY = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_N);
	    break;
	  case 1: /* Table B.15 */
	    params.SBHUFFRDY = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_O);
	    break;
	  case 3: /* Custom table from referred segment */
	    /* We handle this case later by leaving the table as NULL */
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region uses custom RDY huffman table (NYI)");
	    break;
	  case 2: /* invalid */
	  default:
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region specified invalid RDY huffman table");
	    break;
	}
	switch ((huffman_flags & 0x4000) >> 14) {
	  case 0: /* Table B.1 */
	    params.SBHUFFRSIZE = jbig2_build_huffman_table(ctx,
			&jbig2_huffman_params_A);
	    break;
	  case 1: /* Custom table from referred segment */
	    /* We handle this case later by leaving the table as NULL */
	    return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"text region uses custom RSIZE huffman table (NYI)");
	    break;
	}
	
        if (huffman_flags & 0x8000) {
	  jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
 	    "text region huffman flags bit 15 is set, contrary to spec");
	}
        
        /* 7.4.3.1.7 */
        /* For convenience this is done in the body decoder routine */
    }

    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
        "text region: %d x %d @ (%d,%d) %d symbols",
        region_info.width, region_info.height,
        region_info.x, region_info.y, params.SBNUMINSTANCES);
    
    /* 7.4.3.2 (2) - compose the list of symbol dictionaries */
    n_dicts = jbig2_sd_count_referred(ctx, segment);
    if (n_dicts != 0) {
        dicts = jbig2_sd_list_referred(ctx, segment);
    } else {
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                "text region refers to no symbol dictionaries!");
    }
    if (dicts == NULL) {
	return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
		"unable to retrive symbol dictionaries!"
		" previous parsing error?");
    } else {
	int index;
	if (dicts[0] == NULL) {
	    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, 
			segment->number,
                        "unable to find first referenced symbol dictionary!");
	}
	for (index = 1; index < n_dicts; index++)
	    if (dicts[index] == NULL) {
		jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
			"unable to find all referenced symbol dictionaries!");
	    n_dicts = index;
	}
    }

    /* 7.4.3.2 (3) */
    if (!params.SBHUFF && params.SBREFINE) {
	int stats_size = params.SBRTEMPLATE ? 1 << 10 : 1 << 13;
	GR_stats = jbig2_alloc(ctx->allocator, stats_size);
	memset(GR_stats, 0, stats_size);
    }

    image = jbig2_image_new(ctx, region_info.width, region_info.height);

    ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset);
    if (!params.SBHUFF) {
	int SBSYMCODELEN, index;
        int SBNUMSYMS = 0;
	for (index = 0; index < n_dicts; index++) {
	    SBNUMSYMS += dicts[index]->n_symbols;
	}

	as = jbig2_arith_new(ctx, ws);
	ws = 0;

        params.IADT = jbig2_arith_int_ctx_new(ctx);
        params.IAFS = jbig2_arith_int_ctx_new(ctx);
        params.IADS = jbig2_arith_int_ctx_new(ctx);
        params.IAIT = jbig2_arith_int_ctx_new(ctx);
	/* Table 31 */
	for (SBSYMCODELEN = 0; (1 << SBSYMCODELEN) < SBNUMSYMS; SBSYMCODELEN++);
        params.IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
	params.IARI = jbig2_arith_int_ctx_new(ctx);
	params.IARDW = jbig2_arith_int_ctx_new(ctx);
	params.IARDH = jbig2_arith_int_ctx_new(ctx);
	params.IARDX = jbig2_arith_int_ctx_new(ctx);
	params.IARDY = jbig2_arith_int_ctx_new(ctx);
    }

    code = jbig2_decode_text_region(ctx, segment, &params,
                (const Jbig2SymbolDict * const *)dicts, n_dicts, image,
                segment_data + offset, segment->data_length - offset,
		GR_stats, as, ws);

    if (!params.SBHUFF && params.SBREFINE) {
	jbig2_free(ctx->allocator, GR_stats);
    }

    if (params.SBHUFF) {
      jbig2_release_huffman_table(ctx, params.SBHUFFFS);
      jbig2_release_huffman_table(ctx, params.SBHUFFDS);
      jbig2_release_huffman_table(ctx, params.SBHUFFDT);
      jbig2_release_huffman_table(ctx, params.SBHUFFRDX);
      jbig2_release_huffman_table(ctx, params.SBHUFFRDY);
      jbig2_release_huffman_table(ctx, params.SBHUFFRDW);
      jbig2_release_huffman_table(ctx, params.SBHUFFRDH);
      jbig2_release_huffman_table(ctx, params.SBHUFFRSIZE);
    }
    else {
	jbig2_arith_int_ctx_free(ctx, params.IADT);
	jbig2_arith_int_ctx_free(ctx, params.IAFS);
	jbig2_arith_int_ctx_free(ctx, params.IADS);
	jbig2_arith_int_ctx_free(ctx, params.IAIT);
	jbig2_arith_iaid_ctx_free(ctx, params.IAID);
	jbig2_arith_int_ctx_free(ctx, params.IARI);
	jbig2_arith_int_ctx_free(ctx, params.IARDW);
	jbig2_arith_int_ctx_free(ctx, params.IARDH);
	jbig2_arith_int_ctx_free(ctx, params.IARDX);
	jbig2_arith_int_ctx_free(ctx, params.IARDY);
	jbig2_free(ctx->allocator, as);
	jbig2_word_stream_buf_free(ctx, ws);
    }

    jbig2_free(ctx->allocator, dicts);

    /* todo: check errors */

    if ((segment->flags & 63) == 4) {
        /* we have an intermediate region here. save it for later */
        segment->result = image;
    } else {
        /* otherwise composite onto the page */
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, 
            "composing %dx%d decoded text region onto page at (%d, %d)",
            region_info.width, region_info.height, region_info.x, region_info.y);
	jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image,
			      region_info.x, region_info.y, region_info.op);
        jbig2_image_release(ctx, image);
    }
    
    /* success */            
    return 0;
    
    too_short:
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                    "Segment too short");
}