Browse Source

When passing 0 to only one dimension on resize, it will keep one pixel in case aspect ratio results in less than 1 pixel for a dimension.

pull/719/head
David Svånå 8 years ago
parent
commit
f5464b589f
  1. 63
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  2. 34
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

63
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

@ -40,25 +40,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Guard.NotNull(options, nameof(options));
Guard.NotNull(options.Sampler, nameof(options.Sampler));
int tempWidth = options.Size.Width;
int tempHeight = options.Size.Height;
int targetWidth = options.Size.Width;
int targetHeight = options.Size.Height;
// Ensure size is populated across both dimensions.
// These dimensions are used to calculate the final dimensions determined by the mode algorithm.
if (tempWidth == 0 && tempHeight > 0)
{
tempWidth = (int)MathF.Round(sourceSize.Width * tempHeight / (float)sourceSize.Height);
}
if (tempHeight == 0 && tempWidth > 0)
{
tempHeight = (int)MathF.Round(sourceSize.Height * tempWidth / (float)sourceSize.Width);
}
Guard.MustBeGreaterThan(tempWidth, 0, nameof(tempWidth));
Guard.MustBeGreaterThan(tempHeight, 0, nameof(tempHeight));
EnsureSizeBothDimensions(sourceSize.Width, sourceSize.Height, ref targetWidth, ref targetHeight, out _, out _);
(Size size, Rectangle rectangle) = ResizeHelper.CalculateTargetLocationAndBounds(sourceSize, options, tempWidth, tempHeight);
(Size size, Rectangle rectangle) = ResizeHelper.CalculateTargetLocationAndBounds(sourceSize, options, targetWidth, targetHeight);
this.Sampler = options.Sampler;
this.Width = size.Width;
@ -95,15 +84,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Guard.NotNull(sampler, nameof(sampler));
// Ensure size is populated across both dimensions.
if (width == 0 && height > 0)
EnsureSizeBothDimensions(sourceSize.Width, sourceSize.Height, ref width, ref height, out bool changedWidth, out bool changedHeight);
if (changedWidth)
{
width = (int)MathF.Round(sourceSize.Width * height / (float)sourceSize.Height);
resizeRectangle.Width = width;
}
if (height == 0 && width > 0)
if (changedHeight)
{
height = (int)MathF.Round(sourceSize.Height * width / (float)sourceSize.Width);
resizeRectangle.Height = height;
}
@ -142,6 +130,43 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary>
public bool Compand { get; }
/// <summary>
/// Makes sure both target dimensions are >= 1.
/// If only one of the incoming dimensions is 0, it will be modified here to maintain aspect ratio.
/// If it is not possible to keep aspect ratio, make sure at least 1 pixel is kept.
/// </summary>
private static void EnsureSizeBothDimensions(
int sourceWidth,
int sourceHeight,
ref int targetWidth,
ref int targetHeight,
out bool changedTargetWidth,
out bool changedTargetHeight)
{
if (targetWidth == 0 && targetHeight > 0)
{
targetWidth = Math.Max(1, (int)MathF.Round(sourceWidth * targetHeight / (float)sourceHeight));
changedTargetWidth = true;
}
else
{
changedTargetWidth = false;
}
if (targetHeight == 0 && targetWidth > 0)
{
targetHeight = Math.Max(1, (int)MathF.Round(sourceHeight * targetWidth / (float)sourceWidth));
changedTargetHeight = true;
}
else
{
changedTargetHeight = false;
}
Guard.MustBeGreaterThan(targetWidth, 0, nameof(targetWidth));
Guard.MustBeGreaterThan(targetHeight, 0, nameof(targetHeight));
}
/// <summary>
/// Computes the weights to apply at each pixel when resizing.
/// </summary>

34
tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

@ -178,6 +178,32 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
}
}
[Theory]
[WithTestPatternImages(100, 10, DefaultPixelType)]
public void ResizeWidthCannotKeepAspectKeepsOnePixel<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x.Resize(5, 0));
Assert.Equal(5, image.Width);
Assert.Equal(1, image.Height);
}
}
[Theory]
[WithTestPatternImages(10, 100, DefaultPixelType)]
public void ResizeHeightCannotKeepAspectKeepsOnePixel<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x.Resize(0, 5));
Assert.Equal(1, image.Width);
Assert.Equal(5, image.Height);
}
}
[Theory]
[WithFileCollection(nameof(CommonTestImages), DefaultPixelType)]
public void ResizeWithCropWidthMode<TPixel>(TestImageProvider<TPixel> provider)
@ -324,7 +350,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
[InlineData(2, 0)]
public static void BicubicWindowOscillatesCorrectly(float x, float expected)
{
var sampler = KnownResamplers.Bicubic;
IResampler sampler = KnownResamplers.Bicubic;
float result = sampler.GetValue(x);
Assert.Equal(result, expected);
@ -338,7 +364,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
[InlineData(2, 0)]
public static void TriangleWindowOscillatesCorrectly(float x, float expected)
{
var sampler = KnownResamplers.Triangle;
IResampler sampler = KnownResamplers.Triangle;
float result = sampler.GetValue(x);
Assert.Equal(result, expected);
@ -352,7 +378,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
[InlineData(2, 0)]
public static void Lanczos3WindowOscillatesCorrectly(float x, float expected)
{
var sampler = KnownResamplers.Lanczos3;
IResampler sampler = KnownResamplers.Lanczos3;
float result = sampler.GetValue(x);
Assert.Equal(result, expected);
@ -366,7 +392,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
[InlineData(4, 0)]
public static void Lanczos5WindowOscillatesCorrectly(float x, float expected)
{
var sampler = KnownResamplers.Lanczos5;
IResampler sampler = KnownResamplers.Lanczos5;
float result = sampler.GetValue(x);
Assert.Equal(result, expected);

Loading…
Cancel
Save