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