|
pub mod file; |
|
pub mod tags; |
|
mod types; |
|
pub mod values; |
|
|
|
use file::TiffRead; |
|
use num_enum::{FromPrimitive, IntoPrimitive}; |
|
use std::fmt::Display; |
|
use std::io::{Read, Seek}; |
|
use tags::Tag; |
|
use thiserror::Error; |
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, IntoPrimitive)] |
|
#[repr(u16)] |
|
pub enum TagId { |
|
ImageWidth = 0x100, |
|
ImageLength = 0x101, |
|
BitsPerSample = 0x102, |
|
Compression = 0x103, |
|
PhotometricInterpretation = 0x104, |
|
Make = 0x10f, |
|
Model = 0x110, |
|
StripOffsets = 0x111, |
|
Orientation = 0x112, |
|
SamplesPerPixel = 0x115, |
|
RowsPerStrip = 0x116, |
|
StripByteCounts = 0x117, |
|
SubIfd = 0x14a, |
|
JpegOffset = 0x201, |
|
JpegLength = 0x202, |
|
SonyToneCurve = 0x7010, |
|
BlackLevel = 0x7310, |
|
WhiteBalanceRggbLevels = 0x7313, |
|
CfaPatternDim = 0x828d, |
|
CfaPattern = 0x828e, |
|
ColorMatrix1 = 0xc621, |
|
ColorMatrix2 = 0xc622, |
|
|
|
#[num_enum(catch_all)] |
|
Unknown(u16), |
|
} |
|
|
|
#[repr(u16)] |
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, IntoPrimitive)] |
|
pub enum IfdTagType { |
|
Byte = 1, |
|
Ascii = 2, |
|
Short = 3, |
|
Long = 4, |
|
Rational = 5, |
|
SByte = 6, |
|
Undefined = 7, |
|
SShort = 8, |
|
SLong = 9, |
|
SRational = 10, |
|
Float = 11, |
|
Double = 12, |
|
|
|
#[num_enum(catch_all)] |
|
Unknown(u16), |
|
} |
|
|
|
#[derive(Copy, Clone, Debug)] |
|
pub struct IfdEntry { |
|
tag: TagId, |
|
the_type: IfdTagType, |
|
count: u32, |
|
value: u32, |
|
} |
|
|
|
#[derive(Clone, Debug)] |
|
pub struct Ifd { |
|
current_ifd_offset: u32, |
|
ifd_entries: Vec<IfdEntry>, |
|
next_ifd_offset: Option<u32>, |
|
} |
|
|
|
impl Ifd { |
|
pub fn new_first_ifd<R: Read + Seek>(file: &mut TiffRead<R>) -> Result<Self, TiffError> { |
|
file.seek_from_start(4)?; |
|
let current_ifd_offset = file.read_u32()?; |
|
Ifd::new_from_offset(file, current_ifd_offset) |
|
} |
|
|
|
pub fn new_from_offset<R: Read + Seek>(file: &mut TiffRead<R>, offset: u32) -> Result<Self, TiffError> { |
|
if offset == 0 { |
|
return Err(TiffError::InvalidOffset); |
|
} |
|
|
|
file.seek_from_start(offset)?; |
|
let num = file.read_u16()?; |
|
|
|
let mut ifd_entries = Vec::with_capacity(num.into()); |
|
for _ in 0..num { |
|
let tag = file.read_u16()?.into(); |
|
let the_type = file.read_u16()?.into(); |
|
let count = file.read_u32()?; |
|
let value = file.read_u32()?; |
|
|
|
ifd_entries.push(IfdEntry { tag, the_type, count, value }); |
|
} |
|
|
|
let next_ifd_offset = file.read_u32()?; |
|
let next_ifd_offset = if next_ifd_offset == 0 { None } else { Some(next_ifd_offset) }; |
|
|
|
Ok(Ifd { |
|
current_ifd_offset: offset, |
|
ifd_entries, |
|
next_ifd_offset, |
|
}) |
|
} |
|
|
|
fn _next_ifd<R: Read + Seek>(&self, file: &mut TiffRead<R>) -> Result<Self, TiffError> { |
|
Ifd::new_from_offset(file, self.next_ifd_offset.unwrap_or(0)) |
|
} |
|
|
|
pub fn ifd_entries(&self) -> &[IfdEntry] { |
|
&self.ifd_entries |
|
} |
|
|
|
pub fn iter(&self) -> impl Iterator<Item = &IfdEntry> { |
|
self.ifd_entries.iter() |
|
} |
|
|
|
pub fn get_value<T: Tag, R: Read + Seek>(&self, file: &mut TiffRead<R>) -> Result<T::Output, TiffError> { |
|
T::get(self, file) |
|
} |
|
} |
|
|
|
impl Display for Ifd { |
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
|
f.write_str("IFD offset: ")?; |
|
self.current_ifd_offset.fmt(f)?; |
|
f.write_str("\n")?; |
|
|
|
for ifd_entry in self.ifd_entries() { |
|
f.write_fmt(format_args!( |
|
"|- Tag: {:x?}, Type: {:?}, Count: {}, Value: {:x}\n", |
|
ifd_entry.tag, ifd_entry.the_type, ifd_entry.count, ifd_entry.value |
|
))?; |
|
} |
|
|
|
f.write_str("Next IFD offset: ")?; |
|
if let Some(offset) = self.next_ifd_offset { |
|
offset.fmt(f)?; |
|
} else { |
|
f.write_str("None")?; |
|
} |
|
f.write_str("\n")?; |
|
|
|
Ok(()) |
|
} |
|
} |
|
|
|
#[derive(Error, Debug)] |
|
pub enum TiffError { |
|
#[error("The value was invalid")] |
|
InvalidValue, |
|
#[error("The type was invalid")] |
|
InvalidType, |
|
#[error("The count was invalid")] |
|
InvalidCount, |
|
#[error("The tag was missing")] |
|
MissingTag, |
|
#[error("The offset was invalid or zero")] |
|
InvalidOffset, |
|
#[error("An error occurred when converting integer from one type to another")] |
|
ConversionError(#[from] std::num::TryFromIntError), |
|
#[error("An IO Error ocurred")] |
|
IoError(#[from] std::io::Error), |
|
} |
|
|