Browse Source

Fix inheritance and cleanup

pull/386/head
James Jackson-South 9 years ago
parent
commit
85afc5f1f1
  1. 27
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  2. 79
      src/ImageSharp/Processing/Processors/Transforms/AffineProcessor.cs
  3. 18
      src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs
  4. 36
      src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
  5. 33
      src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs
  6. 3
      src/ImageSharp/Processing/Transforms/Resamplers/BicubicResampler.cs
  7. 3
      src/ImageSharp/Processing/Transforms/Resamplers/BoxResampler.cs
  8. 3
      src/ImageSharp/Processing/Transforms/Resamplers/CatmullRomResampler.cs
  9. 3
      src/ImageSharp/Processing/Transforms/Resamplers/HermiteResampler.cs
  10. 3
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos2Resampler.cs
  11. 3
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos3Resampler.cs
  12. 3
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos5Resampler.cs
  13. 3
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos8Resampler.cs
  14. 3
      src/ImageSharp/Processing/Transforms/Resamplers/MitchellNetravaliResampler.cs
  15. 3
      src/ImageSharp/Processing/Transforms/Resamplers/NearestNeighborResampler.cs
  16. 3
      src/ImageSharp/Processing/Transforms/Resamplers/RobidouxSharpResampler.cs
  17. 3
      src/ImageSharp/Processing/Transforms/Resamplers/SplineResampler.cs
  18. 3
      src/ImageSharp/Processing/Transforms/Resamplers/TriangleResampler.cs
  19. 3
      src/ImageSharp/Processing/Transforms/Resamplers/WelchResampler.cs
  20. 37
      src/ImageSharp/Processing/Transforms/Rotate.cs
  21. 45
      src/ImageSharp/Processing/Transforms/Skew.cs
  22. 9
      tests/ImageSharp.Tests/Processing/Transforms/RotateFlipTests.cs
  23. 31
      tests/ImageSharp.Tests/Processing/Transforms/RotateTests.cs
  24. 21
      tests/ImageSharp.Tests/Processing/Transforms/SkewTest.cs

27
src/ImageSharp/Common/Helpers/ImageMaths.cs

@ -147,17 +147,26 @@ namespace SixLabors.ImageSharp
/// <returns> /// <returns>
/// The <see cref="Rectangle"/>. /// The <see cref="Rectangle"/>.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rectangle GetBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) public static Rectangle GetBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix)
{ {
var leftTop = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Top), matrix); // Calculate the position of the four corners in world space by applying
var rightTop = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Top), matrix); // The world matrix to the four corners in object space (0, 0, width, height)
var leftBottom = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Bottom), matrix); var tl = Vector2.Transform(Vector2.Zero, matrix);
var rightBottom = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Bottom), matrix); var tr = Vector2.Transform(new Vector2(rectangle.Width, 0), matrix);
var bl = Vector2.Transform(new Vector2(0, rectangle.Height), matrix);
Vector2[] allCorners = { leftTop, rightTop, leftBottom, rightBottom }; var br = Vector2.Transform(new Vector2(rectangle.Width, rectangle.Height), matrix);
float extentX = allCorners.Select(v => v.X).Max() - allCorners.Select(v => v.X).Min();
float extentY = allCorners.Select(v => v.Y).Max() - allCorners.Select(v => v.Y).Min(); // Find the minimum and maximum "corners" based on the ones above
return new Rectangle(0, 0, (int)MathF.Ceiling(extentX), (int)MathF.Ceiling(extentY)); 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)));
var min = new Vector2(minX, minY);
var max = new Vector2(maxX, maxY);
Vector2 size = max - min;
return new Rectangle((int)MathF.Floor(minX), (int)MathF.Floor(minY), (int)MathF.Ceiling(size.X), (int)MathF.Ceiling(size.Y));
} }
/// <summary> /// <summary>

79
src/ImageSharp/Processing/Processors/Transforms/AffineProcessor.cs

