diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index 3faa072dd3..1d7f33a9a5 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -24,7 +24,8 @@ namespace SixLabors.ImageSharp.Advanced => GetConfiguration((IConfigurable)source); /// - /// Gets the storing the whole pixel buffer in row major order. + /// Gets the representation of the pixels as a of contiguous memory in the source image's pixel format + /// stored in row major order. /// /// The Pixel format. /// The source @@ -36,7 +37,8 @@ namespace SixLabors.ImageSharp.Advanced } /// - /// Gets the storing the whole pixel buffer in row major order. + /// Gets the representation of the pixels as a of contiguous memory in the source image's pixel format + /// stored in row major order. /// /// The Pixel format. /// The source @@ -48,70 +50,98 @@ namespace SixLabors.ImageSharp.Advanced } /// - /// Returns a reference to the 0th element of the Pixel buffer, - /// allowing direct manipulation of pixel data through unsafe operations. - /// The pixel buffer is a contiguous memory area containing Width*Height TPixel elements laid out in row-major order. + /// Gets the representation of the pixels as a of contiguous memory in the source image's pixel format + /// stored in row major order. /// - /// The Pixel format. - /// The source image frame - /// A pinnable reference the first root of the pixel buffer. - public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer(this ImageFrame source) + /// The type of the pixel. + /// The source. + /// The + public static Span GetPixelSpan(this ImageFrame source) where TPixel : struct, IPixel - => ref DangerousGetPinnableReferenceToPixelBuffer((IPixelSource)source); + => source.GetPixelMemory().Span; /// - /// Returns a reference to the 0th element of the Pixel buffer, - /// allowing direct manipulation of pixel data through unsafe operations. - /// The pixel buffer is a contigous memory area containing Width*Height TPixel elements layed out in row-major order. + /// Gets the representation of the pixels as a of contiguous memory in the source image's pixel format + /// stored in row major order. /// - /// The Pixel format. - /// The source image - /// A pinnable reference the first root of the pixel buffer. - public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer(this Image source) + /// The type of the pixel. + /// The source. + /// The + public static Span GetPixelSpan(this Image source) where TPixel : struct, IPixel - => ref source.Frames.RootFrame.DangerousGetPinnableReferenceToPixelBuffer(); + => source.Frames.RootFrame.GetPixelSpan(); /// - /// Gets the representation of the pixels as an area of contiguous memory in the given pixel format. + /// Gets the representation of the pixels as a of contiguous memory + /// at row beginning from the the first pixel on that row. /// /// The type of the pixel. /// The source. + /// The row. /// The - internal static Span GetPixelSpan(this ImageFrame source) + public static Memory GetPixelRowMemory(this ImageFrame source, int rowIndex) where TPixel : struct, IPixel - => GetSpan(source); + => source.PixelBuffer.GetRowMemory(rowIndex); /// - /// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row. + /// Gets the representation of the pixels as of of contiguous memory + /// at row beginning from the the first pixel on that row. /// /// The type of the pixel. /// The source. - /// The row. + /// The row. /// The - internal static Span GetPixelRowSpan(this ImageFrame source, int row) + public static Memory GetPixelRowMemory(this Image source, int rowIndex) where TPixel : struct, IPixel - => GetSpan(source, row); + => source.Frames.RootFrame.GetPixelRowMemory(rowIndex); /// - /// Gets the representation of the pixels as an area of contiguous memory in the given pixel format. + /// Gets the representation of the pixels as a of contiguous memory + /// at row beginning from the the first pixel on that row. /// /// The type of the pixel. /// The source. + /// The row. /// The - internal static Span GetPixelSpan(this Image source) + public static Span GetPixelRowSpan(this ImageFrame source, int rowIndex) where TPixel : struct, IPixel - => source.Frames.RootFrame.GetPixelSpan(); + => source.PixelBuffer.GetRowSpan(rowIndex); /// - /// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row. + /// Gets the representation of the pixels as of of contiguous memory + /// at row beginning from the the first pixel on that row. /// /// The type of the pixel. /// The source. - /// The row. + /// The row. /// The - internal static Span GetPixelRowSpan(this Image source, int row) + public static Span GetPixelRowSpan(this Image source, int rowIndex) + where TPixel : struct, IPixel + => source.Frames.RootFrame.GetPixelRowSpan(rowIndex); + + /// + /// Returns a reference to the 0th element of the Pixel buffer, + /// allowing direct manipulation of pixel data through unsafe operations. + /// The pixel buffer is a contiguous memory area containing Width*Height TPixel elements laid out in row-major order. + /// + /// The Pixel format. + /// The source image frame + /// A pinnable reference the first root of the pixel buffer. + public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer(this ImageFrame source) + where TPixel : struct, IPixel + => ref DangerousGetPinnableReferenceToPixelBuffer((IPixelSource)source); + + /// + /// Returns a reference to the 0th element of the Pixel buffer, + /// allowing direct manipulation of pixel data through unsafe operations. + /// The pixel buffer is a contigous memory area containing Width*Height TPixel elements layed out in row-major order. + /// + /// The Pixel format. + /// The source image + /// A pinnable reference the first root of the pixel buffer. + public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer(this Image source) where TPixel : struct, IPixel - => source.Frames.RootFrame.GetPixelRowSpan(row); + => ref source.Frames.RootFrame.DangerousGetPinnableReferenceToPixelBuffer(); /// /// Gets the assigned to 'source'. diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index 6c07a20d31..c236f250c0 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -50,6 +50,20 @@ namespace SixLabors.ImageSharp.Memory return buffer.GetSpan().Slice(y * buffer.Width, buffer.Width); } + /// + /// Gets a to the row 'y' beginning from the pixel at the first pixel on that row. + /// + /// The buffer + /// The y (row) coordinate + /// The element type + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Memory GetRowMemory(this IBuffer2D buffer, int y) + where T : struct + { + return buffer.Buffer.Memory.Slice(y * buffer.Width, buffer.Width); + } + /// /// Returns the size of the buffer. /// diff --git a/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs b/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs index c148667424..2825ddd770 100644 --- a/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs @@ -21,20 +21,77 @@ namespace SixLabors.ImageSharp.Tests.Advanced public void WhenMemoryIsOwned(TestImageProvider provider) where TPixel : struct, IPixel { - using (Image image = provider.GetImage()) + using (Image image0 = provider.GetImage()) { - Memory memory = image.GetPixelMemory(); - Assert.Equal(image.Width * image.Height, memory.Length); + var targetBuffer = new TPixel[image0.Width * image0.Height]; - var targetBuffer = new TPixel[image.Width * image.Height]; + // Act: + Memory memory = image0.GetPixelMemory(); + + // Assert: + Assert.Equal(image0.Width * image0.Height, memory.Length); memory.Span.CopyTo(targetBuffer); - image.ComparePixelBufferTo(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)] + [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); + } + } + } [Theory] [WithTestPatternImages(131, 127, PixelTypes.Rgba32 | PixelTypes.Bgr24)]