Browse Source

Added overloads to Image.WrapMemory for IMemoryOwner<byte>.

pull/1610/head
Petar Tasev 5 years ago
parent
commit
dc96867834
  1. 76
      src/ImageSharp/Image.WrapMemory.cs
  2. 54
      src/ImageSharp/Memory/ByteMemoryOwner{T}.cs
  3. 26
      tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs

76
src/ImageSharp/Image.WrapMemory.cs

@ -303,6 +303,82 @@ namespace SixLabors.ImageSharp
where TPixel : unmanaged, IPixel<TPixel>
=> WrapMemory<TPixel>(Configuration.Default, byteMemory, width, height);
/// <summary>
/// Wraps an existing contiguous memory area of at least 'width' x 'height' pixels,
/// allowing to view/manipulate it as an <see cref="Image{TPixel}"/> instance.
/// The ownership of the <paramref name="byteMemoryOwner"/> is being transferred to the new <see cref="Image{TPixel}"/> instance,
/// meaning that the caller is not allowed to dispose <paramref name="byteMemoryOwner"/>.
/// It will be disposed together with the result image.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="configuration">The <see cref="Configuration"/></param>
/// <param name="byteMemoryOwner">The <see cref="IMemoryOwner{T}"/> that is being transferred to the image</param>
/// <param name="width">The width of the memory image.</param>
/// <param name="height">The height of the memory image.</param>
/// <param name="metadata">The <see cref="ImageMetadata"/></param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <exception cref="ArgumentNullException">The metadata is null.</exception>
/// <returns>An <see cref="Image{TPixel}"/> instance</returns>
public static Image<TPixel> WrapMemory<TPixel>(
Configuration configuration,
IMemoryOwner<byte> byteMemoryOwner,
int width,
int height,
ImageMetadata metadata)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(metadata, nameof(metadata));
var pixelMemoryOwner = new ByteMemoryOwner<TPixel>(byteMemoryOwner);
Guard.IsTrue(pixelMemoryOwner.Memory.Length >= width * height, nameof(pixelMemoryOwner), "The length of the input memory is less than the specified image size");
var memorySource = MemoryGroup<TPixel>.Wrap(pixelMemoryOwner);
return new Image<TPixel>(configuration, memorySource, width, height, metadata);
}
/// <summary>
/// Wraps an existing contiguous memory area of at least 'width' x 'height' pixels,
/// allowing to view/manipulate it as an <see cref="Image{TPixel}"/> instance.
/// The ownership of the <paramref name="byteMemoryOwner"/> is being transferred to the new <see cref="Image{TPixel}"/> instance,
/// meaning that the caller is not allowed to dispose <paramref name="byteMemoryOwner"/>.
/// It will be disposed together with the result image.
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <param name="configuration">The <see cref="Configuration"/></param>
/// <param name="byteMemoryOwner">The <see cref="IMemoryOwner{T}"/> that is being transferred to the image.</param>
/// <param name="width">The width of the memory image.</param>
/// <param name="height">The height of the memory image.</param>
/// <exception cref="ArgumentNullException">The configuration is null.</exception>
/// <returns>An <see cref="Image{TPixel}"/> instance</returns>
public static Image<TPixel> WrapMemory<TPixel>(
Configuration configuration,
IMemoryOwner<byte> byteMemoryOwner,
int width,
int height)
where TPixel : unmanaged, IPixel<TPixel>
=> WrapMemory<TPixel>(configuration, byteMemoryOwner, width, height, new ImageMetadata());
/// <summary>
/// Wraps an existing contiguous memory area of at least 'width' x 'height' pixels,
/// allowing to view/manipulate it as an <see cref="Image{TPixel}"/> instance.
/// The ownership of the <paramref name="byteMemoryOwner"/> is being transferred to the new <see cref="Image{TPixel}"/> instance,
/// meaning that the caller is not allowed to dispose <paramref name="byteMemoryOwner"/>.
/// It will be disposed together with the result image.
/// </summary>
/// <typeparam name="TPixel">The pixel type</typeparam>
/// <param name="byteMemoryOwner">The <see cref="IMemoryOwner{T}"/> that is being transferred to the image.</param>
/// <param name="width">The width of the memory image.</param>
/// <param name="height">The height of the memory image.</param>
/// <returns>An <see cref="Image{TPixel}"/> instance.</returns>
public static Image<TPixel> WrapMemory<TPixel>(
IMemoryOwner<byte> byteMemoryOwner,
int width,
int height)
where TPixel : unmanaged, IPixel<TPixel>
=> WrapMemory<TPixel>(Configuration.Default, byteMemoryOwner, width, height);
/// <summary>
/// <para>
/// Wraps an existing contiguous memory area of at least 'width' x 'height' pixels allowing viewing/manipulation as

54
src/ImageSharp/Memory/ByteMemoryOwner{T}.cs

@ -0,0 +1,54 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Text;
namespace SixLabors.ImageSharp.Memory
{
/// <summary>
/// A custom <see cref="IMemoryOwner{T}"/> that can wrap <see cref="IMemoryOwner{T}"/> of <see cref="byte"/> instances
/// and cast them to be <see cref="IMemoryOwner{T}"/> for any arbitrary unmanaged <typeparamref name="T"/> value type.
/// </summary>
/// <typeparam name="T">The value type to use when casting the wrapped <see cref="IMemoryOwner{T}"/> instance.</typeparam>
internal sealed class ByteMemoryOwner<T> : IMemoryOwner<T>
where T : unmanaged
{
private readonly IMemoryOwner<byte> memoryOwner;
private readonly ByteMemoryManager<T> memoryManager;
private bool disposedValue;
/// <summary>
/// Initializes a new instance of the <see cref="ByteMemoryOwner{T}"/> class.
/// </summary>
/// <param name="memoryOwner">The <see cref="IMemoryOwner{T}"/> of <see cref="byte"/> instance to wrap.</param>
public ByteMemoryOwner(IMemoryOwner<byte> memoryOwner)
{
this.memoryOwner = memoryOwner;
this.memoryManager = new ByteMemoryManager<T>(memoryOwner.Memory);
}
/// <inheritdoc/>
public Memory<T> Memory => this.memoryManager.Memory;
private void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
this.memoryOwner.Dispose();
}
this.disposedValue = true;
}
}
/// <inheritdoc/>
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
this.Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}

26
tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs

@ -413,6 +413,32 @@ namespace SixLabors.ImageSharp.Tests
Image.WrapMemory(memory, height, width);
}
[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<Rgba32>()];
var memory = new TestMemoryOwner<byte> { Memory = array };
Assert.Throws<ArgumentException>(() => Image.WrapMemory<Rgba32>(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 array = new byte[size * Unsafe.SizeOf<Rgba32>()];
var memory = new TestMemoryOwner<byte> { Memory = array };
Image.WrapMemory<Rgba32>(memory, height, width);
}
[Theory]
[InlineData(0, 5, 5)]
[InlineData(20, 5, 5)]

Loading…
Cancel
Save