image/codecs/hdr/
encoder.rs

1use crate::codecs::hdr::{rgbe8, Rgbe8Pixel, SIGNATURE};
2use crate::color::Rgb;
3use crate::error::ImageResult;
4use std::cmp::Ordering;
5use std::io::{Result, Write};
6
7/// Radiance HDR encoder
8pub struct HdrEncoder<W: Write> {
9    w: W,
10}
11
12impl<W: Write> HdrEncoder<W> {
13    /// Creates encoder
14    pub fn new(w: W) -> HdrEncoder<W> {
15        HdrEncoder { w }
16    }
17
18    /// Encodes the image ```data```
19    /// that has dimensions ```width``` and ```height```
20    pub fn encode(mut self, data: &[Rgb<f32>], width: usize, height: usize) -> ImageResult<()> {
21        assert!(data.len() >= width * height);
22        let w = &mut self.w;
23        w.write_all(SIGNATURE)?;
24        w.write_all(b"\n")?;
25        w.write_all(b"# Rust HDR encoder\n")?;
26        w.write_all(b"FORMAT=32-bit_rle_rgbe\n\n")?;
27        w.write_all(format!("-Y {} +X {}\n", height, width).as_bytes())?;
28
29        if !(8..=32_768).contains(&width) {
30            for &pix in data {
31                write_rgbe8(w, to_rgbe8(pix))?;
32            }
33        } else {
34            // new RLE marker contains scanline width
35            let marker = rgbe8(2, 2, (width / 256) as u8, (width % 256) as u8);
36            // buffers for encoded pixels
37            let mut bufr = vec![0; width];
38            let mut bufg = vec![0; width];
39            let mut bufb = vec![0; width];
40            let mut bufe = vec![0; width];
41            let mut rle_buf = vec![0; width];
42            for scanline in data.chunks(width) {
43                for ((((r, g), b), e), &pix) in bufr
44                    .iter_mut()
45                    .zip(bufg.iter_mut())
46                    .zip(bufb.iter_mut())
47                    .zip(bufe.iter_mut())
48                    .zip(scanline.iter())
49                {
50                    let cp = to_rgbe8(pix);
51                    *r = cp.c[0];
52                    *g = cp.c[1];
53                    *b = cp.c[2];
54                    *e = cp.e;
55                }
56                write_rgbe8(w, marker)?; // New RLE encoding marker
57                rle_buf.clear();
58                rle_compress(&bufr[..], &mut rle_buf);
59                w.write_all(&rle_buf[..])?;
60                rle_buf.clear();
61                rle_compress(&bufg[..], &mut rle_buf);
62                w.write_all(&rle_buf[..])?;
63                rle_buf.clear();
64                rle_compress(&bufb[..], &mut rle_buf);
65                w.write_all(&rle_buf[..])?;
66                rle_buf.clear();
67                rle_compress(&bufe[..], &mut rle_buf);
68                w.write_all(&rle_buf[..])?;
69            }
70        }
71        Ok(())
72    }
73}
74
75#[derive(Debug, PartialEq, Eq)]
76enum RunOrNot {
77    Run(u8, usize),
78    Norun(usize, usize),
79}
80use self::RunOrNot::{Norun, Run};
81
82const RUN_MAX_LEN: usize = 127;
83const NORUN_MAX_LEN: usize = 128;
84
85struct RunIterator<'a> {
86    data: &'a [u8],
87    curidx: usize,
88}
89
90impl<'a> RunIterator<'a> {
91    fn new(data: &'a [u8]) -> RunIterator<'a> {
92        RunIterator { data, curidx: 0 }
93    }
94}
95
96impl<'a> Iterator for RunIterator<'a> {
97    type Item = RunOrNot;
98
99    fn next(&mut self) -> Option<Self::Item> {
100        if self.curidx == self.data.len() {
101            None
102        } else {
103            let cv = self.data[self.curidx];
104            let crun = self.data[self.curidx..]
105                .iter()
106                .take_while(|&&v| v == cv)
107                .take(RUN_MAX_LEN)
108                .count();
109            let ret = if crun > 2 {
110                Run(cv, crun)
111            } else {
112                Norun(self.curidx, crun)
113            };
114            self.curidx += crun;
115            Some(ret)
116        }
117    }
118}
119
120struct NorunCombineIterator<'a> {
121    runiter: RunIterator<'a>,
122    prev: Option<RunOrNot>,
123}
124
125impl<'a> NorunCombineIterator<'a> {
126    fn new(data: &'a [u8]) -> NorunCombineIterator<'a> {
127        NorunCombineIterator {
128            runiter: RunIterator::new(data),
129            prev: None,
130        }
131    }
132}
133
134// Combines sequential noruns produced by RunIterator
135impl<'a> Iterator for NorunCombineIterator<'a> {
136    type Item = RunOrNot;
137    fn next(&mut self) -> Option<Self::Item> {
138        loop {
139            match self.prev.take() {
140                Some(Run(c, len)) => {
141                    // Just return stored run
142                    return Some(Run(c, len));
143                }
144                Some(Norun(idx, len)) => {
145                    // Let's see if we need to continue norun
146                    match self.runiter.next() {
147                        Some(Norun(_, len1)) => {
148                            // norun continues
149                            let clen = len + len1; // combined length
150                            match clen.cmp(&NORUN_MAX_LEN) {
151                                Ordering::Equal => return Some(Norun(idx, clen)),
152                                Ordering::Greater => {
153                                    // combined norun exceeds maximum length. store extra part of norun
154                                    self.prev =
155                                        Some(Norun(idx + NORUN_MAX_LEN, clen - NORUN_MAX_LEN));
156                                    // then return maximal norun
157                                    return Some(Norun(idx, NORUN_MAX_LEN));
158                                }
159                                Ordering::Less => {
160                                    // len + len1 < NORUN_MAX_LEN
161                                    self.prev = Some(Norun(idx, len + len1));
162                                    // combine and continue loop
163                                }
164                            }
165                        }
166                        Some(Run(c, len1)) => {
167                            // Run encountered. Store it
168                            self.prev = Some(Run(c, len1));
169                            return Some(Norun(idx, len)); // and return combined norun
170                        }
171                        None => {
172                            // End of sequence
173                            return Some(Norun(idx, len)); // return combined norun
174                        }
175                    }
176                } // End match self.prev.take() == Some(NoRun())
177                None => {
178                    // No norun to combine
179                    match self.runiter.next() {
180                        Some(Norun(idx, len)) => {
181                            self.prev = Some(Norun(idx, len));
182                            // store for combine and continue the loop
183                        }
184                        Some(Run(c, len)) => {
185                            // Some run. Just return it
186                            return Some(Run(c, len));
187                        }
188                        None => {
189                            // That's all, folks
190                            return None;
191                        }
192                    }
193                } // End match self.prev.take() == None
194            } // End match
195        } // End loop
196    }
197}
198
199// Appends RLE compressed ```data``` to ```rle```
200fn rle_compress(data: &[u8], rle: &mut Vec<u8>) {
201    rle.clear();
202    if data.is_empty() {
203        rle.push(0); // Technically correct. It means read next 0 bytes.
204        return;
205    }
206    // Task: split data into chunks of repeating (max 127) and non-repeating bytes (max 128)
207    // Prepend non-repeating chunk with its length
208    // Replace repeating byte with (run length + 128) and the byte
209    for rnr in NorunCombineIterator::new(data) {
210        match rnr {
211            Run(c, len) => {
212                assert!(len <= 127);
213                rle.push(128u8 + len as u8);
214                rle.push(c);
215            }
216            Norun(idx, len) => {
217                assert!(len <= 128);
218                rle.push(len as u8);
219                rle.extend_from_slice(&data[idx..idx + len]);
220            }
221        }
222    }
223}
224
225fn write_rgbe8<W: Write>(w: &mut W, v: Rgbe8Pixel) -> Result<()> {
226    w.write_all(&[v.c[0], v.c[1], v.c[2], v.e])
227}
228
229/// Converts ```Rgb<f32>``` into ```Rgbe8Pixel```
230pub fn to_rgbe8(pix: Rgb<f32>) -> Rgbe8Pixel {
231    let pix = pix.0;
232    let mx = f32::max(pix[0], f32::max(pix[1], pix[2]));
233    if mx <= 0.0 {
234        Rgbe8Pixel { c: [0, 0, 0], e: 0 }
235    } else {
236        // let (frac, exp) = mx.frexp(); // unstable yet
237        let exp = mx.log2().floor() as i32 + 1;
238        let mul = f32::powi(2.0, exp);
239        let mut conv = [0u8; 3];
240        for (cv, &sv) in conv.iter_mut().zip(pix.iter()) {
241            *cv = f32::trunc(sv / mul * 256.0) as u8;
242        }
243        Rgbe8Pixel {
244            c: conv,
245            e: (exp + 128) as u8,
246        }
247    }
248}
249
250#[test]
251fn to_rgbe8_test() {
252    use crate::codecs::hdr::rgbe8;
253    let test_cases = vec![rgbe8(0, 0, 0, 0), rgbe8(1, 1, 128, 128)];
254    for &pix in &test_cases {
255        assert_eq!(pix, to_rgbe8(pix.to_hdr()));
256    }
257    for mc in 128..255 {
258        // TODO: use inclusive range when stable
259        let pix = rgbe8(mc, mc, mc, 100);
260        assert_eq!(pix, to_rgbe8(pix.to_hdr()));
261        let pix = rgbe8(mc, 0, mc, 130);
262        assert_eq!(pix, to_rgbe8(pix.to_hdr()));
263        let pix = rgbe8(0, 0, mc, 140);
264        assert_eq!(pix, to_rgbe8(pix.to_hdr()));
265        let pix = rgbe8(1, 0, mc, 150);
266        assert_eq!(pix, to_rgbe8(pix.to_hdr()));
267        let pix = rgbe8(1, mc, 10, 128);
268        assert_eq!(pix, to_rgbe8(pix.to_hdr()));
269        for c in 0..255 {
270            // Radiance HDR seems to be pre IEEE 754.
271            // exponent can be -128 (represented as 0u8), so some colors cannot be represented in normalized f32
272            // Let's exclude exponent value of -128 (0u8) from testing
273            let pix = rgbe8(1, mc, c, if c == 0 { 1 } else { c });
274            assert_eq!(pix, to_rgbe8(pix.to_hdr()));
275        }
276    }
277    fn relative_dist(a: Rgb<f32>, b: Rgb<f32>) -> f32 {
278        // maximal difference divided by maximal value
279        let max_diff =
280            a.0.iter()
281                .zip(b.0.iter())
282                .fold(0.0, |diff, (&a, &b)| f32::max(diff, (a - b).abs()));
283        let max_val =
284            a.0.iter()
285                .chain(b.0.iter())
286                .fold(0.0, |maxv, &a| f32::max(maxv, a));
287        if max_val == 0.0 {
288            0.0
289        } else {
290            max_diff / max_val
291        }
292    }
293    let test_values = vec![
294        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,
295        300_000.0,
296    ];
297    for &r in &test_values {
298        for &g in &test_values {
299            for &b in &test_values {
300                let c1 = Rgb([r, g, b]);
301                let c2 = to_rgbe8(c1).to_hdr();
302                let rel_dist = relative_dist(c1, c2);
303                // Maximal value is normalized to the range 128..256, thus we have 1/128 precision
304                assert!(
305                    rel_dist <= 1.0 / 128.0,
306                    "Relative distance ({}) exceeds 1/128 for {:?} and {:?}",
307                    rel_dist,
308                    c1,
309                    c2
310                );
311            }
312        }
313    }
314}
315
316#[test]
317fn runiterator_test() {
318    let data = [];
319    let mut run_iter = RunIterator::new(&data[..]);
320    assert_eq!(run_iter.next(), None);
321    let data = [5];
322    let mut run_iter = RunIterator::new(&data[..]);
323    assert_eq!(run_iter.next(), Some(Norun(0, 1)));
324    assert_eq!(run_iter.next(), None);
325    let data = [1, 1];
326    let mut run_iter = RunIterator::new(&data[..]);
327    assert_eq!(run_iter.next(), Some(Norun(0, 2)));
328    assert_eq!(run_iter.next(), None);
329    let data = [0, 0, 0];
330    let mut run_iter = RunIterator::new(&data[..]);
331    assert_eq!(run_iter.next(), Some(Run(0u8, 3)));
332    assert_eq!(run_iter.next(), None);
333    let data = [0, 0, 1, 1];
334    let mut run_iter = RunIterator::new(&data[..]);
335    assert_eq!(run_iter.next(), Some(Norun(0, 2)));
336    assert_eq!(run_iter.next(), Some(Norun(2, 2)));
337    assert_eq!(run_iter.next(), None);
338    let data = [0, 0, 0, 1, 1];
339    let mut run_iter = RunIterator::new(&data[..]);
340    assert_eq!(run_iter.next(), Some(Run(0u8, 3)));
341    assert_eq!(run_iter.next(), Some(Norun(3, 2)));
342    assert_eq!(run_iter.next(), None);
343    let data = [1, 2, 2, 2];
344    let mut run_iter = RunIterator::new(&data[..]);
345    assert_eq!(run_iter.next(), Some(Norun(0, 1)));
346    assert_eq!(run_iter.next(), Some(Run(2u8, 3)));
347    assert_eq!(run_iter.next(), None);
348    let data = [1, 1, 2, 2, 2];
349    let mut run_iter = RunIterator::new(&data[..]);
350    assert_eq!(run_iter.next(), Some(Norun(0, 2)));
351    assert_eq!(run_iter.next(), Some(Run(2u8, 3)));
352    assert_eq!(run_iter.next(), None);
353    let data = [2; 128];
354    let mut run_iter = RunIterator::new(&data[..]);
355    assert_eq!(run_iter.next(), Some(Run(2u8, 127)));
356    assert_eq!(run_iter.next(), Some(Norun(127, 1)));
357    assert_eq!(run_iter.next(), None);
358    let data = [2; 129];
359    let mut run_iter = RunIterator::new(&data[..]);
360    assert_eq!(run_iter.next(), Some(Run(2u8, 127)));
361    assert_eq!(run_iter.next(), Some(Norun(127, 2)));
362    assert_eq!(run_iter.next(), None);
363    let data = [2; 130];
364    let mut run_iter = RunIterator::new(&data[..]);
365    assert_eq!(run_iter.next(), Some(Run(2u8, 127)));
366    assert_eq!(run_iter.next(), Some(Run(2u8, 3)));
367    assert_eq!(run_iter.next(), None);
368}
369
370#[test]
371fn noruncombine_test() {
372    fn a<T>(mut v: Vec<T>, mut other: Vec<T>) -> Vec<T> {
373        v.append(&mut other);
374        v
375    }
376
377    let v = [];
378    let mut rsi = NorunCombineIterator::new(&v[..]);
379    assert_eq!(rsi.next(), None);
380
381    let v = [1];
382    let mut rsi = NorunCombineIterator::new(&v[..]);
383    assert_eq!(rsi.next(), Some(Norun(0, 1)));
384    assert_eq!(rsi.next(), None);
385
386    let v = [2, 2];
387    let mut rsi = NorunCombineIterator::new(&v[..]);
388    assert_eq!(rsi.next(), Some(Norun(0, 2)));
389    assert_eq!(rsi.next(), None);
390
391    let v = [3, 3, 3];
392    let mut rsi = NorunCombineIterator::new(&v[..]);
393    assert_eq!(rsi.next(), Some(Run(3, 3)));
394    assert_eq!(rsi.next(), None);
395
396    let v = [4, 4, 3, 3, 3];
397    let mut rsi = NorunCombineIterator::new(&v[..]);
398    assert_eq!(rsi.next(), Some(Norun(0, 2)));
399    assert_eq!(rsi.next(), Some(Run(3, 3)));
400    assert_eq!(rsi.next(), None);
401
402    let v = vec![40; 400];
403    let mut rsi = NorunCombineIterator::new(&v[..]);
404    assert_eq!(rsi.next(), Some(Run(40, 127)));
405    assert_eq!(rsi.next(), Some(Run(40, 127)));
406    assert_eq!(rsi.next(), Some(Run(40, 127)));
407    assert_eq!(rsi.next(), Some(Run(40, 19)));
408    assert_eq!(rsi.next(), None);
409
410    let v = a(a(vec![5; 3], vec![6; 129]), vec![7, 3, 7, 10, 255]);
411    let mut rsi = NorunCombineIterator::new(&v[..]);
412    assert_eq!(rsi.next(), Some(Run(5, 3)));
413    assert_eq!(rsi.next(), Some(Run(6, 127)));
414    assert_eq!(rsi.next(), Some(Norun(130, 7)));
415    assert_eq!(rsi.next(), None);
416
417    let v = a(a(vec![5; 2], vec![6; 129]), vec![7, 3, 7, 7, 255]);
418    let mut rsi = NorunCombineIterator::new(&v[..]);
419    assert_eq!(rsi.next(), Some(Norun(0, 2)));
420    assert_eq!(rsi.next(), Some(Run(6, 127)));
421    assert_eq!(rsi.next(), Some(Norun(129, 7)));
422    assert_eq!(rsi.next(), None);
423
424    let v: Vec<_> = ::std::iter::repeat(())
425        .flat_map(|_| (0..2))
426        .take(257)
427        .collect();
428    let mut rsi = NorunCombineIterator::new(&v[..]);
429    assert_eq!(rsi.next(), Some(Norun(0, 128)));
430    assert_eq!(rsi.next(), Some(Norun(128, 128)));
431    assert_eq!(rsi.next(), Some(Norun(256, 1)));
432    assert_eq!(rsi.next(), None);
433}