mirror of https://github.com/SixLabors/ImageSharp
Browse Source
If we normalize the weights to make this work when the output is scaled down we break the edge pixel output. Somehow fix this.af/merge-core
4 changed files with 249 additions and 41 deletions
@ -0,0 +1,47 @@ |
|||
// 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 |
|||
{ |
|||
/// <summary>
|
|||
/// Provides methods that allow the tranformation of images using various algorithms.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class TransformProcessor<TPixel> : AffineProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="TransformProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The transformation matrix</param>
|
|||
public TransformProcessor(Matrix3x2 matrix) |
|||
: this(matrix, KnownResamplers.NearestNeighbor) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="TransformProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The transformation matrix</param>
|
|||
/// <param name="sampler">The sampler to perform the transform operation.</param>
|
|||
public TransformProcessor(Matrix3x2 matrix, IResampler sampler) |
|||
: base(sampler) |
|||
{ |
|||
this.TransformMatrix = matrix; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the transform matrix
|
|||
/// </summary>
|
|||
public Matrix3x2 TransformMatrix { get; } |
|||
|
|||
/// <inheritdoc />
|
|||
protected override Matrix3x2 GetTransformMatrix() |
|||
{ |
|||
return this.TransformMatrix; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Processing.Processors; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Image{TPixel}"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Transforms an image by the given matrix.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to skew.</param>
|
|||
/// <param name="matrix">The transformation matrix.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/></returns>
|
|||
public static IImageProcessingContext<TPixel> Transform<TPixel>(this IImageProcessingContext<TPixel> source, Matrix3x2 matrix) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> Transform(source, matrix, KnownResamplers.NearestNeighbor); |
|||
|
|||
/// <summary>
|
|||
/// Transforms an image by the given matrix using the specified sampling algorithm.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to skew.</param>
|
|||
/// <param name="matrix">The transformation matrix.</param>
|
|||
/// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/></returns>
|
|||
public static IImageProcessingContext<TPixel> Transform<TPixel>(this IImageProcessingContext<TPixel> source, Matrix3x2 matrix, IResampler sampler) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new TransformProcessor<TPixel>(matrix, sampler)); |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Processing.Transforms |
|||
{ |
|||
using System.Numerics; |
|||
using System.Reflection; |
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.Primitives; |
|||
|
|||
using Xunit; |
|||
|
|||
public class TransformTests : FileTestBase |
|||
{ |
|||
public static readonly TheoryData<float, float, float> TransformValues |
|||
= new TheoryData<float, float, float> |
|||
{ |
|||
{ 20, 10, 50 }, |
|||
{ -20, -10, 50 } |
|||
}; |
|||
|
|||
public static readonly List<string> ResamplerNames |
|||
= new List<string> |
|||
{ |
|||
nameof(KnownResamplers.Bicubic), |
|||
//nameof(KnownResamplers.Box),
|
|||
//nameof(KnownResamplers.CatmullRom),
|
|||
//nameof(KnownResamplers.Hermite),
|
|||
//nameof(KnownResamplers.Lanczos2),
|
|||
//nameof(KnownResamplers.Lanczos3),
|
|||
//nameof(KnownResamplers.Lanczos5),
|
|||
//nameof(KnownResamplers.Lanczos8),
|
|||
//nameof(KnownResamplers.MitchellNetravali),
|
|||
//nameof(KnownResamplers.NearestNeighbor),
|
|||
//nameof(KnownResamplers.Robidoux),
|
|||
//nameof(KnownResamplers.RobidouxSharp),
|
|||
//nameof(KnownResamplers.Spline),
|
|||
//nameof(KnownResamplers.Triangle),
|
|||
//nameof(KnownResamplers.Welch),
|
|||
}; |
|||
|
|||
[Theory] |
|||
[WithFileCollection(nameof(DefaultFiles), nameof(TransformValues), DefaultPixelType)] |
|||
public void ImageShouldTransformWithSampler<TPixel>(TestImageProvider<TPixel> provider, float x, float y, float z) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
|
|||
foreach (string resamplerName in ResamplerNames) |
|||
{ |
|||
IResampler sampler = GetResampler(resamplerName); |
|||
using (Image<TPixel> image = provider.GetImage()) |
|||
{ |
|||
Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(-z); |
|||
|
|||
// TODO, how does scale work? 2 means half just now,
|
|||
Matrix3x2 scale = Matrix3x2Extensions.CreateScale(new SizeF(2F, 2F)); |
|||
|
|||
|
|||
image.Mutate(i => i.Transform(scale * rotate, sampler)); |
|||
image.DebugSave(provider, string.Join("_", x, y, resamplerName)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static IResampler GetResampler(string name) |
|||
{ |
|||
PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); |
|||
|
|||
if (property == null) |
|||
{ |
|||
throw new Exception("Invalid property name!"); |
|||
} |
|||
|
|||
return (IResampler)property.GetValue(null); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue