diff --git a/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs b/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs index 542050ecd2..d741ccfd30 100644 --- a/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs +++ b/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs @@ -176,34 +176,7 @@ namespace ImageProcessorCore.Samplers /// The public static Image Rotate(this Image source, float degrees, ProgressEventHandler progressHandler = null) { - return Rotate(source, degrees, new BicubicResampler(), false, progressHandler); - } - - /// - /// Rotates an image by the given angle in degrees. - /// - /// The image to resize. - /// The angle in degrees to perform the rotation. - /// Whether to compress and expand the image color-space to gamma correct the image during processing. - /// A delegate which is called as progress is made processing the image. - /// The - public static Image Rotate(this Image source, float degrees, bool compand, ProgressEventHandler progressHandler = null) - { - return Rotate(source, degrees, new BicubicResampler(), compand, progressHandler); - } - - /// - /// Rotates an image by the given angle in degrees. - /// - /// The image to resize. - /// The angle in degrees to perform the rotation. - /// The to perform the resampling. - /// Whether to compress and expand the image color-space to gamma correct the image during processing. - /// A delegate which is called as progress is made processing the image. - /// The - public static Image Rotate(this Image source, float degrees, IResampler sampler, bool compand, ProgressEventHandler progressHandler = null) - { - Rotate processor = new Rotate(sampler) { Angle = degrees, Compand = compand }; + Rotate processor = new Rotate { Angle = degrees }; processor.OnProgress += progressHandler; try diff --git a/src/ImageProcessorCore/Samplers/Resampler.cs b/src/ImageProcessorCore/Samplers/Resampler.cs index 0554b18e0d..368e031939 100644 --- a/src/ImageProcessorCore/Samplers/Resampler.cs +++ b/src/ImageProcessorCore/Samplers/Resampler.cs @@ -6,8 +6,6 @@ namespace ImageProcessorCore.Samplers { using System; - using System.Collections.Generic; - using System.Threading.Tasks; /// /// Provides methods that allow the resampling of images using various algorithms. @@ -54,58 +52,57 @@ namespace ImageProcessorCore.Samplers /// protected Weights[] PrecomputeWeights(int destinationSize, int sourceSize) { - float xscale = destinationSize / (float)sourceSize; - float width; + float scale = (float)destinationSize / sourceSize; IResampler sampler = this.Sampler; - float fwidth = sampler.Radius; - float fscale; + float radius = sampler.Radius; double left; double right; - double weight = 0; - int n = 0; - int k; + double weight; + int index; + int sum; Weights[] result = new Weights[destinationSize]; - // When expanding, broaden the effective kernel support so that we still + // When shrinking, broaden the effective kernel support so that we still // visit every source pixel. - if (xscale < 0) + if (scale < 1) { - width = sampler.Radius / xscale; - fscale = 1 / xscale; + float width = radius / scale; + float filterScale = 1 / scale; // Make the weights slices, one source for each column or row. for (int i = 0; i < destinationSize; i++) { - float centre = i / xscale; + float centre = i / scale; left = Math.Ceiling(centre - width); right = Math.Floor(centre + width); - float sum = 0; - result[i] = new Weights(); - List builder = new List(); + + result[i] = new Weights + { + Sum = 0, + Values = new Weight[(int)Math.Floor(2 * width + 1)] + }; + for (double j = left; j <= right; j++) { weight = centre - j; - weight = sampler.GetValue((float)weight / fscale) / fscale; + weight = sampler.GetValue((float)(weight / filterScale)) / filterScale; if (j < 0) { - n = (int)-j; + index = (int)-j; } else if (j >= sourceSize) { - n = (int)((sourceSize - j) + sourceSize - 1); + index = (int)((sourceSize - j) + sourceSize - 1); } else { - n = (int)j; + index = (int)j; } - sum++; - builder.Add(new Weight(n, (float)weight)); + sum = (int)result[i].Sum++; + result[i].Values[sum] = new Weight(index, (float)weight); } - - result[i].Values = builder.ToArray(); - result[i].Sum = sum; } } else @@ -113,122 +110,46 @@ namespace ImageProcessorCore.Samplers // Make the weights slices, one source for each column or row. for (int i = 0; i < destinationSize; i++) { - float centre = i / xscale; - left = Math.Ceiling(centre - fwidth); - right = Math.Floor(centre + fwidth); - float sum = 0; - result[i] = new Weights(); + float centre = i / scale; + left = Math.Ceiling(centre - radius); + right = Math.Floor(centre + radius); + result[i] = new Weights + { + Sum = 0, + Values = new Weight[(int)(radius * 2 + 1)] + }; - List builder = new List(); for (double j = left; j <= right; j++) { weight = centre - j; weight = sampler.GetValue((float)weight); if (j < 0) { - n = (int)-j; + index = (int)-j; } else if (j >= sourceSize) { - n = (int)((sourceSize - j) + sourceSize - 1); + index = (int)((sourceSize - j) + sourceSize - 1); } else { - n = (int)j; + index = (int)j; } - sum++; - builder.Add(new Weight(n, (float)weight)); + sum = (int)result[i].Sum++; + result[i].Values[sum] = new Weight(index, (float)weight); } - - result[i].Values = builder.ToArray(); - result[i].Sum = sum; } } return result; } - //protected Weights[] PrecomputeWeights(int destinationSize, int sourceSize) - //{ - // IResampler sampler = this.Sampler; - // float ratio = sourceSize / (float)destinationSize; - // float scale = ratio; - - // // When shrinking, broaden the effective kernel support so that we still - // // visit every source pixel. - // if (scale < 1) - // { - // scale = 1; - // } - - // float scaledRadius = (float)Math.Ceiling(scale * sampler.Radius); - // Weights[] result = new Weights[destinationSize]; - - // // Make the weights slices, one source for each column or row. - // Parallel.For( - // 0, - // destinationSize, - // i => - // { - // float center = ((i + .5f) * ratio) - 0.5f; - // int start = (int)Math.Ceiling(center - scaledRadius); - - // if (start < 0) - // { - // start = 0; - // } - - // int end = (int)Math.Floor(center + scaledRadius); - - // if (end > sourceSize) - // { - // end = sourceSize; - - // if (end < start) - // { - // end = start; - // } - // } - - // float sum = 0; - // result[i] = new Weights(); - - // List builder = new List(); - // for (int a = start; a < end; a++) - // { - // float w = sampler.GetValue((a - center) / scale); - - // if (w < 0 || w > 0) - // { - // sum += w; - // builder.Add(new Weight(a, w)); - // } - // } - - // // Normalise the values - // if (sum > 0 || sum < 0) - // { - // builder.ForEach(w => w.Value /= sum); - // } - - // result[i].Values = builder.ToArray(); - // result[i].Sum = sum; - // }); - - // return result; - //} - /// /// Represents the weight to be added to a scaled pixel. /// - protected class Weight + protected struct Weight { - /// - /// The pixel index. - /// - public readonly int Index; - /// /// Initializes a new instance of the class. /// @@ -241,9 +162,14 @@ namespace ImageProcessorCore.Samplers } /// - /// Gets or sets the result of the interpolation algorithm. + /// Gets the pixel index. + /// + public int Index { get; } + + /// + /// Gets the result of the interpolation algorithm. /// - public float Value { get; set; } + public float Value { get; } } /// @@ -262,4 +188,4 @@ namespace ImageProcessorCore.Samplers public float Sum { get; set; } } } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Samplers/Resamplers/BoxResampler.cs b/src/ImageProcessorCore/Samplers/Resamplers/BoxResampler.cs index 6ef5c0e351..82c405114b 100644 --- a/src/ImageProcessorCore/Samplers/Resamplers/BoxResampler.cs +++ b/src/ImageProcessorCore/Samplers/Resamplers/BoxResampler.cs @@ -17,12 +17,7 @@ namespace ImageProcessorCore.Samplers /// public float GetValue(float x) { - if (x < 0) - { - x = -x; - } - - if (x <= 0.5) + if (x > -0.5 && x <= 0.5) { return 1; } diff --git a/src/ImageProcessorCore/Samplers/Rotate.cs b/src/ImageProcessorCore/Samplers/Rotate.cs index 77cc8e7e7e..42032ae2a7 100644 --- a/src/ImageProcessorCore/Samplers/Rotate.cs +++ b/src/ImageProcessorCore/Samplers/Rotate.cs @@ -10,24 +10,13 @@ namespace ImageProcessorCore.Samplers /// /// Provides methods that allow the rotating of images using various algorithms. /// - public class Rotate : Resampler + public class Rotate : ImageSampler { /// /// The angle of rotation. /// private float angle; - /// - /// Initializes a new instance of the class. - /// - /// - /// The sampler to perform the resize operation. - /// - public Rotate(IResampler sampler) - : base(sampler) - { - } - /// /// Gets or sets the angle of rotation. /// @@ -54,16 +43,6 @@ namespace ImageProcessorCore.Samplers } } - /// - protected override void OnApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) - { - if (!(this.Sampler is NearestNeighborResampler)) - { - this.HorizontalWeights = this.PrecomputeWeights(targetRectangle.Width, sourceRectangle.Width); - this.VerticalWeights = this.PrecomputeWeights(targetRectangle.Height, sourceRectangle.Height); - } - } - /// protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { @@ -73,45 +52,11 @@ namespace ImageProcessorCore.Samplers int endX = targetRectangle.Right; float negativeAngle = -this.angle; Point centre = Rectangle.Center(sourceRectangle); - bool compand = this.Compand; - - if (this.Sampler is NearestNeighborResampler) - { - // Scaling factors - float widthFactor = source.Width / (float)target.Width; - float heightFactor = source.Height / (float)target.Height; - Parallel.For( - startY, - endY, - y => - { - if (y >= targetY && y < targetBottom) - { - // Y coordinates of source points - int originY = (int)((y - targetY) * heightFactor); + // Scaling factors + float widthFactor = source.Width / (float)target.Width; + float heightFactor = source.Height / (float)target.Height; - for (int x = startX; x < endX; x++) - { - // X coordinates of source points - int originX = (int)((x - startX) * widthFactor); - - // Rotate at the centre point - Point rotated = Point.Rotate(new Point(originX, originY), centre, negativeAngle); - if (sourceRectangle.Contains(rotated.X, rotated.Y)) - { - target[x, y] = source[rotated.X, rotated.Y]; - } - } - this.OnRowProcessed(); - } - }); - - // Break out now. - return; - } - - // Interpolate the image using the calculated weights. Parallel.For( startY, endY, @@ -119,46 +64,21 @@ namespace ImageProcessorCore.Samplers { if (y >= targetY && y < targetBottom) { - Weight[] verticalValues = this.VerticalWeights[y].Values; + // Y coordinates of source points + int originY = (int)((y - targetY) * heightFactor); for (int x = startX; x < endX; x++) { - Weight[] horizontalValues = this.HorizontalWeights[x].Values; + // X coordinates of source points + int originX = (int)((x - startX) * widthFactor); - // Destination color components - Color destination = new Color(); - - foreach (Weight yw in verticalValues) + // Rotate at the centre point + Point rotated = Point.Rotate(new Point(originX, originY), centre, negativeAngle); + if (sourceRectangle.Contains(rotated.X, rotated.Y)) { - int originY = yw.Index; - - foreach (Weight xw in horizontalValues) - { - int originX = xw.Index; - - // Rotate at the centre point - Point rotated = Point.Rotate(new Point(originX, originY), centre, negativeAngle); - if (sourceRectangle.Contains(rotated.X, rotated.Y)) - { - target[x, y] = source[rotated.X, rotated.Y]; - } - - if (sourceRectangle.Contains(rotated.X, rotated.Y)) - { - Color sourceColor = compand ? Color.Expand(source[rotated.X, rotated.Y]) : source[rotated.X, rotated.Y]; - destination += sourceColor * yw.Value * xw.Value; - } - } + target[x, y] = source[rotated.X, rotated.Y]; } - - if (compand) - { - destination = Color.Compress(destination); - } - - target[x, y] = destination; } - this.OnRowProcessed(); } });