mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 02:48:12 +08:00
Rename Raw-rs to Rawkit (#2088)
* Rename within files * Rename in CI * Rename the folder and file names * Rename raw_rs to rawkit * Add example to README * Add initial documentation * Small API changes and extra documentation * Bump versions and stuff * Readme improvements * Merge proc-macro crates into one * Add README to rawkit-proc-macros * Remove keywords and categories * Add licenses to rawkit-proc-macros --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
152
libraries/rawkit/src/tiff/file.rs
Normal file
152
libraries/rawkit/src/tiff/file.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum Endian {
|
||||
Little,
|
||||
Big,
|
||||
}
|
||||
|
||||
pub struct TiffRead<R: Read + Seek> {
|
||||
reader: R,
|
||||
endian: Endian,
|
||||
}
|
||||
|
||||
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 = [0_u8; 2];
|
||||
reader.read_exact(&mut data)?;
|
||||
let endian = if data[0] == 0x49 && data[1] == 0x49 {
|
||||
Endian::Little
|
||||
} else if data[0] == 0x4d && data[1] == 0x4d {
|
||||
Endian::Big
|
||||
} else {
|
||||
return Err(error);
|
||||
};
|
||||
|
||||
reader.read_exact(&mut data)?;
|
||||
let magic_number = match endian {
|
||||
Endian::Little => u16::from_le_bytes(data),
|
||||
Endian::Big => u16::from_be_bytes(data),
|
||||
};
|
||||
if magic_number != 42 {
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
Ok(Self { reader, endian })
|
||||
}
|
||||
|
||||
pub fn endian(&self) -> Endian {
|
||||
self.endian
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> Read for TiffRead<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
self.reader.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> Seek for TiffRead<R> {
|
||||
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
|
||||
self.reader.seek(pos)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> TiffRead<R> {
|
||||
pub fn seek_from_start(&mut self, offset: u32) -> Result<u64> {
|
||||
self.reader.seek(SeekFrom::Start(offset.into()))
|
||||
}
|
||||
|
||||
pub fn read_ascii(&mut self) -> Result<char> {
|
||||
let data = self.read_n::<1>()?;
|
||||
Ok(data[0] as char)
|
||||
}
|
||||
|
||||
pub fn read_n<const N: usize>(&mut self) -> Result<[u8; N]> {
|
||||
let mut data = [0_u8; N];
|
||||
self.read_exact(&mut data)?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn read_u8(&mut self) -> Result<u8> {
|
||||
let data = self.read_n()?;
|
||||
match self.endian {
|
||||
Endian::Little => Ok(u8::from_le_bytes(data)),
|
||||
Endian::Big => Ok(u8::from_be_bytes(data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_u16(&mut self) -> Result<u16> {
|
||||
let data = self.read_n()?;
|
||||
match self.endian {
|
||||
Endian::Little => Ok(u16::from_le_bytes(data)),
|
||||
Endian::Big => Ok(u16::from_be_bytes(data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_u32(&mut self) -> Result<u32> {
|
||||
let data = self.read_n()?;
|
||||
match self.endian {
|
||||
Endian::Little => Ok(u32::from_le_bytes(data)),
|
||||
Endian::Big => Ok(u32::from_be_bytes(data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_u64(&mut self) -> Result<u64> {
|
||||
let data = self.read_n()?;
|
||||
match self.endian {
|
||||
Endian::Little => Ok(u64::from_le_bytes(data)),
|
||||
Endian::Big => Ok(u64::from_be_bytes(data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_i8(&mut self) -> Result<i8> {
|
||||
let data = self.read_n()?;
|
||||
match self.endian {
|
||||
Endian::Little => Ok(i8::from_le_bytes(data)),
|
||||
Endian::Big => Ok(i8::from_be_bytes(data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_i16(&mut self) -> Result<i16> {
|
||||
let data = self.read_n()?;
|
||||
match self.endian {
|
||||
Endian::Little => Ok(i16::from_le_bytes(data)),
|
||||
Endian::Big => Ok(i16::from_be_bytes(data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_i32(&mut self) -> Result<i32> {
|
||||
let data = self.read_n()?;
|
||||
match self.endian {
|
||||
Endian::Little => Ok(i32::from_le_bytes(data)),
|
||||
Endian::Big => Ok(i32::from_be_bytes(data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_i64(&mut self) -> Result<i64> {
|
||||
let data = self.read_n()?;
|
||||
match self.endian {
|
||||
Endian::Little => Ok(i64::from_le_bytes(data)),
|
||||
Endian::Big => Ok(i64::from_be_bytes(data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_f32(&mut self) -> Result<f32> {
|
||||
let data = self.read_n()?;
|
||||
match self.endian {
|
||||
Endian::Little => Ok(f32::from_le_bytes(data)),
|
||||
Endian::Big => Ok(f32::from_be_bytes(data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_f64(&mut self) -> Result<f64> {
|
||||
let data = self.read_n()?;
|
||||
match self.endian {
|
||||
Endian::Little => Ok(f64::from_le_bytes(data)),
|
||||
Endian::Big => Ok(f64::from_be_bytes(data)),
|
||||
}
|
||||
}
|
||||
}
|
||||
172
libraries/rawkit/src/tiff/mod.rs
Normal file
172
libraries/rawkit/src/tiff/mod.rs
Normal file
@@ -0,0 +1,172 @@
|
||||
pub mod file;
|
||||
pub mod tags;
|
||||
mod types;
|
||||
pub mod values;
|
||||
|
||||
use file::TiffRead;
|
||||
use tags::Tag;
|
||||
|
||||
use num_enum::{FromPrimitive, IntoPrimitive};
|
||||
use std::fmt::Display;
|
||||
use std::io::{Read, Seek};
|
||||
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),
|
||||
}
|
||||
228
libraries/rawkit/src/tiff/tags.rs
Normal file
228
libraries/rawkit/src/tiff/tags.rs
Normal file
@@ -0,0 +1,228 @@
|
||||
use super::types::{Array, ConstArray, TagType, TypeByte, TypeIfd, TypeLong, TypeNumber, TypeOrientation, TypeSRational, TypeSShort, TypeShort, TypeSonyToneCurve, TypeString};
|
||||
use super::{Ifd, TagId, TiffError, TiffRead};
|
||||
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
pub trait SimpleTag {
|
||||
type Type: TagType;
|
||||
|
||||
const ID: TagId;
|
||||
const NAME: &'static str;
|
||||
}
|
||||
|
||||
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 Orientation;
|
||||
pub struct SamplesPerPixel;
|
||||
pub struct RowsPerStrip;
|
||||
pub struct StripByteCounts;
|
||||
pub struct SubIfd;
|
||||
pub struct JpegOffset;
|
||||
pub struct JpegLength;
|
||||
pub struct SonyDataOffset;
|
||||
pub struct SonyToneCurve;
|
||||
pub struct BlackLevel;
|
||||
pub struct WhiteBalanceRggbLevels;
|
||||
pub struct CfaPatternDim;
|
||||
pub struct CfaPattern;
|
||||
pub struct ColorMatrix1;
|
||||
pub struct ColorMatrix2;
|
||||
|
||||
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 Orientation {
|
||||
type Type = TypeOrientation;
|
||||
|
||||
const ID: TagId = TagId::Orientation;
|
||||
const NAME: &'static str = "Orientation";
|
||||
}
|
||||
|
||||
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 ColorMatrix1 {
|
||||
type Type = Array<TypeSRational>;
|
||||
|
||||
const ID: TagId = TagId::ColorMatrix1;
|
||||
const NAME: &'static str = "Color Matrix 1";
|
||||
}
|
||||
|
||||
impl SimpleTag for ColorMatrix2 {
|
||||
type Type = Array<TypeSRational>;
|
||||
|
||||
const ID: TagId = TagId::ColorMatrix2;
|
||||
const NAME: &'static str = "Color Matrix 2";
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
impl SimpleTag for BlackLevel {
|
||||
type Type = ConstArray<TypeShort, 4>;
|
||||
|
||||
const ID: TagId = TagId::BlackLevel;
|
||||
const NAME: &'static str = "Black Level";
|
||||
}
|
||||
|
||||
impl SimpleTag for WhiteBalanceRggbLevels {
|
||||
type Type = ConstArray<TypeSShort, 4>;
|
||||
|
||||
const ID: TagId = TagId::WhiteBalanceRggbLevels;
|
||||
const NAME: &'static str = "White Balance Levels (RGGB)";
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
399
libraries/rawkit/src/tiff/types.rs
Normal file
399
libraries/rawkit/src/tiff/types.rs
Normal file
@@ -0,0 +1,399 @@
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
use super::file::TiffRead;
|
||||
use super::values::{CurveLookupTable, Rational, Transform};
|
||||
use super::{Ifd, IfdTagType, TiffError};
|
||||
|
||||
pub struct TypeAscii;
|
||||
pub struct TypeByte;
|
||||
pub struct TypeShort;
|
||||
pub struct TypeLong;
|
||||
pub struct TypeRational;
|
||||
pub struct TypeSByte;
|
||||
pub struct TypeSShort;
|
||||
pub struct TypeSLong;
|
||||
pub struct TypeSRational;
|
||||
pub struct TypeFloat;
|
||||
pub struct TypeDouble;
|
||||
pub struct TypeUndefined;
|
||||
|
||||
pub struct TypeNumber;
|
||||
pub struct TypeSNumber;
|
||||
pub struct TypeIfd;
|
||||
|
||||
pub trait PrimitiveType {
|
||||
type Output;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32>;
|
||||
|
||||
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(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::Ascii => Some(1),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_primitive<R: Read + Seek>(_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
let value = file.read_ascii()?;
|
||||
if value.is_ascii() {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(TiffError::InvalidValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeByte {
|
||||
type Output = u8;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::Byte => Some(1),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_primitive<R: Read + Seek>(_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
Ok(file.read_u8()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeShort {
|
||||
type Output = u16;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::Short => Some(2),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_primitive<R: Read + Seek>(_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
Ok(file.read_u16()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeLong {
|
||||
type Output = u32;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::Long => Some(4),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_primitive<R: Read + Seek>(_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
Ok(file.read_u32()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeRational {
|
||||
type Output = Rational<u32>;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::Rational => Some(8),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
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 })
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeSByte {
|
||||
type Output = i8;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::SByte => Some(1),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_primitive<R: Read + Seek>(_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
Ok(file.read_i8()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeSShort {
|
||||
type Output = i16;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::SShort => Some(2),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_primitive<R: Read + Seek>(_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
Ok(file.read_i16()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeSLong {
|
||||
type Output = i32;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::SLong => Some(4),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_primitive<R: Read + Seek>(_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
Ok(file.read_i32()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeSRational {
|
||||
type Output = Rational<i32>;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::SRational => Some(8),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
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 })
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeFloat {
|
||||
type Output = f32;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::Float => Some(4),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_primitive<R: Read + Seek>(_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
Ok(file.read_f32()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeDouble {
|
||||
type Output = f64;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
match the_type {
|
||||
IfdTagType::Double => Some(8),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_primitive<R: Read + Seek>(_: IfdTagType, file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
Ok(file.read_f64()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeUndefined {
|
||||
type Output = ();
|
||||
|
||||
fn get_size(_: IfdTagType) -> Option<u32> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn read_primitive<R: Read + Seek>(_: IfdTagType, _: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeNumber {
|
||||
type Output = u32;
|
||||
|
||||
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>(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!(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeSNumber {
|
||||
type Output = i32;
|
||||
|
||||
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>(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!(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType for TypeIfd {
|
||||
type Output = Ifd;
|
||||
|
||||
fn get_size(the_type: IfdTagType) -> Option<u32> {
|
||||
TypeLong::get_size(the_type)
|
||||
}
|
||||
|
||||
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)?;
|
||||
Ifd::new_from_offset(file, offset)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TagType {
|
||||
type Output;
|
||||
|
||||
fn read<R: Read + Seek>(file: &mut TiffRead<R>) -> Result<Self::Output, TiffError>;
|
||||
}
|
||||
|
||||
impl<T: PrimitiveType> TagType for T {
|
||||
type Output = T::Output;
|
||||
|
||||
fn read<R: Read + Seek>(file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
let the_type = IfdTagType::from(file.read_u16()?);
|
||||
let count = file.read_u32()?;
|
||||
|
||||
if count != 1 {
|
||||
return Err(TiffError::InvalidCount);
|
||||
}
|
||||
|
||||
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(the_type, file)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Array<T: PrimitiveType> {
|
||||
primitive_type: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
pub struct ConstArray<T: PrimitiveType, const N: usize> {
|
||||
primitive_type: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
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 the_type = IfdTagType::from(file.read_u16()?);
|
||||
let count = file.read_u32()?;
|
||||
|
||||
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)?;
|
||||
}
|
||||
|
||||
let mut ans = Vec::with_capacity(count.try_into()?);
|
||||
for _ in 0..count {
|
||||
ans.push(T::read_primitive(the_type, file)?);
|
||||
}
|
||||
Ok(ans)
|
||||
}
|
||||
}
|
||||
|
||||
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 the_type = IfdTagType::from(file.read_u16()?);
|
||||
let count = file.read_u32()?;
|
||||
|
||||
if count != N.try_into()? {
|
||||
return Err(TiffError::InvalidCount);
|
||||
}
|
||||
|
||||
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)?;
|
||||
}
|
||||
|
||||
let mut ans = Vec::with_capacity(count.try_into()?);
|
||||
for _ in 0..count {
|
||||
ans.push(T::read_primitive(the_type, file)?);
|
||||
}
|
||||
ans.try_into().map_err(|_| TiffError::InvalidCount)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TypeString;
|
||||
pub struct TypeSonyToneCurve;
|
||||
pub struct TypeOrientation;
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
impl TagType for TypeOrientation {
|
||||
type Output = Transform;
|
||||
|
||||
fn read<R: Read + Seek>(file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
|
||||
Ok(match TypeShort::read(file)? {
|
||||
1 => Transform::Horizontal,
|
||||
2 => Transform::MirrorHorizontal,
|
||||
3 => Transform::Rotate180,
|
||||
4 => Transform::MirrorVertical,
|
||||
5 => Transform::MirrorHorizontalRotate270,
|
||||
6 => Transform::Rotate90,
|
||||
7 => Transform::MirrorHorizontalRotate90,
|
||||
8 => Transform::Rotate270,
|
||||
_ => return Err(TiffError::InvalidValue),
|
||||
})
|
||||
}
|
||||
}
|
||||
79
libraries/rawkit/src/tiff/values.rs
Normal file
79
libraries/rawkit/src/tiff/values.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
pub trait ToFloat {
|
||||
fn to_float(&self) -> f64;
|
||||
}
|
||||
|
||||
impl ToFloat for u32 {
|
||||
fn to_float(&self) -> f64 {
|
||||
*self as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFloat for i32 {
|
||||
fn to_float(&self) -> f64 {
|
||||
*self as f64
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Rational<T: ToFloat> {
|
||||
pub numerator: T,
|
||||
pub denominator: T,
|
||||
}
|
||||
|
||||
impl<T: ToFloat> ToFloat for Rational<T> {
|
||||
fn to_float(&self) -> f64 {
|
||||
self.numerator.to_float() / self.denominator.to_float()
|
||||
}
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Transform {
|
||||
Horizontal,
|
||||
MirrorHorizontal,
|
||||
Rotate180,
|
||||
MirrorVertical,
|
||||
MirrorHorizontalRotate270,
|
||||
Rotate90,
|
||||
MirrorHorizontalRotate90,
|
||||
Rotate270,
|
||||
}
|
||||
|
||||
impl Transform {
|
||||
pub fn is_identity(&self) -> bool {
|
||||
*self == Transform::Horizontal
|
||||
}
|
||||
|
||||
pub fn will_swap_coordinates(&self) -> bool {
|
||||
use Transform as Tr;
|
||||
|
||||
match *self {
|
||||
Tr::Horizontal | Tr::MirrorHorizontal | Tr::Rotate180 | Tr::MirrorVertical => false,
|
||||
Tr::MirrorHorizontalRotate270 | Tr::Rotate90 | Tr::MirrorHorizontalRotate90 | Tr::Rotate270 => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user