function quantizeAndInverse()

in src/core/jpg.js [466:704]


function quantizeAndInverse(component, blockBufferOffset, p) {
  const qt = component.quantizationTable,
    blockData = component.blockData;
  let v0, v1, v2, v3, v4, v5, v6, v7;
  let p0, p1, p2, p3, p4, p5, p6, p7;
  let t;

  if (!qt) {
    throw new JpegError("missing required Quantization Table.");
  }

  // inverse DCT on rows
  for (let row = 0; row < 64; row += 8) {
    // gather block data
    p0 = blockData[blockBufferOffset + row];
    p1 = blockData[blockBufferOffset + row + 1];
    p2 = blockData[blockBufferOffset + row + 2];
    p3 = blockData[blockBufferOffset + row + 3];
    p4 = blockData[blockBufferOffset + row + 4];
    p5 = blockData[blockBufferOffset + row + 5];
    p6 = blockData[blockBufferOffset + row + 6];
    p7 = blockData[blockBufferOffset + row + 7];

    // dequant p0
    p0 *= qt[row];

    // check for all-zero AC coefficients
    if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
      t = (dctSqrt2 * p0 + 512) >> 10;
      p[row] = t;
      p[row + 1] = t;
      p[row + 2] = t;
      p[row + 3] = t;
      p[row + 4] = t;
      p[row + 5] = t;
      p[row + 6] = t;
      p[row + 7] = t;
      continue;
    }
    // dequant p1 ... p7
    p1 *= qt[row + 1];
    p2 *= qt[row + 2];
    p3 *= qt[row + 3];
    p4 *= qt[row + 4];
    p5 *= qt[row + 5];
    p6 *= qt[row + 6];
    p7 *= qt[row + 7];

    // stage 4
    v0 = (dctSqrt2 * p0 + 128) >> 8;
    v1 = (dctSqrt2 * p4 + 128) >> 8;
    v2 = p2;
    v3 = p6;
    v4 = (dctSqrt1d2 * (p1 - p7) + 128) >> 8;
    v7 = (dctSqrt1d2 * (p1 + p7) + 128) >> 8;
    v5 = p3 << 4;
    v6 = p5 << 4;

    // stage 3
    v0 = (v0 + v1 + 1) >> 1;
    v1 = v0 - v1;
    t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
    v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
    v3 = t;
    v4 = (v4 + v6 + 1) >> 1;
    v6 = v4 - v6;
    v7 = (v7 + v5 + 1) >> 1;
    v5 = v7 - v5;

    // stage 2
    v0 = (v0 + v3 + 1) >> 1;
    v3 = v0 - v3;
    v1 = (v1 + v2 + 1) >> 1;
    v2 = v1 - v2;
    t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
    v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
    v7 = t;
    t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
    v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
    v6 = t;

    // stage 1
    p[row] = v0 + v7;
    p[row + 7] = v0 - v7;
    p[row + 1] = v1 + v6;
    p[row + 6] = v1 - v6;
    p[row + 2] = v2 + v5;
    p[row + 5] = v2 - v5;
    p[row + 3] = v3 + v4;
    p[row + 4] = v3 - v4;
  }

  // inverse DCT on columns
  for (let col = 0; col < 8; ++col) {
    p0 = p[col];
    p1 = p[col + 8];
    p2 = p[col + 16];
    p3 = p[col + 24];
    p4 = p[col + 32];
    p5 = p[col + 40];
    p6 = p[col + 48];
    p7 = p[col + 56];

    // check for all-zero AC coefficients
    if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
      t = (dctSqrt2 * p0 + 8192) >> 14;
      // Convert to 8-bit.
      if (t < -2040) {
        t = 0;
      } else if (t >= 2024) {
        t = 255;
      } else {
        t = (t + 2056) >> 4;
      }
      blockData[blockBufferOffset + col] = t;
      blockData[blockBufferOffset + col + 8] = t;
      blockData[blockBufferOffset + col + 16] = t;
      blockData[blockBufferOffset + col + 24] = t;
      blockData[blockBufferOffset + col + 32] = t;
      blockData[blockBufferOffset + col + 40] = t;
      blockData[blockBufferOffset + col + 48] = t;
      blockData[blockBufferOffset + col + 56] = t;
      continue;
    }

    // stage 4
    v0 = (dctSqrt2 * p0 + 2048) >> 12;
    v1 = (dctSqrt2 * p4 + 2048) >> 12;
    v2 = p2;
    v3 = p6;
    v4 = (dctSqrt1d2 * (p1 - p7) + 2048) >> 12;
    v7 = (dctSqrt1d2 * (p1 + p7) + 2048) >> 12;
    v5 = p3;
    v6 = p5;

    // stage 3
    // Shift v0 by 128.5 << 5 here, so we don't need to shift p0...p7 when
    // converting to UInt8 range later.
    v0 = ((v0 + v1 + 1) >> 1) + 4112;
    v1 = v0 - v1;
    t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
    v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
    v3 = t;
    v4 = (v4 + v6 + 1) >> 1;
    v6 = v4 - v6;
    v7 = (v7 + v5 + 1) >> 1;
    v5 = v7 - v5;

    // stage 2
    v0 = (v0 + v3 + 1) >> 1;
    v3 = v0 - v3;
    v1 = (v1 + v2 + 1) >> 1;
    v2 = v1 - v2;
    t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
    v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
    v7 = t;
    t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
    v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
    v6 = t;

    // stage 1
    p0 = v0 + v7;
    p7 = v0 - v7;
    p1 = v1 + v6;
    p6 = v1 - v6;
    p2 = v2 + v5;
    p5 = v2 - v5;
    p3 = v3 + v4;
    p4 = v3 - v4;

    // Convert to 8-bit integers.
    if (p0 < 16) {
      p0 = 0;
    } else if (p0 >= 4080) {
      p0 = 255;
    } else {
      p0 >>= 4;
    }
    if (p1 < 16) {
      p1 = 0;
    } else if (p1 >= 4080) {
      p1 = 255;
    } else {
      p1 >>= 4;
    }
    if (p2 < 16) {
      p2 = 0;
    } else if (p2 >= 4080) {
      p2 = 255;
    } else {
      p2 >>= 4;
    }
    if (p3 < 16) {
      p3 = 0;
    } else if (p3 >= 4080) {
      p3 = 255;
    } else {
      p3 >>= 4;
    }
    if (p4 < 16) {
      p4 = 0;
    } else if (p4 >= 4080) {
      p4 = 255;
    } else {
      p4 >>= 4;
    }
    if (p5 < 16) {
      p5 = 0;
    } else if (p5 >= 4080) {
      p5 = 255;
    } else {
      p5 >>= 4;
    }
    if (p6 < 16) {
      p6 = 0;
    } else if (p6 >= 4080) {
      p6 = 255;
    } else {
      p6 >>= 4;
    }
    if (p7 < 16) {
      p7 = 0;
    } else if (p7 >= 4080) {
      p7 = 255;
    } else {
      p7 >>= 4;
    }

    // store block data
    blockData[blockBufferOffset + col] = p0;
    blockData[blockBufferOffset + col + 8] = p1;
    blockData[blockBufferOffset + col + 16] = p2;
    blockData[blockBufferOffset + col + 24] = p3;
    blockData[blockBufferOffset + col + 32] = p4;
    blockData[blockBufferOffset + col + 40] = p5;
    blockData[blockBufferOffset + col + 48] = p6;
    blockData[blockBufferOffset + col + 56] = p7;
  }
}