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() },
};