Browse Source

Merge branch 'master' into dp/jpeg-encoder-zigzag

pull/1958/head
Dmitry Pentin 4 years ago
committed by GitHub
parent
commit
4ac5cc51df
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      src/ImageSharp/Formats/Webp/IWebpEncoderOptions.cs
  2. 25
      src/ImageSharp/Formats/Webp/WebpEncoderCore.cs
  3. 4
      src/ImageSharp/Memory/Buffer2DRegion{T}.cs
  4. 41
      src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs
  5. 5
      src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor.cs
  6. 54
      src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs
  7. 10
      src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtility.cs
  8. 5
      src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs
  9. 58
      src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs
  10. 2
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
  11. 2
      tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
  12. 64
      tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedMemoryPoolTests.cs
  13. 2
      tests/ImageSharp.Tests/Memory/BufferAreaTests.cs
  14. 41
      tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs
  15. 40
      tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs
  16. 2
      tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs
  17. 3
      tests/Images/External/ReferenceOutput/AffineTransformTests/Identity_Rgba32_TestPattern100x100.png
  18. 4
      tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_FromSourceRectangle1_Rgba32_TestPattern96x48.png
  19. 4
      tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_FromSourceRectangle2_Rgba32_TestPattern96x48.png
  20. 3
      tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_0.0001.png
  21. 3
      tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_0.png
  22. 3
      tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_57.png
  23. 3
      tests/Images/External/ReferenceOutput/ProjectiveTransformTests/Identity_Rgba32_TestPattern100x100.png
  24. 3
      tests/Images/External/ReferenceOutput/ProjectiveTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_0.0001.png
  25. 3
      tests/Images/External/ReferenceOutput/ProjectiveTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_0.png
  26. 3
      tests/Images/External/ReferenceOutput/ProjectiveTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_57.png

1
src/ImageSharp/Formats/Webp/IWebpEncoderOptions.cs

@ -10,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
{
/// <summary>
/// Gets the webp file format used. Either lossless or lossy.
/// Defaults to lossy.
/// </summary>
WebpFileFormatType? FileFormat { get; }

25
src/ImageSharp/Formats/Webp/WebpEncoderCore.cs

@ -70,6 +70,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// <summary>
/// Indicating what file format compression should be used.
/// Defaults to lossy.
/// </summary>
private readonly WebpFileFormatType? fileFormat;
@ -112,43 +113,43 @@ namespace SixLabors.ImageSharp.Formats.Webp
Guard.NotNull(stream, nameof(stream));
this.configuration = image.GetConfiguration();
bool lossy;
bool lossless;
if (this.fileFormat is not null)
{
lossy = this.fileFormat == WebpFileFormatType.Lossy;
lossless = this.fileFormat == WebpFileFormatType.Lossless;
}
else
{
WebpMetadata webpMetadata = image.Metadata.GetWebpMetadata();
lossy = webpMetadata.FileFormat == WebpFileFormatType.Lossy;
lossless = webpMetadata.FileFormat == WebpFileFormatType.Lossless;
}
if (lossy)
if (lossless)
{
using var enc = new Vp8Encoder(
using var enc = new Vp8LEncoder(
this.memoryAllocator,
this.configuration,
image.Width,
image.Height,
this.quality,
this.method,
this.entropyPasses,
this.filterStrength,
this.spatialNoiseShaping);
this.transparentColorMode,
this.nearLossless,
this.nearLosslessQuality);
enc.Encode(image, stream);
}
else
{
using var enc = new Vp8LEncoder(
using var enc = new Vp8Encoder(
this.memoryAllocator,
this.configuration,
image.Width,
image.Height,
this.quality,
this.method,
this.transparentColorMode,
this.nearLossless,
this.nearLosslessQuality);
this.entropyPasses,
this.filterStrength,
this.spatialNoiseShaping);
enc.Encode(image, stream);
}
}

4
src/ImageSharp/Memory/Buffer2DRegion{T}.cs

