Browse Source

Update based on feedback.

af/octree-no-pixelmap
James Jackson-South 6 years ago
parent
commit
54fb7ab02d
  1. 57
      src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor{TPixel}.cs
  2. 57
      src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor{TPixel}.cs
  3. 2
      src/ImageSharp/Processing/Processors/Transforms/IResampler.cs
  4. 4
      src/ImageSharp/Processing/Processors/Transforms/IResamplingTransformImageProcessor{TPixel}.cs
  5. 0
      src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor.cs
  6. 65
      src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs
  7. 0
      src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor.cs
  8. 0
      src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs
  9. 0
      src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor.cs
  10. 0
      src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs
  11. 2
      src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs
  12. 0
      src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs
  13. 65
      src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs
  14. 0
      src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs
  15. 0
      src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs
  16. 0
      src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs
  17. 2
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs
  18. 2
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs
  19. 2
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/CubicResampler.cs
  20. 2
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/LanczosResampler.cs
  21. 2
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs
  22. 2
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs
  23. 2
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs
  24. 222
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.Transforms.cs
  25. 204
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs

57
src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor{TPixel}.cs

@ -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
{
/// <summary>
/// Provides the base methods to perform affine transforms on an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal partial class AffineTransformProcessor<TPixel> : TransformProcessor<TPixel>, IResamplingImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Size destinationSize;
private readonly Matrix3x2 transformMatrix;
private readonly IResampler resampler;
private ImageFrame<TPixel> source;
private ImageFrame<TPixel> destination;
/// <summary>
/// Initializes a new instance of the <see cref="AffineTransformProcessor{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="definition">The <see cref="AffineTransformProcessor"/> defining the processor parameters.</param>
/// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
public AffineTransformProcessor(Configuration configuration, AffineTransformProcessor definition, Image<TPixel> 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;
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
{
this.source = source;
this.destination = destination;
this.resampler.ApplyTransform(this);
}
/// <inheritdoc/>
public void ApplyTransform<TResampler>(in TResampler sampler)
where TResampler : struct, IResampler
=> ApplyAffineTransform(
this.Configuration,
in sampler,
this.source,
this.destination,
this.transformMatrix);
}
}

57
src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor{TPixel}.cs

@ -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
{
/// <summary>
/// Provides the base methods to perform non-affine transforms on an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal partial class ProjectiveTransformProcessor<TPixel> : TransformProcessor<TPixel>, IResamplingImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Size destinationSize;
private readonly IResampler resampler;
private readonly Matrix4x4 transformMatrix;
private ImageFrame<TPixel> source;
private ImageFrame<TPixel> destination;
/// <summary>
/// Initializes a new instance of the <see cref="ProjectiveTransformProcessor{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="definition">The <see cref="ProjectiveTransformProcessor"/> defining the processor parameters.</param>
/// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
public ProjectiveTransformProcessor(Configuration configuration, ProjectiveTransformProcessor definition, Image<TPixel> 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;
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
{
this.source = source;
this.destination = destination;
this.resampler.ApplyTransform(this);
}
/// <inheritdoc/>
public void ApplyTransform<TResampler>(in TResampler sampler)
where TResampler : struct, IResampler
=> ApplyProjectiveTransform(
this.Configuration,
in sampler,
this.source,
this.destination,
this.transformMatrix);
}
}

2
src/ImageSharp/Processing/Processors/Transforms/IResampler.cs

@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="processor">The transforming image processor.</param> /// <param name="processor">The transforming image processor.</param>
void ApplyTransform<TPixel>(IResamplingImageProcessor<TPixel> processor) void ApplyTransform<TPixel>(IResamplingTransformImageProcessor<TPixel> processor)
where TPixel : struct, IPixel<TPixel>; where TPixel : struct, IPixel<TPixel>;
} }
} }

4
src/ImageSharp/Processing/Processors/Transforms/IResamplingImageProcessor{TPixel}.cs → src/ImageSharp/Processing/Processors/Transforms/IResamplingTransformImageProcessor{TPixel}.cs

