- Added ImageRef structure.

- Added example of code with differences between v3.x and v4.x.
This commit is contained in:
Kirill Kuzminykh
2024-04-24 00:37:39 +03:00
parent f6bf9bbaad
commit 8af42a2cf7
5 changed files with 219 additions and 21 deletions
+114 -12
View File
@@ -20,27 +20,129 @@ A lot of breaking changes have been done in this release:
- Also, traits `IntoImageView` and `IntoImageViewMut` have been added.
They allow you to write runtime adapters to convert your particular
image container into something that provides `ImageView`/`ImageViewMut` trait.
- `Resizer` now has two methods for resize:
- `resize()` accepts `IntoImageView` and `IntoImageViewMut` arguments;
- `resize_typed()` accepts `ImageView` and `ImageViewMut` arguments.
- `Resizer` now has two methods for resize (dynamic and typed):
- `resize()` accepts references to `impl IntoImageView` and `impl IntoImageViewMut`;
- `resize_typed()` accepts references to `impl ImageView` and `impl ImageViewMut`.
- Resize methods also accept the `options` argument.
With help of this argument, you can specify:
With the help of this argument, you can specify:
- how to crop the source image;
- whether to multiply the source image by the alpha channel and
divide the destination image by the alpha channel.
By default, Resizer multiplies and divides by alpha channel
images with `U8x2`, `U8x4`, `U16x2` and `U16x4` pixels.
- The `MulDiv` implementation has been changed in the same way as `Resizer`.
It now has two versions of each method: dynamic and typed.
- Type of image dimensions has been changed from `NonZeroU32` into `u32`.
Now you can create and use images with zero pixels.
- Embedded implementation of image container `Image` moved from root of
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: `TypedImage`, `TypedImageMut`, `CroppedImage`
and `CroppedImageMut`.
- Added optional feature "image". It adds implementation of traits
`IntoImageView` and `IntoImageViewMut` for the
- Added new image containers: `ImageRef`, `TypedImage`, `TypedImageMut`,
`CroppedImage` and `CroppedImageMut`.
- Added optional feature "image".
It adds implementation of traits `IntoImageView` and `IntoImageViewMut` for the
[DynamicImage](https://docs.rs/image/latest/image/enum.DynamicImage.html)
type from the `image` crate. It allows you to use `DynamicImage` instances
as arguments for `Resize::resize()` method.
type from the `image` crate. This implementation allows you to use `DynamicImage`
instances as arguments for methods of this crate.
Look at the difference between versions 3 and 4 on example
of resizing RGBA8 image from given u8-buffer with pixels-data.
3.x version:
```rust
use fast_image_resize::{Image, MulDiv, PixelType, Resizer};
use std::num::NonZeroU32;
fn my_resize(
src_width: u32,
src_height: u32,
src_pixels: &mut [u8],
dst_width: u32,
dst_height: u32,
) -> Image {
let src_width = NonZeroU32::new(src_width).unwrap();
let src_height = NonZeroU32::new(src_height).unwrap();
let src_image = Image::from_slice_u8(
src_width,
src_height,
src_pixels,
PixelType::U8x4,
).unwrap();
// Multiple RGB channels of source image by alpha channel.
let alpha_mul_div = MulDiv::default();
let mut tmp_image = Image::new(
src_width,
src_height,
PixelType::U8x4,
);
alpha_mul_div
.multiply_alpha(
&src_image.view(),
&mut tmp_image.view_mut(),
).unwrap();
// Create container for data of destination image.
let dst_width = NonZeroU32::new(dst_width).unwrap();
let dst_height = NonZeroU32::new(dst_height).unwrap();
let mut dst_image = Image::new(
dst_width,
dst_height,
PixelType::U8x4,
);
// Get mutable view of destination image data.
let mut dst_view = dst_image.view_mut();
// Create Resizer instance and resize source image
// into buffer of destination image.
let mut resizer = Resizer::default();
resizer.resize(&tmp_image.view(), &mut dst_view).unwrap();
// Divide RGB channels of destination image by alpha.
alpha_mul_div.divide_alpha_inplace(&mut dst_view).unwrap();
dst_image
}
```
4.x version:
```rust
use fast_image_resize::images::{Image, ImageRef};
use fast_image_resize::{PixelType, Resizer};
fn my_resize(
src_width: u32,
src_height: u32,
src_pixels: &[u8],
dst_width: u32,
dst_height: u32,
) -> ImageMut {
let src_image = ImageRef::new(
src_width,
src_height,
src_pixels,
PixelType::U8x4,
).unwrap();
// Create container for data of destination image.
let mut dst_image = Image::new(
dst_width,
dst_height,
PixelType::U8x4,
);
// Create Resizer instance and resize source image
// into buffer of destination image.
let mut resizer = Resizer::default();
// By default, Resizer multiplies and divides by alpha channel
// images with U8x2, U8x4, U16x2 and U16x4 pixels.
resizer.resize(&src_image, &mut dst_image, None).unwrap();
dst_image
}
```
## [3.0.4] - 2024-02-15
-1
View File
@@ -10,7 +10,6 @@ use once_cell::sync::Lazy;
use fast_image_resize as fr;
use fast_image_resize::images::Image;
use fast_image_resize::ResizeOptions;
mod structs;
+86
View File
@@ -4,6 +4,92 @@ use crate::{
ImageBufferError, ImageView, ImageViewMut, IntoImageView, IntoImageViewMut, PixelType,
};
/// Simple reference to image data that provides [IntoImageView].
#[derive(Debug, Copy, Clone)]
pub struct ImageRef<'a> {
width: u32,
height: u32,
buffer: &'a [u8],
pixel_type: PixelType,
}
impl<'a> ImageRef<'a> {
/// Create an image with from slice with pixels data.
pub fn new(
width: u32,
height: u32,
buffer: &'a [u8],
pixel_type: PixelType,
) -> Result<Self, ImageBufferError> {
let size = width as usize * height as usize * pixel_type.size();
if buffer.len() < size {
return Err(ImageBufferError::InvalidBufferSize);
}
if !pixel_type.is_aligned(buffer) {
return Err(ImageBufferError::InvalidBufferAlignment);
}
Ok(Self {
width,
height,
buffer,
pixel_type,
})
}
#[inline]
pub fn pixel_type(&self) -> PixelType {
self.pixel_type
}
#[inline]
pub fn width(&self) -> u32 {
self.width
}
#[inline]
pub fn height(&self) -> u32 {
self.height
}
/// Buffer with image pixels data.
#[inline]
pub fn buffer(&self) -> &[u8] {
self.buffer
}
#[inline]
pub fn into_vec(self) -> Vec<u8> {
self.buffer.into()
}
/// Get typed version of the image.
pub fn typed_image<P: InnerPixel>(&self) -> Option<TypedImage<P>> {
if P::pixel_type() != self.pixel_type {
return None;
}
let typed_image = TypedImage::from_buffer(self.width, self.height, self.buffer).unwrap();
Some(typed_image)
}
}
impl<'a> IntoImageView for ImageRef<'a> {
fn pixel_type(&self) -> Option<PixelType> {
Some(self.pixel_type)
}
fn width(&self) -> u32 {
self.width
}
fn height(&self) -> u32 {
self.height
}
fn image_view<P: InnerPixel>(&self) -> Option<impl ImageView<Pixel = P>> {
self.typed_image()
}
}
#[derive(Debug)]
enum BufferContainer<'a> {
MutU8(&'a mut [u8]),
+8 -7
View File
@@ -103,8 +103,9 @@ pub struct Resizer {
impl Resizer {
/// Creates instance of `Resizer`
///
/// By default, instance of `Resizer` created with the best CPU-extensions provided by your CPU.
/// You can change this by use method [Resizer::set_cpu_extensions].
/// By default, instance of `Resizer` created with the best CPU
/// extensions provided by your CPU.
/// You can change this by using method [Resizer::set_cpu_extensions].
pub fn new(algorithm: ResizeAlg) -> Self {
Self {
algorithm,
@@ -112,7 +113,7 @@ impl Resizer {
}
}
/// Resize source image to the size of destination image and save
/// Resize the source image to the size of destination image and save
/// the result to the latter's pixel buffer.
pub fn resize<'o>(
&mut self,
@@ -174,7 +175,7 @@ impl Resizer {
result
}
/// Resize source image to the size of destination image
/// Resize the source image to the size of destination image
/// and save the result to the latter's pixel buffer.
pub fn resize_typed<'o, P: PixelTrait>(
&mut self,
@@ -257,8 +258,8 @@ impl Resizer {
}
/// # Safety
/// This is unsafe because this method allows you to set a CPU-extensions
/// that is not actually supported by your CPU.
/// This is unsafe because this method allows you to set a CPU extensions
/// that is not supported by your CPU.
pub unsafe fn set_cpu_extensions(&mut self, extensions: CpuExtensions) {
self.cpu_extensions = extensions;
self.mul_div.set_cpu_extensions(extensions);
@@ -472,7 +473,7 @@ impl Resizer {
}
}
/// Creates inner image container from part of given buffer.
/// Creates inner image container from part of the given buffer.
/// Buffer may be expanded if its size is less than required for image.
fn get_temp_image_from_buffer<P: PixelTrait>(
buffer: &mut Vec<u8>,
+11 -1
View File
@@ -1,8 +1,18 @@
use fast_image_resize as fr;
use fast_image_resize::images::{CroppedImageMut, Image, TypedImage, TypedImageMut};
use fast_image_resize::images::{CroppedImageMut, Image, ImageRef, TypedImage, TypedImageMut};
use fast_image_resize::pixels::{U8x4, U8};
use fast_image_resize::ImageView;
#[test]
fn create_image_ref_from_small_buffer() {
let width = 64;
let height = 32;
let buffer = vec![0; 64 * 30];
let res = ImageRef::new(width, height, &buffer, fr::PixelType::U8);
assert_eq!(res.unwrap_err(), fr::ImageBufferError::InvalidBufferSize);
}
#[test]
fn create_image_from_small_buffer() {
let width = 64;