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
+7 -3
View File
@@ -1,7 +1,7 @@
use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum Endian {
pub enum Endian {
Little,
Big,
}
@@ -15,7 +15,7 @@ impl<R: Read + Seek> TiffRead<R> {
pub fn new(mut reader: R) -> Result<Self> {
let error = Error::new(ErrorKind::InvalidData, "Invalid Tiff format");
let mut data = [0u8; 2];
let mut data = [0_u8; 2];
reader.read_exact(&mut data)?;
let endian = if data[0] == 0x49 && data[1] == 0x49 {
Endian::Little
@@ -36,6 +36,10 @@ impl<R: Read + Seek> TiffRead<R> {
Ok(Self { reader, endian })
}
pub fn endian(&self) -> Endian {
self.endian
}
}
impl<R: Read + Seek> Read for TiffRead<R> {
@@ -61,7 +65,7 @@ impl<R: Read + Seek> TiffRead<R> {
}
pub fn read_n<const N: usize>(&mut self) -> Result<[u8; N]> {
let mut data = [0u8; N];
let mut data = [0_u8; N];
self.read_exact(&mut data)?;
Ok(data)
}
+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")]
+182 -35
View File
@@ -1,41 +1,188 @@
use super::types::{Array, ConstArray, TagType, TypeByte, TypeIfd, TypeLong, TypeNumber, TypeShort};
use super::TagId;
use super::types::{Array, ConstArray, TagType, TypeByte, TypeIfd, TypeLong, TypeNumber, TypeShort, TypeSonyToneCurve, TypeString};
use super::{Ifd, TagId, TiffError, TiffRead};
pub struct Tag<T: TagType> {
tag_id: TagId,
name: &'static str,
tag_type: std::marker::PhantomData<T>,
use std::io::{Read, Seek};
pub trait SimpleTag {
type Type: TagType;
const ID: TagId;
const NAME: &'static str;
}
impl<T: TagType> Tag<T> {
const fn new(tag_id: TagId, name: &'static str) -> Self {
Tag {
tag_id,
name,
tag_type: std::marker::PhantomData,
pub struct ImageWidth;
pub struct ImageLength;
pub struct BitsPerSample;
pub struct Compression;
pub struct PhotometricInterpretation;
pub struct Make;
pub struct Model;
pub struct StripOffsets;
pub struct SamplesPerPixel;
pub struct RowsPerStrip;
pub struct StripByteCounts;
pub struct SubIfd;
pub struct JpegOffset;
pub struct JpegLength;
pub struct CfaPatternDim;
pub struct CfaPattern;
pub struct SonyDataOffset;
pub struct SonyToneCurve;
impl SimpleTag for ImageWidth {
type Type = TypeNumber;
const ID: TagId = TagId::ImageWidth;
const NAME: &'static str = "Image Width";
}
impl SimpleTag for ImageLength {
type Type = TypeNumber;
const ID: TagId = TagId::ImageLength;
const NAME: &'static str = "Image Length";
}
impl SimpleTag for BitsPerSample {
type Type = TypeShort;
const ID: TagId = TagId::BitsPerSample;
const NAME: &'static str = "Bits per Sample";
}
impl SimpleTag for Compression {
type Type = TypeShort;
const ID: TagId = TagId::Compression;
const NAME: &'static str = "Compression";
}
impl SimpleTag for PhotometricInterpretation {
type Type = TypeShort;
const ID: TagId = TagId::PhotometricInterpretation;
const NAME: &'static str = "Photometric Interpretation";
}
impl SimpleTag for Make {
type Type = TypeString;
const ID: TagId = TagId::Make;
const NAME: &'static str = "Make";
}
impl SimpleTag for Model {
type Type = TypeString;
const ID: TagId = TagId::Model;
const NAME: &'static str = "Model";
}
impl SimpleTag for StripOffsets {
type Type = Array<TypeNumber>;
const ID: TagId = TagId::StripOffsets;
const NAME: &'static str = "Strip Offsets";
}
impl SimpleTag for SamplesPerPixel {
type Type = TypeShort;
const ID: TagId = TagId::SamplesPerPixel;
const NAME: &'static str = "Samples per Pixel";
}
impl SimpleTag for RowsPerStrip {
type Type = TypeNumber;
const ID: TagId = TagId::RowsPerStrip;
const NAME: &'static str = "Rows per Strip";
}
impl SimpleTag for StripByteCounts {
type Type = Array<TypeNumber>;
const ID: TagId = TagId::StripByteCounts;
const NAME: &'static str = "Strip Byte Counts";
}
impl SimpleTag for SubIfd {
type Type = TypeIfd;
const ID: TagId = TagId::SubIfd;
const NAME: &'static str = "SubIFD";
}
impl SimpleTag for JpegOffset {
type Type = TypeLong;
const ID: TagId = TagId::JpegOffset;
const NAME: &'static str = "Jpeg Offset";
}
impl SimpleTag for JpegLength {
type Type = TypeLong;
const ID: TagId = TagId::JpegLength;
const NAME: &'static str = "Jpeg Length";
}
impl SimpleTag for CfaPatternDim {
type Type = ConstArray<TypeShort, 2>;
const ID: TagId = TagId::CfaPatternDim;
const NAME: &'static str = "CFA Pattern Dimension";
}
impl SimpleTag for CfaPattern {
type Type = Array<TypeByte>;
const ID: TagId = TagId::CfaPattern;
const NAME: &'static str = "CFA Pattern";
}
impl SimpleTag for SonyDataOffset {
type Type = TypeLong;
const ID: TagId = TagId::SubIfd;
const NAME: &'static str = "Sony Data Offset";
}
impl SimpleTag for SonyToneCurve {
type Type = TypeSonyToneCurve;
const ID: TagId = TagId::SonyToneCurve;
const NAME: &'static str = "Sony Tone Curve";
}
pub trait Tag {
type Output;
fn get<R: Read + Seek>(ifd: &Ifd, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError>;
}
impl<T: SimpleTag> Tag for T {
type Output = <T::Type as TagType>::Output;
fn get<R: Read + Seek>(ifd: &Ifd, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let tag_id = T::ID;
let index: u32 = ifd.iter().position(|x| x.tag == tag_id).ok_or(TiffError::MissingTag)?.try_into()?;
file.seek_from_start(ifd.current_ifd_offset + 2 + 12 * index + 2)?;
T::Type::read(file)
}
}
impl<T: Tag> Tag for Option<T> {
type Output = Option<T::Output>;
fn get<R: Read + Seek>(ifd: &Ifd, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let result = T::get(ifd, file);
match result {
Err(TiffError::MissingTag) => Ok(None),
Ok(x) => Ok(Some(x)),
Err(x) => Err(x),
}
}
pub fn id(&self) -> TagId {
self.tag_id
}
pub fn name(&self) -> &'static str {
self.name
}
}
pub const IMAGE_WIDTH: Tag<TypeNumber> = Tag::new(TagId::ImageWidth, "Image Width");
pub const IMAGE_LENGTH: Tag<TypeNumber> = Tag::new(TagId::ImageLength, "Image Length");
pub const BITS_PER_SAMPLE: Tag<TypeShort> = Tag::new(TagId::BitsPerSample, "Bits per Sample");
pub const COMPRESSION: Tag<TypeShort> = Tag::new(TagId::Compression, "Compression");
pub const PHOTOMETRIC_INTERPRETATION: Tag<TypeShort> = Tag::new(TagId::PhotometricInterpretation, "Photometric Interpretation");
pub const STRIP_OFFSETS: Tag<Array<TypeNumber>> = Tag::new(TagId::StripOffsets, "Strip Offsets");
pub const SAMPLES_PER_PIXEL: Tag<TypeShort> = Tag::new(TagId::SamplesPerPixel, "Samples per Pixel");
pub const ROWS_PER_STRIP: Tag<TypeNumber> = Tag::new(TagId::RowsPerStrip, "Rows per Strip");
pub const STRIP_BYTE_COUNTS: Tag<Array<TypeNumber>> = Tag::new(TagId::StripByteCounts, "Strip Byte Counts");
pub const SUBIFD: Tag<TypeIfd> = Tag::new(TagId::SubIfd, "SubIFD");
pub const JPEG_OFFSET: Tag<TypeLong> = Tag::new(TagId::JpegOffset, "Jpeg Offset");
pub const JPEG_LENGTH: Tag<TypeLong> = Tag::new(TagId::JpegLength, "Jpeg Length");
pub const CFA_PATTERN_DIM: Tag<ConstArray<TypeShort, 2>> = Tag::new(TagId::CfaPatternDim, "CFA Pattern Dimension");
pub const CFA_PATTERN: Tag<Array<TypeByte>> = Tag::new(TagId::CfaPattern, "CFA Pattern");
+88 -67
View File
@@ -1,7 +1,7 @@
use std::io::{Read, Seek};
use super::file::TiffRead;
use super::values::Rational;
use super::values::{CurveLookupTable, Rational};
use super::{Ifd, IfdTagType, TiffError};
pub struct TypeAscii;
@@ -24,16 +24,16 @@ pub struct TypeIfd;
pub trait PrimitiveType {
type Output;
fn get_size(type_: IfdTagType) -> Option<u32>;
fn get_size(the_type: IfdTagType) -> Option<u32>;
fn read_primitive<R: Read + Seek>(type_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError>;
fn read_primitive<R: Read + Seek>(the_type: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError>;
}
impl PrimitiveType for TypeAscii {
type Output = char;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::Ascii => Some(1),
_ => None,
}
@@ -52,8 +52,8 @@ impl PrimitiveType for TypeAscii {
impl PrimitiveType for TypeByte {
type Output = u8;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::Byte => Some(1),
_ => None,
}
@@ -67,8 +67,8 @@ impl PrimitiveType for TypeByte {
impl PrimitiveType for TypeShort {
type Output = u16;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::Short => Some(2),
_ => None,
}
@@ -82,8 +82,8 @@ impl PrimitiveType for TypeShort {
impl PrimitiveType for TypeLong {
type Output = u32;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::Long => Some(4),
_ => None,
}
@@ -97,16 +97,16 @@ impl PrimitiveType for TypeLong {
impl PrimitiveType for TypeRational {
type Output = Rational<u32>;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::Rational => Some(8),
_ => None,
}
}
fn read_primitive<R: Read + Seek>(type_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let numerator = TypeLong::read_primitive(type_, file)?;
let denominator = TypeLong::read_primitive(type_, file)?;
fn read_primitive<R: Read + Seek>(the_type: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let numerator = TypeLong::read_primitive(the_type, file)?;
let denominator = TypeLong::read_primitive(the_type, file)?;
Ok(Rational { numerator, denominator })
}
@@ -115,8 +115,8 @@ impl PrimitiveType for TypeRational {
impl PrimitiveType for TypeSByte {
type Output = i8;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::SByte => Some(1),
_ => None,
}
@@ -130,8 +130,8 @@ impl PrimitiveType for TypeSByte {
impl PrimitiveType for TypeSShort {
type Output = i16;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::SShort => Some(2),
_ => None,
}
@@ -145,8 +145,8 @@ impl PrimitiveType for TypeSShort {
impl PrimitiveType for TypeSLong {
type Output = i32;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::SLong => Some(4),
_ => None,
}
@@ -160,16 +160,16 @@ impl PrimitiveType for TypeSLong {
impl PrimitiveType for TypeSRational {
type Output = Rational<i32>;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::SRational => Some(8),
_ => None,
}
}
fn read_primitive<R: Read + Seek>(type_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let numerator = TypeSLong::read_primitive(type_, file)?;
let denominator = TypeSLong::read_primitive(type_, file)?;
fn read_primitive<R: Read + Seek>(the_type: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let numerator = TypeSLong::read_primitive(the_type, file)?;
let denominator = TypeSLong::read_primitive(the_type, file)?;
Ok(Rational { numerator, denominator })
}
@@ -178,8 +178,8 @@ impl PrimitiveType for TypeSRational {
impl PrimitiveType for TypeFloat {
type Output = f32;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::Float => Some(4),
_ => None,
}
@@ -193,8 +193,8 @@ impl PrimitiveType for TypeFloat {
impl PrimitiveType for TypeDouble {
type Output = f64;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::Double => Some(8),
_ => None,
}
@@ -220,20 +220,20 @@ impl PrimitiveType for TypeUndefined {
impl PrimitiveType for TypeNumber {
type Output = u32;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
IfdTagType::Byte => TypeByte::get_size(type_),
IfdTagType::Short => TypeShort::get_size(type_),
IfdTagType::Long => TypeLong::get_size(type_),
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::Byte => TypeByte::get_size(the_type),
IfdTagType::Short => TypeShort::get_size(the_type),
IfdTagType::Long => TypeLong::get_size(the_type),
_ => None,
}
}
fn read_primitive<R: Read + Seek>(type_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
Ok(match type_ {
IfdTagType::Byte => TypeByte::read_primitive(type_, file)?.into(),
IfdTagType::Short => TypeShort::read_primitive(type_, file)?.into(),
IfdTagType::Long => TypeLong::read_primitive(type_, file)?,
fn read_primitive<R: Read + Seek>(the_type: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
Ok(match the_type {
IfdTagType::Byte => TypeByte::read_primitive(the_type, file)?.into(),
IfdTagType::Short => TypeShort::read_primitive(the_type, file)?.into(),
IfdTagType::Long => TypeLong::read_primitive(the_type, file)?,
_ => unreachable!(),
})
}
@@ -242,20 +242,20 @@ impl PrimitiveType for TypeNumber {
impl PrimitiveType for TypeSNumber {
type Output = i32;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
IfdTagType::SByte => TypeSByte::get_size(type_),
IfdTagType::SShort => TypeSShort::get_size(type_),
IfdTagType::SLong => TypeSLong::get_size(type_),
fn get_size(the_type: IfdTagType) -> Option<u32> {
match the_type {
IfdTagType::SByte => TypeSByte::get_size(the_type),
IfdTagType::SShort => TypeSShort::get_size(the_type),
IfdTagType::SLong => TypeSLong::get_size(the_type),
_ => None,
}
}
fn read_primitive<R: Read + Seek>(type_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
Ok(match type_ {
IfdTagType::SByte => TypeSByte::read_primitive(type_, file)?.into(),
IfdTagType::SShort => TypeSShort::read_primitive(type_, file)?.into(),
IfdTagType::SLong => TypeSLong::read_primitive(type_, file)?,
fn read_primitive<R: Read + Seek>(the_type: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
Ok(match the_type {
IfdTagType::SByte => TypeSByte::read_primitive(the_type, file)?.into(),
IfdTagType::SShort => TypeSShort::read_primitive(the_type, file)?.into(),
IfdTagType::SLong => TypeSLong::read_primitive(the_type, file)?,
_ => unreachable!(),
})
}
@@ -264,15 +264,12 @@ impl PrimitiveType for TypeSNumber {
impl PrimitiveType for TypeIfd {
type Output = Ifd;
fn get_size(type_: IfdTagType) -> Option<u32> {
match type_ {
IfdTagType::Long => Some(4),
_ => None,
}
fn get_size(the_type: IfdTagType) -> Option<u32> {
TypeLong::get_size(the_type)
}
fn read_primitive<R: Read + Seek>(type_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let offset = TypeLong::read_primitive(type_, file)?;
fn read_primitive<R: Read + Seek>(the_type: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let offset = TypeLong::read_primitive(the_type, file)?;
Ok(Ifd::new_from_offset(file, offset)?)
}
}
@@ -287,20 +284,20 @@ impl<T: PrimitiveType> TagType for T {
type Output = T::Output;
fn read<R: Read + Seek>(file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let type_ = IfdTagType::try_from(file.read_u16()?).map_err(|_| TiffError::InvalidType)?;
let the_type = IfdTagType::try_from(file.read_u16()?).map_err(|_| TiffError::InvalidType)?;
let count = file.read_u32()?;
if count != 1 {
return Err(TiffError::InvalidCount);
}
let size = T::get_size(type_).ok_or(TiffError::InvalidType)?;
let size = T::get_size(the_type).ok_or(TiffError::InvalidType)?;
if count * size > 4 {
let offset = file.read_u32()?;
file.seek_from_start(offset)?;
}
T::read_primitive(type_, file)
T::read_primitive(the_type, file)
}
}
@@ -316,10 +313,10 @@ impl<T: PrimitiveType> TagType for Array<T> {
type Output = Vec<T::Output>;
fn read<R: Read + Seek>(file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let type_ = IfdTagType::try_from(file.read_u16()?).map_err(|_| TiffError::InvalidType)?;
let the_type = IfdTagType::try_from(file.read_u16()?).map_err(|_| TiffError::InvalidType)?;
let count = file.read_u32()?;
let size = T::get_size(type_).ok_or(TiffError::InvalidType)?;
let size = T::get_size(the_type).ok_or(TiffError::InvalidType)?;
if count * size > 4 {
let offset = file.read_u32()?;
file.seek_from_start(offset)?;
@@ -327,7 +324,7 @@ impl<T: PrimitiveType> TagType for Array<T> {
let mut ans = Vec::with_capacity(count.try_into()?);
for _ in 0..count {
ans.push(T::read_primitive(type_, file)?);
ans.push(T::read_primitive(the_type, file)?);
}
Ok(ans)
}
@@ -337,14 +334,14 @@ impl<T: PrimitiveType, const N: usize> TagType for ConstArray<T, N> {
type Output = [T::Output; N];
fn read<R: Read + Seek>(file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let type_ = IfdTagType::try_from(file.read_u16()?).map_err(|_| TiffError::InvalidType)?;
let the_type = IfdTagType::try_from(file.read_u16()?).map_err(|_| TiffError::InvalidType)?;
let count = file.read_u32()?;
if count != N.try_into()? {
return Err(TiffError::InvalidCount);
}
let size = T::get_size(type_).ok_or(TiffError::InvalidType)?;
let size = T::get_size(the_type).ok_or(TiffError::InvalidType)?;
if count * size > 4 {
let offset = file.read_u32()?;
file.seek_from_start(offset)?;
@@ -352,8 +349,32 @@ impl<T: PrimitiveType, const N: usize> TagType for ConstArray<T, N> {
let mut ans = Vec::with_capacity(count.try_into()?);
for _ in 0..count {
ans.push(T::read_primitive(type_, file)?);
ans.push(T::read_primitive(the_type, file)?);
}
ans.try_into().map_err(|_| TiffError::InvalidCount)
}
}
pub struct TypeString;
pub struct TypeSonyToneCurve;
impl TagType for TypeString {
type Output = String;
fn read<R: Read + Seek>(file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let string = Array::<TypeAscii>::read(file)?;
// Skip the NUL character at the end
let len = string.len();
Ok(string.into_iter().take(len - 1).collect())
}
}
impl TagType for TypeSonyToneCurve {
type Output = CurveLookupTable;
fn read<R: Read + Seek>(file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
let values = ConstArray::<TypeShort, 4>::read(file)?;
Ok(CurveLookupTable::from_sony_tone_table(values))
}
}
+26
View File
@@ -2,3 +2,29 @@ pub struct Rational<T> {
pub numerator: T,
pub denominator: T,
}
pub struct CurveLookupTable {
table: Vec<u16>,
}
impl CurveLookupTable {
pub fn from_sony_tone_table(values: [u16; 4]) -> CurveLookupTable {
let mut sony_curve = [0, 0, 0, 0, 0, 4095];
for i in 0..4 {
sony_curve[i + 1] = values[i] >> 2 & 0xfff;
}
let mut table = vec![0_u16; (sony_curve[5] + 1).into()];
for i in 0..5 {
for j in (sony_curve[i] + 1)..=sony_curve[i + 1] {
table[j as usize] = table[(j - 1) as usize] + (1 << i);
}
}
CurveLookupTable { table }
}
pub fn get(&self, x: usize) -> u16 {
self.table[x]
}
}