From 33d097064fd8c5d9e57a84b0df16655c0088faff Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 30 Jul 2016 10:07:59 +1000 Subject: [PATCH] BackgroundColor Former-commit-id: abafddef9276f279c204a312c097cd28aa1d3e58 Former-commit-id: 27079155a41cd95690c7b676601e9df4044a05ca Former-commit-id: 0c77f74fd0194f4bab444d9bb4522422f65ad029 --- .../Filters/BackgroundColor.cs | 41 +++++++++ .../Processors/BackgroundColorProcessor.cs | 84 +++++++++++++++++++ .../Processors/Filters/BackgroundColorTest.cs | 38 +++++++++ 3 files changed, 163 insertions(+) create mode 100644 src/ImageProcessorCore/Filters/BackgroundColor.cs create mode 100644 src/ImageProcessorCore/Filters/Processors/BackgroundColorProcessor.cs create mode 100644 tests/ImageProcessorCore.Tests/Processors/Filters/BackgroundColorTest.cs diff --git a/src/ImageProcessorCore/Filters/BackgroundColor.cs b/src/ImageProcessorCore/Filters/BackgroundColor.cs new file mode 100644 index 0000000000..44f46598b5 --- /dev/null +++ b/src/ImageProcessorCore/Filters/BackgroundColor.cs @@ -0,0 +1,41 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore +{ + using Processors; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Replaces the background color of image with the given one. + /// + /// The pixel format. + /// The packed format. long, float. + /// The image this method extends. + /// The color to set as the background. + /// A delegate which is called as progress is made processing the image. + /// The . + public static Image BackgroundColor(this Image source, T color, ProgressEventHandler progressHandler = null) + where T : IPackedVector + where TP : struct + { + BackgroundColorProcessor processor = new BackgroundColorProcessor(color); + processor.OnProgress += progressHandler; + + try + { + return source.Process(source.Bounds, processor); + } + finally + { + processor.OnProgress -= progressHandler; + } + } + } +} diff --git a/src/ImageProcessorCore/Filters/Processors/BackgroundColorProcessor.cs b/src/ImageProcessorCore/Filters/Processors/BackgroundColorProcessor.cs new file mode 100644 index 0000000000..cc59d2d4fc --- /dev/null +++ b/src/ImageProcessorCore/Filters/Processors/BackgroundColorProcessor.cs @@ -0,0 +1,84 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore.Processors +{ + using System; + using System.Numerics; + using System.Threading.Tasks; + + /// + /// Sets the background color of the image. + /// + public class BackgroundColorProcessor : ImageProcessor + where T : IPackedVector + where TP : struct + { + /// + /// The epsilon for comparing floating point numbers. + /// + private const float Epsilon = 0.001f; + + /// + /// Initializes a new instance of the class. + /// + /// The to set the background color to. + public BackgroundColorProcessor(T color) + { + this.Value = color; + } + + /// + /// Gets the background color value. + /// + public T 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; + Vector4 backgroundColor = this.Value.ToVector4(); + + using (IPixelAccessor sourcePixels = source.Lock()) + using (IPixelAccessor targetPixels = target.Lock()) + { + Parallel.For( + startY, + endY, + Bootstrapper.Instance.ParallelOptions, + y => + { + if (y >= sourceY && y < sourceBottom) + { + for (int x = startX; x < endX; x++) + { + Vector4 color = sourcePixels[x, y].ToVector4(); + float a = color.W; + + if (a < 1 && a > 0) + { + color = Vector4.Lerp(color, backgroundColor, .5f); + } + + if (Math.Abs(a) < Epsilon) + { + color = backgroundColor; + } + + T packed = default(T); + packed.PackVector(color); + targetPixels[x, y] = packed; + } + + this.OnRowProcessed(); + } + }); + } + } + } +} diff --git a/tests/ImageProcessorCore.Tests/Processors/Filters/BackgroundColorTest.cs b/tests/ImageProcessorCore.Tests/Processors/Filters/BackgroundColorTest.cs new file mode 100644 index 0000000000..220d0f3840 --- /dev/null +++ b/tests/ImageProcessorCore.Tests/Processors/Filters/BackgroundColorTest.cs @@ -0,0 +1,38 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore.Tests +{ + using System.IO; + + using Xunit; + + public class BackgroundColorTest : FileTestBase + { + [Fact] + public void ImageShouldApplyBackgroundColorFilter() + { + const string path = "TestOutput/BackgroundColor"; + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + + foreach (string file in Files) + { + using (FileStream stream = File.OpenRead(file)) + { + string filename = Path.GetFileName(file); + Image image = new Image(stream); + using (FileStream output = File.OpenWrite($"{path}/{filename}")) + { + image.BackgroundColor(Color.HotPink) + .Save(output); + } + } + } + } + } +} \ No newline at end of file