Browse Source

Merge pull request #1172 from SixLabors/js/span-accessibility

Improve accessability of Span<T> methods.
pull/1175/head
James Jackson-South 6 years ago
committed by GitHub
parent
commit
de73c63f50
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 78
      src/ImageSharp/Advanced/AdvancedImageExtensions.cs
  2. 35
      src/ImageSharp/ImageFrame{TPixel}.cs
  3. 34
      src/ImageSharp/Image{TPixel}.cs
  4. 5
      tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs
  5. 3
      tests/ImageSharp.Tests/Drawing/DrawImageTests.cs
  6. 5
      tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
  7. 4
      tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs
  8. 22
      tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs
  9. 6
      tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs
  10. 10
      tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs
  11. 9
      tests/ImageSharp.Tests/Image/ImageTests.cs
  12. 11
      tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs
  13. 2
      tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs
  14. 3
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs
  15. 11
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
  16. 6
      tests/ImageSharp.Tests/TestUtilities/TestUtils.cs

78
src/ImageSharp/Advanced/AdvancedImageExtensions.cs

@ -78,84 +78,6 @@ namespace SixLabors.ImageSharp.Advanced
where TPixel : unmanaged, IPixel<TPixel>
=> source?.Frames.RootFrame.GetPixelMemoryGroup() ?? throw new ArgumentNullException(nameof(source));
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> in the source image's pixel format
/// stored in row major order, if the backing buffer is contiguous.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source image.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
/// <exception cref="InvalidOperationException">Thrown when the backing buffer is discontiguous.</exception>
[Obsolete(
@"GetPixelSpan might fail, because the backing buffer could be discontiguous for large images. Use GetPixelMemoryGroup or GetPixelRowSpan instead!")]
public static Span<TPixel> GetPixelSpan<TPixel>(this ImageFrame<TPixel> source)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(source, nameof(source));
IMemoryGroup<TPixel> mg = source.GetPixelMemoryGroup();
if (mg.Count > 1)
{
throw new InvalidOperationException($"GetPixelSpan is invalid, since the backing buffer of this {source.Width}x{source.Height} sized image is discontiguous!");
}
return mg.Single().Span;
}
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory in the source image's pixel format
/// stored in row major order.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
/// <exception cref="InvalidOperationException">Thrown when the backing buffer is discontiguous.</exception>
[Obsolete(
@"GetPixelSpan might fail, because the backing buffer could be discontiguous for large images. Use GetPixelMemoryGroup or GetPixelRowSpan instead!")]
public static Span<TPixel> GetPixelSpan<TPixel>(this Image<TPixel> source)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(source, nameof(source));
return source.Frames.RootFrame.GetPixelSpan();
}
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelRowSpan<TPixel>(this ImageFrame<TPixel> source, int rowIndex)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(source, nameof(source));
Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex));
Guard.MustBeLessThan(rowIndex, source.Height, nameof(rowIndex));
return source.PixelBuffer.GetRowSpan(rowIndex);
}
/// <summary>
/// Gets the representation of the pixels as <see cref="Span{T}"/> of of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="source">The source.</param>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
public static Span<TPixel> GetPixelRowSpan<TPixel>(this Image<TPixel> source, int rowIndex)
where TPixel : unmanaged, IPixel<TPixel>
{
Guard.NotNull(source, nameof(source));
Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex));
Guard.MustBeLessThan(rowIndex, source.Height, nameof(rowIndex));
return source.Frames.RootFrame.PixelBuffer.GetRowSpan(rowIndex);
}
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row.