@ -3,7 +3,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -18,52 +17,40 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// Provides the base methods to perform affine transforms on an image. /// Provides the base methods to perform affine transforms on an image.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class AffineProcessor<TPixel> : ResamplingWeightedProcessor<TPixel> internal abstract class AffineProcessor<TPixel> : CloningImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private Rectangle targetRectangle;
private Matrix3x2 transformMatrix;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AffineProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="AffineProcessor{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="sampler">The sampler to perform the resize operation.</param> /// <param name="sampler">The sampler to perform the resize operation.</param>
protected AffineProcessor(IResampler sampler) protected AffineProcessor(IResampler sampler)
: base(sampler, 1, 1, Rectangles.DefaultRectangle) // Hack to prevent Guard throwing in base, we always set the canvas
{ {
this.Sampler = sampler;
} }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to expand the canvas to fit the transformed image. /// Gets the sampler to perform interpolation of the transform operation.
/// </summary> /// </summary>
public bool Expand { get; set; } = true; public IResampler Sampler { get; }
/// <summary> /// <summary>
/// Returns the processing matrix used for transforming the image. /// Returns the processing matrix used for transforming the image.
/// </summary> /// </summary>
/// <param name="rectangle">The rectangle bounds</param>
/// <returns>The <see cref="Matrix3x2"/></returns> /// <returns>The <see cref="Matrix3x2"/></returns>
protected abstract Matrix3x2 CreateProcessingMatrix(Rectangle rectangle); protected abstract Matrix3x2 GetTransformMatrix();
/// <summary>
/// Creates a new target canvas to contain the results of the matrix transform.
/// </summary>
/// <param name="sourceRectangle">The source rectangle.</param>
protected virtual void CreateNewCanvas(Rectangle sourceRectangle)
{
this.ResizeRectangle = Matrix3x2.Invert(this.CreateProcessingMatrix(sourceRectangle), out Matrix3x2 sizeMatrix)
? ImageMaths.GetBoundingRectangle(sourceRectangle, sizeMatrix)
: sourceRectangle;
this.Width = this.ResizeRectangle.Width;
this.Height = this.ResizeRectangle.Height;
}
/// <inheritdoc/> /// <inheritdoc/>
protected override Image<TPixel> CreateDestination(Image<TPixel> source, Rectangle sourceRectangle) protected override Image<TPixel> CreateDestination(Image<TPixel> source, Rectangle sourceRectangle)
{ {
this.CreateNewCanvas(sourceRectangle); this.ResizeCanvas(sourceRectangle);
// We will always be creating the clone even for mutate because we may need to resize the canvas // We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable<ImageFrame<TPixel>> frames = IEnumerable<ImageFrame<TPixel>> frames =
source.Frames.Select(x => new ImageFrame<TPixel>(this.ResizeRectangle.Width, this.ResizeRectangle.Height, x.MetaData.Clone())); source.Frames.Select(x => new ImageFrame<TPixel>(this.targetRectangle.Width, this.targetRectangle.Height, x.MetaData.Clone()));
// Use the overload to prevent an extra frame being added // Use the overload to prevent an extra frame being added
return new Image<TPixel>(source.GetConfiguration(), source.MetaData.Clone(), frames); return new Image<TPixel>(source.GetConfiguration(), source.MetaData.Clone(), frames);
@ -72,9 +59,11 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle, Configuration configuration) protected override void OnApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Rectangle sourceRectangle, Configuration configuration)
{ {
int height = this.ResizeRectangle.Height; int height = this.targetRectangle.Height;
int width = this.ResizeRectangle.Width; int width = this.targetRectangle.Width;
Rectangle sourceBounds = source.Bounds(); Rectangle sourceBounds = source.Bounds();
// Since could potentially be resizing the canvas we need to recenter the matrix
Matrix3x2 matrix = this.GetCenteredMatrix(source); Matrix3x2 matrix = this.GetCenteredMatrix(source);
if (this.Sampler is NearestNeighborResampler) if (this.Sampler is NearestNeighborResampler)
@ -106,8 +95,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
(float radius, float scale) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); (float radius, float scale) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height);
float xScale = xRadiusScale.scale; float xScale = xRadiusScale.scale;
float yScale = yRadiusScale.scale; float yScale = yRadiusScale.scale;
float xRadius = xRadiusScale.radius; var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius);
float yRadius = yRadiusScale.radius;
IResampler sampler = this.Sampler; IResampler sampler = this.Sampler;
var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY);
@ -125,11 +113,14 @@ namespace SixLabors.ImageSharp.Processing.Processors
var point = Vector2.Transform(new Vector2(x, y), matrix); var point = Vector2.Transform(new Vector2(x, y), matrix);
// Clamp sampling pixel radial extents to the source image edges // Clamp sampling pixel radial extents to the source image edges
Vector2 maxXY = point + radius;
Vector2 minXY = point - radius;
var extents = new Vector4( var extents = new Vector4(
MathF.Ceiling(point.X + xRadius), MathF.Ceiling(maxXY.X),
MathF.Ceiling(point.Y + yRadius), MathF.Ceiling(maxXY.Y),
MathF.Floor(point.X - xRadius), MathF.Floor(minXY.X),
MathF.Floor(point.Y - yRadius)); MathF.Floor(minXY.Y));
extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); extents = Vector4.Clamp(extents, Vector4.Zero, maxSource);
@ -172,9 +163,21 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// </returns> /// </returns>
protected Matrix3x2 GetCenteredMatrix(ImageFrame<TPixel> source) protected Matrix3x2 GetCenteredMatrix(ImageFrame<TPixel> source)
{ {
var translationToTargetCenter = Matrix3x2.CreateTranslation(-this.ResizeRectangle.Width * .5F, -this.ResizeRectangle.Height * .5F); var translationToTargetCenter = Matrix3x2.CreateTranslation(-this.targetRectangle.Width * .5F, -this.targetRectangle.Height * .5F);
var translateToSourceCenter = Matrix3x2.CreateTranslation(source.Width * .5F, source.Height * .5F); var translateToSourceCenter = Matrix3x2.CreateTranslation(source.Width * .5F, source.Height * .5F);
return (translationToTargetCenter * this.CreateProcessingMatrix(this.ResizeRectangle)) * translateToSourceCenter; return translationToTargetCenter * this.transformMatrix * translateToSourceCenter;
}
/// <summary>
/// Creates a new target canvas to contain the results of the matrix transform.
/// </summary>
/// <param name="sourceRectangle">The source rectangle.</param>
private void ResizeCanvas(Rectangle sourceRectangle)
{
this.transformMatrix = this.GetTransformMatrix();
this.targetRectangle = Matrix3x2.Invert(this.transformMatrix, out Matrix3x2 sizeMatrix)
? ImageMaths.GetBoundingRectangle(sourceRectangle, sizeMatrix)
: sourceRectangle;
} }
/// <summary> /// <summary>
@ -196,14 +199,4 @@ namespace SixLabors.ImageSharp.Processing.Processors
return (MathF.Ceiling(scale * this.Sampler.Radius), scale); return (MathF.Ceiling(scale * this.Sampler.Radius), scale);
} }
} }
/// <summary>
/// Contains a static rectangle used for comparison when creating a new canvas.
/// We do this so we can inherit from the resampling weights class and pass the guard in the constructor and also avoid creating a new rectangle each time.
/// </summary>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleType", Justification = "I'm using this only here to prevent duplication in generic types.")]
internal static class Rectangles
{
public static Rectangle DefaultRectangle { get; } = new Rectangle(0, 0, 1, 1);
}
} }

18
src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs

@ -15,13 +15,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
internal class AutoOrientProcessor<TPixel> : ImageProcessor<TPixel> internal class AutoOrientProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <inheritdoc/>
/// Initializes a new instance of the <see cref="AutoOrientProcessor{TPixel}"/> class.
/// </summary>
public AutoOrientProcessor()
{
}
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle) protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{ {
Orientation orientation = GetExifOrientation(source); Orientation orientation = GetExifOrientation(source);
@ -33,7 +27,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
break; break;
case Orientation.BottomRight: case Orientation.BottomRight:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate180, Expand = false }.Apply(source, sourceRectangle); new RotateProcessor<TPixel>((int)RotateType.Rotate180).Apply(source, sourceRectangle);
break; break;
case Orientation.BottomLeft: case Orientation.BottomLeft:
@ -41,21 +35,21 @@ namespace SixLabors.ImageSharp.Processing.Processors
break; break;
case Orientation.LeftTop: case Orientation.LeftTop:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle); new RotateProcessor<TPixel>((int)RotateType.Rotate90).Apply(source, sourceRectangle);
new FlipProcessor<TPixel>(FlipType.Horizontal).Apply(source, sourceRectangle); new FlipProcessor<TPixel>(FlipType.Horizontal).Apply(source, sourceRectangle);
break; break;
case Orientation.RightTop: case Orientation.RightTop:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle); new RotateProcessor<TPixel>((int)RotateType.Rotate90).Apply(source, sourceRectangle);
break; break;
case Orientation.RightBottom: case Orientation.RightBottom:
new FlipProcessor<TPixel>(FlipType.Vertical).Apply(source, sourceRectangle); new FlipProcessor<TPixel>(FlipType.Vertical).Apply(source, sourceRectangle);
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle); new RotateProcessor<TPixel>((int)RotateType.Rotate270).Apply(source, sourceRectangle);
break; break;
case Orientation.LeftBottom: case Orientation.LeftBottom:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle); new RotateProcessor<TPixel>((int)RotateType.Rotate270).Apply(source, sourceRectangle);
break; break;
case Orientation.Unknown: case Orientation.Unknown:

36
src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs

@ -19,39 +19,35 @@ namespace SixLabors.ImageSharp.Processing.Processors
internal class RotateProcessor<TPixel> : AffineProcessor<TPixel> internal class RotateProcessor<TPixel> : AffineProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private Matrix3x2 transformMatrix;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RotateProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="RotateProcessor{TPixel}"/> class.
/// </summary> /// </summary>
public RotateProcessor() /// <param name="angle">The angle of rotation in degrees.</param>
: base(KnownResamplers.NearestNeighbor) public RotateProcessor(float angle)
: this(angle, KnownResamplers.NearestNeighbor)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RotateProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="RotateProcessor{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="degrees">The angle of rotation in degrees.</param>
/// <param name="sampler">The sampler to perform the rotating operation.</param> /// <param name="sampler">The sampler to perform the rotating operation.</param>
public RotateProcessor(IResampler sampler) public RotateProcessor(float degrees, IResampler sampler)
: base(sampler) : base(sampler)
{ {
this.Degrees = degrees;
} }
/// <summary> /// <summary>
/// Gets or sets the angle of processMatrix in degrees. /// Gets the angle of rotation in degrees.
/// </summary> /// </summary>
public float Angle { get; set; } public float Degrees { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override Matrix3x2 CreateProcessingMatrix(Rectangle rectangle) protected override Matrix3x2 GetTransformMatrix()
{ {
if (this.transformMatrix == default(Matrix3x2)) return Matrix3x2Extensions.CreateRotationDegrees(-this.Degrees, PointF.Empty);
{
this.transformMatrix = Matrix3x2Extensions.CreateRotationDegrees(-this.Angle, PointF.Empty);
}
return this.transformMatrix;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -74,7 +70,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
return; return;
} }
if (MathF.Abs(this.Angle) < Constants.Epsilon) if (MathF.Abs(this.Degrees) < Constants.Epsilon)
{ {
// No need to do anything so return. // No need to do anything so return.
return; return;
@ -82,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
profile.RemoveValue(ExifTag.Orientation); profile.RemoveValue(ExifTag.Orientation);
if (this.Expand && profile.GetValue(ExifTag.PixelXDimension) != null) if (profile.GetValue(ExifTag.PixelXDimension) != null)
{ {
profile.SetValue(ExifTag.PixelXDimension, source.Width); profile.SetValue(ExifTag.PixelXDimension, source.Width);
profile.SetValue(ExifTag.PixelYDimension, source.Height); profile.SetValue(ExifTag.PixelYDimension, source.Height);
@ -100,26 +96,26 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// </returns> /// </returns>
private bool OptimizedApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration) private bool OptimizedApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration)
{ {
if (MathF.Abs(this.Angle) < Constants.Epsilon) if (MathF.Abs(this.Degrees) < Constants.Epsilon)
{ {
// The destination will be blank here so copy all the pixel data over // The destination will be blank here so copy all the pixel data over
source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); source.GetPixelSpan().CopyTo(destination.GetPixelSpan());
return true; return true;
} }
if (MathF.Abs(this.Angle - 90) < Constants.Epsilon) if (MathF.Abs(this.Degrees - 90) < Constants.Epsilon)
{ {
this.Rotate90(source, destination, configuration); this.Rotate90(source, destination, configuration);
return true; return true;
} }
if (MathF.Abs(this.Angle - 180) < Constants.Epsilon) if (MathF.Abs(this.Degrees - 180) < Constants.Epsilon)
{ {
this.Rotate180(source, destination, configuration); this.Rotate180(source, destination, configuration);
return true; return true;
} }
if (MathF.Abs(this.Angle - 270) < Constants.Epsilon) if (MathF.Abs(this.Degrees - 270) < Constants.Epsilon)
{ {
this.Rotate270(source, destination, configuration); this.Rotate270(source, destination, configuration);
return true; return true;

33
src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs

@ -14,36 +14,43 @@ namespace SixLabors.ImageSharp.Processing.Processors
internal class SkewProcessor<TPixel> : AffineProcessor<TPixel> internal class SkewProcessor<TPixel> : AffineProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private Matrix3x2 transformMatrix; /// <summary>
/// Initializes a new instance of the <see cref="SkewProcessor{TPixel}"/> class.
/// </summary>
/// <param name="degreesX">The angle in degrees to perform the skew along the x-axis.</param>
/// <param name="degreesY">The angle in degrees to perform the skew along the y-axis.</param>
public SkewProcessor(float degreesX, float degreesY)
: this(degreesX, degreesY, KnownResamplers.NearestNeighbor)
{
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SkewProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="SkewProcessor{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="degreesX">The angle in degrees to perform the skew along the x-axis.</param>
/// <param name="degreesY">The angle in degrees to perform the skew along the y-axis.</param>
/// <param name="sampler">The sampler to perform the skew operation.</param> /// <param name="sampler">The sampler to perform the skew operation.</param>
public SkewProcessor(IResampler sampler) public SkewProcessor(float degreesX, float degreesY, IResampler sampler)
: base(sampler) : base(sampler)
{ {
this.DegreesX = degreesX;
this.DegreesY = degreesY;
} }
/// <summary> /// <summary>
/// Gets or sets the angle of rotation along the x-axis in degrees. /// Gets the angle of rotation along the x-axis in degrees.
/// </summary> /// </summary>
public float AngleX { get; set; } public float DegreesX { get; }
/// <summary> /// <summary>
/// Gets or sets the angle of rotation along the y-axis in degrees. /// Gets the angle of rotation along the y-axis in degrees.
/// </summary> /// </summary>
public float AngleY { get; set; } public float DegreesY { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override Matrix3x2 CreateProcessingMatrix(Rectangle rectangle) protected override Matrix3x2 GetTransformMatrix()
{ {
if (this.transformMatrix == default(Matrix3x2)) return Matrix3x2Extensions.CreateSkewDegrees(-this.DegreesX, -this.DegreesY, PointF.Empty);
{
this.transformMatrix = Matrix3x2Extensions.CreateSkewDegrees(-this.AngleX, -this.AngleY, PointF.Empty);
}
return this.transformMatrix;
} }
} }
} }

3
src/ImageSharp/Processing/Transforms/Resamplers/BicubicResampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -16,7 +14,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/BoxResampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -15,7 +13,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 0.5F; public float Radius => 0.5F;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x > -0.5F && x <= 0.5F) if (x > -0.5F && x <= 0.5F)

3
src/ImageSharp/Processing/Transforms/Resamplers/CatmullRomResampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -17,7 +15,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
const float B = 0; const float B = 0;

3
src/ImageSharp/Processing/Transforms/Resamplers/HermiteResampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -16,7 +14,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
const float B = 0F; const float B = 0F;

3
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos2Resampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -16,7 +14,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos3Resampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -16,7 +14,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 3; public float Radius => 3;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos5Resampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -16,7 +14,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 5; public float Radius => 5;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos8Resampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -16,7 +14,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 8; public float Radius => 8;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/MitchellNetravaliResampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -15,7 +13,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
const float B = 0.3333333F; const float B = 0.3333333F;

3
src/ImageSharp/Processing/Transforms/Resamplers/NearestNeighborResampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -15,7 +13,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 1; public float Radius => 1;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
return x; return x;

3
src/ImageSharp/Processing/Transforms/Resamplers/RobidouxSharpResampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -15,7 +13,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
const float B = 0.2620145123990142F; const float B = 0.2620145123990142F;

3
src/ImageSharp/Processing/Transforms/Resamplers/SplineResampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -15,7 +13,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 2; public float Radius => 2;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
const float B = 1F; const float B = 1F;

3
src/ImageSharp/Processing/Transforms/Resamplers/TriangleResampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -16,7 +14,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 1; public float Radius => 1;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

3
src/ImageSharp/Processing/Transforms/Resamplers/WelchResampler.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -15,7 +13,6 @@ namespace SixLabors.ImageSharp.Processing
public float Radius => 3; public float Radius => 3;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetValue(float x) public float GetValue(float x)
{ {
if (x < 0F) if (x < 0F)

37
src/ImageSharp/Processing/Transforms/Rotate.cs

@ -12,29 +12,6 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
public static partial class ImageExtensions public static partial class ImageExtensions
{ {
/// <summary>
/// Rotates an image by the given angle in degrees, expanding the image to fit the rotated result.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate.</param>
/// <param name="degrees">The angle in degrees to perform the rotation.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, float degrees)
where TPixel : struct, IPixel<TPixel>
=> Rotate(source, degrees, true);
/// <summary>
/// Rotates an image by the given angle in degrees, expanding the image to fit the rotated result.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate.</param>
/// <param name="degrees">The angle in degrees to perform the rotation.</param>
/// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, float degrees, IResampler sampler)
where TPixel : struct, IPixel<TPixel>
=> Rotate(source, degrees, sampler, true);
/// <summary> /// <summary>
/// Rotates and flips an image by the given instructions. /// Rotates and flips an image by the given instructions.
/// </summary> /// </summary>
@ -44,7 +21,7 @@ namespace SixLabors.ImageSharp
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, RotateType rotateType) public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, RotateType rotateType)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Rotate(source, (float)rotateType, false); => Rotate(source, (float)rotateType);
/// <summary> /// <summary>
/// Rotates an image by the given angle in degrees. /// Rotates an image by the given angle in degrees.
@ -52,11 +29,10 @@ namespace SixLabors.ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate.</param> /// <param name="source">The image to rotate.</param>
/// <param name="degrees">The angle in degrees to perform the rotation.</param> /// <param name="degrees">The angle in degrees to perform the rotation.</param>
/// <param name="expand">Whether to expand the image to fit the rotated result.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, float degrees, bool expand) public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, float degrees)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Rotate(source, degrees, KnownResamplers.NearestNeighbor, expand); => Rotate(source, degrees, KnownResamplers.NearestNeighbor);
/// <summary> /// <summary>
/// Rotates an image by the given angle in degrees using the specified sampling algorithm. /// Rotates an image by the given angle in degrees using the specified sampling algorithm.
@ -65,10 +41,9 @@ namespace SixLabors.ImageSharp
/// <param name="source">The image to rotate.</param> /// <param name="source">The image to rotate.</param>
/// <param name="degrees">The angle in degrees to perform the rotation.</param> /// <param name="degrees">The angle in degrees to perform the rotation.</param>
/// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param> /// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param>
/// <param name="expand">Whether to expand the image to fit the rotated result.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, float degrees, IResampler sampler, bool expand) public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, float degrees, IResampler sampler)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new RotateProcessor<TPixel>(sampler) { Angle = degrees, Expand = expand }); => source.ApplyProcessor(new RotateProcessor<TPixel>(degrees, sampler));
} }
} }

45
src/ImageSharp/Processing/Transforms/Skew.cs

@ -12,56 +12,29 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
public static partial class ImageExtensions public static partial class ImageExtensions
{ {
/// <summary>
/// Skews an image by the given angles in degrees, expanding the image to fit the skewed result.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to skew.</param>
/// <param name="degreesX">The angle in degrees to perform the rotation along the x-axis.</param>
/// <param name="degreesY">The angle in degrees to perform the rotation along the y-axis.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Skew<TPixel>(this IImageProcessingContext<TPixel> source, float degreesX, float degreesY)
where TPixel : struct, IPixel<TPixel>
=> Skew(source, degreesX, degreesY, true);
/// <summary>
/// Skews an image by the given angles in degrees using the given sampler, expanding the image to fit the skewed result.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to skew.</param>
/// <param name="degreesX">The angle in degrees to perform the rotation along the x-axis.</param>
/// <param name="degreesY">The angle in degrees to perform the rotation along the y-axis.</param>
/// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Skew<TPixel>(this IImageProcessingContext<TPixel> source, float degreesX, float degreesY, IResampler sampler)
where TPixel : struct, IPixel<TPixel>
=> Skew(source, degreesX, degreesY, sampler, true);
/// <summary> /// <summary>
/// Skews an image by the given angles in degrees. /// Skews an image by the given angles in degrees.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to skew.</param> /// <param name="source">The image to skew.</param>
/// <param name="degreesX">The angle in degrees to perform the rotation along the x-axis.</param> /// <param name="degreesX">The angle in degrees to perform the skew along the x-axis.</param>
/// <param name="degreesY">The angle in degrees to perform the rotation along the y-axis.</param> /// <param name="degreesY">The angle in degrees to perform the skew along the y-axis.</param>
/// <param name="expand">Whether to expand the image to fit the skewed result.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Skew<TPixel>(this IImageProcessingContext<TPixel> source, float degreesX, float degreesY, bool expand) public static IImageProcessingContext<TPixel> Skew<TPixel>(this IImageProcessingContext<TPixel> source, float degreesX, float degreesY)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> Skew(source, degreesX, degreesY, KnownResamplers.NearestNeighbor, expand); => Skew(source, degreesX, degreesY, KnownResamplers.NearestNeighbor);
/// <summary> /// <summary>
/// Skews an image by the given angles in degrees using the specified sampling algorithm. /// Skews an image by the given angles in degrees using the specified sampling algorithm.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to skew.</param> /// <param name="source">The image to skew.</param>
/// <param name="degreesX">The angle in degrees to perform the rotation along the x-axis.</param> /// <param name="degreesX">The angle in degrees to perform the skew along the x-axis.</param>
/// <param name="degreesY">The angle in degrees to perform the rotation along the y-axis.</param> /// <param name="degreesY">The angle in degrees to perform the skew along the y-axis.</param>
/// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param> /// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param>
/// <param name="expand">Whether to expand the image to fit the skewed result.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns> /// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> Skew<TPixel>(this IImageProcessingContext<TPixel> source, float degreesX, float degreesY, IResampler sampler, bool expand) public static IImageProcessingContext<TPixel> Skew<TPixel>(this IImageProcessingContext<TPixel> source, float degreesX, float degreesY, IResampler sampler)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new SkewProcessor<TPixel>(sampler) { AngleX = degreesX, AngleY = degreesY, Expand = expand }); => source.ApplyProcessor(new SkewProcessor<TPixel>(degreesX, degreesY, sampler));
} }
} }

