//! The LIVE JPEG AI decode: `jpegai::decode(codestream, model)` → RGB, with no //! per-image schedule fixtures. Every per-image quantity is derived from the //! bitstream (the residual mask `sigma_skip > 382`, the σ surfaces, indexes, //! rvs); the model bundle supplies only checkpoint constants. Compared against //! the reference decoder's PNG — the same bar as the staged `jpegai_e2e` test, //! but through the dispatchable library entry point. //! //! This is the whole-decode test behind the dispatchable `wai.image.jpegai` ONNX //! path, so a missing input follows the headline-claim rule (support/ //! require_vectors.rs): without its inputs it skips loudly, and with //! `WAI_REQUIRE_SOTA_VECTORS=1` it fails. Its inputs — the float model bundle, the //! traced nets under `model16/`, the extracted model constants and the reference //! PNG — exist only in the local JPEG-AI asset directory //! (`wai/jpegai-vm-assets`, exported from the ISO/IEC 6048-1 reference software; //! not in the repository), and the test also needs the `neural` (ONNX Runtime) and //! `codecs` features. No CI job runs it; it is verified only on a machine holding //! those assets. `WAI_JPEGAI_ASSETS` points it at the directory from elsewhere; a //! directory it names must exist and hold every input, or the test fails with or //! without the switch. Unset or empty, the default below is used, and only that //! default may be absent and skip. #![cfg(all(feature = "neural", feature = "codecs"))] #[path = "support/require_vectors.rs"] mod require_vectors; use require_vectors::InputDir; use wai::neural::jpegai::{decode, JpegAiModel}; const TEST: &str = "jpegai_live::jpegai_live_decode_matches_reference"; const PRODUCE: &str = "the local JPEG-AI asset directory wai/jpegai-vm-assets (exported from the \ ISO/IEC 6048-1 reference software; not in the repository), or WAI_JPEGAI_ASSETS="; /// `WAI_JPEGAI_ASSETS`, else `../jpegai-vm-assets` beside the crate. A variable that /// names a directory that does not exist, or one missing an input, is a /// misconfigured run and fails. fn assets() -> InputDir { require_vectors::env_dir(TEST, "WAI_JPEGAI_ASSETS", "../jpegai-vm-assets", PRODUCE) } #[test] fn jpegai_live_decode_matches_reference() { let a = assets(); // Needs the model bundle (incl. the extracted model-constant files) + the // 256×256 traced nets + the reference PNG. let missing: Vec<&str> = [ "e2e/test256.bin", "e2e/test256_dec.png", "jpegai_factorized_cdfs.json", "jpegai_scaler_vec.json", "jpegai_dequant_consts.json", "model16/CCS_SGMM", ] .into_iter() .filter(|need| !a.join(need).exists()) .collect(); if !missing.is_empty() { a.absent( TEST, &format!("{} not in {}", missing.join(", "), a.display()), PRODUCE, ); return; } let model = JpegAiModel::load(&a).expect("load jpeg-ai model bundle"); let codestream = std::fs::read(a.join("e2e/test256.bin")).unwrap(); let img = decode(&codestream, &model).expect("jpeg-ai decode"); assert_eq!((img.width, img.height), (256, 256)); assert_eq!(img.rgb.len(), 256 * 256 * 3); let refimg = image::open(a.join("e2e/test256_dec.png")).unwrap().to_rgb8(); let mut mismatched = 0usize; let mut maxdiff = 0i32; for i in 0..256 * 256 { let px = refimg.get_pixel((i % 256) as u32, (i / 256) as u32); for c in 0..3 { let d = (img.rgb[i * 3 + c] as i32 - px[c] as i32).abs(); if d > 0 { mismatched += 1; } maxdiff = maxdiff.max(d); } } let total = 3 * 256 * 256; println!("live jpeg-ai decode: {mismatched}/{total} samples differ, max diff {maxdiff}"); assert!(maxdiff <= 1, "pixel deviation beyond rounding: {maxdiff}"); assert!(mismatched * 1000 <= total, "more than 0.1% mismatched: {mismatched}/{total}"); }