From 587baaafe0caa9cb7861fa62b5fe89ee620dd138 Mon Sep 17 00:00:00 2001 From: JimBobSquarePants Date: Wed, 27 Mar 2013 01:55:32 +0000 Subject: [PATCH] Adding brightness and contrast Former-commit-id: cae63b45e203c8581d183d55a74101697e391acd --- .../Helpers/Extensions/StringExtensions.cs | 2 +- src/ImageProcessor/ImageFactory.cs | 67 ++++++- src/ImageProcessor/ImageProcessor.csproj | 2 + src/ImageProcessor/Processors/Brightness.cs | 185 +++++++++++++++++ src/ImageProcessor/Processors/Contrast.cs | 188 ++++++++++++++++++ 5 files changed, 442 insertions(+), 2 deletions(-) create mode 100644 src/ImageProcessor/Processors/Brightness.cs create mode 100644 src/ImageProcessor/Processors/Contrast.cs diff --git a/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs b/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs index 77e105a59..ec9fa9e0c 100644 --- a/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs +++ b/src/ImageProcessor/Helpers/Extensions/StringExtensions.cs @@ -118,7 +118,7 @@ namespace ImageProcessor.Helpers.Extensions { Contract.Requires(!string.IsNullOrWhiteSpace(expression)); - Regex regex = new Regex(@"\d+", RegexOptions.Compiled); + Regex regex = new Regex(@"(-|)\d+", RegexOptions.Compiled); MatchCollection matchCollection = regex.Matches(expression); diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index ab8b5ad25..90c366db7 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -196,7 +196,10 @@ namespace ImageProcessor /// /// Changes the opacity of the current image. /// - /// The percentage by which to alter the images opacity. + /// + /// The percentage by which to alter the images opacity. + /// Any integer between 0 and 100. + /// /// /// The current instance of the class. /// @@ -204,6 +207,12 @@ namespace ImageProcessor { if (this.ShouldProcess) { + // Sanitize the input. + if (percentage > 100 || percentage < 0) + { + percentage = 0; + } + Alpha alpha = new Alpha { DynamicParameter = percentage }; this.Image = alpha.ProcessImage(this); @@ -212,6 +221,62 @@ namespace ImageProcessor return this; } + /// + /// Changes the brightness of the current image. + /// + /// + /// The percentage by which to alter the images brightness. + /// Any integer between -100 and 100. + /// + /// + /// The current instance of the class. + /// + public ImageFactory Brightness(int percentage) + { + if (this.ShouldProcess) + { + // Sanitize the input. + if (percentage > 100 || percentage < -100) + { + percentage = 0; + } + + Brightness brightness = new Brightness { DynamicParameter = percentage }; + + this.Image = brightness.ProcessImage(this); + } + + return this; + } + + /// + /// Changes the contrast of the current image. + /// + /// + /// The percentage by which to alter the images contrast. + /// Any integer between -100 and 100. + /// + /// + /// The current instance of the class. + /// + public ImageFactory Contrast(int percentage) + { + if (this.ShouldProcess) + { + // Sanitize the input. + if (percentage > 100 || percentage < -100) + { + percentage = 0; + } + + Contrast contrast = new Contrast { DynamicParameter = percentage }; + + this.Image = contrast.ProcessImage(this); + } + + return this; + } + /// /// Crops an image to the given coordinates. /// diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index f28352c9e..204c0a126 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -110,6 +110,8 @@ + + diff --git a/src/ImageProcessor/Processors/Brightness.cs b/src/ImageProcessor/Processors/Brightness.cs new file mode 100644 index 000000000..676e819bb --- /dev/null +++ b/src/ImageProcessor/Processors/Brightness.cs @@ -0,0 +1,185 @@ +// ----------------------------------------------------------------------- +// +// 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 brightness component of the image. + /// + public class Brightness : IGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + /// + private static readonly Regex QueryRegex = new Regex(@"brightness=(-|)(?:100|[1-9]?[0-9])", RegexOptions.Compiled); + + #region IGraphicsProcessor Members + /// + /// Gets the name. + /// + public string Name + { + get + { + return "Brightness"; + } + } + + /// + /// Gets the description. + /// + public string Description + { + get + { + return "Changes the the brightness 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 brightnessFactor = (float)this.DynamicParameter / 100; + + // 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[] { 1, 0, 0, 0, 0 }, + new float[] { 0, 1, 0, 0, 0 }, + new float[] { 0, 0, 1, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { brightnessFactor, brightnessFactor, brightnessFactor, 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 + } +} diff --git a/src/ImageProcessor/Processors/Contrast.cs b/src/ImageProcessor/Processors/Contrast.cs new file mode 100644 index 000000000..2259cc3a2 --- /dev/null +++ b/src/ImageProcessor/Processors/Contrast.cs @@ -0,0 +1,188 @@ +// ----------------------------------------------------------------------- +// +// 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 contrast component of the image. + /// + public class Contrast : IGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + /// + private static readonly Regex QueryRegex = new Regex(@"contrast=(-|)(?:100|[1-9]?[0-9])", RegexOptions.Compiled); + + #region IGraphicsProcessor Members + /// + /// Gets the name. + /// + public string Name + { + get + { + return "Contrast"; + } + } + + /// + /// Gets the description. + /// + public string Description + { + get + { + return "Changes the the contrast 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 contrastFactor = (float)this.DynamicParameter / 100; + + // Stop at -1 to prevent inversion. + contrastFactor++; + float factorTransform = 0.5f * (1.0f - contrastFactor); + + // 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[] { contrastFactor, 0, 0, 0, 0 }, + new float[] { 0, contrastFactor, 0, 0, 0 }, + new float[] { 0, 0, contrastFactor, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { factorTransform, factorTransform, factorTransform, 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 + } +}