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);
}
}
}