Skip to content

Commit cc16677

Browse files
committed
Tiff decoder now respects byte order for 16 bit gray images with white is zero
1 parent 5d888be commit cc16677

File tree

7 files changed

+69
-0
lines changed

7 files changed

+69
-0
lines changed

src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ public static TiffBaseColorDecoder<TPixel> Create(TiffColorType colorType, TiffB
3232
DebugGuard.IsTrue(colorMap == null, "colorMap");
3333
return new WhiteIsZero8TiffColor<TPixel>();
3434

35+
case TiffColorType.WhiteIsZero16:
36+
DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 16, "bitsPerSample");
37+
DebugGuard.IsTrue(colorMap == null, "colorMap");
38+
return new WhiteIsZero16TiffColor<TPixel>(byteOrder == ByteOrder.BigEndian);
39+
3540
case TiffColorType.BlackIsZero:
3641
DebugGuard.IsTrue(bitsPerSample.Channels == 1, "bitsPerSample");
3742
DebugGuard.IsTrue(colorMap == null, "colorMap");

src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ internal enum TiffColorType
5353
/// </summary>
5454
WhiteIsZero8,
5555

56+
/// <summary>
57+
/// Grayscale: 0 is imaged as white. The maximum value is imaged as black. Optimized implementation for 16-bit images.
58+
/// </summary>
59+
WhiteIsZero16,
60+
5661
/// <summary>
5762
/// Palette-color.
5863
/// </summary>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
using SixLabors.ImageSharp.Formats.Tiff.Utils;
6+
using SixLabors.ImageSharp.Memory;
7+
using SixLabors.ImageSharp.PixelFormats;
8+
9+
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
10+
{
11+
/// <summary>
12+
/// Implements the 'WhiteIsZero' photometric interpretation for 16-bit grayscale images.
13+
/// </summary>
14+
internal class WhiteIsZero16TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
15+
where TPixel : unmanaged, IPixel<TPixel>
16+
{
17+
private readonly bool isBigEndian;
18+
19+
/// <summary>
20+
/// Initializes a new instance of the <see cref="WhiteIsZero16TiffColor{TPixel}" /> class.
21+
/// </summary>
22+
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
23+
public WhiteIsZero16TiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian;
24+
25+
/// <inheritdoc/>
26+
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
27+
{
28+
var color = default(TPixel);
29+
30+
int offset = 0;
31+
32+
var l16 = default(L16);
33+
for (int y = top; y < top + height; y++)
34+
{
35+
for (int x = left; x < left + width; x++)
36+
{
37+
ushort intensity = (ushort)(ushort.MaxValue - TiffUtils.ConvertToShort(data.Slice(offset, 2), this.isBigEndian));
38+
offset += 2;
39+
40+
l16.PackedValue = intensity;
41+
color.FromL16(l16);
42+
43+
pixels[x, y] = color;
44+
}
45+
}
46+
}
47+
}
48+
}

src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ private static void ParseColorType(this TiffDecoderCore options, ExifProfile exi
111111

112112
switch (bitsPerChannel)
113113
{
114+
case 16:
115+
{
116+
options.ColorType = TiffColorType.WhiteIsZero16;
117+
break;
118+
}
119+
114120
case 8:
115121
{
116122
options.ColorType = TiffColorType.WhiteIsZero8;

tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ public void TiffDecoder_CanDecode_14Bit<TPixel>(TestImageProvider<TPixel> provid
142142
[Theory]
143143
[WithFile(Flower16BitGrayLittleEndian, PixelTypes.Rgba32)]
144144
[WithFile(Flower16BitGray, PixelTypes.Rgba32)]
145+
[WithFile(Flower16BitGrayMinIsWhiteLittleEndian, PixelTypes.Rgba32)]
145146
public void TiffDecoder_CanDecode_16Bit<TPixel>(TestImageProvider<TPixel> provider)
146147
where TPixel : unmanaged, IPixel<TPixel> => TestTiffDecoder(provider);
147148

tests/ImageSharp.Tests/TestImages.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ public static class Tiff
583583
public const string Flower14BitGray = "Tiff/flower-minisblack-14.tiff";
584584
public const string Flower16BitGray = "Tiff/flower-minisblack-16.tiff";
585585
public const string Flower16BitGrayLittleEndian = "Tiff/flower-minisblack-16_lsb.tiff";
586+
public const string Flower16BitGrayMinIsWhiteLittleEndian = "Tiff/flower-miniswhite-16_lsb.tiff";
586587
public const string Issues1716Rgb161616BitLittleEndian = "Tiff/Issues/Issue1716.tiff";
587588

588589
public const string SmallRgbDeflate = "Tiff/rgb_small_deflate.tiff";
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:435c92b453587e1943940111b66afabf70307beb0e1d65e9701fd9bb753eead2
3+
size 6588

0 commit comments

Comments
 (0)