Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

Breaking Changes:
- Trait `ImageDecoderRect` has been removed (#2355, #2681)
- DynamicImage now has Luma32F and LumaA32F variants, and conversions (like
`DynamicImage::grayscale`, and `From<GrayAlpha32FImage>`) may now directly
produce these instead of Rgb32F or Rgba32F

### Version 0.25.9

Expand Down
28 changes: 24 additions & 4 deletions benches/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ pub fn bench_cast_intra_colorspace(c: &mut Criterion) {
b.iter(|| black_box(&luma_source).to_luma16());
});

c.bench_function("cast_dynamic_luma8_luma32f", |b| {
b.iter(|| black_box(&luma_source).to_luma32f());
});

c.bench_function("cast_dynamic_luma8_luma_alpha8", |b| {
b.iter(|| black_box(&luma_source).to_luma_alpha8());
});
Expand All @@ -44,13 +48,21 @@ pub fn bench_cast_intra_colorspace(c: &mut Criterion) {
b.iter(|| black_box(&luma_source).to_luma_alpha16());
});

c.bench_function("cast_dynamic_luma8_luma_alpha32f", |b| {
b.iter(|| black_box(&luma_source).to_luma_alpha32f());
});

let la_source =
DynamicImage::ImageLumaA8(ImageBuffer::from_pixel(256, 256, image::LumaA([0u8, 255])));

c.bench_function("cast_dynamic_luma_alpha8_luma_alpha16", |b| {
b.iter(|| black_box(&la_source).to_luma_alpha16());
});

c.bench_function("cast_dynamic_luma_alpha8_luma_alpha32f", |b| {
b.iter(|| black_box(&la_source).to_luma_alpha32f());
});

c.bench_function("cast_dynamic_luma_alpha8_luma8", |b| {
b.iter(|| black_box(&la_source).to_luma8());
});
Expand All @@ -59,21 +71,29 @@ pub fn bench_cast_intra_colorspace(c: &mut Criterion) {
b.iter(|| black_box(&la_source).to_luma16());
});

c.bench_function("cast_dynamic_luma_alpha8_luma32f", |b| {
b.iter(|| black_box(&la_source).to_luma32f());
});

let la_source =
DynamicImage::ImageLumaA16(ImageBuffer::from_pixel(256, 256, image::LumaA([0u16, 255])));

c.bench_function("cast_dynamic_luma_alpha16_luma_alpha16", |b| {
b.iter(|| black_box(&la_source).to_luma_alpha16());
c.bench_function("cast_dynamic_luma_alpha16_luma_alpha8", |b| {
b.iter(|| black_box(&la_source).to_luma_alpha8());
});

c.bench_function("cast_dynamic_luma_alpha16_luma8", |b| {
b.iter(|| black_box(&la_source).to_luma8());
c.bench_function("cast_dynamic_luma_alpha16_luma_alpha32f", |b| {
b.iter(|| black_box(&la_source).to_luma_alpha32f());
});

c.bench_function("cast_dynamic_luma_alpha16_luma16", |b| {
b.iter(|| black_box(&la_source).to_luma16());
});

c.bench_function("cast_dynamic_luma_alpha16_luma32f", |b| {
b.iter(|| black_box(&la_source).to_luma32f());
});

let rgba32_source =
DynamicImage::ImageRgba32F(ImageBuffer::from_pixel(256, 256, Rgba(Default::default())));

Expand Down
2 changes: 1 addition & 1 deletion src/codecs/jpeg/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ impl<W: Write> ImageEncoder for JpegEncoder<W> {
use ColorType::*;
match img.color() {
L8 | Rgb8 => None,
La8 | L16 | La16 => Some(img.to_luma8().into()),
La8 | L16 | L32F | La16 | La32F => Some(img.to_luma8().into()),
Rgba8 | Rgb16 | Rgb32F | Rgba16 | Rgba32F => Some(img.to_rgb8().into()),
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/codecs/png.rs
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,8 @@ impl<W: Write> ImageEncoder for PngEncoder<W> {
) -> Option<DynamicImage> {
use ColorType::*;
match img.color() {
L32F => Some(img.to_luma16().into()),
La32F => Some(img.to_luma_alpha16().into()),
Rgb32F => Some(img.to_rgb16().into()),
Rgba32F => Some(img.to_rgba16().into()),
L8 | La8 | Rgb8 | Rgba8 | L16 | La16 | Rgb16 | Rgba16 => None,
Expand Down
18 changes: 13 additions & 5 deletions src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ pub enum ColorType {
/// Pixel is 16-bit RGBA
Rgba16,

/// Pixel is 32-bit float luminance
L32F,
/// Pixel is 32-bit float luminance with an alpha channel
La32F,
/// Pixel is 32-bit float RGB
Rgb32F,
/// Pixel is 32-bit float RGBA
Expand All @@ -45,9 +49,9 @@ impl ColorType {
ColorType::L8 => 1,
ColorType::L16 | ColorType::La8 => 2,
ColorType::Rgb8 => 3,
ColorType::Rgba8 | ColorType::La16 => 4,
ColorType::Rgba8 | ColorType::La16 | ColorType::L32F => 4,
ColorType::Rgb16 => 6,
ColorType::Rgba16 => 8,
ColorType::Rgba16 | ColorType::La32F => 8,
ColorType::Rgb32F => 3 * 4,
ColorType::Rgba32F => 4 * 4,
}
Expand All @@ -58,8 +62,8 @@ impl ColorType {
pub fn has_alpha(self) -> bool {
use ColorType::*;
match self {
L8 | L16 | Rgb8 | Rgb16 | Rgb32F => false,
La8 | Rgba8 | La16 | Rgba16 | Rgba32F => true,
L8 | L16 | L32F | Rgb8 | Rgb16 | Rgb32F => false,
La8 | Rgba8 | La16 | Rgba16 | La32F | Rgba32F => true,
}
}

Expand All @@ -68,7 +72,7 @@ impl ColorType {
pub fn has_color(self) -> bool {
use ColorType::*;
match self {
L8 | L16 | La8 | La16 => false,
L8 | L16 | L32F | La8 | La16 | La32F => false,
Rgb8 | Rgb16 | Rgba8 | Rgba16 | Rgb32F | Rgba32F => true,
}
}
Expand Down Expand Up @@ -288,6 +292,8 @@ impl ExtendedColorType {
ExtendedColorType::La16 => Some(ColorType::La16),
ExtendedColorType::Rgb16 => Some(ColorType::Rgb16),
ExtendedColorType::Rgba16 => Some(ColorType::Rgba16),
ExtendedColorType::L32F => Some(ColorType::L32F),
ExtendedColorType::La32F => Some(ColorType::La32F),
ExtendedColorType::Rgb32F => Some(ColorType::Rgb32F),
ExtendedColorType::Rgba32F => Some(ColorType::Rgba32F),
ExtendedColorType::YCbCr8 => Some(ColorType::Rgb8),
Expand All @@ -314,6 +320,8 @@ impl From<ColorType> for ExtendedColorType {
ColorType::La16 => ExtendedColorType::La16,
ColorType::Rgb16 => ExtendedColorType::Rgb16,
ColorType::Rgba16 => ExtendedColorType::Rgba16,
ColorType::L32F => ExtendedColorType::L32F,
ColorType::La32F => ExtendedColorType::La32F,
ColorType::Rgb32F => ExtendedColorType::Rgb32F,
ColorType::Rgba32F => ExtendedColorType::Rgba32F,
}
Expand Down
22 changes: 21 additions & 1 deletion src/imageops/resize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ pub(crate) fn resize_impl(
let resized = resize_rgba16(src.as_raw(), src_size, dst_size, 16, alg)?;
ImageRgba16(ImageBuffer::from_raw(dst_width, dst_height, resized).unwrap())
}
ImageLuma32F(src) => {
let resized = resize_plane_f32(src.as_raw(), src_size, dst_size, alg)?;
ImageLuma32F(ImageBuffer::from_raw(dst_width, dst_height, resized).unwrap())
}
ImageLumaA32F(src) => {
let resized = resize_luma_alpha_f32(src.as_raw(), src_size, dst_size, alg)?;
ImageLumaA32F(ImageBuffer::from_raw(dst_width, dst_height, resized).unwrap())
}
ImageRgb32F(src) => {
let resized = resize_rgb_f32(src.as_raw(), src_size, dst_size, alg)?;
ImageRgb32F(ImageBuffer::from_raw(dst_width, dst_height, resized).unwrap())
Expand Down Expand Up @@ -113,6 +121,10 @@ fn premultiply_alpha(image: &mut DynamicImage) {
DynamicImage::ImageRgba16(buf) => {
premultiply_rgba16(buf.as_mut(), 16);
}
DynamicImage::ImageLuma32F(_) => (),
DynamicImage::ImageLumaA32F(buf) => {
premultiply_luma_alpha_f32(buf.as_mut());
}
DynamicImage::ImageRgb32F(_) => (),
DynamicImage::ImageRgba32F(buf) => {
premultiply_rgba_f32(buf.as_mut());
Expand All @@ -132,6 +144,8 @@ fn unpremultiply_alpha(image: &mut DynamicImage) {
DynamicImage::ImageLumaA16(buf) => unpremultiply_la16(buf.as_mut(), 16),
DynamicImage::ImageRgb16(_) => (),
DynamicImage::ImageRgba16(buf) => unpremultiply_rgba16(buf.as_mut(), 16),
DynamicImage::ImageLuma32F(_) => (),
DynamicImage::ImageLumaA32F(buf) => unpremultiply_luma_alpha_f32(buf),
DynamicImage::ImageRgb32F(_) => (),
DynamicImage::ImageRgba32F(buf) => unpremultiply_rgba_f32(buf),
}
Expand All @@ -148,6 +162,8 @@ fn has_constant_alpha(image: &DynamicImage) -> bool {
DynamicImage::ImageLumaA16(buf) => has_constant_alpha_integer(buf),
DynamicImage::ImageRgb16(_) => true,
DynamicImage::ImageRgba16(buf) => has_constant_alpha_integer(buf),
DynamicImage::ImageLuma32F(_) => true,
DynamicImage::ImageLumaA32F(buf) => has_constant_alpha_f32(buf),
DynamicImage::ImageRgb32F(_) => true,
DynamicImage::ImageRgba32F(buf) => has_constant_alpha_f32(buf),
}
Expand Down Expand Up @@ -185,7 +201,11 @@ where
}

#[must_use]
fn has_constant_alpha_f32(img: &ImageBuffer<crate::Rgba<f32>, Vec<f32>>) -> bool {
fn has_constant_alpha_f32<P, Container>(img: &ImageBuffer<P, Container>) -> bool
where
P: Pixel<Subpixel = f32>,
Container: std::ops::Deref<Target = [f32]>,
{
// Optimizing correctly in presence of NaNs and infinities is tricky, so just do the naive thing for now
let first_pixel_alpha = match img.pixels().next() {
Some(pixel) => pixel.alpha(),
Expand Down
32 changes: 31 additions & 1 deletion src/imageops/sample.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ use crate::imageops::filter_1d::{
filter_2d_sep_rgb_u16, filter_2d_sep_rgba, filter_2d_sep_rgba_f32, filter_2d_sep_rgba_u16,
FilterImageSize,
};
use crate::images::buffer::{Gray16Image, GrayAlpha16Image, Rgb16Image, Rgba16Image};
use crate::images::buffer::{
Gray16Image, Gray32FImage, GrayAlpha16Image, GrayAlpha32FImage, Rgb16Image, Rgba16Image,
};
use crate::traits::{Enlargeable, Pixel, Primitive};
use crate::utils::{clamp, is_integer, vec_try_with_capacity};
use crate::{
Expand Down Expand Up @@ -1435,6 +1437,34 @@ pub(crate) fn gaussian_blur_dyn_image(
Rgba16Image::from_raw(img.width(), img.height(), dest_image).unwrap(),
)
}
DynamicImage::ImageLuma32F(img) => {
let mut dest_image = vec![0f32; img.len()];
filter_2d_sep_plane_f32(
img.as_raw(),
&mut dest_image,
filter_image_size,
&x_axis_kernel,
&y_axis_kernel,
)
.unwrap();
DynamicImage::ImageLuma32F(
Gray32FImage::from_raw(img.width(), img.height(), dest_image).unwrap(),
)
}
DynamicImage::ImageLumaA32F(img) => {
let mut dest_image = vec![0f32; img.len()];
filter_2d_sep_la_f32(
img.as_raw(),
&mut dest_image,
filter_image_size,
&x_axis_kernel,
&y_axis_kernel,
)
.unwrap();
DynamicImage::ImageLumaA32F(
GrayAlpha32FImage::from_raw(img.width(), img.height(), dest_image).unwrap(),
)
}
DynamicImage::ImageRgb32F(img) => {
let mut dest_image = vec![0f32; img.len()];
filter_2d_sep_rgb_f32(
Expand Down
22 changes: 21 additions & 1 deletion src/images/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1916,10 +1916,15 @@ pub(crate) type Gray16Image = ImageBuffer<Luma<u16>, Vec<u16>>;
/// Sendable 16-bit grayscale + alpha channel image buffer
pub(crate) type GrayAlpha16Image = ImageBuffer<LumaA<u16>, Vec<u16>>;

/// An image buffer for 32-bit float grayscale pixels,
/// where the backing container is a flattened vector of floats.
pub(crate) type Gray32FImage = ImageBuffer<Luma<f32>, Vec<f32>>;
/// An image buffer for 32-bit float grayscale + alpha pixels,
/// where the backing container is a flattened vector of floats.
pub(crate) type GrayAlpha32FImage = ImageBuffer<LumaA<f32>, Vec<f32>>;
/// An image buffer for 32-bit float RGB pixels,
/// where the backing container is a flattened vector of floats.
pub type Rgb32FImage = ImageBuffer<Rgb<f32>, Vec<f32>>;

/// An image buffer for 32-bit float RGBA pixels,
/// where the backing container is a flattened vector of floats.
pub type Rgba32FImage = ImageBuffer<Rgba<f32>, Vec<f32>>;
Expand Down Expand Up @@ -1972,11 +1977,26 @@ impl From<DynamicImage> for GrayAlpha16Image {
}
}

impl From<DynamicImage> for Rgb32FImage {
fn from(value: DynamicImage) -> Self {
value.into_rgb32f()
}
}
impl From<DynamicImage> for Rgba32FImage {
fn from(value: DynamicImage) -> Self {
value.into_rgba32f()
}
}
impl From<DynamicImage> for Gray32FImage {
fn from(value: DynamicImage) -> Self {
value.into_luma32f()
}
}
impl From<DynamicImage> for GrayAlpha32FImage {
fn from(value: DynamicImage) -> Self {
value.into_luma_alpha32f()
}
}

#[cfg(test)]
mod test {
Expand Down
Loading
Loading