Browse Source

IBuffer<T>.IsMemoryOwner, Buffer2D<T>.SwapOrCopyContent()

af/merge-core
Anton Firszov 8 years ago
parent
commit
f6dd91922e
  1. 2
      src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs
  2. 2
      src/ImageSharp/Memory/BasicArrayBuffer.cs
  3. 27
      src/ImageSharp/Memory/Buffer2D{T}.cs
  4. 2
      src/ImageSharp/Memory/ConsumedBuffer.cs
  5. 8
      src/ImageSharp/Memory/IBuffer{T}.cs
  6. 5
      src/ImageSharp/Memory/ManagedBufferBase.cs
  7. 2
      src/ImageSharp/Processing/Convolution/Processors/Convolution2DProcessor.cs
  8. 2
      src/ImageSharp/Processing/Convolution/Processors/ConvolutionProcessor.cs
  9. 2
      src/ImageSharp/Processing/Effects/Processors/OilPaintingProcessor.cs
  10. 4
      src/ImageSharp/Processing/Transforms/Processors/FlipProcessor.cs
  11. 32
      tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs
  12. 337
      tests/ImageSharp.Tests/Image/ImageLoadTests.cs
  13. 63
      tests/ImageSharp.Tests/Image/ImageTests.Load_BasicCases.cs
  14. 338
      tests/ImageSharp.Tests/Image/ImageTests.Load_ComplexCases.cs
  15. 70
      tests/ImageSharp.Tests/Image/ImageTests.Save.cs
  16. 24
      tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs
  17. 102
      tests/ImageSharp.Tests/Image/ImageTests.cs
  18. 95
      tests/ImageSharp.Tests/Memory/Buffer2DTests.cs
  19. 9
      tests/ImageSharp.Tests/Memory/BufferTestSuite.cs
  20. 18
      tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs
  21. 21
      tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs
  22. 50
      tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs
  23. 38
      tests/ImageSharp.Tests/TestUtilities/TestUtils.cs

2
src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs

@ -16,7 +16,7 @@ namespace SixLabors.Memory
/// The buffer implementation of <see cref="ArrayPoolMemoryAllocator"/>.
/// In this implementation <see cref="IBuffer{T}.Memory"/> is owned.
/// </summary>
private class Buffer<T> : ManagedBufferBase<T>, IBuffer<T>
private class Buffer<T> : ManagedBufferBase<T>
where T : struct
{
/// <summary>

2
src/ImageSharp/Memory/BasicArrayBuffer.cs

@ -9,7 +9,7 @@ namespace SixLabors.Memory
/// <summary>
/// Wraps an array as an <see cref="IBuffer{T}"/> instance. In this implementation <see cref="IBuffer{T}.Memory"/> is owned.
/// </summary>
internal class BasicArrayBuffer<T> : ManagedBufferBase<T>, IBuffer<T>
internal class BasicArrayBuffer<T> : ManagedBufferBase<T>
where T : struct
{
public BasicArrayBuffer(T[] array, int length)

27
src/ImageSharp/Memory/Buffer2D{T}.cs

@ -39,6 +39,10 @@ namespace SixLabors.Memory
/// </summary>
public IBuffer<T> Buffer { get; private set; }
public Memory<T> Memory => this.Buffer.Memory;
public Span<T> Span => this.Buffer.GetSpan();
/// <summary>
/// Gets a reference to the element at the specified position.
/// </summary>
@ -65,13 +69,34 @@ namespace SixLabors.Memory
this.Buffer?.Dispose();
}
/// <summary>
/// Swaps the contents of 'destination' with 'source' if the buffers are owned (1),
/// copies the contents of 'source' to 'destination' otherwise (2). Buffers should be of same size in case 2!
/// </summary>
public static void SwapOrCopyContent(Buffer2D<T> destination, Buffer2D<T> source)
{
if (source.Buffer.IsMemoryOwner && destination.Buffer.IsMemoryOwner)
{
SwapContents(destination, source);
}
else
{
if (destination.Size() != source.Size())
{
throw new InvalidOperationException("SwapOrCopyContents(): buffers should both owned or the same size!");
}
source.Span.CopyTo(destination.Span);
}
}
/// <summary>
/// Swap the contents (<see cref="Buffer"/>, <see cref="Width"/>, <see cref="Height"/>) of the two buffers.
/// Useful to transfer the contents of a temporary <see cref="Buffer2D{T}"/> to a persistent <see cref="SixLabors.ImageSharp.ImageFrame{T}.PixelBuffer"/>
/// </summary>
/// <param name="a">The first buffer</param>
/// <param name="b">The second buffer</param>
public static void SwapContents(Buffer2D<T> a, Buffer2D<T> b)
private static void SwapContents(Buffer2D<T> a, Buffer2D<T> b)
{
Size aSize = a.Size();
Size bSize = b.Size();

2
src/ImageSharp/Memory/ConsumedBuffer.cs

@ -20,6 +20,8 @@ namespace SixLabors.Memory
public Memory<T> Memory { get; }
public bool IsMemoryOwner => false;
public Span<T> GetSpan()
{
return this.Memory.Span;

8
src/ImageSharp/Memory/IBuffer{T}.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
namespace SixLabors.Memory
{
@ -10,6 +11,8 @@ namespace SixLabors.Memory
/// Depending on it's implementation, an <see cref="IBuffer{T}"/> can (1) OWN or (2) CONSUME the <see cref="Memory{T}"/> instance it wraps.
/// For a deeper understanding of the owner/consumer model, read the following docs: <br/>
/// https://gist.github.com/GrabYourPitchforks/4c3e1935fd4d9fa2831dbfcab35dffc6
/// TODO: We need more SOC here! For owned buffers we should use <see cref="IMemoryOwner{T}"/>.
/// For the consumption case we should not use buffers at all. We need to refactor Buffer2D{T} for this.
/// </summary>
/// <typeparam name="T">The value type</typeparam>
internal interface IBuffer<T> : IDisposable
@ -20,6 +23,11 @@ namespace SixLabors.Memory
/// </summary>
Memory<T> Memory { get; }
/// <summary>
/// Gets a value indicating whether this instance is owning the <see cref="Memory"/>.
/// </summary>
bool IsMemoryOwner { get; }
/// <summary>
/// Gets the span to the memory "promised" by this buffer when it's OWNED (1).
/// Gets `this.Memory.Span` when the buffer CONSUMED (2).

5
src/ImageSharp/Memory/ManagedBufferBase.cs

@ -9,10 +9,13 @@ namespace SixLabors.Memory
/// <summary>
/// Provides a base class for <see cref="IBuffer{T}"/> implementations by implementing pinning logic for <see cref="MemoryManager{T}"/> adaption.
/// </summary>
internal abstract class ManagedBufferBase<T> : System.Buffers.MemoryManager<T>
internal abstract class ManagedBufferBase<T> : System.Buffers.MemoryManager<T>, IBuffer<T>
where T : struct
{
private GCHandle pinHandle;
public bool IsMemoryOwner => true;
/// <summary>
/// Gets the object that should be pinned.
/// </summary>

2
src/ImageSharp/Processing/Convolution/Processors/Convolution2DProcessor.cs

@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
}
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels);
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
}

2
src/ImageSharp/Processing/Convolution/Processors/ConvolutionProcessor.cs

@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors
}
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels);
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
}

