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