1use crate::encoder::TiffValue;
2use core::fmt;
3
4macro_rules! tags {
5 {
6 $( #[$enum_attr:meta] )*
8 $vis:vis enum $name:ident($ty:tt) $(unknown(#[$unknown_meta:meta] $unknown_doc:ident))* {
9 $($(#[$ident_attr:meta])* $tag:ident = $val:expr,)*
11 }
12 } => {
13 $( #[$enum_attr] )*
14 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
15 #[non_exhaustive]
16 #[repr($ty)]
17 pub enum $name {
18 $($(#[$ident_attr])* $tag = $val,)*
19 $(
20 #[$unknown_meta]
21 Unknown($ty),
22 )*
23 }
24
25 impl $name {
26 #[inline(always)]
27 const fn __from_inner_type(n: $ty) -> Result<Self, $ty> {
28 match n {
29 $( $val => Ok($name::$tag), )*
30 n => Err(n),
31 }
32 }
33
34 #[inline(always)]
35 const fn __to_inner_type(&self) -> $ty {
36 match *self {
37 $( $name::$tag => $val, )*
38 $( $name::Unknown($unknown_doc) => { $unknown_doc }, )*
39 }
40 }
41 }
42
43 tags!($name, $ty, $($unknown_doc)*);
44 };
45 ($name:tt, u16, $($unknown_doc:ident)*) => {
47 impl $name {
48 #[inline(always)]
49 pub const fn from_u16(val: u16) -> Option<Self> {
50 match Self::__from_inner_type(val) {
51 Ok(v) => Some(v),
52 Err(_) => None,
53 }
54 }
55
56 $(
57 #[inline(always)]
58 pub const fn from_u16_exhaustive($unknown_doc: u16) -> Self {
59 match Self::__from_inner_type($unknown_doc) {
60 Ok(v) => v,
61 Err(_) => $name::Unknown($unknown_doc),
62 }
63 }
64 )*
65
66 #[inline(always)]
67 pub const fn to_u16(&self) -> u16 {
68 Self::__to_inner_type(self)
69 }
70 }
71 };
72 ($name:tt, $ty:tt, $($unknown_doc:literal)*) => {};
75}
76
77tags! {
79pub enum Tag(u16) unknown(
81 unknown
83) {
84 Artist = 315,
86 BitsPerSample = 258,
88 CellLength = 265, CellWidth = 264, ColorMap = 320, Compression = 259, DateTime = 306,
94 ExtraSamples = 338, FillOrder = 266, FreeByteCounts = 289, FreeOffsets = 288, GrayResponseCurve = 291, GrayResponseUnit = 290, HostComputer = 316,
101 ImageDescription = 270,
102 ImageLength = 257,
103 ImageWidth = 256,
104 Make = 271,
105 MaxSampleValue = 281, MinSampleValue = 280, Model = 272,
108 NewSubfileType = 254, Orientation = 274, PhotometricInterpretation = 262,
111 PlanarConfiguration = 284,
112 ResolutionUnit = 296, RowsPerStrip = 278,
114 SamplesPerPixel = 277,
115 Software = 305,
116 StripByteCounts = 279,
117 StripOffsets = 273,
118 SubfileType = 255, Threshholding = 263, XResolution = 282,
121 YResolution = 283,
122 Predictor = 317,
124 TileWidth = 322,
125 TileLength = 323,
126 TileOffsets = 324,
127 TileByteCounts = 325,
128 SubIfd = 330,
129 SampleFormat = 339,
131 SMinSampleValue = 340, SMaxSampleValue = 341, JPEGTables = 347,
135 #[doc(alias = "YCbCrSubsampling")]
137 ChromaSubsampling = 530, #[doc(alias = "YCbCrPositioning")]
139 ChromaPositioning = 531, ModelPixelScaleTag = 33550, ModelTransformationTag = 34264, ModelTiepointTag = 33922, Copyright = 33_432,
147 ExifDirectory = 0x8769,
149 GpsDirectory = 0x8825,
151 IccProfile = 34675,
153 GeoKeyDirectoryTag = 34735, GeoDoubleParamsTag = 34736, GeoAsciiParamsTag = 34737, ExifVersion = 0x9000,
157 GdalNodata = 42113, }
159}
160
161#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
167pub struct IfdPointer(pub u64);
172
173impl fmt::LowerHex for IfdPointer {
174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175 fmt::LowerHex::fmt(&self.0, f)
176 }
177}
178
179impl core::fmt::UpperHex for IfdPointer {
180 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181 fmt::UpperHex::fmt(&self.0, f)
182 }
183}
184
185tags! {
186pub enum Type(u16) {
188 BYTE = 1,
190 ASCII = 2,
192 SHORT = 3,
194 LONG = 4,
196 RATIONAL = 5,
198 SBYTE = 6,
200 UNDEFINED = 7,
202 SSHORT = 8,
204 SLONG = 9,
206 SRATIONAL = 10,
208 FLOAT = 11,
210 DOUBLE = 12,
212 IFD = 13,
214 LONG8 = 16,
216 SLONG8 = 17,
218 IFD8 = 18,
220}
221}
222
223impl Type {
224 pub(crate) fn byte_len(&self) -> u8 {
225 match *self {
226 Type::BYTE | Type::SBYTE | Type::ASCII | Type::UNDEFINED => 1,
227 Type::SHORT | Type::SSHORT => 2,
228 Type::LONG | Type::SLONG | Type::FLOAT | Type::IFD => 4,
229 Type::LONG8
230 | Type::SLONG8
231 | Type::DOUBLE
232 | Type::RATIONAL
233 | Type::SRATIONAL
234 | Type::IFD8 => 8,
235 }
236 }
237
238 pub(crate) fn value_bytes(&self, count: u64) -> Result<u64, crate::error::TiffError> {
239 let tag_size = u64::from(self.byte_len());
240
241 match count.checked_mul(tag_size) {
242 Some(n) => Ok(n),
243 None => Err(crate::error::TiffError::LimitsExceeded),
244 }
245 }
246
247 pub(crate) fn endian_bytes(self) -> EndianBytes {
248 match self {
249 Type::BYTE | Type::SBYTE | Type::ASCII | Type::UNDEFINED => EndianBytes::One,
250 Type::SHORT | Type::SSHORT => EndianBytes::Two,
251 Type::LONG
252 | Type::SLONG
253 | Type::FLOAT
254 | Type::IFD
255 | Type::RATIONAL
256 | Type::SRATIONAL => EndianBytes::Four,
257 Type::LONG8 | Type::SLONG8 | Type::DOUBLE | Type::IFD8 => EndianBytes::Eight,
258 }
259 }
260}
261
262tags! {
263pub enum CompressionMethod(u16) unknown(
266 unknown
268) {
269 None = 1,
270 Huffman = 2,
271 Fax3 = 3,
272 Fax4 = 4,
273 LZW = 5,
274 JPEG = 6,
275 ModernJPEG = 7,
277 Deflate = 8,
278 OldDeflate = 0x80B2,
279 PackBits = 0x8005,
280
281 ZSTD = 0xC350,
283
284 WebP = 0xC351,
286}
287}
288
289tags! {
290pub enum PhotometricInterpretation(u16) {
291 WhiteIsZero = 0,
292 BlackIsZero = 1,
293 RGB = 2,
294 RGBPalette = 3,
295 TransparencyMask = 4,
296 CMYK = 5,
297 YCbCr = 6,
298 CIELab = 8,
299 IccLab = 9,
300 ItuLab = 10,
301}
302}
303
304tags! {
305pub enum PlanarConfiguration(u16) {
306 Chunky = 1,
307 Planar = 2,
308}
309}
310
311tags! {
312pub enum Predictor(u16) {
313 None = 1,
315 Horizontal = 2,
320 FloatingPoint = 3,
322}
323}
324
325tags! {
326pub enum ResolutionUnit(u16) {
328 None = 1,
329 Inch = 2,
330 Centimeter = 3,
331}
332}
333
334tags! {
335pub enum SampleFormat(u16) unknown(
336 unknown
338) {
339 Uint = 1,
340 Int = 2,
341 IEEEFP = 3,
342 Void = 4,
343}
344}
345
346tags! {
347pub enum ExtraSamples(u16) {
348 Unspecified = 0,
350 AssociatedAlpha = 1,
352 UnassociatedAlpha = 2,
354}
355}
356
357pub struct ValueBuffer {
359 bytes: Vec<u8>,
361
362 ty: Type,
364
365 count: u64,
368
369 byte_order: ByteOrder,
371}
372
373impl ValueBuffer {
374 pub fn empty(ty: Type) -> Self {
378 ValueBuffer {
379 bytes: vec![],
380 ty,
381 count: 0,
382 byte_order: ByteOrder::native(),
383 }
384 }
385
386 pub fn from_value<T: TiffValue>(value: &T) -> Self {
388 ValueBuffer {
389 bytes: value.data().into_owned(),
390 ty: <T as TiffValue>::FIELD_TYPE,
391 count: value.count() as u64,
392 byte_order: ByteOrder::native(),
393 }
394 }
395
396 pub fn byte_order(&self) -> ByteOrder {
397 self.byte_order
398 }
399
400 pub fn data_type(&self) -> Type {
401 self.ty
402 }
403
404 pub fn count(&self) -> u64 {
406 debug_assert!({
407 self.ty
408 .value_bytes(self.count)
409 .is_ok_and(|n| n <= self.bytes.len() as u64)
410 });
411
412 self.count
413 }
414
415 pub fn as_bytes(&self) -> &[u8] {
417 &self.bytes[..self.assumed_len_from_count()]
418 }
419
420 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
422 let len = self.assumed_len_from_count();
423 &mut self.bytes[..len]
424 }
425
426 pub fn set_byte_order(&mut self, byte_order: ByteOrder) {
428 let len = self.assumed_len_from_count();
429
430 self.byte_order
431 .convert(self.ty, &mut self.bytes[..len], byte_order);
432
433 self.byte_order = byte_order;
434 }
435
436 pub(crate) fn prepare_length(&mut self, to_len: usize) {
441 if to_len > self.bytes.len() {
442 self.bytes.resize(to_len, 0);
443 }
444
445 if self.bytes.len() < to_len / 2 {
446 self.bytes.truncate(to_len);
447 self.bytes.shrink_to_fit();
448 }
449 }
450
451 pub(crate) fn assume_type(&mut self, ty: Type, count: u64, bo: ByteOrder) {
456 debug_assert!({
457 ty.value_bytes(count)
458 .is_ok_and(|n| n <= self.bytes.len() as u64)
459 });
460
461 self.byte_order = bo;
462 self.ty = ty;
463 self.count = count;
464 }
465
466 pub(crate) fn raw_bytes_mut(&mut self) -> &mut [u8] {
467 &mut self.bytes
468 }
469
470 fn assumed_len_from_count(&self) -> usize {
471 usize::from(self.ty.byte_len()) * self.count as usize
472 }
473}
474
475#[derive(Clone, Copy, Debug, PartialEq, Eq)]
477pub enum ByteOrder {
478 LittleEndian,
480 BigEndian,
482}
483
484impl ByteOrder {
485 pub const fn native() -> Self {
491 match () {
492 #[cfg(target_endian = "little")]
493 () => ByteOrder::LittleEndian,
494 #[cfg(target_endian = "big")]
495 () => ByteOrder::BigEndian,
496 #[cfg(not(any(target_endian = "big", target_endian = "little")))]
497 () => compile_error!("Unsupported target"),
498 }
499 }
500
501 pub fn convert(self, ty: Type, buffer: &mut [u8], to: ByteOrder) {
507 self.convert_endian_bytes(ty.endian_bytes(), buffer, to)
508 }
509
510 pub(crate) fn convert_endian_bytes(self, cls: EndianBytes, buffer: &mut [u8], to: ByteOrder) {
511 if self == to {
512 return;
513 }
514
515 match cls {
517 EndianBytes::One => {
518 }
520 EndianBytes::Two => {
521 for chunk in buffer.chunks_exact_mut(2) {
522 let chunk: &mut [u8; 2] = chunk.try_into().unwrap();
523 *chunk = u16::from_be_bytes(*chunk).to_le_bytes();
524 }
525 }
526 EndianBytes::Four => {
527 for chunk in buffer.chunks_exact_mut(4) {
528 let chunk: &mut [u8; 4] = chunk.try_into().unwrap();
529 *chunk = u32::from_be_bytes(*chunk).to_le_bytes();
530 }
531 }
532 EndianBytes::Eight => {
533 for chunk in buffer.chunks_exact_mut(8) {
534 let chunk: &mut [u8; 8] = chunk.try_into().unwrap();
535 *chunk = u64::from_be_bytes(*chunk).to_le_bytes();
536 }
537 }
538 }
539 }
540}
541
542#[derive(Clone, Copy)]
544pub(crate) enum EndianBytes {
545 One,
546 Two,
547 Four,
548 Eight,
549}