// SPDX-License-Identifier: AGPL-3.0-or-later mod formats; mod rgba; mod zstd_frame; mod zstd_stream; use formats::is_animated_image_bytes; use rgba::{TransformRequest, crop_rotate_rgba_alloc}; use wasm_bindgen::prelude::*; #[cfg(target_arch = "wasm32")] #[global_allocator] static WASM_ALLOCATOR: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; #[wasm_bindgen] #[allow(clippy::too_many_arguments)] pub fn crop_rotate_rgba_raw( input: &[u8], src_width: u32, src_height: u32, x: u32, y: u32, width: u32, height: u32, rotation_deg: u32, resize_width: Option, resize_height: Option, ) -> Result, JsValue> { crop_rotate_rgba_alloc( input, TransformRequest { src_width, src_height, x, y, width, height, rotation_deg, resize_width: optional_dimension_to_abi(resize_width), resize_height: optional_dimension_to_abi(resize_height), }, ) .map_err(|error| JsValue::from_str(error.message())) } #[wasm_bindgen] pub fn decompress_zstd_frame(input: &[u8]) -> Result, JsValue> { zstd_frame::decompress(input).map_err(zstd_error_to_js) } #[wasm_bindgen] pub fn create_zstd_stream_decoder() -> Result { let decoder = zstd_stream::ZstdStreamDecoder::new().map_err(zstd_error_to_js)?; leak_zstd_stream_decoder(decoder) .ok_or_else(|| JsValue::from_str("libfluxcore zstd stream decoder allocation failed")) } #[wasm_bindgen] pub fn free_zstd_stream_decoder(decoder_ptr: u32) { if decoder_ptr == 0 { return; } unsafe { drop(Box::from_raw( decoder_ptr as usize as *mut zstd_stream::ZstdStreamDecoder, )); } } #[wasm_bindgen] pub fn decompress_zstd_stream_chunk(decoder_ptr: u32, input: &[u8]) -> Result, JsValue> { if decoder_ptr == 0 { return Err(JsValue::from_str("zstd stream decoder is missing")); } let decoder = unsafe { &mut *(decoder_ptr as usize as *mut zstd_stream::ZstdStreamDecoder) }; decoder.decompress_chunk(input).map_err(zstd_error_to_js) } #[wasm_bindgen] pub fn create_zstd_stream_encoder(level: i32) -> Result { let encoder = zstd_stream::ZstdStreamEncoder::new(level).map_err(zstd_error_to_js)?; leak_zstd_stream_encoder(encoder) .ok_or_else(|| JsValue::from_str("libfluxcore zstd stream encoder allocation failed")) } #[wasm_bindgen] pub fn free_zstd_stream_encoder(encoder_ptr: u32) { if encoder_ptr == 0 { return; } unsafe { drop(Box::from_raw( encoder_ptr as usize as *mut zstd_stream::ZstdStreamEncoder, )); } } #[wasm_bindgen] pub fn compress_zstd_stream_chunk(encoder_ptr: u32, input: &[u8]) -> Result, JsValue> { if encoder_ptr == 0 { return Err(JsValue::from_str("zstd stream encoder is missing")); } let encoder = unsafe { &mut *(encoder_ptr as usize as *mut zstd_stream::ZstdStreamEncoder) }; encoder.compress_chunk(input).map_err(zstd_error_to_js) } #[wasm_bindgen] pub fn is_animated_image(input: &[u8]) -> bool { is_animated_image_bytes(input) } fn optional_dimension_to_abi(value: Option) -> u32 { value.filter(|dimension| *dimension > 0).unwrap_or(u32::MAX) } fn zstd_error_to_js(error: zstd_frame::ZstdError) -> JsValue { JsValue::from_str(error.message()) } fn leak_zstd_stream_decoder(decoder: zstd_stream::ZstdStreamDecoder) -> Option { let ptr = Box::into_raw(Box::new(decoder)); match u32::try_from(ptr as usize) { Ok(ptr) => Some(ptr), Err(_) => { unsafe { drop(Box::from_raw(ptr)); } None } } } fn leak_zstd_stream_encoder(encoder: zstd_stream::ZstdStreamEncoder) -> Option { let ptr = Box::into_raw(Box::new(encoder)); match u32::try_from(ptr as usize) { Ok(ptr) => Some(ptr), Err(_) => { unsafe { drop(Box::from_raw(ptr)); } None } } }