diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs
index a1c83415b..75c9190d2 100644
--- a/src/ImageSharp/Common/Helpers/ImageMaths.cs
+++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs
@@ -139,35 +139,6 @@ namespace SixLabors.ImageSharp
return new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);
}
- ///
- /// Gets the bounding from the given matrix.
- ///
- /// The source rectangle.
- /// The transformation matrix.
- ///
- /// The .
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Rectangle GetBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix)
- {
- // Calculate the position of the four corners in world space by applying
- // The world matrix to the four corners in object space (0, 0, width, height)
- var tl = Vector2.Transform(Vector2.Zero, matrix);
- var tr = Vector2.Transform(new Vector2(rectangle.Width, 0), matrix);
- var bl = Vector2.Transform(new Vector2(0, rectangle.Height), matrix);
- var br = Vector2.Transform(new Vector2(rectangle.Width, rectangle.Height), matrix);
-
- // Find the minimum and maximum "corners" based on the ones above
- float minX = MathF.Min(tl.X, MathF.Min(tr.X, MathF.Min(bl.X, br.X)));
- float maxX = MathF.Max(tl.X, MathF.Max(tr.X, MathF.Max(bl.X, br.X)));
- float minY = MathF.Min(tl.Y, MathF.Min(tr.Y, MathF.Min(bl.Y, br.Y)));
- float maxY = MathF.Max(tl.Y, MathF.Max(tr.Y, MathF.Max(bl.Y, br.Y)));
- float sizeX = maxX - minX + .5F;
- float sizeY = maxY - minY + .5F;
-
- return new Rectangle((int)(MathF.Ceiling(minX) - .5F), (int)(MathF.Ceiling(minY) - .5F), (int)MathF.Floor(sizeX), (int)MathF.Floor(sizeY));
- }
-
///
/// Finds the bounding rectangle based on the first instance of any color component other
/// than the given one.
diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineProcessor.cs
index ad8221b88..59b844263 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/AffineProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/AffineProcessor.cs
@@ -67,9 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
{
if (this.targetRectangle == Rectangle.Empty)
{
- this.targetRectangle = Matrix3x2.Invert(this.TransformMatrix, out Matrix3x2 sizeMatrix)
- ? ImageMaths.GetBoundingRectangle(sourceRectangle, sizeMatrix)
- : sourceRectangle;
+ this.targetRectangle = this.GetTransformedBoundingRectangle(sourceRectangle, this.TransformMatrix);
}
// We will always be creating the clone even for mutate because we may need to resize the canvas
@@ -148,6 +146,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Vector2 maxXY = point + radius;
Vector2 minXY = point - radius;
+ // max, maxY, minX, minY
var extents = new Vector4(
MathF.Floor(maxXY.X + .5F),
MathF.Floor(maxXY.Y + .5F),
@@ -245,6 +244,17 @@ namespace SixLabors.ImageSharp.Processing.Processors
return this.TransformMatrix;
}
+ ///
+ /// Gets the bounding relative to the source for the given transformation matrix.
+ ///
+ /// The source rectangle.
+ /// The transformation matrix.
+ /// The
+ protected virtual Rectangle GetTransformedBoundingRectangle(Rectangle sourceRectangle, Matrix3x2 matrix)
+ {
+ return sourceRectangle;
+ }
+
///
/// Calculated the weights for the given point.
/// This method uses more samples than the upscaled version to ensure edge pixels are correctly rendered.
diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineProcessor.cs
index 5f03f94e2..5631af3aa 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineProcessor.cs
@@ -27,5 +27,13 @@ namespace SixLabors.ImageSharp.Processing.Processors
var translateToSourceCenter = Matrix3x2.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F);
return translationToTargetCenter * this.TransformMatrix * translateToSourceCenter;
}
+
+ ///
+ protected override Rectangle GetTransformedBoundingRectangle(Rectangle sourceRectangle, Matrix3x2 matrix)
+ {
+ return Matrix3x2.Invert(this.TransformMatrix, out Matrix3x2 sizeMatrix)
+ ? TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, sizeMatrix)
+ : sourceRectangle;
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
index 7af1c68f1..fa47dadaa 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
@@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
/// The angle of rotation in degrees.
public RotateProcessor(float degrees)
- : this(degrees, KnownResamplers.NearestNeighbor)
+ : this(degrees, KnownResamplers.Bicubic)
{
}
@@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
{
degrees = degrees % 360;
- if (degrees < 0)
+ while (degrees < 0)
{
degrees += 360;
}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs
index 07f082838..b123a309b 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs
@@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// The angle in degrees to perform the skew along the x-axis.
/// The angle in degrees to perform the skew along the y-axis.
public SkewProcessor(float degreesX, float degreesY)
- : this(degreesX, degreesY, KnownResamplers.NearestNeighbor)
+ : this(degreesX, degreesY, KnownResamplers.Bicubic)
{
}
diff --git a/src/ImageSharp/Processing/Transforms/Rotate.cs b/src/ImageSharp/Processing/Transforms/Rotate.cs
index e9ae4fcf3..69fb7ebf0 100644
--- a/src/ImageSharp/Processing/Transforms/Rotate.cs
+++ b/src/ImageSharp/Processing/Transforms/Rotate.cs
@@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp
/// The
public static IImageProcessingContext Rotate(this IImageProcessingContext source, float degrees)
where TPixel : struct, IPixel
- => Rotate(source, degrees, KnownResamplers.NearestNeighbor);
+ => Rotate(source, degrees, KnownResamplers.Bicubic);
///
/// Rotates an image by the given angle in degrees using the specified sampling algorithm.
diff --git a/src/ImageSharp/Processing/Transforms/Skew.cs b/src/ImageSharp/Processing/Transforms/Skew.cs
index b7a431cce..0613a690b 100644
--- a/src/ImageSharp/Processing/Transforms/Skew.cs
+++ b/src/ImageSharp/Processing/Transforms/Skew.cs
@@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp
/// The
public static IImageProcessingContext Skew(this IImageProcessingContext source, float degreesX, float degreesY)
where TPixel : struct, IPixel
- => Skew(source, degreesX, degreesY, KnownResamplers.NearestNeighbor);
+ => Skew(source, degreesX, degreesY, KnownResamplers.Bicubic);
///
/// Skews an image by the given angles in degrees using the specified sampling algorithm.
diff --git a/src/ImageSharp/Processing/Transforms/TransformHelpers.cs b/src/ImageSharp/Processing/Transforms/TransformHelpers.cs
new file mode 100644
index 000000000..6f9560a9f
--- /dev/null
+++ b/src/ImageSharp/Processing/Transforms/TransformHelpers.cs
@@ -0,0 +1,43 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Numerics;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp
+{
+ ///
+ /// Contains helper methods for working with affine transforms
+ ///
+ public class TransformHelpers
+ {
+ ///
+ /// Returns the bounding relative to the source for the given transformation matrix.
+ ///
+ /// The source rectangle.
+ /// The transformation matrix.
+ ///
+ /// The .
+ ///
+ public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix)
+ {
+ // Calculate the position of the four corners in world space by applying
+ // The world matrix to the four corners in object space (0, 0, width, height)
+ var tl = Vector2.Transform(Vector2.Zero, matrix);
+ var tr = Vector2.Transform(new Vector2(rectangle.Width, 0), matrix);
+ var bl = Vector2.Transform(new Vector2(0, rectangle.Height), matrix);
+ var br = Vector2.Transform(new Vector2(rectangle.Width, rectangle.Height), matrix);
+
+ // Find the minimum and maximum "corners" based on the ones above
+ float minX = MathF.Min(tl.X, MathF.Min(tr.X, MathF.Min(bl.X, br.X)));
+ float maxX = MathF.Max(tl.X, MathF.Max(tr.X, MathF.Max(bl.X, br.X)));
+ float minY = MathF.Min(tl.Y, MathF.Min(tr.Y, MathF.Min(bl.Y, br.Y)));
+ float maxY = MathF.Max(tl.Y, MathF.Max(tr.Y, MathF.Max(bl.Y, br.Y)));
+ float sizeX = maxX - minX + .5F;
+ float sizeY = maxY - minY + .5F;
+
+ return new Rectangle((int)(MathF.Ceiling(minX) - .5F), (int)(MathF.Ceiling(minY) - .5F), (int)MathF.Floor(sizeX), (int)MathF.Floor(sizeY));
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformTests.cs
index 59a16eb78..79a1fd445 100644
--- a/tests/ImageSharp.Tests/Processing/Transforms/TransformTests.cs
+++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformTests.cs
@@ -72,7 +72,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
var rotate = Matrix3x2.CreateRotation((float)Math.PI / 4F, new Vector2(5 / 2F, 5 / 2F));
var translate = Matrix3x2.CreateTranslation((7 - 5) / 2F, (7 - 5) / 2F);
- image.Mutate(c => c.Transform(rotate * translate, resampler));
+ Rectangle sourceRectangle = image.Bounds();
+ Matrix3x2 matrix = rotate * translate;
+
+ Rectangle destRectangle = TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix);
+
+ image.Mutate(c => c.Transform(matrix, resampler, destRectangle));
image.DebugSave(provider, resamplerName);
VerifyAllPixelsAreWhiteOrTransparent(image);
@@ -96,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
Matrix3x2 m = rotate * scale * translate;
this.PrintMatrix(m);
-
+
image.Mutate(i => i.Transform(m, KnownResamplers.Bicubic));
image.DebugSave(provider, $"R({angleDeg})_S({sx},{sy})_T({tx},{ty})");
}