use crate::interpret_diff;
use blazediff::DiffOptions;
use blazediff_shared::Image;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(start)]
pub fn _start() {
console_error_panic_hook::set_once();
}
fn image_from_vec(rgba: Vec<u8>, width: u32, height: u32, label: &str) -> Result<Image, 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(Image {
data: rgba,
width,
height,
})
}
fn copy_output(
target: Option<js_sys::Uint8Array>,
output: Option<&Image>,
has_diff: bool,
) -> Result<(), JsError> {
let (Some(target), Some(output)) = (target, output) else {
return Ok(());
};
if target.length() as usize != output.data.len() {
return Err(JsError::new(&format!(
"out_diff: expected {} bytes, got {}",
output.data.len(),
target.length()
)));
}
if has_diff {
target.copy_from(&output.data);
}
Ok(())
}
#[wasm_bindgen(js_name = interpretRgba)]
pub fn interpret_rgba(
rgba_a: Vec<u8>,
rgba_b: Vec<u8>,
width: u32,
height: u32,
threshold: f64,
antialiasing: bool,
out_diff: Option<js_sys::Uint8Array>,
) -> Result<JsValue, JsError> {
let img1 = image_from_vec(rgba_a, width, height, "rgba_a")?;
let img2 = image_from_vec(rgba_b, width, height, "rgba_b")?;
let defaults = DiffOptions::default();
let opts = DiffOptions {
threshold,
include_aa: !antialiasing,
..defaults
};
let mut output_image = out_diff.as_ref().map(|_| Image::new_uninit(width, height));
let result = interpret_diff(&img1, &img2, output_image.as_mut(), &opts)
.map_err(|e| JsError::new(&e.to_string()))?;
copy_output(out_diff, output_image.as_ref(), result.diff_count > 0)?;
serde_wasm_bindgen::to_value(&result).map_err(|e| JsError::new(&e.to_string()))
}