// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Processing.Processors.Convolution; namespace SixLabors.ImageSharp.Tests.Processing.Convolution; [Trait("Category", "Processors")] public class KernelSamplingMapTest { [Fact] public void KernalSamplingMap_Kernel5Image7x7RepeatBorder() { Size kernelSize = new(5, 5); Rectangle bounds = new(0, 0, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Repeat; int[] expected = { 0, 0, 0, 1, 2, 0, 0, 1, 2, 3, 0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 6, 4, 5, 6, 6, 6, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel5Image7x7BounceBorder() { Size kernelSize = new(5, 5); Rectangle bounds = new(0, 0, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Bounce; int[] expected = { 2, 1, 0, 1, 2, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 5, 4, 5, 6, 5, 4, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel5Image7x7MirrorBorder() { Size kernelSize = new(5, 5); Rectangle bounds = new(0, 0, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Mirror; int[] expected = { 1, 0, 0, 1, 2, 0, 0, 1, 2, 3, 0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 6, 4, 5, 6, 6, 5, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel5Image7x7WrapBorder() { Size kernelSize = new(5, 5); Rectangle bounds = new(0, 0, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Wrap; int[] expected = { 5, 6, 0, 1, 2, 6, 0, 1, 2, 3, 0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 0, 4, 5, 6, 0, 1, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel5Image9x9BounceBorder() { Size kernelSize = new(5, 5); Rectangle bounds = new(1, 1, 9, 9); BorderWrappingMode mode = BorderWrappingMode.Bounce; int[] expected = { 3, 2, 1, 2, 3, 2, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 5, 6, 7, 8, 9, 6, 7, 8, 9, 8, 7, 8, 9, 8, 7, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel5Image9x9MirrorBorder() { Size kernelSize = new(5, 5); Rectangle bounds = new(1, 1, 9, 9); BorderWrappingMode mode = BorderWrappingMode.Mirror; int[] expected = { 2, 1, 1, 2, 3, 1, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 5, 6, 7, 8, 9, 6, 7, 8, 9, 9, 7, 8, 9, 9, 8, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel5Image9x9WrapBorder() { Size kernelSize = new(5, 5); Rectangle bounds = new(1, 1, 9, 9); BorderWrappingMode mode = BorderWrappingMode.Wrap; int[] expected = { 8, 9, 1, 2, 3, 9, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 5, 6, 7, 8, 9, 6, 7, 8, 9, 1, 7, 8, 9, 1, 2, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel5Image7x7RepeatBorderTile() { Size kernelSize = new(5, 5); Rectangle bounds = new(2, 2, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Repeat; int[] expected = { 2, 2, 2, 3, 4, 2, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 5, 6, 7, 8, 8, 6, 7, 8, 8, 8, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel5Image7x7BounceBorderTile() { Size kernelSize = new(5, 5); Rectangle bounds = new(2, 2, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Bounce; int[] expected = { 4, 3, 2, 3, 4, 3, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 5, 6, 7, 8, 7, 6, 7, 8, 7, 6, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel5Image7x7MirrorBorderTile() { Size kernelSize = new(5, 5); Rectangle bounds = new(2, 2, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Mirror; int[] expected = { 3, 2, 2, 3, 4, 2, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 5, 6, 7, 8, 8, 6, 7, 8, 8, 7, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel5Image7x7WrapBorderTile() { Size kernelSize = new(5, 5); Rectangle bounds = new(2, 2, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Wrap; int[] expected = { 7, 8, 2, 3, 4, 8, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 5, 6, 7, 8, 2, 6, 7, 8, 2, 3, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel3Image7x7RepeatBorder() { Size kernelSize = new(3, 3); Rectangle bounds = new(0, 0, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Repeat; int[] expected = { 0, 0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 6, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel3Image7x7BounceBorder() { Size kernelSize = new(3, 3); Rectangle bounds = new(0, 0, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Bounce; int[] expected = { 1, 0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 5, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel3Image7x7MirrorBorder() { Size kernelSize = new(3, 3); Rectangle bounds = new(0, 0, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Mirror; int[] expected = { 0, 0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 6, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel3Image7x7WrapBorder() { Size kernelSize = new(3, 3); Rectangle bounds = new(0, 0, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Wrap; int[] expected = { 6, 0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 0, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel3Image7x7RepeatBorderTile() { Size kernelSize = new(3, 3); Rectangle bounds = new(2, 2, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Repeat; int[] expected = { 2, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7, 6, 7, 8, 7, 8, 8, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel3Image7BounceBorderTile() { Size kernelSize = new(3, 3); Rectangle bounds = new(2, 2, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Bounce; int[] expected = { 3, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7, 6, 7, 8, 7, 8, 7, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel3Image7MirrorBorderTile() { Size kernelSize = new(3, 3); Rectangle bounds = new(2, 2, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Mirror; int[] expected = { 2, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7, 6, 7, 8, 7, 8, 8, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel3Image7x7WrapBorderTile() { Size kernelSize = new(3, 3); Rectangle bounds = new(2, 2, 7, 7); BorderWrappingMode mode = BorderWrappingMode.Wrap; int[] expected = { 8, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7, 6, 7, 8, 7, 8, 2, }; this.AssertOffsets(kernelSize, bounds, mode, mode, expected, expected); } [Fact] public void KernalSamplingMap_Kernel3Image7x5WrapBorderTile() { Size kernelSize = new(3, 3); Rectangle bounds = new(2, 2, 7, 5); BorderWrappingMode mode = BorderWrappingMode.Wrap; int[] xExpected = { 8, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7, 6, 7, 8, 7, 8, 2, }; int[] yExpected = { 6, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 2, }; this.AssertOffsets(kernelSize, bounds, mode, mode, xExpected, yExpected); } private void AssertOffsets(Size kernelSize, Rectangle bounds, BorderWrappingMode xBorderMode, BorderWrappingMode yBorderMode, int[] xExpected, int[] yExpected) { // Arrange KernelSamplingMap map = new(Configuration.Default.MemoryAllocator); // Act map.BuildSamplingOffsetMap(kernelSize.Height, kernelSize.Width, bounds, xBorderMode, yBorderMode); // Assert int[] xOffsets = map.GetColumnOffsetSpan().ToArray(); Assert.Equal(xExpected, xOffsets); int[] yOffsets = map.GetRowOffsetSpan().ToArray(); Assert.Equal(yExpected, yOffsets); } }