mirror of https://github.com/SixLabors/ImageSharp
5 changed files with 185 additions and 31 deletions
@ -0,0 +1,63 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using SixLabors.Primitives; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Memory |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents a rectangular area inside a 2D memory buffer (<see cref="Buffer2D{T}"/>).
|
||||
|
/// This type is kind-of 2D Span, but it can live on heap.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">The element type</typeparam>
|
||||
|
internal struct BufferArea<T> |
||||
|
where T : struct |
||||
|
{ |
||||
|
public readonly Rectangle Rectangle; |
||||
|
|
||||
|
public BufferArea(IBuffer2D<T> destinationBuffer, Rectangle rectangle) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThanOrEqualTo(rectangle.X, 0, nameof(rectangle)); |
||||
|
Guard.MustBeGreaterThanOrEqualTo(rectangle.Y, 0, nameof(rectangle)); |
||||
|
Guard.MustBeLessThan(rectangle.Width, destinationBuffer.Width, nameof(rectangle)); |
||||
|
Guard.MustBeLessThan(rectangle.Height, destinationBuffer.Height, nameof(rectangle)); |
||||
|
|
||||
|
this.DestinationBuffer = destinationBuffer; |
||||
|
this.Rectangle = rectangle; |
||||
|
} |
||||
|
|
||||
|
public BufferArea(IBuffer2D<T> destinationBuffer) |
||||
|
: this(destinationBuffer, destinationBuffer.FullRectangle()) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public IBuffer2D<T> DestinationBuffer { get; } |
||||
|
|
||||
|
public Size Size => this.Rectangle.Size; |
||||
|
|
||||
|
public ref T this[int x, int y] => ref this.DestinationBuffer.Span[this.GetIndexOf(x, y)]; |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public Span<T> GetRowSpan(int y) |
||||
|
{ |
||||
|
int yy = this.GetRowIndex(y); |
||||
|
int xx = this.Rectangle.X; |
||||
|
int width = this.Rectangle.Width; |
||||
|
|
||||
|
return this.DestinationBuffer.Span.Slice(yy + xx, width); |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private int GetIndexOf(int x, int y) |
||||
|
{ |
||||
|
int yy = this.GetRowIndex(y); |
||||
|
int xx = this.Rectangle.X + x; |
||||
|
return yy + xx; |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
private int GetRowIndex(int y) |
||||
|
{ |
||||
|
return (y + this.Rectangle.Y) * this.DestinationBuffer.Width; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,30 +0,0 @@ |
|||||
using SixLabors.Primitives; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Memory |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Represents a rectangular area inside a 2D memory buffer. (Most commonly <see cref="Buffer2D{T}"/>)
|
|
||||
/// This type is kind-of 2D Span.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="T">The element type</typeparam>
|
|
||||
internal struct BufferArea2D<T> |
|
||||
where T : struct |
|
||||
{ |
|
||||
public IBuffer2D<T> DestinationBuffer { get; } |
|
||||
|
|
||||
public readonly Rectangle Rectangle; |
|
||||
|
|
||||
public BufferArea2D(IBuffer2D<T> destinationBuffer, Rectangle rectangle) |
|
||||
{ |
|
||||
this.DestinationBuffer = destinationBuffer; |
|
||||
this.Rectangle = rectangle; |
|
||||
} |
|
||||
|
|
||||
public BufferArea2D(Buffer2D<T> destinationBuffer) |
|
||||
: this(destinationBuffer, destinationBuffer.FullRectangle()) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public Size Size => this.Rectangle.Size; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,102 @@ |
|||||
|
// ReSharper disable InconsistentNaming
|
||||
|
namespace SixLabors.ImageSharp.Tests.Memory |
||||
|
{ |
||||
|
using System; |
||||
|
|
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
using SixLabors.Primitives; |
||||
|
|
||||
|
using Xunit; |
||||
|
|
||||
|
public class BufferAreaTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Construct() |
||||
|
{ |
||||
|
using (var buffer = new Buffer2D<int>(10, 20)) |
||||
|
{ |
||||
|
var rectangle = new Rectangle(3,2, 5, 6); |
||||
|
var area = new BufferArea<int>(buffer, rectangle); |
||||
|
|
||||
|
Assert.Equal(buffer, area.DestinationBuffer); |
||||
|
Assert.Equal(rectangle, area.Rectangle); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static Buffer2D<int> CreateTestBuffer(int w, int h) |
||||
|
{ |
||||
|
var buffer = new Buffer2D<int>(w, h); |
||||
|
for (int y = 0; y < h; y++) |
||||
|
{ |
||||
|
for (int x = 0; x < w; x++) |
||||
|
{ |
||||
|
buffer[x, y] = y * 100 + x; |
||||
|
} |
||||
|
} |
||||
|
return buffer; |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData(-1, 1, 0, 0)] |
||||
|
[InlineData(1, -1, 0, 0)] |
||||
|
[InlineData(0, 0, 1, 0)] |
||||
|
[InlineData(0, 0, 0, 42)] |
||||
|
public void Construct_WhenRectangleIsOutsideOfBufferBoundaries_Throws(int dx, int dy, int dWidth, int dHeight) |
||||
|
{ |
||||
|
using (var buffer = new Buffer2D<int>(10, 20)) |
||||
|
{ |
||||
|
Rectangle r = buffer.FullRectangle(); |
||||
|
|
||||
|
r = new Rectangle(r.X+dx, r.Y+dy, r.Width + dWidth, r.Height + dHeight ); |
||||
|
|
||||
|
Assert.ThrowsAny<ArgumentException>( |
||||
|
() => |
||||
|
{ |
||||
|
var area = new BufferArea<int>(buffer, r); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData(2, 3, 2, 2)] |
||||
|
[InlineData(5, 4, 3, 2)] |
||||
|
public void Indexer(int rx, int ry, int x, int y) |
||||
|
{ |
||||
|
using (Buffer2D<int> buffer = CreateTestBuffer(20, 30)) |
||||
|
{ |
||||
|
Rectangle r = new Rectangle(rx, ry, 5, 6); |
||||
|
|
||||
|
BufferArea<int> area = buffer.GetArea(r); |
||||
|
|
||||
|
int value = area[x, y]; |
||||
|
int expected = (ry + y) * 100 + rx + x; |
||||
|
Assert.Equal(expected, value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData(2, 3, 2, 5, 6)] |
||||
|
[InlineData(5, 4, 3, 6, 5)] |
||||
|
public void GetRowSpan(int rx, int ry, int y, int w, int h) |
||||
|
{ |
||||
|
using (Buffer2D<int> buffer = CreateTestBuffer(20, 30)) |
||||
|
{ |
||||
|
Rectangle r = new Rectangle(rx, ry, w, h); |
||||
|
|
||||
|
BufferArea<int> area = buffer.GetArea(r); |
||||
|
|
||||
|
Span<int> span = area.GetRowSpan(y); |
||||
|
|
||||
|
Assert.Equal(w, span.Length); |
||||
|
|
||||
|
for (int i = 0; i < w; i++) |
||||
|
{ |
||||
|
int expected = (ry + y) * 100 + rx + i; |
||||
|
int value = span[i]; |
||||
|
|
||||
|
Assert.Equal(expected, value); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue