From a1a2cec28463e6c10e40c5f27e7d35db989d41bd Mon Sep 17 00:00:00 2001 From: Petar Tasev Date: Wed, 1 Feb 2023 00:45:09 -0800 Subject: [PATCH 1/3] Added L16 support to tiff encoder (unit tests WIP) --- .../Tiff/Compression/HorizontalPredictor.cs | 31 ++++++++++++ .../Formats/Tiff/Constants/TiffConstants.cs | 5 ++ .../Formats/Tiff/TiffBitsPerPixel.cs | 2 +- .../Formats/Tiff/TiffEncoderCore.cs | 20 +++++++- .../Tiff/TiffEncoderEntriesCollector.cs | 20 ++++---- .../Tiff/Writers/TiffColorWriterFactory.cs | 9 ++-- .../Tiff/Writers/TiffGrayL16Writer{TPixel}.cs | 22 +++++++++ .../Formats/Tiff/TiffEncoderTests.cs | 47 +++++++++++++++++-- 8 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/Writers/TiffGrayL16Writer{TPixel}.cs diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index be1d00e7ed..9a4e4ba2b9 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -67,6 +67,11 @@ internal static class HorizontalPredictor { ApplyHorizontalPrediction8Bit(rows, width); } + else if (bitsPerPixel == 16) + { + // Assume rows are L16 grayscale since that's currently the only way 16 bits is supported by encoder + ApplyHorizontalPrediction16Bit(rows, width); + } else if (bitsPerPixel == 24) { ApplyHorizontalPrediction24Bit(rows, width); @@ -102,6 +107,32 @@ internal static class HorizontalPredictor } } + /// + /// Applies a horizontal predictor to the L16 row. + /// Make use of the fact that many continuous-tone images rarely vary much in pixel value from one pixel to the next. + /// In such images, if we replace the pixel values by differences between consecutive pixels, many of the differences should be 0, plus + /// or minus 1, and so on.This reduces the apparent information content and allows LZW to encode the data more compactly. + /// + /// The L16 pixel rows. + /// The width. + [MethodImpl(InliningOptions.ShortMethod)] + private static void ApplyHorizontalPrediction16Bit(Span rows, int width) + { + DebugGuard.IsTrue(rows.Length % width == 0, "Values must be equals"); + int height = rows.Length / width; + for (int y = 0; y < height; y++) + { + Span rowSpan = rows.Slice(y * width, width); + Span rowL16 = MemoryMarshal.Cast(rowSpan); + + for (int x = rowL16.Length - 1; x >= 1; x--) + { + ushort val = (ushort)(rowL16[x].PackedValue - rowL16[x - 1].PackedValue); + rowL16[x].PackedValue = val; + } + } + } + /// /// Applies a horizontal predictor to a gray pixel row. /// diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index 05dacfef65..978860910c 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -73,6 +73,11 @@ internal static class TiffConstants /// public static readonly TiffBitsPerSample BitsPerSample8Bit = new TiffBitsPerSample(8, 0, 0); + /// + /// The bits per sample for 16-bit grayscale images. + /// + public static readonly TiffBitsPerSample BitsPerSample16Bit = new TiffBitsPerSample(16, 0, 0); + /// /// The bits per sample for color images with 8 bits for each color channel. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs index bcc249bbec..38da4b5f8b 100644 --- a/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tiff/TiffBitsPerPixel.cs @@ -54,7 +54,7 @@ public enum TiffBitsPerPixel /// /// 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. + /// Note: The TiffEncoder does not yet support 16 bits per color channel and will default to 16 bits grayscale instead. /// Bit16 = 16, diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index 3a4e71d3e8..94c7fb2b1e 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -376,11 +376,14 @@ internal sealed class TiffEncoderCore : IImageEncoderInternals case TiffBitsPerPixel.Bit8: this.SetEncoderOptions(bitsPerPixel, photometricInterpretation ?? TiffPhotometricInterpretation.BlackIsZero, compression, predictor); break; + case TiffBitsPerPixel.Bit16: + // Assume desire to encode as L16 grayscale + this.SetEncoderOptions(bitsPerPixel, 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.Bit36: case TiffBitsPerPixel.Bit42: @@ -413,13 +416,20 @@ internal sealed class TiffEncoderCore : IImageEncoderInternals return; } - // At the moment only 8 and 32 bits per pixel can be preserved by the tiff encoder. + // At the moment only 8, 16 and 32 bits per pixel can be preserved by the tiff encoder. if (inputBitsPerPixel == 8) { this.SetEncoderOptions(TiffBitsPerPixel.Bit8, TiffPhotometricInterpretation.BlackIsZero, compression, predictor); return; } + if (inputBitsPerPixel == 16) + { + // Assume desire to encode as L16 grayscale + this.SetEncoderOptions(TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, compression, predictor); + return; + } + this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, predictor); return; } @@ -434,6 +444,12 @@ internal sealed class TiffEncoderCore : IImageEncoderInternals return; } + if (inputBitsPerPixel == 16) + { + this.SetEncoderOptions(TiffBitsPerPixel.Bit16, photometricInterpretation, compression, predictor); + return; + } + this.SetEncoderOptions(TiffBitsPerPixel.Bit8, photometricInterpretation, compression, predictor); return; diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs index 7dd073936f..cf9b4ae213 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs @@ -343,20 +343,20 @@ internal class TiffEncoderEntriesCollector return TiffConstants.BitsPerSampleRgb8Bit.ToArray(); case TiffPhotometricInterpretation.WhiteIsZero: - if (encoder.BitsPerPixel == TiffBitsPerPixel.Bit1) + return encoder.BitsPerPixel switch { - return TiffConstants.BitsPerSample1Bit.ToArray(); - } - - return TiffConstants.BitsPerSample8Bit.ToArray(); + TiffBitsPerPixel.Bit1 => TiffConstants.BitsPerSample1Bit.ToArray(), + TiffBitsPerPixel.Bit16 => TiffConstants.BitsPerSample16Bit.ToArray(), + _ => TiffConstants.BitsPerSample8Bit.ToArray() + }; case TiffPhotometricInterpretation.BlackIsZero: - if (encoder.BitsPerPixel == TiffBitsPerPixel.Bit1) + return encoder.BitsPerPixel switch { - return TiffConstants.BitsPerSample1Bit.ToArray(); - } - - return TiffConstants.BitsPerSample8Bit.ToArray(); + TiffBitsPerPixel.Bit1 => TiffConstants.BitsPerSample1Bit.ToArray(), + TiffBitsPerPixel.Bit16 => TiffConstants.BitsPerSample16Bit.ToArray(), + _ => TiffConstants.BitsPerSample8Bit.ToArray() + }; default: return TiffConstants.BitsPerSampleRgb8Bit.ToArray(); diff --git a/src/ImageSharp/Formats/Tiff/Writers/TiffColorWriterFactory.cs b/src/ImageSharp/Formats/Tiff/Writers/TiffColorWriterFactory.cs index a52d49a353..96c8aeb324 100644 --- a/src/ImageSharp/Formats/Tiff/Writers/TiffColorWriterFactory.cs +++ b/src/ImageSharp/Formats/Tiff/Writers/TiffColorWriterFactory.cs @@ -27,12 +27,13 @@ internal static class TiffColorWriterFactory return new TiffPaletteWriter(image, quantizer, pixelSamplingStrategy, memoryAllocator, configuration, entriesCollector, bitsPerPixel); case TiffPhotometricInterpretation.BlackIsZero: case TiffPhotometricInterpretation.WhiteIsZero: - if (bitsPerPixel == 1) + return bitsPerPixel switch { - return new TiffBiColorWriter(image, memoryAllocator, configuration, entriesCollector); - } + 1 => new TiffBiColorWriter(image, memoryAllocator, configuration, entriesCollector), + 16 => new TiffGrayL16Writer(image, memoryAllocator, configuration, entriesCollector), + _ => new TiffGrayWriter(image, memoryAllocator, configuration, entriesCollector) + }; - return new TiffGrayWriter(image, memoryAllocator, configuration, entriesCollector); default: return new TiffRgbWriter(image, memoryAllocator, configuration, entriesCollector); } diff --git a/src/ImageSharp/Formats/Tiff/Writers/TiffGrayL16Writer{TPixel}.cs b/src/ImageSharp/Formats/Tiff/Writers/TiffGrayL16Writer{TPixel}.cs new file mode 100644 index 0000000000..3e0e074e95 --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/Writers/TiffGrayL16Writer{TPixel}.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Tiff.Writers; + +internal sealed class TiffGrayL16Writer : TiffCompositeColorWriter + where TPixel : unmanaged, IPixel +{ + public TiffGrayL16Writer(ImageFrame image, MemoryAllocator memoryAllocator, Configuration configuration, TiffEncoderEntriesCollector entriesCollector) + : base(image, memoryAllocator, configuration, entriesCollector) + { + } + + /// + public override int BitsPerPixel => 16; + + /// + protected override void EncodePixels(Span pixels, Span buffer) => PixelOperations.Instance.ToL16Bytes(this.Configuration, pixels, buffer, pixels.Length); +} diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index 97445ad6cf..bae429e65a 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -17,6 +17,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester [InlineData(TiffPhotometricInterpretation.PaletteColor, TiffBitsPerPixel.Bit8)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffBitsPerPixel.Bit8)] [InlineData(TiffPhotometricInterpretation.WhiteIsZero, TiffBitsPerPixel.Bit8)] + [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffBitsPerPixel.Bit16)] //// Unsupported TiffPhotometricInterpretation should default to 24 bits [InlineData(TiffPhotometricInterpretation.CieLab, TiffBitsPerPixel.Bit24)] [InlineData(TiffPhotometricInterpretation.ColorFilterArray, TiffBitsPerPixel.Bit24)] @@ -28,7 +29,9 @@ public class TiffEncoderTests : TiffEncoderBaseTester { // arrange var tiffEncoder = new TiffEncoder { PhotometricInterpretation = photometricInterpretation }; - using Image input = new Image(10, 10); + using Image input = expectedBitsPerPixel is TiffBitsPerPixel.Bit16 + ? new Image(10, 10) + : new Image(10, 10); using var memStream = new MemoryStream(); // act @@ -44,6 +47,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester [Theory] [InlineData(TiffBitsPerPixel.Bit24)] + [InlineData(TiffBitsPerPixel.Bit16)] [InlineData(TiffBitsPerPixel.Bit8)] [InlineData(TiffBitsPerPixel.Bit4)] [InlineData(TiffBitsPerPixel.Bit1)] @@ -117,14 +121,17 @@ public class TiffEncoderTests : TiffEncoderBaseTester [Theory] [InlineData(null, TiffCompression.Deflate, TiffBitsPerPixel.Bit24, TiffCompression.Deflate)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Deflate, TiffBitsPerPixel.Bit24, TiffCompression.Deflate)] + [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate, TiffBitsPerPixel.Bit16, TiffCompression.Deflate)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate, TiffBitsPerPixel.Bit8, TiffCompression.Deflate)] [InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.Deflate, TiffBitsPerPixel.Bit8, TiffCompression.Deflate)] [InlineData(null, TiffCompression.PackBits, TiffBitsPerPixel.Bit24, TiffCompression.PackBits)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.PackBits, TiffBitsPerPixel.Bit24, TiffCompression.PackBits)] - [InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.PackBits, TiffBitsPerPixel.Bit8, TiffCompression.PackBits)] + [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits, TiffBitsPerPixel.Bit16, TiffCompression.PackBits)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits, TiffBitsPerPixel.Bit8, TiffCompression.PackBits)] + [InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.PackBits, TiffBitsPerPixel.Bit8, TiffCompression.PackBits)] [InlineData(null, TiffCompression.Lzw, TiffBitsPerPixel.Bit24, TiffCompression.Lzw)] [InlineData(TiffPhotometricInterpretation.Rgb, TiffCompression.Lzw, TiffBitsPerPixel.Bit24, TiffCompression.Lzw)] + [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw, TiffBitsPerPixel.Bit16, TiffCompression.Lzw)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw, TiffBitsPerPixel.Bit8, TiffCompression.Lzw)] [InlineData(TiffPhotometricInterpretation.PaletteColor, TiffCompression.Lzw, TiffBitsPerPixel.Bit8, TiffCompression.Lzw)] [InlineData(TiffPhotometricInterpretation.BlackIsZero, TiffCompression.CcittGroup3Fax, TiffBitsPerPixel.Bit1, TiffCompression.CcittGroup3Fax)] @@ -143,7 +150,9 @@ public class TiffEncoderTests : TiffEncoderBaseTester { // arrange var tiffEncoder = new TiffEncoder { PhotometricInterpretation = photometricInterpretation, Compression = compression }; - using Image input = new Image(10, 10); + using Image input = expectedBitsPerPixel is TiffBitsPerPixel.Bit16 + ? new Image(10, 10) + : new Image(10, 10); using var memStream = new MemoryStream(); // act @@ -160,6 +169,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester [Theory] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit1)] [WithFile(GrayscaleUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit8)] + [WithFile(GrayscaleUncompressed, PixelTypes.L16, TiffBitsPerPixel.Bit16)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit24)] [WithFile(Rgb4BitPalette, PixelTypes.Rgba32, TiffBitsPerPixel.Bit4)] [WithFile(RgbPalette, PixelTypes.Rgba32, TiffBitsPerPixel.Bit8)] @@ -406,6 +416,36 @@ public class TiffEncoderTests : TiffEncoderBaseTester where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit8, TiffPhotometricInterpretation.PaletteColor, TiffCompression.Lzw, TiffPredictor.Horizontal, useExactComparer: false, compareTolerance: 0.001f); + [Theory] + [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + public void TiffEncoder_EncodeGray16_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero); + + [Theory] + [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + public void TiffEncoder_EncodeGray16_WithDeflateCompression_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate); + + [Theory] + [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + public void TiffEncoder_EncodeGray16_WithDeflateCompressionAndPredictor_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate, TiffPredictor.Horizontal); + + [Theory] + [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + public void TiffEncoder_EncodeGray16_WithLzwCompression_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw); + + [Theory] + [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + public void TiffEncoder_EncodeGray16_WithLzwCompressionAndPredictor_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw, TiffPredictor.Horizontal); + + [Theory] + [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + public void TiffEncoder_EncodeGray16_WithPackBitsCompression_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits); + [Theory] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)] public void TiffEncoder_EncodeBiColor_BlackIsZero_Works(TestImageProvider provider) @@ -473,6 +513,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester [Theory] [WithFile(GrayscaleUncompressed, PixelTypes.L8, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits)] + [WithFile(GrayscaleUncompressed, PixelTypes.L16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffPhotometricInterpretation.Rgb, TiffCompression.Deflate)] [WithFile(RgbUncompressed, PixelTypes.Rgb24, TiffPhotometricInterpretation.Rgb, TiffCompression.None)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffPhotometricInterpretation.Rgb, TiffCompression.None)] From bd9e1ee5080c3527f053a99b8ce4b70def697819 Mon Sep 17 00:00:00 2001 From: Petar Tasev Date: Wed, 1 Feb 2023 21:46:12 -0800 Subject: [PATCH 2/3] Added unit tests and 16 bit grayscale images --- .../Formats/Tiff/TiffDecoderTests.cs | 2 ++ .../Formats/Tiff/TiffEncoderTests.cs | 16 ++++++++-------- .../Formats/Tiff/TiffMetadataTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 2 ++ .../Calliphora_grayscale_uncompressed_16bit.tiff | 3 +++ .../Input/Tiff/grayscale_uncompressed_16bit.tiff | 3 +++ 6 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 tests/Images/Input/Tiff/Calliphora_grayscale_uncompressed_16bit.tiff create mode 100644 tests/Images/Input/Tiff/grayscale_uncompressed_16bit.tiff diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 8c43fd81d8..31b9ffb318 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -27,6 +27,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester [InlineData(RgbUncompressed, 24, 256, 256, 300, 300, PixelResolutionUnit.PixelsPerInch)] [InlineData(SmallRgbDeflate, 24, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Calliphora_GrayscaleUncompressed, 8, 200, 298, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(Calliphora_GrayscaleUncompressed16Bit, 16, 200, 298, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Flower4BitPalette, 4, 73, 43, 72, 72, PixelResolutionUnit.PixelsPerInch)] public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) { @@ -64,6 +65,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester [Theory] [WithFile(RgbUncompressed, PixelTypes.Rgba32)] [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + [WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)] [WithFile(Calliphora_RgbUncompressed, PixelTypes.Rgba32)] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Uncompressed(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs index bae429e65a..f8aa1551fc 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs @@ -169,7 +169,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester [Theory] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit1)] [WithFile(GrayscaleUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit8)] - [WithFile(GrayscaleUncompressed, PixelTypes.L16, TiffBitsPerPixel.Bit16)] + [WithFile(GrayscaleUncompressed16Bit, PixelTypes.L16, TiffBitsPerPixel.Bit16)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffBitsPerPixel.Bit24)] [WithFile(Rgb4BitPalette, PixelTypes.Rgba32, TiffBitsPerPixel.Bit4)] [WithFile(RgbPalette, PixelTypes.Rgba32, TiffBitsPerPixel.Bit8)] @@ -417,32 +417,32 @@ public class TiffEncoderTests : TiffEncoderBaseTester TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit8, TiffPhotometricInterpretation.PaletteColor, TiffCompression.Lzw, TiffPredictor.Horizontal, useExactComparer: false, compareTolerance: 0.001f); [Theory] - [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + [WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)] public void TiffEncoder_EncodeGray16_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero); [Theory] - [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + [WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)] public void TiffEncoder_EncodeGray16_WithDeflateCompression_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate); [Theory] - [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + [WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)] public void TiffEncoder_EncodeGray16_WithDeflateCompressionAndPredictor_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Deflate, TiffPredictor.Horizontal); [Theory] - [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + [WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)] public void TiffEncoder_EncodeGray16_WithLzwCompression_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw); [Theory] - [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + [WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)] public void TiffEncoder_EncodeGray16_WithLzwCompressionAndPredictor_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.Lzw, TiffPredictor.Horizontal); [Theory] - [WithFile(Calliphora_GrayscaleUncompressed, PixelTypes.Rgba32)] + [WithFile(Calliphora_GrayscaleUncompressed16Bit, PixelTypes.Rgba32)] public void TiffEncoder_EncodeGray16_WithPackBitsCompression_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits); @@ -513,7 +513,7 @@ public class TiffEncoderTests : TiffEncoderBaseTester [Theory] [WithFile(GrayscaleUncompressed, PixelTypes.L8, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits)] - [WithFile(GrayscaleUncompressed, PixelTypes.L16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits)] + [WithFile(GrayscaleUncompressed16Bit, PixelTypes.L16, TiffPhotometricInterpretation.BlackIsZero, TiffCompression.PackBits)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffPhotometricInterpretation.Rgb, TiffCompression.Deflate)] [WithFile(RgbUncompressed, PixelTypes.Rgb24, TiffPhotometricInterpretation.Rgb, TiffCompression.None)] [WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffPhotometricInterpretation.Rgb, TiffCompression.None)] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs index 51c0b6ef7e..5b09a244b5 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs @@ -75,6 +75,7 @@ public class TiffMetadataTests [Theory] [InlineData(Calliphora_BiColorUncompressed, 1)] [InlineData(GrayscaleUncompressed, 8)] + [InlineData(GrayscaleUncompressed16Bit, 16)] [InlineData(RgbUncompressed, 24)] public void Identify_DetectsCorrectBitPerPixel(string imagePath, int expectedBitsPerPixel) { diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 2de508b75c..c714b2f510 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -767,6 +767,7 @@ public static class TestImages public const string Calliphora_GrayscaleDeflate_Predictor = "Tiff/Calliphora_gray_deflate_predictor.tiff"; public const string Calliphora_GrayscaleLzw_Predictor = "Tiff/Calliphora_gray_lzw_predictor.tiff"; public const string Calliphora_GrayscaleDeflate = "Tiff/Calliphora_gray_deflate.tiff"; + public const string Calliphora_GrayscaleUncompressed16Bit = "Tiff/Calliphora_grayscale_uncompressed_16bit.tiff"; public const string Calliphora_RgbDeflate_Predictor = "Tiff/Calliphora_rgb_deflate_predictor.tiff"; public const string Calliphora_RgbJpeg = "Tiff/Calliphora_rgb_jpeg.tiff"; public const string Calliphora_PaletteUncompressed = "Tiff/Calliphora_palette_uncompressed.tiff"; @@ -798,6 +799,7 @@ public static class TestImages public const string GrayscaleDeflateMultistrip = "Tiff/grayscale_deflate_multistrip.tiff"; public const string GrayscaleUncompressed = "Tiff/grayscale_uncompressed.tiff"; + public const string GrayscaleUncompressed16Bit = "Tiff/grayscale_uncompressed_16bit.tiff"; public const string GrayscaleJpegCompressed = "Tiff/JpegCompressedGray.tiff"; public const string PaletteDeflateMultistrip = "Tiff/palette_grayscale_deflate_multistrip.tiff"; public const string PaletteUncompressed = "Tiff/palette_uncompressed.tiff"; diff --git a/tests/Images/Input/Tiff/Calliphora_grayscale_uncompressed_16bit.tiff b/tests/Images/Input/Tiff/Calliphora_grayscale_uncompressed_16bit.tiff new file mode 100644 index 0000000000..62d63a124b --- /dev/null +++ b/tests/Images/Input/Tiff/Calliphora_grayscale_uncompressed_16bit.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:42077e6e0d0e7e32bdc0dadb837aad03fd4ae9ceff158bdf213ea9b76dbc36f1 +size 119601 diff --git a/tests/Images/Input/Tiff/grayscale_uncompressed_16bit.tiff b/tests/Images/Input/Tiff/grayscale_uncompressed_16bit.tiff new file mode 100644 index 0000000000..85391d9fe0 --- /dev/null +++ b/tests/Images/Input/Tiff/grayscale_uncompressed_16bit.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49de8d78dc22c4c7e62b0c02ae409550c0247c49ec4685162a0fe986d3280aa7 +size 131294 From a43ac0cf539a28ece855baf53afa892ab1293f8e Mon Sep 17 00:00:00 2001 From: Petar Tasev Date: Wed, 1 Feb 2023 22:18:01 -0800 Subject: [PATCH 3/3] Added compressed grayscale 16 bit decoder tests --- tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 5 ++++- tests/ImageSharp.Tests/TestImages.cs | 3 +++ tests/Images/Input/Tiff/Calliphora_gray_deflate_16bit.tiff | 3 +++ .../Input/Tiff/Calliphora_gray_deflate_predictor_16bit.tiff | 3 +++ .../Input/Tiff/Calliphora_gray_lzw_predictor_16bit.tiff | 3 +++ 5 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/Images/Input/Tiff/Calliphora_gray_deflate_16bit.tiff create mode 100644 tests/Images/Input/Tiff/Calliphora_gray_deflate_predictor_16bit.tiff create mode 100644 tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor_16bit.tiff diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 31b9ffb318..05c1c5a138 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -35,7 +35,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester using MemoryStream stream = new(testFile.Bytes, false); ImageInfo info = Image.Identify(stream); - Assert.Equal(expectedPixelSize, info.PixelType?.BitsPerPixel); + Assert.Equal(expectedPixelSize, info.PixelType.BitsPerPixel); Assert.Equal(expectedWidth, info.Width); Assert.Equal(expectedHeight, info.Height); Assert.NotNull(info.Metadata); @@ -601,6 +601,8 @@ public class TiffDecoderTests : TiffDecoderBaseTester [WithFile(RgbDeflateMultistrip, PixelTypes.Rgba32)] [WithFile(Calliphora_GrayscaleDeflate, PixelTypes.Rgba32)] [WithFile(Calliphora_GrayscaleDeflate_Predictor, PixelTypes.Rgba32)] + [WithFile(Calliphora_GrayscaleDeflate16Bit, PixelTypes.Rgba32)] + [WithFile(Calliphora_GrayscaleDeflate_Predictor16Bit, PixelTypes.Rgba32)] [WithFile(Calliphora_RgbDeflate_Predictor, PixelTypes.Rgba32)] [WithFile(RgbDeflate, PixelTypes.Rgba32)] [WithFile(RgbDeflatePredictor, PixelTypes.Rgba32)] @@ -617,6 +619,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester [WithFile(Calliphora_RgbPaletteLzw_Predictor, PixelTypes.Rgba32)] [WithFile(Calliphora_RgbLzwPredictor, PixelTypes.Rgba32)] [WithFile(Calliphora_GrayscaleLzw_Predictor, PixelTypes.Rgba32)] + [WithFile(Calliphora_GrayscaleLzw_Predictor16Bit, PixelTypes.Rgba32)] [WithFile(SmallRgbLzw, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_LzwCompressed(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index c714b2f510..c282d81665 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -768,6 +768,9 @@ public static class TestImages public const string Calliphora_GrayscaleLzw_Predictor = "Tiff/Calliphora_gray_lzw_predictor.tiff"; public const string Calliphora_GrayscaleDeflate = "Tiff/Calliphora_gray_deflate.tiff"; public const string Calliphora_GrayscaleUncompressed16Bit = "Tiff/Calliphora_grayscale_uncompressed_16bit.tiff"; + public const string Calliphora_GrayscaleDeflate_Predictor16Bit = "Tiff/Calliphora_gray_deflate_predictor_16bit.tiff"; + public const string Calliphora_GrayscaleLzw_Predictor16Bit = "Tiff/Calliphora_gray_lzw_predictor_16bit.tiff"; + public const string Calliphora_GrayscaleDeflate16Bit = "Tiff/Calliphora_gray_deflate_16bit.tiff"; public const string Calliphora_RgbDeflate_Predictor = "Tiff/Calliphora_rgb_deflate_predictor.tiff"; public const string Calliphora_RgbJpeg = "Tiff/Calliphora_rgb_jpeg.tiff"; public const string Calliphora_PaletteUncompressed = "Tiff/Calliphora_palette_uncompressed.tiff"; diff --git a/tests/Images/Input/Tiff/Calliphora_gray_deflate_16bit.tiff b/tests/Images/Input/Tiff/Calliphora_gray_deflate_16bit.tiff new file mode 100644 index 0000000000..3864a62444 --- /dev/null +++ b/tests/Images/Input/Tiff/Calliphora_gray_deflate_16bit.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4fdf62eb43c0349cb8c6ad67e5389a0f307944d8a8e760667a7f78fcc48a9ffa +size 62698 diff --git a/tests/Images/Input/Tiff/Calliphora_gray_deflate_predictor_16bit.tiff b/tests/Images/Input/Tiff/Calliphora_gray_deflate_predictor_16bit.tiff new file mode 100644 index 0000000000..b25f2d29ea --- /dev/null +++ b/tests/Images/Input/Tiff/Calliphora_gray_deflate_predictor_16bit.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8040010e7f760d09dda49145050b07f32826037c11686d976b4b7949a0c40c18 +size 54086 diff --git a/tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor_16bit.tiff b/tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor_16bit.tiff new file mode 100644 index 0000000000..8f7e72441a --- /dev/null +++ b/tests/Images/Input/Tiff/Calliphora_gray_lzw_predictor_16bit.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:67246d3bfc0c361fae21db04fa0251168c7e12abe3c3cc134cd1d685fb09876f +size 58392