// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using Xunit; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Advanced { public class AdvancedImageExtensionsTests { public class GetPixelMemory { [Theory] [WithSolidFilledImages(1, 1, "Red", PixelTypes.Rgba32)] [WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)] public void WhenMemoryIsOwned(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image0 = provider.GetImage()) { var targetBuffer = new TPixel[image0.Width * image0.Height]; // Act: Memory memory = image0.GetPixelMemory(); // Assert: Assert.Equal(image0.Width * image0.Height, memory.Length); memory.Span.CopyTo(targetBuffer); using (Image image1 = provider.GetImage()) { // We are using a copy of the original image for assertion image1.ComparePixelBufferTo(targetBuffer); } } } [Theory] [WithSolidFilledImages(1, 1, "Red", PixelTypes.Rgba32 | PixelTypes.Bgr24)] [WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)] public void WhenMemoryIsConsumed(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image0 = provider.GetImage()) { var targetBuffer = new TPixel[image0.Width * image0.Height]; image0.GetPixelSpan().CopyTo(targetBuffer); var managerOfExternalMemory = new TestMemoryManager(targetBuffer); Memory externalMemory = managerOfExternalMemory.Memory; using (var image1 = Image.WrapMemory(externalMemory, image0.Width, image0.Height)) { Memory internalMemory = image1.GetPixelMemory(); Assert.Equal(targetBuffer.Length, internalMemory.Length); Assert.True(Unsafe.AreSame(ref targetBuffer[0], ref internalMemory.Span[0])); image0.ComparePixelBufferTo(internalMemory.Span); } // Make sure externalMemory works after destruction: image0.ComparePixelBufferTo(externalMemory.Span); } } } [Theory] [WithSolidFilledImages(1, 1, "Red", PixelTypes.Rgba32)] [WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)] public void GetPixelRowMemory(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) { var targetBuffer = new TPixel[image.Width * image.Height]; // Act: for (int y = 0; y < image.Height; y++) { Memory rowMemory = image.GetPixelRowMemory(y); rowMemory.Span.CopyTo(targetBuffer.AsSpan(image.Width * y)); } // Assert: using (Image image1 = provider.GetImage()) { // We are using a copy of the original image for assertion image1.ComparePixelBufferTo(targetBuffer); } } } [Theory] [WithSolidFilledImages(1, 1, "Red", PixelTypes.Rgba32)] [WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)] public void GetPixelRowSpan(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) { var targetBuffer = new TPixel[image.Width * image.Height]; // Act: for (int y = 0; y < image.Height; y++) { Span rowMemory = image.GetPixelRowSpan(y); rowMemory.CopyTo(targetBuffer.AsSpan(image.Width * y)); } // Assert: using (Image image1 = provider.GetImage()) { // We are using a copy of the original image for assertion image1.ComparePixelBufferTo(targetBuffer); } } } #pragma warning disable 0618 [Theory] [WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)] public unsafe void DangerousGetPinnableReference_CopyToBuffer(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) { var targetBuffer = new TPixel[image.Width * image.Height]; ref byte source = ref Unsafe.As(ref targetBuffer[0]); ref byte dest = ref Unsafe.As(ref image.DangerousGetPinnableReferenceToPixelBuffer()); fixed (byte* targetPtr = &source) fixed (byte* pixelBasePtr = &dest) { uint dataSizeInBytes = (uint)(image.Width * image.Height * Unsafe.SizeOf()); Unsafe.CopyBlock(targetPtr, pixelBasePtr, dataSizeInBytes); } image.ComparePixelBufferTo(targetBuffer); } } } }