diff --git a/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs index 13ac2b01b..963cd1b82 100644 --- a/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs +++ b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs @@ -290,14 +290,14 @@ namespace ImageProcessor.Web.UnitTests [Test] [TestCase("rotate=0", 0F)] [TestCase("rotate=270", 270F)] - [TestCase("rotate=-270", 0F)] + [TestCase("rotate=-270", -270F)] [TestCase("rotate=angle-28", 28F)] - public void TestRotateRegex(string input, int expected) + public void TestRotateRegex(string input, float expected) { Processors.Rotate rotate = new Processors.Rotate(); rotate.MatchRegexIndex(input); - int result = rotate.Processor.DynamicParameter; + float result = rotate.Processor.DynamicParameter; Assert.AreEqual(expected, result); } diff --git a/src/ImageProcessor.Web/Configuration/Resources/processing.config b/src/ImageProcessor.Web/Configuration/Resources/processing.config index c178f04cf..ab0eb300a 100644 --- a/src/ImageProcessor.Web/Configuration/Resources/processing.config +++ b/src/ImageProcessor.Web/Configuration/Resources/processing.config @@ -36,6 +36,7 @@ + diff --git a/src/ImageProcessor.Web/Helpers/CommonParameterParserUtility.cs b/src/ImageProcessor.Web/Helpers/CommonParameterParserUtility.cs index 44f8c20cd..47dd1f1f1 100644 --- a/src/ImageProcessor.Web/Helpers/CommonParameterParserUtility.cs +++ b/src/ImageProcessor.Web/Helpers/CommonParameterParserUtility.cs @@ -102,7 +102,7 @@ namespace ImageProcessor.Web.Helpers { foreach (Match match in ColorRegex.Matches(input)) { - string value = match.Value.Split(new[] { '=', '-' })[1]; + string value = match.Value; if (KnownColors.ContainsKey(value)) { @@ -250,7 +250,7 @@ namespace ImageProcessor.Web.Helpers private static Regex BuildColorRegex() { StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.Append(@"(bgcolor|color|tint|vignette)(=|-)(\d+,\d+,\d+,\d+|([0-9a-fA-F]{3}){1,2}|("); + stringBuilder.Append(@"(\d+,\d+,\d+,\d+|([0-9a-fA-F]{3}){1,2}|("); KnownColor[] knownColors = (KnownColor[])Enum.GetValues(typeof(KnownColor)); diff --git a/src/ImageProcessor.Web/ImageProcessor.Web.csproj b/src/ImageProcessor.Web/ImageProcessor.Web.csproj index 589ef0359..7859ba25a 100644 --- a/src/ImageProcessor.Web/ImageProcessor.Web.csproj +++ b/src/ImageProcessor.Web/ImageProcessor.Web.csproj @@ -51,6 +51,7 @@ + diff --git a/src/ImageProcessor.Web/Processors/BackgroundColor.cs b/src/ImageProcessor.Web/Processors/BackgroundColor.cs index edc9c3b68..e8e88dd55 100644 --- a/src/ImageProcessor.Web/Processors/BackgroundColor.cs +++ b/src/ImageProcessor.Web/Processors/BackgroundColor.cs @@ -75,7 +75,7 @@ namespace ImageProcessor.Web.Processors { // Set the index on the first instance only. this.SortOrder = match.Index; - this.Processor.DynamicParameter = CommonParameterParserUtility.ParseColor(match.Value); + this.Processor.DynamicParameter = CommonParameterParserUtility.ParseColor(match.Value.Split(new[] { '=', '-' })[1]); } index += 1; diff --git a/src/ImageProcessor.Web/Processors/ReplaceColor.cs b/src/ImageProcessor.Web/Processors/ReplaceColor.cs new file mode 100644 index 000000000..286852624 --- /dev/null +++ b/src/ImageProcessor.Web/Processors/ReplaceColor.cs @@ -0,0 +1,162 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates methods allowing the replacement of a color within an image. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System; + using System.Collections.Generic; + using System.Drawing; + using System.Globalization; + using System.Linq; + using System.Text; + using System.Text.RegularExpressions; + + using ImageProcessor.Processors; + using ImageProcessor.Web.Helpers; + + /// + /// Encapsulates methods allowing the replacement of a color within an image. + /// + public class ReplaceColor : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"(replace=|fuzziness=)[^&]+", RegexOptions.Compiled); + + /// + /// The replace regex. + /// + private static readonly Regex ReplaceRegex = new Regex(@"replace=[^&]+", RegexOptions.Compiled); + + /// + /// The fuzz regex. + /// + private static readonly Regex FuzzRegex = new Regex(@"fuzziness=\d+", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public ReplaceColor() + { + this.Processor = new ImageProcessor.Processors.ReplaceColor(); + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder { get; private set; } + + /// + /// Gets the associated graphics processor. + /// + public IGraphicsProcessor Processor { get; private 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; + + // First merge the matches so we can parse . + StringBuilder stringBuilder = new StringBuilder(); + + 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; + } + + stringBuilder.Append(match.Value); + + index += 1; + } + } + + if (this.SortOrder < int.MaxValue) + { + // Match syntax + string toParse = stringBuilder.ToString(); + Color[] colors = this.ParseColor(toParse); + int fuzziness = this.ParseFuzziness(toParse); + this.Processor.DynamicParameter = new Tuple(colors[0], colors[1], fuzziness); + } + + return this.SortOrder; + } + + /// + /// Returns the angle to alter the hue. + /// + /// + /// The input containing the value to parse. + /// + /// + /// The representing the angle. + /// + public Color[] ParseColor(string input) + { + IEnumerable colors = Enumerable.Empty(); + Match match = ReplaceRegex.Match(input); + if (match.Success) + { + string[] colorQuery = match.Value.Split('=')[1].Split('|'); + colors = colorQuery.Select(CommonParameterParserUtility.ParseColor); + } + + return colors.ToArray(); + } + + /// + /// Returns the angle to alter the hue. + /// + /// + /// The input containing the value to parse. + /// + /// + /// The representing the angle. + /// + public int ParseFuzziness(string input) + { + int fuzziness = 0; + + Match match = FuzzRegex.Match(input); + if (match.Success) + { + fuzziness = int.Parse(match.Value.Split('=')[1], CultureInfo.InvariantCulture); + } + + return Math.Max(0, Math.Min(100, fuzziness)); + } + } +} diff --git a/src/ImageProcessor.Web/Processors/Tint.cs b/src/ImageProcessor.Web/Processors/Tint.cs index 73fef8b3f..f8cce6b6e 100644 --- a/src/ImageProcessor.Web/Processors/Tint.cs +++ b/src/ImageProcessor.Web/Processors/Tint.cs @@ -72,7 +72,7 @@ namespace ImageProcessor.Web.Processors { // Set the index on the first instance only. this.SortOrder = match.Index; - this.Processor.DynamicParameter = CommonParameterParserUtility.ParseColor(match.Value); + this.Processor.DynamicParameter = CommonParameterParserUtility.ParseColor(match.Value.Split('=')[1]); } index += 1; diff --git a/src/ImageProcessor.Web/Processors/Vignette.cs b/src/ImageProcessor.Web/Processors/Vignette.cs index 7dc7259d3..56b67f6e1 100644 --- a/src/ImageProcessor.Web/Processors/Vignette.cs +++ b/src/ImageProcessor.Web/Processors/Vignette.cs @@ -79,7 +79,7 @@ namespace ImageProcessor.Web.Processors // Set the index on the first instance only. this.SortOrder = match.Index; - Color color = CommonParameterParserUtility.ParseColor(match.Value); + Color color = CommonParameterParserUtility.ParseColor(match.Value.Split('=')[1]); if (color.Equals(Color.Transparent)) { color = Color.Black; diff --git a/src/ImageProcessor.Web/Processors/Watermark.cs b/src/ImageProcessor.Web/Processors/Watermark.cs index 0e2afa126..b5842ea7e 100644 --- a/src/ImageProcessor.Web/Processors/Watermark.cs +++ b/src/ImageProcessor.Web/Processors/Watermark.cs @@ -66,6 +66,11 @@ namespace ImageProcessor.Web.Processors /// private static readonly Regex ShadowRegex = new Regex(@"((text|font|drop)?)shadow(=|-)true", RegexOptions.Compiled); + /// + /// The regular expression to search strings for the color attribute. + /// + private static readonly Regex ColorRegex = new Regex(@"color(=|-)[^&]+", RegexOptions.Compiled); + /// /// Initializes a new instance of the class. /// @@ -202,12 +207,18 @@ namespace ImageProcessor.Web.Processors /// private Color ParseColor(string input) { - Color textColor = CommonParameterParserUtility.ParseColor(input); - if (!textColor.Equals(Color.Transparent)) + foreach (Match match in ColorRegex.Matches(input)) { - return textColor; + string value = match.Value.Split(new[] { '=', '-' })[1]; + Color textColor = CommonParameterParserUtility.ParseColor(value); + if (!textColor.Equals(Color.Transparent)) + { + return textColor; + } } + + return Color.Black; }