|
|
|
@ -3,11 +3,11 @@ |
|
|
|
|
|
|
|
using System; |
|
|
|
using System.Numerics; |
|
|
|
using System.Threading.Tasks; |
|
|
|
|
|
|
|
using SixLabors.ImageSharp.Advanced; |
|
|
|
using SixLabors.ImageSharp.Memory; |
|
|
|
using SixLabors.ImageSharp.ParallelUtils; |
|
|
|
using SixLabors.ImageSharp.PixelFormats; |
|
|
|
using SixLabors.Memory; |
|
|
|
using SixLabors.Primitives; |
|
|
|
|
|
|
|
namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|
|
|
@ -49,7 +49,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|
|
|
public int BrushSize { get; } |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) |
|
|
|
protected override void OnFrameApply( |
|
|
|
ImageFrame<TPixel> source, |
|
|
|
Rectangle sourceRectangle, |
|
|
|
Configuration configuration) |
|
|
|
{ |
|
|
|
if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width) |
|
|
|
{ |
|
|
|
@ -70,69 +73,74 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|
|
|
{ |
|
|
|
source.CopyTo(targetPixels); |
|
|
|
|
|
|
|
ParallelFor.WithConfiguration( |
|
|
|
startY, |
|
|
|
maxY, |
|
|
|
var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); |
|
|
|
ParallelHelper.IterateRows( |
|
|
|
workingRect, |
|
|
|
configuration, |
|
|
|
y => |
|
|
|
{ |
|
|
|
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); |
|
|
|
Span<TPixel> targetRow = targetPixels.GetRowSpan(y); |
|
|
|
|
|
|
|
for (int x = startX; x < endX; x++) |
|
|
|
rows => |
|
|
|
{ |
|
|
|
int maxIntensity = 0; |
|
|
|
int maxIndex = 0; |
|
|
|
for (int y = rows.Min; y < rows.Max; y++) |
|
|
|
{ |
|
|
|
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); |
|
|
|
Span<TPixel> targetRow = targetPixels.GetRowSpan(y); |
|
|
|
|
|
|
|
int[] intensityBin = new int[levels]; |
|
|
|
float[] redBin = new float[levels]; |
|
|
|
float[] blueBin = new float[levels]; |
|
|
|
float[] greenBin = new float[levels]; |
|
|
|
for (int x = startX; x < endX; x++) |
|
|
|
{ |
|
|
|
int maxIntensity = 0; |
|
|
|
int maxIndex = 0; |
|
|
|
|
|
|
|
for (int fy = 0; fy <= radius; fy++) |
|
|
|
{ |
|
|
|
int fyr = fy - radius; |
|
|
|
int offsetY = y + fyr; |
|
|
|
int[] intensityBin = new int[levels]; |
|
|
|
float[] redBin = new float[levels]; |
|
|
|
float[] blueBin = new float[levels]; |
|
|
|
float[] greenBin = new float[levels]; |
|
|
|
|
|
|
|
offsetY = offsetY.Clamp(0, maxY); |
|
|
|
for (int fy = 0; fy <= radius; fy++) |
|
|
|
{ |
|
|
|
int fyr = fy - radius; |
|
|
|
int offsetY = y + fyr; |
|
|
|
|
|
|
|
Span<TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY); |
|
|
|
offsetY = offsetY.Clamp(0, maxY); |
|
|
|
|
|
|
|
for (int fx = 0; fx <= radius; fx++) |
|
|
|
{ |
|
|
|
int fxr = fx - radius; |
|
|
|
int offsetX = x + fxr; |
|
|
|
offsetX = offsetX.Clamp(0, maxX); |
|
|
|
Span<TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY); |
|
|
|
|
|
|
|
var vector = sourceOffsetRow[offsetX].ToVector4(); |
|
|
|
for (int fx = 0; fx <= radius; fx++) |
|
|
|
{ |
|
|
|
int fxr = fx - radius; |
|
|
|
int offsetX = x + fxr; |
|
|
|
offsetX = offsetX.Clamp(0, maxX); |
|
|
|
|
|
|
|
float sourceRed = vector.X; |
|
|
|
float sourceBlue = vector.Z; |
|
|
|
float sourceGreen = vector.Y; |
|
|
|
var vector = sourceOffsetRow[offsetX].ToVector4(); |
|
|
|
|
|
|
|
int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); |
|
|
|
float sourceRed = vector.X; |
|
|
|
float sourceBlue = vector.Z; |
|
|
|
float sourceGreen = vector.Y; |
|
|
|
|
|
|
|
intensityBin[currentIntensity]++; |
|
|
|
blueBin[currentIntensity] += sourceBlue; |
|
|
|
greenBin[currentIntensity] += sourceGreen; |
|
|
|
redBin[currentIntensity] += sourceRed; |
|
|
|
int currentIntensity = (int)MathF.Round( |
|
|
|
(sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); |
|
|
|
|
|
|
|
if (intensityBin[currentIntensity] > maxIntensity) |
|
|
|
{ |
|
|
|
maxIntensity = intensityBin[currentIntensity]; |
|
|
|
maxIndex = currentIntensity; |
|
|
|
} |
|
|
|
} |
|
|
|
intensityBin[currentIntensity]++; |
|
|
|
blueBin[currentIntensity] += sourceBlue; |
|
|
|
greenBin[currentIntensity] += sourceGreen; |
|
|
|
redBin[currentIntensity] += sourceRed; |
|
|
|
|
|
|
|
float red = MathF.Abs(redBin[maxIndex] / maxIntensity); |
|
|
|
float green = MathF.Abs(greenBin[maxIndex] / maxIntensity); |
|
|
|
float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); |
|
|
|
if (intensityBin[currentIntensity] > maxIntensity) |
|
|
|
{ |
|
|
|
maxIntensity = intensityBin[currentIntensity]; |
|
|
|
maxIndex = currentIntensity; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
ref TPixel pixel = ref targetRow[x]; |
|
|
|
pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); |
|
|
|
float red = MathF.Abs(redBin[maxIndex] / maxIntensity); |
|
|
|
float green = MathF.Abs(greenBin[maxIndex] / maxIntensity); |
|
|
|
float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); |
|
|
|
|
|
|
|
ref TPixel pixel = ref targetRow[x]; |
|
|
|
pixel.PackFromVector4( |
|
|
|
new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels); |
|
|
|
} |
|
|
|
|