in src/core/jbig2.js [580:773]
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
);
} 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(
currentWidth,
currentHeight,
refinementTemplateIndex,
symbol,
rdx,
rdy,
false,
refinementAt,
decodingContext
);
}
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);
}
}
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));
}
newSymbols.push(symbolBitmap);
xMin = xMax;
}
}
}
}
// 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;
}