current implementation of jbig2_decode_generic_region() ignores the case TPGDON == TRUE This produces garbage as we can exercise with test stream 042_8.jb2. We can solve this problem with following simple additions. A) add this line as first one in jbig2_decode_generic_region() in jbig2_generic.c: if (!params->MMR && params->TPGDON) return jbig2_decode_generic_region_TPGDON( ctx, segment, params, as, image, GB_stats ); B) add this code to the same file: static void copy_prev_row( Jbig2Image *image, int row ) { if (!row) { // no previous row memset( image->data, 0, image->stride ); } else { uint8_t *src = image->data + (row - 1) * image->stride; memcpy( src + image->stride, src, image->stride ); } } static int jbig2_decode_generic_template0_TPGDON(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; uint32_t CONTEXT; int x, y; bool bit; int LTP = 0; for (y = 0; y < GBH; y++) { LTP ^= jbig2_arith_decode(as, &GB_stats[0x9B25]); if (!LTP) { for (x = 0; x < GBW; x++) { CONTEXT = jbig2_image_get_pixel(image, x - 1, y); CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6; CONTEXT |= jbig2_image_get_pixel(image, x , y - 1) << 7; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12; CONTEXT |= jbig2_image_get_pixel(image, x , y - 2) << 13; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); jbig2_image_set_pixel(image, x, y, bit); } } else copy_prev_row( image, y ); } return 0; } static int jbig2_decode_generic_template1_TPGDON(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; uint32_t CONTEXT; int x, y; bool bit; int LTP = 0; for (y = 0; y < GBH; y++) { LTP ^= jbig2_arith_decode(as, &GB_stats[0x0795]); if (!LTP) { for (x = 0; x < GBW; x++) { CONTEXT = jbig2_image_get_pixel(image, x - 1, y); CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 3; CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 4; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5; CONTEXT |= jbig2_image_get_pixel(image, x , y - 1) << 6; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8; CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 2) << 9; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 10; CONTEXT |= jbig2_image_get_pixel(image, x , y - 2) << 11; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 12; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); jbig2_image_set_pixel(image, x, y, bit); } } else copy_prev_row( image, y ); } return 0; } static int jbig2_decode_generic_template2_TPGDON(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; uint32_t CONTEXT; int x, y; bool bit; int LTP = 0; for (y = 0; y < GBH; y++) { LTP ^= jbig2_arith_decode(as, &GB_stats[0xE5]); if (!LTP) { for (x = 0; x < GBW; x++) { CONTEXT = jbig2_image_get_pixel(image, x - 1, y); CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 2; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 3; CONTEXT |= jbig2_image_get_pixel(image, x , y - 1) << 4; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 5; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 6; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 7; CONTEXT |= jbig2_image_get_pixel(image, x , y - 2) << 8; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 9; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); jbig2_image_set_pixel(image, x, y, bit); } } else copy_prev_row( image, y ); } return 0; } static int jbig2_decode_generic_template3_TPGDON(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; uint32_t CONTEXT; int x, y; bool bit; int LTP = 0; for (y = 0; y < GBH; y++) { LTP ^= jbig2_arith_decode(as, &GB_stats[0x0195]); if (!LTP) { for (x = 0; x < GBW; x++) { CONTEXT = jbig2_image_get_pixel(image, x - 1, y); CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5; CONTEXT |= jbig2_image_get_pixel(image, x , y - 1) << 6; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); jbig2_image_set_pixel(image, x, y, bit); } } else copy_prev_row( image, y ); } return 0; } int jbig2_decode_generic_region_TPGDON(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { switch (params->GBTEMPLATE) { case 0: return jbig2_decode_generic_template0_TPGDON(ctx, segment, params, as, image, GB_stats); break; case 1: return jbig2_decode_generic_template1_TPGDON(ctx, segment, params, as, image, GB_stats); break; case 2: return jbig2_decode_generic_template2_TPGDON(ctx, segment, params, as, image, GB_stats); break; case 3: return jbig2_decode_generic_template3_TPGDON(ctx, segment, params, as, image, GB_stats); break; } return -1; }
Thanks for the patch. It works great, giving correct rendering on 042_8.jb2 and the problem file in bug 690791. As a substantial contribution, we require copyright assignment before we can take the patch. Are you willing to do that?
I agree to assign you the copyright of this solution.
Thanks for the contribution! I've pushed a version of the patch, edited for coding style to git, and committed the same to the gs svn tree r10372. *** This bug has been marked as a duplicate of 690791 ***