function decodeSymbolDictionary()

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;
}