Skip to content

Commit 9f59241

Browse files
Merge pull request #1118 from SixLabors/js/faster-transforms
Faster Transforms
2 parents 91b899f + c1b4bbd commit 9f59241

File tree

58 files changed

+1126
-1069
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1126
-1069
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) Six Labors and contributors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
using System.Reflection;
6+
using System.Runtime.CompilerServices;
7+
using SixLabors.ImageSharp;
8+
9+
namespace SixLabors
10+
{
11+
internal static partial class Guard
12+
{
13+
/// <summary>
14+
/// Ensures that the value is a value type.
15+
/// </summary>
16+
/// <param name="value">The target object, which cannot be null.</param>
17+
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
18+
/// <typeparam name="TValue">The type of the value.</typeparam>
19+
/// <exception cref="ArgumentException"><paramref name="value"/> is not a value type.</exception>
20+
[MethodImpl(InliningOptions.ShortMethod)]
21+
public static void MustBeValueType<TValue>(TValue value, string parameterName)
22+
{
23+
if (!value.GetType().GetTypeInfo().IsValueType)
24+
{
25+
ThrowArgumentException("Type must be a struct.", parameterName);
26+
}
27+
}
28+
}
29+
}

src/ImageSharp/Common/Helpers/ImageMaths.cs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -242,40 +242,6 @@ public static float SinC(float f)
242242
return 1F;
243243
}
244244

245-
/// <summary>
246-
/// Returns the result of a B-C filter against the given value.
247-
/// <see href="http://www.imagemagick.org/Usage/filter/#cubic_bc"/>
248-
/// </summary>
249-
/// <param name="x">The value to process.</param>
250-
/// <param name="b">The B-Spline curve variable.</param>
251-
/// <param name="c">The Cardinal curve variable.</param>
252-
/// <returns>
253-
/// The <see cref="float"/>.
254-
/// </returns>
255-
[MethodImpl(InliningOptions.ShortMethod)]
256-
public static float GetBcValue(float x, float b, float c)
257-
{
258-
if (x < 0F)
259-
{
260-
x = -x;
261-
}
262-
263-
float temp = x * x;
264-
if (x < 1F)
265-
{
266-
x = ((12 - (9 * b) - (6 * c)) * (x * temp)) + ((-18 + (12 * b) + (6 * c)) * temp) + (6 - (2 * b));
267-
return x / 6F;
268-
}
269-
270-
if (x < 2F)
271-
{
272-
x = ((-b - (6 * c)) * (x * temp)) + (((6 * b) + (30 * c)) * temp) + (((-12 * b) - (48 * c)) * x) + ((8 * b) + (24 * c));
273-
return x / 6F;
274-
}
275-
276-
return 0F;
277-
}
278-
279245
/// <summary>
280246
/// Gets the bounding <see cref="Rectangle"/> from the given points.
281247
/// </summary>

src/ImageSharp/Processing/AffineTransformBuilder.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public AffineTransformBuilder PrependRotationDegrees(float degrees)
3131
/// <param name="radians">The amount of rotation, in radians.</param>
3232
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
3333
public AffineTransformBuilder PrependRotationRadians(float radians)
34-
=> this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size));
34+
=> this.Prepend(size => TransformUtilities.CreateRotationMatrixRadians(radians, size));
3535

3636
/// <summary>
3737
/// Prepends a rotation matrix using the given rotation in degrees at the given origin.
@@ -67,7 +67,7 @@ public AffineTransformBuilder AppendRotationDegrees(float degrees)
6767
/// <param name="radians">The amount of rotation, in radians.</param>
6868
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
6969
public AffineTransformBuilder AppendRotationRadians(float radians)
70-
=> this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size));
70+
=> this.Append(size => TransformUtilities.CreateRotationMatrixRadians(radians, size));
7171

7272
/// <summary>
7373
/// Appends a rotation matrix using the given rotation in degrees at the given origin.
@@ -142,7 +142,7 @@ public AffineTransformBuilder AppendScale(Vector2 scales)
142142
/// <param name="degreesY">The Y angle, in degrees.</param>
143143
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
144144
public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY)
145-
=> this.Prepend(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size));
145+
=> this.Prepend(size => TransformUtilities.CreateSkewMatrixDegrees(degreesX, degreesY, size));
146146

147147
/// <summary>
148148
/// Prepends a centered skew matrix from the give angles in radians.
@@ -151,7 +151,7 @@ public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY)
151151
/// <param name="radiansY">The Y angle, in radians.</param>
152152
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
153153
public AffineTransformBuilder PrependSkewRadians(float radiansX, float radiansY)
154-
=> this.Prepend(size => TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size));
154+
=> this.Prepend(size => TransformUtilities.CreateSkewMatrixRadians(radiansX, radiansY, size));
155155

