diff --git a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs
index 3c75a6418..c254eaeb3 100644
--- a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs
+++ b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
@@ -8,8 +8,15 @@ namespace SixLabors.ImageSharp
///
/// The exception that is thrown when an error occurs when applying a process to an image.
///
- public sealed class ImageProcessingException : Exception
+ public class ImageProcessingException : Exception
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ImageProcessingException()
+ {
+ }
+
///
/// Initializes a new instance of the class with the name of the
/// parameter that causes this exception.
@@ -32,4 +39,4 @@ namespace SixLabors.ImageSharp
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs
index dde7beb3e..51a110dfc 100644
--- a/src/ImageSharp/Processing/AffineTransformBuilder.cs
+++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
@@ -284,6 +284,11 @@ namespace SixLabors.ImageSharp.Processing
matrix *= factory(size);
}
+ if (TransformUtilities.IsNaN(matrix))
+ {
+ throw new DegenerateTransformException("Matrix is NaN. Check input values.");
+ }
+
return matrix;
}
@@ -299,4 +304,4 @@ namespace SixLabors.ImageSharp.Processing
return this;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs b/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs
new file mode 100644
index 000000000..970a044dc
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs
@@ -0,0 +1,42 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Transforms
+{
+ ///
+ /// Represents an error that occurs during a transform operation.
+ ///
+ public sealed class DegenerateTransformException : ImageProcessingException
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public DegenerateTransformException()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message.
+ ///
+ /// The message that describes the error.
+ public DegenerateTransformException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with a specified error message and a reference to the inner exception that is
+ /// the cause of this exception.
+ ///
+ /// The error message that explains the reason for the exception.
+ /// The exception that is the cause of the current exception, or a null reference ( in Visual Basic) if no inner exception is specified.
+ public DegenerateTransformException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs
index 0760d2e3e..329d57f3d 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs
@@ -12,6 +12,35 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
///
internal static class TransformUtilities
{
+ ///
+ /// Returns a value that indicates whether the specified matrix contains any values
+ /// that are not a number .
+ ///
+ /// The transform matrix.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static bool IsNaN(Matrix3x2 matrix)
+ {
+ return float.IsNaN(matrix.M11) || float.IsNaN(matrix.M12)
+ || float.IsNaN(matrix.M21) || float.IsNaN(matrix.M22)
+ || float.IsNaN(matrix.M31) || float.IsNaN(matrix.M32);
+ }
+
+ ///
+ /// Returns a value that indicates whether the specified matrix contains any values
+ /// that are not a number .
+ ///
+ /// The transform matrix.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static bool IsNaN(Matrix4x4 matrix)
+ {
+ return float.IsNaN(matrix.M11) || float.IsNaN(matrix.M12) || float.IsNaN(matrix.M13) || float.IsNaN(matrix.M14)
+ || float.IsNaN(matrix.M21) || float.IsNaN(matrix.M22) || float.IsNaN(matrix.M23) || float.IsNaN(matrix.M24)
+ || float.IsNaN(matrix.M31) || float.IsNaN(matrix.M32) || float.IsNaN(matrix.M33) || float.IsNaN(matrix.M34)
+ || float.IsNaN(matrix.M41) || float.IsNaN(matrix.M42) || float.IsNaN(matrix.M43) || float.IsNaN(matrix.M44);
+ }
+
///
/// Applies the projective transform against the given coordinates flattened into the 2D space.
///
diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs
index ef44dc16d..caebc34a3 100644
--- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs
+++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
@@ -300,6 +300,11 @@ namespace SixLabors.ImageSharp.Processing
matrix *= factory(size);
}
+ if (TransformUtilities.IsNaN(matrix))
+ {
+ throw new DegenerateTransformException("Matrix is NaN. Check input values.");
+ }
+
return matrix;
}
@@ -315,4 +320,4 @@ namespace SixLabors.ImageSharp.Processing
return this;
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs
index 42017f3af..70b5be73e 100644
--- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs
+++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
@@ -8,7 +8,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
{
public class AffineTransformBuilderTests : TransformBuilderTestBase
{
- protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder();
+ protected override AffineTransformBuilder CreateBuilder()
+ => new AffineTransformBuilder();
protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees)
=> builder.AppendRotationDegrees(degrees);
@@ -67,4 +68,4 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
return Vector2.Transform(sourcePoint, matrix);
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs
index 309a73fb4..22388a0ac 100644
--- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs
+++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs
@@ -1,6 +1,7 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System;
using System.Numerics;
using SixLabors.ImageSharp.Processing;
@@ -8,20 +9,25 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
{
public class ProjectiveTransformBuilderTests : TransformBuilderTestBase
{
- protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder();
+ protected override ProjectiveTransformBuilder CreateBuilder()
+ => new ProjectiveTransformBuilder();
- protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees);
+ protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees)
+ => builder.AppendRotationDegrees(degrees);
- protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin);
+ protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin)
+ => builder.AppendRotationDegrees(degrees, origin);
- protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians);
+ protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians)
+ => builder.AppendRotationRadians(radians);
- protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin);
+ protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin)
+ => builder.AppendRotationRadians(radians, origin);
protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale);
protected override void AppendSkewDegrees(ProjectiveTransformBuilder builder, float degreesX, float degreesY)
- => builder.AppendSkewDegrees(degreesX, degreesY);
+ => builder.AppendSkewDegrees(degreesX, degreesY);
protected override void AppendSkewDegrees(ProjectiveTransformBuilder builder, float degreesX, float degreesY, Vector2 origin)
=> builder.AppendSkewDegrees(degreesX, degreesY, origin);
@@ -44,7 +50,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
protected override void PrependSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY, Vector2 origin)
=> builder.PrependSkewRadians(radiansX, radiansY, origin);
- protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate);
+ protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate)
+ => builder.PrependTranslation(translate);
protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) =>
builder.PrependRotationRadians(radians, origin);
diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs
index 21359799e..8c75cea7f 100644
--- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs
+++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs
@@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
{
// These operations should be size-agnostic:
var size = new Size(123, 321);
- TBuilder builder = this.CreateBuilder(size);
+ TBuilder builder = this.CreateBuilder();
this.AppendScale(builder, new SizeF(scale));
this.AppendTranslation(builder, translate);
@@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
{
// Translate ans scale are size-agnostic:
var size = new Size(456, 432);
- TBuilder builder = this.CreateBuilder(size);
+ TBuilder builder = this.CreateBuilder();
this.AppendTranslation(builder, translate);
this.AppendScale(builder, new SizeF(scale));
@@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
public void LocationOffsetIsPrepended(int locationX, int locationY)
{
var rectangle = new Rectangle(locationX, locationY, 10, 10);
- TBuilder builder = this.CreateBuilder(rectangle);
+ TBuilder builder = this.CreateBuilder();
this.AppendScale(builder, new SizeF(2, 2));
@@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
float y)
{
var size = new Size(width, height);
- TBuilder builder = this.CreateBuilder(size);
+ TBuilder builder = this.CreateBuilder();
this.AppendRotationDegrees(builder, degrees);
@@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
float y)
{
var size = new Size(width, height);
- TBuilder builder = this.CreateBuilder(size);
+ TBuilder builder = this.CreateBuilder();
var centerPoint = new Vector2(cx, cy);
this.AppendRotationDegrees(builder, degrees, centerPoint);
@@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
float y)
{
var size = new Size(width, height);
- TBuilder builder = this.CreateBuilder(size);
+ TBuilder builder = this.CreateBuilder();
this.AppendSkewDegrees(builder, degreesX, degreesY);
@@ -176,7 +176,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
float y)
{
var size = new Size(width, height);
- TBuilder builder = this.CreateBuilder(size);
+ TBuilder builder = this.CreateBuilder();
var centerPoint = new Vector2(cx, cy);
this.AppendSkewDegrees(builder, degreesX, degreesY, centerPoint);
@@ -194,8 +194,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
public void AppendPrependOpposite()
{
var rectangle = new Rectangle(-1, -1, 3, 3);
- TBuilder b1 = this.CreateBuilder(rectangle);
- TBuilder b2 = this.CreateBuilder(rectangle);
+ TBuilder b1 = this.CreateBuilder();
+ TBuilder b2 = this.CreateBuilder();
const float pi = (float)Math.PI;
@@ -232,14 +232,24 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
Assert.ThrowsAny(
() =>
{
- TBuilder builder = this.CreateBuilder(size);
+ TBuilder builder = this.CreateBuilder();
this.Execute(builder, new Rectangle(Point.Empty, size), Vector2.Zero);
});
}
- protected TBuilder CreateBuilder(Size size) => this.CreateBuilder(new Rectangle(Point.Empty, size));
+ [Fact]
+ public void ThrowsForInvalidMatrix()
+ {
+ Assert.ThrowsAny(
+ () =>
+ {
+ TBuilder builder = this.CreateBuilder();
+ this.AppendSkewDegrees(builder, 45, 45);
+ this.Execute(builder, new Rectangle(0, 0, 150, 150), Vector2.Zero);
+ });
+ }
- protected abstract TBuilder CreateBuilder(Rectangle rectangle);
+ protected abstract TBuilder CreateBuilder();
protected abstract void AppendRotationDegrees(TBuilder builder, float degrees);