Skip to content

Commit 1732481

Browse files
committed
Add ICC Lab interpretation
The CIE Lab interpretation uses heterogeneous samples, and the ITU Lab encoding requires the Tag Decode (433, 0x01B1) which has default values depending on bit depth and convering values into floating points, probably. See also Photometric Interpretation: <https://web.archive.org/web/20050309053132/http://www.awaresystems.be/imaging/tiff/tifftags/photometricinterpretation.html> See also Tag Decode: <https://web.archive.org/web/20050309072856/http://www.awaresystems.be/imaging/tiff/tifftags/decode.html>
1 parent 2d90179 commit 1732481

File tree

3 files changed

+70
-5
lines changed

3 files changed

+70
-5
lines changed

src/decoder/image.rs

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,19 @@ pub(crate) struct ReadoutLayout {
9595
pub planar_config: PlanarConfiguration,
9696

9797
/// The sample interpretation (interpret with planar_config).
98+
///
99+
/// FIXME: we should not require this here. The ability to turn out the raw bytes from the
100+
/// sample arrays is very different from turning out interpretable color. Firstly we can always
101+
/// readout `Multiband` but currently only use that ColorType in special circumstances (it must
102+
/// not overlap cases where actually want to use a ColorType).
103+
///
104+
/// And then we have CIE Lab, which uses a tuple of `(u8, i8, i8)`, that is still filterable
105+
/// but still not represented by any of our `DecoderResult` variants. Other color variants
106+
/// depend on extra tags (YCbCrCoefficients/0x0211) and we don't have a good side channel to
107+
/// tag the output with all that TIFF specific information, so arguably we should process and
108+
/// apply those to the data so it becomes a self-contained representation.
109+
///
110+
/// This should be computed at a higher level, in `Decoder`, instead.
98111
pub color: ColorType,
99112
/// The number of bytes from one row to another.
100113
pub minimum_row_stride: usize,
@@ -435,15 +448,60 @@ impl Image {
435448
}),
436449
}
437450
}
438-
// TODO: this is bad we should not fail at this point
439-
PhotometricInterpretation::RGBPalette
440-
| PhotometricInterpretation::TransparencyMask
441-
| PhotometricInterpretation::CIELab => Err(TiffError::UnsupportedError(
451+
// ```
452+
// struct IccLab /* Interpretation 9* {
453+
// pub L: u8, // SampleFormat::Uint
454+
// pub a: u8, // SampleFormat::Uint, defined as TiffLab::a + 128
455+
// pub b: u8, // SampleFormat::Uint, defined as TiffLab::b + 128
456+
// }
457+
// ```
458+
PhotometricInterpretation::IccLab => match self.photometric_samples {
459+
3 if matches!(self.sample_format, SampleFormat::Uint) => {
460+
Ok(ColorType::Lab(self.bits_per_sample))
461+
}
462+
_ => Err(TiffError::UnsupportedError(
463+
TiffUnsupportedError::InterpretationWithBits(
464+
self.photometric_interpretation,
465+
vec![self.bits_per_sample; self.samples as usize],
466+
),
467+
)),
468+
},
469+
// Unsupported due to inherently heterogeneous sample types. This is represented as:
470+
// ```
471+
// struct TiffLab /* Interpretation 8* {
472+
// pub L: u8, // SampleFormat::Uint
473+
// pub a: i8, // SampleFormat::Int
474+
// pub b: i8, // SampleFormat::Int
475+
// }
476+
// ```
477+
PhotometricInterpretation::CIELab => Err(TiffError::UnsupportedError(
442478
TiffUnsupportedError::InterpretationWithBits(
443-
self.photometric_interpretation,
479+
PhotometricInterpretation::CIELab,
444480
vec![self.bits_per_sample; self.samples as usize],
445481
),
446482
)),
483+
// Unsupported due to extra unfiltering and conversion steps. We need to find the
484+
// Decode tag (SRATIONAL; 2 * SamplesPerPixel) and apply the following conversion:
485+
//
486+
// L* = Decode[0] + Lsample x (Decode[1] - Decode[0]) / (2^n -1)
487+
// …
488+
//
489+
// So we'll have a larger depth in the output and either worry about reducing fractions
490+
// or turn everything into floats. That's a lot of decisions.
491+
PhotometricInterpretation::ItuLab => Err(TiffError::UnsupportedError(
492+
TiffUnsupportedError::InterpretationWithBits(
493+
PhotometricInterpretation::CIELab,
494+
vec![self.bits_per_sample; self.samples as usize],
495+
),
496+
)),
497+
PhotometricInterpretation::RGBPalette | PhotometricInterpretation::TransparencyMask => {
498+
Err(TiffError::UnsupportedError(
499+
TiffUnsupportedError::InterpretationWithBits(
500+
self.photometric_interpretation,
501+
vec![self.bits_per_sample; self.samples as usize],
502+
),
503+
))
504+
}
447505
}
448506
}
449507

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ pub enum ColorType {
4444
/// Pixel is YCbCr
4545
YCbCr(u8),
4646

47+
/// Pixel is CIE L*a*b* (ICC LAb)
48+
Lab(u8),
49+
4750
/// Pixel has multiple bands/channels
4851
Multiband { bit_depth: u8, num_samples: u16 },
4952
}
@@ -58,6 +61,7 @@ impl ColorType {
5861
| ColorType::CMYK(b)
5962
| ColorType::CMYKA(b)
6063
| ColorType::YCbCr(b)
64+
| ColorType::Lab(b)
6165
| ColorType::Multiband { bit_depth: b, .. } => b,
6266
}
6367
}
@@ -72,6 +76,7 @@ impl ColorType {
7276
ColorType::CMYK(_) => 4,
7377
ColorType::CMYKA(_) => 5,
7478
ColorType::YCbCr(_) => 3,
79+
ColorType::Lab(_) => 3,
7580
ColorType::Multiband { num_samples, .. } => num_samples,
7681
}
7782
}

src/tags.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ pub enum PhotometricInterpretation(u16) {
266266
CMYK = 5,
267267
YCbCr = 6,
268268
CIELab = 8,
269+
IccLab = 9,
270+
ItuLab = 10,
269271
}
270272
}
271273

0 commit comments

Comments
 (0)