Skip to content

Conversation

@JimBobSquarePants
Copy link
Member

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

This pull request adds support for decoding TIFF images with CIE Lab color data in both 8-bit and 16-bit per channel formats, including both planar and interleaved storage. It also updates the CMYK TIFF decoder to support ICC color profile conversion and makes the decoder factory aware of these new types. The changes improve color accuracy and extensibility for TIFF decoding.

New TIFF color decoders and ICC profile support:

  • Added CieLab16TiffColor<TPixel> and CieLab16PlanarTiffColor<TPixel> classes to decode 16-bit per channel CIE Lab TIFF images, with proper ICC profile conversion and endianness handling. [1] [2]
  • Updated CmykTiffColor<TPixel> to support ICC profile conversion and use buffer-based SIMD processing for more efficient decoding. [1] [2]

Refactoring and naming consistency:

  • Renamed CieLabTiffColor<TPixel> and CieLabPlanarTiffColor<TPixel> to CieLab8TiffColor<TPixel> and CieLab8PlanarTiffColor<TPixel>, respectively, to clarify that these handle 8-bit per channel data. [1] [2]

Decoder factory enhancements:

  • Updated TiffColorDecoderFactory<TPixel> to instantiate the correct decoder based on bits per sample and to pass necessary metadata, options, and allocator for ICC profile-aware decoders. [1] [2] [3] [4] [5]

Minor improvements:

  • Used C# type inference for default struct initialization in YCbCrToRgbConverter.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds TIFF decoding improvements to support CIE Lab 16-bit (chunky + planar) and enables ICC-based color conversion for CMYK/Lab paths, plus updates wiring so decoders can access frame metadata and decoder options.

Changes:

  • Add new 16-bit CIE Lab TIFF color decoders (chunky + planar) with endianness handling and ICC conversion support.
  • Update CMYK TIFF decoding to support ICC conversion and use buffer/SIMD-based row processing.
  • Pass ImageFrameMetadata + DecoderOptions into the TIFF color decoder factory; add tests + new LFS test assets/reference outputs.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs Passes frame metadata/options into color decoder creation for ICC-aware decoding.
