diff --git a/Cargo.toml b/Cargo.toml index c8d9b72805..da7d2dc161 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "image" -version = "0.25.1" +version = "0.26.0" edition = "2021" resolver = "2" @@ -22,12 +22,12 @@ categories = ["multimedia::images", "multimedia::encoding", "encoding"] exclude = ["src/png/testdata/*", "examples/*", "tests/*"] include = [ - "/LICENSE-APACHE", - "/LICENSE-MIT", - "/README.md", - "/CHANGES.md", - "/src/", - "/benches/", + "/LICENSE-APACHE", + "/LICENSE-MIT", + "/README.md", + "/CHANGES.md", + "/src/", + "/benches/", ] [package.metadata.docs.rs] @@ -35,9 +35,12 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] -bytemuck = { version = "1.8.0", features = ["extern_crate_alloc"] } # includes cast_vec +bytemuck = { version = "1.8.0", features = [ + "extern_crate_alloc", +] } # includes cast_vec byteorder-lite = "0.1.0" num-traits = { version = "0.2.0" } +pixeli = "0.2.1" # Optional dependencies color_quant = { version = "1.1", optional = true } @@ -67,7 +70,23 @@ criterion = "0.5.0" default = ["rayon", "default-formats"] # Format features -default-formats = ["avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp"] +default-formats = [ + "avif", + "bmp", + "dds", + "exr", + "ff", + "gif", + "hdr", + "ico", + "jpeg", + "png", + "pnm", + "qoi", + "tga", + "tiff", + "webp", +] avif = ["dep:ravif", "dep:rgb"] bmp = [] dds = [] @@ -86,10 +105,17 @@ webp = ["dep:image-webp"] # Other features rayon = ["dep:rayon"] # Enables multi-threading -nasm = ["ravif?/asm"] # Enables use of nasm by rav1e (requires nasm to be installed) +nasm = [ + "ravif?/asm", +] # Enables use of nasm by rav1e (requires nasm to be installed) color_quant = ["dep:color_quant"] # Enables color quantization -avif-native = ["dep:mp4parse", "dep:dcv-color-primitives", "dep:dav1d"] # Enable native dependency libdav1d -benchmarks = [] # Build some inline benchmarks. Useful only during development (requires nightly Rust) +avif-native = [ + "dep:mp4parse", + "dep:dcv-color-primitives", + "dep:dav1d", +] # Enable native dependency libdav1d +benchmarks = [ +] # Build some inline benchmarks. Useful only during development (requires nightly Rust) [[bench]] path = "benches/decode.rs" diff --git a/README.md b/README.md index e3eb168058..7c8eb542a0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Image + [](https://crates.io/crates/image) [](https://docs.rs/image) [](https://github.com/image-rs/image/actions) @@ -42,23 +43,23 @@ image format encoders and decoders. -| Format | Decoding | Encoding | -| -------- | ----------------------------------------- | --------------------------------------- | -| AVIF | Yes (8-bit only) \* | Yes (lossy only) | -| BMP | Yes | Yes | -| DDS | Yes | --- | -| Farbfeld | Yes | Yes | -| GIF | Yes | Yes | -| HDR | Yes | Yes | -| ICO | Yes | Yes | -| JPEG | Yes | Yes | -| EXR | Yes | Yes | -| PNG | Yes | Yes | -| PNM | Yes | Yes | -| QOI | Yes | Yes | -| TGA | Yes | Yes | -| TIFF | Yes | Yes | -| WebP | Yes | Yes (lossless only) | +| Format | Decoding | Encoding | +| -------- | ------------------- | ------------------- | +| AVIF | Yes (8-bit only) \* | Yes (lossy only) | +| BMP | Yes | Yes | +| DDS | Yes | --- | +| Farbfeld | Yes | Yes | +| GIF | Yes | Yes | +| HDR | Yes | Yes | +| ICO | Yes | Yes | +| JPEG | Yes | Yes | +| EXR | Yes | Yes | +| PNG | Yes | Yes | +| PNM | Yes | Yes | +| QOI | Yes | Yes | +| TGA | Yes | Yes | +| TIFF | Yes | Yes | +| WebP | Yes | Yes (lossless only) | - \* Requires the `avif-native` feature, uses the libdav1d C library. @@ -68,11 +69,13 @@ This crate provides a number of different types for representing images. Individual pixels within images are indexed with (0,0) at the top left corner. ### [`ImageBuffer`](https://docs.rs/image/*/image/struct.ImageBuffer.html) + An image parameterised by its Pixel type, represented by a width and height and a vector of pixels. It provides direct access to its pixels and implements the `GenericImageView` and `GenericImage` traits. ### [`DynamicImage`](https://docs.rs/image/*/image/enum.DynamicImage.html) + A `DynamicImage` is an enumeration over all supported `ImageBuffer
` types.
Its exact image type is determined at runtime. It is the type returned when
opening an image. For convenience `DynamicImage` reimplements all image
@@ -83,11 +86,11 @@ processing functions.
Traits that provide methods for inspecting (`GenericImageView`) and manipulating (`GenericImage`) images, parameterised over the image's pixel type.
### [`SubImage`](https://docs.rs/image/*/image/struct.SubImage.html)
+
A view into another image, delimited by the coordinates of a rectangle.
The coordinates given set the position of the top left corner of the rectangle.
This is used to perform image processing functions on a subregion of an image.
-
## The [`ImageDecoder`](https://docs.rs/image/*/image/trait.ImageDecoder.html) and [`ImageDecoderRect`](https://docs.rs/image/*/image/trait.ImageDecoderRect.html) Traits
All image format decoders implement the `ImageDecoder` trait which provide
@@ -96,46 +99,50 @@ additionally provide `ImageDecoderRect` implementations which allow for
decoding only part of an image at once.
The most important methods for decoders are...
-+ **dimensions**: Return a tuple containing the width and height of the image.
-+ **color_type**: Return the color type of the image data produced by this decoder.
-+ **read_image**: Decode the entire image into a slice of bytes.
+
+- **dimensions**: Return a tuple containing the width and height of the image.
+- **color_type**: Return the color type of the image data produced by this decoder.
+- **read_image**: Decode the entire image into a slice of bytes.
## Pixels
`image` provides the following pixel types:
-+ **Rgb**: RGB pixel
-+ **Rgba**: RGB with alpha (RGBA pixel)
-+ **Luma**: Grayscale pixel
-+ **LumaA**: Grayscale with alpha
+
+- **Rgb**: RGB pixel
+- **Rgba**: RGB with alpha (RGBA pixel)
+- **Luma**: Grayscale pixel
+- **LumaA**: Grayscale with alpha
All pixels are parameterised by their component type.
## Image Processing Functions
+
These are the functions defined in the `imageops` module. All functions operate on types that implement the `GenericImage` trait.
Note that some of the functions are very slow in debug mode. Make sure to use release mode if you experience any performance issues.
-+ **blur**: Performs a Gaussian blur on the supplied image.
-+ **brighten**: Brighten the supplied image.
-+ **huerotate**: Hue rotate the supplied image by degrees.
-+ **contrast**: Adjust the contrast of the supplied image.
-+ **crop**: Return a mutable view into an image.
-+ **filter3x3**: Perform a 3x3 box filter on the supplied image.
-+ **flip_horizontal**: Flip an image horizontally.
-+ **flip_vertical**: Flip an image vertically.
-+ **grayscale**: Convert the supplied image to grayscale.
-+ **invert**: Invert each pixel within the supplied image This function operates in place.
-+ **resize**: Resize the supplied image to the specified dimensions.
-+ **rotate180**: Rotate an image 180 degrees clockwise.
-+ **rotate270**: Rotate an image 270 degrees clockwise.
-+ **rotate90**: Rotate an image 90 degrees clockwise.
-+ **unsharpen**: Performs an unsharpen mask on the supplied image.
+- **blur**: Performs a Gaussian blur on the supplied image.
+- **brighten**: Brighten the supplied image.
+- **huerotate**: Hue rotate the supplied image by degrees.
+- **contrast**: Adjust the contrast of the supplied image.
+- **crop**: Return a mutable view into an image.
+- **filter3x3**: Perform a 3x3 box filter on the supplied image.
+- **flip_horizontal**: Flip an image horizontally.
+- **flip_vertical**: Flip an image vertically.
+- **grayscale**: Convert the supplied image to grayscale.
+- **invert**: Invert each pixel within the supplied image This function operates in place.
+- **resize**: Resize the supplied image to the specified dimensions.
+- **rotate180**: Rotate an image 180 degrees clockwise.
+- **rotate270**: Rotate an image 270 degrees clockwise.
+- **rotate90**: Rotate an image 90 degrees clockwise.
+- **unsharpen**: Performs an unsharpen mask on the supplied image.
For more options, see the [`imageproc`](https://crates.io/crates/imageproc) crate.
## Examples
+
### Opening and Saving Images
-`image` provides the `open` function for opening images from a path. The image
+`image` provides the `open` function for opening images from a path. The image
format is determined from the path's file extension. An `io` module provides a
reader which offer some more control.
@@ -173,7 +180,7 @@ let mut imgbuf = image::ImageBuffer::new(imgx, imgy);
for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
let r = (0.3 * x as f32) as u8;
let b = (0.3 * y as f32) as u8;
- *pixel = image::Rgb([r, 0, b]);
+ *pixel = pixeli::Rgb{r, g: 0, b};
}
// A redundant loop to demonstrate reading image data
@@ -192,8 +199,7 @@ for x in 0..imgx {
}
let pixel = imgbuf.get_pixel_mut(x, y);
- let image::Rgb(data) = *pixel;
- *pixel = image::Rgb([data[0], i as u8, data[2]]);
+ *pixel = pixeli::Rgb{r: pixel.r, g: i as u8, b: pixel.b};
}
}
@@ -206,6 +212,7 @@ Example output:
### Writing raw buffers
+
If the high level interface is not needed because the image was obtained by other means, `image` provides the function `save_buffer` to save a buffer to a file.
```rust,no_run
diff --git a/benches/copy_from.rs b/benches/copy_from.rs
index 37a4af8b9d..2731f1951f 100644
--- a/benches/copy_from.rs
+++ b/benches/copy_from.rs
@@ -1,9 +1,28 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
-use image::{GenericImage, ImageBuffer, Rgba};
+use image::{GenericImage, ImageBuffer};
+use pixeli::Rgba;
pub fn bench_copy_from(c: &mut Criterion) {
- let src = ImageBuffer::from_pixel(2048, 2048, Rgba([255u8, 0, 0, 255]));
- let mut dst = ImageBuffer::from_pixel(2048, 2048, Rgba([0u8, 0, 0, 255]));
+ let src = ImageBuffer::from_pixel(
+ 2048,
+ 2048,
+ Rgba {
+ r: 255u8,
+ g: 0,
+ b: 0,
+ a: 255,
+ },
+ );
+ let mut dst = ImageBuffer::from_pixel(
+ 2048,
+ 2048,
+ Rgba {
+ r: 0u8,
+ g: 0,
+ b: 0,
+ a: 255,
+ },
+ );
c.bench_function("copy_from", |b| {
b.iter(|| dst.copy_from(black_box(&src), 0, 0))
diff --git a/examples/concat/main.rs b/examples/concat/main.rs
index 63dcb09167..0bc9413e50 100644
--- a/examples/concat/main.rs
+++ b/examples/concat/main.rs
@@ -1,4 +1,5 @@
-use image::{GenericImage, GenericImageView, ImageBuffer, Pixel, Primitive};
+use image::{Blend, GenericImage, GenericImageView, ImageBuffer};
+use pixeli::{ContiguousPixel, Pixel, PixelComponent};
/// Example showcasing a generic implementation of image concatenation.
///
@@ -20,8 +21,8 @@ fn main() {
fn h_concat(images: &[I]) -> ImageBuffer
>
where
I: GenericImageView ::from_slice(v))
+ self.chunks
+ .next()
+ .map(|v| ::from_component_slice_ref(v))
}
#[inline(always)]
@@ -42,22 +46,26 @@ where
}
}
-impl<'a, P: Pixel + 'a> ExactSizeIterator for Pixels<'a, P>
+impl<'a, P: 'a> ExactSizeIterator for Pixels<'a, P>
where
- P::Subpixel: 'a,
+ P: ContiguousPixel,
+ P::Component: 'a,
{
fn len(&self) -> usize {
self.chunks.len()
}
}
-impl<'a, P: Pixel + 'a> DoubleEndedIterator for Pixels<'a, P>
+impl<'a, P: 'a> DoubleEndedIterator for Pixels<'a, P>
where
- P::Subpixel: 'a,
+ P: ContiguousPixel,
+ P::Component: 'a,
{
#[inline(always)]
fn next_back(&mut self) -> Option<&'a P> {
- self.chunks.next_back().map(|v| ::from_slice(v))
+ self.chunks
+ .next_back()
+ .map(|v| ::from_component_slice_ref(v))
}
}
@@ -71,7 +79,7 @@ impl ::from_slice_mut(v))
+ self.chunks
+ .next()
+ .map(|v| ::from_component_slice_mut(v))
}
#[inline(always)]
@@ -106,30 +117,33 @@ where
}
}
-impl<'a, P: Pixel + 'a> ExactSizeIterator for PixelsMut<'a, P>
+impl<'a, P: 'a> ExactSizeIterator for PixelsMut<'a, P>
where
- P::Subpixel: 'a,
+ P: ContiguousPixel,
+ P::Component: 'a,
{
fn len(&self) -> usize {
self.chunks.len()
}
}
-impl<'a, P: Pixel + 'a> DoubleEndedIterator for PixelsMut<'a, P>
+impl<'a, P: 'a> DoubleEndedIterator for PixelsMut<'a, P>
where
- P::Subpixel: 'a,
+ P: ContiguousPixel,
+ P::Component: 'a,
{
#[inline(always)]
fn next_back(&mut self) -> Option<&'a mut P> {
self.chunks
.next_back()
- .map(|v| ::from_slice_mut(v))
+ .map(|v| ::from_component_slice_mut(v))
}
}
-impl fmt::Debug for PixelsMut<'_, P>
where
- P::Subpixel: fmt::Debug,
+ P: ContiguousPixel,
+ P::Component: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("PixelsMut")
@@ -145,16 +159,16 @@ where
/// [`ImageBuffer::rows`]: ../struct.ImageBuffer.html#method.rows
pub struct Rows<'a, P: Pixel + 'a>
where
- ::Subpixel: 'a,
+ ::Component: 'a,
{
- pixels: ChunksExact<'a, P::Subpixel>,
+ pixels: ChunksExact<'a, P::Component>,
}
impl<'a, P: Pixel + 'a> Rows<'a, P> {
/// Construct the iterator from image pixels. This is not public since it has a (hidden) panic
/// condition. The `pixels` slice must be large enough so that all pixels are addressable.
- fn with_image(pixels: &'a [P::Subpixel], width: u32, height: u32) -> Self {
- let row_len = (width as usize) * usize::from( ::CHANNEL_COUNT);
+ fn with_image(pixels: &'a [P::Component], width: u32, height: u32) -> Self {
+ let row_len = (width as usize) * usize::from( ::COMPONENT_COUNT);
if row_len == 0 {
Rows {
pixels: [].chunks_exact(1),
@@ -174,7 +188,7 @@ impl<'a, P: Pixel + 'a> Rows<'a, P> {
impl<'a, P: Pixel + 'a> Iterator for Rows<'a, P>
where
- P::Subpixel: 'a,
+ P::Component: 'a,
{
type Item = Pixels<'a, P>;
@@ -182,8 +196,8 @@ where
fn next(&mut self) -> Option ::CHANNEL_COUNT as usize),
+ // Note: this is not reached when COMPONENT_COUNT is 0.
+ chunks: row.chunks_exact( ::COMPONENT_COUNT as usize),
})
}
@@ -196,7 +210,7 @@ where
impl<'a, P: Pixel + 'a> ExactSizeIterator for Rows<'a, P>
where
- P::Subpixel: 'a,
+ P::Component: 'a,
{
fn len(&self) -> usize {
self.pixels.len()
@@ -205,14 +219,14 @@ where
impl<'a, P: Pixel + 'a> DoubleEndedIterator for Rows<'a, P>
where
- P::Subpixel: 'a,
+ P::Component: 'a,
{
#[inline(always)]
fn next_back(&mut self) -> Option ::CHANNEL_COUNT as usize),
+ // Note: this is not reached when COMPONENT_COUNT is 0.
+ chunks: row.chunks_exact( ::COMPONENT_COUNT as usize),
})
}
}
@@ -227,7 +241,7 @@ impl ::Subpixel: 'a,
+ ::Component: 'a,
{
- pixels: ChunksExactMut<'a, P::Subpixel>,
+ pixels: ChunksExactMut<'a, P::Component>,
}
impl<'a, P: Pixel + 'a> RowsMut<'a, P> {
/// Construct the iterator from image pixels. This is not public since it has a (hidden) panic
/// condition. The `pixels` slice must be large enough so that all pixels are addressable.
- fn with_image(pixels: &'a mut [P::Subpixel], width: u32, height: u32) -> Self {
- let row_len = (width as usize) * usize::from( ::CHANNEL_COUNT);
+ fn with_image(pixels: &'a mut [P::Component], width: u32, height: u32) -> Self {
+ let row_len = (width as usize) * usize::from( ::COMPONENT_COUNT);
if row_len == 0 {
RowsMut {
pixels: [].chunks_exact_mut(1),
@@ -272,7 +286,7 @@ impl<'a, P: Pixel + 'a> RowsMut<'a, P> {
impl<'a, P: Pixel + 'a> Iterator for RowsMut<'a, P>
where
- P::Subpixel: 'a,
+ P::Component: 'a,
{
type Item = PixelsMut<'a, P>;
@@ -280,8 +294,8 @@ where
fn next(&mut self) -> Option ::CHANNEL_COUNT as usize),
+ // Note: this is not reached when COMPONENT_COUNT is 0.
+ chunks: row.chunks_exact_mut( ::COMPONENT_COUNT as usize),
})
}
@@ -294,7 +308,7 @@ where
impl<'a, P: Pixel + 'a> ExactSizeIterator for RowsMut<'a, P>
where
- P::Subpixel: 'a,
+ P::Component: 'a,
{
fn len(&self) -> usize {
self.pixels.len()
@@ -303,21 +317,21 @@ where
impl<'a, P: Pixel + 'a> DoubleEndedIterator for RowsMut<'a, P>
where
- P::Subpixel: 'a,
+ P::Component: 'a,
{
#[inline(always)]
fn next_back(&mut self) -> Option ::CHANNEL_COUNT as usize),
+ // Note: this is not reached when COMPONENT_COUNT is 0.
+ chunks: row.chunks_exact_mut( ::COMPONENT_COUNT as usize),
})
}
}
impl ::Subpixel: 'a,
+ ::Component: 'a,
{
pixels: Pixels<'a, P>,
x: u32,
@@ -337,9 +351,10 @@ where
width: u32,
}
-impl<'a, P: Pixel + 'a> Iterator for EnumeratePixels<'a, P>
+impl<'a, P: 'a> Iterator for EnumeratePixels<'a, P>
where
- P::Subpixel: 'a,
+ P: ContiguousPixel,
+ P::Component: 'a,
{
type Item = (u32, u32, &'a P);
@@ -361,9 +376,10 @@ where
}
}
-impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumeratePixels<'a, P>
+impl<'a, P: 'a> ExactSizeIterator for EnumeratePixels<'a, P>
where
- P::Subpixel: 'a,
+ P: ContiguousPixel,
+ P::Component: 'a,
{
fn len(&self) -> usize {
self.pixels.len()
@@ -381,7 +397,7 @@ impl ::Subpixel: 'a,
+ ::Component: 'a,
{
rows: Rows<'a, P>,
y: u32,
@@ -405,7 +421,7 @@ where
impl<'a, P: Pixel + 'a> Iterator for EnumerateRows<'a, P>
where
- P::Subpixel: 'a,
+ P::Component: 'a,
{
type Item = (u32, EnumeratePixels<'a, P>);
@@ -435,7 +451,7 @@ where
impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumerateRows<'a, P>
where
- P::Subpixel: 'a,
+ P::Component: 'a,
{
fn len(&self) -> usize {
self.rows.len()
@@ -453,7 +469,7 @@ impl ::Subpixel: 'a,
+ ::Component: 'a,
{
pixels: PixelsMut<'a, P>,
x: u32,
@@ -475,9 +491,10 @@ where
width: u32,
}
-impl<'a, P: Pixel + 'a> Iterator for EnumeratePixelsMut<'a, P>
+impl<'a, P: 'a> Iterator for EnumeratePixelsMut<'a, P>
where
- P::Subpixel: 'a,
+ P: ContiguousPixel,
+ P::Component: 'a,
{
type Item = (u32, u32, &'a mut P);
@@ -499,18 +516,20 @@ where
}
}
-impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumeratePixelsMut<'a, P>
+impl<'a, P: 'a> ExactSizeIterator for EnumeratePixelsMut<'a, P>
where
- P::Subpixel: 'a,
+ P: ContiguousPixel,
+ P::Component: 'a,
{
fn len(&self) -> usize {
self.pixels.len()
}
}
-impl fmt::Debug for EnumeratePixelsMut<'_, P>
where
- P::Subpixel: fmt::Debug,
+ P: ContiguousPixel,
+ P::Component: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("EnumeratePixelsMut")
@@ -525,7 +544,7 @@ where
/// Enumerate the rows of an image.
pub struct EnumerateRowsMut<'a, P: Pixel + 'a>
where
- ::Subpixel: 'a,
+ ::Component: 'a,
{
rows: RowsMut<'a, P>,
y: u32,
@@ -534,7 +553,7 @@ where
impl<'a, P: Pixel + 'a> Iterator for EnumerateRowsMut<'a, P>
where
- P::Subpixel: 'a,
+ P::Component: 'a,
{
type Item = (u32, EnumeratePixelsMut<'a, P>);
@@ -564,7 +583,7 @@ where
impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumerateRowsMut<'a, P>
where
- P::Subpixel: 'a,
+ P::Component: 'a,
{
fn len(&self) -> usize {
self.rows.len()
@@ -573,7 +592,7 @@ where
impl ImageBuffer
where
- P: Pixel,
- Container: Deref ::CHANNEL_COUNT as usize),
+ .chunks_exact( ::COMPONENT_COUNT as usize),
}
}
@@ -773,7 +793,9 @@ where
(x, y),
(self.width, self.height)
),
- Some(pixel_indices) => ::from_slice(&self.data[pixel_indices]),
+ Some(pixel_indices) => {
+ ::from_component_slice_ref(&self.data[pixel_indices])
+ }
}
}
@@ -783,7 +805,7 @@ where
if x >= self.width {
return None;
}
- let num_channels = ::CHANNEL_COUNT as usize;
+ let num_channels = ::COMPONENT_COUNT as usize;
let i = (y as usize)
.saturating_mul(self.width as usize)
.saturating_add(x as usize)
@@ -791,7 +813,7 @@ where
self.data
.get(i..i.checked_add(num_channels)?)
- .map(|pixel_indices| ::from_slice(pixel_indices))
+ .map(|pixel_indices| ::from_component_slice_ref(pixel_indices))
}
/// Test that the image fits inside the buffer.
@@ -805,7 +827,7 @@ where
}
fn image_buffer_len(width: u32, height: u32) -> Option ::CHANNEL_COUNT as usize)
+ Some( ::COMPONENT_COUNT as usize)
.and_then(|size| size.checked_mul(width as usize))
.and_then(|size| size.checked_mul(height as usize))
}
@@ -821,7 +843,7 @@ where
#[inline(always)]
fn pixel_indices_unchecked(&self, x: u32, y: u32) -> Range ::CHANNEL_COUNT as usize;
+ let no_channels = ::COMPONENT_COUNT as usize;
// If in bounds, this can't overflow as we have tested that at construction!
let min_index = (y as usize * self.width as usize + x as usize) * no_channels;
min_index..min_index + no_channels
@@ -830,7 +852,7 @@ where
/// Get the format of the buffer when viewed as a matrix of samples.
pub fn sample_layout(&self) -> SampleLayout {
// None of these can overflow, as all our memory is addressable.
- SampleLayout::row_major_packed( ::CHANNEL_COUNT, self.width, self.height)
+ SampleLayout::row_major_packed( ::COMPONENT_COUNT, self.width, self.height)
}
/// Return the raw sample buffer with its stride an dimension information.
@@ -841,7 +863,7 @@ where
/// also byte strides.
pub fn into_flat_samples(self) -> FlatSamples ImageBuffer
where
- P: Pixel,
- Container: Deref ::CHANNEL_COUNT as usize),
+ .chunks_exact_mut( ::COMPONENT_COUNT as usize),
}
}
@@ -951,7 +973,9 @@ where
(x, y),
(self.width, self.height)
),
- Some(pixel_indices) => ::from_slice_mut(&mut self.data[pixel_indices]),
+ Some(pixel_indices) => {
+ ::from_component_slice_mut(&mut self.data[pixel_indices])
+ }
}
}
@@ -961,7 +985,7 @@ where
if x >= self.width {
return None;
}
- let num_channels = ::CHANNEL_COUNT as usize;
+ let num_channels = ::COMPONENT_COUNT as usize;
let i = (y as usize)
.saturating_mul(self.width as usize)
.saturating_add(x as usize)
@@ -969,7 +993,7 @@ where
self.data
.get_mut(i..i.checked_add(num_channels)?)
- .map(|pixel_indices| ::from_slice_mut(pixel_indices))
+ .map(|pixel_indices| ::from_component_slice_mut(pixel_indices))
}
/// Puts a pixel at location `(x, y)`
@@ -986,9 +1010,9 @@ where
impl ImageBuffer
where
- P: Pixel,
- [P::Subpixel]: EncodableLayout,
- Container: Deref ImageBuffer
where
- P: Pixel,
- [P::Subpixel]: EncodableLayout,
- Container: Deref ImageBuffer
where
- P: Pixel,
- [P::Subpixel]: EncodableLayout,
- Container: Deref ImageBuffer
where
- P: Pixel,
- [P::Subpixel]: EncodableLayout,
- Container: Deref Deref for ImageBuffer
where
P: Pixel,
- Container: Deref DerefMut for ImageBuffer
where
P: Pixel,
- Container: Deref Index<(u32, u32)> for ImageBuffer
where
- P: Pixel,
- Container: Deref IndexMut<(u32, u32)> for ImageBuffer
where
- P: Pixel,
- Container: Deref Clone for ImageBuffer
where
P: Pixel,
- Container: Deref {
ImageBuffer {
@@ -1167,8 +1191,8 @@ where
impl GenericImageView for ImageBuffer
where
- P: Pixel,
- Container: Deref ::from_slice(self.data.get_unchecked(indices))
+ ::from_components(self.data.get_unchecked(indices).iter().copied())
}
}
impl GenericImage for ImageBuffer
where
- P: Pixel,
- Container: Deref ::from_slice_mut(self.data.get_unchecked_mut(indices));
- *p = pixel
+ let pixel_data = self.data.get_unchecked_mut(indices);
+ let pixel_mut = P::from_component_slice_mut(pixel_data);
+ *pixel_mut = pixel;
}
/// Put a pixel at location (x, y), taking into account alpha channels
@@ -1260,15 +1285,18 @@ where
// there is no such function as `into_vec`, whereas `into_raw` did work, and
// `into_vec` is redundant anyway, because `into_raw` will give you the vector,
// and it is more generic.
-impl > {
- /// Creates a new image buffer based on a `Vec ImageBuffer >
+where
+ P: ContiguousPixel,
+{
+ /// Creates a new image buffer based on a `Vec > {
+ pub fn new(width: u32, height: u32) -> ImageBuffer > {
let size = Self::image_buffer_len(width, height)
.expect("Buffer length in `ImageBuffer::new` overflows usize");
ImageBuffer {
@@ -1284,7 +1312,7 @@ impl > {
/// # Panics
///
/// Panics when the resulting image is larger the the maximum size of a vector.
- pub fn from_pixel(width: u32, height: u32, pixel: P) -> ImageBuffer > {
+ pub fn from_pixel(width: u32, height: u32, pixel: P) -> ImageBuffer > {
let mut buf = ImageBuffer::new(width, height);
for p in buf.pixels_mut() {
*p = pixel
@@ -1299,7 +1327,7 @@ impl > {
/// # Panics
///
/// Panics when the resulting image is larger the the maximum size of a vector.
- pub fn from_fn >
+ pub fn from_fn >
where
F: FnMut(u32, u32) -> P,
{
@@ -1315,14 +1343,14 @@ impl > {
pub fn from_vec(
width: u32,
height: u32,
- buf: Vec ::from_slice(v))
+ .map(|v| ::from_component_slice_ref(v))
.drive_unindexed(consumer)
}
@@ -40,12 +40,12 @@ where
impl<'a, P> IndexedParallelIterator for PixelsPar<'a, P>
where
- P: Pixel + Sync + 'a,
- P::Subpixel: Sync + 'a,
+ P: ContiguousPixel + Sync + 'a,
+ P::Component: Sync + 'a,
{
fn drive ::from_slice(v))
+ .map(|v| ::from_component_slice_ref(v))
.drive(consumer)
}
@@ -55,7 +55,7 @@ where
fn with_producer ::from_slice(v))
+ .map(|v| ::from_component_slice_ref(v))
.with_producer(callback)
}
}
@@ -63,7 +63,7 @@ where
impl fmt::Debug for PixelsPar<'_, P>
where
P: Pixel + Sync,
- P::Subpixel: Sync + fmt::Debug,
+ P::Component: Sync + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("PixelsPar")
@@ -76,15 +76,15 @@ where
pub struct PixelsMutPar<'a, P>
where
P: Pixel + Send + Sync + 'a,
- P::Subpixel: Send + Sync + 'a,
+ P::Component: Send + Sync + 'a,
{
- chunks: ChunksExactMut<'a, P::Subpixel>,
+ chunks: ChunksExactMut<'a, P::Component>,
}
impl<'a, P> ParallelIterator for PixelsMutPar<'a, P>
where
- P: Pixel + Send + Sync + 'a,
- P::Subpixel: Send + Sync + 'a,
+ P: ContiguousPixel + Send + Sync + 'a,
+ P::Component: Send + Sync + 'a,
{
type Item = &'a mut P;
@@ -93,7 +93,7 @@ where
C: UnindexedConsumer ::from_slice_mut(v))
+ .map(|v| ::from_component_slice_mut(v))
.drive_unindexed(consumer)
}
@@ -104,12 +104,12 @@ where
impl<'a, P> IndexedParallelIterator for PixelsMutPar<'a, P>
where
- P: Pixel + Send + Sync + 'a,
- P::Subpixel: Send + Sync + 'a,
+ P: ContiguousPixel + Send + Sync + 'a,
+ P::Component: Send + Sync + 'a,
{
fn drive ::from_slice_mut(v))
+ .map(|v| ::from_component_slice_mut(v))
.drive(consumer)
}
@@ -119,7 +119,7 @@ where
fn with_producer ::from_slice_mut(v))
+ .map(|v| ::from_component_slice_mut(v))
.with_producer(callback)
}
}
@@ -127,7 +127,7 @@ where
impl fmt::Debug for PixelsMutPar<'_, P>
where
P: Pixel + Send + Sync,
- P::Subpixel: Send + Sync + fmt::Debug,
+ P::Component: Send + Sync + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("PixelsMutPar")
@@ -141,7 +141,7 @@ where
pub struct EnumeratePixelsPar<'a, P>
where
P: Pixel + Sync + 'a,
- P::Subpixel: Sync + 'a,
+ P::Component: Sync + 'a,
{
pixels: PixelsPar<'a, P>,
width: u32,
@@ -149,8 +149,8 @@ where
impl<'a, P> ParallelIterator for EnumeratePixelsPar<'a, P>
where
- P: Pixel + Sync + 'a,
- P::Subpixel: Sync + 'a,
+ P: ContiguousPixel + Sync + 'a,
+ P::Component: Sync + 'a,
{
type Item = (u32, u32, &'a P);
@@ -177,8 +177,8 @@ where
impl<'a, P> IndexedParallelIterator for EnumeratePixelsPar<'a, P>
where
- P: Pixel + Sync + 'a,
- P::Subpixel: Sync + 'a,
+ P: ContiguousPixel + Sync + 'a,
+ P::Component: Sync + 'a,
{
fn drive fmt::Debug for EnumeratePixelsPar<'_, P>
where
P: Pixel + Sync,
- P::Subpixel: Sync + fmt::Debug,
+ P::Component: Sync + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("EnumeratePixelsPar")
@@ -228,7 +228,7 @@ where
pub struct EnumeratePixelsMutPar<'a, P>
where
P: Pixel + Send + Sync + 'a,
- P::Subpixel: Send + Sync + 'a,
+ P::Component: Send + Sync + 'a,
{
pixels: PixelsMutPar<'a, P>,
width: u32,
@@ -236,8 +236,8 @@ where
impl<'a, P> ParallelIterator for EnumeratePixelsMutPar<'a, P>
where
- P: Pixel + Send + Sync + 'a,
- P::Subpixel: Send + Sync + 'a,
+ P: ContiguousPixel + Send + Sync + 'a,
+ P::Component: Send + Sync + 'a,
{
type Item = (u32, u32, &'a mut P);
@@ -264,8 +264,8 @@ where
impl<'a, P> IndexedParallelIterator for EnumeratePixelsMutPar<'a, P>
where
- P: Pixel + Send + Sync + 'a,
- P::Subpixel: Send + Sync + 'a,
+ P: ContiguousPixel + Send + Sync + 'a,
+ P::Component: Send + Sync + 'a,
{
fn drive fmt::Debug for EnumeratePixelsMutPar<'_, P>
where
P: Pixel + Send + Sync,
- P::Subpixel: Send + Sync + fmt::Debug,
+ P::Component: Send + Sync + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("EnumeratePixelsMutPar")
@@ -313,9 +313,9 @@ where
impl ImageBuffer
where
- P: Pixel + Sync,
- P::Subpixel: Sync,
- Container: Deref ::CHANNEL_COUNT as usize),
+ .par_chunks_exact( ::COMPONENT_COUNT as usize),
}
}
@@ -343,9 +343,9 @@ where
impl ImageBuffer
where
- P: Pixel + Send + Sync,
- P::Subpixel: Send + Sync,
- Container: Deref ::CHANNEL_COUNT as usize),
+ .par_chunks_exact_mut( ::COMPONENT_COUNT as usize),
}
}
@@ -372,10 +372,10 @@ where
}
}
-impl ImageBuffer >
+impl ImageBuffer >
where
- P: Pixel + Send + Sync,
- P::Subpixel: Send + Sync,
+ P: ContiguousPixel + Send + Sync,
+ P::Component: Send + Sync,
{
/// Constructs a new ImageBuffer by repeated application of the supplied function,
/// utilizing multi-threading via `rayon`.
@@ -385,7 +385,7 @@ where
/// # Panics
///
/// Panics when the resulting image is larger the the maximum size of a vector.
- pub fn from_par_fn >
+ pub fn from_par_fn >
where
F: Fn(u32, u32) -> P + Send + Sync,
{
@@ -400,9 +400,11 @@ where
#[cfg(test)]
mod test {
- use crate::{Rgb, RgbImage};
+ use pixeli::Rgb;
use rayon::iter::{IndexedParallelIterator, ParallelIterator};
+ use crate::RgbImage;
+
fn test_width_height(width: u32, height: u32, len: usize) {
let mut image = RgbImage::new(width, height);
@@ -430,7 +432,7 @@ mod test {
#[test]
fn iter_parity() {
let mut image1 = RgbImage::from_fn(17, 29, |x, y| {
- Rgb(std::array::from_fn(|i| {
+ Rgb::from(std::array::from_fn::<_, 3, _>(|i| {
((x + y * 98 + i as u32 * 27) % 255) as u8
}))
});
@@ -458,7 +460,8 @@ mod test {
#[cfg(test)]
#[cfg(feature = "benchmarks")]
mod benchmarks {
- use crate::{Rgb, RgbImage};
+ use crate::RgbImage;
+ use pixeli::{Pixel, Rgb};
const S: u32 = 1024;
@@ -489,7 +492,7 @@ mod benchmarks {
fn pixel_func() -> Rgb ,
+ image: ImageBuffer ,
) -> Img<&'buf [RGBA8]>
where
- P: Pixel + 'static,
- Rgba ,
+ P: ContiguousPixel + 'static,
+ Rgba ,
{
let (width, height) = image.dimensions();
// TODO: conversion re-using the target buffer?
@@ -245,22 +245,22 @@ impl