2
src/ImageSharp/Processing/Effects/Processors/OilPaintingProcessor.cs

@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.Processing.Effects.Processors
}
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels);
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
}

4
src/ImageSharp/Processing/Transforms/Processors/FlipProcessor.cs

@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
altSourceRow.CopyTo(targetRow);
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels);
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
}
});
Buffer2D<TPixel>.SwapContents(source.PixelBuffer, targetPixels);
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
}
}

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

@ -6,11 +6,14 @@ using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Advanced
{
using System.Buffers;
using SixLabors.Memory;
public class AdvancedImageExtensionsTests
{
public class GetPixelMemory
@ -40,34 +43,6 @@ namespace SixLabors.ImageSharp.Tests.Advanced
}
}
class TestMemoryManager<TPixel> : MemoryManager<TPixel>
{
public TestMemoryManager(TPixel[] pixelArray)
{
this.PixelArray = pixelArray;
}
public TPixel[] PixelArray { get; }
protected override void Dispose(bool disposing)
{
}
public override Span<TPixel> GetSpan()
{
return this.PixelArray;
}
public override MemoryHandle Pin(int elementIndex = 0)
{
throw new NotImplementedException();
}
public override void Unpin()
{
throw new NotImplementedException();
}
}
[Theory]
[WithSolidFilledImages(1, 1, "Red", PixelTypes.Rgba32 | PixelTypes.Bgr24)]
@ -97,6 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Advanced
image0.ComparePixelBufferTo(externalMemory.Span);
}
}
}
[Theory]

337
tests/ImageSharp.Tests/Image/ImageLoadTests.cs

