Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
92 lines (74 sloc) 2.93 KB
/////////////////////////////////////////////////////////////////////////////////
// Paint.NET //
// Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
// See license-pdn.txt for full licensing and attribution details. //
// //
// Ported to Pinta by: Olivier Dufour <olivier.duff@gmail.com> //
/////////////////////////////////////////////////////////////////////////////////
using System;
namespace Pinta.ImageManipulation.Effects
{
public class MotionBlurEffect : BaseEffect
{
private double angle;
private int distance;
private bool centered;
/// <summary>
/// Creates a new effect that will apply a motion blur to an image.
/// </summary>
/// <param name="angle">Angle of the motion blur.</param>
/// <param name="distance">Distance to apply the blur. Valid range is 1 - 200.</param>
/// <param name="centered">Whether the blur is centered.</param>
public MotionBlurEffect (double angle = 25, int distance = 10, bool centered = true)
{
if (distance < 1 || distance > 200)
throw new ArgumentOutOfRangeException ("distance");
this.angle = angle;
this.distance = distance;
this.centered = centered;
}
#region Algorithm Code Ported From PDN
protected unsafe override void RenderLine (ISurface src, ISurface dst, Rectangle rect)
{
PointD start = new PointD (0, 0);
double theta = ((double)(angle + 180) * 2 * Math.PI) / 360.0;
double alpha = (double)distance;
PointD end = new PointD ((float)alpha * Math.Cos (theta), (float)(-alpha * Math.Sin (theta)));
if (centered) {
start.X = -end.X / 2.0f;
start.Y = -end.Y / 2.0f;
end.X /= 2.0f;
end.Y /= 2.0f;
}
PointD[] points = new PointD[((1 + distance) * 3) / 2];
if (points.Length == 1) {
points[0] = new PointD (0, 0);
} else {
for (int i = 0; i < points.Length; ++i) {
float frac = (float)i / (float)(points.Length - 1);
points[i] = Utility.Lerp (start, end, frac);
}
}
ColorBgra* samples = stackalloc ColorBgra[points.Length];
int src_width = src.Width;
int src_height = src.Height;
for (int y = rect.Top; y <= rect.Bottom; ++y) {
ColorBgra* dstPtr = dst.GetPointAddress (rect.Left, y);
for (int x = rect.Left; x <= rect.Right; ++x) {
int sampleCount = 0;
for (int j = 0; j < points.Length; ++j) {
PointD pt = new PointD (points[j].X + (float)x, points[j].Y + (float)y);
if (pt.X >= 0 && pt.Y >= 0 && pt.X <= (src_width - 1) && pt.Y <= (src_height - 1)) {
samples[sampleCount] = Utility.GetBilinearSampleClamped (src, (float)pt.X, (float)pt.Y);
++sampleCount;
}
}
*dstPtr = ColorBgra.Blend (samples, sampleCount);
++dstPtr;
}
}
}
#endregion
}
}