| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /* Copyright (C) 2001-2023 Artifex Software, Inc.
- All Rights Reserved.
- This software is provided AS-IS with no warranty, either express or
- implied.
- 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.
- Refer to licensing information at http://www.artifex.com or contact
- Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
- CA 94129, USA, for further information.
- */
- /*
- jbig2dec
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "os_types.h"
- #include <stdlib.h>
- #ifdef OUTPUT_PBM
- #include <stdio.h>
- #endif
- #include "jbig2.h"
- #include "jbig2_priv.h"
- #include "jbig2_image.h"
- #include "jbig2_page.h"
- #include "jbig2_segment.h"
- /* dump the page struct info */
- static void
- dump_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2Page *page)
- {
- if (page->x_resolution == 0) {
- jbig2_error(ctx, JBIG2_SEVERITY_INFO, 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, 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, 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, segment->number, "\tmaximum stripe size: %d", page->stripe_size);
- }
- }
- /**
- * 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, *pages;
- /* 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 */
- {
- size_t index, j;
- index = ctx->current_page;
- while (ctx->pages[index].state != JBIG2_PAGE_FREE) {
- index++;
- if (index >= ctx->max_page_index) {
- /* grow the list */
- if (ctx->max_page_index == UINT32_MAX) {
- return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "too many pages in jbig2 image");
- }
- else if (ctx->max_page_index > (UINT32_MAX >> 2)) {
- ctx->max_page_index = UINT32_MAX;
- }
- pages = jbig2_renew(ctx, ctx->pages, Jbig2Page, (ctx->max_page_index <<= 2));
- if (pages == NULL) {
- return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to reallocate pages");
- }
- ctx->pages = pages;
- 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];
- /* Check for T.88 amendment 3 */
- if (page->flags & 0x80)
- return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "page segment indicates use of color segments (NYI)");
- /* 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 marked as striped, assuming striped with maximum strip size");
- page->striped = TRUE;
- page->stripe_size = 0x7FFF;
- }
- 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 appropriate 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_WARNING, 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;
- }
- /**
- * jbig2_end_of_stripe: parse and implement an end of stripe segment
- **/
- int
- jbig2_end_of_stripe(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
- {
- Jbig2Page *page = &ctx->pages[ctx->current_page];
- uint32_t end_row;
- if (segment->data_length < 4)
- return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
- end_row = jbig2_get_uint32(segment_data);
- if (end_row < page->end_row) {
- jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
- "end of stripe segment with non-positive end row advance (new end row %d vs current end row %d)", end_row, page->end_row);
- } else {
- jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of stripe: advancing end row from %u to %u", page->end_row, end_row);
- }
- page->end_row = end_row;
- return 0;
- }
- /**
- * jbig2_complete_page: complete a page image
- *
- * called upon seeing an 'end of page' segment, this routine
- * marks a page as completed so it can be returned.
- * compositing will have already happened in the previous
- * segment handlers.
- **/
- int
- jbig2_complete_page(Jbig2Ctx *ctx)
- {
- int code;
- /* check for unfinished segments */
- if (ctx->segment_index != ctx->n_segments) {
- Jbig2Segment *segment = ctx->segments[ctx->segment_index];
- /* Some versions of Xerox Workcentre generate PDF files
- with the segment data length field of the last segment
- set to -1. Try to cope with this here. */
- if ((segment->data_length & 0xffffffff) == 0xffffffff) {
- jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "file has an invalid segment data length; trying to decode using the available data");
- segment->data_length = ctx->buf_wr_ix - ctx->buf_rd_ix;
- code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix);
- ctx->buf_rd_ix += segment->data_length;
- ctx->segment_index++;
- if (code < 0) {
- return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to parse segment");
- }
- }
- }
- /* ensure image exists before marking page as complete */
- if (ctx->pages[ctx->current_page].image == NULL) {
- return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page has no image, cannot be completed");
- }
- ctx->pages[ctx->current_page].state = JBIG2_PAGE_COMPLETE;
- return 0;
- }
- /**
- * jbig2_end_of_page: parse and implement an end of page segment
- **/
- int
- jbig2_end_of_page(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
- {
- uint32_t page_number = ctx->pages[ctx->current_page].number;
- int code;
- if (segment->page_association != page_number) {
- jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
- "end of page marker for page %d doesn't match current page number %d", segment->page_association, page_number);
- }
- jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of page %d", page_number);
- code = jbig2_complete_page(ctx);
- if (code < 0)
- return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to complete page");
- #ifdef OUTPUT_PBM
- code = jbig2_image_write_pbm(ctx->pages[ctx->current_page].image, stdout);
- if (code < 0)
- return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to write page image");
- #endif
- return 0;
- }
- /**
- * jbig2_add_page_result: composite a decoding result onto a page
- *
- * this is called to add the results of segment decode (when it
- * is an image) to a page image buffer
- **/
- int
- jbig2_page_add_result(Jbig2Ctx *ctx, Jbig2Page *page, Jbig2Image *image, uint32_t x, uint32_t y, Jbig2ComposeOp op)
- {
- int code;
- if (x > INT32_MAX || y > INT32_MAX)
- return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "unsupported image coordinates");
- /* ensure image exists first */
- if (page->image == NULL)
- return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page info possibly missing, no image defined");
- /* grow the page to accommodate a new stripe if necessary */
- if (page->striped && page->height == 0xFFFFFFFF) {
- uint32_t new_height;
- if (y > UINT32_MAX - image->height)
- return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "adding image at coordinate would grow page out of bounds");
- new_height = y + image->height;
- if (page->image->height < new_height) {
- Jbig2Image *resized_image = NULL;
- jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "growing page buffer to %u rows to accommodate new stripe", new_height);
- resized_image = jbig2_image_resize(ctx, page->image, page->image->width, new_height, page->flags & 4);
- if (resized_image == NULL) {
- return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "unable to resize image to accommodate new stripe");
- }
- page->image = resized_image;
- }
- }
- code = jbig2_image_compose(ctx, page->image, image, x, y, op);
- if (code < 0)
- return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to compose image with page");
- return 0;
- }
- /**
- * jbig2_get_page: return the next available page image buffer
- *
- * the client can call this at any time to check if any pages
- * have been decoded. If so, it returns the first available
- * one. The client should then call jbig2_release_page() when
- * it no longer needs to refer to the image buffer.
- *
- * since this is a public routine for the library clients, we
- * return an image structure pointer, even though the function
- * name refers to a page; the page structure is private.
- **/
- Jbig2Image *
- jbig2_page_out(Jbig2Ctx *ctx)
- {
- uint32_t index;
- /* search for a completed page */
- for (index = 0; index < ctx->max_page_index; index++) {
- if (ctx->pages[index].state == JBIG2_PAGE_COMPLETE) {
- Jbig2Image *img = ctx->pages[index].image;
- uint32_t page_number = ctx->pages[index].number;
- if (img == NULL) {
- jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page %d returned with no associated image", page_number);
- continue;
- }
- ctx->pages[index].state = JBIG2_PAGE_RETURNED;
- jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page %d returned to the client", page_number);
- return jbig2_image_reference(ctx, img);
- }
- }
- /* no pages available */
- return NULL;
- }
- /**
- * jbig2_release_page: tell the library a page can be freed
- **/
- void
- jbig2_release_page(Jbig2Ctx *ctx, Jbig2Image *image)
- {
- uint32_t index;
- if (image == NULL)
- return;
- /* find the matching page struct and mark it released */
- for (index = 0; index < ctx->max_page_index; index++) {
- if (ctx->pages[index].image == image) {
- jbig2_image_release(ctx, image);
- ctx->pages[index].state = JBIG2_PAGE_RELEASED;
- jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page %d released by the client", ctx->pages[index].number);
- return;
- }
- }
- /* no matching pages */
- jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to release unknown page");
- }
|