@ -1,337 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.IO;
using Moq;
using Xunit;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Tests
{
/// <summary>
/// Tests the <see cref="Image"/> class.
/// </summary>
public partial class ImageLoadTests : IDisposable
{
private readonly Mock<IFileSystem> fileSystem;
private Image<Rgba32> returnImage;
private Mock<IImageDecoder> localDecoder;
private readonly string FilePath;
private readonly IImageFormatDetector localMimeTypeDetector;
private readonly Mock<IImageFormat> localImageFormatMock;
public Configuration LocalConfiguration { get; private set; }
public byte[] Marker { get; private set; }
public MemoryStream DataStream { get; private set; }
public byte[] DecodedData { get; private set; }
public ImageLoadTests()
{
this.returnImage = new Image<Rgba32>(1, 1);
this.localImageFormatMock = new Mock<IImageFormat>();
this.localDecoder = new Mock<IImageDecoder>();
this.localMimeTypeDetector = new MockImageFormatDetector(this.localImageFormatMock.Object);
this.localDecoder.Setup(x => x.Decode<Rgba32>(It.IsAny<Configuration>(), It.IsAny<Stream>()))
.Callback<Configuration, Stream>((c, s) =>
{
using (var ms = new MemoryStream())
{
s.CopyTo(ms);
this.DecodedData = ms.ToArray();
}
})
.Returns(this.returnImage);
this.fileSystem = new Mock<IFileSystem>();
this.LocalConfiguration = new Configuration
{
FileSystem = this.fileSystem.Object
};
this.LocalConfiguration.ImageFormatsManager.AddImageFormatDetector(this.localMimeTypeDetector);
this.LocalConfiguration.ImageFormatsManager.SetDecoder(this.localImageFormatMock.Object, this.localDecoder.Object);
TestFormat.RegisterGlobalTestFormat();
this.Marker = Guid.NewGuid().ToByteArray();
this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker);
this.FilePath = Guid.NewGuid().ToString();
this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream);
TestFileSystem.RegisterGlobalTestFormat();
TestFileSystem.Global.AddFile(this.FilePath, this.DataStream);
}
[Fact]
public void LoadFromStream()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.DataStream);
Assert.NotNull(img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromNoneSeekableStream()
{
NoneSeekableStream stream = new NoneSeekableStream(this.DataStream);
Image<Rgba32> img = Image.Load<Rgba32>(stream);
Assert.NotNull(img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromStreamWithType()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.DataStream);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Rgba32>(), img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromStreamWithConfig()
{
Stream stream = new MemoryStream();
Image<Rgba32> img = Image.Load<Rgba32>(this.LocalConfiguration, stream);
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, stream));
}
[Fact]
public void LoadFromStreamWithTypeAndConfig()
{
Stream stream = new MemoryStream();
Image<Rgba32> img = Image.Load<Rgba32>(this.LocalConfiguration, stream);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, stream));
}
[Fact]
public void LoadFromStreamWithDecoder()
{
Stream stream = new MemoryStream();
Image<Rgba32> img = Image.Load<Rgba32>(stream, this.localDecoder.Object);
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, stream));
}
[Fact]
public void LoadFromStreamWithTypeAndDecoder()
{
Stream stream = new MemoryStream();
Image<Rgba32> img = Image.Load<Rgba32>(stream, this.localDecoder.Object);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, stream));
}
[Fact]
public void LoadFromBytes()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.DataStream.ToArray());
Assert.NotNull(img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromBytesWithType()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.DataStream.ToArray());
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Rgba32>(), img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromBytesWithConfig()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.LocalConfiguration, this.DataStream.ToArray());
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, It.IsAny<Stream>()));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithTypeAndConfig()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.LocalConfiguration, this.DataStream.ToArray());
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, It.IsAny<Stream>()));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithDecoder()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.DataStream.ToArray(), this.localDecoder.Object);
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, It.IsAny<Stream>()));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithTypeAndDecoder()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.DataStream.ToArray(), this.localDecoder.Object);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, It.IsAny<Stream>()));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromFile()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.DataStream);
Assert.NotNull(img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromFileWithType()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.DataStream);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Rgba32>(), img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromFileWithConfig()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.LocalConfiguration, this.FilePath);
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, this.DataStream));
}
[Fact]
public void LoadFromFileWithTypeAndConfig()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.LocalConfiguration, this.FilePath);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, this.DataStream));
}
[Fact]
public void LoadFromFileWithDecoder()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.FilePath, this.localDecoder.Object);
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, this.DataStream));
}
[Fact]
public void LoadFromFileWithTypeAndDecoder()
{
Image<Rgba32> img = Image.Load<Rgba32>(this.FilePath, this.localDecoder.Object);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, this.DataStream));
}
[Fact]
public void LoadFromPixelData_Pixels()
{
var img = Image.LoadPixelData<Rgba32>(new Rgba32[] {
Rgba32.Black, Rgba32.White,
Rgba32.White, Rgba32.Black,
}, 2, 2);
Assert.NotNull(img);
using (var px = img.Lock())
{
Assert.Equal(Rgba32.Black, px[0, 0]);
Assert.Equal(Rgba32.White, px[0, 1]);
Assert.Equal(Rgba32.White, px[1, 0]);
Assert.Equal(Rgba32.Black, px[1, 1]);
}
}
[Fact]
public void LoadFromPixelData_Bytes()
{
var img = Image.LoadPixelData<Rgba32>(new byte[] {
0,0,0,255, // 0,0
255,255,255,255, // 0,1
255,255,255,255, // 1,0
0,0,0,255, // 1,1
}, 2, 2);
Assert.NotNull(img);
using (var px = img.Lock())
{
Assert.Equal(Rgba32.Black, px[0, 0]);
Assert.Equal(Rgba32.White, px[0, 1]);
Assert.Equal(Rgba32.White, px[1, 0]);
Assert.Equal(Rgba32.Black, px[1, 1]);
}
}
[Fact]
public void LoadsImageWithoutThrowingCrcException()
{
var image1Provider = TestImageProvider<Rgba32>.File(TestImages.Png.VersioningImage1);
using (Image<Rgba32> img = image1Provider.GetImage())
{
Assert.Equal(166036, img.Frames.RootFrame.GetPixelSpan().Length);
}
}
public void Dispose()
{
// clean up the global object;
this.returnImage?.Dispose();
}
}
}

63
tests/ImageSharp.Tests/Image/ImageTests.Load_BasicCases.cs

@ -0,0 +1,63 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests
{
public partial class ImageTests
{
public class Load_BasicCases
{
[Fact]
public void ByteArray()
{
Assert.Throws<ArgumentNullException>(() =>
{
Image.Load<Rgba32>((byte[])null);
});
var file = TestFile.Create(TestImages.Bmp.Car);
using (var image = Image.Load<Rgba32>(file.Bytes))
{
Assert.Equal(600, image.Width);
Assert.Equal(450, image.Height);
}
}
[Fact]
public void FileSystemPath()
{
var file = TestFile.Create(TestImages.Bmp.Car);
using (var image = Image.Load<Rgba32>(file.FullPath))
{
Assert.Equal(600, image.Width);
Assert.Equal(450, image.Height);
}
}
[Fact]
public void FileSystemPath_FileNotFound()
{
System.IO.FileNotFoundException ex = Assert.Throws<System.IO.FileNotFoundException>(
() =>
{
Image.Load<Rgba32>(Guid.NewGuid().ToString());
});
}
[Fact]
public void FileSystemPath_NullPath()
{
ArgumentNullException ex = Assert.Throws<ArgumentNullException>(
() =>
{
Image.Load<Rgba32>((string)null);
});
}
}
}
}

338
tests/ImageSharp.Tests/Image/ImageTests.Load_ComplexCases.cs

