1use std::cmp::Ordering;
2use std::io::{Result, Write};
3
4use crate::codecs::hdr::{rgbe8, Rgbe8Pixel, SIGNATURE};
5use crate::color::Rgb;
6use crate::error::{ImageResult, UnsupportedError, UnsupportedErrorKind};
7use crate::{ExtendedColorType, ImageEncoder, ImageError, ImageFormat};
8
9pub struct HdrEncoder<W: Write> {
11 w: W,
12}
13
14impl<W: Write> ImageEncoder for HdrEncoder<W> {
15 fn write_image(
16 self,
17 unaligned_bytes: &[u8],
18 width: u32,
19 height: u32,
20 color_type: ExtendedColorType,
21 ) -> ImageResult<()> {
22 match color_type {
23 ExtendedColorType::Rgb32F => {
24 let bytes_per_pixel = color_type.bits_per_pixel() as usize / 8;
25 let rgbe_pixels = unaligned_bytes
26 .chunks_exact(bytes_per_pixel)
27 .map(|bytes| to_rgbe8(Rgb::<f32>(bytemuck::pod_read_unaligned(bytes))));
28
29 self.encode_pixels(rgbe_pixels, width as usize, height as usize)
31 }
32 _ => Err(ImageError::Unsupported(
33 UnsupportedError::from_format_and_kind(
34 ImageFormat::Hdr.into(),
35 UnsupportedErrorKind::Color(color_type),
36 ),
37 )),
38 }
39 }
40}
41
42impl<W: Write> HdrEncoder<W> {
43 pub fn new(w: W) -> HdrEncoder<W> {
45 HdrEncoder { w }
46 }
47
48 pub fn encode(self, rgb: &[Rgb<f32>], width: usize, height: usize) -> ImageResult<()> {
51 self.encode_pixels(rgb.iter().map(|&rgb| to_rgbe8(rgb)), width, height)
52 }
53
54 fn encode_pixels(
58 mut self,
59 mut flattened_rgbe_pixels: impl ExactSizeIterator<Item = Rgbe8Pixel>,
60 width: usize,
61 height: usize,
62 ) -> ImageResult<()> {
63 assert!(
64 flattened_rgbe_pixels.len() >= width * height,
65 "not enough pixels provided"
66 ); let w = &mut self.w;
69 w.write_all(SIGNATURE)?;
70 w.write_all(b"\n")?;
71 w.write_all(b"# Rust HDR encoder\n")?;
72 w.write_all(b"FORMAT=32-bit_rle_rgbe\n\n")?;
73 w.write_all(format!("-Y {height} +X {width}\n").as_bytes())?;
74
75 if !(8..=32_768).contains(&width) {
76 for pixel in flattened_rgbe_pixels {
77 write_rgbe8(w, pixel)?;
78 }
79 } else {
80 let marker = rgbe8(2, 2, (width / 256) as u8, (width % 256) as u8);
82 let mut bufr = vec![0; width];
84 let mut bufg = vec![0; width];
85 let mut bufb = vec![0; width];
86 let mut bufe = vec![0; width];
87 let mut rle_buf = vec![0; width];
88 for _scanline_index in 0..height {
89 assert!(flattened_rgbe_pixels.len() >= width); for ((((r, g), b), e), pixel) in bufr
92 .iter_mut()
93 .zip(bufg.iter_mut())
94 .zip(bufb.iter_mut())
95 .zip(bufe.iter_mut())
96 .zip(&mut flattened_rgbe_pixels)
97 {
98 *r = pixel.c[0];
99 *g = pixel.c[1];
100 *b = pixel.c[2];
101 *e = pixel.e;
102 }
103
104 write_rgbe8(w, marker)?; rle_buf.clear();
106 rle_compress(&bufr[..], &mut rle_buf);
107 w.write_all(&rle_buf[..])?;
108 rle_buf.clear();
109 rle_compress(&bufg[..], &mut rle_buf);
110 w.write_all(&rle_buf[..])?;
111 rle_buf.clear();
112 rle_compress(&bufb[..], &mut rle_buf);
113 w.write_all(&rle_buf[..])?;
114 rle_buf.clear();
115 rle_compress(&bufe[..], &mut rle_buf);
116 w.write_all(&rle_buf[..])?;
117 }
118 }
119 Ok(())
120 }
121}
122
123#[derive(Debug, PartialEq, Eq)]
124enum RunOrNot {
125 Run(u8, usize),
126 Norun(usize, usize),
127}
128
129use self::RunOrNot::{Norun, Run};
130
131const RUN_MAX_LEN: usize = 127;
132const NORUN_MAX_LEN: usize = 128;
133
134struct RunIterator<'a> {
135 data: &'a [u8],
136 curidx: usize,
137}
138
139impl<'a> RunIterator<'a> {
140 fn new(data: &'a [u8]) -> RunIterator<'a> {
141 RunIterator { data, curidx: 0 }
142 }
143}
144
145impl Iterator for RunIterator<'_> {
146 type Item = RunOrNot;
147
148 fn next(&mut self) -> Option<Self::Item> {
149 if self.curidx == self.data.len() {
150 None
151 } else {
152 let cv = self.data[self.curidx];
153 let crun = self.data[self.curidx..]
154 .iter()
155 .take_while(|&&v| v == cv)
156 .take(RUN_MAX_LEN)
157 .count();
158 let ret = if crun > 2 {
159 Run(cv, crun)
160 } else {
161 Norun(self.curidx, crun)
162 };
163 self.curidx += crun;
164 Some(ret)
165 }
166 }
167}
168
169struct NorunCombineIterator<'a> {
170 runiter: RunIterator<'a>,
171 prev: Option<RunOrNot>,
172}
173
174impl<'a> NorunCombineIterator<'a> {
175 fn new(data: &'a [u8]) -> NorunCombineIterator<'a> {
176 NorunCombineIterator {
177 runiter: RunIterator::new(data),
178 prev: None,
179 }
180 }
181}
182
183impl Iterator for NorunCombineIterator<'_> {
185 type Item = RunOrNot;
186
187 fn next(&mut self) -> Option<Self::Item> {
188 loop {
189 match self.prev.take() {
190 Some(Run(c, len)) => {
191 return Some(Run(c, len));
193 }
194 Some(Norun(idx, len)) => {
195 match self.runiter.next() {
197 Some(Norun(_, len1)) => {
198 let clen = len + len1; match clen.cmp(&NORUN_MAX_LEN) {
201 Ordering::Equal => return Some(Norun(idx, clen)),
202 Ordering::Greater => {
203 self.prev =
205 Some(Norun(idx + NORUN_MAX_LEN, clen - NORUN_MAX_LEN));
206 return Some(Norun(idx, NORUN_MAX_LEN));
208 }
209 Ordering::Less => {
210 self.prev = Some(Norun(idx, len + len1));
212 }
214 }
215 }
216 Some(Run(c, len1)) => {
217 self.prev = Some(Run(c, len1));
219 return Some(Norun(idx, len)); }
221 None => {
222 return Some(Norun(idx, len)); }
225 }
226 } None => {
228 match self.runiter.next() {
230 Some(Norun(idx, len)) => {
231 self.prev = Some(Norun(idx, len));
232 }
234 Some(Run(c, len)) => {
235 return Some(Run(c, len));
237 }
238 None => {
239 return None;
241 }
242 }
243 } } } }
247}
248
249fn rle_compress(data: &[u8], rle: &mut Vec<u8>) {
251 rle.clear();
252 if data.is_empty() {
253 rle.push(0); return;
255 }
256 for rnr in NorunCombineIterator::new(data) {
260 match rnr {
261 Run(c, len) => {
262 assert!(len <= 127);
263 rle.push(128u8 + len as u8);
264 rle.push(c);
265 }
266 Norun(idx, len) => {
267 assert!(len <= 128);
268 rle.push(len as u8);
269 rle.extend_from_slice(&data[idx..idx + len]);
270 }
271 }
272 }
273}
274
275fn write_rgbe8<W: Write>(w: &mut W, v: Rgbe8Pixel) -> Result<()> {
276 w.write_all(&[v.c[0], v.c[1], v.c[2], v.e])
277}
278
279pub(crate) fn to_rgbe8(pix: Rgb<f32>) -> Rgbe8Pixel {
281 let pix = pix.0;
282 let mx = f32::max(pix[0], f32::max(pix[1], pix[2]));
283 if mx <= 0.0 {
284 Rgbe8Pixel { c: [0, 0, 0], e: 0 }
285 } else {
286 let exp = mx.log2().floor() as i32 + 1;
288 let mul = f32::powi(2.0, exp);
289 let mut conv = [0u8; 3];
290 for (cv, &sv) in conv.iter_mut().zip(pix.iter()) {
291 *cv = f32::trunc(sv / mul * 256.0) as u8;
292 }
293 Rgbe8Pixel {
294 c: conv,
295 e: (exp + 128) as u8,
296 }
297 }
298}
299
300#[test]
301fn to_rgbe8_test() {
302 use crate::codecs::hdr::rgbe8;
303 let test_cases = vec![rgbe8(0, 0, 0, 0), rgbe8(1, 1, 128, 128)];
304 for &pix in &test_cases {
305 assert_eq!(pix, to_rgbe8(pix.to_hdr()));
306 }
307 for mc in 128..255 {
308 let pix = rgbe8(mc, mc, mc, 100);
310 assert_eq!(pix, to_rgbe8(pix.to_hdr()));
311 let pix = rgbe8(mc, 0, mc, 130);
312 assert_eq!(pix, to_rgbe8(pix.to_hdr()));
313 let pix = rgbe8(0, 0, mc, 140);
314 assert_eq!(pix, to_rgbe8(pix.to_hdr()));
315 let pix = rgbe8(1, 0, mc, 150);
316 assert_eq!(pix, to_rgbe8(pix.to_hdr()));
317 let pix = rgbe8(1, mc, 10, 128);
318 assert_eq!(pix, to_rgbe8(pix.to_hdr()));
319 for c in 0..255 {
320 let pix = rgbe8(1, mc, c, if c == 0 { 1 } else { c });
324 assert_eq!(pix, to_rgbe8(pix.to_hdr()));
325 }
326 }
327 fn relative_dist(a: Rgb<f32>, b: Rgb<f32>) -> f32 {
328 let max_diff =
330 a.0.iter()
331 .zip(b.0.iter())
332 .fold(0.0, |diff, (&a, &b)| f32::max(diff, (a - b).abs()));
333 let max_val =
334 a.0.iter()
335 .chain(b.0.iter())
336 .fold(0.0, |maxv, &a| f32::max(maxv, a));
337 if max_val == 0.0 {
338 0.0
339 } else {
340 max_diff / max_val
341 }
342 }
343 let test_values = vec![
344 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,
345 300_000.0,
346 ];
347 for &r in &test_values {
348 for &g in &test_values {
349 for &b in &test_values {
350 let c1 = Rgb([r, g, b]);
351 let c2 = to_rgbe8(c1).to_hdr();
352 let rel_dist = relative_dist(c1, c2);
353 assert!(
355 rel_dist <= 1.0 / 128.0,
356 "Relative distance ({rel_dist}) exceeds 1/128 for {c1:?} and {c2:?}"
357 );
358 }
359 }
360 }
361}
362
363#[test]
364fn runiterator_test() {
365 let data = [];
366 let mut run_iter = RunIterator::new(&data[..]);
367 assert_eq!(run_iter.next(), None);
368 let data = [5];
369 let mut run_iter = RunIterator::new(&data[..]);
370 assert_eq!(run_iter.next(), Some(Norun(0, 1)));
371 assert_eq!(run_iter.next(), None);
372 let data = [1, 1];
373 let mut run_iter = RunIterator::new(&data[..]);
374 assert_eq!(run_iter.next(), Some(Norun(0, 2)));
375 assert_eq!(run_iter.next(), None);
376 let data = [0, 0, 0];
377 let mut run_iter = RunIterator::new(&data[..]);
378 assert_eq!(run_iter.next(), Some(Run(0u8, 3)));
379 assert_eq!(run_iter.next(), None);
380 let data = [0, 0, 1, 1];
381 let mut run_iter = RunIterator::new(&data[..]);
382 assert_eq!(run_iter.next(), Some(Norun(0, 2)));
383 assert_eq!(run_iter.next(), Some(Norun(2, 2)));
384 assert_eq!(run_iter.next(), None);
385 let data = [0, 0, 0, 1, 1];
386 let mut run_iter = RunIterator::new(&data[..]);
387 assert_eq!(run_iter.next(), Some(Run(0u8, 3)));
388 assert_eq!(run_iter.next(), Some(Norun(3, 2)));
389 assert_eq!(run_iter.next(), None);
390 let data = [1, 2, 2, 2];
391 let mut run_iter = RunIterator::new(&data[..]);
392 assert_eq!(run_iter.next(), Some(Norun(0, 1)));
393 assert_eq!(run_iter.next(), Some(Run(2u8, 3)));
394 assert_eq!(run_iter.next(), None);
395 let data = [1, 1, 2, 2, 2];
396 let mut run_iter = RunIterator::new(&data[..]);
397 assert_eq!(run_iter.next(), Some(Norun(0, 2)));
398 assert_eq!(run_iter.next(), Some(Run(2u8, 3)));
399 assert_eq!(run_iter.next(), None);
400 let data = [2; 128];
401 let mut run_iter = RunIterator::new(&data[..]);
402 assert_eq!(run_iter.next(), Some(Run(2u8, 127)));
403 assert_eq!(run_iter.next(), Some(Norun(127, 1)));
404 assert_eq!(run_iter.next(), None);
405 let data = [2; 129];
406 let mut run_iter = RunIterator::new(&data[..]);
407 assert_eq!(run_iter.next(), Some(Run(2u8, 127)));
408 assert_eq!(run_iter.next(), Some(Norun(127, 2)));
409 assert_eq!(run_iter.next(), None);
410 let data = [2; 130];
411 let mut run_iter = RunIterator::new(&data[..]);
412 assert_eq!(run_iter.next(), Some(Run(2u8, 127)));
413 assert_eq!(run_iter.next(), Some(Run(2u8, 3)));
414 assert_eq!(run_iter.next(), None);
415}
416
417#[test]
418fn noruncombine_test() {
419 fn a<T>(mut v: Vec<T>, mut other: Vec<T>) -> Vec<T> {
420 v.append(&mut other);
421 v
422 }
423
424 let v = [];
425 let mut rsi = NorunCombineIterator::new(&v[..]);
426 assert_eq!(rsi.next(), None);
427
428 let v = [1];
429 let mut rsi = NorunCombineIterator::new(&v[..]);
430 assert_eq!(rsi.next(), Some(Norun(0, 1)));
431 assert_eq!(rsi.next(), None);
432
433 let v = [2, 2];
434 let mut rsi = NorunCombineIterator::new(&v[..]);
435 assert_eq!(rsi.next(), Some(Norun(0, 2)));
436 assert_eq!(rsi.next(), None);
437
438 let v = [3, 3, 3];
439 let mut rsi = NorunCombineIterator::new(&v[..]);
440 assert_eq!(rsi.next(), Some(Run(3, 3)));
441 assert_eq!(rsi.next(), None);
442
443 let v = [4, 4, 3, 3, 3];
444 let mut rsi = NorunCombineIterator::new(&v[..]);
445 assert_eq!(rsi.next(), Some(Norun(0, 2)));
446 assert_eq!(rsi.next(), Some(Run(3, 3)));
447 assert_eq!(rsi.next(), None);
448
449 let v = vec![40; 400];
450 let mut rsi = NorunCombineIterator::new(&v[..]);
451 assert_eq!(rsi.next(), Some(Run(40, 127)));
452 assert_eq!(rsi.next(), Some(Run(40, 127)));
453 assert_eq!(rsi.next(), Some(Run(40, 127)));
454 assert_eq!(rsi.next(), Some(Run(40, 19)));
455 assert_eq!(rsi.next(), None);
456
457 let v = a(a(vec![5; 3], vec![6; 129]), vec![7, 3, 7, 10, 255]);
458 let mut rsi = NorunCombineIterator::new(&v[..]);
459 assert_eq!(rsi.next(), Some(Run(5, 3)));
460 assert_eq!(rsi.next(), Some(Run(6, 127)));
461 assert_eq!(rsi.next(), Some(Norun(130, 7)));
462 assert_eq!(rsi.next(), None);
463
464 let v = a(a(vec![5; 2], vec![6; 129]), vec![7, 3, 7, 7, 255]);
465 let mut rsi = NorunCombineIterator::new(&v[..]);
466 assert_eq!(rsi.next(), Some(Norun(0, 2)));
467 assert_eq!(rsi.next(), Some(Run(6, 127)));
468 assert_eq!(rsi.next(), Some(Norun(129, 7)));
469 assert_eq!(rsi.next(), None);
470
471 let v: Vec<_> = std::iter::repeat(())
472 .flat_map(|()| 0..2)
473 .take(257)
474 .collect();
475 let mut rsi = NorunCombineIterator::new(&v[..]);
476 assert_eq!(rsi.next(), Some(Norun(0, 128)));
477 assert_eq!(rsi.next(), Some(Norun(128, 128)));
478 assert_eq!(rsi.next(), Some(Norun(256, 1)));
479 assert_eq!(rsi.next(), None);
480}