35
src/ImageSharp/ImageFrame{TPixel}.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
@ -166,6 +167,40 @@ namespace SixLabors.ImageSharp
}
}
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// </summary>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when row index is out of range.</exception>
public Span<TPixel> GetPixelRowSpan(int rowIndex)
{
Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex));
Guard.MustBeLessThan(rowIndex, this.Height, nameof(rowIndex));
return this.PixelBuffer.GetRowSpan(rowIndex);
}
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> in the source image's pixel format
/// stored in row major order, if the backing buffer is contiguous.
/// </summary>
/// <param name="span">The <see cref="Span{T}"/>.</param>
/// <returns>The <see cref="bool"/>.</returns>
public bool TryGetSinglePixelSpan(out Span<TPixel> span)
{
IMemoryGroup<TPixel> mg = this.GetPixelMemoryGroup();
if (mg.Count > 1)
{
span = default;
return false;
}
span = mg.Single().Span;
return true;
}
/// <summary>
/// Gets a reference to the pixel at the specified position.
/// </summary>

34
src/ImageSharp/Image{TPixel}.cs

@ -163,6 +163,40 @@ namespace SixLabors.ImageSharp
}
}
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// </summary>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when row index is out of range.</exception>
public Span<TPixel> GetPixelRowSpan(int rowIndex)
{
Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex));
Guard.MustBeLessThan(rowIndex, this.Height, nameof(rowIndex));
return this.PixelSource.PixelBuffer.GetRowSpan(rowIndex);
}
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> in the source image's pixel format
/// stored in row major order, if the backing buffer is contiguous.
/// </summary>
/// <param name="span">The <see cref="Span{T}"/>.</param>
/// <returns>The <see cref="bool"/>.</returns>
public bool TryGetSinglePixelSpan(out Span<TPixel> span)
{
IMemoryGroup<TPixel> mg = this.GetPixelMemoryGroup();
if (mg.Count > 1)
{
span = default;
return false;
}
span = mg.Single().Span;
return true;
}
/// <summary>
/// Clones the current image
/// </summary>

5
tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs

@ -61,7 +61,10 @@ namespace SixLabors.ImageSharp.Tests.Advanced
{
using Image<TPixel> image0 = provider.GetImage();
var targetBuffer = new TPixel[image0.Width * image0.Height];
image0.GetPixelSpan().CopyTo(targetBuffer);
Assert.True(image0.TryGetSinglePixelSpan(out Span<TPixel> sourceBuffer));
sourceBuffer.CopyTo(targetBuffer);
var managerOfExternalMemory = new TestMemoryManager<TPixel>(targetBuffer);

3
tests/ImageSharp.Tests/Drawing/DrawImageTests.cs

@ -128,7 +128,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (Image<Rgba32> background = provider.GetImage())
using (var overlay = new Image<Rgba32>(50, 50))
{
overlay.GetPixelSpan().Fill(Color.Black);
Assert.True(overlay.TryGetSinglePixelSpan(out Span<Rgba32> overlaySpan));
overlaySpan.Fill(Color.Black);
background.Mutate(c => c.DrawImage(overlay, new Point(x, y), PixelColorBlendingMode.Normal, 1F));

5
tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs

@ -164,7 +164,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif
{
ImageFrame<Rgba32> first = kumin1.Frames[i];
ImageFrame<Rgba32> second = kumin2.Frames[i];
first.ComparePixelBufferTo(second.GetPixelSpan());
Assert.True(second.TryGetSinglePixelSpan(out Span<Rgba32> secondSpan));
first.ComparePixelBufferTo(secondSpan);
}
}
}

4
tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs

