wai-web: expose the byte-exact JPEG-AI mANS decode to wasm (decodeJpegAiMans) #51
1 changed files with 39 additions and 0 deletions
|
|
@ -133,3 +133,42 @@ pub fn det_build_index(sigma_q: i64, edges_q: &[i64]) -> usize {
|
|||
pub fn blake3_hex(bytes: &[u8]) -> String {
|
||||
blake3::hash(bytes).to_hex().to_string()
|
||||
}
|
||||
|
||||
// ---- JPEG-AI byte-exact mANS: the ISO entropy decode, in the browser ----
|
||||
|
||||
/// Decode the ISO/IEC 6048 JPEG-AI **mANS** entropy stream in the browser, byte-exact —
|
||||
/// the same pure-i64 decoder native sinks run (`wai::jpegai_mans`), compiled to wasm32.
|
||||
///
|
||||
/// A **reproduction vector**: given the reference stream `mem`, the integer PMF rows
|
||||
/// (`pmf_flat`, `n_rows × 256` row-major), the per-distribution `bounds`, and the
|
||||
/// per-position `sigma` distribution indices + coded-position `masks` (0/1), it returns
|
||||
/// the decoded residual symbols. The decode is entirely integer, so the symbols — and
|
||||
/// their hash — are identical on every machine. The page hashes them and compares to the
|
||||
/// digest the native reference produced; a byte-identical match across host + browser is
|
||||
/// the whole point of the integer-entropy contract. This is the same stream and
|
||||
/// symbols the cross-architecture byte-equality matrix checks natively.
|
||||
#[wasm_bindgen(js_name = decodeJpegAiMans)]
|
||||
pub fn decode_jpegai_mans(
|
||||
mem: &[u8],
|
||||
pmf_flat: &[i64],
|
||||
bounds: &[u8],
|
||||
sigma: &[u8],
|
||||
masks: &[u8],
|
||||
) -> Vec<i16> {
|
||||
use wai::jpegai_mans::{build_decode_transitions, cdf_from_pmf, MansDecoder};
|
||||
const WIDTH: usize = 256;
|
||||
let rows = pmf_flat.len() / WIDTH;
|
||||
let pmf: Vec<Vec<i64>> =
|
||||
(0..rows).map(|r| pmf_flat[r * WIDTH..(r + 1) * WIDTH].to_vec()).collect();
|
||||
let flat: Vec<u32> = build_decode_transitions(&pmf, &cdf_from_pmf(&pmf))
|
||||
.iter()
|
||||
.flatten()
|
||||
.copied()
|
||||
.collect();
|
||||
let mut dec = MansDecoder::new(mem, &[mem.len() as u32]);
|
||||
dec.set_sgm_transitions(&flat, bounds);
|
||||
let masks_b: Vec<bool> = masks.iter().map(|&m| m != 0).collect();
|
||||
let mut out = vec![0i16; sigma.len()];
|
||||
dec.decode_sgm(sigma, &mut out, &masks_b);
|
||||
out
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue