Browse Source

Use Configuration over MemoryManager for ImageFrame<TPixel>

pull/593/head
James Jackson-South 8 years ago
parent
commit
71d5819d94
  1. 2
      src/ImageSharp/Configuration.cs
  2. 15
      src/ImageSharp/ImageFrame.LoadPixelData.cs
  3. 2
      src/ImageSharp/ImageFrameCollection.cs
  4. 85
      src/ImageSharp/ImageFrame{TPixel}.cs
  5. 2
      src/ImageSharp/Image{TPixel}.cs
  6. 2
      src/ImageSharp/Processing/Transforms/Processors/AffineTransformProcessor.cs
  7. 2
      src/ImageSharp/Processing/Transforms/Processors/CropProcessor.cs
  8. 2
      src/ImageSharp/Processing/Transforms/Processors/ProjectiveTransformProcessor.cs
  9. 2
      src/ImageSharp/Processing/Transforms/Processors/ResizeProcessor.cs
  10. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs
  11. 40
      tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs

2
src/ImageSharp/Configuration.cs

@ -18,7 +18,7 @@ using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Provides initialization code which allows extending the library.
/// Provides configuration code which allows altering default behaviour or extending the library.
/// </summary>
public sealed class Configuration
{

15
src/ImageSharp/ImageFrame.LoadPixelData.cs

@ -4,7 +4,6 @@
using System;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
@ -12,37 +11,37 @@ namespace SixLabors.ImageSharp
/// <content>
/// Adds static methods allowing the creation of new image from raw pixel data.
/// </content>
internal static partial class ImageFrame
internal static class ImageFrame
{
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array in <typeparamref name="TPixel"/> format.
/// </summary>
/// <param name="memoryManager">The memory manager to use for allocations</param>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static ImageFrame<TPixel> LoadPixelData<TPixel>(MemoryManager memoryManager, ReadOnlySpan<byte> data, int width, int height)
public static ImageFrame<TPixel> LoadPixelData<TPixel>(Configuration configuration, ReadOnlySpan<byte> data, int width, int height)
where TPixel : struct, IPixel<TPixel>
=> LoadPixelData(memoryManager, MemoryMarshal.Cast<byte, TPixel>(data), width, height);
=> LoadPixelData(configuration, MemoryMarshal.Cast<byte, TPixel>(data), width, height);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the raw <typeparamref name="TPixel"/> data.
/// </summary>
/// <param name="memoryManager">The memory manager to use for allocations</param>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="data">The Span containing the image Pixel data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static ImageFrame<TPixel> LoadPixelData<TPixel>(MemoryManager memoryManager, ReadOnlySpan<TPixel> data, int width, int height)
public static ImageFrame<TPixel> LoadPixelData<TPixel>(Configuration configuration, ReadOnlySpan<TPixel> data, int width, int height)
where TPixel : struct, IPixel<TPixel>
{
int count = width * height;
Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data));
var image = new ImageFrame<TPixel>(memoryManager, width, height);
var image = new ImageFrame<TPixel>(configuration, width, height);
data.Slice(0, count).CopyTo(image.GetPixelSpan());

2
src/ImageSharp/ImageFrameCollection.cs

@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(source, nameof(source));
var frame = ImageFrame.LoadPixelData(
this.parent.GetMemoryManager(),
this.parent.GetConfiguration(),
new ReadOnlySpan<TPixel>(source),
this.RootFrame.Width,
this.RootFrame.Height);

85
src/ImageSharp/ImageFrame{TPixel}.cs

@ -4,7 +4,6 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
@ -19,53 +18,61 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public sealed class ImageFrame<TPixel> : IPixelSource<TPixel>, IDisposable
where TPixel : struct, IPixel<TPixel> {
where TPixel : struct, IPixel<TPixel>
{
private readonly Configuration configuration;
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
internal ImageFrame(MemoryManager memoryManager, int width, int height)
: this(memoryManager, width, height, new ImageFrameMetaData()) {
internal ImageFrame(Configuration configuration, int width, int height)
: this(configuration, width, height, new ImageFrameMetaData())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="size">The <see cref="Size"/> of the frame.</param>
/// <param name="metaData">The meta data.</param>
internal ImageFrame(Configuration configuration, Size size, ImageFrameMetaData metaData)
: this(configuration, size.Width, size.Height, metaData)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metaData">The meta data.</param>
internal ImageFrame(MemoryManager memoryManager, int width, int height, ImageFrameMetaData metaData)
internal ImageFrame(Configuration configuration, int width, int height, ImageFrameMetaData metaData)
: this(configuration, width, height, default, metaData)
{
Guard.NotNull(memoryManager, nameof(memoryManager));
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
Guard.NotNull(metaData, nameof(metaData));
this.MemoryManager = memoryManager;
this.PixelBuffer = memoryManager.AllocateClean2D<TPixel>(width, height);
this.MetaData = metaData;
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The <see cref="Configuration"/> to use for buffer allocation and parallel options to clear the buffer with.</param>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="backgroundColor">The color to clear the image with.</param>
internal ImageFrame(Configuration configuration, int width, int height, TPixel backgroundColor)
: this(configuration, width, height, backgroundColor, new ImageFrameMetaData()) {
: this(configuration, width, height, backgroundColor, new ImageFrameMetaData())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class.
/// </summary>
/// <param name="configuration">The <see cref="Configuration"/> to use for buffer allocation and parallel options to clear the buffer with.</param>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="backgroundColor">The color to clear the image with.</param>
@ -77,31 +84,31 @@ namespace SixLabors.ImageSharp
Guard.MustBeGreaterThan(height, 0, nameof(height));
Guard.NotNull(metaData, nameof(metaData));
this.configuration = configuration;
this.MemoryManager = configuration.MemoryManager;
this.PixelBuffer = this.MemoryManager.Allocate2D<TPixel>(width, height, false);
this.Clear(configuration.ParallelOptions, backgroundColor);
this.MetaData = metaData;
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="size">The <see cref="Size"/> of the frame.</param>
/// <param name="metaData">The meta data.</param>
internal ImageFrame(MemoryManager memoryManager, Size size, ImageFrameMetaData metaData)
: this(memoryManager, size.Width, size.Height, metaData) {
if (!default(TPixel).Equals(backgroundColor))
{
this.Clear(configuration.ParallelOptions, backgroundColor);
}
this.MetaData = metaData;
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class.
/// </summary>
/// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="source">The source.</param>
internal ImageFrame(MemoryManager memoryManager, ImageFrame<TPixel> source)
internal ImageFrame(Configuration configuration, ImageFrame<TPixel> source)
{
this.MemoryManager = memoryManager;
this.PixelBuffer = memoryManager.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(source, nameof(source));
this.configuration = configuration;
this.MemoryManager = configuration.MemoryManager;
this.PixelBuffer = this.MemoryManager.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
source.PixelBuffer.Span.CopyTo(this.PixelBuffer.Span);
this.MetaData = source.MetaData.Clone();
}
@ -276,13 +283,12 @@ namespace SixLabors.ImageSharp
return this.Clone() as ImageFrame<TPixel2>;
}
var target = new ImageFrame<TPixel2>(this.MemoryManager, this.Width, this.Height, this.MetaData.Clone());
var target = new ImageFrame<TPixel2>(this.configuration, this.Width, this.Height, this.MetaData.Clone());
// TODO: ImageFrame has no visibility of the current configuration. It should have.
ParallelFor.WithTemporaryBuffer(
0,
this.Height,
Configuration.Default,
this.configuration,
this.Width,
(int y, IBuffer<Vector4> tempRowBuffer) =>
{
@ -302,12 +308,13 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <param name="parallelOptions">The parallel options.</param>
/// <param name="value">The value to initialize the bitmap with.</param>
internal void Clear(ParallelOptions parallelOptions, TPixel value) {
internal void Clear(ParallelOptions parallelOptions, TPixel value)
{
Parallel.For(
0,
this.Height,
parallelOptions,
(int y) =>
y =>
{
Span<TPixel> targetRow = this.GetPixelRowSpan(y);
targetRow.Fill(value);
@ -320,7 +327,7 @@ namespace SixLabors.ImageSharp
/// <returns>The <see cref="ImageFrame{TPixel}"/></returns>
internal ImageFrame<TPixel> Clone()
{
return new ImageFrame<TPixel>(this.MemoryManager, this);
return new ImageFrame<TPixel>(this.configuration, this);
}
/// <inheritdoc/>

2
src/ImageSharp/Image{TPixel}.cs

@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp
this.configuration = configuration ?? Configuration.Default;
this.PixelType = new PixelTypeInfo(Unsafe.SizeOf<TPixel>() * 8);
this.MetaData = metadata ?? new ImageMetaData();
this.frames = new ImageFrameCollection<TPixel>(this, width, height, default(TPixel));
this.frames = new ImageFrameCollection<TPixel>(this, width, height, default);
}
/// <summary>

2
src/ImageSharp/Processing/Transforms/Processors/AffineTransformProcessor.cs

@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
{
// We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable<ImageFrame<TPixel>> frames =
source.Frames.Select(x => new ImageFrame<TPixel>(source.GetMemoryManager(), this.TargetDimensions, x.MetaData.Clone()));
source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.TargetDimensions, x.MetaData.Clone()));
// Use the overload to prevent an extra frame being added
return new Image<TPixel>(source.GetConfiguration(), source.MetaData.Clone(), frames);

2
src/ImageSharp/Processing/Transforms/Processors/CropProcessor.cs

@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
protected override Image<TPixel> CreateDestination(Image<TPixel> source, Rectangle sourceRectangle)
{
// We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable<ImageFrame<TPixel>> frames = source.Frames.Select(x => new ImageFrame<TPixel>(source.GetMemoryManager(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.Clone()));
IEnumerable<ImageFrame<TPixel>> frames = source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.Clone()));
// Use the overload to prevent an extra frame being added
return new Image<TPixel>(source.GetConfiguration(), source.MetaData.Clone(), frames);

2
src/ImageSharp/Processing/Transforms/Processors/ProjectiveTransformProcessor.cs

@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
{
// We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable<ImageFrame<TPixel>> frames =
source.Frames.Select(x => new ImageFrame<TPixel>(source.GetMemoryManager(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.Clone()));
source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.Clone()));
// Use the overload to prevent an extra frame being added
return new Image<TPixel>(source.GetConfiguration(), source.MetaData.Clone(), frames);

2
src/ImageSharp/Processing/Transforms/Processors/ResizeProcessor.cs

@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
protected override Image<TPixel> CreateDestination(Image<TPixel> source, Rectangle sourceRectangle)
{
// We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable<ImageFrame<TPixel>> frames = source.Frames.Select(x => new ImageFrame<TPixel>(source.GetMemoryManager(), this.Width, this.Height, x.MetaData.Clone()));
IEnumerable<ImageFrame<TPixel>> frames = source.Frames.Select(x => new ImageFrame<TPixel>(source.GetConfiguration(), this.Width, this.Height, x.MetaData.Clone()));
// Use the overload to prevent an extra frame being added
return new Image<TPixel>(source.GetConfiguration(), source.MetaData.Clone(), frames);

2
tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
string imageFile = provider.SourceFileOrDescription;
using (PdfJsJpegDecoderCore decoder = JpegFixture.ParsePdfJsStream(imageFile))
using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryManager, decoder))
using (var imageFrame = new ImageFrame<Rgba32>(Configuration.Default.MemoryManager, decoder.ImageWidth, decoder.ImageHeight))
using (var imageFrame = new ImageFrame<Rgba32>(Configuration.Default, decoder.ImageWidth, decoder.ImageHeight))
{
pp.DoPostProcessorStep(imageFrame);

40
tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs

@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests
{
ArgumentException ex = Assert.Throws<ArgumentException>(() =>
{
this.collection.AddFrame(new ImageFrame<Rgba32>(Configuration.Default.MemoryManager, 1, 1));
this.collection.AddFrame(new ImageFrame<Rgba32>(Configuration.Default, 1, 1));
});
Assert.StartsWith("Frame must have the same dimensions as the image.", ex.Message);
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests
{
ArgumentException ex = Assert.Throws<ArgumentException>(() =>
{
this.collection.InsertFrame(1, new ImageFrame<Rgba32>(Configuration.Default.MemoryManager, 1, 1));
this.collection.InsertFrame(1, new ImageFrame<Rgba32>(Configuration.Default, 1, 1));
});
Assert.StartsWith("Frame must have the same dimensions as the image.", ex.Message);
@ -102,8 +102,8 @@ namespace SixLabors.ImageSharp.Tests
ArgumentException ex = Assert.Throws<ArgumentException>(() =>
{
var collection = new ImageFrameCollection<Rgba32>(this.image, new[] {
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,1,1),
new ImageFrame<Rgba32>(Configuration.Default,10,10),
new ImageFrame<Rgba32>(Configuration.Default,1,1)
});
});
@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests
public void RemoveAtFrame_ThrowIfRemovingLastFrame()
{
var collection = new ImageFrameCollection<Rgba32>(this.image, new[] {
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10)
new ImageFrame<Rgba32>(Configuration.Default,10,10)
});
InvalidOperationException ex = Assert.Throws<InvalidOperationException>(() =>
@ -129,8 +129,8 @@ namespace SixLabors.ImageSharp.Tests
{
var collection = new ImageFrameCollection<Rgba32>(this.image, new[] {
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default,10,10),
new ImageFrame<Rgba32>(Configuration.Default,10,10)
});
collection.RemoveFrame(0);
@ -141,8 +141,8 @@ namespace SixLabors.ImageSharp.Tests
public void RootFrameIsFrameAtIndexZero()
{
var collection = new ImageFrameCollection<Rgba32>(this.image, new[] {
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default,10,10),
new ImageFrame<Rgba32>(Configuration.Default,10,10)
});
Assert.Equal(collection.RootFrame, collection[0]);
@ -152,8 +152,8 @@ namespace SixLabors.ImageSharp.Tests
public void ConstructorPopulatesFrames()
{
var collection = new ImageFrameCollection<Rgba32>(this.image, new[] {
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default,10,10),
new ImageFrame<Rgba32>(Configuration.Default,10,10)
});
Assert.Equal(2, collection.Count);
@ -163,8 +163,8 @@ namespace SixLabors.ImageSharp.Tests
public void DisposeClearsCollection()
{
var collection = new ImageFrameCollection<Rgba32>(this.image, new[] {
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default,10,10),
new ImageFrame<Rgba32>(Configuration.Default,10,10)
});
collection.Dispose();
@ -176,8 +176,8 @@ namespace SixLabors.ImageSharp.Tests
public void Dispose_DisposesAllInnerFrames()
{
var collection = new ImageFrameCollection<Rgba32>(this.image, new[] {
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default.MemoryManager,10,10),
new ImageFrame<Rgba32>(Configuration.Default,10,10),
new ImageFrame<Rgba32>(Configuration.Default,10,10)
});
IPixelSource<Rgba32>[] framesSnapShot = collection.OfType<IPixelSource<Rgba32>>().ToArray();
@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Tests
{
using (Image<TPixel> img = provider.GetImage())
{
img.Frames.AddFrame(new ImageFrame<TPixel>(Configuration.Default.MemoryManager, 10, 10));// add a frame anyway
img.Frames.AddFrame(new ImageFrame<TPixel>(Configuration.Default, 10, 10));// add a frame anyway
using (Image<TPixel> cloned = img.Frames.CloneFrame(0))
{
Assert.Equal(2, img.Frames.Count);
@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.Tests
{
var sourcePixelData = img.GetPixelSpan().ToArray();
img.Frames.AddFrame(new ImageFrame<TPixel>(Configuration.Default.MemoryManager, 10, 10));
img.Frames.AddFrame(new ImageFrame<TPixel>(Configuration.Default, 10, 10));
using (Image<TPixel> cloned = img.Frames.ExportFrame(0))
{
Assert.Equal(1, img.Frames.Count);
@ -254,7 +254,7 @@ namespace SixLabors.ImageSharp.Tests
public void AddFrame_clones_sourceFrame()
{
var pixelData = this.image.Frames.RootFrame.GetPixelSpan().ToArray();
var otherFRame = new ImageFrame<Rgba32>(Configuration.Default.MemoryManager, 10, 10);
var otherFRame = new ImageFrame<Rgba32>(Configuration.Default, 10, 10);
var addedFrame = this.image.Frames.AddFrame(otherFRame);
addedFrame.ComparePixelBufferTo(otherFRame.GetPixelSpan());
Assert.NotEqual(otherFRame, addedFrame);
@ -264,7 +264,7 @@ namespace SixLabors.ImageSharp.Tests
public void InsertFrame_clones_sourceFrame()
{
var pixelData = this.image.Frames.RootFrame.GetPixelSpan().ToArray();
var otherFRame = new ImageFrame<Rgba32>(Configuration.Default.MemoryManager, 10, 10);
var otherFRame = new ImageFrame<Rgba32>(Configuration.Default, 10, 10);
var addedFrame = this.image.Frames.InsertFrame(0, otherFRame);
addedFrame.ComparePixelBufferTo(otherFRame.GetPixelSpan());
Assert.NotEqual(otherFRame, addedFrame);
@ -318,7 +318,7 @@ namespace SixLabors.ImageSharp.Tests
this.image.Frames.CreateFrame();
}
var frame = new ImageFrame<Rgba32>(Configuration.Default.MemoryManager, 10, 10);
var frame = new ImageFrame<Rgba32>(Configuration.Default, 10, 10);
Assert.False(this.image.Frames.Contains(frame));
}

Loading…
Cancel
Save