| 1 | /* Copyright (C) 2001-2019 Artifex Software, Inc. |
| 2 | All Rights Reserved. |
| 3 | |
| 4 | This software is provided AS-IS with no warranty, either express or |
| 5 | implied. |
| 6 | |
| 7 | This software is distributed under license and may not be copied, |
| 8 | modified or distributed except as expressly authorized under the terms |
| 9 | of the license contained in the file LICENSE in this distribution. |
| 10 | |
| 11 | Refer to licensing information at http://www.artifex.com or contact |
| 12 | Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, |
| 13 | CA 94945, U.S.A., +1(415)492-9861, for further information. |
| 14 | */ |
| 15 | |
| 16 | /* |
| 17 | jbig2dec |
| 18 | */ |
| 19 | |
| 20 | #ifdef HAVE_CONFIG_H |
| 21 | #include "config.h" |
| 22 | #endif |
| 23 | #include "os_types.h" |
| 24 | |
| 25 | #include <stdlib.h> |
| 26 | |
| 27 | #ifdef OUTPUT_PBM |
| 28 | #include <stdio.h> |
| 29 | #endif |
| 30 | |
| 31 | #include "jbig2.h" |
| 32 | #include "jbig2_priv.h" |
| 33 | #include "jbig2_image.h" |
| 34 | #include "jbig2_page.h" |
| 35 | #include "jbig2_segment.h" |
| 36 | |
| 37 | /* dump the page struct info */ |
| 38 | static void |
| 39 | dump_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2Page *page) |
| 40 | { |
| 41 | if (page->x_resolution == 0) { |
| 42 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "page %d image is %dx%d (unknown res)" , page->number, page->width, page->height); |
| 43 | } else if (page->x_resolution == page->y_resolution) { |
| 44 | 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); |
| 45 | } else { |
| 46 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
| 47 | "page %d image is %dx%d (%dx%d ppm)" , page->number, page->width, page->height, page->x_resolution, page->y_resolution); |
| 48 | } |
| 49 | if (page->striped) { |
| 50 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "\tmaximum stripe size: %d" , page->stripe_size); |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | /** |
| 55 | * jbig2_page_info: parse page info segment |
| 56 | * |
| 57 | * Parse the page info segment data and fill out a corresponding |
| 58 | * Jbig2Page struct and ready it for subsequent rendered data, |
| 59 | * including allocating an image buffer for the page (or the first stripe) |
| 60 | **/ |
| 61 | int |
| 62 | jbig2_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) |
| 63 | { |
| 64 | Jbig2Page *page, *pages; |
| 65 | |
| 66 | /* a new page info segment implies the previous page is finished */ |
| 67 | page = &(ctx->pages[ctx->current_page]); |
| 68 | if (page->number != 0 && (page->state == JBIG2_PAGE_NEW || page->state == JBIG2_PAGE_FREE)) { |
| 69 | page->state = JBIG2_PAGE_COMPLETE; |
| 70 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unexpected page info segment, marking previous page finished" ); |
| 71 | } |
| 72 | |
| 73 | /* find a free page */ |
| 74 | { |
| 75 | int index, j; |
| 76 | |
| 77 | index = ctx->current_page; |
| 78 | while (ctx->pages[index].state != JBIG2_PAGE_FREE) { |
| 79 | index++; |
| 80 | if (index >= ctx->max_page_index) { |
| 81 | /* grow the list */ |
| 82 | pages = jbig2_renew(ctx, ctx->pages, Jbig2Page, (ctx->max_page_index <<= 2)); |
| 83 | if (pages == NULL) { |
| 84 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to reallocate pages" ); |
| 85 | } |
| 86 | ctx->pages = pages; |
| 87 | for (j = index; j < ctx->max_page_index; j++) { |
| 88 | ctx->pages[j].state = JBIG2_PAGE_FREE; |
| 89 | ctx->pages[j].number = 0; |
| 90 | ctx->pages[j].image = NULL; |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | page = &(ctx->pages[index]); |
| 95 | ctx->current_page = index; |
| 96 | page->state = JBIG2_PAGE_NEW; |
| 97 | page->number = segment->page_association; |
| 98 | } |
| 99 | |
| 100 | /* FIXME: would be nice if we tried to work around this */ |
| 101 | if (segment->data_length < 19) { |
| 102 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short" ); |
| 103 | } |
| 104 | |
| 105 | /* 7.4.8.x */ |
| 106 | page->width = jbig2_get_uint32(segment_data); |
| 107 | page->height = jbig2_get_uint32(segment_data + 4); |
| 108 | |
| 109 | page->x_resolution = jbig2_get_uint32(segment_data + 8); |
| 110 | page->y_resolution = jbig2_get_uint32(segment_data + 12); |
| 111 | page->flags = segment_data[16]; |
| 112 | /* Check for T.88 amendment 3 */ |
| 113 | if (page->flags & 0x80) |
| 114 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "page segment indicates use of color segments (NYI)" ); |
| 115 | |
| 116 | /* 7.4.8.6 */ |
| 117 | { |
| 118 | int16_t striping = jbig2_get_int16(segment_data + 17); |
| 119 | |
| 120 | if (striping & 0x8000) { |
| 121 | page->striped = TRUE; |
| 122 | page->stripe_size = striping & 0x7FFF; |
| 123 | } else { |
| 124 | page->striped = FALSE; |
| 125 | page->stripe_size = 0; /* would page->height be better? */ |
| 126 | } |
| 127 | } |
| 128 | if (page->height == 0xFFFFFFFF && page->striped == FALSE) { |
| 129 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "height is unspecified but page is not marked as striped, assuming striped with maximum strip size" ); |
| 130 | page->striped = TRUE; |
| 131 | page->stripe_size = 0x7FFF; |
| 132 | } |
| 133 | page->end_row = 0; |
| 134 | |
| 135 | if (segment->data_length > 19) { |
| 136 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "extra data in segment" ); |
| 137 | } |
| 138 | |
| 139 | dump_page_info(ctx, segment, page); |
| 140 | |
| 141 | /* allocate an appropriate page image buffer */ |
| 142 | /* 7.4.8.2 */ |
| 143 | if (page->height == 0xFFFFFFFF) { |
| 144 | page->image = jbig2_image_new(ctx, page->width, page->stripe_size); |
| 145 | } else { |
| 146 | page->image = jbig2_image_new(ctx, page->width, page->height); |
| 147 | } |
| 148 | if (page->image == NULL) { |
| 149 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate buffer for page image" ); |
| 150 | } else { |
| 151 | /* 8.2 (3) fill the page with the default pixel value */ |
| 152 | jbig2_image_clear(ctx, page->image, (page->flags & 4)); |
| 153 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
| 154 | "allocated %dx%d page image (%d bytes)" , page->image->width, page->image->height, page->image->stride * page->image->height); |
| 155 | } |
| 156 | |
| 157 | return 0; |
| 158 | } |
| 159 | |
| 160 | /** |
| 161 | * jbig2_end_of_stripe: parse and implement an end of stripe segment |
| 162 | **/ |
| 163 | int |
| 164 | jbig2_end_of_stripe(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) |
| 165 | { |
| 166 | Jbig2Page *page = &ctx->pages[ctx->current_page]; |
| 167 | uint32_t end_row; |
| 168 | |
| 169 | if (segment->data_length < 4) |
| 170 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short" ); |
| 171 | end_row = jbig2_get_uint32(segment_data); |
| 172 | if (end_row < page->end_row) { |
| 173 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
| 174 | "end of stripe segment with non-positive end row advance (new end row %d vs current end row %d)" , end_row, page->end_row); |
| 175 | } else { |
| 176 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of stripe: advancing end row from %u to %u" , page->end_row, end_row); |
| 177 | } |
| 178 | |
| 179 | page->end_row = end_row; |
| 180 | |
| 181 | return 0; |
| 182 | } |
| 183 | |
| 184 | /** |
| 185 | * jbig2_complete_page: complete a page image |
| 186 | * |
| 187 | * called upon seeing an 'end of page' segment, this routine |
| 188 | * marks a page as completed so it can be returned. |
| 189 | * compositing will have already happened in the previous |
| 190 | * segment handlers. |
| 191 | **/ |
| 192 | int |
| 193 | jbig2_complete_page(Jbig2Ctx *ctx) |
| 194 | { |
| 195 | int code; |
| 196 | |
| 197 | /* check for unfinished segments */ |
| 198 | if (ctx->segment_index != ctx->n_segments) { |
| 199 | Jbig2Segment *segment = ctx->segments[ctx->segment_index]; |
| 200 | |
| 201 | /* Some versions of Xerox Workcentre generate PDF files |
| 202 | with the segment data length field of the last segment |
| 203 | set to -1. Try to cope with this here. */ |
| 204 | if ((segment->data_length & 0xffffffff) == 0xffffffff) { |
| 205 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "file has an invalid segment data length; trying to decode using the available data" ); |
| 206 | segment->data_length = ctx->buf_wr_ix - ctx->buf_rd_ix; |
| 207 | code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix); |
| 208 | ctx->buf_rd_ix += segment->data_length; |
| 209 | ctx->segment_index++; |
| 210 | if (code < 0) { |
| 211 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to parse segment" ); |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | /* ensure image exists before marking page as complete */ |
| 217 | if (ctx->pages[ctx->current_page].image == NULL) { |
| 218 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "page has no image, cannot be completed" ); |
| 219 | } |
| 220 | |
| 221 | ctx->pages[ctx->current_page].state = JBIG2_PAGE_COMPLETE; |
| 222 | return 0; |
| 223 | } |
| 224 | |
| 225 | /** |
| 226 | * jbig2_end_of_page: parse and implement an end of page segment |
| 227 | **/ |
| 228 | int |
| 229 | jbig2_end_of_page(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) |
| 230 | { |
| 231 | uint32_t page_number = ctx->pages[ctx->current_page].number; |
| 232 | int code; |
| 233 | |
| 234 | if (segment->page_association != page_number) { |
| 235 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
| 236 | "end of page marker for page %d doesn't match current page number %d" , segment->page_association, page_number); |
| 237 | } |
| 238 | |
| 239 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of page %d" , page_number); |
| 240 | |
| 241 | code = jbig2_complete_page(ctx); |
| 242 | if (code < 0) |
| 243 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to complete page" ); |
| 244 | |
| 245 | #ifdef OUTPUT_PBM |
| 246 | code = jbig2_image_write_pbm(ctx->pages[ctx->current_page].image, stdout); |
| 247 | if (code < 0) |
| 248 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to write page image" ); |
| 249 | #endif |
| 250 | |
| 251 | return 0; |
| 252 | } |
| 253 | |
| 254 | /** |
| 255 | * jbig2_add_page_result: composite a decoding result onto a page |
| 256 | * |
| 257 | * this is called to add the results of segment decode (when it |
| 258 | * is an image) to a page image buffer |
| 259 | **/ |
| 260 | int |
| 261 | jbig2_page_add_result(Jbig2Ctx *ctx, Jbig2Page *page, Jbig2Image *image, uint32_t x, uint32_t y, Jbig2ComposeOp op) |
| 262 | { |
| 263 | int code; |
| 264 | |
| 265 | /* ensure image exists first */ |
| 266 | if (page->image == NULL) |
| 267 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "page info possibly missing, no image defined" ); |
| 268 | |
| 269 | /* grow the page to accommodate a new stripe if necessary */ |
| 270 | if (page->striped && page->height == 0xFFFFFFFF) { |
| 271 | uint32_t new_height = y + image->height; |
| 272 | if (page->image->height < new_height) { |
| 273 | Jbig2Image *resized_image = NULL; |
| 274 | |
| 275 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "growing page buffer to %u rows to accommodate new stripe" , new_height); |
| 276 | resized_image = jbig2_image_resize(ctx, page->image, page->image->width, new_height, page->flags & 4); |
| 277 | if (resized_image == NULL) { |
| 278 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unable to resize image to accommodate new stripe" ); |
| 279 | } |
| 280 | page->image = resized_image; |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | code = jbig2_image_compose(ctx, page->image, image, x, y, op); |
| 285 | if (code < 0) |
| 286 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to compose image with page" ); |
| 287 | |
| 288 | return 0; |
| 289 | } |
| 290 | |
| 291 | /** |
| 292 | * jbig2_get_page: return the next available page image buffer |
| 293 | * |
| 294 | * the client can call this at any time to check if any pages |
| 295 | * have been decoded. If so, it returns the first available |
| 296 | * one. The client should then call jbig2_release_page() when |
| 297 | * it no longer needs to refer to the image buffer. |
| 298 | * |
| 299 | * since this is a public routine for the library clients, we |
| 300 | * return an image structure pointer, even though the function |
| 301 | * name refers to a page; the page structure is private. |
| 302 | **/ |
| 303 | Jbig2Image * |
| 304 | jbig2_page_out(Jbig2Ctx *ctx) |
| 305 | { |
| 306 | int index; |
| 307 | |
| 308 | /* search for a completed page */ |
| 309 | for (index = 0; index < ctx->max_page_index; index++) { |
| 310 | if (ctx->pages[index].state == JBIG2_PAGE_COMPLETE) { |
| 311 | Jbig2Image *img = ctx->pages[index].image; |
| 312 | uint32_t page_number = ctx->pages[index].number; |
| 313 | |
| 314 | if (img == NULL) { |
| 315 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "page %d returned with no associated image" , page_number); |
| 316 | continue; |
| 317 | } |
| 318 | |
| 319 | ctx->pages[index].state = JBIG2_PAGE_RETURNED; |
| 320 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "page %d returned to the client" , page_number); |
| 321 | return jbig2_image_reference(ctx, img); |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | /* no pages available */ |
| 326 | return NULL; |
| 327 | } |
| 328 | |
| 329 | /** |
| 330 | * jbig2_release_page: tell the library a page can be freed |
| 331 | **/ |
| 332 | void |
| 333 | jbig2_release_page(Jbig2Ctx *ctx, Jbig2Image *image) |
| 334 | { |
| 335 | int index; |
| 336 | |
| 337 | if (image == NULL) |
| 338 | return; |
| 339 | |
| 340 | /* find the matching page struct and mark it released */ |
| 341 | for (index = 0; index < ctx->max_page_index; index++) { |
| 342 | if (ctx->pages[index].image == image) { |
| 343 | jbig2_image_release(ctx, image); |
| 344 | ctx->pages[index].state = JBIG2_PAGE_RELEASED; |
| 345 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "page %d released by the client" , ctx->pages[index].number); |
| 346 | return; |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | /* no matching pages */ |
| 351 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to release unknown page" ); |
| 352 | } |
| 353 | |