@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Memory
/// <param name="y">The row index</param>
/// <returns>The span</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> GetRowSpan(int y)
public Span<T> DangerousGetRowSpan(int y)
{
int yy = this.Rectangle.Y + y;
int xx = this.Rectangle.X;
@ -152,7 +152,7 @@ namespace SixLabors.ImageSharp.Memory
for (int y = 0; y < this.Rectangle.Height; y++)
{
Span<T> row = this.GetRowSpan(y);
Span<T> row = this.DangerousGetRowSpan(y);
row.Clear();
}
}

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

@ -46,38 +46,25 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// <inheritdoc/>
Image<TPixel> ICloningImageProcessor<TPixel>.CloneAndExecute()
{
try
{
Image<TPixel> clone = this.CreateTarget();
this.CheckFrameCount(this.Source, clone);
Image<TPixel> clone = this.CreateTarget();
this.CheckFrameCount(this.Source, clone);
Configuration configuration = this.Configuration;
this.BeforeImageApply(clone);
Configuration configuration = this.Configuration;
this.BeforeImageApply(clone);
for (int i = 0; i < this.Source.Frames.Count; i++)
{
ImageFrame<TPixel> sourceFrame = this.Source.Frames[i];
ImageFrame<TPixel> clonedFrame = clone.Frames[i];
for (int i = 0; i < this.Source.Frames.Count; i++)
{
ImageFrame<TPixel> sourceFrame = this.Source.Frames[i];
ImageFrame<TPixel> clonedFrame = clone.Frames[i];
this.BeforeFrameApply(sourceFrame, clonedFrame);
this.OnFrameApply(sourceFrame, clonedFrame);
this.AfterFrameApply(sourceFrame, clonedFrame);
}
this.BeforeFrameApply(sourceFrame, clonedFrame);
this.OnFrameApply(sourceFrame, clonedFrame);
this.AfterFrameApply(sourceFrame, clonedFrame);
}
this.AfterImageApply(clone);
this.AfterImageApply(clone);
return clone;
}
#if DEBUG
catch (Exception)
{
throw;
#else
catch (Exception ex)
{
throw new ImageProcessingException($"An error occurred when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex);
#endif
}
return clone;
}
/// <inheritdoc/>

5
src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor.cs

@ -21,6 +21,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Guard.NotNull(sampler, nameof(sampler));
Guard.MustBeValueType(sampler, nameof(sampler));
if (TransformUtils.IsDegenerate(matrix))
{
throw new DegenerateTransformException("Matrix is degenerate. Check input values.");
}
this.Sampler = sampler;
this.TransformMatrix = matrix;
this.DestinationSize = targetDimensions;

54
src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs

@ -61,10 +61,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Matrix3x2 matrix = this.transformMatrix;
// Handle transforms that result in output identical to the original.
if (matrix.Equals(default) || matrix.Equals(Matrix3x2.Identity))
// Degenerate matrices are already handled in the upstream definition.
if (matrix.Equals(Matrix3x2.Identity))
{
// The clone will be blank here copy all the pixel data over
source.GetPixelMemoryGroup().CopyTo(destination.GetPixelMemoryGroup());
var interest = Rectangle.Intersect(this.SourceRectangle, destination.Bounds());
Buffer2DRegion<TPixel> sourceBuffer = source.PixelBuffer.GetRegion(interest);
Buffer2DRegion<TPixel> destbuffer = destination.PixelBuffer.GetRegion(interest);
for (int y = 0; y < sourceBuffer.Height; y++)
{
sourceBuffer.DangerousGetRowSpan(y).CopyTo(destbuffer.DangerousGetRowSpan(y));
}
return;
}
@ -73,7 +81,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
if (sampler is NearestNeighborResampler)
{
var nnOperation = new NNAffineOperation(source.PixelBuffer, destination.PixelBuffer, matrix);
var nnOperation = new NNAffineOperation(
source.PixelBuffer,
Rectangle.Intersect(this.SourceRectangle, source.Bounds()),
destination.PixelBuffer,
matrix);
ParallelRowIterator.IterateRows(
configuration,
destination.Bounds(),
@ -85,6 +98,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
var operation = new AffineOperation<TResampler>(
configuration,
source.PixelBuffer,
Rectangle.Intersect(this.SourceRectangle, source.Bounds()),
destination.PixelBuffer,
in sampler,
matrix);
@ -105,12 +119,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)]
public NNAffineOperation(
Buffer2D<TPixel> source,
Rectangle bounds,
Buffer2D<TPixel> destination,
Matrix3x2 matrix)
{
this.source = source;
this.bounds = bounds;
this.destination = destination;
this.bounds = source.Bounds();
this.matrix = matrix;
}
@ -138,6 +153,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
private readonly Configuration configuration;
private readonly Buffer2D<TPixel> source;
private readonly Rectangle bounds;
private readonly Buffer2D<TPixel> destination;
private readonly TResampler sampler;
private readonly Matrix3x2 matrix;
@ -148,12 +164,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public AffineOperation(
Configuration configuration,
Buffer2D<TPixel> source,
Rectangle bounds,
Buffer2D<TPixel> destination,
in TResampler sampler,
Matrix3x2 matrix)
{
this.configuration = configuration;
this.source = source;
this.bounds = bounds;
this.destination = destination;
this.sampler = sampler;
this.matrix = matrix;
@ -182,8 +200,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
TResampler sampler = this.sampler;
float yRadius = this.yRadius;
float xRadius = this.xRadius;
int maxY = this.source.Height - 1;
int maxX = this.source.Width - 1;
int minY = this.bounds.Y;
int maxY = this.bounds.Bottom - 1;
int minX = this.bounds.X;
int maxX = this.bounds.Right - 1;
for (int y = rows.Min; y < rows.Max; y++)
{
@ -200,10 +220,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
float pY = point.Y;
float pX = point.X;
int top = LinearTransformUtility.GetRangeStart(yRadius, pY, maxY);
int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, maxY);
int left = LinearTransformUtility.GetRangeStart(xRadius, pX, maxX);
int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, maxX);
int top = LinearTransformUtility.GetRangeStart(yRadius, pY, minY, maxY);
int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, minY, maxY);
int left = LinearTransformUtility.GetRangeStart(xRadius, pX, minX, maxX);
int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, minX, maxX);
if (bottom == top || right == left)
{
@ -245,8 +265,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
TResampler sampler = this.sampler;
float yRadius = this.yRadius;
float xRadius = this.xRadius;
int maxY = this.source.Height - 1;
int maxX = this.source.Width - 1;
int minY = this.bounds.Y;
int maxY = this.bounds.Bottom - 1;
int minX = this.bounds.X;
int maxX = this.bounds.Right - 1;
for (int y = rows.Min; y < rows.Max; y++)
{
@ -263,10 +285,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
float pY = point.Y;
float pX = point.X;
int top = LinearTransformUtility.GetRangeStart(yRadius, pY, maxY);
int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, maxY);
int left = LinearTransformUtility.GetRangeStart(xRadius, pX, maxX);
int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, maxX);
int top = LinearTransformUtility.GetRangeStart(yRadius, pY, minY, maxY);
int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, minY, maxY);
int left = LinearTransformUtility.GetRangeStart(xRadius, pX, minX, maxX);
int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, minX, maxX);
if (bottom == top || right == left)
{

10
src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtility.cs

@ -39,11 +39,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary>
/// <param name="radius">The radius.</param>
/// <param name="center">The center position.</param>
/// <param name="min">The min allowed amouunt.</param>
/// <param name="max">The max allowed amouunt.</param>
/// <returns>The <see cref="int"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static int GetRangeStart(float radius, float center, int max)
=> Numerics.Clamp((int)MathF.Ceiling(center - radius), 0, max);
public static int GetRangeStart(float radius, float center, int min, int max)
=> Numerics.Clamp((int)MathF.Ceiling(center - radius), min, max);
/// <summary>
/// Gets the end position (inclusive) for a sampling range given
@ -51,10 +52,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary>
/// <param name="radius">The radius.</param>
/// <param name="center">The center position.</param>
/// <param name="min">The min allowed amouunt.</param>
/// <param name="max">The max allowed amouunt.</param>
/// <returns>The <see cref="int"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static int GetRangeEnd(float radius, float center, int max)
=> Numerics.Clamp((int)MathF.Floor(center + radius), 0, max);
public static int GetRangeEnd(float radius, float center, int min, int max)
=> Numerics.Clamp((int)MathF.Floor(center + radius), min, max);
}
}

5
src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs

@ -21,6 +21,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Guard.NotNull(sampler, nameof(sampler));
Guard.MustBeValueType(sampler, nameof(sampler));
if (TransformUtils.IsDegenerate(matrix))
{
throw new DegenerateTransformException("Matrix is degenerate. Check input values.");
}
this.Sampler = sampler;
this.TransformMatrix = matrix;
this.DestinationSize = targetDimensions;

58
src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs

@ -60,10 +60,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Matrix4x4 matrix = this.transformMatrix;
// Handle transforms that result in output identical to the original.
if (matrix.Equals(default) || matrix.Equals(Matrix4x4.Identity))
// Degenerate matrices are already handled in the upstream definition.
if (matrix.Equals(Matrix4x4.Identity))
{
// The clone will be blank here copy all the pixel data over
source.GetPixelMemoryGroup().CopyTo(destination.GetPixelMemoryGroup());
var interest = Rectangle.Intersect(this.SourceRectangle, destination.Bounds());
Buffer2DRegion<TPixel> sourceBuffer = source.PixelBuffer.GetRegion(interest);
Buffer2DRegion<TPixel> destbuffer = destination.PixelBuffer.GetRegion(interest);
for (int y = 0; y < sourceBuffer.Height; y++)
{
sourceBuffer.DangerousGetRowSpan(y).CopyTo(destbuffer.DangerousGetRowSpan(y));
}
return;
}
@ -72,7 +80,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
if (sampler is NearestNeighborResampler)
{
var nnOperation = new NNProjectiveOperation(source.PixelBuffer, destination.PixelBuffer, matrix);
var nnOperation = new NNProjectiveOperation(
source.PixelBuffer,
Rectangle.Intersect(this.SourceRectangle, source.Bounds()),
destination.PixelBuffer,
matrix);
ParallelRowIterator.IterateRows(
configuration,
destination.Bounds(),
@ -84,6 +97,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
var operation = new ProjectiveOperation<TResampler>(
configuration,
source.PixelBuffer,
Rectangle.Intersect(this.SourceRectangle, source.Bounds()),
destination.PixelBuffer,
in sampler,
matrix);
@ -104,12 +118,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)]
public NNProjectiveOperation(
Buffer2D<TPixel> source,
Rectangle bounds,
Buffer2D<TPixel> destination,
Matrix4x4 matrix)
{
this.source = source;
this.bounds = bounds;
this.destination = destination;
this.bounds = source.Bounds();
this.matrix = matrix;
}
@ -137,6 +152,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
private readonly Configuration configuration;
private readonly Buffer2D<TPixel> source;
private readonly Rectangle bounds;
private readonly Buffer2D<TPixel> destination;
private readonly TResampler sampler;
private readonly Matrix4x4 matrix;
@ -147,18 +163,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public ProjectiveOperation(
Configuration configuration,
Buffer2D<TPixel> source,
Rectangle bounds,
Buffer2D<TPixel> destination,
in TResampler sampler,
Matrix4x4 matrix)
{
this.configuration = configuration;
this.source = source;
this.bounds = bounds;
this.destination = destination;
this.sampler = sampler;
this.matrix = matrix;
this.yRadius = LinearTransformUtility.GetSamplingRadius(in sampler, source.Height, destination.Height);
this.xRadius = LinearTransformUtility.GetSamplingRadius(in sampler, source.Width, destination.Width);
this.yRadius = LinearTransformUtility.GetSamplingRadius(in sampler, bounds.Height, destination.Height);
this.xRadius = LinearTransformUtility.GetSamplingRadius(in sampler, bounds.Width, destination.Width);
}
[MethodImpl(InliningOptions.ShortMethod)]
@ -181,8 +199,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
TResampler sampler = this.sampler;
float yRadius = this.yRadius;
float xRadius = this.xRadius;
int maxY = this.source.Height - 1;
int maxX = this.source.Width - 1;
int minY = this.bounds.Y;
int maxY = this.bounds.Bottom - 1;
int minX = this.bounds.X;
int maxX = this.bounds.Right - 1;
for (int y = rows.Min; y < rows.Max; y++)
{
@ -199,10 +219,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
float pY = point.Y;
float pX = point.X;
int top = LinearTransformUtility.GetRangeStart(yRadius, pY, maxY);
int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, maxY);
int left = LinearTransformUtility.GetRangeStart(xRadius, pX, maxX);
int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, maxX);
int top = LinearTransformUtility.GetRangeStart(yRadius, pY, minY, maxY);
int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, minY, maxY);
int left = LinearTransformUtility.GetRangeStart(xRadius, pX, minX, maxX);
int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, minX, maxX);
if (bottom <= top || right <= left)
{
@ -244,8 +264,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
TResampler sampler = this.sampler;
float yRadius = this.yRadius;
float xRadius = this.xRadius;
int maxY = this.source.Height - 1;
int maxX = this.source.Width - 1;
int minY = this.bounds.Y;
int maxY = this.bounds.Bottom - 1;
int minX = this.bounds.X;
int maxX = this.bounds.Right - 1;
for (int y = rows.Min; y < rows.Max; y++)
{
@ -262,10 +284,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
float pY = point.Y;
float pX = point.X;
int top = LinearTransformUtility.GetRangeStart(yRadius, pY, maxY);
int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, maxY);
int left = LinearTransformUtility.GetRangeStart(xRadius, pX, maxX);
int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, maxX);
int top = LinearTransformUtility.GetRangeStart(yRadius, pY, minY, maxY);
int bottom = LinearTransformUtility.GetRangeEnd(yRadius, pY, minY, maxY);
int left = LinearTransformUtility.GetRangeStart(xRadius, pX, minX, maxX);
int right = LinearTransformUtility.GetRangeEnd(xRadius, pX, minX, maxX);
if (bottom <= top || right <= left)
{

2
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
for (int y = calculationInterval.Min; y < calculationInterval.Max; y++)
{
Span<TPixel> sourceRow = this.source.GetRowSpan(y);
Span<TPixel> sourceRow = this.source.DangerousGetRowSpan(y);
PixelOperations<TPixel>.Instance.ToVector4(
this.configuration,

2
tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs

@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp
private static string TestImageLossyFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, Lossy.NoFilter06);
[Theory]
[WithFile(Flag, PixelTypes.Rgba32, WebpFileFormatType.Lossless)] // if its not a webp input image, it should default to lossless.
[WithFile(Flag, PixelTypes.Rgba32, WebpFileFormatType.Lossy)] // If its not a webp input image, it should default to lossy.
[WithFile(Lossless.NoTransform1, PixelTypes.Rgba32, WebpFileFormatType.Lossless)]
[WithFile(Lossy.Bike, PixelTypes.Rgba32, WebpFileFormatType.Lossy)]
public void Encode_PreserveRatio<TPixel>(TestImageProvider<TPixel> provider, WebpFileFormatType expectedFormat)

64
tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedMemoryPoolTests.cs

@ -245,43 +245,45 @@ namespace SixLabors.ImageSharp.Tests.Memory.Allocators
cleanup.Register(b1);
}
public static readonly bool IsNotMacOS = !TestEnvironment.IsOSX;
// TODO: Investigate MacOS failures
[ConditionalTheory(nameof(IsNotMacOS))]
[Theory]
[InlineData(false)]
[InlineData(true)]
public void RentReturnRelease_SubsequentRentReturnsDifferentHandles(bool multiple)
{
var pool = new UniformUnmanagedMemoryPool(16, 16);
using var cleanup = new CleanupUtil(pool);
UnmanagedMemoryHandle b0 = pool.Rent();
IntPtr h0 = b0.Handle;
UnmanagedMemoryHandle b1 = pool.Rent();
IntPtr h1 = b1.Handle;
pool.Return(b0);
pool.Return(b1);
pool.Release();
// Do some unmanaged allocations to make sure new pool buffers are different:
IntPtr[] dummy = Enumerable.Range(0, 100).Select(_ => Marshal.AllocHGlobal(16)).ToArray();
cleanup.Register(dummy);
RemoteExecutor.Invoke(RunTest, multiple.ToString()).Dispose();
if (multiple)
static void RunTest(string multipleInner)
{
UnmanagedMemoryHandle b = pool.Rent();
cleanup.Register(b);
Assert.NotEqual(h0, b.Handle);
Assert.NotEqual(h1, b.Handle);
}
else
{
UnmanagedMemoryHandle[] b = pool.Rent(2);
cleanup.Register(b);
Assert.NotEqual(h0, b[0].Handle);
Assert.NotEqual(h1, b[0].Handle);
Assert.NotEqual(h0, b[1].Handle);
Assert.NotEqual(h1, b[1].Handle);
var pool = new UniformUnmanagedMemoryPool(16, 16);
using var cleanup = new CleanupUtil(pool);
UnmanagedMemoryHandle b0 = pool.Rent();
IntPtr h0 = b0.Handle;
UnmanagedMemoryHandle b1 = pool.Rent();
IntPtr h1 = b1.Handle;
pool.Return(b0);
pool.Return(b1);
pool.Release();
// Do some unmanaged allocations to make sure new pool buffers are different:
IntPtr[] dummy = Enumerable.Range(0, 100).Select(_ => Marshal.AllocHGlobal(16)).ToArray();
cleanup.Register(dummy);
if (bool.Parse(multipleInner))
{
UnmanagedMemoryHandle b = pool.Rent();
cleanup.Register(b);
Assert.NotEqual(h0, b.Handle);
Assert.NotEqual(h1, b.Handle);
}
else
{
UnmanagedMemoryHandle[] b = pool.Rent(2);
cleanup.Register(b);
Assert.NotEqual(h0, b[0].Handle);
Assert.NotEqual(h1, b[0].Handle);
Assert.NotEqual(h0, b[1].Handle);
Assert.NotEqual(h1, b[1].Handle);
}
}
}

2
tests/ImageSharp.Tests/Memory/BufferAreaTests.cs

@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Memory
Buffer2DRegion<int> region = buffer.GetRegion(r);
Span<int> span = region.GetRowSpan(y);
Span<int> span = region.DangerousGetRowSpan(y);
Assert.Equal(w, span.Length);

41
tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs

@ -4,6 +4,7 @@
using System;
using System.Numerics;
using System.Reflection;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
@ -224,6 +225,46 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
c => c.Transform(builder));
}
[Fact]
public void Issue1911()
{
using var image = new Image<Rgba32>(100, 100);
image.Mutate(x => x = x.Transform(new Rectangle(0, 0, 99, 100), Matrix3x2.Identity, new Size(99, 100), KnownResamplers.Lanczos2));
Assert.Equal(99, image.Width);
Assert.Equal(100, image.Height);
}
[Theory]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32)]
public void Identity<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
Matrix3x2 m = Matrix3x2.Identity;
Rectangle r = new(25, 25, 50, 50);
image.Mutate(x => x.Transform(r, m, new Size(100, 100), KnownResamplers.Bicubic));
image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider);
}
[Theory]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32, 0.0001F)]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32, 57F)]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32, 0F)]
public void Transform_With_Custom_Dimensions<TPixel>(TestImageProvider<TPixel> provider, float radians)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
var m = Matrix3x2.CreateRotation(radians, new Vector2(50, 50));
Rectangle r = new(25, 25, 50, 50);
image.Mutate(x => x.Transform(r, m, new Size(100, 100), KnownResamplers.Bicubic));
image.DebugSave(provider, testOutputDetails: radians);
image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails: radians);
}
private static IResampler GetResampler(string name)
{
PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name);

