@raven-js/cortex
Version:
Zero-dependency machine learning, AI, and data processing library for modern JavaScript
80 lines (70 loc) • 2.57 kB
JavaScript
/**
* @author Anonyfox <max@anonyfox.com>
* @license MIT
* @see {@link https://github.com/Anonyfox/ravenjs}
* @see {@link https://ravenjs.dev}
* @see {@link https://anonyfox.com}
*/
/**
* @file JPEG quantization tables and quality scaling.
*
* Provides base Annex K tables (natural order), and a scaling function that maps
* quality 1..100 to scaled Int32Array tables for Y and C with clamping to [1,255].
*/
import { zigZagToNatural } from "./zigzag.js";
/**
* Base JPEG quantization tables from Annex K (JFIF defaults), in zig-zag order.
* We convert to natural order at load time.
*/
const BASE_LUMA_ZZ = Uint8Array.from([
16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51,
87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99,
]);
const BASE_CHROMA_ZZ = Uint8Array.from([
17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99,
]);
/**
* Convert a zig-zag ordered 64-entry table to natural order Int32Array.
* @param {Uint8Array} zz
*/
function toNatural(zz) {
const out = new Int32Array(64);
for (let i = 0; i < 64; i++) out[zigZagToNatural[i]] = zz[i] | 0;
return out;
}
export const BASE_LUMA = toNatural(BASE_LUMA_ZZ);
export const BASE_CHROMA = toNatural(BASE_CHROMA_ZZ);
/**
* Map quality (1..100) to scale factor per standard mapping.
* @param {number} q
*/
export function qualityToScale(q) {
if (!Number.isFinite(q)) throw new Error("ERR_QUALITY: not finite");
const qc = Math.min(100, Math.max(1, Math.floor(q)));
return qc < 50 ? Math.floor(5000 / qc) : Math.floor(200 - 2 * qc);
}
/**
* Scale a base table by a scale factor (sf) and clamp to [1,255].
* @param {Int32Array} base
* @param {number} sf
*/
function scaleTable(base, sf) {
const out = new Int32Array(64);
for (let i = 0; i < 64; i++) {
const v = Math.floor((base[i] * sf + 50) / 100);
out[i] = v < 1 ? 1 : v > 255 ? 255 : v;
}
return out;
}
/**
* Compute scaled luma and chroma quant tables from quality 1..100.
* @param {number} quality
* @returns {{ qY: Int32Array, qC: Int32Array }}
*/
export function buildQuantTables(quality) {
const sf = qualityToScale(quality);
return { qY: scaleTable(BASE_LUMA, sf), qC: scaleTable(BASE_CHROMA, sf) };
}