use crate::{milo, MiloOptions, Rgba8};
use wasm_bindgen::prelude::*;
#[wasm_bindgen(start)]
pub fn _start() {
console_error_panic_hook::set_once();
}
#[wasm_bindgen]
pub struct MiloResult {
raw_error: f64,
mos: f64,
mask: Vec<f32>,
error_map: Vec<f32>,
width: u32,
height: u32,
}
#[wasm_bindgen]
impl MiloResult {
#[wasm_bindgen(getter, js_name = rawError)]
pub fn raw_error(&self) -> f64 {
self.raw_error
}
#[wasm_bindgen(getter)]
pub fn mos(&self) -> f64 {
self.mos
}
#[wasm_bindgen(getter)]
pub fn width(&self) -> u32 {
self.width
}
#[wasm_bindgen(getter)]
pub fn height(&self) -> u32 {
self.height
}
pub fn mask(&self) -> Vec<f32> {
self.mask.clone()
}
#[wasm_bindgen(js_name = errorMap)]
pub fn error_map(&self) -> Vec<f32> {
self.error_map.clone()
}
}
fn checked(rgba: Vec<u8>, width: u32, height: u32, label: &str) -> Result<Vec<u8>, JsError> {
let expected = (width as usize)
.checked_mul(height as usize)
.and_then(|v| v.checked_mul(4))
.ok_or_else(|| JsError::new("width*height overflow"))?;
if rgba.len() != expected {
return Err(JsError::new(&format!(
"{}: expected {} bytes (width*height*4), got {}",
label,
expected,
rgba.len()
)));
}
Ok(rgba)
}
#[wasm_bindgen(js_name = miloRgba)]
pub fn milo_rgba(
reference: Vec<u8>,
distorted: Vec<u8>,
width: u32,
height: u32,
) -> Result<MiloResult, JsError> {
let reference = checked(reference, width, height, "reference")?;
let distorted = checked(distorted, width, height, "distorted")?;
let (w, h) = (width as usize, height as usize);
let outcome = milo(
Rgba8::new(&reference, w, h),
Rgba8::new(&distorted, w, h),
&MiloOptions::default(),
)
.map_err(|e| JsError::new(&e.to_string()))?;
Ok(MiloResult {
raw_error: outcome.raw_error,
mos: outcome.mos,
mask: outcome.mask,
error_map: outcome.error_map,
width,
height,
})
}