|
|
|
@ -5,7 +5,6 @@ using System; |
|
|
|
using System.Buffers; |
|
|
|
using System.Numerics; |
|
|
|
using System.Runtime.CompilerServices; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
|
|
|
|
using SixLabors.ImageSharp.Advanced; |
|
|
|
using SixLabors.ImageSharp.Advanced.ParallelUtils; |
|
|
|
@ -58,88 +57,84 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|
|
|
|
|
|
|
Configuration configuration = this.Configuration; |
|
|
|
|
|
|
|
using (Buffer2D<TPixel> targetPixels = this.Configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size())) |
|
|
|
{ |
|
|
|
source.CopyTo(targetPixels); |
|
|
|
|
|
|
|
var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); |
|
|
|
ParallelHelper.IterateRows( |
|
|
|
workingRect, |
|
|
|
this.Configuration, |
|
|
|
(rows) => |
|
|
|
using Buffer2D<TPixel> targetPixels = this.Configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size()); |
|
|
|
source.CopyTo(targetPixels); |
|
|
|
|
|
|
|
var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); |
|
|
|
ParallelHelper.IterateRows( |
|
|
|
workingRect, |
|
|
|
this.Configuration, |
|
|
|
(rows) => |
|
|
|
{ |
|
|
|
// Rent the shared buffer only once per parallel item.
|
|
|
|
using IMemoryOwner<float> bins = configuration.MemoryAllocator.Allocate<float>(levels * 4); |
|
|
|
ref float binsRef = ref bins.GetReference(); |
|
|
|
ref int intensityBinRef = ref Unsafe.As<float, int>(ref binsRef); |
|
|
|
ref float redBinRef = ref Unsafe.Add(ref binsRef, levels); |
|
|
|
ref float blueBinRef = ref Unsafe.Add(ref redBinRef, levels); |
|
|
|
ref float greenBinRef = ref Unsafe.Add(ref blueBinRef, levels); |
|
|
|
|
|
|
|
for (int y = rows.Min; y < rows.Max; y++) |
|
|
|
{ |
|
|
|
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); |
|
|
|
Span<TPixel> targetRow = targetPixels.GetRowSpan(y); |
|
|
|
|
|
|
|
for (int x = startX; x < endX; x++) |
|
|
|
{ |
|
|
|
// Rent the shared buffer only once per parallel item.
|
|
|
|
using (IMemoryOwner<float> bins = configuration.MemoryAllocator.Allocate<float>(levels * 4)) |
|
|
|
{ |
|
|
|
ref float binsRef = ref bins.GetReference(); |
|
|
|
ref int intensityBinRef = ref Unsafe.As<float, int>(ref binsRef); |
|
|
|
ref float redBinRef = ref Unsafe.Add(ref binsRef, levels); |
|
|
|
ref float blueBinRef = ref Unsafe.Add(ref redBinRef, levels); |
|
|
|
ref float greenBinRef = ref Unsafe.Add(ref blueBinRef, levels); |
|
|
|
|
|
|
|
for (int y = rows.Min; y < rows.Max; y++) |
|
|
|
{ |
|
|
|
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); |
|
|
|
Span<TPixel> targetRow = targetPixels.GetRowSpan(y); |
|
|
|
|
|
|
|
for (int x = startX; x < endX; x++) |
|
|
|
{ |
|
|
|
int maxIntensity = 0; |
|
|
|
int maxIndex = 0; |
|
|
|
|
|
|
|
// Clear the current shared buffer before processing each target pixel
|
|
|
|
bins.Memory.Span.Clear(); |
|
|
|
int maxIntensity = 0; |
|
|
|
int maxIndex = 0; |
|
|
|
|
|
|
|
for (int fy = 0; fy <= radius; fy++) |
|
|
|
{ |
|
|
|
int fyr = fy - radius; |
|
|
|
int offsetY = y + fyr; |
|
|
|
// Clear the current shared buffer before processing each target pixel
|
|
|
|
bins.Memory.Span.Clear(); |
|
|
|
|
|
|
|
offsetY = offsetY.Clamp(0, maxY); |
|
|
|
|
|
|
|
Span<TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY); |
|
|
|
for (int fy = 0; fy <= radius; fy++) |
|
|
|
{ |
|
|
|
int fyr = fy - radius; |
|
|
|
int offsetY = y + fyr; |
|
|
|
|
|
|
|
for (int fx = 0; fx <= radius; fx++) |
|
|
|
{ |
|
|
|
int fxr = fx - radius; |
|
|
|
int offsetX = x + fxr; |
|
|
|
offsetX = offsetX.Clamp(0, maxX); |
|
|
|
offsetY = offsetY.Clamp(0, maxY); |
|
|
|
|
|
|
|
var vector = sourceOffsetRow[offsetX].ToVector4(); |
|
|
|
Span<TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY); |
|
|
|
|
|
|
|
float sourceRed = vector.X; |
|
|
|
float sourceBlue = vector.Z; |
|
|
|
float sourceGreen = vector.Y; |
|
|
|
for (int fx = 0; fx <= radius; fx++) |
|
|
|
{ |
|
|
|
int fxr = fx - radius; |
|
|
|
int offsetX = x + fxr; |
|
|
|
offsetX = offsetX.Clamp(0, maxX); |
|
|
|
|
|
|
|
int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); |
|
|
|
var vector = sourceOffsetRow[offsetX].ToVector4(); |
|
|
|
|
|
|
|
Unsafe.Add(ref intensityBinRef, currentIntensity)++; |
|
|
|
Unsafe.Add(ref redBinRef, currentIntensity) += sourceRed; |
|
|
|
Unsafe.Add(ref blueBinRef, currentIntensity) += sourceBlue; |
|
|
|
Unsafe.Add(ref greenBinRef, currentIntensity) += sourceGreen; |
|
|
|
float sourceRed = vector.X; |
|
|
|
float sourceBlue = vector.Z; |
|
|
|
float sourceGreen = vector.Y; |
|
|
|
|
|
|
|
if (Unsafe.Add(ref intensityBinRef, currentIntensity) > maxIntensity) |
|
|
|
{ |
|
|
|
maxIntensity = Unsafe.Add(ref intensityBinRef, currentIntensity); |
|
|
|
maxIndex = currentIntensity; |
|
|
|
} |
|
|
|
} |
|
|
|
int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); |
|
|
|
|
|
|
|
float red = MathF.Abs(Unsafe.Add(ref redBinRef, maxIndex) / maxIntensity); |
|
|
|
float blue = MathF.Abs(Unsafe.Add(ref blueBinRef, maxIndex) / maxIntensity); |
|
|
|
float green = MathF.Abs(Unsafe.Add(ref greenBinRef, maxIndex) / maxIntensity); |
|
|
|
float alpha = sourceRow[x].ToVector4().W; |
|
|
|
Unsafe.Add(ref intensityBinRef, currentIntensity)++; |
|
|
|
Unsafe.Add(ref redBinRef, currentIntensity) += sourceRed; |
|
|
|
Unsafe.Add(ref blueBinRef, currentIntensity) += sourceBlue; |
|
|
|
Unsafe.Add(ref greenBinRef, currentIntensity) += sourceGreen; |
|
|
|
|
|
|
|
ref TPixel pixel = ref targetRow[x]; |
|
|
|
pixel.FromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); |
|
|
|
} |
|
|
|
if (Unsafe.Add(ref intensityBinRef, currentIntensity) > maxIntensity) |
|
|
|
{ |
|
|
|
maxIntensity = Unsafe.Add(ref intensityBinRef, currentIntensity); |
|
|
|
maxIndex = currentIntensity; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
float red = MathF.Abs(Unsafe.Add(ref redBinRef, maxIndex) / maxIntensity); |
|
|
|
float blue = MathF.Abs(Unsafe.Add(ref blueBinRef, maxIndex) / maxIntensity); |
|
|
|
float green = MathF.Abs(Unsafe.Add(ref greenBinRef, maxIndex) / maxIntensity); |
|
|
|
float alpha = sourceRow[x].ToVector4().W; |
|
|
|
|
|
|
|
ref TPixel pixel = ref targetRow[x]; |
|
|
|
pixel.FromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels); |
|
|
|
} |
|
|
|
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|