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