From f1d485d39b45619ea4d1dfffc11eb0489d663d0f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 22 Oct 2015 23:05:26 +1100 Subject: [PATCH] Add Alpha, enhance Contrast Former-commit-id: a06e8058488c43fa8048b4ffd480d8424d88cc27 Former-commit-id: f0edb842766e8c2d2276625aa23b79ca1739918e Former-commit-id: c55ff7a504d21ce4941fe51596c1beb621ef2082 --- src/ImageProcessor/Filters/Alpha.cs | 56 +++++++++++++++++++ src/ImageProcessor/Filters/Contrast.cs | 54 ++++++++++-------- .../Filters/ImageFilterExtensions.cs | 46 ++++++++++++++- src/ImageProcessor/ImageProcessor.csproj | 2 + .../Processors/Filters/FilterTests.cs | 28 +--------- .../Processors/Samplers/SamplerTests.cs | 3 +- 6 files changed, 137 insertions(+), 52 deletions(-) create mode 100644 src/ImageProcessor/Filters/Alpha.cs diff --git a/src/ImageProcessor/Filters/Alpha.cs b/src/ImageProcessor/Filters/Alpha.cs new file mode 100644 index 000000000..672e5263a --- /dev/null +++ b/src/ImageProcessor/Filters/Alpha.cs @@ -0,0 +1,56 @@ +// +// Copyright © James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor.Filters +{ + using System; + + /// + /// An to change the Alpha of an . + /// + public class Alpha : ParallelImageProcessor + { + /// + /// 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 Alpha(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) + { + double alpha = this.Value / 100.0; + int sourceY = sourceRectangle.Y; + int sourceBottom = sourceRectangle.Bottom; + int startX = sourceRectangle.X; + int endX = sourceRectangle.Right; + + for (int y = startY; y < endY; y++) + { + if (y >= sourceY && y < sourceBottom) + { + for (int x = startX; x < endX; x++) + { + Bgra color = source[x, y]; + double a = color.A * alpha; + target[x, y] = new Bgra(color.B, color.G, color.R, a.ToByte()); + } + } + } + } + } +} diff --git a/src/ImageProcessor/Filters/Contrast.cs b/src/ImageProcessor/Filters/Contrast.cs index 6c3336fca..d08bcfcc2 100644 --- a/src/ImageProcessor/Filters/Contrast.cs +++ b/src/ImageProcessor/Filters/Contrast.cs @@ -17,7 +17,7 @@ namespace ImageProcessor.Filters /// /// The new contrast of the image. Must be between -100 and 100. /// - /// is less than -100 is greater than 100. + /// is less than -100 or is greater than 100. /// public Contrast(int contrast) { @@ -34,35 +34,45 @@ namespace ImageProcessor.Filters protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { double contrast = (100.0 + this.Value) / 100.0; + int sourceY = sourceRectangle.Y; + int sourceBottom = sourceRectangle.Bottom; + int startX = sourceRectangle.X; + int endX = sourceRectangle.Right; for (int y = startY; y < endY; y++) { - for (int x = sourceRectangle.X; x < sourceRectangle.Right; x++) + if (y >= sourceY && y < sourceBottom) { - Bgra color = source[x, y]; + for (int x = startX; x < endX; x++) + { + Bgra sourceColor = source[x, y]; + sourceColor = PixelOperations.ToLinear(sourceColor); - double r = color.R / 255.0; - r -= 0.5; - r *= contrast; - r += 0.5; - r *= 255; - r = r.ToByte(); + double r = sourceColor.R / 255.0; + r -= 0.5; + r *= contrast; + r += 0.5; + r *= 255; + r = r.ToByte(); - double g = color.G / 255.0; - g -= 0.5; - g *= contrast; - g += 0.5; - g *= 255; - g = g.ToByte(); + double g = sourceColor.G / 255.0; + g -= 0.5; + g *= contrast; + g += 0.5; + g *= 255; + g = g.ToByte(); - double b = color.B / 255.0; - b -= 0.5; - b *= contrast; - b += 0.5; - b *= 255; - b = b.ToByte(); + double b = sourceColor.B / 255.0; + b -= 0.5; + b *= contrast; + b += 0.5; + b *= 255; + b = b.ToByte(); - target[x, y] = new Bgra((byte)b, (byte)g, (byte)r, color.A); + Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), sourceColor.A); + destinationColor = PixelOperations.ToSrgb(destinationColor); + target[x, y] = destinationColor; + } } } } diff --git a/src/ImageProcessor/Filters/ImageFilterExtensions.cs b/src/ImageProcessor/Filters/ImageFilterExtensions.cs index 674f4f0e4..351a1921e 100644 --- a/src/ImageProcessor/Filters/ImageFilterExtensions.cs +++ b/src/ImageProcessor/Filters/ImageFilterExtensions.cs @@ -6,7 +6,7 @@ namespace ImageProcessor.Filters { /// - /// Exstensions methods for to apply filters to the image. + /// Extensions methods for to apply filters to the image. /// public static class ImageFilterExtensions { @@ -16,6 +16,48 @@ namespace ImageProcessor.Filters /// The image this method extends. /// The new contrast of the image. Must be between -100 and 100. /// The . - public static Image Contrast(this Image source, int amount) => source.Process(new Contrast(amount)); + public static Image Contrast(this Image source, int amount) + { + return Contrast(source, amount, source.Bounds); + } + + /// + /// Alters the contrast component of the image. + /// + /// The image this method extends. + /// The new contrast of the image. Must be between -100 and 100. + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// The . + public static Image Contrast(this Image source, int amount, Rectangle sourceRectangle) + { + return source.Process(sourceRectangle, new Contrast(amount)); + } + + /// + /// Alters the alpha component of the image. + /// + /// The image this method extends. + /// The new opacity of the image. Must be between 0 and 100. + /// The . + public static Image Alpha(this Image source, int percent) + { + return Alpha(source, percent, source.Bounds); + } + + /// + /// Alters the alpha component of the image. + /// + /// 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 draw. + /// + /// The . + public static Image Alpha(this Image source, int percent, Rectangle sourceRectangle) + { + return source.Process(sourceRectangle, new Alpha(percent)); + } } } diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index a7ec6d89a..53b0946a9 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -43,6 +43,7 @@ + @@ -181,6 +182,7 @@ + diff --git a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs index dac009328..4d6cb78a5 100644 --- a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs +++ b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs @@ -1,12 +1,10 @@  namespace ImageProcessor.Tests { - using System.Collections.Generic; using System.Diagnostics; using System.IO; using ImageProcessor.Filters; - using ImageProcessor.Samplers; using Xunit; @@ -16,6 +14,7 @@ namespace ImageProcessor.Tests { { "Contrast-50", new Contrast(50) }, { "Contrast--50", new Contrast(-50) }, + { "Alpha--50", new Alpha(50) }, }; [Theory] @@ -43,30 +42,5 @@ namespace ImageProcessor.Tests } } } - - [Fact] - public void ResizeImage() - { - if (!Directory.Exists("Resized")) - { - Directory.CreateDirectory("Resized"); - } - - foreach (string file in Files) - { - using (FileStream stream = File.OpenRead(file)) - { - Stopwatch watch = Stopwatch.StartNew(); - Image image = new Image(stream); - string filename = Path.GetFileName(file); - using (FileStream output = File.OpenWrite($"Resized/{ Path.GetFileName(filename) }")) - { - image.Resize(400, 400).Save(output); - } - - Trace.WriteLine($"{ filename }: { watch.ElapsedMilliseconds}ms"); - } - } - } } } diff --git a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs index ffa4c5d54..c35ff951e 100644 --- a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs +++ b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs @@ -46,7 +46,8 @@ namespace ImageProcessor.Tests string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); using (FileStream output = File.OpenWrite($"Resized/{filename}")) { - image.Resize(image.Width / 2, image.Height / 2, sampler).Save(output); + //image.Resize(image.Width / 2, image.Height / 2, sampler).Save(output); + image.Resize(500, 500, sampler, new Rectangle(0, 0, 100, 100), new Rectangle(0, 0, 500, 500)).Save(output); } Trace.WriteLine($"{name}: {watch.ElapsedMilliseconds}ms");