156156
/// <summary>
157157
/// Prepends a skew matrix using the given angles in degrees at the given origin.
@@ -180,7 +180,7 @@ public AffineTransformBuilder PrependSkewRadians(float radiansX, float radiansY,
180180
/// <param name="degreesY">The Y angle, in degrees.</param>
181181
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
182182
public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY)
183-
=> this.Append(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size));
183+
=> this.Append(size => TransformUtilities.CreateSkewMatrixDegrees(degreesX, degreesY, size));
184184

185185
/// <summary>
186186
/// Appends a centered skew matrix from the give angles in radians.
@@ -189,7 +189,7 @@ public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY)
189189
/// <param name="radiansY">The Y angle, in radians.</param>
190190
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
191191
public AffineTransformBuilder AppendSkewRadians(float radiansX, float radiansY)
192-
=> this.Append(size => TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size));
192+
=> this.Append(size => TransformUtilities.CreateSkewMatrixRadians(radiansX, radiansY, size));
193193

194194
/// <summary>
195195
/// Appends a skew matrix using the given angles in degrees at the given origin.

src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public static IImageProcessingContext Transform(
5252
IResampler sampler)
5353
{
5454
Matrix3x2 transform = builder.BuildMatrix(sourceRectangle);
55-
Size targetDimensions = TransformUtils.GetTransformedSize(sourceRectangle.Size, transform);
55+
Size targetDimensions = TransformUtilities.GetTransformedSize(sourceRectangle.Size, transform);
5656
return ctx.Transform(sourceRectangle, transform, targetDimensions, sampler);
5757
}
5858

@@ -116,7 +116,7 @@ public static IImageProcessingContext Transform(
116116
IResampler sampler)
117117
{
118118
Matrix4x4 transform = builder.BuildMatrix(sourceRectangle);
119-
Size targetDimensions = TransformUtils.GetTransformedSize(sourceRectangle.Size, transform);
119+
Size targetDimensions = TransformUtilities.GetTransformedSize(sourceRectangle.Size, transform);
120120
return ctx.Transform(sourceRectangle, transform, targetDimensions, sampler);
121121
}
122122

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Six Labors and contributors.
1+
// Copyright (c) Six Labors and contributors.
22
// Licensed under the Apache License, Version 2.0.
33

44
using SixLabors.ImageSharp.Processing.Processors.Transforms;
@@ -13,86 +13,86 @@ public static class KnownResamplers
1313
/// <summary>
1414
/// Gets the Bicubic sampler that implements the bicubic kernel algorithm W(x)
1515
/// </summary>
16-
public static IResampler Bicubic { get; } = new BicubicResampler();
16+
public static IResampler Bicubic { get; } = default(BicubicResampler);
1717

1818
/// <summary>
1919
/// Gets the Box sampler that implements the box algorithm. Similar to nearest neighbor when upscaling.
2020
/// When downscaling the pixels will average, merging pixels together.
2121
/// </summary>
22-
public static IResampler Box { get; } = new BoxResampler();
22+
public static IResampler Box { get; } = default(BoxResampler);
2323

2424
/// <summary>
2525
/// Gets the Catmull-Rom sampler, a well known standard Cubic Filter often used as a interpolation function
2626
/// </summary>
27-
public static IResampler CatmullRom { get; } = new CatmullRomResampler();
27+
public static IResampler CatmullRom { get; } = CubicResampler.CatmullRom;
2828

2929
/// <summary>
3030
/// Gets the Hermite sampler. A type of smoothed triangular interpolation filter that rounds off strong edges while
3131
/// preserving flat 'color levels' in the original image.
3232
/// </summary>
33-
public static IResampler Hermite { get; } = new HermiteResampler();
33+
public static IResampler Hermite { get; } = CubicResampler.Hermite;
3434

3535
/// <summary>
3636
/// Gets the Lanczos kernel sampler that implements smooth interpolation with a radius of 2 pixels.
3737
/// This algorithm provides sharpened results when compared to others when downsampling.
3838
/// </summary>
39-
public static IResampler Lanczos2 { get; } = new Lanczos2Resampler();
39+
public static IResampler Lanczos2 { get; } = LanczosResampler.Lanczos2;
4040

4141
/// <summary>
4242
/// Gets the Lanczos kernel sampler that implements smooth interpolation with a radius of 3 pixels
4343
/// This algorithm provides sharpened results when compared to others when downsampling.
4444
/// </summary>
45-
public static IResampler Lanczos3 { get; } = new Lanczos3Resampler();
45+
public static IResampler Lanczos3 { get; } = LanczosResampler.Lanczos3;
4646

4747
/// <summary>
4848
/// Gets the Lanczos kernel sampler that implements smooth interpolation with a radius of 5 pixels
4949
/// This algorithm provides sharpened results when compared to others when downsampling.
5050
/// </summary>
51-
public static IResampler Lanczos5 { get; } = new Lanczos5Resampler();
51+
public static IResampler Lanczos5 { get; } = LanczosResampler.Lanczos5;
5252

5353
/// <summary>
5454
/// Gets the Lanczos kernel sampler that implements smooth interpolation with a radius of 8 pixels
5555
/// This algorithm provides sharpened results when compared to others when downsampling.
5656
/// </summary>
57-
public static IResampler Lanczos8 { get; } = new Lanczos8Resampler();
57+
public static IResampler Lanczos8 { get; } = LanczosResampler.Lanczos8;
5858

