pdf.js/src/core/jbig2.js

2573 lines
69 KiB
JavaScript
Raw Normal View History

2012-09-01 07:48:21 +09:00
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2012-06-17 05:15:42 +09:00
import { BaseException, shadow } from "../shared/util.js";
import { log2, readInt8, readUint16, readUint32 } from "./core_utils.js";
import { ArithmeticDecoder } from "./arithmetic_decoder.js";
import { CCITTFaxDecoder } from "./ccitt.js";
class Jbig2Error extends BaseException {
constructor(msg) {
super(`JBIG2 error: ${msg}`);
2017-06-29 05:51:31 +09:00
}
}
2017-06-29 05:51:31 +09:00
// Utility data structures
class ContextCache {
getContexts(id) {
if (id in this) {
return this[id];
}
return (this[id] = new Int8Array(1 << 16));
}
}
class DecodingContext {
constructor(data, start, end) {
this.data = data;
this.start = start;
this.end = end;
}
get decoder() {
const decoder = new ArithmeticDecoder(this.data, this.start, this.end);
return shadow(this, "decoder", decoder);
}
get contextCache() {
const cache = new ContextCache();
return shadow(this, "contextCache", cache);
}
}
// Annex A. Arithmetic Integer Decoding Procedure
// A.2 Procedure for decoding values
function decodeInteger(contextCache, procedure, decoder) {
const contexts = contextCache.getContexts(procedure);
let prev = 1;
function readBits(length) {
let v = 0;
for (let i = 0; i < length; i++) {
const bit = decoder.readBit(contexts, prev);
prev = prev < 256 ? (prev << 1) | bit : (((prev << 1) | bit) & 511) | 256;
v = (v << 1) | bit;
}
return v >>> 0;
}
2014-05-11 01:03:54 +09:00
const sign = readBits(1);
// prettier-ignore
/* eslint-disable no-nested-ternary */
const value = readBits(1) ?
2014-05-11 01:03:54 +09:00
(readBits(1) ?
(readBits(1) ?
(readBits(1) ?
(readBits(1) ?
(readBits(32) + 4436) :
readBits(12) + 340) :
readBits(8) + 84) :
readBits(6) + 20) :
readBits(4) + 4) :
readBits(2);
/* eslint-enable no-nested-ternary */
if (sign === 0) {
return value;
} else if (value > 0) {
return -value;
}
return null;
}
// A.3 The IAID decoding procedure
function decodeIAID(contextCache, decoder, codeLength) {
const contexts = contextCache.getContexts("IAID");
let prev = 1;
for (let i = 0; i < codeLength; i++) {
const bit = decoder.readBit(contexts, prev);
prev = (prev << 1) | bit;
}
if (codeLength < 31) {
return prev & ((1 << codeLength) - 1);
}
return prev & 0x7fffffff;
}
// 7.3 Segment types
const SegmentTypes = [
"SymbolDictionary",
null,
null,
null,
"IntermediateTextRegion",
null,
"ImmediateTextRegion",
"ImmediateLosslessTextRegion",
null,
null,
null,
null,
null,
null,
null,
null,
"PatternDictionary",
null,
null,
null,
"IntermediateHalftoneRegion",
null,
"ImmediateHalftoneRegion",
"ImmediateLosslessHalftoneRegion",
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
"IntermediateGenericRegion",
null,
"ImmediateGenericRegion",
"ImmediateLosslessGenericRegion",
"IntermediateGenericRefinementRegion",
null,
"ImmediateGenericRefinementRegion",
"ImmediateLosslessGenericRefinementRegion",
null,
null,
null,
null,
"PageInformation",
"EndOfPage",
"EndOfStripe",
"EndOfFile",
"Profiles",
"Tables",
null,
null,
null,
null,
null,
null,
null,
null,
"Extension",
];
const CodingTemplates = [
[
{ x: -1, y: -2 },
{ x: 0, y: -2 },
{ x: 1, y: -2 },
{ x: -2, y: -1 },
{ x: -1, y: -1 },
{ x: 0, y: -1 },
{ x: 1, y: -1 },
{ x: 2, y: -1 },
{ x: -4, y: 0 },
{ x: -3, y: 0 },
{ x: -2, y: 0 },
{ x: -1, y: 0 },
],
[
{ x: -1, y: -2 },
{ x: 0, y: -2 },
{ x: 1, y: -2 },
{ x: 2, y: -2 },
{ x: -2, y: -1 },
{ x: -1, y: -1 },
{ x: 0, y: -1 },
{ x: 1, y: -1 },
{ x: 2, y: -1 },
{ x: -3, y: 0 },
{ x: -2, y: 0 },
{ x: -1, y: 0 },
],
[
{ x: -1, y: -2 },
{ x: 0, y: -2 },
{ x: 1, y: -2 },
{ x: -2, y: -1 },
{ x: -1, y: -1 },
{ x: 0, y: -1 },
{ x: 1, y: -1 },
{ x: -2, y: 0 },
{ x: -1, y: 0 },
],
[
{ x: -3, y: -1 },
{ x: -2, y: -1 },
{ x: -1, y: -1 },
{ x: 0, y: -1 },
{ x: 1, y: -1 },
{ x: -4, y: 0 },
{ x: -3, y: 0 },
{ x: -2, y: 0 },
{ x: -1, y: 0 },
],
];
const RefinementTemplates = [
{
coding: [
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
{ x: 0, y: -1 },
{ x: 1, y: -1 },
{ x: -1, y: 0 },
],
reference: [
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
{ x: 0, y: -1 },
{ x: 1, y: -1 },
{ x: -1, y: 0 },
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: -1, y: 1 },
{ x: 0, y: 1 },
{ x: 1, y: 1 },
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
],
},
{
coding: [
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
{ x: -1, y: -1 },
{ x: 0, y: -1 },
{ x: 1, y: -1 },
{ x: -1, y: 0 },
],
reference: [
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
{ x: 0, y: -1 },
{ x: -1, y: 0 },
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 0, y: 1 },
{ x: 1, y: 1 },
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
],
},
];
// See 6.2.5.7 Decoding the bitmap.
const ReusedContexts = [
0x9b25, // 10011 0110010 0101
0x0795, // 0011 110010 101
0x00e5, // 001 11001 01
0x0195, // 011001 0101
];
const RefinementReusedContexts = [
0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference)
0x0008, // '0000' + '001000'
];
function decodeBitmapTemplate0(width, height, decodingContext) {
const decoder = decodingContext.decoder;
const contexts = decodingContext.contextCache.getContexts("GB");
const bitmap = [];
let contextLabel, i, j, pixel, row, row1, row2;
// ...ooooo....
// ..ooooooo... Context template for current pixel (X)
// .ooooX...... (concatenate values of 'o'-pixels to get contextLabel)
const OLD_PIXEL_MASK = 0x7bf7; // 01111 0111111 0111
for (i = 0; i < height; i++) {
row = bitmap[i] = new Uint8Array(width);
row1 = i < 1 ? row : bitmap[i - 1];
row2 = i < 2 ? row : bitmap[i - 2];
// At the beginning of each row:
// Fill contextLabel with pixels that are above/right of (X)
contextLabel =
(row2[0] << 13) |
(row2[1] << 12) |
(row2[2] << 11) |
(row1[0] << 7) |
(row1[1] << 6) |
(row1[2] << 5) |
(row1[3] << 4);
for (j = 0; j < width; j++) {
row[j] = pixel = decoder.readBit(contexts, contextLabel);
// At each pixel: Clear contextLabel pixels that are shifted
// out of the context, then add new ones.
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
contextLabel =
((contextLabel & OLD_PIXEL_MASK) << 1) |
(j + 3 < width ? row2[j + 3] << 11 : 0) |
(j + 4 < width ? row1[j + 4] << 4 : 0) |
pixel;
2014-08-01 22:29:03 +09:00
}
}
return bitmap;
}
2014-08-01 22:29:03 +09:00
// 6.2 Generic Region Decoding Procedure
function decodeBitmap(
mmr,
width,
height,
templateIndex,
prediction,
skip,
at,
decodingContext
) {
if (mmr) {
const input = new Reader(
decodingContext.data,
decodingContext.start,
decodingContext.end
);
return decodeMMRBitmap(input, width, height, false);
2014-08-01 22:29:03 +09:00
}
// Use optimized version for the most common case
if (
templateIndex === 0 &&
!skip &&
!prediction &&
at.length === 4 &&
at[0].x === 3 &&
at[0].y === -1 &&
at[1].x === -3 &&
at[1].y === -1 &&
at[2].x === 2 &&
at[2].y === -2 &&
at[3].x === -2 &&
at[3].y === -2
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
) {
return decodeBitmapTemplate0(width, height, decodingContext);
}
2012-06-17 05:15:42 +09:00
const useskip = !!skip;
const template = CodingTemplates[templateIndex].concat(at);
// Sorting is non-standard, and it is not required. But sorting increases
// the number of template bits that can be reused from the previous
// contextLabel in the main loop.
template.sort(function (a, b) {
return a.y - b.y || a.x - b.x;
});
const templateLength = template.length;
const templateX = new Int8Array(templateLength);
const templateY = new Int8Array(templateLength);
const changingTemplateEntries = [];
let reuseMask = 0,
minX = 0,
maxX = 0,
minY = 0;
let c, k;
for (k = 0; k < templateLength; k++) {
templateX[k] = template[k].x;
templateY[k] = template[k].y;
minX = Math.min(minX, template[k].x);
maxX = Math.max(maxX, template[k].x);
minY = Math.min(minY, template[k].y);
// Check if the template pixel appears in two consecutive context labels,
// so it can be reused. Otherwise, we add it to the list of changing
// template entries.
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
if (
k < templateLength - 1 &&
template[k].y === template[k + 1].y &&
template[k].x === template[k + 1].x - 1
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
) {
reuseMask |= 1 << (templateLength - 1 - k);
} else {
changingTemplateEntries.push(k);
2014-08-01 22:29:03 +09:00
}
}
const changingEntriesLength = changingTemplateEntries.length;
const changingTemplateX = new Int8Array(changingEntriesLength);
const changingTemplateY = new Int8Array(changingEntriesLength);
const changingTemplateBit = new Uint16Array(changingEntriesLength);
for (c = 0; c < changingEntriesLength; c++) {
k = changingTemplateEntries[c];
changingTemplateX[c] = template[k].x;
changingTemplateY[c] = template[k].y;
changingTemplateBit[c] = 1 << (templateLength - 1 - k);
}
2014-08-01 22:29:03 +09:00
// Get the safe bounding box edges from the width, height, minX, maxX, minY
const sbb_left = -minX;
const sbb_top = -minY;
const sbb_right = width - maxX;
const pseudoPixelContext = ReusedContexts[templateIndex];
let row = new Uint8Array(width);
const bitmap = [];
const decoder = decodingContext.decoder;
const contexts = decodingContext.contextCache.getContexts("GB");
let ltp = 0,
j,
i0,
j0,
contextLabel = 0,
bit,
shift;
for (let i = 0; i < height; i++) {
if (prediction) {
const sltp = decoder.readBit(contexts, pseudoPixelContext);
ltp ^= sltp;
if (ltp) {
bitmap.push(row); // duplicate previous row
continue;
2014-02-28 18:53:09 +09:00
}
2012-06-17 05:15:42 +09:00
}
row = new Uint8Array(row);
bitmap.push(row);
for (j = 0; j < width; j++) {
if (useskip && skip[i][j]) {
row[j] = 0;
continue;
2012-06-17 05:15:42 +09:00
}
// Are we in the middle of a scanline, so we can reuse contextLabel
// bits?
if (j >= sbb_left && j < sbb_right && i >= sbb_top) {
// If yes, we can just shift the bits that are reusable and only
// fetch the remaining ones.
contextLabel = (contextLabel << 1) & reuseMask;
for (k = 0; k < changingEntriesLength; k++) {
i0 = i + changingTemplateY[k];
j0 = j + changingTemplateX[k];
bit = bitmap[i0][j0];
if (bit) {
bit = changingTemplateBit[k];
contextLabel |= bit;
2014-02-28 18:53:09 +09:00
}
}
} else {
// compute the contextLabel from scratch
contextLabel = 0;
shift = templateLength - 1;
for (k = 0; k < templateLength; k++, shift--) {
j0 = j + templateX[k];
if (j0 >= 0 && j0 < width) {
i0 = i + templateY[k];
if (i0 >= 0) {
bit = bitmap[i0][j0];
if (bit) {
contextLabel |= bit << shift;
}
2014-02-28 18:53:09 +09:00
}
}
2012-06-17 05:15:42 +09:00
}
}
const pixel = decoder.readBit(contexts, contextLabel);
row[j] = pixel;
2012-06-17 05:15:42 +09:00
}
}
return bitmap;
}
// 6.3.2 Generic Refinement Region Decoding Procedure
function decodeRefinement(
width,
height,
templateIndex,
referenceBitmap,
offsetX,
offsetY,
prediction,
at,
decodingContext
) {
let codingTemplate = RefinementTemplates[templateIndex].coding;
if (templateIndex === 0) {
codingTemplate = codingTemplate.concat([at[0]]);
}
const codingTemplateLength = codingTemplate.length;
const codingTemplateX = new Int32Array(codingTemplateLength);
const codingTemplateY = new Int32Array(codingTemplateLength);
let k;
for (k = 0; k < codingTemplateLength; k++) {
codingTemplateX[k] = codingTemplate[k].x;
codingTemplateY[k] = codingTemplate[k].y;
}
let referenceTemplate = RefinementTemplates[templateIndex].reference;
if (templateIndex === 0) {
referenceTemplate = referenceTemplate.concat([at[1]]);
}
const referenceTemplateLength = referenceTemplate.length;
const referenceTemplateX = new Int32Array(referenceTemplateLength);
const referenceTemplateY = new Int32Array(referenceTemplateLength);
for (k = 0; k < referenceTemplateLength; k++) {
referenceTemplateX[k] = referenceTemplate[k].x;
referenceTemplateY[k] = referenceTemplate[k].y;
}
const referenceWidth = referenceBitmap[0].length;
const referenceHeight = referenceBitmap.length;
const pseudoPixelContext = RefinementReusedContexts[templateIndex];
const bitmap = [];
const decoder = decodingContext.decoder;
const contexts = decodingContext.contextCache.getContexts("GR");
let ltp = 0;
for (let i = 0; i < height; i++) {
if (prediction) {
const sltp = decoder.readBit(contexts, pseudoPixelContext);
ltp ^= sltp;
if (ltp) {
throw new Jbig2Error("prediction is not supported");
}
2012-06-22 07:26:24 +09:00
}
const row = new Uint8Array(width);
bitmap.push(row);
for (let j = 0; j < width; j++) {
let i0, j0;
let contextLabel = 0;
for (k = 0; k < codingTemplateLength; k++) {
i0 = i + codingTemplateY[k];
j0 = j + codingTemplateX[k];
if (i0 < 0 || j0 < 0 || j0 >= width) {
contextLabel <<= 1; // out of bound pixel
} else {
contextLabel = (contextLabel << 1) | bitmap[i0][j0];
}
2012-06-22 07:26:24 +09:00
}
for (k = 0; k < referenceTemplateLength; k++) {
i0 = i + referenceTemplateY[k] - offsetY;
j0 = j + referenceTemplateX[k] - offsetX;
if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || j0 >= referenceWidth) {
contextLabel <<= 1; // out of bound pixel
} else {
contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];
2012-06-22 07:26:24 +09:00
}
}
const pixel = decoder.readBit(contexts, contextLabel);
row[j] = pixel;
2012-06-22 07:26:24 +09:00
}
}
return bitmap;
}
// 6.5.5 Decoding the symbol dictionary
function decodeSymbolDictionary(
huffman,
refinement,
symbols,
numberOfNewSymbols,
numberOfExportedSymbols,
huffmanTables,
templateIndex,
at,
refinementTemplateIndex,
refinementAt,
decodingContext,
huffmanInput
) {
if (huffman && refinement) {
throw new Jbig2Error("symbol refinement with Huffman is not supported");
}
const newSymbols = [];
let currentHeight = 0;
let symbolCodeLength = log2(symbols.length + numberOfNewSymbols);
const decoder = decodingContext.decoder;
const contextCache = decodingContext.contextCache;
let tableB1, symbolWidths;
if (huffman) {
tableB1 = getStandardTable(1); // standard table B.1
symbolWidths = [];
symbolCodeLength = Math.max(symbolCodeLength, 1); // 6.5.8.2.3
}
while (newSymbols.length < numberOfNewSymbols) {
const deltaHeight = huffman
? huffmanTables.tableDeltaHeight.decode(huffmanInput)
: decodeInteger(contextCache, "IADH", decoder); // 6.5.6
currentHeight += deltaHeight;
let currentWidth = 0,
totalWidth = 0;
const firstSymbol = huffman ? symbolWidths.length : 0;
while (true) {
const deltaWidth = huffman
? huffmanTables.tableDeltaWidth.decode(huffmanInput)
: decodeInteger(contextCache, "IADW", decoder); // 6.5.7
if (deltaWidth === null) {
break; // OOB
}
currentWidth += deltaWidth;
totalWidth += currentWidth;
let bitmap;
if (refinement) {
// 6.5.8.2 Refinement/aggregate-coded symbol bitmap
const numberOfInstances = decodeInteger(contextCache, "IAAI", decoder);
if (numberOfInstances > 1) {
bitmap = decodeTextRegion(
huffman,
refinement,
currentWidth,
currentHeight,
0,
numberOfInstances,
1, // strip size
symbols.concat(newSymbols),
symbolCodeLength,
0, // transposed
0, // ds offset
1, // top left 7.4.3.1.1
0, // OR operator
huffmanTables,
refinementTemplateIndex,
refinementAt,
decodingContext,
0,
huffmanInput
);
2012-06-22 07:26:24 +09:00
} else {
const symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
const rdx = decodeInteger(contextCache, "IARDX", decoder); // 6.4.11.3
const rdy = decodeInteger(contextCache, "IARDY", decoder); // 6.4.11.4
const symbol =
symbolId < symbols.length
? symbols[symbolId]
: newSymbols[symbolId - symbols.length];
bitmap = decodeRefinement(
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
currentWidth,
currentHeight,
refinementTemplateIndex,
symbol,
rdx,
rdy,
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
false,
refinementAt,
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
decodingContext
);
2018-01-24 00:04:07 +09:00
}
newSymbols.push(bitmap);
} else if (huffman) {
// Store only symbol width and decode a collective bitmap when the
// height class is done.
symbolWidths.push(currentWidth);
} else {
// 6.5.8.1 Direct-coded symbol bitmap
bitmap = decodeBitmap(
false,
currentWidth,
currentHeight,
templateIndex,
false,
null,
at,
decodingContext
);
newSymbols.push(bitmap);
2018-01-24 00:04:07 +09:00
}
}
if (huffman && !refinement) {
// 6.5.9 Height class collective bitmap
const bitmapSize = huffmanTables.tableBitmapSize.decode(huffmanInput);
huffmanInput.byteAlign();
let collectiveBitmap;
if (bitmapSize === 0) {
// Uncompressed collective bitmap
collectiveBitmap = readUncompressedBitmap(
huffmanInput,
totalWidth,
currentHeight
);
} else {
// MMR collective bitmap
const originalEnd = huffmanInput.end;
const bitmapEnd = huffmanInput.position + bitmapSize;
huffmanInput.end = bitmapEnd;
collectiveBitmap = decodeMMRBitmap(
huffmanInput,
totalWidth,
currentHeight,
false
);
huffmanInput.end = originalEnd;
huffmanInput.position = bitmapEnd;
}
const numberOfSymbolsDecoded = symbolWidths.length;
if (firstSymbol === numberOfSymbolsDecoded - 1) {
// collectiveBitmap is a single symbol.
newSymbols.push(collectiveBitmap);
} else {
// Divide collectiveBitmap into symbols.
let i,
y,
xMin = 0,
xMax,
bitmapWidth,
symbolBitmap;
for (i = firstSymbol; i < numberOfSymbolsDecoded; i++) {
bitmapWidth = symbolWidths[i];
xMax = xMin + bitmapWidth;
symbolBitmap = [];
for (y = 0; y < currentHeight; y++) {
symbolBitmap.push(collectiveBitmap[y].subarray(xMin, xMax));
2018-01-24 00:04:07 +09:00
}
newSymbols.push(symbolBitmap);
xMin = xMax;
2012-06-22 07:26:24 +09:00
}
}
}
}
2018-01-24 00:04:07 +09:00
// 6.5.10 Exported symbols
const exportedSymbols = [],
flags = [];
let currentFlag = false,
i,
ii;
const totalSymbolsLength = symbols.length + numberOfNewSymbols;
while (flags.length < totalSymbolsLength) {
let runLength = huffman
? tableB1.decode(huffmanInput)
: decodeInteger(contextCache, "IAEX", decoder);
while (runLength--) {
flags.push(currentFlag);
}
currentFlag = !currentFlag;
}
for (i = 0, ii = symbols.length; i < ii; i++) {
if (flags[i]) {
exportedSymbols.push(symbols[i]);
}
}
for (let j = 0; j < numberOfNewSymbols; i++, j++) {
if (flags[i]) {
exportedSymbols.push(newSymbols[j]);
}
}
return exportedSymbols;
}
function decodeTextRegion(
huffman,
refinement,
width,
height,
defaultPixelValue,
numberOfSymbolInstances,
stripSize,
inputSymbols,
symbolCodeLength,
transposed,
dsOffset,
referenceCorner,
combinationOperator,
huffmanTables,
refinementTemplateIndex,
refinementAt,
decodingContext,
logStripSize,
huffmanInput
) {
if (huffman && refinement) {
throw new Jbig2Error("refinement with Huffman is not supported");
}
// Prepare bitmap
const bitmap = [];
let i, row;
for (i = 0; i < height; i++) {
row = new Uint8Array(width);
if (defaultPixelValue) {
for (let j = 0; j < width; j++) {
row[j] = defaultPixelValue;
}
}
bitmap.push(row);
}
const decoder = decodingContext.decoder;
const contextCache = decodingContext.contextCache;
let stripT = huffman
? -huffmanTables.tableDeltaT.decode(huffmanInput)
: -decodeInteger(contextCache, "IADT", decoder); // 6.4.6
let firstS = 0;
i = 0;
while (i < numberOfSymbolInstances) {
const deltaT = huffman
? huffmanTables.tableDeltaT.decode(huffmanInput)
: decodeInteger(contextCache, "IADT", decoder); // 6.4.6
stripT += deltaT;
const deltaFirstS = huffman
? huffmanTables.tableFirstS.decode(huffmanInput)
: decodeInteger(contextCache, "IAFS", decoder); // 6.4.7
firstS += deltaFirstS;
let currentS = firstS;
do {
let currentT = 0; // 6.4.9
if (stripSize > 1) {
currentT = huffman
? huffmanInput.readBits(logStripSize)
: decodeInteger(contextCache, "IAIT", decoder);
}
const t = stripSize * stripT + currentT;
const symbolId = huffman
? huffmanTables.symbolIDTable.decode(huffmanInput)
: decodeIAID(contextCache, decoder, symbolCodeLength);
const applyRefinement =
refinement &&
(huffman
? huffmanInput.readBit()
: decodeInteger(contextCache, "IARI", decoder));
let symbolBitmap = inputSymbols[symbolId];
let symbolWidth = symbolBitmap[0].length;
let symbolHeight = symbolBitmap.length;
if (applyRefinement) {
const rdw = decodeInteger(contextCache, "IARDW", decoder); // 6.4.11.1
const rdh = decodeInteger(contextCache, "IARDH", decoder); // 6.4.11.2
const rdx = decodeInteger(contextCache, "IARDX", decoder); // 6.4.11.3
const rdy = decodeInteger(contextCache, "IARDY", decoder); // 6.4.11.4
symbolWidth += rdw;
symbolHeight += rdh;
symbolBitmap = decodeRefinement(
symbolWidth,
symbolHeight,
refinementTemplateIndex,
symbolBitmap,
(rdw >> 1) + rdx,
(rdh >> 1) + rdy,
false,
refinementAt,
decodingContext
);
}
const offsetT = t - (referenceCorner & 1 ? 0 : symbolHeight - 1);
const offsetS = currentS - (referenceCorner & 2 ? symbolWidth - 1 : 0);
let s2, t2, symbolRow;
if (transposed) {
// Place Symbol Bitmap from T1,S1
for (s2 = 0; s2 < symbolHeight; s2++) {
row = bitmap[offsetS + s2];
if (!row) {
continue;
}
symbolRow = symbolBitmap[s2];
// To ignore Parts of Symbol bitmap which goes
// outside bitmap region
const maxWidth = Math.min(width - offsetT, symbolWidth);
switch (combinationOperator) {
case 0: // OR
for (t2 = 0; t2 < maxWidth; t2++) {
row[offsetT + t2] |= symbolRow[t2];
}
break;
case 2: // XOR
for (t2 = 0; t2 < maxWidth; t2++) {
row[offsetT + t2] ^= symbolRow[t2];
}
break;
default:
throw new Jbig2Error(
`operator ${combinationOperator} is not supported`
);
2012-06-22 07:26:24 +09:00
}
}
currentS += symbolHeight - 1;
} else {
for (t2 = 0; t2 < symbolHeight; t2++) {
row = bitmap[offsetT + t2];
if (!row) {
continue;
}
symbolRow = symbolBitmap[t2];
switch (combinationOperator) {
case 0: // OR
for (s2 = 0; s2 < symbolWidth; s2++) {
row[offsetS + s2] |= symbolRow[s2];
}
break;
case 2: // XOR
for (s2 = 0; s2 < symbolWidth; s2++) {
row[offsetS + s2] ^= symbolRow[s2];
}
break;
default:
throw new Jbig2Error(
`operator ${combinationOperator} is not supported`
);
}
}
currentS += symbolWidth - 1;
}
i++;
const deltaS = huffman
? huffmanTables.tableDeltaS.decode(huffmanInput)
: decodeInteger(contextCache, "IADS", decoder); // 6.4.8
if (deltaS === null) {
break; // OOB
}
currentS += deltaS + dsOffset;
} while (true);
}
return bitmap;
}
function decodePatternDictionary(
mmr,
patternWidth,
patternHeight,
maxPatternIndex,
template,
decodingContext
) {
const at = [];
if (!mmr) {
at.push({
x: -patternWidth,
y: 0,
});
if (template === 0) {
at.push(
{
x: -3,
y: -1,
},
{
x: 2,
y: -2,
},
{
x: -2,
y: -2,
}
);
}
}
const collectiveWidth = (maxPatternIndex + 1) * patternWidth;
const collectiveBitmap = decodeBitmap(
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
mmr,
collectiveWidth,
patternHeight,
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
template,
false,
null,
at,
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
decodingContext
);
// Divide collective bitmap into patterns.
const patterns = [];
for (let i = 0; i <= maxPatternIndex; i++) {
const patternBitmap = [];
const xMin = patternWidth * i;
const xMax = xMin + patternWidth;
for (let y = 0; y < patternHeight; y++) {
patternBitmap.push(collectiveBitmap[y].subarray(xMin, xMax));
}
patterns.push(patternBitmap);
}
return patterns;
}
function decodeHalftoneRegion(
mmr,
patterns,
template,
regionWidth,
regionHeight,
defaultPixelValue,
enableSkip,
combinationOperator,
gridWidth,
gridHeight,
gridOffsetX,
gridOffsetY,
gridVectorX,
gridVectorY,
decodingContext
) {
const skip = null;
if (enableSkip) {
throw new Jbig2Error("skip is not supported");
}
if (combinationOperator !== 0) {
throw new Jbig2Error(
`operator "${combinationOperator}" is not supported in halftone region`
);
}
// Prepare bitmap.
const regionBitmap = [];
let i, j, row;
for (i = 0; i < regionHeight; i++) {
row = new Uint8Array(regionWidth);
if (defaultPixelValue) {
for (j = 0; j < regionWidth; j++) {
row[j] = defaultPixelValue;
}
}
regionBitmap.push(row);
}
const numberOfPatterns = patterns.length;
const pattern0 = patterns[0];
const patternWidth = pattern0[0].length,
patternHeight = pattern0.length;
const bitsPerValue = log2(numberOfPatterns);
const at = [];
if (!mmr) {
at.push({
x: template <= 1 ? 3 : 2,
y: -1,
});
if (template === 0) {
at.push(
{
x: -3,
y: -1,
},
{
x: 2,
y: -2,
},
{
x: -2,
y: -2,
}
);
}
}
// Annex C. Gray-scale Image Decoding Procedure.
const grayScaleBitPlanes = [];
let mmrInput, bitmap;
if (mmr) {
// MMR bit planes are in one continuous stream. Only EOFB codes indicate
// the end of each bitmap, so EOFBs must be decoded.
mmrInput = new Reader(
decodingContext.data,
decodingContext.start,
decodingContext.end
);
}
for (i = bitsPerValue - 1; i >= 0; i--) {
2018-01-24 00:04:07 +09:00
if (mmr) {
bitmap = decodeMMRBitmap(mmrInput, gridWidth, gridHeight, true);
} else {
bitmap = decodeBitmap(
false,
gridWidth,
gridHeight,
template,
false,
skip,
at,
decodingContext
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
);
2018-01-24 00:04:07 +09:00
}
grayScaleBitPlanes[i] = bitmap;
}
// 6.6.5.2 Rendering the patterns.
let mg, ng, bit, patternIndex, patternBitmap, x, y, patternRow, regionRow;
for (mg = 0; mg < gridHeight; mg++) {
for (ng = 0; ng < gridWidth; ng++) {
bit = 0;
patternIndex = 0;
for (j = bitsPerValue - 1; j >= 0; j--) {
bit = grayScaleBitPlanes[j][mg][ng] ^ bit; // Gray decoding
patternIndex |= bit << j;
2018-01-24 00:04:07 +09:00
}
patternBitmap = patterns[patternIndex];
x = (gridOffsetX + mg * gridVectorY + ng * gridVectorX) >> 8;
y = (gridOffsetY + mg * gridVectorX - ng * gridVectorY) >> 8;
// Draw patternBitmap at (x, y).
if (
x >= 0 &&
x + patternWidth <= regionWidth &&
y >= 0 &&
y + patternHeight <= regionHeight
) {
for (i = 0; i < patternHeight; i++) {
regionRow = regionBitmap[y + i];
patternRow = patternBitmap[i];
for (j = 0; j < patternWidth; j++) {
regionRow[x + j] |= patternRow[j];
}
}
} else {
let regionX, regionY;
for (i = 0; i < patternHeight; i++) {
regionY = y + i;
if (regionY < 0 || regionY >= regionHeight) {
continue;
}
regionRow = regionBitmap[regionY];
patternRow = patternBitmap[i];
for (j = 0; j < patternWidth; j++) {
regionX = x + j;
if (regionX >= 0 && regionX < regionWidth) {
regionRow[regionX] |= patternRow[j];
}
}
}
}
}
}
return regionBitmap;
}
function readSegmentHeader(data, start) {
const segmentHeader = {};
segmentHeader.number = readUint32(data, start);
const flags = data[start + 4];
const segmentType = flags & 0x3f;
if (!SegmentTypes[segmentType]) {
throw new Jbig2Error("invalid segment type: " + segmentType);
}
segmentHeader.type = segmentType;
segmentHeader.typeName = SegmentTypes[segmentType];
segmentHeader.deferredNonRetain = !!(flags & 0x80);
const pageAssociationFieldSize = !!(flags & 0x40);
const referredFlags = data[start + 5];
let referredToCount = (referredFlags >> 5) & 7;
const retainBits = [referredFlags & 31];
let position = start + 6;
if (referredFlags === 7) {
referredToCount = readUint32(data, position - 1) & 0x1fffffff;
position += 3;
let bytes = (referredToCount + 7) >> 3;
retainBits[0] = data[position++];
while (--bytes > 0) {
retainBits.push(data[position++]);
}
} else if (referredFlags === 5 || referredFlags === 6) {
throw new Jbig2Error("invalid referred-to flags");
}
segmentHeader.retainBits = retainBits;
let referredToSegmentNumberSize = 4;
if (segmentHeader.number <= 256) {
referredToSegmentNumberSize = 1;
} else if (segmentHeader.number <= 65536) {
referredToSegmentNumberSize = 2;
}
const referredTo = [];
let i, ii;
for (i = 0; i < referredToCount; i++) {
let number;
if (referredToSegmentNumberSize === 1) {
number = data[position];
} else if (referredToSegmentNumberSize === 2) {
number = readUint16(data, position);
} else {
number = readUint32(data, position);
}
referredTo.push(number);
position += referredToSegmentNumberSize;
}
segmentHeader.referredTo = referredTo;
if (!pageAssociationFieldSize) {
segmentHeader.pageAssociation = data[position++];
} else {
segmentHeader.pageAssociation = readUint32(data, position);
position += 4;
}
segmentHeader.length = readUint32(data, position);
position += 4;
if (segmentHeader.length === 0xffffffff) {
// 7.2.7 Segment data length, unknown segment length
if (segmentType === 38) {
// ImmediateGenericRegion
const genericRegionInfo = readRegionSegmentInformation(data, position);
const genericRegionSegmentFlags =
data[position + RegionSegmentInformationFieldLength];
const genericRegionMmr = !!(genericRegionSegmentFlags & 1);
// searching for the segment end
const searchPatternLength = 6;
const searchPattern = new Uint8Array(searchPatternLength);
if (!genericRegionMmr) {
searchPattern[0] = 0xff;
searchPattern[1] = 0xac;
}
searchPattern[2] = (genericRegionInfo.height >>> 24) & 0xff;
searchPattern[3] = (genericRegionInfo.height >> 16) & 0xff;
searchPattern[4] = (genericRegionInfo.height >> 8) & 0xff;
searchPattern[5] = genericRegionInfo.height & 0xff;
for (i = position, ii = data.length; i < ii; i++) {
let j = 0;
while (j < searchPatternLength && searchPattern[j] === data[i + j]) {
j++;
}
if (j === searchPatternLength) {
segmentHeader.length = i + searchPatternLength;
break;
}
}
if (segmentHeader.length === 0xffffffff) {
throw new Jbig2Error("segment end was not found");
2012-06-17 05:15:42 +09:00
}
} else {
throw new Jbig2Error("invalid unknown segment length");
}
}
segmentHeader.headerEnd = position;
return segmentHeader;
}
function readSegments(header, data, start, end) {
const segments = [];
let position = start;
while (position < end) {
const segmentHeader = readSegmentHeader(data, position);
position = segmentHeader.headerEnd;
const segment = {
header: segmentHeader,
data,
};
if (!header.randomAccess) {
segment.start = position;
position += segmentHeader.length;
segment.end = position;
}
segments.push(segment);
if (segmentHeader.type === 51) {
break; // end of file is found
2012-06-17 05:15:42 +09:00
}
}
if (header.randomAccess) {
for (let i = 0, ii = segments.length; i < ii; i++) {
segments[i].start = position;
position += segments[i].header.length;
segments[i].end = position;
2012-06-17 05:15:42 +09:00
}
}
return segments;
}
// 7.4.1 Region segment information field
function readRegionSegmentInformation(data, start) {
return {
width: readUint32(data, start),
height: readUint32(data, start + 4),
x: readUint32(data, start + 8),
y: readUint32(data, start + 12),
combinationOperator: data[start + 16] & 7,
};
}
const RegionSegmentInformationFieldLength = 17;
function processSegment(segment, visitor) {
const header = segment.header;
const data = segment.data,
end = segment.end;
let position = segment.start;
let args, at, i, atLength;
switch (header.type) {
case 0: // SymbolDictionary
// 7.4.2 Symbol dictionary segment syntax
const dictionary = {};
const dictionaryFlags = readUint16(data, position); // 7.4.2.1.1
dictionary.huffman = !!(dictionaryFlags & 1);
dictionary.refinement = !!(dictionaryFlags & 2);
dictionary.huffmanDHSelector = (dictionaryFlags >> 2) & 3;
dictionary.huffmanDWSelector = (dictionaryFlags >> 4) & 3;
dictionary.bitmapSizeSelector = (dictionaryFlags >> 6) & 1;
dictionary.aggregationInstancesSelector = (dictionaryFlags >> 7) & 1;
dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256);
dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512);
dictionary.template = (dictionaryFlags >> 10) & 3;
dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1;
position += 2;
if (!dictionary.huffman) {
atLength = dictionary.template === 0 ? 4 : 1;
at = [];
for (i = 0; i < atLength; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1),
});
position += 2;
}
dictionary.at = at;
}
if (dictionary.refinement && !dictionary.refinementTemplate) {
at = [];
for (i = 0; i < 2; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1),
});
position += 2;
}
dictionary.refinementAt = at;
}
dictionary.numberOfExportedSymbols = readUint32(data, position);
position += 4;
dictionary.numberOfNewSymbols = readUint32(data, position);
position += 4;
args = [
dictionary,
header.number,
header.referredTo,
data,
position,
end,
];
break;
case 6: // ImmediateTextRegion
case 7: // ImmediateLosslessTextRegion
const textRegion = {};
textRegion.info = readRegionSegmentInformation(data, position);
position += RegionSegmentInformationFieldLength;
const textRegionSegmentFlags = readUint16(data, position);
position += 2;
textRegion.huffman = !!(textRegionSegmentFlags & 1);
textRegion.refinement = !!(textRegionSegmentFlags & 2);
textRegion.logStripSize = (textRegionSegmentFlags >> 2) & 3;
textRegion.stripSize = 1 << textRegion.logStripSize;
textRegion.referenceCorner = (textRegionSegmentFlags >> 4) & 3;
textRegion.transposed = !!(textRegionSegmentFlags & 64);
textRegion.combinationOperator = (textRegionSegmentFlags >> 7) & 3;
textRegion.defaultPixelValue = (textRegionSegmentFlags >> 9) & 1;
textRegion.dsOffset = (textRegionSegmentFlags << 17) >> 27;
textRegion.refinementTemplate = (textRegionSegmentFlags >> 15) & 1;
if (textRegion.huffman) {
const textRegionHuffmanFlags = readUint16(data, position);
position += 2;
textRegion.huffmanFS = textRegionHuffmanFlags & 3;
textRegion.huffmanDS = (textRegionHuffmanFlags >> 2) & 3;
textRegion.huffmanDT = (textRegionHuffmanFlags >> 4) & 3;
textRegion.huffmanRefinementDW = (textRegionHuffmanFlags >> 6) & 3;
textRegion.huffmanRefinementDH = (textRegionHuffmanFlags >> 8) & 3;
textRegion.huffmanRefinementDX = (textRegionHuffmanFlags >> 10) & 3;
textRegion.huffmanRefinementDY = (textRegionHuffmanFlags >> 12) & 3;
textRegion.huffmanRefinementSizeSelector = !!(
textRegionHuffmanFlags & 0x4000
);
}
if (textRegion.refinement && !textRegion.refinementTemplate) {
at = [];
for (i = 0; i < 2; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1),
});
position += 2;
}
textRegion.refinementAt = at;
}
textRegion.numberOfSymbolInstances = readUint32(data, position);
position += 4;
args = [textRegion, header.referredTo, data, position, end];
break;
case 16: // PatternDictionary
// 7.4.4. Pattern dictionary segment syntax
const patternDictionary = {};
const patternDictionaryFlags = data[position++];
patternDictionary.mmr = !!(patternDictionaryFlags & 1);
patternDictionary.template = (patternDictionaryFlags >> 1) & 3;
patternDictionary.patternWidth = data[position++];
patternDictionary.patternHeight = data[position++];
patternDictionary.maxPatternIndex = readUint32(data, position);
position += 4;
args = [patternDictionary, header.number, data, position, end];
break;
case 22: // ImmediateHalftoneRegion
case 23: // ImmediateLosslessHalftoneRegion
// 7.4.5 Halftone region segment syntax
const halftoneRegion = {};
halftoneRegion.info = readRegionSegmentInformation(data, position);
position += RegionSegmentInformationFieldLength;
const halftoneRegionFlags = data[position++];
halftoneRegion.mmr = !!(halftoneRegionFlags & 1);
halftoneRegion.template = (halftoneRegionFlags >> 1) & 3;
halftoneRegion.enableSkip = !!(halftoneRegionFlags & 8);
halftoneRegion.combinationOperator = (halftoneRegionFlags >> 4) & 7;
halftoneRegion.defaultPixelValue = (halftoneRegionFlags >> 7) & 1;
halftoneRegion.gridWidth = readUint32(data, position);
position += 4;
halftoneRegion.gridHeight = readUint32(data, position);
position += 4;
halftoneRegion.gridOffsetX = readUint32(data, position) & 0xffffffff;
position += 4;
halftoneRegion.gridOffsetY = readUint32(data, position) & 0xffffffff;
position += 4;
halftoneRegion.gridVectorX = readUint16(data, position);
position += 2;
halftoneRegion.gridVectorY = readUint16(data, position);
position += 2;
args = [halftoneRegion, header.referredTo, data, position, end];
break;
case 38: // ImmediateGenericRegion
case 39: // ImmediateLosslessGenericRegion
const genericRegion = {};
genericRegion.info = readRegionSegmentInformation(data, position);
position += RegionSegmentInformationFieldLength;
const genericRegionSegmentFlags = data[position++];
genericRegion.mmr = !!(genericRegionSegmentFlags & 1);
genericRegion.template = (genericRegionSegmentFlags >> 1) & 3;
genericRegion.prediction = !!(genericRegionSegmentFlags & 8);
if (!genericRegion.mmr) {
atLength = genericRegion.template === 0 ? 4 : 1;
at = [];
for (i = 0; i < atLength; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1),
});
position += 2;
}
genericRegion.at = at;
}
args = [genericRegion, data, position, end];
break;
case 48: // PageInformation
const pageInfo = {
width: readUint32(data, position),
height: readUint32(data, position + 4),
resolutionX: readUint32(data, position + 8),
resolutionY: readUint32(data, position + 12),
2012-06-17 05:15:42 +09:00
};
if (pageInfo.height === 0xffffffff) {
delete pageInfo.height;
2012-06-17 05:15:42 +09:00
}
const pageSegmentFlags = data[position + 16];
readUint16(data, position + 17); // pageStripingInformation
pageInfo.lossless = !!(pageSegmentFlags & 1);
pageInfo.refinement = !!(pageSegmentFlags & 2);
pageInfo.defaultPixelValue = (pageSegmentFlags >> 2) & 1;
pageInfo.combinationOperator = (pageSegmentFlags >> 3) & 3;
pageInfo.requiresBuffer = !!(pageSegmentFlags & 32);
pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64);
args = [pageInfo];
break;
case 49: // EndOfPage
break;
case 50: // EndOfStripe
break;
case 51: // EndOfFile
break;
case 53: // Tables
args = [header.number, data, position, end];
break;
case 62: // 7.4.15 defines 2 extension types which
// are comments and can be ignored.
break;
default:
throw new Jbig2Error(
`segment type ${header.typeName}(${header.type})` +
" is not implemented"
);
}
const callbackName = "on" + header.typeName;
if (callbackName in visitor) {
visitor[callbackName].apply(visitor, args);
}
}
function processSegments(segments, visitor) {
for (let i = 0, ii = segments.length; i < ii; i++) {
processSegment(segments[i], visitor);
}
}
function parseJbig2Chunks(chunks) {
const visitor = new SimpleSegmentVisitor();
for (let i = 0, ii = chunks.length; i < ii; i++) {
const chunk = chunks[i];
const segments = readSegments({}, chunk.data, chunk.start, chunk.end);
processSegments(segments, visitor);
}
return visitor.buffer;
}
function parseJbig2(data) {
const end = data.length;
let position = 0;
if (
data[position] !== 0x97 ||
data[position + 1] !== 0x4a ||
data[position + 2] !== 0x42 ||
data[position + 3] !== 0x32 ||
data[position + 4] !== 0x0d ||
data[position + 5] !== 0x0a ||
data[position + 6] !== 0x1a ||
data[position + 7] !== 0x0a
) {
throw new Jbig2Error("parseJbig2 - invalid header.");
}
const header = Object.create(null);
position += 8;
const flags = data[position++];
header.randomAccess = !(flags & 1);
if (!(flags & 2)) {
header.numberOfPages = readUint32(data, position);
position += 4;
}
const segments = readSegments(header, data, position, end);
const visitor = new SimpleSegmentVisitor();
processSegments(segments, visitor);
const { width, height } = visitor.currentPageInfo;
const bitPacked = visitor.buffer;
const imgData = new Uint8ClampedArray(width * height);
let q = 0,
k = 0;
for (let i = 0; i < height; i++) {
let mask = 0,
buffer;
for (let j = 0; j < width; j++) {
if (!mask) {
mask = 128;
buffer = bitPacked[k++];
}
imgData[q++] = buffer & mask ? 0 : 255;
mask >>= 1;
2012-06-17 05:15:42 +09:00
}
}
return { imgData, width, height };
}
class SimpleSegmentVisitor {
onPageInformation(info) {
this.currentPageInfo = info;
const rowSize = (info.width + 7) >> 3;
const buffer = new Uint8ClampedArray(rowSize * info.height);
// The contents of ArrayBuffers are initialized to 0.
// Fill the buffer with 0xFF only if info.defaultPixelValue is set
if (info.defaultPixelValue) {
for (let i = 0, ii = buffer.length; i < ii; i++) {
buffer[i] = 0xff;
2012-06-17 05:15:42 +09:00
}
}
this.buffer = buffer;
2012-06-17 05:15:42 +09:00
}
drawBitmap(regionInfo, bitmap) {
const pageInfo = this.currentPageInfo;
const width = regionInfo.width,
height = regionInfo.height;
const rowSize = (pageInfo.width + 7) >> 3;
const combinationOperator = pageInfo.combinationOperatorOverride
? regionInfo.combinationOperator
: pageInfo.combinationOperator;
const buffer = this.buffer;
const mask0 = 128 >> (regionInfo.x & 7);
let offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3);
let i, j, mask, offset;
switch (combinationOperator) {
case 0: // OR
for (i = 0; i < height; i++) {
mask = mask0;
offset = offset0;
for (j = 0; j < width; j++) {
if (bitmap[i][j]) {
buffer[offset] |= mask;
}
mask >>= 1;
if (!mask) {
mask = 128;
offset++;
}
}
offset0 += rowSize;
}
break;
case 2: // XOR
for (i = 0; i < height; i++) {
mask = mask0;
offset = offset0;
for (j = 0; j < width; j++) {
if (bitmap[i][j]) {
buffer[offset] ^= mask;
}
mask >>= 1;
if (!mask) {
mask = 128;
offset++;
}
2012-06-17 05:15:42 +09:00
}
offset0 += rowSize;
2012-06-17 05:15:42 +09:00
}
break;
2012-06-17 05:15:42 +09:00
default:
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
throw new Jbig2Error(
`operator ${combinationOperator} is not supported`
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
);
2012-06-17 05:15:42 +09:00
}
}
onImmediateGenericRegion(region, data, start, end) {
const regionInfo = region.info;
const decodingContext = new DecodingContext(data, start, end);
const bitmap = decodeBitmap(
region.mmr,
regionInfo.width,
regionInfo.height,
region.template,
region.prediction,
null,
region.at,
decodingContext
);
this.drawBitmap(regionInfo, bitmap);
2012-06-17 05:15:42 +09:00
}
onImmediateLosslessGenericRegion() {
this.onImmediateGenericRegion.apply(this, arguments);
2012-06-17 05:15:42 +09:00
}
onSymbolDictionary(
dictionary,
currentSegment,
referredSegments,
data,
start,
end
) {
let huffmanTables, huffmanInput;
if (dictionary.huffman) {
huffmanTables = getSymbolDictionaryHuffmanTables(
dictionary,
referredSegments,
this.customTables
);
huffmanInput = new Reader(data, start, end);
}
// Combines exported symbols from all referred segments
let symbols = this.symbols;
if (!symbols) {
this.symbols = symbols = {};
}
let inputSymbols = [];
for (let i = 0, ii = referredSegments.length; i < ii; i++) {
const referredSymbols = symbols[referredSegments[i]];
// referredSymbols is undefined when we have a reference to a Tables
// segment instead of a SymbolDictionary.
if (referredSymbols) {
inputSymbols = inputSymbols.concat(referredSymbols);
}
}
const decodingContext = new DecodingContext(data, start, end);
symbols[currentSegment] = decodeSymbolDictionary(
dictionary.huffman,
dictionary.refinement,
inputSymbols,
dictionary.numberOfNewSymbols,
dictionary.numberOfExportedSymbols,
huffmanTables,
dictionary.template,
dictionary.at,
dictionary.refinementTemplate,
dictionary.refinementAt,
decodingContext,
huffmanInput
);
}
onImmediateTextRegion(region, referredSegments, data, start, end) {
const regionInfo = region.info;
let huffmanTables, huffmanInput;
// Combines exported symbols from all referred segments
const symbols = this.symbols;
let inputSymbols = [];
for (let i = 0, ii = referredSegments.length; i < ii; i++) {
const referredSymbols = symbols[referredSegments[i]];
// referredSymbols is undefined when we have a reference to a Tables
// segment instead of a SymbolDictionary.
if (referredSymbols) {
inputSymbols = inputSymbols.concat(referredSymbols);
2012-06-17 05:15:42 +09:00
}
}
const symbolCodeLength = log2(inputSymbols.length);
if (region.huffman) {
huffmanInput = new Reader(data, start, end);
huffmanTables = getTextRegionHuffmanTables(
region,
referredSegments,
this.customTables,
inputSymbols.length,
huffmanInput
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
);
}
const decodingContext = new DecodingContext(data, start, end);
const bitmap = decodeTextRegion(
region.huffman,
region.refinement,
regionInfo.width,
regionInfo.height,
region.defaultPixelValue,
region.numberOfSymbolInstances,
region.stripSize,
inputSymbols,
symbolCodeLength,
region.transposed,
region.dsOffset,
region.referenceCorner,
region.combinationOperator,
huffmanTables,
region.refinementTemplate,
region.refinementAt,
decodingContext,
region.logStripSize,
huffmanInput
);
this.drawBitmap(regionInfo, bitmap);
}
onImmediateLosslessTextRegion() {
this.onImmediateTextRegion.apply(this, arguments);
}
onPatternDictionary(dictionary, currentSegment, data, start, end) {
let patterns = this.patterns;
if (!patterns) {
this.patterns = patterns = {};
}
const decodingContext = new DecodingContext(data, start, end);
patterns[currentSegment] = decodePatternDictionary(
dictionary.mmr,
dictionary.patternWidth,
dictionary.patternHeight,
dictionary.maxPatternIndex,
dictionary.template,
decodingContext
);
}
onImmediateHalftoneRegion(region, referredSegments, data, start, end) {
// HalftoneRegion refers to exactly one PatternDictionary.
const patterns = this.patterns[referredSegments[0]];
const regionInfo = region.info;
const decodingContext = new DecodingContext(data, start, end);
const bitmap = decodeHalftoneRegion(
region.mmr,
patterns,
region.template,
regionInfo.width,
regionInfo.height,
region.defaultPixelValue,
region.enableSkip,
region.combinationOperator,
region.gridWidth,
region.gridHeight,
region.gridOffsetX,
region.gridOffsetY,
region.gridVectorX,
region.gridVectorY,
decodingContext
);
this.drawBitmap(regionInfo, bitmap);
}
2012-06-17 05:15:42 +09:00
onImmediateLosslessHalftoneRegion() {
this.onImmediateHalftoneRegion.apply(this, arguments);
}
onTables(currentSegment, data, start, end) {
let customTables = this.customTables;
if (!customTables) {
this.customTables = customTables = {};
}
customTables[currentSegment] = decodeTablesSegment(data, start, end);
}
}
class HuffmanLine {
constructor(lineData) {
2018-01-24 00:04:07 +09:00
if (lineData.length === 2) {
// OOB line.
this.isOOB = true;
this.rangeLow = 0;
this.prefixLength = lineData[0];
this.rangeLength = 0;
this.prefixCode = lineData[1];
this.isLowerRange = false;
} else {
// Normal, upper range or lower range line.
// Upper range lines are processed like normal lines.
this.isOOB = false;
this.rangeLow = lineData[0];
this.prefixLength = lineData[1];
this.rangeLength = lineData[2];
this.prefixCode = lineData[3];
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
this.isLowerRange = lineData[4] === "lower";
2018-01-24 00:04:07 +09:00
}
}
}
2018-01-24 00:04:07 +09:00
class HuffmanTreeNode {
constructor(line) {
2018-01-24 00:04:07 +09:00
this.children = [];
if (line) {
// Leaf node
this.isLeaf = true;
this.rangeLength = line.rangeLength;
this.rangeLow = line.rangeLow;
this.isLowerRange = line.isLowerRange;
this.isOOB = line.isOOB;
} else {
// Intermediate or root node
this.isLeaf = false;
}
}
buildTree(line, shift) {
const bit = (line.prefixCode >> shift) & 1;
if (shift <= 0) {
// Create a leaf node.
this.children[bit] = new HuffmanTreeNode(line);
} else {
// Create an intermediate node and continue recursively.
let node = this.children[bit];
2018-01-24 00:04:07 +09:00
if (!node) {
this.children[bit] = node = new HuffmanTreeNode(null);
2018-01-24 00:04:07 +09:00
}
node.buildTree(line, shift - 1);
}
}
2018-01-24 00:04:07 +09:00
decodeNode(reader) {
if (this.isLeaf) {
if (this.isOOB) {
return null;
}
const htOffset = reader.readBits(this.rangeLength);
return this.rangeLow + (this.isLowerRange ? -htOffset : htOffset);
}
const node = this.children[reader.readBit()];
if (!node) {
throw new Jbig2Error("invalid Huffman data");
}
return node.decodeNode(reader);
}
}
class HuffmanTable {
constructor(lines, prefixCodesDone) {
2018-01-24 00:04:07 +09:00
if (!prefixCodesDone) {
this.assignPrefixCodes(lines);
}
// Create Huffman tree.
this.rootNode = new HuffmanTreeNode(null);
for (let i = 0, ii = lines.length; i < ii; i++) {
const line = lines[i];
2018-01-24 00:04:07 +09:00
if (line.prefixLength > 0) {
this.rootNode.buildTree(line, line.prefixLength - 1);
}
}
}
decode(reader) {
return this.rootNode.decodeNode(reader);
}
2018-01-24 00:04:07 +09:00
assignPrefixCodes(lines) {
// Annex B.3 Assigning the prefix codes.
const linesLength = lines.length;
let prefixLengthMax = 0;
for (let i = 0; i < linesLength; i++) {
prefixLengthMax = Math.max(prefixLengthMax, lines[i].prefixLength);
}
const histogram = new Uint32Array(prefixLengthMax + 1);
for (let i = 0; i < linesLength; i++) {
histogram[lines[i].prefixLength]++;
}
let currentLength = 1,
firstCode = 0,
currentCode,
currentTemp,
line;
histogram[0] = 0;
while (currentLength <= prefixLengthMax) {
firstCode = (firstCode + histogram[currentLength - 1]) << 1;
currentCode = firstCode;
currentTemp = 0;
while (currentTemp < linesLength) {
line = lines[currentTemp];
if (line.prefixLength === currentLength) {
line.prefixCode = currentCode;
currentCode++;
2018-01-24 00:04:07 +09:00
}
currentTemp++;
2018-01-24 00:04:07 +09:00
}
currentLength++;
}
}
}
2018-01-24 00:04:07 +09:00
function decodeTablesSegment(data, start, end) {
// Decodes a Tables segment, i.e., a custom Huffman table.
// Annex B.2 Code table structure.
const flags = data[start];
const lowestValue = readUint32(data, start + 1) & 0xffffffff;
const highestValue = readUint32(data, start + 5) & 0xffffffff;
const reader = new Reader(data, start + 9, end);
const prefixSizeBits = ((flags >> 1) & 7) + 1;
const rangeSizeBits = ((flags >> 4) & 7) + 1;
const lines = [];
let prefixLength,
rangeLength,
currentRangeLow = lowestValue;
// Normal table lines
do {
2018-01-24 00:04:07 +09:00
prefixLength = reader.readBits(prefixSizeBits);
rangeLength = reader.readBits(rangeSizeBits);
2018-01-24 00:04:07 +09:00
lines.push(
new HuffmanLine([currentRangeLow, prefixLength, rangeLength, 0])
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
);
currentRangeLow += 1 << rangeLength;
} while (currentRangeLow < highestValue);
2018-01-24 00:04:07 +09:00
// Lower range table line
prefixLength = reader.readBits(prefixSizeBits);
lines.push(new HuffmanLine([lowestValue - 1, prefixLength, 32, 0, "lower"]));
2018-01-24 00:04:07 +09:00
// Upper range table line
prefixLength = reader.readBits(prefixSizeBits);
lines.push(new HuffmanLine([highestValue, prefixLength, 32, 0]));
2018-01-24 00:04:07 +09:00
if (flags & 1) {
// Out-of-band table line
prefixLength = reader.readBits(prefixSizeBits);
lines.push(new HuffmanLine([prefixLength, 0]));
2018-01-24 00:04:07 +09:00
}
return new HuffmanTable(lines, false);
}
2018-01-24 00:04:07 +09:00
const standardTablesCache = {};
2018-01-24 00:04:07 +09:00
function getStandardTable(number) {
// Annex B.5 Standard Huffman tables.
let table = standardTablesCache[number];
if (table) {
2018-01-24 00:04:07 +09:00
return table;
}
let lines;
switch (number) {
case 1:
lines = [
[0, 1, 4, 0x0],
[16, 2, 8, 0x2],
[272, 3, 16, 0x6],
[65808, 3, 32, 0x7], // upper
];
break;
case 2:
lines = [
[0, 1, 0, 0x0],
[1, 2, 0, 0x2],
[2, 3, 0, 0x6],
[3, 4, 3, 0xe],
[11, 5, 6, 0x1e],
[75, 6, 32, 0x3e], // upper
[6, 0x3f], // OOB
];
break;
case 3:
lines = [
[-256, 8, 8, 0xfe],
[0, 1, 0, 0x0],
[1, 2, 0, 0x2],
[2, 3, 0, 0x6],
[3, 4, 3, 0xe],
[11, 5, 6, 0x1e],
[-257, 8, 32, 0xff, "lower"],
[75, 7, 32, 0x7e], // upper
[6, 0x3e], // OOB
];
break;
case 4:
lines = [
[1, 1, 0, 0x0],
[2, 2, 0, 0x2],
[3, 3, 0, 0x6],
[4, 4, 3, 0xe],
[12, 5, 6, 0x1e],
[76, 5, 32, 0x1f], // upper
];
break;
case 5:
lines = [
[-255, 7, 8, 0x7e],
[1, 1, 0, 0x0],
[2, 2, 0, 0x2],
[3, 3, 0, 0x6],
[4, 4, 3, 0xe],
[12, 5, 6, 0x1e],
[-256, 7, 32, 0x7f, "lower"],
[76, 6, 32, 0x3e], // upper
];
break;
case 6:
lines = [
[-2048, 5, 10, 0x1c],
[-1024, 4, 9, 0x8],
[-512, 4, 8, 0x9],
[-256, 4, 7, 0xa],
[-128, 5, 6, 0x1d],
[-64, 5, 5, 0x1e],
[-32, 4, 5, 0xb],
[0, 2, 7, 0x0],
[128, 3, 7, 0x2],
[256, 3, 8, 0x3],
[512, 4, 9, 0xc],
[1024, 4, 10, 0xd],
[-2049, 6, 32, 0x3e, "lower"],
[2048, 6, 32, 0x3f], // upper
];
break;
case 7:
lines = [
[-1024, 4, 9, 0x8],
[-512, 3, 8, 0x0],
[-256, 4, 7, 0x9],
[-128, 5, 6, 0x1a],
[-64, 5, 5, 0x1b],
[-32, 4, 5, 0xa],
[0, 4, 5, 0xb],
[32, 5, 5, 0x1c],
[64, 5, 6, 0x1d],
[128, 4, 7, 0xc],
[256, 3, 8, 0x1],
[512, 3, 9, 0x2],
[1024, 3, 10, 0x3],
[-1025, 5, 32, 0x1e, "lower"],
[2048, 5, 32, 0x1f], // upper
];
break;
case 8:
lines = [
[-15, 8, 3, 0xfc],
[-7, 9, 1, 0x1fc],
[-5, 8, 1, 0xfd],
[-3, 9, 0, 0x1fd],
[-2, 7, 0, 0x7c],
[-1, 4, 0, 0xa],
[0, 2, 1, 0x0],
[2, 5, 0, 0x1a],
[3, 6, 0, 0x3a],
[4, 3, 4, 0x4],
[20, 6, 1, 0x3b],
[22, 4, 4, 0xb],
[38, 4, 5, 0xc],
[70, 5, 6, 0x1b],
[134, 5, 7, 0x1c],
[262, 6, 7, 0x3c],
[390, 7, 8, 0x7d],
[646, 6, 10, 0x3d],
[-16, 9, 32, 0x1fe, "lower"],
[1670, 9, 32, 0x1ff], // upper
[2, 0x1], // OOB
];
break;
case 9:
lines = [
[-31, 8, 4, 0xfc],
[-15, 9, 2, 0x1fc],
[-11, 8, 2, 0xfd],
[-7, 9, 1, 0x1fd],
[-5, 7, 1, 0x7c],
[-3, 4, 1, 0xa],
[-1, 3, 1, 0x2],
[1, 3, 1, 0x3],
[3, 5, 1, 0x1a],
[5, 6, 1, 0x3a],
[7, 3, 5, 0x4],
[39, 6, 2, 0x3b],
[43, 4, 5, 0xb],
[75, 4, 6, 0xc],
[139, 5, 7, 0x1b],
[267, 5, 8, 0x1c],
[523, 6, 8, 0x3c],
[779, 7, 9, 0x7d],
[1291, 6, 11, 0x3d],
[-32, 9, 32, 0x1fe, "lower"],
[3339, 9, 32, 0x1ff], // upper
[2, 0x0], // OOB
];
break;
case 10:
lines = [
[-21, 7, 4, 0x7a],
[-5, 8, 0, 0xfc],
[-4, 7, 0, 0x7b],
[-3, 5, 0, 0x18],
[-2, 2, 2, 0x0],
[2, 5, 0, 0x19],
[3, 6, 0, 0x36],
[4, 7, 0, 0x7c],
[5, 8, 0, 0xfd],
[6, 2, 6, 0x1],
[70, 5, 5, 0x1a],
[102, 6, 5, 0x37],
[134, 6, 6, 0x38],
[198, 6, 7, 0x39],
[326, 6, 8, 0x3a],
[582, 6, 9, 0x3b],
[1094, 6, 10, 0x3c],
[2118, 7, 11, 0x7d],
[-22, 8, 32, 0xfe, "lower"],
[4166, 8, 32, 0xff], // upper
[2, 0x2], // OOB
];
break;
case 11:
lines = [
[1, 1, 0, 0x0],
[2, 2, 1, 0x2],
[4, 4, 0, 0xc],
[5, 4, 1, 0xd],
[7, 5, 1, 0x1c],
[9, 5, 2, 0x1d],
[13, 6, 2, 0x3c],
[17, 7, 2, 0x7a],
[21, 7, 3, 0x7b],
[29, 7, 4, 0x7c],
[45, 7, 5, 0x7d],
[77, 7, 6, 0x7e],
[141, 7, 32, 0x7f], // upper
];
break;
case 12:
lines = [
[1, 1, 0, 0x0],
[2, 2, 0, 0x2],
[3, 3, 1, 0x6],
[5, 5, 0, 0x1c],
[6, 5, 1, 0x1d],
[8, 6, 1, 0x3c],
[10, 7, 0, 0x7a],
[11, 7, 1, 0x7b],
[13, 7, 2, 0x7c],
[17, 7, 3, 0x7d],
[25, 7, 4, 0x7e],
[41, 8, 5, 0xfe],
[73, 8, 32, 0xff], // upper
];
break;
case 13:
lines = [
[1, 1, 0, 0x0],
[2, 3, 0, 0x4],
[3, 4, 0, 0xc],
[4, 5, 0, 0x1c],
[5, 4, 1, 0xd],
[7, 3, 3, 0x5],
[15, 6, 1, 0x3a],
[17, 6, 2, 0x3b],
[21, 6, 3, 0x3c],
[29, 6, 4, 0x3d],
[45, 6, 5, 0x3e],
[77, 7, 6, 0x7e],
[141, 7, 32, 0x7f], // upper
];
break;
case 14:
lines = [
[-2, 3, 0, 0x4],
[-1, 3, 0, 0x5],
[0, 1, 0, 0x0],
[1, 3, 0, 0x6],
[2, 3, 0, 0x7],
];
break;
case 15:
lines = [
[-24, 7, 4, 0x7c],
[-8, 6, 2, 0x3c],
[-4, 5, 1, 0x1c],
[-2, 4, 0, 0xc],
[-1, 3, 0, 0x4],
[0, 1, 0, 0x0],
[1, 3, 0, 0x5],
[2, 4, 0, 0xd],
[3, 5, 1, 0x1d],
[5, 6, 2, 0x3d],
[9, 7, 4, 0x7d],
[-25, 7, 32, 0x7e, "lower"],
[25, 7, 32, 0x7f], // upper
];
break;
default:
throw new Jbig2Error(`standard table B.${number} does not exist`);
}
for (let i = 0, ii = lines.length; i < ii; i++) {
lines[i] = new HuffmanLine(lines[i]);
}
table = new HuffmanTable(lines, true);
standardTablesCache[number] = table;
return table;
}
2018-01-24 00:04:07 +09:00
class Reader {
constructor(data, start, end) {
2018-01-24 00:04:07 +09:00
this.data = data;
this.start = start;
this.end = end;
this.position = start;
this.shift = -1;
this.currentByte = 0;
}
readBit() {
if (this.shift < 0) {
2018-01-24 00:04:07 +09:00
if (this.position >= this.end) {
throw new Jbig2Error("end of data while reading bit");
2018-01-24 00:04:07 +09:00
}
this.currentByte = this.data[this.position++];
this.shift = 7;
2018-01-24 00:04:07 +09:00
}
const bit = (this.currentByte >> this.shift) & 1;
this.shift--;
return bit;
2018-01-24 00:04:07 +09:00
}
readBits(numBits) {
let result = 0,
i;
for (i = numBits - 1; i >= 0; i--) {
result |= this.readBit() << i;
2018-01-24 00:04:07 +09:00
}
return result;
}
2018-01-24 00:04:07 +09:00
byteAlign() {
this.shift = -1;
}
2018-01-24 00:04:07 +09:00
next() {
if (this.position >= this.end) {
return -1;
2018-01-24 00:04:07 +09:00
}
return this.data[this.position++];
}
}
2018-01-24 00:04:07 +09:00
function getCustomHuffmanTable(index, referredTo, customTables) {
// Returns a Tables segment that has been earlier decoded.
// See 7.4.2.1.6 (symbol dictionary) or 7.4.3.1.6 (text region).
let currentIndex = 0;
for (let i = 0, ii = referredTo.length; i < ii; i++) {
const table = customTables[referredTo[i]];
if (table) {
if (index === currentIndex) {
return table;
}
currentIndex++;
2018-01-24 00:04:07 +09:00
}
}
throw new Jbig2Error("can't find custom Huffman table");
}
2018-01-24 00:04:07 +09:00
function getTextRegionHuffmanTables(
textRegion,
referredTo,
customTables,
numberOfSymbols,
reader
) {
// 7.4.3.1.7 Symbol ID Huffman table decoding
// Read code lengths for RUNCODEs 0...34.
const codes = [];
for (let i = 0; i <= 34; i++) {
const codeLength = reader.readBits(4);
codes.push(new HuffmanLine([i, codeLength, 0, 0]));
}
// Assign Huffman codes for RUNCODEs.
const runCodesTable = new HuffmanTable(codes, false);
// Read a Huffman code using the assignment above.
// Interpret the RUNCODE codes and the additional bits (if any).
codes.length = 0;
for (let i = 0; i < numberOfSymbols; ) {
const codeLength = runCodesTable.decode(reader);
if (codeLength >= 32) {
let repeatedLength, numberOfRepeats, j;
switch (codeLength) {
case 32:
if (i === 0) {
throw new Jbig2Error("no previous value in symbol ID table");
}
numberOfRepeats = reader.readBits(2) + 3;
repeatedLength = codes[i - 1].prefixLength;
break;
case 33:
numberOfRepeats = reader.readBits(3) + 3;
repeatedLength = 0;
break;
case 34:
numberOfRepeats = reader.readBits(7) + 11;
repeatedLength = 0;
break;
default:
throw new Jbig2Error("invalid code length in symbol ID table");
}
for (j = 0; j < numberOfRepeats; j++) {
codes.push(new HuffmanLine([i, repeatedLength, 0, 0]));
i++;
}
} else {
codes.push(new HuffmanLine([i, codeLength, 0, 0]));
i++;
2018-01-24 00:04:07 +09:00
}
}
reader.byteAlign();
const symbolIDTable = new HuffmanTable(codes, false);
// 7.4.3.1.6 Text region segment Huffman table selection
let customIndex = 0,
tableFirstS,
tableDeltaS,
tableDeltaT;
switch (textRegion.huffmanFS) {
case 0:
case 1:
tableFirstS = getStandardTable(textRegion.huffmanFS + 6);
break;
case 3:
tableFirstS = getCustomHuffmanTable(
customIndex,
referredTo,
customTables
);
customIndex++;
break;
default:
throw new Jbig2Error("invalid Huffman FS selector");
}
2018-01-24 00:04:07 +09:00
switch (textRegion.huffmanDS) {
case 0:
case 1:
case 2:
tableDeltaS = getStandardTable(textRegion.huffmanDS + 8);
break;
case 3:
tableDeltaS = getCustomHuffmanTable(
customIndex,
referredTo,
customTables
);
customIndex++;
break;
default:
throw new Jbig2Error("invalid Huffman DS selector");
}
2018-01-24 00:04:07 +09:00
switch (textRegion.huffmanDT) {
case 0:
case 1:
case 2:
tableDeltaT = getStandardTable(textRegion.huffmanDT + 11);
break;
case 3:
tableDeltaT = getCustomHuffmanTable(
customIndex,
referredTo,
customTables
);
customIndex++;
break;
default:
throw new Jbig2Error("invalid Huffman DT selector");
2018-01-24 00:04:07 +09:00
}
if (textRegion.refinement) {
// Load tables RDW, RDH, RDX and RDY.
throw new Jbig2Error("refinement with Huffman is not supported");
}
2018-01-24 00:04:07 +09:00
return {
symbolIDTable,
tableFirstS,
tableDeltaS,
tableDeltaT,
};
}
2018-01-24 00:04:07 +09:00
function getSymbolDictionaryHuffmanTables(
dictionary,
referredTo,
customTables
) {
// 7.4.2.1.6 Symbol dictionary segment Huffman table selection
let customIndex = 0,
tableDeltaHeight,
tableDeltaWidth;
switch (dictionary.huffmanDHSelector) {
case 0:
case 1:
tableDeltaHeight = getStandardTable(dictionary.huffmanDHSelector + 4);
break;
case 3:
tableDeltaHeight = getCustomHuffmanTable(
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
customIndex,
referredTo,
customTables
);
2018-01-24 00:04:07 +09:00
customIndex++;
break;
default:
throw new Jbig2Error("invalid Huffman DH selector");
}
2018-01-24 00:04:07 +09:00
switch (dictionary.huffmanDWSelector) {
case 0:
case 1:
tableDeltaWidth = getStandardTable(dictionary.huffmanDWSelector + 2);
break;
case 3:
tableDeltaWidth = getCustomHuffmanTable(
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
customIndex,
referredTo,
customTables
);
customIndex++;
break;
default:
throw new Jbig2Error("invalid Huffman DW selector");
}
2018-01-24 00:04:07 +09:00
let tableBitmapSize, tableAggregateInstances;
if (dictionary.bitmapSizeSelector) {
tableBitmapSize = getCustomHuffmanTable(
customIndex,
referredTo,
customTables
);
customIndex++;
} else {
tableBitmapSize = getStandardTable(1);
2018-01-24 00:04:07 +09:00
}
if (dictionary.aggregationInstancesSelector) {
tableAggregateInstances = getCustomHuffmanTable(
customIndex,
referredTo,
customTables
);
} else {
tableAggregateInstances = getStandardTable(1);
}
return {
tableDeltaHeight,
tableDeltaWidth,
tableBitmapSize,
tableAggregateInstances,
};
}
function readUncompressedBitmap(reader, width, height) {
const bitmap = [];
for (let y = 0; y < height; y++) {
const row = new Uint8Array(width);
bitmap.push(row);
for (let x = 0; x < width; x++) {
row[x] = reader.readBit();
2018-01-24 00:04:07 +09:00
}
reader.byteAlign();
}
return bitmap;
}
function decodeMMRBitmap(input, width, height, endOfBlock) {
// MMR is the same compression algorithm as the PDF filter
// CCITTFaxDecode with /K -1.
const params = {
K: -1,
Columns: width,
Rows: height,
BlackIs1: true,
EndOfBlock: endOfBlock,
};
const decoder = new CCITTFaxDecoder(input, params);
const bitmap = [];
let currentByte,
eof = false;
for (let y = 0; y < height; y++) {
const row = new Uint8Array(width);
bitmap.push(row);
let shift = -1;
for (let x = 0; x < width; x++) {
if (shift < 0) {
currentByte = decoder.readNextChar();
if (currentByte === -1) {
// Set the rest of the bits to zero.
currentByte = 0;
eof = true;
2018-01-24 00:04:07 +09:00
}
shift = 7;
2018-01-24 00:04:07 +09:00
}
row[x] = (currentByte >> shift) & 1;
shift--;
2018-01-24 00:04:07 +09:00
}
}
2018-01-24 00:04:07 +09:00
if (endOfBlock && !eof) {
// Read until EOFB has been consumed.
const lookForEOFLimit = 5;
for (let i = 0; i < lookForEOFLimit; i++) {
if (decoder.readNextChar() === -1) {
break;
2018-01-24 00:04:07 +09:00
}
}
}
return bitmap;
}
class Jbig2Image {
parseChunks(chunks) {
return parseJbig2Chunks(chunks);
}
2012-06-17 05:15:42 +09:00
parse(data) {
const { imgData, width, height } = parseJbig2(data);
this.width = width;
this.height = height;
return imgData;
}
}
Enable auto-formatting of the entire code-base using Prettier (issue 11444) Note that Prettier, purposely, has only limited [configuration options](https://prettier.io/docs/en/options.html). The configuration file is based on [the one in `mozilla central`](https://searchfox.org/mozilla-central/source/.prettierrc) with just a few additions (to avoid future breakage if the defaults ever changes). Prettier is being used for a couple of reasons: - To be consistent with `mozilla-central`, where Prettier is already in use across the tree. - To ensure a *consistent* coding style everywhere, which is automatically enforced during linting (since Prettier is used as an ESLint plugin). This thus ends "all" formatting disussions once and for all, removing the need for review comments on most stylistic matters. Many ESLint options are now redundant, and I've tried my best to remove all the now unnecessary options (but I may have missed some). Note also that since Prettier considers the `printWidth` option as a guide, rather than a hard rule, this patch resorts to a small hack in the ESLint config to ensure that *comments* won't become too long. *Please note:* This patch is generated automatically, by appending the `--fix` argument to the ESLint call used in the `gulp lint` task. It will thus require some additional clean-up, which will be done in a *separate* commit. (On a more personal note, I'll readily admit that some of the changes Prettier makes are *extremely* ugly. However, in the name of consistency we'll probably have to live with that.)
2019-12-25 23:59:37 +09:00
export { Jbig2Image };