From 3b4be3631365ab9b3794a63decaf9d0cc18b9a9e Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 4 Jun 2021 18:55:49 +0200 Subject: [PATCH 01/11] Keep BitsPerSample array when decoding tiff, otherwise bits per channel would be ambiguous if we only keep bits per pixel --- .../Formats/Tiff/TiffBitsPerSample.cs | 56 --------- .../Tiff/TiffBitsPerSampleExtensions.cs | 111 ------------------ .../Formats/Tiff/TiffDecoderCore.cs | 12 +- .../Formats/Tiff/TiffDecoderOptionsParser.cs | 54 ++++----- .../Formats/Tiff/TiffFrameMetadata.cs | 9 +- .../Formats/Tiff/TiffMetadataTests.cs | 2 +- 6 files changed, 36 insertions(+), 208 deletions(-) delete mode 100644 src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs delete mode 100644 src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs deleted file mode 100644 index 088ef5d6f..000000000 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Formats.Tiff -{ - /// - /// The number of bits per component. - /// - public enum TiffBitsPerSample - { - /// - /// The Bits per samples is not known. - /// - Unknown = 0, - - /// - /// One bit per sample for bicolor images. - /// - Bit1 = 1, - - /// - /// Four bits per sample for grayscale images with 16 different levels of gray or paletted images with a palette of 16 colors. - /// - Bit4 = 4, - - /// - /// Eight bits per sample for grayscale images with 256 different levels of gray or paletted images with a palette of 256 colors. - /// - Bit8 = 8, - - /// - /// Six bits per sample, each channel has 2 bits. - /// - Bit6 = 6, - - /// - /// Twelve bits per sample, each channel has 4 bits. - /// - Bit12 = 12, - - /// - /// 24 bits per sample, each color channel has 8 Bits. - /// - Bit24 = 24, - - /// - /// 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 deleted file mode 100644 index ca0f0befc..000000000 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using SixLabors.ImageSharp.Formats.Tiff.Constants; - -namespace SixLabors.ImageSharp.Formats.Tiff -{ - internal static class TiffBitsPerSampleExtensions - { - /// - /// Gets the bits per channel array for a given BitsPerSample value, e,g, for RGB888: [8, 8, 8] - /// - /// The tiff bits per sample. - /// Bits per sample array. - public static ushort[] Bits(this TiffBitsPerSample tiffBitsPerSample) - { - switch (tiffBitsPerSample) - { - case TiffBitsPerSample.Bit1: - return TiffConstants.BitsPerSample1Bit; - case TiffBitsPerSample.Bit4: - return TiffConstants.BitsPerSample4Bit; - case TiffBitsPerSample.Bit6: - return TiffConstants.BitsPerSampleRgb2Bit; - case TiffBitsPerSample.Bit8: - return TiffConstants.BitsPerSample8Bit; - case TiffBitsPerSample.Bit12: - return TiffConstants.BitsPerSampleRgb4Bit; - case TiffBitsPerSample.Bit24: - return TiffConstants.BitsPerSampleRgb8Bit; - case TiffBitsPerSample.Bit30: - return TiffConstants.BitsPerSampleRgb10Bit; - case TiffBitsPerSample.Bit42: - return TiffConstants.BitsPerSampleRgb14Bit; - - default: - return Array.Empty(); - } - } - - /// - /// Maps an array of bits per sample to a concrete enum value. - /// - /// The bits per sample array. - /// TiffBitsPerSample enum value. - public static TiffBitsPerSample GetBitsPerSample(this ushort[] bitsPerSample) - { - 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]) - { - return TiffBitsPerSample.Bit30; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb8Bit[2] && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb8Bit[1] && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb8Bit[0]) - { - return TiffBitsPerSample.Bit24; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb4Bit[2] && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb4Bit[1] && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb4Bit[0]) - { - return TiffBitsPerSample.Bit12; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb2Bit[2] && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb2Bit[1] && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb2Bit[0]) - { - return TiffBitsPerSample.Bit6; - } - - break; - - case 1: - if (bitsPerSample[0] == TiffConstants.BitsPerSample1Bit[0]) - { - return TiffBitsPerSample.Bit1; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample4Bit[0]) - { - return TiffBitsPerSample.Bit4; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample8Bit[0]) - { - return TiffBitsPerSample.Bit8; - } - - break; - } - - return TiffBitsPerSample.Unknown; - } - } -} diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index fadb4f7c2..294407ef9 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -50,9 +50,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff } /// - /// Gets or sets the number of bits per component of the pixel format used to decode the image. + /// Gets or sets the bits per sample. /// - public TiffBitsPerSample BitsPerSample { get; set; } + public ushort[] BitsPerSample { get; set; } /// /// Gets or sets the bits per pixel. @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff } else { - bitsPerPixel = this.BitsPerSample.Bits()[plane]; + bitsPerPixel = this.BitsPerSample[plane]; } int bytesPerRow = ((width * bitsPerPixel) + 7) / 8; @@ -225,7 +225,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts) where TPixel : unmanaged, IPixel { - int stripsPerPixel = this.BitsPerSample.Bits().Length; + int stripsPerPixel = this.BitsPerSample.Length; int stripsPerPlane = stripOffsets.Length / stripsPerPixel; int bitsPerPixel = this.BitsPerPixel; @@ -243,7 +243,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions); - RgbPlanarTiffColor colorDecoder = TiffColorDecoderFactory.CreatePlanar(this.ColorType, this.BitsPerSample.Bits(), this.ColorMap); + RgbPlanarTiffColor colorDecoder = TiffColorDecoderFactory.CreatePlanar(this.ColorType, this.BitsPerSample, this.ColorMap); for (int i = 0; i < stripsPerPlane; i++) { @@ -286,7 +286,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions); - TiffBaseColorDecoder colorDecoder = TiffColorDecoderFactory.Create(this.ColorType, this.BitsPerSample.Bits(), this.ColorMap); + TiffBaseColorDecoder colorDecoder = TiffColorDecoderFactory.Create(this.ColorType, this.BitsPerSample, this.ColorMap); for (int stripIndex = 0; stripIndex < stripOffsets.Length; stripIndex++) { diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index eeac6a33c..a71c4cb05 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff options.Predictor = frameMetadata.Predictor ?? TiffPredictor.None; options.PhotometricInterpretation = frameMetadata.PhotometricInterpretation ?? TiffPhotometricInterpretation.Rgb; options.BitsPerPixel = frameMetadata.BitsPerPixel != null ? (int)frameMetadata.BitsPerPixel.Value : (int)TiffBitsPerPixel.Bit24; - options.BitsPerSample = GetBitsPerSample(frameMetadata.BitsPerPixel); + options.BitsPerSample = frameMetadata.BitsPerSample ?? Array.Empty(); options.ParseColorType(exifProfile); options.ParseCompression(frameMetadata.Compression, exifProfile); @@ -99,26 +99,27 @@ namespace SixLabors.ImageSharp.Formats.Tiff { case TiffPhotometricInterpretation.WhiteIsZero: { - if (options.BitsPerSample.Bits().Length != 1) + if (options.BitsPerSample.Length != 1) { TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); } - switch (options.BitsPerSample) + ushort bitsPerChannel = options.BitsPerSample[0]; + switch (bitsPerChannel) { - case TiffBitsPerSample.Bit8: + case 8: { options.ColorType = TiffColorType.WhiteIsZero8; break; } - case TiffBitsPerSample.Bit4: + case 4: { options.ColorType = TiffColorType.WhiteIsZero4; break; } - case TiffBitsPerSample.Bit1: + case 1: { options.ColorType = TiffColorType.WhiteIsZero1; break; @@ -136,26 +137,27 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffPhotometricInterpretation.BlackIsZero: { - if (options.BitsPerSample.Bits().Length != 1) + if (options.BitsPerSample.Length != 1) { TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); } - switch (options.BitsPerSample) + ushort bitsPerChannel = options.BitsPerSample[0]; + switch (bitsPerChannel) { - case TiffBitsPerSample.Bit8: + case 8: { options.ColorType = TiffColorType.BlackIsZero8; break; } - case TiffBitsPerSample.Bit4: + case 4: { options.ColorType = TiffColorType.BlackIsZero4; break; } - case TiffBitsPerSample.Bit1: + case 1: { options.ColorType = TiffColorType.BlackIsZero1; break; @@ -173,30 +175,31 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffPhotometricInterpretation.Rgb: { - if (options.BitsPerSample.Bits().Length != 3) + if (options.BitsPerSample.Length != 3) { TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); } if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky) { - switch (options.BitsPerSample) + ushort bitsPerChannel = options.BitsPerSample[0]; + switch (bitsPerChannel) { - case TiffBitsPerSample.Bit42: + case 14: options.ColorType = TiffColorType.Rgb141414; break; - case TiffBitsPerSample.Bit30: + case 10: options.ColorType = TiffColorType.Rgb101010; break; - case TiffBitsPerSample.Bit24: + case 8: options.ColorType = TiffColorType.Rgb888; break; - case TiffBitsPerSample.Bit12: + case 4: options.ColorType = TiffColorType.Rgb444; break; - case TiffBitsPerSample.Bit6: + case 2: options.ColorType = TiffColorType.Rgb222; break; default: @@ -217,7 +220,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff options.ColorMap = exifProfile.GetValue(ExifTag.ColorMap)?.Value; if (options.ColorMap != null) { - if (options.BitsPerSample.Bits().Length != 1) + if (options.BitsPerSample.Length != 1) { TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); } @@ -291,18 +294,5 @@ namespace SixLabors.ImageSharp.Formats.Tiff } } } - - private static TiffBitsPerSample GetBitsPerSample(TiffBitsPerPixel? bitsPerPixel) => bitsPerPixel switch - { - TiffBitsPerPixel.Bit1 => TiffBitsPerSample.Bit1, - TiffBitsPerPixel.Bit4 => TiffBitsPerSample.Bit4, - TiffBitsPerPixel.Bit6 => TiffBitsPerSample.Bit6, - TiffBitsPerPixel.Bit8 => TiffBitsPerSample.Bit8, - 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/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index 25a0578e9..ef7573d3e 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs @@ -35,6 +35,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// public TiffBitsPerPixel? BitsPerPixel { get; set; } + /// + /// Gets or sets number of bits per component. + /// + public ushort[] BitsPerSample { get; set; } + /// /// Gets or sets the compression scheme used on the image data. /// @@ -72,8 +77,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff { if (profile != null) { - ushort[] bitsPerSample = profile.GetValue(ExifTag.BitsPerSample)?.Value; - meta.BitsPerPixel = BitsPerPixelFromBitsPerSample(bitsPerSample); + meta.BitsPerSample = profile.GetValue(ExifTag.BitsPerSample)?.Value; + meta.BitsPerPixel = BitsPerPixelFromBitsPerSample(meta.BitsPerSample); meta.Compression = (TiffCompression?)profile.GetValue(ExifTag.Compression)?.Value; meta.PhotometricInterpretation = (TiffPhotometricInterpretation?)profile.GetValue(ExifTag.PhotometricInterpretation)?.Value; diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs index ab350f720..c80d9fc16 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff { Assert.NotNull(frameMetaData); Assert.NotNull(frameMetaData.BitsPerPixel); - Assert.Equal(TiffBitsPerSample.Bit4, (TiffBitsPerSample)frameMetaData.BitsPerPixel); + Assert.Equal(TiffBitsPerPixel.Bit4, frameMetaData.BitsPerPixel); Assert.Equal(TiffCompression.Lzw, frameMetaData.Compression); Assert.Equal(TiffPhotometricInterpretation.PaletteColor, frameMetaData.PhotometricInterpretation); Assert.Equal(TiffPredictor.None, frameMetaData.Predictor); From 3b18d705e3e90b4cb4f83ceb59a4e88afffd2f20 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 5 Jun 2021 08:31:46 +0200 Subject: [PATCH 02/11] Additional tests for gray tiff images --- .../Formats/Tiff/TiffBitsPerPixel.cs | 21 ++++++++++++ .../Formats/Tiff/TiffEncoderCore.cs | 5 ++- .../Formats/Tiff/TiffDecoderTests.cs | 32 +++++++++++++++++++ .../Formats/Tiff/TiffEncoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 8 +++++ .../ReferenceCodecs/MagickReferenceDecoder.cs | 2 +- .../Input/Tiff/flower-minisblack-02.tiff | 3 ++ .../Input/Tiff/flower-minisblack-06.tiff | 3 ++ .../Input/Tiff/flower-minisblack-08.tiff | 3 ++ .../Input/Tiff/flower-minisblack-10.tiff | 3 ++ .../Input/Tiff/flower-minisblack-12.tiff | 3 ++ .../Input/Tiff/flower-minisblack-14.tiff | 3 ++ .../Input/Tiff/flower-minisblack-16.tiff | 3 ++ .../Images/Input/Tiff/flower-palette-02.tiff | 3 ++ 14 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 tests/Images/Input/Tiff/flower-minisblack-02.tiff create mode 100644 tests/Images/Input/Tiff/flower-minisblack-06.tiff create mode 100644 tests/Images/Input/Tiff/flower-minisblack-08.tiff create mode 100644 tests/Images/Input/Tiff/flower-minisblack-10.tiff create mode 100644 tests/Images/Input/Tiff/flower-minisblack-12.tiff create mode 100644 tests/Images/Input/Tiff/flower-minisblack-14.tiff create mode 100644 tests/Images/Input/Tiff/flower-minisblack-16.tiff create mode 100644 tests/Images/Input/Tiff/flower-palette-02.tiff diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs index ab9f3cbec..d2a57e7b8 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs @@ -30,6 +30,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Bit8 = 8, + /// + /// 10 bits per pixel, for gray images. + /// + /// Note: The TiffEncoder does not yet support 10 bits per pixel and will default to 24 bits per pixel instead. + /// + Bit10 = 10, + /// /// 12 bits per pixel. 4 bit for each color channel. /// @@ -37,6 +44,20 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Bit12 = 12, + /// + /// 14 bits per pixel, for gray images. + /// + /// Note: The TiffEncoder does not yet support 14 bits per pixel images and will default to 24 bits per pixel instead. + /// + Bit14 = 14, + + /// + /// 16 bits per pixel, for gray images. + /// + /// Note: The TiffEncoder does not yet support 16 bits per color channel and will default to 24 bits per pixel instead. + /// + Bit16 = 16, + /// /// 24 bits per pixel. One byte for each color channel. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index d5137c435..047575c87 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -320,10 +320,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff this.SetEncoderOptions(bitsPerPixel, photometricInterpretation ?? TiffPhotometricInterpretation.BlackIsZero, compression, predictor); break; case TiffBitsPerPixel.Bit6: + case TiffBitsPerPixel.Bit10: case TiffBitsPerPixel.Bit12: + case TiffBitsPerPixel.Bit14: + case TiffBitsPerPixel.Bit16: case TiffBitsPerPixel.Bit30: case TiffBitsPerPixel.Bit42: - // Encoding 42, 30, 12 and 6 bits per pixel is not yet supported. Default to 24 bits. + // Encoding not yet supported bits per pixel will 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 02b7f97d9..04749159d 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -99,18 +99,50 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff public void TiffDecoder_CanDecode_4Bit_WithPalette(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider, ReferenceDecoder, useExactComparer: false, 0.01f); + [Theory] + [WithFile(Flower2BitPalette, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_2Bit_WithPalette(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider, ReferenceDecoder, useExactComparer: false, 0.01f); + + [Theory] + [WithFile(Flower2BitGray, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_2Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] [WithFile(FlowerRgb222Contiguous, PixelTypes.Rgba32)] [WithFile(FlowerRgb222Planar, PixelTypes.Rgba32)] + [WithFile(Flower6BitGray, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_6Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] + [WithFile(Flower8BitGray, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_8Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + + [Theory] + [WithFile(Flower10BitGray, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_10Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] [WithFile(FlowerRgb444Contiguous, PixelTypes.Rgba32)] [WithFile(FlowerRgb444Planar, PixelTypes.Rgba32)] + [WithFile(Flower12BitGray, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_12Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] + [WithFile(Flower14BitGray, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_14Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + + [Theory] + [WithFile(Flower16BitGray, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_16Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] [WithFile(FlowerRgb101010Contiguous, PixelTypes.Rgba32)] [WithFile(FlowerRgb101010Planar, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 7c386a6a9..9d360fb7e 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -81,6 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [InlineData(TiffBitsPerPixel.Bit42)] [InlineData(TiffBitsPerPixel.Bit30)] [InlineData(TiffBitsPerPixel.Bit12)] + [InlineData(TiffBitsPerPixel.Bit10)] [InlineData(TiffBitsPerPixel.Bit6)] public void EncoderOptions_UnsupportedBitPerPixel_DefaultTo24Bits(TiffBitsPerPixel bitsPerPixel) { diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 9471a6393..e31a1cf5c 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -568,6 +568,14 @@ namespace SixLabors.ImageSharp.Tests public const string FlowerRgb444Planar = "Tiff/flower-rgb-planar-04.tiff"; public const string FlowerRgb222Contiguous = "Tiff/flower-rgb-contig-02.tiff"; public const string FlowerRgb222Planar = "Tiff/flower-rgb-planar-02.tiff"; + public const string Flower2BitGray = "Tiff/flower-minisblack-02.tiff"; + public const string Flower2BitPalette = "Tiff/flower-palette-02.tiff"; + public const string Flower6BitGray = "Tiff/flower-minisblack-06.tiff"; + public const string Flower8BitGray = "Tiff/flower-minisblack-08.tiff"; + public const string Flower10BitGray = "Tiff/flower-minisblack-10.tiff"; + public const string Flower12BitGray = "Tiff/flower-minisblack-12.tiff"; + public const string Flower14BitGray = "Tiff/flower-minisblack-14.tiff"; + public const string Flower16BitGray = "Tiff/flower-minisblack-16.tiff"; public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff"; public const string SmallRgbLzw = "Tiff/rgb_small_lzw.tiff"; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index dffbeac49..294bd20fb 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs MemoryGroup framePixels = frame.PixelBuffer.FastMemoryGroup; using IUnsafePixelCollection pixels = magicFrame.GetPixelsUnsafe(); - if (magicFrame.Depth == 8 || magicFrame.Depth == 4 || magicFrame.Depth == 2 || magicFrame.Depth == 1 || magicFrame.Depth == 10) + if (magicFrame.Depth == 8 || magicFrame.Depth == 6 || magicFrame.Depth == 4 || magicFrame.Depth == 2 || magicFrame.Depth == 1 || magicFrame.Depth == 10 || magicFrame.Depth == 12) { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); diff --git a/tests/Images/Input/Tiff/flower-minisblack-02.tiff b/tests/Images/Input/Tiff/flower-minisblack-02.tiff new file mode 100644 index 000000000..d6ce305fe --- /dev/null +++ b/tests/Images/Input/Tiff/flower-minisblack-02.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3122afede012fa00b8cb379b2f9125a34a38188c3346ec5e18d3b4bddcbb451b +size 1131 diff --git a/tests/Images/Input/Tiff/flower-minisblack-06.tiff b/tests/Images/Input/Tiff/flower-minisblack-06.tiff new file mode 100644 index 000000000..53db4e112 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-minisblack-06.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0c13012d8d35215b01192eb38058db4543486c60b4918beec8719a94d1e208e +size 2679 diff --git a/tests/Images/Input/Tiff/flower-minisblack-08.tiff b/tests/Images/Input/Tiff/flower-minisblack-08.tiff new file mode 100644 index 000000000..02acb1511 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-minisblack-08.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1268d843a2338409ec3a9f5a5a62e23d38c3a898035619994a02f21eff7590bf +size 3453 diff --git a/tests/Images/Input/Tiff/flower-minisblack-10.tiff b/tests/Images/Input/Tiff/flower-minisblack-10.tiff new file mode 100644 index 000000000..770197726 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-minisblack-10.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a91d6946730604dd65c63f1653fb33031682f26218de33ebf3d0b362cb6883af +size 4269 diff --git a/tests/Images/Input/Tiff/flower-minisblack-12.tiff b/tests/Images/Input/Tiff/flower-minisblack-12.tiff new file mode 100644 index 000000000..320083c32 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-minisblack-12.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86fc9309872f4e4668350b95fae315d878ec9658046d738050a2743f5fa44446 +size 5043 diff --git a/tests/Images/Input/Tiff/flower-minisblack-14.tiff b/tests/Images/Input/Tiff/flower-minisblack-14.tiff new file mode 100644 index 000000000..34fca95b5 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-minisblack-14.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dcd07668c73f24c2a13133ac4910b59a568502a6d3762675eef61a7e3b090165 +size 5817 diff --git a/tests/Images/Input/Tiff/flower-minisblack-16.tiff b/tests/Images/Input/Tiff/flower-minisblack-16.tiff new file mode 100644 index 000000000..0791941f9 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-minisblack-16.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79531a10710dee89b86e2467818b7c03a24ff28ebd98c7bdcc292559671e1887 +size 6591 diff --git a/tests/Images/Input/Tiff/flower-palette-02.tiff b/tests/Images/Input/Tiff/flower-palette-02.tiff new file mode 100644 index 000000000..eb80e4de8 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-palette-02.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75e74d8816942ff6e9dfda411f9171f0f1dd1a5a88cb1410238b55a2b2aeeb71 +size 1164 From bbd71e2ce756d9cbc37c269bf88814a0f3eadb2a Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 5 Jun 2021 15:36:59 +0200 Subject: [PATCH 03/11] Add support decoding for 12 bits per channel tiff's --- .../TiffColorDecoderFactory{TPixel}.cs | 10 ++++++++++ .../Tiff/PhotometricInterpretation/TiffColorType.cs | 5 +++++ src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs | 7 +++++++ .../Formats/Tiff/TiffDecoderOptionsParser.cs | 4 ++++ src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs | 1 + .../ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 5 +++++ .../ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Tiff/flower-rgb-contig-12.tiff | 3 +++ 9 files changed, 37 insertions(+) create mode 100644 tests/Images/Input/Tiff/flower-rgb-contig-12.tiff diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs index 5555eb537..548ee2d4d 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.Rgb121212: + DebugGuard.IsTrue( + bitsPerSample.Length == 3 + && bitsPerSample[2] == 12 + && bitsPerSample[1] == 12 + && bitsPerSample[0] == 12, + "bitsPerSample"); + DebugGuard.IsTrue(colorMap == null, "colorMap"); + return new RgbTiffColor(bitsPerSample); + case TiffColorType.Rgb141414: DebugGuard.IsTrue( bitsPerSample.Length == 3 diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs index 22d819953..37a878fed 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 12 bits for each channel. + /// + Rgb121212, + /// /// RGB color image with 14 bits for each channel. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs index d2a57e7b8..08f0777ea 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs @@ -70,6 +70,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Bit30 = 30, + /// + /// 36 bits per pixel. 12 bit for each color channel. + /// + /// Note: The TiffEncoder does not yet support 12 bits per color channel and will default to 24 bits per pixel instead. + /// + Bit36 = 36, + /// /// 42 bits per pixel. 14 bit for each color channel. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index a71c4cb05..8b7e0cf45 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -189,6 +189,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff options.ColorType = TiffColorType.Rgb141414; break; + case 12: + options.ColorType = TiffColorType.Rgb121212; + break; + case 10: options.ColorType = TiffColorType.Rgb101010; break; diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index 047575c87..281f61c7f 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -325,6 +325,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffBitsPerPixel.Bit14: case TiffBitsPerPixel.Bit16: case TiffBitsPerPixel.Bit30: + case TiffBitsPerPixel.Bit36: case TiffBitsPerPixel.Bit42: // Encoding not yet supported bits per pixel will default to 24 bits. this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, TiffPredictor.None); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 04749159d..9b2cd9a00 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -149,6 +149,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff public void TiffDecoder_CanDecode_30Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] + [WithFile(FlowerRgb121212Contiguous, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_36Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] [WithFile(FlowerRgb141414Contiguous, PixelTypes.Rgba32)] [WithFile(FlowerRgb141414Planar, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 9d360fb7e..f722f5384 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -79,6 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [Theory] [InlineData(TiffBitsPerPixel.Bit42)] + [InlineData(TiffBitsPerPixel.Bit36)] [InlineData(TiffBitsPerPixel.Bit30)] [InlineData(TiffBitsPerPixel.Bit12)] [InlineData(TiffBitsPerPixel.Bit10)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index e31a1cf5c..00d0a0219 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -564,6 +564,7 @@ namespace SixLabors.ImageSharp.Tests 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 FlowerRgb121212Contiguous = "Tiff/flower-rgb-contig-12.tiff"; public const string FlowerRgb444Contiguous = "Tiff/flower-rgb-contig-04.tiff"; public const string FlowerRgb444Planar = "Tiff/flower-rgb-planar-04.tiff"; public const string FlowerRgb222Contiguous = "Tiff/flower-rgb-contig-02.tiff"; diff --git a/tests/Images/Input/Tiff/flower-rgb-contig-12.tiff b/tests/Images/Input/Tiff/flower-rgb-contig-12.tiff new file mode 100644 index 000000000..c890c777a --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-contig-12.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f7a63eb8636e2b1ee39dfda4d0bddfc98bdc9eb94bea2dd657619331fa38b5b +size 14483 From 6281743b3bb36d2f7331832f87f2ad0f51da61ee Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 5 Jun 2021 16:47:34 +0200 Subject: [PATCH 04/11] Add support decoding for 16 bits per channel tiff's --- .../TiffColorDecoderFactory{TPixel}.cs | 10 ++++++++++ .../Tiff/PhotometricInterpretation/TiffColorType.cs | 5 +++++ src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs | 7 +++++++ .../Formats/Tiff/TiffDecoderOptionsParser.cs | 4 ++++ src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs | 1 + .../ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 6 ++++++ .../ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 2 ++ tests/Images/Input/Tiff/flower-rgb-contig-16.tiff | 3 +++ tests/Images/Input/Tiff/flower-rgb-planar-16.tiff | 3 +++ 10 files changed, 42 insertions(+) create mode 100644 tests/Images/Input/Tiff/flower-rgb-contig-16.tiff create mode 100644 tests/Images/Input/Tiff/flower-rgb-planar-16.tiff diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs index 548ee2d4d..4ca7ed915 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs @@ -117,6 +117,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); + case TiffColorType.Rgb161616: + DebugGuard.IsTrue( + bitsPerSample.Length == 3 + && bitsPerSample[2] == 16 + && bitsPerSample[1] == 16 + && bitsPerSample[0] == 16, + "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 37a878fed..517926c23 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs @@ -88,6 +88,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation /// Rgb141414, + /// + /// RGB color image with 16 bits for each channel. + /// + Rgb161616, + /// /// RGB Full Color. Planar configuration of data. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs index 08f0777ea..73f3f4b77 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs @@ -83,5 +83,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Note: The TiffEncoder does not yet support 14 bits per color channel and will default to 24 bits per pixel instead. /// Bit42 = 42, + + /// + /// 48 bits per pixel. 16 bit for each color channel. + /// + /// Note: The TiffEncoder does not yet support 16 bits per color channel and will default to 24 bits per pixel instead. + /// + Bit48 = 48, } } diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 8b7e0cf45..3ba64b18c 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -185,6 +185,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff ushort bitsPerChannel = options.BitsPerSample[0]; switch (bitsPerChannel) { + case 16: + options.ColorType = TiffColorType.Rgb161616; + break; + case 14: options.ColorType = TiffColorType.Rgb141414; break; diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index 281f61c7f..2273d759f 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -327,6 +327,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffBitsPerPixel.Bit30: case TiffBitsPerPixel.Bit36: case TiffBitsPerPixel.Bit42: + case TiffBitsPerPixel.Bit48: // Encoding not yet supported bits per pixel will default to 24 bits. this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, TiffPredictor.None); break; diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 9b2cd9a00..6b82f4281 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -160,6 +160,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff public void TiffDecoder_CanDecode_42Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] + [WithFile(FlowerRgb161616Contiguous, PixelTypes.Rgba32)] + [WithFile(FlowerRgb161616Planar, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_48Bit(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 f722f5384..acbed8ac2 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.Bit48)] [InlineData(TiffBitsPerPixel.Bit42)] [InlineData(TiffBitsPerPixel.Bit36)] [InlineData(TiffBitsPerPixel.Bit30)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 00d0a0219..28ef20cf4 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 FlowerRgb161616Contiguous = "Tiff/flower-rgb-contig-16.tiff"; + public const string FlowerRgb161616Planar = "Tiff/flower-rgb-planar-16.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"; diff --git a/tests/Images/Input/Tiff/flower-rgb-contig-16.tiff b/tests/Images/Input/Tiff/flower-rgb-contig-16.tiff new file mode 100644 index 000000000..125de5b9f --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-contig-16.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab3d6b619a198ff2e5fdd8f9752bf43c5b03a782625b1f0e3f2cfe0f20c4b24a +size 19177 diff --git a/tests/Images/Input/Tiff/flower-rgb-planar-16.tiff b/tests/Images/Input/Tiff/flower-rgb-planar-16.tiff new file mode 100644 index 000000000..939fd9471 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-planar-16.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a143fb6c5792fa7755e06feb757c745ad68944336985dc5be8a0c37247fe36d +size 19177 From aba1050bae1a1dc0aee0a72d275933a8f6b41254 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 5 Jun 2021 17:11:35 +0200 Subject: [PATCH 05/11] Throw exception for single channel tiff when bits per sample is larger then 16 --- .../Formats/Tiff/TiffDecoderOptionsParser.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 3ba64b18c..014dd5538 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -105,6 +105,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff } ushort bitsPerChannel = options.BitsPerSample[0]; + if (bitsPerChannel > 16) + { + TiffThrowHelper.ThrowNotSupported("Bits per sample is not supported."); + } + switch (bitsPerChannel) { case 8: @@ -143,6 +148,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff } ushort bitsPerChannel = options.BitsPerSample[0]; + if (bitsPerChannel > 16) + { + TiffThrowHelper.ThrowNotSupported("Bits per sample is not supported."); + } + switch (bitsPerChannel) { case 8: From 67f7b78293ab0d4bd7798ca7837c54f71352f1e2 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 11 Jun 2021 12:25:13 +0200 Subject: [PATCH 06/11] Re-Introduce TiffBitsPerSample --- .../Formats/Tiff/Constants/TiffConstants.cs | 40 +++++ .../Formats/Tiff/TiffBitsPerSample.cs | 96 ++++++++++ .../Tiff/TiffBitsPerSampleExtensions.cs | 170 ++++++++++++++++++ .../Formats/Tiff/TiffDecoderOptionsParser.cs | 2 +- .../Formats/Tiff/TiffFrameMetadata.cs | 9 +- tests/ImageSharp.Tests/TestImages.cs | 4 +- 6 files changed, 313 insertions(+), 8 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs create mode 100644 src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index 6fe412b92..5733bada9 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -85,16 +85,46 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants /// public static readonly ushort[] BitsPerSample1Bit = { 1 }; + /// + /// The bits per sample for images with a 2 color palette. + /// + public static readonly ushort[] BitsPerSample2Bit = { 2 }; + /// /// The bits per sample for images with a 4 color palette. /// public static readonly ushort[] BitsPerSample4Bit = { 4 }; + /// + /// The bits per sample for 6 bit gray images. + /// + public static readonly ushort[] BitsPerSample6Bit = { 6 }; + /// /// The bits per sample for 8 bit images. /// public static readonly ushort[] BitsPerSample8Bit = { 8 }; + /// + /// The bits per sample for 10 bit gray images. + /// + public static readonly ushort[] BitsPerSample10Bit = { 10 }; + + /// + /// The bits per sample for 12 bit gray images. + /// + public static readonly ushort[] BitsPerSample12Bit = { 12 }; + + /// + /// The bits per sample for 14 bit gray images. + /// + public static readonly ushort[] BitsPerSample14Bit = { 14 }; + + /// + /// The bits per sample for 16 bit gray images. + /// + public static readonly ushort[] BitsPerSample16Bit = { 16 }; + /// /// The bits per sample for color images with 2 bits for each color channel. /// @@ -115,11 +145,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants /// public static readonly ushort[] BitsPerSampleRgb10Bit = { 10, 10, 10 }; + /// + /// The bits per sample for color images with 12 bits for each color channel. + /// + public static readonly ushort[] BitsPerSampleRgb12Bit = { 12, 12, 12 }; + /// /// The bits per sample for color images with 14 bits for each color channel. /// public static readonly ushort[] BitsPerSampleRgb14Bit = { 14, 14, 14 }; + /// + /// The bits per sample for color images with 14 bits for each color channel. + /// + public static readonly ushort[] BitsPerSampleRgb16Bit = { 16, 16, 16 }; + /// /// The list of mimetypes that equate to a tiff. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs new file mode 100644 index 000000000..71f6b5bf9 --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs @@ -0,0 +1,96 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Tiff +{ + /// + /// The number of bits per component. + /// + public enum TiffBitsPerSample + { + /// + /// The bits per samples is not known. + /// + Unknown = 0, + + /// + /// One bit per sample for bicolor images. + /// + Bit1, + + /// + /// Two bits per sample for grayscale images with 4 different levels of gray or paletted images with a palette of 4 colors. + /// + Bit2, + + /// + /// Four bits per sample for grayscale images with 16 different levels of gray or paletted images with a palette of 16 colors. + /// + Bit4, + + /// + /// Six bits per sample for grayscale images. + /// + Bit6, + + /// + /// Eight bits per sample for grayscale images with 256 different levels of gray or paletted images with a palette of 256 colors. + /// + Bit8, + + /// + /// Ten bits per sample for grayscale images. + /// + Bit10, + + /// + /// Twelve bits per sample for grayscale images. + /// + Bit12, + + /// + /// Fourteen bits per sample for grayscale images. + /// + Bit14, + + /// + /// Sixteen bits per sample for grayscale images. + /// + Bit16, + + /// + /// 6 bits per sample, each channel has 2 bits. + /// + Rgb222, + + /// + /// Twelve bits per sample, each channel has 4 bits. + /// + Rgb444, + + /// + /// 24 bits per sample, each color channel has 8 Bits. + /// + Rgb888, + + /// + /// Thirty bits per sample, each channel has 10 bits. + /// + Rgb101010, + + /// + /// Thirty six bits per sample, each channel has 12 bits. + /// + Rgb121212, + + /// + /// Forty two bits per sample, each channel has 14 bits. + /// + Rgb141414, + + /// + /// Forty eight bits per sample, each channel has 16 bits. + /// + Rgb161616, + } +} diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs new file mode 100644 index 000000000..5ec1331b3 --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs @@ -0,0 +1,170 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.Formats.Tiff.Constants; + +namespace SixLabors.ImageSharp.Formats.Tiff +{ + internal static class TiffBitsPerSampleExtensions + { + /// + /// Gets the bits per channel array for a given BitsPerSample value, e,g, for RGB888: [8, 8, 8] + /// + /// The tiff bits per sample. + /// Bits per sample array. + public static ushort[] BitsPerChannel(this TiffBitsPerSample tiffBitsPerSample) + { + switch (tiffBitsPerSample) + { + case TiffBitsPerSample.Bit1: + return TiffConstants.BitsPerSample1Bit; + case TiffBitsPerSample.Bit2: + return TiffConstants.BitsPerSample2Bit; + case TiffBitsPerSample.Bit4: + return TiffConstants.BitsPerSample4Bit; + case TiffBitsPerSample.Bit6: + return TiffConstants.BitsPerSample6Bit; + case TiffBitsPerSample.Bit8: + return TiffConstants.BitsPerSample8Bit; + case TiffBitsPerSample.Bit10: + return TiffConstants.BitsPerSample10Bit; + case TiffBitsPerSample.Bit12: + return TiffConstants.BitsPerSample12Bit; + case TiffBitsPerSample.Bit14: + return TiffConstants.BitsPerSample14Bit; + case TiffBitsPerSample.Bit16: + return TiffConstants.BitsPerSample16Bit; + case TiffBitsPerSample.Rgb222: + return TiffConstants.BitsPerSampleRgb2Bit; + case TiffBitsPerSample.Rgb444: + return TiffConstants.BitsPerSampleRgb4Bit; + case TiffBitsPerSample.Rgb888: + return TiffConstants.BitsPerSampleRgb8Bit; + case TiffBitsPerSample.Rgb101010: + return TiffConstants.BitsPerSampleRgb10Bit; + case TiffBitsPerSample.Rgb121212: + return TiffConstants.BitsPerSampleRgb12Bit; + case TiffBitsPerSample.Rgb141414: + return TiffConstants.BitsPerSampleRgb14Bit; + case TiffBitsPerSample.Rgb161616: + return TiffConstants.BitsPerSampleRgb16Bit; + default: + return Array.Empty(); + } + } + + /// + /// Maps an array of bits per sample to a concrete enum value. + /// + /// The bits per sample array. + /// TiffBitsPerSample enum value. + public static TiffBitsPerSample GetBitsPerSample(this ushort[] bitsPerSample) + { + switch (bitsPerSample.Length) + { + case 3: + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb16Bit[2] && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb16Bit[1] && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb16Bit[0]) + { + return TiffBitsPerSample.Rgb161616; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb14Bit[2] && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb14Bit[1] && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb14Bit[0]) + { + return TiffBitsPerSample.Rgb141414; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb12Bit[2] && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb12Bit[1] && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb12Bit[0]) + { + return TiffBitsPerSample.Rgb121212; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb10Bit[2] && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb10Bit[1] && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb10Bit[0]) + { + return TiffBitsPerSample.Rgb101010; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb8Bit[2] && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb8Bit[1] && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb8Bit[0]) + { + return TiffBitsPerSample.Rgb888; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb4Bit[2] && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb4Bit[1] && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb4Bit[0]) + { + return TiffBitsPerSample.Rgb444; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb2Bit[2] && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb2Bit[1] && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb2Bit[0]) + { + return TiffBitsPerSample.Rgb222; + } + + break; + + case 1: + if (bitsPerSample[0] == TiffConstants.BitsPerSample1Bit[0]) + { + return TiffBitsPerSample.Bit1; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample2Bit[0]) + { + return TiffBitsPerSample.Bit2; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample4Bit[0]) + { + return TiffBitsPerSample.Bit4; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample6Bit[0]) + { + return TiffBitsPerSample.Bit6; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample8Bit[0]) + { + return TiffBitsPerSample.Bit8; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample10Bit[0]) + { + return TiffBitsPerSample.Bit10; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample12Bit[0]) + { + return TiffBitsPerSample.Bit12; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample14Bit[0]) + { + return TiffBitsPerSample.Bit14; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample16Bit[0]) + { + return TiffBitsPerSample.Bit16; + } + + break; + } + + return TiffBitsPerSample.Unknown; + } + } +} diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 014dd5538..1efc82602 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff options.Predictor = frameMetadata.Predictor ?? TiffPredictor.None; options.PhotometricInterpretation = frameMetadata.PhotometricInterpretation ?? TiffPhotometricInterpretation.Rgb; options.BitsPerPixel = frameMetadata.BitsPerPixel != null ? (int)frameMetadata.BitsPerPixel.Value : (int)TiffBitsPerPixel.Bit24; - options.BitsPerSample = frameMetadata.BitsPerSample ?? Array.Empty(); + options.BitsPerSample = frameMetadata.BitsPerSample != null ? frameMetadata.BitsPerSample?.BitsPerChannel() : Array.Empty(); options.ParseColorType(exifProfile); options.ParseCompression(frameMetadata.Compression, exifProfile); diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index ef7573d3e..62e9fb4e2 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// /// Gets or sets number of bits per component. /// - public ushort[] BitsPerSample { get; set; } + public TiffBitsPerSample? BitsPerSample { get; set; } /// /// Gets or sets the compression scheme used on the image data. @@ -77,11 +77,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff { if (profile != null) { - meta.BitsPerSample = profile.GetValue(ExifTag.BitsPerSample)?.Value; - meta.BitsPerPixel = BitsPerPixelFromBitsPerSample(meta.BitsPerSample); + meta.BitsPerSample = profile.GetValue(ExifTag.BitsPerSample) != null ? profile.GetValue(ExifTag.BitsPerSample)?.Value.GetBitsPerSample() : null; + meta.BitsPerPixel = BitsPerPixelFromBitsPerSample(meta.BitsPerSample?.BitsPerChannel()); meta.Compression = (TiffCompression?)profile.GetValue(ExifTag.Compression)?.Value; - meta.PhotometricInterpretation = - (TiffPhotometricInterpretation?)profile.GetValue(ExifTag.PhotometricInterpretation)?.Value; + meta.PhotometricInterpretation = (TiffPhotometricInterpretation?)profile.GetValue(ExifTag.PhotometricInterpretation)?.Value; meta.Predictor = (TiffPredictor?)profile.GetValue(ExifTag.Predictor)?.Value; profile.RemoveValue(ExifTag.BitsPerSample); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 28ef20cf4..7eca4795d 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -558,8 +558,6 @@ namespace SixLabors.ImageSharp.Tests public const string RgbPalette = "Tiff/rgb_palette.tiff"; public const string Rgb4BitPalette = "Tiff/bike_colorpalette_4bit.tiff"; 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 FlowerRgb161616Contiguous = "Tiff/flower-rgb-contig-16.tiff"; public const string FlowerRgb161616Planar = "Tiff/flower-rgb-planar-16.tiff"; public const string FlowerRgb141414Contiguous = "Tiff/flower-rgb-contig-14.tiff"; @@ -573,6 +571,8 @@ namespace SixLabors.ImageSharp.Tests public const string FlowerRgb222Planar = "Tiff/flower-rgb-planar-02.tiff"; public const string Flower2BitGray = "Tiff/flower-minisblack-02.tiff"; public const string Flower2BitPalette = "Tiff/flower-palette-02.tiff"; + public const string Flower4BitPalette = "Tiff/flower-palette-04.tiff"; + public const string Flower4BitPaletteGray = "Tiff/flower-minisblack-04.tiff"; public const string Flower6BitGray = "Tiff/flower-minisblack-06.tiff"; public const string Flower8BitGray = "Tiff/flower-minisblack-08.tiff"; public const string Flower10BitGray = "Tiff/flower-minisblack-10.tiff"; From aa848d74e9e77496ba5a2c13343efb9709629e83 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 11 Jun 2021 19:10:23 +0200 Subject: [PATCH 07/11] Change BitsPerSample to a struct --- .../Formats/Tiff/Constants/TiffConstants.cs | 32 +- .../Formats/Tiff/TiffBitsPerSample.cs | 302 +++++++++++++----- .../Tiff/TiffBitsPerSampleExtensions.cs | 170 ---------- .../Formats/Tiff/TiffDecoderOptionsParser.cs | 2 +- .../Tiff/TiffEncoderEntriesCollector.cs | 16 +- .../Formats/Tiff/TiffFrameMetadata.cs | 27 +- 6 files changed, 252 insertions(+), 297 deletions(-) delete mode 100644 src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index 5733bada9..8d9fb94a4 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -83,82 +83,82 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants /// /// The bits per sample for 1 bit bicolor images. /// - public static readonly ushort[] BitsPerSample1Bit = { 1 }; + public static readonly TiffBitsPerSample BitsPerSample1Bit = new TiffBitsPerSample(1, 0, 0); /// /// The bits per sample for images with a 2 color palette. /// - public static readonly ushort[] BitsPerSample2Bit = { 2 }; + public static readonly TiffBitsPerSample BitsPerSample2Bit = new TiffBitsPerSample(2, 0, 0); /// /// The bits per sample for images with a 4 color palette. /// - public static readonly ushort[] BitsPerSample4Bit = { 4 }; + public static readonly TiffBitsPerSample BitsPerSample4Bit = new TiffBitsPerSample(4, 0, 0); /// /// The bits per sample for 6 bit gray images. /// - public static readonly ushort[] BitsPerSample6Bit = { 6 }; + public static readonly TiffBitsPerSample BitsPerSample6Bit = new TiffBitsPerSample(6, 0, 0); /// /// The bits per sample for 8 bit images. /// - public static readonly ushort[] BitsPerSample8Bit = { 8 }; + public static readonly TiffBitsPerSample BitsPerSample8Bit = new TiffBitsPerSample(8, 0, 0); /// /// The bits per sample for 10 bit gray images. /// - public static readonly ushort[] BitsPerSample10Bit = { 10 }; + public static readonly TiffBitsPerSample BitsPerSample10Bit = new TiffBitsPerSample(10, 0, 0); /// /// The bits per sample for 12 bit gray images. /// - public static readonly ushort[] BitsPerSample12Bit = { 12 }; + public static readonly TiffBitsPerSample BitsPerSample12Bit = new TiffBitsPerSample(12, 0, 0); /// /// The bits per sample for 14 bit gray images. /// - public static readonly ushort[] BitsPerSample14Bit = { 14 }; + public static readonly TiffBitsPerSample BitsPerSample14Bit = new TiffBitsPerSample(14, 0, 0); /// /// The bits per sample for 16 bit gray images. /// - public static readonly ushort[] BitsPerSample16Bit = { 16 }; + public static readonly TiffBitsPerSample BitsPerSample16Bit = new TiffBitsPerSample(16, 0, 0); /// /// The bits per sample for color images with 2 bits for each color channel. /// - public static readonly ushort[] BitsPerSampleRgb2Bit = { 2, 2, 2 }; + public static readonly TiffBitsPerSample BitsPerSampleRgb2Bit = new TiffBitsPerSample(2, 2, 2); /// /// The bits per sample for color images with 4 bits for each color channel. /// - public static readonly ushort[] BitsPerSampleRgb4Bit = { 4, 4, 4 }; + public static readonly TiffBitsPerSample BitsPerSampleRgb4Bit = new TiffBitsPerSample(4, 4, 4); /// /// The bits per sample for color images with 8 bits for each color channel. /// - public static readonly ushort[] BitsPerSampleRgb8Bit = { 8, 8, 8 }; + public static readonly TiffBitsPerSample BitsPerSampleRgb8Bit = new TiffBitsPerSample(8, 8, 8); /// /// The bits per sample for color images with 10 bits for each color channel. /// - public static readonly ushort[] BitsPerSampleRgb10Bit = { 10, 10, 10 }; + public static readonly TiffBitsPerSample BitsPerSampleRgb10Bit = new TiffBitsPerSample(10, 10, 10); /// /// The bits per sample for color images with 12 bits for each color channel. /// - public static readonly ushort[] BitsPerSampleRgb12Bit = { 12, 12, 12 }; + public static readonly TiffBitsPerSample BitsPerSampleRgb12Bit = new TiffBitsPerSample(12, 12, 12); /// /// The bits per sample for color images with 14 bits for each color channel. /// - public static readonly ushort[] BitsPerSampleRgb14Bit = { 14, 14, 14 }; + public static readonly TiffBitsPerSample BitsPerSampleRgb14Bit = new TiffBitsPerSample(14, 14, 14); /// /// The bits per sample for color images with 14 bits for each color channel. /// - public static readonly ushort[] BitsPerSampleRgb16Bit = { 16, 16, 16 }; + public static readonly TiffBitsPerSample BitsPerSampleRgb16Bit = new TiffBitsPerSample(16, 16, 16); /// /// The list of mimetypes that equate to a tiff. diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs index 71f6b5bf9..b79730a12 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs @@ -1,96 +1,242 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using System; +using SixLabors.ImageSharp.Formats.Tiff.Constants; + namespace SixLabors.ImageSharp.Formats.Tiff { /// /// The number of bits per component. /// - public enum TiffBitsPerSample + public readonly struct TiffBitsPerSample : IEquatable { /// - /// The bits per samples is not known. - /// - Unknown = 0, - - /// - /// One bit per sample for bicolor images. - /// - Bit1, - - /// - /// Two bits per sample for grayscale images with 4 different levels of gray or paletted images with a palette of 4 colors. - /// - Bit2, - - /// - /// Four bits per sample for grayscale images with 16 different levels of gray or paletted images with a palette of 16 colors. - /// - Bit4, - - /// - /// Six bits per sample for grayscale images. - /// - Bit6, - - /// - /// Eight bits per sample for grayscale images with 256 different levels of gray or paletted images with a palette of 256 colors. - /// - Bit8, - - /// - /// Ten bits per sample for grayscale images. - /// - Bit10, - - /// - /// Twelve bits per sample for grayscale images. + /// The bits for the channel 0. /// - Bit12, + public readonly ushort Channel0; /// - /// Fourteen bits per sample for grayscale images. + /// The bits for the channel 1. /// - Bit14, + public readonly ushort Channel1; /// - /// Sixteen bits per sample for grayscale images. - /// - Bit16, - - /// - /// 6 bits per sample, each channel has 2 bits. - /// - Rgb222, - - /// - /// Twelve bits per sample, each channel has 4 bits. - /// - Rgb444, - - /// - /// 24 bits per sample, each color channel has 8 Bits. - /// - Rgb888, - - /// - /// Thirty bits per sample, each channel has 10 bits. - /// - Rgb101010, - - /// - /// Thirty six bits per sample, each channel has 12 bits. - /// - Rgb121212, - - /// - /// Forty two bits per sample, each channel has 14 bits. - /// - Rgb141414, - - /// - /// Forty eight bits per sample, each channel has 16 bits. - /// - Rgb161616, + /// The bits for the channel 2. + /// + public readonly ushort Channel2; + + /// + /// Initializes a new instance of the struct. + /// + /// The bits for the channel 0. + /// The bits for the channel 1. + /// The bits for the channel 2. + public TiffBitsPerSample(ushort channel0, ushort channel1, ushort channel2) + { + this.Channel0 = (ushort)Numerics.Clamp(channel0, 1, 32); + this.Channel1 = (ushort)Numerics.Clamp(channel1, 0, 32); + this.Channel2 = (ushort)Numerics.Clamp(channel2, 0, 32); + } + + /// + /// Tries to parse a ushort array and convert it into a TiffBitsPerSample struct. + /// + /// The value to parse. + /// The tiff bits per sample. + /// True, if the value could be parsed. + public static bool TryParse(ushort[] value, out TiffBitsPerSample sample) + { + if (value is null || value.Length == 0) + { + sample = default; + return false; + } + + ushort c2; + ushort c1; + ushort c0; + switch (value.Length) + { + case 3: + c2 = value[2]; + c1 = value[1]; + c0 = value[0]; + break; + case 2: + c2 = 0; + c1 = value[1]; + c0 = value[0]; + break; + default: + c2 = 0; + c1 = 0; + c0 = value[0]; + break; + } + + sample = new TiffBitsPerSample(c0, c1, c2); + return true; + } + + /// + public override bool Equals(object obj) + => obj is TiffBitsPerSample sample && this.Equals(sample); + + /// + public bool Equals(TiffBitsPerSample other) + => this.Channel0 == other.Channel0 + && this.Channel1 == other.Channel1 + && this.Channel2 == other.Channel2; + + /// + public override int GetHashCode() + => HashCode.Combine(this.Channel0, this.Channel1, this.Channel2); + + /// + /// Converts the bits per sample struct to an ushort array. + /// + /// Bits per sample as ushort array. + public ushort[] ToArray() + { + if (this.Channel1 == 0) + { + return new[] { this.Channel0 }; + } + + if (this.Channel2 == 0) + { + return new[] { this.Channel0, this.Channel1 }; + } + + return new[] { this.Channel0, this.Channel1, this.Channel2 }; + } + + /// + /// Maps an array of bits per sample to a concrete struct value. + /// + /// The bits per sample array. + /// TiffBitsPerSample enum value. + public static TiffBitsPerSample? GetBitsPerSample(ushort[] bitsPerSample) + { + switch (bitsPerSample.Length) + { + case 3: + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb16Bit.Channel2 && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb16Bit.Channel1 && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb16Bit.Channel0) + { + return TiffConstants.BitsPerSampleRgb16Bit; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb14Bit.Channel2 && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb14Bit.Channel1 && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb14Bit.Channel0) + { + return TiffConstants.BitsPerSampleRgb14Bit; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb12Bit.Channel2 && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb12Bit.Channel1 && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb12Bit.Channel0) + { + return TiffConstants.BitsPerSampleRgb12Bit; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb10Bit.Channel2 && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb10Bit.Channel1 && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb10Bit.Channel0) + { + return TiffConstants.BitsPerSampleRgb10Bit; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb8Bit.Channel2 && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb8Bit.Channel1 && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb8Bit.Channel0) + { + return TiffConstants.BitsPerSampleRgb8Bit; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb4Bit.Channel2 && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb4Bit.Channel1 && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb4Bit.Channel0) + { + return TiffConstants.BitsPerSampleRgb4Bit; + } + + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb2Bit.Channel2 && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb2Bit.Channel1 && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb2Bit.Channel0) + { + return TiffConstants.BitsPerSampleRgb2Bit; + } + + break; + + case 1: + if (bitsPerSample[0] == TiffConstants.BitsPerSample1Bit.Channel0) + { + return TiffConstants.BitsPerSample1Bit; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample2Bit.Channel0) + { + return TiffConstants.BitsPerSample2Bit; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample4Bit.Channel0) + { + return TiffConstants.BitsPerSample4Bit; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample6Bit.Channel0) + { + return TiffConstants.BitsPerSample6Bit; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample8Bit.Channel0) + { + return TiffConstants.BitsPerSample8Bit; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample10Bit.Channel0) + { + return TiffConstants.BitsPerSample10Bit; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample12Bit.Channel0) + { + return TiffConstants.BitsPerSample12Bit; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample14Bit.Channel0) + { + return TiffConstants.BitsPerSample14Bit; + } + + if (bitsPerSample[0] == TiffConstants.BitsPerSample16Bit.Channel0) + { + return TiffConstants.BitsPerSample16Bit; + } + + break; + } + + return null; + } + + /// + /// Gets the bits per pixel for the given bits per sample. + /// + /// Bits per pixel. + public TiffBitsPerPixel BitsPerPixel() + { + int bitsPerPixel = this.Channel0 + this.Channel1 + this.Channel2; + return (TiffBitsPerPixel)bitsPerPixel; + } + + /// + public override string ToString() + => $"TiffBitsPerSample({this.Channel0}, {this.Channel1}, {this.Channel2})"; } } diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs deleted file mode 100644 index 5ec1331b3..000000000 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using SixLabors.ImageSharp.Formats.Tiff.Constants; - -namespace SixLabors.ImageSharp.Formats.Tiff -{ - internal static class TiffBitsPerSampleExtensions - { - /// - /// Gets the bits per channel array for a given BitsPerSample value, e,g, for RGB888: [8, 8, 8] - /// - /// The tiff bits per sample. - /// Bits per sample array. - public static ushort[] BitsPerChannel(this TiffBitsPerSample tiffBitsPerSample) - { - switch (tiffBitsPerSample) - { - case TiffBitsPerSample.Bit1: - return TiffConstants.BitsPerSample1Bit; - case TiffBitsPerSample.Bit2: - return TiffConstants.BitsPerSample2Bit; - case TiffBitsPerSample.Bit4: - return TiffConstants.BitsPerSample4Bit; - case TiffBitsPerSample.Bit6: - return TiffConstants.BitsPerSample6Bit; - case TiffBitsPerSample.Bit8: - return TiffConstants.BitsPerSample8Bit; - case TiffBitsPerSample.Bit10: - return TiffConstants.BitsPerSample10Bit; - case TiffBitsPerSample.Bit12: - return TiffConstants.BitsPerSample12Bit; - case TiffBitsPerSample.Bit14: - return TiffConstants.BitsPerSample14Bit; - case TiffBitsPerSample.Bit16: - return TiffConstants.BitsPerSample16Bit; - case TiffBitsPerSample.Rgb222: - return TiffConstants.BitsPerSampleRgb2Bit; - case TiffBitsPerSample.Rgb444: - return TiffConstants.BitsPerSampleRgb4Bit; - case TiffBitsPerSample.Rgb888: - return TiffConstants.BitsPerSampleRgb8Bit; - case TiffBitsPerSample.Rgb101010: - return TiffConstants.BitsPerSampleRgb10Bit; - case TiffBitsPerSample.Rgb121212: - return TiffConstants.BitsPerSampleRgb12Bit; - case TiffBitsPerSample.Rgb141414: - return TiffConstants.BitsPerSampleRgb14Bit; - case TiffBitsPerSample.Rgb161616: - return TiffConstants.BitsPerSampleRgb16Bit; - default: - return Array.Empty(); - } - } - - /// - /// Maps an array of bits per sample to a concrete enum value. - /// - /// The bits per sample array. - /// TiffBitsPerSample enum value. - public static TiffBitsPerSample GetBitsPerSample(this ushort[] bitsPerSample) - { - switch (bitsPerSample.Length) - { - case 3: - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb16Bit[2] && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb16Bit[1] && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb16Bit[0]) - { - return TiffBitsPerSample.Rgb161616; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb14Bit[2] && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb14Bit[1] && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb14Bit[0]) - { - return TiffBitsPerSample.Rgb141414; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb12Bit[2] && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb12Bit[1] && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb12Bit[0]) - { - return TiffBitsPerSample.Rgb121212; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb10Bit[2] && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb10Bit[1] && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb10Bit[0]) - { - return TiffBitsPerSample.Rgb101010; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb8Bit[2] && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb8Bit[1] && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb8Bit[0]) - { - return TiffBitsPerSample.Rgb888; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb4Bit[2] && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb4Bit[1] && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb4Bit[0]) - { - return TiffBitsPerSample.Rgb444; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb2Bit[2] && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb2Bit[1] && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb2Bit[0]) - { - return TiffBitsPerSample.Rgb222; - } - - break; - - case 1: - if (bitsPerSample[0] == TiffConstants.BitsPerSample1Bit[0]) - { - return TiffBitsPerSample.Bit1; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample2Bit[0]) - { - return TiffBitsPerSample.Bit2; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample4Bit[0]) - { - return TiffBitsPerSample.Bit4; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample6Bit[0]) - { - return TiffBitsPerSample.Bit6; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample8Bit[0]) - { - return TiffBitsPerSample.Bit8; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample10Bit[0]) - { - return TiffBitsPerSample.Bit10; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample12Bit[0]) - { - return TiffBitsPerSample.Bit12; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample14Bit[0]) - { - return TiffBitsPerSample.Bit14; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample16Bit[0]) - { - return TiffBitsPerSample.Bit16; - } - - break; - } - - return TiffBitsPerSample.Unknown; - } - } -} diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 1efc82602..0699359c0 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff options.Predictor = frameMetadata.Predictor ?? TiffPredictor.None; options.PhotometricInterpretation = frameMetadata.PhotometricInterpretation ?? TiffPhotometricInterpretation.Rgb; options.BitsPerPixel = frameMetadata.BitsPerPixel != null ? (int)frameMetadata.BitsPerPixel.Value : (int)TiffBitsPerPixel.Bit24; - options.BitsPerSample = frameMetadata.BitsPerSample != null ? frameMetadata.BitsPerSample?.BitsPerChannel() : Array.Empty(); + options.BitsPerSample = frameMetadata.BitsPerSample != null ? frameMetadata.BitsPerSample?.ToArray() : Array.Empty(); options.ParseColorType(exifProfile); options.ParseCompression(frameMetadata.Compression, exifProfile); diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs index 9bc0792c4..43a086849 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs @@ -318,34 +318,34 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffPhotometricInterpretation.PaletteColor: if (encoder.BitsPerPixel == TiffBitsPerPixel.Bit4) { - return TiffConstants.BitsPerSample4Bit; + return TiffConstants.BitsPerSample4Bit.ToArray(); } else { - return TiffConstants.BitsPerSample8Bit; + return TiffConstants.BitsPerSample8Bit.ToArray(); } case TiffPhotometricInterpretation.Rgb: - return TiffConstants.BitsPerSampleRgb8Bit; + return TiffConstants.BitsPerSampleRgb8Bit.ToArray(); case TiffPhotometricInterpretation.WhiteIsZero: if (encoder.BitsPerPixel == TiffBitsPerPixel.Bit1) { - return TiffConstants.BitsPerSample1Bit; + return TiffConstants.BitsPerSample1Bit.ToArray(); } - return TiffConstants.BitsPerSample8Bit; + return TiffConstants.BitsPerSample8Bit.ToArray(); case TiffPhotometricInterpretation.BlackIsZero: if (encoder.BitsPerPixel == TiffBitsPerPixel.Bit1) { - return TiffConstants.BitsPerSample1Bit; + return TiffConstants.BitsPerSample1Bit.ToArray(); } - return TiffConstants.BitsPerSample8Bit; + return TiffConstants.BitsPerSample8Bit.ToArray(); default: - return TiffConstants.BitsPerSampleRgb8Bit; + return TiffConstants.BitsPerSampleRgb8Bit.ToArray(); } } diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index 62e9fb4e2..76db6e75f 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff } /// - /// Parses the given Exif profile to populate the properties of the tiff frame meta data.. + /// Parses the given Exif profile to populate the properties of the tiff frame meta data. /// /// The tiff frame meta data. /// The Exif profile containing tiff frame directory tags. @@ -77,8 +77,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff { if (profile != null) { - meta.BitsPerSample = profile.GetValue(ExifTag.BitsPerSample) != null ? profile.GetValue(ExifTag.BitsPerSample)?.Value.GetBitsPerSample() : null; - meta.BitsPerPixel = BitsPerPixelFromBitsPerSample(meta.BitsPerSample?.BitsPerChannel()); + meta.BitsPerSample = profile.GetValue(ExifTag.BitsPerSample) != null ? TiffBitsPerSample.GetBitsPerSample(profile.GetValue(ExifTag.BitsPerSample)?.Value) : null; + meta.BitsPerPixel = meta.BitsPerSample?.BitsPerPixel(); meta.Compression = (TiffCompression?)profile.GetValue(ExifTag.Compression)?.Value; meta.PhotometricInterpretation = (TiffPhotometricInterpretation?)profile.GetValue(ExifTag.PhotometricInterpretation)?.Value; meta.Predictor = (TiffPredictor?)profile.GetValue(ExifTag.Predictor)?.Value; @@ -90,27 +90,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff } } - /// - /// Gets the bits per pixel for the given bits per sample. - /// - /// The tiff bits per sample. - /// Bits per pixel. - private static TiffBitsPerPixel? BitsPerPixelFromBitsPerSample(ushort[] bitsPerSample) - { - if (bitsPerSample == null) - { - return null; - } - - int bitsPerPixel = 0; - foreach (ushort bits in bitsPerSample) - { - bitsPerPixel += bits; - } - - return (TiffBitsPerPixel)bitsPerPixel; - } - /// public IDeepCloneable DeepClone() => new TiffFrameMetadata(this); } From 9891a2ef3b0249cf795fefc6ab4d4ece3d0d9c5b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 12 Jun 2021 16:51:54 +0200 Subject: [PATCH 08/11] Remove not needed GetBitsPerSample method --- .../Formats/Tiff/TiffBitsPerSample.cs | 114 ------------------ .../Formats/Tiff/TiffFrameMetadata.cs | 7 +- 2 files changed, 6 insertions(+), 115 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs index b79730a12..bdf5a20c1 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using SixLabors.ImageSharp.Formats.Tiff.Constants; namespace SixLabors.ImageSharp.Formats.Tiff { @@ -112,119 +111,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff return new[] { this.Channel0, this.Channel1, this.Channel2 }; } - /// - /// Maps an array of bits per sample to a concrete struct value. - /// - /// The bits per sample array. - /// TiffBitsPerSample enum value. - public static TiffBitsPerSample? GetBitsPerSample(ushort[] bitsPerSample) - { - switch (bitsPerSample.Length) - { - case 3: - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb16Bit.Channel2 && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb16Bit.Channel1 && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb16Bit.Channel0) - { - return TiffConstants.BitsPerSampleRgb16Bit; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb14Bit.Channel2 && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb14Bit.Channel1 && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb14Bit.Channel0) - { - return TiffConstants.BitsPerSampleRgb14Bit; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb12Bit.Channel2 && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb12Bit.Channel1 && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb12Bit.Channel0) - { - return TiffConstants.BitsPerSampleRgb12Bit; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb10Bit.Channel2 && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb10Bit.Channel1 && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb10Bit.Channel0) - { - return TiffConstants.BitsPerSampleRgb10Bit; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb8Bit.Channel2 && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb8Bit.Channel1 && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb8Bit.Channel0) - { - return TiffConstants.BitsPerSampleRgb8Bit; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb4Bit.Channel2 && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb4Bit.Channel1 && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb4Bit.Channel0) - { - return TiffConstants.BitsPerSampleRgb4Bit; - } - - if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb2Bit.Channel2 && - bitsPerSample[1] == TiffConstants.BitsPerSampleRgb2Bit.Channel1 && - bitsPerSample[0] == TiffConstants.BitsPerSampleRgb2Bit.Channel0) - { - return TiffConstants.BitsPerSampleRgb2Bit; - } - - break; - - case 1: - if (bitsPerSample[0] == TiffConstants.BitsPerSample1Bit.Channel0) - { - return TiffConstants.BitsPerSample1Bit; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample2Bit.Channel0) - { - return TiffConstants.BitsPerSample2Bit; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample4Bit.Channel0) - { - return TiffConstants.BitsPerSample4Bit; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample6Bit.Channel0) - { - return TiffConstants.BitsPerSample6Bit; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample8Bit.Channel0) - { - return TiffConstants.BitsPerSample8Bit; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample10Bit.Channel0) - { - return TiffConstants.BitsPerSample10Bit; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample12Bit.Channel0) - { - return TiffConstants.BitsPerSample12Bit; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample14Bit.Channel0) - { - return TiffConstants.BitsPerSample14Bit; - } - - if (bitsPerSample[0] == TiffConstants.BitsPerSample16Bit.Channel0) - { - return TiffConstants.BitsPerSample16Bit; - } - - break; - } - - return null; - } - /// /// Gets the bits per pixel for the given bits per sample. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index 76db6e75f..e2a55b94b 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs @@ -77,7 +77,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff { if (profile != null) { - meta.BitsPerSample = profile.GetValue(ExifTag.BitsPerSample) != null ? TiffBitsPerSample.GetBitsPerSample(profile.GetValue(ExifTag.BitsPerSample)?.Value) : null; + ushort[] bitsPerSampleValue = profile.GetValue(ExifTag.BitsPerSample)?.Value; + if (bitsPerSampleValue != null && TiffBitsPerSample.TryParse(bitsPerSampleValue, out TiffBitsPerSample bitsPerSample)) + { + meta.BitsPerSample = bitsPerSample; + } + meta.BitsPerPixel = meta.BitsPerSample?.BitsPerPixel(); meta.Compression = (TiffCompression?)profile.GetValue(ExifTag.Compression)?.Value; meta.PhotometricInterpretation = (TiffPhotometricInterpretation?)profile.GetValue(ExifTag.PhotometricInterpretation)?.Value; From 3b8bed5e9966d007d72275052431c39a76265702 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 12 Jun 2021 16:53:59 +0200 Subject: [PATCH 09/11] Remove not used constants --- .../Formats/Tiff/Constants/TiffConstants.cs | 90 ------------------- 1 file changed, 90 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index 8d9fb94a4..b54545141 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -40,41 +40,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants /// public const int RowsPerStripInfinity = 2147483647; - /// - /// Size (in bytes) of the TIFF file header. - /// - public const int SizeOfTiffHeader = 8; - - /// - /// Size (in bytes) of each individual TIFF IFD entry - /// - public const int SizeOfIfdEntry = 12; - - /// - /// Size (in bytes) of the Short and SShort data types - /// - public const int SizeOfShort = 2; - - /// - /// Size (in bytes) of the Long and SLong data types - /// - public const int SizeOfLong = 4; - /// /// Size (in bytes) of the Rational and SRational data types /// public const int SizeOfRational = 8; - /// - /// Size (in bytes) of the Float data type - /// - public const int SizeOfFloat = 4; - - /// - /// Size (in bytes) of the Double data type - /// - public const int SizeOfDouble = 8; - /// /// The default strip size is 8k. /// @@ -85,81 +55,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants /// public static readonly TiffBitsPerSample BitsPerSample1Bit = new TiffBitsPerSample(1, 0, 0); - /// - /// The bits per sample for images with a 2 color palette. - /// - public static readonly TiffBitsPerSample BitsPerSample2Bit = new TiffBitsPerSample(2, 0, 0); - /// /// The bits per sample for images with a 4 color palette. /// public static readonly TiffBitsPerSample BitsPerSample4Bit = new TiffBitsPerSample(4, 0, 0); - /// - /// The bits per sample for 6 bit gray images. - /// - public static readonly TiffBitsPerSample BitsPerSample6Bit = new TiffBitsPerSample(6, 0, 0); - /// /// The bits per sample for 8 bit images. /// public static readonly TiffBitsPerSample BitsPerSample8Bit = new TiffBitsPerSample(8, 0, 0); - /// - /// The bits per sample for 10 bit gray images. - /// - public static readonly TiffBitsPerSample BitsPerSample10Bit = new TiffBitsPerSample(10, 0, 0); - - /// - /// The bits per sample for 12 bit gray images. - /// - public static readonly TiffBitsPerSample BitsPerSample12Bit = new TiffBitsPerSample(12, 0, 0); - - /// - /// The bits per sample for 14 bit gray images. - /// - public static readonly TiffBitsPerSample BitsPerSample14Bit = new TiffBitsPerSample(14, 0, 0); - - /// - /// The bits per sample for 16 bit gray images. - /// - public static readonly TiffBitsPerSample BitsPerSample16Bit = new TiffBitsPerSample(16, 0, 0); - - /// - /// The bits per sample for color images with 2 bits for each color channel. - /// - public static readonly TiffBitsPerSample BitsPerSampleRgb2Bit = new TiffBitsPerSample(2, 2, 2); - - /// - /// The bits per sample for color images with 4 bits for each color channel. - /// - public static readonly TiffBitsPerSample BitsPerSampleRgb4Bit = new TiffBitsPerSample(4, 4, 4); - /// /// The bits per sample for color images with 8 bits for each color channel. /// public static readonly TiffBitsPerSample BitsPerSampleRgb8Bit = new TiffBitsPerSample(8, 8, 8); - /// - /// The bits per sample for color images with 10 bits for each color channel. - /// - public static readonly TiffBitsPerSample BitsPerSampleRgb10Bit = new TiffBitsPerSample(10, 10, 10); - - /// - /// The bits per sample for color images with 12 bits for each color channel. - /// - public static readonly TiffBitsPerSample BitsPerSampleRgb12Bit = new TiffBitsPerSample(12, 12, 12); - - /// - /// The bits per sample for color images with 14 bits for each color channel. - /// - public static readonly TiffBitsPerSample BitsPerSampleRgb14Bit = new TiffBitsPerSample(14, 14, 14); - - /// - /// The bits per sample for color images with 14 bits for each color channel. - /// - public static readonly TiffBitsPerSample BitsPerSampleRgb16Bit = new TiffBitsPerSample(16, 16, 16); - /// /// The list of mimetypes that equate to a tiff. /// From 22f4b7c12cc9041254b4b7960bd2d2da72db28eb Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 12 Jun 2021 19:18:23 +0200 Subject: [PATCH 10/11] Remove not needed null check for bits per sample --- src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index e2a55b94b..002dbf039 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs @@ -77,8 +77,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff { if (profile != null) { - ushort[] bitsPerSampleValue = profile.GetValue(ExifTag.BitsPerSample)?.Value; - if (bitsPerSampleValue != null && TiffBitsPerSample.TryParse(bitsPerSampleValue, out TiffBitsPerSample bitsPerSample)) + if (TiffBitsPerSample.TryParse(profile.GetValue(ExifTag.BitsPerSample)?.Value, out TiffBitsPerSample bitsPerSample)) { meta.BitsPerSample = bitsPerSample; } From 2ec796ff8ffee8f4db6bc0f86201342f1fca641e Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 13 Jun 2021 13:10:42 +0200 Subject: [PATCH 11/11] Change BitsPerSample from ushort[] to TiffBitsPerSample struct --- .../BlackIsZeroTiffColor{TPixel}.cs | 4 +- .../PaletteTiffColor{TPixel}.cs | 4 +- .../RgbPlanarTiffColor{TPixel}.cs | 8 +- .../RgbTiffColor{TPixel}.cs | 8 +- .../TiffColorDecoderFactory{TPixel}.cs | 79 +++++++++---------- .../WhiteIsZeroTiffColor{TPixel}.cs | 4 +- .../Formats/Tiff/TiffBitsPerSample.cs | 12 ++- .../Formats/Tiff/TiffDecoderCore.cs | 24 +++++- .../Formats/Tiff/TiffDecoderOptionsParser.cs | 17 ++-- .../BlackIsZeroTiffColorTests.cs | 6 +- .../PaletteTiffColorTests.cs | 11 +-- .../RgbPlanarTiffColorTests.cs | 46 +++++------ .../RgbTiffColorTests.cs | 48 +++++------ .../WhiteIsZeroTiffColorTests.cs | 6 +- 14 files changed, 150 insertions(+), 127 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs index 83cef8e75..a4e5e45df 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs @@ -19,9 +19,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation private readonly float factor; - public BlackIsZeroTiffColor(ushort[] bitsPerSample) + public BlackIsZeroTiffColor(TiffBitsPerSample bitsPerSample) { - this.bitsPerSample0 = bitsPerSample[0]; + this.bitsPerSample0 = bitsPerSample.Channel0; this.factor = (1 << this.bitsPerSample0) - 1.0f; } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs index 7ed25f822..796227953 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs @@ -21,9 +21,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation /// The number of bits per sample for each pixel. /// The RGB color lookup table to use for decoding the image. - public PaletteTiffColor(ushort[] bitsPerSample, ushort[] colorMap) + public PaletteTiffColor(TiffBitsPerSample bitsPerSample, ushort[] colorMap) { - this.bitsPerSample0 = bitsPerSample[0]; + this.bitsPerSample0 = bitsPerSample.Channel0; int colorCount = 1 << this.bitsPerSample0; this.palette = GeneratePalette(colorMap, colorCount); } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs index b40158fce..8dda0cf38 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs @@ -26,11 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation private readonly ushort bitsPerSampleB; - public RgbPlanarTiffColor(ushort[] bitsPerSample) + public RgbPlanarTiffColor(TiffBitsPerSample bitsPerSample) { - this.bitsPerSampleR = bitsPerSample[0]; - this.bitsPerSampleG = bitsPerSample[1]; - this.bitsPerSampleB = bitsPerSample[2]; + this.bitsPerSampleR = bitsPerSample.Channel0; + this.bitsPerSampleG = bitsPerSample.Channel1; + this.bitsPerSampleB = bitsPerSample.Channel2; this.rFactor = (1 << this.bitsPerSampleR) - 1.0f; this.gFactor = (1 << this.bitsPerSampleG) - 1.0f; diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs index 816ba67b7..259bb8efa 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs @@ -27,11 +27,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation private readonly ushort bitsPerSampleB; - public RgbTiffColor(ushort[] bitsPerSample) + public RgbTiffColor(TiffBitsPerSample bitsPerSample) { - this.bitsPerSampleR = bitsPerSample[0]; - this.bitsPerSampleG = bitsPerSample[1]; - this.bitsPerSampleB = bitsPerSample[2]; + this.bitsPerSampleR = bitsPerSample.Channel0; + this.bitsPerSampleG = bitsPerSample.Channel1; + this.bitsPerSampleB = bitsPerSample.Channel2; this.rFactor = (1 << this.bitsPerSampleR) - 1.0f; this.gFactor = (1 << this.bitsPerSampleG) - 1.0f; diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs index 4ca7ed915..36d2ab746 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs @@ -8,127 +8,125 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation internal static class TiffColorDecoderFactory where TPixel : unmanaged, IPixel { - public static TiffBaseColorDecoder Create(TiffColorType colorType, ushort[] bitsPerSample, ushort[] colorMap) + public static TiffBaseColorDecoder Create(TiffColorType colorType, TiffBitsPerSample bitsPerSample, ushort[] colorMap) { switch (colorType) { case TiffColorType.WhiteIsZero: - DebugGuard.IsTrue(bitsPerSample.Length == 1, "bitsPerSample"); + DebugGuard.IsTrue(bitsPerSample.Channels == 1, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new WhiteIsZeroTiffColor(bitsPerSample); case TiffColorType.WhiteIsZero1: - DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 1, "bitsPerSample"); + DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 1, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new WhiteIsZero1TiffColor(); case TiffColorType.WhiteIsZero4: - DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 4, "bitsPerSample"); + DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 4, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new WhiteIsZero4TiffColor(); case TiffColorType.WhiteIsZero8: - DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 8, "bitsPerSample"); + DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 8, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new WhiteIsZero8TiffColor(); case TiffColorType.BlackIsZero: - DebugGuard.IsTrue(bitsPerSample.Length == 1, "bitsPerSample"); + DebugGuard.IsTrue(bitsPerSample.Channels == 1, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new BlackIsZeroTiffColor(bitsPerSample); case TiffColorType.BlackIsZero1: - DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 1, "bitsPerSample"); + DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 1, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new BlackIsZero1TiffColor(); case TiffColorType.BlackIsZero4: - DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 4, "bitsPerSample"); + DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 4, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new BlackIsZero4TiffColor(); case TiffColorType.BlackIsZero8: - DebugGuard.IsTrue(bitsPerSample.Length == 1 && bitsPerSample[0] == 8, "bitsPerSample"); + DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 8, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new BlackIsZero8TiffColor(); case TiffColorType.Rgb: - DebugGuard.NotNull(bitsPerSample, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); case TiffColorType.Rgb222: DebugGuard.IsTrue( - bitsPerSample.Length == 3 - && bitsPerSample[2] == 2 - && bitsPerSample[1] == 2 - && bitsPerSample[0] == 2, + bitsPerSample.Channels == 3 + && bitsPerSample.Channel2 == 2 + && bitsPerSample.Channel1 == 2 + && bitsPerSample.Channel0 == 2, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); case TiffColorType.Rgb444: DebugGuard.IsTrue( - bitsPerSample.Length == 3 - && bitsPerSample[2] == 4 - && bitsPerSample[1] == 4 - && bitsPerSample[0] == 4, + bitsPerSample.Channels == 3 + && bitsPerSample.Channel2 == 4 + && bitsPerSample.Channel1 == 4 + && bitsPerSample.Channel0 == 4, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new Rgb444TiffColor(); case TiffColorType.Rgb888: DebugGuard.IsTrue( - bitsPerSample.Length == 3 - && bitsPerSample[2] == 8 - && bitsPerSample[1] == 8 - && bitsPerSample[0] == 8, + bitsPerSample.Channels == 3 + && bitsPerSample.Channel2 == 8 + && bitsPerSample.Channel1 == 8 + && bitsPerSample.Channel0 == 8, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new Rgb888TiffColor(); case TiffColorType.Rgb101010: DebugGuard.IsTrue( - bitsPerSample.Length == 3 - && bitsPerSample[2] == 10 - && bitsPerSample[1] == 10 - && bitsPerSample[0] == 10, + bitsPerSample.Channels == 3 + && bitsPerSample.Channel2 == 10 + && bitsPerSample.Channel1 == 10 + && bitsPerSample.Channel0 == 10, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); case TiffColorType.Rgb121212: DebugGuard.IsTrue( - bitsPerSample.Length == 3 - && bitsPerSample[2] == 12 - && bitsPerSample[1] == 12 - && bitsPerSample[0] == 12, + bitsPerSample.Channels == 3 + && bitsPerSample.Channel2 == 12 + && bitsPerSample.Channel1 == 12 + && bitsPerSample.Channel0 == 12, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); case TiffColorType.Rgb141414: DebugGuard.IsTrue( - bitsPerSample.Length == 3 - && bitsPerSample[2] == 14 - && bitsPerSample[1] == 14 - && bitsPerSample[0] == 14, + bitsPerSample.Channels == 3 + && bitsPerSample.Channel2 == 14 + && bitsPerSample.Channel1 == 14 + && bitsPerSample.Channel0 == 14, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); case TiffColorType.Rgb161616: DebugGuard.IsTrue( - bitsPerSample.Length == 3 - && bitsPerSample[2] == 16 - && bitsPerSample[1] == 16 - && bitsPerSample[0] == 16, + bitsPerSample.Channels == 3 + && bitsPerSample.Channel2 == 16 + && bitsPerSample.Channel1 == 16 + && bitsPerSample.Channel0 == 16, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); case TiffColorType.PaletteColor: - DebugGuard.NotNull(bitsPerSample, "bitsPerSample"); DebugGuard.NotNull(colorMap, "colorMap"); return new PaletteTiffColor(bitsPerSample, colorMap); @@ -137,12 +135,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation } } - public static RgbPlanarTiffColor CreatePlanar(TiffColorType colorType, ushort[] bitsPerSample, ushort[] colorMap) + public static RgbPlanarTiffColor CreatePlanar(TiffColorType colorType, TiffBitsPerSample bitsPerSample, ushort[] colorMap) { switch (colorType) { case TiffColorType.RgbPlanar: - DebugGuard.NotNull(bitsPerSample, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbPlanarTiffColor(bitsPerSample); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs index 697fe2f07..04b6f98e5 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs @@ -19,9 +19,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation private readonly float factor; - public WhiteIsZeroTiffColor(ushort[] bitsPerSample) + public WhiteIsZeroTiffColor(TiffBitsPerSample bitsPerSample) { - this.bitsPerSample0 = bitsPerSample[0]; + this.bitsPerSample0 = bitsPerSample.Channel0; this.factor = (float)Math.Pow(2, this.bitsPerSample0) - 1.0f; } diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs index bdf5a20c1..8fd26ac13 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs @@ -25,6 +25,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// public readonly ushort Channel2; + /// + /// The number of channels. + /// + public readonly byte Channels; + /// /// Initializes a new instance of the struct. /// @@ -33,9 +38,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// The bits for the channel 2. public TiffBitsPerSample(ushort channel0, ushort channel1, ushort channel2) { - this.Channel0 = (ushort)Numerics.Clamp(channel0, 1, 32); + this.Channel0 = (ushort)Numerics.Clamp(channel0, 0, 32); this.Channel1 = (ushort)Numerics.Clamp(channel1, 0, 32); this.Channel2 = (ushort)Numerics.Clamp(channel2, 0, 32); + + this.Channels = 0; + this.Channels += (byte)(this.Channel0 != 0 ? 1 : 0); + this.Channels += (byte)(this.Channel1 != 0 ? 1 : 0); + this.Channels += (byte)(this.Channel2 != 0 ? 1 : 0); } /// diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 294407ef9..5ce696118 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// /// Gets or sets the bits per sample. /// - public ushort[] BitsPerSample { get; set; } + public TiffBitsPerSample BitsPerSample { get; set; } /// /// Gets or sets the bits per pixel. @@ -198,7 +198,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// The size (in bytes) of the required pixel buffer. private int CalculateStripBufferSize(int width, int height, int plane = -1) { - int bitsPerPixel; + DebugGuard.MustBeLessThanOrEqualTo(plane, 3, nameof(plane)); + + int bitsPerPixel = 0; if (this.PlanarConfiguration == TiffPlanarConfiguration.Chunky) { @@ -207,7 +209,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff } else { - bitsPerPixel = this.BitsPerSample[plane]; + switch (plane) + { + case 0: + bitsPerPixel = this.BitsPerSample.Channel0; + break; + case 1: + bitsPerPixel = this.BitsPerSample.Channel1; + break; + case 2: + bitsPerPixel = this.BitsPerSample.Channel2; + break; + default: + TiffThrowHelper.ThrowNotSupported("More then 3 color channels are not supported"); + break; + } } int bytesPerRow = ((width * bitsPerPixel) + 7) / 8; @@ -225,7 +241,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts) where TPixel : unmanaged, IPixel { - int stripsPerPixel = this.BitsPerSample.Length; + int stripsPerPixel = this.BitsPerSample.Channels; int stripsPerPlane = stripOffsets.Length / stripsPerPixel; int bitsPerPixel = this.BitsPerPixel; diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 0699359c0..288f01cd1 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Linq; using SixLabors.ImageSharp.Formats.Tiff.Compression; using SixLabors.ImageSharp.Formats.Tiff.Constants; @@ -69,7 +68,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff options.Predictor = frameMetadata.Predictor ?? TiffPredictor.None; options.PhotometricInterpretation = frameMetadata.PhotometricInterpretation ?? TiffPhotometricInterpretation.Rgb; options.BitsPerPixel = frameMetadata.BitsPerPixel != null ? (int)frameMetadata.BitsPerPixel.Value : (int)TiffBitsPerPixel.Bit24; - options.BitsPerSample = frameMetadata.BitsPerSample != null ? frameMetadata.BitsPerSample?.ToArray() : Array.Empty(); + options.BitsPerSample = frameMetadata.BitsPerSample ?? new TiffBitsPerSample(0, 0, 0); options.ParseColorType(exifProfile); options.ParseCompression(frameMetadata.Compression, exifProfile); @@ -99,12 +98,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff { case TiffPhotometricInterpretation.WhiteIsZero: { - if (options.BitsPerSample.Length != 1) + if (options.BitsPerSample.Channels != 1) { TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); } - ushort bitsPerChannel = options.BitsPerSample[0]; + ushort bitsPerChannel = options.BitsPerSample.Channel0; if (bitsPerChannel > 16) { TiffThrowHelper.ThrowNotSupported("Bits per sample is not supported."); @@ -142,12 +141,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffPhotometricInterpretation.BlackIsZero: { - if (options.BitsPerSample.Length != 1) + if (options.BitsPerSample.Channels != 1) { TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); } - ushort bitsPerChannel = options.BitsPerSample[0]; + ushort bitsPerChannel = options.BitsPerSample.Channel0; if (bitsPerChannel > 16) { TiffThrowHelper.ThrowNotSupported("Bits per sample is not supported."); @@ -185,14 +184,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffPhotometricInterpretation.Rgb: { - if (options.BitsPerSample.Length != 3) + if (options.BitsPerSample.Channels != 3) { TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); } if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky) { - ushort bitsPerChannel = options.BitsPerSample[0]; + ushort bitsPerChannel = options.BitsPerSample.Channel0; switch (bitsPerChannel) { case 16: @@ -238,7 +237,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff options.ColorMap = exifProfile.GetValue(ExifTag.ColorMap)?.Value; if (options.ColorMap != null) { - if (options.BitsPerSample.Length != 1) + if (options.BitsPerSample.Channels != 1) { TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs index 579ee0290..769ab850e 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Collections.Generic; - +using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; using SixLabors.ImageSharp.PixelFormats; @@ -154,11 +154,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation [MemberData(nameof(BilevelData))] [MemberData(nameof(Grayscale4_Data))] [MemberData(nameof(Grayscale8_Data))] - public void Decode_WritesPixelData(byte[] inputData, int bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult) + public void Decode_WritesPixelData(byte[] inputData, ushort bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult) { AssertDecode(expectedResult, pixels => { - new BlackIsZeroTiffColor(new[] { (ushort)bitsPerSample }).Decode(inputData, pixels, left, top, width, height); + new BlackIsZeroTiffColor(new TiffBitsPerSample(bitsPerSample, 0, 0)).Decode(inputData, pixels, left, top, width, height); }); } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PaletteTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PaletteTiffColorTests.cs index 0da1d8bbd..e368cd5f1 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PaletteTiffColorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PaletteTiffColorTests.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Collections.Generic; - +using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; using SixLabors.ImageSharp.PixelFormats; @@ -83,10 +83,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation [Theory] [MemberData(nameof(Palette4Data))] [MemberData(nameof(Palette8Data))] - public void Decode_WritesPixelData(byte[] inputData, ushort bitsPerSample, ushort[] colorMap, int left, int top, int width, int height, Rgba32[][] expectedResult) => AssertDecode(expectedResult, pixels => - { - new PaletteTiffColor(new[] { bitsPerSample }, colorMap).Decode(inputData, pixels, left, top, width, height); - }); + public void Decode_WritesPixelData(byte[] inputData, ushort bitsPerSample, ushort[] colorMap, int left, int top, int width, int height, Rgba32[][] expectedResult) + => AssertDecode(expectedResult, pixels => + { + new PaletteTiffColor(new TiffBitsPerSample(bitsPerSample, 0, 0), colorMap).Decode(inputData, pixels, left, top, width, height); + }); private static uint[][] GeneratePalette(int count) { diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColorTests.cs index abfae6ab4..e9c73a668 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColorTests.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; - +using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -101,17 +101,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation { get { - yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 0, 4, 4, Rgb4Result4X4 }; - yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 0, 4, 4, Offset(Rgb4Result4X4, 0, 0, 6, 6) }; - yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 1, 0, 4, 4, Offset(Rgb4Result4X4, 1, 0, 6, 6) }; - yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 1, 4, 4, Offset(Rgb4Result4X4, 0, 1, 6, 6) }; - yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 1, 1, 4, 4, Offset(Rgb4Result4X4, 1, 1, 6, 6) }; - - yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 0, 3, 4, Rgb4Result3X4 }; - yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 0, 3, 4, Offset(Rgb4Result3X4, 0, 0, 6, 6) }; - yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 1, 0, 3, 4, Offset(Rgb4Result3X4, 1, 0, 6, 6) }; - yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 1, 3, 4, Offset(Rgb4Result3X4, 0, 1, 6, 6) }; - yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 1, 1, 3, 4, Offset(Rgb4Result3X4, 1, 1, 6, 6) }; + yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 4, 4, Rgb4Result4X4 }; + yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 4, 4, Offset(Rgb4Result4X4, 0, 0, 6, 6) }; + yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 1, 0, 4, 4, Offset(Rgb4Result4X4, 1, 0, 6, 6) }; + yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 1, 4, 4, Offset(Rgb4Result4X4, 0, 1, 6, 6) }; + yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 1, 1, 4, 4, Offset(Rgb4Result4X4, 1, 1, 6, 6) }; + + yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 3, 4, Rgb4Result3X4 }; + yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 3, 4, Offset(Rgb4Result3X4, 0, 0, 6, 6) }; + yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 1, 0, 3, 4, Offset(Rgb4Result3X4, 1, 0, 6, 6) }; + yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 1, 3, 4, Offset(Rgb4Result3X4, 0, 1, 6, 6) }; + yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 1, 1, 3, 4, Offset(Rgb4Result3X4, 1, 1, 6, 6) }; } } @@ -170,11 +170,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation { get { - yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 0, 4, 4, Rgb8Result4X4 }; - yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 0, 4, 4, Offset(Rgb8Result4X4, 0, 0, 6, 6) }; - yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 1, 0, 4, 4, Offset(Rgb8Result4X4, 1, 0, 6, 6) }; - yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 1, 4, 4, Offset(Rgb8Result4X4, 0, 1, 6, 6) }; - yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 1, 1, 4, 4, Offset(Rgb8Result4X4, 1, 1, 6, 6) }; + yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 0, 4, 4, Rgb8Result4X4 }; + yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 0, 4, 4, Offset(Rgb8Result4X4, 0, 0, 6, 6) }; + yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 1, 0, 4, 4, Offset(Rgb8Result4X4, 1, 0, 6, 6) }; + yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 1, 4, 4, Offset(Rgb8Result4X4, 0, 1, 6, 6) }; + yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 1, 1, 4, 4, Offset(Rgb8Result4X4, 1, 1, 6, 6) }; } } @@ -230,11 +230,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation { get { - yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 0, 4, 4, Rgb484Result4X4 }; - yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 0, 4, 4, Offset(Rgb484Result4X4, 0, 0, 6, 6) }; - yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 1, 0, 4, 4, Offset(Rgb484Result4X4, 1, 0, 6, 6) }; - yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 1, 4, 4, Offset(Rgb484Result4X4, 0, 1, 6, 6) }; - yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 1, 1, 4, 4, Offset(Rgb484Result4X4, 1, 1, 6, 6) }; + yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 0, 4, 4, Rgb484Result4X4 }; + yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 0, 4, 4, Offset(Rgb484Result4X4, 0, 0, 6, 6) }; + yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 1, 0, 4, 4, Offset(Rgb484Result4X4, 1, 0, 6, 6) }; + yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 1, 4, 4, Offset(Rgb484Result4X4, 0, 1, 6, 6) }; + yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 1, 1, 4, 4, Offset(Rgb484Result4X4, 1, 1, 6, 6) }; } } @@ -242,7 +242,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation [MemberData(nameof(Rgb4Data))] [MemberData(nameof(Rgb8Data))] [MemberData(nameof(Rgb484_Data))] - public void Decode_WritesPixelData(byte[][] inputData, ushort[] bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult) + public void Decode_WritesPixelData(byte[][] inputData, TiffBitsPerSample bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult) { AssertDecode(expectedResult, pixels => { diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs index 4abde8f17..9adf59e48 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Collections.Generic; - +using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; using SixLabors.ImageSharp.PixelFormats; @@ -63,17 +63,17 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation { get { - yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 0, 4, 4, Rgb4Result4X4 }; - yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 0, 4, 4, Offset(Rgb4Result4X4, 0, 0, 6, 6) }; - yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 1, 0, 4, 4, Offset(Rgb4Result4X4, 1, 0, 6, 6) }; - yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 0, 1, 4, 4, Offset(Rgb4Result4X4, 0, 1, 6, 6) }; - yield return new object[] { Rgb4Bytes4X4, new ushort[] { 4, 4, 4 }, 1, 1, 4, 4, Offset(Rgb4Result4X4, 1, 1, 6, 6) }; - - yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 0, 3, 4, Rgb4Result3X4 }; - yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 0, 3, 4, Offset(Rgb4Result3X4, 0, 0, 6, 6) }; - yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 1, 0, 3, 4, Offset(Rgb4Result3X4, 1, 0, 6, 6) }; - yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 0, 1, 3, 4, Offset(Rgb4Result3X4, 0, 1, 6, 6) }; - yield return new object[] { Rgb4Bytes3X4, new ushort[] { 4, 4, 4 }, 1, 1, 3, 4, Offset(Rgb4Result3X4, 1, 1, 6, 6) }; + yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 4, 4, Rgb4Result4X4 }; + yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 4, 4, Offset(Rgb4Result4X4, 0, 0, 6, 6) }; + yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 1, 0, 4, 4, Offset(Rgb4Result4X4, 1, 0, 6, 6) }; + yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 0, 1, 4, 4, Offset(Rgb4Result4X4, 0, 1, 6, 6) }; + yield return new object[] { Rgb4Bytes4X4, new TiffBitsPerSample(4, 4, 4), 1, 1, 4, 4, Offset(Rgb4Result4X4, 1, 1, 6, 6) }; + + yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 3, 4, Rgb4Result3X4 }; + yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 0, 3, 4, Offset(Rgb4Result3X4, 0, 0, 6, 6) }; + yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 1, 0, 3, 4, Offset(Rgb4Result3X4, 1, 0, 6, 6) }; + yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 0, 1, 3, 4, Offset(Rgb4Result3X4, 0, 1, 6, 6) }; + yield return new object[] { Rgb4Bytes3X4, new TiffBitsPerSample(4, 4, 4), 1, 1, 3, 4, Offset(Rgb4Result3X4, 1, 1, 6, 6) }; } } @@ -111,11 +111,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation { get { - yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 0, 4, 4, Rgb8Result4X4 }; - yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 0, 4, 4, Offset(Rgb8Result4X4, 0, 0, 6, 6) }; - yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 1, 0, 4, 4, Offset(Rgb8Result4X4, 1, 0, 6, 6) }; - yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 0, 1, 4, 4, Offset(Rgb8Result4X4, 0, 1, 6, 6) }; - yield return new object[] { Rgb8Bytes4X4, new ushort[] { 8, 8, 8 }, 1, 1, 4, 4, Offset(Rgb8Result4X4, 1, 1, 6, 6) }; + yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 0, 4, 4, Rgb8Result4X4 }; + yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 0, 4, 4, Offset(Rgb8Result4X4, 0, 0, 6, 6) }; + yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 1, 0, 4, 4, Offset(Rgb8Result4X4, 1, 0, 6, 6) }; + yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 0, 1, 4, 4, Offset(Rgb8Result4X4, 0, 1, 6, 6) }; + yield return new object[] { Rgb8Bytes4X4, new TiffBitsPerSample(8, 8, 8), 1, 1, 4, 4, Offset(Rgb8Result4X4, 1, 1, 6, 6) }; } } @@ -153,11 +153,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation { get { - yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 0, 4, 4, Rgb484Result4X4 }; - yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 0, 4, 4, Offset(Rgb484Result4X4, 0, 0, 6, 6) }; - yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 1, 0, 4, 4, Offset(Rgb484Result4X4, 1, 0, 6, 6) }; - yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 0, 1, 4, 4, Offset(Rgb484Result4X4, 0, 1, 6, 6) }; - yield return new object[] { Rgb484Bytes4X4, new ushort[] { 4, 8, 4 }, 1, 1, 4, 4, Offset(Rgb484Result4X4, 1, 1, 6, 6) }; + yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 0, 4, 4, Rgb484Result4X4 }; + yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 0, 4, 4, Offset(Rgb484Result4X4, 0, 0, 6, 6) }; + yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 1, 0, 4, 4, Offset(Rgb484Result4X4, 1, 0, 6, 6) }; + yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 0, 1, 4, 4, Offset(Rgb484Result4X4, 0, 1, 6, 6) }; + yield return new object[] { Rgb484Bytes4X4, new TiffBitsPerSample(4, 8, 4), 1, 1, 4, 4, Offset(Rgb484Result4X4, 1, 1, 6, 6) }; } } @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation [MemberData(nameof(Rgb4Data))] [MemberData(nameof(Rgb8Data))] [MemberData(nameof(Rgb484Data))] - public void Decode_WritesPixelData(byte[] inputData, ushort[] bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult) + public void Decode_WritesPixelData(byte[] inputData, TiffBitsPerSample bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult) { AssertDecode(expectedResult, pixels => { @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation [Theory] [MemberData(nameof(Rgb8Data))] - public void Decode_WritesPixelData_8Bit(byte[] inputData, ushort[] bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult) + public void Decode_WritesPixelData_8Bit(byte[] inputData, TiffBitsPerSample bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult) { AssertDecode(expectedResult, pixels => { diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColorTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColorTests.cs index 620fddd7d..1d3304e4c 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColorTests.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Collections.Generic; - +using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; using SixLabors.ImageSharp.PixelFormats; @@ -154,11 +154,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation [MemberData(nameof(BilevelData))] [MemberData(nameof(Grayscale4Data))] [MemberData(nameof(Grayscale8Data))] - public void Decode_WritesPixelData(byte[] inputData, int bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult) + public void Decode_WritesPixelData(byte[] inputData, ushort bitsPerSample, int left, int top, int width, int height, Rgba32[][] expectedResult) { AssertDecode(expectedResult, pixels => { - new WhiteIsZeroTiffColor(new[] { (ushort)bitsPerSample }).Decode(inputData, pixels, left, top, width, height); + new WhiteIsZeroTiffColor(new TiffBitsPerSample(bitsPerSample, 0, 0)).Decode(inputData, pixels, left, top, width, height); }); }