src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs Adjusts CieLab parsing to allow more than just 8-bit (but currently lacks bit-depth validation).
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs Selects new CIE Lab 8/16-bit decoders and passes ICC context to ICC-aware decoders.
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs Adds ICC conversion support and SIMD row conversion pipeline.
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLab8TiffColor{TPixel}.cs Renames 8-bit CieLab decoder for clarity.
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLab8PlanarTiffColor{TPixel}.cs Renames 8-bit planar CieLab decoder for clarity.
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLab16TiffColor{TPixel}.cs New 16-bit chunky CieLab decoder (endianness + ICC conversion).
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLab16PlanarTiffColor{TPixel}.cs New 16-bit planar CieLab decoder (endianness + ICC conversion).
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrConverter.cs Minor default initialization simplification.
tests/ImageSharp.Tests/TestImages.cs Adds TIFF ICC test image paths.
tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs Adds ICC conversion test; currently also comments out an existing test case.
tests/Images/Input/Tiff/icc-profiles/* Adds new LFS-backed TIFF ICC test assets.
tests/Images/External/ReferenceOutput/TiffDecoderTests/* Adds new LFS-backed reference outputs for ICC conversion test.
.github/workflows/build-and-test.yml Adjusts PR trigger types.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 25 to 27
[Theory]
[WithFile(MultiframeDifferentVariants, PixelTypes.Rgba32)]
// [WithFile(MultiframeDifferentVariants, PixelTypes.Rgba32)]
[WithFile(Cmyk64BitDeflate, PixelTypes.Rgba32)]
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A decoder negative-coverage case was disabled by commenting out the [WithFile(MultiframeDifferentVariants, PixelTypes.Rgba32)] attribute. This reduces test coverage and can hide regressions. Either re-enable it, or replace it with a new/updated NotSupported assertion that reflects the intended behavior for that file (and add a short comment explaining why).

Copilot uses AI. Check for mistakes.
@@ -452,13 +452,9 @@ private static void ParseColorType(this TiffDecoderCore options, ExifProfile exi
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported for CieLab images.");
}

Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CieLab parsing no longer validates BitsPerSample beyond the channel count. Since downstream decoding currently branches based on Channel0, inputs like 10/12/14-bit or mismatched per-channel bit depths would be accepted and then decoded incorrectly. Consider validating here that all 3 channels have the same supported bit depth (likely 8 or 16) and throw NotSupported otherwise.

Suggested change
ushort bitsPerChannel = options.BitsPerSample.Channel0;
if (bitsPerChannel != 8 && bitsPerChannel != 16)
{
TiffThrowHelper.ThrowNotSupported("Only 8 bits or 16 bits per channel are supported for CieLab images.");
}

Copilot uses AI. Check for mistakes.
Comment on lines +405 to 416
if (bitsPerSample.Channel0 == 8)
{
return new CieLab8TiffColor<TPixel>();
}

return new CieLab16TiffColor<TPixel>(
configuration,
options,
metadata,
memoryAllocator,
byteOrder == ByteOrder.BigEndian);

Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CieLab decoder selection is based only on bitsPerSample.Channel0, and the previous per-channel validation was removed. If the TIFF has non-8/16 bit depths (eg 12-bit) or mismatched channel bit depths, this will incorrectly fall back to the 16-bit decoder instead of failing fast. Please validate that Channel0/1/2 are all equal and either 8 or 16; otherwise throw NotSupported (or keep a DebugGuard + runtime check).

Suggested change
if (bitsPerSample.Channel0 == 8)
{
return new CieLab8TiffColor<TPixel>();
}
return new CieLab16TiffColor<TPixel>(
configuration,
options,
metadata,
memoryAllocator,
byteOrder == ByteOrder.BigEndian);
bool all8Bit =
bitsPerSample.Channel0 == 8
&& bitsPerSample.Channel1 == 8
&& bitsPerSample.Channel2 == 8;
bool all16Bit =
bitsPerSample.Channel0 == 16
&& bitsPerSample.Channel1 == 16
&& bitsPerSample.Channel2 == 16;
DebugGuard.IsTrue(all8Bit || all16Bit, "bitsPerSample");
if (all8Bit)
{
return new CieLab8TiffColor<TPixel>();
}
if (all16Bit)
{
return new CieLab16TiffColor<TPixel>(
configuration,
options,
metadata,
memoryAllocator,
byteOrder == ByteOrder.BigEndian);
}
throw new System.NotSupportedException("CieLab color requires bitsPerSample of 8 or 16 bits for all three channels.");

Copilot uses AI. Check for mistakes.
Comment on lines 460 to +463
case TiffColorType.CieLabPlanar:
return new CieLabPlanarTiffColor<TPixel>();
return bitsPerSample.Channel0 == 8
? new CieLab8PlanarTiffColor<TPixel>()
: new CieLab16PlanarTiffColor<TPixel>(
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CieLabPlanar selection also branches only on bitsPerSample.Channel0 and doesn't assert bitsPerSample.Channels == 3 or validate supported bit depths. Add validation that the sample count is 3 and that Channel0/1/2 are all equal and either 8 or 16, otherwise throw NotSupported to avoid silent mis-decoding.

Copilot uses AI. Check for mistakes.
}
}

#pragma warning disable IDE0060 // Remove unused parameter
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#pragma warning disable IDE0060 is introduced without a corresponding restore and appears unnecessary since the new parameters are used in the CieLabPlanar branch. Please remove the pragma (preferred) or scope it tightly with #pragma warning restore IDE0060 right after the affected code.

Suggested change
#pragma warning disable IDE0060 // Remove unused parameter

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants