// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using ImageMagick; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { public class MagickReferenceDecoder : IImageDecoder { public static MagickReferenceDecoder Instance { get; } = new MagickReferenceDecoder(); private static void FromRgba32Bytes(Configuration configuration, Span rgbaBytes, IMemoryGroup destinationGroup) where TPixel : struct, IPixel { foreach (Memory m in destinationGroup) { Span destBuffer = m.Span; PixelOperations.Instance.FromRgba32Bytes( configuration, rgbaBytes, destBuffer, destBuffer.Length); rgbaBytes = rgbaBytes.Slice(destBuffer.Length * 4); } } private static void FromRgba64Bytes(Configuration configuration, Span rgbaBytes, IMemoryGroup destinationGroup) where TPixel : struct, IPixel { foreach (Memory m in destinationGroup) { Span destBuffer = m.Span; PixelOperations.Instance.FromRgba64Bytes( configuration, rgbaBytes, destBuffer, destBuffer.Length); rgbaBytes = rgbaBytes.Slice(destBuffer.Length * 8); } } public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { using var magickImage = new MagickImage(stream); var result = new Image(configuration, magickImage.Width, magickImage.Height); MemoryGroup resultPixels = result.GetRootFramePixelBuffer().FastMemoryGroup; using (IPixelCollection pixels = magickImage.GetPixelsUnsafe()) { if (magickImage.Depth == 8) { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); FromRgba32Bytes(configuration, data, resultPixels); } else if (magickImage.Depth == 16) { ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); FromRgba64Bytes(configuration, bytes, resultPixels); } else { throw new InvalidOperationException(); } } return result; } public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream); } }