// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Drawing.Processors { using System; using System.Numerics; using System.Runtime.CompilerServices; /// /// 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 TColor : struct, IPixel { /// /// Initializes a new instance of the class. /// /// The target. internal BrushApplicator(PixelAccessor target) { this.Target = target; } /// /// Gets the destinaion /// protected PixelAccessor Target { get; } /// /// Gets the color for a single pixel. /// /// The x cordinate. /// The y cordinate. /// The a that should be applied to the pixel. internal abstract TColor 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 number of pixels effected by this scanline. /// The offset fromthe begining of the opacity data starts. /// 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(float[] scanlineBuffer, int scanlineWidth, int offset, int x, int y) { DebugGuard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth)); using (PinnedBuffer buffer = new PinnedBuffer(scanlineBuffer)) { BufferSpan slice = buffer.Slice(offset); for (int xPos = 0; xPos < scanlineWidth; xPos++) { int targetX = xPos + x; int targetY = y; float opacity = slice[xPos]; if (opacity > Constants.Epsilon) { Vector4 backgroundVector = this.Target[targetX, targetY].ToVector4(); Vector4 sourceVector = this[targetX, targetY].ToVector4(); Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity); TColor packed = default(TColor); packed.PackFromVector4(finalColor); this.Target[targetX, targetY] = packed; } } } } } }