From db342184362a85bc194931fd16948bc31967f474 Mon Sep 17 00:00:00 2001 From: Jason Finch Date: Sun, 18 Oct 2026 09:23:14 +1000 Subject: [PATCH 1/3] Default a missing TIFF BitsPerSample to one bit per sample TIFF 6.0 defines a default of one bit for each sample when the BitsPerSample entry is absent, and bilevel fax and scanner files often omit it. The decoder assumed 8-bit RGB instead, so such files failed to decode or reported the wrong bit depth. The default now uses one bit for each of the SamplesPerPixel samples. --- .../Formats/Tiff/TiffFrameMetadata.cs | 22 ++++++- .../Formats/Tiff/TiffDecoderTests.cs | 61 +++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index d977b5f29f..3098e38dd1 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs @@ -216,10 +216,26 @@ private static void Parse(TiffFrameMetadata meta, ExifProfile profile) meta.EncodingWidth = GetImageWidth(profile); meta.EncodingHeight = GetImageHeight(profile); - if (profile.TryGetValue(ExifTag.BitsPerSample, out IExifValue? bitsPerSampleValue) - && TiffBitsPerSample.TryParse(bitsPerSampleValue.Value, out TiffBitsPerSample bitsPerSample)) + if (profile.TryGetValue(ExifTag.BitsPerSample, out IExifValue? bitsPerSampleValue)) { - meta.BitsPerSample = bitsPerSample; + if (TiffBitsPerSample.TryParse(bitsPerSampleValue.Value, out TiffBitsPerSample bitsPerSample)) + { + meta.BitsPerSample = bitsPerSample; + } + } + else + { + // TIFF 6.0 defines a default of one bit for each sample when the entry is absent, which bilevel + // fax and scanner files rely on. SamplesPerPixel defaults to one, and at most four samples are used. + int samplesPerPixel = profile.TryGetValue(ExifTag.SamplesPerPixel, out IExifValue? samplesPerPixelValue) + ? samplesPerPixelValue.Value + : 1; + + meta.BitsPerSample = new TiffBitsPerSample( + 1, + (ushort)(samplesPerPixel > 1 ? 1 : 0), + (ushort)(samplesPerPixel > 2 ? 1 : 0), + (ushort)(samplesPerPixel > 3 ? 1 : 0)); } meta.BitsPerPixel = meta.BitsPerSample.BitsPerPixel(); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index bab79d8ecf..134b392587 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -2,12 +2,15 @@ // Licensed under the Six Labors Split License. // ReSharper disable InconsistentNaming +using System.Buffers.Binary; using System.Numerics; using System.Runtime.Intrinsics.X86; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Tiff; +using SixLabors.ImageSharp.Formats.Tiff.Constants; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities; @@ -1006,6 +1009,64 @@ public void Decode_MalformedIccProfile_ThrowsWithStrict() }); } + /// + /// A bilevel TIFF without a BitsPerSample entry uses the TIFF 6.0 default of one bit per sample. + /// + /// The compression of the encoded image. + [Theory] + [InlineData(TiffCompression.None)] + [InlineData(TiffCompression.CcittGroup4Fax)] + public void TiffDecoder_CanDecode_BilevelWithoutBitsPerSample(TiffCompression compression) + { + using Image source = new(16, 8); + for (int y = 0; y < source.Height; y++) + { + for (int x = 0; x < source.Width; x++) + { + source[x, y] = new L8((byte)((x + y) % 3 == 0 ? 255 : 0)); + } + } + + using MemoryStream stream = new(); + source.Save(stream, new TiffEncoder { BitsPerPixel = TiffBitsPerPixel.Bit1, Compression = compression }); + byte[] withBitsPerSample = stream.ToArray(); + + // Move the BitsPerSample entry to an unused private tag, so the decoder no longer finds it. + byte[] withoutBitsPerSample = (byte[])withBitsPerSample.Clone(); + RenameFirstDirectoryEntry(withoutBitsPerSample, ExifTagValue.BitsPerSample, 65000); + + using Image expected = Image.Load(withBitsPerSample); + using Image actual = Image.Load(withoutBitsPerSample); + ImageInfo info = Image.Identify(withoutBitsPerSample); + + ImageComparer.Exact.VerifySimilarity(expected, actual); + Assert.Equal(TiffBitsPerPixel.Bit1, actual.Frames.RootFrame.Metadata.GetTiffMetadata().BitsPerPixel); + Assert.Equal(1, info.PixelType.BitsPerPixel); + } + private static byte[] CreateTiffWithMalformedIccProfile() => CorruptedMetadataImageFactory.CreateImageWithMalformedIccProfile(new TiffEncoder()); + + /// + /// Changes the tag of an entry in the first directory of a little-endian TIFF. + /// + /// The encoded TIFF. + /// The tag of the entry to change. + /// The new tag number. + private static void RenameFirstDirectoryEntry(byte[] tiff, ExifTagValue tag, ushort newTag) + { + int ifdOffset = (int)BinaryPrimitives.ReadUInt32LittleEndian(tiff.AsSpan(4)); + int count = BinaryPrimitives.ReadUInt16LittleEndian(tiff.AsSpan(ifdOffset)); + for (int i = 0; i < count; i++) + { + int entry = ifdOffset + 2 + (i * 12); + if (BinaryPrimitives.ReadUInt16LittleEndian(tiff.AsSpan(entry)) == (ushort)tag) + { + BinaryPrimitives.WriteUInt16LittleEndian(tiff.AsSpan(entry), newTag); + return; + } + } + + throw new InvalidOperationException($"Tag {tag} not found."); + } } From 9163c7632c071d9c0c25fdb1238010445c4dd3ea Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Oct 2026 14:44:13 +1000 Subject: [PATCH 2/3] Correct TIFF default initialization and use stored sample-depth inputs Keep absent file tags separate from newly constructed RGB metadata. Initialize the shared eight-bit RGB alias after the value it references. Preserve zero sample depths for unusable present entries instead of inheriting RGB defaults. Reject unsupported SamplesPerPixel counts when resolving an absent BitsPerSample tag, so the four-channel representation cannot silently change the file layout. Document the file defaults from TIFF 6.0 pages 29 and 39 at the parsing boundary. Replace the PR's runtime TIFF encoding and tag rewriting with seven stored files (3396 bytes), derived from the existing basi3p02_fax4 fixture. Verify sorted IFDs and exact tag values independently; Pillow/libtiff confirms the valid missing-tag variants retain the original pixels. Test Decode, Identify, frame metadata, and all integrity modes through existing APIs. Remove the tag-rewriting helper. Six of eight focused regressions fail on current main. All eight now pass. Release .NET 10: 869 TIFF-related and shared decoder tests passed. No tolerances or reference images changed. --- .../Formats/Tiff/Constants/TiffConstants.cs | 12 +- .../Formats/Tiff/TiffFrameMetadata.cs | 22 +++- src/ImageSharp/Formats/Tiff/TiffMetadata.cs | 4 + .../Formats/Tiff/TiffDecoderTests.cs | 103 ++++++++++-------- .../Formats/Tiff/TiffMetadataTests.cs | 16 +++ tests/ImageSharp.Tests/TestImages.cs | 8 ++ .../defaults/bilevel-no-bitspersample-g4.tiff | 3 + .../bilevel-no-bitspersample-none.tiff | 3 + ...l-no-bitspersample-or-samplesperpixel.tiff | 3 + .../Tiff/defaults/empty-bitspersample.tiff | 3 + ...no-bitspersample-samplesperpixel-five.tiff | 3 + ...no-bitspersample-samplesperpixel-zero.tiff | 3 + .../Tiff/defaults/zero-bitspersample.tiff | 3 + 13 files changed, 129 insertions(+), 57 deletions(-) create mode 100644 tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-g4.tiff create mode 100644 tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-none.tiff create mode 100644 tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-or-samplesperpixel.tiff create mode 100644 tests/Images/Input/Tiff/defaults/empty-bitspersample.tiff create mode 100644 tests/Images/Input/Tiff/defaults/no-bitspersample-samplesperpixel-five.tiff create mode 100644 tests/Images/Input/Tiff/defaults/no-bitspersample-samplesperpixel-zero.tiff create mode 100644 tests/Images/Input/Tiff/defaults/zero-bitspersample.tiff diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index c24eee484b..6a41c05ca7 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -68,11 +68,6 @@ internal static class TiffConstants /// public const TiffBitsPerPixel DefaultBitsPerPixel = TiffBitsPerPixel.Bit24; - /// - /// The default bits per sample for color images with 8 bits for each color channel. - /// - public static readonly TiffBitsPerSample DefaultBitsPerSample = BitsPerSampleRgb8Bit; - /// /// The default compression is None. /// @@ -108,6 +103,13 @@ internal static class TiffConstants /// public static readonly TiffBitsPerSample BitsPerSampleRgb8Bit = new(8, 8, 8); + // Initialize this alias after the value it references. Static fields initialize in declaration order. + + /// + /// The default bits per sample for color images with 8 bits for each color channel. + /// + public static readonly TiffBitsPerSample DefaultBitsPerSample = BitsPerSampleRgb8Bit; + /// /// The list of mime types that equate to a tiff. /// diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index 3098e38dd1..ace750065e 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs @@ -51,6 +51,10 @@ private TiffFrameMetadata(TiffFrameMetadata other) /// /// Gets or sets number of bits per component. /// + /// + /// New metadata uses eight bits for each RGB component. + /// On decode, an absent tag means one bit for each sample. + /// public TiffBitsPerSample BitsPerSample { get; set; } = TiffConstants.DefaultBitsPerSample; /// @@ -218,19 +222,25 @@ private static void Parse(TiffFrameMetadata meta, ExifProfile profile) if (profile.TryGetValue(ExifTag.BitsPerSample, out IExifValue? bitsPerSampleValue)) { - if (TiffBitsPerSample.TryParse(bitsPerSampleValue.Value, out TiffBitsPerSample bitsPerSample)) - { - meta.BitsPerSample = bitsPerSample; - } + // TryParse returns zero sample depths on failure. A present invalid entry must not inherit the RGB defaults. + meta.BitsPerSample = TiffBitsPerSample.TryParse(bitsPerSampleValue.Value, out TiffBitsPerSample bitsPerSample) + ? bitsPerSample + : default; } else { - // TIFF 6.0 defines a default of one bit for each sample when the entry is absent, which bilevel - // fax and scanner files rely on. SamplesPerPixel defaults to one, and at most four samples are used. + // TIFF 6.0 defines one bit per sample when BitsPerSample is absent (page 29). + // SamplesPerPixel defaults to one (page 39). These file defaults differ from new metadata's RGB defaults. int samplesPerPixel = profile.TryGetValue(ExifTag.SamplesPerPixel, out IExifValue? samplesPerPixelValue) ? samplesPerPixelValue.Value : 1; + // This metadata type stores at most four sample depths. Do not reduce a different count to a supported layout. + if (samplesPerPixel is < 1 or > 4) + { + TiffThrowHelper.ThrowNotSupported("Only TIFF images with one to four samples per pixel are supported."); + } + meta.BitsPerSample = new TiffBitsPerSample( 1, (ushort)(samplesPerPixel > 1 ? 1 : 0), diff --git a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs index 51939cb1f3..75eef07997 100644 --- a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs @@ -54,6 +54,10 @@ private TiffMetadata(TiffMetadata other) /// /// Gets or sets number of bits per component. Derived from the root frame. /// + /// + /// New metadata uses eight bits for each RGB component. + /// On decode, an absent tag means one bit for each sample. + /// public TiffBitsPerSample BitsPerSample { get; set; } = TiffConstants.DefaultBitsPerSample; /// diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 134b392587..bc2595c98f 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -2,15 +2,12 @@ // Licensed under the Six Labors Split License. // ReSharper disable InconsistentNaming -using System.Buffers.Binary; using System.Numerics; using System.Runtime.Intrinsics.X86; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Tiff; -using SixLabors.ImageSharp.Formats.Tiff.Constants; using SixLabors.ImageSharp.Metadata; -using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities; @@ -1010,63 +1007,77 @@ public void Decode_MalformedIccProfile_ThrowsWithStrict() } /// - /// A bilevel TIFF without a BitsPerSample entry uses the TIFF 6.0 default of one bit per sample. + /// Missing sample-depth tags use the TIFF default in Decode and Identify under every integrity mode. /// - /// The compression of the encoded image. + /// The stored bilevel TIFF without BitsPerSample, with or without SamplesPerPixel. [Theory] - [InlineData(TiffCompression.None)] - [InlineData(TiffCompression.CcittGroup4Fax)] - public void TiffDecoder_CanDecode_BilevelWithoutBitsPerSample(TiffCompression compression) + [InlineData(BilevelWithoutBitsPerSampleUncompressed)] + [InlineData(BilevelWithoutBitsPerSampleFax4)] + [InlineData(BilevelWithoutSampleTags)] + public void TiffDecoder_CanDecode_BilevelWithoutBitsPerSample(string path) { - using Image source = new(16, 8); - for (int y = 0; y < source.Height; y++) + using Image expected = Image.Load(TestFile.Create(Fax4Compressed).Bytes); + byte[] data = TestFile.Create(path).Bytes; + + foreach (SegmentIntegrityHandling integrity in Enum.GetValues()) { - for (int x = 0; x < source.Width; x++) - { - source[x, y] = new L8((byte)((x + y) % 3 == 0 ? 255 : 0)); - } + DecoderOptions options = new() { SegmentIntegrityHandling = integrity }; + using Image actual = Image.Load(options, data); + ImageInfo info = Image.Identify(options, data); + + ImageComparer.Exact.VerifySimilarity(expected, actual); + TiffFrameMetadata metadata = actual.Frames.RootFrame.Metadata.GetTiffMetadata(); + Assert.Equal(new TiffBitsPerSample(1, 0, 0), metadata.BitsPerSample); + Assert.Equal(TiffBitsPerPixel.Bit1, metadata.BitsPerPixel); + Assert.Equal(1, info.PixelType.BitsPerPixel); + Assert.Equal(TiffBitsPerPixel.Bit1, info.FrameMetadataCollection[0].GetTiffMetadata().BitsPerPixel); } + } - using MemoryStream stream = new(); - source.Save(stream, new TiffEncoder { BitsPerPixel = TiffBitsPerPixel.Bit1, Compression = compression }); - byte[] withBitsPerSample = stream.ToArray(); - - // Move the BitsPerSample entry to an unused private tag, so the decoder no longer finds it. - byte[] withoutBitsPerSample = (byte[])withBitsPerSample.Clone(); - RenameFirstDirectoryEntry(withoutBitsPerSample, ExifTagValue.BitsPerSample, 65000); - - using Image expected = Image.Load(withBitsPerSample); - using Image actual = Image.Load(withoutBitsPerSample); - ImageInfo info = Image.Identify(withoutBitsPerSample); + /// + /// A missing sample-depth tag must not reduce an unsupported sample count to a supported layout. + /// + /// The stored TIFF with zero or five declared samples per pixel. + [Theory] + [InlineData(MissingBitsPerSampleWithZeroSamples)] + [InlineData(MissingBitsPerSampleWithFiveSamples)] + public void TiffDecoder_WithoutBitsPerSample_RejectsUnsupportedSampleCounts(string path) + { + byte[] data = TestFile.Create(path).Bytes; - ImageComparer.Exact.VerifySimilarity(expected, actual); - Assert.Equal(TiffBitsPerPixel.Bit1, actual.Frames.RootFrame.Metadata.GetTiffMetadata().BitsPerPixel); - Assert.Equal(1, info.PixelType.BitsPerPixel); + foreach (SegmentIntegrityHandling integrity in Enum.GetValues()) + { + DecoderOptions options = new() { SegmentIntegrityHandling = integrity }; + Assert.Throws(() => Image.Identify(options, data)); + Assert.Throws(() => + { + using Image image = Image.Load(options, data); + }); + } } - private static byte[] CreateTiffWithMalformedIccProfile() - => CorruptedMetadataImageFactory.CreateImageWithMalformedIccProfile(new TiffEncoder()); - /// - /// Changes the tag of an entry in the first directory of a little-endian TIFF. + /// A present but unusable sample-depth tag must not inherit a valid default layout. /// - /// The encoded TIFF. - /// The tag of the entry to change. - /// The new tag number. - private static void RenameFirstDirectoryEntry(byte[] tiff, ExifTagValue tag, ushort newTag) + /// The stored TIFF with an empty or zero-valued BitsPerSample entry. + [Theory] + [InlineData(EmptyBitsPerSample)] + [InlineData(ZeroBitsPerSample)] + public void TiffDecoder_PresentInvalidBitsPerSample_IsNotDefaulted(string path) { - int ifdOffset = (int)BinaryPrimitives.ReadUInt32LittleEndian(tiff.AsSpan(4)); - int count = BinaryPrimitives.ReadUInt16LittleEndian(tiff.AsSpan(ifdOffset)); - for (int i = 0; i < count; i++) + byte[] data = TestFile.Create(path).Bytes; + + foreach (SegmentIntegrityHandling integrity in Enum.GetValues()) { - int entry = ifdOffset + 2 + (i * 12); - if (BinaryPrimitives.ReadUInt16LittleEndian(tiff.AsSpan(entry)) == (ushort)tag) + DecoderOptions options = new() { SegmentIntegrityHandling = integrity }; + Assert.Throws(() => { - BinaryPrimitives.WriteUInt16LittleEndian(tiff.AsSpan(entry), newTag); - return; - } + using Image image = Image.Load(options, data); + }); } - - throw new InvalidOperationException($"Tag {tag} not found."); } + + private static byte[] CreateTiffWithMalformedIccProfile() + => CorruptedMetadataImageFactory.CreateImageWithMalformedIccProfile(new TiffEncoder()); + } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs index d181cacb5a..0fa6467ca9 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs @@ -27,6 +27,22 @@ private class NumberComparer : IEqualityComparer public int GetHashCode(Number obj) => obj.GetHashCode(); } + /// + /// New image and frame metadata use eight-bit RGB, independently of the defaults for absent file tags. + /// + [Fact] + public void TiffMetadata_DefaultsToEightBitRgb() + { + TiffMetadata imageMetadata = new(); + TiffFrameMetadata frameMetadata = new(); + TiffBitsPerSample expected = new(8, 8, 8); + + Assert.Equal(expected, imageMetadata.BitsPerSample); + Assert.Equal(expected, frameMetadata.BitsPerSample); + Assert.Equal(TiffBitsPerPixel.Bit24, imageMetadata.BitsPerPixel); + Assert.Equal(TiffBitsPerPixel.Bit24, frameMetadata.BitsPerPixel); + } + [Fact] public void TiffMetadata_CloneIsDeep() { diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index b15f7ae0fb..e4c3fffff6 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -1002,6 +1002,14 @@ public static class Tiff public const string Benchmark_RgbPackbits = "medium_rgb_packbits.tiff"; public const string Benchmark_RgbUncompressed = "medium_rgb_uncompressed.tiff"; + public const string BilevelWithoutBitsPerSampleUncompressed = "Tiff/defaults/bilevel-no-bitspersample-none.tiff"; + public const string BilevelWithoutBitsPerSampleFax4 = "Tiff/defaults/bilevel-no-bitspersample-g4.tiff"; + public const string BilevelWithoutSampleTags = "Tiff/defaults/bilevel-no-bitspersample-or-samplesperpixel.tiff"; + public const string MissingBitsPerSampleWithZeroSamples = "Tiff/defaults/no-bitspersample-samplesperpixel-zero.tiff"; + public const string MissingBitsPerSampleWithFiveSamples = "Tiff/defaults/no-bitspersample-samplesperpixel-five.tiff"; + public const string EmptyBitsPerSample = "Tiff/defaults/empty-bitspersample.tiff"; + public const string ZeroBitsPerSample = "Tiff/defaults/zero-bitspersample.tiff"; + public const string Calliphora_GrayscaleUncompressed = "Tiff/Calliphora_grayscale_uncompressed.tiff"; public const string Calliphora_GrayscaleDeflate_Predictor = "Tiff/Calliphora_gray_deflate_predictor.tiff"; public const string Calliphora_GrayscaleLzw_Predictor = "Tiff/Calliphora_gray_lzw_predictor.tiff"; diff --git a/tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-g4.tiff b/tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-g4.tiff new file mode 100644 index 0000000000..4ee08baf73 --- /dev/null +++ b/tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-g4.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e25f990d596ef9f0a50a7e891dbda11d9912f61f6f9c5fc67aa6a6bb26ddda2e +size 468 diff --git a/tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-none.tiff b/tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-none.tiff new file mode 100644 index 0000000000..7761945900 --- /dev/null +++ b/tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-none.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27acb91aec7b5e4a90602129bb17f04bd149d5ab55564d09ba298a95a1a828cf +size 440 diff --git a/tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-or-samplesperpixel.tiff b/tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-or-samplesperpixel.tiff new file mode 100644 index 0000000000..1c37372676 --- /dev/null +++ b/tests/Images/Input/Tiff/defaults/bilevel-no-bitspersample-or-samplesperpixel.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4d3e75163b6fc2afb689501a6a249f22ab8029012786d9a8917173f591fbd43 +size 428 diff --git a/tests/Images/Input/Tiff/defaults/empty-bitspersample.tiff b/tests/Images/Input/Tiff/defaults/empty-bitspersample.tiff new file mode 100644 index 0000000000..21189ebde7 --- /dev/null +++ b/tests/Images/Input/Tiff/defaults/empty-bitspersample.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:392157cdd816ce57ef33aeb585c70d27d20cd31364807cb9750bea09495943f1 +size 440 diff --git a/tests/Images/Input/Tiff/defaults/no-bitspersample-samplesperpixel-five.tiff b/tests/Images/Input/Tiff/defaults/no-bitspersample-samplesperpixel-five.tiff new file mode 100644 index 0000000000..8b693687af --- /dev/null +++ b/tests/Images/Input/Tiff/defaults/no-bitspersample-samplesperpixel-five.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:878be6433aeebcfe1f69d2099cf0186b1d48a79306c3aa5034122e094d808e0c +size 590 diff --git a/tests/Images/Input/Tiff/defaults/no-bitspersample-samplesperpixel-zero.tiff b/tests/Images/Input/Tiff/defaults/no-bitspersample-samplesperpixel-zero.tiff new file mode 100644 index 0000000000..b6cfe767f7 --- /dev/null +++ b/tests/Images/Input/Tiff/defaults/no-bitspersample-samplesperpixel-zero.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84caa139af2d4bc5b61b89fcc4c06a90f464c26c6c91d019bccd3836f51ddd16 +size 590 diff --git a/tests/Images/Input/Tiff/defaults/zero-bitspersample.tiff b/tests/Images/Input/Tiff/defaults/zero-bitspersample.tiff new file mode 100644 index 0000000000..7ea562ed96 --- /dev/null +++ b/tests/Images/Input/Tiff/defaults/zero-bitspersample.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fde04a56b5010542fdd79c3b55bf6bf93559fbc03e03197686036451c0691a92 +size 440 From 55bb574f3ae8cfb1048d065d05eb051e16e9242e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Oct 2026 14:59:47 +1000 Subject: [PATCH 3/3] Remove redundant TIFF metadata remarks --- src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs | 4 ---- src/ImageSharp/Formats/Tiff/TiffMetadata.cs | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs index ace750065e..d6daaef93e 100644 --- a/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs @@ -51,10 +51,6 @@ private TiffFrameMetadata(TiffFrameMetadata other) /// /// Gets or sets number of bits per component. /// - /// - /// New metadata uses eight bits for each RGB component. - /// On decode, an absent tag means one bit for each sample. - /// public TiffBitsPerSample BitsPerSample { get; set; } = TiffConstants.DefaultBitsPerSample; /// diff --git a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs index 75eef07997..51939cb1f3 100644 --- a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs @@ -54,10 +54,6 @@ private TiffMetadata(TiffMetadata other) /// /// Gets or sets number of bits per component. Derived from the root frame. /// - /// - /// New metadata uses eight bits for each RGB component. - /// On decode, an absent tag means one bit for each sample. - /// public TiffBitsPerSample BitsPerSample { get; set; } = TiffConstants.DefaultBitsPerSample; ///