From c6f5a8aaa01369794eac5c4958718f5d6f018595 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 1 Jun 2021 23:48:48 +0200 Subject: [PATCH 01/11] Add support for decoding 12 bits per pixel tiff's --- .../Formats/Tiff/Constants/TiffConstants.cs | 7 ++- .../Rgb444TiffColor{TPixel}.cs | 60 +++++++++++++++++++ .../RgbPlanarTiffColor{TPixel}.cs | 1 - .../TiffColorDecoderFactory{TPixel}.cs | 10 ++++ .../TiffColorType.cs | 5 ++ .../Formats/Tiff/TiffBitsPerPixel.cs | 7 +++ .../Formats/Tiff/TiffBitsPerSample.cs | 5 ++ .../Tiff/TiffBitsPerSampleExtensions.cs | 9 +++ .../Formats/Tiff/TiffDecoderCore.cs | 2 +- .../Formats/Tiff/TiffDecoderOptionsParser.cs | 17 +++++- .../Formats/Tiff/TiffEncoderCore.cs | 6 +- .../Tiff/TiffEncoderEntriesCollector.cs | 11 +++- .../Formats/Tiff/TiffDecoderTests.cs | 12 ++++ .../Formats/Tiff/TiffMetadataTests.cs | 5 +- tests/ImageSharp.Tests/TestImages.cs | 2 + .../Input/Tiff/flower-rgb-contig-04.tiff | 3 + .../Input/Tiff/flower-rgb-planar-04.tiff | 3 + 17 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs create mode 100644 tests/Images/Input/Tiff/flower-rgb-contig-04.tiff create mode 100644 tests/Images/Input/Tiff/flower-rgb-planar-04.tiff diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index a30890a69e..988b1242ae 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -96,10 +96,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants public static readonly ushort[] BitsPerSample8Bit = { 8 }; /// - /// The bits per sample for images with 8 bits for each color channel. + /// The bits per sample for color images with 8 bits for each color channel. /// public static readonly ushort[] BitsPerSampleRgb8Bit = { 8, 8, 8 }; + /// + /// The bits per sample for color images with 4 bits for each color channel. + /// + public static readonly ushort[] BitsPerSampleRgb4Bit = { 4, 4, 4 }; + /// /// The list of mimetypes that equate to a tiff. /// diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs new file mode 100644 index 0000000000..d8c48942f8 --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs @@ -0,0 +1,60 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation +{ + /// + /// Implements the 'RGB' photometric interpretation for 4 bits per color channel images. + /// + internal class Rgb444TiffColor : TiffBaseColorDecoder + where TPixel : unmanaged, IPixel + { + /// + public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) + { + var color = default(TPixel); + + int offset = 0; + + var bgra = default(Bgra4444); + for (int y = top; y < top + height; y++) + { + Span pixelRow = pixels.GetRowSpan(y); + + for (int x = left; x < left + width; x += 2) + { + byte r = (byte)((data[offset] & 0xF0) >> 4); + byte g = (byte)(data[offset] & 0xF); + offset++; + byte b = (byte)((data[offset] & 0xF0) >> 4); + + bgra.PackedValue = ToBgraPackedValue(b, g, r); + color.FromScaledVector4(bgra.ToScaledVector4()); + pixelRow[x] = color; + if (x + 1 >= pixelRow.Length) + { + offset++; + break; + } + + r = (byte)(data[offset] & 0xF); + offset++; + g = (byte)((data[offset] & 0xF0) >> 4); + b = (byte)(data[offset] & 0xF); + offset++; + + bgra.PackedValue = ToBgraPackedValue(b, g, r); + color.FromScaledVector4(bgra.ToScaledVector4()); + pixelRow[x + 1] = color; + } + } + } + + private static ushort ToBgraPackedValue(byte b, byte g, byte r) => (ushort)(b | (g << 4) | (r << 8) | (0xF << 12)); + } +} diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs index e45dd44bdc..b40158fcee 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs @@ -27,7 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation private readonly ushort bitsPerSampleB; public RgbPlanarTiffColor(ushort[] bitsPerSample) - /* : base(bitsPerSample, null) */ { this.bitsPerSampleR = bitsPerSample[0]; this.bitsPerSampleG = bitsPerSample[1]; diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs index 0a7941dfbc..d78b06aa7f 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs @@ -57,6 +57,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); + case TiffColorType.Rgb444: + DebugGuard.IsTrue( + bitsPerSample.Length == 3 + && bitsPerSample[0] == 4 + && bitsPerSample[1] == 4 + && bitsPerSample[2] == 4, + "bitsPerSample"); + DebugGuard.IsTrue(colorMap == null, "colorMap"); + return new Rgb444TiffColor(); + case TiffColorType.Rgb888: DebugGuard.IsTrue( bitsPerSample.Length == 3 diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs index 484d231633..089dc31ade 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs @@ -63,6 +63,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation /// Rgb888, + /// + /// RGB color image with 4 bits for each channel. + /// + Rgb444, + /// /// RGB Full Color. Planar configuration of data. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs index 35a9a590bb..289637fc32 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs @@ -23,6 +23,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Bit8 = 8, + /// + /// 14 bits per pixel. 4 bit for each color channel. + /// + /// Note: The TiffEncoder does not yet support 4 bits per color channel and will default to 24 bits per pixel. + /// + Bit12 = 12, + /// /// 24 bits per pixel. One byte for each color channel. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs index bc74cbc5fb..992a5ad6eb 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs @@ -28,6 +28,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Bit8 = 8, + /// + /// Twelve bits per sample, each channel has 4 bits. + /// + Bit12 = 12, + /// /// 24 bits per sample, each color channel has 8 Bits. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs index 5c4c374bef..32ef547ba4 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs @@ -23,6 +23,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff return TiffConstants.BitsPerSample4Bit; case TiffBitsPerSample.Bit8: return TiffConstants.BitsPerSample8Bit; + case TiffBitsPerSample.Bit12: + return TiffConstants.BitsPerSampleRgb4Bit; case TiffBitsPerSample.Bit24: return TiffConstants.BitsPerSampleRgb8Bit; @@ -48,6 +50,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff return TiffBitsPerSample.Bit24; } + if (bitsPerSample[0] == TiffConstants.BitsPerSampleRgb4Bit[0] && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb4Bit[1] && + bitsPerSample[2] == TiffConstants.BitsPerSampleRgb4Bit[2]) + { + return TiffBitsPerSample.Bit12; + } + break; case 1: diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 50882c0072..fadb4f7c2e 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -294,7 +294,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff int top = rowsPerStrip * stripIndex; if (top + stripHeight > frame.Height) { - // Make sure we ignore any strips that are not needed for the image (if too many are present) + // Make sure we ignore any strips that are not needed for the image (if too many are present). break; } diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index b5f3e7cf1e..1b48cd08f6 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -1,6 +1,7 @@ // 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; @@ -179,7 +180,18 @@ namespace SixLabors.ImageSharp.Formats.Tiff if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky) { - options.ColorType = options.BitsPerSample == TiffBitsPerSample.Bit24 ? TiffColorType.Rgb888 : TiffColorType.Rgb; + switch (options.BitsPerSample) + { + case TiffBitsPerSample.Bit24: + options.ColorType = TiffColorType.Rgb888; + break; + case TiffBitsPerSample.Bit12: + options.ColorType = TiffColorType.Rgb444; + break; + default: + TiffThrowHelper.ThrowNotSupported("Bits per sample is nut supported."); + break; + } } else { @@ -274,8 +286,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffBitsPerPixel.Bit1 => TiffBitsPerSample.Bit1, TiffBitsPerPixel.Bit4 => TiffBitsPerSample.Bit4, TiffBitsPerPixel.Bit8 => TiffBitsPerSample.Bit8, + TiffBitsPerPixel.Bit12 => TiffBitsPerSample.Bit12, TiffBitsPerPixel.Bit24 => TiffBitsPerSample.Bit24, - _ => TiffBitsPerSample.Bit24, + _ => throw new NotSupportedException("The bits per pixel are not supported"), }; } } diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index 74c516f63b..6b5ca0086f 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -306,7 +306,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffBitsPerPixel.Bit1: if (compression == TiffCompression.Ccitt1D || compression == TiffCompression.CcittGroup3Fax || compression == TiffCompression.CcittGroup4Fax) { - // The normal PhotometricInterpretation for bilevel CCITT compressed data is WhiteIsZero. + // The “normal” PhotometricInterpretation for bilevel CCITT compressed data is WhiteIsZero. this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.WhiteIsZero, compression, TiffPredictor.None); break; } @@ -319,6 +319,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffBitsPerPixel.Bit8: this.SetEncoderOptions(bitsPerPixel, photometricInterpretation ?? TiffPhotometricInterpretation.BlackIsZero, compression, predictor); break; + case TiffBitsPerPixel.Bit12: + // Encoding 12 bits per pixel is not yet supported. Default to 24 bits. + this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, TiffPredictor.None); + break; default: this.SetEncoderOptions(bitsPerPixel, TiffPhotometricInterpretation.Rgb, compression, predictor); break; diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs index 09605bc690..9bc0792c40 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs @@ -66,8 +66,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff Value = SoftwareValue }; - this.collector.Add(width); - this.collector.Add(height); + this.collector.AddOrReplace(width); + this.collector.AddOrReplace(height); this.ProcessResolution(image.Metadata, rootFrameExifProfile); this.ProcessProfiles(image.Metadata, rootFrameExifProfile, rootFrameXmpBytes); @@ -227,7 +227,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff exifProfile.RemoveValue(ExifTag.IccProfile); } - TiffMetadata tiffMetadata = imageMetadata.GetTiffMetadata(); if (xmpProfile != null) { var xmp = new ExifByteArray(ExifTagValue.XMP, ExifDataType.Byte) @@ -252,6 +251,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff public void Process(TiffEncoderCore encoder) { + var planarConfig = new ExifShort(ExifTagValue.PlanarConfiguration) + { + Value = (ushort)TiffPlanarConfiguration.Chunky + }; + var samplesPerPixel = new ExifLong(ExifTagValue.SamplesPerPixel) { Value = GetSamplesPerPixel(encoder) @@ -274,6 +278,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff Value = (ushort)encoder.PhotometricInterpretation }; + this.collector.AddOrReplace(planarConfig); this.collector.AddOrReplace(samplesPerPixel); this.collector.AddOrReplace(bitPerSample); this.collector.AddOrReplace(compression); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 1a72046fb3..2144ddfdb3 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -105,6 +105,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff } } + [Theory] + [WithFile(FlowerRgb444Contiguous, PixelTypes.Rgba32)] + [WithFile(FlowerRgb444Planar, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_12Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + if (TestEnvironment.IsWindows) + { + TestTiffDecoder(provider, new SystemDrawingReferenceDecoder()); + } + } + [Theory] [WithFile(GrayscaleDeflateMultistrip, PixelTypes.Rgba32)] [WithFile(RgbDeflateMultistrip, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs index 3aded7b0e3..68244b3b12 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs @@ -288,10 +288,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.Equal("This is Изготовитель камеры", exifProfileInput.GetValue(ExifTag.Make).Value); Assert.Equal("This is Авторские права", exifProfileInput.GetValue(ExifTag.Copyright).Value); - Assert.Equal(exifProfileInput.Values.Count, encodedImageExifProfile.Values.Count); Assert.Equal(exifProfileInput.GetValue(ExifTag.ImageDescription).Value, encodedImageExifProfile.GetValue(ExifTag.ImageDescription).Value); Assert.Equal(exifProfileInput.GetValue(ExifTag.Make).Value, encodedImageExifProfile.GetValue(ExifTag.Make).Value); Assert.Equal(exifProfileInput.GetValue(ExifTag.Copyright).Value, encodedImageExifProfile.GetValue(ExifTag.Copyright).Value); + + // Note that the encoded profile has PlanarConfiguration explicitly set, which is missing in the original image profile. + Assert.Equal((ushort)TiffPlanarConfiguration.Chunky, encodedImageExifProfile.GetValue(ExifTag.PlanarConfiguration).Value); + Assert.Equal(exifProfileInput.Values.Count + 1, encodedImageExifProfile.Values.Count); } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 09394d4ea0..d1c29489fb 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 FlowerRgb444Contiguous = "Tiff/flower-rgb-contig-04.tiff"; + public const string FlowerRgb444Planar = "Tiff/flower-rgb-planar-04.tiff"; public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff"; public const string SmallRgbLzw = "Tiff/rgb_small_lzw.tiff"; diff --git a/tests/Images/Input/Tiff/flower-rgb-contig-04.tiff b/tests/Images/Input/Tiff/flower-rgb-contig-04.tiff new file mode 100644 index 0000000000..d9a141f29a --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-contig-04.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96c4c1dfc23a0d9e5c6189717647fa117b08aac9a40c63e3945d3e674df4c3c6 +size 5049 diff --git a/tests/Images/Input/Tiff/flower-rgb-planar-04.tiff b/tests/Images/Input/Tiff/flower-rgb-planar-04.tiff new file mode 100644 index 0000000000..7a2270e486 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-planar-04.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca4434aa1a8c52654b20596c7c428c9016e089de75c29dc6ddcd32708874005c +size 5117 From bc723d308bce60736b7de8041547ef7bb7fc61f9 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 2 Jun 2021 10:38:54 +0200 Subject: [PATCH 02/11] Add 4 bit and 2 bit depth to the valid bit depth for the magick reference decoder --- .../TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 4e2866be1f..885d12e774 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs MemoryGroup framePixels = frame.PixelBuffer.FastMemoryGroup; using IUnsafePixelCollection pixels = magicFrame.GetPixelsUnsafe(); - if (magicFrame.Depth == 8 || magicFrame.Depth == 1) + if (magicFrame.Depth == 8 || magicFrame.Depth == 4 || magicFrame.Depth == 2 || magicFrame.Depth == 1) { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); From 5e0f75f1197e256b03de24dcb5834bb7470397d1 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 2 Jun 2021 10:39:13 +0200 Subject: [PATCH 03/11] Dont skip tests on linux, use magick decoder --- .../Formats/Tiff/TiffDecoderTests.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 2144ddfdb3..c58977813a 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -97,25 +97,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(Flower4BitPalette, PixelTypes.Rgba32)] [WithFile(Flower4BitPaletteGray, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_4Bit_WithPalette(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - if (TestEnvironment.IsWindows) - { - TestTiffDecoder(provider, new SystemDrawingReferenceDecoder(), useExactComparer: false, 0.01f); - } - } + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider, ReferenceDecoder, useExactComparer: false, 0.01f); [Theory] [WithFile(FlowerRgb444Contiguous, PixelTypes.Rgba32)] [WithFile(FlowerRgb444Planar, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_12Bit(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - if (TestEnvironment.IsWindows) - { - TestTiffDecoder(provider, new SystemDrawingReferenceDecoder()); - } - } + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); [Theory] [WithFile(GrayscaleDeflateMultistrip, PixelTypes.Rgba32)] From cc081b0de7071c84d984318078cc4de8c1321529 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 2 Jun 2021 14:09:32 +0200 Subject: [PATCH 04/11] Use magick decoder for 4bit test, add test for encoding option with 12 bpp --- .../Formats/Tiff/TiffEncoderTests.cs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 105514c982..61bccc008d 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -77,6 +77,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.Equal(TiffCompression.None, frameMetaData.Compression); } + [Theory] + [InlineData(TiffBitsPerPixel.Bit12)] + public void EncoderOptions_UnsupportedBitPerPixel_DefaultTo24Bits(TiffBitsPerPixel bitsPerPixel) + { + // arrange + var tiffEncoder = new TiffEncoder { BitsPerPixel = bitsPerPixel }; + using Image input = new Image(10, 10); + using var memStream = new MemoryStream(); + + // act + input.Save(memStream, tiffEncoder); + + // assert + memStream.Position = 0; + using var output = Image.Load(memStream); + + TiffFrameMetadata frameMetaData = output.Frames.RootFrame.Metadata.GetTiffMetadata(); + Assert.Equal(TiffBitsPerPixel.Bit24, frameMetaData.BitsPerPixel); + } + [Theory] [InlineData(null, TiffCompression.Deflate, TiffBitsPerPixel.Bit24, TiffCompression.Deflate)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Deflate, TiffBitsPerPixel.Bit24, TiffCompression.Deflate)] @@ -300,8 +320,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(Flower4BitPaletteGray, PixelTypes.Rgba32)] public void TiffEncoder_EncodeColorPalette_With4Bit_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => - //// Note: The magick reference decoder does not support 4 bit tiff's, so we use our TIFF decoder instead. - TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit4, TiffPhotometricInterpretation.PaletteColor, useExactComparer: false, compareTolerance: 0.003f, imageDecoder: new TiffDecoder()); + TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit4, TiffPhotometricInterpretation.PaletteColor, useExactComparer: false, compareTolerance: 0.003f); [Theory] [WithFile(Calliphora_PaletteUncompressed, PixelTypes.Rgba32)] From 85ef0fe2ca9e674abea787b7d9f8258b7d257e6e Mon Sep 17 00:00:00 2001 From: Brian Popow <38701097+brianpopow@users.noreply.github.com> Date: Wed, 2 Jun 2021 20:25:08 +0200 Subject: [PATCH 05/11] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs | 4 ++-- src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs index 32ef547ba4..4910cf9527 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs @@ -50,9 +50,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff return TiffBitsPerSample.Bit24; } - if (bitsPerSample[0] == TiffConstants.BitsPerSampleRgb4Bit[0] && + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb4Bit[2] && bitsPerSample[1] == TiffConstants.BitsPerSampleRgb4Bit[1] && - bitsPerSample[2] == TiffConstants.BitsPerSampleRgb4Bit[2]) + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb4Bit[0]) { return TiffBitsPerSample.Bit12; } diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 1b48cd08f6..b38ff68c18 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -189,7 +189,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff options.ColorType = TiffColorType.Rgb444; break; default: - TiffThrowHelper.ThrowNotSupported("Bits per sample is nut supported."); + TiffThrowHelper.ThrowNotSupported("Bits per sample is not supported."); break; } } From 3a6a5e9201a7ba00bfc57e8ed4ba6fd732518286 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 2 Jun 2021 20:27:08 +0200 Subject: [PATCH 06/11] Flip order of comparing BitsPerSample --- src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs index 4910cf9527..0687b0104a 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs @@ -43,9 +43,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff switch (bitsPerSample.Length) { case 3: - if (bitsPerSample[0] == TiffConstants.BitsPerSampleRgb8Bit[0] && + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb8Bit[2] && bitsPerSample[1] == TiffConstants.BitsPerSampleRgb8Bit[1] && - bitsPerSample[2] == TiffConstants.BitsPerSampleRgb8Bit[2]) + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb8Bit[0]) { return TiffBitsPerSample.Bit24; } From 580723fc0aac40443d52a4636acadeb7b3e9b000 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 3 Jun 2021 10:34:52 +0200 Subject: [PATCH 07/11] Add test for encode and reload planar tiff --- src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs | 2 +- tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs | 6 ++++++ tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs index 289637fc32..4b65f88b8c 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff Bit8 = 8, /// - /// 14 bits per pixel. 4 bit for each color channel. + /// 12 bits per pixel. 4 bit for each color channel. /// /// Note: The TiffEncoder does not yet support 4 bits per color channel and will default to 24 bits per pixel. /// diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 61bccc008d..dd3ef133e6 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -248,6 +248,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.Equal(expectedCompression, frameMetaData.Compression); } + // This makes sure, that when decoding a planar tiff, the planar configuration is not carried over to the encoded image. + [Theory] + [WithFile(FlowerRgb444Planar, PixelTypes.Rgba32)] + public void TiffEncoder_EncodePlanar_AndReload_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, imageDecoder: new TiffDecoder()); + [Theory] [WithFile(Calliphora_RgbUncompressed, PixelTypes.Rgba32)] public void TiffEncoder_EncodeRgb_Works(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs index 68244b3b12..ab350f720e 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs @@ -293,7 +293,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.Equal(exifProfileInput.GetValue(ExifTag.Copyright).Value, encodedImageExifProfile.GetValue(ExifTag.Copyright).Value); // Note that the encoded profile has PlanarConfiguration explicitly set, which is missing in the original image profile. - Assert.Equal((ushort)TiffPlanarConfiguration.Chunky, encodedImageExifProfile.GetValue(ExifTag.PlanarConfiguration).Value); + Assert.Equal((ushort)TiffPlanarConfiguration.Chunky, encodedImageExifProfile.GetValue(ExifTag.PlanarConfiguration)?.Value); Assert.Equal(exifProfileInput.Values.Count + 1, encodedImageExifProfile.Values.Count); } } From 42d5d9ee912f8d5d1b8307cc5d916fddc7a89387 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 3 Jun 2021 12:10:27 +0200 Subject: [PATCH 08/11] Add support for decoding 6 bit per pixel tiff's --- src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs | 9 +++++++-- .../TiffColorDecoderFactory{TPixel}.cs | 10 ++++++++++ .../Tiff/PhotometricInterpretation/TiffColorType.cs | 9 +++++++-- src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs | 9 ++++++++- src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs | 5 +++++ .../Formats/Tiff/TiffBitsPerSampleExtensions.cs | 9 +++++++++ .../Formats/Tiff/TiffDecoderOptionsParser.cs | 4 ++++ src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs | 3 ++- .../ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 6 ++++++ .../ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 2 ++ tests/Images/Input/Tiff/flower-rgb-contig-02.tiff | 3 +++ tests/Images/Input/Tiff/flower-rgb-planar-02.tiff | 3 +++ 13 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 tests/Images/Input/Tiff/flower-rgb-contig-02.tiff create mode 100644 tests/Images/Input/Tiff/flower-rgb-planar-02.tiff diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index 988b1242ae..f56488a52f 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -96,15 +96,20 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants public static readonly ushort[] BitsPerSample8Bit = { 8 }; /// - /// The bits per sample for color images with 8 bits for each color channel. + /// The bits per sample for color images with 2 bits for each color channel. /// - public static readonly ushort[] BitsPerSampleRgb8Bit = { 8, 8, 8 }; + public static readonly ushort[] BitsPerSampleRgb2Bit = { 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 }; + /// + /// The bits per sample for color images with 8 bits for each color channel. + /// + public static readonly ushort[] BitsPerSampleRgb8Bit = { 8, 8, 8 }; + /// /// The list of mimetypes that equate to a tiff. /// diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs index d78b06aa7f..2c59fdf137 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs @@ -57,6 +57,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); + case TiffColorType.Rgb222: + DebugGuard.IsTrue( + bitsPerSample.Length == 3 + && bitsPerSample[0] == 2 + && bitsPerSample[1] == 2 + && bitsPerSample[2] == 2, + "bitsPerSample"); + DebugGuard.IsTrue(colorMap == null, "colorMap"); + return new RgbTiffColor(bitsPerSample); + case TiffColorType.Rgb444: DebugGuard.IsTrue( bitsPerSample.Length == 3 diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs index 089dc31ade..1d6535fd71 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs @@ -59,15 +59,20 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation Rgb, /// - /// RGB Full Color. Optimized implementation for 8-bit images. + /// RGB color image with 2 bits for each channel. /// - Rgb888, + Rgb222, /// /// RGB color image with 4 bits for each channel. /// Rgb444, + /// + /// RGB Full Color. Optimized implementation for 8-bit images. + /// + Rgb888, + /// /// RGB Full Color. Planar configuration of data. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs index 4b65f88b8c..0dee1105bb 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs @@ -18,6 +18,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Bit4 = 4, + /// + /// 6 bits per pixel. 2 bit for each color channel. + /// + /// Note: The TiffEncoder does not yet support 2 bits per color channel and will default to 24 bits per pixel instead. + /// + Bit6 = 6, + /// /// 8 bits per pixel, grayscale or color palette images. /// @@ -26,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// /// 12 bits per pixel. 4 bit for each color channel. /// - /// Note: The TiffEncoder does not yet support 4 bits per color channel and will default to 24 bits per pixel. + /// Note: The TiffEncoder does not yet support 4 bits per color channel and will default to 24 bits per pixel instead. /// Bit12 = 12, diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs index 992a5ad6eb..0a4962b530 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs @@ -28,6 +28,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Bit8 = 8, + /// + /// Six bits per sample, each channel has 2 bits. + /// + Bit6 = 6, + /// /// Twelve bits per sample, each channel has 4 bits. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs index 0687b0104a..923e355f40 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs @@ -21,6 +21,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff return TiffConstants.BitsPerSample1Bit; case TiffBitsPerSample.Bit4: return TiffConstants.BitsPerSample4Bit; + case TiffBitsPerSample.Bit6: + return TiffConstants.BitsPerSampleRgb2Bit; case TiffBitsPerSample.Bit8: return TiffConstants.BitsPerSample8Bit; case TiffBitsPerSample.Bit12: @@ -57,6 +59,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff 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: diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index b38ff68c18..1c2ee2443d 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -188,6 +188,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffBitsPerSample.Bit12: options.ColorType = TiffColorType.Rgb444; break; + case TiffBitsPerSample.Bit6: + options.ColorType = TiffColorType.Rgb222; + break; default: TiffThrowHelper.ThrowNotSupported("Bits per sample is not supported."); break; @@ -285,6 +288,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff { TiffBitsPerPixel.Bit1 => TiffBitsPerSample.Bit1, TiffBitsPerPixel.Bit4 => TiffBitsPerSample.Bit4, + TiffBitsPerPixel.Bit6 => TiffBitsPerSample.Bit6, TiffBitsPerPixel.Bit8 => TiffBitsPerSample.Bit8, TiffBitsPerPixel.Bit12 => TiffBitsPerSample.Bit12, TiffBitsPerPixel.Bit24 => TiffBitsPerSample.Bit24, diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index 6b5ca0086f..b61a0c0e1a 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -319,8 +319,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffBitsPerPixel.Bit8: this.SetEncoderOptions(bitsPerPixel, photometricInterpretation ?? TiffPhotometricInterpretation.BlackIsZero, compression, predictor); break; + case TiffBitsPerPixel.Bit6: case TiffBitsPerPixel.Bit12: - // Encoding 12 bits per pixel is not yet supported. Default to 24 bits. + // Encoding 12 and 6 bits per pixel is not yet supported. Default to 24 bits. this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, TiffPredictor.None); break; default: diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index c58977813a..ad27ed0fcc 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -99,6 +99,12 @@ 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(FlowerRgb222Contiguous, PixelTypes.Rgba32)] + [WithFile(FlowerRgb222Planar, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_6Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] [WithFile(FlowerRgb444Contiguous, PixelTypes.Rgba32)] [WithFile(FlowerRgb444Planar, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index dd3ef133e6..1b3104e728 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.Bit12)] + [InlineData(TiffBitsPerPixel.Bit6)] public void EncoderOptions_UnsupportedBitPerPixel_DefaultTo24Bits(TiffBitsPerPixel bitsPerPixel) { // arrange diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index d1c29489fb..3eff09c75f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -562,6 +562,8 @@ namespace SixLabors.ImageSharp.Tests public const string Flower4BitPaletteGray = "Tiff/flower-minisblack-04.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"; + public const string FlowerRgb222Planar = "Tiff/flower-rgb-planar-02.tiff"; public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff"; public const string SmallRgbLzw = "Tiff/rgb_small_lzw.tiff"; diff --git a/tests/Images/Input/Tiff/flower-rgb-contig-02.tiff b/tests/Images/Input/Tiff/flower-rgb-contig-02.tiff new file mode 100644 index 0000000000..a2d253dbd5 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-contig-02.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fbcd225c0db343f0cc984c35609b81f6413ebc1ba2ce2494d3607db375e969ff +size 2685 diff --git a/tests/Images/Input/Tiff/flower-rgb-planar-02.tiff b/tests/Images/Input/Tiff/flower-rgb-planar-02.tiff new file mode 100644 index 0000000000..8b301a534d --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-planar-02.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21c4ede6382d8c72cb8e6f7939203d5111b362646a9727d95a2f63310ec8e5b3 +size 2795 From 8e6fad805cef36a305a332b517d5ba7a13e6a5e9 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 3 Jun 2021 12:35:30 +0200 Subject: [PATCH 09/11] Add support for decoding 30 bit per pixel tiff's --- src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs | 5 +++++ .../TiffColorDecoderFactory{TPixel}.cs | 10 ++++++++++ .../Tiff/PhotometricInterpretation/TiffColorType.cs | 5 +++++ src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs | 7 +++++++ src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs | 5 +++++ .../Formats/Tiff/TiffBitsPerSampleExtensions.cs | 9 +++++++++ .../Formats/Tiff/TiffDecoderOptionsParser.cs | 5 +++++ src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs | 3 ++- .../ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 6 ++++++ .../ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 2 ++ .../ReferenceCodecs/MagickReferenceDecoder.cs | 2 +- tests/Images/Input/Tiff/flower-rgb-contig-10.tiff | 3 +++ tests/Images/Input/Tiff/flower-rgb-planar-10.tiff | 3 +++ 14 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 tests/Images/Input/Tiff/flower-rgb-contig-10.tiff create mode 100644 tests/Images/Input/Tiff/flower-rgb-planar-10.tiff diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index f56488a52f..2327528b0e 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -110,6 +110,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants /// public static readonly ushort[] BitsPerSampleRgb8Bit = { 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 }; + /// /// The list of mimetypes that equate to a tiff. /// diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs index 2c59fdf137..9ebf48620a 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs @@ -87,6 +87,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation DebugGuard.IsTrue(colorMap == null, "colorMap"); return new Rgb888TiffColor(); + case TiffColorType.Rgb101010: + DebugGuard.IsTrue( + bitsPerSample.Length == 3 + && bitsPerSample[0] == 10 + && bitsPerSample[1] == 10 + && bitsPerSample[2] == 10, + "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 1d6535fd71..afa86b1430 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs @@ -73,6 +73,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation /// Rgb888, + /// + /// RGB color image with 10 bits for each channel. + /// + Rgb101010, + /// /// RGB Full Color. Planar configuration of data. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs index 0dee1105bb..dc1ef0fd6e 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs @@ -41,5 +41,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// 24 bits per pixel. One byte for each color channel. /// Bit24 = 24, + + /// + /// 30 bits per pixel. 10 bit for each color channel. + /// + /// Note: The TiffEncoder does not yet support 10 bits per color channel and will default to 24 bits per pixel instead. + /// + Bit30 = 30, } } diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs index 0a4962b530..02378ded30 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs @@ -42,5 +42,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// 24 bits per sample, each color channel has 8 Bits. /// Bit24 = 24, + + /// + /// Thirty bits per sample, each channel has 10 bits. + /// + Bit30 = 30, } } diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs index 923e355f40..51a5a53a7a 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs @@ -29,6 +29,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff return TiffConstants.BitsPerSampleRgb4Bit; case TiffBitsPerSample.Bit24: return TiffConstants.BitsPerSampleRgb8Bit; + case TiffBitsPerSample.Bit30: + return TiffConstants.BitsPerSampleRgb10Bit; default: return Array.Empty(); @@ -45,6 +47,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff switch (bitsPerSample.Length) { case 3: + 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]) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 1c2ee2443d..cf6ac6dc75 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -182,6 +182,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff { switch (options.BitsPerSample) { + case TiffBitsPerSample.Bit30: + options.ColorType = TiffColorType.Rgb101010; + break; + case TiffBitsPerSample.Bit24: options.ColorType = TiffColorType.Rgb888; break; @@ -292,6 +296,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffBitsPerPixel.Bit8 => TiffBitsPerSample.Bit8, TiffBitsPerPixel.Bit12 => TiffBitsPerSample.Bit12, TiffBitsPerPixel.Bit24 => TiffBitsPerSample.Bit24, + TiffBitsPerPixel.Bit30 => TiffBitsPerSample.Bit30, _ => throw new NotSupportedException("The bits per pixel are not supported"), }; } diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index b61a0c0e1a..edfa215cc5 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -321,7 +321,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff break; case TiffBitsPerPixel.Bit6: case TiffBitsPerPixel.Bit12: - // Encoding 12 and 6 bits per pixel is not yet supported. Default to 24 bits. + case TiffBitsPerPixel.Bit30: + // Encoding 30, 12 and 6 bits per pixel is not yet supported. Default to 24 bits. this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, TiffPredictor.None); break; default: diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index ad27ed0fcc..0dd8e0e22e 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -111,6 +111,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff public void TiffDecoder_CanDecode_12Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] + [WithFile(FlowerRgb101010Contiguous, PixelTypes.Rgba32)] + [WithFile(FlowerRgb101010Planar, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_30Bit(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 1b3104e728..19cfc42e4f 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.Bit30)] [InlineData(TiffBitsPerPixel.Bit12)] [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 3eff09c75f..05045d06a4 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 FlowerRgb101010Contiguous = "Tiff/flower-rgb-contig-10.tiff"; + public const string FlowerRgb101010Planar = "Tiff/flower-rgb-planar-10.tiff"; public const string FlowerRgb444Contiguous = "Tiff/flower-rgb-contig-04.tiff"; public const string FlowerRgb444Planar = "Tiff/flower-rgb-planar-04.tiff"; public const string FlowerRgb222Contiguous = "Tiff/flower-rgb-contig-02.tiff"; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 885d12e774..30c2214b5a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -87,7 +87,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) + if (magicFrame.Depth == 8 || magicFrame.Depth == 4 || magicFrame.Depth == 2 || magicFrame.Depth == 1 || magicFrame.Depth == 10) { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); diff --git a/tests/Images/Input/Tiff/flower-rgb-contig-10.tiff b/tests/Images/Input/Tiff/flower-rgb-contig-10.tiff new file mode 100644 index 0000000000..2b271c8004 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-contig-10.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68168ea1c2e50e674a7c5c41e5b055c881adf8cb940d0fd033a927a7ebdd7b6f +size 12117 diff --git a/tests/Images/Input/Tiff/flower-rgb-planar-10.tiff b/tests/Images/Input/Tiff/flower-rgb-planar-10.tiff new file mode 100644 index 0000000000..be0acd6465 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-planar-10.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f53948d4a36c80f45d70a315d2e76514ec41cabe982c06dbbd0d47e671120e2 +size 12211 From deed7485253358e25319875da649c0807cb42a1b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 3 Jun 2021 13:20:18 +0200 Subject: [PATCH 10/11] Add support for decoding 10 bit per channel rgb tiff's --- src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs | 5 +++++ .../TiffColorDecoderFactory{TPixel}.cs | 10 ++++++++++ .../Tiff/PhotometricInterpretation/TiffColorType.cs | 5 +++++ src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs | 7 +++++++ src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs | 5 +++++ .../Formats/Tiff/TiffBitsPerSampleExtensions.cs | 9 +++++++++ .../Formats/Tiff/TiffDecoderOptionsParser.cs | 5 +++++ src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs | 3 ++- .../ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 6 ++++++ .../ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 2 ++ .../ReferenceCodecs/MagickReferenceDecoder.cs | 7 ++----- tests/Images/Input/Tiff/flower-rgb-contig-14.tiff | 3 +++ tests/Images/Input/Tiff/flower-rgb-planar-14.tiff | 3 +++ 14 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 tests/Images/Input/Tiff/flower-rgb-contig-14.tiff create mode 100644 tests/Images/Input/Tiff/flower-rgb-planar-14.tiff diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index 2327528b0e..6fe412b925 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -115,6 +115,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants /// public static readonly ushort[] BitsPerSampleRgb10Bit = { 10, 10, 10 }; + /// + /// The bits per sample for color images with 14 bits for each color channel. + /// + public static readonly ushort[] BitsPerSampleRgb14Bit = { 14, 14, 14 }; + /// /// The list of mimetypes that equate to a tiff. /// diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs index 9ebf48620a..924415850d 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs @@ -97,6 +97,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); + case TiffColorType.Rgb141414: + DebugGuard.IsTrue( + bitsPerSample.Length == 3 + && bitsPerSample[0] == 14 + && bitsPerSample[1] == 14 + && bitsPerSample[2] == 14, + "bitsPerSample"); + DebugGuard.IsTrue(colorMap == null, "colorMap"); + return new RgbTiffColor(bitsPerSample); + case TiffColorType.PaletteColor: DebugGuard.NotNull(bitsPerSample, "bitsPerSample"); DebugGuard.NotNull(colorMap, "colorMap"); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs index afa86b1430..22d8199533 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs @@ -78,6 +78,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation /// Rgb101010, + /// + /// RGB color image with 14 bits for each channel. + /// + Rgb141414, + /// /// RGB Full Color. Planar configuration of data. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs index dc1ef0fd6e..ab9f3cbec0 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs @@ -48,5 +48,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Note: The TiffEncoder does not yet support 10 bits per color channel and will default to 24 bits per pixel instead. /// Bit30 = 30, + + /// + /// 42 bits per pixel. 14 bit for each color channel. + /// + /// Note: The TiffEncoder does not yet support 14 bits per color channel and will default to 24 bits per pixel instead. + /// + Bit42 = 42, } } diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs index 02378ded30..088ef5d6f8 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs @@ -47,5 +47,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// Thirty bits per sample, each channel has 10 bits. /// Bit30 = 30, + + /// + /// Forty two bits per sample, each channel has 14 bits. + /// + Bit42 = 42, } } diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs index 51a5a53a7a..ca0f0befcc 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs @@ -31,6 +31,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff return TiffConstants.BitsPerSampleRgb8Bit; case TiffBitsPerSample.Bit30: return TiffConstants.BitsPerSampleRgb10Bit; + case TiffBitsPerSample.Bit42: + return TiffConstants.BitsPerSampleRgb14Bit; default: return Array.Empty(); @@ -47,6 +49,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff switch (bitsPerSample.Length) { case 3: + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb14Bit[2] && + bitsPerSample[1] == TiffConstants.BitsPerSampleRgb14Bit[1] && + bitsPerSample[0] == TiffConstants.BitsPerSampleRgb14Bit[0]) + { + return TiffBitsPerSample.Bit42; + } + if (bitsPerSample[2] == TiffConstants.BitsPerSampleRgb10Bit[2] && bitsPerSample[1] == TiffConstants.BitsPerSampleRgb10Bit[1] && bitsPerSample[0] == TiffConstants.BitsPerSampleRgb10Bit[0]) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index cf6ac6dc75..eeac6a33c2 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -182,6 +182,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff { switch (options.BitsPerSample) { + case TiffBitsPerSample.Bit42: + options.ColorType = TiffColorType.Rgb141414; + break; + case TiffBitsPerSample.Bit30: options.ColorType = TiffColorType.Rgb101010; break; @@ -297,6 +301,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffBitsPerPixel.Bit12 => TiffBitsPerSample.Bit12, TiffBitsPerPixel.Bit24 => TiffBitsPerSample.Bit24, TiffBitsPerPixel.Bit30 => TiffBitsPerSample.Bit30, + TiffBitsPerPixel.Bit42 => TiffBitsPerSample.Bit42, _ => throw new NotSupportedException("The bits per pixel are not supported"), }; } diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index edfa215cc5..d5137c4357 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -322,7 +322,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff case TiffBitsPerPixel.Bit6: case TiffBitsPerPixel.Bit12: case TiffBitsPerPixel.Bit30: - // Encoding 30, 12 and 6 bits per pixel is not yet supported. Default to 24 bits. + case TiffBitsPerPixel.Bit42: + // Encoding 42, 30, 12 and 6 bits per pixel is not yet supported. Default to 24 bits. this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, TiffPredictor.None); break; default: diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 0dd8e0e22e..02b7f97d94 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -117,6 +117,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff public void TiffDecoder_CanDecode_30Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] + [WithFile(FlowerRgb141414Contiguous, PixelTypes.Rgba32)] + [WithFile(FlowerRgb141414Planar, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_42Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] [WithFile(GrayscaleDeflateMultistrip, PixelTypes.Rgba32)] [WithFile(RgbDeflateMultistrip, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 19cfc42e4f..7c386a6a9a 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -78,6 +78,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff } [Theory] + [InlineData(TiffBitsPerPixel.Bit42)] [InlineData(TiffBitsPerPixel.Bit30)] [InlineData(TiffBitsPerPixel.Bit12)] [InlineData(TiffBitsPerPixel.Bit6)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 05045d06a4..9471a63937 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -560,6 +560,8 @@ namespace SixLabors.ImageSharp.Tests public const string RgbPaletteDeflate = "Tiff/rgb_palette_deflate.tiff"; public const string Flower4BitPalette = "Tiff/flower-palette-04.tiff"; public const string Flower4BitPaletteGray = "Tiff/flower-minisblack-04.tiff"; + public const string FlowerRgb141414Contiguous = "Tiff/flower-rgb-contig-14.tiff"; + public const string FlowerRgb141414Planar = "Tiff/flower-rgb-planar-14.tiff"; public const string FlowerRgb101010Contiguous = "Tiff/flower-rgb-contig-10.tiff"; public const string FlowerRgb101010Planar = "Tiff/flower-rgb-planar-10.tiff"; public const string FlowerRgb444Contiguous = "Tiff/flower-rgb-contig-04.tiff"; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 30c2214b5a..dffbeac497 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -25,10 +25,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { } - public MagickReferenceDecoder(bool validate) - { - this.validate = validate; - } + public MagickReferenceDecoder(bool validate) => this.validate = validate; public static MagickReferenceDecoder Instance { get; } = new MagickReferenceDecoder(); @@ -93,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs FromRgba32Bytes(configuration, data, framePixels); } - else if (magicFrame.Depth == 16) + else if (magicFrame.Depth == 16 || magicFrame.Depth == 14) { ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); diff --git a/tests/Images/Input/Tiff/flower-rgb-contig-14.tiff b/tests/Images/Input/Tiff/flower-rgb-contig-14.tiff new file mode 100644 index 0000000000..d4d6a9492d --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-contig-14.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a419a8e2f89321501ca8ad70d2a19d37a7bf3a8c2f45c809acc30be59139ae29 +size 16855 diff --git a/tests/Images/Input/Tiff/flower-rgb-planar-14.tiff b/tests/Images/Input/Tiff/flower-rgb-planar-14.tiff new file mode 100644 index 0000000000..2d517268e9 --- /dev/null +++ b/tests/Images/Input/Tiff/flower-rgb-planar-14.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d28f021d40f53a011053f9644400fee2d29c02f97b4101fec899251125dbb18e +size 16855 From 036b95bd7a49ba105febee78c88198fa0e07ba08 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 3 Jun 2021 14:44:20 +0200 Subject: [PATCH 11/11] Flip order of comparing bitsPerSample --- .../TiffColorDecoderFactory{TPixel}.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs index 924415850d..5555eb537c 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs @@ -60,9 +60,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation case TiffColorType.Rgb222: DebugGuard.IsTrue( bitsPerSample.Length == 3 - && bitsPerSample[0] == 2 + && bitsPerSample[2] == 2 && bitsPerSample[1] == 2 - && bitsPerSample[2] == 2, + && bitsPerSample[0] == 2, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); @@ -70,9 +70,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation case TiffColorType.Rgb444: DebugGuard.IsTrue( bitsPerSample.Length == 3 - && bitsPerSample[0] == 4 + && bitsPerSample[2] == 4 && bitsPerSample[1] == 4 - && bitsPerSample[2] == 4, + && bitsPerSample[0] == 4, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new Rgb444TiffColor(); @@ -80,9 +80,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation case TiffColorType.Rgb888: DebugGuard.IsTrue( bitsPerSample.Length == 3 - && bitsPerSample[0] == 8 + && bitsPerSample[2] == 8 && bitsPerSample[1] == 8 - && bitsPerSample[2] == 8, + && bitsPerSample[0] == 8, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new Rgb888TiffColor(); @@ -90,9 +90,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation case TiffColorType.Rgb101010: DebugGuard.IsTrue( bitsPerSample.Length == 3 - && bitsPerSample[0] == 10 + && bitsPerSample[2] == 10 && bitsPerSample[1] == 10 - && bitsPerSample[2] == 10, + && bitsPerSample[0] == 10, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample); @@ -100,9 +100,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation case TiffColorType.Rgb141414: DebugGuard.IsTrue( bitsPerSample.Length == 3 - && bitsPerSample[0] == 14 + && bitsPerSample[2] == 14 && bitsPerSample[1] == 14 - && bitsPerSample[2] == 14, + && bitsPerSample[0] == 14, "bitsPerSample"); DebugGuard.IsTrue(colorMap == null, "colorMap"); return new RgbTiffColor(bitsPerSample);