diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index d72556b0e3..1616f3a3ab 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -7,6 +7,7 @@ using ImageMagick.Formats; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Exr; +using SixLabors.ImageSharp.Formats.Heif; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Tiff; @@ -45,6 +46,8 @@ public class MagickReferenceDecoder : ImageDecoder public static MagickReferenceDecoder Exr { get; } = new(ExrFormat.Instance); + public static MagickReferenceDecoder Heif { get; } = new(HeifFormat.Instance); + protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) { ImageMetadata metadata = new(); @@ -83,13 +86,13 @@ public class MagickReferenceDecoder : ImageDecoder (int)magicFrame.Height); using IUnsafePixelCollection pixels = magicFrame.GetPixelsUnsafe(); - if (magicFrame.Depth is 12 or 10 or 8 or 6 or 5 or 4 or 3 or 2 or 1) + if (magicFrame.Depth is 8 or 6 or 5 or 4 or 3 or 2 or 1) { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); FromRgba32Bytes(configuration, data, buffer); } - else if (magicFrame.Depth is 14 or 16 or 32) + else if (magicFrame.Depth is 10 or 12 or 14 or 16 or 32) { if (this.imageFormat is PngFormat png) { @@ -97,6 +100,21 @@ public class MagickReferenceDecoder : ImageDecoder } ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); + if (this.imageFormat is HeifFormat && magicFrame.Depth is 10 or 12) + { + // The HEIF reader left-aligns native samples in its 16-bit channels. Recover the declared + // sample values before expanding their full range to Rgba64; a shift alone leaves white + // below 65535 and changes every nonzero component's normalized value. + int depth = (int)magicFrame.Depth; + int shift = 16 - depth; + int maximum = (1 << depth) - 1; + for (int i = 0; i < data.Length; i++) + { + int sample = data[i] >> shift; + data[i] = (ushort)(((sample * 65535) + (maximum / 2)) / maximum); + } + } + Span bytes = MemoryMarshal.Cast(data.AsSpan()); FromRgba64Bytes(configuration, bytes, buffer); } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index ba2a2f3797..8e07ad086f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -85,6 +85,12 @@ public static partial class TestEnvironment bmpEncoder, new BmpImageFormatDetector()); + cfg.ConfigureCodecs( + HeifFormat.Instance, + MagickReferenceDecoder.Heif, + new HeifEncoder(), + new HeifImageFormatDetector()); + return cfg; } }