diff --git a/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs index 8c3edcadf..ff374a9ac 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. namespace SixLabors.ImageSharp.Processing @@ -34,9 +34,10 @@ namespace SixLabors.ImageSharp.Processing Size = new Size(width, height), Mode = ResizeMode.BoxPad, Sampler = KnownResamplers.NearestNeighbor, + PadColor = color }; - return color.Equals(default) ? source.Resize(options) : source.Resize(options).BackgroundColor(color); + return source.Resize(options); } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index 3d6900683..ef6a15fc9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs @@ -21,19 +21,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms (Size size, Rectangle rectangle) = ResizeHelper.CalculateTargetLocationAndBounds(sourceSize, options); - this.Sampler = options.Sampler; + this.Options = options; this.DestinationWidth = size.Width; this.DestinationHeight = size.Height; this.DestinationRectangle = rectangle; - this.Compand = options.Compand; - this.PremultiplyAlpha = options.PremultiplyAlpha; } - /// - /// Gets the sampler to perform the resize operation. - /// - public IResampler Sampler { get; } - /// /// Gets the destination width. /// @@ -50,14 +43,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public Rectangle DestinationRectangle { get; } /// - /// Gets a value indicating whether to compress or expand individual pixel color values on processing. - /// - public bool Compand { get; } - - /// - /// Gets a value indicating whether to premultiply the alpha (if it exists) during the resize operation. + /// Gets the resize options. /// - public bool PremultiplyAlpha { get; } + public ResizeOptions Options { get; } /// public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index b486e4225..c0bf9291e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -17,12 +16,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal class ResizeProcessor : TransformProcessor, IResamplingTransformImageProcessor where TPixel : unmanaged, IPixel { + private readonly ResizeOptions options; private readonly int destinationWidth; private readonly int destinationHeight; private readonly IResampler resampler; private readonly Rectangle destinationRectangle; - private readonly bool compand; - private readonly bool premultiplyAlpha; private Image destination; public ResizeProcessor(Configuration configuration, ResizeProcessor definition, Image source, Rectangle sourceRectangle) @@ -31,13 +29,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.destinationWidth = definition.DestinationWidth; this.destinationHeight = definition.DestinationHeight; this.destinationRectangle = definition.DestinationRectangle; - this.resampler = definition.Sampler; - this.premultiplyAlpha = definition.PremultiplyAlpha; - this.compand = definition.Compand; + this.options = definition.Options; + this.resampler = definition.Options.Sampler; } /// - protected override Size GetDestinationSize() => new Size(this.destinationWidth, this.destinationHeight); + protected override Size GetDestinationSize() => new(this.destinationWidth, this.destinationHeight); /// protected override void BeforeImageApply(Image destination) @@ -62,8 +59,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Image destination = this.destination; Rectangle sourceRectangle = this.SourceRectangle; Rectangle destinationRectangle = this.destinationRectangle; - bool compand = this.compand; - bool premultiplyAlpha = this.premultiplyAlpha; + bool compand = this.options.Compand; + bool premultiplyAlpha = this.options.PremultiplyAlpha; + bool shouldFill = (this.options.Mode == ResizeMode.BoxPad || this.options.Mode == ResizeMode.Pad) + && this.options.PadColor != default; + TPixel fillColor = this.options.PadColor.ToPixel(); // Handle resize dimensions identical to the original if (source.Width == destination.Width @@ -91,6 +91,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ImageFrame sourceFrame = source.Frames[i]; ImageFrame destinationFrame = destination.Frames[i]; + if (shouldFill) + { + destinationFrame.Clear(fillColor); + } + ApplyNNResizeFrameTransform( configuration, sourceFrame, @@ -123,6 +128,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ImageFrame sourceFrame = source.Frames[i]; ImageFrame destinationFrame = destination.Frames[i]; + if (shouldFill) + { + destinationFrame.Clear(fillColor); + } + ApplyResizeFrameTransform( configuration, sourceFrame, diff --git a/src/ImageSharp/Processing/ResizeOptions.cs b/src/ImageSharp/Processing/ResizeOptions.cs index 4b31998da..62cf8ab23 100644 --- a/src/ImageSharp/Processing/ResizeOptions.cs +++ b/src/ImageSharp/Processing/ResizeOptions.cs @@ -51,5 +51,10 @@ namespace SixLabors.ImageSharp.Processing /// the alpha (if it exists) during the resize operation. /// public bool PremultiplyAlpha { get; set; } = true; + + /// + /// Gets or sets the color to use as a background when padding an image. + /// + public Color PadColor { get; set; } } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs index b1441d109..780758c2b 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs @@ -20,41 +20,37 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public void ImageShouldPad(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage()) - { - image.Mutate(x => x.Pad(image.Width + 50, image.Height + 50)); - image.DebugSave(provider); + using Image image = provider.GetImage(); + image.Mutate(x => x.Pad(image.Width + 50, image.Height + 50)); + image.DebugSave(provider); - // Check pixels are empty - for (int y = 0; y < 25; y++) + // Check pixels are empty + for (int y = 0; y < 25; y++) + { + for (int x = 0; x < 25; x++) { - for (int x = 0; x < 25; x++) - { - Assert.Equal(default, image[x, y]); - } + Assert.Equal(default, image[x, y]); } } } [Theory] - [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)] + [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32 | PixelTypes.Rgb24)] public void ImageShouldPadWithBackgroundColor(TestImageProvider provider) where TPixel : unmanaged, IPixel { - var color = Color.Red; + Color color = Color.Red; TPixel expected = color.ToPixel(); - using (Image image = provider.GetImage()) - { - image.Mutate(x => x.Pad(image.Width + 50, image.Height + 50, color)); - image.DebugSave(provider); + using Image image = provider.GetImage(); + image.Mutate(x => x.Pad(image.Width + 50, image.Height + 50, color)); + image.DebugSave(provider); - // Check pixels are filled - for (int y = 0; y < 25; y++) + // Check pixels are filled + for (int y = 0; y < 25; y++) + { + for (int x = 0; x < 25; x++) { - for (int x = 0; x < 25; x++) - { - Assert.Equal(expected, image[x, y]); - } + Assert.Equal(expected, image[x, y]); } } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs index 227e470d4..3e6726ba0 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(width, resizeProcessor.DestinationWidth); Assert.Equal(height, resizeProcessor.DestinationHeight); - Assert.Equal(sampler, resizeProcessor.Sampler); + Assert.Equal(sampler, resizeProcessor.Options.Sampler); } } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs index 60f7aaa0b..a29f4c035 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(width, resizeProcessor.DestinationWidth); Assert.Equal(height, resizeProcessor.DestinationHeight); - Assert.Equal(sampler, resizeProcessor.Sampler); + Assert.Equal(sampler, resizeProcessor.Options.Sampler); } [Fact] @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(width, resizeProcessor.DestinationWidth); Assert.Equal(height, resizeProcessor.DestinationHeight); - Assert.Equal(sampler, resizeProcessor.Sampler); - Assert.Equal(compand, resizeProcessor.Compand); + Assert.Equal(sampler, resizeProcessor.Options.Sampler); + Assert.Equal(compand, resizeProcessor.Options.Compand); } [Fact] @@ -78,8 +78,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(width, resizeProcessor.DestinationWidth); Assert.Equal(height, resizeProcessor.DestinationHeight); - Assert.Equal(sampler, resizeProcessor.Sampler); - Assert.Equal(compand, resizeProcessor.Compand); + Assert.Equal(sampler, resizeProcessor.Options.Sampler); + Assert.Equal(compand, resizeProcessor.Options.Compand); // Ensure options are not altered. Assert.Equal(width, resizeOptions.Size.Width);