9
tests/ImageSharp.Tests/Processing/Transforms/RotateFlipTests.cs

@ -25,14 +25,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
[InlineData(RotateType.Rotate90, FlipType.Vertical, 90)] [InlineData(RotateType.Rotate90, FlipType.Vertical, 90)]
[InlineData(RotateType.Rotate180, FlipType.Vertical, 180)] [InlineData(RotateType.Rotate180, FlipType.Vertical, 180)]
[InlineData(RotateType.Rotate270, FlipType.Vertical, 270)] [InlineData(RotateType.Rotate270, FlipType.Vertical, 270)]
public void Rotate_degreesFloat_RotateProcessorWithAnglesSetAndExpandTrue(RotateType angle, FlipType flip, float expectedAngle) public void Rotate_degreesFloat_RotateProcessorWithAnglesSetrue(RotateType angle, FlipType flip, float expectedAngle)
{ {
this.operations.RotateFlip(angle, flip); this.operations.RotateFlip(angle, flip);
var rotateProcessor = this.Verify<RotateProcessor<Rgba32>>(0); RotateProcessor<Rgba32> rotateProcessor = this.Verify<RotateProcessor<Rgba32>>(0);
var flipProcessor = this.Verify<FlipProcessor<Rgba32>>(1); FlipProcessor<Rgba32> flipProcessor = this.Verify<FlipProcessor<Rgba32>>(1);
Assert.Equal(expectedAngle, rotateProcessor.Angle); Assert.Equal(expectedAngle, rotateProcessor.Degrees);
Assert.False(rotateProcessor.Expand);
Assert.Equal(flip, flipProcessor.FlipType); Assert.Equal(flip, flipProcessor.FlipType);
} }
} }

31
tests/ImageSharp.Tests/Processing/Transforms/RotateTests.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using Xunit; using Xunit;
@ -10,46 +9,28 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
{ {
public class RotateTests : BaseImageOperationsExtensionTest public class RotateTests : BaseImageOperationsExtensionTest
{ {
[Theory] [Theory]
[InlineData(85.6f)] [InlineData(85.6f)]
[InlineData(21)] [InlineData(21)]
public void Rotate_degreesFloat_RotateProcessorWithAnglesSetAndExpandTrue(float angle) public void RotateDegreesFloatRotateProcessorWithAnglesSet(float angle)
{ {
this.operations.Rotate(angle); this.operations.Rotate(angle);
var processor = this.Verify<RotateProcessor<Rgba32>>(); RotateProcessor<Rgba32> processor = this.Verify<RotateProcessor<Rgba32>>();
Assert.Equal(angle, processor.Angle); Assert.Equal(angle, processor.Degrees);
Assert.True(processor.Expand);
} }
[Theory] [Theory]
[InlineData(RotateType.None, 0)] [InlineData(RotateType.None, 0)]
[InlineData(RotateType.Rotate90, 90)] [InlineData(RotateType.Rotate90, 90)]
[InlineData(RotateType.Rotate180, 180)] [InlineData(RotateType.Rotate180, 180)]
[InlineData(RotateType.Rotate270, 270)] [InlineData(RotateType.Rotate270, 270)]
public void Rotate_RotateType_RotateProcessorWithAnglesConvertedFromEnumAndExpandTrue(RotateType angle, float expectedangle) public void RotateRotateTypeRotateProcessorWithAnglesConvertedFromEnum(RotateType angle, float expectedangle)
{ {
this.operations.Rotate(angle); // is this api needed ??? this.operations.Rotate(angle); // is this api needed ???
var processor = this.Verify<RotateProcessor<Rgba32>>(); RotateProcessor<Rgba32> processor = this.Verify<RotateProcessor<Rgba32>>();
Assert.Equal(expectedangle, processor.Angle);
Assert.False(processor.Expand);
}
[Theory]
[InlineData(85.6f, false)]
[InlineData(21, true)]
[InlineData(21, false)]
public void Rotate_degreesFloat_expand_RotateProcessorWithAnglesSetAndExpandSet(float angle, bool expand)
{
this.operations.Rotate(angle, expand);
var processor = this.Verify<RotateProcessor<Rgba32>>();
Assert.Equal(angle, processor.Angle); Assert.Equal(expectedangle, processor.Degrees);
Assert.Equal(expand, processor.Expand);
} }
} }
} }

