- 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:
Kirill Kuzminykh
2022-03-22 00:18:26 +03:00
parent bcf86e0cf1
commit d657aef4cf
6 changed files with 194 additions and 93 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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();
+22
View File
@@ -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;