/** * 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, int x, int y, Jbig2ComposeOp op) { /* ensure image exists first */ if (page->image == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "page info possibly missing, no image defined"); return 0; } /* grow the page to accomodate a new stripe if necessary */ if (page->striped) { int new_height = y + image->height + page->end_row; if (page->image->height < new_height) { jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "growing page buffer to %d rows " "to accomodate new stripe", new_height); jbig2_image_resize(ctx, page->image, page->image->width, new_height); } } jbig2_image_compose(ctx, page->image, image, x, y + page->end_row, op); 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, int x, int y, Jbig2ComposeOp op) { /* grow the page to accomodate a new stripe if necessary */ if (page->striped) { int new_height = y + image->height + page->end_row; if (page->image->height < new_height) { jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "growing page buffer to %d rows " "to accomodate new stripe", new_height); jbig2_image_resize(ctx, page->image, page->image->width, new_height); } } jbig2_image_compose(ctx, page->image, image, x, y + page->end_row, JBIG2_COMPOSE_OR); return 0; }
/** * jbig2_decode_text_region: decode a text region segment * * @ctx: jbig2 decoder context * @segment: jbig2 segment (header) structure * @params: parameters from the text region header * @dicts: an array of referenced symbol dictionaries * @n_dicts: the number of referenced symbol dictionaries * @image: image structure in which to store the decoded region bitmap * @data: pointer to text region data to be decoded * @size: length of text region data * * Implements the text region decoding procedure * described in section 6.4 of the JBIG2 spec. * * returns: 0 on success **/ int jbig2_decode_text_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2TextRegionParams *params, const Jbig2SymbolDict * const *dicts, const int n_dicts, Jbig2Image *image, const byte *data, const size_t size, Jbig2ArithCx *GR_stats, Jbig2ArithState *as, Jbig2WordStream *ws) { /* relevent bits of 6.4.4 */ uint32_t NINSTANCES; uint32_t ID; int32_t STRIPT; int32_t FIRSTS; int32_t DT; int32_t DFS; int32_t IDS; int32_t CURS; int32_t CURT; int S,T; int x,y; bool first_symbol; uint32_t index, SBNUMSYMS; Jbig2Image *IB = NULL; Jbig2HuffmanState *hs = NULL; Jbig2HuffmanTable *SBSYMCODES = NULL; int code = 0; int RI; SBNUMSYMS = 0; for (index = 0; index < n_dicts; index++) { SBNUMSYMS += dicts[index]->n_symbols; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "symbol list contains %d glyphs in %d dictionaries", SBNUMSYMS, n_dicts); if (params->SBHUFF) { Jbig2HuffmanTable *runcodes = NULL; Jbig2HuffmanParams runcodeparams; Jbig2HuffmanLine runcodelengths[35]; Jbig2HuffmanLine *symcodelengths = NULL; Jbig2HuffmanParams symcodeparams; int err, len, range, r; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "huffman coded text region"); hs = jbig2_huffman_new(ctx, ws); if (hs == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for text region"); return -1; } /* 7.4.3.1.7 - decode symbol ID Huffman table */ /* this is actually part of the segment header, but it is more convenient to handle it here */ /* parse and build the runlength code huffman table */ for (index = 0; index < 35; index++) { runcodelengths[index].PREFLEN = jbig2_huffman_get_bits(hs, 4); runcodelengths[index].RANGELEN = 0; runcodelengths[index].RANGELOW = index; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, " read runcode%d length %d", index, runcodelengths[index].PREFLEN); } runcodeparams.HTOOB = 0; runcodeparams.lines = runcodelengths; runcodeparams.n_lines = 35; runcodes = jbig2_build_huffman_table(ctx, &runcodeparams); if (runcodes == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error constructing symbol id runcode table!"); code = -1; goto cleanup1; } /* decode the symbol id codelengths using the runlength table */ symcodelengths = jbig2_new(ctx, Jbig2HuffmanLine, SBNUMSYMS); if (symcodelengths == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "memory allocation failure reading symbol ID huffman table!"); code = -1; goto cleanup1; } index = 0; while (index < SBNUMSYMS) { code = jbig2_huffman_get(hs, runcodes, &err); if (err != 0 || code < 0 || code >= 35) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error reading symbol ID huffman table!"); code = err ? err : -1; goto cleanup1; } if (code < 32) { len = code; range = 1; } else { if (code == 32) { len = symcodelengths[index-1].PREFLEN; if (index < 1) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding symbol id table: run length with no antecedent!"); code = -1; goto cleanup1; } } else { len = 0; /* code == 33 or 34 */ } if (code == 32) range = jbig2_huffman_get_bits(hs, 2) + 3; else if (code == 33) range = jbig2_huffman_get_bits(hs, 3) + 3; else if (code == 34) range = jbig2_huffman_get_bits(hs, 7) + 11; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, " read runcode%d at index %d (length %d range %d)", code, index, len, range); if (index+range > SBNUMSYMS) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "runlength extends %d entries beyond the end of symbol id table!", index+range - SBNUMSYMS); range = SBNUMSYMS - index; } for (r = 0; r < range; r++) { symcodelengths[index+r].PREFLEN = len; symcodelengths[index+r].RANGELEN = 0; symcodelengths[index+r].RANGELOW = index + r; } index += r; } if (index < SBNUMSYMS) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "runlength codes do not cover the available symbol set"); } symcodeparams.HTOOB = 0; symcodeparams.lines = symcodelengths; symcodeparams.n_lines = SBNUMSYMS; /* skip to byte boundary */ jbig2_huffman_skip(hs); /* finally, construct the symbol id huffman table itself */ SBSYMCODES = jbig2_build_huffman_table(ctx, &symcodeparams); cleanup1: jbig2_free(ctx->allocator, symcodelengths); jbig2_release_huffman_table(ctx, runcodes); if (SBSYMCODES == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not construct Symbol ID huffman table!"); jbig2_huffman_free(ctx, hs); return ((code != 0) ? code : -1); } } /* 6.4.5 (1) */ jbig2_image_clear(ctx, image, params->SBDEFPIXEL); /* 6.4.6 */ if (params->SBHUFF) { STRIPT = jbig2_huffman_get(hs, params->SBHUFFDT, &code); } else { code = jbig2_arith_int_decode(params->IADT, as, &STRIPT); if (code < 0) goto cleanup2; } /* 6.4.5 (2) */ STRIPT *= -(params->SBSTRIPS); FIRSTS = 0; NINSTANCES = 0; /* 6.4.5 (3) */ while (NINSTANCES < params->SBNUMINSTANCES) { /* (3b) */ if (params->SBHUFF) { DT = jbig2_huffman_get(hs, params->SBHUFFDT, &code); } else { code = jbig2_arith_int_decode(params->IADT, as, &DT); if (code < 0) goto cleanup2; } DT *= params->SBSTRIPS; STRIPT += DT; first_symbol = TRUE; /* 6.4.5 (3c) - decode symbols in strip */ for (;;) { /* (3c.i) */ if (first_symbol) { /* 6.4.7 */ if (params->SBHUFF) { DFS = jbig2_huffman_get(hs, params->SBHUFFFS, &code); } else { code = jbig2_arith_int_decode(params->IAFS, as, &DFS); if (code < 0) goto cleanup2; } FIRSTS += DFS; CURS = FIRSTS; first_symbol = FALSE; } else { /* (3c.ii) / 6.4.8 */ if (params->SBHUFF) { IDS = jbig2_huffman_get(hs, params->SBHUFFDS, &code); } else { code = jbig2_arith_int_decode(params->IADS, as, &IDS); } if (code) { break; } CURS += IDS + params->SBDSOFFSET; } /* (3c.iii) / 6.4.9 */ if (params->SBSTRIPS == 1) { CURT = 0; } else if (params->SBHUFF) { CURT = jbig2_huffman_get_bits(hs, params->LOGSBSTRIPS); } else { code = jbig2_arith_int_decode(params->IAIT, as, &CURT); if (code < 0) goto cleanup2; } T = STRIPT + CURT; /* (3b.iv) / 6.4.10 - decode the symbol id */ if (params->SBHUFF) { ID = jbig2_huffman_get(hs, SBSYMCODES, &code); } else { code = jbig2_arith_iaid_decode(params->IAID, as, (int *)&ID); if (code < 0) goto cleanup2; } if (ID >= SBNUMSYMS) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol id out of range! (%d/%d)", ID, SBNUMSYMS); } /* (3c.v) / 6.4.11 - look up the symbol bitmap IB */ { uint32_t id = ID; index = 0; while (id >= dicts[index]->n_symbols) id -= dicts[index++]->n_symbols; IB = jbig2_image_clone(ctx, dicts[index]->glyphs[id]); } if (params->SBREFINE) { if (params->SBHUFF) { RI = jbig2_huffman_get_bits(hs, 1); } else { code = jbig2_arith_int_decode(params->IARI, as, &RI); if (code < 0) goto cleanup2; } } else { RI = 0; } if (RI) { Jbig2RefinementRegionParams rparams; Jbig2Image *IBO; int32_t RDW, RDH, RDX, RDY; Jbig2Image *refimage; int BMSIZE = 0; int code1 = 0; int code2 = 0; int code3 = 0; int code4 = 0; int code5 = 0; /* 6.4.11 (1, 2, 3, 4) */ if (!params->SBHUFF) { code1 = jbig2_arith_int_decode(params->IARDW, as, &RDW); code2 = jbig2_arith_int_decode(params->IARDH, as, &RDH); code3 = jbig2_arith_int_decode(params->IARDX, as, &RDX); code4 = jbig2_arith_int_decode(params->IARDY, as, &RDY); } else { RDW = jbig2_huffman_get(hs, params->SBHUFFRDW, &code1); RDH = jbig2_huffman_get(hs, params->SBHUFFRDH, &code2); RDX = jbig2_huffman_get(hs, params->SBHUFFRDX, &code3); RDY = jbig2_huffman_get(hs, params->SBHUFFRDY, &code4); BMSIZE = jbig2_huffman_get(hs, params->SBHUFFRSIZE, &code5); jbig2_huffman_skip(hs); } if ((code1 < 0) || (code2 < 0) || (code3 < 0) || (code4 < 0) || (code5 < 0)) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode data"); goto cleanup2; } /* 6.4.11 (6) */ IBO = IB; refimage = jbig2_image_new(ctx, IBO->width + RDW, IBO->height + RDH); if (refimage == NULL) { jbig2_image_release(ctx, IBO); if (params->SBHUFF) { jbig2_release_huffman_table(ctx, SBSYMCODES); } return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "couldn't allocate reference image"); } /* Table 12 */ rparams.GRTEMPLATE = params->SBRTEMPLATE; rparams.reference = IBO; rparams.DX = (RDW >> 1) + RDX; rparams.DY = (RDH >> 1) + RDY; rparams.TPGRON = 0; memcpy(rparams.grat, params->sbrat, 4); jbig2_decode_refinement_region(ctx, segment, &rparams, as, refimage, GR_stats); IB = refimage; jbig2_image_release(ctx, IBO); /* 6.4.11 (7) */ if (params->SBHUFF) { jbig2_huffman_advance(hs, BMSIZE); } } /* (3c.vi) */ if ((!params->TRANSPOSED) && (params->REFCORNER > 1)) { CURS += IB->width - 1; } else if ((params->TRANSPOSED) && !(params->REFCORNER & 1)) { CURS += IB->height - 1; } /* (3c.vii) */ S = CURS; /* (3c.viii) */ if (!params->TRANSPOSED) { switch (params->REFCORNER) { case JBIG2_CORNER_TOPLEFT: x = S; y = T; break; case JBIG2_CORNER_TOPRIGHT: x = S - IB->width + 1; y = T; break; case JBIG2_CORNER_BOTTOMLEFT: x = S; y = T - IB->height + 1; break; case JBIG2_CORNER_BOTTOMRIGHT: x = S - IB->width + 1; y = T - IB->height + 1; break; } } else { /* TRANSPOSED */ switch (params->REFCORNER) { case JBIG2_CORNER_TOPLEFT: x = T; y = S; break; case JBIG2_CORNER_TOPRIGHT: x = T - IB->width + 1; y = S; break; case JBIG2_CORNER_BOTTOMLEFT: x = T; y = S - IB->height + 1; break; case JBIG2_CORNER_BOTTOMRIGHT: x = T - IB->width + 1; y = S - IB->height + 1; break; } } /* (3c.ix) */ #ifdef JBIG2_DEBUG jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "composing glyph id %d: %dx%d @ (%d,%d) symbol %d/%d", ID, IB->width, IB->height, x, y, NINSTANCES + 1, params->SBNUMINSTANCES); #endif jbig2_image_compose(ctx, image, IB, x, y, params->SBCOMBOP); /* (3c.x) */ if ((!params->TRANSPOSED) && (params->REFCORNER < 2)) { CURS += IB->width -1 ; } else if ((params->TRANSPOSED) && (params->REFCORNER & 1)) { CURS += IB->height - 1; } /* (3c.xi) */ NINSTANCES++; jbig2_image_release(ctx, IB); } /* end strip */ } /* 6.4.5 (4) */ cleanup2: if (params->SBHUFF) { jbig2_release_huffman_table(ctx, SBSYMCODES); } jbig2_huffman_free(ctx, hs); return code; }