// // 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.Threading.Tasks; using ImageSharp.PixelFormats; using ImageSharp.Processing; /// /// Combines two images together by blending the pixels. /// /// The pixel format. internal class DrawImageProcessor : ImageProcessor where TPixel : struct, IPixel { /// /// Initializes a new instance of the class. /// /// The image to blend with the currently processing image. /// The size to draw the blended image. /// The location to draw the blended image. /// The opacity of the image to blend. Between 0 and 100. public DrawImageProcessor(Image image, Size size, Point location, int alpha = 100) { Guard.MustBeBetweenOrEqualTo(alpha, 0, 100, nameof(alpha)); this.Image = image; this.Size = size; this.Alpha = alpha; this.Location = location; } /// /// Gets the image to blend. /// public Image Image { get; private set; } /// /// Gets the alpha percentage value. /// public int Alpha { get; } /// /// Gets the size to draw the blended image. /// public Size Size { get; } /// /// Gets the location to draw the blended image. /// public Point Location { get; } /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { if (this.Image.Bounds.Size != this.Size) { // should Resize be moved to core? this.Image = this.Image.Resize(this.Size.Width, this.Size.Height); } // Align start/end positions. Rectangle bounds = this.Image.Bounds; int minX = Math.Max(this.Location.X, sourceRectangle.X); int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); int minY = Math.Max(this.Location.Y, sourceRectangle.Y); int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); float alpha = this.Alpha / 100F; using (PixelAccessor toBlendPixels = this.Image.Lock()) using (PixelAccessor sourcePixels = source.Lock()) { Parallel.For( minY, maxY, this.ParallelOptions, y => { for (int x = minX; x < maxX; x++) { Vector4 backgroundVector = sourcePixels[x, y].ToVector4(); Vector4 sourceVector = toBlendPixels[x - minX, y - minY].ToVector4(); // Lerping colors is dependent on the alpha of the blended color backgroundVector = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, alpha); TPixel packed = default(TPixel); packed.PackFromVector4(backgroundVector); sourcePixels[x, y] = packed; } }); } } } }