From 8ea6ad70ab19b72ff182065b1b2d06a4cb992a55 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 9 Dec 2016 10:53:11 +1100 Subject: [PATCH] Move Rotate and Skew --- .../Transforms/Matrix3x2Processor.cs | 25 ++++---- .../Processors/Transforms/RotateProcessor.cs | 62 ++++++++++--------- .../Processors/Transforms/SkewProcessor.cs | 17 ++--- src/ImageSharp/Samplers/Transforms/Rotate.cs | 2 +- src/ImageSharp/Samplers/Transforms/Skew.cs | 2 +- .../{Samplers => Filters}/RotateTest.cs | 0 .../{Samplers => Filters}/SkewTest.cs | 0 7 files changed, 57 insertions(+), 51 deletions(-) rename tests/ImageSharp.Tests/Processors/{Samplers => Filters}/RotateTest.cs (100%) rename tests/ImageSharp.Tests/Processors/{Samplers => Filters}/SkewTest.cs (100%) diff --git a/src/ImageSharp/Samplers/Processors/Transforms/Matrix3x2Processor.cs b/src/ImageSharp/Samplers/Processors/Transforms/Matrix3x2Processor.cs index 169441648..e72e8aa61 100644 --- a/src/ImageSharp/Samplers/Processors/Transforms/Matrix3x2Processor.cs +++ b/src/ImageSharp/Samplers/Processors/Transforms/Matrix3x2Processor.cs @@ -12,38 +12,39 @@ namespace ImageSharp.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public abstract class Matrix3x2Processor : ImageSamplingProcessor + public abstract class Matrix3x2Processor : ImageFilteringProcessor where TColor : struct, IPackedPixel where TPacked : struct { /// - /// Creates a new target to contain the results of the matrix transform. + /// Gets the rectangle designating the target canvas. + /// + protected Rectangle CanvasRectangle { get; private set; } + + /// + /// Creates a new target canvas to contain the results of the matrix transform. /// - /// Target image to apply the process to. /// The source rectangle. /// The processing matrix. - protected static void CreateNewTarget(ImageBase target, Rectangle sourceRectangle, Matrix3x2 processMatrix) + protected void CreateNewCanvas(Rectangle sourceRectangle, Matrix3x2 processMatrix) { Matrix3x2 sizeMatrix; - if (Matrix3x2.Invert(processMatrix, out sizeMatrix)) - { - Rectangle rectangle = ImageMaths.GetBoundingRectangle(sourceRectangle, sizeMatrix); - target.SetPixels(rectangle.Width, rectangle.Height, new TColor[rectangle.Width * rectangle.Height]); - } + this.CanvasRectangle = Matrix3x2.Invert(processMatrix, out sizeMatrix) + ? ImageMaths.GetBoundingRectangle(sourceRectangle, sizeMatrix) + : sourceRectangle; } /// /// Gets a transform matrix adjusted to center upon the target image bounds. /// - /// Target image to apply the process to. /// The source image. /// The transform matrix. /// /// The . /// - protected static Matrix3x2 GetCenteredMatrix(ImageBase target, ImageBase source, Matrix3x2 matrix) + protected Matrix3x2 GetCenteredMatrix(ImageBase source, Matrix3x2 matrix) { - Matrix3x2 translationToTargetCenter = Matrix3x2.CreateTranslation(-target.Width * .5F, -target.Height * .5F); + Matrix3x2 translationToTargetCenter = Matrix3x2.CreateTranslation(-this.CanvasRectangle.Width * .5F, -this.CanvasRectangle.Height * .5F); Matrix3x2 translateToSourceCenter = Matrix3x2.CreateTranslation(source.Width * .5F, source.Height * .5F); return (translationToTargetCenter * matrix) * translateToSourceCenter; } diff --git a/src/ImageSharp/Samplers/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Samplers/Processors/Transforms/RotateProcessor.cs index a9e69678d..2ab16d592 100644 --- a/src/ImageSharp/Samplers/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Samplers/Processors/Transforms/RotateProcessor.cs @@ -19,7 +19,7 @@ namespace ImageSharp.Processors where TPacked : struct { /// - /// The tranform matrix to apply. + /// The transform matrix to apply. /// private Matrix3x2 processMatrix; @@ -34,19 +34,20 @@ namespace ImageSharp.Processors public bool Expand { get; set; } = true; /// - public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { - if (this.OptimizedApply(target, source)) + if (this.OptimizedApply(source)) { return; } - int height = target.Height; - int width = target.Width; - Matrix3x2 matrix = GetCenteredMatrix(target, source, this.processMatrix); + int height = this.CanvasRectangle.Height; + int width = this.CanvasRectangle.Width; + Matrix3x2 matrix = this.GetCenteredMatrix(source, this.processMatrix); + TColor[] target = new TColor[width * height]; using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) + using (PixelAccessor targetPixels = target.Lock(width, height)) { Parallel.For( 0, @@ -64,10 +65,12 @@ namespace ImageSharp.Processors } }); } + + source.SetPixels(width, height, target); } /// - protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { const float Epsilon = .0001F; @@ -79,40 +82,39 @@ namespace ImageSharp.Processors this.processMatrix = Point.CreateRotation(new Point(0, 0), -this.Angle); if (this.Expand) { - CreateNewTarget(target, sourceRectangle, this.processMatrix); + this.CreateNewCanvas(sourceRectangle, this.processMatrix); } } /// /// Rotates the images with an optimized method when the angle is 90, 180 or 270 degrees. /// - /// The target image. /// The source image. /// The - private bool OptimizedApply(ImageBase target, ImageBase source) + private bool OptimizedApply(ImageBase source) { const float Epsilon = .0001F; if (Math.Abs(this.Angle) < Epsilon) { - target.ClonePixels(target.Width, target.Height, source.Pixels); + // No need to do anything so return. return true; } if (Math.Abs(this.Angle - 90) < Epsilon) { - this.Rotate90(target, source); + this.Rotate90(source); return true; } if (Math.Abs(this.Angle - 180) < Epsilon) { - this.Rotate180(target, source); + this.Rotate180(source); return true; } if (Math.Abs(this.Angle - 270) < Epsilon) { - this.Rotate270(target, source); + this.Rotate270(source); return true; } @@ -122,16 +124,15 @@ namespace ImageSharp.Processors /// /// Rotates the image 270 degrees clockwise at the centre point. /// - /// The target image. /// The source image. - private void Rotate270(ImageBase target, ImageBase source) + private void Rotate270(ImageBase source) { int width = source.Width; int height = source.Height; - Image temp = new Image(height, width); + TColor[] target = new TColor[width * height]; using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor tempPixels = temp.Lock()) + using (PixelAccessor targetPixels = target.Lock(height, width)) { Parallel.For( 0, @@ -144,26 +145,26 @@ namespace ImageSharp.Processors int newX = height - y - 1; newX = height - newX - 1; int newY = width - x - 1; - tempPixels[newX, newY] = sourcePixels[x, y]; + targetPixels[newX, newY] = sourcePixels[x, y]; } }); } - target.SetPixels(height, width, temp.Pixels); + source.SetPixels(height, width, target); } /// /// Rotates the image 180 degrees clockwise at the centre point. /// - /// The target image. /// The source image. - private void Rotate180(ImageBase target, ImageBase source) + private void Rotate180(ImageBase source) { int width = source.Width; int height = source.Height; + TColor[] target = new TColor[width * height]; using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) + using (PixelAccessor targetPixels = target.Lock(width, height)) { Parallel.For( 0, @@ -179,21 +180,22 @@ namespace ImageSharp.Processors } }); } + + source.SetPixels(width, height, target); } /// /// Rotates the image 90 degrees clockwise at the centre point. /// - /// The target image. /// The source image. - private void Rotate90(ImageBase target, ImageBase source) + private void Rotate90(ImageBase source) { int width = source.Width; int height = source.Height; - Image temp = new Image(height, width); + TColor[] target = new TColor[width * height]; using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor tempPixels = temp.Lock()) + using (PixelAccessor targetPixels = target.Lock(height, width)) { Parallel.For( 0, @@ -204,12 +206,12 @@ namespace ImageSharp.Processors for (int x = 0; x < width; x++) { int newX = height - y - 1; - tempPixels[newX, x] = sourcePixels[x, y]; + targetPixels[newX, x] = sourcePixels[x, y]; } }); } - target.SetPixels(height, width, temp.Pixels); + source.SetPixels(height, width, target); } } } \ No newline at end of file diff --git a/src/ImageSharp/Samplers/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Samplers/Processors/Transforms/SkewProcessor.cs index 1db363a77..49aa51254 100644 --- a/src/ImageSharp/Samplers/Processors/Transforms/SkewProcessor.cs +++ b/src/ImageSharp/Samplers/Processors/Transforms/SkewProcessor.cs @@ -39,14 +39,15 @@ namespace ImageSharp.Processors public bool Expand { get; set; } = true; /// - public override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { - int height = target.Height; - int width = target.Width; - Matrix3x2 matrix = GetCenteredMatrix(target, source, this.processMatrix); + int height = this.CanvasRectangle.Height; + int width = this.CanvasRectangle.Width; + Matrix3x2 matrix = this.GetCenteredMatrix(source, this.processMatrix); + TColor[] target = new TColor[width * height]; using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) + using (PixelAccessor targetPixels = target.Lock(width, height)) { Parallel.For( 0, @@ -64,15 +65,17 @@ namespace ImageSharp.Processors } }); } + + source.SetPixels(width, height, target); } /// - protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { this.processMatrix = Point.CreateSkew(new Point(0, 0), -this.AngleX, -this.AngleY); if (this.Expand) { - CreateNewTarget(target, sourceRectangle, this.processMatrix); + this.CreateNewCanvas(sourceRectangle, this.processMatrix); } } } diff --git a/src/ImageSharp/Samplers/Transforms/Rotate.cs b/src/ImageSharp/Samplers/Transforms/Rotate.cs index f8f0a59e8..5815bc0dd 100644 --- a/src/ImageSharp/Samplers/Transforms/Rotate.cs +++ b/src/ImageSharp/Samplers/Transforms/Rotate.cs @@ -56,7 +56,7 @@ namespace ImageSharp where TPacked : struct { RotateProcessor processor = new RotateProcessor { Angle = degrees, Expand = expand }; - return source.Process(source.Width, source.Height, source.Bounds, source.Bounds, processor); + return source.Process(source.Bounds, processor); } } } diff --git a/src/ImageSharp/Samplers/Transforms/Skew.cs b/src/ImageSharp/Samplers/Transforms/Skew.cs index 4aa756842..cced53c95 100644 --- a/src/ImageSharp/Samplers/Transforms/Skew.cs +++ b/src/ImageSharp/Samplers/Transforms/Skew.cs @@ -43,7 +43,7 @@ namespace ImageSharp where TPacked : struct { SkewProcessor processor = new SkewProcessor { AngleX = degreesX, AngleY = degreesY, Expand = expand }; - return source.Process(source.Width, source.Height, source.Bounds, source.Bounds, processor); + return source.Process(source.Bounds, processor); } } } diff --git a/tests/ImageSharp.Tests/Processors/Samplers/RotateTest.cs b/tests/ImageSharp.Tests/Processors/Filters/RotateTest.cs similarity index 100% rename from tests/ImageSharp.Tests/Processors/Samplers/RotateTest.cs rename to tests/ImageSharp.Tests/Processors/Filters/RotateTest.cs diff --git a/tests/ImageSharp.Tests/Processors/Samplers/SkewTest.cs b/tests/ImageSharp.Tests/Processors/Filters/SkewTest.cs similarity index 100% rename from tests/ImageSharp.Tests/Processors/Samplers/SkewTest.cs rename to tests/ImageSharp.Tests/Processors/Filters/SkewTest.cs