1 use num_traits::identities::Zero;
2 use scoped_threadpool::Pool;
3 #[cfg(test)]
4 use std::borrow::Cow;
5 use std::convert::TryFrom;
6 use std::io::{self, BufRead, Cursor, Read, Seek};
7 use std::iter::Iterator;
8 use std::marker::PhantomData;
9 use std::mem;
10 use std::path::Path;
11 use crate::Primitive;
12 
13 use crate::color::{ColorType, Rgb};
14 use crate::error::{ImageError, ImageResult};
15 use crate::image::{self, ImageDecoder, ImageDecoderExt, Progress};
16 
17 /// Adapter to conform to ```ImageDecoder``` trait
18 #[derive(Debug)]
19 pub struct HDRAdapter<R: BufRead> {
20     inner: Option<HdrDecoder<R>>,
21     // data: Option<Vec<u8>>,
22     meta: HDRMetadata,
23 }
24 
25 impl<R: BufRead> HDRAdapter<R> {
26     /// Creates adapter
new(r: R) -> ImageResult<HDRAdapter<R>>27     pub fn new(r: R) -> ImageResult<HDRAdapter<R>> {
28         let decoder = HdrDecoder::new(r)?;
29         let meta = decoder.metadata();
30         Ok(HDRAdapter {
31             inner: Some(decoder),
32             meta,
33         })
34     }
35 
36     /// Allows reading old Radiance HDR images
new_nonstrict(r: R) -> ImageResult<HDRAdapter<R>>37     pub fn new_nonstrict(r: R) -> ImageResult<HDRAdapter<R>> {
38         let decoder = HdrDecoder::with_strictness(r, false)?;
39         let meta = decoder.metadata();
40         Ok(HDRAdapter {
41             inner: Some(decoder),
42             meta,
43         })
44     }
45 
46     /// Read the actual data of the image, and store it in Self::data.
read_image_data(&mut self, buf: &mut [u8]) -> ImageResult<()>47     fn read_image_data(&mut self, buf: &mut [u8]) -> ImageResult<()> {
48         assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
49         match self.inner.take() {
50             Some(decoder) => {
51                 let img: Vec<Rgb<u8>> = decoder.read_image_ldr()?;
52                 for (i, Rgb(data)) in img.into_iter().enumerate() {
53                     buf[(i*3)..][..3].copy_from_slice(&data);
54                 }
55 
56                 Ok(())
57             }
58             None => Err(ImageError::ImageEnd),
59         }
60     }
61 }
62 
63 /// Wrapper struct around a `Cursor<Vec<u8>>`
64 pub struct HdrReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
65 impl<R> Read for HdrReader<R> {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>66     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
67         self.0.read(buf)
68     }
read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize>69     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
70         if self.0.position() == 0 && buf.is_empty() {
71             mem::swap(buf, self.0.get_mut());
72             Ok(buf.len())
73         } else {
74             self.0.read_to_end(buf)
75         }
76     }
77 }
78 
79 impl<'a, R: 'a + BufRead> ImageDecoder<'a> for HDRAdapter<R> {
80     type Reader = HdrReader<R>;
81 
dimensions(&self) -> (u32, u32)82     fn dimensions(&self) -> (u32, u32) {
83         (self.meta.width, self.meta.height)
84     }
85 
color_type(&self) -> ColorType86     fn color_type(&self) -> ColorType {
87         ColorType::Rgb8
88     }
89 
into_reader(self) -> ImageResult<Self::Reader>90     fn into_reader(self) -> ImageResult<Self::Reader> {
91         Ok(HdrReader(Cursor::new(image::decoder_to_vec(self)?), PhantomData))
92     }
93 
read_image(mut self, buf: &mut [u8]) -> ImageResult<()>94     fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
95         self.read_image_data(buf)
96     }
97 }
98 
99 impl<'a, R: 'a + BufRead + Seek> ImageDecoderExt<'a> for HDRAdapter<R> {
read_rect_with_progress<F: Fn(Progress)>( &mut self, x: u32, y: u32, width: u32, height: u32, buf: &mut [u8], progress_callback: F, ) -> ImageResult<()>100     fn read_rect_with_progress<F: Fn(Progress)>(
101         &mut self,
102         x: u32,
103         y: u32,
104         width: u32,
105         height: u32,
106         buf: &mut [u8],
107         progress_callback: F,
108     ) -> ImageResult<()> {
109         image::load_rect(x, y, width, height, buf, progress_callback, self, |_, _| unreachable!(),
110                          |s, buf| s.read_image_data(buf).map(|_| buf.len()))
111     }
112 }
113 
114 /// Radiance HDR file signature
115 pub const SIGNATURE: &[u8] = b"#?RADIANCE";
116 const SIGNATURE_LENGTH: usize = 10;
117 
118 /// An Radiance HDR decoder
119 #[derive(Debug)]
120 pub struct HdrDecoder<R> {
121     r: R,
122     width: u32,
123     height: u32,
124     meta: HDRMetadata,
125 }
126 
127 /// Refer to [wikipedia](https://en.wikipedia.org/wiki/RGBE_image_format)
128 #[repr(C)]
129 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
130 pub struct RGBE8Pixel {
131     /// Color components
132     pub c: [u8; 3],
133     /// Exponent
134     pub e: u8,
135 }
136 
137 /// Creates ```RGBE8Pixel``` from components
rgbe8(r: u8, g: u8, b: u8, e: u8) -> RGBE8Pixel138 pub fn rgbe8(r: u8, g: u8, b: u8, e: u8) -> RGBE8Pixel {
139     RGBE8Pixel { c: [r, g, b], e }
140 }
141 
142 impl RGBE8Pixel {
143     /// Converts ```RGBE8Pixel``` into ```Rgb<f32>``` linearly
144     #[inline]
to_hdr(self) -> Rgb<f32>145     pub fn to_hdr(self) -> Rgb<f32> {
146         if self.e == 0 {
147             Rgb([0.0, 0.0, 0.0])
148         } else {
149             //            let exp = f32::ldexp(1., self.e as isize - (128 + 8)); // unstable
150             let exp = f32::exp2(<f32 as From<_>>::from(self.e) - (128.0 + 8.0));
151             Rgb([
152                 exp * <f32 as From<_>>::from(self.c[0]),
153                 exp * <f32 as From<_>>::from(self.c[1]),
154                 exp * <f32 as From<_>>::from(self.c[2]),
155             ])
156         }
157     }
158 
159     /// Converts ```RGBE8Pixel``` into ```Rgb<T>``` with scale=1 and gamma=2.2
160     ///
161     /// color_ldr = (color_hdr*scale)<sup>gamma</sup>
162     ///
163     /// # Panic
164     ///
165     /// Panics when ```T::max_value()``` cannot be represented as f32.
166     #[inline]
to_ldr<T: Primitive + Zero>(self) -> Rgb<T>167     pub fn to_ldr<T: Primitive + Zero>(self) -> Rgb<T> {
168         self.to_ldr_scale_gamma(1.0, 2.2)
169     }
170 
171     /// Converts RGBE8Pixel into Rgb<T> using provided scale and gamma
172     ///
173     /// color_ldr = (color_hdr*scale)<sup>gamma</sup>
174     ///
175     /// # Panic
176     ///
177     /// Panics when T::max_value() cannot be represented as f32.
178     /// Panics when scale or gamma is NaN
179     #[inline]
to_ldr_scale_gamma<T: Primitive + Zero>(self, scale: f32, gamma: f32) -> Rgb<T>180     pub fn to_ldr_scale_gamma<T: Primitive + Zero>(self, scale: f32, gamma: f32) -> Rgb<T> {
181         let Rgb(data) = self.to_hdr();
182         let (r, g, b) = (data[0], data[1], data[2]);
183         #[inline]
184         fn sg<T: Primitive + Zero>(v: f32, scale: f32, gamma: f32) -> T {
185             let t_max = T::max_value();
186             // Disassembly shows that t_max_f32 is compiled into constant
187             let t_max_f32: f32 = num_traits::NumCast::from(t_max)
188                 .expect("to_ldr_scale_gamma: maximum value of type is not representable as f32");
189             let fv = f32::powf(v * scale, gamma) * t_max_f32 + 0.5;
190             if fv < 0.0 {
191                 T::zero()
192             } else if fv > t_max_f32 {
193                 t_max
194             } else {
195                 num_traits::NumCast::from(fv)
196                     .expect("to_ldr_scale_gamma: cannot convert f32 to target type. NaN?")
197             }
198         }
199         Rgb([
200             sg(r, scale, gamma),
201             sg(g, scale, gamma),
202             sg(b, scale, gamma),
203         ])
204     }
205 }
206 
207 impl<R: BufRead> HdrDecoder<R> {
208     /// Reads Radiance HDR image header from stream ```r```
209     /// if the header is valid, creates HdrDecoder
210     /// strict mode is enabled
new(reader: R) -> ImageResult<HdrDecoder<R>>211     pub fn new(reader: R) -> ImageResult<HdrDecoder<R>> {
212         HdrDecoder::with_strictness(reader, true)
213     }
214 
215     /// Reads Radiance HDR image header from stream ```reader```,
216     /// if the header is valid, creates ```HdrDecoder```.
217     ///
218     /// strict enables strict mode
219     ///
220     /// Warning! Reading wrong file in non-strict mode
221     ///   could consume file size worth of memory in the process.
with_strictness(mut reader: R, strict: bool) -> ImageResult<HdrDecoder<R>>222     pub fn with_strictness(mut reader: R, strict: bool) -> ImageResult<HdrDecoder<R>> {
223         let mut attributes = HDRMetadata::new();
224 
225         {
226             // scope to make borrowck happy
227             let r = &mut reader;
228             if strict {
229                 let mut signature = [0; SIGNATURE_LENGTH];
230                 r.read_exact(&mut signature)?;
231                 if signature != SIGNATURE {
232                     return Err(ImageError::FormatError(
233                         "Radiance HDR signature not found".to_string(),
234                     ));
235                 } // no else
236                   // skip signature line ending
237                 read_line_u8(r)?;
238             } else {
239                 // Old Radiance HDR files (*.pic) don't use signature
240                 // Let them be parsed in non-strict mode
241             }
242             // read header data until empty line
243             loop {
244                 match read_line_u8(r)? {
245                     None => {
246                         // EOF before end of header
247                         return Err(ImageError::FormatError("EOF in header".into()));
248                     }
249                     Some(line) => {
250                         if line.is_empty() {
251                             // end of header
252                             break;
253                         } else if line[0] == b'#' {
254                             // line[0] will not panic, line.len() == 0 is false here
255                             // skip comments
256                             continue;
257                         } // no else
258                           // process attribute line
259                         let line = String::from_utf8_lossy(&line[..]);
260                         attributes.update_header_info(&line, strict)?;
261                     } // <= Some(line)
262                 } // match read_line_u8()
263             } // loop
264         } // scope to end borrow of reader
265           // parse dimensions
266         let (width, height) = match read_line_u8(&mut reader)? {
267             None => {
268                 // EOF instead of image dimensions
269                 return Err(ImageError::FormatError("EOF in dimensions line".into()));
270             }
271             Some(dimensions) => {
272                 let dimensions = String::from_utf8_lossy(&dimensions[..]);
273                 parse_dimensions_line(&dimensions, strict)?
274             }
275         };
276 
277         Ok(HdrDecoder {
278             r: reader,
279 
280             width,
281             height,
282             meta: HDRMetadata {
283                 width,
284                 height,
285                 ..attributes
286             },
287         })
288     } // end with_strictness
289 
290     /// Returns file metadata. Refer to ```HDRMetadata``` for details.
metadata(&self) -> HDRMetadata291     pub fn metadata(&self) -> HDRMetadata {
292         self.meta.clone()
293     }
294 
295     /// Consumes decoder and returns a vector of RGBE8 pixels
read_image_native(mut self) -> ImageResult<Vec<RGBE8Pixel>>296     pub fn read_image_native(mut self) -> ImageResult<Vec<RGBE8Pixel>> {
297         // Don't read anything if image is empty
298         if self.width == 0 || self.height == 0 {
299             return Ok(vec![]);
300         }
301         // expression self.width > 0 && self.height > 0 is true from now to the end of this method
302         let pixel_count = self.width as usize * self.height as usize;
303         let mut ret = vec![Default::default(); pixel_count];
304         for chunk in ret.chunks_mut(self.width as usize) {
305             read_scanline(&mut self.r, chunk)?;
306         }
307         Ok(ret)
308     }
309 
310     /// Consumes decoder and returns a vector of transformed pixels
read_image_transform<T: Send, F: Send + Sync + Fn(RGBE8Pixel) -> T>( mut self, f: F, output_slice: &mut [T], ) -> ImageResult<()>311     pub fn read_image_transform<T: Send, F: Send + Sync + Fn(RGBE8Pixel) -> T>(
312         mut self,
313         f: F,
314         output_slice: &mut [T],
315     ) -> ImageResult<()> {
316         assert_eq!(
317             output_slice.len(),
318             self.width as usize * self.height as usize
319         );
320 
321         // Don't read anything if image is empty
322         if self.width == 0 || self.height == 0 {
323             return Ok(());
324         }
325 
326         let chunks_iter = output_slice.chunks_mut(self.width as usize);
327         let mut pool = Pool::new(8); //
328 
329         (pool.scoped(|scope| {
330             for chunk in chunks_iter {
331                 let mut buf = vec![Default::default(); self.width as usize];
332                 read_scanline(&mut self.r, &mut buf[..])?;
333                 let f = &f;
334                 scope.execute(move || {
335                     for (dst, &pix) in chunk.iter_mut().zip(buf.iter()) {
336                         *dst = f(pix);
337                     }
338                 });
339             }
340             Ok(())
341         }) as Result<(), ImageError>)?;
342         Ok(())
343     }
344 
345     /// Consumes decoder and returns a vector of Rgb<u8> pixels.
346     /// scale = 1, gamma = 2.2
read_image_ldr(self) -> ImageResult<Vec<Rgb<u8>>>347     pub fn read_image_ldr(self) -> ImageResult<Vec<Rgb<u8>>> {
348         let mut ret = vec![Rgb([0, 0, 0]); self.width as usize * self.height as usize];
349         self.read_image_transform(|pix| pix.to_ldr(), &mut ret[..])?;
350         Ok(ret)
351     }
352 
353     /// Consumes decoder and returns a vector of Rgb<f32> pixels.
354     ///
read_image_hdr(self) -> ImageResult<Vec<Rgb<f32>>>355     pub fn read_image_hdr(self) -> ImageResult<Vec<Rgb<f32>>> {
356         let mut ret = vec![Rgb([0.0, 0.0, 0.0]); self.width as usize * self.height as usize];
357         self.read_image_transform(|pix| pix.to_hdr(), &mut ret[..])?;
358         Ok(ret)
359     }
360 }
361 
362 impl<R: BufRead> IntoIterator for HdrDecoder<R> {
363     type Item = ImageResult<RGBE8Pixel>;
364     type IntoIter = HDRImageDecoderIterator<R>;
365 
into_iter(self) -> Self::IntoIter366     fn into_iter(self) -> Self::IntoIter {
367         HDRImageDecoderIterator {
368             r: self.r,
369             scanline_cnt: self.height as usize,
370             buf: vec![Default::default(); self.width as usize],
371             col: 0,
372             scanline: 0,
373             trouble: true, // make first call to `next()` read scanline
374             error_encountered: false,
375         }
376     }
377 }
378 
379 /// Scanline buffered pixel by pixel iterator
380 pub struct HDRImageDecoderIterator<R: BufRead> {
381     r: R,
382     scanline_cnt: usize,
383     buf: Vec<RGBE8Pixel>, // scanline buffer
384     col: usize,           // current position in scanline
385     scanline: usize,      // current scanline
386     trouble: bool,        // optimization, true indicates that we need to check something
387     error_encountered: bool,
388 }
389 
390 impl<R: BufRead> HDRImageDecoderIterator<R> {
391     // Advances counter to the next pixel
392     #[inline]
advance(&mut self)393     fn advance(&mut self) {
394         self.col += 1;
395         if self.col == self.buf.len() {
396             self.col = 0;
397             self.scanline += 1;
398             self.trouble = true;
399         }
400     }
401 }
402 
403 impl<R: BufRead> Iterator for HDRImageDecoderIterator<R> {
404     type Item = ImageResult<RGBE8Pixel>;
405 
next(&mut self) -> Option<Self::Item>406     fn next(&mut self) -> Option<Self::Item> {
407         if !self.trouble {
408             let ret = self.buf[self.col];
409             self.advance();
410             Some(Ok(ret))
411         } else {
412             // some condition is pending
413             if self.buf.is_empty() || self.scanline == self.scanline_cnt {
414                 // No more pixels
415                 return None;
416             } // no else
417             if self.error_encountered {
418                 self.advance();
419                 // Error was encountered. Keep producing errors.
420                 // ImageError can't implement Clone, so just dump some error
421                 return Some(Err(ImageError::ImageEnd));
422             } // no else
423             if self.col == 0 {
424                 // fill scanline buffer
425                 match read_scanline(&mut self.r, &mut self.buf[..]) {
426                     Ok(_) => {
427                         // no action required
428                     }
429                     Err(err) => {
430                         self.advance();
431                         self.error_encountered = true;
432                         self.trouble = true;
433                         return Some(Err(err));
434                     }
435                 }
436             } // no else
437             self.trouble = false;
438             let ret = self.buf[0];
439             self.advance();
440             Some(Ok(ret))
441         }
442     }
443 
size_hint(&self) -> (usize, Option<usize>)444     fn size_hint(&self) -> (usize, Option<usize>) {
445         let total_cnt = self.buf.len() * self.scanline_cnt;
446         let cur_cnt = self.buf.len() * self.scanline + self.col;
447         let remaining = total_cnt - cur_cnt;
448         (remaining, Some(remaining))
449     }
450 }
451 
452 impl<R: BufRead> ExactSizeIterator for HDRImageDecoderIterator<R> {}
453 
454 // Precondition: buf.len() > 0
read_scanline<R: BufRead>(r: &mut R, buf: &mut [RGBE8Pixel]) -> ImageResult<()>455 fn read_scanline<R: BufRead>(r: &mut R, buf: &mut [RGBE8Pixel]) -> ImageResult<()> {
456     assert!(!buf.is_empty());
457     let width = buf.len();
458     // first 4 bytes in scanline allow to determine compression method
459     let fb = read_rgbe(r)?;
460     if fb.c[0] == 2 && fb.c[1] == 2 && fb.c[2] < 128 {
461         // denormalized pixel value (2,2,<128,_) indicates new per component RLE method
462         // decode_component guarantees that offset is within 0 .. width
463         // therefore we can skip bounds checking here, but we will not
464         decode_component(r, width, |offset, value| buf[offset].c[0] = value)?;
465         decode_component(r, width, |offset, value| buf[offset].c[1] = value)?;
466         decode_component(r, width, |offset, value| buf[offset].c[2] = value)?;
467         decode_component(r, width, |offset, value| buf[offset].e = value)?;
468     } else {
469         // old RLE method (it was considered old around 1991, should it be here?)
470         decode_old_rle(r, fb, buf)?;
471     }
472     Ok(())
473 }
474 
475 #[inline(always)]
read_byte<R: BufRead>(r: &mut R) -> io::Result<u8>476 fn read_byte<R: BufRead>(r: &mut R) -> io::Result<u8> {
477     let mut buf = [0u8];
478     r.read_exact(&mut buf[..])?;
479     Ok(buf[0])
480 }
481 
482 // Guarantees that first parameter of set_component will be within pos .. pos+width
483 #[inline]
decode_component<R: BufRead, S: FnMut(usize, u8)>( r: &mut R, width: usize, mut set_component: S, ) -> ImageResult<()>484 fn decode_component<R: BufRead, S: FnMut(usize, u8)>(
485     r: &mut R,
486     width: usize,
487     mut set_component: S,
488 ) -> ImageResult<()> {
489     let mut buf = [0; 128];
490     let mut pos = 0;
491     while pos < width {
492         // increment position by a number of decompressed values
493         pos += {
494             let rl = read_byte(r)?;
495             if rl <= 128 {
496                 // sanity check
497                 if pos + rl as usize > width {
498                     return Err(ImageError::FormatError(
499                         "Wrong length of decoded scanline".into(),
500                     ));
501                 }
502                 // read values
503                 r.read_exact(&mut buf[0..rl as usize])?;
504                 for (offset, &value) in buf[0..rl as usize].iter().enumerate() {
505                     set_component(pos + offset, value);
506                 }
507                 rl as usize
508             } else {
509                 // run
510                 let rl = rl - 128;
511                 // sanity check
512                 if pos + rl as usize > width {
513                     return Err(ImageError::FormatError(
514                         "Wrong length of decoded scanline".into(),
515                     ));
516                 }
517                 // fill with same value
518                 let value = read_byte(r)?;
519                 for offset in 0..rl as usize {
520                     set_component(pos + offset, value);
521                 }
522                 rl as usize
523             }
524         };
525     }
526     if pos != width {
527         return Err(ImageError::FormatError(
528             "Wrong length of decoded scanline".into(),
529         ));
530     }
531     Ok(())
532 }
533 
534 // Decodes scanline, places it into buf
535 // Precondition: buf.len() > 0
536 // fb - first 4 bytes of scanline
decode_old_rle<R: BufRead>( r: &mut R, fb: RGBE8Pixel, buf: &mut [RGBE8Pixel], ) -> ImageResult<()>537 fn decode_old_rle<R: BufRead>(
538     r: &mut R,
539     fb: RGBE8Pixel,
540     buf: &mut [RGBE8Pixel],
541 ) -> ImageResult<()> {
542     assert!(!buf.is_empty());
543     let width = buf.len();
544     // convenience function.
545     // returns run length if pixel is a run length marker
546     #[inline]
547     fn rl_marker(pix: RGBE8Pixel) -> Option<usize> {
548         if pix.c == [1, 1, 1] {
549             Some(pix.e as usize)
550         } else {
551             None
552         }
553     }
554     // first pixel in scanline should not be run length marker
555     // it is error if it is
556     if rl_marker(fb).is_some() {
557         return Err(ImageError::FormatError(
558             "First pixel of a scanline shouldn't be run length marker".into(),
559         ));
560     }
561     buf[0] = fb; // set first pixel of scanline
562 
563     let mut x_off = 1; // current offset from beginning of a scanline
564     let mut rl_mult = 1; // current run length multiplier
565     let mut prev_pixel = fb;
566     while x_off < width {
567         let pix = read_rgbe(r)?;
568         // it's harder to forget to increase x_off if I write this this way.
569         x_off += {
570             if let Some(rl) = rl_marker(pix) {
571                 // rl_mult takes care of consecutive RL markers
572                 let rl = rl * rl_mult;
573                 rl_mult *= 256;
574                 if x_off + rl <= width {
575                     // do run
576                     for b in &mut buf[x_off..x_off + rl] {
577                         *b = prev_pixel;
578                     }
579                 } else {
580                     return Err(ImageError::FormatError(
581                         "Wrong length of decoded scanline".into(),
582                     ));
583                 };
584                 rl // value to increase x_off by
585             } else {
586                 rl_mult = 1; // chain of consecutive RL markers is broken
587                 prev_pixel = pix;
588                 buf[x_off] = pix;
589                 1 // value to increase x_off by
590             }
591         };
592     }
593     if x_off != width {
594         return Err(ImageError::FormatError(
595             "Wrong length of decoded scanline".into(),
596         ));
597     }
598     Ok(())
599 }
600 
read_rgbe<R: BufRead>(r: &mut R) -> io::Result<RGBE8Pixel>601 fn read_rgbe<R: BufRead>(r: &mut R) -> io::Result<RGBE8Pixel> {
602     let mut buf = [0u8; 4];
603     r.read_exact(&mut buf[..])?;
604     Ok(RGBE8Pixel {
605         c: [buf[0], buf[1], buf[2]],
606         e: buf[3],
607     })
608 }
609 
610 /// Metadata for Radiance HDR image
611 #[derive(Debug, Clone)]
612 pub struct HDRMetadata {
613     /// Width of decoded image. It could be either scanline length,
614     /// or scanline count, depending on image orientation.
615     pub width: u32,
616     /// Height of decoded image. It depends on orientation too.
617     pub height: u32,
618     /// Orientation matrix. For standard orientation it is ((1,0),(0,1)) - left to right, top to bottom.
619     /// First pair tells how resulting pixel coordinates change along a scanline.
620     /// Second pair tells how they change from one scanline to the next.
621     pub orientation: ((i8, i8), (i8, i8)),
622     /// Divide color values by exposure to get to get physical radiance in
623     /// watts/steradian/m<sup>2</sup>
624     ///
625     /// Image may not contain physical data, even if this field is set.
626     pub exposure: Option<f32>,
627     /// Divide color values by corresponding tuple member (r, g, b) to get to get physical radiance
628     /// in watts/steradian/m<sup>2</sup>
629     ///
630     /// Image may not contain physical data, even if this field is set.
631     pub color_correction: Option<(f32, f32, f32)>,
632     /// Pixel height divided by pixel width
633     pub pixel_aspect_ratio: Option<f32>,
634     /// All lines contained in image header are put here. Ordering of lines is preserved.
635     /// Lines in the form "key=value" are represented as ("key", "value").
636     /// All other lines are ("", "line")
637     pub custom_attributes: Vec<(String, String)>,
638 }
639 
640 impl HDRMetadata {
new() -> HDRMetadata641     fn new() -> HDRMetadata {
642         HDRMetadata {
643             width: 0,
644             height: 0,
645             orientation: ((1, 0), (0, 1)),
646             exposure: None,
647             color_correction: None,
648             pixel_aspect_ratio: None,
649             custom_attributes: vec![],
650         }
651     }
652 
653     // Updates header info, in strict mode returns error for malformed lines (no '=' separator)
654     // unknown attributes are skipped
update_header_info(&mut self, line: &str, strict: bool) -> ImageResult<()>655     fn update_header_info(&mut self, line: &str, strict: bool) -> ImageResult<()> {
656         // split line at first '='
657         // old Radiance HDR files (*.pic) feature tabs in key, so                vvv trim
658         let maybe_key_value = split_at_first(line, "=").map(|(key, value)| (key.trim(), value));
659         // save all header lines in custom_attributes
660         match maybe_key_value {
661             Some((key, val)) => self
662                 .custom_attributes
663                 .push((key.to_owned(), val.to_owned())),
664             None => self.custom_attributes.push(("".into(), line.to_owned())),
665         }
666         // parse known attributes
667         match maybe_key_value {
668             Some(("FORMAT", val)) => {
669                 if val.trim() != "32-bit_rle_rgbe" {
670                     // XYZE isn't supported yet
671                     return Err(ImageError::UnsupportedError(limit_string_len(val, 20)));
672                 }
673             }
674             Some(("EXPOSURE", val)) => {
675                 match val.trim().parse::<f32>() {
676                     Ok(v) => {
677                         self.exposure = Some(self.exposure.unwrap_or(1.0) * v); // all encountered exposure values should be multiplied
678                     }
679                     Err(parse_error) => {
680                         if strict {
681                             return Err(ImageError::FormatError(format!(
682                                 "Cannot parse EXPOSURE value: {}",
683                                 parse_error
684                             )));
685                         } // no else, skip this line in non-strict mode
686                     }
687                 };
688             }
689             Some(("PIXASPECT", val)) => {
690                 match val.trim().parse::<f32>() {
691                     Ok(v) => {
692                         self.pixel_aspect_ratio = Some(self.pixel_aspect_ratio.unwrap_or(1.0) * v);
693                         // all encountered exposure values should be multiplied
694                     }
695                     Err(parse_error) => {
696                         if strict {
697                             return Err(ImageError::FormatError(format!(
698                                 "Cannot parse PIXASPECT value: {}",
699                                 parse_error
700                             )));
701                         } // no else, skip this line in non-strict mode
702                     }
703                 };
704             }
705             Some(("COLORCORR", val)) => {
706                 let mut rgbcorr = [1.0, 1.0, 1.0];
707                 match parse_space_separated_f32(val, &mut rgbcorr, "COLORCORR") {
708                     Ok(extra_numbers) => {
709                         if strict && extra_numbers {
710                             return Err(ImageError::FormatError(
711                                 "Extra numbers in COLORCORR".into(),
712                             ));
713                         } // no else, just ignore extra numbers
714                         let (rc, gc, bc) = self.color_correction.unwrap_or((1.0, 1.0, 1.0));
715                         self.color_correction =
716                             Some((rc * rgbcorr[0], gc * rgbcorr[1], bc * rgbcorr[2]));
717                     }
718                     Err(err) => {
719                         if strict {
720                             return Err(err);
721                         } // no else, skip malformed line in non-strict mode
722                     }
723                 }
724             }
725             None => {
726                 // old Radiance HDR files (*.pic) contain commands in a header
727                 // just skip them
728             }
729             _ => {
730                 // skip unknown attribute
731             }
732         } // match attributes
733         Ok(())
734     }
735 }
736 
parse_space_separated_f32(line: &str, vals: &mut [f32], name: &str) -> ImageResult<bool>737 fn parse_space_separated_f32(line: &str, vals: &mut [f32], name: &str) -> ImageResult<bool> {
738     let mut nums = line.split_whitespace();
739     for val in vals.iter_mut() {
740         if let Some(num) = nums.next() {
741             match num.parse::<f32>() {
742                 Ok(v) => *val = v,
743                 Err(err) => {
744                     return Err(ImageError::FormatError(format!(
745                         "f32 parse error in {}: {}",
746                         name,
747                         err
748                     )));
749                 }
750             }
751         } else {
752             // not enough numbers in line
753             return Err(ImageError::FormatError(format!(
754                 "Not enough numbers in {}",
755                 name
756             )));
757         }
758     }
759     Ok(nums.next().is_some())
760 }
761 
762 // Parses dimension line "-Y height +X width"
763 // returns (width, height) or error
parse_dimensions_line(line: &str, strict: bool) -> ImageResult<(u32, u32)>764 fn parse_dimensions_line(line: &str, strict: bool) -> ImageResult<(u32, u32)> {
765     let mut dim_parts = line.split_whitespace();
766     let err = "Malformed dimensions line";
767     let c1_tag = dim_parts
768         .next()
769         .ok_or_else(|| ImageError::FormatError(err.into()))?;
770     let c1_str = dim_parts
771         .next()
772         .ok_or_else(|| ImageError::FormatError(err.into()))?;
773     let c2_tag = dim_parts
774         .next()
775         .ok_or_else(|| ImageError::FormatError(err.into()))?;
776     let c2_str = dim_parts
777         .next()
778         .ok_or_else(|| ImageError::FormatError(err.into()))?;
779     if strict && dim_parts.next().is_some() {
780         // extra data in dimensions line
781         return Err(ImageError::FormatError(err.into()));
782     } // no else
783       // dimensions line is in the form "-Y 10 +X 20"
784       // There are 8 possible orientations: +Y +X, +X -Y and so on
785     match (c1_tag, c2_tag) {
786         ("-Y", "+X") => {
787             // Common orientation (left-right, top-down)
788             // c1_str is height, c2_str is width
789             let height = c1_str.parse::<u32>().into_image_error(err)?;
790             let width = c2_str.parse::<u32>().into_image_error(err)?;
791             Ok((width, height))
792         }
793         _ => Err(ImageError::FormatError(format!(
794             "Unsupported orientation {} {}",
795             limit_string_len(c1_tag, 4),
796             limit_string_len(c2_tag, 4)
797         ))),
798     } // final expression. Returns value
799 }
800 
801 trait IntoImageError<T> {
into_image_error(self, description: &str) -> ImageResult<T>802     fn into_image_error(self, description: &str) -> ImageResult<T>;
803 }
804 
805 impl<T> IntoImageError<T> for ::std::result::Result<T, ::std::num::ParseFloatError> {
into_image_error(self, description: &str) -> ImageResult<T>806     fn into_image_error(self, description: &str) -> ImageResult<T> {
807         self.map_err(|err| {
808             ImageError::FormatError(format!("{} {}", description, err))
809         })
810     }
811 }
812 
813 impl<T> IntoImageError<T> for ::std::result::Result<T, ::std::num::ParseIntError> {
into_image_error(self, description: &str) -> ImageResult<T>814     fn into_image_error(self, description: &str) -> ImageResult<T> {
815         self.map_err(|err| {
816             ImageError::FormatError(format!("{} {}", description, err))
817         })
818     }
819 }
820 
821 // Returns string with no more than len+3 characters
limit_string_len(s: &str, len: usize) -> String822 fn limit_string_len(s: &str, len: usize) -> String {
823     let s_char_len = s.chars().count();
824     if s_char_len > len {
825         s.chars().take(len).chain("...".chars()).collect()
826     } else {
827         s.into()
828     }
829 }
830 
831 // Splits string into (before separator, after separator) tuple
832 // or None if separator isn't found
split_at_first<'a>(s: &'a str, separator: &str) -> Option<(&'a str, &'a str)>833 fn split_at_first<'a>(s: &'a str, separator: &str) -> Option<(&'a str, &'a str)> {
834     match s.find(separator) {
835         None | Some(0) => None,
836         Some(p) if p >= s.len() - separator.len() => None,
837         Some(p) => Some((&s[..p], &s[(p + separator.len())..])),
838     }
839 }
840 
841 #[test]
split_at_first_test()842 fn split_at_first_test() {
843     assert_eq!(split_at_first(&Cow::Owned("".into()), "="), None);
844     assert_eq!(split_at_first(&Cow::Owned("=".into()), "="), None);
845     assert_eq!(split_at_first(&Cow::Owned("= ".into()), "="), None);
846     assert_eq!(
847         split_at_first(&Cow::Owned(" = ".into()), "="),
848         Some((" ", " "))
849     );
850     assert_eq!(
851         split_at_first(&Cow::Owned("EXPOSURE= ".into()), "="),
852         Some(("EXPOSURE", " "))
853     );
854     assert_eq!(
855         split_at_first(&Cow::Owned("EXPOSURE= =".into()), "="),
856         Some(("EXPOSURE", " ="))
857     );
858     assert_eq!(
859         split_at_first(&Cow::Owned("EXPOSURE== =".into()), "=="),
860         Some(("EXPOSURE", " ="))
861     );
862     assert_eq!(split_at_first(&Cow::Owned("EXPOSURE".into()), ""), None);
863 }
864 
865 // Reads input until b"\n" or EOF
866 // Returns vector of read bytes NOT including end of line characters
867 //   or return None to indicate end of file
read_line_u8<R: BufRead>(r: &mut R) -> ::std::io::Result<Option<Vec<u8>>>868 fn read_line_u8<R: BufRead>(r: &mut R) -> ::std::io::Result<Option<Vec<u8>>> {
869     let mut ret = Vec::with_capacity(16);
870     match r.read_until(b'\n', &mut ret) {
871         Ok(0) => Ok(None),
872         Ok(_) => {
873             if let Some(&b'\n') = ret[..].last() {
874                 let _ = ret.pop();
875             }
876             Ok(Some(ret))
877         }
878         Err(err) => Err(err),
879     }
880 }
881 
882 #[test]
read_line_u8_test()883 fn read_line_u8_test() {
884     let buf: Vec<_> = (&b"One\nTwo\nThree\nFour\n\n\n"[..]).into();
885     let input = &mut ::std::io::Cursor::new(buf);
886     assert_eq!(&read_line_u8(input).unwrap().unwrap()[..], &b"One"[..]);
887     assert_eq!(&read_line_u8(input).unwrap().unwrap()[..], &b"Two"[..]);
888     assert_eq!(&read_line_u8(input).unwrap().unwrap()[..], &b"Three"[..]);
889     assert_eq!(&read_line_u8(input).unwrap().unwrap()[..], &b"Four"[..]);
890     assert_eq!(&read_line_u8(input).unwrap().unwrap()[..], &b""[..]);
891     assert_eq!(&read_line_u8(input).unwrap().unwrap()[..], &b""[..]);
892     assert_eq!(read_line_u8(input).unwrap(), None);
893 }
894 
895 /// Helper function for reading raw 3-channel f32 images
read_raw_file<P: AsRef<Path>>(path: P) -> ::std::io::Result<Vec<Rgb<f32>>>896 pub fn read_raw_file<P: AsRef<Path>>(path: P) -> ::std::io::Result<Vec<Rgb<f32>>> {
897     use byteorder::{LittleEndian as LE, ReadBytesExt};
898     use std::fs::File;
899     use std::io::BufReader;
900 
901     let mut r = BufReader::new(File::open(path)?);
902     let w = r.read_u32::<LE>()? as usize;
903     let h = r.read_u32::<LE>()? as usize;
904     let c = r.read_u32::<LE>()? as usize;
905     assert_eq!(c, 3);
906     let cnt = w * h;
907     let mut ret = Vec::with_capacity(cnt);
908     for _ in 0..cnt {
909         let cr = r.read_f32::<LE>()?;
910         let cg = r.read_f32::<LE>()?;
911         let cb = r.read_f32::<LE>()?;
912         ret.push(Rgb([cr, cg, cb]));
913     }
914     Ok(ret)
915 }
916