Browse Source

Adding new resize modes and config files

Former-commit-id: 960fa630e2c2ccd72aff1ad4b96d576299e4f482
af/merge-core
James South 13 years ago
parent
commit
faf6fdc6bf
  1. 1
      src/ImageProcessor.sln
  2. 27
      src/ImageProcessor/ImageFactory.cs
  3. 1
      src/ImageProcessor/ImageProcessor.csproj
  4. 43
      src/ImageProcessor/Imaging/AnchorPosition.cs
  5. 61
      src/ImageProcessor/Imaging/ResizeLayer.cs
  6. 12
      src/ImageProcessor/Imaging/ResizeMode.cs
  7. 2
      src/ImageProcessor/Processors/Constrain.cs
  8. 71
      src/ImageProcessor/Processors/Resize.cs
  9. 65
      src/ImageProcessor/Processors/ResizeBase.cs
  10. 9
      src/TestWebsites/NET45/Test_Website_NET45/Test_Website_NET45.csproj
  11. 13
      src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Index.cshtml
  12. 34
      src/TestWebsites/NET45/Test_Website_NET45/Web.config
  13. 3
      src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/cache.config
  14. 18
      src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config
  15. 8
      src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/security.config

1
src/ImageProcessor.sln

@ -78,7 +78,6 @@ Global
{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Debug|x86.ActiveCfg = Debug|Any CPU
{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Release|Any CPU.Build.0 = Release|Any CPU

27
src/ImageProcessor/ImageFactory.cs

@ -500,7 +500,32 @@ namespace ImageProcessor
var resizeSettings = new Dictionary<string, string> { { "MaxWidth", width.ToString("G") }, { "MaxHeight", height.ToString("G") } };
Resize resize = new Resize { DynamicParameter = new Size(width, height), Settings = resizeSettings };
ResizeLayer resizeLayer = new ResizeLayer(new Size(width, height));
Resize resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings };
this.Image = resize.ProcessImage(this);
}
return this;
}
/// <summary>
/// Resizes the current image to the given dimensions.
/// </summary>
/// <param name="resizeLayer">
/// The <see cref="ResizeLayer"/> containing the properties required to resize the image.
/// </param>
/// <returns>
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
public ImageFactory Resize(ResizeLayer resizeLayer)
{
if (this.ShouldProcess)
{
var resizeSettings = new Dictionary<string, string> { { "MaxWidth", resizeLayer.Size.Width.ToString("G") }, { "MaxHeight", resizeLayer.Size.Height.ToString("G") } };
Resize resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings };
this.Image = resize.ProcessImage(this);
}

1
src/ImageProcessor/ImageProcessor.csproj

@ -61,6 +61,7 @@
<Compile Include="Helpers\Extensions\EnumExtensions.cs" />
<Compile Include="Helpers\Extensions\StringExtensions.cs" />
<Compile Include="ImageFactory.cs" />
<Compile Include="Imaging\AnchorPosition.cs" />
<Compile Include="Imaging\ColorQuantizer.cs" />
<Compile Include="Imaging\ResizeLayer.cs" />
<Compile Include="Imaging\Filters\BlackWhiteMatrixFilter.cs" />

43
src/ImageProcessor/Imaging/AnchorPosition.cs

@ -0,0 +1,43 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AnchorPosition.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Enumerated anchor positions to apply to resized images.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging
{
/// <summary>
/// Enumerated anchor positions to apply to resized images.
/// </summary>
public enum AnchorPosition
{
/// <summary>
/// Anchors the position of the image to the top of it's bounding container.
/// </summary>
Top,
/// <summary>
/// Anchors the position of the image to the center of it's bounding container.
/// </summary>
Center,
/// <summary>
/// Anchors the position of the image to the bottom of it's bounding container.
/// </summary>
Bottom,
/// <summary>
/// Anchors the position of the image to the left of it's bounding container.
/// </summary>
Left,
/// <summary>
/// Anchors the position of the image to the right of it's bounding container.
/// </summary>
Right
}
}

