// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Advanced.Unsafe;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Drawing.Brushes.Processors
{
///
/// primitive that converts a point in to a color for discovering the fill color based on an implementation
///
/// The pixel format.
///
public abstract class BrushApplicator : IDisposable // disposable will be required if/when there is an ImageBrush
where TPixel : struct, IPixel
{
///
/// Initializes a new instance of the class.
///
/// The target.
/// The options.
internal BrushApplicator(ImageBase target, GraphicsOptions options)
{
this.Target = target;
this.Options = options;
this.Blender = PixelOperations.Instance.GetPixelBlender(options.BlenderMode);
}
///
/// Gets the blendder
///
internal PixelBlender Blender { get; }
///
/// Gets the destinaion
///
protected ImageBase Target { get; }
///
/// Gets the blend percentage
///
protected GraphicsOptions Options { get; private set; }
///
/// Gets the color for a single pixel.
///
/// The x cordinate.
/// The y cordinate.
/// The a that should be applied to the pixel.
internal abstract TPixel this[int x, int y] { get; }
///
public abstract void Dispose();
///
/// Applies the opactiy weighting for each pixel in a scanline to the target based on the pattern contained in the brush.
///
/// The a collection of opacity values between 0 and 1 to be merged with the brushed color value before being applied to the target.
/// The x position in the target pixel space that the start of the scanline data corresponds to.
/// The y position in the target pixel space that whole scanline corresponds to.
/// scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.
internal virtual void Apply(Span scanline, int x, int y)
{
using (var amountBuffer = new Buffer(scanline.Length))
using (var overlay = new Buffer(scanline.Length))
{
for (int i = 0; i < scanline.Length; i++)
{
if (this.Options.BlendPercentage < 1)
{
amountBuffer[i] = scanline[i] * this.Options.BlendPercentage;
}
overlay[i] = this[x + i, y];
}
Span destinationRow = this.Target.GetPixelRowSpan(x).Slice(y, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
}
}
}
}