From deed7485253358e25319875da649c0807cb42a1b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 3 Jun 2021 13:20:18 +0200 Subject: [PATCH] Add support for decoding 10 bit per channel rgb tiff's --- src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs | 5 +++++ .../TiffColorDecoderFactory{TPixel}.cs | 10 ++++++++++ .../Tiff/PhotometricInterpretation/TiffColorType.cs | 5 +++++ src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs | 7 +++++++ src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs | 5 +++++ .../Formats/Tiff/TiffBitsPerSampleExtensions.cs | 9 +++++++++ .../Formats/Tiff/TiffDecoderOptionsParser.cs | 5 +++++ src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs | 3 ++- .../ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 6 ++++++ .../ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 2 ++ .../ReferenceCodecs/MagickReferenceDecoder.cs | 7 ++----- tests/Images/Input/Tiff/flower-rgb-contig-14.tiff | 3 +++ tests/Images/Input/Tiff/flower-rgb-planar-14.tiff | 3 +++ 14 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 tests/Images/Input/Tiff/flower-rgb-contig-14.tiff create mode 100644 tests/Images/Input/Tiff/flower-rgb-planar-14.tiff diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index 2327528b0..6fe412b92 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -115,6 +115,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants /// public static readonly ushort[] BitsPerSampleRgb10Bit = { 10, 10, 10 }; + /// + /// The bits per sample for color images with 14 bits for each color channel. + /// + public static readonly ushort[] BitsPerSampleRgb14Bit = { 14, 14, 14 }; + /// /// The list of mimetypes that equate to a tiff. /// diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs index 9ebf48620..924415850 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs @@ -97,6 +97,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); + case TiffColorType.Rgb141414: + DebugGuard.IsTrue( + bitsPerSample.Length == 3 + && bitsPerSample[0] == 14 + && bitsPerSample[1] == 14 + && bitsPerSample[2] == 14, + "bitsPerSample"); + DebugGuard.IsTrue(colorMap == null, "colorMap"); + return new RgbTiffColor(bitsPerSample); + case TiffColorType.PaletteColor: DebugGuard.NotNull(bitsPerSample, "bitsPerSample"); DebugGuard.NotNull(colorMap, "colorMap"); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs index afa86b143..22d819953 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs @@ -78,6 +78,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation /// Rgb101010, + /// + /// RGB color image with 14 bits for each channel. + /// + Rgb141414, + /// /// RGB Full Color. Planar configuration of data. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs index dc1ef0fd6..ab9f3cbec 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs @@ -48,5 +48,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Note: The TiffEncoder does not yet support 10 bits per color channel and will default to 24 bits per pixel instead. /// Bit30 = 30, + + /// + /// 42 bits per pixel. 14 bit for each color channel. + /// + /// Note: The TiffEncoder does not yet support 14 bits per color channel and will default to 24 bits per pixel instead. + /// + Bit42 = 42, } } diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs index 02378ded3..088ef5d6f 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs @@ -47,5 +47,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Thirty bits per sample, each channel has 10 bits. /// Bit30 = 30, + + /// + /// Forty two bits per sample, each channel has 14 bits. + /// + Bit42 = 42, } } diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs index 51a5a53a7..ca0f0befc 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs @@ -31,6 +31,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff return TiffConstants.BitsPerSampleRgb8Bit; case TiffBitsPerSample.Bit30: return TiffConstants.BitsPerSampleRgb10Bit; + case TiffBitsPerSample.Bit42: + return TiffConstants.BitsPerSampleRgb14Bit; default: return Array.Empty(); @@ -47,6 +49,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff switch (bitsPerSample.Length) { case 3: + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb14Bit[2] && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb14Bit[1] && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb14Bit[0]) + { + return TiffBitsPerSample.Bit42; + } + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb10Bit[2] && bitsPerSample[1] == TiffConstants.BitsPerSampleRgb10Bit[1] && bitsPerSample[0] == TiffConstants.BitsPerSampleRgb10Bit[0]) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index cf6ac6dc7..eeac6a33c 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -182,6 +182,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff { switch (options.BitsPerSample) { + case TiffBitsPerSample.Bit42: + options.ColorType = TiffColorType.Rgb141414; + break; + case TiffBitsPerSample.Bit30: options.ColorType = TiffColorType.Rgb101010; break; @@ -297,6 +301,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffBitsPerPixel.Bit12 => TiffBitsPerSample.Bit12, TiffBitsPerPixel.Bit24 => TiffBitsPerSample.Bit24, TiffBitsPerPixel.Bit30 => TiffBitsPerSample.Bit30, + TiffBitsPerPixel.Bit42 => TiffBitsPerSample.Bit42, _ => throw new NotSupportedException("The bits per pixel are not supported"), }; } diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index edfa215cc..d5137c435 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -322,7 +322,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffBitsPerPixel.Bit6: case TiffBitsPerPixel.Bit12: case TiffBitsPerPixel.Bit30: - // Encoding 30, 12 and 6 bits per pixel is not yet supported. Default to 24 bits. + case TiffBitsPerPixel.Bit42: + // Encoding 42, 30, 12 and 6 bits per pixel is not yet supported. Default to 24 bits. this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, TiffPredictor.None); break; default: diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 0dd8e0e22..02b7f97d9 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -117,6 +117,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff public void TiffDecoder_CanDecode_30Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] + [WithFile(FlowerRgb141414Contiguous, PixelTypes.Rgba32)] + [WithFile(FlowerRgb141414Planar, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_42Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] [WithFile(GrayscaleDeflateMultistrip, PixelTypes.Rgba32)] [WithFile(RgbDeflateMultistrip, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 19cfc42e4..7c386a6a9 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -78,6 +78,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff } [Theory] + [InlineData(TiffBitsPerPixel.Bit42)] [InlineData(TiffBitsPerPixel.Bit30)] [InlineData(TiffBitsPerPixel.Bit12)] [InlineData(TiffBitsPerPixel.Bit6)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 05045d06a..9471a6393 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -560,6 +560,8 @@ namespace SixLabors.ImageSharp.Tests public const string RgbPaletteDeflate = "Tiff/rgb_palette_deflate.tiff"; public const string Flower4BitPalette = "Tiff/flower-palette-04.tiff"; public const string Flower4BitPaletteGray = "Tiff/flower-minisblack-04.tiff"; + public const string FlowerRgb141414Contiguous = "Tiff/flower-rgb-contig-14.tiff"; + public const string FlowerRgb141414Planar = "Tiff/flower-rgb-planar-14.tiff"; public const string FlowerRgb101010Contiguous = "Tiff/flower-rgb-contig-10.tiff"; public const string FlowerRgb101010Planar = "Tiff/flower-rgb-planar-10.tiff"; public const string FlowerRgb444Contiguous = "Tiff/flower-rgb-contig-04.tiff"; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 30c2214b5..dffbeac49 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -25,10 +25,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { } - public MagickReferenceDecoder(bool validate) - { - this.validate = validate; - } + public MagickReferenceDecoder(bool validate) => this.validate = validate; public static MagickReferenceDecoder Instance { get; } = new MagickReferenceDecoder(); @@ -93,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs FromRgba32Bytes(configuration, data, framePixels); } - else if (magicFrame.Depth == 16) + else if (magicFrame.Depth == 16 || magicFrame.Depth == 14) { ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); diff --git a/tests/Images/Input/Tiff/flower-rgb-contig-14.tiff b/tests/Images/Input/Tiff/flower-rgb-contig-14.tiff new file mode 100644 index 000000000..d4d6a9492 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-contig-14.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a419a8e2f89321501ca8ad70d2a19d37a7bf3a8c2f45c809acc30be59139ae29 +size 16855 diff --git a/tests/Images/Input/Tiff/flower-rgb-planar-14.tiff b/tests/Images/Input/Tiff/flower-rgb-planar-14.tiff new file mode 100644 index 000000000..2d517268e --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-planar-14.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d28f021d40f53a011053f9644400fee2d29c02f97b4101fec899251125dbb18e +size 16855