Skip to content

Commit

Permalink
Add vignette filter
Browse files Browse the repository at this point in the history
  • Loading branch information
hajduakos committed Apr 2, 2020
1 parent c5f83ab commit c4d7d3d
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 1 deletion.
9 changes: 9 additions & 0 deletions FilterLib.Tests/FilterTests/BorderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,14 @@ public void TestFadeBorder()
Assert.IsTrue(Common.CheckFilter("_input.bmp", "FadeBorder_20_Red.bmp",
new FadeBorderFilter(Size.Absolute(20), new RGB(255, 0, 0)), 1));
}

[Test]
public void TestVignette()
{
Assert.IsTrue(Common.CheckFilter("_input.bmp", "_input.bmp", new VignetteFilter(Size.Relative(3), Size.Relative(2)), 1));
Assert.IsTrue(Common.CheckFilter("_input.bmp", "Vignette_150pct_60pct.bmp", new VignetteFilter(Size.Relative(1.5f), Size.Relative(0.6f)), 1));
Assert.IsTrue(Common.CheckFilter("_input.bmp", "Vignette_150pct_60pct.bmp", new VignetteFilter(Size.Absolute(120), Size.Absolute(48)), 1));
Assert.IsTrue(Common.CheckFilter("_input.bmp", "Vignette_100pct_90pct.bmp", new VignetteFilter(Size.Relative(1f), Size.Relative(0.9f)), 1));
}
}
}
2 changes: 1 addition & 1 deletion FilterLib.Tests/ReflectiveApiTests/ApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class ApiTests
{
[Test]
public void TestListFilters() =>
Assert.AreEqual(56, ReflectiveApi.GetFilterTypes().ToArray().Length);
Assert.AreEqual(57, ReflectiveApi.GetFilterTypes().ToArray().Length);

[Test]
public void TestListBlends() =>
Expand Down
13 changes: 13 additions & 0 deletions FilterLib.Tests/ReflectiveApiTests/BorderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public void TestJitterBorder()
Assert.AreEqual(new RGB(255, 0, 0), ff.Color);
Assert.AreEqual(15, ff.Seed);
}

[Test]
public void TestFadeBorder()
{
Expand All @@ -31,5 +32,17 @@ public void TestFadeBorder()
Assert.AreEqual(8, ff.Width.ToAbsolute(0));
Assert.AreEqual(new RGB(255, 0, 0), ff.Color);
}

[Test]
public void TestVignette()
{
IFilter f = ReflectiveApi.ConstructFilterByName("Vignette");
Assert.IsInstanceOf<VignetteFilter>(f);
ReflectiveApi.SetFilterPropertyByName(f, "Radius", "120%");
ReflectiveApi.SetFilterPropertyByName(f, "ClearRadius", "40px");
VignetteFilter ff = f as VignetteFilter;
Assert.AreEqual(240, ff.Radius.ToAbsolute(200));
Assert.AreEqual(40, ff.ClearRadius.ToAbsolute(200));
}
}
}
Binary file not shown.
Binary file not shown.
100 changes: 100 additions & 0 deletions FilterLib/Filters/Border/VignetteFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using FilterLib.Reporting;
using FilterLib.Util;
using System;
using System.Drawing;
using System.Drawing.Imaging;

namespace FilterLib.Filters.Border
{
/// <summary>
/// Vignette filter.
/// </summary>
[Filter]
public sealed class VignetteFilter : FilterInPlaceBase
{

/// <summary>
/// Radius of the vignette, outside is black.
/// </summary>
[FilterParam]
public Util.Size Radius { get; set; }

/// <summary>
/// Radius of the clear zone.
/// </summary>
[FilterParam]
public Util.Size ClearRadius { get; set; }

/// <summary>
/// Constructor.
/// </summary>
public VignetteFilter() : this(Util.Size.Relative(3), Util.Size.Relative(2)) { }

/// <summary>
/// Constructor.
/// </summary>
/// <param name="radius">Radius of the vignette</param>
/// <param name="clearRadius">Radius of the clear zone</param>
public VignetteFilter(Util.Size radius, Util.Size clearRadius)
{
this.Radius = radius;
this.ClearRadius = clearRadius;
}

/// <summary>
/// Apply filter by modifying the original image.
/// </summary>
/// <param name="image">Input image</param>
/// <param name="reporter">Reporter (optional)</param>
public override void ApplyInPlace(Bitmap image, IReporter reporter = null)
{
reporter?.Start();
using (DisposableBitmapData bmd = new DisposableBitmapData(image, PixelFormat.Format24bppRgb))
{
int wMul3 = image.Width * 3;
int w = image.Width, h = image.Height;
int x, y;
float xShifted, yShifted, ellipseRadius;
float a1 = Radius.ToAbsolute(w / 2);
float a0 = ClearRadius.ToAbsolute(w / 2);
if (a1 < a0) throw new ArgumentException("Radius must be larger than clear zone radius.");
float halfWidth = w / 2f, halfHeight = h / 2f;
float ratioSquare = w * w / (float)(h * h);
double normalizer = Math.PI / (a1 - a0);
double op;

unsafe
{
// Iterate through rows
for (y = 0; y < h; ++y)
{
// Get row
byte* row = (byte*)bmd.Scan0 + (y * bmd.Stride);
// Iterate through columns
for (x = 0; x < wMul3; x += 3)
{
// Calculate coordinates with the origin at the center
xShifted = x / 3f - halfWidth;
yShifted = y - halfHeight;
// Calculate the radius (A) of the ellipse on which the point is
ellipseRadius = (float)Math.Sqrt(xShifted * xShifted + yShifted * yShifted * ratioSquare);
// If the point is outside the vignette area, set the color to black
if (ellipseRadius > a1) row[x] = row[x + 1] = row[x + 2] = 0;
// Else if the point is outside the clear zone, calculate opacity
else if (ellipseRadius >= a0)
{
op = Math.Cos((ellipseRadius - a0) * normalizer) / 2f + 0.5f; // Cosine transition
//op = 1- (a_tmp - a0) / (a1 - a0); // Linear transition
row[x] = (byte)(row[x] * op);
row[x + 1] = (byte)(row[x + 1] * op);
row[x + 2] = (byte)(row[x + 2] * op);
}
}
if ((y & 63) == 0) reporter?.Report(y, 0, h - 1);
}
}
}
reporter?.Done();
}
}
}

0 comments on commit c4d7d3d

Please sign in to comment.