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: u8 = self.data[self.curidx];
104 let crun: usize = self.data[self.curidx..]
105 .iter()
106 .take_while(|&&v: u8| v == cv)
107 .take(RUN_MAX_LEN)
108 .count();
109 let ret: RunOrNot = 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: RunOrNot in NorunCombineIterator::new(data) {
210 match rnr {
211 Run(c: u8, len: usize) => {
212 assert!(len <= 127);
213 rle.push(128u8 + len as u8);
214 rle.push(c);
215 }
216 Norun(idx: usize, len: usize) => {
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: [f32; 3] = pix.0;
232 let mx: f32 = f32::max(self:pix[0], other:f32::max(self:pix[1], other: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: i32 = mx.log2().floor() as i32 + 1;
238 let mul: f32 = f32::powi(self:2.0, n:exp);
239 let mut conv: [u8; 3] = [0u8; 3];
240 for (cv: &mut u8, &sv: f32) in conv.iter_mut().zip(pix.iter()) {
241 *cv = f32::trunc(self: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}
434