@ -0,0 +1,338 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
using Moq;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests
{
public partial class ImageTests
{
/// <summary>
/// Tests the <see cref="Image"/> class.
/// </summary>
public class Load_ComplexCases : IDisposable
{
private readonly Mock<IFileSystem> fileSystem;
private readonly Image<Rgba32> returnImage;
private readonly Mock<IImageDecoder> localDecoder;
private readonly string FilePath;
private readonly IImageFormatDetector localMimeTypeDetector;
private readonly Mock<IImageFormat> localImageFormatMock;
public Configuration LocalConfiguration { get; private set; }
public byte[] Marker { get; private set; }
public MemoryStream DataStream { get; private set; }
public byte[] DecodedData { get; private set; }
public Load_ComplexCases()
{
this.returnImage = new Image<Rgba32>(1, 1);
this.localImageFormatMock = new Mock<IImageFormat>();
this.localDecoder = new Mock<IImageDecoder>();
this.localMimeTypeDetector = new MockImageFormatDetector(this.localImageFormatMock.Object);
this.localDecoder.Setup(x => x.Decode<Rgba32>(It.IsAny<Configuration>(), It.IsAny<Stream>()))
.Callback<Configuration, Stream>((c, s) =>
{
using (var ms = new MemoryStream())
{
s.CopyTo(ms);
this.DecodedData = ms.ToArray();
}
})
.Returns(this.returnImage);
this.fileSystem = new Mock<IFileSystem>();
this.LocalConfiguration = new Configuration
{
FileSystem = this.fileSystem.Object
};
this.LocalConfiguration.ImageFormatsManager.AddImageFormatDetector(this.localMimeTypeDetector);
this.LocalConfiguration.ImageFormatsManager.SetDecoder(this.localImageFormatMock.Object, this.localDecoder.Object);
TestFormat.RegisterGlobalTestFormat();
this.Marker = Guid.NewGuid().ToByteArray();
this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker);
this.FilePath = Guid.NewGuid().ToString();
this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream);
TestFileSystem.RegisterGlobalTestFormat();
TestFileSystem.Global.AddFile(this.FilePath, this.DataStream);
}
[Fact]
public void LoadFromStream()
{
var img = Image.Load<Rgba32>(this.DataStream);
Assert.NotNull(img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromNoneSeekableStream()
{
var stream = new NoneSeekableStream(this.DataStream);
var img = Image.Load<Rgba32>(stream);
Assert.NotNull(img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromStreamWithType()
{
var img = Image.Load<Rgba32>(this.DataStream);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Rgba32>(), img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromStreamWithConfig()
{
Stream stream = new MemoryStream();
var img = Image.Load<Rgba32>(this.LocalConfiguration, stream);
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, stream));
}
[Fact]
public void LoadFromStreamWithTypeAndConfig()
{
Stream stream = new MemoryStream();
var img = Image.Load<Rgba32>(this.LocalConfiguration, stream);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, stream));
}
[Fact]
public void LoadFromStreamWithDecoder()
{
Stream stream = new MemoryStream();
var img = Image.Load<Rgba32>(stream, this.localDecoder.Object);
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, stream));
}
[Fact]
public void LoadFromStreamWithTypeAndDecoder()
{
Stream stream = new MemoryStream();
var img = Image.Load<Rgba32>(stream, this.localDecoder.Object);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, stream));
}
[Fact]
public void LoadFromBytes()
{
var img = Image.Load<Rgba32>(this.DataStream.ToArray());
Assert.NotNull(img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromBytesWithType()
{
var img = Image.Load<Rgba32>(this.DataStream.ToArray());
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Rgba32>(), img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromBytesWithConfig()
{
var img = Image.Load<Rgba32>(this.LocalConfiguration, this.DataStream.ToArray());
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, It.IsAny<Stream>()));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithTypeAndConfig()
{
var img = Image.Load<Rgba32>(this.LocalConfiguration, this.DataStream.ToArray());
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, It.IsAny<Stream>()));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithDecoder()
{
var img = Image.Load<Rgba32>(this.DataStream.ToArray(), this.localDecoder.Object);
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, It.IsAny<Stream>()));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromBytesWithTypeAndDecoder()
{
var img = Image.Load<Rgba32>(this.DataStream.ToArray(), this.localDecoder.Object);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, It.IsAny<Stream>()));
Assert.Equal(this.DataStream.ToArray(), this.DecodedData);
}
[Fact]
public void LoadFromFile()
{
var img = Image.Load<Rgba32>(this.DataStream);
Assert.NotNull(img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromFileWithType()
{
var img = Image.Load<Rgba32>(this.DataStream);
Assert.NotNull(img);
Assert.Equal(TestFormat.GlobalTestFormat.Sample<Rgba32>(), img);
TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default);
}
[Fact]
public void LoadFromFileWithConfig()
{
var img = Image.Load<Rgba32>(this.LocalConfiguration, this.FilePath);
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, this.DataStream));
}
[Fact]
public void LoadFromFileWithTypeAndConfig()
{
var img = Image.Load<Rgba32>(this.LocalConfiguration, this.FilePath);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(this.LocalConfiguration, this.DataStream));
}
[Fact]
public void LoadFromFileWithDecoder()
{
var img = Image.Load<Rgba32>(this.FilePath, this.localDecoder.Object);
Assert.NotNull(img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, this.DataStream));
}
[Fact]
public void LoadFromFileWithTypeAndDecoder()
{
var img = Image.Load<Rgba32>(this.FilePath, this.localDecoder.Object);
Assert.NotNull(img);
Assert.Equal(this.returnImage, img);
this.localDecoder.Verify(x => x.Decode<Rgba32>(Configuration.Default, this.DataStream));
}
[Fact]
public void LoadFromPixelData_Pixels()
{
var img = Image.LoadPixelData<Rgba32>(new Rgba32[] {
Rgba32.Black, Rgba32.White,
Rgba32.White, Rgba32.Black,
}, 2, 2);
Assert.NotNull(img);
Assert.Equal(Rgba32.Black, img[0, 0]);
Assert.Equal(Rgba32.White, img[0, 1]);
Assert.Equal(Rgba32.White, img[1, 0]);
Assert.Equal(Rgba32.Black, img[1, 1]);
}
[Fact]
public void LoadFromPixelData_Bytes()
{
var img = Image.LoadPixelData<Rgba32>(new byte[] {
0,0,0,255, // 0,0
255,255,255,255, // 0,1
255,255,255,255, // 1,0
0,0,0,255, // 1,1
}, 2, 2);
Assert.NotNull(img);
Assert.Equal(Rgba32.Black, img[0, 0]);
Assert.Equal(Rgba32.White, img[0, 1]);
Assert.Equal(Rgba32.White, img[1, 0]);
Assert.Equal(Rgba32.Black, img[1, 1]);
}
[Fact]
public void LoadsImageWithoutThrowingCrcException()
{
var image1Provider = TestImageProvider<Rgba32>.File(TestImages.Png.VersioningImage1);
using (Image<Rgba32> img = image1Provider.GetImage())
{
Assert.Equal(166036, img.Frames.RootFrame.GetPixelSpan().Length);
}
}
public void Dispose()
{
// clean up the global object;
this.returnImage?.Dispose();
}
}
}
}

