From f5464b589fddd9852b41ad3a2f6293ff96980815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sv=C3=A5n=C3=A5?= Date: Sun, 30 Sep 2018 20:49:24 +0200 Subject: [PATCH] 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. --- .../Processors/Transforms/ResizeProcessor.cs | 63 +++++++++++++------ .../Processors/Transforms/ResizeTests.cs | 34 ++++++++-- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 76abc64996..2f1ef68652 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/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 /// public bool Compand { get; } + /// + /// 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. + /// + 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)); + } + /// /// Computes the weights to apply at each pixel when resizing. /// diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 746d8da16e..d1d473bbd2 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/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(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image 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(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image 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(TestImageProvider 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);