Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,6 @@ jobs:
sdk-preview: true
runtime: -x64
codecov: false
- os: macos-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable
framework: net10.0
sdk: 10.0.x
sdk-preview: true
runtime: -x64
codecov: false
- os: macos-26
framework: net10.0
sdk: 10.0.x
Expand All @@ -99,11 +93,6 @@ jobs:
sdk: 8.0.x
runtime: -x64
codecov: false
- os: macos-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable
framework: net8.0
sdk: 8.0.x
runtime: -x64
codecov: false
- os: macos-26
framework: net8.0
sdk: 8.0.x
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

#nullable disable

using System.Buffers;
Expand Down Expand Up @@ -48,31 +49,53 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in

using IMemoryOwner<Vector4> vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate<Vector4>(width) : null;
Span<Vector4> vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : [];
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);

if (this.isBigEndian)
if (this.isBigEndian)
{
if (hasAssociatedAlpha)
{
for (int x = 0; x < pixelRow.Length; x++)
for (int y = top; y < top + height; y++)
{
ushort r = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ushort g = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ushort b = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ushort a = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;

pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorFromRgba64Premultiplied<TPixel>(r, g, b, a)
: TPixel.FromRgba64(new Rgba64(r, g, b, a));
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);

for (int x = 0; x < pixelRow.Length; x++)
{
ushort r = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset + 2, 2));
ushort b = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset + 4, 2));
ushort a = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset + 6, 2));
offset += 8;

pixelRow[x] = TiffUtilities.ColorFromRgba64Premultiplied<TPixel>(r, g, b, a);
}
}
}
else
{
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);

for (int x = 0; x < pixelRow.Length; x++)
{
ushort r = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset + 2, 2));
ushort b = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset + 4, 2));
ushort a = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset + 6, 2));
offset += 8;

pixelRow[x] = TPixel.FromRgba64(new Rgba64(r, g, b, a));
}
}
}
}
else
{
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
int byteCount = pixelRow.Length * 8;

PixelOperations<TPixel>.Instance.FromRgba64Bytes(
this.configuration,
data.Slice(offset, byteCount),
Expand Down
7 changes: 6 additions & 1 deletion src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ public static TPixel ColorFromRgba64Premultiplied<TPixel>(ushort r, ushort g, us
return TPixel.FromRgba64(default);
}

return TPixel.FromRgba64(new Rgba64((ushort)(r / a), (ushort)(g / a), (ushort)(b / a), a));
float scale = 65535f / a;
ushort ur = (ushort)Math.Min(r * scale, 65535);
ushort ug = (ushort)Math.Min(g * scale, 65535);
ushort ub = (ushort)Math.Min(b * scale, 65535);

return TPixel.FromRgba64(new Rgba64(ur, ug, ub, a));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
13 changes: 13 additions & 0 deletions tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,19 @@ public void TiffDecoder_CanDecode_YccK<TPixel>(TestImageProvider<TPixel> provide
image.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.0001F), provider);
}

[Theory]
[WithFile(Issues3031, PixelTypes.Rgba64)]
[WithFile(Rgba16BitAssociatedAlphaBigEndian, PixelTypes.Rgba64)]
[WithFile(Rgba16BitAssociatedAlphaLittleEndian, PixelTypes.Rgba64)]
public void TiffDecoder_CanDecode_64Bit_WithAssociatedAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(TiffDecoder.Instance);
image.DebugSave(provider);

image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}

[Theory]
[WithFile(Issues2454_A, PixelTypes.Rgba32)]
[WithFile(Issues2454_B, PixelTypes.Rgba32)]
Expand Down
51 changes: 51 additions & 0 deletions tests/ImageSharp.Tests/Formats/Tiff/Utils/TiffUtilitiesTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.PixelFormats;

namespace SixLabors.ImageSharp.Tests.Formats.Tiff.Utils;

[Trait("Format", "Tiff")]
public class TiffUtilitiesTest
{
[Theory]
[InlineData(0, 0, 0, 0)]
[InlineData(42, 84, 128, 0)]
[InlineData(65535, 65535, 65535, 0)]
public void ColorFromRgba64Premultiplied_WithZeroAlpha_ReturnsDefaultPixel(ushort r, ushort g, ushort b, ushort a)
{
Rgba64 actual = TiffUtilities.ColorFromRgba64Premultiplied<Rgba64>(r, g, b, a);

Assert.Equal(default, actual);
}

[Theory]
[InlineData(65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535)]
[InlineData(32767, 0, 0, 65535, 32767, 0, 0, 65535)]
[InlineData(0, 32767, 0, 65535, 0, 32767, 0, 65535)]
[InlineData(0, 0, 32767, 65535, 0, 0, 32767, 65535)]
public void ColorFromRgba64Premultiplied_WithNoAlpha_ReturnExpectedValues(ushort r, ushort g, ushort b, ushort a, ushort expectedR, ushort expectedG, ushort expectedB, ushort expectedA)
{
Rgba64 actual = TiffUtilities.ColorFromRgba64Premultiplied<Rgba64>(r, g, b, a);

Assert.Equal(new Rgba64(expectedR, expectedG, expectedB, expectedA), actual);
}

[Theory]
[InlineData(32766, 0, 0, 32766, 65535, 0, 0, 32766)] // Red, 50% Alpha
[InlineData(0, 32766, 0, 32766, 0, 65535, 0, 32766)] // Green, 50% Alpha
[InlineData(0, 0, 32766, 32766, 0, 0, 65535, 32766)] // Blue, 50% Alpha
[InlineData(8191, 0, 0, 16383, 32765, 0, 0, 16383)] // Red, 25% Alpha
[InlineData(0, 8191, 0, 16383, 0, 32765, 0, 16383)] // Green, 25% Alpha
[InlineData(0, 0, 8191, 16383, 0, 0, 32765, 16383)] // Blue, 25% Alpha
[InlineData(8191, 0, 0, 0, 0, 0, 0, 0)] // Red, 0% Alpha
[InlineData(0, 8191, 0, 0, 0, 0, 0, 0)] // Green, 0% Alpha
[InlineData(0, 0, 8191, 0, 0, 0, 0, 0)] // Blue, 0% Alpha
public void ColorFromRgba64Premultiplied_WithAlpha_ReturnExpectedValues(ushort r, ushort g, ushort b, ushort a, ushort expectedR, ushort expectedG, ushort expectedB, ushort expectedA)
{
Rgba64 actual = TiffUtilities.ColorFromRgba64Premultiplied<Rgba64>(r, g, b, a);

Assert.Equal(new Rgba64(expectedR, expectedG, expectedB, expectedA), actual);
}
}
1 change: 1 addition & 0 deletions tests/ImageSharp.Tests/TestImages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,7 @@ public static class Tiff
public const string Issues2435 = "Tiff/Issues/Issue2435.tiff";
public const string Issues2454_A = "Tiff/Issues/Issue2454_A.tif";
public const string Issues2454_B = "Tiff/Issues/Issue2454_B.tif";
public const string Issues3031 = "Tiff/Issues/Issue3031.tiff";
public const string Issues2587 = "Tiff/Issues/Issue2587.tiff";
public const string Issues2679 = "Tiff/Issues/Issue2679.tiff";
public const string JpegCompressedGray0000539558 = "Tiff/Issues/JpegCompressedGray-0000539558.tiff";
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions tests/Images/Input/Tiff/Issues/Issue3031.tiff
Git LFS file not shown
Loading