diff --git a/README.md b/README.md index fefb793..dbb2aba 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Below you can find a quick example usage of this crate. It introduces the basics ```rust use ffimage::color::{Gray, Rgb}; -use ffimage::iter::{ColorConvertExt, PixelsExt, WriteExt}; +use ffimage::iter::{BytesExt, ColorConvertExt, PixelsExt}; fn main() { // This is our RGB image memory (2x2 pixels). @@ -42,6 +42,7 @@ fn main() { .copied() .pixels::>() .colorconvert::>() + .bytes() .write(&mut gray); } ``` diff --git a/ffimage-yuv/benches/convert.rs b/ffimage-yuv/benches/convert.rs index c3426b9..47f9bd0 100644 --- a/ffimage-yuv/benches/convert.rs +++ b/ffimage-yuv/benches/convert.rs @@ -2,7 +2,7 @@ use criterion::{black_box, criterion_group, Criterion}; use ffimage::{ color::Rgb, - iter::{ColorConvertExt, PixelsExt, WriteExt}, + iter::{BytesExt, ColorConvertExt, PixelsExt}, }; use ffimage_yuv::{yuv::Yuv, yuv420::Yuv420p, yuv422::Yuv422}; @@ -19,6 +19,7 @@ pub fn yuv_to_rgb(c: &mut Criterion) { .copied() .pixels::>() .colorconvert::>() + .bytes() .write(black_box(&mut rgb)) }) }); @@ -43,6 +44,7 @@ pub fn yuv422_to_rgb(c: &mut Criterion) { .colorconvert::<[Yuv; 2]>() .flatten() .colorconvert::>() + .bytes() .write(black_box(&mut rgb)); }) }, @@ -64,6 +66,7 @@ pub fn yuv420p_to_rgb(c: &mut Criterion) { Yuv420p::pack(&yuv420p) .into_iter() .colorconvert::>() + .bytes() .write(black_box(&mut rgb)); }) }, diff --git a/ffimage/benches/convert.rs b/ffimage/benches/convert.rs index 709ded3..871bee7 100644 --- a/ffimage/benches/convert.rs +++ b/ffimage/benches/convert.rs @@ -2,7 +2,7 @@ use criterion::{black_box, criterion_group, Criterion}; use ffimage::{ color::{Bgr, Gray, Rgb}, - iter::{ColorConvertExt, PixelsExt, WriteExt}, + iter::{BytesExt, ColorConvertExt, PixelsExt}, }; pub fn rgb_to_bgr(c: &mut Criterion) { @@ -18,6 +18,7 @@ pub fn rgb_to_bgr(c: &mut Criterion) { .copied() .pixels::>() .colorconvert::>() + .bytes() .write(black_box(&mut bgr)) }) }); @@ -37,6 +38,7 @@ pub fn rgb_to_gray(c: &mut Criterion) { .copied() .pixels::>() .colorconvert::>() + .bytes() .write(black_box(&mut gray)) }) }); diff --git a/ffimage/src/iter.rs b/ffimage/src/iter.rs index fbc92bd..0240e25 100644 --- a/ffimage/src/iter.rs +++ b/ffimage/src/iter.rs @@ -93,25 +93,63 @@ where /// The trait is automatically implemented for all pixel types which implement the /// `Deref` trait where T: Copy and C means the number of channels /// (e.g. 3 for RGB). -pub trait WriteExt<'a, T, O, const C: usize>: Iterator { - fn write(self, out: O) +pub trait BytesExt: Iterator { + fn bytes(self) -> Bytes where Self: Sized, - Self::Item: Deref, - T: 'a + Copy, + { + Bytes::new(self) + } +} + +impl BytesExt for I where I: Iterator {} + +pub struct Bytes { + _marker: PhantomData, + iter: I, +} + +impl Bytes { + pub fn new(iter: I) -> Self { + Bytes { + _marker: PhantomData, + iter, + } + } +} + +impl Iterator for Bytes +where + T: Copy, + I: Iterator, + I::Item: Deref, +{ + type Item = [T; C]; + + fn next(&mut self) -> Option { + Some(*self.iter.next()?) + } +} + +impl<'a, T, I, const C: usize> Bytes +where + T: 'a + Copy, + I: Iterator, + I::Item: Deref, +{ + pub fn write(self, out: O) + where O: IntoIterator, { let mut out = out.into_iter(); self.for_each(|chunk| { - for i in 0..C { - *(out.next().unwrap()) = chunk[i]; - } + chunk.iter().for_each(|channel| { + *(out.next().expect("output iterator ended prematurely")) = *channel + }) }); } } -impl<'a, T, I, O, const C: usize> WriteExt<'a, T, O, C> for I where I: Iterator {} - #[cfg(test)] mod tests { use super::*; @@ -129,13 +167,14 @@ mod tests { } #[test] - fn write() { + fn bytes() { let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9]; let mut out = [0; 9]; buf.iter() .copied() .pixels::>() .colorconvert::>() + .bytes() .write(&mut out); assert_eq!(out, [3, 2, 1, 6, 5, 4, 9, 8, 7]); }