diff --git a/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs b/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs
index 706970835..051b75f70 100644
--- a/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs
+++ b/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs
@@ -6,7 +6,6 @@
namespace ImageProcessorCore
{
using System;
- using System.Collections.Generic;
using System.Linq;
using System.Numerics;
diff --git a/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs
index 82a8d5cff..07760cf2a 100644
--- a/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs
+++ b/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs
@@ -13,75 +13,18 @@ namespace ImageProcessorCore.Processors
///
public class SkewProcessor : ImageSampler
{
- ///
- /// The image used for storing the first pass pixels.
- ///
- private Image firstPass;
-
- ///
- /// The angle of rotation along the x-axis.
- ///
- private float angleX;
-
- ///
- /// The angle of rotation along the y-axis.
- ///
- private float angleY;
-
///
public override int Parallelism { get; set; } = 1;
///
/// Gets or sets the angle of rotation along the x-axis in degrees.
///
- public float AngleX
- {
- get
- {
- return this.angleX;
- }
-
- set
- {
- if (value > 360)
- {
- value -= 360;
- }
-
- if (value < 0)
- {
- value += 360;
- }
-
- this.angleX = value;
- }
- }
+ public float AngleX { get; set; }
///
/// Gets or sets the angle of rotation along the y-axis in degrees.
///
- public float AngleY
- {
- get
- {
- return this.angleY;
- }
-
- set
- {
- if (value > 360)
- {
- value -= 360;
- }
-
- if (value < 0)
- {
- value += 360;
- }
-
- this.angleY = value;
- }
- }
+ public float AngleY { get; set; }
///
/// Gets or sets the center point.
@@ -96,65 +39,64 @@ namespace ImageProcessorCore.Processors
///
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.
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);
+ Point centre = this.Center;
+ Matrix3x2 skew = Point.CreateSkew(centre, -this.AngleX, -this.AngleY);
+ Matrix3x2 invertedSkew;
+ Matrix3x2.Invert(skew, out invertedSkew);
+ Rectangle bounds = ImageMaths.GetBoundingRectangle(source.Bounds, invertedSkew);
+ target.SetPixels(bounds.Width, bounds.Height, new float[bounds.Width * bounds.Height * 4]);
}
}
///
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
- int height = this.firstPass.Height;
+ int height = target.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);
+ int endX = target.Width;
+ Point centre = this.Center;
+
+ Matrix3x2 invertedSkew;
+ Matrix3x2 skew = Point.CreateSkew(centre, -this.AngleX, -this.AngleY);
+ Matrix3x2.Invert(skew, out invertedSkew);
+ Vector2 rightTop = Vector2.Transform(new Vector2(source.Width, 0), invertedSkew);
+ Vector2 leftBottom = Vector2.Transform(new Vector2(0, source.Height), invertedSkew);
- // Since we are not working in parallel we use full height and width
- // of the first pass image.
- using (PixelAccessor firstPassPixels = this.firstPass.Lock())
+ if (this.AngleX < 0 && this.AngleY > 0)
+ {
+ skew = Point.CreateSkew(new Point((int)-leftBottom.X, (int)leftBottom.Y), -this.AngleX, -this.AngleY);
+ }
+
+ if (this.AngleX > 0 && this.AngleY < 0)
+ {
+ skew = Point.CreateSkew(new Point((int)rightTop.X, (int)-rightTop.Y), -this.AngleX, -this.AngleY);
+ }
+
+ if (this.AngleX < 0 && this.AngleY < 0)
+ {
+ skew = Point.CreateSkew(new Point(target.Width - 1, target.Height - 1), -this.AngleX, -this.AngleY);
+ }
+
+ using (PixelAccessor sourcePixels = source.Lock())
using (PixelAccessor targetPixels = target.Lock())
{
Parallel.For(
0,
height,
y =>
+ {
+ for (int x = startX; x < endX; x++)
{
- for (int x = startX; x < endX; x++)
+ Point skewed = Point.Skew(new Point(x, y), skew);
+ if (source.Bounds.Contains(skewed.X, skewed.Y))
{
- // Skew at the centre point
- Point skewed = Point.Skew(new Point(x, y), skew);
- if (this.firstPass.Bounds.Contains(skewed.X, skewed.Y))
- {
- targetPixels[x, y] = firstPassPixels[skewed.X, skewed.Y];
- }
+ targetPixels[x, y] = sourcePixels[skewed.X, skewed.Y];
}
-
- this.OnRowProcessed();
- });
+ }
+ this.OnRowProcessed();
+ });
}
}
}
diff --git a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
index b5f98a73f..8c12e14f1 100644
--- a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
+++ b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
@@ -454,7 +454,7 @@ namespace ImageProcessorCore.Tests
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"TestOutput/Skew/{filename}"))
{
- image.Skew(20, 10, this.ProgressUpdate)
+ image.Skew(-15, 12, this.ProgressUpdate)
.Save(output);
}
}