61
src/ImageProcessor/Imaging/ResizeLayer.cs

@ -23,38 +23,69 @@ namespace ImageProcessor.Imaging
/// <summary>
/// Initializes a new instance of the <see cref="ResizeLayer"/> class.
/// </summary>
public ResizeLayer()
/// <param name="size">
/// The <see cref="T:System.Drawing.Size"/> containing the width and height to set the image to.
/// </param>
public ResizeLayer(Size size)
{
this.Size = size;
this.ResizeMode = ResizeMode.Pad;
this.AnchorPosition = AnchorPosition.Center;
this.BackgroundColor = Color.Transparent;
}
/// <summary>
/// Initializes a new instance of the <see cref="ResizeLayer"/> class.
/// </summary>
/// <param name="size">
/// The <see cref="T:System.Drawing.Size"/> containing the width and height to set the image to.
/// </param>
/// <param name="resizeMode">
/// The resize mode to apply to resized image.
/// The <see cref="ResizeMode"/> to apply to resized image.
/// </param>
public ResizeLayer(ResizeMode resizeMode)
public ResizeLayer(Size size, ResizeMode resizeMode)
{
this.Size = size;
this.ResizeMode = resizeMode;
this.AnchorPosition = AnchorPosition.Center;
this.BackgroundColor = Color.Transparent;
}
/// <summary>
/// Initializes a new instance of the <see cref="ResizeLayer"/> class.
/// </summary>
/// <param name="resizeMode">
/// The resize mode to apply to resized image.
/// <param name="size">
/// The <see cref="T:System.Drawing.Size"/> containing the width and height to set the image to.
/// </param>
/// <param name="anchorPosition">
/// The <see cref="AnchorPosition"/> to apply to resized image.
/// </param>
public ResizeLayer(Size size, AnchorPosition anchorPosition)
{
this.Size = size;
this.AnchorPosition = anchorPosition;
this.ResizeMode = ResizeMode.Pad;
this.BackgroundColor = Color.Transparent;
}
/// <summary>
/// Initializes a new instance of the <see cref="ResizeLayer"/> class.
/// </summary>
/// <param name="backgroundColor">
/// The <see cref="T:System.Drawing.Color"/> to set as the background color.
/// <remarks>Used for image formats that do not support transparency</remarks>
/// </param>
public ResizeLayer(ResizeMode resizeMode, Color backgroundColor)
/// <param name="resizeMode">
/// The resize mode to apply to resized image.
/// </param>
/// <param name="anchorPosition">
/// The <see cref="AnchorPosition"/> to apply to resized image.
/// </param>
public ResizeLayer(Color backgroundColor, ResizeMode resizeMode = ResizeMode.Pad, AnchorPosition anchorPosition = AnchorPosition.Center)
{
this.ResizeMode = resizeMode;
this.BackgroundColor = backgroundColor;
this.ResizeMode = resizeMode;
this.AnchorPosition = anchorPosition;
}
#endregion
@ -65,14 +96,19 @@ namespace ImageProcessor.Imaging
public Size Size { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to ResizeMode the layer.
/// Gets or sets the background color.
/// </summary>
public Color BackgroundColor { get; set; }
/// <summary>
/// Gets or sets the resize mode.
/// </summary>
public ResizeMode ResizeMode { get; set; }
/// <summary>
/// Gets or sets the background color.
/// Gets or sets the anchor position.
/// </summary>
public Color BackgroundColor { get; set; }
public AnchorPosition AnchorPosition { get; set; }
#endregion
/// <summary>
@ -96,8 +132,9 @@ namespace ImageProcessor.Imaging
return false;
}
return this.Size == resizeLayer.Size
return this.Size == resizeLayer.Size
&& this.ResizeMode == resizeLayer.ResizeMode
&& this.AnchorPosition == resizeLayer.AnchorPosition
&& this.BackgroundColor == resizeLayer.BackgroundColor;
}
@ -109,7 +146,7 @@ namespace ImageProcessor.Imaging
/// </returns>
public override int GetHashCode()
{
return this.Size.GetHashCode() + this.ResizeMode.GetHashCode() + this.BackgroundColor.GetHashCode();
return this.Size.GetHashCode() + this.ResizeMode.GetHashCode() + this.AnchorPosition.GetHashCode() + this.BackgroundColor.GetHashCode();
}
}
}

