diff --git a/src/decoder/image.rs b/src/decoder/image.rs index 4ff351b5..eef5d0a5 100644 --- a/src/decoder/image.rs +++ b/src/decoder/image.rs @@ -95,6 +95,19 @@ pub(crate) struct ReadoutLayout { pub planar_config: PlanarConfiguration, /// The sample interpretation (interpret with planar_config). + /// + /// FIXME: we should not require this here. The ability to turn out the raw bytes from the + /// sample arrays is very different from turning out interpretable color. Firstly we can always + /// readout `Multiband` but currently only use that ColorType in special circumstances (it must + /// not overlap cases where actually want to use a ColorType). + /// + /// And then we have CIE Lab, which uses a tuple of `(u8, i8, i8)`, that is still filterable + /// but still not represented by any of our `DecoderResult` variants. Other color variants + /// depend on extra tags (YCbCrCoefficients/0x0211) and we don't have a good side channel to + /// tag the output with all that TIFF specific information, so arguably we should process and + /// apply those to the data so it becomes a self-contained representation. + /// + /// This should be computed at a higher level, in `Decoder`, instead. pub color: ColorType, /// The number of bytes from one row to another. pub minimum_row_stride: usize, @@ -435,15 +448,60 @@ impl Image { }), } } - // TODO: this is bad we should not fail at this point - PhotometricInterpretation::RGBPalette - | PhotometricInterpretation::TransparencyMask - | PhotometricInterpretation::CIELab => Err(TiffError::UnsupportedError( + // ``` + // struct IccLab /* Interpretation 9* { + // pub L: u8, // SampleFormat::Uint + // pub a: u8, // SampleFormat::Uint, defined as TiffLab::a + 128 + // pub b: u8, // SampleFormat::Uint, defined as TiffLab::b + 128 + // } + // ``` + PhotometricInterpretation::IccLab => match self.photometric_samples { + 3 if matches!(self.sample_format, SampleFormat::Uint) => { + Ok(ColorType::Lab(self.bits_per_sample)) + } + _ => Err(TiffError::UnsupportedError( + TiffUnsupportedError::InterpretationWithBits( + self.photometric_interpretation, + vec![self.bits_per_sample; self.samples as usize], + ), + )), + }, + // Unsupported due to inherently heterogeneous sample types. This is represented as: + // ``` + // struct TiffLab /* Interpretation 8* { + // pub L: u8, // SampleFormat::Uint + // pub a: i8, // SampleFormat::Int + // pub b: i8, // SampleFormat::Int + // } + // ``` + PhotometricInterpretation::CIELab => Err(TiffError::UnsupportedError( TiffUnsupportedError::InterpretationWithBits( - self.photometric_interpretation, + PhotometricInterpretation::CIELab, vec![self.bits_per_sample; self.samples as usize], ), )), + // Unsupported due to extra unfiltering and conversion steps. We need to find the + // Decode tag (SRATIONAL; 2 * SamplesPerPixel) and apply the following conversion: + // + // L* = Decode[0] + Lsample x (Decode[1] - Decode[0]) / (2^n -1) + // … + // + // So we'll have a larger depth in the output and either worry about reducing fractions + // or turn everything into floats. That's a lot of decisions. + PhotometricInterpretation::ItuLab => Err(TiffError::UnsupportedError( + TiffUnsupportedError::InterpretationWithBits( + PhotometricInterpretation::CIELab, + vec![self.bits_per_sample; self.samples as usize], + ), + )), + PhotometricInterpretation::RGBPalette | PhotometricInterpretation::TransparencyMask => { + Err(TiffError::UnsupportedError( + TiffUnsupportedError::InterpretationWithBits( + self.photometric_interpretation, + vec![self.bits_per_sample; self.samples as usize], + ), + )) + } } } diff --git a/src/lib.rs b/src/lib.rs index 39b9ddbe..e7c2f1c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,9 @@ pub enum ColorType { /// Pixel is YCbCr YCbCr(u8), + /// Pixel is CIE L*a*b* (ICC LAb) + Lab(u8), + /// Pixel has multiple bands/channels Multiband { bit_depth: u8, num_samples: u16 }, } @@ -58,6 +61,7 @@ impl ColorType { | ColorType::CMYK(b) | ColorType::CMYKA(b) | ColorType::YCbCr(b) + | ColorType::Lab(b) | ColorType::Multiband { bit_depth: b, .. } => b, } } @@ -72,6 +76,7 @@ impl ColorType { ColorType::CMYK(_) => 4, ColorType::CMYKA(_) => 5, ColorType::YCbCr(_) => 3, + ColorType::Lab(_) => 3, ColorType::Multiband { num_samples, .. } => num_samples, } } diff --git a/src/tags.rs b/src/tags.rs index 7e4aa31b..f456f659 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -266,6 +266,8 @@ pub enum PhotometricInterpretation(u16) { CMYK = 5, YCbCr = 6, CIELab = 8, + IccLab = 9, + ItuLab = 10, } }