diff --git a/src/ImageProcessor/Filters/Blend.cs b/src/ImageProcessor/Filters/Blend.cs new file mode 100644 index 000000000..2bc6ace25 --- /dev/null +++ b/src/ImageProcessor/Filters/Blend.cs @@ -0,0 +1,77 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor.Filters +{ + using System.Threading.Tasks; + + /// + /// Combines two images together by blending the pixels. + /// + public class Blend : ParallelImageProcessor + { + /// + /// The image to blend. + /// + private readonly ImageBase toBlend; + + /// + /// Initializes a new instance of the class. + /// + /// The image to blend. + /// The opacity of the image to blend. Between 0 and 100. + public Blend(ImageBase image, int alpha = 100) + { + Guard.MustBeBetweenOrEqualTo(alpha, 0, 100, nameof(alpha)); + this.toBlend = image; + this.Value = alpha; + } + + /// + /// Gets the alpha percentage value. + /// + public int Value { get; } + + /// + protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + { + int sourceY = sourceRectangle.Y; + int sourceBottom = sourceRectangle.Bottom; + int startX = sourceRectangle.X; + int endX = sourceRectangle.Right; + Rectangle bounds = this.toBlend.Bounds; + float alpha = this.Value / 100f; + + Parallel.For( + startY, + endY, + y => + { + if (y >= sourceY && y < sourceBottom) + { + for (int x = startX; x < endX; x++) + { + Color color = source[x, y]; + + if (bounds.Contains(x, y)) + { + Color blendedColor = this.toBlend[x, y]; + + // Combining colors is dependent on the alpha of the blended color + float alphaFactor = alpha > 0 ? alpha : blendedColor.A; + float invertedAlphaFactor = 1 - alphaFactor; + + color.R = (color.R * invertedAlphaFactor) + (blendedColor.R * alphaFactor); + color.G = (color.G * invertedAlphaFactor) + (blendedColor.G * alphaFactor); + color.B = (color.B * invertedAlphaFactor) + (blendedColor.B * alphaFactor); + } + + target[x, y] = color; + } + } + }); + } + } +} diff --git a/src/ImageProcessor/Filters/ImageFilterExtensions.cs b/src/ImageProcessor/Filters/ImageFilterExtensions.cs index 73fe8c34c..cc2a7222e 100644 --- a/src/ImageProcessor/Filters/ImageFilterExtensions.cs +++ b/src/ImageProcessor/Filters/ImageFilterExtensions.cs @@ -35,6 +35,18 @@ namespace ImageProcessor.Filters return source.Process(rectangle, new Alpha(percent)); } + /// + /// Combines the given image together with the current one by blending their pixels. + /// + /// The image this method extends. + /// The image to blend with the currently processing image. + /// The opacity of the image image to blend. Must be between 0 and 100. + /// The . + public static Image Blend(this Image source, ImageBase image, int percent = 100) + { + return source.Process(source.Bounds, new Blend(image, percent)); + } + /// /// Alters the contrast component of the image. /// diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 4c5c260d8..3560f88b2 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -48,9 +48,10 @@ + - + diff --git a/src/ImageProcessor/Numerics/Rectangle.cs b/src/ImageProcessor/Numerics/Rectangle.cs index 6fe8a6388..bf3be3498 100644 --- a/src/ImageProcessor/Numerics/Rectangle.cs +++ b/src/ImageProcessor/Numerics/Rectangle.cs @@ -140,6 +140,21 @@ namespace ImageProcessor return !left.Equals(right); } + /// + /// Determines if the specfied point is contained within the rectangular region defined by + /// this . + /// + /// The x-coordinate of the given point. + /// The y-coordinate of the given point. + /// The + public bool Contains(int x, int y) + { + return this.X <= x + && x < this.X + this.Width + && this.Y <= y + && y < this.Y + this.Height; + } + /// /// Indicates whether this instance and a specified object are equal. /// diff --git a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs index 479ce6341..96824e264 100644 --- a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs +++ b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs @@ -16,8 +16,9 @@ namespace ImageProcessor.Tests //{ "Brightness--50", new Brightness(-50) }, //{ "Contrast-50", new Contrast(50) }, //{ "Contrast--50", new Contrast(-50) }, - { "Saturation-50", new Saturation(50) }, - { "Saturation--50", new Saturation(-50) }, + { "Blend", new Blend(new Image(File.OpenRead("../../TestImages/Formats/Bmp/Car.bmp")),50)}, + //{ "Saturation-50", new Saturation(50) }, + //{ "Saturation--50", new Saturation(-50) }, //{ "Alpha--50", new Alpha(50) }, //{ "Invert", new Invert() }, //{ "Sepia", new Sepia() },