diff --git a/src/ImageSharp/Memory/RowInterval.cs b/src/ImageSharp/Memory/RowInterval.cs
index 835e880e9..7e144e37c 100644
--- a/src/ImageSharp/Memory/RowInterval.cs
+++ b/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
///
/// Represents an interval of rows in a and/or
///
- internal readonly struct RowInterval
+ internal readonly struct RowInterval : IEquatable
{
///
/// Initializes a new instance of the struct.
@@ -36,7 +38,40 @@ namespace SixLabors.ImageSharp.Memory
///
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);
+ }
+
///
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;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
index e9e39ef13..66a17e2d7 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
+++ b/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 source,
@@ -82,14 +84,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.tempRowBuffer = configuration.MemoryAllocator.Allocate(this.sourceRectangle.Width);
this.tempColumnBuffer = configuration.MemoryAllocator.Allocate(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 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 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 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 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 tempRowSpan = this.tempRowBuffer.GetSpan();
- for (int y = minY; y < maxY; y++)
+ for (int y = window.Min; y < window.Max; y++)
{
Span 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 firstPassSpan = this.buffer.Span.Slice(y - minY);
+ Span firstPassSpan = this.buffer.Span.Slice(y - window.Min);
for (int x = this.destWorkingRect.Left; x < this.destWorkingRect.Right; x++)
{
diff --git a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs
index 629b3cdeb..3aead6aaa 100644
--- a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs
+++ b/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);
+ }
}
}