// 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.Memory; 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 { /// /// The color to paint. /// private readonly Color color; /// /// Initializes a new instance of the class. /// /// The color. public SolidBrush(Color color) { this.color = color; } /// /// Gets the color. /// /// /// The color. /// public Color Color => this.color; /// public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options) where TPixel : struct, IPixel { return new SolidBrushApplicator(source, this.color.ToPixel(), options); } /// /// The solid brush applicator. /// private class SolidBrushApplicator : BrushApplicator where TPixel : struct, IPixel { /// /// Initializes a new instance of the class. /// /// The source image. /// The color. /// The options public SolidBrushApplicator(ImageFrame source, TPixel color, GraphicsOptions options) : base(source, options) { this.Colors = source.MemoryAllocator.Allocate(source.Width); this.Colors.GetSpan().Fill(color); } /// /// Gets the colors. /// protected IMemoryOwner Colors { get; } /// /// Gets the color for a single pixel. /// /// The x. /// The y. /// /// The color /// internal override TPixel this[int x, int y] => this.Colors.GetSpan()[x]; /// public override void Dispose() { this.Colors.Dispose(); } /// 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.Target.Configuration; if (this.Options.BlendPercentage == 1f) { this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); } else { using (IMemoryOwner amountBuffer = memoryAllocator.Allocate(scanline.Length)) { Span amountSpan = amountBuffer.GetSpan(); for (int i = 0; i < scanline.Length; i++) { amountSpan[i] = scanline[i] * this.Options.BlendPercentage; } this.Blender.Blend( configuration, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan); } } } } } }