12
src/ImageProcessor/Imaging/ResizeMode.cs

@ -23,6 +23,16 @@ namespace ImageProcessor.Imaging
/// <summary>
/// Stretches the resized image to fit the bounds of its container.
/// </summary>
Stretch
Stretch,
/// <summary>
/// Crops the resized image to fit the bounds of its container.
/// </summary>
Crop,
/// <summary>
/// Constrains the resized image to fit the bounds of its container.
/// </summary>
Constrain
}
}

2
src/ImageProcessor/Processors/Constrain.cs

@ -128,7 +128,7 @@ namespace ImageProcessor.Processors
int.TryParse(this.Settings["MaxWidth"], out defaultMaxWidth);
int.TryParse(this.Settings["MaxHeight"], out defaultMaxHeight);
return this.ResizeImage(factory, newSize.Width, newSize.Height, defaultMaxWidth, defaultMaxHeight, ResizeMode.Pad, Color.Transparent);
return this.ResizeImage(factory, newSize.Width, newSize.Height, defaultMaxWidth, defaultMaxHeight, Color.Transparent);
}
return factory.Image;

71
src/ImageProcessor/Processors/Resize.cs

@ -30,17 +30,22 @@ namespace ImageProcessor.Processors
/// <summary>
/// The regular expression to search strings for.
/// </summary>
private static readonly Regex QueryRegex = new Regex(@"((width|height)=\d+)|(mode=(pad|stretch|crop))|(bgcolor=([0-9a-fA-F]{3}){1,2})", RegexOptions.Compiled);
private static readonly Regex QueryRegex = new Regex(@"((width|height)=\d+)|(mode=(pad|stretch|crop|constrain))|(anchor=(top|bottom|left|right|center))|(bgcolor=([0-9a-fA-F]{3}){1,2})", RegexOptions.Compiled);
/// <summary>
/// The regular expression to search strings for the size attribute.
/// </summary>
private static readonly Regex SizeRegex = new Regex(@"(width|height)=\d+");
private static readonly Regex SizeRegex = new Regex(@"(width|height)=\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)");
private static readonly Regex ModeRegex = new Regex(@"mode=(pad|stretch|crop|constrain)", 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 color attribute.
@ -101,7 +106,6 @@ namespace ImageProcessor.Processors
// Set the sort order to max to allow filtering.
this.SortOrder = int.MaxValue;
ResizeLayer resizeLayer = new ResizeLayer();
// First merge the matches so we can parse .
StringBuilder stringBuilder = new StringBuilder();
@ -125,9 +129,13 @@ namespace ImageProcessor.Processors
// Match syntax
string toParse = stringBuilder.ToString();
resizeLayer.Size = this.ParseSize(toParse);
resizeLayer.ResizeMode = this.ParseMode(toParse);
resizeLayer.BackgroundColor = this.ParseColor(toParse);
Size size = this.ParseSize(toParse);
ResizeLayer resizeLayer = new ResizeLayer(size)
{
ResizeMode = this.ParseMode(toParse),
AnchorPosition = this.ParsePosition(toParse),
BackgroundColor = this.ParseColor(toParse)
};
this.DynamicParameter = resizeLayer;
return this.SortOrder;
@ -148,6 +156,7 @@ namespace ImageProcessor.Processors
int width = this.DynamicParameter.Size.Width ?? 0;
int height = this.DynamicParameter.Size.Height ?? 0;
ResizeMode mode = this.DynamicParameter.ResizeMode;
AnchorPosition anchor = this.DynamicParameter.AnchorPosition;
Color backgroundColor = this.DynamicParameter.BackgroundColor;
int defaultMaxWidth;
@ -155,7 +164,15 @@ namespace ImageProcessor.Processors
int.TryParse(this.Settings["MaxWidth"], out defaultMaxWidth);
int.TryParse(this.Settings["MaxHeight"], out defaultMaxHeight);
return this.ResizeImage(factory, width, height, defaultMaxWidth, defaultMaxHeight, mode, backgroundColor);
if (mode == ResizeMode.Constrain)
{
// Just use the old constrain plugin to handle the resize.
var constrainSettings = new Dictionary<string, string> { { "MaxWidth", defaultMaxWidth.ToString("G") }, { "MaxHeight", defaultMaxHeight.ToString("G") } };
Constrain constrain = new Constrain { DynamicParameter = new Size(width, height), Settings = constrainSettings };
return constrain.ProcessImage(factory);
}
return this.ResizeImage(factory, width, height, defaultMaxWidth, defaultMaxHeight, backgroundColor, mode, anchor);
}
#endregion
@ -228,6 +245,10 @@ namespace ImageProcessor.Processors
{
case "stretch":
return ResizeMode.Stretch;
case "crop":
return ResizeMode.Crop;
case "constrain":
return ResizeMode.Constrain;
default:
return ResizeMode.Pad;
}
@ -236,6 +257,40 @@ namespace ImageProcessor.Processors
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>
/// Returns the correct <see cref="T:System.Drawing.Color"/> for the given string.
/// </summary>

