mirror of
https://github.com/Cykooz/fast_image_resize.git
synced 2026-10-08 01:11:09 +00:00
- Renamed CroppedImage into TypedCroppedImage.
- Renamed `CroppedImageMut` into `TypedCroppedImageMut`.
This commit is contained in:
+1
-1
@@ -41,7 +41,7 @@ A lot of breaking changes have been done in this release:
|
||||
- `Image` (embedded implementation of image container) moved from root of
|
||||
the crate into module `images`.
|
||||
- Added new image containers: `ImageRef`, `TypedImageRef`, `TypedImage`,
|
||||
`CroppedImage` and `CroppedImageMut`.
|
||||
`TypedCroppedImage` and `TypedCroppedImageMut`.
|
||||
- Added optional feature "image".
|
||||
It adds implementation of traits `IntoImageView` and `IntoImageViewMut` for the
|
||||
[DynamicImage](https://docs.rs/image/latest/image/enum.DynamicImage.html)
|
||||
|
||||
+2
-2
@@ -8,8 +8,8 @@ pub enum ImageError {
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Clone, Copy)]
|
||||
#[error("Size of slice with pixels is smaller than required")]
|
||||
pub struct InvalidPixelsSliceSize;
|
||||
#[error("Size of container with pixels is smaller than required")]
|
||||
pub struct InvalidPixelsSize;
|
||||
|
||||
#[derive(Error, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ImageBufferError {
|
||||
|
||||
+62
-40
@@ -21,37 +21,9 @@ fn check_crop_box(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
macro_rules! cropped_image_impl {
|
||||
($wrapper_name:ident<$view_trait:ident>, $doc:expr) => {
|
||||
#[doc = $doc]
|
||||
pub struct $wrapper_name<V: $view_trait + Sized> {
|
||||
image_view: V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl<V: $view_trait + Sized> $wrapper_name<V> {
|
||||
pub fn new(
|
||||
image_view: V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<Self, CropBoxError> {
|
||||
check_crop_box(&image_view, left, top, width, height)?;
|
||||
Ok(Self {
|
||||
image_view,
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<V: $view_trait> ImageView for $wrapper_name<V> {
|
||||
macro_rules! image_view_impl {
|
||||
($wrapper_name:ident<$view_trait:ident>) => {
|
||||
unsafe impl<'a, V: $view_trait> ImageView for $wrapper_name<'a, V> {
|
||||
type Pixel = V::Pixel;
|
||||
|
||||
fn width(&self) -> u32 {
|
||||
@@ -76,16 +48,66 @@ macro_rules! cropped_image_impl {
|
||||
};
|
||||
}
|
||||
|
||||
cropped_image_impl!(
|
||||
CroppedImage<ImageView>,
|
||||
"It is wrapper that provides [ImageView] for part of wrapped image."
|
||||
);
|
||||
cropped_image_impl!(
|
||||
CroppedImageMut<ImageViewMut>,
|
||||
"It is wrapper that provides [ImageViewMut] for part of wrapped image."
|
||||
);
|
||||
/// It is a typed wrapper that provides [ImageView] for part of wrapped image.
|
||||
pub struct TypedCroppedImage<'a, V: ImageView> {
|
||||
image_view: &'a V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
unsafe impl<V: ImageViewMut> ImageViewMut for CroppedImageMut<V> {
|
||||
impl<'a, V: ImageView> TypedCroppedImage<'a, V> {
|
||||
pub fn new(
|
||||
image_view: &'a V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<Self, CropBoxError> {
|
||||
check_crop_box(image_view, left, top, width, height)?;
|
||||
Ok(Self {
|
||||
image_view,
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
image_view_impl!(TypedCroppedImage<ImageView>);
|
||||
|
||||
/// It is a typed wrapper that provides [ImageView] and [ImageViewMut] for part of wrapped image.
|
||||
pub struct TypedCroppedImageMut<'a, V: ImageViewMut> {
|
||||
image_view: &'a mut V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
impl<'a, V: ImageViewMut> TypedCroppedImageMut<'a, V> {
|
||||
pub fn new(
|
||||
image_view: &'a mut V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<Self, CropBoxError> {
|
||||
check_crop_box(image_view, left, top, width, height)?;
|
||||
Ok(Self {
|
||||
image_view,
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
image_view_impl!(TypedCroppedImageMut<ImageViewMut>);
|
||||
|
||||
unsafe impl<'a, V: ImageViewMut> ImageViewMut for TypedCroppedImageMut<'a, V> {
|
||||
fn iter_rows_mut(&mut self, start_row: u32) -> impl Iterator<Item = &mut [Self::Pixel]> {
|
||||
let left = self.left as usize;
|
||||
let right = left + self.width as usize;
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::fmt::Debug;
|
||||
|
||||
use crate::images::BufferContainer;
|
||||
use crate::pixels::InnerPixel;
|
||||
use crate::{ImageBufferError, ImageView, ImageViewMut, InvalidPixelsSliceSize};
|
||||
use crate::{ImageBufferError, ImageView, ImageViewMut, InvalidPixelsSize};
|
||||
|
||||
/// Generic reference to image data that provides [ImageView].
|
||||
#[derive(Debug)]
|
||||
@@ -13,10 +13,10 @@ pub struct TypedImageRef<'a, P> {
|
||||
}
|
||||
|
||||
impl<'a, P> TypedImageRef<'a, P> {
|
||||
pub fn new(width: u32, height: u32, pixels: &'a [P]) -> Result<Self, InvalidPixelsSliceSize> {
|
||||
pub fn new(width: u32, height: u32, pixels: &'a [P]) -> Result<Self, InvalidPixelsSize> {
|
||||
let pixels_count = width as usize * height as usize;
|
||||
if pixels.len() < pixels_count {
|
||||
return Err(InvalidPixelsSliceSize);
|
||||
return Err(InvalidPixelsSize);
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
@@ -105,14 +105,26 @@ impl<P: Default + Copy + Debug> TypedImage<'static, P> {
|
||||
}
|
||||
|
||||
impl<'a, P: InnerPixel> TypedImage<'a, P> {
|
||||
pub fn from_pixels(
|
||||
pub fn from_pixels(width: u32, height: u32, pixels: Vec<P>) -> Result<Self, InvalidPixelsSize> {
|
||||
let pixels_count = width as usize * height as usize;
|
||||
if pixels.len() < pixels_count {
|
||||
return Err(InvalidPixelsSize);
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
pixels: BufferContainer::Owned(pixels),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_pixels_slice(
|
||||
width: u32,
|
||||
height: u32,
|
||||
pixels: &'a mut [P],
|
||||
) -> Result<Self, InvalidPixelsSliceSize> {
|
||||
) -> Result<Self, InvalidPixelsSize> {
|
||||
let pixels_count = width as usize * height as usize;
|
||||
if pixels.len() < pixels_count {
|
||||
return Err(InvalidPixelsSliceSize);
|
||||
return Err(InvalidPixelsSize);
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
@@ -131,7 +143,16 @@ impl<'a, P: InnerPixel> TypedImage<'a, P> {
|
||||
return Err(ImageBufferError::InvalidBufferSize);
|
||||
}
|
||||
let pixels = align_buffer_to_mut(buffer)?;
|
||||
Self::from_pixels(width, height, pixels).map_err(|_| ImageBufferError::InvalidBufferSize)
|
||||
Self::from_pixels_slice(width, height, pixels)
|
||||
.map_err(|_| ImageBufferError::InvalidBufferSize)
|
||||
}
|
||||
|
||||
pub fn pixels(&self) -> &[P] {
|
||||
self.pixels.borrow()
|
||||
}
|
||||
|
||||
pub fn pixels_mut(&mut self) -> &mut [P] {
|
||||
self.pixels.borrow_mut()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -508,7 +508,7 @@ fn get_temp_image_from_buffer<P: PixelTrait>(
|
||||
buffer.resize(buf_size, 0);
|
||||
}
|
||||
let pixels = unsafe { buffer.align_to_mut::<P>().1 };
|
||||
TypedImage::from_pixels(width, height, &mut pixels[0..pixels_count]).unwrap()
|
||||
TypedImage::from_pixels_slice(width, height, &mut pixels[0..pixels_count]).unwrap()
|
||||
}
|
||||
|
||||
fn resample_nearest<P: InnerPixel>(
|
||||
|
||||
@@ -84,7 +84,7 @@ fn mul_div_alpha_test<P: PixelTrait>(
|
||||
let mut dst_pixels = src_pixels.clone();
|
||||
|
||||
let src_image = TypedImageRef::new(width, height, &src_pixels).unwrap();
|
||||
let mut dst_image = TypedImage::from_pixels(width, height, &mut dst_pixels).unwrap();
|
||||
let mut dst_image = TypedImage::from_pixels_slice(width, height, &mut dst_pixels).unwrap();
|
||||
|
||||
let mut alpha_mul_div: MulDiv = Default::default();
|
||||
unsafe {
|
||||
@@ -125,7 +125,7 @@ fn mul_div_alpha_test<P: PixelTrait>(
|
||||
|
||||
// Inplace
|
||||
let mut src_pixels_clone = src_pixels.clone();
|
||||
let mut image = TypedImage::from_pixels(width, height, &mut src_pixels_clone).unwrap();
|
||||
let mut image = TypedImage::from_pixels_slice(width, height, &mut src_pixels_clone).unwrap();
|
||||
|
||||
match oper {
|
||||
Oper::Mul => alpha_mul_div
|
||||
|
||||
+61
-20
@@ -1,5 +1,7 @@
|
||||
use fast_image_resize as fr;
|
||||
use fast_image_resize::images::{CroppedImageMut, Image, ImageRef, TypedImage, TypedImageRef};
|
||||
use fast_image_resize::images::{
|
||||
Image, ImageRef, TypedCroppedImage, TypedCroppedImageMut, TypedImage, TypedImageRef,
|
||||
};
|
||||
use fast_image_resize::pixels::{U8x4, U8};
|
||||
use fast_image_resize::{ImageView, ResizeOptions};
|
||||
|
||||
@@ -46,7 +48,7 @@ fn create_type_image_ref_from_small_buffer() {
|
||||
let buffer = vec![U8::new(0); 64 * 30];
|
||||
|
||||
let res = TypedImageRef::<U8>::new(width, height, &buffer);
|
||||
assert!(matches!(res, Err(fr::InvalidPixelsSliceSize)));
|
||||
assert!(matches!(res, Err(fr::InvalidPixelsSize)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -76,16 +78,55 @@ fn create_typed_image_from_big_buffer() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn crop_view_mut() {
|
||||
// White source image
|
||||
let src_image =
|
||||
Image::from_vec_u8(64, 32, vec![255; 64 * 32 * 4], fr::PixelType::U8x4).unwrap();
|
||||
let src_image = src_image.typed_image::<U8x4>().unwrap();
|
||||
// Black destination image
|
||||
let mut dst_image = Image::new(64, 32, fr::PixelType::U8x4);
|
||||
fn typed_cropped_image() {
|
||||
const BLACK: U8x4 = U8x4::new([0; 4]);
|
||||
const WHITE: U8x4 = U8x4::new([255; 4]);
|
||||
|
||||
let mut cropped_dst_image =
|
||||
CroppedImageMut::new(dst_image.typed_image_mut::<U8x4>().unwrap(), 10, 10, 44, 12).unwrap();
|
||||
let mut source_pixels = Vec::with_capacity(64 * 64);
|
||||
source_pixels.extend((0..64 * 64).map(|i| {
|
||||
let y = i / 64;
|
||||
if (10..54).contains(&y) {
|
||||
let x = i % 64;
|
||||
if (10..54).contains(&x) {
|
||||
return WHITE;
|
||||
}
|
||||
}
|
||||
BLACK
|
||||
}));
|
||||
|
||||
// Black source image with white square inside
|
||||
let src_image = TypedImage::<U8x4>::from_pixels(64, 64, source_pixels).unwrap();
|
||||
// Black destination image
|
||||
let mut dst_image = TypedImage::<U8x4>::new(40, 40);
|
||||
|
||||
let cropped_src_image = TypedCroppedImage::new(&src_image, 10, 10, 44, 44).unwrap();
|
||||
assert_eq!(cropped_src_image.width(), 44);
|
||||
assert_eq!(cropped_src_image.height(), 44);
|
||||
|
||||
let mut resizer = fr::Resizer::new();
|
||||
resizer
|
||||
.resize_typed(
|
||||
&cropped_src_image,
|
||||
&mut dst_image,
|
||||
&ResizeOptions::new().resize_alg(fr::ResizeAlg::Nearest),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let white_block = vec![WHITE; 40 * 40];
|
||||
assert_eq!(dst_image.pixels(), white_block);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typed_cropped_image_mut() {
|
||||
const BLACK: U8x4 = U8x4::new([0; 4]);
|
||||
const WHITE: U8x4 = U8x4::new([255; 4]);
|
||||
|
||||
// White source image
|
||||
let src_image = TypedImage::from_pixels(64, 32, vec![WHITE; 64 * 32]).unwrap();
|
||||
// Black destination image
|
||||
let mut dst_image = TypedImage::<U8x4>::new(64, 32);
|
||||
|
||||
let mut cropped_dst_image = TypedCroppedImageMut::new(&mut dst_image, 10, 10, 44, 12).unwrap();
|
||||
assert_eq!(cropped_dst_image.width(), 44);
|
||||
assert_eq!(cropped_dst_image.height(), 12);
|
||||
|
||||
@@ -98,21 +139,21 @@ fn crop_view_mut() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let row_size: usize = 64 * 4;
|
||||
let dst_buffer = dst_image.buffer();
|
||||
let dst_pixels = dst_image.pixels();
|
||||
|
||||
let black_block = vec![0u8; 10 * row_size];
|
||||
let row_size: usize = 64;
|
||||
let black_block = vec![BLACK; 10 * row_size];
|
||||
// Top border
|
||||
assert_eq!(dst_buffer[0..10 * row_size], black_block);
|
||||
assert_eq!(dst_pixels[0..10 * row_size], black_block);
|
||||
|
||||
// Middle rows
|
||||
let mut middle_row = vec![0u8; 10 * 4];
|
||||
middle_row.extend(vec![255u8; 44 * 4]);
|
||||
middle_row.extend(vec![0u8; 10 * 4]);
|
||||
for row in dst_buffer.chunks_exact(row_size).skip(10 * 4).take(12 * 4) {
|
||||
let mut middle_row = vec![BLACK; 10];
|
||||
middle_row.extend(vec![WHITE; 44]);
|
||||
middle_row.extend(vec![BLACK; 10]);
|
||||
for row in dst_pixels.chunks_exact(row_size).skip(10).take(12) {
|
||||
assert_eq!(row, middle_row);
|
||||
}
|
||||
|
||||
// Bottom border
|
||||
assert_eq!(dst_buffer[22 * row_size..], black_block);
|
||||
assert_eq!(dst_pixels[22 * row_size..], black_block);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user