Raw-rs: make decoder for ARW1 and ARW2 formats (#1775)

* convert Tag into a trait

* Create ARW 1 decoder

* add decoder for sony tone curve table

* create decoder for arw 2.1 format

* add windsock.arw to the tests

* create derive macro for Tag and use it in decoders

* add license to tag-derive

* add code to identify model

* impl Display for Ifd

* Code review

* Fix type variable name

* Fix compilation

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Elbert Ronnie
2024-06-28 03:23:05 -07:00
committed by GitHub
co-authored by Keavon Chambers
parent c9a33e44bd
commit fd3613018a
16 changed files with 720 additions and 160 deletions
+51 -22
View File
@@ -4,13 +4,13 @@ mod types;
pub mod values;
use file::TiffRead;
use num_enum::{FromPrimitive, IntoPrimitive, TryFromPrimitive};
use tags::Tag;
use num_enum::{FromPrimitive, IntoPrimitive};
use std::fmt::Display;
use std::io::{Read, Seek};
use thiserror::Error;
use tags::Tag;
use types::TagType;
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
#[repr(u16)]
pub enum TagId {
@@ -19,6 +19,8 @@ pub enum TagId {
BitsPerSample = 0x102,
Compression = 0x103,
PhotometricInterpretation = 0x104,
Make = 0x10f,
Model = 0x110,
StripOffsets = 0x111,
SamplesPerPixel = 0x115,
RowsPerStrip = 0x116,
@@ -26,6 +28,7 @@ pub enum TagId {
SubIfd = 0x14a,
JpegOffset = 0x201,
JpegLength = 0x202,
SonyToneCurve = 0x7010,
CfaPatternDim = 0x828d,
CfaPattern = 0x828e,
@@ -34,26 +37,29 @@ pub enum TagId {
}
#[repr(u16)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
pub enum IfdTagType {
Ascii = 2,
Byte = 1,
Ascii = 2,
Short = 3,
Long = 4,
Rational = 5,
SByte = 6,
Undefined = 7,
SShort = 8,
SLong = 9,
SRational = 10,
Float = 11,
Double = 12,
Undefined = 7,
#[num_enum(catch_all)]
Unknown(u16),
}
#[derive(Copy, Clone, Debug)]
pub struct IfdEntry {
tag: TagId,
type_: u16,
the_type: IfdTagType,
count: u32,
value: u32,
}
@@ -66,15 +72,15 @@ pub struct Ifd {
}
impl Ifd {
pub fn new_first_ifd<R: Read + Seek>(file: &mut TiffRead<R>) -> std::io::Result<Self> {
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) -> std::io::Result<Self> {
pub fn new_from_offset<R: Read + Seek>(file: &mut TiffRead<R>, offset: u32) -> Result<Self, TiffError> {
if offset == 0 {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "Ifd at offset zero does not exist"));
return Err(TiffError::InvalidOffset);
}
file.seek_from_start(offset)?;
@@ -83,15 +89,15 @@ impl Ifd {
let mut ifd_entries = Vec::with_capacity(num.into());
for _ in 0..num {
let tag = file.read_u16()?.into();
let type_ = file.read_u16()?;
let the_type = file.read_u16()?.into();
let count = file.read_u32()?;
let value = file.read_u32()?;
ifd_entries.push(IfdEntry { tag, type_, count, value });
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 { Some(next_ifd_offset) } else { None };
let next_ifd_offset = if next_ifd_offset == 0 { None } else { Some(next_ifd_offset) };
Ok(Ifd {
current_ifd_offset: offset,
@@ -100,7 +106,7 @@ impl Ifd {
})
}
fn next_ifd<R: Read + Seek>(&self, file: &mut TiffRead<R>) -> std::io::Result<Self> {
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))
}
@@ -112,12 +118,33 @@ impl Ifd {
self.ifd_entries.iter()
}
pub fn get<T: TagType, R: Read + Seek>(&self, tag: Tag<T>, file: &mut TiffRead<R>) -> Result<T::Output, TiffError> {
let tag_id = tag.id();
let index: u32 = self.iter().position(|x| x.tag == tag_id).ok_or(TiffError::InvalidTag)?.try_into()?;
pub fn get_value<T: Tag, R: Read + Seek>(&self, file: &mut TiffRead<R>) -> Result<T::Output, TiffError> {
T::get(self, file)
}
}
file.seek_from_start(self.current_ifd_offset + 2 + 12 * index + 2)?;
T::read(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(())
}
}
@@ -129,8 +156,10 @@ pub enum TiffError {
InvalidType,
#[error("The count was invalid")]
InvalidCount,
#[error("The tag was invalid")]
InvalidTag,
#[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")]