Browse Source

Merge remote-tracking branch 'upstream/main' into png-icc

pull/3028/head
James Jackson-South 4 weeks ago
parent
commit
49461a176c
  1. 11
      .github/workflows/build-and-test.yml
  2. 2
      src/ImageSharp/Formats/Png/PngMetadata.cs
  3. 57
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
  4. 7
      src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs
  5. 5
      src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs
  6. 25
      tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs
  7. 13
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  8. 51
      tests/ImageSharp.Tests/Formats/Tiff/Utils/TiffUtilitiesTest.cs
  9. 26
      tests/ImageSharp.Tests/Formats/WebP/WebpVp8XTests.cs
  10. 1
      tests/ImageSharp.Tests/TestImages.cs
  11. 3
      tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_64Bit_WithAssociatedAlpha_Rgba64_Issue3031.png
  12. 3
      tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_64Bit_WithAssociatedAlpha_Rgba64_RgbaAssociatedAlpha16bit_lsb.png
  13. 3
      tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_64Bit_WithAssociatedAlpha_Rgba64_RgbaAssociatedAlpha16bit_msb.png
  14. 3
      tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_BigEndian_AssociatedAlpha_Rgba16161616_Rgba64_Issue3031.png
  15. 3
      tests/Images/Input/Tiff/Issues/Issue3031.tiff

11
.github/workflows/build-and-test.yml

@ -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
@ -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

2
src/ImageSharp/Formats/Png/PngMetadata.cs

@ -111,7 +111,7 @@ public class PngMetadata : IFormatMetadata<PngMetadata>
color = PngColorType.Rgb;
break;
default:
if (colorType.HasFlag(PixelColorType.Luminance))
if (colorType.HasFlag(PixelColorType.Luminance | PixelColorType.Alpha))
{
color = PngColorType.GrayscaleWithAlpha;
break;

57
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs

@ -1,5 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#nullable disable
using System.Buffers;
@ -48,31 +49,53 @@ internal class Rgba16161616TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
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),

7
src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs

@ -45,7 +45,12 @@ internal static class TiffUtilities
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)]

5
src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs

@ -123,7 +123,10 @@ internal readonly struct WebpVp8X : IEquatable<WebpVp8X>
long pos = RiffHelper.BeginWriteChunk(stream, (uint)WebpChunkType.Vp8X);
stream.WriteByte(flags);
stream.Position += 3; // Reserved bytes
Span<byte> reserved = stackalloc byte[3];
stream.Write(reserved);
WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Width - 1);
WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Height - 1);

25
tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs

@ -336,4 +336,29 @@ public class PngMetadataTests
Assert.Equal(42, (int)exif.GetValue(ExifTag.ImageNumber).Value);
}
[Theory]
[InlineData(PixelColorType.Binary, PngColorType.Palette)]
[InlineData(PixelColorType.Indexed, PngColorType.Palette)]
[InlineData(PixelColorType.Luminance, PngColorType.Grayscale)]
[InlineData(PixelColorType.RGB, PngColorType.Rgb)]
[InlineData(PixelColorType.BGR, PngColorType.Rgb)]
[InlineData(PixelColorType.YCbCr, PngColorType.RgbWithAlpha)]
[InlineData(PixelColorType.CMYK, PngColorType.RgbWithAlpha)]
[InlineData(PixelColorType.YCCK, PngColorType.RgbWithAlpha)]
public void FromFormatConnectingMetadata_ConvertColorTypeAsExpected(PixelColorType pixelColorType, PngColorType expectedPngColorType)
{
FormatConnectingMetadata formatConnectingMetadata = new()
{
PixelTypeInfo = new PixelTypeInfo(24)
{
ColorType = pixelColorType,
},
};
PngMetadata actual = PngMetadata.FromFormatConnectingMetadata(formatConnectingMetadata);
Assert.Equal(expectedPngColorType, actual.ColorType);
}
}

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

@ -365,6 +365,19 @@ public class TiffDecoderTests : TiffDecoderBaseTester
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)]

51
tests/ImageSharp.Tests/Formats/Tiff/Utils/TiffUtilitiesTest.cs

@ -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);
}
}

26
tests/ImageSharp.Tests/Formats/WebP/WebpVp8XTests.cs

@ -0,0 +1,26 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Webp.Chunks;
namespace SixLabors.ImageSharp.Tests.Formats.WebP;
[Trait("Format", "Webp")]
public class WebpVp8XTests
{
[Fact]
public void WebpVp8X_WriteTo_Writes_Reserved_Bytes()
{
// arrange
WebpVp8X header = new(false, false, false, false, false, 10, 40);
MemoryStream ms = new();
byte[] expected = [86, 80, 56, 88, 10, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 39, 0, 0];
// act
header.WriteTo(ms);
// assert
byte[] actual = ms.ToArray();
Assert.Equal(expected, actual);
}
}

1
tests/ImageSharp.Tests/TestImages.cs

@ -1151,6 +1151,7 @@ public static class TestImages
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";

3
tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_64Bit_WithAssociatedAlpha_Rgba64_Issue3031.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c33a2f63836975bdc7631f26634b3fb0ae98bfaff730300877339cb568141cde
size 124

3
tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_64Bit_WithAssociatedAlpha_Rgba64_RgbaAssociatedAlpha16bit_lsb.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e50dfa103459d21642df5e1ca760081fbdfe3b7244624d9d87d8a20f45b51bbe
size 117953

3
tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_64Bit_WithAssociatedAlpha_Rgba64_RgbaAssociatedAlpha16bit_msb.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3333503012aa29e23f0d0e52993ad3499514251208fb3318e2bb1560d54650fa
size 117956

3
tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_BigEndian_AssociatedAlpha_Rgba16161616_Rgba64_Issue3031.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c33a2f63836975bdc7631f26634b3fb0ae98bfaff730300877339cb568141cde
size 124

3
tests/Images/Input/Tiff/Issues/Issue3031.tiff

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6e4d2db56a1b7fdea09ed65eab1d10a02952821f6662ca77caa44b8c51b30310
size 416
Loading…
Cancel
Save