From 3a2d001eaf1ce777fa27db17ba6737a9d995817c Mon Sep 17 00:00:00 2001 From: dirk Date: Sat, 13 Aug 2016 15:31:12 +0200 Subject: [PATCH] Moved the Flip and Rotate code from FlipRotate to their own Processors and call those inside RotateFlip. Former-commit-id: 59a0db810427fcfd9c7426392f5de94317d928bd Former-commit-id: 89d27c015fbc972372f3697c06864dd71f458574 Former-commit-id: 160b946dcbfc868be3d014c2ef6410cbb40d4ef7 --- src/ImageProcessorCore/Samplers/Flip.cs | 41 +++ .../Samplers/Options/RotateType.cs | 6 +- .../Samplers/Processors/FlipProcessor.cs | 119 +++++++++ .../Processors/RotateFlipProcessor.cs | 240 ------------------ .../Samplers/Processors/RotateProcessor.cs | 139 ++++++++++ src/ImageProcessorCore/Samplers/Rotate.cs | 16 ++ src/ImageProcessorCore/Samplers/RotateFlip.cs | 15 +- 7 files changed, 321 insertions(+), 255 deletions(-) create mode 100644 src/ImageProcessorCore/Samplers/Flip.cs create mode 100644 src/ImageProcessorCore/Samplers/Processors/FlipProcessor.cs delete mode 100644 src/ImageProcessorCore/Samplers/Processors/RotateFlipProcessor.cs diff --git a/src/ImageProcessorCore/Samplers/Flip.cs b/src/ImageProcessorCore/Samplers/Flip.cs new file mode 100644 index 0000000000..9e0bd3121c --- /dev/null +++ b/src/ImageProcessorCore/Samplers/Flip.cs @@ -0,0 +1,41 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore +{ + using Processors; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Flips an image by the given instructions. + /// + /// The pixel format. + /// The packed format. long, float. + /// The image to rotate, flip, or both. + /// The to perform the flip. + /// A delegate which is called as progress is made processing the image. + /// The + public static Image Flip(this Image source, FlipType flipType, ProgressEventHandler progressHandler = null) + where T : IPackedVector + where TP : struct + { + FlipProcessor processor = new FlipProcessor(flipType); + processor.OnProgress += progressHandler; + + try + { + return source.Process(source.Width, source.Height, source.Bounds, source.Bounds, processor); + } + finally + { + processor.OnProgress -= progressHandler; + } + } + } +} diff --git a/src/ImageProcessorCore/Samplers/Options/RotateType.cs b/src/ImageProcessorCore/Samplers/Options/RotateType.cs index 43644de858..a2572bee1d 100644 --- a/src/ImageProcessorCore/Samplers/Options/RotateType.cs +++ b/src/ImageProcessorCore/Samplers/Options/RotateType.cs @@ -18,16 +18,16 @@ namespace ImageProcessorCore /// /// Rotate the image by 90 degrees clockwise. /// - Rotate90, + Rotate90 = 90, /// /// Rotate the image by 180 degrees clockwise. /// - Rotate180, + Rotate180 = 180, /// /// Rotate the image by 270 degrees clockwise. /// - Rotate270 + Rotate270 = 270 } } diff --git a/src/ImageProcessorCore/Samplers/Processors/FlipProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/FlipProcessor.cs new file mode 100644 index 0000000000..c4de4a121e --- /dev/null +++ b/src/ImageProcessorCore/Samplers/Processors/FlipProcessor.cs @@ -0,0 +1,119 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore.Processors +{ + using System; + using System.Threading.Tasks; + + /// + /// Provides methods that allow the flipping of an image around its center point. + /// + /// The pixel format. + /// The packed format. long, float. + public class FlipProcessor : ImageSampler + where T : IPackedVector + where TP : struct + { + /// + /// Initializes a new instance of the class. + /// + /// The used to perform flipping. + public FlipProcessor(FlipType flipType) + { + this.FlipType = flipType; + } + + /// + /// Gets the used to perform flipping. + /// + public FlipType FlipType { get; } + + /// + protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + { + target.ClonePixels(target.Width, target.Height, source.Pixels); + + switch (this.FlipType) + { + // No default needed as we have already set the pixels. + case FlipType.Vertical: + this.FlipX(target); + break; + case FlipType.Horizontal: + this.FlipY(target); + break; + } + } + + /// + /// Swaps the image at the X-axis, which goes horizontally through the middle + /// at half the height of the image. + /// + /// Target image to apply the process to. + private void FlipX(ImageBase target) + { + int width = target.Width; + int height = target.Height; + int halfHeight = (int)Math.Ceiling(target.Height * .5F); + Image temp = new Image(width, height); + temp.ClonePixels(width, height, target.Pixels); + + using (IPixelAccessor targetPixels = target.Lock()) + using (IPixelAccessor tempPixels = temp.Lock()) + { + Parallel.For( + 0, + halfHeight, + this.ParallelOptions, + y => + { + for (int x = 0; x < width; x++) + { + int newY = height - y - 1; + targetPixels[x, y] = tempPixels[x, newY]; + targetPixels[x, newY] = tempPixels[x, y]; + } + + this.OnRowProcessed(); + }); + } + } + + /// + /// Swaps the image at the Y-axis, which goes vertically through the middle + /// at half of the width of the image. + /// + /// Target image to apply the process to. + private void FlipY(ImageBase target) + { + int width = target.Width; + int height = target.Height; + int halfWidth = (int)Math.Ceiling(width * .5F); + Image temp = new Image(width, height); + temp.ClonePixels(width, height, target.Pixels); + + using (IPixelAccessor targetPixels = target.Lock()) + using (IPixelAccessor tempPixels = temp.Lock()) + { + Parallel.For( + 0, + height, + this.ParallelOptions, + y => + { + for (int x = 0; x < halfWidth; x++) + { + int newX = width - x - 1; + targetPixels[x, y] = tempPixels[newX, y]; + targetPixels[newX, y] = tempPixels[x, y]; + } + + this.OnRowProcessed(); + }); + } + } + } +} diff --git a/src/ImageProcessorCore/Samplers/Processors/RotateFlipProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/RotateFlipProcessor.cs deleted file mode 100644 index 764e68de68..0000000000 --- a/src/ImageProcessorCore/Samplers/Processors/RotateFlipProcessor.cs +++ /dev/null @@ -1,240 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageProcessorCore.Processors -{ - using System; - using System.Threading.Tasks; - - /// - /// Provides methods that allow the rotation and flipping of an image around its center point. - /// - /// The pixel format. - /// The packed format. long, float. - public class RotateFlipProcessor : ImageSampler - where T : IPackedVector - where TP : struct - { - /// - /// Initializes a new instance of the class. - /// - /// The used to perform rotation. - /// The used to perform flipping. - public RotateFlipProcessor(RotateType rotateType, FlipType flipType) - { - this.RotateType = rotateType; - this.FlipType = flipType; - } - - /// - /// Gets the used to perform flipping. - /// - public FlipType FlipType { get; } - - /// - /// Gets the used to perform rotation. - /// - public RotateType RotateType { get; } - - /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) - { - switch (this.RotateType) - { - case RotateType.Rotate90: - this.Rotate90(target, source); - break; - case RotateType.Rotate180: - this.Rotate180(target, source); - break; - case RotateType.Rotate270: - this.Rotate270(target, source); - break; - default: - target.ClonePixels(target.Width, target.Height, source.Pixels); - break; - } - - switch (this.FlipType) - { - // No default needed as we have already set the pixels. - case FlipType.Vertical: - this.FlipX(target); - break; - case FlipType.Horizontal: - this.FlipY(target); - break; - } - } - - /// - /// Rotates the image 270 degrees clockwise at the centre point. - /// - /// The target image. - /// The source image. - private void Rotate270(ImageBase target, ImageBase source) - { - int width = source.Width; - int height = source.Height; - Image temp = new Image(height, width); - - using (IPixelAccessor sourcePixels = source.Lock()) - using (IPixelAccessor tempPixels = temp.Lock()) - { - Parallel.For( - 0, - height, - this.ParallelOptions, - y => - { - for (int x = 0; x < width; x++) - { - int newX = height - y - 1; - newX = height - newX - 1; - int newY = width - x - 1; - newY = width - newY - 1; - tempPixels[newX, newY] = sourcePixels[x, y]; - } - - this.OnRowProcessed(); - }); - } - - target.SetPixels(height, width, temp.Pixels); - } - - /// - /// Rotates the image 180 degrees clockwise at the centre point. - /// - /// The target image. - /// The source image. - private void Rotate180(ImageBase target, ImageBase source) - { - int width = source.Width; - int height = source.Height; - - using (IPixelAccessor sourcePixels = source.Lock()) - using (IPixelAccessor targetPixels = target.Lock()) - { - Parallel.For( - 0, - height, - this.ParallelOptions, - y => - { - for (int x = 0; x < width; x++) - { - int newX = width - x - 1; - int newY = height - y - 1; - targetPixels[newX, newY] = sourcePixels[x, y]; - } - - this.OnRowProcessed(); - }); - } - } - - /// - /// Rotates the image 90 degrees clockwise at the centre point. - /// - /// The target image. - /// The source image. - private void Rotate90(ImageBase target, ImageBase source) - { - int width = source.Width; - int height = source.Height; - Image temp = new Image(height, width); - - using (IPixelAccessor sourcePixels = source.Lock()) - using (IPixelAccessor tempPixels = temp.Lock()) - { - Parallel.For( - 0, - height, - this.ParallelOptions, - y => - { - for (int x = 0; x < width; x++) - { - int newX = height - y - 1; - tempPixels[newX, x] = sourcePixels[x, y]; - } - - this.OnRowProcessed(); - }); - } - - target.SetPixels(height, width, temp.Pixels); - } - - /// - /// Swaps the image at the X-axis, which goes horizontally through the middle - /// at half the height of the image. - /// - /// Target image to apply the process to. - private void FlipX(ImageBase target) - { - int width = target.Width; - int height = target.Height; - int halfHeight = (int)Math.Ceiling(target.Height * .5F); - Image temp = new Image(width, height); - temp.ClonePixels(width, height, target.Pixels); - - using (IPixelAccessor targetPixels = target.Lock()) - using (IPixelAccessor tempPixels = temp.Lock()) - { - Parallel.For( - 0, - halfHeight, - this.ParallelOptions, - y => - { - for (int x = 0; x < width; x++) - { - int newY = height - y - 1; - targetPixels[x, y] = tempPixels[x, newY]; - targetPixels[x, newY] = tempPixels[x, y]; - } - - this.OnRowProcessed(); - }); - } - } - - /// - /// Swaps the image at the Y-axis, which goes vertically through the middle - /// at half of the width of the image. - /// - /// Target image to apply the process to. - private void FlipY(ImageBase target) - { - int width = target.Width; - int height = target.Height; - int halfWidth = (int)Math.Ceiling(width * .5F); - Image temp = new Image(width, height); - temp.ClonePixels(width, height, target.Pixels); - - using (IPixelAccessor targetPixels = target.Lock()) - using (IPixelAccessor tempPixels = temp.Lock()) - { - Parallel.For( - 0, - height, - this.ParallelOptions, - y => - { - for (int x = 0; x < halfWidth; x++) - { - int newX = width - x - 1; - targetPixels[x, y] = tempPixels[newX, y]; - targetPixels[newX, y] = tempPixels[x, y]; - } - - this.OnRowProcessed(); - }); - } - } - } -} diff --git a/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs index 97faf89331..e4568fd2d1 100644 --- a/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs @@ -34,6 +34,11 @@ namespace ImageProcessorCore.Processors /// protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) { + if (Angle == 90 || Angle == 180 || Angle == 270) + { + return; + } + this.processMatrix = Point.CreateRotation(new Point(0, 0), -this.Angle); if (this.Expand) { @@ -44,6 +49,11 @@ namespace ImageProcessorCore.Processors /// protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { + if (OptimizedApply(target, source)) + { + return; + } + int height = target.Height; int width = target.Width; Matrix3x2 matrix = GetCenteredMatrix(target, source, this.processMatrix); @@ -70,5 +80,134 @@ namespace ImageProcessorCore.Processors }); } } + + /// + /// Rotates the images with an optimized method when the angle is 90, 180 or 270 degrees. + /// + /// The target image. + /// The source image. + /// + private bool OptimizedApply(ImageBase target, ImageBase source) + { + if (Angle == 90) + { + this.Rotate90(target, source); + return true; + } + + if (Angle == 180) + { + this.Rotate180(target, source); + return true; + } + + if (Angle == 270) + { + this.Rotate270(target, source); + return true; + } + + return false; + } + + /// + /// Rotates the image 270 degrees clockwise at the centre point. + /// + /// The target image. + /// The source image. + private void Rotate270(ImageBase target, ImageBase source) + { + int width = source.Width; + int height = source.Height; + Image temp = new Image(height, width); + + using (IPixelAccessor sourcePixels = source.Lock()) + using (IPixelAccessor tempPixels = temp.Lock()) + { + Parallel.For( + 0, + height, + this.ParallelOptions, + y => + { + for (int x = 0; x < width; x++) + { + int newX = height - y - 1; + newX = height - newX - 1; + int newY = width - x - 1; + newY = width - newY - 1; + tempPixels[newX, newY] = sourcePixels[x, y]; + } + + this.OnRowProcessed(); + }); + } + + target.SetPixels(height, width, temp.Pixels); + } + + /// + /// Rotates the image 180 degrees clockwise at the centre point. + /// + /// The target image. + /// The source image. + private void Rotate180(ImageBase target, ImageBase source) + { + int width = source.Width; + int height = source.Height; + + using (IPixelAccessor sourcePixels = source.Lock()) + using (IPixelAccessor targetPixels = target.Lock()) + { + Parallel.For( + 0, + height, + this.ParallelOptions, + y => + { + for (int x = 0; x < width; x++) + { + int newX = width - x - 1; + int newY = height - y - 1; + targetPixels[newX, newY] = sourcePixels[x, y]; + } + + this.OnRowProcessed(); + }); + } + } + + /// + /// Rotates the image 90 degrees clockwise at the centre point. + /// + /// The target image. + /// The source image. + private void Rotate90(ImageBase target, ImageBase source) + { + int width = source.Width; + int height = source.Height; + Image temp = new Image(height, width); + + using (IPixelAccessor sourcePixels = source.Lock()) + using (IPixelAccessor tempPixels = temp.Lock()) + { + Parallel.For( + 0, + height, + this.ParallelOptions, + y => + { + for (int x = 0; x < width; x++) + { + int newX = height - y - 1; + tempPixels[newX, x] = sourcePixels[x, y]; + } + + this.OnRowProcessed(); + }); + } + + target.SetPixels(height, width, temp.Pixels); + } } } \ No newline at end of file diff --git a/src/ImageProcessorCore/Samplers/Rotate.cs b/src/ImageProcessorCore/Samplers/Rotate.cs index ad00518f14..21249bcc24 100644 --- a/src/ImageProcessorCore/Samplers/Rotate.cs +++ b/src/ImageProcessorCore/Samplers/Rotate.cs @@ -28,6 +28,22 @@ namespace ImageProcessorCore return Rotate(source, degrees, true, progressHandler); } + /// + /// Rotates and flips an image by the given instructions. + /// + /// The pixel format. + /// The packed format. long, float. + /// The image to rotate. + /// The to perform the rotation. + /// A delegate which is called as progress is made processing the image. + /// The + public static Image Rotate(this Image source, RotateType rotateType, ProgressEventHandler progressHandler = null) + where T : IPackedVector + where TP : struct + { + return Rotate(source, (float)rotateType, false, progressHandler); + } + /// /// Rotates an image by the given angle in degrees. /// diff --git a/src/ImageProcessorCore/Samplers/RotateFlip.cs b/src/ImageProcessorCore/Samplers/RotateFlip.cs index 093af8503f..0cd513d34f 100644 --- a/src/ImageProcessorCore/Samplers/RotateFlip.cs +++ b/src/ImageProcessorCore/Samplers/RotateFlip.cs @@ -18,7 +18,6 @@ namespace ImageProcessorCore /// The pixel format. /// The packed format. long, float. /// The image to rotate, flip, or both. - /// The to perform the rotation. /// The to perform the flip. /// A delegate which is called as progress is made processing the image. /// The @@ -26,17 +25,9 @@ namespace ImageProcessorCore where T : IPackedVector where TP : struct { - RotateFlipProcessor processor = new RotateFlipProcessor(rotateType, flipType); - processor.OnProgress += progressHandler; - - try - { - return source.Process(source.Width, source.Height, source.Bounds, source.Bounds, processor); - } - finally - { - processor.OnProgress -= progressHandler; - } + return source + .Rotate(rotateType, progressHandler) + .Flip(flipType, progressHandler); } } }