Browse Source

Allow pad to work for non-alpha pixel formats

pull/2034/head
James Jackson-South 4 years ago
parent
commit
7ca5680cd2
  1. 5
      src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs
  2. 18
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs
  3. 28
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs
  4. 5
      src/ImageSharp/Processing/ResizeOptions.cs
  5. 40
      tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs
  6. 2
      tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs
  7. 10
      tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs

5
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);
}
}
}

18
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;
}
/// <summary>
/// Gets the sampler to perform the resize operation.
/// </summary>
public IResampler Sampler { get; }
/// <summary>
/// Gets the destination width.
/// </summary>
@ -50,14 +43,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public Rectangle DestinationRectangle { get; }
/// <summary>
/// Gets a value indicating whether to compress or expand individual pixel color values on processing.
/// </summary>
public bool Compand { get; }
/// <summary>
/// Gets a value indicating whether to premultiply the alpha (if it exists) during the resize operation.
/// Gets the resize options.
/// </summary>
public bool PremultiplyAlpha { get; }
public ResizeOptions Options { get; }
/// <inheritdoc />
public override ICloningImageProcessor<TPixel> CreatePixelSpecificCloningProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle)

28
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<TPixel> : TransformProcessor<TPixel>, IResamplingTransformImageProcessor<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
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<TPixel> destination;
public ResizeProcessor(Configuration configuration, ResizeProcessor definition, Image<TPixel> 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;
}
/// <inheritdoc/>
protected override Size GetDestinationSize() => new Size(this.destinationWidth, this.destinationHeight);
protected override Size GetDestinationSize() => new(this.destinationWidth, this.destinationHeight);
/// <inheritdoc/>
protected override void BeforeImageApply(Image<TPixel> destination)
@ -62,8 +59,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Image<TPixel> 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<TPixel>();
// Handle resize dimensions identical to the original
if (source.Width == destination.Width
@ -91,6 +91,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ImageFrame<TPixel> sourceFrame = source.Frames[i];
ImageFrame<TPixel> destinationFrame = destination.Frames[i];
if (shouldFill)
{
destinationFrame.Clear(fillColor);
}
ApplyNNResizeFrameTransform(
configuration,
sourceFrame,
@ -123,6 +128,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ImageFrame<TPixel> sourceFrame = source.Frames[i];
ImageFrame<TPixel> destinationFrame = destination.Frames[i];
if (shouldFill)
{
destinationFrame.Clear(fillColor);
}
ApplyResizeFrameTransform(
configuration,
sourceFrame,

5
src/ImageSharp/Processing/ResizeOptions.cs

@ -51,5 +51,10 @@ namespace SixLabors.ImageSharp.Processing
/// the alpha (if it exists) during the resize operation.
/// </summary>
public bool PremultiplyAlpha { get; set; } = true;
/// <summary>
/// Gets or sets the color to use as a background when padding an image.
/// </summary>
public Color PadColor { get; set; }
}
}

40
tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs

@ -20,41 +20,37 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
public void ImageShouldPad<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x.Pad(image.Width + 50, image.Height + 50));
image.DebugSave(provider);
using Image<TPixel> 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<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
var color = Color.Red;
Color color = Color.Red;
TPixel expected = color.ToPixel<TPixel>();
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x.Pad(image.Width + 50, image.Height + 50, color));
image.DebugSave(provider);
using Image<TPixel> 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]);
}
}
}

2
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);
}
}
}

10
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);

Loading…
Cancel
Save