From 7833742a03ab5c1cc064bbe1e8011bbef2e291bd Mon Sep 17 00:00:00 2001 From: Beinsezii Date: Mon, 3 Jun 2024 01:53:19 -0700 Subject: [PATCH] Add channel `weave` and `unweave` functions --- src/lib.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 2d45e91..29cbf38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,39 @@ fn spowf(n: f32, power: f32) -> f32 { n.abs().powf(power).copysign(n) } +/// Create an array of separate channel buffers from a single interwoven buffer. +/// Copies the data. +pub fn unweave(slice: &[f32]) -> [Box<[f32]>; N] { + let len = slice.len() / N; + let mut result: [Vec; N] = (0..N) + .map(|_| Vec::with_capacity(len)) + .collect::>>() + .try_into() + .unwrap(); + + slice.chunks_exact(N).for_each(|chunk| { + chunk + .iter() + .zip(result.iter_mut()) + .for_each(|(v, arr)| arr.push(*v)); + }); + + result.map(|v| v.into_boxed_slice()) +} + +/// Create a monolithic woven buffer using unwoven independent channel buffers. +/// Copies the data. +pub fn weave(array: [Box<[f32]>; N]) -> Box<[f32]> { + let len = array[0].len(); + (0..len) + .into_iter() + .fold(Vec::with_capacity(len * N), |mut acc, it| { + (0..N).into_iter().for_each(|n| acc.push(array[n][it])); + acc + }) + .into_boxed_slice() +} + // ### CONSTS ### {{{ /// Standard Illuminant D65. @@ -1592,6 +1625,31 @@ mod tests { assert_eq!(pixels, smol); } + #[test] + fn interweave() { + let slice: Vec = SRGB.iter().fold(Vec::new(), |mut acc, it| { + acc.extend_from_slice(it); + acc + }); + let mut new = slice.clone(); + new.push(1234.5678); + + let deinterleaved = unweave::<3>(&new); + assert_eq!(deinterleaved[0].len(), deinterleaved[1].len()); + assert_eq!(deinterleaved[0].len(), deinterleaved[2].len()); + let chunked: Vec<[f32; 3]> = (0..deinterleaved[0].len()).fold(Vec::new(), |mut acc, it| { + acc.push([ + deinterleaved[0][it], + deinterleaved[1][it], + deinterleaved[2][it], + ]); + acc + }); + + assert_eq!(SRGB, &chunked); + assert_eq!(slice.as_slice(), weave(deinterleaved).as_ref()) + } + #[test] fn nan_checks() { let it = [1e+3, -1e+3, 1e-3, -1e-3];