// // 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 DrawImageEffectProcessor : 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. /// Pixel function effect to apply on every pixel /// The opacity of the image to blend. Between 0 and 100. public DrawImageEffectProcessor(Image image, Size size, Point location, Func pixelFunction, int alpha = 100) { Guard.MustBeBetweenOrEqualTo(alpha, 0, 100, nameof(alpha)); this.Image = image; this.PixelFunction = pixelFunction; this.Size = size; this.Location = location; this.Alpha = alpha; } /// /// Gets the image to blend. /// public Image Image { get; private set; } /// /// Gets The function effect to apply on a per pixel basis /// public Func PixelFunction { 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 target, 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 sourcePixels = this.Image.Lock()) using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, maxY, this.ParallelOptions, y => { for (int x = minX; x < maxX; x++) { TPixel targetColor = targetPixels[x, y]; TPixel sourceColor = sourcePixels[x - minX, y - minY]; targetPixels[x, y] = this.PixelFunction(targetColor, sourceColor, alpha); } }); } } } }