1use std::io::{self, BufRead, Seek, SeekFrom};
2
3use crate::{
4 util::{read_i32, read_null_terminated_string, read_u32, Endian},
5 ImageResult, ImageSize,
6};
7
8pub fn size<R: BufRead + Seek>(reader: &mut R) -> ImageResult<ImageSize> {
9 reader.seek(SeekFrom::Start(4))?;
10
11 // If long names flag is set then max attribute name and type name is 255, otherwise it's only 31
12 let flags = read_u32(reader, &Endian::Little)?;
13 let long_names = flags & 0x400 != 0;
14 let max_name_size = if long_names { 255 } else { 31 };
15
16 // Read header attributes until we find the dataWindow attribute
17 loop {
18 let attr_name = read_null_terminated_string(reader, max_name_size)?;
19 if attr_name.is_empty() {
20 break; // End of the header
21 }
22
23 let attr_type = read_null_terminated_string(reader, max_name_size)?;
24
25 // Skip attr_size
26 let attr_size = read_u32(reader, &Endian::Little)?;
27
28 if attr_name == "dataWindow" && attr_type == "box2i" {
29 // Read the data window values
30 let x_min = read_i32(reader, &Endian::Little)? as i64;
31 let y_min = read_i32(reader, &Endian::Little)? as i64;
32 let x_max = read_i32(reader, &Endian::Little)? as i64;
33 let y_max = read_i32(reader, &Endian::Little)? as i64;
34
35 if x_min > x_max || y_min > y_max {
36 continue;
37 }
38
39 let width = (x_max - x_min + 1) as usize;
40 let height = (y_max - y_min + 1) as usize;
41
42 return Ok(ImageSize { width, height });
43 } else {
44 // Skip the attribute value
45 reader.seek(SeekFrom::Current(attr_size as i64))?;
46 }
47 }
48
49 Err(io::Error::new(io::ErrorKind::InvalidData, "Data window not found").into())
50}
51
52pub fn matches(header: &[u8]) -> bool {
53 let exr_magic_number: [u8; 4] = [0x76, 0x2f, 0x31, 0x01];
54 header.starts_with(&exr_magic_number)
55}
56