diff --git a/src/ImageProcessor/Filters/Brightness.cs b/src/ImageProcessor/Filters/Brightness.cs new file mode 100644 index 0000000000..5edd4963fa --- /dev/null +++ b/src/ImageProcessor/Filters/Brightness.cs @@ -0,0 +1,77 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor.Filters +{ + using System; + using System.Numerics; + using System.Threading.Tasks; + + /// + /// An to change the brightness of an . + /// + public class Brightness : ParallelImageProcessor + { + /// + /// Initializes a new instance of the class. + /// + /// The new brightness of the image. Must be between -100 and 100. + /// + /// is less than -100 or is greater than 100. + /// + public Brightness(int brightness) + { + Guard.MustBeBetweenOrEqualTo(brightness, -100, 100, nameof(brightness)); + this.Value = brightness; + } + + /// + /// Gets the brightness value. + /// + public int Value { get; } + + /// + protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + { + float brightness = this.Value / 100f; + int sourceY = sourceRectangle.Y; + int sourceBottom = sourceRectangle.Bottom; + int startX = sourceRectangle.X; + int endX = sourceRectangle.Right; + + Parallel.For( + startY, + endY, + y => + { + if (y >= sourceY && y < sourceBottom) + { + for (int x = startX; x < endX; x++) + { + target[x, y] = AdjustBrightness(source[x, y], brightness); + } + } + }); + } + + /// + /// Returns a with the brightness adjusted. + /// + /// The source color. + /// The brightness adjustment factor. + /// + /// The . + /// + private static Color AdjustBrightness(Color color, float brightness) + { + color = PixelOperations.ToLinear(color); + + Vector3 vector3 = color.ToVector3(); + vector3 += new Vector3(brightness, brightness, brightness); + + return PixelOperations.ToSrgb(new Color(vector3, color.A)); + } + } +} diff --git a/src/ImageProcessor/Filters/ColorMatrix/ColorMatrix.cs b/src/ImageProcessor/Filters/ColorMatrix/ColorMatrix.cs index 6885acc070..0cab8e1ef6 100644 --- a/src/ImageProcessor/Filters/ColorMatrix/ColorMatrix.cs +++ b/src/ImageProcessor/Filters/ColorMatrix/ColorMatrix.cs @@ -8,7 +8,7 @@ namespace ImageProcessor.Filters { /// - /// Defines a 5 x 5 matrix that contains the coordinates for the RGBAW color space. + /// Defines a 5x5 matrix that contains the coordinates for the RGBAW color space. /// public sealed class ColorMatrix { diff --git a/src/ImageProcessor/Filters/Contrast.cs b/src/ImageProcessor/Filters/Contrast.cs index 0986dc3d0f..50d45d397b 100644 --- a/src/ImageProcessor/Filters/Contrast.cs +++ b/src/ImageProcessor/Filters/Contrast.cs @@ -67,6 +67,7 @@ namespace ImageProcessor.Filters { color = PixelOperations.ToLinear(color); + // Seems to be faster than Vector3. color.R -= 0.5f; color.R *= contrast; color.R += 0.5f; diff --git a/src/ImageProcessor/Filters/Saturation.cs b/src/ImageProcessor/Filters/Saturation.cs new file mode 100644 index 0000000000..7167d6d00e --- /dev/null +++ b/src/ImageProcessor/Filters/Saturation.cs @@ -0,0 +1,78 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor.Filters +{ + using System; + using System.Numerics; + using System.Threading.Tasks; + + /// + /// An to change the saturation of an . + /// + public class Saturation : ParallelImageProcessor + { + /// + /// Initializes a new instance of the class. + /// + /// The new saturation of the image. Must be between -100 and 100. + /// + /// is less than -100 or is greater than 100. + /// + public Saturation(int saturation) + { + Guard.MustBeBetweenOrEqualTo(saturation, -100, 100, nameof(saturation)); + this.Value = saturation; + } + + /// + /// Gets the saturation value. + /// + public int Value { get; } + + /// + protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + { + float saturation = this.Value / 100f; + int sourceY = sourceRectangle.Y; + int sourceBottom = sourceRectangle.Bottom; + int startX = sourceRectangle.X; + int endX = sourceRectangle.Right; + + Parallel.For( + startY, + endY, + y => + { + if (y >= sourceY && y < sourceBottom) + { + for (int x = startX; x < endX; x++) + { + target[x, y] = AdjustSaturation(source[x, y], saturation); + } + } + }); + } + + /// + /// Returns a with the saturation adjusted. + /// + /// The source color. + /// The saturation adjustment factor. + /// + /// The . + /// + private static Color AdjustSaturation(Color color, float saturation) + { + //color = PixelOperations.ToLinear(color); + + // TODO: This can be done with a matrix. But why can I not get conversion to work? + Hsv hsv = color; + return new Hsv(hsv.H, saturation, hsv.V); + + //return PixelOperations.ToSrgb(newHsv); + } + } +} diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 48294d14f7..fdb70a1833 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -48,6 +48,9 @@ + + + diff --git a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs index e1fe80d01d..ace61db0db 100644 --- a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs +++ b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs @@ -12,16 +12,20 @@ namespace ImageProcessor.Tests { public static readonly TheoryData Filters = new TheoryData { + //{ "Brightness-50", new Brightness(50) }, + //{ "Brightness--50", new Brightness(-50) }, //{ "Contrast-50", new Contrast(50) }, //{ "Contrast--50", new Contrast(-50) }, + { "Saturation-100", new Saturation(100) }, + { "Saturation--0", new Saturation(0) }, //{ "Alpha--50", new Alpha(50) }, - { "Invert", new Invert() }, - { "Sepia", new Sepia() }, - { "BlackWhite", new BlackWhite() }, - { "Lomograph", new Lomograph() }, - { "Polaroid", new Polaroid() }, - { "GreyscaleBt709", new GreyscaleBt709() }, - { "GreyscaleBt601", new GreyscaleBt601() }, + //{ "Invert", new Invert() }, + //{ "Sepia", new Sepia() }, + //{ "BlackWhite", new BlackWhite() }, + //{ "Lomograph", new Lomograph() }, + //{ "Polaroid", new Polaroid() }, + //{ "GreyscaleBt709", new GreyscaleBt709() }, + //{ "GreyscaleBt601", new GreyscaleBt601() }, }; [Theory]