70
tests/ImageSharp.Tests/Image/ImageTests.Save.cs

@ -0,0 +1,70 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// ReSharper disable InconsistentNaming
using System;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
namespace SixLabors.ImageSharp.Tests
{
using SixLabors.ImageSharp.Formats;
public partial class ImageTests
{
public class Save
{
[Fact]
public void DetecedEncoding()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = System.IO.Path.Combine(dir, "DetecedEncoding.png");
using (var image = new Image<Rgba32>(10, 10))
{
image.Save(file);
}
using (var img = Image.Load(file, out IImageFormat mime))
{
Assert.Equal("image/png", mime.DefaultMimeType);
}
}
[Fact]
public void WhenExtensionIsUnknown_Throws()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = System.IO.Path.Combine(dir, "UnknownExtensionsEncoding_Throws.tmp");
NotSupportedException ex = Assert.Throws<NotSupportedException>(
() =>
{
using (var image = new Image<Rgba32>(10, 10))
{
image.Save(file);
}
});
}
[Fact]
public void SetEncoding()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = System.IO.Path.Combine(dir, "SetEncoding.dat");
using (var image = new Image<Rgba32>(10, 10))
{
image.Save(file, new PngEncoder());
}
using (var img = Image.Load(file, out var mime))
{
Assert.Equal("image/png", mime.DefaultMimeType);
}
}
}
}
}

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

@ -0,0 +1,24 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Memory;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests
{
public partial class ImageTests
{
public class WrapMemory
{
[Fact]
public void ConsumedBuffer_IsMemoryOwner_ReturnsFalse()
{
var memory = new Memory<int>(new int[55]);
var buffer = new ConsumedBuffer<int>(memory);
Assert.False(buffer.IsMemoryOwner);
}
}
}
}

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

@ -1,19 +1,17 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests
{
/// <summary>
/// Tests the <see cref="Image"/> class.
/// </summary>
public class ImageTests
public partial class ImageTests
{
public class Constructor
{
@ -64,101 +62,5 @@ namespace SixLabors.ImageSharp.Tests
}
}
}
[Fact]
public void Load_ByteArray()
{
Assert.Throws<ArgumentNullException>(() =>
{
Image.Load<Rgba32>((byte[])null);
});
TestFile file = TestFile.Create(TestImages.Bmp.Car);
using (Image<Rgba32> image = Image.Load<Rgba32>(file.Bytes))
{
Assert.Equal(600, image.Width);
Assert.Equal(450, image.Height);
}
}
[Fact]
public void Load_FileSystemPath()
{
TestFile file = TestFile.Create(TestImages.Bmp.Car);
using (Image<Rgba32> image = Image.Load<Rgba32>(file.FullPath))
{
Assert.Equal(600, image.Width);
Assert.Equal(450, image.Height);
}
}
[Fact]
public void Load_FileSystemPath_FileNotFound()
{
System.IO.FileNotFoundException ex = Assert.Throws<System.IO.FileNotFoundException>(
() =>
{
Image.Load<Rgba32>(Guid.NewGuid().ToString());
});
}
[Fact]
public void Load_FileSystemPath_NullPath()
{
ArgumentNullException ex = Assert.Throws<ArgumentNullException>(
() =>
{
Image.Load<Rgba32>((string)null);
});
}
[Fact]
public void Save_DetecedEncoding()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = System.IO.Path.Combine(dir, "Save_DetecedEncoding.png");
using (Image<Rgba32> image = new Image<Rgba32>(10, 10))
{
image.Save(file);
}
using (Image<Rgba32> img = Image.Load(file, out var mime))
{
Assert.Equal("image/png", mime.DefaultMimeType);
}
}
[Fact]
public void Save_WhenExtensionIsUnknown_Throws()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = System.IO.Path.Combine(dir, "Save_UnknownExtensionsEncoding_Throws.tmp");
NotSupportedException ex = Assert.Throws<NotSupportedException>(
() =>
{
using (Image<Rgba32> image = new Image<Rgba32>(10, 10))
{
image.Save(file);
}
});
}
[Fact]
public void Save_SetEncoding()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageTests));
string file = System.IO.Path.Combine(dir, "Save_SetEncoding.dat");
using (Image<Rgba32> image = new Image<Rgba32>(10, 10))
{
image.Save(file, new PngEncoder());
}
using (Image<Rgba32> img = Image.Load(file, out var mime))
{
Assert.Equal("image/png", mime.DefaultMimeType);
}
}
}
}

