diff --git a/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs b/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs
index 662a41f1b..ab4394feb 100644
--- a/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs
+++ b/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs
@@ -112,15 +112,13 @@ namespace ImageProcessorCore
///
/// Returns the given degrees converted to radians.
///
- ///
- /// The angle in degrees.
- ///
+ /// The angle in degrees.
///
- /// The representing the degree as radians.
+ /// The representing the degree as radians.
///
- public static double DegreesToRadians(double angleInDegrees)
+ public static float DegreesToRadians(float degrees)
{
- return angleInDegrees * (PI / 180);
+ return degrees * (PI / 180);
}
///
@@ -140,6 +138,24 @@ namespace ImageProcessorCore
return new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);
}
+ // http://gamedev.stackexchange.com/questions/22840/create-a-rectangle-struct-to-be-rotated-and-have-a-intersects-function
+ public static Rectangle GetBoundingRotatedRectangle(Rectangle rectangle, float degrees, Point center)
+ {
+ float radians = DegreesToRadians(degrees);
+ Matrix3x2 matrix = Matrix3x2.CreateRotation(radians, center.ToVector2());
+
+ Vector2 leftTop = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Top), matrix);
+ Vector2 rightTop = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Top), matrix);
+ Vector2 leftBottom = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Bottom), matrix);
+ Vector2 rightBottom = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Bottom), matrix);
+
+ Vector2 min = Vector2.Min(Vector2.Min(leftTop, rightTop), Vector2.Min(leftBottom, rightBottom));
+ Vector2 max = Vector2.Max(Vector2.Max(leftTop, rightTop), Vector2.Max(leftBottom, rightBottom));
+
+ // TODO: minY is wrong - negative
+ return new Rectangle((int)min.X, (int)min.Y, (int)(max.X - min.X), (int)(max.Y - min.Y));
+ }
+
///
/// Calculates the new size after rotation.
///
diff --git a/src/ImageProcessorCore/Numerics/Point.cs b/src/ImageProcessorCore/Numerics/Point.cs
index 472a1c773..f1fe3c5ec 100644
--- a/src/ImageProcessorCore/Numerics/Point.cs
+++ b/src/ImageProcessorCore/Numerics/Point.cs
@@ -159,26 +159,26 @@ namespace ImageProcessorCore
}
///
- /// Rotates a point around a given a rotation matrix.
+ /// Creates a rotation matrix for the given point and angle.
///
- /// The point to rotate
- /// Rotation matrix used
- ///
- public static Point Rotate( Point point, Matrix3x2 rotation )
+ /// The origin point to rotate around
+ /// Rotation in degrees
+ /// The rotation
+ public static Matrix3x2 CreateRotation(Point origin, float degrees)
{
- return new Point( Vector2.Transform( point.backingVector, rotation ) );
+ float radians = (float)ImageMaths.DegreesToRadians(degrees);
+ return Matrix3x2.CreateRotation(radians, origin.backingVector);
}
///
- /// Creates a rotation matrix for
+ /// Rotates a point around a given a rotation matrix.
///
- /// The origin point to rotate around
- /// Rotation in degrees
- ///
- public static Matrix3x2 CreateRotatation( Point origin, float degrees )
+ /// The point to rotate
+ /// Rotation matrix used
+ /// The rotated
+ public static Point Rotate(Point point, Matrix3x2 rotation)
{
- float radians = (float)ImageMaths.DegreesToRadians( degrees );
- return Matrix3x2.CreateRotation( radians, origin.backingVector );
+ return new Point(Vector2.Transform(point.backingVector, rotation));
}
///
@@ -187,26 +187,48 @@ namespace ImageProcessorCore
/// The point to rotate
/// The center point to rotate around.
/// The angle in degrees.
- ///
+ /// The rotated
public static Point Rotate(Point point, Point origin, float degrees)
{
- float radians = (float)ImageMaths.DegreesToRadians(degrees);
- return new Point(Vector2.Transform(point.backingVector, Matrix3x2.CreateRotation(radians, origin.backingVector)));
+ return new Point(Vector2.Transform(point.backingVector, CreateRotation(origin, degrees)));
}
///
- /// Skews a point around a given origin by the specified angles in degrees.
+ /// Creates a skew matrix for the given point and angle.
+ ///
+ /// The origin point to rotate around
+ /// The x-angle in degrees.
+ /// The y-angle in degrees.
+ /// The rotation
+ public static Matrix3x2 CreateSkew(Point origin, float degreesX, float degreesY)
+ {
+ float radiansX = (float)ImageMaths.DegreesToRadians(degreesX);
+ float radiansY = (float)ImageMaths.DegreesToRadians(degreesY);
+ return Matrix3x2.CreateSkew(radiansX, radiansY, origin.backingVector);
+ }
+
+ ///
+ /// Skews a point using a given a skew matrix.
///
/// The point to rotate
+ /// Rotation matrix used
+ /// The rotated
+ public static Point Skew(Point point, Matrix3x2 skew)
+ {
+ return new Point(Vector2.Transform(point.backingVector, skew));
+ }
+
+ ///
+ /// Skews a point around a given origin by the specified angles in degrees.
+ ///
+ /// The point to skew.
/// The center point to rotate around.
/// The x-angle in degrees.
/// The y-angle in degrees.
- ///
+ /// The skewed
public static Point Skew(Point point, Point origin, float degreesX, float degreesY)
{
- float radiansX = (float)ImageMaths.DegreesToRadians(degreesX);
- float radiansY = (float)ImageMaths.DegreesToRadians(degreesY);
- return new Point(Vector2.Transform(point.backingVector, Matrix3x2.CreateSkew(degreesX, degreesY, origin.backingVector)));
+ return new Point(Vector2.Transform(point.backingVector, CreateSkew(origin, degreesX, degreesY)));
}
///
@@ -223,8 +245,7 @@ namespace ImageProcessorCore
return "Point [ Empty ]";
}
- return
- $"Point [ X={this.X}, Y={this.Y} ]";
+ return $"Point [ X={this.X}, Y={this.Y} ]";
}
///
diff --git a/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs b/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs
index f28723276..45dc3c913 100644
--- a/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs
+++ b/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs
@@ -239,7 +239,7 @@ namespace ImageProcessorCore.Samplers
///
/// The image to rotate.
/// The angle in degrees to perform the rotation.
- /// The center point at which to skew the image.
+ /// The center point at which to rotate the image.
/// Whether to expand the image to fit the rotated result.
/// A delegate which is called as progress is made processing the image.
/// The
@@ -291,7 +291,7 @@ namespace ImageProcessorCore.Samplers
/// The
public static Image Skew(this Image source, float degreesX, float degreesY, ProgressEventHandler progressHandler = null)
{
- return Skew(source, degreesX, degreesY, Rectangle.Center(source.Bounds), progressHandler);
+ return Skew(source, degreesX, degreesY, Point.Empty, progressHandler);
}
///
diff --git a/src/ImageProcessorCore/Samplers/Rotate.cs b/src/ImageProcessorCore/Samplers/Rotate.cs
index 1de1b57af..a14b3cee1 100644
--- a/src/ImageProcessorCore/Samplers/Rotate.cs
+++ b/src/ImageProcessorCore/Samplers/Rotate.cs
@@ -71,7 +71,7 @@ namespace ImageProcessorCore.Samplers
{
// First find out how the target rectangle should be.
Rectangle rectangle = ImageMaths.GetBoundingRotatedRectangle(source.Width, source.Height, -this.angle);
-
+ Rectangle rectangle2 = ImageMaths.GetBoundingRotatedRectangle(sourceRectangle, -this.angle, this.Center);
ResizeOptions options = new ResizeOptions
{
Size = new Size(rectangle.Width, rectangle.Height),
@@ -102,7 +102,7 @@ namespace ImageProcessorCore.Samplers
int endX = this.firstPass.Bounds.Right;
float negativeAngle = -this.angle;
Point centre = this.Center == Point.Empty ? Rectangle.Center(this.firstPass.Bounds) : this.Center;
- Matrix3x2 rotation = Point.CreateRotatation(centre, negativeAngle);
+ Matrix3x2 rotation = Point.CreateRotation(centre, negativeAngle);
// Since we are not working in parallel we use full height and width of the first pass image.
Parallel.For(
diff --git a/src/ImageProcessorCore/Samplers/Skew.cs b/src/ImageProcessorCore/Samplers/Skew.cs
index 17e42833f..1d88811d1 100644
--- a/src/ImageProcessorCore/Samplers/Skew.cs
+++ b/src/ImageProcessorCore/Samplers/Skew.cs
@@ -5,6 +5,7 @@
namespace ImageProcessorCore.Samplers
{
+ using System.Numerics;
using System.Threading.Tasks;
///
@@ -89,10 +90,7 @@ namespace ImageProcessorCore.Samplers
float negativeAngleX = -this.angleX;
float negativeAngleY = -this.angleY;
Point centre = this.Center == Point.Empty ? Rectangle.Center(sourceRectangle) : this.Center;
-
- // Scaling factors
- float widthFactor = source.Width / (float)target.Width;
- float heightFactor = source.Height / (float)target.Height;
+ Matrix3x2 skew = Point.CreateSkew(centre, negativeAngleX, negativeAngleY);
Parallel.For(
startY,
@@ -102,20 +100,21 @@ namespace ImageProcessorCore.Samplers
if (y >= targetY && y < targetBottom)
{
// Y coordinates of source points
- int originY = (int)((y - targetY) * heightFactor);
+ int originY = y - targetY;
for (int x = startX; x < endX; x++)
{
// X coordinates of source points
- int originX = (int)((x - startX) * widthFactor);
+ int originX = x - startX;
// Skew at the centre point
- Point skewed = Point.Skew(new Point(originX, originY), centre, negativeAngleX, negativeAngleY);
+ Point skewed = Point.Skew(new Point(originX, originY), skew);
if (sourceRectangle.Contains(skewed.X, skewed.Y))
{
target[x, y] = source[skewed.X, skewed.Y];
}
}
+
this.OnRowProcessed();
}
});
diff --git a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
index 845bf0b1b..7d57934f0 100644
--- a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
+++ b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
@@ -452,6 +452,7 @@
Directory.CreateDirectory("TestOutput/Skew");
}
+ // Matches live example http://www.w3schools.com/css/tryit.asp?filename=trycss3_transform_skew
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
@@ -463,7 +464,7 @@
using (Image image = new Image(stream))
using (FileStream output = File.OpenWrite($"TestOutput/Skew/{filename}"))
{
- image.Skew(45, 45, this.ProgressUpdate)
+ image.Skew(20, 10, this.ProgressUpdate)
.Save(output);
}
diff --git a/tests/TestWebsites/MVC/Properties/launchSettings.json b/tests/TestWebsites/MVC/Properties/launchSettings.json
new file mode 100644
index 000000000..0ce7c413b
--- /dev/null
+++ b/tests/TestWebsites/MVC/Properties/launchSettings.json
@@ -0,0 +1,19 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:55993/",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file