diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor{TPixel}.cs deleted file mode 100644 index 78310707c8..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// Provides the base methods to perform affine transforms on an image. - /// - /// The pixel format. - internal partial class AffineTransformProcessor : TransformProcessor, IResamplingImageProcessor - where TPixel : struct, IPixel - { - private readonly Size destinationSize; - private readonly Matrix3x2 transformMatrix; - private readonly IResampler resampler; - private ImageFrame source; - private ImageFrame destination; - - /// - /// Initializes a new instance of the class. - /// - /// The configuration which allows altering default behaviour or extending the library. - /// The defining the processor parameters. - /// The source for the current processor instance. - /// The source area to process for the current processor instance. - public AffineTransformProcessor(Configuration configuration, AffineTransformProcessor definition, Image source, Rectangle sourceRectangle) - : base(configuration, source, sourceRectangle) - { - this.destinationSize = definition.DestinationSize; - this.transformMatrix = definition.TransformMatrix; - this.resampler = definition.Sampler; - } - - protected override Size GetDestinationSize() => this.destinationSize; - - /// - protected override void OnFrameApply(ImageFrame source, ImageFrame destination) - { - this.source = source; - this.destination = destination; - this.resampler.ApplyTransform(this); - } - - /// - public void ApplyTransform(in TResampler sampler) - where TResampler : struct, IResampler - => ApplyAffineTransform( - this.Configuration, - in sampler, - this.source, - this.destination, - this.transformMatrix); - } -} diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor{TPixel}.cs deleted file mode 100644 index 8954d826f5..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// Provides the base methods to perform non-affine transforms on an image. - /// - /// The pixel format. - internal partial class ProjectiveTransformProcessor : TransformProcessor, IResamplingImageProcessor - where TPixel : struct, IPixel - { - private readonly Size destinationSize; - private readonly IResampler resampler; - private readonly Matrix4x4 transformMatrix; - private ImageFrame source; - private ImageFrame destination; - - /// - /// Initializes a new instance of the class. - /// - /// The configuration which allows altering default behaviour or extending the library. - /// The defining the processor parameters. - /// The source for the current processor instance. - /// The source area to process for the current processor instance. - public ProjectiveTransformProcessor(Configuration configuration, ProjectiveTransformProcessor definition, Image source, Rectangle sourceRectangle) - : base(configuration, source, sourceRectangle) - { - this.destinationSize = definition.DestinationSize; - this.transformMatrix = definition.TransformMatrix; - this.resampler = definition.Sampler; - } - - protected override Size GetDestinationSize() => this.destinationSize; - - /// - protected override void OnFrameApply(ImageFrame source, ImageFrame destination) - { - this.source = source; - this.destination = destination; - this.resampler.ApplyTransform(this); - } - - /// - public void ApplyTransform(in TResampler sampler) - where TResampler : struct, IResampler - => ApplyProjectiveTransform( - this.Configuration, - in sampler, - this.source, - this.destination, - this.transformMatrix); - } -} diff --git a/src/ImageSharp/Processing/Processors/Transforms/IResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/IResampler.cs index 616872f2ab..c0c3be869b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/IResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/IResampler.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The pixel format. /// The transforming image processor. - void ApplyTransform(IResamplingImageProcessor processor) + void ApplyTransform(IResamplingTransformImageProcessor processor) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/IResamplingImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/IResamplingTransformImageProcessor{TPixel}.cs similarity index 87% rename from src/ImageSharp/Processing/Processors/Transforms/IResamplingImageProcessor{TPixel}.cs rename to src/ImageSharp/Processing/Processors/Transforms/IResamplingTransformImageProcessor{TPixel}.cs index cfa2df641d..ab750f7fb3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/IResamplingImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/IResamplingTransformImageProcessor{TPixel}.cs @@ -6,10 +6,10 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// - /// Implements an algorithm to alter the pixels of an image via a resampling transforms. + /// Implements an algorithm to alter the pixels of an image via resampling transforms. /// /// The pixel format. - public interface IResamplingImageProcessor : IImageProcessor + public interface IResamplingTransformImageProcessor : IImageProcessor where TPixel : struct, IPixel { /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor{TPixel}.Transforms.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs similarity index 75% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor{TPixel}.Transforms.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs index 3190857dd0..72bfa4c0be 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor{TPixel}.Transforms.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs @@ -11,28 +11,53 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { - /// - /// Contains the application code for performing an affine transform. - /// - internal partial class AffineTransformProcessor + /// + /// Provides the base methods to perform affine transforms on an image. + /// + /// The pixel format. + internal class AffineTransformProcessor : TransformProcessor, IResamplingTransformImageProcessor + where TPixel : struct, IPixel { + private readonly Size destinationSize; + private readonly Matrix3x2 transformMatrix; + private readonly IResampler resampler; + private ImageFrame source; + private ImageFrame destination; + /// - /// Applies an affine transformation upon an image. + /// Initializes a new instance of the class. /// - /// The type of sampler. - /// The configuration. - /// The pixel sampler. - /// The source image frame. - /// The destination image frame. - /// The transform matrix. - public static void ApplyAffineTransform( - Configuration configuration, - in TResampler sampler, - ImageFrame source, - ImageFrame destination, - Matrix3x2 matrix) + /// The configuration which allows altering default behaviour or extending the library. + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public AffineTransformProcessor(Configuration configuration, AffineTransformProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) + { + this.destinationSize = definition.DestinationSize; + this.transformMatrix = definition.TransformMatrix; + this.resampler = definition.Sampler; + } + + protected override Size GetDestinationSize() => this.destinationSize; + + /// + protected override void OnFrameApply(ImageFrame source, ImageFrame destination) + { + this.source = source; + this.destination = destination; + this.resampler.ApplyTransform(this); + } + + /// + public void ApplyTransform(in TResampler sampler) where TResampler : struct, IResampler { + Configuration configuration = this.Configuration; + ImageFrame source = this.source; + ImageFrame destination = this.destination; + Matrix3x2 matrix = this.transformMatrix; + // Handle transforms that result in output identical to the original. if (matrix.Equals(default) || matrix.Equals(Matrix3x2.Identity)) { @@ -55,8 +80,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } - int yRadius = AutomorphicTransformUtilities.GetSamplingRadius(in sampler, source.Height, destination.Height); - int xRadius = AutomorphicTransformUtilities.GetSamplingRadius(in sampler, source.Width, destination.Width); + int yRadius = LinearTransformUtilities.GetSamplingRadius(in sampler, source.Height, destination.Height); + int xRadius = LinearTransformUtilities.GetSamplingRadius(in sampler, source.Width, destination.Width); var radialExtents = new Vector2(xRadius, yRadius); int yLength = (yRadius * 2) + 1; int xLength = (xRadius * 2) + 1; @@ -186,7 +211,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Use the single precision position to calculate correct bounding pixels // otherwise we get rogue pixels outside of the bounds. var point = Vector2.Transform(new Vector2(x, y), this.matrix); - AutomorphicTransformUtilities.Convolve( + LinearTransformUtilities.Convolve( in this.sampler, point, sourceBuffer, diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/AutoOrientProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/AutoOrientProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/AutoOrientProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/AutoOrientProcessor{TPixel}.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/FlipProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/FlipProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/FlipProcessor{TPixel}.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/AutomorphicTransformUtilities.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs similarity index 98% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/AutomorphicTransformUtilities.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs index b2283af010..4fb1e27e09 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/AutomorphicTransformUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Utility methods for affine and projective transforms. /// - internal static class AutomorphicTransformUtilities + internal static class LinearTransformUtilities { [MethodImpl(InliningOptions.ShortMethod)] internal static int GetSamplingRadius(in TResampler sampler, int sourceSize, int destinationSize) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor{TPixel}.Transforms.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs similarity index 75% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor{TPixel}.Transforms.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs index c824bebaec..b3315fa554 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor{TPixel}.Transforms.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs @@ -11,28 +11,53 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { - /// - /// Contains the application code for performing a projective transform. - /// - internal partial class ProjectiveTransformProcessor + /// + /// Provides the base methods to perform non-affine transforms on an image. + /// + /// The pixel format. + internal class ProjectiveTransformProcessor : TransformProcessor, IResamplingTransformImageProcessor + where TPixel : struct, IPixel { + private readonly Size destinationSize; + private readonly IResampler resampler; + private readonly Matrix4x4 transformMatrix; + private ImageFrame source; + private ImageFrame destination; + /// - /// Applies a projective transformation upon an image. + /// Initializes a new instance of the class. /// - /// The type of sampler. - /// The configuration. - /// The pixel sampler. - /// The source image frame. - /// The destination image frame. - /// The transform matrix. - public static void ApplyProjectiveTransform( - Configuration configuration, - in TResampler sampler, - ImageFrame source, - ImageFrame destination, - Matrix4x4 matrix) + /// The configuration which allows altering default behaviour or extending the library. + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public ProjectiveTransformProcessor(Configuration configuration, ProjectiveTransformProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) + { + this.destinationSize = definition.DestinationSize; + this.transformMatrix = definition.TransformMatrix; + this.resampler = definition.Sampler; + } + + protected override Size GetDestinationSize() => this.destinationSize; + + /// + protected override void OnFrameApply(ImageFrame source, ImageFrame destination) + { + this.source = source; + this.destination = destination; + this.resampler.ApplyTransform(this); + } + + /// + public void ApplyTransform(in TResampler sampler) where TResampler : struct, IResampler { + Configuration configuration = this.Configuration; + ImageFrame source = this.source; + ImageFrame destination = this.destination; + Matrix4x4 matrix = this.transformMatrix; + // Handle transforms that result in output identical to the original. if (matrix.Equals(default) || matrix.Equals(Matrix4x4.Identity)) { @@ -55,8 +80,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } - int yRadius = AutomorphicTransformUtilities.GetSamplingRadius(in sampler, source.Height, destination.Height); - int xRadius = AutomorphicTransformUtilities.GetSamplingRadius(in sampler, source.Width, destination.Width); + int yRadius = LinearTransformUtilities.GetSamplingRadius(in sampler, source.Height, destination.Height); + int xRadius = LinearTransformUtilities.GetSamplingRadius(in sampler, source.Width, destination.Width); var radialExtents = new Vector2(xRadius, yRadius); int yLength = (yRadius * 2) + 1; int xLength = (xRadius * 2) + 1; @@ -186,7 +211,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Use the single precision position to calculate correct bounding pixels // otherwise we get rogue pixels outside of the bounds. Vector2 point = TransformUtilities.ProjectiveTransform2D(x, y, this.matrix); - AutomorphicTransformUtilities.Convolve( + LinearTransformUtilities.Convolve( in this.sampler, point, sourceBuffer, diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/RotateProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/RotateProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/RotateProcessor{TPixel}.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Automorphic/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Automorphic/SkewProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs index 2992bbf5ac..085c81aad8 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// [MethodImpl(InliningOptions.ShortMethod)] - public void ApplyTransform(IResamplingImageProcessor processor) + public void ApplyTransform(IResamplingTransformImageProcessor processor) where TPixel : struct, IPixel => processor.ApplyTransform(in this); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs index 98a789e342..af2abb5f47 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// [MethodImpl(InliningOptions.ShortMethod)] - public void ApplyTransform(IResamplingImageProcessor processor) + public void ApplyTransform(IResamplingTransformImageProcessor processor) where TPixel : struct, IPixel => processor.ApplyTransform(in this); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CubicResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CubicResampler.cs index a6fba1b33d..b399326741 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CubicResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CubicResampler.cs @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// [MethodImpl(InliningOptions.ShortMethod)] - public void ApplyTransform(IResamplingImageProcessor processor) + public void ApplyTransform(IResamplingTransformImageProcessor processor) where TPixel : struct, IPixel => processor.ApplyTransform(in this); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/LanczosResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/LanczosResampler.cs index 90d60e1b08..202edcd363 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/LanczosResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/LanczosResampler.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// [MethodImpl(InliningOptions.ShortMethod)] - public void ApplyTransform(IResamplingImageProcessor processor) + public void ApplyTransform(IResamplingTransformImageProcessor processor) where TPixel : struct, IPixel => processor.ApplyTransform(in this); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs index 20f0a9fb85..0bce3d1297 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// [MethodImpl(InliningOptions.ShortMethod)] - public void ApplyTransform(IResamplingImageProcessor processor) + public void ApplyTransform(IResamplingTransformImageProcessor processor) where TPixel : struct, IPixel => processor.ApplyTransform(in this); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs index 9cf9ae66af..42459d4a3c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// [MethodImpl(InliningOptions.ShortMethod)] - public void ApplyTransform(IResamplingImageProcessor processor) + public void ApplyTransform(IResamplingTransformImageProcessor processor) where TPixel : struct, IPixel => processor.ApplyTransform(in this); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs index a162c7411f..6142dbe062 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// [MethodImpl(InliningOptions.ShortMethod)] - public void ApplyTransform(IResamplingImageProcessor processor) + public void ApplyTransform(IResamplingTransformImageProcessor processor) where TPixel : struct, IPixel => processor.ApplyTransform(in this); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.Transforms.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.Transforms.cs deleted file mode 100644 index 78f63ee0d3..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.Transforms.cs +++ /dev/null @@ -1,222 +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.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// Contains the application code for resizing. - /// - internal partial class ResizeProcessor - where TPixel : struct, IPixel - { - /// - /// Applies an resizing transformation upon an image. - /// - /// The type of sampler. - /// The configuration. - /// The pixel sampler. - /// The source image. - /// The destination image. - /// The source bounds. - /// The destination location. - /// Whether to compress or expand individual pixel color values on processing. - public static void ApplyResizeTransform( - Configuration configuration, - in TResampler sampler, - Image source, - Image destination, - Rectangle sourceRectangle, - Rectangle destinationRectangle, - bool compand) - where TResampler : struct, IResampler - { - // Handle resize dimensions identical to the original - if (source.Width == destination.Width - && source.Height == destination.Height - && sourceRectangle == destinationRectangle) - { - for (int i = 0; i < source.Frames.Count; i++) - { - ImageFrame sourceFrame = source.Frames[i]; - ImageFrame destinationFrame = destination.Frames[i]; - - // The cloned will be blank here copy all the pixel data over - sourceFrame.GetPixelMemoryGroup().CopyTo(destinationFrame.GetPixelMemoryGroup()); - } - - return; - } - - var interest = Rectangle.Intersect(destinationRectangle, destination.Bounds()); - - if (sampler is NearestNeighborResampler) - { - for (int i = 0; i < source.Frames.Count; i++) - { - ImageFrame sourceFrame = source.Frames[i]; - ImageFrame destinationFrame = destination.Frames[i]; - - ApplyNNResizeFrameTransform( - configuration, - sourceFrame, - destinationFrame, - sourceRectangle, - destinationRectangle, - interest); - } - - return; - } - - // Since all image frame dimensions have to be the same we can calculate - // the kernel maps and reuse for all frames. - MemoryAllocator allocator = configuration.MemoryAllocator; - using var horizontalKernelMap = ResizeKernelMap.Calculate( - in sampler, - destinationRectangle.Width, - sourceRectangle.Width, - allocator); - - using var verticalKernelMap = ResizeKernelMap.Calculate( - in sampler, - destinationRectangle.Height, - sourceRectangle.Height, - allocator); - - for (int i = 0; i < source.Frames.Count; i++) - { - ImageFrame sourceFrame = source.Frames[i]; - ImageFrame destinationFrame = destination.Frames[i]; - - ApplyResizeFrameTransform( - configuration, - sourceFrame, - destinationFrame, - horizontalKernelMap, - verticalKernelMap, - sourceRectangle, - destinationRectangle, - interest, - compand); - } - } - - private static void ApplyNNResizeFrameTransform( - Configuration configuration, - ImageFrame source, - ImageFrame destination, - Rectangle sourceRectangle, - Rectangle destinationRectangle, - Rectangle interest) - { - // Scaling factors - float widthFactor = sourceRectangle.Width / (float)destinationRectangle.Width; - float heightFactor = sourceRectangle.Height / (float)destinationRectangle.Height; - - var operation = new NNRowIntervalOperation( - sourceRectangle, - destinationRectangle, - widthFactor, - heightFactor, - source, - destination); - - ParallelRowIterator.IterateRows( - configuration, - interest, - in operation); - } - - private static void ApplyResizeFrameTransform( - Configuration configuration, - ImageFrame source, - ImageFrame destination, - ResizeKernelMap horizontalKernelMap, - ResizeKernelMap verticalKernelMap, - Rectangle sourceRectangle, - Rectangle destinationRectangle, - Rectangle interest, - bool compand) - { - PixelConversionModifiers conversionModifiers = - PixelConversionModifiers.Premultiply.ApplyCompanding(compand); - - BufferArea sourceArea = source.PixelBuffer.GetArea(sourceRectangle); - - // To reintroduce parallel processing, we would launch multiple workers - // for different row intervals of the image. - using (var worker = new ResizeWorker( - configuration, - sourceArea, - conversionModifiers, - horizontalKernelMap, - verticalKernelMap, - destination.Width, - interest, - destinationRectangle.Location)) - { - worker.Initialize(); - - var workingInterval = new RowInterval(interest.Top, interest.Bottom); - worker.FillDestinationPixels(workingInterval, destination.PixelBuffer); - } - } - - private readonly struct NNRowIntervalOperation : IRowIntervalOperation - { - private readonly Rectangle sourceBounds; - private readonly Rectangle destinationBounds; - private readonly float widthFactor; - private readonly float heightFactor; - private readonly ImageFrame source; - private readonly ImageFrame destination; - - [MethodImpl(InliningOptions.ShortMethod)] - public NNRowIntervalOperation( - Rectangle sourceBounds, - Rectangle destinationBounds, - float widthFactor, - float heightFactor, - ImageFrame source, - ImageFrame destination) - { - this.sourceBounds = sourceBounds; - this.destinationBounds = destinationBounds; - this.widthFactor = widthFactor; - this.heightFactor = heightFactor; - this.source = source; - this.destination = destination; - } - - [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) - { - int sourceX = this.sourceBounds.X; - int sourceY = this.sourceBounds.Y; - int destX = this.destinationBounds.X; - int destY = this.destinationBounds.Y; - int destLeft = this.destinationBounds.Left; - int destRight = this.destinationBounds.Right; - - for (int y = rows.Min; y < rows.Max; y++) - { - // Y coordinates of source points - Span sourceRow = this.source.GetPixelRowSpan((int)(((y - destY) * this.heightFactor) + sourceY)); - Span targetRow = this.destination.GetPixelRowSpan(y); - - for (int x = destLeft; x < destRight; x++) - { - // X coordinates of source points - targetRow[x] = sourceRow[(int)(((x - destX) * this.widthFactor) + sourceX)]; - } - } - } - } - } -} diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index 5b69184d7c..1a6b8030db 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -1,6 +1,10 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -9,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Implements resizing of images using various resamplers. /// /// The pixel format. - internal partial class ResizeProcessor : TransformProcessor, IResamplingImageProcessor + internal partial class ResizeProcessor : TransformProcessor, IResamplingTransformImageProcessor where TPixel : struct, IPixel { private readonly int destinationWidth; @@ -48,14 +52,196 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } public void ApplyTransform(in TResampler sampler) - where TResampler : struct, IResampler => - ApplyResizeTransform( - this.Configuration, + where TResampler : struct, IResampler + { + Configuration configuration = this.Configuration; + Image source = this.Source; + Image destination = this.destination; + Rectangle sourceRectangle = this.SourceRectangle; + Rectangle destinationRectangle = this.destinationRectangle; + bool compand = this.compand; + + // Handle resize dimensions identical to the original + if (source.Width == destination.Width + && source.Height == destination.Height + && sourceRectangle == destinationRectangle) + { + for (int i = 0; i < source.Frames.Count; i++) + { + ImageFrame sourceFrame = source.Frames[i]; + ImageFrame destinationFrame = destination.Frames[i]; + + // The cloned will be blank here copy all the pixel data over + sourceFrame.GetPixelMemoryGroup().CopyTo(destinationFrame.GetPixelMemoryGroup()); + } + + return; + } + + var interest = Rectangle.Intersect(destinationRectangle, destination.Bounds()); + + if (sampler is NearestNeighborResampler) + { + for (int i = 0; i < source.Frames.Count; i++) + { + ImageFrame sourceFrame = source.Frames[i]; + ImageFrame destinationFrame = destination.Frames[i]; + + ApplyNNResizeFrameTransform( + configuration, + sourceFrame, + destinationFrame, + sourceRectangle, + destinationRectangle, + interest); + } + + return; + } + + // Since all image frame dimensions have to be the same we can calculate + // the kernel maps and reuse for all frames. + MemoryAllocator allocator = configuration.MemoryAllocator; + using var horizontalKernelMap = ResizeKernelMap.Calculate( + in sampler, + destinationRectangle.Width, + sourceRectangle.Width, + allocator); + + using var verticalKernelMap = ResizeKernelMap.Calculate( in sampler, - this.Source, - this.destination, - this.SourceRectangle, - this.destinationRectangle, - this.compand); + destinationRectangle.Height, + sourceRectangle.Height, + allocator); + + for (int i = 0; i < source.Frames.Count; i++) + { + ImageFrame sourceFrame = source.Frames[i]; + ImageFrame destinationFrame = destination.Frames[i]; + + ApplyResizeFrameTransform( + configuration, + sourceFrame, + destinationFrame, + horizontalKernelMap, + verticalKernelMap, + sourceRectangle, + destinationRectangle, + interest, + compand); + } + } + + private static void ApplyNNResizeFrameTransform( + Configuration configuration, + ImageFrame source, + ImageFrame destination, + Rectangle sourceRectangle, + Rectangle destinationRectangle, + Rectangle interest) + { + // Scaling factors + float widthFactor = sourceRectangle.Width / (float)destinationRectangle.Width; + float heightFactor = sourceRectangle.Height / (float)destinationRectangle.Height; + + var operation = new NNRowIntervalOperation( + sourceRectangle, + destinationRectangle, + widthFactor, + heightFactor, + source, + destination); + + ParallelRowIterator.IterateRows( + configuration, + interest, + in operation); + } + + private static void ApplyResizeFrameTransform( + Configuration configuration, + ImageFrame source, + ImageFrame destination, + ResizeKernelMap horizontalKernelMap, + ResizeKernelMap verticalKernelMap, + Rectangle sourceRectangle, + Rectangle destinationRectangle, + Rectangle interest, + bool compand) + { + PixelConversionModifiers conversionModifiers = + PixelConversionModifiers.Premultiply.ApplyCompanding(compand); + + BufferArea sourceArea = source.PixelBuffer.GetArea(sourceRectangle); + + // To reintroduce parallel processing, we would launch multiple workers + // for different row intervals of the image. + using (var worker = new ResizeWorker( + configuration, + sourceArea, + conversionModifiers, + horizontalKernelMap, + verticalKernelMap, + destination.Width, + interest, + destinationRectangle.Location)) + { + worker.Initialize(); + + var workingInterval = new RowInterval(interest.Top, interest.Bottom); + worker.FillDestinationPixels(workingInterval, destination.PixelBuffer); + } + } + + private readonly struct NNRowIntervalOperation : IRowIntervalOperation + { + private readonly Rectangle sourceBounds; + private readonly Rectangle destinationBounds; + private readonly float widthFactor; + private readonly float heightFactor; + private readonly ImageFrame source; + private readonly ImageFrame destination; + + [MethodImpl(InliningOptions.ShortMethod)] + public NNRowIntervalOperation( + Rectangle sourceBounds, + Rectangle destinationBounds, + float widthFactor, + float heightFactor, + ImageFrame source, + ImageFrame destination) + { + this.sourceBounds = sourceBounds; + this.destinationBounds = destinationBounds; + this.widthFactor = widthFactor; + this.heightFactor = heightFactor; + this.source = source; + this.destination = destination; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void Invoke(in RowInterval rows) + { + int sourceX = this.sourceBounds.X; + int sourceY = this.sourceBounds.Y; + int destX = this.destinationBounds.X; + int destY = this.destinationBounds.Y; + int destLeft = this.destinationBounds.Left; + int destRight = this.destinationBounds.Right; + + for (int y = rows.Min; y < rows.Max; y++) + { + // Y coordinates of source points + Span sourceRow = this.source.GetPixelRowSpan((int)(((y - destY) * this.heightFactor) + sourceY)); + Span targetRow = this.destination.GetPixelRowSpan(y); + + for (int x = destLeft; x < destRight; x++) + { + // X coordinates of source points + targetRow[x] = sourceRow[(int)(((x - destX) * this.widthFactor) + sourceX)]; + } + } + } + } } }