diff --git a/src/ImageSharp/DefaultInternalImageProcessorContext.cs b/src/ImageSharp/DefaultInternalImageProcessorContext.cs
index 6e6feed84e..cdfd582be0 100644
--- a/src/ImageSharp/DefaultInternalImageProcessorContext.cs
+++ b/src/ImageSharp/DefaultInternalImageProcessorContext.cs
@@ -46,6 +46,9 @@ namespace SixLabors.ImageSharp
return this.destination;
}
+ ///
+ public Rectangle Bounds() => this.source.Bounds();
+
///
public IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle)
{
@@ -70,7 +73,7 @@ namespace SixLabors.ImageSharp
///
public IImageProcessingContext ApplyProcessor(IImageProcessor processor)
{
- return this.ApplyProcessor(processor, this.source.Bounds());
+ return this.ApplyProcessor(processor, this.Bounds());
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/IImageProcessingContext{TPixel}.cs b/src/ImageSharp/IImageProcessingContext{TPixel}.cs
index 552e8d579d..281c925673 100644
--- a/src/ImageSharp/IImageProcessingContext{TPixel}.cs
+++ b/src/ImageSharp/IImageProcessingContext{TPixel}.cs
@@ -14,6 +14,12 @@ namespace SixLabors.ImageSharp
public interface IImageProcessingContext
where TPixel : struct, IPixel
{
+ ///
+ /// Gets the source image bounds
+ ///
+ /// The
+ Rectangle Bounds();
+
///
/// Adds the processor to the current set of image operations to be applied.
///
@@ -40,7 +46,7 @@ namespace SixLabors.ImageSharp
///
/// Adds the processors to the current image
///
- /// The current image or a new image depending on withere this is alloed to mutate the source image.
+ /// The current image or a new image depending on whether this is allowed to mutate the source image.
Image Apply();
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs
index 5ea23726e8..b39ae9e6a9 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs
@@ -21,27 +21,6 @@ namespace SixLabors.ImageSharp.Processing.Processors
internal class AffineTransformProcessor : InterpolatedTransformProcessorBase
where TPixel : struct, IPixel
{
- private Size targetDimensions;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The transform matrix
- public AffineTransformProcessor(Matrix3x2 matrix)
- : this(matrix, KnownResamplers.Bicubic)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The transform matrix
- /// The sampler to perform the transform operation.
- public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler)
- : this(matrix, sampler, Size.Empty)
- {
- }
-
///
/// Initializes a new instance of the class.
///
@@ -52,7 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
: base(sampler)
{
this.TransformMatrix = matrix;
- this.targetDimensions = targetDimensions;
+ this.TargetDimensions = targetDimensions;
}
///
@@ -60,18 +39,17 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
public Matrix3x2 TransformMatrix { get; }
+ ///
+ /// Gets the target dimensions to constrain the transformed image to
+ ///
+ public Size TargetDimensions { get; }
+
///
protected override Image CreateDestination(Image source, Rectangle sourceRectangle)
{
- if (this.targetDimensions == Size.Empty)
- {
- // TODO: CreateDestination() should not modify the processors state! (kinda CQRS)
- this.targetDimensions = this.GetTransformedDimensions(sourceRectangle.Size, this.TransformMatrix);
- }
-
// We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable> frames =
- source.Frames.Select(x => new ImageFrame(this.targetDimensions, x.MetaData.Clone()));
+ source.Frames.Select(x => new ImageFrame(this.TargetDimensions, x.MetaData.Clone()));
// Use the overload to prevent an extra frame being added
return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames);
@@ -84,8 +62,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
Rectangle sourceRectangle,
Configuration configuration)
{
- int height = this.targetDimensions.Height;
- int width = this.targetDimensions.Width;
+ int height = this.TargetDimensions.Height;
+ int width = this.TargetDimensions.Width;
Rectangle sourceBounds = source.Bounds();
var targetBounds = new Rectangle(0, 0, width, height);
@@ -205,8 +183,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
var vector = source[i, j].ToVector4();
// Values are first premultiplied to prevent darkening of edge pixels
- Vector4 mupltiplied = vector.Premultiply();
- sum += mupltiplied * xWeight * yWeight;
+ Vector4 multiplied = vector.Premultiply();
+ sum += multiplied * xWeight * yWeight;
}
}
@@ -231,16 +209,5 @@ namespace SixLabors.ImageSharp.Processing.Processors
{
return this.TransformMatrix;
}
-
- ///
- /// Gets the bounding relative to the source for the given transformation matrix.
- ///
- /// The source rectangle.
- /// The transformation matrix.
- /// The
- protected virtual Size GetTransformedDimensions(Size sourceDimensions, Matrix3x2 matrix)
- {
- return sourceDimensions;
- }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs
index c39311bc33..7f811eebc1 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs
@@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
protected override void BeforeImageApply(Image source, Rectangle sourceRectangle)
{
Orientation orientation = GetExifOrientation(source);
-
+ Size size = sourceRectangle.Size;
switch (orientation)
{
case Orientation.TopRight:
@@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
break;
case Orientation.BottomRight:
- new RotateProcessor((int)RotateType.Rotate180).Apply(source, sourceRectangle);
+ new RotateProcessor((int)RotateType.Rotate180, size).Apply(source, sourceRectangle);
break;
case Orientation.BottomLeft:
@@ -35,21 +35,21 @@ namespace SixLabors.ImageSharp.Processing.Processors
break;
case Orientation.LeftTop:
- new RotateProcessor((int)RotateType.Rotate90).Apply(source, sourceRectangle);
+ new RotateProcessor((int)RotateType.Rotate90, size).Apply(source, sourceRectangle);
new FlipProcessor(FlipType.Horizontal).Apply(source, sourceRectangle);
break;
case Orientation.RightTop:
- new RotateProcessor((int)RotateType.Rotate90).Apply(source, sourceRectangle);
+ new RotateProcessor((int)RotateType.Rotate90, size).Apply(source, sourceRectangle);
break;
case Orientation.RightBottom:
new FlipProcessor(FlipType.Vertical).Apply(source, sourceRectangle);
- new RotateProcessor((int)RotateType.Rotate270).Apply(source, sourceRectangle);
+ new RotateProcessor((int)RotateType.Rotate270, size).Apply(source, sourceRectangle);
break;
case Orientation.LeftBottom:
- new RotateProcessor((int)RotateType.Rotate270).Apply(source, sourceRectangle);
+ new RotateProcessor((int)RotateType.Rotate270, size).Apply(source, sourceRectangle);
break;
case Orientation.Unknown:
diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs
index 1e24b7c280..6b8314d172 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs
@@ -19,8 +19,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
/// The transform matrix
/// The sampler to perform the transform operation.
- protected CenteredAffineTransformProcessor(Matrix3x2 matrix, IResampler sampler)
- : base(matrix, sampler)
+ /// The source image size
+ protected CenteredAffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size sourceSize)
+ : base(matrix, sampler, GetTransformedDimensions(sourceSize, matrix))
{
}
@@ -30,11 +31,10 @@ namespace SixLabors.ImageSharp.Processing.Processors
return TransformHelpers.GetCenteredTransformMatrix(sourceRectangle, destinationRectangle, this.TransformMatrix);
}
- ///
- protected override Size GetTransformedDimensions(Size sourceDimensions, Matrix3x2 matrix)
+ private static Size GetTransformedDimensions(Size sourceDimensions, Matrix3x2 matrix)
{
var sourceRectangle = new Rectangle(0, 0, sourceDimensions.Width, sourceDimensions.Height);
- return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, this.TransformMatrix).Size;
+ return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix).Size;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs
index 92a008d7ab..081ea84610 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs
@@ -19,8 +19,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
/// The transform matrix
/// The sampler to perform the transform operation.
- protected CenteredProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler)
- : base(matrix, sampler)
+ /// The source image size
+ protected CenteredProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size sourceSize)
+ : base(matrix, sampler, GetTransformedDimensions(sourceSize, matrix))
{
}
@@ -30,11 +31,10 @@ namespace SixLabors.ImageSharp.Processing.Processors
return TransformHelpers.GetCenteredTransformMatrix(sourceRectangle, destinationRectangle, this.TransformMatrix);
}
- ///
- protected override Size GetTransformedDimensions(Size sourceDimensions, Matrix4x4 matrix)
+ private static Size GetTransformedDimensions(Size sourceDimensions, Matrix4x4 matrix)
{
var sourceRectangle = new Rectangle(0, 0, sourceDimensions.Width, sourceDimensions.Height);
- return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, this.TransformMatrix).Size;
+ return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix).Size;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs
index 00547d0147..91cdfac734 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs
@@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
+// TODO: Convert this into a cloning processor inheriting TransformProcessor once Anton's memory PR is merged
namespace SixLabors.ImageSharp.Processing.Processors
{
///
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs
index 90e33bddf2..34147b44f9 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs
@@ -22,27 +22,6 @@ namespace SixLabors.ImageSharp.Processing.Processors
internal class ProjectiveTransformProcessor : InterpolatedTransformProcessorBase
where TPixel : struct, IPixel
{
- private Size targetDimensions;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The transform matrix
- public ProjectiveTransformProcessor(Matrix4x4 matrix)
- : this(matrix, KnownResamplers.Bicubic)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The transform matrix
- /// The sampler to perform the transform operation.
- public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler)
- : this(matrix, sampler, Size.Empty)
- {
- }
-
///
/// Initializes a new instance of the class.
///
@@ -53,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
: base(sampler)
{
this.TransformMatrix = matrix;
- this.targetDimensions = targetDimensions;
+ this.TargetDimensions = targetDimensions;
}
///
@@ -61,18 +40,17 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
public Matrix4x4 TransformMatrix { get; }
+ ///
+ /// Gets the target dimensions to constrain the transformed image to
+ ///
+ public Size TargetDimensions { get; }
+
///
protected override Image CreateDestination(Image source, Rectangle sourceRectangle)
{
- if (this.targetDimensions == Size.Empty)
- {
- // TODO: CreateDestination() should not modify the processors state! (kinda CQRS)
- this.targetDimensions = this.GetTransformedDimensions(sourceRectangle.Size, this.TransformMatrix);
- }
-
// We will always be creating the clone even for mutate because we may need to resize the canvas
IEnumerable> frames =
- source.Frames.Select(x => new ImageFrame(this.targetDimensions.Width, this.targetDimensions.Height, x.MetaData.Clone()));
+ source.Frames.Select(x => new ImageFrame(this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.Clone()));
// Use the overload to prevent an extra frame being added
return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames);
@@ -81,8 +59,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
protected override void OnApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration)
{
- int height = this.targetDimensions.Height;
- int width = this.targetDimensions.Width;
+ int height = this.TargetDimensions.Height;
+ int width = this.TargetDimensions.Width;
Rectangle sourceBounds = source.Bounds();
var targetBounds = new Rectangle(0, 0, width, height);
@@ -202,8 +180,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
var vector = source[i, j].ToVector4();
// Values are first premultiplied to prevent darkening of edge pixels
- Vector4 mupltiplied = vector.Premultiply();
- sum += mupltiplied * xWeight * yWeight;
+ Vector4 multiplied = vector.Premultiply();
+ sum += multiplied * xWeight * yWeight;
}
}
@@ -228,16 +206,5 @@ namespace SixLabors.ImageSharp.Processing.Processors
{
return this.TransformMatrix;
}
-
- ///
- /// Gets the bounding relative to the source for the given transformation matrix.
- ///
- /// The source rectangle.
- /// The transformation matrix.
- /// The
- protected virtual Size GetTransformedDimensions(Size sourceDimensions, Matrix4x4 matrix)
- {
- return sourceDimensions;
- }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
deleted file mode 100644
index b9cb58707c..0000000000
--- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.PixelFormats;
-using SixLabors.Primitives;
-
-namespace SixLabors.ImageSharp.Processing.Processors
-{
- ///
- /// Provides methods that allow the resizing of images using various algorithms.
- /// Adapted from
- ///
- /// The pixel format.
- internal abstract class ResamplingWeightedProcessor : TransformProcessorBase
- where TPixel : struct, IPixel
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The sampler to perform the resize operation.
- /// The target width.
- /// The target height.
- ///
- /// The structure that specifies the portion of the target image object to draw to.
- ///
- protected ResamplingWeightedProcessor(IResampler sampler, int width, int height, Rectangle resizeRectangle)
- {
- Guard.NotNull(sampler, nameof(sampler));
- Guard.MustBeGreaterThan(width, 0, nameof(width));
- Guard.MustBeGreaterThan(height, 0, nameof(height));
-
- this.Sampler = sampler;
- this.Width = width;
- this.Height = height;
- this.ResizeRectangle = resizeRectangle;
- }
-
- ///
- /// Gets the sampler to perform the resize operation.
- ///
- public IResampler Sampler { get; }
-
- ///
- /// Gets or sets the width.
- ///
- public int Width { get; protected set; }
-
- ///
- /// Gets or sets the height.
- ///
- public int Height { get; protected set; }
-
- ///
- /// Gets or sets the resize rectangle.
- ///
- public Rectangle ResizeRectangle { get; protected set; }
-
- ///
- /// Gets or sets the horizontal weights.
- ///
- protected WeightsBuffer HorizontalWeights { get; set; }
-
- ///
- /// Gets or sets the vertical weights.
- ///
- protected WeightsBuffer VerticalWeights { get; set; }
-
- ///
- /// Computes the weights to apply at each pixel when resizing.
- ///
- /// The destination size
- /// The source size
- /// The
- // TODO: Made internal to simplify experimenting with weights data. Make it protected again when finished figuring out how to optimize all the stuff!
- internal unsafe WeightsBuffer PrecomputeWeights(int destinationSize, int sourceSize)
- {
- float ratio = (float)sourceSize / destinationSize;
- float scale = ratio;
-
- if (scale < 1F)
- {
- scale = 1F;
- }
-
- IResampler sampler = this.Sampler;
- float radius = MathF.Ceiling(scale * sampler.Radius);
- var result = new WeightsBuffer(sourceSize, destinationSize);
-
- for (int i = 0; i < destinationSize; i++)
- {
- float center = ((i + .5F) * ratio) - .5F;
-
- // Keep inside bounds.
- int left = (int)Math.Ceiling(center - radius);
- if (left < 0)
- {
- left = 0;
- }
-
- int right = (int)Math.Floor(center + radius);
- if (right > sourceSize - 1)
- {
- right = sourceSize - 1;
- }
-
- float sum = 0;
-
- WeightsWindow ws = result.GetWeightsWindow(i, left, right);
- result.Weights[i] = ws;
-
- ref float weightsBaseRef = ref ws.GetStartReference();
-
- for (int j = left; j <= right; j++)
- {
- float weight = sampler.GetValue((j - center) / scale);
- sum += weight;
-
- // weights[j - left] = weight:
- Unsafe.Add(ref weightsBaseRef, j - left) = weight;
- }
-
- // Normalise, best to do it here rather than in the pixel loop later on.
- if (sum > 0)
- {
- for (int w = 0; w < ws.Length; w++)
- {
- // weights[w] = weights[w] / sum:
- ref float wRef = ref Unsafe.Add(ref weightsBaseRef, w);
- wRef = wRef / sum;
- }
- }
- }
-
- return result;
- }
-
- ///
- protected override void BeforeApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration)
- {
- if (!(this.Sampler is NearestNeighborResampler))
- {
- this.HorizontalWeights = this.PrecomputeWeights(
- this.ResizeRectangle.Width,
- sourceRectangle.Width);
-
- this.VerticalWeights = this.PrecomputeWeights(
- this.ResizeRectangle.Height,
- sourceRectangle.Height);
- }
- }
-
- ///
- protected override void AfterApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration)
- {
- base.AfterApply(source, destination, sourceRectangle, configuration);
- this.HorizontalWeights?.Dispose();
- this.HorizontalWeights = null;
- this.VerticalWeights?.Dispose();
- this.VerticalWeights = null;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
index b05d77868f..bccf665a48 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
@@ -5,10 +5,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
+using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
-using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@@ -16,19 +16,62 @@ namespace SixLabors.ImageSharp.Processing.Processors
{
///
/// Provides methods that allow the resizing of images using various algorithms.
+ /// Adapted from
///
/// The pixel format.
- internal class ResizeProcessor : ResamplingWeightedProcessor
+ internal class ResizeProcessor : TransformProcessorBase
where TPixel : struct, IPixel
{
+ // The following fields are not immutable but are optionally created on demand.
+ private WeightsBuffer horizontalWeights;
+ private WeightsBuffer verticalWeights;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The resize options
+ /// The source image size
+ public ResizeProcessor(ResizeOptions options, Size sourceSize)
+ {
+ Guard.NotNull(options, nameof(options));
+ Guard.NotNull(options.Sampler, nameof(options.Sampler));
+
+ int tempWidth = options.Size.Width;
+ int tempHeight = options.Size.Height;
+
+ // Ensure size is populated across both dimensions.
+ // These dimensions are used to calculate the final dimensions determined by the mode algorithm.
+ if (tempWidth == 0 && tempHeight > 0)
+ {
+ tempWidth = (int)MathF.Round(sourceSize.Width * tempHeight / (float)sourceSize.Height);
+ }
+
+ if (tempHeight == 0 && tempWidth > 0)
+ {
+ tempHeight = (int)MathF.Round(sourceSize.Height * tempWidth / (float)sourceSize.Width);
+ }
+
+ Guard.MustBeGreaterThan(tempWidth, 0, nameof(tempWidth));
+ Guard.MustBeGreaterThan(tempHeight, 0, nameof(tempHeight));
+
+ (Size size, Rectangle rectangle) locationBounds = ResizeHelper.CalculateTargetLocationAndBounds(sourceSize, options, tempWidth, tempHeight);
+
+ this.Sampler = options.Sampler;
+ this.Width = locationBounds.size.Width;
+ this.Height = locationBounds.size.Height;
+ this.ResizeRectangle = locationBounds.rectangle;
+ this.Compand = options.Compand;
+ }
+
///
/// Initializes a new instance of the class.
///
/// The sampler to perform the resize operation.
/// The target width.
/// The target height.
- public ResizeProcessor(IResampler sampler, int width, int height)
- : base(sampler, width, height, new Rectangle(0, 0, width, height))
+ /// The source image size
+ public ResizeProcessor(IResampler sampler, int width, int height, Size sourceSize)
+ : this(sampler, width, height, sourceSize, new Rectangle(0, 0, width, height), false)
{
}
@@ -38,18 +81,131 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// The sampler to perform the resize operation.
/// The target width.
/// The target height.
+ /// The source image size
///
/// The structure that specifies the portion of the target image object to draw to.
///
- public ResizeProcessor(IResampler sampler, int width, int height, Rectangle resizeRectangle)
- : base(sampler, width, height, resizeRectangle)
+ /// Whether to compress or expand individual pixel color values on processing.
+ public ResizeProcessor(IResampler sampler, int width, int height, Size sourceSize, Rectangle resizeRectangle, bool compand)
{
+ Guard.NotNull(sampler, nameof(sampler));
+
+ // Ensure size is populated across both dimensions.
+ if (width == 0 && height > 0)
+ {
+ width = (int)MathF.Round(sourceSize.Width * height / (float)sourceSize.Height);
+ resizeRectangle.Width = width;
+ }
+
+ if (height == 0 && width > 0)
+ {
+ height = (int)MathF.Round(sourceSize.Height * width / (float)sourceSize.Width);
+ resizeRectangle.Height = height;
+ }
+
+ Guard.MustBeGreaterThan(width, 0, nameof(width));
+ Guard.MustBeGreaterThan(height, 0, nameof(height));
+
+ this.Sampler = sampler;
+ this.Width = width;
+ this.Height = height;
+ this.ResizeRectangle = resizeRectangle;
+ this.Compand = compand;
}
///
- /// Gets or sets a value indicating whether to compress or expand individual pixel color values on processing.
+ /// Gets the sampler to perform the resize operation.
///
- public bool Compand { get; set; }
+ public IResampler Sampler { get; }
+
+ ///
+ /// Gets the target width.
+ ///
+ public int Width { get; }
+
+ ///
+ /// Gets the target height.
+ ///
+ public int Height { get; }
+
+ ///
+ /// Gets the resize rectangle.
+ ///
+ public Rectangle ResizeRectangle { get; }
+
+ ///
+ /// Gets a value indicating whether to compress or expand individual pixel color values on processing.
+ ///
+ public bool Compand { get; }
+
+ ///
+ /// Computes the weights to apply at each pixel when resizing.
+ ///
+ /// The destination size
+ /// The source size
+ /// The
+ // TODO: Made internal to simplify experimenting with weights data. Make it private when finished figuring out how to optimize all the stuff!
+ internal WeightsBuffer PrecomputeWeights(int destinationSize, int sourceSize)
+ {
+ float ratio = (float)sourceSize / destinationSize;
+ float scale = ratio;
+
+ if (scale < 1F)
+ {
+ scale = 1F;
+ }
+
+ IResampler sampler = this.Sampler;
+ float radius = MathF.Ceiling(scale * sampler.Radius);
+ var result = new WeightsBuffer(sourceSize, destinationSize);
+
+ for (int i = 0; i < destinationSize; i++)
+ {
+ float center = ((i + .5F) * ratio) - .5F;
+
+ // Keep inside bounds.
+ int left = (int)Math.Ceiling(center - radius);
+ if (left < 0)
+ {
+ left = 0;
+ }
+
+ int right = (int)Math.Floor(center + radius);
+ if (right > sourceSize - 1)
+ {
+ right = sourceSize - 1;
+ }
+
+ float sum = 0;
+
+ WeightsWindow ws = result.GetWeightsWindow(i, left, right);
+ result.Weights[i] = ws;
+
+ ref float weightsBaseRef = ref ws.GetStartReference();
+
+ for (int j = left; j <= right; j++)
+ {
+ float weight = sampler.GetValue((j - center) / scale);
+ sum += weight;
+
+ // weights[j - left] = weight:
+ Unsafe.Add(ref weightsBaseRef, j - left) = weight;
+ }
+
+ // Normalize, best to do it here rather than in the pixel loop later on.
+ if (sum > 0)
+ {
+ for (int w = 0; w < ws.Length; w++)
+ {
+ // weights[w] = weights[w] / sum:
+ ref float wRef = ref Unsafe.Add(ref weightsBaseRef, w);
+ wRef = wRef / sum;
+ }
+ }
+ }
+
+ return result;
+ }
///
protected override Image CreateDestination(Image source, Rectangle sourceRectangle)
@@ -62,6 +218,21 @@ namespace SixLabors.ImageSharp.Processing.Processors
return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames);
}
+ ///
+ protected override void BeforeApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration)
+ {
+ if (!(this.Sampler is NearestNeighborResampler))
+ {
+ this.horizontalWeights = this.PrecomputeWeights(
+ this.ResizeRectangle.Width,
+ sourceRectangle.Width);
+
+ this.verticalWeights = this.PrecomputeWeights(
+ this.ResizeRectangle.Height,
+ sourceRectangle.Height);
+ }
+ }
+
///
protected override void OnApply(ImageFrame source, ImageFrame cloned, Rectangle sourceRectangle, Configuration configuration)
{
@@ -139,7 +310,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
{
for (int x = minX; x < maxX; x++)
{
- WeightsWindow window = this.HorizontalWeights.Weights[x - startX];
+ WeightsWindow window = this.horizontalWeights.Weights[x - startX];
firstPassRow[x] = window.ComputeExpandedWeightedRowSum(tempRowBuffer, sourceX);
}
}
@@ -147,7 +318,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
{
for (int x = minX; x < maxX; x++)
{
- WeightsWindow window = this.HorizontalWeights.Weights[x - startX];
+ WeightsWindow window = this.horizontalWeights.Weights[x - startX];
firstPassRow[x] = window.ComputeWeightedRowSum(tempRowBuffer, sourceX);
}
}
@@ -161,8 +332,8 @@ namespace SixLabors.ImageSharp.Processing.Processors
configuration.ParallelOptions,
y =>
{
- // Ensure offsets are normalised for cropping and padding.
- WeightsWindow window = this.VerticalWeights.Weights[y - startY];
+ // Ensure offsets are normalized for cropping and padding.
+ WeightsWindow window = this.verticalWeights.Weights[y - startY];
Span targetRow = cloned.GetPixelRowSpan(y);
if (this.Compand)
@@ -191,5 +362,15 @@ namespace SixLabors.ImageSharp.Processing.Processors
});
}
}
+
+ ///
+ protected override void AfterApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration)
+ {
+ base.AfterApply(source, destination, sourceRectangle, configuration);
+ this.horizontalWeights?.Dispose();
+ this.horizontalWeights = null;
+ this.verticalWeights?.Dispose();
+ this.verticalWeights = null;
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
index b93c869152..824ae4310f 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
@@ -22,8 +22,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// Initializes a new instance of the class.
///
/// The angle of rotation in degrees.
- public RotateProcessor(float degrees)
- : this(degrees, KnownResamplers.Bicubic)
+ /// The source image size
+ public RotateProcessor(float degrees, Size sourceSize)
+ : this(degrees, KnownResamplers.Bicubic, sourceSize)
{
}
@@ -32,8 +33,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
/// The angle of rotation in degrees.
/// The sampler to perform the rotating operation.
- public RotateProcessor(float degrees, IResampler sampler)
- : base(Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty), sampler)
+ /// The source image size
+ public RotateProcessor(float degrees, IResampler sampler, Size sourceSize)
+ : base(Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty), sampler, sourceSize)
{
this.Degrees = degrees;
}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs
index 8c47b35274..8e3ab7c34f 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs
@@ -18,8 +18,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
/// The angle in degrees to perform the skew along the x-axis.
/// The angle in degrees to perform the skew along the y-axis.
- public SkewProcessor(float degreesX, float degreesY)
- : this(degreesX, degreesY, KnownResamplers.Bicubic)
+ /// The source image size
+ public SkewProcessor(float degreesX, float degreesY, Size sourceSize)
+ : this(degreesX, degreesY, KnownResamplers.Bicubic, sourceSize)
{
}
@@ -29,8 +30,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// The angle in degrees to perform the skew along the x-axis.
/// The angle in degrees to perform the skew along the y-axis.
/// The sampler to perform the skew operation.
- public SkewProcessor(float degreesX, float degreesY, IResampler sampler)
- : base(Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty), sampler)
+ /// The source image size
+ public SkewProcessor(float degreesX, float degreesY, IResampler sampler, Size sourceSize)
+ : base(Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty), sampler, sourceSize)
{
this.DegreesX = degreesX;
this.DegreesY = degreesY;
diff --git a/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs b/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs
index 17a0cc428f..ba6f4509d8 100644
--- a/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs
+++ b/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs
@@ -3,7 +3,6 @@
using System;
using System.Linq;
-using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
@@ -17,52 +16,39 @@ namespace SixLabors.ImageSharp.Processing
///
/// Calculates the target location and bounds to perform the resize operation against.
///
- /// The pixel format.
- /// The source image.
+ /// The source image size.
/// The resize options.
+ /// The target width
+ /// The target height
///
- /// The .
+ /// The .
///
- public static Rectangle CalculateTargetLocationAndBounds(ImageFrame source, ResizeOptions options)
- where TPixel : struct, IPixel
+ public static (Size, Rectangle) CalculateTargetLocationAndBounds(Size sourceSize, ResizeOptions options, int width, int height)
{
switch (options.Mode)
{
case ResizeMode.Crop:
- return CalculateCropRectangle(source, options);
+ return CalculateCropRectangle(sourceSize, options, width, height);
case ResizeMode.Pad:
- return CalculatePadRectangle(source, options);
+ return CalculatePadRectangle(sourceSize, options, width, height);
case ResizeMode.BoxPad:
- return CalculateBoxPadRectangle(source, options);
+ return CalculateBoxPadRectangle(sourceSize, options, width, height);
case ResizeMode.Max:
- return CalculateMaxRectangle(source, options);
+ return CalculateMaxRectangle(sourceSize, options, width, height);
case ResizeMode.Min:
- return CalculateMinRectangle(source, options);
+ return CalculateMinRectangle(sourceSize, options, width, height);
// Last case ResizeMode.Stretch:
default:
- return new Rectangle(0, 0, options.Size.Width, options.Size.Height);
+ return (new Size(width, height), new Rectangle(0, 0, width, height));
}
}
- ///
- /// Calculates the target rectangle for crop mode.
- ///
- /// The pixel format.
- /// The source image.
- /// The resize options.
- ///
- /// The .
- ///
- private static Rectangle CalculateCropRectangle(ImageFrame source, ResizeOptions options)
- where TPixel : struct, IPixel
+ private static (Size, Rectangle) CalculateCropRectangle(Size source, ResizeOptions options, int width, int height)
{
- int width = options.Size.Width;
- int height = options.Size.Height;
-
if (width <= 0 || height <= 0)
{
- return new Rectangle(0, 0, source.Width, source.Height);
+ return (new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
}
float ratio;
@@ -161,27 +147,14 @@ namespace SixLabors.ImageSharp.Processing
destinationWidth = (int)MathF.Ceiling(sourceWidth * percentHeight);
}
- return new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight);
+ return (new Size(width, height), new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
}
- ///
- /// Calculates the target rectangle for pad mode.
- ///
- /// The pixel format.
- /// The source image.
- /// The resize options.
- ///
- /// The .
- ///
- private static Rectangle CalculatePadRectangle(ImageFrame source, ResizeOptions options)
- where TPixel : struct, IPixel
+ private static (Size, Rectangle) CalculatePadRectangle(Size source, ResizeOptions options, int width, int height)
{
- int width = options.Size.Width;
- int height = options.Size.Height;
-
if (width <= 0 || height <= 0)
{
- return new Rectangle(0, 0, source.Width, source.Height);
+ return (new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
}
float ratio;
@@ -242,27 +215,14 @@ namespace SixLabors.ImageSharp.Processing
}
}
- return new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight);
+ return (new Size(width, height), new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
}
- ///
- /// Calculates the target rectangle for box pad mode.
- ///
- /// The pixel format.
- /// The source image.
- /// The resize options.
- ///
- /// The .
- ///
- private static Rectangle CalculateBoxPadRectangle(ImageFrame source, ResizeOptions options)
- where TPixel : struct, IPixel
+ private static (Size, Rectangle) CalculateBoxPadRectangle(Size source, ResizeOptions options, int width, int height)
{
- int width = options.Size.Width;
- int height = options.Size.Height;
-
if (width <= 0 || height <= 0)
{
- return new Rectangle(0, 0, source.Width, source.Height);
+ return (new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
}
int sourceWidth = source.Width;
@@ -325,27 +285,15 @@ namespace SixLabors.ImageSharp.Processing
break;
}
- return new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight);
+ return (new Size(width, height), new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
}
// Switch to pad mode to downscale and calculate from there.
- return CalculatePadRectangle(source, options);
+ return CalculatePadRectangle(source, options, width, height);
}
- ///
- /// Calculates the target rectangle for max mode.
- ///
- /// The pixel format.
- /// The source image.
- /// The resize options.
- ///
- /// The .
- ///
- private static Rectangle CalculateMaxRectangle(ImageFrame source, ResizeOptions options)
- where TPixel : struct, IPixel
+ private static (Size, Rectangle) CalculateMaxRectangle(Size source, ResizeOptions options, int width, int height)
{
- int width = options.Size.Width;
- int height = options.Size.Height;
int destinationWidth = width;
int destinationHeight = height;
@@ -369,24 +317,11 @@ namespace SixLabors.ImageSharp.Processing
}
// Replace the size to match the rectangle.
- options.Size = new Size(width, height);
- return new Rectangle(0, 0, destinationWidth, destinationHeight);
+ return (new Size(width, height), new Rectangle(0, 0, destinationWidth, destinationHeight));
}
- ///
- /// Calculates the target rectangle for min mode.
- ///
- /// The pixel format.
- /// The source image.
- /// The resize options.
- ///
- /// The .
- ///
- private static Rectangle CalculateMinRectangle(ImageFrame source, ResizeOptions options)
- where TPixel : struct, IPixel
+ private static (Size, Rectangle) CalculateMinRectangle(Size source, ResizeOptions options, int width, int height)
{
- int width = options.Size.Width;
- int height = options.Size.Height;
int sourceWidth = source.Width;
int sourceHeight = source.Height;
int destinationWidth;
@@ -395,8 +330,7 @@ namespace SixLabors.ImageSharp.Processing
// Don't upscale
if (width > sourceWidth || height > sourceHeight)
{
- options.Size = new Size(sourceWidth, sourceHeight);
- return new Rectangle(0, 0, sourceWidth, sourceHeight);
+ return (new Size(sourceWidth, sourceWidth), new Rectangle(0, 0, sourceWidth, sourceHeight));
}
// Fractional variants for preserving aspect ratio.
@@ -438,8 +372,7 @@ namespace SixLabors.ImageSharp.Processing
}
// Replace the size to match the rectangle.
- options.Size = new Size(width, height);
- return new Rectangle(0, 0, destinationWidth, destinationHeight);
+ return (new Size(width, height), new Rectangle(0, 0, destinationWidth, destinationHeight));
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Transforms/Options/ResizeOptions.cs b/src/ImageSharp/Processing/Transforms/Options/ResizeOptions.cs
index d20eaefb11..f13fa77c99 100644
--- a/src/ImageSharp/Processing/Transforms/Options/ResizeOptions.cs
+++ b/src/ImageSharp/Processing/Transforms/Options/ResizeOptions.cs
@@ -41,6 +41,6 @@ namespace SixLabors.ImageSharp.Processing
/// Gets or sets a value indicating whether to compress
/// or expand individual pixel colors the value on processing.
///
- public bool Compand { get; set; }
+ public bool Compand { get; set; } = false;
}
}
diff --git a/src/ImageSharp/Processing/Transforms/Resize.cs b/src/ImageSharp/Processing/Transforms/Resize.cs
index 832b02dea7..853f461339 100644
--- a/src/ImageSharp/Processing/Transforms/Resize.cs
+++ b/src/ImageSharp/Processing/Transforms/Resize.cs
@@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors;
@@ -24,29 +23,10 @@ namespace SixLabors.ImageSharp
/// Passing zero for one of height or width within the resize options will automatically preserve the aspect ratio of the original image
public static IImageProcessingContext Resize(this IImageProcessingContext source, ResizeOptions options)
where TPixel : struct, IPixel
- {
- return source.Apply(img =>
- {
- // Cheat and bound through a run, inside here we should just be mutating, this really needs moving over to a processor
- // Ensure size is populated across both dimensions.
- if (options.Size.Width == 0 && options.Size.Height > 0)
- {
- options.Size = new Size((int)MathF.Round(img.Width * options.Size.Height / (float)img.Height), options.Size.Height);
- }
-
- if (options.Size.Height == 0 && options.Size.Width > 0)
- {
- options.Size = new Size(options.Size.Width, (int)MathF.Round(img.Height * options.Size.Width / (float)img.Width));
- }
-
- Rectangle targetRectangle = ResizeHelper.CalculateTargetLocationAndBounds(img.Frames.RootFrame, options);
-
- img.Mutate(x => Resize(x, options.Size.Width, options.Size.Height, options.Sampler, targetRectangle, options.Compand));
- });
- }
+ => source.ApplyProcessor(new ResizeProcessor(options, source.Bounds().Size));
///
- /// Resizes an image to the given .
+ /// Resizes an image to the given .
///
/// The pixel format.
/// The image to resize.
@@ -55,12 +35,10 @@ namespace SixLabors.ImageSharp
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
public static IImageProcessingContext Resize(this IImageProcessingContext source, Size size)
where TPixel : struct, IPixel
- {
- return Resize(source, size.Width, size.Height, KnownResamplers.Bicubic, false);
- }
+ => Resize(source, size.Width, size.Height, KnownResamplers.Bicubic, false);
///
- /// Resizes an image to the given .
+ /// Resizes an image to the given .
///
/// The pixel format.
/// The image to resize.
@@ -70,9 +48,7 @@ namespace SixLabors.ImageSharp
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
public static IImageProcessingContext Resize(this IImageProcessingContext source, Size size, bool compand)
where TPixel : struct, IPixel
- {
- return Resize(source, size.Width, size.Height, KnownResamplers.Bicubic, compand);
- }
+ => Resize(source, size.Width, size.Height, KnownResamplers.Bicubic, compand);
///
/// Resizes an image to the given width and height.
@@ -85,9 +61,7 @@ namespace SixLabors.ImageSharp
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height)
where TPixel : struct, IPixel
- {
- return Resize(source, width, height, KnownResamplers.Bicubic, false);
- }
+ => Resize(source, width, height, KnownResamplers.Bicubic, false);
///
/// Resizes an image to the given width and height.
@@ -101,9 +75,7 @@ namespace SixLabors.ImageSharp
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, bool compand)
where TPixel : struct, IPixel
- {
- return Resize(source, width, height, KnownResamplers.Bicubic, compand);
- }
+ => Resize(source, width, height, KnownResamplers.Bicubic, compand);
///
/// Resizes an image to the given width and height with the given sampler.
@@ -117,9 +89,7 @@ namespace SixLabors.ImageSharp
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, IResampler sampler)
where TPixel : struct, IPixel
- {
- return Resize(source, width, height, sampler, false);
- }
+ => Resize(source, width, height, sampler, false);
///
/// Resizes an image to the given width and height with the given sampler.
@@ -133,9 +103,7 @@ namespace SixLabors.ImageSharp
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
public static IImageProcessingContext Resize(this IImageProcessingContext source, Size size, IResampler sampler, bool compand)
where TPixel : struct, IPixel
- {
- return Resize(source, size.Width, size.Height, sampler, new Rectangle(0, 0, size.Width, size.Height), compand);
- }
+ => Resize(source, size.Width, size.Height, sampler, new Rectangle(0, 0, size.Width, size.Height), compand);
///
/// Resizes an image to the given width and height with the given sampler.
@@ -150,9 +118,7 @@ namespace SixLabors.ImageSharp
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, IResampler sampler, bool compand)
where TPixel : struct, IPixel
- {
- return Resize(source, width, height, sampler, new Rectangle(0, 0, width, height), compand);
- }
+ => Resize(source, width, height, sampler, new Rectangle(0, 0, width, height), compand);
///
/// Resizes an image to the given width and height with the given sampler and
@@ -172,34 +138,19 @@ namespace SixLabors.ImageSharp
/// Whether to compress and expand the image color-space to gamma correct the image during processing.
/// The
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
- public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, IResampler sampler, Rectangle sourceRectangle, Rectangle targetRectangle, bool compand)
+ public static IImageProcessingContext Resize(
+ this IImageProcessingContext source,
+ int width,
+ int height,
+ IResampler sampler,
+ Rectangle sourceRectangle,
+ Rectangle targetRectangle,
+ bool compand)
where TPixel : struct, IPixel
- {
- return source.Apply(img =>
- {
- // TODO : Stop cheating here and move this stuff into the processors itself
- if (width == 0 && height > 0)
- {
- width = (int)MathF.Round(img.Width * height / (float)img.Height);
- targetRectangle.Width = width;
- }
-
- if (height == 0 && width > 0)
- {
- height = (int)MathF.Round(img.Height * width / (float)img.Width);
- targetRectangle.Height = height;
- }
-
- Guard.MustBeGreaterThan(width, 0, nameof(width));
- Guard.MustBeGreaterThan(height, 0, nameof(height));
-
- img.Mutate(x => x.ApplyProcessor(new ResizeProcessor(sampler, width, height, targetRectangle) { Compand = compand }, sourceRectangle));
- });
- }
+ => source.ApplyProcessor(new ResizeProcessor(sampler, width, height, source.Bounds().Size, targetRectangle, compand), sourceRectangle);
///
- /// Resizes an image to the given width and height with the given sampler and
- /// source rectangle.
+ /// Resizes an image to the given width and height with the given sampler and source rectangle.
///
/// The pixel format.
/// The image to resize.
@@ -212,29 +163,14 @@ namespace SixLabors.ImageSharp
/// Whether to compress and expand the image color-space to gamma correct the image during processing.
/// The
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
- public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, IResampler sampler, Rectangle targetRectangle, bool compand)
+ public static IImageProcessingContext Resize(
+ this IImageProcessingContext source,
+ int width,
+ int height,
+ IResampler sampler,
+ Rectangle targetRectangle,
+ bool compand)
where TPixel : struct, IPixel
- {
- return source.Apply(img =>
- {
- // TODO : stop cheating here and move this stuff into the processors itself
- if (width == 0 && height > 0)
- {
- width = (int)MathF.Round(img.Width * height / (float)img.Height);
- targetRectangle.Width = width;
- }
-
- if (height == 0 && width > 0)
- {
- height = (int)MathF.Round(img.Height * width / (float)img.Width);
- targetRectangle.Height = height;
- }
-
- Guard.MustBeGreaterThan(width, 0, nameof(width));
- Guard.MustBeGreaterThan(height, 0, nameof(height));
-
- img.Mutate(x => x.ApplyProcessor(new ResizeProcessor(sampler, width, height, targetRectangle) { Compand = compand }));
- });
- }
+ => source.ApplyProcessor(new ResizeProcessor(sampler, width, height, source.Bounds().Size, targetRectangle, compand));
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Transforms/Rotate.cs b/src/ImageSharp/Processing/Transforms/Rotate.cs
index 69fb7ebf0c..6ffefca5cf 100644
--- a/src/ImageSharp/Processing/Transforms/Rotate.cs
+++ b/src/ImageSharp/Processing/Transforms/Rotate.cs
@@ -44,6 +44,6 @@ namespace SixLabors.ImageSharp
/// The
public static IImageProcessingContext Rotate(this IImageProcessingContext source, float degrees, IResampler sampler)
where TPixel : struct, IPixel
- => source.ApplyProcessor(new RotateProcessor(degrees, sampler));
+ => source.ApplyProcessor(new RotateProcessor(degrees, sampler, source.Bounds().Size));
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Transforms/Skew.cs b/src/ImageSharp/Processing/Transforms/Skew.cs
index 0613a690b8..25db33059a 100644
--- a/src/ImageSharp/Processing/Transforms/Skew.cs
+++ b/src/ImageSharp/Processing/Transforms/Skew.cs
@@ -35,6 +35,6 @@ namespace SixLabors.ImageSharp
/// The
public static IImageProcessingContext Skew(this IImageProcessingContext source, float degreesX, float degreesY, IResampler sampler)
where TPixel : struct, IPixel
- => source.ApplyProcessor(new SkewProcessor(degreesX, degreesY, sampler));
+ => source.ApplyProcessor(new SkewProcessor(degreesX, degreesY, sampler, source.Bounds().Size));
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Transforms/Transform.cs b/src/ImageSharp/Processing/Transforms/Transform.cs
index 326ed75862..58d3ae13e7 100644
--- a/src/ImageSharp/Processing/Transforms/Transform.cs
+++ b/src/ImageSharp/Processing/Transforms/Transform.cs
@@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp
/// The
public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix3x2 matrix, IResampler sampler)
where TPixel : struct, IPixel
- => Transform(source, matrix, sampler, Size.Empty);
+ => Transform(source, matrix, sampler, source.Bounds());
///
/// Transforms an image by the given matrix using the specified sampling algorithm
@@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp
/// The
internal static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix, IResampler sampler)
where TPixel : struct, IPixel
- => Transform(source, matrix, sampler, Rectangle.Empty);
+ => Transform(source, matrix, sampler, source.Bounds());
///
/// Applies a projective transform to the image by the given matrix using the specified sampling algorithm.
diff --git a/tests/ImageSharp.Tests/BaseImageOperationsExtensionTest.cs b/tests/ImageSharp.Tests/BaseImageOperationsExtensionTest.cs
index 37696987cc..ec46e66107 100644
--- a/tests/ImageSharp.Tests/BaseImageOperationsExtensionTest.cs
+++ b/tests/ImageSharp.Tests/BaseImageOperationsExtensionTest.cs
@@ -16,29 +16,31 @@ namespace SixLabors.ImageSharp.Tests
private readonly FakeImageOperationsProvider.FakeImageOperations internalOperations;
protected readonly Rectangle rect;
protected readonly GraphicsOptions options;
+ private Image source;
public BaseImageOperationsExtensionTest()
{
- this.options = new GraphicsOptions(false) { };
+ this.options = new GraphicsOptions(false);
+ this.source = new Image(91 + 324, 123 + 56);
this.rect = new Rectangle(91, 123, 324, 56); // make this random?
- this.internalOperations = new FakeImageOperationsProvider.FakeImageOperations(null, false);
+ this.internalOperations = new FakeImageOperationsProvider.FakeImageOperations(this.source, false);
this.operations = this.internalOperations;
}
public T Verify(int index = 0)
{
- Assert.InRange(index, 0, this.internalOperations.applied.Count - 1);
+ Assert.InRange(index, 0, this.internalOperations.Applied.Count - 1);
- var operation = this.internalOperations.applied[index];
+ var operation = this.internalOperations.Applied[index];
return Assert.IsType(operation.Processor);
}
public T Verify(Rectangle rect, int index = 0)
{
- Assert.InRange(index, 0, this.internalOperations.applied.Count - 1);
+ Assert.InRange(index, 0, this.internalOperations.Applied.Count - 1);
- var operation = this.internalOperations.applied[index];
+ var operation = this.internalOperations.Applied[index];
Assert.Equal(rect, operation.Rectangle);
return Assert.IsType(operation.Processor);
diff --git a/tests/ImageSharp.Tests/FakeImageOperationsProvider.cs b/tests/ImageSharp.Tests/FakeImageOperationsProvider.cs
index f750bfcfad..9803af9f8d 100644
--- a/tests/ImageSharp.Tests/FakeImageOperationsProvider.cs
+++ b/tests/ImageSharp.Tests/FakeImageOperationsProvider.cs
@@ -1,12 +1,11 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
+
+using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.PixelFormats;
-using SixLabors.ImageSharp.Processing;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Tests
@@ -23,13 +22,13 @@ namespace SixLabors.ImageSharp.Tests
public IEnumerable> Created(Image source) where TPixel : struct, IPixel
{
return this.ImageOperators.OfType>()
- .Where(x => x.source == source);
+ .Where(x => x.Source == source);
}
- public IEnumerable.AppliedOpperation> AppliedOperations(Image source) where TPixel : struct, IPixel
+ public IEnumerable.AppliedOperation> AppliedOperations(Image source) where TPixel : struct, IPixel
{
return Created(source)
- .SelectMany(x => x.applied);
+ .SelectMany(x => x.Applied);
}
public IInternalImageProcessingContext CreateImageProcessingContext(Image source, bool mutate) where TPixel : struct, IPixel
@@ -43,32 +42,31 @@ namespace SixLabors.ImageSharp.Tests
public class FakeImageOperations : IInternalImageProcessingContext
where TPixel : struct, IPixel
{
- public Image source;
-
- public List applied = new List();
- public bool mutate;
+ private bool mutate;
public FakeImageOperations(Image source, bool mutate)
{
this.mutate = mutate;
- if (mutate)
- {
- this.source = source;
- }
- else
- {
- this.source = source?.Clone();
- }
+ this.Source = mutate ? source : source?.Clone();
}
+ public Image Source { get; }
+
+ public List Applied { get; } = new List();
+
public Image Apply()
{
- return source;
+ return this.Source;
+ }
+
+ public Rectangle Bounds()
+ {
+ return this.Source.Bounds();
}
public IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle)
{
- applied.Add(new AppliedOpperation
+ this.Applied.Add(new AppliedOperation
{
Processor = processor,
Rectangle = rectangle
@@ -78,13 +76,13 @@ namespace SixLabors.ImageSharp.Tests
public IImageProcessingContext ApplyProcessor(IImageProcessor processor)
{
- applied.Add(new AppliedOpperation
+ this.Applied.Add(new AppliedOperation
{
Processor = processor
});
return this;
}
- public struct AppliedOpperation
+ public struct AppliedOperation
{
public Rectangle? Rectangle { get; set; }
public IImageProcessor Processor { get; set; }
diff --git a/tests/ImageSharp.Tests/ImageOperationTests.cs b/tests/ImageSharp.Tests/ImageOperationTests.cs
index 59722a84d2..a5d6d2eb96 100644
--- a/tests/ImageSharp.Tests/ImageOperationTests.cs
+++ b/tests/ImageSharp.Tests/ImageOperationTests.cs
@@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Tests
{
var operations = new FakeImageOperationsProvider.FakeImageOperations(null, false);
operations.ApplyProcessors(this.processor);
- Assert.Contains(this.processor, operations.applied.Select(x => x.Processor));
+ Assert.Contains(this.processor, operations.Applied.Select(x => x.Processor));
}
public void Dispose()
diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs
index 98dbbadaba..77471b2ba2 100644
--- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs
+++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs
@@ -11,6 +11,8 @@ using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
{
+ using SixLabors.Primitives;
+
public class ResizeProfilingBenchmarks : MeasureFixture
{
public ResizeProfilingBenchmarks(ITestOutputHelper output)
@@ -38,9 +40,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
// [Fact]
public void PrintWeightsData()
{
- var proc = new ResizeProcessor(KnownResamplers.Bicubic, 200, 200);
+ var size = new Size(500, 500);
+ var proc = new ResizeProcessor(KnownResamplers.Bicubic, 200, 200, size);
- WeightsBuffer weights = proc.PrecomputeWeights(200, 500);
+ WeightsBuffer weights = proc.PrecomputeWeights(proc.Width, size.Width);
var bld = new StringBuilder();