| 1 | use std::io::{self, BufRead, Seek, SeekFrom}; |
| 2 | |
| 3 | use crate::{ |
| 4 | util::{read_i32, read_null_terminated_string, read_u32, Endian}, |
| 5 | ImageResult, ImageSize, |
| 6 | }; |
| 7 | |
| 8 | pub 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 | |
| 52 | pub 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 | |