95
tests/ImageSharp.Tests/Memory/Buffer2DTests.cs

@ -1,11 +1,14 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Memory
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.ImageSharp.Tests.Common;
using SixLabors.Primitives;
@ -128,22 +131,92 @@ namespace SixLabors.ImageSharp.Tests.Memory
Assert.True(Unsafe.AreSame(ref expected, ref actual));
}
}
[Fact]
public void SwapContents()
public class SwapOrCopyContent
{
using (Buffer2D<int> a = this.MemoryAllocator.Allocate2D<int>(10, 5))
using (Buffer2D<int> b = this.MemoryAllocator.Allocate2D<int>(3, 7))
private MemoryAllocator MemoryAllocator { get; } = new MockMemoryAllocator();
[Fact]
public void WhenBothBuffersAreMemoryOwners_ShouldSwap()
{
using (Buffer2D<int> a = this.MemoryAllocator.Allocate2D<int>(10, 5))
using (Buffer2D<int> b = this.MemoryAllocator.Allocate2D<int>(3, 7))
{
IBuffer<int> aa = a.Buffer;
IBuffer<int> bb = b.Buffer;
Buffer2D<int>.SwapOrCopyContent(a, b);
Assert.Equal(bb, a.Buffer);
Assert.Equal(aa, b.Buffer);
Assert.Equal(new Size(3, 7), a.Size());
Assert.Equal(new Size(10, 5), b.Size());
}
}
[Fact]
public void WhenDestIsNotMemoryOwner_SameSize_ShouldCopy()
{
var data = new Rgba32[3 * 7];
var color = new Rgba32(1, 2, 3, 4);
var mmg = new TestMemoryManager<Rgba32>(data);
var aBuff = new ConsumedBuffer<Rgba32>(mmg.Memory);
using (Buffer2D<Rgba32> a = new Buffer2D<Rgba32>(aBuff, 3, 7))
{
IBuffer<Rgba32> aa = a.Buffer;
// Precondition:
Assert.Equal(aBuff, aa);
using (Buffer2D<Rgba32> b = this.MemoryAllocator.Allocate2D<Rgba32>(3, 7))
{
IBuffer<Rgba32> bb = b.Buffer;
bb.GetSpan()[10] = color;
// Act:
Buffer2D<Rgba32>.SwapOrCopyContent(a, b);
// Assert:
Assert.Equal(aBuff, a.Buffer);
Assert.Equal(bb, b.Buffer);
}
// Assert:
Assert.Equal(color, a.Buffer.GetSpan()[10]);
}
}
[Fact]
public void WhenDestIsNotMemoryOwner_DifferentSize_Throws()
{
IBuffer<int> aa = a.Buffer;
IBuffer<int> bb = b.Buffer;
var data = new Rgba32[3 * 7];
var color = new Rgba32(1, 2, 3, 4);
data[10] = color;
Buffer2D<int>.SwapContents(a, b);
var mmg = new TestMemoryManager<Rgba32>(data);
var aBuff = new ConsumedBuffer<Rgba32>(mmg.Memory);
Assert.Equal(bb, a.Buffer);
Assert.Equal(new Size(3, 7), a.Size());
Assert.Equal(new Size(10, 5), b.Size());
using (Buffer2D<Rgba32> a = new Buffer2D<Rgba32>(aBuff, 3, 7))
{
IBuffer<Rgba32> aa = a.Buffer;
using (Buffer2D<Rgba32> b = this.MemoryAllocator.Allocate2D<Rgba32>(3, 8))
{
IBuffer<Rgba32> bb = b.Buffer;
Assert.ThrowsAny<InvalidOperationException>(
() =>
{
Buffer2D<Rgba32>.SwapOrCopyContent(a, b);
});
}
Assert.Equal(color, a.Buffer.GetSpan()[10]);
}
}
}
}
}

9
tests/ImageSharp.Tests/Memory/BufferTestSuite.cs

@ -64,6 +64,15 @@ namespace SixLabors.ImageSharp.Tests.Memory
public static readonly TheoryData<int> LenthValues = new TheoryData<int> { 0, 1, 7, 1023, 1024 };
[Fact]
public void IsMemoryOwner()
{
using (IBuffer<float> buffer = this.MemoryAllocator.Allocate<float>(42))
{
Assert.True(buffer.IsMemoryOwner);
}
}
[Theory]
[MemberData(nameof(LenthValues))]
public void HasCorrectLength_byte(int desiredLength)

18
tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs

@ -7,9 +7,12 @@ using SixLabors.ImageSharp.Processing.Convolution;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.Primitives;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
{
using SixLabors.ImageSharp.Advanced;
public class DetectEdgesTest : FileTestBase
{
private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.001f);
@ -30,6 +33,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution
EdgeDetectionOperators.Sobel
};
[Theory]
[WithFileCollection(nameof(CommonTestImages), DefaultPixelType)]
public void DetectEdges_WorksOnWrappedMemoryImage<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
provider.RunValidatingProcessorTestOnWrappedMemoryImage(
ctx =>
{
Size size = ctx.GetCurrentSize();
var bounds = new Rectangle(10, 10, size.Width / 2, size.Height / 2);
ctx.DetectEdges(bounds);
},
testName: nameof(this.DetectEdges_InBox));
}
[Theory]
[WithTestPatternImages(nameof(DetectEdgesFilters), 100, 100, DefaultPixelType)]
[WithFileCollection(nameof(CommonTestImages), nameof(DetectEdgesFilters), DefaultPixelType)]

21
tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs

@ -5,6 +5,7 @@ using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
{
@ -23,15 +24,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
};
[Theory]
[WithFileCollection(nameof(FlipFiles), nameof(FlipValues), DefaultPixelType)]
public void ImageShouldFlip<TPixel>(TestImageProvider<TPixel> provider, FlipMode flipType)
[WithTestPatternImages(nameof(FlipValues), 53, 37, DefaultPixelType)]
[WithTestPatternImages(nameof(FlipValues), 17, 32, DefaultPixelType)]
public void Flip<TPixel>(TestImageProvider<TPixel> provider, FlipMode flipMode)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x.Flip(flipType));
image.DebugSave(provider, flipType);
}
provider.RunValidatingProcessorTest(ctx => ctx.Flip(flipMode), testOutputDetails: flipMode);
}
[Theory]
[WithTestPatternImages(nameof(FlipValues), 53, 37, DefaultPixelType)]
[WithTestPatternImages(nameof(FlipValues), 17, 32, DefaultPixelType)]
public void Flip_WorksOnWrappedMemoryImage<TPixel>(TestImageProvider<TPixel> provider, FlipMode flipMode)
where TPixel : struct, IPixel<TPixel>
{
provider.RunValidatingProcessorTestOnWrappedMemoryImage(ctx => ctx.Flip(flipMode), testOutputDetails: flipMode);
}
}
}

50
tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs

@ -0,0 +1,50 @@
using System;
using System.Buffers;
namespace SixLabors.ImageSharp.Tests
{
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
class TestMemoryManager<T> : MemoryManager<T>
where T : struct, IPixel<T>
{
public TestMemoryManager(T[] pixelArray)
{
this.PixelArray = pixelArray;
}
public T[] PixelArray { get; }
protected override void Dispose(bool disposing)
{
}
public override Span<T> GetSpan()
{
return this.PixelArray;
}
public override MemoryHandle Pin(int elementIndex = 0)
{
throw new NotImplementedException();
}
public override void Unpin()
{
throw new NotImplementedException();
}
public static TestMemoryManager<T> CreateAsCopyOfPixelData(Span<T> pixelData)
{
var pixelArray = new T[pixelData.Length];
pixelData.CopyTo(pixelArray);
return new TestMemoryManager<T>(pixelArray);
}
public static TestMemoryManager<T> CreateAsCopyOfPixelData(Image<T> image)
{
return CreateAsCopyOfPixelData(image.GetPixelSpan());
}
}
}

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

@ -14,6 +14,8 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Tests
{
using SixLabors.ImageSharp.Advanced;
/// <summary>
/// Various utility and extension methods.
/// </summary>
@ -186,6 +188,42 @@ namespace SixLabors.ImageSharp.Tests
}
}
public static void RunValidatingProcessorTestOnWrappedMemoryImage<TPixel>(
this TestImageProvider<TPixel> provider,
Action<IImageProcessingContext<TPixel>> process,
object testOutputDetails = null,
ImageComparer comparer = null,
string testName = null)
where TPixel : struct, IPixel<TPixel>
{
if (comparer == null)
{
comparer = ImageComparer.TolerantPercentage(0.001f);
}
if (testName != null)
{
provider.Utility.TestName = testName;
}
using (Image<TPixel> image0 = provider.GetImage())
{
var mmg = TestMemoryManager<TPixel>.CreateAsCopyOfPixelData(image0.GetPixelSpan());
using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height))
{
image1.Mutate(process);
image1.DebugSave(provider, testOutputDetails);
// TODO: Investigate the cause of pixel inaccuracies under Linux
if (TestEnvironment.IsWindows)
{
image1.CompareToReferenceOutput(comparer, provider, testOutputDetails);
}
}
}
}
/// <summary>
/// Same as <see cref="RunValidatingProcessorTest{TPixel}"/> but with an additional <see cref="Rectangle"/> parameter passed to 'process'
/// </summary>

Loading…
Cancel
Save