Browse Source

moar RowInterval stuff

af/merge-core
Anton Firszov 7 years ago
parent
commit
398736a09b
  1. 37
      src/ImageSharp/Memory/RowInterval.cs
  2. 43
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
  3. 49
      tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs

37
src/ImageSharp/Memory/RowInterval.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory
@ -8,7 +10,7 @@ namespace SixLabors.ImageSharp.Memory
/// <summary>
/// Represents an interval of rows in a <see cref="Rectangle"/> and/or <see cref="Buffer2D{T}"/>
/// </summary>
internal readonly struct RowInterval
internal readonly struct RowInterval : IEquatable<RowInterval>
{
/// <summary>
/// Initializes a new instance of the <see cref="RowInterval"/> struct.
@ -36,7 +38,40 @@ namespace SixLabors.ImageSharp.Memory
/// </summary>
public int Height => this.Max - this.Min;
public static bool operator ==(RowInterval left, RowInterval right)
{
return left.Equals(right);
}
public static bool operator !=(RowInterval left, RowInterval right)
{
return !left.Equals(right);
}
/// <inheritdoc />
public override string ToString() => $"RowInterval [{this.Min}->{this.Max}]";
public RowInterval Slice(int start) => new RowInterval(this.Min + start, this.Max);
public RowInterval Slice(int start, int length) => new RowInterval(this.Min + start, this.Min + start + length);
public bool Equals(RowInterval other)
{
return this.Min == other.Min && this.Max == other.Max;
}
public override bool Equals(object obj)
{
return !ReferenceEquals(null, obj) && obj is RowInterval other && this.Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return (this.Min * 397) ^ this.Max;
}
}
}
}

43
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

@ -45,6 +45,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly int windowHeight;
private RowInterval currentWindow;
public ResizeWorker(
Configuration configuration,
BufferArea<TPixel> source,
@ -82,14 +84,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width);
this.tempColumnBuffer = configuration.MemoryAllocator.Allocate<Vector4>(destWidth);
this.CurrentMinY = 0;
this.CurrentMaxY = this.windowHeight;
this.currentWindow = new RowInterval(0, this.windowHeight);
}
public int CurrentMaxY { get; private set; }
public int CurrentMinY { get; private set; }
public void Dispose()
{
this.buffer.Dispose();
@ -100,18 +97,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<Vector4> GetColumnSpan(int x, int startY)
{
return this.buffer.GetRowSpan(x).Slice(startY - this.CurrentMinY);
return this.buffer.GetRowSpan(x).Slice(startY - this.currentWindow.Min);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<Vector4> GetColumnSpan(int x)
{
return this.buffer.GetRowSpan(x);
}
public void Initialize()
{
this.CalculateFirstPassValues(0, this.windowHeight);
this.CalculateFirstPassValues(this.currentWindow);
}
public void FillDestinationPixels(int minY, int maxY, int startY, Buffer2D<TPixel> destination)
@ -123,14 +115,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
// Ensure offsets are normalized for cropping and padding.
ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY);
while (kernel.StartIndex + kernel.Length > this.CurrentMaxY)
while (kernel.StartIndex + kernel.Length > this.currentWindow.Max)
{
this.Slide();
}
ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan);
int top = kernel.StartIndex - this.CurrentMinY;
int top = kernel.StartIndex - this.currentWindow.Min;
for (int x = 0; x < this.destWidth; x++)
{
@ -146,17 +138,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
}
}
public void Slide()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Span<Vector4> GetColumnSpan(int x)
{
return this.buffer.GetRowSpan(x);
}
private void Slide()
{
this.CurrentMinY = this.CurrentMinY + this.windowBandDiameter;
this.CurrentMaxY = Math.Min(this.CurrentMaxY + this.windowBandDiameter, this.sourceRectangle.Height);
this.CalculateFirstPassValues(this.CurrentMinY, this.CurrentMaxY);
int minY = this.currentWindow.Min + this.windowBandDiameter;
int maxY = Math.Min(this.currentWindow.Max + this.windowBandDiameter, this.sourceRectangle.Height);
this.currentWindow = new RowInterval(minY, maxY);
this.CalculateFirstPassValues(this.currentWindow);
}
private void CalculateFirstPassValues(int minY, int maxY)
private void CalculateFirstPassValues(RowInterval window)
{
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan();
for (int y = minY; y < maxY; y++)
for (int y = window.Min; y < window.Max; y++)
{
Span<TPixel> sourceRow = this.source.GetRowSpan(y);
@ -167,7 +166,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.conversionModifiers);
// ref Vector4 firstPassBaseRef = ref this.buffer.Span[y - top];
Span<Vector4> firstPassSpan = this.buffer.Span.Slice(y - minY);
Span<Vector4> firstPassSpan = this.buffer.Span.Slice(y - window.Min);
for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++)
{

49
tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs

@ -34,5 +34,54 @@ namespace SixLabors.ImageSharp.Tests.Helpers
Assert.True(Unsafe.AreSame(ref expected0, ref actual0));
}
}
[Fact]
public void Slice1()
{
RowInterval rowInterval = new RowInterval(10, 20);
RowInterval sliced = rowInterval.Slice(5);
Assert.Equal(15, sliced.Min);
Assert.Equal(20, sliced.Max);
}
[Fact]
public void Slice2()
{
RowInterval rowInterval = new RowInterval(10, 20);
RowInterval sliced = rowInterval.Slice(3, 5);
Assert.Equal(13, sliced.Min);
Assert.Equal(18, sliced.Max);
}
[Fact]
public void Equality_WhenTrue()
{
RowInterval a = new RowInterval(42, 123);
RowInterval b = new RowInterval(42, 123);
Assert.True(a.Equals(b));
Assert.True(a.Equals((object)b));
Assert.True(a == b);
Assert.Equal(a.GetHashCode(), b.GetHashCode());
}
[Fact]
public void Equality_WhenFalse()
{
RowInterval a = new RowInterval(42, 123);
RowInterval b = new RowInterval(42, 125);
RowInterval c = new RowInterval(40, 123);
Assert.False(a.Equals(b));
Assert.False(c.Equals(a));
Assert.False(b.Equals(c));
Assert.False(a.Equals((object)b));
Assert.False(a.Equals(null));
Assert.False(a == b);
Assert.True(a != c);
}
}
}

Loading…
Cancel
Save