@@ -11,7 +11,8 @@ namespace SixLabors.ImageSharp.Processing;
11
11
/// </summary>
12
12
public class AffineTransformBuilder
13
13
{
14
- private readonly List < Func < Size , Matrix3x2 > > matrixFactories = new List < Func < Size , Matrix3x2 > > ( ) ;
14
+ private readonly List < Func < Size , Matrix3x2 > > transformMatrixFactories = new ( ) ;
15
+ private readonly List < Func < Size , Matrix3x2 > > boundsMatrixFactories = new ( ) ;
15
16
16
17
/// <summary>
17
18
/// Prepends a rotation matrix using the given rotation angle in degrees
@@ -29,7 +30,9 @@ public AffineTransformBuilder PrependRotationDegrees(float degrees)
29
30
/// <param name="radians">The amount of rotation, in radians.</param>
30
31
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
31
32
public AffineTransformBuilder PrependRotationRadians ( float radians )
32
- => this . Prepend ( size => TransformUtils . CreateRotationMatrixRadians ( radians , size ) ) ;
33
+ => this . Prepend (
34
+ size => TransformUtils . CreateRotationTransformMatrixRadians ( radians , size ) ,
35
+ size => TransformUtils . CreateRotationBoundsMatrixRadians ( radians , size ) ) ;
33
36
34
37
/// <summary>
35
38
/// Prepends a rotation matrix using the given rotation in degrees at the given origin.
@@ -65,7 +68,9 @@ public AffineTransformBuilder AppendRotationDegrees(float degrees)
65
68
/// <param name="radians">The amount of rotation, in radians.</param>
66
69
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
67
70
public AffineTransformBuilder AppendRotationRadians ( float radians )
68
- => this . Append ( size => TransformUtils . CreateRotationMatrixRadians ( radians , size ) ) ;
71
+ => this . Append (
72
+ size => TransformUtils . CreateRotationTransformMatrixRadians ( radians , size ) ,
73
+ size => TransformUtils . CreateRotationBoundsMatrixRadians ( radians , size ) ) ;
69
74
70
75
/// <summary>
71
76
/// Appends a rotation matrix using the given rotation in degrees at the given origin.
@@ -140,7 +145,9 @@ public AffineTransformBuilder AppendScale(Vector2 scales)
140
145
/// <param name="degreesY">The Y angle, in degrees.</param>
141
146
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
142
147
public AffineTransformBuilder PrependSkewDegrees ( float degreesX , float degreesY )
143
- => this . Prepend ( size => TransformUtils . CreateSkewMatrixDegrees ( degreesX , degreesY , size ) ) ;
148
+ => this . Prepend (
149
+ size => TransformUtils . CreateSkewTransformMatrixDegrees ( degreesX , degreesY , size ) ,
150
+ size => TransformUtils . CreateSkewBoundsMatrixDegrees ( degreesX , degreesY , size ) ) ;
144
151
145
152
/// <summary>
146
153
/// Prepends a centered skew matrix from the give angles in radians.
@@ -149,7 +156,9 @@ public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY)
149
156
/// <param name="radiansY">The Y angle, in radians.</param>
150
157
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
151
158
public AffineTransformBuilder PrependSkewRadians ( float radiansX , float radiansY )
152
- => this . Prepend ( size => TransformUtils . CreateSkewMatrixRadians ( radiansX , radiansY , size ) ) ;
159
+ => this . Prepend (
160
+ size => TransformUtils . CreateSkewTransformMatrixRadians ( radiansX , radiansY , size ) ,
161
+ size => TransformUtils . CreateSkewBoundsMatrixRadians ( radiansX , radiansY , size ) ) ;
153
162
154
163
/// <summary>
155
164
/// Prepends a skew matrix using the given angles in degrees at the given origin.
@@ -178,7 +187,9 @@ public AffineTransformBuilder PrependSkewRadians(float radiansX, float radiansY,
178
187
/// <param name="degreesY">The Y angle, in degrees.</param>
179
188
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
180
189
public AffineTransformBuilder AppendSkewDegrees ( float degreesX , float degreesY )
181
- => this . Append ( size => TransformUtils . CreateSkewMatrixDegrees ( degreesX , degreesY , size ) ) ;
190
+ => this . Append (
191
+ size => TransformUtils . CreateSkewTransformMatrixDegrees ( degreesX , degreesY , size ) ,
192
+ size => TransformUtils . CreateSkewBoundsMatrixDegrees ( degreesX , degreesY , size ) ) ;
182
193
183
194
/// <summary>
184
195
/// Appends a centered skew matrix from the give angles in radians.
@@ -187,7 +198,9 @@ public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY)
187
198
/// <param name="radiansY">The Y angle, in radians.</param>
188
199
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
189
200
public AffineTransformBuilder AppendSkewRadians ( float radiansX , float radiansY )
190
- => this . Append ( size => TransformUtils . CreateSkewMatrixRadians ( radiansX , radiansY , size ) ) ;
201
+ => this . Append (
202
+ size => TransformUtils . CreateSkewTransformMatrixRadians ( radiansX , radiansY , size ) ,
203
+ size => TransformUtils . CreateSkewBoundsMatrixRadians ( radiansX , radiansY , size ) ) ;
191
204
192
205
/// <summary>
193
206
/// Appends a skew matrix using the given angles in degrees at the given origin.
@@ -254,7 +267,7 @@ public AffineTransformBuilder AppendTranslation(Vector2 position)
254
267
public AffineTransformBuilder PrependMatrix ( Matrix3x2 matrix )
255
268
{
256
269
CheckDegenerate ( matrix ) ;
257
- return this . Prepend ( _ => matrix ) ;
270
+ return this . Prepend ( _ => matrix , _ => matrix ) ;
258
271
}
259
272
260
273
/// <summary>
@@ -270,7 +283,7 @@ public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix)
270
283
public AffineTransformBuilder AppendMatrix ( Matrix3x2 matrix )
271
284
{
272
285
CheckDegenerate ( matrix ) ;
273
- return this . Append ( _ => matrix ) ;
286
+ return this . Append ( _ => matrix , _ => matrix ) ;
274
287
}
275
288
276
289
/// <summary>
@@ -281,7 +294,7 @@ public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix)
281
294
public Matrix3x2 BuildMatrix ( Size sourceSize ) => this . BuildMatrix ( new Rectangle ( Point . Empty , sourceSize ) ) ;
282
295
283
296
/// <summary>
284
- /// Returns the combined matrix for a given source rectangle.
297
+ /// Returns the combined transform matrix for a given source rectangle.
285
298
/// </summary>
286
299
/// <param name="sourceRectangle">The rectangle in the source image.</param>
287
300
/// <exception cref="DegenerateTransformException">
@@ -296,11 +309,11 @@ public Matrix3x2 BuildMatrix(Rectangle sourceRectangle)
296
309
Guard . MustBeGreaterThan ( sourceRectangle . Height , 0 , nameof ( sourceRectangle ) ) ;
297
310
298
311
// Translate the origin matrix to cater for source rectangle offsets.
299
- var matrix = Matrix3x2 . CreateTranslation ( - sourceRectangle . Location ) ;
312
+ Matrix3x2 matrix = Matrix3x2 . CreateTranslation ( - sourceRectangle . Location ) ;
300
313
301
314
Size size = sourceRectangle . Size ;
302
315
303
- foreach ( Func < Size , Matrix3x2 > factory in this . matrixFactories )
316
+ foreach ( Func < Size , Matrix3x2 > factory in this . transformMatrixFactories )
304
317
{
305
318
matrix *= factory ( size ) ;
306
319
}
@@ -310,6 +323,32 @@ public Matrix3x2 BuildMatrix(Rectangle sourceRectangle)
310
323
return matrix ;
311
324
}
312
325
326
+ /// <summary>
327
+ /// Returns the size of a rectangle large enough to contain the transformed source rectangle.
328
+ /// </summary>
329
+ /// <param name="sourceRectangle">The rectangle in the source image.</param>
330
+ /// <exception cref="DegenerateTransformException">
331
+ /// The resultant matrix is degenerate containing one or more values equivalent
332
+ /// to <see cref="float.NaN"/> or a zero determinant and therefore cannot be used
333
+ /// for linear transforms.
334
+ /// </exception>
335
+ /// <returns>The <see cref="Size"/>.</returns>
336
+ public Size GetTransformedSize ( Rectangle sourceRectangle )
337
+ {
338
+ Size size = sourceRectangle . Size ;
339
+
340
+ // Translate the origin matrix to cater for source rectangle offsets.
341
+ Matrix3x2 matrix = Matrix3x2 . CreateTranslation ( - sourceRectangle . Location ) ;
342
+
343
+ foreach ( Func < Size , Matrix3x2 > factory in this . boundsMatrixFactories )
344
+ {
345
+ matrix *= factory ( size ) ;
346
+ CheckDegenerate ( matrix ) ;
347
+ }
348
+
349
+ return TransformUtils . GetTransformedSize ( size , matrix ) ;
350
+ }
351
+
313
352
private static void CheckDegenerate ( Matrix3x2 matrix )
314
353
{
315
354
if ( TransformUtils . IsDegenerate ( matrix ) )
@@ -318,15 +357,17 @@ private static void CheckDegenerate(Matrix3x2 matrix)
318
357
}
319
358
}
320
359
321
- private AffineTransformBuilder Prepend ( Func < Size , Matrix3x2 > factory )
360
+ private AffineTransformBuilder Prepend ( Func < Size , Matrix3x2 > transformFactory , Func < Size , Matrix3x2 > boundsFactory )
322
361
{
323
- this . matrixFactories . Insert ( 0 , factory ) ;
362
+ this . transformMatrixFactories . Insert ( 0 , transformFactory ) ;
363
+ this . boundsMatrixFactories . Insert ( 0 , boundsFactory ) ;
324
364
return this ;
325
365
}
326
366
327
- private AffineTransformBuilder Append ( Func < Size , Matrix3x2 > factory )
367
+ private AffineTransformBuilder Append ( Func < Size , Matrix3x2 > transformFactory , Func < Size , Matrix3x2 > boundsFactory )
328
368
{
329
- this . matrixFactories . Add ( factory ) ;
369
+ this . transformMatrixFactories . Add ( transformFactory ) ;
370
+ this . boundsMatrixFactories . Add ( boundsFactory ) ;
330
371
return this ;
331
372
}
332
373
}
0 commit comments