diff options
Diffstat (limited to 'vendor/image/src/codecs/hdr/encoder.rs')
-rw-r--r-- | vendor/image/src/codecs/hdr/encoder.rs | 433 |
1 files changed, 0 insertions, 433 deletions
diff --git a/vendor/image/src/codecs/hdr/encoder.rs b/vendor/image/src/codecs/hdr/encoder.rs deleted file mode 100644 index c3a176d..0000000 --- a/vendor/image/src/codecs/hdr/encoder.rs +++ /dev/null @@ -1,433 +0,0 @@ -use crate::codecs::hdr::{rgbe8, Rgbe8Pixel, SIGNATURE}; -use crate::color::Rgb; -use crate::error::ImageResult; -use std::cmp::Ordering; -use std::io::{Result, Write}; - -/// Radiance HDR encoder -pub struct HdrEncoder<W: Write> { - w: W, -} - -impl<W: Write> HdrEncoder<W> { - /// Creates encoder - pub fn new(w: W) -> HdrEncoder<W> { - HdrEncoder { w } - } - - /// Encodes the image ```data``` - /// that has dimensions ```width``` and ```height``` - pub fn encode(mut self, data: &[Rgb<f32>], width: usize, height: usize) -> ImageResult<()> { - assert!(data.len() >= width * height); - let w = &mut self.w; - w.write_all(SIGNATURE)?; - w.write_all(b"\n")?; - w.write_all(b"# Rust HDR encoder\n")?; - w.write_all(b"FORMAT=32-bit_rle_rgbe\n\n")?; - w.write_all(format!("-Y {} +X {}\n", height, width).as_bytes())?; - - if !(8..=32_768).contains(&width) { - for &pix in data { - write_rgbe8(w, to_rgbe8(pix))?; - } - } else { - // new RLE marker contains scanline width - let marker = rgbe8(2, 2, (width / 256) as u8, (width % 256) as u8); - // buffers for encoded pixels - let mut bufr = vec![0; width]; - let mut bufg = vec![0; width]; - let mut bufb = vec![0; width]; - let mut bufe = vec![0; width]; - let mut rle_buf = vec![0; width]; - for scanline in data.chunks(width) { - for ((((r, g), b), e), &pix) in bufr - .iter_mut() - .zip(bufg.iter_mut()) - .zip(bufb.iter_mut()) - .zip(bufe.iter_mut()) - .zip(scanline.iter()) - { - let cp = to_rgbe8(pix); - *r = cp.c[0]; - *g = cp.c[1]; - *b = cp.c[2]; - *e = cp.e; - } - write_rgbe8(w, marker)?; // New RLE encoding marker - rle_buf.clear(); - rle_compress(&bufr[..], &mut rle_buf); - w.write_all(&rle_buf[..])?; - rle_buf.clear(); - rle_compress(&bufg[..], &mut rle_buf); - w.write_all(&rle_buf[..])?; - rle_buf.clear(); - rle_compress(&bufb[..], &mut rle_buf); - w.write_all(&rle_buf[..])?; - rle_buf.clear(); - rle_compress(&bufe[..], &mut rle_buf); - w.write_all(&rle_buf[..])?; - } - } - Ok(()) - } -} - -#[derive(Debug, PartialEq, Eq)] -enum RunOrNot { - Run(u8, usize), - Norun(usize, usize), -} -use self::RunOrNot::{Norun, Run}; - -const RUN_MAX_LEN: usize = 127; -const NORUN_MAX_LEN: usize = 128; - -struct RunIterator<'a> { - data: &'a [u8], - curidx: usize, -} - -impl<'a> RunIterator<'a> { - fn new(data: &'a [u8]) -> RunIterator<'a> { - RunIterator { data, curidx: 0 } - } -} - -impl<'a> Iterator for RunIterator<'a> { - type Item = RunOrNot; - - fn next(&mut self) -> Option<Self::Item> { - if self.curidx == self.data.len() { - None - } else { - let cv = self.data[self.curidx]; - let crun = self.data[self.curidx..] - .iter() - .take_while(|&&v| v == cv) - .take(RUN_MAX_LEN) - .count(); - let ret = if crun > 2 { - Run(cv, crun) - } else { - Norun(self.curidx, crun) - }; - self.curidx += crun; - Some(ret) - } - } -} - -struct NorunCombineIterator<'a> { - runiter: RunIterator<'a>, - prev: Option<RunOrNot>, -} - -impl<'a> NorunCombineIterator<'a> { - fn new(data: &'a [u8]) -> NorunCombineIterator<'a> { - NorunCombineIterator { - runiter: RunIterator::new(data), - prev: None, - } - } -} - -// Combines sequential noruns produced by RunIterator -impl<'a> Iterator for NorunCombineIterator<'a> { - type Item = RunOrNot; - fn next(&mut self) -> Option<Self::Item> { - loop { - match self.prev.take() { - Some(Run(c, len)) => { - // Just return stored run - return Some(Run(c, len)); - } - Some(Norun(idx, len)) => { - // Let's see if we need to continue norun - match self.runiter.next() { - Some(Norun(_, len1)) => { - // norun continues - let clen = len + len1; // combined length - match clen.cmp(&NORUN_MAX_LEN) { - Ordering::Equal => return Some(Norun(idx, clen)), - Ordering::Greater => { - // combined norun exceeds maximum length. store extra part of norun - self.prev = - Some(Norun(idx + NORUN_MAX_LEN, clen - NORUN_MAX_LEN)); - // then return maximal norun - return Some(Norun(idx, NORUN_MAX_LEN)); - } - Ordering::Less => { - // len + len1 < NORUN_MAX_LEN - self.prev = Some(Norun(idx, len + len1)); - // combine and continue loop - } - } - } - Some(Run(c, len1)) => { - // Run encountered. Store it - self.prev = Some(Run(c, len1)); - return Some(Norun(idx, len)); // and return combined norun - } - None => { - // End of sequence - return Some(Norun(idx, len)); // return combined norun - } - } - } // End match self.prev.take() == Some(NoRun()) - None => { - // No norun to combine - match self.runiter.next() { - Some(Norun(idx, len)) => { - self.prev = Some(Norun(idx, len)); - // store for combine and continue the loop - } - Some(Run(c, len)) => { - // Some run. Just return it - return Some(Run(c, len)); - } - None => { - // That's all, folks - return None; - } - } - } // End match self.prev.take() == None - } // End match - } // End loop - } -} - -// Appends RLE compressed ```data``` to ```rle``` -fn rle_compress(data: &[u8], rle: &mut Vec<u8>) { - rle.clear(); - if data.is_empty() { - rle.push(0); // Technically correct. It means read next 0 bytes. - return; - } - // Task: split data into chunks of repeating (max 127) and non-repeating bytes (max 128) - // Prepend non-repeating chunk with its length - // Replace repeating byte with (run length + 128) and the byte - for rnr in NorunCombineIterator::new(data) { - match rnr { - Run(c, len) => { - assert!(len <= 127); - rle.push(128u8 + len as u8); - rle.push(c); - } - Norun(idx, len) => { - assert!(len <= 128); - rle.push(len as u8); - rle.extend_from_slice(&data[idx..idx + len]); - } - } - } -} - -fn write_rgbe8<W: Write>(w: &mut W, v: Rgbe8Pixel) -> Result<()> { - w.write_all(&[v.c[0], v.c[1], v.c[2], v.e]) -} - -/// Converts ```Rgb<f32>``` into ```Rgbe8Pixel``` -pub fn to_rgbe8(pix: Rgb<f32>) -> Rgbe8Pixel { - let pix = pix.0; - let mx = f32::max(pix[0], f32::max(pix[1], pix[2])); - if mx <= 0.0 { - Rgbe8Pixel { c: [0, 0, 0], e: 0 } - } else { - // let (frac, exp) = mx.frexp(); // unstable yet - let exp = mx.log2().floor() as i32 + 1; - let mul = f32::powi(2.0, exp); - let mut conv = [0u8; 3]; - for (cv, &sv) in conv.iter_mut().zip(pix.iter()) { - *cv = f32::trunc(sv / mul * 256.0) as u8; - } - Rgbe8Pixel { - c: conv, - e: (exp + 128) as u8, - } - } -} - -#[test] -fn to_rgbe8_test() { - use crate::codecs::hdr::rgbe8; - let test_cases = vec![rgbe8(0, 0, 0, 0), rgbe8(1, 1, 128, 128)]; - for &pix in &test_cases { - assert_eq!(pix, to_rgbe8(pix.to_hdr())); - } - for mc in 128..255 { - // TODO: use inclusive range when stable - let pix = rgbe8(mc, mc, mc, 100); - assert_eq!(pix, to_rgbe8(pix.to_hdr())); - let pix = rgbe8(mc, 0, mc, 130); - assert_eq!(pix, to_rgbe8(pix.to_hdr())); - let pix = rgbe8(0, 0, mc, 140); - assert_eq!(pix, to_rgbe8(pix.to_hdr())); - let pix = rgbe8(1, 0, mc, 150); - assert_eq!(pix, to_rgbe8(pix.to_hdr())); - let pix = rgbe8(1, mc, 10, 128); - assert_eq!(pix, to_rgbe8(pix.to_hdr())); - for c in 0..255 { - // Radiance HDR seems to be pre IEEE 754. - // exponent can be -128 (represented as 0u8), so some colors cannot be represented in normalized f32 - // Let's exclude exponent value of -128 (0u8) from testing - let pix = rgbe8(1, mc, c, if c == 0 { 1 } else { c }); - assert_eq!(pix, to_rgbe8(pix.to_hdr())); - } - } - fn relative_dist(a: Rgb<f32>, b: Rgb<f32>) -> f32 { - // maximal difference divided by maximal value - let max_diff = - a.0.iter() - .zip(b.0.iter()) - .fold(0.0, |diff, (&a, &b)| f32::max(diff, (a - b).abs())); - let max_val = - a.0.iter() - .chain(b.0.iter()) - .fold(0.0, |maxv, &a| f32::max(maxv, a)); - if max_val == 0.0 { - 0.0 - } else { - max_diff / max_val - } - } - let test_values = vec![ - 0.000_001, 0.000_02, 0.000_3, 0.004, 0.05, 0.6, 7.0, 80.0, 900.0, 1_000.0, 20_000.0, - 300_000.0, - ]; - for &r in &test_values { - for &g in &test_values { - for &b in &test_values { - let c1 = Rgb([r, g, b]); - let c2 = to_rgbe8(c1).to_hdr(); - let rel_dist = relative_dist(c1, c2); - // Maximal value is normalized to the range 128..256, thus we have 1/128 precision - assert!( - rel_dist <= 1.0 / 128.0, - "Relative distance ({}) exceeds 1/128 for {:?} and {:?}", - rel_dist, - c1, - c2 - ); - } - } - } -} - -#[test] -fn runiterator_test() { - let data = []; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), None); - let data = [5]; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), Some(Norun(0, 1))); - assert_eq!(run_iter.next(), None); - let data = [1, 1]; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), Some(Norun(0, 2))); - assert_eq!(run_iter.next(), None); - let data = [0, 0, 0]; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), Some(Run(0u8, 3))); - assert_eq!(run_iter.next(), None); - let data = [0, 0, 1, 1]; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), Some(Norun(0, 2))); - assert_eq!(run_iter.next(), Some(Norun(2, 2))); - assert_eq!(run_iter.next(), None); - let data = [0, 0, 0, 1, 1]; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), Some(Run(0u8, 3))); - assert_eq!(run_iter.next(), Some(Norun(3, 2))); - assert_eq!(run_iter.next(), None); - let data = [1, 2, 2, 2]; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), Some(Norun(0, 1))); - assert_eq!(run_iter.next(), Some(Run(2u8, 3))); - assert_eq!(run_iter.next(), None); - let data = [1, 1, 2, 2, 2]; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), Some(Norun(0, 2))); - assert_eq!(run_iter.next(), Some(Run(2u8, 3))); - assert_eq!(run_iter.next(), None); - let data = [2; 128]; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), Some(Run(2u8, 127))); - assert_eq!(run_iter.next(), Some(Norun(127, 1))); - assert_eq!(run_iter.next(), None); - let data = [2; 129]; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), Some(Run(2u8, 127))); - assert_eq!(run_iter.next(), Some(Norun(127, 2))); - assert_eq!(run_iter.next(), None); - let data = [2; 130]; - let mut run_iter = RunIterator::new(&data[..]); - assert_eq!(run_iter.next(), Some(Run(2u8, 127))); - assert_eq!(run_iter.next(), Some(Run(2u8, 3))); - assert_eq!(run_iter.next(), None); -} - -#[test] -fn noruncombine_test() { - fn a<T>(mut v: Vec<T>, mut other: Vec<T>) -> Vec<T> { - v.append(&mut other); - v - } - - let v = vec![]; - let mut rsi = NorunCombineIterator::new(&v[..]); - assert_eq!(rsi.next(), None); - - let v = vec![1]; - let mut rsi = NorunCombineIterator::new(&v[..]); - assert_eq!(rsi.next(), Some(Norun(0, 1))); - assert_eq!(rsi.next(), None); - - let v = vec![2, 2]; - let mut rsi = NorunCombineIterator::new(&v[..]); - assert_eq!(rsi.next(), Some(Norun(0, 2))); - assert_eq!(rsi.next(), None); - - let v = vec![3, 3, 3]; - let mut rsi = NorunCombineIterator::new(&v[..]); - assert_eq!(rsi.next(), Some(Run(3, 3))); - assert_eq!(rsi.next(), None); - - let v = vec![4, 4, 3, 3, 3]; - let mut rsi = NorunCombineIterator::new(&v[..]); - assert_eq!(rsi.next(), Some(Norun(0, 2))); - assert_eq!(rsi.next(), Some(Run(3, 3))); - assert_eq!(rsi.next(), None); - - let v = vec![40; 400]; - let mut rsi = NorunCombineIterator::new(&v[..]); - assert_eq!(rsi.next(), Some(Run(40, 127))); - assert_eq!(rsi.next(), Some(Run(40, 127))); - assert_eq!(rsi.next(), Some(Run(40, 127))); - assert_eq!(rsi.next(), Some(Run(40, 19))); - assert_eq!(rsi.next(), None); - - let v = a(a(vec![5; 3], vec![6; 129]), vec![7, 3, 7, 10, 255]); - let mut rsi = NorunCombineIterator::new(&v[..]); - assert_eq!(rsi.next(), Some(Run(5, 3))); - assert_eq!(rsi.next(), Some(Run(6, 127))); - assert_eq!(rsi.next(), Some(Norun(130, 7))); - assert_eq!(rsi.next(), None); - - let v = a(a(vec![5; 2], vec![6; 129]), vec![7, 3, 7, 7, 255]); - let mut rsi = NorunCombineIterator::new(&v[..]); - assert_eq!(rsi.next(), Some(Norun(0, 2))); - assert_eq!(rsi.next(), Some(Run(6, 127))); - assert_eq!(rsi.next(), Some(Norun(129, 7))); - assert_eq!(rsi.next(), None); - - let v: Vec<_> = ::std::iter::repeat(()) - .flat_map(|_| (0..2)) - .take(257) - .collect(); - let mut rsi = NorunCombineIterator::new(&v[..]); - assert_eq!(rsi.next(), Some(Norun(0, 128))); - assert_eq!(rsi.next(), Some(Norun(128, 128))); - assert_eq!(rsi.next(), Some(Norun(256, 1))); - assert_eq!(rsi.next(), None); -} |