From 485571a65b9b8f71ab96fc3983cedbfde271c171 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 26 May 2022 16:31:25 +0200 Subject: [PATCH] Add support for decoding planar tiff with cielab colorspace --- .../CieLabPlanarTiffColor{TPixel}.cs | 49 +++++++++++++++++++ .../TiffColorDecoderFactory{TPixel}.cs | 3 ++ .../TiffColorType.cs | 5 ++ .../YCbCrPlanarTiffColor{TPixel}.cs | 3 ++ .../Formats/Tiff/TiffDecoderOptionsParser.cs | 4 +- 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs new file mode 100644 index 0000000000..b0420f9920 --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs @@ -0,0 +1,49 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation +{ + /// + /// Implements decoding pixel data with photometric interpretation of type 'CieLab' with the planar configuration. + /// + internal class CieLabPlanarTiffColor : TiffBasePlanarColorDecoder + where TPixel : unmanaged, IPixel + { + private readonly ColorSpaceConverter colorSpaceConverter = new(); + + private const float Inv255 = 1.0f / 255.0f; + + /// + public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) + { + Span l = data[0].GetSpan(); + Span a = data[1].GetSpan(); + Span b = data[2].GetSpan(); + + var color = default(TPixel); + int offset = 0; + for (int y = top; y < top + height; y++) + { + Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width); + for (int x = 0; x < pixelRow.Length; x++) + { + var lab = new CieLab((l[offset] & 0xFF) * 100f * Inv255, (sbyte)a[offset], (sbyte)b[offset]); + var rgb = this.colorSpaceConverter.ToRgb(lab); + + color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); + pixelRow[x] = color; + + offset++; + } + } + } + } +} diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs index ce146c9572..4b0bca08b8 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs @@ -430,6 +430,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation case TiffColorType.YCbCrPlanar: return new YCbCrPlanarTiffColor(referenceBlackAndWhite, ycbcrCoefficients, ycbcrSubSampling); + case TiffColorType.CieLabPlanar: + return new CieLabPlanarTiffColor(); + case TiffColorType.Rgb161616Planar: DebugGuard.IsTrue(colorMap == null, "colorMap"); return new Rgb16PlanarTiffColor(byteOrder == ByteOrder.BigEndian); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs index b5fdcbea9e..0c0cc07c8f 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs @@ -282,5 +282,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation /// The pixels are stored in CieLab format. /// CieLab, + + /// + /// The pixels are stored in CieLab format as planar. + /// + CieLabPlanar, } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs index 465c8fba3a..5e0aecfe15 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs @@ -9,6 +9,9 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation { + /// + /// Implements decoding pixel data with photometric interpretation of type 'YCbCr' with the planar configuration. + /// internal class YCbCrPlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index f1c04a3828..3da64ad841 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -397,8 +397,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffPhotometricInterpretation.CieLab: { - options.ColorType = TiffColorType.CieLab; - if (options.BitsPerSample.Channels != 3) { TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported for CieLab images."); @@ -410,6 +408,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffThrowHelper.ThrowNotSupported("Only 8 bits per channel is supported for CieLab images."); } + options.ColorType = options.PlanarConfiguration == TiffPlanarConfiguration.Chunky ? TiffColorType.CieLab : TiffColorType.CieLabPlanar; + break; }