diff --git a/src/ImageProcessorCore/Samplers/Processors/ProcessMatrixHelper.cs b/src/ImageProcessorCore/Samplers/Processors/ProcessMatrixHelper.cs
new file mode 100644
index 000000000..428fc4084
--- /dev/null
+++ b/src/ImageProcessorCore/Samplers/Processors/ProcessMatrixHelper.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using System.Threading.Tasks;
+
+namespace ImageProcessorCore
+{
+
+ public static class ProcessMatrixHelper
+ {
+ public static void CreateNewTarget(ImageBase target, 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 float[rectangle.Width*rectangle.Height*4]);
+ }
+ }
+ public static Matrix3x2 Matrix3X2(ImageBase target, ImageBase source, Matrix3x2 processMatrix)
+ {
+ Matrix3x2 translationToTargetCenter = Matrix3x2.CreateTranslation(-target.Width / 2f, -target.Height / 2f);
+ Matrix3x2 translateToSourceCenter = Matrix3x2.CreateTranslation(source.Width / 2f, source.Height / 2f);
+ Matrix3x2 apply = (translationToTargetCenter * processMatrix) * translateToSourceCenter;
+ return apply;
+ }
+
+ public static void DrawHorizontalData(ImageBase target, ImageBase source, int y, Matrix3x2 apply)
+ {
+ for (int x = 0; x < target.Width; x++)
+ {
+ Point rotated = Point.Rotate(new Point(x, y), apply);
+ if (source.Bounds.Contains(rotated.X, rotated.Y))
+ {
+ target[x, y] = source[rotated.X, rotated.Y];
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs
index 0b6dd1a11..7a8e5f981 100644
--- a/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs
+++ b/src/ImageProcessorCore/Samplers/Processors/RotateProcessor.cs
@@ -13,12 +13,10 @@ namespace ImageProcessorCore
///
public class RotateProcessor : ImageSampler
{
- ///
- /// The image used for storing the first pass pixels.
- ///
+ private Matrix3x2 processMatrix;
///
- /// The angle of rotation in degrees.
+ /// The angle of processMatrix in degrees.
///
private float angle;
@@ -26,7 +24,7 @@ namespace ImageProcessorCore
public override int Parallelism { get; set; } = 1;
///
- /// Gets or sets the angle of rotation in degrees.
+ /// Gets or sets the angle of processMatrix in degrees.
///
public float Angle
{
@@ -40,8 +38,6 @@ namespace ImageProcessorCore
this.angle = value;
}
}
-
-
///
/// Gets or sets a value indicating whether to expand the canvas to fit the rotated image.
///
@@ -50,50 +46,26 @@ namespace ImageProcessorCore
///
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{
+ processMatrix = Point.CreateRotation(new Point(0, 0), -this.angle);
if (this.Expand)
{
- // First find out how big the target rectangle should be.
- Point centre = Rectangle.Center(sourceRectangle);
- Matrix3x2 rotation = Point.CreateRotation(centre, -this.angle);
- Rectangle rectangle = ImageMaths.GetBoundingRectangle(sourceRectangle, rotation);
- target.SetPixels(rectangle.Width, rectangle.Height, new float[rectangle.Width * rectangle.Height * 4]);
+ processMatrix = Point.CreateRotation(new Point(0,0), -this.angle);
+ ProcessMatrixHelper.CreateNewTarget(target, sourceRectangle,processMatrix);
}
}
///
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
-
- Matrix3x2 rotation = Point.CreateRotation(new Point(0, 0), -this.angle);
- Matrix3x2 tran = Matrix3x2.CreateTranslation(-target.Width / 2f, -target.Height / 2f);
- rotation = tran * rotation;
- Matrix3x2 tran2 = Matrix3x2.CreateTranslation(source.Width / 2f, source.Height / 2f);
- rotation = rotation * tran2;
-
-
+ var apply = ProcessMatrixHelper.Matrix3X2(target, source,processMatrix);
Parallel.For(
0,
target.Height,
y =>
{
- for (int x = 0; x < target.Width; x++)
- {
- // Rotate at the centre point
- Point rotated = Point.Rotate(new Point(x, y), rotation);
- if (source.Bounds.Contains(rotated.X, rotated.Y))
- {
- target[x, y] = source[rotated.X, rotated.Y];
- }
- }
-
- this.OnRowProcessed();
+ ProcessMatrixHelper.DrawHorizontalData(target, source, y, apply);
+ OnRowProcessed();
});
}
-
- ///
- protected override void AfterApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle)
- {
-
- }
}
}
\ No newline at end of file
diff --git a/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs
index 1bfcfb7e2..99b9f5457 100644
--- a/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs
+++ b/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs
@@ -13,10 +13,7 @@ namespace ImageProcessorCore
///
public class SkewProcessor : ImageSampler
{
- ///
- /// The image used for storing the first pass pixels.
- ///
- private Image firstPass;
+ private Matrix3x2 processMatrix;
///
/// The angle of rotation along the x-axis.
@@ -43,16 +40,6 @@ namespace ImageProcessorCore
set
{
- if (value > 360)
- {
- value -= 360;
- }
-
- if (value < 0)
- {
- value += 360;
- }
-
this.angleX = value;
}
}
@@ -69,16 +56,6 @@ namespace ImageProcessorCore
set
{
- if (value > 360)
- {
- value -= 360;
- }
-
- if (value < 0)
- {
- value += 360;
- }
-
this.angleY = value;
}
}
@@ -96,69 +73,26 @@ namespace ImageProcessorCore
///
protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
{
- // If we are expanding we need to pad the bounds of the source rectangle.
- // We can use the resizer in nearest neighbor mode to do this fairly quickly.
+ processMatrix = Point.CreateSkew(new Point(0, 0), -this.angleX, -this.angleY);
if (this.Expand)
{
- // First find out how big the target rectangle should be.
- Point centre = this.Center == Point.Empty ? Rectangle.Center(sourceRectangle) : this.Center;
- Matrix3x2 skew = Point.CreateSkew(centre, -this.angleX, -this.angleY);
- Rectangle rectangle = ImageMaths.GetBoundingRectangle(sourceRectangle, skew);
- ResizeOptions options = new ResizeOptions
- {
- Size = new Size(rectangle.Width, rectangle.Height),
- Mode = ResizeMode.BoxPad
- };
-
- // Get the padded bounds and resize the image.
- Rectangle bounds = ResizeHelper.CalculateTargetLocationAndBounds(source, options);
- this.firstPass = new Image(rectangle.Width, rectangle.Height);
- target.SetPixels(rectangle.Width, rectangle.Height, new float[rectangle.Width * rectangle.Height * 4]);
- new ResizeProcessor(new NearestNeighborResampler()).Apply(this.firstPass, source, rectangle.Width, rectangle.Height, bounds, sourceRectangle);
- }
- else
- {
- // Just clone the pixels across.
- this.firstPass = new Image(source.Width, source.Height);
- this.firstPass.ClonePixels(source.Width, source.Height, source.Pixels);
+ ProcessMatrixHelper.CreateNewTarget(target, sourceRectangle, processMatrix);
}
}
///
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
- int height = this.firstPass.Height;
- int startX = 0;
- int endX = this.firstPass.Width;
- Point centre = this.Center == Point.Empty ? Rectangle.Center(this.firstPass.Bounds) : this.Center;
- Matrix3x2 skew = Point.CreateSkew(centre, -this.angleX, -this.angleY);
-
- // Since we are not working in parallel we use full height and width
- // of the first pass image.
+ var apply = ProcessMatrixHelper.Matrix3X2(target, source, processMatrix);
Parallel.For(
0,
- height,
+ target.Height,
y =>
{
- for (int x = startX; x < endX; x++)
- {
- // Skew at the centre point
- Point skewed = Point.Skew(new Point(x, y), skew);
- if (this.firstPass.Bounds.Contains(skewed.X, skewed.Y))
- {
- target[x, y] = this.firstPass[skewed.X, skewed.Y];
- }
- }
-
- this.OnRowProcessed();
+ ProcessMatrixHelper.DrawHorizontalData(target, source, y, apply);
+ OnRowProcessed();
});
- }
- ///
- protected override void AfterApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle)
- {
- // Cleanup.
- this.firstPass.Dispose();
}
}
}
\ No newline at end of file
diff --git a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
index 29ab3be26..cffc39427 100644
--- a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
+++ b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
@@ -471,7 +471,7 @@
using (Image image = new Image(stream))
using (FileStream output = File.OpenWrite($"TestOutput/Rotate/{filename}"))
{
- image.Rotate(20, this.ProgressUpdate)
+ image.Rotate(-170, this.ProgressUpdate)
.Save(output);
}
@@ -500,7 +500,7 @@
using (Image image = new Image(stream))
using (FileStream output = File.OpenWrite($"TestOutput/Skew/{filename}"))
{
- image.Skew(20, 10, this.ProgressUpdate)
+ image.Skew(-20, -10, this.ProgressUpdate)
.Save(output);
}