From 0e5938f92a3cb021be2068c1b6c7282c62017b6a Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 29 Jan 2021 19:04:31 +0100 Subject: [PATCH] Parse T4 Options: honor eol padding, if present --- .../Tiff/Compression/FaxCompressionOptions.cs | 36 +++++++++ .../ModifiedHuffmanTiffCompression.cs | 4 +- .../Formats/Tiff/Compression/T4BitReader.cs | 74 +++++++++++-------- .../Tiff/Compression/T4TiffCompression.cs | 17 +++-- .../Compression/TiffCompressionFactory.cs | 11 ++- src/ImageSharp/Formats/Tiff/README.md | 2 +- .../Formats/Tiff/TiffDecoderCore.cs | 16 +++- .../Formats/Tiff/TiffDecoderOptionsParser.cs | 13 +++- .../Codecs/DecodeTiff.cs | 2 +- .../Formats/Tiff/TiffDecoderTests.cs | 41 +++------- tests/ImageSharp.Tests/TestImages.cs | 1 + ...alliphora_ccitt_fax3_with_eol_padding.tiff | 3 + 12 files changed, 142 insertions(+), 78 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/Compression/FaxCompressionOptions.cs create mode 100644 tests/Images/Input/Tiff/Calliphora_ccitt_fax3_with_eol_padding.tiff diff --git a/src/ImageSharp/Formats/Tiff/Compression/FaxCompressionOptions.cs b/src/ImageSharp/Formats/Tiff/Compression/FaxCompressionOptions.cs new file mode 100644 index 0000000000..d5171db657 --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/Compression/FaxCompressionOptions.cs @@ -0,0 +1,36 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression +{ + /// + /// Fax compression options, see TIFF spec page 51f (T4Options). + /// + [Flags] + public enum FaxCompressionOptions : uint + { + /// + /// No options. + /// + None = 0, + + /// + /// If set, 2-dimensional coding is used (otherwise 1-dimensional is assumed). + /// + TwoDimensionalCoding = 1, + + /// + /// If set, uncompressed mode is used. + /// + UncompressedMode = 2, + + /// + /// If set, fill bits have been added as necessary before EOL codes such that + /// EOL always ends on a byte boundary, thus ensuring an EOL-sequence of 1 byte + /// preceded by a zero nibble: xxxx-0000 0000-0001. + /// + EolPadding = 4 + } +} diff --git a/src/ImageSharp/Formats/Tiff/Compression/ModifiedHuffmanTiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/ModifiedHuffmanTiffCompression.cs index e46b0621dd..539fc83dce 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/ModifiedHuffmanTiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/ModifiedHuffmanTiffCompression.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression /// The photometric interpretation. /// The image width. public ModifiedHuffmanTiffCompression(MemoryAllocator allocator, TiffPhotometricInterpretation photometricInterpretation, int width) - : base(allocator, photometricInterpretation, width) + : base(allocator, FaxCompressionOptions.None, photometricInterpretation, width) { } @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression byte whiteValue = (byte)(isWhiteZero ? 0 : 1); byte blackValue = (byte)(isWhiteZero ? 1 : 0); - using var bitReader = new T4BitReader(stream, byteCount, this.Allocator, isModifiedHuffman: true); + using var bitReader = new T4BitReader(stream, byteCount, this.Allocator, eolPadding: false, isModifiedHuffman: true); buffer.Clear(); uint bitsWritten = 0; diff --git a/src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs b/src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs index f7b6200fa4..35dd829ffc 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/T4BitReader.cs @@ -35,11 +35,6 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression /// private ulong position; - /// - /// Indicates, if the current run are white pixels. - /// - private bool isWhiteRun; - /// /// Indicates whether its the first line of data which is read from the image. /// @@ -50,24 +45,27 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression /// private bool terminationCodeFound; - /// - /// Number of pixels in the current run. - /// - private uint runLength; - /// /// We keep track if its the start of the row, because each run is expected to start with a white run. /// If the image row itself starts with black, a white run of zero is expected. /// private bool isStartOfRow; + /// + /// Indicates whether the modified huffman compression, as specified in the TIFF spec in section 10, is used. + /// private readonly bool isModifiedHuffmanRle; + /// + /// Indicates, if fill bits have been added as necessary before EOL codes such that EOL always ends on a byte boundary. Defaults to false. + /// + private readonly bool eolPadding; + private readonly int dataLength; private const int MinCodeLength = 2; - private const int MaxCodeLength = 13; + private readonly int maxCodeLength = 13; private static readonly Dictionary WhiteLen4TermCodes = new Dictionary() { @@ -225,8 +223,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression /// The compressed input stream. /// The number of bytes to read from the stream. /// The memory allocator. - /// Indicates, if its the modified huffman code variation. - public T4BitReader(Stream input, int bytesToRead, MemoryAllocator allocator, bool isModifiedHuffman = false) + /// Indicates, if fill bits have been added as necessary before EOL codes such that EOL always ends on a byte boundary. Defaults to false. + /// Indicates, if its the modified huffman code variation. Defaults to false. + public T4BitReader(Stream input, int bytesToRead, MemoryAllocator allocator, bool eolPadding = false, bool isModifiedHuffman = false) { this.Data = allocator.Allocate(bytesToRead); this.ReadImageDataFromStream(input, bytesToRead); @@ -237,11 +236,17 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression this.value = 0; this.curValueBitsRead = 0; this.position = 0; - this.isWhiteRun = true; + this.IsWhiteRun = true; this.isFirstScanLine = true; this.isStartOfRow = true; this.terminationCodeFound = false; - this.runLength = 0; + this.RunLength = 0; + this.eolPadding = eolPadding; + + if (this.eolPadding) + { + this.maxCodeLength = 24; + } } /// @@ -268,17 +273,28 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression /// /// Gets a value indicating whether the current run is a white pixel run, otherwise its a black pixel run. /// - public bool IsWhiteRun => this.isWhiteRun; + public bool IsWhiteRun { get; private set; } /// /// Gets the number of pixels in the current run. /// - public uint RunLength => this.runLength; + public uint RunLength { get; private set; } /// /// Gets a value indicating whether the end of a pixel row has been reached. /// - public bool IsEndOfScanLine => this.curValueBitsRead == 12 && this.value == 1; + public bool IsEndOfScanLine + { + get + { + if (this.eolPadding) + { + return this.curValueBitsRead >= 12 && this.value == 1; + } + + return this.curValueBitsRead == 12 && this.value == 1; + } + } /// /// Read the next run of pixels. @@ -287,7 +303,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression { if (this.terminationCodeFound) { - this.isWhiteRun = !this.IsWhiteRun; + this.IsWhiteRun = !this.IsWhiteRun; this.terminationCodeFound = false; } @@ -296,7 +312,8 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression if (this.isFirstScanLine && !this.isModifiedHuffmanRle) { // We expect an EOL before the first data. - this.value = this.ReadValue(12); + this.value = this.ReadValue(this.eolPadding ? 16 : 12); + if (!this.IsEndOfScanLine) { TiffThrowHelper.ThrowImageFormatException("t4 parsing error: expected start of data marker not found"); @@ -310,7 +327,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression do { - if (this.curValueBitsRead > MaxCodeLength) + if (this.curValueBitsRead > this.maxCodeLength) { TiffThrowHelper.ThrowImageFormatException("t4 parsing error: invalid code length read"); } @@ -320,11 +337,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression { if (this.IsWhiteRun) { - this.runLength += this.WhiteMakeupCodeRunLength(); + this.RunLength += this.WhiteMakeupCodeRunLength(); } else { - this.runLength += this.BlackMakeupCodeRunLength(); + this.RunLength += this.BlackMakeupCodeRunLength(); } this.isStartOfRow = false; @@ -338,7 +355,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression // Each line starts with a white run. If the image starts with black, a white run with length zero is written. if (this.isStartOfRow && this.IsWhiteRun && this.WhiteTerminatingCodeRunLength() == 0) { - this.isWhiteRun = !this.IsWhiteRun; + this.IsWhiteRun = !this.IsWhiteRun; this.Reset(); this.isStartOfRow = false; continue; @@ -346,11 +363,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression if (this.IsWhiteRun) { - this.runLength += this.WhiteTerminatingCodeRunLength(); + this.RunLength += this.WhiteTerminatingCodeRunLength(); } else { - this.runLength += this.BlackTerminatingCodeRunLength(); + this.RunLength += this.BlackTerminatingCodeRunLength(); } this.terminationCodeFound = true; @@ -374,7 +391,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression public void StartNewRow() { // Each new row starts with a white run. - this.isWhiteRun = true; + this.IsWhiteRun = true; this.isStartOfRow = true; this.terminationCodeFound = false; @@ -770,14 +787,13 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression if (resetRunLength) { - this.runLength = 0; + this.RunLength = 0; } } private uint ReadValue(int nBits) { Guard.MustBeGreaterThan(nBits, 0, nameof(nBits)); - Guard.MustBeLessThanOrEqualTo(nBits, 12, nameof(nBits)); uint v = 0; int shift = nBits; diff --git a/src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs b/src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs index 8ffb2e6926..2d0d7f5753 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/T4TiffCompression.cs @@ -14,25 +14,32 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression /// internal class T4TiffCompression : TiffBaseCompression { + private readonly FaxCompressionOptions faxCompressionOptions; + /// /// Initializes a new instance of the class. /// /// The memory allocator. + /// Fax compression options. /// The photometric interpretation. /// The image width. - public T4TiffCompression(MemoryAllocator allocator, TiffPhotometricInterpretation photometricInterpretation, int width) - : base(allocator, photometricInterpretation, width) - { - } + public T4TiffCompression(MemoryAllocator allocator, FaxCompressionOptions faxOptions, TiffPhotometricInterpretation photometricInterpretation, int width) + : base(allocator, photometricInterpretation, width) => this.faxCompressionOptions = faxOptions; /// protected override void Decompress(BufferedReadStream stream, int byteCount, Span buffer) { + if (this.faxCompressionOptions.HasFlag(FaxCompressionOptions.TwoDimensionalCoding)) + { + TiffThrowHelper.ThrowNotSupported("TIFF CCITT 2D compression is not yet supported"); + } + bool isWhiteZero = this.PhotometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero; byte whiteValue = (byte)(isWhiteZero ? 0 : 1); byte blackValue = (byte)(isWhiteZero ? 1 : 0); - using var bitReader = new T4BitReader(stream, byteCount, this.Allocator); + var eolPadding = this.faxCompressionOptions.HasFlag(FaxCompressionOptions.EolPadding); + using var bitReader = new T4BitReader(stream, byteCount, this.Allocator, eolPadding); buffer.Clear(); uint bitsWritten = 0; diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffCompressionFactory.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffCompressionFactory.cs index 2e2fa51458..55cd64b777 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffCompressionFactory.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffCompressionFactory.cs @@ -8,7 +8,14 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression { internal static class TiffCompressionFactory { - public static TiffBaseCompression Create(TiffDecoderCompressionType compressionType, MemoryAllocator allocator, TiffPhotometricInterpretation photometricInterpretation, int width, int bitsPerPixel, TiffPredictor predictor) + public static TiffBaseCompression Create( + TiffDecoderCompressionType compressionType, + MemoryAllocator allocator, + TiffPhotometricInterpretation photometricInterpretation, + int width, + int bitsPerPixel, + TiffPredictor predictor, + FaxCompressionOptions faxOptions) { switch (compressionType) { @@ -28,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression case TiffDecoderCompressionType.T4: DebugGuard.IsTrue(predictor == TiffPredictor.None, "predictor"); - return new T4TiffCompression(allocator, photometricInterpretation, width); + return new T4TiffCompression(allocator, faxOptions, photometricInterpretation, width); case TiffDecoderCompressionType.HuffmanRle: DebugGuard.IsTrue(predictor == TiffPredictor.None, "predictor"); diff --git a/src/ImageSharp/Formats/Tiff/README.md b/src/ImageSharp/Formats/Tiff/README.md index 7e88310484..8f06bbb595 100644 --- a/src/ImageSharp/Formats/Tiff/README.md +++ b/src/ImageSharp/Formats/Tiff/README.md @@ -121,7 +121,7 @@ Decoder: |PageName | | | | |XPosition | | | | |YPosition | | | | -|T4Options | | | | +|T4Options | | Y | | |T6Options | | | | |PageNumber | | | | |TransferFunction | | | | diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index e6d5f873dd..c6d3f42ba1 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff internal class TiffDecoderCore : IImageDecoderInternals { /// - /// The global configuration + /// The global configuration. /// private readonly Configuration configuration; @@ -60,6 +60,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff /// public ushort[] BitsPerSample { get; set; } + /// + /// Gets or sets the bits per pixel. + /// public int BitsPerPixel { get; set; } /// @@ -77,6 +80,11 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff /// public TiffDecoderCompressionType CompressionType { get; set; } + /// + /// Gets or sets the Fax specific compression options. + /// + public FaxCompressionOptions FaxCompressionOptions { get; set; } + /// /// Gets or sets the planar configuration type to use when decoding the image. /// @@ -88,7 +96,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff public TiffPhotometricInterpretation PhotometricInterpretation { get; set; } /// - /// Gets or sets the predictor. + /// Gets or sets the horizontal predictor. /// public TiffPredictor Predictor { get; set; } @@ -284,7 +292,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff stripBuffers[stripIndex] = this.memoryAllocator.AllocateManagedByteBuffer(uncompressedStripSize); } - TiffBaseCompression decompressor = TiffCompressionFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, width, bitsPerPixel, this.Predictor); + TiffBaseCompression decompressor = TiffCompressionFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions); RgbPlanarTiffColor colorDecoder = TiffColorDecoderFactory.CreatePlanar(this.ColorType, this.BitsPerSample, this.ColorMap); @@ -321,7 +329,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff Buffer2D pixels = frame.PixelBuffer; - TiffBaseCompression decompressor = TiffCompressionFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, width, bitsPerPixel, this.Predictor); + TiffBaseCompression decompressor = TiffCompressionFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions); TiffBaseColorDecoder colorDecoder = TiffColorDecoderFactory.Create(this.ColorType, this.BitsPerSample, this.ColorMap); diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 713c85c06d..5e1851018f 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.Runtime.CompilerServices; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants; using SixLabors.ImageSharp.Metadata.Profiles.Exif; @@ -57,7 +58,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff options.BitsPerPixel = entries.BitsPerPixel; ParseColorType(options, entries); - ParseCompression(options, entries.Compression); + ParseCompression(options, entries); } private static void ParseColorType(this TiffDecoderCore options, TiffFrameMetadata entries) @@ -208,8 +209,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff } } - private static void ParseCompression(this TiffDecoderCore options, TiffCompression compression) + private static void ParseCompression(this TiffDecoderCore options, TiffFrameMetadata entries) { + TiffCompression compression = entries.Compression; switch (compression) { case TiffCompression.None: @@ -240,6 +242,13 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff case TiffCompression.CcittGroup3Fax: { options.CompressionType = TiffDecoderCompressionType.T4; + IExifValue t4options = entries.FrameTags.Find(tag => tag.Tag == ExifTag.T4Options); + if (t4options != null) + { + var t4OptionValue = (FaxCompressionOptions)t4options.GetValue(); + options.FaxCompressionOptions = t4OptionValue; + } + break; } diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs index 15bb183655..fb506528f9 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs @@ -3,7 +3,7 @@ // Enable this for using larger Tiff files. Those files are very large (> 700MB) and therefor not part of the git repo. // Use the scripts gen_big.ps1 and gen_medium.ps1 in tests\Images\Input\Tiff\Benchmarks to generate those images. -// #define BIG_TESTS +//// #define BIG_TESTS using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index c2cfeb053e..f9ee8b1051 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -39,10 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [Theory] [WithFileCollection(nameof(NotSupportedImages), PixelTypes.Rgba32)] public void ThrowsNotSupported(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - Assert.Throws(() => provider.GetImage(TiffDecoder)); - } + where TPixel : unmanaged, IPixel => Assert.Throws(() => provider.GetImage(TiffDecoder)); [Theory] [InlineData(TestImages.Tiff.RgbUncompressed, 24, 256, 256, 300, 300, PixelResolutionUnit.PixelsPerInch)] @@ -91,10 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(Calliphora_RgbUncompressed, PixelTypes.Rgba32)] [WithFile(Calliphora_BiColorUncompressed, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Uncompressed(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - TestTiffDecoder(provider); - } + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); [Theory] [WithFile(Calliphora_PaletteUncompressed, PixelTypes.Rgba32)] @@ -103,10 +97,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(RgbPaletteDeflate, PixelTypes.Rgba32)] [WithFile(PaletteUncompressed, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_WithPalette(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - TestTiffDecoder(provider); - } + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); [Theory] [WithFile(GrayscaleDeflateMultistrip, PixelTypes.Rgba32)] @@ -118,10 +109,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(RgbDeflatePredictor, PixelTypes.Rgba32)] [WithFile(SmallRgbDeflate, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_DeflateCompressed(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - TestTiffDecoder(provider); - } + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); [Theory] [WithFile(RgbLzwPredictor, PixelTypes.Rgba32)] @@ -134,10 +122,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(Calliphora_GrayscaleLzw_Predictor, PixelTypes.Rgba32)] [WithFile(SmallRgbLzw, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_LzwCompressed(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - TestTiffDecoder(provider); - } + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); [Theory] [WithFile(HuffmanRleAllTermCodes, PixelTypes.Rgba32)] @@ -145,30 +130,22 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(HuffmanRle_basi3p02, PixelTypes.Rgba32)] [WithFile(Calliphora_HuffmanCompressed, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_HuffmanCompressed(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - TestTiffDecoder(provider); - } + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); [Theory] [WithFile(CcittFax3AllTermCodes, PixelTypes.Rgba32)] [WithFile(CcittFax3AllMakeupCodes, PixelTypes.Rgba32)] [WithFile(Calliphora_Fax3Compressed, PixelTypes.Rgba32)] + [WithFile(Calliphora_Fax3Compressed_WithEolPadding, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_Fax3Compressed(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - TestTiffDecoder(provider); - } + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); [Theory] [WithFile(Calliphora_RgbPackbits, PixelTypes.Rgba32)] [WithFile(RgbPackbits, PixelTypes.Rgba32)] [WithFile(RgbPackbitsMultistrip, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode_PackBitsCompressed(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - TestTiffDecoder(provider); - } + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); [Theory] [WithFileCollection(nameof(MultiframeTestImages), PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index e8baad2f7d..4edfdc9259 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -522,6 +522,7 @@ namespace SixLabors.ImageSharp.Tests public const string Calliphora_RgbPackbits = "Tiff/Calliphora_rgb_packbits.tiff"; public const string Calliphora_RgbUncompressed = "Tiff/Calliphora_rgb_uncompressed.tiff"; public const string Calliphora_Fax3Compressed = "Tiff/Calliphora_ccitt_fax3.tiff"; + public const string Calliphora_Fax3Compressed_WithEolPadding = "Tiff/Calliphora_ccitt_fax3_with_eol_padding.tiff"; public const string Calliphora_Fax4Compressed = "Tiff/Calliphora_ccitt_fax4.tiff"; public const string Calliphora_HuffmanCompressed = "Tiff/Calliphora_huffman_rle.tiff"; public const string Calliphora_BiColorUncompressed = "Tiff/Calliphora_bicolor_uncompressed.tiff"; diff --git a/tests/Images/Input/Tiff/Calliphora_ccitt_fax3_with_eol_padding.tiff b/tests/Images/Input/Tiff/Calliphora_ccitt_fax3_with_eol_padding.tiff new file mode 100644 index 0000000000..2072b0c47d --- /dev/null +++ b/tests/Images/Input/Tiff/Calliphora_ccitt_fax3_with_eol_padding.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:15e0f4f04699c7253ce422a7741ada192615182da53e9fd86bdf547cd991b290 +size 126382