From 7469f64ff3ed4dd1d9f785b54c4dc03c26bea139 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 30 Oct 2014 21:12:14 +0000 Subject: [PATCH] Adding mask to web Former-commit-id: 8c6e97ecedbaf295fe2596f1c4f39879440b7d82 Former-commit-id: b4940ff77158bb37cb8c3072ea62b99e719ecb10 --- .../Images/masks/mask.png | 3 + .../Configuration/Resources/processing.config | 7 +- .../Helpers/ImageHelpers.cs | 14 +- .../ImageProcessor.Web.csproj | 1 + src/ImageProcessor.Web/Processors/Mask.cs | 185 ++++++++++++++++++ src/TestWebsites/MVC/Web.config | 4 +- 6 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 src/ImageProcessor.UnitTests/Images/masks/mask.png create mode 100644 src/ImageProcessor.Web/Processors/Mask.cs diff --git a/src/ImageProcessor.UnitTests/Images/masks/mask.png b/src/ImageProcessor.UnitTests/Images/masks/mask.png new file mode 100644 index 0000000000..39a5b05c5c --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/masks/mask.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b76febb5bd44ae5624851482c5368a32f87ee1124a332115dd4f5421e19b269c +size 3284 diff --git a/src/ImageProcessor.Web/Configuration/Resources/processing.config b/src/ImageProcessor.Web/Configuration/Resources/processing.config index a1fed5fbdd..9d4a463090 100644 --- a/src/ImageProcessor.Web/Configuration/Resources/processing.config +++ b/src/ImageProcessor.Web/Configuration/Resources/processing.config @@ -12,7 +12,7 @@ - + @@ -27,6 +27,11 @@ + + + + + diff --git a/src/ImageProcessor.Web/Helpers/ImageHelpers.cs b/src/ImageProcessor.Web/Helpers/ImageHelpers.cs index 2b7946d779..29d7953a40 100644 --- a/src/ImageProcessor.Web/Helpers/ImageHelpers.cs +++ b/src/ImageProcessor.Web/Helpers/ImageHelpers.cs @@ -24,7 +24,13 @@ namespace ImageProcessor.Web.Helpers /// /// The regex pattern. /// - private static readonly string ExtensionRegexPattern = BuildExtensionRegexPattern(); + public static readonly string ExtensionRegexPattern = BuildExtensionRegexPattern(); + + /// + /// The exclude regex for matching things to ignore when parsing image extensions. + /// I'd like to make something more extensible than this. + /// + private static readonly Regex ExcludeRegex = new Regex(@"mask=[\w+-]+.", RegexOptions.IgnoreCase); /// /// The image format regex. @@ -57,6 +63,12 @@ namespace ImageProcessor.Web.Helpers /// public static string GetExtension(string input) { + // First filter out any troublesome elements. + foreach (Match exlude in ExcludeRegex.Matches(input)) + { + input = input.Replace(exlude.Value, string.Empty); + } + Match match = FormatRegex.Match(input); if (match.Success) diff --git a/src/ImageProcessor.Web/ImageProcessor.Web.csproj b/src/ImageProcessor.Web/ImageProcessor.Web.csproj index c8171d4ba2..98f0385af3 100644 --- a/src/ImageProcessor.Web/ImageProcessor.Web.csproj +++ b/src/ImageProcessor.Web/ImageProcessor.Web.csproj @@ -48,6 +48,7 @@ + diff --git a/src/ImageProcessor.Web/Processors/Mask.cs b/src/ImageProcessor.Web/Processors/Mask.cs new file mode 100644 index 0000000000..f5ad7d454c --- /dev/null +++ b/src/ImageProcessor.Web/Processors/Mask.cs @@ -0,0 +1,185 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Applies a mask to the given image. If the mask is not the same size as the image +// it will be centered against the image. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System; + using System.Drawing; + using System.IO; + using System.Text; + using System.Text.RegularExpressions; + using System.Web.Hosting; + + using ImageProcessor.Processors; + using ImageProcessor.Web.Extensions; + using ImageProcessor.Web.Helpers; + + /// + /// Applies a mask to the given image. If the mask is not the same size as the image + /// it will be centered against the image. + /// + public class Mask : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"(mask=|maskposition=)[^&]+", RegexOptions.Compiled); + + /// + /// The mask image regex. + /// + private static readonly Regex PixelRegex = new Regex(@"mask=[\w+-]+." + ImageHelpers.ExtensionRegexPattern); + + /// + /// The point regex. + /// + private static readonly Regex PointRegex = new Regex(@"maskposition=\d+,\d+", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public Mask() + { + this.Processor = new ImageProcessor.Processors.Mask(); + } + + /// + /// 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(); + Image image = this.ParseImage(toParse); + Point? rectangle = this.ParsePoint(toParse); + this.Processor.DynamicParameter = new Tuple(image, rectangle); + } + + return this.SortOrder; + } + + /// + /// Returns the correct size of pixels. + /// + /// + /// The input containing the value to parse. + /// + /// + /// The representing the pixel size. + /// + public Image ParseImage(string input) + { + Image image = null; + + // Correctly parse the path. + string path; + this.Processor.Settings.TryGetValue("VirtualPath", out path); + + if (!string.IsNullOrWhiteSpace(path) && path.StartsWith("~/")) + { + Match match = PixelRegex.Match(input); + + if (match.Success) + { + string imagePath = HostingEnvironment.MapPath(path); + if (imagePath != null) + { + imagePath = Path.Combine(imagePath, match.Value.Split('=')[1]); + using (ImageFactory factory = new ImageFactory()) + { + factory.Load(imagePath); + image = new Bitmap(factory.Image); + } + } + } + } + + return image; + } + + /// + /// Returns the correct for the given string. + /// + /// + /// The input string containing the value to parse. + /// + /// + /// The correct + /// + private Point? ParsePoint(string input) + { + int[] dimensions = { }; + + foreach (Match match in PointRegex.Matches(input)) + { + dimensions = match.Value.ToPositiveIntegerArray(); + } + + if (dimensions.Length == 2) + { + return new Point(dimensions[0], dimensions[1]); + } + + return null; + } + } +} diff --git a/src/TestWebsites/MVC/Web.config b/src/TestWebsites/MVC/Web.config index 9bef44eafd..5aae58e7ed 100644 --- a/src/TestWebsites/MVC/Web.config +++ b/src/TestWebsites/MVC/Web.config @@ -5,7 +5,7 @@ --> - +