@ -6,10 +6,10 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{ {
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
public interface IResamplingImageProcessor<TPixel> : IImageProcessor<TPixel> public interface IResamplingTransformImageProcessor<TPixel> : IImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>

0
src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor.cs

65
src/ImageSharp/Processing/Processors/Transforms/Automorphic/AffineTransformProcessor{TPixel}.Transforms.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs

@ -11,28 +11,53 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{ {
/// <content> /// <summary>
/// Contains the application code for performing an affine transform. /// Provides the base methods to perform affine transforms on an image.
/// </content> /// </summary>
internal partial class AffineTransformProcessor<TPixel> /// <typeparam name="TPixel">The pixel format.</typeparam>
internal class AffineTransformProcessor<TPixel> : TransformProcessor<TPixel>, IResamplingTransformImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{ {
private readonly Size destinationSize;
private readonly Matrix3x2 transformMatrix;
private readonly IResampler resampler;
private ImageFrame<TPixel> source;
private ImageFrame<TPixel> destination;
/// <summary> /// <summary>
/// Applies an affine transformation upon an image. /// Initializes a new instance of the <see cref="AffineTransformProcessor{TPixel}"/> class.
/// </summary> /// </summary>
/// <typeparam name="TResampler">The type of sampler.</typeparam> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="configuration">The configuration.</param> /// <param name="definition">The <see cref="AffineTransformProcessor"/> defining the processor parameters.</param>
/// <param name="sampler">The pixel sampler.</param> /// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
/// <param name="source">The source image frame.</param> /// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
/// <param name="destination">The destination image frame.</param> public AffineTransformProcessor(Configuration configuration, AffineTransformProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
/// <param name="matrix">The transform matrix.</param> : base(configuration, source, sourceRectangle)
public static void ApplyAffineTransform<TResampler>( {
Configuration configuration, this.destinationSize = definition.DestinationSize;
in TResampler sampler, this.transformMatrix = definition.TransformMatrix;
ImageFrame<TPixel> source, this.resampler = definition.Sampler;
ImageFrame<TPixel> destination, }
Matrix3x2 matrix)
protected override Size GetDestinationSize() => this.destinationSize;
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
{
this.source = source;
this.destination = destination;
this.resampler.ApplyTransform(this);
}
/// <inheritdoc/>
public void ApplyTransform<TResampler>(in TResampler sampler)
where TResampler : struct, IResampler where TResampler : struct, IResampler
{ {
Configuration configuration = this.Configuration;
ImageFrame<TPixel> source = this.source;
ImageFrame<TPixel> destination = this.destination;
Matrix3x2 matrix = this.transformMatrix;
// Handle transforms that result in output identical to the original. // Handle transforms that result in output identical to the original.
if (matrix.Equals(default) || matrix.Equals(Matrix3x2.Identity)) if (matrix.Equals(default) || matrix.Equals(Matrix3x2.Identity))
{ {
@ -55,8 +80,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return; return;
} }
int yRadius = AutomorphicTransformUtilities.GetSamplingRadius(in sampler, source.Height, destination.Height); int yRadius = LinearTransformUtilities.GetSamplingRadius(in sampler, source.Height, destination.Height);
int xRadius = AutomorphicTransformUtilities.GetSamplingRadius(in sampler, source.Width, destination.Width); int xRadius = LinearTransformUtilities.GetSamplingRadius(in sampler, source.Width, destination.Width);
var radialExtents = new Vector2(xRadius, yRadius); var radialExtents = new Vector2(xRadius, yRadius);
int yLength = (yRadius * 2) + 1; int yLength = (yRadius * 2) + 1;
int xLength = (xRadius * 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 // Use the single precision position to calculate correct bounding pixels
// otherwise we get rogue pixels outside of the bounds. // otherwise we get rogue pixels outside of the bounds.
var point = Vector2.Transform(new Vector2(x, y), this.matrix); var point = Vector2.Transform(new Vector2(x, y), this.matrix);
AutomorphicTransformUtilities.Convolve( LinearTransformUtilities.Convolve(
in this.sampler, in this.sampler,
point, point,
sourceBuffer, sourceBuffer,

0
src/ImageSharp/Processing/Processors/Transforms/Automorphic/AutoOrientProcessor.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor.cs

0
src/ImageSharp/Processing/Processors/Transforms/Automorphic/AutoOrientProcessor{TPixel}.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs

0
src/ImageSharp/Processing/Processors/Transforms/Automorphic/FlipProcessor.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor.cs

0
src/ImageSharp/Processing/Processors/Transforms/Automorphic/FlipProcessor{TPixel}.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs

2
src/ImageSharp/Processing/Processors/Transforms/Automorphic/AutomorphicTransformUtilities.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary> /// <summary>
/// Utility methods for affine and projective transforms. /// Utility methods for affine and projective transforms.
/// </summary> /// </summary>
internal static class AutomorphicTransformUtilities internal static class LinearTransformUtilities
{ {
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
internal static int GetSamplingRadius<TResampler>(in TResampler sampler, int sourceSize, int destinationSize) internal static int GetSamplingRadius<TResampler>(in TResampler sampler, int sourceSize, int destinationSize)

0
src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs

65
src/ImageSharp/Processing/Processors/Transforms/Automorphic/ProjectiveTransformProcessor{TPixel}.Transforms.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs

@ -11,28 +11,53 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{ {
/// <content> /// <summary>
/// Contains the application code for performing a projective transform. /// Provides the base methods to perform non-affine transforms on an image.
/// </content> /// </summary>
internal partial class ProjectiveTransformProcessor<TPixel> /// <typeparam name="TPixel">The pixel format.</typeparam>
internal class ProjectiveTransformProcessor<TPixel> : TransformProcessor<TPixel>, IResamplingTransformImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{ {
private readonly Size destinationSize;
private readonly IResampler resampler;
private readonly Matrix4x4 transformMatrix;
private ImageFrame<TPixel> source;
private ImageFrame<TPixel> destination;
/// <summary> /// <summary>
/// Applies a projective transformation upon an image. /// Initializes a new instance of the <see cref="ProjectiveTransformProcessor{TPixel}"/> class.
/// </summary> /// </summary>
/// <typeparam name="TResampler">The type of sampler.</typeparam> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="configuration">The configuration.</param> /// <param name="definition">The <see cref="ProjectiveTransformProcessor"/> defining the processor parameters.</param>
/// <param name="sampler">The pixel sampler.</param> /// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
/// <param name="source">The source image frame.</param> /// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
/// <param name="destination">The destination image frame.</param> public ProjectiveTransformProcessor(Configuration configuration, ProjectiveTransformProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
/// <param name="matrix">The transform matrix.</param> : base(configuration, source, sourceRectangle)
public static void ApplyProjectiveTransform<TResampler>( {
Configuration configuration, this.destinationSize = definition.DestinationSize;
in TResampler sampler, this.transformMatrix = definition.TransformMatrix;
ImageFrame<TPixel> source, this.resampler = definition.Sampler;
ImageFrame<TPixel> destination, }
Matrix4x4 matrix)
protected override Size GetDestinationSize() => this.destinationSize;
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
{
this.source = source;
this.destination = destination;
this.resampler.ApplyTransform(this);
}
/// <inheritdoc/>
public void ApplyTransform<TResampler>(in TResampler sampler)
where TResampler : struct, IResampler where TResampler : struct, IResampler
{ {
Configuration configuration = this.Configuration;
ImageFrame<TPixel> source = this.source;
ImageFrame<TPixel> destination = this.destination;
Matrix4x4 matrix = this.transformMatrix;
// Handle transforms that result in output identical to the original. // Handle transforms that result in output identical to the original.
if (matrix.Equals(default) || matrix.Equals(Matrix4x4.Identity)) if (matrix.Equals(default) || matrix.Equals(Matrix4x4.Identity))
{ {
@ -55,8 +80,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return; return;
} }
int yRadius = AutomorphicTransformUtilities.GetSamplingRadius(in sampler, source.Height, destination.Height); int yRadius = LinearTransformUtilities.GetSamplingRadius(in sampler, source.Height, destination.Height);
int xRadius = AutomorphicTransformUtilities.GetSamplingRadius(in sampler, source.Width, destination.Width); int xRadius = LinearTransformUtilities.GetSamplingRadius(in sampler, source.Width, destination.Width);
var radialExtents = new Vector2(xRadius, yRadius); var radialExtents = new Vector2(xRadius, yRadius);
int yLength = (yRadius * 2) + 1; int yLength = (yRadius * 2) + 1;
int xLength = (xRadius * 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 // Use the single precision position to calculate correct bounding pixels
// otherwise we get rogue pixels outside of the bounds. // otherwise we get rogue pixels outside of the bounds.
Vector2 point = TransformUtilities.ProjectiveTransform2D(x, y, this.matrix); Vector2 point = TransformUtilities.ProjectiveTransform2D(x, y, this.matrix);
AutomorphicTransformUtilities.Convolve( LinearTransformUtilities.Convolve(
in this.sampler, in this.sampler,
point, point,
sourceBuffer, sourceBuffer,

0
src/ImageSharp/Processing/Processors/Transforms/Automorphic/RotateProcessor.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs

0
src/ImageSharp/Processing/Processors/Transforms/Automorphic/RotateProcessor{TPixel}.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs

0
src/ImageSharp/Processing/Processors/Transforms/Automorphic/SkewProcessor.cs → src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs

2
src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs

@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void ApplyTransform<TPixel>(IResamplingImageProcessor<TPixel> processor) public void ApplyTransform<TPixel>(IResamplingTransformImageProcessor<TPixel> processor)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> processor.ApplyTransform(in this); => processor.ApplyTransform(in this);
} }

2
src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs

@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void ApplyTransform<TPixel>(IResamplingImageProcessor<TPixel> processor) public void ApplyTransform<TPixel>(IResamplingTransformImageProcessor<TPixel> processor)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> processor.ApplyTransform(in this); => processor.ApplyTransform(in this);
} }

2
src/ImageSharp/Processing/Processors/Transforms/Resamplers/CubicResampler.cs

@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void ApplyTransform<TPixel>(IResamplingImageProcessor<TPixel> processor) public void ApplyTransform<TPixel>(IResamplingTransformImageProcessor<TPixel> processor)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> processor.ApplyTransform(in this); => processor.ApplyTransform(in this);
} }

2
src/ImageSharp/Processing/Processors/Transforms/Resamplers/LanczosResampler.cs

@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void ApplyTransform<TPixel>(IResamplingImageProcessor<TPixel> processor) public void ApplyTransform<TPixel>(IResamplingTransformImageProcessor<TPixel> processor)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> processor.ApplyTransform(in this); => processor.ApplyTransform(in this);
} }

2
src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void ApplyTransform<TPixel>(IResamplingImageProcessor<TPixel> processor) public void ApplyTransform<TPixel>(IResamplingTransformImageProcessor<TPixel> processor)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> processor.ApplyTransform(in this); => processor.ApplyTransform(in this);
} }

2
src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs

@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void ApplyTransform<TPixel>(IResamplingImageProcessor<TPixel> processor) public void ApplyTransform<TPixel>(IResamplingTransformImageProcessor<TPixel> processor)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> processor.ApplyTransform(in this); => processor.ApplyTransform(in this);
} }

2
src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs

@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void ApplyTransform<TPixel>(IResamplingImageProcessor<TPixel> processor) public void ApplyTransform<TPixel>(IResamplingTransformImageProcessor<TPixel> processor)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> processor.ApplyTransform(in this); => processor.ApplyTransform(in this);
} }

222
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.Transforms.cs

@ -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
{
/// <content>
/// Contains the application code for resizing.
/// </content>
internal partial class ResizeProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Applies an resizing transformation upon an image.
/// </summary>
/// <typeparam name="TResampler">The type of sampler.</typeparam>
/// <param name="configuration">The configuration.</param>
/// <param name="sampler">The pixel sampler.</param>
/// <param name="source">The source image.</param>
/// <param name="destination">The destination image.</param>
/// <param name="sourceRectangle">The source bounds.</param>
/// <param name="destinationRectangle">The destination location.</param>
/// <param name="compand">Whether to compress or expand individual pixel color values on processing.</param>
public static void ApplyResizeTransform<TResampler>(
Configuration configuration,
in TResampler sampler,
Image<TPixel> source,
Image<TPixel> 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<TPixel> sourceFrame = source.Frames[i];
ImageFrame<TPixel> 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<TPixel> sourceFrame = source.Frames[i];
ImageFrame<TPixel> 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<TPixel> sourceFrame = source.Frames[i];
ImageFrame<TPixel> destinationFrame = destination.Frames[i];
ApplyResizeFrameTransform(
configuration,
sourceFrame,
destinationFrame,
horizontalKernelMap,
verticalKernelMap,
sourceRectangle,
destinationRectangle,
interest,
compand);
}
}
private static void ApplyNNResizeFrameTransform(
Configuration configuration,
ImageFrame<TPixel> source,
ImageFrame<TPixel> 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<TPixel> source,
ImageFrame<TPixel> destination,
ResizeKernelMap horizontalKernelMap,
ResizeKernelMap verticalKernelMap,
Rectangle sourceRectangle,
Rectangle destinationRectangle,
Rectangle interest,
bool compand)
{
PixelConversionModifiers conversionModifiers =
PixelConversionModifiers.Premultiply.ApplyCompanding(compand);
BufferArea<TPixel> 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<TPixel>(
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<TPixel> source;
private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)]
public NNRowIntervalOperation(
Rectangle sourceBounds,
Rectangle destinationBounds,
float widthFactor,
float heightFactor,
ImageFrame<TPixel> source,
ImageFrame<TPixel> 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<TPixel> sourceRow = this.source.GetPixelRowSpan((int)(((y - destY) * this.heightFactor) + sourceY));
Span<TPixel> 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)];
}
}
}
}
}
}

204
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs

@ -1,6 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // 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; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -9,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// Implements resizing of images using various resamplers. /// Implements resizing of images using various resamplers.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
internal partial class ResizeProcessor<TPixel> : TransformProcessor<TPixel>, IResamplingImageProcessor<TPixel> internal partial class ResizeProcessor<TPixel> : TransformProcessor<TPixel>, IResamplingTransformImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private readonly int destinationWidth; private readonly int destinationWidth;
@ -48,14 +52,196 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
public void ApplyTransform<TResampler>(in TResampler sampler) public void ApplyTransform<TResampler>(in TResampler sampler)
where TResampler : struct, IResampler => where TResampler : struct, IResampler
ApplyResizeTransform( {
this.Configuration, Configuration configuration = this.Configuration;
Image<TPixel> source = this.Source;
Image<TPixel> 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<TPixel> sourceFrame = source.Frames[i];
ImageFrame<TPixel> 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<TPixel> sourceFrame = source.Frames[i];
ImageFrame<TPixel> 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, in sampler,
this.Source, destinationRectangle.Height,
this.destination, sourceRectangle.Height,
this.SourceRectangle, allocator);
this.destinationRectangle,
this.compand); for (int i = 0; i < source.Frames.Count; i++)
{
ImageFrame<TPixel> sourceFrame = source.Frames[i];
ImageFrame<TPixel> destinationFrame = destination.Frames[i];
ApplyResizeFrameTransform(
configuration,
sourceFrame,
destinationFrame,
horizontalKernelMap,
verticalKernelMap,
sourceRectangle,
destinationRectangle,
interest,
compand);
}
}
private static void ApplyNNResizeFrameTransform(
Configuration configuration,
ImageFrame<TPixel> source,
ImageFrame<TPixel> 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<TPixel> source,
ImageFrame<TPixel> destination,
ResizeKernelMap horizontalKernelMap,
ResizeKernelMap verticalKernelMap,
Rectangle sourceRectangle,
Rectangle destinationRectangle,
Rectangle interest,
bool compand)
{
PixelConversionModifiers conversionModifiers =
PixelConversionModifiers.Premultiply.ApplyCompanding(compand);
BufferArea<TPixel> 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<TPixel>(
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<TPixel> source;
private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)]
public NNRowIntervalOperation(
Rectangle sourceBounds,
Rectangle destinationBounds,
float widthFactor,
float heightFactor,
ImageFrame<TPixel> source,
ImageFrame<TPixel> 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<TPixel> sourceRow = this.source.GetPixelRowSpan((int)(((y - destY) * this.heightFactor) + sourceY));
Span<TPixel> 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)];
}
}
}
}
} }
} }

Loading…
Cancel
Save