diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs index 0271caa5d..ce677c515 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs @@ -4,6 +4,7 @@ using System; using System.Buffers; using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -37,78 +38,83 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays /// protected override void OnFrameApply(ImageFrame source) { - // TODO: can we simplify the rectangle calculation? - int startY = this.SourceRectangle.Y; - int endY = this.SourceRectangle.Bottom; - int startX = this.SourceRectangle.X; - int endX = this.SourceRectangle.Right; TPixel glowColor = this.definition.GlowColor.ToPixel(); - Vector2 center = Rectangle.Center(this.SourceRectangle); + float blendPercent = this.definition.GraphicsOptions.BlendPercentage; - float finalRadius = this.definition.Radius.Calculate(source.Size()); + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); + Vector2 center = Rectangle.Center(interest); + float finalRadius = this.definition.Radius.Calculate(interest.Size); float maxDistance = finalRadius > 0 - ? MathF.Min(finalRadius, this.SourceRectangle.Width * .5F) - : this.SourceRectangle.Width * .5F; + ? MathF.Min(finalRadius, interest.Width * .5F) + : interest.Width * .5F; - // Align start/end positions. - int minX = Math.Max(0, startX); - int maxX = Math.Min(source.Width, endX); - int minY = Math.Max(0, startY); - int maxY = Math.Min(source.Height, endY); + Configuration configuration = this.Configuration; + MemoryAllocator allocator = configuration.MemoryAllocator; - // Reset offset if necessary. - if (minX > 0) - { - startX = 0; - } + using IMemoryOwner rowColors = allocator.Allocate(interest.Width); + rowColors.GetSpan().Fill(glowColor); + + ParallelRowIterator.IterateRows( + interest, + configuration, + new RowIntervalAction(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source)); + } - if (minY > 0) + private readonly struct RowIntervalAction : IRowIntervalAction + { + private readonly Configuration configuration; + private readonly Rectangle bounds; + private readonly PixelBlender blender; + private readonly Vector2 center; + private readonly float maxDistance; + private readonly float blendPercent; + private readonly IMemoryOwner colors; + private readonly ImageFrame source; + + [MethodImpl(InliningOptions.ShortMethod)] + public RowIntervalAction( + Configuration configuration, + Rectangle bounds, + IMemoryOwner colors, + PixelBlender blender, + Vector2 center, + float maxDistance, + float blendPercent, + ImageFrame source) { - startY = 0; + this.configuration = configuration; + this.bounds = bounds; + this.colors = colors; + this.blender = blender; + this.center = center; + this.maxDistance = maxDistance; + this.blendPercent = blendPercent; + this.source = source; } - int width = maxX - minX; - int offsetX = minX - startX; - - var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); - - float blendPercentage = this.definition.GraphicsOptions.BlendPercentage; - Configuration configuration = this.Configuration; - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - - using (IMemoryOwner rowColors = memoryAllocator.Allocate(width)) + [MethodImpl(InliningOptions.ShortMethod)] + public void Invoke(in RowInterval rows, Memory memory) { - rowColors.GetSpan().Fill(glowColor); - - ParallelRowIterator.IterateRows( - workingRect, - configuration, - (rows, amounts) => - { - Span amountsSpan = amounts.Span; - - for (int y = rows.Min; y < rows.Max; y++) - { - int offsetY = y - startY; - - for (int i = 0; i < width; i++) - { - float distance = Vector2.Distance(center, new Vector2(i + offsetX, offsetY)); - amountsSpan[i] = - (blendPercentage * (1 - (.95F * (distance / maxDistance)))).Clamp(0, 1); - } - - Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); - - this.blender.Blend( - configuration, - destination, - destination, - rowColors.GetSpan(), - amountsSpan); - } - }); + Span amountsSpan = memory.Span; + + for (int y = rows.Min; y < rows.Max; y++) + { + for (int i = 0; i < this.bounds.Width; i++) + { + float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y)); + amountsSpan[i] = (this.blendPercent * (1 - (.95F * (distance / this.maxDistance)))).Clamp(0, 1); + } + + Span destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width); + + this.blender.Blend( + this.configuration, + destination, + destination, + this.colors.GetSpan(), + amountsSpan); + } } } }