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