ltmarx / core /dct.ts
harelcain's picture
Upload 37 files
f2f99a3 verified
/**
* 8x8 DCT forward and inverse transforms
* Separable implementation: rows then columns β€” O(N^3) instead of O(N^4)
* Reuses temp buffers to avoid per-call allocations
*/
const N = 8;
// Precompute cosine table: cos((2i+1)*j*PI / 16) for i,j in [0,8)
const COS_TABLE = new Float64Array(N * N);
for (let i = 0; i < N; i++) {
for (let j = 0; j < N; j++) {
COS_TABLE[i * N + j] = Math.cos(((2 * i + 1) * j * Math.PI) / (2 * N));
}
}
// Precompute alpha normalization table: alpha(u) * alpha(v) for all (u,v)
const ALPHA_0 = 1 / Math.sqrt(N);
const ALPHA_K = Math.sqrt(2 / N);
const ALPHA_UV = new Float64Array(N * N);
const ALPHA = new Float64Array(N);
for (let k = 0; k < N; k++) ALPHA[k] = k === 0 ? ALPHA_0 : ALPHA_K;
for (let u = 0; u < N; u++) {
for (let v = 0; v < N; v++) {
ALPHA_UV[u * N + v] = ALPHA[u] * ALPHA[v];
}
}
// Precompute scaled cosine: ALPHA[k] * COS_TABLE[i*N+k] for forward transform
const SCALED_COS = new Float64Array(N * N);
for (let i = 0; i < N; i++) {
for (let k = 0; k < N; k++) {
SCALED_COS[i * N + k] = ALPHA[k] * COS_TABLE[i * N + k];
}
}
// Shared temp buffers (avoids allocation per call)
const _temp64 = new Float64Array(64);
const _temp8 = new Float64Array(8);
/**
* Forward 8x8 DCT on a block (in-place)
* Separable: transform rows, then columns β€” O(8^3) = 512 ops vs O(8^4) = 4096
*/
export function dctForward8x8(block: Float64Array): void {
// Step 1: Transform each row (spatial x β†’ frequency v)
for (let x = 0; x < N; x++) {
const rowOff = x * N;
for (let v = 0; v < N; v++) {
let sum = 0;
for (let y = 0; y < N; y++) {
sum += block[rowOff + y] * COS_TABLE[y * N + v];
}
_temp64[rowOff + v] = ALPHA[v] * sum;
}
}
// Step 2: Transform each column (spatial x β†’ frequency u)
for (let v = 0; v < N; v++) {
for (let u = 0; u < N; u++) {
let sum = 0;
for (let x = 0; x < N; x++) {
sum += _temp64[x * N + v] * COS_TABLE[x * N + u];
}
block[u * N + v] = ALPHA[u] * sum;
}
}
}
/**
* Inverse 8x8 DCT on a block (in-place)
* Separable: inverse columns, then inverse rows
*/
export function dctInverse8x8(block: Float64Array): void {
// Step 1: Inverse transform columns (frequency u β†’ spatial x)
for (let v = 0; v < N; v++) {
for (let x = 0; x < N; x++) {
let sum = 0;
for (let u = 0; u < N; u++) {
sum += ALPHA[u] * block[u * N + v] * COS_TABLE[x * N + u];
}
_temp64[x * N + v] = sum;
}
}
// Step 2: Inverse transform rows (frequency v β†’ spatial y)
for (let x = 0; x < N; x++) {
const rowOff = x * N;
for (let y = 0; y < N; y++) {
let sum = 0;
for (let v = 0; v < N; v++) {
sum += ALPHA[v] * _temp64[rowOff + v] * COS_TABLE[y * N + v];
}
block[rowOff + y] = sum;
}
}
}
/**
* Zigzag scan order for 8x8 block
* Maps zigzag index β†’ [row, col]
*/
export const ZIGZAG_ORDER: [number, number][] = [
[0,0],[0,1],[1,0],[2,0],[1,1],[0,2],[0,3],[1,2],
[2,1],[3,0],[4,0],[3,1],[2,2],[1,3],[0,4],[0,5],
[1,4],[2,3],[3,2],[4,1],[5,0],[6,0],[5,1],[4,2],
[3,3],[2,4],[1,5],[0,6],[0,7],[1,6],[2,5],[3,4],
[4,3],[5,2],[6,1],[7,0],[7,1],[6,2],[5,3],[4,4],
[3,5],[2,6],[1,7],[2,7],[3,6],[4,5],[5,4],[6,3],
[7,2],[7,3],[6,4],[5,5],[4,6],[3,7],[4,7],[5,6],
[6,5],[7,4],[7,5],[6,6],[5,7],[6,7],[7,6],[7,7],
];
/**
* Extract an 8x8 block from a subband into a reusable buffer
*/
export function extractBlock(
data: Float64Array,
width: number,
blockRow: number,
blockCol: number,
out?: Float64Array
): Float64Array {
const block = out || new Float64Array(64);
const startY = blockRow * 8;
const startX = blockCol * 8;
for (let r = 0; r < 8; r++) {
const srcOff = (startY + r) * width + startX;
const dstOff = r * 8;
for (let c = 0; c < 8; c++) {
block[dstOff + c] = data[srcOff + c];
}
}
return block;
}
/**
* Write an 8x8 block back into a subband
*/
export function writeBlock(
data: Float64Array,
width: number,
blockRow: number,
blockCol: number,
block: Float64Array
): void {
const startY = blockRow * 8;
const startX = blockCol * 8;
for (let r = 0; r < 8; r++) {
const dstOff = (startY + r) * width + startX;
const srcOff = r * 8;
for (let c = 0; c < 8; c++) {
data[dstOff + c] = block[srcOff + c];
}
}
}