// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Buffers; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing { /// /// Provides an implementation of a solid brush for painting solid color areas. /// public class SolidBrush : IBrush { /// /// Initializes a new instance of the class. /// /// The color. public SolidBrush(Color color) { this.Color = color; } /// /// Gets the color. /// public Color Color { get; } /// public BrushApplicator CreateApplicator( Configuration configuration, GraphicsOptions options, ImageFrame source, RectangleF region) where TPixel : struct, IPixel { return new SolidBrushApplicator(configuration, options, source, this.Color.ToPixel()); } /// /// The solid brush applicator. /// private class SolidBrushApplicator : BrushApplicator where TPixel : struct, IPixel { private bool isDisposed; /// /// Initializes a new instance of the class. /// /// The configuration instance to use when performing operations. /// The graphics options. /// The source image. /// The color. public SolidBrushApplicator( Configuration configuration, GraphicsOptions options, ImageFrame source, TPixel color) : base(configuration, options, source) { this.Colors = source.MemoryAllocator.Allocate(source.Width); this.Colors.Memory.Span.Fill(color); } /// /// Gets the colors. /// protected IMemoryOwner Colors { get; private set; } /// internal override TPixel this[int x, int y] => this.Colors.Memory.Span[x]; /// protected override void Dispose(bool disposing) { if (this.isDisposed) { return; } if (disposing) { this.Colors.Dispose(); } this.Colors = null; this.isDisposed = true; } /// internal override void Apply(Span scanline, int x, int y) { Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x); // constrain the spans to each other if (destinationRow.Length > scanline.Length) { destinationRow = destinationRow.Slice(0, scanline.Length); } else { scanline = scanline.Slice(0, destinationRow.Length); } MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; Configuration configuration = this.Configuration; if (this.Options.BlendPercentage == 1f) { this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.Memory.Span, scanline); } else { using (IMemoryOwner amountBuffer = memoryAllocator.Allocate(scanline.Length)) { Span amountSpan = amountBuffer.Memory.Span; for (int i = 0; i < scanline.Length; i++) { amountSpan[i] = scanline[i] * this.Options.BlendPercentage; } this.Blender.Blend( configuration, destinationRow, destinationRow, this.Colors.Memory.Span, amountSpan); } } } } } }