From 32a2f6df370abd234989f3dd076691685b86c154 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 8 Nov 2020 13:06:28 +0100 Subject: [PATCH 1/6] Add unowned Image.WrapMemory(void*) overloads --- src/ImageSharp/Image.WrapMemory.cs | 66 +++++++++++++++++++ src/ImageSharp/Memory/ByteMemoryManager{T}.cs | 1 + .../Memory/UnmanagedMemoryManager{T}.cs | 60 +++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 src/ImageSharp/Memory/UnmanagedMemoryManager{T}.cs diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index d89c44dc56..b080c78887 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -220,5 +220,71 @@ public static Image WrapMemory( int height) where TPixel : unmanaged, IPixel => WrapMemory(Configuration.Default, byteMemory, width, height); + + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, + /// allowing to view/manipulate it as an instance. + /// + /// The pixel type + /// The + /// The pointer to the target memory buffer to wrap. + /// The width of the memory image. + /// The height of the memory image. + /// The . + /// The configuration is null. + /// The metadata is null. + /// An instance + public static unsafe Image WrapMemory( + Configuration configuration, + void* pointer, + int width, + int height, + ImageMetadata metadata) + where TPixel : unmanaged, IPixel + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(metadata, nameof(metadata)); + + var memoryManager = new UnmanagedMemoryManager(pointer, width * height); + + var memorySource = MemoryGroup.Wrap(memoryManager.Memory); + return new Image(configuration, memorySource, width, height, metadata); + } + + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, + /// allowing to view/manipulate it as an instance. + /// + /// The pixel type + /// The + /// The pointer to the target memory buffer to wrap. + /// The width of the memory image. + /// The height of the memory image. + /// The configuration is null. + /// An instance. + public static unsafe Image WrapMemory( + Configuration configuration, + void* pointer, + int width, + int height) + where TPixel : unmanaged, IPixel + => WrapMemory(configuration, pointer, width, height, new ImageMetadata()); + + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, + /// allowing to view/manipulate it as an instance. + /// The memory is being observed, the caller remains responsible for managing it's lifecycle. + /// + /// The pixel type. + /// The pointer to the target memory buffer to wrap. + /// The width of the memory image. + /// The height of the memory image. + /// An instance. + public static unsafe Image WrapMemory( + void* pointer, + int width, + int height) + where TPixel : unmanaged, IPixel + => WrapMemory(Configuration.Default, pointer, width, height); } } diff --git a/src/ImageSharp/Memory/ByteMemoryManager{T}.cs b/src/ImageSharp/Memory/ByteMemoryManager{T}.cs index 223709df65..1731639582 100644 --- a/src/ImageSharp/Memory/ByteMemoryManager{T}.cs +++ b/src/ImageSharp/Memory/ByteMemoryManager{T}.cs @@ -1,5 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. + using System; using System.Buffers; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Memory/UnmanagedMemoryManager{T}.cs b/src/ImageSharp/Memory/UnmanagedMemoryManager{T}.cs new file mode 100644 index 0000000000..58eaee320a --- /dev/null +++ b/src/ImageSharp/Memory/UnmanagedMemoryManager{T}.cs @@ -0,0 +1,60 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; + +namespace SixLabors.ImageSharp.Memory +{ + /// + /// A custom that can wrap a rawpointer to a buffer of a specified type. + /// + /// The value type to use when casting the wrapped instance. + /// This manager doesn't own the memory buffer that it points to. + internal sealed unsafe class UnmanagedMemoryManager : MemoryManager + where T : unmanaged + { + /// + /// The pointer to the memory buffer. + /// + private readonly void* pointer; + + /// + /// The length of the memory area. + /// + private readonly int length; + + /// + /// Initializes a new instance of the class. + /// + /// The pointer to the memory buffer. + /// The length of the memory area. + public UnmanagedMemoryManager(void* pointer, int length) + { + this.pointer = pointer; + this.length = length; + } + + /// + protected override void Dispose(bool disposing) + { + } + + /// + public override Span GetSpan() + { + return new Span(this.pointer, this.length); + } + + /// + public override MemoryHandle Pin(int elementIndex = 0) + { + return new MemoryHandle(((T*)this.pointer) + elementIndex); + } + + /// + public override void Unpin() + { + } + } +} From aa0c0aafdd16e936d8ef54dc48cec0dbfd5800f6 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 8 Nov 2020 13:12:28 +0100 Subject: [PATCH 2/6] Add pointer null check on construction --- src/ImageSharp/Image.WrapMemory.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index b080c78887..dff888c13b 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -242,6 +242,7 @@ public static unsafe Image WrapMemory( ImageMetadata metadata) where TPixel : unmanaged, IPixel { + Guard.IsFalse(pointer == null, nameof(pointer), "Pointer must be not null"); Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(metadata, nameof(metadata)); From 0f7926fe12513d872ce93faea7249b0e51de1d20 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 8 Nov 2020 13:19:00 +0100 Subject: [PATCH 3/6] Add unit tests for WrapMemory(void*) overloads --- .../Image/ImageTests.WrapMemory.cs | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 7dc7dbb30c..637b4d8170 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -282,6 +282,76 @@ public void WrapSystemDrawingBitmap_FromBytes_WhenObserved() } } + [Fact] + public unsafe void WrapMemory_FromPointer_CreatedImageIsCorrect() + { + var cfg = Configuration.CreateDefaultInstance(); + var metaData = new ImageMetadata(); + + var array = new Rgba32[25]; + + fixed (void* ptr = array) + { + using (var image = Image.WrapMemory(cfg, ptr, 5, 5, metaData)) + { + Assert.True(image.TryGetSinglePixelSpan(out Span imageSpan)); + ref Rgba32 pixel0 = ref imageSpan[0]; + Assert.True(Unsafe.AreSame(ref array[0], ref pixel0)); + ref Rgba32 pixel_1 = ref imageSpan[imageSpan.Length - 1]; + Assert.True(Unsafe.AreSame(ref array[array.Length - 1], ref pixel_1)); + + Assert.Equal(cfg, image.GetConfiguration()); + Assert.Equal(metaData, image.Metadata); + } + } + } + + [Fact] + public unsafe void WrapSystemDrawingBitmap_FromPointer_WhenObserved() + { + if (ShouldSkipBitmapTest) + { + return; + } + + using (var bmp = new Bitmap(51, 23)) + { + using (var memoryManager = new BitmapMemoryManager(bmp)) + { + Memory pixelMemory = memoryManager.Memory; + Bgra32 bg = Color.Red; + Bgra32 fg = Color.Green; + + fixed (void* p = pixelMemory.Span) + { + using (var image = Image.WrapMemory(p, bmp.Width, bmp.Height)) + { + Span pixelSpan = pixelMemory.Span; + Span imageSpan = image.GetRootFramePixelBuffer().GetSingleMemory().Span; + + Assert.Equal(pixelSpan.Length, imageSpan.Length); + Assert.True(Unsafe.AreSame(ref pixelSpan.GetPinnableReference(), ref imageSpan.GetPinnableReference())); + + Assert.True(image.TryGetSinglePixelSpan(out imageSpan)); + imageSpan.Fill(bg); + for (var i = 10; i < 20; i++) + { + image.GetPixelRowSpan(i).Slice(10, 10).Fill(fg); + } + } + + Assert.False(memoryManager.IsDisposed); + } + } + + string fn = System.IO.Path.Combine( + TestEnvironment.ActualOutputDirectoryFullPath, + $"{nameof(this.WrapSystemDrawingBitmap_WhenObserved)}.bmp"); + + bmp.Save(fn, ImageFormat.Bmp); + } + } + [Theory] [InlineData(0, 5, 5)] [InlineData(20, 5, 5)] @@ -333,6 +403,17 @@ public void WrapMemory_MemoryOfByte_InvalidSize(int size, int height, int width) Assert.Throws(() => Image.WrapMemory(memory, height, width)); } + [Theory] + [InlineData(0, 5, 5)] + [InlineData(20, 5, 5)] + [InlineData(26, 5, 5)] + [InlineData(2, 1, 1)] + [InlineData(1023, 32, 32)] + public unsafe void WrapMemory_Pointer_Null(int size, int height, int width) + { + Assert.Throws(() => Image.WrapMemory((void*)null, height, width)); + } + private static bool ShouldSkipBitmapTest => !TestEnvironment.Is64BitProcess || (TestHelpers.ImageSharpBuiltAgainst != "netcoreapp3.1" && TestHelpers.ImageSharpBuiltAgainst != "netcoreapp2.1"); } From 834a179f3ad4eab01231f9c96daa797ba9cfa3dd Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 12 Dec 2020 15:15:22 +0100 Subject: [PATCH 4/6] Improved XML docs for Image.WrapMemory APIs --- src/ImageSharp/Image.WrapMemory.cs | 90 +++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index dff888c13b..7785929312 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -18,6 +18,14 @@ public abstract partial class Image /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an instance. + /// The ownership of the underlying buffer for the input instance is not being transferred to + /// the new instance, meaning that consumers of this method need to make sure the input buffer + /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is not disposed. + /// For instance, if the input instance is one retrieved from an instance + /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still + /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. /// /// The pixel type /// The @@ -47,6 +55,14 @@ public static Image WrapMemory( /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an instance. + /// The ownership of the underlying buffer for the input instance is not being transferred to + /// the new instance, meaning that consumers of this method need to make sure the input buffer + /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is not disposed. + /// For instance, if the input instance is one retrieved from an instance + /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still + /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. /// /// The pixel type /// The @@ -66,7 +82,14 @@ public static Image WrapMemory( /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an instance. - /// The memory is being observed, the caller remains responsible for managing it's lifecycle. + /// The ownership of the underlying buffer for the input instance is not being transferred to + /// the new instance, meaning that consumers of this method need to make sure the input buffer + /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is not disposed. + /// For instance, if the input instance is one retrieved from an instance + /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still + /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. /// /// The pixel type. /// The pixel memory. @@ -156,6 +179,14 @@ public static Image WrapMemory( /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an instance. + /// The ownership of the underlying buffer for the input instance is not being transferred to + /// the new instance, meaning that consumers of this method need to make sure the input buffer + /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is not disposed. + /// For instance, if the input instance is one retrieved from an instance + /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still + /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. /// /// The pixel type /// The @@ -188,6 +219,14 @@ public static Image WrapMemory( /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an instance. + /// The ownership of the underlying buffer for the input instance is not being transferred to + /// the new instance, meaning that consumers of this method need to make sure the input buffer + /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is not disposed. + /// For instance, if the input instance is one retrieved from an instance + /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still + /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. /// /// The pixel type /// The @@ -207,7 +246,14 @@ public static Image WrapMemory( /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an instance. - /// The memory is being observed, the caller remains responsible for managing it's lifecycle. + /// The ownership of the underlying buffer for the input instance is not being transferred to + /// the new instance, meaning that consumers of this method need to make sure the input buffer + /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is not disposed. + /// For instance, if the input instance is one retrieved from an instance + /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still + /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. /// /// The pixel type. /// The byte memory representing the pixel data. @@ -224,6 +270,19 @@ public static Image WrapMemory( /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an instance. + /// This method relies on callers to carefully manage the target memory area being referenced by the + /// pointer, and it requires that the lifetime of such a memory area is at least equal to that of the returned + /// instance. For instance, if the input pointer references an unmanaged memory area, + /// callers need to ensure that that memory area is not freed as long as the returned is + /// in use and not disposed. The same applies if the input memory area points to a pinned managed object, as callers + /// need to ensure that object will remain pinned as long as the instance is in use. + /// Failing to do so constitutes undefined behavior and will likely lead to memory corruption and runtime crashes. + /// Note that if you have a or an array (which can be cast to ) of + /// either or values, it is highly recommended to use one of the other + /// available overloads of this method instead (such as + /// or , to make the resulting code less error + /// prone and avoid having to pin the underlying memory buffer in use. This method is primarily meant to be used when + /// doing interop or working with buffers that are located in unmanaged memory. /// /// The pixel type /// The @@ -255,6 +314,19 @@ public static unsafe Image WrapMemory( /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an instance. + /// This method relies on callers to carefully manage the target memory area being referenced by the + /// pointer, and it requires that the lifetime of such a memory area is at least equal to that of the returned + /// instance. For instance, if the input pointer references an unmanaged memory area, + /// callers need to ensure that that memory area is not freed as long as the returned is + /// in use and not disposed. The same applies if the input memory area points to a pinned managed object, as callers + /// need to ensure that object will remain pinned as long as the instance is in use. + /// Failing to do so constitutes undefined behavior and will likely lead to memory corruption and runtime crashes. + /// Note that if you have a or an array (which can be cast to ) of + /// either or values, it is highly recommended to use one of the other + /// available overloads of this method instead (such as + /// or , to make the resulting code less error + /// prone and avoid having to pin the underlying memory buffer in use. This method is primarily meant to be used when + /// doing interop or working with buffers that are located in unmanaged memory. /// /// The pixel type /// The @@ -274,7 +346,19 @@ public static unsafe Image WrapMemory( /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an instance. - /// The memory is being observed, the caller remains responsible for managing it's lifecycle. + /// This method relies on callers to carefully manage the target memory area being referenced by the + /// pointer, and it requires that the lifetime of such a memory area is at least equal to that of the returned + /// instance. For instance, if the input pointer references an unmanaged memory area, + /// callers need to ensure that that memory area is not freed as long as the returned is + /// in use and not disposed. The same applies if the input memory area points to a pinned managed object, as callers + /// need to ensure that object will remain pinned as long as the instance is in use. + /// Failing to do so constitutes undefined behavior and will likely lead to memory corruption and runtime crashes. + /// Note that if you have a or an array (which can be cast to ) of + /// either or values, it is highly recommended to use one of the other + /// available overloads of this method instead (such as + /// or , to make the resulting code less error + /// prone and avoid having to pin the underlying memory buffer in use. This method is primarily meant to be used when + /// doing interop or working with buffers that are located in unmanaged memory. /// /// The pixel type. /// The pointer to the target memory buffer to wrap. From 648c1dcdeb20229c821037dc119ca76d28221afd Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 14 Dec 2020 18:13:21 +0100 Subject: [PATCH 5/6] Improve formatting for XML docs --- src/ImageSharp/Image.WrapMemory.cs | 198 ++++++++++++++++++----------- 1 file changed, 126 insertions(+), 72 deletions(-) diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index 7785929312..383f643969 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -16,16 +16,22 @@ namespace SixLabors.ImageSharp public abstract partial class Image { /// - /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, - /// allowing to view/manipulate it as an instance. - /// The ownership of the underlying buffer for the input instance is not being transferred to - /// the new instance, meaning that consumers of this method need to make sure the input buffer - /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was - /// created), or that the owning object is not disposed until the returned is not disposed. - /// For instance, if the input instance is one retrieved from an instance + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as + /// an instance. + /// + /// + /// Please note: using this method does not transfer the ownership of the underlying buffer of the input + /// to the new instance. This means that consumers of this method must ensure that the input buffer + /// is either self-contained, (for example, a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is disposed. + /// + /// + /// If the input instance is one retrieved from an instance /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other - /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers appropriately. + /// /// /// The pixel type /// The @@ -53,16 +59,22 @@ public static Image WrapMemory( } /// - /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, - /// allowing to view/manipulate it as an instance. - /// The ownership of the underlying buffer for the input instance is not being transferred to - /// the new instance, meaning that consumers of this method need to make sure the input buffer - /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was - /// created), or that the owning object is not disposed until the returned is not disposed. - /// For instance, if the input instance is one retrieved from an instance + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as + /// an instance. + /// + /// + /// Please note: using this method does not transfer the ownership of the underlying buffer of the input + /// to the new instance. This means that consumers of this method must ensure that the input buffer + /// is either self-contained, (for example, a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is disposed. + /// + /// + /// If the input instance is one retrieved from an instance /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other - /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers appropriately. + /// /// /// The pixel type /// The @@ -80,16 +92,22 @@ public static Image WrapMemory( => WrapMemory(configuration, pixelMemory, width, height, new ImageMetadata()); /// - /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, - /// allowing to view/manipulate it as an instance. - /// The ownership of the underlying buffer for the input instance is not being transferred to - /// the new instance, meaning that consumers of this method need to make sure the input buffer - /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was - /// created), or that the owning object is not disposed until the returned is not disposed. - /// For instance, if the input instance is one retrieved from an instance + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as + /// an instance. + /// + /// + /// Please note: using this method does not transfer the ownership of the underlying buffer of the input + /// to the new instance. This means that consumers of this method must ensure that the input buffer + /// is either self-contained, (for example, a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is disposed. + /// + /// + /// If the input instance is one retrieved from an instance /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other - /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers appropriately. + /// /// /// The pixel type. /// The pixel memory. @@ -177,16 +195,22 @@ public static Image WrapMemory( => WrapMemory(Configuration.Default, pixelMemoryOwner, width, height); /// - /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, - /// allowing to view/manipulate it as an instance. - /// The ownership of the underlying buffer for the input instance is not being transferred to - /// the new instance, meaning that consumers of this method need to make sure the input buffer - /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was - /// created), or that the owning object is not disposed until the returned is not disposed. - /// For instance, if the input instance is one retrieved from an instance + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as + /// an instance. + /// + /// + /// Please note: using this method does not transfer the ownership of the underlying buffer of the input + /// to the new instance. This means that consumers of this method must ensure that the input buffer + /// is either self-contained, (for example, a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is disposed. + /// + /// + /// If the input instance is one retrieved from an instance /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other - /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers appropriately. + /// /// /// The pixel type /// The @@ -217,16 +241,22 @@ public static Image WrapMemory( } /// - /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, - /// allowing to view/manipulate it as an instance. - /// The ownership of the underlying buffer for the input instance is not being transferred to - /// the new instance, meaning that consumers of this method need to make sure the input buffer - /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was - /// created), or that the owning object is not disposed until the returned is not disposed. - /// For instance, if the input instance is one retrieved from an instance + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as + /// an instance. + /// + /// + /// Please note: using this method does not transfer the ownership of the underlying buffer of the input + /// to the new instance. This means that consumers of this method must ensure that the input buffer + /// is either self-contained, (for example, a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is disposed. + /// + /// + /// If the input instance is one retrieved from an instance /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other - /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers appropriately. + /// /// /// The pixel type /// The @@ -244,16 +274,22 @@ public static Image WrapMemory( => WrapMemory(configuration, byteMemory, width, height, new ImageMetadata()); /// - /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, - /// allowing to view/manipulate it as an instance. - /// The ownership of the underlying buffer for the input instance is not being transferred to - /// the new instance, meaning that consumers of this method need to make sure the input buffer - /// is either self-contianed (for instance, this is the case for a instance wrapping a new array that was - /// created), or that the owning object is not disposed until the returned is not disposed. - /// For instance, if the input instance is one retrieved from an instance + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as + /// an instance. + /// + /// + /// Please note: using this method does not transfer the ownership of the underlying buffer of the input + /// to the new instance. This means that consumers of this method must ensure that the input buffer + /// is either self-contained, (for example, a instance wrapping a new array that was + /// created), or that the owning object is not disposed until the returned is disposed. + /// + /// + /// If the input instance is one retrieved from an instance /// rented from a memory pool (such as ), and that owning instance is disposed while the image is still /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other - /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers properly. + /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers appropriately. + /// /// /// The pixel type. /// The byte memory representing the pixel data. @@ -268,21 +304,27 @@ public static Image WrapMemory( => WrapMemory(Configuration.Default, byteMemory, width, height); /// - /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, - /// allowing to view/manipulate it as an instance. - /// This method relies on callers to carefully manage the target memory area being referenced by the - /// pointer, and it requires that the lifetime of such a memory area is at least equal to that of the returned - /// instance. For instance, if the input pointer references an unmanaged memory area, - /// callers need to ensure that that memory area is not freed as long as the returned is + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as + /// an instance. + /// + /// + /// Please note: this method relies on callers to carefully manage the target memory area being referenced by the + /// pointer and that the lifetime of such a memory area is at least equal to that of the returned + /// instance. For example, if the input pointer references an unmanaged memory area, + /// callers must ensure that the memory area is not freed as long as the returned is /// in use and not disposed. The same applies if the input memory area points to a pinned managed object, as callers - /// need to ensure that object will remain pinned as long as the instance is in use. + /// must ensure that objects will remain pinned as long as the instance is in use. /// Failing to do so constitutes undefined behavior and will likely lead to memory corruption and runtime crashes. - /// Note that if you have a or an array (which can be cast to ) of + /// + /// + /// Note also that if you have a or an array (which can be cast to ) of /// either or values, it is highly recommended to use one of the other /// available overloads of this method instead (such as /// or , to make the resulting code less error /// prone and avoid having to pin the underlying memory buffer in use. This method is primarily meant to be used when /// doing interop or working with buffers that are located in unmanaged memory. + /// /// /// The pixel type /// The @@ -312,21 +354,27 @@ public static unsafe Image WrapMemory( } /// - /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, - /// allowing to view/manipulate it as an instance. - /// This method relies on callers to carefully manage the target memory area being referenced by the - /// pointer, and it requires that the lifetime of such a memory area is at least equal to that of the returned - /// instance. For instance, if the input pointer references an unmanaged memory area, - /// callers need to ensure that that memory area is not freed as long as the returned is + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as + /// an instance. + /// + /// + /// Please note: this method relies on callers to carefully manage the target memory area being referenced by the + /// pointer and that the lifetime of such a memory area is at least equal to that of the returned + /// instance. For example, if the input pointer references an unmanaged memory area, + /// callers must ensure that the memory area is not freed as long as the returned is /// in use and not disposed. The same applies if the input memory area points to a pinned managed object, as callers - /// need to ensure that object will remain pinned as long as the instance is in use. + /// must ensure that objects will remain pinned as long as the instance is in use. /// Failing to do so constitutes undefined behavior and will likely lead to memory corruption and runtime crashes. - /// Note that if you have a or an array (which can be cast to ) of + /// + /// + /// Note also that if you have a or an array (which can be cast to ) of /// either or values, it is highly recommended to use one of the other /// available overloads of this method instead (such as /// or , to make the resulting code less error /// prone and avoid having to pin the underlying memory buffer in use. This method is primarily meant to be used when /// doing interop or working with buffers that are located in unmanaged memory. + /// /// /// The pixel type /// The @@ -344,21 +392,27 @@ public static unsafe Image WrapMemory( => WrapMemory(configuration, pointer, width, height, new ImageMetadata()); /// - /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, - /// allowing to view/manipulate it as an instance. - /// This method relies on callers to carefully manage the target memory area being referenced by the - /// pointer, and it requires that the lifetime of such a memory area is at least equal to that of the returned - /// instance. For instance, if the input pointer references an unmanaged memory area, - /// callers need to ensure that that memory area is not freed as long as the returned is + /// + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as + /// an instance. + /// + /// + /// Please note: this method relies on callers to carefully manage the target memory area being referenced by the + /// pointer and that the lifetime of such a memory area is at least equal to that of the returned + /// instance. For example, if the input pointer references an unmanaged memory area, + /// callers must ensure that the memory area is not freed as long as the returned is /// in use and not disposed. The same applies if the input memory area points to a pinned managed object, as callers - /// need to ensure that object will remain pinned as long as the instance is in use. + /// must ensure that objects will remain pinned as long as the instance is in use. /// Failing to do so constitutes undefined behavior and will likely lead to memory corruption and runtime crashes. - /// Note that if you have a or an array (which can be cast to ) of + /// + /// + /// Note also that if you have a or an array (which can be cast to ) of /// either or values, it is highly recommended to use one of the other /// available overloads of this method instead (such as /// or , to make the resulting code less error /// prone and avoid having to pin the underlying memory buffer in use. This method is primarily meant to be used when /// doing interop or working with buffers that are located in unmanaged memory. + /// /// /// The pixel type. /// The pointer to the target memory buffer to wrap. From 17796d83bd0c1e47f29f2718671d7b2aa6922aa5 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 14 Dec 2020 23:05:13 +0100 Subject: [PATCH 6/6] Fix inaccurate test method name Co-authored-by: Anton Firszov --- tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 637b4d8170..02a8381808 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -307,7 +307,7 @@ public unsafe void WrapMemory_FromPointer_CreatedImageIsCorrect() } [Fact] - public unsafe void WrapSystemDrawingBitmap_FromPointer_WhenObserved() + public unsafe void WrapSystemDrawingBitmap_FromPointer() { if (ShouldSkipBitmapTest) {