From ec50f7ab4f96315fc3850187362c2a08798ae601 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 29 Jul 2016 16:50:37 +1000 Subject: [PATCH] Alpha Former-commit-id: a4b0ac45cb416e863496495ff9ac3d71585a46e6 Former-commit-id: ea2e5a6d2315d14f6ed566ff6c91b73c83b1feb5 Former-commit-id: 8a3cf0d04075c5da03b5d1ab747013d1efdd6491 --- src/ImageProcessorCore/Filters/Alpha.cs | 60 +++++++++++++++ .../Filters/Processors/AlphaProcessor.cs | 75 +++++++++++++++++++ .../Filters/Processors/BrightnessProcessor.cs | 2 +- .../Processors/Filters/AlphaTest.cs | 47 ++++++++++++ 4 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 src/ImageProcessorCore/Filters/Alpha.cs create mode 100644 src/ImageProcessorCore/Filters/Processors/AlphaProcessor.cs create mode 100644 tests/ImageProcessorCore.Tests/Processors/Filters/AlphaTest.cs diff --git a/src/ImageProcessorCore/Filters/Alpha.cs b/src/ImageProcessorCore/Filters/Alpha.cs new file mode 100644 index 000000000..545639afa --- /dev/null +++ b/src/ImageProcessorCore/Filters/Alpha.cs @@ -0,0 +1,60 @@ +// +// 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 + { + /// + /// Alters the alpha component of the image. + /// + /// The pixel format. + /// The packed format. long, float. + /// The image this method extends. + /// The new opacity of the image. Must be between 0 and 100. + /// A delegate which is called as progress is made processing the image. + /// The . + public static Image Alpha(this Image source, int percent, ProgressEventHandler progressHandler = null) + where T : IPackedVector + where TP : struct + { + return Alpha(source, percent, source.Bounds, progressHandler); + } + + /// + /// Alters the alpha component of the image. + /// + /// The pixel format. + /// The packed format. long, float. + /// The image this method extends. + /// The new opacity of the image. Must be between 0 and 100. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// A delegate which is called as progress is made processing the image. + /// The . + public static Image Alpha(this Image source, int percent, Rectangle rectangle, ProgressEventHandler progressHandler = null) + where T : IPackedVector + where TP : struct + { + AlphaProcessor processor = new AlphaProcessor(percent); + processor.OnProgress += progressHandler; + + try + { + return source.Process(rectangle, processor); + } + finally + { + processor.OnProgress -= progressHandler; + } + } + } +} diff --git a/src/ImageProcessorCore/Filters/Processors/AlphaProcessor.cs b/src/ImageProcessorCore/Filters/Processors/AlphaProcessor.cs new file mode 100644 index 000000000..b4595ac4b --- /dev/null +++ b/src/ImageProcessorCore/Filters/Processors/AlphaProcessor.cs @@ -0,0 +1,75 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore.Processors +{ + using System.Numerics; + using System.Threading.Tasks; + + /// + /// An to change the Alpha of an . + /// + /// The pixel format. + /// The packed format. long, float. + public class AlphaProcessor : ImageProcessor + where T : IPackedVector + where TP : struct + { + /// + /// Initializes a new instance of the class. + /// + /// The percentage to adjust the opacity of the image. Must be between 0 and 100. + /// + /// is less than 0 or is greater than 100. + /// + public AlphaProcessor(int percent) + { + Guard.MustBeBetweenOrEqualTo(percent, 0, 100, nameof(percent)); + this.Value = percent; + } + + /// + /// Gets the alpha value. + /// + public int Value { get; } + + /// + protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + { + float alpha = this.Value / 100f; + int sourceY = sourceRectangle.Y; + int sourceBottom = sourceRectangle.Bottom; + int startX = sourceRectangle.X; + int endX = sourceRectangle.Right; + Vector4 alphaVector = new Vector4(1, 1, 1, alpha); + + using (IPixelAccessor sourcePixels = source.Lock()) + using (IPixelAccessor targetPixels = target.Lock()) + { + Parallel.For( + startY, + endY, + y => + { + if (y >= sourceY && y < sourceBottom) + { + for (int x = startX; x < endX; x++) + { + Vector4 color = sourcePixels[x, y].ToVector4(); + color *= alphaVector; + + T packed = default(T); + packed.PackVector(color); + targetPixels[x, y] = packed; + } + + this.OnRowProcessed(); + } + }); + + } + } + } +} diff --git a/src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs b/src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs index 3b3be22a5..f9197d143 100644 --- a/src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs @@ -9,7 +9,7 @@ namespace ImageProcessorCore.Processors using System.Threading.Tasks; /// - /// An to change the brightness of an . + /// An to change the brightness of an . /// /// The pixel format. /// The packed format. long, float. diff --git a/tests/ImageProcessorCore.Tests/Processors/Filters/AlphaTest.cs b/tests/ImageProcessorCore.Tests/Processors/Filters/AlphaTest.cs new file mode 100644 index 000000000..6176cbb71 --- /dev/null +++ b/tests/ImageProcessorCore.Tests/Processors/Filters/AlphaTest.cs @@ -0,0 +1,47 @@ +// +// 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 AlphaTest : FileTestBase + { + public static readonly TheoryData AlphaValues + = new TheoryData + { + 20 , + 80 , + }; + + [Theory] + [MemberData("AlphaValues")] + public void ImageShouldApplyAlphaFilter(int value) + { + const string path = "TestOutput/Alpha"; + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + + foreach (string file in Files) + { + using (FileStream stream = File.OpenRead(file)) + { + string filename = Path.GetFileNameWithoutExtension(file) + "-" + value + Path.GetExtension(file); + + Image image = new Image(stream); + using (FileStream output = File.OpenWrite($"{path}/{filename}")) + { + image.Alpha(value) + .Save(output); + } + } + } + } + } +} \ No newline at end of file