mirror of
https://github.com/Cykooz/fast_image_resize.git
synced 2026-10-08 01:11:09 +00:00
Fixed implementation of TypedCroppedImage, TypedCroppedImageMut, CroppedImage and CroppedImageMut.
This commit is contained in:
+9
-3
@@ -4,6 +4,14 @@
|
||||
|
||||
- Added Gaussian filter for convolution algorithm.
|
||||
- Method `PixelType::size()` was made public.
|
||||
- Added new image containers:
|
||||
- `ImageRef`
|
||||
- `TypedImageRef`
|
||||
- `TypedImage`
|
||||
- `TypedCroppedImage`
|
||||
- `TypedCroppedImageMut`
|
||||
- `CroppedImage`
|
||||
- `CroppedImageMut`
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -11,7 +19,7 @@
|
||||
|
||||
### Changed
|
||||
|
||||
A lot of breaking changes have been done in this release:
|
||||
A lot of **breaking changes** have been done in this release:
|
||||
|
||||
- Structures `ImageView` and `ImageViewMut` have been removed. They always
|
||||
did unnecessary memory allocation to store references to image rows.
|
||||
@@ -40,8 +48,6 @@ A lot of breaking changes have been done in this release:
|
||||
Now you can create and use zero-sized images.
|
||||
- `Image` (embedded implementation of image container) moved from root of
|
||||
the crate into module `images`.
|
||||
- Added new image containers: `ImageRef`, `TypedImageRef`, `TypedImage`,
|
||||
`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)
|
||||
|
||||
@@ -141,6 +141,7 @@ codegen-units = 1
|
||||
|
||||
[profile.test]
|
||||
opt-level = 3
|
||||
incremental = true
|
||||
|
||||
|
||||
[package.metadata.release]
|
||||
|
||||
+68
-81
@@ -1,73 +1,37 @@
|
||||
use crate::{CropBoxError, ImageView, ImageViewMut};
|
||||
use crate::images::{check_crop_box, TypedCroppedImage, TypedCroppedImageMut};
|
||||
use crate::{
|
||||
CropBoxError, ImageView, ImageViewMut, IntoImageView, IntoImageViewMut, PixelTrait, PixelType,
|
||||
};
|
||||
|
||||
fn check_crop_box(
|
||||
image_view: &impl ImageView,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<(), CropBoxError> {
|
||||
let img_width = image_view.width();
|
||||
let img_height = image_view.height();
|
||||
|
||||
if left >= img_width || top >= img_height {
|
||||
return Err(CropBoxError::PositionIsOutOfImageBoundaries);
|
||||
}
|
||||
let right = left + width;
|
||||
let bottom = top + height;
|
||||
if right > img_width || bottom > img_height {
|
||||
return Err(CropBoxError::SizeIsOutOfImageBoundaries);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn height(&self) -> u32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn iter_rows(&self, start_row: u32) -> impl Iterator<Item = &[Self::Pixel]> {
|
||||
let left = self.left as usize;
|
||||
let right = left + self.width as usize;
|
||||
self.image_view
|
||||
.iter_rows(self.top + start_row)
|
||||
.take((self.height - start_row) as usize)
|
||||
// SAFETY: correct values of the left and the right
|
||||
// are guaranteed by new() method.
|
||||
.map(move |row| unsafe { row.get_unchecked(left..right) })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// It is a typed wrapper that provides [ImageView] for part of wrapped image.
|
||||
pub struct TypedCroppedImage<'a, V: ImageView> {
|
||||
image_view: &'a V,
|
||||
/// It is a wrapper that provides [IntoImageView] for part of wrapped image.
|
||||
pub struct CroppedImage<'a, V: IntoImageView> {
|
||||
image: &'a V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl<'a, V: ImageView> TypedCroppedImage<'a, V> {
|
||||
/// It is a wrapper that provides [IntoImageView] and [IntoImageViewMut] for part of wrapped image.
|
||||
pub struct CroppedImageMut<'a, V: IntoImageView> {
|
||||
image: &'a mut V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl<'a, V: IntoImageView> CroppedImage<'a, V> {
|
||||
pub fn new(
|
||||
image_view: &'a V,
|
||||
image: &'a V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<Self, CropBoxError> {
|
||||
check_crop_box(image_view, left, top, width, height)?;
|
||||
check_crop_box(image.width(), image.height(), left, top, width, height)?;
|
||||
Ok(Self {
|
||||
image_view,
|
||||
image,
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
@@ -76,27 +40,17 @@ impl<'a, V: ImageView> TypedCroppedImage<'a, V> {
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
impl<'a, V: IntoImageView> CroppedImageMut<'a, V> {
|
||||
pub fn new(
|
||||
image_view: &'a mut V,
|
||||
image: &'a mut V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<Self, CropBoxError> {
|
||||
check_crop_box(image_view, left, top, width, height)?;
|
||||
check_crop_box(image.width(), image.height(), left, top, width, height)?;
|
||||
Ok(Self {
|
||||
image_view,
|
||||
image,
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
@@ -105,17 +59,50 @@ impl<'a, V: ImageViewMut> TypedCroppedImageMut<'a, V> {
|
||||
}
|
||||
}
|
||||
|
||||
image_view_impl!(TypedCroppedImageMut<ImageViewMut>);
|
||||
impl<'a, V: IntoImageView> IntoImageView for CroppedImage<'a, V> {
|
||||
fn pixel_type(&self) -> Option<PixelType> {
|
||||
self.image.pixel_type()
|
||||
}
|
||||
|
||||
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;
|
||||
self.image_view
|
||||
.iter_rows_mut(self.top + start_row)
|
||||
.take((self.height - start_row) as usize)
|
||||
// SAFETY: correct values of the left and the right
|
||||
// are guaranteed by new() method.
|
||||
.map(move |row| unsafe { row.get_unchecked_mut(left..right) })
|
||||
fn width(&self) -> u32 {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn height(&self) -> u32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn image_view<P: PixelTrait>(&self) -> Option<impl ImageView<Pixel = P>> {
|
||||
self.image.image_view().map(|v| {
|
||||
TypedCroppedImage::new(v, self.left, self.top, self.width, self.height).unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: IntoImageView> IntoImageView for CroppedImageMut<'a, V> {
|
||||
fn pixel_type(&self) -> Option<PixelType> {
|
||||
self.image.pixel_type()
|
||||
}
|
||||
|
||||
fn width(&self) -> u32 {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn height(&self) -> u32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn image_view<P: PixelTrait>(&self) -> Option<impl ImageView<Pixel = P>> {
|
||||
self.image.image_view().map(|v| {
|
||||
TypedCroppedImage::new(v, self.left, self.top, self.width, self.height).unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: IntoImageViewMut> IntoImageViewMut for CroppedImageMut<'a, V> {
|
||||
fn image_view_mut<P: PixelTrait>(&mut self) -> Option<impl ImageViewMut<Pixel = P>> {
|
||||
self.image.image_view_mut().map(|v| {
|
||||
TypedCroppedImageMut::new(v, self.left, self.top, self.width, self.height).unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,18 @@ impl<'a> ImageRef<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_pixels<P: PixelTrait>(
|
||||
width: u32,
|
||||
height: u32,
|
||||
pixels: &'a [P],
|
||||
) -> Result<Self, ImageBufferError> {
|
||||
let (head, buffer, _) = unsafe { pixels.align_to::<u8>() };
|
||||
if !head.is_empty() {
|
||||
return Err(ImageBufferError::InvalidBufferAlignment);
|
||||
}
|
||||
Self::new(width, height, buffer, P::pixel_type())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pixel_type(&self) -> PixelType {
|
||||
self.pixel_type
|
||||
@@ -86,7 +98,7 @@ impl<'a> IntoImageView for ImageRef<'a> {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn image_view<P: InnerPixel>(&self) -> Option<impl ImageView<Pixel = P>> {
|
||||
fn image_view<P: PixelTrait>(&self) -> Option<impl ImageView<Pixel = P>> {
|
||||
self.typed_image()
|
||||
}
|
||||
}
|
||||
@@ -210,7 +222,7 @@ impl<'a> Image<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get typed version of the image.
|
||||
/// Get the typed version of the image.
|
||||
pub fn typed_image<P: InnerPixel>(&self) -> Option<TypedImageRef<P>> {
|
||||
if P::pixel_type() != self.pixel_type {
|
||||
return None;
|
||||
@@ -220,7 +232,7 @@ impl<'a> Image<'a> {
|
||||
Some(typed_image)
|
||||
}
|
||||
|
||||
/// Get typed mutable version of the image.
|
||||
/// Get the typed mutable version of the image.
|
||||
pub fn typed_image_mut<P: InnerPixel>(&mut self) -> Option<TypedImage<P>> {
|
||||
if P::pixel_type() != self.pixel_type {
|
||||
return None;
|
||||
@@ -5,8 +5,7 @@ use image::DynamicImage;
|
||||
|
||||
use crate::image_view::try_pixel_type;
|
||||
use crate::images::{TypedImage, TypedImageRef};
|
||||
use crate::pixels::InnerPixel;
|
||||
use crate::{ImageView, ImageViewMut, IntoImageView, IntoImageViewMut, PixelType};
|
||||
use crate::{ImageView, ImageViewMut, IntoImageView, IntoImageViewMut, PixelTrait, PixelType};
|
||||
|
||||
impl IntoImageView for DynamicImage {
|
||||
fn pixel_type(&self) -> Option<PixelType> {
|
||||
@@ -31,7 +30,7 @@ impl IntoImageView for DynamicImage {
|
||||
self.height()
|
||||
}
|
||||
|
||||
fn image_view<P: InnerPixel>(&self) -> Option<impl ImageView<Pixel = P>> {
|
||||
fn image_view<P: PixelTrait>(&self) -> Option<impl ImageView<Pixel = P>> {
|
||||
if let Ok(pixel_type) = try_pixel_type(self) {
|
||||
if P::pixel_type() == pixel_type {
|
||||
return TypedImageRef::<P>::from_buffer(
|
||||
@@ -47,7 +46,7 @@ impl IntoImageView for DynamicImage {
|
||||
}
|
||||
|
||||
impl IntoImageViewMut for DynamicImage {
|
||||
fn image_view_mut<P: InnerPixel>(&mut self) -> Option<impl ImageViewMut<Pixel = P>> {
|
||||
fn image_view_mut<P: PixelTrait>(&mut self) -> Option<impl ImageViewMut<Pixel = P>> {
|
||||
if let Ok(pixel_type) = try_pixel_type(self) {
|
||||
if P::pixel_type() == pixel_type {
|
||||
return TypedImage::<P>::from_buffer(
|
||||
|
||||
+4
-2
@@ -2,11 +2,13 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub use cropped_image::*;
|
||||
pub use dyn_image::*;
|
||||
pub use image::*;
|
||||
pub use typed_cropped_image::*;
|
||||
pub use typed_image::*;
|
||||
|
||||
mod cropped_image;
|
||||
mod dyn_image;
|
||||
mod image;
|
||||
mod typed_cropped_image;
|
||||
mod typed_image;
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
use crate::{CropBoxError, ImageView, ImageViewMut};
|
||||
|
||||
pub(crate) fn check_crop_box(
|
||||
img_width: u32,
|
||||
img_height: u32,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<(), CropBoxError> {
|
||||
if left >= img_width || top >= img_height {
|
||||
return Err(CropBoxError::PositionIsOutOfImageBoundaries);
|
||||
}
|
||||
let right = left + width;
|
||||
let bottom = top + height;
|
||||
if right > img_width || bottom > img_height {
|
||||
return Err(CropBoxError::SizeIsOutOfImageBoundaries);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 {
|
||||
self.width
|
||||
}
|
||||
|
||||
fn height(&self) -> u32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn iter_rows(&self, start_row: u32) -> impl Iterator<Item = &[Self::Pixel]> {
|
||||
let left = self.left as usize;
|
||||
let right = left + self.width as usize;
|
||||
self.image_view
|
||||
.get_ref()
|
||||
.iter_rows(self.top + start_row)
|
||||
.take((self.height - start_row) as usize)
|
||||
// SAFETY: correct values of the left and the right
|
||||
// are guaranteed by new() method.
|
||||
.map(move |row| unsafe { row.get_unchecked(left..right) })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
enum View<'a, V: 'a> {
|
||||
Borrowed(&'a V),
|
||||
Owned(V),
|
||||
}
|
||||
|
||||
impl<'a, V> View<'a, V> {
|
||||
fn get_ref(&self) -> &V {
|
||||
match self {
|
||||
Self::Borrowed(v_ref) => v_ref,
|
||||
Self::Owned(v_own) => v_own,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ViewMut<'a, V: 'a> {
|
||||
Borrowed(&'a mut V),
|
||||
Owned(V),
|
||||
}
|
||||
|
||||
impl<'a, V> ViewMut<'a, V> {
|
||||
fn get_ref(&self) -> &V {
|
||||
match self {
|
||||
Self::Borrowed(v_ref) => v_ref,
|
||||
Self::Owned(v_own) => v_own,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mut(&mut self) -> &mut V {
|
||||
match self {
|
||||
Self::Borrowed(p_ref) => p_ref,
|
||||
Self::Owned(vec) => vec,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// It is a typed wrapper that provides [ImageView] for part of wrapped image.
|
||||
pub struct TypedCroppedImage<'a, V: ImageView + 'a> {
|
||||
image_view: View<'a, V>,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
/// It is a typed wrapper that provides [ImageView] and [ImageViewMut] for part of wrapped image.
|
||||
pub struct TypedCroppedImageMut<'a, V: ImageViewMut> {
|
||||
image_view: ViewMut<'a, V>,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl<'a, V: ImageView + 'a> TypedCroppedImage<'a, V> {
|
||||
pub fn new(
|
||||
image_view: V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<Self, CropBoxError> {
|
||||
check_crop_box(
|
||||
image_view.width(),
|
||||
image_view.height(),
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
)?;
|
||||
Ok(Self {
|
||||
image_view: View::Owned(image_view),
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_ref(
|
||||
image_view: &'a V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<Self, CropBoxError> {
|
||||
check_crop_box(
|
||||
image_view.width(),
|
||||
image_view.height(),
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
)?;
|
||||
Ok(Self {
|
||||
image_view: View::Borrowed(image_view),
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: ImageViewMut> TypedCroppedImageMut<'a, V> {
|
||||
pub fn new(
|
||||
image_view: V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<Self, CropBoxError> {
|
||||
check_crop_box(
|
||||
image_view.width(),
|
||||
image_view.height(),
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
)?;
|
||||
Ok(Self {
|
||||
image_view: ViewMut::Owned(image_view),
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_ref(
|
||||
image_view: &'a mut V,
|
||||
left: u32,
|
||||
top: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<Self, CropBoxError> {
|
||||
check_crop_box(
|
||||
image_view.width(),
|
||||
image_view.height(),
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
)?;
|
||||
Ok(Self {
|
||||
image_view: ViewMut::Borrowed(image_view),
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
image_view_impl!(TypedCroppedImage<ImageView>);
|
||||
|
||||
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;
|
||||
self.image_view
|
||||
.get_mut()
|
||||
.iter_rows_mut(self.top + start_row)
|
||||
.take((self.height - start_row) as usize)
|
||||
// SAFETY: correct values of the left and the right
|
||||
// are guaranteed by new() method.
|
||||
.map(move |row| unsafe { row.get_unchecked_mut(left..right) })
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,10 @@ impl<'a, P> TypedImageRef<'a, P> {
|
||||
let pixels = align_buffer_to(buffer)?;
|
||||
Self::new(width, height, pixels).map_err(|_| ImageBufferError::InvalidBufferSize)
|
||||
}
|
||||
|
||||
pub fn pixels(&self) -> &[P] {
|
||||
self.pixels
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a, P: InnerPixel> ImageView for TypedImageRef<'a, P> {
|
||||
|
||||
+96
-9
@@ -1,9 +1,10 @@
|
||||
use fast_image_resize as fr;
|
||||
use fast_image_resize::images::{
|
||||
Image, ImageRef, TypedCroppedImage, TypedCroppedImageMut, TypedImage, TypedImageRef,
|
||||
CroppedImage, CroppedImageMut, Image, ImageRef, TypedCroppedImage, TypedCroppedImageMut,
|
||||
TypedImage, TypedImageRef,
|
||||
};
|
||||
use fast_image_resize::pixels::{U8x4, U8};
|
||||
use fast_image_resize::{ImageView, ResizeOptions};
|
||||
use fast_image_resize::{ImageView, IntoImageView, PixelType, ResizeOptions};
|
||||
|
||||
#[test]
|
||||
fn create_image_ref_from_small_buffer() {
|
||||
@@ -11,7 +12,7 @@ fn create_image_ref_from_small_buffer() {
|
||||
let height = 32;
|
||||
let buffer = vec![0; 64 * 30];
|
||||
|
||||
let res = ImageRef::new(width, height, &buffer, fr::PixelType::U8);
|
||||
let res = ImageRef::new(width, height, &buffer, PixelType::U8);
|
||||
assert_eq!(res.unwrap_err(), fr::ImageBufferError::InvalidBufferSize);
|
||||
}
|
||||
|
||||
@@ -21,10 +22,10 @@ fn create_image_from_small_buffer() {
|
||||
let height = 32;
|
||||
let mut buffer = vec![0; 64 * 30];
|
||||
|
||||
let res = Image::from_slice_u8(width, height, &mut buffer, fr::PixelType::U8);
|
||||
let res = Image::from_slice_u8(width, height, &mut buffer, PixelType::U8);
|
||||
assert_eq!(res.unwrap_err(), fr::ImageBufferError::InvalidBufferSize);
|
||||
|
||||
let res = Image::from_vec_u8(width, height, buffer, fr::PixelType::U8);
|
||||
let res = Image::from_vec_u8(width, height, buffer, PixelType::U8);
|
||||
assert_eq!(res.unwrap_err(), fr::ImageBufferError::InvalidBufferSize);
|
||||
}
|
||||
|
||||
@@ -34,10 +35,10 @@ fn create_image_from_big_buffer() {
|
||||
let height = 32;
|
||||
let mut buffer = vec![0; 65 * 32];
|
||||
|
||||
let res = Image::from_slice_u8(width, height, &mut buffer, fr::PixelType::U8);
|
||||
let res = Image::from_slice_u8(width, height, &mut buffer, PixelType::U8);
|
||||
assert!(res.is_ok());
|
||||
|
||||
let res = Image::from_vec_u8(width, height, buffer, fr::PixelType::U8);
|
||||
let res = Image::from_vec_u8(width, height, buffer, PixelType::U8);
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
|
||||
@@ -99,7 +100,7 @@ fn typed_cropped_image() {
|
||||
// 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();
|
||||
let cropped_src_image = TypedCroppedImage::from_ref(&src_image, 10, 10, 44, 44).unwrap();
|
||||
assert_eq!(cropped_src_image.width(), 44);
|
||||
assert_eq!(cropped_src_image.height(), 44);
|
||||
|
||||
@@ -116,6 +117,47 @@ fn typed_cropped_image() {
|
||||
assert_eq!(dst_image.pixels(), white_block);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cropped_image() {
|
||||
const BLACK: U8x4 = U8x4::new([0; 4]);
|
||||
const WHITE: U8x4 = U8x4::new([255; 4]);
|
||||
|
||||
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 = ImageRef::from_pixels(64, 64, &source_pixels).unwrap();
|
||||
// Black destination image
|
||||
let mut dst_image = Image::new(40, 40, PixelType::U8x4);
|
||||
|
||||
let cropped_src_image = CroppedImage::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(
|
||||
&cropped_src_image,
|
||||
&mut dst_image,
|
||||
&ResizeOptions::new().resize_alg(fr::ResizeAlg::Nearest),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let dst_typed_image = dst_image.typed_image().unwrap();
|
||||
let dst_pixels: &[U8x4] = dst_typed_image.pixels();
|
||||
let white_block = vec![WHITE; 40 * 40];
|
||||
assert_eq!(dst_pixels, white_block);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typed_cropped_image_mut() {
|
||||
const BLACK: U8x4 = U8x4::new([0; 4]);
|
||||
@@ -126,7 +168,8 @@ fn typed_cropped_image_mut() {
|
||||
// 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();
|
||||
let mut cropped_dst_image =
|
||||
TypedCroppedImageMut::from_ref(&mut dst_image, 10, 10, 44, 12).unwrap();
|
||||
assert_eq!(cropped_dst_image.width(), 44);
|
||||
assert_eq!(cropped_dst_image.height(), 12);
|
||||
|
||||
@@ -157,3 +200,47 @@ fn typed_cropped_image_mut() {
|
||||
// Bottom border
|
||||
assert_eq!(dst_pixels[22 * row_size..], black_block);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cropped_image_mut() {
|
||||
const BLACK: U8x4 = U8x4::new([0; 4]);
|
||||
const WHITE: U8x4 = U8x4::new([255; 4]);
|
||||
|
||||
// White source image
|
||||
let src_pixels = vec![WHITE; 64 * 32];
|
||||
let src_image = ImageRef::from_pixels(64, 32, &src_pixels).unwrap();
|
||||
// Black destination image
|
||||
let mut dst_image = Image::new(64, 32, PixelType::U8x4);
|
||||
|
||||
let mut cropped_dst_image = CroppedImageMut::new(&mut dst_image, 10, 10, 44, 12).unwrap();
|
||||
assert_eq!(cropped_dst_image.width(), 44);
|
||||
assert_eq!(cropped_dst_image.height(), 12);
|
||||
|
||||
let mut resizer = fr::Resizer::new();
|
||||
resizer
|
||||
.resize(
|
||||
&src_image,
|
||||
&mut cropped_dst_image,
|
||||
&ResizeOptions::new().resize_alg(fr::ResizeAlg::Nearest),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let dst_typed_image = dst_image.typed_image().unwrap();
|
||||
let dst_pixels: &[U8x4] = dst_typed_image.pixels();
|
||||
|
||||
let row_size: usize = 64;
|
||||
let black_block = vec![BLACK; 10 * row_size];
|
||||
// Top border
|
||||
assert_eq!(dst_pixels[0..10 * row_size], black_block);
|
||||
|
||||
// Middle rows
|
||||
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_pixels[22 * row_size..], black_block);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user