40
tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs

@ -147,6 +147,46 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
}
}
[Fact]
public void Issue1911()
{
using var image = new Image<Rgba32>(100, 100);
image.Mutate(x => x = x.Transform(new Rectangle(0, 0, 99, 100), Matrix4x4.Identity, new Size(99, 100), KnownResamplers.Lanczos2));
Assert.Equal(99, image.Width);
Assert.Equal(100, image.Height);
}
[Theory]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32)]
public void Identity<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
Matrix4x4 m = Matrix4x4.Identity;
Rectangle r = new(25, 25, 50, 50);
image.Mutate(x => x.Transform(r, m, new Size(100, 100), KnownResamplers.Bicubic));
image.DebugSave(provider);
image.CompareToReferenceOutput(ValidatorComparer, provider);
}
[Theory]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32, 0.0001F)]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32, 57F)]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32, 0F)]
public void Transform_With_Custom_Dimensions<TPixel>(TestImageProvider<TPixel> provider, float radians)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
Matrix4x4 m = Matrix4x4.CreateRotationX(radians, new Vector3(50, 50, 1F)) * Matrix4x4.CreateRotationY(radians, new Vector3(50, 50, 1F));
Rectangle r = new(25, 25, 50, 50);
image.Mutate(x => x.Transform(r, m, new Size(100, 100), KnownResamplers.Bicubic));
image.DebugSave(provider, testOutputDetails: radians);
image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails: radians);
}
private static IResampler GetResampler(string name)
{
PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name);

