mirror of
https://github.com/Cykooz/fast_image_resize.git
synced 2026-10-08 01:11:09 +00:00
- Allowed to create an instance of Image, ImageVew and ImageViewMut from a buffer larger than necessary (#5).
- Removed methods: `Image::from_vec_u32()`, `Image::from_slice_u32()`. - Removed error `InvalidBufferSizeError`.
This commit is contained in:
@@ -110,6 +110,7 @@ impl NormalizerGuard16 {
|
||||
pub unsafe fn clip(&self, v: i32) -> u8 {
|
||||
let index = (640 + (v >> self.precision)) as usize;
|
||||
// index must be in range [(640-512)..(640+511)]
|
||||
debug_assert!((128..=1151).contains(&index));
|
||||
*CLIP8_LOOKUPS.get_unchecked(index)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-8
@@ -1,6 +1,6 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug, Clone, Copy)]
|
||||
#[derive(Error, Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ImageRowsError {
|
||||
#[error("Count of rows don't match to image height")]
|
||||
InvalidRowsCount,
|
||||
@@ -8,19 +8,15 @@ pub enum ImageRowsError {
|
||||
InvalidRowSize,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Clone, Copy)]
|
||||
#[error("Size of buffer don't match to image dimensions")]
|
||||
pub struct InvalidBufferSizeError;
|
||||
|
||||
#[derive(Error, Debug, Clone, Copy)]
|
||||
#[derive(Error, Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ImageBufferError {
|
||||
#[error("Size of buffer don't match to image dimensions")]
|
||||
#[error("Size of buffer is smaller than required.")]
|
||||
InvalidBufferSize,
|
||||
#[error("Alignment of buffer don't match to alignment of u32")]
|
||||
InvalidBufferAlignment,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Clone, Copy)]
|
||||
#[derive(Error, Debug, Clone, Copy, PartialEq)]
|
||||
pub enum CropBoxError {
|
||||
#[error("Position of the crop box is out of the image boundaries")]
|
||||
PositionIsOutOfImageBoundaries,
|
||||
|
||||
+81
-60
@@ -2,13 +2,11 @@ use std::num::NonZeroU32;
|
||||
|
||||
use crate::image_view::{ImageRows, ImageRowsMut, TypedImageView, TypedImageViewMut};
|
||||
use crate::pixels::{Pixel, PixelType, U16x3, U8x3, U8x4, F32, I32, U8};
|
||||
use crate::{ImageBufferError, ImageView, ImageViewMut, InvalidBufferSizeError};
|
||||
use crate::{ImageBufferError, ImageView, ImageViewMut};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum PixelsContainer<'a> {
|
||||
MutU32(&'a mut [u32]),
|
||||
MutU8(&'a mut [u8]),
|
||||
VecU32(Vec<u32>),
|
||||
VecU8(Vec<u8>),
|
||||
}
|
||||
|
||||
@@ -28,9 +26,9 @@ impl<'a> Image<'a> {
|
||||
let pixels = match pixel_type {
|
||||
PixelType::U8x3 => PixelsContainer::VecU8(vec![0; pixels_count * U8x3::size()]),
|
||||
PixelType::U16x3 => PixelsContainer::VecU8(vec![0; pixels_count * U16x3::size()]),
|
||||
PixelType::U8x4 | PixelType::I32 | PixelType::F32 => {
|
||||
PixelsContainer::VecU32(vec![0; pixels_count])
|
||||
}
|
||||
PixelType::U8x4 => PixelsContainer::VecU8(vec![0; pixels_count * U8x4::size()]),
|
||||
PixelType::I32 => PixelsContainer::VecU8(vec![0; pixels_count * I32::size()]),
|
||||
PixelType::F32 => PixelsContainer::VecU8(vec![0; pixels_count * F32::size()]),
|
||||
PixelType::U8 => PixelsContainer::VecU8(vec![0; pixels_count]),
|
||||
};
|
||||
Self {
|
||||
@@ -41,24 +39,6 @@ impl<'a> Image<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_vec_u32(
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
buffer: Vec<u32>,
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, InvalidBufferSizeError> {
|
||||
let size = (width.get() * height.get()) as usize;
|
||||
if buffer.len() != size {
|
||||
return Err(InvalidBufferSizeError);
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
pixels: PixelsContainer::VecU32(buffer),
|
||||
pixel_type,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_vec_u8(
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
@@ -66,7 +46,7 @@ impl<'a> Image<'a> {
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, ImageBufferError> {
|
||||
let size = (width.get() * height.get()) as usize * pixel_type.size();
|
||||
if buffer.len() != size {
|
||||
if buffer.len() < size {
|
||||
return Err(ImageBufferError::InvalidBufferSize);
|
||||
}
|
||||
if !pixel_type.is_aligned(&buffer) {
|
||||
@@ -80,24 +60,6 @@ impl<'a> Image<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_slice_u32(
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
buffer: &'a mut [u32],
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, InvalidBufferSizeError> {
|
||||
let size = (width.get() * height.get()) as usize;
|
||||
if buffer.len() != size {
|
||||
return Err(InvalidBufferSizeError);
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
pixels: PixelsContainer::MutU32(buffer),
|
||||
pixel_type,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_slice_u8(
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
@@ -105,7 +67,7 @@ impl<'a> Image<'a> {
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, ImageBufferError> {
|
||||
let size = (width.get() * height.get()) as usize * pixel_type.size();
|
||||
if buffer.len() != size {
|
||||
if buffer.len() < size {
|
||||
return Err(ImageBufferError::InvalidBufferSize);
|
||||
}
|
||||
if !pixel_type.is_aligned(buffer) {
|
||||
@@ -138,19 +100,16 @@ impl<'a> Image<'a> {
|
||||
#[inline(always)]
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
match &self.pixels {
|
||||
PixelsContainer::MutU32(p) => unsafe { p.align_to::<u8>().1 },
|
||||
PixelsContainer::MutU8(p) => *p,
|
||||
PixelsContainer::VecU32(v) => unsafe { v.align_to::<u8>().1 },
|
||||
PixelsContainer::VecU8(v) => v,
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutable buffer with image pixels.
|
||||
#[inline(always)]
|
||||
fn buffer_mut(&mut self) -> &mut [u8] {
|
||||
match &mut self.pixels {
|
||||
PixelsContainer::MutU32(p) => unsafe { p.align_to_mut::<u8>().1 },
|
||||
PixelsContainer::MutU8(p) => p,
|
||||
PixelsContainer::VecU32(ref mut v) => unsafe { v.align_to_mut::<u8>().1 },
|
||||
PixelsContainer::VecU8(ref mut v) => v.as_mut_slice(),
|
||||
}
|
||||
}
|
||||
@@ -158,30 +117,61 @@ impl<'a> Image<'a> {
|
||||
#[inline(always)]
|
||||
pub fn view(&self) -> ImageView {
|
||||
let buffer = self.buffer();
|
||||
let rows_count = self.height.get() as usize;
|
||||
let rows = match self.pixel_type {
|
||||
PixelType::U8x3 => {
|
||||
let pixels = unsafe { buffer.align_to::<U8x3>().1 };
|
||||
ImageRows::U8x3(pixels.chunks_exact(self.width.get() as usize).collect())
|
||||
ImageRows::U8x3(
|
||||
pixels
|
||||
.chunks_exact(self.width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U8x4 => {
|
||||
let pixels = unsafe { buffer.align_to::<U8x4>().1 };
|
||||
ImageRows::U8x4(pixels.chunks_exact(self.width.get() as usize).collect())
|
||||
ImageRows::U8x4(
|
||||
pixels
|
||||
.chunks_exact(self.width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U16x3 => {
|
||||
let pixels = unsafe { buffer.align_to::<U16x3>().1 };
|
||||
ImageRows::U16x3(pixels.chunks_exact(self.width.get() as usize).collect())
|
||||
ImageRows::U16x3(
|
||||
pixels
|
||||
.chunks_exact(self.width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::I32 => {
|
||||
let pixels = unsafe { buffer.align_to::<I32>().1 };
|
||||
ImageRows::I32(pixels.chunks_exact(self.width.get() as usize).collect())
|
||||
ImageRows::I32(
|
||||
pixels
|
||||
.chunks_exact(self.width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::F32 => {
|
||||
let pixels = unsafe { buffer.align_to::<F32>().1 };
|
||||
ImageRows::F32(pixels.chunks_exact(self.width.get() as usize).collect())
|
||||
ImageRows::F32(
|
||||
pixels
|
||||
.chunks_exact(self.width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U8 => {
|
||||
let pixels = unsafe { buffer.align_to::<U8>().1 };
|
||||
ImageRows::U8(pixels.chunks_exact(self.width.get() as usize).collect())
|
||||
ImageRows::U8(
|
||||
pixels
|
||||
.chunks_exact(self.width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
};
|
||||
ImageView::new(self.width, self.height, rows).unwrap()
|
||||
@@ -193,30 +183,61 @@ impl<'a> Image<'a> {
|
||||
let width = self.width;
|
||||
let height = self.height;
|
||||
let buffer = self.buffer_mut();
|
||||
let rows_count = height.get() as usize;
|
||||
let rows = match pixel_type {
|
||||
PixelType::U8x3 => {
|
||||
let pixels = unsafe { buffer.align_to_mut::<U8x3>().1 };
|
||||
ImageRowsMut::U8x3(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::U8x3(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U8x4 => {
|
||||
let pixels = unsafe { buffer.align_to_mut::<U8x4>().1 };
|
||||
ImageRowsMut::U8x4(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::U8x4(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U16x3 => {
|
||||
let pixels = unsafe { buffer.align_to_mut::<U16x3>().1 };
|
||||
ImageRowsMut::U16x3(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::U16x3(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::I32 => {
|
||||
let pixels = unsafe { buffer.align_to_mut::<I32>().1 };
|
||||
ImageRowsMut::I32(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::I32(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::F32 => {
|
||||
let pixels = unsafe { buffer.align_to_mut::<F32>().1 };
|
||||
ImageRowsMut::F32(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::F32(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U8 => {
|
||||
let pixels = unsafe { buffer.align_to_mut::<U8>().1 };
|
||||
ImageRowsMut::U8(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::U8(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
};
|
||||
ImageViewMut::new(width, height, rows).unwrap()
|
||||
|
||||
+76
-14
@@ -137,33 +137,64 @@ impl<'a> ImageView<'a> {
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, ImageBufferError> {
|
||||
let size = (width.get() * height.get()) as usize * pixel_type.size();
|
||||
if buffer.len() != size {
|
||||
if buffer.len() < size {
|
||||
return Err(ImageBufferError::InvalidBufferSize);
|
||||
}
|
||||
let rows_count = height.get() as usize;
|
||||
let rows = match pixel_type {
|
||||
PixelType::U8x3 => {
|
||||
let pixels = align_buffer_to(buffer)?;
|
||||
ImageRows::U8x3(pixels.chunks_exact(width.get() as usize).collect())
|
||||
ImageRows::U8x3(
|
||||
pixels
|
||||
.chunks_exact(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U8x4 => {
|
||||
let pixels = align_buffer_to(buffer)?;
|
||||
ImageRows::U8x4(pixels.chunks_exact(width.get() as usize).collect())
|
||||
ImageRows::U8x4(
|
||||
pixels
|
||||
.chunks_exact(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U16x3 => {
|
||||
let pixels = align_buffer_to(buffer)?;
|
||||
ImageRows::U16x3(pixels.chunks_exact(width.get() as usize).collect())
|
||||
ImageRows::U16x3(
|
||||
pixels
|
||||
.chunks_exact(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::I32 => {
|
||||
let pixels = align_buffer_to(buffer)?;
|
||||
ImageRows::I32(pixels.chunks_exact(width.get() as usize).collect())
|
||||
ImageRows::I32(
|
||||
pixels
|
||||
.chunks_exact(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::F32 => {
|
||||
let pixels = align_buffer_to(buffer)?;
|
||||
ImageRows::F32(pixels.chunks_exact(width.get() as usize).collect())
|
||||
ImageRows::F32(
|
||||
pixels
|
||||
.chunks_exact(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U8 => {
|
||||
let pixels = align_buffer_to(buffer)?;
|
||||
ImageRows::U8(pixels.chunks_exact(width.get() as usize).collect())
|
||||
ImageRows::U8(
|
||||
pixels
|
||||
.chunks_exact(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
};
|
||||
Ok(Self {
|
||||
@@ -486,33 +517,64 @@ impl<'a> ImageViewMut<'a> {
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, ImageBufferError> {
|
||||
let size = (width.get() * height.get()) as usize * pixel_type.size();
|
||||
if buffer.len() != size {
|
||||
if buffer.len() < size {
|
||||
return Err(ImageBufferError::InvalidBufferSize);
|
||||
}
|
||||
let rows_count = height.get() as usize;
|
||||
let rows = match pixel_type {
|
||||
PixelType::U8x3 => {
|
||||
let pixels = align_buffer_to_mut(buffer)?;
|
||||
ImageRowsMut::U8x3(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::U8x3(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U8x4 => {
|
||||
let pixels = align_buffer_to_mut(buffer)?;
|
||||
ImageRowsMut::U8x4(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::U8x4(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U16x3 => {
|
||||
let pixels = align_buffer_to_mut(buffer)?;
|
||||
ImageRowsMut::U16x3(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::U16x3(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::I32 => {
|
||||
let pixels = align_buffer_to_mut(buffer)?;
|
||||
ImageRowsMut::I32(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::I32(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::F32 => {
|
||||
let pixels = align_buffer_to_mut(buffer)?;
|
||||
ImageRowsMut::F32(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::F32(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
PixelType::U8 => {
|
||||
let pixels = align_buffer_to_mut(buffer)?;
|
||||
ImageRowsMut::U8(pixels.chunks_exact_mut(width.get() as usize).collect())
|
||||
ImageRowsMut::U8(
|
||||
pixels
|
||||
.chunks_exact_mut(width.get() as usize)
|
||||
.take(rows_count)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
};
|
||||
Ok(Self {
|
||||
|
||||
+10
-11
@@ -178,17 +178,17 @@ fn divide_alpha_native_test() {
|
||||
|
||||
#[test]
|
||||
fn multiply_alpha_real_image_test() {
|
||||
let mut pixels = vec![0u32; 256 * 256];
|
||||
let mut pixels = vec![0u8; 256 * 256 * 4];
|
||||
let mut i: usize = 0;
|
||||
for alpha in 0..=255u8 {
|
||||
for color in 0..=255u8 {
|
||||
let pixel = u32::from_le_bytes([color, color, color, alpha]);
|
||||
pixels[i] = pixel;
|
||||
i += 1;
|
||||
let pixel = pixels.get_mut(i..i + 4).unwrap();
|
||||
pixel.copy_from_slice(&[color, color, color, alpha]);
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
let size = NonZeroU32::new(256).unwrap();
|
||||
let src_image = Image::from_vec_u32(size, size, pixels, PixelType::U8x4).unwrap();
|
||||
let src_image = Image::from_vec_u8(size, size, pixels, PixelType::U8x4).unwrap();
|
||||
let mut dst_image = Image::new(size, size, PixelType::U8x4);
|
||||
|
||||
let mut alpha_mul_div: MulDiv = Default::default();
|
||||
@@ -216,19 +216,18 @@ fn multiply_alpha_real_image_test() {
|
||||
|
||||
#[test]
|
||||
fn divide_alpha_real_image_test() {
|
||||
let mut pixels = vec![0u32; 256 * 256];
|
||||
let mut pixels = vec![0u8; 256 * 256 * 4];
|
||||
let mut i: usize = 0;
|
||||
for alpha in 0..=255u8 {
|
||||
for color in 0..=255u8 {
|
||||
let multiplied_color = (color as f64 * (alpha as f64 / 255.)).round().min(255.) as u8;
|
||||
let pixel =
|
||||
u32::from_le_bytes([multiplied_color, multiplied_color, multiplied_color, alpha]);
|
||||
pixels[i] = pixel;
|
||||
i += 1;
|
||||
let pixel = pixels.get_mut(i..i + 4).unwrap();
|
||||
pixel.copy_from_slice(&[multiplied_color, multiplied_color, multiplied_color, alpha]);
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
let size = NonZeroU32::new(256).unwrap();
|
||||
let src_image = Image::from_vec_u32(size, size, pixels, PixelType::U8x4).unwrap();
|
||||
let src_image = Image::from_vec_u8(size, size, pixels, PixelType::U8x4).unwrap();
|
||||
let mut dst_image = Image::new(size, size, PixelType::U8x4);
|
||||
|
||||
let mut alpha_mul_div: MulDiv = Default::default();
|
||||
|
||||
@@ -136,6 +136,28 @@ fn downscale_u8() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downscale_u8_1() {
|
||||
let src_vec = vec![1u8; 1280 * 720];
|
||||
let src_image = Image::from_vec_u8(
|
||||
NonZeroU32::new(1280).unwrap(),
|
||||
NonZeroU32::new(720).unwrap(),
|
||||
src_vec,
|
||||
PixelType::U8,
|
||||
)
|
||||
.unwrap();
|
||||
let mut dst_iamge = Image::new(
|
||||
NonZeroU32::new(64).unwrap(),
|
||||
NonZeroU32::new(64).unwrap(),
|
||||
PixelType::U8,
|
||||
);
|
||||
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
|
||||
unsafe { resizer.set_cpu_extensions(CpuExtensions::Avx2) };
|
||||
resizer
|
||||
.resize(&src_image.view(), &mut dst_iamge.view_mut())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upscale_u8() {
|
||||
type P = U8;
|
||||
|
||||
Reference in New Issue
Block a user