From 398736a09bc4764415a4f52bc3f3b6ba5f1867ee Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 19 Apr 2019 16:47:01 +0200 Subject: [PATCH] moar RowInterval stuff --- src/ImageSharp/Memory/RowInterval.cs | 37 +++++++++++++- .../Transforms/Resize/ResizeWorker.cs | 43 ++++++++-------- .../Helpers/RowIntervalTests.cs | 49 +++++++++++++++++++ 3 files changed, 106 insertions(+), 23 deletions(-) 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); + } } }