65
src/ImageProcessor/Processors/ResizeBase.cs

@ -90,16 +90,27 @@ namespace ImageProcessor.Processors
/// <param name="defaultMaxHeight">
/// The default max height to resize the image to.
/// </param>
/// <param name="resizeMode">
/// Whether to pad the image to fill the set size.
/// </param>
/// <param name="backgroundColor">
/// The background color to pad the image with.
/// </param>
/// <param name="resizeMode">
/// The mode with which to resize the image.
/// </param>
/// <param name="anchorPosition">
/// The anchor position to place the image at.
/// </param>
/// <returns>
/// The processed image from the current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
protected Image ResizeImage(ImageFactory factory, int width, int height, int defaultMaxWidth, int defaultMaxHeight, ResizeMode resizeMode, Color backgroundColor)
protected Image ResizeImage(
ImageFactory factory,
int width,
int height,
int defaultMaxWidth,
int defaultMaxHeight,
Color backgroundColor,
ResizeMode resizeMode = ResizeMode.Pad,
AnchorPosition anchorPosition = AnchorPosition.Center)
{
Bitmap newImage = null;
Image image = factory.Image;
@ -142,6 +153,52 @@ namespace ImageProcessor.Processors
}
}
// Change the destination rectangle coordinates if cropping and
// there has been a set width and height.
if (resizeMode == ResizeMode.Crop && width > 0 && height > 0)
{
double ratio;
if (percentHeight < percentWidth)
{
ratio = percentWidth;
switch (anchorPosition)
{
case AnchorPosition.Top:
destinationY = 0;
break;
case AnchorPosition.Bottom:
destinationY = (int)(height - (sourceHeight * ratio));
break;
default:
destinationY = (int)((height - (sourceHeight * ratio)) / 2);
break;
}
destinationHeight = (int)Math.Floor(sourceHeight * percentWidth);
}
else
{
ratio = percentHeight;
switch (anchorPosition)
{
case AnchorPosition.Left:
destinationX = 0;
break;
case AnchorPosition.Right:
destinationX = (int)(width - (sourceWidth * ratio));
break;
default:
destinationX = (int)((width - (sourceWidth * ratio)) / 2);
break;
}
destinationWidth = (int)Math.Floor(sourceWidth * percentHeight);
}
}
// If height or width is not passed we assume that the standard ratio is to be kept.
if (height == 0)
{

9
src/TestWebsites/NET45/Test_Website_NET45/Test_Website_NET45.csproj

@ -188,6 +188,15 @@
<Name>ImageProcessor</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="config\imageprocessor\cache.config" />
</ItemGroup>
<ItemGroup>
<Content Include="config\imageprocessor\processing.config" />
</ItemGroup>
<ItemGroup>
<Content Include="config\imageprocessor\security.config" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>

13
src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Index.cshtml

@ -19,7 +19,7 @@
</section>
<section>
<div class="row">
<h2>Padded</h2>
<h2>Reside Pad</h2>
<div class="column-4">
<img src="/images/Penguins.jpg?width=300&height=500" />
</div>
@ -28,6 +28,17 @@
</div>
</div>
</section>
<section>
<div class="row">
<h2>Resize Crop</h2>
<div class="column-4">
<img src="/images/Penguins.jpg?width=300&height=500&mode=crop" />
</div>
<div class="column-8">
<img src="/images/udendørs.jpg?width=600&height=250&mode=crop" />
</div>
</div>
</section>
<section>
<h2>Filter</h2>
<div class="row">

34
src/TestWebsites/NET45/Test_Website_NET45/Web.config

@ -12,7 +12,11 @@
<section name="cache" requirePermission="false" type="ImageProcessor.Web.Config.ImageCacheSection, ImageProcessor.Web"/>
</sectionGroup>
</configSections>
<imageProcessor >
<security configSource="config\imageprocessor\security.config"/>
<cache configSource="config\imageprocessor\cache.config"/>
<processing configSource="config\imageprocessor\processing.config"/>
</imageProcessor>
<appSettings>
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
@ -59,33 +63,5 @@
<modules>
<add name="ImageProcessorModule" type="ImageProcessor.Web.HttpModules.ImageProcessingModule, ImageProcessor.Web"/>
</modules>
</system.webServer>
<imageProcessor>
<security allowRemoteDownloads="true" timeout="300000" maxBytes="524288" remotePrefix="/remote.axd">
<whiteList>
<add url="http://images.mymovies.net"/>
<add url="http://www.theworldeffect.com" />
<add url="http://maps.googleapis.com" extensionLess="true" imageFormat="png"/>
</whiteList>
</security>
<cache virtualPath="~/app_data/cache" maxDays="56"/>
<processing>
<plugins>
<plugin name="Resize">
<settings>
<setting key="MaxWidth" value="3000"/>
<setting key="MaxHeight" value="3000"/>
</settings>
</plugin>
<plugin name="Constrain">
<settings>
<setting key="MaxWidth" value="3000"/>
<setting key="MaxHeight" value="3000"/>
</settings>
</plugin>
</plugins>
</processing>
</imageProcessor>
</configuration>

3
src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/cache.config

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8" ?>
<cache virtualPath="~/app_data/cache" maxDays="56"/>

18
src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<processing>
<plugins>
<plugin name="Resize">
<settings>
<setting key="MaxWidth" value="3000"/>
<setting key="MaxHeight" value="3000"/>
</settings>
</plugin>
<plugin name="Constrain">
<settings>
<setting key="MaxWidth" value="3000"/>
<setting key="MaxHeight" value="3000"/>
</settings>
</plugin>
</plugins>
</processing>

8
src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/security.config

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<security allowRemoteDownloads="true" timeout="300000" maxBytes="524288" remotePrefix="/remote.axd">
<whiteList>
<add url="http://images.mymovies.net"/>
<add url="http://www.theworldeffect.com" />
<add url="http://maps.googleapis.com" extensionLess="true" imageFormat="png"/>
</whiteList>
</security>
Loading…
Cancel
Save