Browse Source

Merge branch 'main' into bp/extrasamples2

pull/2062/head
James Jackson-South 4 years ago
committed by GitHub
parent
commit
9fc42d7555
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs
  2. 2
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
  3. 15
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs
  4. 27
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs
  5. 6
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs
  6. 4
      tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithBoxPadMode_CalliphoraPartial.png
  7. 4
      tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithPadMode_CalliphoraPartial.png

6
src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Processing namespace SixLabors.ImageSharp.Processing
{ {
/// <summary> /// <summary>
@ -29,9 +31,11 @@ namespace SixLabors.ImageSharp.Processing
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns> /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext Pad(this IImageProcessingContext source, int width, int height, Color color) public static IImageProcessingContext Pad(this IImageProcessingContext source, int width, int height, Color color)
{ {
Size size = source.GetCurrentSize();
var options = new ResizeOptions var options = new ResizeOptions
{ {
Size = new Size(width, height), // Prevent downsizing.
Size = new Size(Math.Max(width, size.Width), Math.Max(height, size.Height)),
Mode = ResizeMode.BoxPad, Mode = ResizeMode.BoxPad,
Sampler = KnownResamplers.NearestNeighbor, Sampler = KnownResamplers.NearestNeighbor,
PadColor = color PadColor = color

2
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs

@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// Returns a <see cref="ResizeKernel"/> for an index value between 0 and DestinationSize - 1. /// Returns a <see cref="ResizeKernel"/> for an index value between 0 and DestinationSize - 1.
/// </summary> /// </summary>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
internal ref ResizeKernel GetKernel(int destIdx) => ref this.kernels[destIdx]; internal ref ResizeKernel GetKernel(nint destIdx) => ref this.kernels[destIdx];
/// <summary> /// <summary>
/// Computes the weights to apply at each pixel when resizing. /// Computes the weights to apply at each pixel when resizing.

15
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs

@ -61,9 +61,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Rectangle destinationRectangle = this.destinationRectangle; Rectangle destinationRectangle = this.destinationRectangle;
bool compand = this.options.Compand; bool compand = this.options.Compand;
bool premultiplyAlpha = this.options.PremultiplyAlpha; bool premultiplyAlpha = this.options.PremultiplyAlpha;
TPixel fillColor = this.options.PadColor.ToPixel<TPixel>();
bool shouldFill = (this.options.Mode == ResizeMode.BoxPad || this.options.Mode == ResizeMode.Pad) bool shouldFill = (this.options.Mode == ResizeMode.BoxPad || this.options.Mode == ResizeMode.Pad)
&& this.options.PadColor != default; && this.options.PadColor != default;
TPixel fillColor = this.options.PadColor.ToPixel<TPixel>();
// Handle resize dimensions identical to the original // Handle resize dimensions identical to the original
if (source.Width == destination.Width if (source.Width == destination.Width
@ -209,21 +209,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
// To reintroduce parallel processing, we would launch multiple workers // To reintroduce parallel processing, we would launch multiple workers
// for different row intervals of the image. // for different row intervals of the image.
using (var worker = new ResizeWorker<TPixel>( using var worker = new ResizeWorker<TPixel>(
configuration, configuration,
sourceRegion, sourceRegion,
conversionModifiers, conversionModifiers,
horizontalKernelMap, horizontalKernelMap,
verticalKernelMap, verticalKernelMap,
destination.Width,
interest, interest,
destinationRectangle.Location)) destinationRectangle.Location);
{ worker.Initialize();
worker.Initialize();
var workingInterval = new RowInterval(interest.Top, interest.Bottom); var workingInterval = new RowInterval(interest.Top, interest.Bottom);
worker.FillDestinationPixels(workingInterval, destination.PixelBuffer); worker.FillDestinationPixels(workingInterval, destination.PixelBuffer);
}
} }
private readonly struct NNRowOperation : IRowOperation private readonly struct NNRowOperation : IRowOperation

27
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs

@ -39,8 +39,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ResizeKernelMap verticalKernelMap; private readonly ResizeKernelMap verticalKernelMap;
private readonly int destWidth;
private readonly Rectangle targetWorkingRect; private readonly Rectangle targetWorkingRect;
private readonly Point targetOrigin; private readonly Point targetOrigin;
@ -57,7 +55,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
PixelConversionModifiers conversionModifiers, PixelConversionModifiers conversionModifiers,
ResizeKernelMap horizontalKernelMap, ResizeKernelMap horizontalKernelMap,
ResizeKernelMap verticalKernelMap, ResizeKernelMap verticalKernelMap,
int destWidth,
Rectangle targetWorkingRect, Rectangle targetWorkingRect,
Point targetOrigin) Point targetOrigin)
{ {
@ -67,7 +64,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.conversionModifiers = conversionModifiers; this.conversionModifiers = conversionModifiers;
this.horizontalKernelMap = horizontalKernelMap; this.horizontalKernelMap = horizontalKernelMap;
this.verticalKernelMap = verticalKernelMap; this.verticalKernelMap = verticalKernelMap;
this.destWidth = destWidth;
this.targetWorkingRect = targetWorkingRect; this.targetWorkingRect = targetWorkingRect;
this.targetOrigin = targetOrigin; this.targetOrigin = targetOrigin;
@ -80,19 +76,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int numberOfWindowBands = ResizeHelper.CalculateResizeWorkerHeightInWindowBands( int numberOfWindowBands = ResizeHelper.CalculateResizeWorkerHeightInWindowBands(
this.windowBandHeight, this.windowBandHeight,
destWidth, targetWorkingRect.Width,
workingBufferLimitHintInBytes); workingBufferLimitHintInBytes);
this.workerHeight = Math.Min(this.sourceRectangle.Height, numberOfWindowBands * this.windowBandHeight); this.workerHeight = Math.Min(this.sourceRectangle.Height, numberOfWindowBands * this.windowBandHeight);
this.transposedFirstPassBuffer = configuration.MemoryAllocator.Allocate2D<Vector4>( this.transposedFirstPassBuffer = configuration.MemoryAllocator.Allocate2D<Vector4>(
this.workerHeight, this.workerHeight,
destWidth, targetWorkingRect.Width,
preferContiguosImageBuffers: true, preferContiguosImageBuffers: true,
options: AllocationOptions.Clean); options: AllocationOptions.Clean);
this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width); this.tempRowBuffer = configuration.MemoryAllocator.Allocate<Vector4>(this.sourceRectangle.Width);
this.tempColumnBuffer = configuration.MemoryAllocator.Allocate<Vector4>(destWidth); this.tempColumnBuffer = configuration.MemoryAllocator.Allocate<Vector4>(targetWorkingRect.Width);
this.currentWindow = new RowInterval(0, this.workerHeight); this.currentWindow = new RowInterval(0, this.workerHeight);
} }
@ -118,6 +114,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
// When creating transposedFirstPassBuffer, we made sure it's contiguous: // When creating transposedFirstPassBuffer, we made sure it's contiguous:
Span<Vector4> transposedFirstPassBufferSpan = this.transposedFirstPassBuffer.DangerousGetSingleSpan(); Span<Vector4> transposedFirstPassBufferSpan = this.transposedFirstPassBuffer.DangerousGetSingleSpan();
int left = this.targetWorkingRect.Left;
int right = this.targetWorkingRect.Right;
int width = this.targetWorkingRect.Width;
for (int y = rowInterval.Min; y < rowInterval.Max; y++) for (int y = rowInterval.Min; y < rowInterval.Max; y++)
{ {
// Ensure offsets are normalized for cropping and padding. // Ensure offsets are normalized for cropping and padding.
@ -131,9 +130,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan); ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan);
int top = kernel.StartIndex - this.currentWindow.Min; int top = kernel.StartIndex - this.currentWindow.Min;
ref Vector4 fpBase = ref transposedFirstPassBufferSpan[top]; ref Vector4 fpBase = ref transposedFirstPassBufferSpan[top];
for (int x = 0; x < this.destWidth; x++) for (nint x = 0; x < (right - left); x++)
{ {
ref Vector4 firstPassColumnBase = ref Unsafe.Add(ref fpBase, x * this.workerHeight); ref Vector4 firstPassColumnBase = ref Unsafe.Add(ref fpBase, x * this.workerHeight);
@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Unsafe.Add(ref tempRowBase, x) = kernel.ConvolveCore(ref firstPassColumnBase); Unsafe.Add(ref tempRowBase, x) = kernel.ConvolveCore(ref firstPassColumnBase);
} }
Span<TPixel> targetRowSpan = destination.DangerousGetRowSpan(y); Span<TPixel> targetRowSpan = destination.DangerousGetRowSpan(y).Slice(left, width);
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, tempColSpan, targetRowSpan, this.conversionModifiers); PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, tempColSpan, targetRowSpan, this.conversionModifiers);
} }
@ -170,6 +170,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan(); Span<Vector4> tempRowSpan = this.tempRowBuffer.GetSpan();
Span<Vector4> transposedFirstPassBufferSpan = this.transposedFirstPassBuffer.DangerousGetSingleSpan(); Span<Vector4> transposedFirstPassBufferSpan = this.transposedFirstPassBuffer.DangerousGetSingleSpan();
int left = this.targetWorkingRect.Left;
int right = this.targetWorkingRect.Right;
int targetOriginX = this.targetOrigin.X;
for (int y = calculationInterval.Min; y < calculationInterval.Max; y++) for (int y = calculationInterval.Min; y < calculationInterval.Max; y++)
{ {
Span<TPixel> sourceRow = this.source.DangerousGetRowSpan(y); Span<TPixel> sourceRow = this.source.DangerousGetRowSpan(y);
@ -184,13 +187,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
// Span<Vector4> firstPassSpan = transposedFirstPassBufferSpan.Slice(y - this.currentWindow.Min); // Span<Vector4> firstPassSpan = transposedFirstPassBufferSpan.Slice(y - this.currentWindow.Min);
ref Vector4 firstPassBaseRef = ref transposedFirstPassBufferSpan[y - this.currentWindow.Min]; ref Vector4 firstPassBaseRef = ref transposedFirstPassBufferSpan[y - this.currentWindow.Min];
for (int x = this.targetWorkingRect.Left; x < this.targetWorkingRect.Right; x++) for (nint x = left, z = 0; x < right; x++, z++)
{ {
ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - this.targetOrigin.X); ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - targetOriginX);
// optimization for: // optimization for:
// firstPassSpan[x * this.workerHeight] = kernel.Convolve(tempRowSpan); // firstPassSpan[x * this.workerHeight] = kernel.Convolve(tempRowSpan);
Unsafe.Add(ref firstPassBaseRef, x * this.workerHeight) = kernel.Convolve(tempRowSpan); Unsafe.Add(ref firstPassBaseRef, z * this.workerHeight) = kernel.Convolve(tempRowSpan);
} }
} }
} }

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

