diff --git a/src/ImageProcessor/Common/Helpers/ImageMaths.cs b/src/ImageProcessor/Common/Helpers/ImageMaths.cs
index 2e2f49bee..e0362992a 100644
--- a/src/ImageProcessor/Common/Helpers/ImageMaths.cs
+++ b/src/ImageProcessor/Common/Helpers/ImageMaths.cs
@@ -12,6 +12,41 @@ namespace ImageProcessor
///
internal static class ImageMaths
{
+ ///
+ /// Returns the result of a B-C filter against the given value.
+ ///
+ ///
+ /// The value to process.
+ /// The B-Spline curve variable.
+ /// The Cardinal curve variable.
+ ///
+ /// The .
+ ///
+ public static double GetBcValue(double x, double b, double c)
+ {
+ double temp;
+
+ if (x < 0)
+ {
+ x = -x;
+ }
+
+ temp = x * x;
+ if (x < 1)
+ {
+ x = ((12 - (9 * b) - (6 * c)) * (x * temp)) + ((-18 + (12 * b) + (6 * c)) * temp) + (6 - (2 * b));
+ return x / 6;
+ }
+
+ if (x < 2)
+ {
+ x = ((-b - (6 * c)) * (x * temp)) + (((6 * b) + (30 * c)) * temp) + (((-12 * b) - (48 * c)) * x) + ((8 * b) + (24 * c));
+ return x / 6;
+ }
+
+ return 0;
+ }
+
///
/// Gets the result of a sine cardinal function for the given value.
///
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index 7843b88bf..bc3b47826 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -181,10 +181,20 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -197,7 +207,6 @@
-
diff --git a/src/ImageProcessor/ImageProcessor.csproj.DotSettings b/src/ImageProcessor/ImageProcessor.csproj.DotSettings
index 33397fdd2..9d4487f0f 100644
--- a/src/ImageProcessor/ImageProcessor.csproj.DotSettings
+++ b/src/ImageProcessor/ImageProcessor.csproj.DotSettings
@@ -12,4 +12,5 @@
True
True
True
- True
\ No newline at end of file
+ True
+ True
\ No newline at end of file
diff --git a/src/ImageProcessor/Samplers/BicubicResampler.cs b/src/ImageProcessor/Samplers/Resamplers/BicubicResampler.cs
similarity index 96%
rename from src/ImageProcessor/Samplers/BicubicResampler.cs
rename to src/ImageProcessor/Samplers/Resamplers/BicubicResampler.cs
index 4c0d285af..20c4643cb 100644
--- a/src/ImageProcessor/Samplers/BicubicResampler.cs
+++ b/src/ImageProcessor/Samplers/Resamplers/BicubicResampler.cs
@@ -12,7 +12,7 @@ namespace ImageProcessor.Samplers
public class BicubicResampler : IResampler
{
///
- public double Radius => 4;
+ public double Radius => 2;
///
public double GetValue(double x)
diff --git a/src/ImageProcessor/Samplers/Resamplers/BoxResampler.cs b/src/ImageProcessor/Samplers/Resamplers/BoxResampler.cs
new file mode 100644
index 000000000..7983261da
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Resamplers/BoxResampler.cs
@@ -0,0 +1,32 @@
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ ///
+ /// The function implements the box (nearest neighbour) algorithm.
+ ///
+ public class BoxResampler : IResampler
+ {
+ ///
+ public double Radius => 0.5;
+
+ ///
+ public double GetValue(double x)
+ {
+ if (x < 0)
+ {
+ x = -x;
+ }
+
+ if (x <= 0.5)
+ {
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/Resamplers/CatmullRomResampler.cs b/src/ImageProcessor/Samplers/Resamplers/CatmullRomResampler.cs
new file mode 100644
index 000000000..816cf0607
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Resamplers/CatmullRomResampler.cs
@@ -0,0 +1,26 @@
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ ///
+ /// The function implements the Catmull-Rom algorithm.
+ ///
+ ///
+ public class CatmullRomResampler : IResampler
+ {
+ ///
+ public double Radius => 2;
+
+ ///
+ public double GetValue(double x)
+ {
+ const double B = 0;
+ const double C = 1 / 2d;
+
+ return ImageMaths.GetBcValue(x, B, C);
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/Resamplers/HermiteResampler.cs b/src/ImageProcessor/Samplers/Resamplers/HermiteResampler.cs
new file mode 100644
index 000000000..666c3372d
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Resamplers/HermiteResampler.cs
@@ -0,0 +1,26 @@
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ ///
+ /// The function implements the hermite algorithm.
+ ///
+ ///
+ public class HermiteResampler : IResampler
+ {
+ ///
+ public double Radius => 2;
+
+ ///
+ public double GetValue(double x)
+ {
+ const double B = 0;
+ const double C = 0;
+
+ return ImageMaths.GetBcValue(x, B, C);
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/IResampler.cs b/src/ImageProcessor/Samplers/Resamplers/IResampler.cs
similarity index 100%
rename from src/ImageProcessor/Samplers/IResampler.cs
rename to src/ImageProcessor/Samplers/Resamplers/IResampler.cs
diff --git a/src/ImageProcessor/Samplers/Lanczos5Resampler.cs b/src/ImageProcessor/Samplers/Resamplers/Lanczos3Resampler.cs
similarity index 82%
rename from src/ImageProcessor/Samplers/Lanczos5Resampler.cs
rename to src/ImageProcessor/Samplers/Resamplers/Lanczos3Resampler.cs
index 1d7008d58..3a154303d 100644
--- a/src/ImageProcessor/Samplers/Lanczos5Resampler.cs
+++ b/src/ImageProcessor/Samplers/Resamplers/Lanczos3Resampler.cs
@@ -1,4 +1,4 @@
-//
+//
// Copyright © James South and contributors.
// Licensed under the Apache License, Version 2.0.
//
@@ -9,10 +9,10 @@ namespace ImageProcessor.Samplers
/// The function implements the Lanczos kernel algorithm as described on
/// Wikipedia
///
- public class Lanczos5Resampler : IResampler
+ public class Lanczos3Resampler : IResampler
{
///
- public double Radius => 5;
+ public double Radius => 3;
///
public double GetValue(double x)
diff --git a/src/ImageProcessor/Samplers/Resamplers/MitchellNetravaliResampler.cs b/src/ImageProcessor/Samplers/Resamplers/MitchellNetravaliResampler.cs
new file mode 100644
index 000000000..acf5c51d6
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Resamplers/MitchellNetravaliResampler.cs
@@ -0,0 +1,26 @@
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ ///
+ /// The function implements the mitchell algorithm as described on
+ /// Wikipedia
+ ///
+ public class MitchellNetravaliResampler : IResampler
+ {
+ ///
+ public double Radius => 2;
+
+ ///
+ public double GetValue(double x)
+ {
+ const double B = 1 / 3d;
+ const double C = 1 / 3d;
+
+ return ImageMaths.GetBcValue(x, B, C);
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/Resamplers/RobidouxResampler.cs b/src/ImageProcessor/Samplers/Resamplers/RobidouxResampler.cs
new file mode 100644
index 000000000..dcfea2870
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Resamplers/RobidouxResampler.cs
@@ -0,0 +1,26 @@
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ ///
+ /// The function implements the Robidoux algorithm.
+ ///
+ ///
+ public class RobidouxResampler : IResampler
+ {
+ ///
+ public double Radius => 2;
+
+ ///
+ public double GetValue(double x)
+ {
+ const double B = 0.3782;
+ const double C = 0.3109;
+
+ return ImageMaths.GetBcValue(x, B, C);
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/Resamplers/RobidouxSharpResampler.cs b/src/ImageProcessor/Samplers/Resamplers/RobidouxSharpResampler.cs
new file mode 100644
index 000000000..dfb8d9bfd
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Resamplers/RobidouxSharpResampler.cs
@@ -0,0 +1,26 @@
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ ///
+ /// The function implements the Robidoux Sharp algorithm.
+ ///
+ ///
+ public class RobidouxSharpResampler : IResampler
+ {
+ ///
+ public double Radius => 2;
+
+ ///
+ public double GetValue(double x)
+ {
+ const double B = 0.2620;
+ const double C = 0.3690;
+
+ return ImageMaths.GetBcValue(x, B, C);
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/Resamplers/RobidouxSoftResampler.cs b/src/ImageProcessor/Samplers/Resamplers/RobidouxSoftResampler.cs
new file mode 100644
index 000000000..a6bbfada8
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Resamplers/RobidouxSoftResampler.cs
@@ -0,0 +1,26 @@
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ ///
+ /// The function implements the Robidoux Soft algorithm.
+ ///
+ ///
+ public class RobidouxSoftResampler : IResampler
+ {
+ ///
+ public double Radius => 2;
+
+ ///
+ public double GetValue(double x)
+ {
+ const double B = 0.6796;
+ const double C = 0.1602;
+
+ return ImageMaths.GetBcValue(x, B, C);
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/Resamplers/SplineResampler.cs b/src/ImageProcessor/Samplers/Resamplers/SplineResampler.cs
new file mode 100644
index 000000000..f3ed32ef0
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Resamplers/SplineResampler.cs
@@ -0,0 +1,26 @@
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ ///
+ /// The function implements the spline algorithm.
+ ///
+ ///
+ public class SplineResampler : IResampler
+ {
+ ///
+ public double Radius => 2;
+
+ ///
+ public double GetValue(double x)
+ {
+ const double B = 1;
+ const double C = 0;
+
+ return ImageMaths.GetBcValue(x, B, C);
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/Resamplers/TriangleResampler.cs b/src/ImageProcessor/Samplers/Resamplers/TriangleResampler.cs
new file mode 100644
index 000000000..66ff6a1ae
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Resamplers/TriangleResampler.cs
@@ -0,0 +1,32 @@
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ ///
+ /// The function implements the triangle (bilinear) algorithm.
+ ///
+ public class TriangleResampler : IResampler
+ {
+ ///
+ public double Radius => 1;
+
+ ///
+ public double GetValue(double x)
+ {
+ if (x < 0)
+ {
+ x = -x;
+ }
+
+ if (x < 1)
+ {
+ return 1 - x;
+ }
+
+ return 0;
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/Resamplers/WelchResampler.cs b/src/ImageProcessor/Samplers/Resamplers/WelchResampler.cs
new file mode 100644
index 000000000..db395ba85
--- /dev/null
+++ b/src/ImageProcessor/Samplers/Resamplers/WelchResampler.cs
@@ -0,0 +1,33 @@
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Samplers
+{
+ ///
+ /// The function implements the welch algorithm.
+ ///
+ ///
+ public class WelchResampler : IResampler
+ {
+ ///
+ public double Radius => 3;
+
+ ///
+ public double GetValue(double x)
+ {
+ if (x < 0)
+ {
+ x = -x;
+ }
+
+ if (x < 3)
+ {
+ return ImageMaths.SinC(x) * (1.0 - (x * x / 9.0));
+ }
+
+ return 0;
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/Resize.cs b/src/ImageProcessor/Samplers/Resize.cs
index 3dc3b166f..811294eb5 100644
--- a/src/ImageProcessor/Samplers/Resize.cs
+++ b/src/ImageProcessor/Samplers/Resize.cs
@@ -12,6 +12,11 @@ namespace ImageProcessor.Samplers
///
public class Resize : ParallelImageProcessor
{
+ ///
+ /// The epsilon for comparing floating point numbers.
+ ///
+ private const float Epsilon = 0.0001f;
+
///
/// Initializes a new instance of the class.
///
@@ -78,11 +83,16 @@ namespace ImageProcessor.Samplers
double b = 0;
double a = 0;
- for (int yy = left; yy < right; yy++)
+ for (int yy = left; yy <= right; yy++)
{
// Get Y cooefficient
double kernel1 = this.Sampler.GetValue(dy - yy);
+ if (Math.Abs(kernel1) < Epsilon)
+ {
+ continue;
+ }
+
int originY2 = originY1 + yy;
if (originY2 < 0)
{
@@ -94,11 +104,16 @@ namespace ImageProcessor.Samplers
originY2 = maxHeight;
}
- for (int xx = left; xx < right; xx++)
+ for (int xx = left; xx <= right; xx++)
{
// Get X cooefficient
double kernel2 = kernel1 * this.Sampler.GetValue(xx - dx);
+ if (Math.Abs(kernel2) < Epsilon)
+ {
+ continue;
+ }
+
int originX2 = originX1 + xx;
if (originX2 < 0)
{
diff --git a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs
index ab4511ad3..7a9e0f732 100644
--- a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs
+++ b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs
@@ -14,7 +14,16 @@ namespace ImageProcessor.Tests
new TheoryData
{
{ "Bicubic", new BicubicResampler() },
- //{ "Lanczos3", new Lanczos5Resampler() }
+ { "Bilinear", new TriangleResampler() },
+ { "NearestNeighbour", new BoxResampler() },
+ { "Lanczos3", new Lanczos3Resampler() },
+ { "MitchellNetravali", new MitchellNetravaliResampler() },
+ { "Hermite", new HermiteResampler() },
+ { "Spline", new SplineResampler() },
+ { "Robidoux", new RobidouxResampler() },
+ { "RobidouxSharp", new RobidouxSharpResampler() },
+ { "RobidouxSoft", new RobidouxSoftResampler() },
+ { "Welch", new WelchResampler() }
};
[Theory]
@@ -52,7 +61,7 @@ namespace ImageProcessor.Tests
[InlineData(2, 0)]
public static void Lanczos3WindowOscillatesCorrectly(double x, double expected)
{
- Lanczos5Resampler sampler = new Lanczos5Resampler();
+ Lanczos3Resampler sampler = new Lanczos3Resampler();
double result = sampler.GetValue(x);
Assert.Equal(result, expected);