use crate::error::IoError;
use kornia_image::{Image, ImageSize};
pub const MAX_IMAGE_PIXELS: usize = 1 << 30;
pub fn check_image_dimensions(width: usize, height: usize) -> Result<(), IoError> {
match width.checked_mul(height) {
Some(pixels) if pixels <= MAX_IMAGE_PIXELS => Ok(()),
_ => Err(IoError::ImageTooLarge {
width,
height,
max_pixels: MAX_IMAGE_PIXELS,
}),
}
}
pub(crate) fn try_alloc_zeroed<T: Clone + Default>(len: usize) -> Result<Vec<T>, IoError> {
let mut buf = Vec::new();
buf.try_reserve_exact(len)
.map_err(|_| IoError::AllocationFailed(len.saturating_mul(std::mem::size_of::<T>())))?;
buf.resize(len, T::default());
Ok(buf)
}
pub(crate) fn alloc_image<T: Clone + Default, const C: usize>(
size: ImageSize,
) -> Result<Image<T, C>, IoError> {
check_image_dimensions(size.width, size.height)?;
let data = try_alloc_zeroed(size.checked_len(C)?)?;
Ok(Image::new(size, data)?)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rejects_oversized_and_overflowing_dimensions() {
assert!(check_image_dimensions(32768, 32768).is_ok());
assert!(check_image_dimensions(65535, 65535).is_err());
assert!(check_image_dimensions(usize::MAX, 2).is_err());
}
#[test]
fn alloc_image_checks_limits() -> Result<(), IoError> {
let img = alloc_image::<u16, 3>(ImageSize {
width: 4,
height: 2,
})?;
assert_eq!(img.as_slice(), &[0u16; 24]);
assert!(matches!(
alloc_image::<u8, 1>(ImageSize {
width: 65535,
height: 65535,
}),
Err(IoError::ImageTooLarge { .. })
));
Ok(())
}
}