ref: 5d215388772fd0c2931cdc4cafca74c1256bfea6
dir: /jbig2_generic.c/
/** * Generic region handlers. **/ #define OUTPUT_PBM #include <stdint.h> #include <stddef.h> #ifdef OUTPUT_PBM #include <stdio.h> #endif #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" #include "jbig2_generic.h" typedef struct { int32_t width; int32_t height; int32_t x; int32_t y; byte flags; } Jbig2RegionSegmentInfo; static int jbig2_decode_generic_template0(Jbig2Ctx *ctx, int32_t seg_number, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, byte *gbreg, Jbig2ArithCx *GB_stats) { int GBW = params->GBW; int rowstride = (GBW + 7) >> 3; int x, y; byte *gbreg_line = gbreg; bool LTP = 0; /* todo: currently we only handle the nominal gbat location */ #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, params->GBH); #endif for (y = 0; y < params->GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; uint32_t line_m2; int padded_width = (GBW + 7) & -8; line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0; line_m2 = (y >= 2) ? gbreg_line[-(rowstride << 1)] << 6 : 0; CONTEXT = (line_m1 & 0x7f0) | (line_m2 & 0xf800); /* 6.2.5.7 3d */ for (x = 0; x < padded_width; x += 8) { byte result = 0; int x_minor; int minor_width = GBW - x > 8 ? 8 : GBW - x; if (y >= 1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0); if (y >= 2) line_m2 = (line_m2 << 8) | (x + 8 < GBW ? gbreg_line[-(rowstride << 1) + (x >> 3) + 1] << 6: 0); /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { bool bit; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x7bf7) << 1) | bit | ((line_m1 >> (7 - x_minor)) & 0x10) | ((line_m2 >> (7 - x_minor)) & 0x800); } gbreg_line[x >> 3] = result; } #ifdef OUTPUT_PBM fwrite(gbreg_line, 1, rowstride, stdout); #endif gbreg_line += rowstride; } return 0; } static int jbig2_decode_generic_template1(Jbig2Ctx *ctx, int32_t seg_number, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, byte *gbreg, Jbig2ArithCx *GB_stats) { int GBW = params->GBW; int rowstride = (GBW + 7) >> 3; int x, y; byte *gbreg_line = gbreg; bool LTP = 0; /* todo: currently we only handle the nominal gbat location */ #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, params->GBH); #endif for (y = 0; y < params->GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; uint32_t line_m2; int padded_width = (GBW + 7) & -8; line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0; line_m2 = (y >= 2) ? gbreg_line[-(rowstride << 1)] << 5 : 0; CONTEXT = ((line_m1 >> 1) & 0x1f8) | ((line_m2 >> 1) & 0x1e00); /* 6.2.5.7 3d */ for (x = 0; x < padded_width; x += 8) { byte result = 0; int x_minor; int minor_width = GBW - x > 8 ? 8 : GBW - x; if (y >= 1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0); if (y >= 2) line_m2 = (line_m2 << 8) | (x + 8 < GBW ? gbreg_line[-(rowstride << 1) + (x >> 3) + 1] << 5: 0); /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { bool bit; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0xefb) << 1) | bit | ((line_m1 >> (8 - x_minor)) & 0x8) | ((line_m2 >> (8 - x_minor)) & 0x200); } gbreg_line[x >> 3] = result; } #ifdef OUTPUT_PBM fwrite(gbreg_line, 1, rowstride, stdout); #endif gbreg_line += rowstride; } return 0; } /** * jbig2_decode_generic_region: Decode a generic region. * @ctx: The context for allocation and error reporting. * @params: Parameters, as specified in Table 2. * @data: The input data. * @size: The size of the input data, in bytes. * @gbreg: Where to store the decoded data. * * Decodes a generic region, according to section 6.2. The caller should * have allocated the memory for @gbreg, which is packed 8 pixels to a * byte, scanlines aligned to one byte boundaries. * * Todo: I think the stats need to be an argument. * * Return code: 0 on success. **/ int jbig2_decode_generic_region(Jbig2Ctx *ctx, int32_t seg_number, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, byte *gbreg, Jbig2ArithCx *GB_stats) { if (!params->MMR && params->GBTEMPLATE == 0) return jbig2_decode_generic_template0(ctx, seg_number, params, as, gbreg, GB_stats); else if (!params->MMR && params->GBTEMPLATE == 1) return jbig2_decode_generic_template1(ctx, seg_number, params, as, gbreg, GB_stats); { int i; for (i = 0; i < 8; i++) printf ("gbat[%d] = %d\n", i, params->gbat[i]); } jbig2_error(ctx, JBIG2_SEVERITY_WARNING, seg_number, "decode_generic_region: MMR=%d, GBTEMPLATE=%d NYI", params->MMR, params->GBTEMPLATE); return -1; } void jbig2_get_region_segment_info(Jbig2RegionSegmentInfo *info, const byte *segment_data) { /* 7.4.1 */ info->width = jbig2_get_int32(segment_data); info->height = jbig2_get_int32(segment_data + 4); info->x = jbig2_get_int32(segment_data + 8); info->y = jbig2_get_int32(segment_data + 12); info->flags = segment_data[16]; } int jbig2_immediate_generic_region(Jbig2Ctx *ctx, Jbig2SegmentHeader *sh, const uint8_t *segment_data) { Jbig2RegionSegmentInfo rsi; byte seg_flags; int8_t gbat[8]; int offset; int gbat_bytes = 0; Jbig2GenericRegionParams params; int code; byte *gbreg; Jbig2WordStream *ws; Jbig2ArithState *as; Jbig2ArithCx *GB_stats = NULL; /* 7.4.6 */ if (sh->data_length < 18) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, sh->segment_number, "Segment too short"); jbig2_get_region_segment_info(&rsi, segment_data); jbig2_error(ctx, JBIG2_SEVERITY_INFO, sh->segment_number, "generic region: %d x %d @ (%d, %d), flags = %02x", rsi.width, rsi.height, rsi.x, rsi.y, rsi.flags); /* 7.4.6.2 */ seg_flags = segment_data[17]; jbig2_error(ctx, JBIG2_SEVERITY_INFO, sh->segment_number, "segment flags = %02x", seg_flags); if ((seg_flags & 1) && (seg_flags & 6)) jbig2_error(ctx, JBIG2_SEVERITY_WARNING, sh->segment_number, "MMR is 1, but GBTEMPLATE is not 0"); /* 7.4.6.3 */ if (!(seg_flags & 1)) { gbat_bytes = (seg_flags & 6) ? 2 : 8; if (18 + gbat_bytes > sh->data_length) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, sh->segment_number, "Segment too short"); memcpy(gbat, segment_data + 18, gbat_bytes); jbig2_error(ctx, JBIG2_SEVERITY_INFO, sh->segment_number, "gbat: %d, %d", gbat[0], gbat[1]); } offset = 18 + gbat_bytes; /* Table 34 */ params.MMR = seg_flags & 1; params.GBTEMPLATE = (seg_flags & 6) >> 1; params.TPGDON = (seg_flags & 8) >> 3; params.USESKIP = 0; params.GBW = rsi.width; params.GBH = rsi.height; memcpy (params.gbat, gbat, gbat_bytes); gbreg = jbig2_alloc(ctx->allocator, ((rsi.width + 7) >> 3) * rsi.height); ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, sh->data_length - offset); as = jbig2_arith_new(ctx, ws); if (!params.MMR) { int stats_size = params.GBTEMPLATE == 0 ? 65536 : params.GBTEMPLATE == 1 ? 8192 : 1024; GB_stats = jbig2_alloc(ctx->allocator, stats_size); memset(GB_stats, 0, stats_size); } code = jbig2_decode_generic_region(ctx, sh->segment_number, ¶ms, as, gbreg, GB_stats); /* todo: stash gbreg as segment result */ /* todo: free ws, as */ jbig2_free(ctx->allocator, GB_stats); return code; }