diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs
index 90c366db7..6644284c9 100644
--- a/src/ImageProcessor/ImageFactory.cs
+++ b/src/ImageProcessor/ImageFactory.cs
@@ -431,6 +431,34 @@ namespace ImageProcessor
return this;
}
+ ///
+ /// Changes the saturation of the current image.
+ ///
+ ///
+ /// The percentage by which to alter the images saturation.
+ /// Any integer between -100 and 100.
+ ///
+ ///
+ /// The current instance of the class.
+ ///
+ public ImageFactory Saturate(int percentage)
+ {
+ if (this.ShouldProcess)
+ {
+ // Sanitize the input.
+ if (percentage > 100 || percentage < -100)
+ {
+ percentage = 0;
+ }
+
+ Saturate saturate = new Saturate { DynamicParameter = percentage };
+
+ this.Image = saturate.ProcessImage(this);
+ }
+
+ return this;
+ }
+
///
/// Adds a vignette image effect to the current image.
///
@@ -499,7 +527,9 @@ namespace ImageProcessor
ImageCodecInfo.GetImageEncoders().FirstOrDefault(
ici => ici.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase));
+// ReSharper disable AssignNullToNotNullAttribute
this.Image.Save(filePath, imageCodecInfo, encoderParameters);
+// ReSharper restore AssignNullToNotNullAttribute
}
}
else
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index 204c0a126..3041c3f54 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -112,6 +112,7 @@
+
diff --git a/src/ImageProcessor/Processors/IGraphicsProcessor.cs b/src/ImageProcessor/Processors/IGraphicsProcessor.cs
index 83b0e5ce4..96c6525d3 100644
--- a/src/ImageProcessor/Processors/IGraphicsProcessor.cs
+++ b/src/ImageProcessor/Processors/IGraphicsProcessor.cs
@@ -8,7 +8,6 @@
namespace ImageProcessor.Processors
{
#region Using
-
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
diff --git a/src/ImageProcessor/Processors/Saturate.cs b/src/ImageProcessor/Processors/Saturate.cs
new file mode 100644
index 000000000..c3f566a38
--- /dev/null
+++ b/src/ImageProcessor/Processors/Saturate.cs
@@ -0,0 +1,219 @@
+// -----------------------------------------------------------------------
+//
+// Copyright (c) James South.
+// Licensed under the Apache License, Version 2.0.
+//
+// -----------------------------------------------------------------------
+
+namespace ImageProcessor.Processors
+{
+ #region Using
+ using System.Collections.Generic;
+ using System.Drawing;
+ using System.Drawing.Imaging;
+ using System.Text.RegularExpressions;
+ using ImageProcessor.Helpers.Extensions;
+ #endregion
+
+ ///
+ /// Encapsulates methods to change the saturation component of the image.
+ ///
+ ///
+ ///
+ ///
+ public class Saturate : IGraphicsProcessor
+ {
+ ///
+ /// The regular expression to search strings for.
+ ///
+ ///
+ private static readonly Regex QueryRegex = new Regex(@"saturate=(-|)(?:100|[1-9]?[0-9])", RegexOptions.Compiled);
+
+ #region IGraphicsProcessor Members
+ ///
+ /// Gets the name.
+ ///
+ public string Name
+ {
+ get
+ {
+ return "Saturate";
+ }
+ }
+
+ ///
+ /// Gets the description.
+ ///
+ public string Description
+ {
+ get
+ {
+ return "Changes the the saturation component of the image.";
+ }
+ }
+
+ ///
+ /// Gets the regular expression to search strings for.
+ ///
+ public Regex RegexPattern
+ {
+ get
+ {
+ return QueryRegex;
+ }
+ }
+
+ ///
+ /// Gets or sets DynamicParameter.
+ ///
+ public dynamic DynamicParameter
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets the order in which this processor is to be used in a chain.
+ ///
+ public int SortOrder
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Gets or sets any additional settings required by the processor.
+ ///
+ public Dictionary Settings
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// The position in the original string where the first character of the captured substring was found.
+ ///
+ ///
+ /// The query string to search.
+ ///
+ ///
+ /// The zero-based starting position in the original string where the captured substring was found.
+ ///
+ public int MatchRegexIndex(string queryString)
+ {
+ int index = 0;
+
+ // Set the sort order to max to allow filtering.
+ this.SortOrder = int.MaxValue;
+
+ foreach (Match match in this.RegexPattern.Matches(queryString))
+ {
+ if (match.Success)
+ {
+ if (index == 0)
+ {
+ // Set the index on the first instance only.
+ this.SortOrder = match.Index;
+ int percentage = match.Value.ToIntegerArray()[0];
+
+ this.DynamicParameter = percentage;
+ }
+
+ index += 1;
+ }
+ }
+
+ return this.SortOrder;
+ }
+
+ ///
+ /// Processes the image.
+ ///
+ ///
+ /// The the current instance of the class containing
+ /// the image to process.
+ ///
+ ///
+ /// The processed image from the current instance of the class.
+ ///
+ public Image ProcessImage(ImageFactory factory)
+ {
+ Bitmap newImage = null;
+ Image image = factory.Image;
+
+ try
+ {
+ float saturationFactor = (float)this.DynamicParameter / 100;
+
+ // 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.
+ float saturationComplement = 1.0f - saturationFactor;
+ float saturationComplementR = 0.3086f * saturationComplement;
+ float saturationComplementG = 0.6094f * saturationComplement;
+ float saturationComplementB = 0.0820f * saturationComplement;
+
+ // Dont use an object initializer here.
+ newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb);
+ newImage.Tag = image.Tag;
+
+ ColorMatrix colorMatrix =
+ new ColorMatrix(
+ new float[][]
+ {
+ new float[]
+ {
+ saturationComplementR + saturationFactor, saturationComplementR,
+ saturationComplementR, 0, 0
+ },
+ new float[]
+ {
+ saturationComplementG, saturationComplementG + saturationFactor,
+ saturationComplementG, 0, 0
+ },
+ new float[]
+ {
+ saturationComplementB, saturationComplementB,
+ saturationComplementB + saturationFactor, 0, 0
+ },
+ new float[] { 0, 0, 0, 1, 0 },
+ new float[] { 0, 0, 0, 0, 1 }
+ });
+
+ using (Graphics graphics = Graphics.FromImage(newImage))
+ {
+ using (ImageAttributes imageAttributes = new ImageAttributes())
+ {
+ imageAttributes.SetColorMatrix(colorMatrix);
+
+ graphics.DrawImage(
+ image,
+ new Rectangle(0, 0, image.Width, image.Height),
+ 0,
+ 0,
+ image.Width,
+ image.Height,
+ GraphicsUnit.Pixel,
+ imageAttributes);
+
+ image.Dispose();
+ image = newImage;
+ }
+ }
+ }
+ catch
+ {
+ if (newImage != null)
+ {
+ newImage.Dispose();
+ }
+ }
+
+ return image;
+ }
+ #endregion
+ }
+}