@ -472,7 +472,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
var options = new ResizeOptions var options = new ResizeOptions
{ {
Size = new Size(image.Width + 200, image.Height + 200), Size = new Size(image.Width + 200, image.Height + 200),
Mode = ResizeMode.BoxPad Mode = ResizeMode.BoxPad,
PadColor = Color.HotPink
}; };
image.Mutate(x => x.Resize(options)); image.Mutate(x => x.Resize(options));
@ -580,7 +581,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
var options = new ResizeOptions var options = new ResizeOptions
{ {
Size = new Size(image.Width + 200, image.Height), Size = new Size(image.Width + 200, image.Height),
Mode = ResizeMode.Pad Mode = ResizeMode.Pad,
PadColor = Color.Lavender
}; };
image.Mutate(x => x.Resize(options)); image.Mutate(x => x.Resize(options));

4
tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithBoxPadMode_CalliphoraPartial.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:1642520a9d4491f55af5a83280423929529e3d528637538d148b9dc2ecdd6d2d oid sha256:77086032bab11b91c68bc1686179063edbadc9d453574e4f087b2bbd677b4c8e
size 365839 size 402367

4
tests/Images/External/ReferenceOutput/ResizeTests/ResizeWithPadMode_CalliphoraPartial.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:060826324dcd4baa1df1b075707a9bd9527cf87c1d156e3beb3d8abb499bdcd5 oid sha256:5c0653aa2b726574fbea4cc308c269ff5e534d38bb48c0e77470c11042a395fd
size 361829 size 400267

Loading…
Cancel
Save