@ -9,6 +9,7 @@ using ImageMagick;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Tga
{
@ -46,7 +47,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
{
magickImage.AutoOrient();
var result = new Image<TPixel>(configuration, magickImage.Width, magickImage.Height);
Span<TPixel> resultPixels = result.GetPixelSpan();
Assert.True(result.TryGetSinglePixelSpan(out Span<TPixel> resultPixels));
using (IPixelCollection pixels = magickImage.GetPixelsUnsafe())
{

22
tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs

@ -198,7 +198,9 @@ namespace SixLabors.ImageSharp.Tests
using (Image<TPixel> cloned = img.Frames.CloneFrame(0))
{
Assert.Equal(2, img.Frames.Count);
cloned.ComparePixelBufferTo(img.GetPixelSpan());
Assert.True(img.TryGetSinglePixelSpan(out Span<TPixel> imgSpan));
cloned.ComparePixelBufferTo(imgSpan);
}
}
}
@ -210,7 +212,8 @@ namespace SixLabors.ImageSharp.Tests
{
using (Image<TPixel> img = provider.GetImage())
{
var sourcePixelData = img.GetPixelSpan().ToArray();
Assert.True(img.TryGetSinglePixelSpan(out Span<TPixel> imgSpan));
TPixel[] sourcePixelData = imgSpan.ToArray();
img.Frames.AddFrame(new ImageFrame<TPixel>(Configuration.Default, 10, 10));
using (Image<TPixel> cloned = img.Frames.ExportFrame(0))
@ -242,7 +245,8 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void AddFrameFromPixelData()
{
var pixelData = this.Image.Frames.RootFrame.GetPixelSpan().ToArray();
Assert.True(this.Image.Frames.RootFrame.TryGetSinglePixelSpan(out Span<Rgba32> imgSpan));
var pixelData = imgSpan.ToArray();
this.Image.Frames.AddFrame(pixelData);
Assert.Equal(2, this.Image.Frames.Count);
}
@ -251,8 +255,10 @@ namespace SixLabors.ImageSharp.Tests
public void AddFrame_clones_sourceFrame()
{
var otherFrame = new ImageFrame<Rgba32>(Configuration.Default, 10, 10);
var addedFrame = this.Image.Frames.AddFrame(otherFrame);
addedFrame.ComparePixelBufferTo(otherFrame.GetPixelSpan());
ImageFrame<Rgba32> addedFrame = this.Image.Frames.AddFrame(otherFrame);
Assert.True(otherFrame.TryGetSinglePixelSpan(out Span<Rgba32> otherFrameSpan));
addedFrame.ComparePixelBufferTo(otherFrameSpan);
Assert.NotEqual(otherFrame, addedFrame);
}
@ -260,8 +266,10 @@ namespace SixLabors.ImageSharp.Tests
public void InsertFrame_clones_sourceFrame()
{
var otherFrame = new ImageFrame<Rgba32>(Configuration.Default, 10, 10);
var addedFrame = this.Image.Frames.InsertFrame(0, otherFrame);
addedFrame.ComparePixelBufferTo(otherFrame.GetPixelSpan());
ImageFrame<Rgba32> addedFrame = this.Image.Frames.InsertFrame(0, otherFrame);
Assert.True(otherFrame.TryGetSinglePixelSpan(out Span<Rgba32> otherFrameSpan));
addedFrame.ComparePixelBufferTo(otherFrameSpan);
Assert.NotEqual(otherFrame, addedFrame);
}

6
tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs

@ -159,7 +159,8 @@ namespace SixLabors.ImageSharp.Tests
var expectedClone = (Image<TPixel>)cloned;
expectedClone.ComparePixelBufferTo(img.GetPixelSpan());
Assert.True(img.TryGetSinglePixelSpan(out Span<TPixel> imgSpan));
expectedClone.ComparePixelBufferTo(imgSpan);
}
}
}
@ -171,7 +172,8 @@ namespace SixLabors.ImageSharp.Tests
{
using (Image<TPixel> img = provider.GetImage())
{
var sourcePixelData = img.GetPixelSpan().ToArray();
Assert.True(img.TryGetSinglePixelSpan(out Span<TPixel> imgSpan));
var sourcePixelData = imgSpan.ToArray();
ImageFrameCollection nonGenericFrameCollection = img.Frames;

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

@ -91,7 +91,8 @@ namespace SixLabors.ImageSharp.Tests
using (var image = Image.WrapMemory(cfg, memory, 5, 5, metaData))
{
ref Rgba32 pixel0 = ref image.GetPixelSpan()[0];
Assert.True(image.TryGetSinglePixelSpan(out Span<Rgba32> imageSpan));
ref Rgba32 pixel0 = ref imageSpan[0];
Assert.True(Unsafe.AreSame(ref array[0], ref pixel0));
Assert.Equal(cfg, image.GetConfiguration());
@ -118,7 +119,8 @@ namespace SixLabors.ImageSharp.Tests
using (var image = Image.WrapMemory(memory, bmp.Width, bmp.Height))
{
Assert.Equal(memory, image.GetRootFramePixelBuffer().GetSingleMemory());
image.GetPixelSpan().Fill(bg);
Assert.True(image.TryGetSinglePixelSpan(out Span<Bgra32> imageSpan));
imageSpan.Fill(bg);
for (var i = 10; i < 20; i++)
{
image.GetPixelRowSpan(i).Slice(10, 10).Fill(fg);
@ -153,8 +155,8 @@ namespace SixLabors.ImageSharp.Tests
using (var image = Image.WrapMemory(memoryManager, bmp.Width, bmp.Height))
{
Assert.Equal(memoryManager.Memory, image.GetRootFramePixelBuffer().GetSingleMemory());
image.GetPixelSpan().Fill(bg);
Assert.True(image.TryGetSinglePixelSpan(out Span<Bgra32> imageSpan));
imageSpan.Fill(bg);
for (var i = 10; i < 20; i++)
{
image.GetPixelRowSpan(i).Slice(10, 10).Fill(fg);

9
tests/ImageSharp.Tests/Image/ImageTests.cs

@ -27,7 +27,8 @@ namespace SixLabors.ImageSharp.Tests
{
Assert.Equal(11, image.Width);
Assert.Equal(23, image.Height);
Assert.Equal(11 * 23, image.GetPixelSpan().Length);
Assert.True(image.TryGetSinglePixelSpan(out Span<Rgba32> imageSpan));
Assert.Equal(11 * 23, imageSpan.Length);
image.ComparePixelBufferTo(default(Rgba32));
Assert.Equal(Configuration.Default, image.GetConfiguration());
@ -43,7 +44,8 @@ namespace SixLabors.ImageSharp.Tests
{
Assert.Equal(11, image.Width);
Assert.Equal(23, image.Height);
Assert.Equal(11 * 23, image.GetPixelSpan().Length);
Assert.True(image.TryGetSinglePixelSpan(out Span<Rgba32> imageSpan));
Assert.Equal(11 * 23, imageSpan.Length);
image.ComparePixelBufferTo(default(Rgba32));
Assert.Equal(configuration, image.GetConfiguration());
@ -60,7 +62,8 @@ namespace SixLabors.ImageSharp.Tests
{
Assert.Equal(11, image.Width);
Assert.Equal(23, image.Height);
Assert.Equal(11 * 23, image.GetPixelSpan().Length);
Assert.True(image.TryGetSinglePixelSpan(out Span<Rgba32> imageSpan));
Assert.Equal(11 * 23, imageSpan.Length);
image.ComparePixelBufferTo(color);
Assert.Equal(configuration, image.GetConfiguration());

11
tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using Xunit;
@ -17,5 +18,15 @@ namespace SixLabors.ImageSharp.Tests
image.Mutate(c => c.Resize(1000, 1000));
image.DebugSave(provider);
}
[Theory]
[WithBasicTestPatternImages(width: 10, height: 10, PixelTypes.Rgba32)]
public void GetSingleSpan(TestImageProvider<Rgba32> provider)
{
provider.LimitAllocatorBufferCapacity().InPixels(10);
using Image<Rgba32> image = provider.GetImage();
Assert.False(image.TryGetSinglePixelSpan(out Span<Rgba32> imageSpan));
Assert.False(image.Frames.RootFrame.TryGetSinglePixelSpan(out Span<Rgba32> imageFrameSpan));
}
}
}

2
tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs

@ -241,7 +241,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
private static void VerifyAllPixelsAreWhiteOrTransparent<TPixel>(Image<TPixel> image)
where TPixel : unmanaged, IPixel<TPixel>
{
Span<TPixel> data = image.Frames.RootFrame.GetPixelSpan();
Assert.True(image.Frames.RootFrame.TryGetSinglePixelSpan(out Span<TPixel> data));
var white = new Rgb24(255, 255, 255);
foreach (TPixel pixel in data)
{

3
tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

@ -244,7 +244,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
{
using (Image<TPixel> image0 = provider.GetImage())
{
var mmg = TestMemoryManager<TPixel>.CreateAsCopyOf(image0.GetPixelSpan());
Assert.True(image0.TryGetSinglePixelSpan(out Span<TPixel> imageSpan));
var mmg = TestMemoryManager<TPixel>.CreateAsCopyOf(imageSpan);
using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height))
{

11
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -417,8 +417,7 @@ namespace SixLabors.ImageSharp.Tests
Span<TPixel> expectedPixels)
where TPixel : unmanaged, IPixel<TPixel>
{
Span<TPixel> actualPixels = image.GetPixelSpan();
Assert.True(image.TryGetSinglePixelSpan(out Span<TPixel> actualPixels));
CompareBuffers(expectedPixels, actualPixels);
return image;
@ -478,7 +477,7 @@ namespace SixLabors.ImageSharp.Tests
public static ImageFrame<TPixel> ComparePixelBufferTo<TPixel>(this ImageFrame<TPixel> imageFrame, TPixel expectedPixel)
where TPixel : unmanaged, IPixel<TPixel>
{
Span<TPixel> actualPixels = imageFrame.GetPixelSpan();
Assert.True(imageFrame.TryGetSinglePixelSpan(out Span<TPixel> actualPixels));
for (int i = 0; i < actualPixels.Length; i++)
{
@ -493,8 +492,7 @@ namespace SixLabors.ImageSharp.Tests
Span<TPixel> expectedPixels)
where TPixel : unmanaged, IPixel<TPixel>
{
Span<TPixel> actual = image.GetPixelSpan();
Assert.True(image.TryGetSinglePixelSpan(out Span<TPixel> actual));
Assert.True(expectedPixels.Length == actual.Length, "Buffer sizes are not equal!");
for (int i = 0; i < expectedPixels.Length; i++)
@ -677,8 +675,7 @@ namespace SixLabors.ImageSharp.Tests
{
var image = new Image<Rgba32>(buffer.Width, buffer.Height);
Span<Rgba32> pixels = image.Frames.RootFrame.GetPixelSpan();
Assert.True(image.Frames.RootFrame.TryGetSinglePixelSpan(out Span<Rgba32> pixels));
Span<float> bufferSpan = buffer.GetSingleSpan();
for (int i = 0; i < bufferSpan.Length; i++)

6
tests/ImageSharp.Tests/TestUtilities/TestUtils.cs

@ -14,6 +14,7 @@ using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
namespace SixLabors.ImageSharp.Tests
{
@ -160,7 +161,7 @@ namespace SixLabors.ImageSharp.Tests
ImageComparer comparer = null)
where TPixel : unmanaged, IPixel<TPixel>
{
comparer??= ImageComparer.Exact;
comparer ??= ImageComparer.Exact;
using Image<TPixel> expected = provider.GetImage();
int width = expected.Width;
expected.Mutate(process);
@ -277,7 +278,8 @@ namespace SixLabors.ImageSharp.Tests
using (Image<TPixel> image0 = provider.GetImage())
{
var mmg = TestMemoryManager<TPixel>.CreateAsCopyOf(image0.GetPixelSpan());
Assert.True(image0.TryGetSinglePixelSpan(out Span<TPixel> imageSpan));
var mmg = TestMemoryManager<TPixel>.CreateAsCopyOf(imageSpan);
using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height))
{

Loading…
Cancel
Save