diff --git a/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs b/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs index 8c58bc78b..730d212ff 100644 --- a/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs +++ b/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs @@ -13,6 +13,13 @@ namespace ImageProcessor.Filters /// public class ColorMatrixFilter : ParallelImageProcessor { + /// + /// Initializes a new instance of the class. + /// + public ColorMatrixFilter() + { + } + /// /// Initializes a new instance of the class. /// @@ -23,9 +30,9 @@ namespace ImageProcessor.Filters } /// - /// Gets the matrix value. + /// Gets or sets the matrix value. /// - public Matrix4x4 Value { get; } + public Matrix4x4 Value { get; set; } /// protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) diff --git a/src/ImageProcessor/Filters/ColorMatrix/Polaroid.cs b/src/ImageProcessor/Filters/ColorMatrix/Polaroid.cs index 875b44b7d..3c190a836 100644 --- a/src/ImageProcessor/Filters/ColorMatrix/Polaroid.cs +++ b/src/ImageProcessor/Filters/ColorMatrix/Polaroid.cs @@ -24,7 +24,7 @@ namespace ImageProcessor.Filters M21 = -0.022f, M22 = 1.578f, M23 = -0.022f, - M31 = .616f, + M31 = .216f, M32 = -.16f, M33 = 1.5831f, M41 = 0.02f, diff --git a/src/ImageProcessor/Filters/ColorMatrix/Saturation.cs b/src/ImageProcessor/Filters/ColorMatrix/Saturation.cs new file mode 100644 index 000000000..17a932cf2 --- /dev/null +++ b/src/ImageProcessor/Filters/ColorMatrix/Saturation.cs @@ -0,0 +1,56 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor.Filters +{ + using System; + using System.Numerics; + + /// + /// An to change the saturation of an . + /// + public class Saturation : ColorMatrixFilter + { + /// + /// 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)); + float saturationFactor = saturation / 100f; + + // Stop at -1 to prevent inversion. + saturationFactor++; + + // The matrix is set up to "shear" the colour space using the following set of values. + // Note that each colour component has an effective luminance which contributes to the + // overall brightness of the pixel. + // See http://graficaobscura.com/matrix/index.html + float saturationComplement = 1.0f - saturationFactor; + float saturationComplementR = 0.3086f * saturationComplement; + float saturationComplementG = 0.6094f * saturationComplement; + float saturationComplementB = 0.0820f * saturationComplement; + + Matrix4x4 matrix = new Matrix4x4() + { + M11 = saturationComplementR + saturationFactor, + M12 = saturationComplementR, + M13 = saturationComplementR, + M21 = saturationComplementG, + M22 = saturationComplementG + saturationFactor, + M23 = saturationComplementG, + M31 = saturationComplementB, + M32 = saturationComplementB, + M33 = saturationComplementB + saturationFactor, + }; + + this.Value = matrix; + } + } +} diff --git a/src/ImageProcessor/Filters/Saturation.cs b/src/ImageProcessor/Filters/Saturation.cs deleted file mode 100644 index 7167d6d00..000000000 --- a/src/ImageProcessor/Filters/Saturation.cs +++ /dev/null @@ -1,78 +0,0 @@ -// -// 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/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs index 810a872fd..479ce6341 100644 --- a/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs +++ b/tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs @@ -16,15 +16,15 @@ namespace ImageProcessor.Tests //{ "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) }, + { "Saturation-50", new Saturation(50) }, + { "Saturation--50", new Saturation(-50) }, //{ "Alpha--50", new Alpha(50) }, //{ "Invert", new Invert() }, //{ "Sepia", new Sepia() }, //{ "BlackWhite", new BlackWhite() }, //{ "Lomograph", new Lomograph() }, //{ "Polaroid", new Polaroid() }, - { "Brownie", new Kodachrome() }, + //{ "Kodachrome", new Kodachrome() }, //{ "GreyscaleBt709", new GreyscaleBt709() }, //{ "GreyscaleBt601", new GreyscaleBt601() }, };