2
tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs

@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization
var white = new L8(255);
for (int y = 0; y < region.Height; y++)
{
region.GetRowSpan(y).Fill(white);
region.DangerousGetRowSpan(y).Fill(white);
}
}

3
tests/Images/External/ReferenceOutput/AffineTransformTests/Identity_Rgba32_TestPattern100x100.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:da8229605bda413676a42f587df250a743540e6e00c04eacb1e622f223e19595
size 3564

4
tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_FromSourceRectangle1_Rgba32_TestPattern96x48.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b01d54838d678b61c3b7a1c7e76ff9a60b3f5f4faef5af848231177eac956eb1
size 1262
oid sha256:bbe1ffaf7b801fd92724438cc810fd0c5506e0a907b970c4f0bf5bec3627ca2a
size 551

4
tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_FromSourceRectangle2_Rgba32_TestPattern96x48.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d34394771605c2a70cc23f3841592c20d22a68aaabf2ad6e8aba7348a181afb3
size 531
oid sha256:b45933471a1af1b6d4112240e1bc6b6187065a872043ddbf917200ce9e8cc84b
size 371

3
tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_0.0001.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dd3b29b530e221618f65cd5e493b21fe3c27804fde7664636b7bb002f72abbb2
size 3663

3
tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_0.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:da8229605bda413676a42f587df250a743540e6e00c04eacb1e622f223e19595
size 3564

3
tests/Images/External/ReferenceOutput/AffineTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_57.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a35757fef08a6fd9b37e719d5be7a82d5ff79f0395e082f697d9ebe9c7f03cc8
size 5748

3
tests/Images/External/ReferenceOutput/ProjectiveTransformTests/Identity_Rgba32_TestPattern100x100.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:da8229605bda413676a42f587df250a743540e6e00c04eacb1e622f223e19595
size 3564

3
tests/Images/External/ReferenceOutput/ProjectiveTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_0.0001.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:39c25539c3c9b8926bf65c041df693a60617bbe8653bb72357bde5ab6342c59c
size 3618

3
tests/Images/External/ReferenceOutput/ProjectiveTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_0.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:da8229605bda413676a42f587df250a743540e6e00c04eacb1e622f223e19595
size 3564

3
tests/Images/External/ReferenceOutput/ProjectiveTransformTests/Transform_With_Custom_Dimensions_Rgba32_TestPattern100x100_57.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8b1fc95fdf07c7443147205afffb157aa82f94818cfbb833a615c42f584fbda0
size 5070
Loading…
Cancel
Save