21
tests/ImageSharp.Tests/Processing/Transforms/SkewTest.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors;
using Xunit; using Xunit;
@ -10,25 +9,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
public class SkewTest : BaseImageOperationsExtensionTest public class SkewTest : BaseImageOperationsExtensionTest
{ {
[Fact] [Fact]
public void Skew_x_y_CreateSkewProcessorWithAnglesSetAndExpandTrue() public void SkewXYCreateSkewProcessorWithAnglesSet()
{ {
this.operations.Skew(10, 20); this.operations.Skew(10, 20);
var processor = this.Verify<SkewProcessor<Rgba32>>(); SkewProcessor<Rgba32> processor = this.Verify<SkewProcessor<Rgba32>>();
Assert.Equal(10, processor.AngleX); Assert.Equal(10, processor.DegreesX);
Assert.Equal(20, processor.AngleY); Assert.Equal(20, processor.DegreesY);
Assert.True(processor.Expand);
}
[Fact]
public void Skew_x_y_expand_CreateSkewProcessorWithAnglesSetAndExpandTrue()
{
this.operations.Skew(10, 20, false);
var processor = this.Verify<SkewProcessor<Rgba32>>();
Assert.Equal(10, processor.AngleX);
Assert.Equal(20, processor.AngleY);
Assert.False(processor.Expand);
} }
} }
} }
Loading…
Cancel
Save