mirror of https://github.com/SixLabors/ImageSharp
322 changed files with 9231 additions and 15059 deletions
@ -0,0 +1,54 @@ |
|||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<PropertyGroup> |
|||
<MSBuildCommunityTasksPath>.\</MSBuildCommunityTasksPath> |
|||
</PropertyGroup> |
|||
|
|||
<Import Project=".\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" /> |
|||
|
|||
<!-- |
|||
**************************************************** |
|||
VARIABLES |
|||
***************************************************** |
|||
--> |
|||
|
|||
<PropertyGroup> |
|||
<BuildConfiguration>Release</BuildConfiguration> |
|||
<BuildFolder>_BuildOutput\</BuildFolder> |
|||
<IncludeSymbols>False</IncludeSymbols> |
|||
<BuildFolderAbsolutePath>$(MSBuildProjectDirectory)\$(BuildFolder)</BuildFolderAbsolutePath> |
|||
<SolutionBinFolderAbsolutePath>$(BuildFolderAbsolutePath)ImageProcessor.Plugins.WebP\lib\net45</SolutionBinFolderAbsolutePath> |
|||
<BuildInputDir>..\src\Plugins\ImageProcessor\ImageProcessor.Plugins.WebP\</BuildInputDir> |
|||
</PropertyGroup> |
|||
|
|||
<!-- |
|||
**************************************************** |
|||
TARGETS |
|||
***************************************************** |
|||
--> |
|||
|
|||
<Target Name="Build" DependsOnTargets="BuildImageProcessorPluginsWebP"> |
|||
<Message Text="Build finished" /> |
|||
</Target> |
|||
|
|||
<Target Name="BuildImageProcessorPluginsWebP" DependsOnTargets="SetVersionNumber"> |
|||
<Message Text="Compiling ImageProcessor.Plugins.WebP project to build\$(BuildFolder)" Importance="High" /> |
|||
|
|||
<MSBuild Projects="$(BuildInputDir)\ImageProcessor.Plugins.WebP.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);PipelineDependsOnBuild=False;OutDir=$(SolutionBinFolderAbsolutePath);" Targets="Clean;Rebuild;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False" /> |
|||
|
|||
<Message Text="Finished compiling project" Importance="High" /> |
|||
</Target> |
|||
|
|||
<Target Name="SetVersionNumber" Condition="'$(BUILD_RELEASE)'!=''"> |
|||
<Message Text="Creating Version File: $(BUILD_RELEASE)"/> |
|||
<ItemGroup> |
|||
<AssemblyFiles Include="$(BuildInputDir)Properties\AssemblyInfo.cs;" /> |
|||
</ItemGroup> |
|||
|
|||
<FileUpdate Files="@(AssemblyFiles)" |
|||
Multiline="true" |
|||
Singleline="false" |
|||
Regex="(AssemblyVersion|AssemblyFileVersionAttribute|AssemblyFileVersion)\("([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?"\)" |
|||
ReplacementText="$1("$(BUILD_RELEASE)")" /> |
|||
|
|||
</Target> |
|||
</Project> |
|||
@ -0,0 +1,32 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> |
|||
<metadata> |
|||
<id>ImageProcessor.Plugins.WebP</id> |
|||
<version>1.0.0.0</version> |
|||
<title>ImageProcessor.Plugins.WebP</title> |
|||
<authors>James South</authors> |
|||
<owners>James South</owners> |
|||
<projectUrl>http://imageprocessor.org</projectUrl> |
|||
<iconUrl>http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png</iconUrl> |
|||
<requireLicenseAcceptance>false</requireLicenseAcceptance> |
|||
<description>Adds support to ImageProcessor for the WebP image format. |
|||
|
|||
If you use ImageProcessor please get in touch via my twitter @james_m_south |
|||
|
|||
Feedback is always welcome</description> |
|||
<summary>Adds support to ImageProcessor for the WebP image format.</summary> |
|||
<releaseNotes /> |
|||
<copyright>James South</copyright> |
|||
<language>en-GB</language> |
|||
<tags>Image Imaging ASP Performance Processing HttpModule Cache Resize Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png WebP Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated</tags> |
|||
<dependencies> |
|||
<group targetFramework=".NETFramework4.5"> |
|||
<dependency id="ImageProcessor" version="2.0.0.0" /> |
|||
</group> |
|||
</dependencies> |
|||
</metadata> |
|||
<files> |
|||
<file src="..\_BuildOutput\ImageProcessor.Plugins.WebP\lib\net45\ImageProcessor.Plugins.WebP.dll" target="lib\net45\ImageProcessor.Plugins.WebP.dll" /> |
|||
<file src="..\content\ImageProcessor.Plugins.WebP\web.config.transform" target="content\web.config.transform" /> |
|||
</files> |
|||
</package> |
|||
@ -0,0 +1,9 @@ |
|||
<?xml version="1.0"?> |
|||
<configuration> |
|||
<system.webServer> |
|||
<staticContent> |
|||
<remove fileExtension=".webp"/> |
|||
<mimeMap fileExtension=".webp" mimeType="image/webp" /> |
|||
</staticContent> |
|||
</system.webServer> |
|||
</configuration> |
|||
@ -0,0 +1,38 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="DoubleExtensionsUnitTests.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Runs unit tests on the <see cref="DoubleExtensions" /> extension methods
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.UnitTests.Extensions |
|||
{ |
|||
using Common.Extensions; |
|||
using NUnit.Framework; |
|||
|
|||
/// <summary>
|
|||
/// Test harness for the DoubleExtensions extension methods
|
|||
/// </summary>
|
|||
[TestFixture] |
|||
public class DoubleExtensionsUnitTests |
|||
{ |
|||
/// <summary>
|
|||
/// Tests the double to byte conversion
|
|||
/// </summary>
|
|||
/// <param name="input">Double input</param>
|
|||
/// <param name="expected">Expected result</param>
|
|||
[Test] |
|||
[TestCase(-10, 0x0)] |
|||
[TestCase(1.5, 0x1)] |
|||
[TestCase(25.7, 0x19)] |
|||
[TestCase(1289047, 0xFF)] |
|||
public void TestDoubleToByte(double input, byte expected) |
|||
{ |
|||
byte result = input.ToByte(); |
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="IntegerExtensionsUnitTests.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Runs unit tests on the <see cref="IntegerExtensions" /> extension methods
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.UnitTests.Extensions |
|||
{ |
|||
using Common.Extensions; |
|||
using NUnit.Framework; |
|||
|
|||
/// <summary>
|
|||
/// Provides a test harness for the integer extension class
|
|||
/// </summary>
|
|||
[TestFixture] |
|||
public class IntegerExtensionsUnitTests |
|||
{ |
|||
/// <summary>
|
|||
/// Tests the "ToByte" extension
|
|||
/// </summary>
|
|||
/// <param name="input">Integer input</param>
|
|||
/// <param name="expected">Expected result</param>
|
|||
[Test] |
|||
[TestCase(21, 0x15)] |
|||
[TestCase(190, 0xBE)] |
|||
[TestCase(3156, 0xFF)] |
|||
public void ToByteTest(int input, byte expected) |
|||
{ |
|||
byte result = input.ToByte(); |
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1 @@ |
|||
75b37593bb2e505bf4fbe874eaf30debd6161c2e |
|||
@ -0,0 +1 @@ |
|||
d0a1a39a6729e826098ae5e987c22c34c989b7e3 |
|||
@ -0,0 +1 @@ |
|||
9160894da31fedebb1fcd64eb57ca173187c63a6 |
|||
@ -0,0 +1 @@ |
|||
b169fac4f1591e81e91c0bb6fed6dcf62a34c80e |
|||
@ -0,0 +1 @@ |
|||
9d7e7964a2285363171929315b15ec69f14831ef |
|||
@ -0,0 +1 @@ |
|||
be31c9c0dea90586e2965208611fad024f6a5b08 |
|||
@ -0,0 +1 @@ |
|||
51ccec74a0351599de104f166b32d2860acaf089 |
|||
@ -0,0 +1 @@ |
|||
d7adbea2db4e3388541e31a229e5741677aaa7fd |
|||
@ -0,0 +1 @@ |
|||
b301e58d431a78d3f17be53be1cdc94c86286389 |
|||
@ -0,0 +1 @@ |
|||
ee5a15e7f8fc2655d5c1fc736a05857ab3d885bd |
|||
@ -0,0 +1 @@ |
|||
b6434b5a35e989d4fa71ede1a8316fedeee7ae5f |
|||
@ -0,0 +1 @@ |
|||
c789aaec248568c24394b05c02db4233e0c5a4eb |
|||
@ -0,0 +1 @@ |
|||
a41fb1117e1d730a4a488dcb67e0b867aa3c614e |
|||
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 50 KiB |
@ -0,0 +1 @@ |
|||
189f79f9b9604c5413aba928662d84edd426142d |
|||
@ -0,0 +1 @@ |
|||
f731bdf700d2718f528317263264e5466374c5e5 |
|||
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 55 KiB |
@ -1,217 +0,0 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="RegularExpressionUnitTests.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Unit tests for the ImageProcessor regular expressions
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.UnitTests |
|||
{ |
|||
using System; |
|||
using System.Drawing; |
|||
using ImageProcessor.Imaging; |
|||
using ImageProcessor.Processors; |
|||
using NUnit.Framework; |
|||
|
|||
/// <summary>
|
|||
/// Test harness for the regular expressions
|
|||
/// </summary>
|
|||
[TestFixture] |
|||
public class RegularExpressionUnitTests |
|||
{ |
|||
/// <summary>
|
|||
/// The alpha regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestAlphaRegex() |
|||
{ |
|||
const string Querystring = "alpha=56"; |
|||
const int Expected = 56; |
|||
|
|||
Alpha alpha = new Alpha(); |
|||
alpha.MatchRegexIndex(Querystring); |
|||
|
|||
int actual = alpha.DynamicParameter; |
|||
|
|||
Assert.AreEqual(Expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The brightness regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestBrightnessRegex() |
|||
{ |
|||
const string Querystring = "brightness=56"; |
|||
const int Expected = 56; |
|||
|
|||
Brightness brightness = new Brightness(); |
|||
brightness.MatchRegexIndex(Querystring); |
|||
|
|||
int actual = brightness.DynamicParameter; |
|||
|
|||
Assert.AreEqual(Expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The contrast regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestContrastRegex() |
|||
{ |
|||
const string Querystring = "contrast=56"; |
|||
const int Expected = 56; |
|||
|
|||
Contrast contrast = new Contrast(); |
|||
contrast.MatchRegexIndex(Querystring); |
|||
|
|||
int actual = contrast.DynamicParameter; |
|||
|
|||
Assert.AreEqual(Expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The rotate regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestCropRegex() |
|||
{ |
|||
const string Querystring = "crop=0,0,150,300"; |
|||
CropLayer expected = new CropLayer(0, 0, 150, 300, CropMode.Pixels); |
|||
|
|||
Crop crop = new Crop(); |
|||
crop.MatchRegexIndex(Querystring); |
|||
|
|||
CropLayer actual = crop.DynamicParameter; |
|||
Assert.AreEqual(expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The filter regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestFilterRegex() |
|||
{ |
|||
// Should really write more for the other filters.
|
|||
const string Querystring = "filter=lomograph"; |
|||
const string Expected = "lomograph"; |
|||
|
|||
Filter filter = new Filter(); |
|||
filter.MatchRegexIndex(Querystring); |
|||
|
|||
string actual = filter.DynamicParameter; |
|||
|
|||
Assert.AreEqual(Expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The format regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestFormatRegex() |
|||
{ |
|||
const string Querystring = "format=gif"; |
|||
const string Expected = "gif"; |
|||
|
|||
Format format = new Format(); |
|||
format.MatchRegexIndex(Querystring); |
|||
|
|||
string actual = format.DynamicParameter; |
|||
|
|||
Assert.AreEqual(Expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The quality regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestQualityRegex() |
|||
{ |
|||
const string Querystring = "quality=56"; |
|||
const int Expected = 56; |
|||
|
|||
Quality quality = new Quality(); |
|||
quality.MatchRegexIndex(Querystring); |
|||
|
|||
int actual = quality.DynamicParameter; |
|||
|
|||
Assert.AreEqual(Expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The resize regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestResizeRegex() |
|||
{ |
|||
const string Querystring = "width=300"; |
|||
ResizeLayer expected = new ResizeLayer(new Size(300, 0)); |
|||
|
|||
Resize resize = new Resize(); |
|||
|
|||
resize.MatchRegexIndex(Querystring); |
|||
ResizeLayer actual = resize.DynamicParameter; |
|||
|
|||
Assert.AreEqual(expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The rotate regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestRotateRegex() |
|||
{ |
|||
const string Querystring = "rotate=270"; |
|||
RotateLayer expected = new RotateLayer(270, Color.Transparent); |
|||
|
|||
Rotate rotate = new Rotate(); |
|||
rotate.MatchRegexIndex(Querystring); |
|||
|
|||
RotateLayer actual = rotate.DynamicParameter; |
|||
|
|||
Assert.AreEqual(expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The rounded corners regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestRoundedCornersRegex() |
|||
{ |
|||
const string Querystring = "roundedcorners=30"; |
|||
RoundedCornerLayer expected = new RoundedCornerLayer(30, true, true, true, true); |
|||
|
|||
RoundedCorners roundedCorners = new RoundedCorners(); |
|||
roundedCorners.MatchRegexIndex(Querystring); |
|||
|
|||
RoundedCornerLayer actual = roundedCorners.DynamicParameter; |
|||
|
|||
Assert.AreEqual(expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The rounded corners regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestTintRegex() |
|||
{ |
|||
const string HexQuerystring = "tint=6aa6cc"; |
|||
const string RgbaQuerystring = "tint=106,166,204,255"; |
|||
Color expectedHex = ColorTranslator.FromHtml("#" + "6aa6cc"); |
|||
Color expectedRgba = Color.FromArgb(255, 106, 166, 204); |
|||
|
|||
Tint tint = new Tint(); |
|||
tint.MatchRegexIndex(HexQuerystring); |
|||
Color actualHex = tint.DynamicParameter; |
|||
Assert.AreEqual(expectedHex, actualHex); |
|||
|
|||
tint = new Tint(); |
|||
tint.MatchRegexIndex(RgbaQuerystring); |
|||
Color actualRgba = tint.DynamicParameter; |
|||
Assert.AreEqual(expectedRgba, actualRgba); |
|||
} |
|||
} |
|||
} |
|||
@ -1,4 +1,4 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<packages> |
|||
<package id="NUnit" version="2.6.3" targetFramework="net40" /> |
|||
<package id="NUnit" version="2.6.3" targetFramework="net451" /> |
|||
</packages> |
|||
@ -0,0 +1,160 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="StringExtensionsUnitTests.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Test harness for the string extensions
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.UnitTests.Extensions |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
using ImageProcessor.Web.Extensions; |
|||
using NUnit.Framework; |
|||
|
|||
/// <summary>
|
|||
/// Test harness for the string extensions
|
|||
/// </summary>
|
|||
[TestFixture] |
|||
public class StringExtensionsUnitTests |
|||
{ |
|||
/// <summary>
|
|||
/// Tests the passing to an integer array
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestToIntegerArray() |
|||
{ |
|||
Dictionary<string, int[]> data = new Dictionary<string, int[]> |
|||
{ |
|||
{ |
|||
"123-456,78-90", |
|||
new[] { 123, 456, 78, 90 } |
|||
}, |
|||
{ |
|||
"87390174,741897498,74816,748297,57355", |
|||
new[] |
|||
{ |
|||
87390174, 741897498, 74816, |
|||
748297, 57355 |
|||
} |
|||
}, |
|||
{ "1-2-3", new[] { 1, 2, 3 } } |
|||
}; |
|||
|
|||
foreach (KeyValuePair<string, int[]> item in data) |
|||
{ |
|||
int[] result = item.Key.ToPositiveIntegerArray(); |
|||
Assert.AreEqual(item.Value, result); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Tests the passing to an float array
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestToFloatArray() |
|||
{ |
|||
Dictionary<string, float[]> data = new Dictionary<string, float[]> |
|||
{ |
|||
{ |
|||
"12.3-4.56,78-9.0", |
|||
new[] { 12.3F, 4.56F, 78, 9 } |
|||
}, |
|||
{ |
|||
"87390.174,7.41897498,748.16,748297,5.7355", |
|||
new[] |
|||
{ |
|||
87390.174F, 7.41897498F, |
|||
748.16F, 748297, 5.7355F |
|||
} |
|||
}, |
|||
{ "1-2-3", new float[] { 1, 2, 3 } } |
|||
}; |
|||
|
|||
foreach (KeyValuePair<string, float[]> item in data) |
|||
{ |
|||
float[] result = item.Key.ToPositiveFloatArray(); |
|||
Assert.AreEqual(item.Value, result); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Tests the MD5 fingerprint
|
|||
/// </summary>
|
|||
/// <param name="input">The input value</param>
|
|||
/// <param name="expected">The expected output of the hash</param>
|
|||
[Test] |
|||
[TestCase("test input", "2e7f7a62eabf0993239ca17c78c464d9")] |
|||
[TestCase("lorem ipsum dolor", "96ee002fee25e8b675a477c9750fa360")] |
|||
[TestCase("LoReM IpSuM DoLoR", "41e201da794c7fbdb8ce5526a71c8c83")] |
|||
[TestCase("1234567890", "e15e31c3d8898c92ab172a4311be9e84")] |
|||
public void TestToMd5Fingerprint(string input, string expected) |
|||
{ |
|||
string result = input.ToMD5Fingerprint(); |
|||
bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); |
|||
Assert.True(comparison); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Tests the SHA-1 fingerprint
|
|||
/// </summary>
|
|||
/// <param name="input">The input value</param>
|
|||
/// <param name="expected">The expected output of the hash</param>
|
|||
[Test] |
|||
[TestCase("test input", "49883b34e5a0f48224dd6230f471e9dc1bdbeaf5")] |
|||
[TestCase("lorem ipsum dolor", "75899ad8827a32493928903aecd6e931bf36f967")] |
|||
[TestCase("LoReM IpSuM DoLoR", "2f44519afae72fc0837b72c6b53cb11338a1f916")] |
|||
[TestCase("1234567890", "01b307acba4f54f55aafc33bb06bbbf6ca803e9a")] |
|||
public void TestToSHA1Fingerprint(string input, string expected) |
|||
{ |
|||
string result = input.ToSHA1Fingerprint(); |
|||
bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); |
|||
Assert.True(comparison); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Tests if the value is a valid URI path name. I.E the path part of a uri.
|
|||
/// </summary>
|
|||
/// <param name="input">The value to test</param>
|
|||
/// <param name="expected">Whether the value is correct</param>
|
|||
/// <remarks>
|
|||
/// The full RFC3986 does not seem to pass the test with the square brackets
|
|||
/// ':' is failing for some reason in VS but not elsewhere. Could be a build issue.
|
|||
/// </remarks>
|
|||
[Test] |
|||
[TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", true)] |
|||
[TestCase("-", true)] |
|||
[TestCase(".", true)] |
|||
[TestCase("_", true)] |
|||
[TestCase("~", true)] |
|||
[TestCase(":", true)] |
|||
[TestCase("/", true)] |
|||
[TestCase("?", true)] |
|||
[TestCase("#", false)] |
|||
[TestCase("[", false)] |
|||
[TestCase("]", false)]
|
|||
[TestCase("@", true)] |
|||
[TestCase("!", true)] |
|||
[TestCase("$", true)] |
|||
[TestCase("&", true)] |
|||
[TestCase("'", true)] |
|||
[TestCase("(", true)] |
|||
[TestCase(")", true)] |
|||
[TestCase("*", true)] |
|||
[TestCase("+", true)] |
|||
[TestCase(",", true)] |
|||
[TestCase(";", true)] |
|||
[TestCase("=", true)] |
|||
[TestCase("lorem ipsum", false)] |
|||
[TestCase("é", false)] |
|||
public void TestIsValidUriPathName(string input, bool expected) |
|||
{ |
|||
bool result = input.IsValidVirtualPathName(); |
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,112 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<PropertyGroup> |
|||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
|||
<ProjectGuid>{961340C8-8C93-401D-A0A2-FF9EC61E5260}</ProjectGuid> |
|||
<OutputType>Library</OutputType> |
|||
<AppDesignerFolder>Properties</AppDesignerFolder> |
|||
<RootNamespace>ImageProcessor.Web.UnitTests</RootNamespace> |
|||
<AssemblyName>ImageProcessor.Web.UnitTests</AssemblyName> |
|||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
|||
<FileAlignment>512</FileAlignment> |
|||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> |
|||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> |
|||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> |
|||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath> |
|||
<IsCodedUITest>False</IsCodedUITest> |
|||
<TestProjectType>UnitTest</TestProjectType> |
|||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> |
|||
<RestorePackages>true</RestorePackages> |
|||
<TargetFrameworkProfile /> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
|||
<DebugSymbols>true</DebugSymbols> |
|||
<DebugType>full</DebugType> |
|||
<Optimize>false</Optimize> |
|||
<OutputPath>bin\Debug\</OutputPath> |
|||
<DefineConstants>DEBUG;TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
|||
<DebugType>pdbonly</DebugType> |
|||
<Optimize>true</Optimize> |
|||
<OutputPath>bin\Release\</OutputPath> |
|||
<DefineConstants>TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<Reference Include="Microsoft.CSharp" /> |
|||
<Reference Include="nunit.framework"> |
|||
<HintPath>..\packages\NUnit.2.6.3\lib\nunit.framework.dll</HintPath> |
|||
</Reference> |
|||
<Reference Include="System" /> |
|||
<Reference Include="System.Drawing" /> |
|||
</ItemGroup> |
|||
<Choose> |
|||
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'"> |
|||
<ItemGroup> |
|||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> |
|||
</ItemGroup> |
|||
</When> |
|||
<Otherwise /> |
|||
</Choose> |
|||
<ItemGroup> |
|||
<Compile Include="Extensions\StringExtensionsUnitTests.cs" /> |
|||
<Compile Include="RegularExpressionUnitTests.cs" /> |
|||
<Compile Include="Properties\AssemblyInfo.cs" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<None Include="packages.config" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<ProjectReference Include="..\ImageProcessor.Web\ImageProcessor.Web.csproj"> |
|||
<Project>{d011a778-59c8-4bfa-a770-c350216bf161}</Project> |
|||
<Name>ImageProcessor.Web</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\ImageProcessor\ImageProcessor.csproj"> |
|||
<Project>{3b5dd734-fb7a-487d-8ce6-55e7af9aea7e}</Project> |
|||
<Name>ImageProcessor</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\Plugins\ImageProcessor\ImageProcessor.Plugins.WebP\ImageProcessor.Plugins.WebP.csproj"> |
|||
<Project>{2cf69699-959a-44dc-a281-4e2596c25043}</Project> |
|||
<Name>ImageProcessor.Plugins.WebP</Name> |
|||
</ProjectReference> |
|||
</ItemGroup> |
|||
<Choose> |
|||
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'"> |
|||
<ItemGroup> |
|||
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> |
|||
<Private>False</Private> |
|||
</Reference> |
|||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> |
|||
<Private>False</Private> |
|||
</Reference> |
|||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> |
|||
<Private>False</Private> |
|||
</Reference> |
|||
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> |
|||
<Private>False</Private> |
|||
</Reference> |
|||
</ItemGroup> |
|||
</When> |
|||
</Choose> |
|||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" /> |
|||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |
|||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" /> |
|||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> |
|||
<PropertyGroup> |
|||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> |
|||
</PropertyGroup> |
|||
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" /> |
|||
</Target> |
|||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. |
|||
Other similar extension points exist, see Microsoft.Common.targets. |
|||
<Target Name="BeforeBuild"> |
|||
</Target> |
|||
<Target Name="AfterBuild"> |
|||
</Target> |
|||
--> |
|||
</Project> |
|||
@ -0,0 +1,474 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="RegularExpressionUnitTests.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Unit tests for the ImageProcessor regular expressions
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.UnitTests |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Drawing; |
|||
using ImageProcessor.Imaging; |
|||
using ImageProcessor.Imaging.Filters; |
|||
using ImageProcessor.Imaging.Formats; |
|||
using ImageProcessor.Plugins.WebP.Imaging.Formats; |
|||
|
|||
using NUnit.Framework; |
|||
|
|||
/// <summary>
|
|||
/// Test harness for the regular expressions
|
|||
/// </summary>
|
|||
[TestFixture] |
|||
public class RegularExpressionUnitTests |
|||
{ |
|||
/// <summary>
|
|||
/// The alpha regex unit test.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string.
|
|||
/// </param>
|
|||
/// <param name="expected">
|
|||
/// The expected result.
|
|||
/// </param>
|
|||
[Test] |
|||
[TestCase("alpha=66", 66)] |
|||
[TestCase("alpha=-66", 66)] |
|||
[TestCase("alpha=101", 1)] |
|||
[TestCase("alpha=-101", 1)] |
|||
[TestCase("alpha=000053", 53)] |
|||
public void TestAlphaRegex(string input, int expected) |
|||
{ |
|||
Processors.Alpha alpha = new Processors.Alpha(); |
|||
alpha.MatchRegexIndex(input); |
|||
int result = alpha.Processor.DynamicParameter; |
|||
|
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The contrast regex unit test.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string.
|
|||
/// </param>
|
|||
/// <param name="expected">
|
|||
/// The expected result.
|
|||
/// </param>
|
|||
[Test] |
|||
[TestCase("brightness=56", 56)] |
|||
[TestCase("brightness=84", 84)] |
|||
[TestCase("brightness=66", 66)] |
|||
[TestCase("brightness=101", 1)] |
|||
[TestCase("brightness=00001", 1)] |
|||
[TestCase("brightness=-50", -50)] |
|||
[TestCase("brightness=0", 0)] |
|||
public void TestBrightnesstRegex(string input, int expected) |
|||
{ |
|||
Processors.Brightness brightness = new Processors.Brightness(); |
|||
brightness.MatchRegexIndex(input); |
|||
int result = brightness.Processor.DynamicParameter; |
|||
|
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The contrast regex unit test.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string.
|
|||
/// </param>
|
|||
/// <param name="expected">
|
|||
/// The expected result.
|
|||
/// </param>
|
|||
[Test] |
|||
[TestCase("contrast=56", 56)] |
|||
[TestCase("contrast=84", 84)] |
|||
[TestCase("contrast=66", 66)] |
|||
[TestCase("contrast=101", 1)] |
|||
[TestCase("contrast=00001", 1)] |
|||
[TestCase("contrast=-50", -50)] |
|||
[TestCase("contrast=0", 0)] |
|||
public void TestContrastRegex(string input, int expected) |
|||
{ |
|||
Processors.Contrast contrast = new Processors.Contrast(); |
|||
contrast.MatchRegexIndex(input); |
|||
int result = contrast.Processor.DynamicParameter; |
|||
|
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The rotate regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestCropRegex() |
|||
{ |
|||
const string Querystring = "crop=0,0,150,300"; |
|||
CropLayer expected = new CropLayer(0, 0, 150, 300, CropMode.Pixels); |
|||
|
|||
Processors.Crop crop = new Processors.Crop(); |
|||
crop.MatchRegexIndex(Querystring); |
|||
|
|||
CropLayer actual = crop.Processor.DynamicParameter; |
|||
Assert.AreEqual(expected, actual); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The filter regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
|
|||
public void TestFilterRegex() |
|||
{ |
|||
Dictionary<string, IMatrixFilter> data = new Dictionary<string, IMatrixFilter> |
|||
{ |
|||
{ |
|||
"filter=lomograph", MatrixFilters.Lomograph |
|||
}, |
|||
{ |
|||
"filter=polaroid", MatrixFilters.Polaroid |
|||
}, |
|||
{ |
|||
"filter=comic", MatrixFilters.Comic |
|||
}, |
|||
{ |
|||
"filter=greyscale", MatrixFilters.GreyScale |
|||
}, |
|||
{ |
|||
"filter=blackwhite", MatrixFilters.BlackWhite |
|||
}, |
|||
{ |
|||
"filter=invert", MatrixFilters.Invert |
|||
}, |
|||
{ |
|||
"filter=gotham", MatrixFilters.Gotham |
|||
}, |
|||
{ |
|||
"filter=hisatch", MatrixFilters.HiSatch |
|||
}, |
|||
{ |
|||
"filter=losatch", MatrixFilters.LoSatch |
|||
}, |
|||
{ |
|||
"filter=sepia", MatrixFilters.Sepia |
|||
} |
|||
}; |
|||
|
|||
Processors.Filter filter = new Processors.Filter(); |
|||
foreach (KeyValuePair<string, IMatrixFilter> item in data) |
|||
{ |
|||
filter.MatchRegexIndex(item.Key); |
|||
IMatrixFilter result = filter.Processor.DynamicParameter; |
|||
Assert.AreEqual(item.Value, result); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The format regex unit test.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input querystring.
|
|||
/// </param>
|
|||
/// <param name="expected">
|
|||
/// The expected type.
|
|||
/// </param>
|
|||
[Test] |
|||
[TestCase("format=bmp", typeof(BitmapFormat))] |
|||
[TestCase("format=png", typeof(PngFormat))] |
|||
[TestCase("format=png8", typeof(PngFormat))] |
|||
[TestCase("format=jpeg", typeof(JpegFormat))] |
|||
[TestCase("format=jpg", typeof(JpegFormat))] |
|||
[TestCase("format=gif", typeof(GifFormat))] |
|||
[TestCase("format=webp", typeof(WebPFormat))] |
|||
public void TestFormatRegex(string input, Type expected) |
|||
{ |
|||
Processors.Format format = new Processors.Format(); |
|||
format.MatchRegexIndex(input); |
|||
Type result = format.Processor.DynamicParameter.GetType(); |
|||
|
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The quality regex unit test.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input.
|
|||
/// </param>
|
|||
/// <param name="expected">
|
|||
/// The expected result.
|
|||
/// </param>
|
|||
[Test] |
|||
[TestCase("quality=56", 56)] |
|||
[TestCase("quality=84", 84)] |
|||
[TestCase("quality=66", 66)] |
|||
[TestCase("quality=101", 1)] |
|||
[TestCase("quality=00001", 1)] |
|||
[TestCase("quality=-50", 50)] |
|||
[TestCase("quality=0", 0)] |
|||
public void TestQualityRegex(string input, int expected) |
|||
{ |
|||
Processors.Quality quality = new Processors.Quality(); |
|||
quality.MatchRegexIndex(input); |
|||
int result = quality.Processor.DynamicParameter; |
|||
|
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The meta regex unit test.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input.
|
|||
/// </param>
|
|||
/// <param name="expected">
|
|||
/// The expected result.
|
|||
/// </param>
|
|||
[Test] |
|||
[TestCase("meta=true", true)] |
|||
[TestCase("meta=false", false)] |
|||
public void TestMetaRegex(string input, bool expected) |
|||
{ |
|||
Processors.Meta meta = new Processors.Meta(); |
|||
meta.MatchRegexIndex(input); |
|||
bool result = meta.Processor.DynamicParameter; |
|||
|
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The resize regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestResizeRegex() |
|||
{ |
|||
Dictionary<string, ResizeLayer> data = new Dictionary<string, ResizeLayer> |
|||
{ |
|||
{ |
|||
"width=300", new ResizeLayer(new Size(300, 0)) |
|||
}, |
|||
{ |
|||
"height=300", new ResizeLayer(new Size(0, 300)) |
|||
}, |
|||
{ |
|||
"height=300&mode=crop", new ResizeLayer(new Size(0, 300), ResizeMode.Crop) |
|||
}, |
|||
{ |
|||
"width=300&mode=crop", new ResizeLayer(new Size(300, 0), ResizeMode.Crop) |
|||
}, |
|||
{ |
|||
"width=600&heightratio=0.416", new ResizeLayer(new Size(600, 250)) |
|||
}, |
|||
{ |
|||
"width=600&height=250&mode=max", new ResizeLayer(new Size(600, 250), ResizeMode.Max) |
|||
} |
|||
}; |
|||
|
|||
Processors.Resize resize = new Processors.Resize(); |
|||
foreach (KeyValuePair<string, ResizeLayer> item in data) |
|||
{ |
|||
resize.MatchRegexIndex(item.Key); |
|||
ResizeLayer result = resize.Processor.DynamicParameter; |
|||
Assert.AreEqual(item.Value, result); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The rotate regex unit test.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string.
|
|||
/// </param>
|
|||
/// <param name="expected">
|
|||
/// The expected result.
|
|||
/// </param>
|
|||
[Test] |
|||
[TestCase("rotate=0", 0)] |
|||
[TestCase("rotate=270", 270)] |
|||
[TestCase("rotate=-270", 0)] |
|||
[TestCase("rotate=angle-28", 28)] |
|||
public void TestRotateRegex(string input, int expected) |
|||
{ |
|||
Processors.Rotate rotate = new Processors.Rotate(); |
|||
rotate.MatchRegexIndex(input); |
|||
|
|||
int result = rotate.Processor.DynamicParameter; |
|||
|
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The rounded corners regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestRoundedCornersRegex() |
|||
{ |
|||
Dictionary<string, RoundedCornerLayer> data = new Dictionary<string, RoundedCornerLayer> |
|||
{ |
|||
{ |
|||
"roundedcorners=30", new RoundedCornerLayer(30) |
|||
}, |
|||
{ |
|||
"roundedcorners=radius-26|tl-true|tr-false|bl-true|br-false", new RoundedCornerLayer(26, true, false, true, false) |
|||
}, |
|||
{ |
|||
"roundedcorners=26,tl=true,tr=false,bl=true,br=false", new RoundedCornerLayer(26, true, false, true, false) |
|||
} |
|||
}; |
|||
|
|||
Processors.RoundedCorners roundedCorners = new Processors.RoundedCorners(); |
|||
foreach (KeyValuePair<string, RoundedCornerLayer> item in data) |
|||
{ |
|||
roundedCorners.MatchRegexIndex(item.Key); |
|||
RoundedCornerLayer result = roundedCorners.Processor.DynamicParameter; |
|||
Assert.AreEqual(item.Value, result); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The saturation regex unit test.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string.
|
|||
/// </param>
|
|||
/// <param name="expected">
|
|||
/// The expected result.
|
|||
/// </param>
|
|||
[Test] |
|||
[TestCase("saturation=56", 56)] |
|||
[TestCase("saturation=84", 84)] |
|||
[TestCase("saturation=66", 66)] |
|||
[TestCase("saturation=101", 1)] |
|||
[TestCase("saturation=00001", 1)] |
|||
[TestCase("saturation=-50", -50)] |
|||
[TestCase("saturation=0", 0)] |
|||
public void TestSaturationRegex(string input, int expected) |
|||
{ |
|||
Processors.Saturation saturation = new Processors.Saturation(); |
|||
saturation.MatchRegexIndex(input); |
|||
int result = saturation.Processor.DynamicParameter; |
|||
|
|||
Assert.AreEqual(expected, result); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The tint regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestTintRegex() |
|||
{ |
|||
Dictionary<string, Color> data = new Dictionary<string, Color> |
|||
{ |
|||
{ |
|||
"tint=6aa6cc", ColorTranslator.FromHtml("#" + "6aa6cc") |
|||
}, |
|||
{ |
|||
"tint=106,166,204,255", Color.FromArgb(255, 106, 166, 204) |
|||
}, |
|||
{ |
|||
"tint=fff", Color.FromArgb(255, 255, 255, 255) |
|||
}, |
|||
{ |
|||
"tint=white", Color.White |
|||
} |
|||
}; |
|||
|
|||
Processors.Tint tint = new Processors.Tint(); |
|||
foreach (KeyValuePair<string, Color> item in data) |
|||
{ |
|||
tint.MatchRegexIndex(item.Key); |
|||
Color result = tint.Processor.DynamicParameter; |
|||
Assert.AreEqual(item.Value, result); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The vignette regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestVignetteRegex() |
|||
{ |
|||
Dictionary<string, Color> data = new Dictionary<string, Color> |
|||
{ |
|||
{ |
|||
"vignette", Color.Black |
|||
}, |
|||
{ |
|||
"vignette=true", Color.Black |
|||
}, |
|||
{ |
|||
"vignette=6aa6cc", ColorTranslator.FromHtml("#" + "6aa6cc") |
|||
}, |
|||
{ |
|||
"vignette=106,166,204,255", Color.FromArgb(255, 106, 166, 204) |
|||
}, |
|||
{ |
|||
"vignette=fff", Color.FromArgb(255, 255, 255, 255) |
|||
}, |
|||
{ |
|||
"vignette=white", Color.White |
|||
} |
|||
}; |
|||
|
|||
Processors.Vignette vignette = new Processors.Vignette(); |
|||
foreach (KeyValuePair<string, Color> item in data) |
|||
{ |
|||
vignette.MatchRegexIndex(item.Key); |
|||
Color result = vignette.Processor.DynamicParameter; |
|||
Assert.AreEqual(item.Value, result); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The watermark regex unit test.
|
|||
/// </summary>
|
|||
[Test] |
|||
public void TestWaterMarkRegex() |
|||
{ |
|||
Dictionary<string, TextLayer> data = new Dictionary<string, TextLayer> |
|||
{ |
|||
{ |
|||
"watermark=text-watermark goodness,color-fff,size-36,style-italic,opacity-80,position-30,150,shadow-true,font-arial", |
|||
new TextLayer |
|||
{ |
|||
Text = "watermark goodness", |
|||
FontColor = ColorTranslator.FromHtml("#" + "ffffff"), |
|||
FontSize = 36, |
|||
Style = FontStyle.Italic, |
|||
Opacity = 80, |
|||
Position = new Point(30, 150), |
|||
DropShadow = true, |
|||
FontFamily = new FontFamily("arial") |
|||
} |
|||
}, |
|||
{ |
|||
"watermark=watermark goodness&color=fff&fontsize=36&fontstyle=italic&fontopacity=80&textposition=30,150&textshadow=true&fontfamily=arial", |
|||
new TextLayer |
|||
{ |
|||
Text = "watermark goodness", |
|||
FontColor = ColorTranslator.FromHtml("#" + "ffffff"), |
|||
FontSize = 36, |
|||
Style = FontStyle.Italic, |
|||
Opacity = 80, |
|||
Position = new Point(30, 150), |
|||
DropShadow = true, |
|||
FontFamily = new FontFamily("arial") |
|||
} |
|||
} |
|||
}; |
|||
|
|||
Processors.Watermark watermark = new Processors.Watermark(); |
|||
foreach (KeyValuePair<string, TextLayer> item in data) |
|||
{ |
|||
watermark.MatchRegexIndex(item.Key); |
|||
TextLayer result = watermark.Processor.DynamicParameter; |
|||
Assert.AreEqual(item.Value, result); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<packages> |
|||
<package id="NUnit" version="2.6.3" targetFramework="net451" /> |
|||
</packages> |
|||
@ -0,0 +1 @@ |
|||
<cache virtualPath="~/app_data/cache" maxDays="365"/> |
|||
@ -0,0 +1,43 @@ |
|||
<processing preserveExifMetaData="false"> |
|||
<presets> |
|||
</presets> |
|||
<plugins autoLoadPlugins="true"> |
|||
<plugin name="Alpha" type="ImageProcessor.Web.Processors.Alpha, ImageProcessor.Web"/> |
|||
<plugin name="AutoRotate" type="ImageProcessor.Web.Processors.AutoRotate, ImageProcessor.Web"/> |
|||
<plugin name="BackgroundColor" type="ImageProcessor.Web.Processors.BackgroundColor, ImageProcessor.Web"/> |
|||
<plugin name="Brightness" type="ImageProcessor.Web.Processors.Brightness, ImageProcessor.Web"/> |
|||
<plugin name="Contrast" type="ImageProcessor.Web.Processors.Contrast, ImageProcessor.Web"/> |
|||
<plugin name="Crop" type="ImageProcessor.Web.Processors.Crop, ImageProcessor.Web"/> |
|||
<plugin name="Filter" type="ImageProcessor.Web.Processors.Filter, ImageProcessor.Web"/> |
|||
<plugin name="Flip" type="ImageProcessor.Web.Processors.Flip, ImageProcessor.Web"/> |
|||
<plugin name="Format" type="ImageProcessor.Web.Processors.Format, ImageProcessor.Web"/> |
|||
<plugin name="GaussianBlur" type="ImageProcessor.Web.Processors.GaussianBlur, ImageProcessor.Web"> |
|||
<settings> |
|||
<setting key="MaxSize" value="22"/> |
|||
<setting key="MaxSigma" value="5.1"/> |
|||
<setting key="MaxThreshold" value="100"/> |
|||
</settings> |
|||
</plugin> |
|||
<plugin name="GaussianSharpen" type="ImageProcessor.Web.Processors.GaussianSharpen, ImageProcessor.Web"> |
|||
<settings> |
|||
<setting key="MaxSize" value="22"/> |
|||
<setting key="MaxSigma" value="5.1"/> |
|||
<setting key="MaxThreshold" value="100"/> |
|||
</settings> |
|||
</plugin> |
|||
<plugin name="Meta" type="ImageProcessor.Web.Processors.Meta, ImageProcessor.Web"/> |
|||
<plugin name="Quality" type="ImageProcessor.Web.Processors.Quality, ImageProcessor.Web"/> |
|||
<plugin name="Resize" type="ImageProcessor.Web.Processors.Resize, ImageProcessor.Web"> |
|||
<settings> |
|||
<setting key="MaxWidth" value="5000"/> |
|||
<setting key="MaxHeight" value="5000"/> |
|||
</settings> |
|||
</plugin> |
|||
<plugin name="Rotate" type="ImageProcessor.Web.Processors.Rotate, ImageProcessor.Web"/> |
|||
<plugin name="RoundedCorners" type="ImageProcessor.Web.Processors.RoundedCorners, ImageProcessor.Web"/> |
|||
<plugin name="Saturation" type="ImageProcessor.Web.Processors.Saturation, ImageProcessor.Web"/> |
|||
<plugin name="Tint" type="ImageProcessor.Web.Processors.Tint, ImageProcessor.Web"/> |
|||
<plugin name="Vignette" type="ImageProcessor.Web.Processors.Vignette, ImageProcessor.Web"/> |
|||
<plugin name="Watermark" type="ImageProcessor.Web.Processors.Watermark, ImageProcessor.Web"/> |
|||
</plugins> |
|||
</processing> |
|||
@ -0,0 +1,134 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="AsyncDuplicateLock.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Throttles duplicate requests.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
namespace ImageProcessor.Web.Helpers |
|||
{ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Throttles duplicate requests.
|
|||
/// Based loosely on <see href="http://stackoverflow.com/a/21011273/427899"/>
|
|||
/// </summary>
|
|||
public sealed class AsyncDuplicateLock |
|||
{ |
|||
/// <summary>
|
|||
/// The collection of semaphore slims.
|
|||
/// </summary>
|
|||
private static readonly ConcurrentDictionary<object, SemaphoreSlim> SemaphoreSlims |
|||
= new ConcurrentDictionary<object, SemaphoreSlim>(); |
|||
|
|||
/// <summary>
|
|||
/// Locks against the given key.
|
|||
/// </summary>
|
|||
/// <param name="key">
|
|||
/// The key that identifies the current object.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The disposable <see cref="Task"/>.
|
|||
/// </returns>
|
|||
public IDisposable Lock(object key) |
|||
{ |
|||
DisposableScope releaser = new DisposableScope( |
|||
key, |
|||
s => |
|||
{ |
|||
SemaphoreSlim locker; |
|||
if (SemaphoreSlims.TryRemove(s, out locker)) |
|||
{ |
|||
locker.Release(); |
|||
locker.Dispose(); |
|||
} |
|||
}); |
|||
|
|||
SemaphoreSlim semaphore = SemaphoreSlims.GetOrAdd(key, new SemaphoreSlim(1, 1)); |
|||
semaphore.Wait(); |
|||
return releaser; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Asynchronously locks against the given key.
|
|||
/// </summary>
|
|||
/// <param name="key">
|
|||
/// The key that identifies the current object.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The disposable <see cref="Task"/>.
|
|||
/// </returns>
|
|||
public Task<IDisposable> LockAsync(object key) |
|||
{ |
|||
DisposableScope releaser = new DisposableScope( |
|||
key, |
|||
s => |
|||
{ |
|||
SemaphoreSlim locker; |
|||
if (SemaphoreSlims.TryRemove(s, out locker)) |
|||
{ |
|||
locker.Release(); |
|||
locker.Dispose(); |
|||
} |
|||
}); |
|||
|
|||
Task<IDisposable> releaserTask = Task.FromResult(releaser as IDisposable); |
|||
SemaphoreSlim semaphore = SemaphoreSlims.GetOrAdd(key, new SemaphoreSlim(1, 1)); |
|||
|
|||
Task waitTask = semaphore.WaitAsync(); |
|||
|
|||
return waitTask.IsCompleted |
|||
? releaserTask |
|||
: waitTask.ContinueWith( |
|||
(_, r) => (IDisposable)r, |
|||
releaser, |
|||
CancellationToken.None, |
|||
TaskContinuationOptions.ExecuteSynchronously, |
|||
TaskScheduler.Default); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The disposable scope.
|
|||
/// </summary>
|
|||
private sealed class DisposableScope : IDisposable |
|||
{ |
|||
/// <summary>
|
|||
/// The key
|
|||
/// </summary>
|
|||
private readonly object key; |
|||
|
|||
/// <summary>
|
|||
/// The close scope action.
|
|||
/// </summary>
|
|||
private readonly Action<object> closeScopeAction; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DisposableScope"/> class.
|
|||
/// </summary>
|
|||
/// <param name="key">
|
|||
/// The key.
|
|||
/// </param>
|
|||
/// <param name="closeScopeAction">
|
|||
/// The close scope action.
|
|||
/// </param>
|
|||
public DisposableScope(object key, Action<object> closeScopeAction) |
|||
{ |
|||
this.key = key; |
|||
this.closeScopeAction = closeScopeAction; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The dispose.
|
|||
/// </summary>
|
|||
public void Dispose() |
|||
{ |
|||
this.closeScopeAction(this.key); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,268 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="CommonParameterParserUtility.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods to correctly parse querystring parameters.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Helpers |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Drawing; |
|||
using System.Globalization; |
|||
using System.Text; |
|||
using System.Text.RegularExpressions; |
|||
|
|||
using ImageProcessor.Common.Extensions; |
|||
using ImageProcessor.Imaging; |
|||
using ImageProcessor.Web.Extensions; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to correctly parse querystring parameters.
|
|||
/// </summary>
|
|||
public static class CommonParameterParserUtility |
|||
{ |
|||
/// <summary>
|
|||
/// The collection of known colors.
|
|||
/// </summary>
|
|||
private static readonly Dictionary<string, KnownColor> KnownColors = new Dictionary<string, KnownColor>(); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for colors.
|
|||
/// </summary>
|
|||
private static readonly Regex ColorRegex = BuildColorRegex(); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for angles.
|
|||
/// </summary>
|
|||
private static readonly Regex AngleRegex = new Regex(@"(rotate|angle)(=|-)(?:3[0-5][0-9]|[12][0-9]{2}|[1-9][0-9]?)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for values between 1 and 100.
|
|||
/// </summary>
|
|||
private static readonly Regex In100RangeRegex = new Regex(@"(-?(0*(?:[1-9][0-9]?|100)))", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The sharpen regex.
|
|||
/// </summary>
|
|||
private static readonly Regex BlurSharpenRegex = new Regex(@"(blur|sharpen)=\d+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The sigma regex.
|
|||
/// </summary>
|
|||
private static readonly Regex SigmaRegex = new Regex(@"sigma(=|-)\d+(.?\d+)?", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The threshold regex.
|
|||
/// </summary>
|
|||
private static readonly Regex ThresholdRegex = new Regex(@"threshold(=|-)\d+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Int32"/> containing the angle for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Int32"/> containing the angle for the given string.
|
|||
/// </returns>
|
|||
public static int ParseAngle(string input) |
|||
{ |
|||
foreach (Match match in AngleRegex.Matches(input)) |
|||
{ |
|||
// Split on angle
|
|||
int angle; |
|||
string value = match.Value.Split(new[] { '=', '-' })[1]; |
|||
int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out angle); |
|||
return angle; |
|||
} |
|||
|
|||
// No rotate - matches the RotateLayer default.
|
|||
return 0; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Drawing.Color"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Drawing.Color"/>
|
|||
/// </returns>
|
|||
public static Color ParseColor(string input) |
|||
{ |
|||
foreach (Match match in ColorRegex.Matches(input)) |
|||
{ |
|||
string value = match.Value.Split(new[] { '=', '-' })[1]; |
|||
|
|||
if (KnownColors.ContainsKey(value)) |
|||
{ |
|||
return Color.FromKnownColor(KnownColors[value]); |
|||
} |
|||
|
|||
if (value.Contains(",")) |
|||
{ |
|||
int[] split = value.ToPositiveIntegerArray(); |
|||
byte red = split[0].ToByte(); |
|||
byte green = split[1].ToByte(); |
|||
byte blue = split[2].ToByte(); |
|||
byte alpha = split[3].ToByte(); |
|||
|
|||
return Color.FromArgb(alpha, red, green, blue); |
|||
} |
|||
|
|||
// Split on color-hex
|
|||
return ColorTranslator.FromHtml("#" + value); |
|||
} |
|||
|
|||
return Color.Transparent; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Int32"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Int32"/> between -100 and 100.
|
|||
/// </returns>
|
|||
public static int ParseIn100Range(string input) |
|||
{ |
|||
int value = 0; |
|||
foreach (Match match in In100RangeRegex.Matches(input)) |
|||
{ |
|||
value = int.Parse(match.Value, CultureInfo.InvariantCulture); |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="GaussianLayer"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <param name="maxSize">
|
|||
/// The maximum size to set the Gaussian kernel to.
|
|||
/// </param>
|
|||
/// <param name="maxSigma">
|
|||
/// The maximum Sigma value (standard deviation) for Gaussian function used to calculate the kernel.
|
|||
/// </param>
|
|||
/// <param name="maxThreshold">
|
|||
/// The maximum threshold value, which is added to each weighted sum of pixels.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="GaussianLayer"/> .
|
|||
/// </returns>
|
|||
public static GaussianLayer ParseGaussianLayer(string input, int maxSize, double maxSigma, int maxThreshold) |
|||
{ |
|||
int size = ParseBlurSharpen(input); |
|||
double sigma = ParseSigma(input); |
|||
int threshold = ParseThreshold(input); |
|||
|
|||
size = maxSize < size ? maxSize : size; |
|||
sigma = maxSigma < sigma ? maxSigma : sigma; |
|||
threshold = maxThreshold < threshold ? maxThreshold : threshold; |
|||
|
|||
return new GaussianLayer(size, sigma, threshold); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Int32"/> containing the blur value
|
|||
/// for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Int32"/> for the given string.
|
|||
/// </returns>
|
|||
private static int ParseBlurSharpen(string input) |
|||
{ |
|||
// ReSharper disable once LoopCanBeConvertedToQuery
|
|||
foreach (Match match in BlurSharpenRegex.Matches(input)) |
|||
{ |
|||
return Convert.ToInt32(match.Value.Split('=')[1]); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Double"/> containing the sigma value
|
|||
/// for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Double"/> for the given string.
|
|||
/// </returns>
|
|||
private static double ParseSigma(string input) |
|||
{ |
|||
foreach (Match match in SigmaRegex.Matches(input)) |
|||
{ |
|||
// split on text-
|
|||
return Convert.ToDouble(match.Value.Split(new[] { '=', '-' })[1]); |
|||
} |
|||
|
|||
return 1.4d; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Int32"/> containing the threshold value
|
|||
/// for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Int32"/> for the given string.
|
|||
/// </returns>
|
|||
private static int ParseThreshold(string input) |
|||
{ |
|||
// ReSharper disable once LoopCanBeConvertedToQuery
|
|||
foreach (Match match in ThresholdRegex.Matches(input)) |
|||
{ |
|||
return Convert.ToInt32(match.Value.Split(new[] { '=', '-' })[1]); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Builds a regular expression for the three main colour types.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// The <see cref="Regex"/> to match colors.
|
|||
/// </returns>
|
|||
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}|("); |
|||
|
|||
KnownColor[] knownColors = (KnownColor[])Enum.GetValues(typeof(KnownColor)); |
|||
|
|||
for (int i = 0; i < knownColors.Length; i++) |
|||
{ |
|||
KnownColor knownColor = knownColors[i]; |
|||
string name = knownColor.ToString().ToLowerInvariant(); |
|||
|
|||
KnownColors.Add(name, knownColor); |
|||
|
|||
stringBuilder.Append(i > 0 ? "|" + name : name); |
|||
} |
|||
|
|||
stringBuilder.Append("))"); |
|||
|
|||
return new Regex(stringBuilder.ToString(), RegexOptions.IgnoreCase); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,133 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="ImageHelpers.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// The image helpers.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Helpers |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Configuration; |
|||
using ImageProcessor.Imaging.Formats; |
|||
|
|||
/// <summary>
|
|||
/// The image helpers.
|
|||
/// </summary>
|
|||
public static class ImageHelpers |
|||
{ |
|||
/// <summary>
|
|||
/// The regex pattern.
|
|||
/// </summary>
|
|||
private static readonly string ExtensionRegexPattern = BuildExtensionRegexPattern(); |
|||
|
|||
/// <summary>
|
|||
/// The image format regex.
|
|||
/// </summary>
|
|||
private static readonly Regex FormatRegex = new Regex(@"(\.?)(png8|" + ExtensionRegexPattern + ")", RegexOptions.IgnoreCase | RegexOptions.RightToLeft); |
|||
|
|||
/// <summary>
|
|||
/// The image format regex for matching the file format at the end of a string.
|
|||
/// </summary>
|
|||
private static readonly Regex EndFormatRegex = new Regex(@"(\.)" + ExtensionRegexPattern + "$", RegexOptions.IgnoreCase | RegexOptions.RightToLeft); |
|||
|
|||
/// <summary>
|
|||
/// Checks a given string to check whether the value contains a valid image extension.
|
|||
/// </summary>
|
|||
/// <param name="fileName">The string containing the filename to check.</param>
|
|||
/// <returns>True the value contains a valid image extension, otherwise false.</returns>
|
|||
public static bool IsValidImageExtension(string fileName) |
|||
{ |
|||
return EndFormatRegex.IsMatch(fileName); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct file extension for the given string input
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The string to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct file extension for the given string input if it can find one; otherwise an empty string.
|
|||
/// </returns>
|
|||
public static string GetExtension(string input) |
|||
{ |
|||
Match match = FormatRegex.Match(input); |
|||
|
|||
if (match.Success) |
|||
{ |
|||
// Ah the enigma that is the png file.
|
|||
if (match.Value.ToLowerInvariant().EndsWith("png8")) |
|||
{ |
|||
return "png"; |
|||
} |
|||
|
|||
return match.Value; |
|||
} |
|||
|
|||
return string.Empty; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Get the correct mime-type for the given string input.
|
|||
/// </summary>
|
|||
/// <param name="identifier">
|
|||
/// The identifier.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="string"/> matching the correct mime-type.
|
|||
/// </returns>
|
|||
public static string GetMimeType(string identifier) |
|||
{ |
|||
identifier = GetExtension(identifier).Replace(".", string.Empty); |
|||
List<ISupportedImageFormat> formats = ImageProcessorBootstrapper.Instance.SupportedImageFormats.ToList(); |
|||
ISupportedImageFormat format = formats.FirstOrDefault(f => f.FileExtensions.Any(e => e.Equals(identifier, StringComparison.InvariantCultureIgnoreCase))); |
|||
|
|||
if (format != null) |
|||
{ |
|||
return format.MimeType; |
|||
} |
|||
|
|||
return string.Empty; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Builds a regular expression from the <see cref="T:ImageProcessor.Imaging.Formats.ISupportedImageFormat"/> type, this allows extensibility.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// The <see cref="Regex"/> to match matrix filters.
|
|||
/// </returns>
|
|||
private static string BuildExtensionRegexPattern() |
|||
{ |
|||
StringBuilder stringBuilder = new StringBuilder(); |
|||
stringBuilder.Append("("); |
|||
int counter = 0; |
|||
foreach (ISupportedImageFormat imageFormat in ImageProcessorBootstrapper.Instance.SupportedImageFormats) |
|||
{ |
|||
foreach (string fileExtension in imageFormat.FileExtensions) |
|||
{ |
|||
if (counter == 0) |
|||
{ |
|||
stringBuilder.Append(fileExtension.ToLowerInvariant()); |
|||
} |
|||
else |
|||
{ |
|||
stringBuilder.AppendFormat("|{0}", fileExtension.ToLowerInvariant()); |
|||
} |
|||
} |
|||
|
|||
counter++; |
|||
} |
|||
|
|||
stringBuilder.Append(")"); |
|||
return stringBuilder.ToString(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="NativeMethods.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Provides access to unmanaged native methods.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Helpers |
|||
{ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
/// <summary>
|
|||
/// Provides access to unmanaged native methods.
|
|||
/// </summary>
|
|||
internal class NativeMethods |
|||
{ |
|||
/// <summary>
|
|||
/// Loads the specified module into the address space of the calling process.
|
|||
/// The specified module may cause other modules to be loaded.
|
|||
/// </summary>
|
|||
/// <param name="libname">
|
|||
/// The name of the module. This can be either a library module or
|
|||
/// an executable module.
|
|||
/// </param>
|
|||
/// <returns>If the function succeeds, the return value is a handle to the module; otherwise null.</returns>
|
|||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] |
|||
public static extern IntPtr LoadLibrary(string libname); |
|||
|
|||
/// <summary>
|
|||
/// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count.
|
|||
/// When the reference count reaches zero, the module is unloaded from the address space of the calling
|
|||
/// process and the handle is no longer valid.
|
|||
/// </summary>
|
|||
/// <param name="hModule">A handle to the loaded library module.
|
|||
/// The LoadLibrary, LoadLibraryEx, GetModuleHandle, or GetModuleHandleEx function returns this handle.</param>
|
|||
/// <returns>If the function succeeds, the return value is nonzero; otherwise zero.</returns>
|
|||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)] |
|||
public static extern bool FreeLibrary(IntPtr hModule); |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="PostProcessingEventArgs.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// The post processing event arguments.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Helpers |
|||
{ |
|||
using System; |
|||
|
|||
/// <summary>
|
|||
/// The post processing event arguments.
|
|||
/// </summary>
|
|||
public class PostProcessingEventArgs : EventArgs |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the cached image path.
|
|||
/// </summary>
|
|||
public string CachedImagePath { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="ImageFactoryExtensions.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Extends the ImageFactory class to provide a fluent API.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web |
|||
{ |
|||
#region Using
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using ImageProcessor.Web.Configuration; |
|||
using ImageProcessor.Web.Processors; |
|||
#endregion
|
|||
|
|||
/// <summary>
|
|||
/// Extends the ImageFactory class to provide a fluent API.
|
|||
/// </summary>
|
|||
public static class ImageFactoryExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// The object to lock against.
|
|||
/// </summary>
|
|||
private static readonly object SyncRoot = new object(); |
|||
|
|||
/// <summary>
|
|||
/// Auto processes image files based on any query string parameters added to the image path.
|
|||
/// </summary>
|
|||
/// <param name="factory">
|
|||
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class
|
|||
/// that this method extends.
|
|||
/// </param>
|
|||
/// <param name="queryString">The collection of querystring parameters to process.</param>
|
|||
/// <returns>
|
|||
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
|
|||
/// </returns>
|
|||
public static ImageFactory AutoProcess(this ImageFactory factory, string queryString) |
|||
{ |
|||
if (factory.ShouldProcess) |
|||
{ |
|||
// It's faster to lock and run through our activated list than to create new instances.
|
|||
lock (SyncRoot) |
|||
{ |
|||
// Get a list of all graphics processors that have parsed and matched the query string.
|
|||
List<IWebGraphicsProcessor> graphicsProcessors = |
|||
ImageProcessorConfiguration.Instance.GraphicsProcessors |
|||
.Where(x => x.MatchRegexIndex(queryString) != int.MaxValue) |
|||
.OrderBy(y => y.SortOrder) |
|||
.ToList(); |
|||
|
|||
// Loop through and process the image.
|
|||
foreach (IWebGraphicsProcessor graphicsProcessor in graphicsProcessors) |
|||
{ |
|||
factory.CurrentImageFormat.ApplyProcessor(graphicsProcessor.Processor.ProcessImage, factory); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return factory; |
|||
} |
|||
} |
|||
} |
|||
@ -1,146 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<PropertyGroup> |
|||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
|||
<ProductVersion>8.0.30703</ProductVersion> |
|||
<SchemaVersion>2.0</SchemaVersion> |
|||
<ProjectGuid>{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}</ProjectGuid> |
|||
<OutputType>Library</OutputType> |
|||
<AppDesignerFolder>Properties</AppDesignerFolder> |
|||
<RootNamespace>ImageProcessor.Web</RootNamespace> |
|||
<AssemblyName>ImageProcessor.Web</AssemblyName> |
|||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
|||
<FileAlignment>512</FileAlignment> |
|||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> |
|||
<RestorePackages>true</RestorePackages> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
|||
<DebugSymbols>true</DebugSymbols> |
|||
<DebugType>full</DebugType> |
|||
<Optimize>false</Optimize> |
|||
<OutputPath>bin\Debug\</OutputPath> |
|||
<DefineConstants>TRACE;DEBUG;USE_CSHARP_SQLITE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
|||
<DebugType>pdbonly</DebugType> |
|||
<Optimize>true</Optimize> |
|||
<OutputPath>bin\Release\</OutputPath> |
|||
<DefineConstants>TRACE;USE_CSHARP_SQLITE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'All|AnyCPU'"> |
|||
<DebugSymbols>true</DebugSymbols> |
|||
<OutputPath>bin\All\</OutputPath> |
|||
<DefineConstants>TRACE;DEBUG;USE_CSHARP_SQLITE</DefineConstants> |
|||
<DebugType>full</DebugType> |
|||
<PlatformTarget>AnyCPU</PlatformTarget> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<Reference Include="Microsoft.CSharp" /> |
|||
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> |
|||
<SpecificVersion>False</SpecificVersion> |
|||
<HintPath>..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath> |
|||
</Reference> |
|||
<Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> |
|||
<SpecificVersion>False</SpecificVersion> |
|||
<HintPath>..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath> |
|||
</Reference> |
|||
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> |
|||
<SpecificVersion>False</SpecificVersion> |
|||
<HintPath>..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath> |
|||
</Reference> |
|||
<Reference Include="System" /> |
|||
<Reference Include="System.Configuration" /> |
|||
<Reference Include="System.Core" /> |
|||
<Reference Include="System.Drawing" /> |
|||
<Reference Include="System.IO"> |
|||
<HintPath>..\..\packages\Microsoft.Bcl.1.1.9\lib\net40\System.IO.dll</HintPath> |
|||
<Private>True</Private> |
|||
</Reference> |
|||
<Reference Include="System.Net" /> |
|||
<Reference Include="System.Runtime"> |
|||
<HintPath>..\..\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Runtime.dll</HintPath> |
|||
</Reference> |
|||
<Reference Include="System.Runtime.Caching" /> |
|||
<Reference Include="System.Threading.Tasks"> |
|||
<HintPath>..\..\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Threading.Tasks.dll</HintPath> |
|||
</Reference> |
|||
<Reference Include="System.Web" /> |
|||
<Reference Include="System.Data" /> |
|||
<Reference Include="System.XML" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Compile Include="..\NET45\Caching\CachedImage.cs" /> |
|||
<Compile Include="..\NET45\Caching\CacheIndexer.cs"> |
|||
<Link>CacheIndexer.cs</Link> |
|||
</Compile> |
|||
<Compile Include="..\NET45\Caching\DiskCache.cs" /> |
|||
<Compile Include="..\NET45\Caching\MemCache.cs"> |
|||
<Link>MemCache.cs</Link> |
|||
</Compile> |
|||
<Compile Include="..\NET45\Config\ImageCacheSection.cs" /> |
|||
<Compile Include="..\NET45\Config\ImageProcessingSection.cs" /> |
|||
<Compile Include="..\NET45\Config\ImageProcessorConfig.cs" /> |
|||
<Compile Include="..\NET45\Config\ImageSecuritySection.cs" /> |
|||
<Compile Include="..\NET45\Extensions\DirectoryInfoExtensions.cs"> |
|||
<Link>DirectoryInfoExtensions.cs</Link> |
|||
</Compile> |
|||
<Compile Include="..\NET45\Helpers\ImageHelpers.cs"> |
|||
<Link>ImageHelpers.cs</Link> |
|||
</Compile> |
|||
<Compile Include="..\NET45\Helpers\RemoteFile.cs" /> |
|||
<Compile Include="..\NET45\Helpers\ResourceHelpers.cs"> |
|||
<Link>ResourceHelpers.cs</Link> |
|||
</Compile> |
|||
<Compile Include="..\NET45\Helpers\TaskHelpers.cs" /> |
|||
<Compile Include="..\NET45\HttpModules\ImageProcessingModule.cs" /> |
|||
<Compile Include="..\NET45\ImageFactoryExtensions.cs" /> |
|||
<Compile Include="..\NET45\Properties\AssemblyInfo.cs" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\ImageProcessor\ImageProcessor.csproj"> |
|||
<Project>{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}</Project> |
|||
<Name>ImageProcessor</Name> |
|||
</ProjectReference> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<EmbeddedResource Include="..\NET45\Config\Resources\cache.config"> |
|||
<Link>Config\Resources\cache.config</Link> |
|||
</EmbeddedResource> |
|||
<EmbeddedResource Include="..\NET45\Config\Resources\processing.config"> |
|||
<Link>Config\Resources\processing.config</Link> |
|||
</EmbeddedResource> |
|||
<EmbeddedResource Include="..\NET45\Config\Resources\security.config"> |
|||
<Link>Config\Resources\security.config</Link> |
|||
</EmbeddedResource> |
|||
<None Include="app.config"> |
|||
<SubType>Designer</SubType> |
|||
</None> |
|||
<None Include="packages.config"> |
|||
<SubType>Designer</SubType> |
|||
</None> |
|||
</ItemGroup> |
|||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |
|||
<PropertyGroup> |
|||
<PostBuildEvent> |
|||
</PostBuildEvent> |
|||
</PropertyGroup> |
|||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" /> |
|||
<Import Project="..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" /> |
|||
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''"> |
|||
<Error Condition="!Exists('..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" /> |
|||
<Error Condition="Exists('..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" /> |
|||
</Target> |
|||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. |
|||
Other similar extension points exist, see Microsoft.Common.targets. |
|||
<Target Name="BeforeBuild"> |
|||
</Target> |
|||
<Target Name="AfterBuild"> |
|||
</Target> |
|||
--> |
|||
</Project> |
|||
@ -1,11 +0,0 @@ |
|||
<StyleCopSettings Version="105"> |
|||
<Analyzers> |
|||
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules"> |
|||
<AnalyzerSettings> |
|||
<StringProperty Name="CompanyName">James South</StringProperty> |
|||
<StringProperty Name="Copyright">Copyright (c) James South. |
|||
Licensed under the Apache License, Version 2.0.</StringProperty> |
|||
</AnalyzerSettings> |
|||
</Analyzer> |
|||
</Analyzers> |
|||
</StyleCopSettings> |
|||
@ -1,15 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<configuration> |
|||
<runtime> |
|||
<assemblyBinding xmlns:bcl="urn:schemas-microsoft-com:bcl" xmlns="urn:schemas-microsoft-com:asm.v1"> |
|||
<dependentAssembly bcl:name="System.Runtime"> |
|||
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> |
|||
<bindingRedirect oldVersion="0.0.0.0-2.6.9.0" newVersion="2.6.9.0" /> |
|||
</dependentAssembly> |
|||
<dependentAssembly bcl:name="System.Threading.Tasks"> |
|||
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> |
|||
<bindingRedirect oldVersion="0.0.0.0-2.6.9.0" newVersion="2.6.9.0" /> |
|||
</dependentAssembly> |
|||
</assemblyBinding> |
|||
</runtime> |
|||
</configuration> |
|||
@ -1,6 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<packages> |
|||
<package id="Microsoft.Bcl" version="1.1.9" targetFramework="net40" /> |
|||
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net40" /> |
|||
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net40" /> |
|||
</packages> |
|||
@ -1 +0,0 @@ |
|||
<cache virtualPath="~/app_data/cache" maxDays="356"/> |
|||
@ -1,41 +0,0 @@ |
|||
<processing preserveExifMetaData="false"> |
|||
<presets> |
|||
</presets> |
|||
<plugins autoLoadPlugins="true"> |
|||
<plugin name="Alpha" type="ImageProcessor.Processors.Alpha, ImageProcessor"/> |
|||
<plugin name="AutoRotate" type="ImageProcessor.Processors.AutoRotate, ImageProcessor"/> |
|||
<plugin name="Brightness" type="ImageProcessor.Processors.Brightness, ImageProcessor"/> |
|||
<plugin name="Contrast" type="ImageProcessor.Processors.Contrast, ImageProcessor"/> |
|||
<plugin name="Crop" type="ImageProcessor.Processors.Crop, ImageProcessor"/> |
|||
<plugin name="Filter" type="ImageProcessor.Processors.Filter, ImageProcessor"/> |
|||
<plugin name="Flip" type="ImageProcessor.Processors.Flip, ImageProcessor"/> |
|||
<plugin name="Format" type="ImageProcessor.Processors.Format, ImageProcessor"/> |
|||
<plugin name="GaussianBlur" type="ImageProcessor.Processors.GaussianBlur, ImageProcessor"> |
|||
<settings> |
|||
<setting key="MaxSize" value="22"/> |
|||
<setting key="MaxSigma" value="5.1"/> |
|||
<setting key="MaxThreshold" value="100"/> |
|||
</settings> |
|||
</plugin> |
|||
<plugin name="GaussianSharpen" type="ImageProcessor.Processors.GaussianSharpen, ImageProcessor"> |
|||
<settings> |
|||
<setting key="MaxSize" value="22"/> |
|||
<setting key="MaxSigma" value="5.1"/> |
|||
<setting key="MaxThreshold" value="100"/> |
|||
</settings> |
|||
</plugin> |
|||
<plugin name="Quality" type="ImageProcessor.Processors.Quality, ImageProcessor"/> |
|||
<plugin name="Resize" type="ImageProcessor.Processors.Resize, ImageProcessor"> |
|||
<settings> |
|||
<setting key="MaxWidth" value="5000"/> |
|||
<setting key="MaxHeight" value="5000"/> |
|||
</settings> |
|||
</plugin> |
|||
<plugin name="Rotate" type="ImageProcessor.Processors.Rotate, ImageProcessor"/> |
|||
<plugin name="RoundedCorners" type="ImageProcessor.Processors.RoundedCorners, ImageProcessor"/> |
|||
<plugin name="Saturation" type="ImageProcessor.Processors.Saturation, ImageProcessor"/> |
|||
<plugin name="Tint" type="ImageProcessor.Processors.Tint, ImageProcessor"/> |
|||
<plugin name="Vignette" type="ImageProcessor.Processors.Vignette, ImageProcessor"/> |
|||
<plugin name="Watermark" type="ImageProcessor.Processors.Watermark, ImageProcessor"/> |
|||
</plugins> |
|||
</processing> |
|||
@ -1,57 +0,0 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="ImageHelpers.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// The image helpers.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Helpers |
|||
{ |
|||
#region Using
|
|||
using System.Text.RegularExpressions; |
|||
#endregion
|
|||
|
|||
/// <summary>
|
|||
/// The image helpers.
|
|||
/// </summary>
|
|||
public static class ImageHelpers |
|||
{ |
|||
/// <summary>
|
|||
/// The image format regex.
|
|||
/// </summary>
|
|||
private static readonly Regex FormatRegex = new Regex(@"(\.?)(j(pg|peg)|bmp|png|gif|ti(ff|f)|ico)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.RightToLeft); |
|||
|
|||
/// <summary>
|
|||
/// The image format regex for matching the file format at the end of a string.
|
|||
/// </summary>
|
|||
private static readonly Regex EndFormatRegex = new Regex(@"(\.)(j(pg|peg)|bmp|png|gif|ti(ff|f)|ico)$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.RightToLeft); |
|||
|
|||
/// <summary>
|
|||
/// Checks a given string to check whether the value contains a valid image extension.
|
|||
/// </summary>
|
|||
/// <param name="fileName">The string containing the filename to check.</param>
|
|||
/// <returns>True the value contains a valid image extension, otherwise false.</returns>
|
|||
public static bool IsValidImageExtension(string fileName) |
|||
{ |
|||
return EndFormatRegex.IsMatch(fileName); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct file extension for the given string input
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The string to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct file extension for the given string input if it can find one; otherwise an empty string.
|
|||
/// </returns>
|
|||
public static string GetExtension(string input) |
|||
{ |
|||
Match match = FormatRegex.Matches(input)[0]; |
|||
return match.Success ? match.Value : string.Empty; |
|||
} |
|||
} |
|||
} |
|||
@ -1,51 +0,0 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="TaskHelpers.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Provides some syntactic sugar to run tasks.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Helpers |
|||
{ |
|||
#region Using
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
#endregion
|
|||
|
|||
/// <summary>
|
|||
/// Provides some syntactic sugar to run tasks.
|
|||
/// </summary>
|
|||
public sealed class TaskHelpers |
|||
{ |
|||
/// <summary>
|
|||
/// Queues the specified work to run on the ThreadPool and returns a Task handle for that work.
|
|||
/// </summary>
|
|||
/// <param name="action">The work to execute asynchronously</param>
|
|||
/// <returns>A Task that represents the work queued to execute in the ThreadPool.</returns>
|
|||
/// <exception cref="T:System.ArgumentNullException">
|
|||
/// The <paramref name="action"/> parameter was null.
|
|||
/// </exception>
|
|||
public static Task Run(Action action) |
|||
{ |
|||
return Task.Factory.StartNew(action); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Queues the specified work to run on the ThreadPool and returns a proxy for the
|
|||
/// Task(TResult) returned by <paramref name="function"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TResult">The type of the result returned by the proxy Task.</typeparam>
|
|||
/// <param name="function">The work to execute asynchronously</param>
|
|||
/// <returns>A Task(TResult) that represents a proxy for the Task(TResult) returned by <paramref name="function"/>.</returns>
|
|||
/// <exception cref="T:System.ArgumentNullException">
|
|||
/// The <paramref name="function"/> parameter was null.
|
|||
/// </exception>
|
|||
public static Task<TResult> Run<TResult>(Func<TResult> function) |
|||
{ |
|||
return Task<TResult>.Factory.StartNew(function); |
|||
} |
|||
} |
|||
} |
|||
@ -1,130 +0,0 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="ImageFactoryExtensions.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Extends the ImageFactory class to provide a fluent API.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web |
|||
{ |
|||
#region Using
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Drawing; |
|||
using System.Drawing.Imaging; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using ImageProcessor.Extensions; |
|||
using ImageProcessor.Imaging; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Config; |
|||
#endregion
|
|||
|
|||
/// <summary>
|
|||
/// Extends the ImageFactory class to provide a fluent API.
|
|||
/// </summary>
|
|||
public static class ImageFactoryExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// The object to lock against.
|
|||
/// </summary>
|
|||
private static readonly object SyncRoot = new object(); |
|||
|
|||
/// <summary>
|
|||
/// Auto processes image files based on any query string parameters added to the image path.
|
|||
/// </summary>
|
|||
/// <param name="factory">
|
|||
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class
|
|||
/// that this method extends.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
|
|||
/// </returns>
|
|||
public static ImageFactory AutoProcess(this ImageFactory factory) |
|||
{ |
|||
if (factory.ShouldProcess) |
|||
{ |
|||
// It's faster to lock and run through our activated list than to create new instances.
|
|||
lock (SyncRoot) |
|||
{ |
|||
// Get a list of all graphics processors that have parsed and matched the query string.
|
|||
List<IGraphicsProcessor> graphicsProcessors = |
|||
ImageProcessorConfig.Instance.GraphicsProcessors |
|||
.Where(x => x.MatchRegexIndex(factory.QueryString) != int.MaxValue) |
|||
.OrderBy(y => y.SortOrder) |
|||
.ToList(); |
|||
|
|||
// Loop through and process the image.
|
|||
foreach (IGraphicsProcessor graphicsProcessor in graphicsProcessors) |
|||
{ |
|||
ApplyProcessor(graphicsProcessor.ProcessImage, factory); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return factory; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Processes the image.
|
|||
/// </summary>
|
|||
/// <param name="processor">
|
|||
/// The processor.
|
|||
/// </param>
|
|||
/// <param name="factory">
|
|||
/// The factory.
|
|||
/// </param>
|
|||
private static void ApplyProcessor(Func<ImageFactory, Image> processor, ImageFactory factory) |
|||
{ |
|||
ImageInfo imageInfo = factory.Image.GetImageInfo(factory.ImageFormat); |
|||
|
|||
if (imageInfo.IsAnimated) |
|||
{ |
|||
OctreeQuantizer quantizer = new OctreeQuantizer(255, 8); |
|||
|
|||
// We don't dispose of the memory stream as that is disposed when a new image is created and doing so
|
|||
// beforehand will cause an exception.
|
|||
MemoryStream stream = new MemoryStream(); |
|||
using (GifEncoder encoder = new GifEncoder(stream, null, null, imageInfo.LoopCount)) |
|||
{ |
|||
foreach (GifFrame frame in imageInfo.GifFrames) |
|||
{ |
|||
factory.Update(frame.Image); |
|||
frame.Image = quantizer.Quantize(processor.Invoke(factory)); |
|||
encoder.AddFrame(frame); |
|||
} |
|||
} |
|||
|
|||
stream.Position = 0; |
|||
factory.Update(Image.FromStream(stream)); |
|||
} |
|||
else |
|||
{ |
|||
factory.Update(processor.Invoke(factory)); |
|||
} |
|||
|
|||
// Set the property item information from any Exif metadata.
|
|||
// We do this here so that they can be changed between processor methods.
|
|||
if (factory.PreserveExifData) |
|||
{ |
|||
foreach (KeyValuePair<int, PropertyItem> propertItem in factory.ExifPropertyItems) |
|||
{ |
|||
try |
|||
{ |
|||
factory.Image.SetPropertyItem(propertItem.Value); |
|||
} |
|||
// ReSharper disable once EmptyGeneralCatchClause
|
|||
catch |
|||
{ |
|||
// Do nothing. The image format does not handle EXIF data.
|
|||
// TODO: empty catch is fierce code smell.
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,18 +0,0 @@ |
|||
<StyleCopSettings Version="105"> |
|||
<GlobalSettings> |
|||
<CollectionProperty Name="RecognizedWords"> |
|||
<Value>exif</Value> |
|||
<Value>Mutexes</Value> |
|||
<Value>querystring</Value> |
|||
</CollectionProperty> |
|||
</GlobalSettings> |
|||
<Analyzers> |
|||
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules"> |
|||
<AnalyzerSettings> |
|||
<StringProperty Name="CompanyName">James South</StringProperty> |
|||
<StringProperty Name="Copyright">Copyright (c) James South. |
|||
Licensed under the Apache License, Version 2.0.</StringProperty> |
|||
</AnalyzerSettings> |
|||
</Analyzer> |
|||
</Analyzers> |
|||
</StyleCopSettings> |
|||
@ -0,0 +1,90 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Alpha.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods to change the alpha component of the image to effect its transparency.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System; |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to change the alpha component of the image to effect its transparency.
|
|||
/// </summary>
|
|||
public class Alpha : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"alpha=[^&|,]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Alpha"/> class.
|
|||
/// </summary>
|
|||
public Alpha() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Alpha(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">The query string to search.</param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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 = Math.Abs(CommonParameterParserUtility.ParseIn100Range(match.Value)); |
|||
this.Processor.DynamicParameter = percentage; |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,94 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="AutoRotate.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Performs auto-rotation to ensure that EXIF defined rotation is reflected in
|
|||
// the final image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
|
|||
/// <summary>
|
|||
/// Performs auto-rotation to ensure that EXIF defined rotation is reflected in
|
|||
/// the final image.
|
|||
/// </summary>
|
|||
public class AutoRotate : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"autorotate=true", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="AutoRotate"/> class.
|
|||
/// </summary>
|
|||
public AutoRotate() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.AutoRotate(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="BackgroundColor.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Changes the background color of an image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Changes the background color of an image.
|
|||
/// </summary>
|
|||
public class BackgroundColor : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"bgcolor(=|-)[^&]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BackgroundColor"/> class.
|
|||
/// </summary>
|
|||
public BackgroundColor() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.BackgroundColor(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">The query string to search.</param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
this.Processor.DynamicParameter = CommonParameterParserUtility.ParseColor(match.Value); |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Brightness.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods to change the brightness component of the image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to change the brightness component of the image.
|
|||
/// </summary>
|
|||
public class Brightness : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"brightness=[^&|,]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Brightness"/> class.
|
|||
/// </summary>
|
|||
public Brightness() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Brightness(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">The query string to search.</param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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 = CommonParameterParserUtility.ParseIn100Range(match.Value); |
|||
this.Processor.DynamicParameter = percentage; |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Contrast.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods to change the contrast component of the image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to change the contrast component of the image.
|
|||
/// </summary>
|
|||
public class Contrast : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"contrast=[^&|,]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Contrast"/> class.
|
|||
/// </summary>
|
|||
public Contrast() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Contrast(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">The query string to search.</param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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 = CommonParameterParserUtility.ParseIn100Range(match.Value); |
|||
this.Processor.DynamicParameter = percentage; |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,167 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Crop.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Crops an image to the given directions.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Text; |
|||
using System.Text.RegularExpressions; |
|||
|
|||
using ImageProcessor.Imaging; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Extensions; |
|||
|
|||
/// <summary>
|
|||
/// Crops an image to the given directions.
|
|||
/// </summary>
|
|||
public class Crop : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// <see href="http://stackoverflow.com/a/6400969/427899"/>
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"(crop=|cropmode=)[^&]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The coordinate regex.
|
|||
/// </summary>
|
|||
private static readonly Regex CoordinateRegex = new Regex(@"crop=\d+(.\d+)?[,-]\d+(.\d+)?[,-]\d+(.\d+)?[,-]\d+(.\d+)?", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The mode regex.
|
|||
/// </summary>
|
|||
private static readonly Regex ModeRegex = new Regex(@"cropmode=(pixels|percent)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Crop"/> class.
|
|||
/// </summary>
|
|||
public Crop() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Crop(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">The query string to search.</param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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(); |
|||
|
|||
float[] coordinates = this.ParseCoordinates(toParse); |
|||
CropMode cropMode = this.ParseMode(toParse); |
|||
|
|||
CropLayer cropLayer = new CropLayer(coordinates[0], coordinates[1], coordinates[2], coordinates[3], cropMode); |
|||
this.Processor.DynamicParameter = cropLayer; |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="CropMode"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="CropMode"/>.
|
|||
/// </returns>
|
|||
private CropMode ParseMode(string input) |
|||
{ |
|||
foreach (Match match in ModeRegex.Matches(input)) |
|||
{ |
|||
// Split on =
|
|||
string mode = match.Value.Split('=')[1]; |
|||
|
|||
switch (mode) |
|||
{ |
|||
case "percent": |
|||
return CropMode.Percentage; |
|||
case "pixels": |
|||
return CropMode.Pixels; |
|||
} |
|||
} |
|||
|
|||
return CropMode.Pixels; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="CropMode"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="CropMode"/>.
|
|||
/// </returns>
|
|||
private float[] ParseCoordinates(string input) |
|||
{ |
|||
float[] floats = { }; |
|||
|
|||
foreach (Match match in CoordinateRegex.Matches(input)) |
|||
{ |
|||
floats = match.Value.ToPositiveFloatArray(); |
|||
} |
|||
|
|||
return floats; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,161 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Filter.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods with which to add filters to an image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using System.Text; |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Imaging.Filters; |
|||
using ImageProcessor.Processors; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods with which to add filters to an image.
|
|||
/// </summary>
|
|||
public class Filter : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = BuildRegex(); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Filter"/> class.
|
|||
/// </summary>
|
|||
public Filter() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Filter(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the processor.
|
|||
/// </summary>
|
|||
/// <value>
|
|||
/// The processor.
|
|||
/// </value>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
this.Processor.DynamicParameter = this.ParseFilter(match.Value.Split('=')[1]); |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Builds a regular expression from the <see cref="MatrixFilters"/> type, this allows extensibility.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// The <see cref="Regex"/> to match matrix filters.
|
|||
/// </returns>
|
|||
private static Regex BuildRegex() |
|||
{ |
|||
const BindingFlags Flags = BindingFlags.Public | BindingFlags.Static; |
|||
Type type = typeof(MatrixFilters); |
|||
IEnumerable<PropertyInfo> filters = type.GetProperties(Flags) |
|||
.Where(p => p.PropertyType.IsAssignableFrom(typeof(IMatrixFilter))) |
|||
.ToList(); |
|||
|
|||
StringBuilder stringBuilder = new StringBuilder(); |
|||
stringBuilder.Append("filter=("); |
|||
int counter = 0; |
|||
|
|||
foreach (PropertyInfo filter in filters) |
|||
{ |
|||
if (counter == 0) |
|||
{ |
|||
stringBuilder.Append(filter.Name.ToLowerInvariant()); |
|||
} |
|||
else |
|||
{ |
|||
stringBuilder.AppendFormat("|{0}", filter.Name.ToLowerInvariant()); |
|||
} |
|||
|
|||
counter++; |
|||
} |
|||
|
|||
stringBuilder.Append(")"); |
|||
|
|||
return new Regex(stringBuilder.ToString(), RegexOptions.IgnoreCase); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Parses the input string to return the correct <see cref="IMatrixFilter"/>.
|
|||
/// </summary>
|
|||
/// <param name="identifier">
|
|||
/// The identifier.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="IMatrixFilter"/>.
|
|||
/// </returns>
|
|||
private IMatrixFilter ParseFilter(string identifier) |
|||
{ |
|||
const BindingFlags Flags = BindingFlags.Public | BindingFlags.Static; |
|||
|
|||
Type type = typeof(MatrixFilters); |
|||
PropertyInfo filter = |
|||
type.GetProperties(Flags) |
|||
.Where(p => p.PropertyType.IsAssignableFrom(typeof(IMatrixFilter))) |
|||
.First(p => p.Name.Equals(identifier, StringComparison.InvariantCultureIgnoreCase)); |
|||
|
|||
return filter.GetValue(null, null) as IMatrixFilter; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,103 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Flip.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Flips an image horizontally or vertically.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Drawing; |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
|
|||
/// <summary>
|
|||
/// Flips an image horizontally or vertically.
|
|||
/// </summary>
|
|||
public class Flip : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"flip=(horizontal|vertical|both)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Flip"/> class.
|
|||
/// </summary>
|
|||
public Flip() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Flip(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
string direction = match.Value.Split('=')[1]; |
|||
|
|||
switch (direction) |
|||
{ |
|||
case "horizontal": |
|||
this.Processor.DynamicParameter = RotateFlipType.RotateNoneFlipX; |
|||
break; |
|||
case "vertical": |
|||
this.Processor.DynamicParameter = RotateFlipType.RotateNoneFlipY; |
|||
break; |
|||
default: |
|||
this.Processor.DynamicParameter = RotateFlipType.RotateNoneFlipXY; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,166 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Format.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Sets the output of the image to a specific format.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Text.RegularExpressions; |
|||
|
|||
using ImageProcessor.Configuration; |
|||
using ImageProcessor.Imaging.Formats; |
|||
using ImageProcessor.Processors; |
|||
|
|||
/// <summary>
|
|||
/// Sets the output of the image to a specific format.
|
|||
/// </summary>
|
|||
public class Format : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = BuildRegex(); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Format"/> class.
|
|||
/// </summary>
|
|||
public Format() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Format(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
|
|||
ISupportedImageFormat format = this.ParseFormat(match.Value.Split('=')[1]); |
|||
if (format != null) |
|||
{ |
|||
this.Processor.DynamicParameter = format; |
|||
} |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Builds a regular expression from the <see cref="T:ImageProcessor.Imaging.Formats.ISupportedImageFormat"/> type, this allows extensibility.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// The <see cref="Regex"/> to match matrix filters.
|
|||
/// </returns>
|
|||
private static Regex BuildRegex() |
|||
{ |
|||
StringBuilder stringBuilder = new StringBuilder(); |
|||
|
|||
// png8 is a special case for determining indexed pngs.
|
|||
stringBuilder.Append("format=(png8"); |
|||
foreach (ISupportedImageFormat imageFormat in ImageProcessorBootstrapper.Instance.SupportedImageFormats) |
|||
{ |
|||
foreach (string fileExtension in imageFormat.FileExtensions) |
|||
{ |
|||
stringBuilder.AppendFormat("|{0}", fileExtension.ToLowerInvariant()); |
|||
} |
|||
} |
|||
|
|||
stringBuilder.Append(")"); |
|||
|
|||
return new Regex(stringBuilder.ToString(), RegexOptions.IgnoreCase); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Parses the input string to return the correct <see cref="ISupportedImageFormat"/>.
|
|||
/// </summary>
|
|||
/// <param name="identifier">
|
|||
/// The identifier.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="ISupportedImageFormat"/>.
|
|||
/// </returns>
|
|||
private ISupportedImageFormat ParseFormat(string identifier) |
|||
{ |
|||
identifier = identifier.ToLowerInvariant(); |
|||
string finalIdentifier = identifier.Equals("png8") ? "png" : identifier; |
|||
ISupportedImageFormat newFormat = null; |
|||
List<ISupportedImageFormat> formats = ImageProcessorBootstrapper.Instance.SupportedImageFormats.ToList(); |
|||
ISupportedImageFormat format = formats.FirstOrDefault(f => f.FileExtensions.Any(e => e.Equals(finalIdentifier, StringComparison.InvariantCultureIgnoreCase))); |
|||
|
|||
if (format != null) |
|||
{ |
|||
// Return a new instance as we want to use instance properties.
|
|||
newFormat = Activator.CreateInstance(format.GetType()) as ISupportedImageFormat; |
|||
|
|||
if (newFormat != null) |
|||
{ |
|||
// I wish this wasn't hard-coded but there's no way I can
|
|||
// find to preserve the palette.
|
|||
if (identifier.Equals("png8")) |
|||
{ |
|||
newFormat.IsIndexed = true; |
|||
} |
|||
else if (identifier.Equals("png")) |
|||
{ |
|||
newFormat.IsIndexed = false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return newFormat; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,101 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="GaussianBlur.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Applies a Gaussian blur to the image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Globalization; |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Applies a Gaussian blur to the image.
|
|||
/// </summary>
|
|||
public class GaussianBlur : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"blur=[^&]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GaussianBlur"/> class.
|
|||
/// </summary>
|
|||
public GaussianBlur() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.GaussianBlur(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
|
|||
// Normalise and set the variables.
|
|||
int maxSize; |
|||
double maxSigma; |
|||
int maxThreshold; |
|||
|
|||
int.TryParse(this.Processor.Settings["MaxSize"], NumberStyles.Any, CultureInfo.InvariantCulture, out maxSize); |
|||
double.TryParse(this.Processor.Settings["MaxSigma"], NumberStyles.Any, CultureInfo.InvariantCulture, out maxSigma); |
|||
int.TryParse(this.Processor.Settings["MaxThreshold"], NumberStyles.Any, CultureInfo.InvariantCulture, out maxThreshold); |
|||
|
|||
this.Processor.DynamicParameter = CommonParameterParserUtility.ParseGaussianLayer(queryString, maxSize, maxSigma, maxThreshold); |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,101 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="GaussianSharpen.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Applies a Gaussian sharpen to the image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Globalization; |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Applies a Gaussian sharpen to the image.
|
|||
/// </summary>
|
|||
public class GaussianSharpen : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"sharpen=[^&]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GaussianSharpen"/> class.
|
|||
/// </summary>
|
|||
public GaussianSharpen() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.GaussianSharpen(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
|
|||
// Normalise and set the variables.
|
|||
int maxSize; |
|||
double maxSigma; |
|||
int maxThreshold; |
|||
|
|||
int.TryParse(this.Processor.Settings["MaxSize"], NumberStyles.Any, CultureInfo.InvariantCulture, out maxSize); |
|||
double.TryParse(this.Processor.Settings["MaxSigma"], NumberStyles.Any, CultureInfo.InvariantCulture, out maxSigma); |
|||
int.TryParse(this.Processor.Settings["MaxThreshold"], NumberStyles.Any, CultureInfo.InvariantCulture, out maxThreshold); |
|||
|
|||
this.Processor.DynamicParameter = CommonParameterParserUtility.ParseGaussianLayer(queryString, maxSize, maxSigma, maxThreshold); |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="IWebGraphicsProcessor.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Defines properties and methods for ImageProcessor.Web Plugins.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
|
|||
/// <summary>
|
|||
/// Defines properties and methods for ImageProcessor.Web Plugins.
|
|||
/// </summary>
|
|||
public interface IWebGraphicsProcessor |
|||
{ |
|||
#region Properties
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
Regex RegexPattern { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
int SortOrder { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
IGraphicsProcessor Processor { get; } |
|||
#endregion
|
|||
|
|||
#region Methods
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
int MatchRegexIndex(string queryString); |
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Meta.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods to control preservation of meta information.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to control preservation of meta information.
|
|||
/// </summary>
|
|||
public class Meta : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"meta=(true|false)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Meta"/> class.
|
|||
/// </summary>
|
|||
public Meta() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Meta(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
|
|||
bool preserve = bool.Parse(match.Value.Split('=')[1]); |
|||
|
|||
this.Processor.DynamicParameter = preserve; |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,90 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Quality.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods to change the quality component of the image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System; |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to change the quality component of the image.
|
|||
/// </summary>
|
|||
public class Quality : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"quality=[^&|,]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Quality"/> class.
|
|||
/// </summary>
|
|||
public Quality() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Quality(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">The query string to search.</param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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 = Math.Abs(CommonParameterParserUtility.ParseIn100Range(match.Value)); |
|||
this.Processor.DynamicParameter = percentage; |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,325 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Resize.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Resizes an image to the given dimensions.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Drawing; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Text.RegularExpressions; |
|||
|
|||
using ImageProcessor.Imaging; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Extensions; |
|||
|
|||
/// <summary>
|
|||
/// Resizes an image to the given dimensions.
|
|||
/// </summary>
|
|||
public class Resize : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"(width|height)=|(width|height)ratio=|mode=|anchor=|center=|upscale=", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the size attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex SizeRegex = new Regex(@"(width|height)=\d+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the ratio attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex RatioRegex = new Regex(@"(width|height)ratio=\d+(.\d+)?", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the mode attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex ModeRegex = new Regex(@"mode=(pad|stretch|crop|max)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the anchor attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex AnchorRegex = new Regex(@"anchor=(top|bottom|left|right|center)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the center attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex CenterRegex = new Regex(@"center=\d+(.\d+)?[,-]\d+(.\d+)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the upscale attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex UpscaleRegex = new Regex(@"upscale=false", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Resize"/> class.
|
|||
/// </summary>
|
|||
public Resize() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Resize(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">The query string to search.</param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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(queryString); |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
// Match syntax
|
|||
string toParse = stringBuilder.ToString(); |
|||
|
|||
Size size = this.ParseSize(toParse); |
|||
ResizeLayer resizeLayer = new ResizeLayer(size) |
|||
{ |
|||
ResizeMode = this.ParseMode(toParse), |
|||
AnchorPosition = this.ParsePosition(toParse), |
|||
Upscale = !UpscaleRegex.IsMatch(toParse), |
|||
CenterCoordinates = this.ParseCoordinates(toParse), |
|||
}; |
|||
|
|||
this.Processor.DynamicParameter = resizeLayer; |
|||
|
|||
// Correctly parse any restrictions.
|
|||
string restrictions; |
|||
this.Processor.Settings.TryGetValue("RestrictTo", out restrictions); |
|||
((ImageProcessor.Processors.Resize)this.Processor).RestrictedSizes = this.ParseRestrictions(restrictions); |
|||
return this.SortOrder; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="Size"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="Size"/>.
|
|||
/// </returns>
|
|||
private Size ParseSize(string input) |
|||
{ |
|||
const string Width = "width="; |
|||
const string Height = "height="; |
|||
const string WidthRatio = "widthratio="; |
|||
const string HeightRatio = "heightratio="; |
|||
Size size = new Size(); |
|||
|
|||
// First merge the matches so we can parse .
|
|||
StringBuilder stringBuilder = new StringBuilder(); |
|||
foreach (Match match in SizeRegex.Matches(input)) |
|||
{ |
|||
stringBuilder.Append(match.Value); |
|||
} |
|||
|
|||
// First cater for single dimensions.
|
|||
string value = stringBuilder.ToString(); |
|||
|
|||
if (input.Contains(Width) && !input.Contains(Height)) |
|||
{ |
|||
size = new Size(value.ToPositiveIntegerArray()[0], 0); |
|||
} |
|||
|
|||
if (input.Contains(Height) && !input.Contains(Width)) |
|||
{ |
|||
size = new Size(0, value.ToPositiveIntegerArray()[0]); |
|||
} |
|||
|
|||
// Both dimensions supplied.
|
|||
if (input.Contains(Height) && input.Contains(Width)) |
|||
{ |
|||
int[] dimensions = value.ToPositiveIntegerArray(); |
|||
|
|||
// Check the order in which they have been supplied.
|
|||
size = input.IndexOf(Width, StringComparison.Ordinal) < input.IndexOf(Height, StringComparison.Ordinal) |
|||
? new Size(dimensions[0], dimensions[1]) |
|||
: new Size(dimensions[1], dimensions[0]); |
|||
} |
|||
|
|||
// Calculate any ratio driven sizes.
|
|||
if (size.Width == 0 || size.Height == 0) |
|||
{ |
|||
stringBuilder.Clear(); |
|||
foreach (Match match in RatioRegex.Matches(input)) |
|||
{ |
|||
stringBuilder.Append(match.Value); |
|||
} |
|||
|
|||
value = stringBuilder.ToString(); |
|||
|
|||
// Replace 0 width
|
|||
if (size.Width == 0 && size.Height > 0 && input.Contains(WidthRatio) && !input.Contains(HeightRatio)) |
|||
{ |
|||
size.Width = (int)Math.Ceiling(value.ToPositiveFloatArray()[0] * size.Height); |
|||
} |
|||
|
|||
// Replace 0 height
|
|||
if (size.Height == 0 && size.Width > 0 && input.Contains(HeightRatio) && !input.Contains(WidthRatio)) |
|||
{ |
|||
size.Height = (int)Math.Ceiling(value.ToPositiveFloatArray()[0] * size.Width); |
|||
} |
|||
} |
|||
|
|||
return size; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="ResizeMode"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="ResizeMode"/>.
|
|||
/// </returns>
|
|||
private ResizeMode ParseMode(string input) |
|||
{ |
|||
foreach (Match match in ModeRegex.Matches(input)) |
|||
{ |
|||
// Split on =
|
|||
string mode = match.Value.Split('=')[1]; |
|||
|
|||
switch (mode) |
|||
{ |
|||
case "stretch": |
|||
return ResizeMode.Stretch; |
|||
case "crop": |
|||
return ResizeMode.Crop; |
|||
case "max": |
|||
return ResizeMode.Max; |
|||
default: |
|||
return ResizeMode.Pad; |
|||
} |
|||
} |
|||
|
|||
return ResizeMode.Pad; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="AnchorPosition"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="AnchorPosition"/>.
|
|||
/// </returns>
|
|||
private AnchorPosition ParsePosition(string input) |
|||
{ |
|||
foreach (Match match in AnchorRegex.Matches(input)) |
|||
{ |
|||
// Split on =
|
|||
string anchor = match.Value.Split('=')[1]; |
|||
|
|||
switch (anchor) |
|||
{ |
|||
case "top": |
|||
return AnchorPosition.Top; |
|||
case "bottom": |
|||
return AnchorPosition.Bottom; |
|||
case "left": |
|||
return AnchorPosition.Left; |
|||
case "right": |
|||
return AnchorPosition.Right; |
|||
default: |
|||
return AnchorPosition.Center; |
|||
} |
|||
} |
|||
|
|||
return AnchorPosition.Center; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Parses the coordinates.
|
|||
/// </summary>
|
|||
/// <param name="input">The input.</param>
|
|||
/// <returns>The <see cref="float"/> array containing the coordinates</returns>
|
|||
private float[] ParseCoordinates(string input) |
|||
{ |
|||
float[] floats = { }; |
|||
|
|||
foreach (Match match in CenterRegex.Matches(input)) |
|||
{ |
|||
floats = match.Value.ToPositiveFloatArray(); |
|||
} |
|||
|
|||
return floats; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a <see cref="List{T}"/> of sizes to restrict resizing to.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="List{Size}"/> to restrict resizing to.
|
|||
/// </returns>
|
|||
private List<Size> ParseRestrictions(string input) |
|||
{ |
|||
List<Size> sizes = new List<Size>(); |
|||
|
|||
if (!string.IsNullOrWhiteSpace(input)) |
|||
{ |
|||
sizes.AddRange(input.Split(',').Select(this.ParseSize)); |
|||
} |
|||
|
|||
return sizes; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,96 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Rotate.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods to rotate an image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to rotate an image.
|
|||
/// </summary>
|
|||
public class Rotate : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"(rotate|angle)(=|-)[^&|,]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rotate"/> class.
|
|||
/// </summary>
|
|||
public Rotate() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Rotate(); |
|||
} |
|||
|
|||
#region IGraphicsProcessor Members
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder |
|||
{ |
|||
get; |
|||
private set; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
this.Processor.DynamicParameter = CommonParameterParserUtility.ParseAngle(match.Value); |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,173 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="RoundedCorners.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods to add rounded corners to an image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Globalization; |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Imaging; |
|||
using ImageProcessor.Processors; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to add rounded corners to an image.
|
|||
/// </summary>
|
|||
public class RoundedCorners : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"roundedcorners=[^&]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the angle attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex RadiusRegex = new Regex(@"(roundedcorners|radius)(=|-)(\d+)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the top left attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex TopLeftRegex = new Regex(@"tl(=|-)(true|false)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the top right attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex TopRightRegex = new Regex(@"tr(=|-)(true|false)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the bottom left attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex BottomLeftRegex = new Regex(@"bl(=|-)(true|false)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the bottom right attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex BottomRightRegex = new Regex(@"br(=|-)(true|false)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="RoundedCorners"/> class.
|
|||
/// </summary>
|
|||
public RoundedCorners() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.RoundedCorners(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">The query string to search.</param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
|
|||
RoundedCornerLayer roundedCornerLayer = new RoundedCornerLayer( |
|||
this.ParseRadius(queryString), |
|||
this.ParseCorner(TopLeftRegex, queryString), |
|||
this.ParseCorner(TopRightRegex, queryString), |
|||
this.ParseCorner(BottomLeftRegex, queryString), |
|||
this.ParseCorner(BottomRightRegex, queryString)); |
|||
|
|||
this.Processor.DynamicParameter = roundedCornerLayer; |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
|
|||
#region Private Methods
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Int32"/> containing the radius for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Int32"/> containing the radius for the given string.
|
|||
/// </returns>
|
|||
private int ParseRadius(string input) |
|||
{ |
|||
foreach (Match match in RadiusRegex.Matches(input)) |
|||
{ |
|||
// Split on radius-
|
|||
int radius; |
|||
int.TryParse(match.Value.Split(new[] { '=', '-' })[1], NumberStyles.Any, CultureInfo.InvariantCulture, out radius); |
|||
return radius; |
|||
} |
|||
|
|||
// No corners - matches the RoundedCorner default.
|
|||
return 0; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a <see cref="T:System.Boolean"/> either true or false.
|
|||
/// </summary>
|
|||
/// <param name="corner">
|
|||
/// The corner.
|
|||
/// </param>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Boolean"/> true or false.
|
|||
/// </returns>
|
|||
private bool ParseCorner(Regex corner, string input) |
|||
{ |
|||
foreach (Match match in corner.Matches(input)) |
|||
{ |
|||
// Split on corner-
|
|||
bool cornerRound; |
|||
bool.TryParse(match.Value.Split(new[] { '=', '-' })[1], out cornerRound); |
|||
return cornerRound; |
|||
} |
|||
|
|||
// No corners - matches the RoundedCorner default.
|
|||
return true; |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Saturation.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods to change the saturation component of the image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to change the saturation component of the image.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <see href="http://www.bobpowell.net/imagesaturation.htm"/>
|
|||
/// </remarks>
|
|||
public class Saturation : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"saturation=[^&|,]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Saturation"/> class.
|
|||
/// </summary>
|
|||
public Saturation() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Saturation(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">The query string to search.</param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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 = CommonParameterParserUtility.ParseIn100Range(match.Value); |
|||
this.Processor.DynamicParameter = percentage; |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Tint.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Tints an image with the given color.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Tints an image with the given color.
|
|||
/// </summary>
|
|||
public class Tint : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"tint=[^&]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Tint"/> class.
|
|||
/// </summary>
|
|||
public Tint() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Tint(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get { return QueryRegex; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">The query string to search.</param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
this.Processor.DynamicParameter = CommonParameterParserUtility.ParseColor(match.Value); |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,98 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Vignette.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods with which to add a vignette image effect to an image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Drawing; |
|||
using System.Text.RegularExpressions; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods with which to add a vignette image effect to an image.
|
|||
/// </summary>
|
|||
public class Vignette : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"vignette(=true)?[^&]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Vignette"/> class.
|
|||
/// </summary>
|
|||
public Vignette() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Vignette(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
|
|||
Color color = CommonParameterParserUtility.ParseColor(match.Value); |
|||
if (color.Equals(Color.Transparent)) |
|||
{ |
|||
color = Color.Black; |
|||
} |
|||
|
|||
this.Processor.DynamicParameter = color; |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,341 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="Watermark.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// Encapsulates methods to add a watermark text overlay to an image.
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.Processors |
|||
{ |
|||
using System.Drawing; |
|||
using System.Drawing.Text; |
|||
using System.Globalization; |
|||
using System.Linq; |
|||
using System.Text.RegularExpressions; |
|||
|
|||
using ImageProcessor.Imaging; |
|||
using ImageProcessor.Processors; |
|||
using ImageProcessor.Web.Extensions; |
|||
using ImageProcessor.Web.Helpers; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates methods to add a watermark text overlay to an image.
|
|||
/// </summary>
|
|||
public class Watermark : IWebGraphicsProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The regular expression to search strings for.
|
|||
/// </summary>
|
|||
private static readonly Regex QueryRegex = new Regex(@"watermark=[^&]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the text attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex TextRegex = new Regex(@"(watermark=[^text-]|text-)[^/:?#\[\]@!$&'()*%\|,;=&]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the position attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex PositionRegex = new Regex(@"(text)?position(=|-)\d+[-,]\d+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the font size attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex FontSizeRegex = new Regex(@"((font)?)size(=|-)\d{1,3}", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the font style attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex FontStyleRegex = new Regex(@"((font)?)style(=|-)(bold|italic|regular|strikeout|underline)", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the font family attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex FontFamilyRegex = new Regex(@"font(family)?(=|-)[^/:?#\[\]@!$&'()*%\|,;=0-9]+", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the opacity attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex OpacityRegex = new Regex(@"((font)?)opacity(=|-)(?:100|[1-9]?[0-9])", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// The regular expression to search strings for the shadow attribute.
|
|||
/// </summary>
|
|||
private static readonly Regex ShadowRegex = new Regex(@"((text|font|drop)?)shadow(=|-)true", RegexOptions.Compiled); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Watermark"/> class.
|
|||
/// </summary>
|
|||
public Watermark() |
|||
{ |
|||
this.Processor = new ImageProcessor.Processors.Watermark(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the regular expression to search strings for.
|
|||
/// </summary>
|
|||
public Regex RegexPattern |
|||
{ |
|||
get |
|||
{ |
|||
return QueryRegex; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the order in which this processor is to be used in a chain.
|
|||
/// </summary>
|
|||
public int SortOrder { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the associated graphics processor.
|
|||
/// </summary>
|
|||
public IGraphicsProcessor Processor { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// The position in the original string where the first character of the captured substring was found.
|
|||
/// </summary>
|
|||
/// <param name="queryString">
|
|||
/// The query string to search.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The zero-based starting position in the original string where the captured substring was found.
|
|||
/// </returns>
|
|||
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; |
|||
|
|||
TextLayer textLayer = new TextLayer |
|||
{ |
|||
Text = this.ParseText(queryString), |
|||
Position = this.ParsePosition(queryString), |
|||
FontColor = this.ParseColor(queryString), |
|||
FontSize = this.ParseFontSize(queryString), |
|||
FontFamily = this.ParseFontFamily(queryString), |
|||
Style = this.ParseFontStyle(queryString), |
|||
DropShadow = this.ParseDropShadow(queryString) |
|||
}; |
|||
|
|||
textLayer.Opacity = this.ParseOpacity(queryString, textLayer.FontColor); |
|||
|
|||
this.Processor.DynamicParameter = textLayer; |
|||
} |
|||
|
|||
index += 1; |
|||
} |
|||
} |
|||
|
|||
return this.SortOrder; |
|||
} |
|||
|
|||
#region Private Methods
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.String"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.String"/> for the given string.
|
|||
/// </returns>
|
|||
private string ParseText(string input) |
|||
{ |
|||
foreach (Match match in TextRegex.Matches(input)) |
|||
{ |
|||
// split on text-
|
|||
return match.Value.Split(new[] { '=', '-' })[1].Replace("+", " "); |
|||
} |
|||
|
|||
return string.Empty; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Drawing.Point"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Drawing.Point"/>
|
|||
/// </returns>
|
|||
private Point ParsePosition(string input) |
|||
{ |
|||
foreach (Match match in PositionRegex.Matches(input)) |
|||
{ |
|||
int[] position = match.Value.ToPositiveIntegerArray(); |
|||
|
|||
if (position != null) |
|||
{ |
|||
int x = position[0]; |
|||
int y = position[1]; |
|||
|
|||
return new Point(x, y); |
|||
} |
|||
} |
|||
|
|||
return Point.Empty; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Drawing.Color"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Drawing.Color"/>
|
|||
/// </returns>
|
|||
private Color ParseColor(string input) |
|||
{ |
|||
Color textColor = CommonParameterParserUtility.ParseColor(input); |
|||
if (!textColor.Equals(Color.Transparent)) |
|||
{ |
|||
return textColor; |
|||
} |
|||
|
|||
return Color.Black; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Int32"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Int32"/>
|
|||
/// </returns>
|
|||
private int ParseFontSize(string input) |
|||
{ |
|||
foreach (Match match in FontSizeRegex.Matches(input)) |
|||
{ |
|||
// split on size-value
|
|||
return int.Parse(match.Value.Split(new[] { '=', '-' })[1], CultureInfo.InvariantCulture); |
|||
} |
|||
|
|||
// Matches the default number in TextLayer.
|
|||
return 48; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Drawing.FontStyle"/> for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The string containing the respective font style.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Drawing.FontStyle"/>
|
|||
/// </returns>
|
|||
private FontStyle ParseFontStyle(string input) |
|||
{ |
|||
FontStyle fontStyle = FontStyle.Bold; |
|||
|
|||
foreach (Match match in FontStyleRegex.Matches(input)) |
|||
{ |
|||
// split on style-
|
|||
switch (match.Value.Split(new[] |
|||
{ |
|||
'=', '-' |
|||
})[1]) |
|||
{ |
|||
case "italic": |
|||
fontStyle = FontStyle.Italic; |
|||
break; |
|||
case "regular": |
|||
fontStyle = FontStyle.Regular; |
|||
break; |
|||
case "strikeout": |
|||
fontStyle = FontStyle.Strikeout; |
|||
break; |
|||
case "underline": |
|||
fontStyle = FontStyle.Underline; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return fontStyle; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.String"/> containing the font family for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.String"/> containing the font family for the given string.
|
|||
/// </returns>
|
|||
private FontFamily ParseFontFamily(string input) |
|||
{ |
|||
foreach (Match match in FontFamilyRegex.Matches(input)) |
|||
{ |
|||
// split on font-
|
|||
string font = match.Value.Split(new[] { '=', '-' })[1].Replace("+", " "); |
|||
|
|||
return new FontFamily(font); |
|||
} |
|||
|
|||
return new FontFamily(GenericFontFamilies.SansSerif); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the correct <see cref="T:System.Int32"/> containing the opacity for the given string.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <param name="color">
|
|||
/// The <see cref="T:System.Drawing.Color"/> of the current <see cref="TextLayer"/>.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The correct <see cref="T:System.Int32"/> containing the opacity for the given string.
|
|||
/// </returns>
|
|||
private int ParseOpacity(string input, Color color) |
|||
{ |
|||
if (color.A < 255) |
|||
{ |
|||
return (color.A / 255) * 100; |
|||
} |
|||
|
|||
foreach (Match match in OpacityRegex.Matches(input)) |
|||
{ |
|||
// Split on opacity-
|
|||
return int.Parse(match.Value.Split(new[] { '=', '-' })[1], CultureInfo.InvariantCulture); |
|||
} |
|||
|
|||
// Full opacity - matches the TextLayer default.
|
|||
return 100; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a value indicating whether the watermark is to have a shadow.
|
|||
/// </summary>
|
|||
/// <param name="input">
|
|||
/// The input string containing the value to parse.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The true if the watermark is to have a shadow; otherwise false.
|
|||
/// </returns>
|
|||
private bool ParseDropShadow(string input) |
|||
{ |
|||
return ShadowRegex.Matches(input).Cast<Match>().Any(); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue