Skip to content

Commit d38fba4

Browse files
authored
Merge pull request #317 from image-rs/cielab
Add ICC Lab interpretation
2 parents 355ecc8 + 1732481 commit d38fba4

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)