1 | use crate::codecs::hdr::{rgbe8, Rgbe8Pixel, SIGNATURE}; |
2 | use crate::color::Rgb; |
3 | use crate::error::ImageResult; |
4 | use std::cmp::Ordering; |
5 | use std::io::{Result, Write}; |
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 |
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)] |
76 | enum RunOrNot { |
77 | Run(u8, usize), |
78 | Norun(usize, usize), |
79 | } |
80 | use self::RunOrNot::{Norun, Run}; |
81 | |
82 | const RUN_MAX_LEN: usize = 127; |
83 | const NORUN_MAX_LEN: usize = 128; |
84 | |
85 | struct RunIterator<'a> { |
86 | data: &'a [u8], |
87 | curidx: usize, |
88 | } |
89 | |
90 | impl<'a> RunIterator<'a> { |
91 | fn new(data: &'a [u8]) -> RunIterator<'a> { |
92 | RunIterator { data, curidx: 0 } |
93 | } |
94 | } |
95 | |
96 | impl<'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 | |
120 | struct NorunCombineIterator<'a> { |
121 | runiter: RunIterator<'a>, |
122 | prev: Option<RunOrNot>, |
123 | } |
124 | |
125 | impl<'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 |
135 | impl<'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``` |
200 | fn 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 | |
225 | fn 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``` |
230 | pub 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 ] |
251 | fn 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 ] |
317 | fn 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 ] |
371 | fn 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 | |