diff --git a/README.md b/README.md
index 6cc8e5304..ab16bbb76 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
@@ -26,9 +26,16 @@ Built against [.NET Standard 1.3](https://docs.microsoft.com/en-us/dotnet/standa
## License
- ImageSharp is licensed under the [Apache License, Version 2.0](https://opensource.org/licenses/Apache-2.0)
-- An alternative Commercial License can be purchased for projects and applications requiring support.
+- An alternative Commercial Support License can be purchased **for projects and applications requiring support**.
Please visit https://sixlabors.com/pricing for details.
+## Support Six Labors
+
+Support the efforts of the development of the Six Labors projects.
+ - [Purchase a Commercial Support License :heart:](https://sixlabors.com/pricing/)
+ - [Become a sponsor via GitHub Sponsors :heart:]( https://github.com/sponsors/SixLabors)
+ - [Become a sponsor via Open Collective :heart:](https://opencollective.com/sixlabors)
+
## Documentation
- [Detailed documentation](https://sixlabors.github.io/docs/) for the ImageSharp API is available. This includes additional conceptual documentation to help you get started.
@@ -57,7 +64,7 @@ If you prefer, you can compile ImageSharp yourself (please do and help!)
- Using [Visual Studio 2019](https://visualstudio.microsoft.com/vs/)
- Make sure you have the latest version installed
- - Make sure you have [the .NET Core 3.1 SDK](https://www.microsoft.com/net/core#windows) installed
+ - Make sure you have [the .NET 5 SDK](https://www.microsoft.com/net/core#windows) installed
Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**:
@@ -96,40 +103,6 @@ Please... Spread the word, contribute algorithms, submit performance improvement
- [Scott Williams](https://github.com/tocsoft)
- [Brian Popow](https://github.com/brianpopow)
-## Sponsor Six Labors
-
-Support the efforts of the development of the Six Labors projects. [[Become a sponsor :heart:](https://opencollective.com/sixlabors#sponsor)]
-
-### Platinum Sponsors
-Become a platinum sponsor with a monthly donation of $2000 (providing 32 hours of maintenance and development) and get 2 hours of dedicated support (remote support available through chat or screen-sharing) per month.
-
-In addition you get your logo (large) on our README on GitHub and the home page (large) of sixlabors.com
-
-
-
-### Gold Sponsors
-Become a gold sponsor with a monthly donation of $1000 (providing 16 hours of maintenance and development) and get 1 hour of dedicated support (remote support available through chat or screen-sharing) per month.
-
-In addition you get your logo (large) on our README on GitHub and the home page (medium) of sixlabors.com
-
-









-
-### Silver Sponsors
-Become a silver sponsor with a monthly donation of $500 (providing 8 hours of maintenance and development) and get your logo (medium) on our README on GitHub and the product pages of sixlabors.com
-









-### Bronze Sponsors
-Become a bronze sponsor with a monthly donation of $100 and get your logo (small) on our README on GitHub.
-
-
-
-
-
-
-
-
-
-
-
diff --git a/shared-infrastructure b/shared-infrastructure
index 41fff7bf7..0ea21d9e2 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit 41fff7bf7ddb1d118898db1ddba43b95ba6ed0bb
+Subproject commit 0ea21d9e2a76d307dae9cfb74e33234b259352b7
diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs
index b0efdb60d..115d51921 100644
--- a/src/ImageSharp/Image.WrapMemory.cs
+++ b/src/ImageSharp/Image.WrapMemory.cs
@@ -303,6 +303,82 @@ namespace SixLabors.ImageSharp
where TPixel : unmanaged, IPixel
=> WrapMemory(Configuration.Default, byteMemory, width, height);
+ ///
+ /// Wraps an existing contiguous memory area of at least 'width' x 'height' pixels,
+ /// allowing to view/manipulate it as an instance.
+ /// The ownership of the is being transferred to the new instance,
+ /// meaning that the caller is not allowed to dispose .
+ /// It will be disposed together with the result image.
+ ///
+ /// The pixel type
+ /// The
+ /// The that is being transferred to the image
+ /// 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 Image WrapMemory(
+ Configuration configuration,
+ IMemoryOwner byteMemoryOwner,
+ int width,
+ int height,
+ ImageMetadata metadata)
+ where TPixel : unmanaged, IPixel
+ {
+ Guard.NotNull(configuration, nameof(configuration));
+ Guard.NotNull(metadata, nameof(metadata));
+
+ var pixelMemoryOwner = new ByteMemoryOwner(byteMemoryOwner);
+
+ Guard.IsTrue(pixelMemoryOwner.Memory.Length >= (long)width * height, nameof(pixelMemoryOwner), "The length of the input memory is less than the specified image size");
+
+ var memorySource = MemoryGroup.Wrap(pixelMemoryOwner);
+ return new Image(configuration, memorySource, width, height, metadata);
+ }
+
+ ///
+ /// Wraps an existing contiguous memory area of at least 'width' x 'height' pixels,
+ /// allowing to view/manipulate it as an instance.
+ /// The ownership of the is being transferred to the new instance,
+ /// meaning that the caller is not allowed to dispose .
+ /// It will be disposed together with the result image.
+ ///
+ /// The pixel type.
+ /// The
+ /// The that is being transferred to the image.
+ /// The width of the memory image.
+ /// The height of the memory image.
+ /// The configuration is null.
+ /// An instance
+ public static Image WrapMemory(
+ Configuration configuration,
+ IMemoryOwner byteMemoryOwner,
+ int width,
+ int height)
+ where TPixel : unmanaged, IPixel
+ => WrapMemory(configuration, byteMemoryOwner, width, height, new ImageMetadata());
+
+ ///
+ /// Wraps an existing contiguous memory area of at least 'width' x 'height' pixels,
+ /// allowing to view/manipulate it as an instance.
+ /// The ownership of the is being transferred to the new instance,
+ /// meaning that the caller is not allowed to dispose .
+ /// It will be disposed together with the result image.
+ ///
+ /// The pixel type
+ /// The that is being transferred to the image.
+ /// The width of the memory image.
+ /// The height of the memory image.
+ /// An instance.
+ public static Image WrapMemory(
+ IMemoryOwner byteMemoryOwner,
+ int width,
+ int height)
+ where TPixel : unmanaged, IPixel
+ => WrapMemory(Configuration.Default, byteMemoryOwner, width, height);
+
///
///
/// Wraps an existing contiguous memory area of at least 'width' x 'height' pixels allowing viewing/manipulation as
diff --git a/src/ImageSharp/Memory/ByteMemoryOwner{T}.cs b/src/ImageSharp/Memory/ByteMemoryOwner{T}.cs
new file mode 100644
index 000000000..3cf62bbc1
--- /dev/null
+++ b/src/ImageSharp/Memory/ByteMemoryOwner{T}.cs
@@ -0,0 +1,54 @@
+// 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 of instances
+ /// and cast them to be for any arbitrary unmanaged value type.
+ ///
+ /// The value type to use when casting the wrapped instance.
+ internal sealed class ByteMemoryOwner : IMemoryOwner
+ where T : unmanaged
+ {
+ private readonly IMemoryOwner memoryOwner;
+ private readonly ByteMemoryManager memoryManager;
+ private bool disposedValue;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The of instance to wrap.
+ public ByteMemoryOwner(IMemoryOwner memoryOwner)
+ {
+ this.memoryOwner = memoryOwner;
+ this.memoryManager = new ByteMemoryManager(memoryOwner.Memory);
+ }
+
+ ///
+ public Memory Memory => this.memoryManager.Memory;
+
+ private void Dispose(bool disposing)
+ {
+ if (!this.disposedValue)
+ {
+ if (disposing)
+ {
+ this.memoryOwner.Dispose();
+ }
+
+ this.disposedValue = true;
+ }
+ }
+
+ ///
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+ this.Dispose(disposing: true);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs
index 17c73cc83..bb75578a4 100644
--- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs
+++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs
@@ -380,11 +380,11 @@ namespace SixLabors.ImageSharp.Tests
private class TestMemoryOwner : IMemoryOwner
{
+ public bool Disposed { get; private set; }
+
public Memory Memory { get; set; }
- public void Dispose()
- {
- }
+ public void Dispose() => this.Disposed = true;
}
[Theory]
@@ -410,7 +410,68 @@ namespace SixLabors.ImageSharp.Tests
var array = new Rgba32[size];
var memory = new TestMemoryOwner { Memory = array };
- Image.WrapMemory(memory, height, width);
+ using (var img = Image.WrapMemory(memory, width, height))
+ {
+ Assert.Equal(width, img.Width);
+ Assert.Equal(height, img.Height);
+
+ for (int i = 0; i < height; ++i)
+ {
+ var arrayIndex = width * i;
+
+ Span rowSpan = img.GetPixelRowSpan(i);
+ ref Rgba32 r0 = ref rowSpan[0];
+ ref Rgba32 r1 = ref array[arrayIndex];
+
+ Assert.True(Unsafe.AreSame(ref r0, ref r1));
+ }
+ }
+
+ Assert.True(memory.Disposed);
+ }
+
+ [Theory]
+ [InlineData(0, 5, 5)]
+ [InlineData(20, 5, 5)]
+ [InlineData(1023, 32, 32)]
+ public void WrapMemory_IMemoryOwnerOfByte_InvalidSize(int size, int height, int width)
+ {
+ var array = new byte[size * Unsafe.SizeOf()];
+ var memory = new TestMemoryOwner { Memory = array };
+
+ Assert.Throws(() => Image.WrapMemory(memory, height, width));
+ }
+
+ [Theory]
+ [InlineData(25, 5, 5)]
+ [InlineData(26, 5, 5)]
+ [InlineData(2, 1, 1)]
+ [InlineData(1024, 32, 32)]
+ [InlineData(2048, 32, 32)]
+ public void WrapMemory_IMemoryOwnerOfByte_ValidSize(int size, int height, int width)
+ {
+ var pixelSize = Unsafe.SizeOf();
+ var array = new byte[size * pixelSize];
+ var memory = new TestMemoryOwner { Memory = array };
+
+ using (var img = Image.WrapMemory(memory, width, height))
+ {
+ Assert.Equal(width, img.Width);
+ Assert.Equal(height, img.Height);
+
+ for (int i = 0; i < height; ++i)
+ {
+ var arrayIndex = pixelSize * width * i;
+
+ Span rowSpan = img.GetPixelRowSpan(i);
+ ref Rgba32 r0 = ref rowSpan[0];
+ ref Rgba32 r1 = ref Unsafe.As(ref array[arrayIndex]);
+
+ Assert.True(Unsafe.AreSame(ref r0, ref r1));
+ }
+ }
+
+ Assert.True(memory.Disposed);
}
[Theory]