mirror of https://github.com/SixLabors/ImageSharp
Browse Source
KernelSamplingMap.CorrectBorder sliced the offset span by radius * kernelSize, so bounds narrower than the kernel radius threw ArgumentOutOfRangeException (GaussianBlur of a 130x8 region with sigma 10, for example), and bounds exactly equal to the radius let Bounce offsets escape the sampling range by folding an overshoot of a full extent to min - 1. Route bounds no larger than the radius through an exact per-mode correction that folds each offset into range: clamp for Repeat, periodic reflection for Mirror and Bounce, and true modulo for Wrap. The single-pass corrections are unchanged for larger bounds.pull/3152/head
3 changed files with 143 additions and 1 deletions
@ -0,0 +1,50 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using SixLabors.ImageSharp.Processing.Processors.Convolution; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution; |
||||
|
|
||||
|
[Trait("Category", "Processors")] |
||||
|
[GroupOutput("Convolution")] |
||||
|
public class KernelSamplingMapTests |
||||
|
{ |
||||
|
public static readonly TheoryData<BorderWrappingMode, int, int> BoundsSmallerThanKernel = new() |
||||
|
{ |
||||
|
{ BorderWrappingMode.Repeat, 8, 5 }, |
||||
|
{ BorderWrappingMode.Mirror, 8, 5 }, |
||||
|
{ BorderWrappingMode.Bounce, 8, 5 }, |
||||
|
{ BorderWrappingMode.Wrap, 8, 5 }, |
||||
|
{ BorderWrappingMode.Repeat, 1, 1 }, |
||||
|
{ BorderWrappingMode.Mirror, 1, 1 }, |
||||
|
{ BorderWrappingMode.Bounce, 1, 1 }, |
||||
|
{ BorderWrappingMode.Wrap, 1, 1 }, |
||||
|
{ BorderWrappingMode.Repeat, 30, 30 }, |
||||
|
{ BorderWrappingMode.Mirror, 30, 30 }, |
||||
|
{ BorderWrappingMode.Bounce, 30, 30 }, |
||||
|
{ BorderWrappingMode.Wrap, 30, 30 }, |
||||
|
}; |
||||
|
|
||||
|
[Theory] |
||||
|
[MemberData(nameof(BoundsSmallerThanKernel))] |
||||
|
public void BuildSamplingOffsetMap_BoundsSmallerThanKernelRadius_OffsetsStayInBounds(BorderWrappingMode mode, int width, int height) |
||||
|
{ |
||||
|
// A 61-tap kernel has radius 30, so these bounds are covered entirely by the border
|
||||
|
// regions and offsets can overshoot the bounds by more than one sampling extent.
|
||||
|
const int kernelSize = 61; |
||||
|
Rectangle bounds = new(100, 200, width, height); |
||||
|
|
||||
|
using KernelSamplingMap map = new(Configuration.Default.MemoryAllocator); |
||||
|
map.BuildSamplingOffsetMap(kernelSize, kernelSize, bounds, mode, mode); |
||||
|
|
||||
|
foreach (int x in map.GetColumnOffsetSpan()) |
||||
|
{ |
||||
|
Assert.InRange(x, bounds.Left, bounds.Right - 1); |
||||
|
} |
||||
|
|
||||
|
foreach (int y in map.GetRowOffsetSpan()) |
||||
|
{ |
||||
|
Assert.InRange(y, bounds.Top, bounds.Bottom - 1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue