diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index f644fbefb5..e8908fe05e 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -24,13 +24,14 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgba = new Rgba64(0, 0, 0, 65535); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - rgba = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba64(rgba); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba64(temp); } } @@ -95,13 +96,14 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgb = default(Rgb48); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - rgb = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgb48(rgb); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgb48(temp); } } @@ -166,13 +168,14 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgba = new Rgba32(0, 0, 0, 255); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - rgba = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(rgba); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba32(temp); } } @@ -237,13 +240,14 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var bgra = new Bgra32(0, 0, 0, 255); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - bgra = Unsafe.Add(ref sourceRef, i); - dp.PackFromBgra32(bgra); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromBgra32(temp); } } @@ -308,13 +312,14 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgba = new Rgba32(0, 0, 0, 255); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - rgba.Rgb = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(rgba); + temp.Rgb = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba32(temp); } } @@ -379,13 +384,14 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgba = new Rgba32(0, 0, 0, 255); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - rgba.Bgr = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(rgba); + temp.Bgr = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba32(temp); } } @@ -450,13 +456,14 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var argb = new Argb32(0, 0, 0, 255); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - argb = Unsafe.Add(ref sourceRef, i); - dp.PackFromArgb32(argb); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromArgb32(temp); } } @@ -509,4 +516,5 @@ namespace SixLabors.ImageSharp.PixelFormats } } + } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index 1a6ac60f58..5c762c7df1 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -10,132 +10,8 @@ <#@ import namespace="System.Runtime.InteropServices" #> <#@ output extension=".cs" #> <# - void GenerateToDestFormatMethods(string pixelType) - { - #> - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . - /// - /// The span of source pixels - /// The destination span of data. - /// The number of pixels to convert. - internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); - sp.To<#=pixelType#>(ref dp); - } - } - - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void To<#=pixelType#>Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) - { - this.To<#=pixelType#>(sourceColors, MemoryMarshal.Cast>(destBytes), count); - } - <# - } - - void GeneratePackFromMethodUsingPackFromRgba64(string pixelType, string rgbaOperationCode) - { - #> - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - var rgba = new Rgba64(0, 0, 0, 65535); - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=rgbaOperationCode#> - dp.PackFromRgba64(rgba); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); - } - <# - } - - void GeneratePackFromMethodUsingPackFromRgb48(string pixelType, string rgbaOperationCode) - { - #> - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - var rgb = default(Rgb48); - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=rgbaOperationCode#> - dp.PackFromRgb48(rgb); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); - } - <# - } - void GeneratePackFromMethodUsingPackFromRgba32(string pixelType, string rgbaOperationCode) + void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode) { #> @@ -152,13 +28,14 @@ ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgba = new Rgba32(0, 0, 0, 255); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! + var temp = NamedColors<<#=tempPixelType#>>.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=rgbaOperationCode#> - dp.PackFromRgba32(rgba); + <#=assignToTempCode#> + dp.PackFrom<#=tempPixelType#>(temp); } } @@ -177,86 +54,43 @@ <# } - void GeneratePackFromMethodUsingPackFromArgb32(string pixelType, string argbOperationCode) - { - #> + void GenerateToDestFormatMethods(string pixelType) + { + #> /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Bulk version of . /// - /// The source of data. - /// The to the destination pixels. + /// The span of source pixels + /// The destination span of data. /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) + internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> dest, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - var argb = new Argb32(0, 0, 0, 255); + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(dest); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=argbOperationCode#> - dp.PackFromArgb32(argb); + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); + sp.To<#=pixelType#>(ref dp); } } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); - } - <# - } - - void GeneratePackFromMethodUsingPackFromBgra32(string pixelType, string bgraOperationCode) - { - #> /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - var bgra = new Bgra32(0, 0, 0, 255); - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=bgraOperationCode#> - dp.PackFromBgra32(bgra); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source bytes. - /// The to the destination pixels. + /// The to the source colors. + /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void To<#=pixelType#>Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); + this.To<#=pixelType#>(sourceColors, MemoryMarshal.Cast>(destBytes), count); } <# } @@ -275,29 +109,28 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations { <# - - GeneratePackFromMethodUsingPackFromRgba64("Rgba64", "rgba = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba64"); - GeneratePackFromMethodUsingPackFromRgb48("Rgb48", "rgb = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Rgb48", "Rgb48", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgb48"); - GeneratePackFromMethodUsingPackFromRgba32("Rgba32", "rgba = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Rgba32", "Rgba32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba32"); - GeneratePackFromMethodUsingPackFromBgra32("Bgra32", "bgra = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Bgra32", "Bgra32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Bgra32"); - GeneratePackFromMethodUsingPackFromRgba32("Rgb24", "rgba.Rgb = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Rgb24", "Rgba32", "temp.Rgb = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgb24"); - GeneratePackFromMethodUsingPackFromRgba32("Bgr24", "rgba.Bgr = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Bgr24", "Rgba32", "temp.Bgr = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Bgr24"); - GeneratePackFromMethodUsingPackFromArgb32("Argb32", "argb = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Argb32"); - #> } + } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 76abc64996..53cd9e9d3e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -40,25 +40,28 @@ 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) + // 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 the minimum is is kept. + const int min = 1; + if (targetWidth == 0 && targetHeight > 0) { - tempWidth = (int)MathF.Round(sourceSize.Width * tempHeight / (float)sourceSize.Height); + targetWidth = (int)MathF.Max(min, MathF.Round(sourceSize.Width * targetHeight / (float)sourceSize.Height)); } - if (tempHeight == 0 && tempWidth > 0) + if (targetHeight == 0 && targetWidth > 0) { - tempHeight = (int)MathF.Round(sourceSize.Height * tempWidth / (float)sourceSize.Width); + targetHeight = (int)MathF.Max(min, MathF.Round(sourceSize.Height * targetWidth / (float)sourceSize.Width)); } - Guard.MustBeGreaterThan(tempWidth, 0, nameof(tempWidth)); - Guard.MustBeGreaterThan(tempHeight, 0, nameof(tempHeight)); + Guard.MustBeGreaterThan(targetWidth, 0, nameof(targetWidth)); + Guard.MustBeGreaterThan(targetHeight, 0, nameof(targetHeight)); - (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 +98,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Guard.NotNull(sampler, nameof(sampler)); // Ensure size is populated across both dimensions. + // 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 the minimum is is kept. + const int min = 1; if (width == 0 && height > 0) { - width = (int)MathF.Round(sourceSize.Width * height / (float)sourceSize.Height); + width = (int)MathF.Max(min, MathF.Round(sourceSize.Width * height / (float)sourceSize.Height)); resizeRectangle.Width = width; } if (height == 0 && width > 0) { - height = (int)MathF.Round(sourceSize.Height * width / (float)sourceSize.Width); + height = (int)MathF.Max(min, MathF.Round(sourceSize.Height * width / (float)sourceSize.Width)); resizeRectangle.Height = height; } diff --git a/src/ImageSharp/Processing/ResizeExtensions.cs b/src/ImageSharp/Processing/ResizeExtensions.cs index 8a370db693..7b6c14d7de 100644 --- a/src/ImageSharp/Processing/ResizeExtensions.cs +++ b/src/ImageSharp/Processing/ResizeExtensions.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Processing /// The image to resize. /// The resize options. /// The - /// Passing zero for one of height or width within the resize options will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width within the resize options will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, ResizeOptions options) where TPixel : struct, IPixel => source.ApplyProcessor(new ResizeProcessor(options, source.GetCurrentSize())); @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Processing /// The image to resize. /// The target image size. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, Size size) where TPixel : struct, IPixel => Resize(source, size.Width, size.Height, KnownResamplers.Bicubic, false); @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing /// The target image size. /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, Size size, bool compand) where TPixel : struct, IPixel => Resize(source, size.Width, size.Height, KnownResamplers.Bicubic, compand); @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing /// The target image width. /// The target image height. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height) where TPixel : struct, IPixel => Resize(source, width, height, KnownResamplers.Bicubic, false); @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing /// The target image height. /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, bool compand) where TPixel : struct, IPixel => Resize(source, width, height, KnownResamplers.Bicubic, compand); @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing /// The target image height. /// The to perform the resampling. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, IResampler sampler) where TPixel : struct, IPixel => Resize(source, width, height, sampler, false); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Processing /// The to perform the resampling. /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, Size size, IResampler sampler, bool compand) where TPixel : struct, IPixel => Resize(source, size.Width, size.Height, sampler, new Rectangle(0, 0, size.Width, size.Height), compand); @@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing /// The to perform the resampling. /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, IResampler sampler, bool compand) where TPixel : struct, IPixel => Resize(source, width, height, sampler, new Rectangle(0, 0, width, height), compand); @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Processing /// /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize( this IImageProcessingContext source, int width, @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.Processing /// /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize( this IImageProcessingContext source, int width, 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);