diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs
index c1e11a1d42..84d0d2ea1d 100644
--- a/src/ImageSharp/Processing/AffineTransformBuilder.cs
+++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs
@@ -349,6 +349,16 @@ public class AffineTransformBuilder
internal static SizeF GetTransformedSize(Rectangle sourceRectangle, Matrix3x2 matrix)
=> TransformUtilities.GetRawTransformedSize(matrix, sourceRectangle.Size);
+ ///
+ /// Clears all accumulated transform matrices, resetting the builder to its initial state.
+ ///
+ /// The .
+ public AffineTransformBuilder Clear()
+ {
+ this.transformMatrixFactories.Clear();
+ return this;
+ }
+
private static void CheckDegenerate(Matrix3x2 matrix)
{
if (TransformUtilities.IsDegenerate(matrix))
diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs
index e40a307a3d..74da440401 100644
--- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs
+++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs
@@ -397,6 +397,16 @@ public class ProjectiveTransformBuilder
internal static SizeF GetTransformedSize(Rectangle sourceRectangle, Matrix4x4 matrix)
=> TransformUtilities.GetRawTransformedSize(matrix, sourceRectangle.Size);
+ ///
+ /// Clears all accumulated transform matrices, resetting the builder to its initial state.
+ ///
+ /// The .
+ public ProjectiveTransformBuilder Clear()
+ {
+ this.transformMatrixFactories.Clear();
+ return this;
+ }
+
private static void CheckDegenerate(Matrix4x4 matrix)
{
if (TransformUtilities.IsDegenerate(matrix))
diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs
index 232571d4d0..d0e4cf5663 100644
--- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs
+++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs
@@ -58,6 +58,9 @@ public class AffineTransformBuilderTests : TransformBuilderTestBase builder.PrependTranslation(translate);
+ protected override void ClearBuilder(AffineTransformBuilder builder)
+ => builder.Clear();
+
protected override Vector2 Execute(
AffineTransformBuilder builder,
Rectangle rectangle,
diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs
index a0380033fd..dcc6533163 100644
--- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs
+++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs
@@ -55,6 +55,9 @@ public class ProjectiveTransformBuilderTests : TransformBuilderTestBase
builder.PrependRotationRadians(radians, origin);
+ protected override void ClearBuilder(ProjectiveTransformBuilder builder)
+ => builder.Clear();
+
protected override Vector2 Execute(
ProjectiveTransformBuilder builder,
Rectangle rectangle,
diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs
index 73215b1c6f..12f8326fc7 100644
--- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs
+++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs
@@ -248,6 +248,48 @@ public abstract class TransformBuilderTestBase
});
}
+ [Fact]
+ public void Clear_ResetsBuilderToIdentity()
+ {
+ Size size = new(100, 100);
+ Rectangle rectangle = new(Point.Empty, size);
+ Vector2 source = new(10, 20);
+
+ TBuilder builder = this.CreateBuilder();
+
+ // Apply a transform that changes the point.
+ this.AppendScale(builder, new SizeF(2, 3));
+ this.AppendTranslation(builder, new PointF(50, 50));
+ Vector2 transformed = this.Execute(builder, rectangle, source);
+ Assert.NotEqual(source, transformed, Comparer);
+
+ // Clear and verify the builder produces identity behavior.
+ this.ClearBuilder(builder);
+ Vector2 afterClear = this.Execute(builder, rectangle, source);
+ Assert.Equal(source, afterClear, Comparer);
+ }
+
+ [Fact]
+ public void Clear_AllowsReuse()
+ {
+ Size size = new(100, 100);
+ Rectangle rectangle = new(Point.Empty, size);
+ Vector2 source = new(10, 20);
+
+ TBuilder builder = this.CreateBuilder();
+
+ // First transform: scale by 2.
+ this.AppendScale(builder, new SizeF(2, 2));
+ Vector2 scaled = this.Execute(builder, rectangle, source);
+ Assert.Equal(new Vector2(20, 40), scaled, Comparer);
+
+ // Clear and apply a different transform: translate.
+ this.ClearBuilder(builder);
+ this.AppendTranslation(builder, new PointF(5, 10));
+ Vector2 translated = this.Execute(builder, rectangle, source);
+ Assert.Equal(new Vector2(15, 30), translated, Comparer);
+ }
+
protected abstract TBuilder CreateBuilder();
protected abstract void AppendRotationDegrees(TBuilder builder, float degrees);
@@ -282,5 +324,7 @@ public abstract class TransformBuilderTestBase
protected abstract void PrependTranslation(TBuilder builder, PointF translate);
+ protected abstract void ClearBuilder(TBuilder builder);
+
protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint);
}