diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs index 7423fdbfe..a9b91e837 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -27,9 +28,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays /// The source area to process for the current processor instance. public BackgroundColorProcessor(Configuration configuration, BackgroundColorProcessor definition, Image source, Rectangle sourceRectangle) : base(configuration, source, sourceRectangle) - { - this.definition = definition; - } + => this.definition = definition; /// protected override void OnFrameApply(ImageFrame source) @@ -37,65 +36,69 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays TPixel color = this.definition.Color.ToPixel(); GraphicsOptions graphicsOptions = this.definition.GraphicsOptions; - int startY = this.SourceRectangle.Y; - int endY = this.SourceRectangle.Bottom; - int startX = this.SourceRectangle.X; - int endX = this.SourceRectangle.Right; + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); - // 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 memoryAllocator = configuration.MemoryAllocator; - // Reset offset if necessary. - if (minX > 0) - { - startX = 0; - } + using IMemoryOwner colors = memoryAllocator.Allocate(interest.Width); + using IMemoryOwner amount = memoryAllocator.Allocate(interest.Width); - if (minY > 0) - { - startY = 0; - } + colors.GetSpan().Fill(color); + amount.GetSpan().Fill(graphicsOptions.BlendPercentage); - int width = maxX - minX; + PixelBlender blender = PixelOperations.Instance.GetPixelBlender(graphicsOptions); - var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); - Configuration configuration = this.Configuration; - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - - using (IMemoryOwner colors = memoryAllocator.Allocate(width)) - using (IMemoryOwner amount = memoryAllocator.Allocate(width)) - { - // Be careful! Do not capture colorSpan & amountSpan in the lambda below! - Span colorSpan = colors.GetSpan(); - Span amountSpan = amount.GetSpan(); + ParallelRowIterator.IterateRows( + interest, + configuration, + new RowIntervalAction(configuration, interest, blender, amount, colors, source)); + } - colorSpan.Fill(color); - amountSpan.Fill(graphicsOptions.BlendPercentage); + private readonly struct RowIntervalAction : IRowIntervalAction + { + private readonly Configuration configuration; + private readonly Rectangle bounds; + private readonly PixelBlender blender; + private readonly IMemoryOwner amount; + private readonly IMemoryOwner colors; + private readonly ImageFrame source; - PixelBlender blender = PixelOperations.Instance.GetPixelBlender(graphicsOptions); + [MethodImpl(InliningOptions.ShortMethod)] + public RowIntervalAction( + Configuration configuration, + Rectangle bounds, + PixelBlender blender, + IMemoryOwner amount, + IMemoryOwner colors, + ImageFrame source) + { + this.configuration = configuration; + this.bounds = bounds; + this.blender = blender; + this.amount = amount; + this.colors = colors; + this.source = source; + } - ParallelRowIterator.IterateRows( - workingRect, - configuration, - rows => - { - for (int y = rows.Min; y < rows.Max; y++) - { - Span destination = - source.GetPixelRowSpan(y - startY).Slice(minX - startX, width); + [MethodImpl(InliningOptions.ShortMethod)] + public void Invoke(in RowInterval rows) + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span destination = + this.source.GetPixelRowSpan(y) + .Slice(this.bounds.X, this.bounds.Width); - // This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one - blender.Blend( - configuration, - destination, - colors.GetSpan(), - destination, - amount.GetSpan()); - } - }); + // Switch color & destination in the 2nd and 3rd places because we are + // applying the target color under the current one. + this.blender.Blend( + this.configuration, + destination, + this.colors.GetSpan(), + destination, + this.amount.GetSpan()); + } } } }