1use std::io::{BufRead, Seek};
2
3use crate::errors::{ImageError, ImageResult};
4use crate::types::{Color, Dimensions, Format, ImageMeta};
5
6const SIGNATURE: [u8; 11] = [
7 0x23, 0x3f, 0x52, 0x41, 0x44, 0x49, 0x41, 0x4e, 0x43, 0x45, 0x0a,
8];
9
10pub fn load<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResult<ImageMeta> {
11 read_signature(image)?;
12
13 let (dimensions, color) = read_header(image)?;
14
15 Ok(ImageMeta {
16 animation_frames: None,
17 color,
18 dimensions,
19 format: Format::Hdr,
20 })
21}
22
23fn read_signature<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResult {
24 let mut signature = [0u8; 11];
25 image.read_exact(&mut signature)?;
26 if SIGNATURE != signature {
27 return Err(ImageError::InvalidSignature);
28 }
29 Ok(())
30}
31
32fn read_header<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResult<(Dimensions, Color)> {
33 use crate::types::ColorMode::*;
34
35 let color = Color {
36 mode: Rgb,
37 alpha_channel: false,
38 resolution: 32,
39 };
40 while let Some(Ok(line)) = image.lines().next() {
41 if line.starts_with('#') || line.is_empty() {
43 continue;
44 }
45
46 if let Some((key, value)) = line.split_once("=") {
48 match key {
49 "FORMAT" => match value {
50 "32-bit_rle_rgbe" => {}
51 "32-bit_rle_xyze" => {}
52 _ => {
53 return Err(ImageError::CorruptImage(
54 format!("Unsupported format: {}", value).into(),
55 ));
56 }
57 },
58 "PRIMARIES" => {}
59 _ => {}
60 }
61 }
62 else {
64 let mut iter = line.split_whitespace();
65 let c1_tag = iter
66 .next()
67 .ok_or(ImageError::CorruptImage("Error parsing dimension".into()))?;
68 let c1_str = iter
69 .next()
70 .ok_or(ImageError::CorruptImage("Error parsing dimension".into()))?;
71 let c2_tag = iter
72 .next()
73 .ok_or(ImageError::CorruptImage("Error parsing dimension".into()))?;
74 let c2_str = iter
75 .next()
76 .ok_or(ImageError::CorruptImage("Error parsing dimension".into()))?;
77 match (c1_tag, c2_tag) {
78 ("-Y", "+X") => {
79 let height = c1_str.parse::<u32>().map_err(|err| {
82 ImageError::CorruptImage(format!("Error parsing height: {err}").into())
83 })?;
84 let width = c2_str.parse::<u32>().map_err(|err| {
85 ImageError::CorruptImage(format!("Error parsing width: {err}").into())
86 })?;
87 return Ok((Dimensions { width, height }, color));
88 }
89 _ => return Err(ImageError::Unsupported),
90 }
91 }
92 }
93 Err(ImageError::Unsupported)
94}