Add basic thumbnail extraction to Rawkit (#2659)

* Add `CompressionValue`

* Rename `Transform` to `OrientationValue`

* Add basic thumbnail extraction

* Add `ThumbnailFormat`

* fmt + clippy fixes
This commit is contained in:
Dr George Atkinson
2025-12-20 18:08:21 -08:00
committed by GitHub
parent d441a02e72
commit c21ccf5284
9 changed files with 171 additions and 80 deletions
+5 -5
View File
@@ -26,8 +26,8 @@ pub enum TagId {
RowsPerStrip = 0x116,
StripByteCounts = 0x117,
SubIfd = 0x14a,
JpegOffset = 0x201,
JpegLength = 0x202,
ThumbnailOffset = 0x201,
ThumbnailLength = 0x202,
SonyToneCurve = 0x7010,
BlackLevel = 0x7310,
WhiteBalanceRggbLevels = 0x7313,
@@ -88,10 +88,10 @@ impl Ifd {
}
file.seek_from_start(offset)?;
let num = file.read_u16()?;
let num_entries = file.read_u16()?;
let mut ifd_entries = Vec::with_capacity(num.into());
for _ in 0..num {
let mut ifd_entries = Vec::with_capacity(num_entries.into());
for _ in 0..num_entries {
let tag = file.read_u16()?.into();
let the_type = file.read_u16()?.into();
let count = file.read_u32()?;
+8 -8
View File
@@ -1,4 +1,4 @@
use super::types::{Array, ConstArray, TagType, TypeByte, TypeIfd, TypeLong, TypeNumber, TypeOrientation, TypeSRational, TypeSShort, TypeShort, TypeSonyToneCurve, TypeString};
use super::types::{Array, ConstArray, TagType, TypeByte, TypeCompression, TypeIfd, TypeLong, TypeNumber, TypeOrientation, TypeSRational, TypeSShort, TypeShort, TypeSonyToneCurve, TypeString};
use super::{Ifd, TagId, TiffError, TiffRead};
use std::io::{Read, Seek};
@@ -22,8 +22,8 @@ pub struct SamplesPerPixel;
pub struct RowsPerStrip;
pub struct StripByteCounts;
pub struct SubIfd;
pub struct JpegOffset;
pub struct JpegLength;
pub struct ThumbnailOffset;
pub struct ThumbnailLength;
pub struct SonyDataOffset;
pub struct SonyToneCurve;
pub struct BlackLevel;
@@ -55,7 +55,7 @@ impl SimpleTag for BitsPerSample {
}
impl SimpleTag for Compression {
type Type = TypeShort;
type Type = TypeCompression;
const ID: TagId = TagId::Compression;
const NAME: &'static str = "Compression";
@@ -124,17 +124,17 @@ impl SimpleTag for SubIfd {
const NAME: &'static str = "SubIFD";
}
impl SimpleTag for JpegOffset {
impl SimpleTag for ThumbnailOffset {
type Type = TypeLong;
const ID: TagId = TagId::JpegOffset;
const ID: TagId = TagId::ThumbnailOffset;
const NAME: &'static str = "Jpeg Offset";
}
impl SimpleTag for JpegLength {
impl SimpleTag for ThumbnailLength {
type Type = TypeLong;
const ID: TagId = TagId::JpegLength;
const ID: TagId = TagId::ThumbnailLength;
const NAME: &'static str = "Jpeg Length";
}
+12 -13
View File
@@ -1,5 +1,5 @@
use super::file::TiffRead;
use super::values::{CurveLookupTable, Rational, Transform};
use super::values::{CompressionValue, CurveLookupTable, OrientationValue, Rational};
use super::{Ifd, IfdTagType, TiffError};
use std::io::{Read, Seek};
@@ -350,6 +350,7 @@ impl<T: PrimitiveType, const N: usize> TagType for ConstArray<T, N> {
}
}
pub struct TypeCompression;
pub struct TypeString;
pub struct TypeSonyToneCurve;
pub struct TypeOrientation;
@@ -376,19 +377,17 @@ impl TagType for TypeSonyToneCurve {
}
impl TagType for TypeOrientation {
type Output = Transform;
type Output = OrientationValue;
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),
})
OrientationValue::try_from(TypeShort::read(file)?).map_err(|_| TiffError::InvalidValue)
}
}
impl TagType for TypeCompression {
type Output = CompressionValue;
fn read<R: Read + Seek>(file: &mut TiffRead<R>) -> Result<Self::Output, TiffError> {
CompressionValue::try_from(TypeShort::read(file)?).map_err(|_| TiffError::InvalidValue)
}
}
+69 -16
View File
@@ -1,3 +1,5 @@
use num_enum::{IntoPrimitive, TryFromPrimitive};
pub trait ToFloat {
fn to_float(&self) -> f64;
}
@@ -51,29 +53,80 @@ impl CurveLookupTable {
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Transform {
Horizontal,
MirrorHorizontal,
Rotate180,
MirrorVertical,
MirrorHorizontalRotate270,
Rotate90,
MirrorHorizontalRotate90,
Rotate270,
#[derive(Copy, Clone, Eq, PartialEq, Debug, IntoPrimitive, TryFromPrimitive)]
#[repr(u16)]
pub enum OrientationValue {
Horizontal = 1,
MirrorHorizontal = 2,
Rotate180 = 3,
MirrorVertical = 4,
MirrorHorizontalRotate270 = 5,
Rotate90 = 6,
MirrorHorizontalRotate90 = 7,
Rotate270 = 8,
}
impl Transform {
impl OrientationValue {
pub fn is_identity(&self) -> bool {
*self == Transform::Horizontal
*self == Self::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,
Self::Horizontal | Self::MirrorHorizontal | Self::Rotate180 | Self::MirrorVertical => false,
Self::MirrorHorizontalRotate270 | Self::Rotate90 | Self::MirrorHorizontalRotate90 | Self::Rotate270 => true,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
#[repr(u16)]
#[allow(non_camel_case_types)]
pub enum CompressionValue {
Uncompressed = 1,
CCITT_1D = 2,
T4 = 3,
T6 = 4,
LZW = 5,
JPEG_Old = 6,
JPEG = 7,
AdobeDeflate = 8,
JBIG_BW = 9,
JBIG_Color = 10,
KODAK_626 = 262,
Next = 32766,
Sony_ARW_Compressed = 32767,
Packed_Raw = 32769,
Samsung_SRW_Compressed = 32770,
CCIRLEW = 32771,
Samsung_SRW_Compressed_2 = 32772,
PackedBits = 32773,
Thunderscan = 32809,
Kodak_KDC_Compressed = 32867,
IT8CTPAD = 32895,
IT8LW = 32896,
IT8MP = 32897,
IT8BL = 32898,
PixarFilm = 32908,
PixarLog = 32909,
Deflate = 32946,
DCS = 32947,
AperioJPEG2K_YCbCr = 33003,
AperioJPEG2K_RGB = 33005,
JBIG = 34661,
SGILog = 34676,
SGILog24 = 34677,
JPEG2K = 34712,
NikonNEFCompressed = 34713,
JBIG2_TIFF_FX = 34715,
ESRI_Lerc = 34887,
LossyJPEG = 34892,
LZMA2 = 34925,
PNG = 34933,
JPEG_XR = 34934,
Zstd = 50000,
WebP = 50001,
JPEG_XL = 52546,
Kodak_DCR_Compressed = 65000,
Pentax_PEF_Compressed = 65535,
}