ref: 7c9bb193bcd464c3979a8d1e534b7b0950050935
dir: /jbig2_generic.c/
/* Copyright (C) 2001-2019 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., 1305 Grant Avenue - Suite 200, Novato, CA 94945, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /** * Generic region handlers. **/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include <stddef.h> #include <string.h> /* memcpy(), memset() */ #ifdef OUTPUT_PBM #include <stdio.h> #endif #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" #include "jbig2_generic.h" #include "jbig2_image.h" #include "jbig2_mmr.h" #include "jbig2_page.h" #include "jbig2_segment.h" #if !defined (UINT32_MAX) #define UINT32_MAX 0xffffffff #endif /* This is an explanation of the unoptimized and optimized generic region decoder implementations below, wherein we try to explain all the magic numbers. The generic region decoders decode the output pixels one row at a time, top to bottom. Within each row the pixels are decoded left to right. The input for the arithmetic integer decoder used to decode each pixel is a context consisting of up to 16 previously decoded pixels. These pixels are chosen according to a predefined template placed relative to the location of the pixel to be decoded (6.2.5.3 figures 3, 4, 5 and 6). There are four different template that may be used (6.2.5.3). The template to use is determined by GBTEMPLATE. GBTEMPLATE is set in the symbol dictionary (6.5.8.1), generic region (7.4.6.4), or when decoding a halftone region's gray-scale image (annex C.5). Most of the pixels in each template have fixed locations relative to the pixel to be decoded. However, all templates have at least one adaptive pixel. The adaptive pixels have nominal locations, but these locations may be changed by GBAT. GBAT is set in the symbol dictionary (7.4.2.1.2), generic region (7.4.6.1), or hard coded as for halftone patterns (6.7.5). Adaptive pixels are restricted to fall within a field of previously decoded pixels relative to the pixel to be decoded (figure 7). The relative Y-coordinate for these adaptive pixels may vary between -128 and 0. The relative X-coordinate may vary between -128 and +127 (however, if the Y-coordinate is 0 the range of the X-coordinate is further restricted to -128 to -1 since the pixels at locations 0 to +127 have not yet been decoded). If a template refers to a pixel location that reside outside of the image boundaries its value is assumed to be 0. UNOPTIMIZED DECODER The unoptimized decoders first check the contents of GBAT. If GBAT specifies that any of the adaptive pixels reside outside the allowed field the decoding is aborted. Next, each row is processed top to bottom, left to right, one pixel at a time. For each pixel a context is created containing the bit values of the pixels that fall inside the template. The order these bits are stored in the context is implementation dependent (6.2.5.3). We store the bit values in the CONTEXT variable from LSB to MSB, starting with the value of the pixel to the left of the current pixel, continuing right to left, bottom to top following the template. Using the CONTEXT created from these pixel values, the arithmetic integer decoder retrieves the pixel value, which is then written into the output image. Example when GBTEMPLATE is 2: The figure below represents a pixel grid of the output image. Each pixel is a single bit in the image. The pixel "OO" in the figure below is about to be decoded. The pixels "??" have not been decoded yet. The CONTEXT variable is constructed by combining the bit values from the pixels referred to by the template, shifted to their corresponding bit position. . . . . . . . . . . . . . . . . ...+----+----+----+----+----+----+----+... | | | X9 | X8 | X7 | | | ...+----+----+----+----+----+----+----+... | | X6 | X5 | X4 | X3 | A1 | | ...+----+----+----+----+----+----+----+... | | X2 | X1 | OO | ?? | ?? | ?? | ...+----+----+----+----+----+----+----+... . . . . . . . . . . . . . . . . In the table below pixel OO is assumed to be at coordinate (x, y). Bit 9: Pixel at location (x-1, y-2) (This is fixed pixel X9) Bit 8: Pixel at location (x , y-2) (This is fixed pixel X8) Bit 7: Pixel at location (x+1, y-2) (This is fixed pixel X7) Bit 6: Pixel at location (x-2, y-1) (This is fixed pixel X6) Bit 5: Pixel at location (x-1, y-1) (This is fixed pixel X5) Bit 4: Pixel at location (x , y-1) (This is fixed pixel X4) Bit 3: Pixel at location (x+1, y-1) (This is fixed pixel X3) Bit 2: Pixel at location (x+2, y-1) (This is adaptive pixel A1) Bit 1: Pixel at location (x-2, y ) (This is fixed pixel X2) Bit 0: Pixel at location (x-1, y ) (This is fixed pixel X1) The location of adaptive pixel A1 may not always be at the nominal location (x+2, y-1). It could be at any pixel location to the left or above OO as specified by GBAT, e.g. at the location (x-128, y+127). OPTIMIZED DECODER The optimized decoders work differently. They strive to avoid recreating the arithmetic integer decoder context from scratch for every pixel decoded. Instead they reuse part of the CONTEXT used to compute the previous pixel (the pixel to left of the one now being decoded). They also keep two sliding windows of pixel bit values from the two rows of pixels immediately above the pixel to be decoded. These are stored in the 32-bit variables line_m1 (row above the pixel to be decoded) and line_m2 (row above that of line_m1). These optimized decoders ONLY work for the nominal adaptive pixel locations since these locations are hard-coded into the implementation. The bit ordering in the CONTEXT variable is identical to the unoptimized case described above. The optimized decoders decode the output pixels one row at a time, top to bottom. Within each row the pixels are decoded in batches of up to eight pixels at a time (except possibly the right most batch which may be less than eight pixels). The batches in a row are decoded in sequence from left to right. Within each such batch the pixels are decoded in sequence from left to right. Before decoding the pixels in a row the two sliding windows of pixel values are reset. The first eight pixels of the row above the pixel to be decoded is stored in line_m1, while line_m2 stores the first eight pixels of the row above that of line_m1. The figure below illustrates the situation where the template has been placed so that the decoded pixel OO is the very first pixel of a row. It also gives labels to various pixels that we will refer to below. . . . . . . . . . . . | . . . . . . . . . . + + +----+----+----+----+----+----+----+----+----+----+... X9 | X8 | X7 | m1 | m2 | m3 | m4 | m5 | m6 | m7 | | + + +----+----+----+----+----+----+----+----+----+----+... X6 X5 | X4 | X3 | A1 | n1 | n2 | n3 | n4 | n5 | n6 | n7 | + + +----+----+----+----+----+----+----+----+----+----+... X2 X1 | OO | | | | | | | | | | + + +----+----+----+----+----+----+----+----+----+----+... | . . . . . . . . . . . . . . . . . . . . . The pixels X1, X2, X5, X6 and X9 all reside outside the left edge of the image. These pixels (like all others outside the image) can according to 6.2.5.2 be assumed to be 0. line_m1 stores n5 through n1 as well as A1, and X3 through X6. line_m2 stores m6 through m1 as well as X7 through X9. The bits in line_m2 are also shifted left four bits as seen below. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | bit position ------------------------------------------------+------------------ 0 0 0 0 0 0 X6 X5 X4 X3 A1 n1 n2 n3 n4 n5 | line_m1 0 0 0 X9 X8 X7 m1 m2 m3 m4 m5 m6 0 0 0 0 | line_m2 The way line_m1 and line_m2 are stored means we can simply shift them by the same amount to move the sliding window. The bit order in line_m1 and line_m2 matches the ordering in the CONTEXT variable. Each bit for the 'A' and 'X' pixels in line_m1 and line_m2 correspond to the equivalent bits in CONTEXT, only shifted right by 3 bits. Thus X3 is bit 3 in CONTEXT and bit 6 in line_m1, etc. The initial arithmetic integer decoder context is created and stored in the CONTEXT variable by masking, shifting, and bitwise ORing the contents of line_m1 and line_m2. The "CONTEXT contents" row is only shown for clarity, it is not present in the code. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | bit position ------------------------------------------------+--------------------------- 0 0 0 0 0 0 0 0 0 X6 X5 X4 X3 A1 n1 n2 | line_m1 >> 3 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 | mask for line_m1 (0x7c) 0 0 0 0 0 0 0 0 0 X6 X5 X4 X3 A1 0 0 | line_m1 AND mask ------------------------------------------------+--------------------------- 0 0 0 0 0 0 X9 X8 X7 m1 m2 m3 m4 m5 m6 0 | line_m2 >> 3 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 | mask for line_m2 (0x380) 0 0 0 0 0 0 X9 X8 X7 0 0 0 0 0 0 0 | line_m2 AND mask ------------------------------------------------+--------------------------- 0 0 0 0 0 0 X9 X8 X7 X6 X5 X4 X3 A1 0 0 | CONTEXT = line_m1 OR line_m2 ------------------------------------------------+--------------------------- 0 0 0 0 0 0 X9 X8 X7 X6 X5 X4 X3 A1 X2 X1 | CONTEXT contents Each batch is normally 8 bits, but at the right edge of the image we may have fewer pixels to decode. The minor_width is how many pixels the current batch should decode, with a counter variable x_minor to keep track of the current pixel being decoded. In order to process a new batch of pixels, unless we're at the rightmost batch of pixels, we need to refill the sliding window variables with eight new bits. Looking at the diagram above we can see that in order to decode eight pixels starting with O0 we'll need to have bits up to pixel 'n7' for line_m1 and 'm7' for line_m2 available (A1 and X7 moved right 7 times). To do this simply and quickly, we shift line_m1 left by 8 bits, and OR in the next byte from corresponding row. Likewise for line_m2, but the next byte from the image is also shifted left by 4 bits to compensate for line_m2 having the four least significant bits unused. These new eight bits contain the bit values of the eight pixels to the right of those already present in line_m1 and line_m2. We call these new bits m7 through mE, and n6 through nD, as illustrated below. 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | bit position ------------------------------------------------------------------------+------------- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 X6 X5 X4 X3 A1 n1 n2 n3 n4 n5 | original line_m1 0 0 0 0 0 0 X6 X5 X4 X3 A1 n1 n2 n3 n4 n5 0 0 0 0 0 0 0 0 | line_m1 shifted left by 8 0 0 0 0 0 0 X6 X5 X4 X3 A1 n1 n2 n3 n4 n5 n6 n7 n8 n9 nA nB nC nD | line_m1 with new bits ORed in ------------------------------------------------------------------------+------------- 0 0 0 0 0 0 0 0 0 0 0 X9 X8 X7 m1 m2 m3 m4 m5 m6 0 0 0 0 | original line_m2 0 0 0 X9 X8 X7 m1 m2 m3 m4 m5 m6 0 0 0 0 0 0 0 0 0 0 0 0 | line_m2 shifted left by 8 0 0 0 X9 X8 X7 m1 m2 m3 m4 m5 m6 m7 m8 m9 mA mB mC mD mE 0 0 0 0 | line_m2 with new bits ORed in . . . . . . . . . . . . . . . . . . . . | . . . . . . . . . . . . . . . . . . . + + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+... X9 | X8 | X7 | m1 | m2 | m3 | m4 | m5 | m6 | m7 | m8 | m9 | mA | mB | mC | mD | mE | | | | + + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+... X6 X5 | X4 | X3 | A1 | n1 | n2 | n3 | n4 | n5 | n6 | n7 | n8 | n9 | nA | nB | nC | nD | | | | + + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+... X2 X1 | OO | | | | | | | | | | | | | | | | | | | + + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+... | . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CONTEXT, line_m1 and line_m2 now contain all necessary bits to decode a full batch of eight pixels. The first pixel in the batch is decoded using this CONTEXT. After that, for each following pixel we need to update the CONTEXT using both the last decoded pixel value and new bits from line_m1 and line_m2. . . . . . . . . . . . . . . . . . . . . | . . . . . . . . . . . . . . . . . . . + + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+... (X9)|_X8_|_X7_|>m1<| m2 | m3 | m4 | m5 | m6 | m7 | m8 | m9 | mA | mB | mC | mD | mE | | | | + + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+... (X6) _X5_|_X4_|_X3_|_A1_|>n1<| n2 | n3 | n4 | n5 | n6 | n7 | n8 | n9 | nA | nB | nC | nD | | | | + + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+... (X2) _X1_|>OO<| oo | | | | | | | | | | | | | | | | | | + + +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+... | . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . This figure illustrates what happens when the same template is overlaid on itself shifted one pixel to the right in order to decode the next pixel. Pixels marked with _ _ are pixels that are present in both templates' CONTEXTs and can be reused. Pixels marked with ( ) are pixels from the first template that are no longer necessary and can be removed from CONTEXT. Pixels marked with > < are new pixels that were not part of the original CONTEXT, and so need to be moved into the CONTEXT at the appropriate locations. In general the leftmost pixels of each template row can be forgotten, while new pixels are needed at the right most location of each row. The CONTEXT corresponding to the current pixel OO and how it is masked is shown below. Note how the left most pixel of each row of the template is NOT propagated to the CONTEXT, these pixels are X2, X6 and X9. This is done by having the mask being 0 at the corresponding locations. 9 8 7 6 5 4 3 2 1 0 | bit position ------------------------------+------------- X9 X8 X7 X6 X5 X4 X3 A1 X2 X1 | pixel values from CONTEXT 0 1 1 0 1 1 1 1 0 1 | reused pixel bit value mask (0x1bd) 0 X8 X7 0 X5 X4 X3 A1 0 X1 | reused pixel values from CONTEXT Next the CONTEXT is shifted left by one bit to make it reference the next pixel to be decoded. The pixel bit value we just decoded is then written into the bit corresponding to X1. The sliding windows in line_m1 and line_m2 are both shifted (10 - x_minor) bits to the right to make the needed pixels' bit values appear at the correct positions to be ORed into CONTEXT. Note that this shift amount depends on which bit in the batch is currently being computed, as is given by the x_minor counter. In the example below we assume that x_minor is 0. 9 8 7 6 5 4 3 2 1 0 | bit position ------------------------------+-------------- 0 X8 X7 0 X5 X4 X3 A1 0 0 | reused pixels from CONTEXT X8 X7 0 X5 X4 X3 A1 0 0 0 | reused pixels shifted left 1 bit ------------------------------+-------------- X8 X7 0 X5 X4 X3 A1 0 X1 OO | new CONTEXT with current pixel at LSB ------------------------------+-------------- 0 0 X6 X5 X4 X3 A1 n1 n2 n3 | line_m1 shifted (10 - x_minor) bits to the right 0 0 0 0 0 0 0 1 0 0 | mask for new adaptive pixel one row above (0x4) X8 X7 0 X5 X4 X3 A1 n1 X1 OO | new CONTEXT with new adaptive pixel ------------------------------+-------------- X8 X7 m1 m2 m3 m4 m5 m6 m7 m8 | line_m2 with new bits ORed in 0 0 1 0 0 0 0 0 0 0 | mask for new pixel two rows above (0x80) X8 X7 m1 X5 X4 X3 A1 n1 X1 OO | new CONTEXT with new pixel This makes the computation of the new CONTEXT be: NEWCONTEXT = (CONTEXT & 0x1bd) << 1 NEWCONTEXT |= newbit; NEWCONTEXT |= (line_m1 >> (10-x_minor)) & 0x4; NEWCONTEXT |= (line_m2 >> (10-x_minor)) & 0x80; The optimized decoding functions for GBTEMPLATE 0, 1 and 3 all work similarly. */ /* return the appropriate context size for the given template */ int jbig2_generic_stats_size(Jbig2Ctx *ctx, int template) { int stats_size = template == 0 ? 1 << 16 : template == 1 ? 1 << 13 : 1 << 10; return stats_size; } static int jbig2_decode_generic_template0(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const uint32_t GBW = image->width; const uint32_t GBH = image->height; const uint32_t rowstride = image->stride; uint32_t x, y; byte *line2 = NULL; byte *line1 = NULL; byte *gbreg_line = (byte *) image->data; #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); #endif if (GBW <= 0) return 0; for (y = 0; y < GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; uint32_t line_m2; uint32_t padded_width = (GBW + 7) & -8; int code = 0; line_m1 = line1 ? line1[0] : 0; line_m2 = line2 ? line2[0] << 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 (line1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? line1[(x >> 3) + 1] : 0); if (line2) line_m2 = (line_m2 << 8) | (x + 8 < GBW ? line2[(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], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 optimized"); 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 line2 = line1; line1 = gbreg_line; gbreg_line += rowstride; } return 0; } #define pixel_outside_field(x, y) \ ((y) < -128 || (y) > 0 || (x) < -128 || ((y) < 0 && (x) > 127) || ((y) == 0 && (x) >= 0)) static int jbig2_decode_generic_template0_unopt(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const uint32_t GBW = image->width; const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; bool bit; int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1]) || pixel_outside_field(params->gbat[2], params->gbat[3]) || pixel_outside_field(params->gbat[4], params->gbat[5]) || pixel_outside_field(params->gbat[6], params->gbat[7])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); /* this version is generic and easy to understand, but very slow */ for (y = 0; y < GBH; y++) { for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { jbig2_image_set_pixel(image, x, y, 0); continue; } CONTEXT = 0; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0; 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 + 0, 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 + 0, 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], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 unoptimized"); jbig2_image_set_pixel(image, x, y, bit); } } return 0; } static int jbig2_decode_generic_template1_unopt(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const uint32_t GBW = image->width; const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; bool bit; int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); /* this version is generic and easy to understand, but very slow */ for (y = 0; y < GBH; y++) { for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { jbig2_image_set_pixel(image, x, y, 0); continue; } CONTEXT = 0; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0; 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 + 0, 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 + 0, y - 2) << 11; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 12; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 unoptimized"); jbig2_image_set_pixel(image, x, y, bit); } } return 0; } static int jbig2_decode_generic_template1(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const uint32_t GBW = image->width; const uint32_t GBH = image->height; const uint32_t rowstride = image->stride; uint32_t x, y; byte *line2 = NULL; byte *line1 = NULL; byte *gbreg_line = (byte *) image->data; int code = 0; #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); #endif if (GBW <= 0) return 0; for (y = 0; y < GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; uint32_t line_m2; uint32_t padded_width = (GBW + 7) & -8; line_m1 = line1 ? line1[0] : 0; line_m2 = line2 ? line2[0] << 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 (line1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? line1[(x >> 3) + 1] : 0); if (line2) line_m2 = (line_m2 << 8) | (x + 8 < GBW ? line2[(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], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 optimized"); 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 line2 = line1; line1 = gbreg_line; gbreg_line += rowstride; } return 0; } static int jbig2_decode_generic_template2_unopt(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const uint32_t GBW = image->width; const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; bool bit; int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); /* this version is generic and easy to understand, but very slow */ for (y = 0; y < GBH; y++) { for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { jbig2_image_set_pixel(image, x, y, 0); continue; } CONTEXT = 0; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0; 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 + 0, 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 + 0, y - 2) << 8; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 9; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 unoptimized"); jbig2_image_set_pixel(image, x, y, bit); } } return 0; } static int jbig2_decode_generic_template2(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const uint32_t GBW = image->width; const uint32_t GBH = image->height; const uint32_t rowstride = image->stride; uint32_t x, y; byte *line2 = NULL; byte *line1 = NULL; byte *gbreg_line = (byte *) image->data; int code = 0; #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); #endif if (GBW <= 0) return 0; for (y = 0; y < GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; uint32_t line_m2; uint32_t padded_width = (GBW + 7) & -8; line_m1 = line1 ? line1[0] : 0; line_m2 = line2 ? line2[0] << 4 : 0; CONTEXT = ((line_m1 >> 3) & 0x7c) | ((line_m2 >> 3) & 0x380); /* 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 (line1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? line1[(x >> 3) + 1] : 0); if (line2) line_m2 = (line_m2 << 8) | (x + 8 < GBW ? line2[(x >> 3) + 1] << 4 : 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], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 optimized"); result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x1bd) << 1) | bit | ((line_m1 >> (10 - x_minor)) & 0x4) | ((line_m2 >> (10 - x_minor)) & 0x80); } gbreg_line[x >> 3] = result; } #ifdef OUTPUT_PBM fwrite(gbreg_line, 1, rowstride, stdout); #endif line2 = line1; line1 = gbreg_line; gbreg_line += rowstride; } return 0; } static int jbig2_decode_generic_template3(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const uint32_t GBW = image->width; const uint32_t GBH = image->height; const uint32_t rowstride = image->stride; byte *line1 = NULL; byte *gbreg_line = (byte *) image->data; uint32_t x, y; int code; #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); #endif if (GBW <= 0) return 0; for (y = 0; y < GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; uint32_t padded_width = (GBW + 7) & -8; line_m1 = line1 ? line1[0] : 0; CONTEXT = (line_m1 >> 1) & 0x3f0; /* 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 (line1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? line1[(x >> 3) + 1] : 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], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 optimized"); result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x1f7) << 1) | bit | ((line_m1 >> (8 - x_minor)) & 0x10); } gbreg_line[x >> 3] = result; } #ifdef OUTPUT_PBM fwrite(gbreg_line, 1, rowstride, stdout); #endif line1 = gbreg_line; gbreg_line += rowstride; } return 0; } static int jbig2_decode_generic_template3_unopt(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const uint32_t GBW = image->width; const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; bool bit; int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); /* this version is generic and easy to understand, but very slow */ for (y = 0; y < GBH; y++) { for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { jbig2_image_set_pixel(image, x, y, 0); continue; } CONTEXT = 0; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0; 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 + 0, 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], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 unoptimized"); jbig2_image_set_pixel(image, x, y, bit); } } return 0; } static void copy_prev_row(Jbig2Image *image, int row) { if (!row) { /* no previous row */ memset(image->data, 0, image->stride); } else { /* duplicate data from the previous row */ 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 uint32_t GBW = image->width; const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; bool bit; int LTP = 0; int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1]) || pixel_outside_field(params->gbat[2], params->gbat[3]) || pixel_outside_field(params->gbat[4], params->gbat[5]) || pixel_outside_field(params->gbat[6], params->gbat[7])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); for (y = 0; y < GBH; y++) { LTP ^= jbig2_arith_decode(as, &GB_stats[0x9B25], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 TPGDON1"); if (!LTP) { for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { jbig2_image_set_pixel(image, x, y, 0); continue; } 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], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 TPGDON2"); 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 uint32_t GBW = image->width; const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; bool bit; int LTP = 0; int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); for (y = 0; y < GBH; y++) { LTP ^= jbig2_arith_decode(as, &GB_stats[0x0795], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 TPGDON1"); if (!LTP) { for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { jbig2_image_set_pixel(image, x, y, 0); continue; } 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], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 TPGDON2"); 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 uint32_t GBW = image->width; const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; bool bit; int LTP = 0; int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); for (y = 0; y < GBH; y++) { LTP ^= jbig2_arith_decode(as, &GB_stats[0xE5], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 TPGDON1"); if (!LTP) { for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { jbig2_image_set_pixel(image, x, y, 0); continue; } 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], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 TPGDON2"); 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 uint32_t GBW = image->width; const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; bool bit; int LTP = 0; int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); for (y = 0; y < GBH; y++) { LTP ^= jbig2_arith_decode(as, &GB_stats[0x0195], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 TPGDON1"); if (!LTP) { for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { jbig2_image_set_pixel(image, x, y, 0); continue; } 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], &code); if (code) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 TPGDON2"); jbig2_image_set_pixel(image, x, y, bit); } } else { copy_prev_row(image, y); } } return 0; } static 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); case 1: return jbig2_decode_generic_template1_TPGDON(ctx, segment, params, as, image, GB_stats); case 2: return jbig2_decode_generic_template2_TPGDON(ctx, segment, params, as, image, GB_stats); case 3: return jbig2_decode_generic_template3_TPGDON(ctx, segment, params, as, image, GB_stats); } return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unsupported GBTEMPLATE (%d)", params->GBTEMPLATE); } /** * jbig2_decode_generic_region: Decode a generic region. * @ctx: The context for allocation and error reporting. * @segment: A segment reference for error reporting. * @params: Decoding parameter set. * @as: Arithmetic decoder state. * @image: Where to store the decoded data. * @GB_stats: Arithmetic stats. * * Decodes a generic region, according to section 6.2. The caller should * pass an already allocated Jbig2Image object for @image * * Because this API is based on an arithmetic decoding state, it is * not suitable for MMR decoding. * * Return code: 0 on success. **/ int jbig2_decode_generic_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int8_t *gbat = params->gbat; if (image->stride * image->height > (1 << 26) && segment->data_length < image->stride * image->height / (1 << 16)) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "region is far larger than data provided (%d << %d), aborting to prevent DOS", segment->data_length, image->stride * image->height); } if (!params->MMR && params->TPGDON) return jbig2_decode_generic_region_TPGDON(ctx, segment, params, as, image, GB_stats); if (!params->MMR && params->GBTEMPLATE == 0) { if (!params->USESKIP && gbat[0] == +3 && gbat[1] == -1 && gbat[2] == -3 && gbat[3] == -1 && gbat[4] == +2 && gbat[5] == -2 && gbat[6] == -2 && gbat[7] == -2) return jbig2_decode_generic_template0(ctx, segment, params, as, image, GB_stats); else return jbig2_decode_generic_template0_unopt(ctx, segment, params, as, image, GB_stats); } else if (!params->MMR && params->GBTEMPLATE == 1) { if (!params->USESKIP && gbat[0] == +3 && gbat[1] == -1) return jbig2_decode_generic_template1(ctx, segment, params, as, image, GB_stats); else return jbig2_decode_generic_template1_unopt(ctx, segment, params, as, image, GB_stats); } else if (!params->MMR && params->GBTEMPLATE == 2) { if (!params->USESKIP && gbat[0] == 2 && gbat[1] == -1) return jbig2_decode_generic_template2(ctx, segment, params, as, image, GB_stats); else return jbig2_decode_generic_template2_unopt(ctx, segment, params, as, image, GB_stats); } else if (!params->MMR && params->GBTEMPLATE == 3) { if (!params->USESKIP && gbat[0] == 2 && gbat[1] == -1) return jbig2_decode_generic_template3(ctx, segment, params, as, image, GB_stats); else return jbig2_decode_generic_template3_unopt(ctx, segment, params, as, image, GB_stats); } { int i; for (i = 0; i < 8; i++) jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "gbat[%d] = %d", i, params->gbat[i]); } return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unsupported generic region (MMR=%d, GBTEMPLATE=%d)", params->MMR, params->GBTEMPLATE); } /** * Handler for immediate generic region segments */ int jbig2_immediate_generic_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) { Jbig2RegionSegmentInfo rsi; byte seg_flags; int8_t gbat[8]; int offset; uint32_t gbat_bytes = 0; Jbig2GenericRegionParams params; int code = 0; Jbig2Image *image = NULL; Jbig2WordStream *ws = NULL; Jbig2ArithState *as = NULL; Jbig2ArithCx *GB_stats = NULL; uint32_t height; Jbig2Page *page = &ctx->pages[ctx->current_page]; /* 7.4.6 */ if (segment->data_length < 18) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short"); jbig2_get_region_segment_info(&rsi, segment_data); jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "generic region: %u x %u @ (%u, %u), flags = %02x", rsi.width, rsi.height, rsi.x, rsi.y, rsi.flags); /* 7.4.6.4 */ height = rsi.height; if (segment->rows != UINT32_MAX) { if (segment->rows > rsi.height) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment contains more rows than stated in header"); height = segment->rows; } /* 7.4.6.2 */ seg_flags = segment_data[17]; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "segment flags = %02x", seg_flags); if ((seg_flags & 1) && (seg_flags & 6)) jbig2_error(ctx, JBIG2_SEVERITY_WARNING, 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 > segment->data_length) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short"); memcpy(gbat, segment_data + 18, gbat_bytes); jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "gbat: %d, %d", gbat[0], gbat[1]); } offset = 18 + gbat_bytes; /* Check for T.88 amendment 2 */ if ((seg_flags >> 5) & 1) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment uses 12 adaptive template pixels (NYI)"); /* Table 34 */ params.MMR = seg_flags & 1; params.GBTEMPLATE = (seg_flags & 6) >> 1; params.TPGDON = (seg_flags & 8) >> 3; params.USESKIP = 0; memcpy(params.gbat, gbat, gbat_bytes); if (page->height == 0xffffffff && page->striped && page->stripe_size > 0) { if (rsi.y >= page->end_row + page->stripe_size) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "ignoring %u x %u region at (%u, %u) outside of stripe at row %u covering %u rows, on page of height %u", rsi.width, rsi.height, rsi.x, rsi.y, page->end_row, page->stripe_size, page->image->height); return 0; } if (height > page->end_row + page->stripe_size) { height = page->end_row + page->stripe_size; } } else { if (rsi.y >= page->height) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "ignoring %u x %u region at (%u, %u) outside of page of height %u", rsi.width, rsi.height, rsi.x, rsi.y, page->height); return 0; } if (height > page->height - rsi .y) { height = page->height - rsi.y; } } if (height == 0) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "nothing remains of region, ignoring"); return 0; } image = jbig2_image_new(ctx, rsi.width, height); if (image == NULL) return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate generic image"); jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "allocated %d x %d image buffer for region decode results", rsi.width, height); if (params.MMR) { code = jbig2_decode_generic_mmr(ctx, segment, ¶ms, segment_data + offset, segment->data_length - offset, image); if (code < 0) { code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode MMR-coded generic region"); goto cleanup; } } else { int stats_size = jbig2_generic_stats_size(ctx, params.GBTEMPLATE); GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size); if (GB_stats == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate arithmetic decoder states when handling immediate generic region"); goto cleanup; } memset(GB_stats, 0, stats_size); ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset); if (ws == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocated word stream when handling immediate generic region"); goto cleanup; } as = jbig2_arith_new(ctx, ws); if (as == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate arithmetic coding state when handling immediate generic region"); goto cleanup; } code = jbig2_decode_generic_region(ctx, segment, ¶ms, as, image, GB_stats); if (code < 0) { code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode immediate generic region"); goto cleanup; } } code = jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, rsi.x, rsi.y, rsi.op); if (code < 0) code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to add result to page"); cleanup: jbig2_free(ctx->allocator, as); jbig2_word_stream_buf_free(ctx, ws); jbig2_free(ctx->allocator, GB_stats); jbig2_image_release(ctx, image); return code; }