5959
/// <summary>
6060
/// Gets the Mitchell-Netravali sampler. This seperable cubic algorithm yields a very good equilibrium between
6161
/// detail preservation (sharpness) and smoothness.
6262
/// </summary>
63-
public static IResampler MitchellNetravali { get; } = new MitchellNetravaliResampler();
63+
public static IResampler MitchellNetravali { get; } = CubicResampler.MitchellNetravali;
6464

6565
/// <summary>
6666
/// Gets the Nearest-Neighbour sampler that implements the nearest neighbor algorithm. This uses a very fast, unscaled filter
6767
/// which will select the closest pixel to the new pixels position.
6868
/// </summary>
69-
public static IResampler NearestNeighbor { get; } = new NearestNeighborResampler();
69+
public static IResampler NearestNeighbor { get; } = default(NearestNeighborResampler);
7070

7171
/// <summary>
7272
/// Gets the Robidoux sampler. This algorithm developed by Nicolas Robidoux providing a very good equilibrium between
7373
/// detail preservation (sharpness) and smoothness comparable to <see cref="MitchellNetravali"/>.
7474
/// </summary>
75-
public static IResampler Robidoux { get; } = new RobidouxResampler();
75+
public static IResampler Robidoux { get; } = CubicResampler.Robidoux;
7676

7777
/// <summary>
7878
/// Gets the Robidoux Sharp sampler. A sharpened form of the <see cref="Robidoux"/> sampler
7979
/// </summary>
80-
public static IResampler RobidouxSharp { get; } = new RobidouxSharpResampler();
80+
public static IResampler RobidouxSharp { get; } = CubicResampler.RobidouxSharp;
8181

8282
/// <summary>
83-
/// Gets the Spline sampler. A seperable cubic algorithm similar to <see cref="MitchellNetravali"/> but yielding smoother results.
83+
/// Gets the Spline sampler. A separable cubic algorithm similar to <see cref="MitchellNetravali"/> but yielding smoother results.
8484
/// </summary>
85-
public static IResampler Spline { get; } = new SplineResampler();
85+
public static IResampler Spline { get; } = CubicResampler.Spline;
8686

8787
/// <summary>
8888
/// Gets the Triangle sampler, otherwise known as Bilinear. This interpolation algorithm can be used where perfect image transformation
8989
/// with pixel matching is impossible, so that one can calculate and assign appropriate intensity values to pixels
9090
/// </summary>
91-
public static IResampler Triangle { get; } = new TriangleResampler();
91+
public static IResampler Triangle { get; } = default(TriangleResampler);
9292

9393
/// <summary>
9494
/// Gets the Welch sampler. A high speed algorithm that delivers very sharpened results.
9595
/// </summary>
96-
public static IResampler Welch { get; } = new WelchResampler();
96+
public static IResampler Welch { get; } = default(WelchResampler);
9797
}
98-
}
98+
}

src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ public void Dispose()
110110
}
111111

112112
/// <summary>
113-
/// Gets the size of the target image.
113+
/// Gets the size of the destination image.
114114
/// </summary>
115115
/// <returns>The <see cref="Size"/>.</returns>
116-
protected abstract Size GetTargetSize();
116+
protected abstract Size GetDestinationSize();
117117

118118
/// <summary>
119119
/// This method is called before the process is applied to prepare the processor.
@@ -168,21 +168,21 @@ protected virtual void Dispose(bool disposing)
168168
private Image<TPixel> CreateTarget()
169169
{
170170
Image<TPixel> source = this.Source;
171-
Size targetSize = this.GetTargetSize();
171+
Size destinationSize = this.GetDestinationSize();
172172

173173
// We will always be creating the clone even for mutate because we may need to resize the canvas.
174-
var targetFrames = new ImageFrame<TPixel>[source.Frames.Count];
175-
for (int i = 0; i < targetFrames.Length; i++)
174+
var destinationFrames = new ImageFrame<TPixel>[source.Frames.Count];
175+
for (int i = 0; i < destinationFrames.Length; i++)
176176
{
177-
targetFrames[i] = new ImageFrame<TPixel>(
177+
destinationFrames[i] = new ImageFrame<TPixel>(
178178
this.Configuration,
179-
targetSize.Width,
180-
targetSize.Height,
179+
destinationSize.Width,
180+
destinationSize.Height,
181181
source.Frames[i].Metadata.DeepClone());
182182
}
183183

184184
// Use the overload to prevent an extra frame being added.
185-
return new Image<TPixel>(this.Configuration, source.Metadata.DeepClone(), targetFrames);
185+
return new Image<TPixel>(this.Configuration, source.Metadata.DeepClone(), destinationFrames);
186186
}
187187

188188
private void CheckFrameCount(Image<TPixel> a, Image<TPixel> b)

0 commit comments

Comments
 (0)