shithub: jbig2

Download patch

ref: be7e85301ae58f21e9bbc60eb58ae58fc1217465
parent: e74ec354988c96bbc2320b0594a5b3eeb39ef1d3
author: Sebastian Rasmussen <sebras@gmail.com>
date: Tue Jul 3 16:02:04 EDT 2018

jbig2dec: Implement support for generic region pixel skipping.

--- a/jbig2_generic.c
+++ b/jbig2_generic.c
@@ -148,6 +148,10 @@
 
     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;
@@ -194,6 +198,10 @@
 
     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;
@@ -303,6 +311,10 @@
 
     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;
@@ -469,6 +481,10 @@
 
     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;
@@ -529,6 +545,10 @@
             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;
@@ -581,6 +601,10 @@
             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;
@@ -630,6 +654,10 @@
             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;
@@ -676,6 +704,10 @@
             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;
@@ -750,23 +782,23 @@
         return jbig2_decode_generic_region_TPGDON(ctx, segment, params, as, image, GB_stats);
 
     if (!params->MMR && params->GBTEMPLATE == 0) {
-        if (gbat[0] == +3 && gbat[1] == -1 && gbat[2] == -3 && gbat[3] == -1 && gbat[4] == +2 && gbat[5] == -2 && gbat[6] == -2 && gbat[7] == -2)
+        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 (gbat[0] == +3 && gbat[1] == -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 (gbat[0] == 2 && gbat[1] == -1)
+        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 (gbat[0] == 2 && gbat[1] == -1)
+        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);
--- a/jbig2_generic.h
+++ b/jbig2_generic.h
@@ -32,7 +32,7 @@
     int GBTEMPLATE;
     bool TPGDON;
     bool USESKIP;
-    /* SKIP */
+    Jbig2Image *SKIP;
     int8_t gbat[8];
 } Jbig2GenericRegionParams;
 
--- a/jbig2_halftone.c
+++ b/jbig2_halftone.c
@@ -298,6 +298,7 @@
     rparams.GBTEMPLATE = GSTEMPLATE;
     rparams.TPGDON = 0;
     rparams.USESKIP = GSUSESKIP;
+    rparams.SKIP = GSKIP;
     rparams.gbat[0] = (GSTEMPLATE <= 1 ? 3 : 2);
     rparams.gbat[1] = -1;
     rparams.gbat[2] = -3;
@@ -453,33 +454,47 @@
 {
     uint32_t HBPP;
     uint32_t HNUMPATS;
-    uint8_t **GI;
+    uint8_t **GI = NULL;
     Jbig2Image *HSKIP = NULL;
     Jbig2PatternDict *HPATS;
     uint32_t i;
-    uint32_t mg, ng;
+    int32_t mg, ng;
     int32_t x, y;
     uint8_t gray_val;
-    int code;
+    int code = 0;
 
+    /* We need the patterns used in this region, get them from the referred pattern dictionary */
+    HPATS = jbig2_decode_ht_region_get_hpats(ctx, segment);
+    if (!HPATS) {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "no pattern dictionary found, skipping halftone image");
+        goto cleanup;
+    }
+
     /* 6.6.5 point 1. Fill bitmap with HDEFPIXEL */
     memset(image->data, params->HDEFPIXEL, image->stride * image->height);
 
-    /* 6.6.5 point 2. compute HSKIP */
+    /* 6.6.5 point 2. compute HSKIP according to 6.6.5.1 */
     if (params->HENABLESKIP == 1) {
-        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unhandled option HENABLESKIP (NYI)");
-    }
+        HSKIP = jbig2_image_new(ctx, params->HGW, params->HGH);
+        if (HSKIP == NULL)
+            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate skip image");
 
-    /* 6.6.5 point 3. set HBPP to ceil(log2(HNUMPATS)):
-     * we need the number of patterns used in this region (HNUMPATS)
-     * get it from referred pattern dictionary */
+        for (mg = 0; mg < params->HGH; ++mg) {
+            for (ng = 0; ng < params->HGW; ++ng) {
+                x = (params->HGX + mg * (int32_t) params->HRY + ng * (int32_t) params->HRX) >> 8;
+                y = (params->HGY + mg * (int32_t) params->HRX - ng * (int32_t) params->HRY) >> 8;
 
-    HPATS = jbig2_decode_ht_region_get_hpats(ctx, segment);
-    if (!HPATS)
-        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "no pattern dictionary found, skipping halftone image");
-    HNUMPATS = HPATS->n_patterns;
+                if (x + HPATS->HPW <= 0 || x >= (int32_t) image->width || y + HPATS->HPH <= 0 || y >= (int32_t) image->height) {
+                    jbig2_image_set_pixel(HSKIP, ng, mg, 1);
+                } else {
+                    jbig2_image_set_pixel(HSKIP, ng, mg, 0);
+                }
+            }
+        }
+    }
 
-    /* calculate ceil(log2(HNUMPATS)) */
+    /* 6.6.5 point 3. set HBPP to ceil(log2(HNUMPATS)): */
+    HNUMPATS = HPATS->n_patterns;
     HBPP = 0;
     while (HNUMPATS > (1U << ++HBPP));
 
@@ -486,35 +501,42 @@
     /* 6.6.5 point 4. decode gray-scale image as mentioned in annex C */
     GI = jbig2_decode_gray_scale_image(ctx, segment, data, size,
                                        params->HMMR, params->HGW, params->HGH, HBPP, params->HENABLESKIP, HSKIP, params->HTEMPLATE, GB_stats);
-    if (!GI)
-        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to acquire gray-scale image, skipping halftone image");
+    if (!GI) {
+        code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to acquire gray-scale image, skipping halftone image");
+        goto cleanup;
+    }
 
     /* 6.6.5 point 5. place patterns with procedure mentioned in 6.6.5.2 */
     for (mg = 0; mg < params->HGH; ++mg) {
         for (ng = 0; ng < params->HGW; ++ng) {
-            x = (params->HGX + mg * params->HRY + ng * params->HRX) >> 8;
-            y = (params->HGY + mg * params->HRX - ng * params->HRY) >> 8;
+            x = (params->HGX + mg * (int32_t) params->HRY + ng * (int32_t) params->HRX) >> 8;
+            y = (params->HGY + mg * (int32_t) params->HRX - ng * (int32_t) params->HRY) >> 8;
 
             /* prevent pattern index >= HNUMPATS */
             gray_val = GI[ng][mg];
             if (gray_val >= HNUMPATS) {
-                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "gray-scale image uses value %d which larger than pattern dictionary", gray_val);
+                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "gray-scale index %d out of range, using largest index", gray_val);
                 /* use highest available pattern */
                 gray_val = HNUMPATS - 1;
             }
             code = jbig2_image_compose(ctx, image, HPATS->patterns[gray_val], x, y, params->op);
-            if (code < 0)
-                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to compose pattern with gray-scale image");
+            if (code < 0) {
+                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to compose pattern with gray-scale image");
+                goto cleanup;
+            }
         }
     }
 
-    /* free GI */
-    for (i = 0; i < params->HGW; ++i) {
-        jbig2_free(ctx->allocator, GI[i]);
+cleanup:
+    if (GI) {
+        for (i = 0; i < params->HGW; ++i) {
+            jbig2_free(ctx->allocator, GI[i]);
+        }
     }
     jbig2_free(ctx->allocator, GI);
+    jbig2_image_release(ctx, HSKIP);
 
-    return 0;
+    return code;
 }
 
 /**