Browse Source

Add Lanczos3

Former-commit-id: ffc9b65f1a7643d7a1581dc702d507ee247aab91
Former-commit-id: e079559f8b9293a40b86a946825d4cd734ef0e69
Former-commit-id: 7b795cc9803c78b1d2b434b4d7c1479ebd42809f
af/merge-core
James Jackson-South 11 years ago
parent
commit
8b3afb334b
  1. 56
      src/ImageProcessor/Common/Helpers/ImageMaths.cs
  2. 2
      src/ImageProcessor/ImageExtensions.cs
  3. 2
      src/ImageProcessor/ImageProcessor.csproj
  4. 33
      src/ImageProcessor/Samplers/Lanczos3Resampler.cs
  5. 4
      tests/ImageProcessor.Tests/Filters/FilterTests.cs
  6. 1
      tests/ImageProcessor.Tests/ImageProcessor.Tests.csproj
  7. 74
      tests/ImageProcessor.Tests/Samplers/SamplerTests.cs

56
src/ImageProcessor/Common/Helpers/ImageMaths.cs

@ -0,0 +1,56 @@
// <copyright file="ImageMaths.cs" company="James South">
// Copyright © James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor
{
using System;
/// <summary>
/// Provides common mathematical methods.
/// </summary>
internal static class ImageMaths
{
/// <summary>
/// Gets the result of a sine cardinal function for the given value.
/// </summary>
/// <param name="x">
/// The value to calculate the result for.
/// </param>
/// <returns>
/// The <see cref="double"/>.
/// </returns>
public static double SinC(double x)
{
const double Epsilon = .0001;
if (Math.Abs(x) > Epsilon)
{
x *= Math.PI;
return Clean(Math.Sin(x) / x);
}
return 1.0;
}
/// <summary>
/// Ensures that any passed double is correctly rounded to zero
/// </summary>
/// <param name="x">The value to clean.</param>
/// <returns>
/// The <see cref="double"/>
/// </returns>.
private static double Clean(double x)
{
const double Epsilon = .0001;
if (Math.Abs(x) < Epsilon)
{
return 0.0;
}
return x;
}
}
}

2
src/ImageProcessor/ImageExtensions.cs

@ -119,7 +119,7 @@ namespace ImageProcessor
for (int i = 0; i < source.Frames.Count; i++)
{
ImageFrame sourceFrame = source.Frames[i];
ImageFrame tranformedFrame = clone ? new ImageFrame(sourceFrame) : new ImageFrame();
ImageFrame tranformedFrame = clone ? new ImageFrame(sourceFrame) : new ImageFrame { FrameDelay = sourceFrame.FrameDelay };
action(sourceFrame, tranformedFrame);
if (!clone)

2
src/ImageProcessor/ImageProcessor.csproj

@ -40,6 +40,7 @@
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="Common\Helpers\ImageMaths.cs" />
<Compile Include="Common\Helpers\PixelOperations.cs" />
<Compile Include="Filters\Contrast.cs" />
<Compile Include="Filters\ImageFilterExtensions.cs" />
@ -179,6 +180,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Numerics\Rectangle.cs" />
<Compile Include="Numerics\Size.cs" />
<Compile Include="Samplers\Lanczos3Resampler.cs" />
<Compile Include="Samplers\BicubicResampler.cs" />
<Compile Include="Samplers\ImageSampleExtensions.cs" />
<Compile Include="Samplers\IResampler.cs" />

33
src/ImageProcessor/Samplers/Lanczos3Resampler.cs

@ -0,0 +1,33 @@
// <copyright file="BicubicResampler.cs" company="James South">
// Copyright © James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Samplers
{
/// <summary>
/// The function implements the Lanczos kernel algorithm as described on
/// <see href="https://en.wikipedia.org/wiki/Lanczos_resampling#Algorithm">Wikipedia</see>
/// </summary>
public class Lanczos3Resampler : IResampler
{
/// <inheritdoc/>
public double Radius => 3;
/// <inheritdoc/>
public double GetValue(double x)
{
if (x < 0)
{
x = -x;
}
if (x < 3)
{
return ImageMaths.SinC(x) * ImageMaths.SinC(x / 3f);
}
return 0;
}
}
}

4
tests/ImageProcessor.Tests/Filters/FilterTests.cs

@ -14,12 +14,12 @@ namespace ImageProcessor.Tests.Filters
{
public static readonly List<string> Files = new List<string>
{
{ "../../TestImages/Formats/Jpg/Backdrop.jpg"},
//{ "../../TestImages/Formats/Jpg/Backdrop.jpg"},
//{ "../../TestImages/Formats/Bmp/Car.bmp" },
//{ "../../TestImages/Formats/Png/cmyk.png" },
//{ "../../TestImages/Formats/Gif/a.gif" },
//{ "../../TestImages/Formats/Gif/leaf.gif" },
//{ "../../TestImages/Formats/Gif/ani.gif" },
{ "../../TestImages/Formats/Gif/ani.gif" },
//{ "../../TestImages/Formats/Gif/ani2.gif" },
//{ "../../TestImages/Formats/Gif/giphy.gif" },
};

1
tests/ImageProcessor.Tests/ImageProcessor.Tests.csproj

@ -60,6 +60,7 @@
<Compile Include="Numerics\PointTests.cs" />
<Compile Include="Numerics\SizeTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Samplers\SamplerTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

74
tests/ImageProcessor.Tests/Samplers/SamplerTests.cs

@ -0,0 +1,74 @@

namespace ImageProcessor.Tests.Filters
{
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Samplers;
using Xunit;
public class SamplerTests
{
public static readonly List<string> Files = new List<string>
{
{ "../../TestImages/Formats/Jpg/Backdrop.jpg" },
{ "../../TestImages/Formats/Bmp/Car.bmp" },
{ "../../TestImages/Formats/Png/cmyk.png" },
//{ "../../TestImages/Formats/Gif/a.gif" },
{ "../../TestImages/Formats/Gif/leaf.gif" },
//{ "../../TestImages/Formats/Gif/ani.gif" },
//{ "../../TestImages/Formats/Gif/ani2.gif" },
//{ "../../TestImages/Formats/Gif/giphy.gif" },
};
public static readonly TheoryData<string, IResampler> Samplers =
new TheoryData<string, IResampler>
{
{ "Bicubic", new BicubicResampler() },
{ "Lanczos3", new Lanczos3Resampler() }
};
[Theory]
[MemberData("Samplers")]
public void ResizeImage(string name, IResampler sampler)
{
if (!Directory.Exists("Resized"))
{
Directory.CreateDirectory("Resized");
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Stopwatch watch = Stopwatch.StartNew();
Image image = new Image(stream);
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"Resized/{filename}"))
{
image.Resize(900, 900, sampler).Save(output);
}
Trace.WriteLine($"{name}: {watch.ElapsedMilliseconds}ms");
}
}
}
[Theory]
[InlineData(-2, 0)]
[InlineData(-1, 0)]
[InlineData(0, 1)]
[InlineData(1, 0)]
[InlineData(2, 0)]
[InlineData(2, 0)]
public static void Lanczos3WindowOscillatesCorrectly(double x, double expected)
{
Lanczos3Resampler sampler = new Lanczos3Resampler();
double result = sampler.GetValue(x);
Assert.Equal(result, expected);
}
}
}
Loading…
Cancel
Save