mirror of
https://github.com/Cykooz/fast_image_resize.git
synced 2026-10-08 01:11:09 +00:00
- Added ImageRef structure.
- Added example of code with differences between v3.x and v4.x.
This commit is contained in:
+114
-12
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user