Browse Source

Merge branch 'pr/15' into dev

Former-commit-id: 41a710f1d30868606b3c81a90a5b2b0e0a499316
af/merge-core
James South 13 years ago
parent
commit
cd6f7a976f
  1. 1
      README.md
  2. 56
      src/ImageProcessor.Tests/RegularExpressionUnitTests.cs
  3. 2
      src/ImageProcessor/ImageProcessor.csproj
  4. 88
      src/ImageProcessor/Processors/Constrain.cs
  5. 108
      src/ImageProcessor/Processors/Resize.cs
  6. 104
      src/ImageProcessor/Processors/ResizeBase.cs

1
README.md

@ -18,6 +18,7 @@ Core plugins at present include:
- Reset (Resets the image to its original loaded state)
- Resize
- Rotate (Rotate the image through 360º)
- RoundedCorners (Add rounded corners to each optional corner)
- Saturation
- Vignette (Adds a vignette effect to images)
- Watermark (Set a text watermark)

56
src/ImageProcessor.Tests/RegularExpressionUnitTests.cs

@ -56,24 +56,44 @@ namespace ImageProcessor.Tests
Assert.AreEqual(Expected, actual);
}
/// <summary>
/// The contrast regex unit test.
/// </summary>
[TestMethod]
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>
/// <summary>
/// The contrast regex unit test.
/// </summary>
[TestMethod]
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 constrain regex unit test.
/// </summary>
[TestMethod]
public void TestConstrainRegex()
{
const string Querystring = "constrain=100,200";
const int ExpectedWidth = 100;
const int ExpectedHeight = 200;
Constrain contrast = new Constrain();
contrast.MatchRegexIndex(Querystring);
int actualWidth = contrast.DynamicParameter.Width;
int actualHeight = contrast.DynamicParameter.Height;
Assert.AreEqual(ExpectedWidth, actualWidth);
Assert.AreEqual(ExpectedHeight, actualHeight);
}
/// <summary>
/// The rotate regex unit test.
/// </summary>
[TestMethod]

2
src/ImageProcessor/ImageProcessor.csproj

@ -81,7 +81,9 @@
<Compile Include="Imaging\TextLayer.cs" />
<Compile Include="Processors\Alpha.cs" />
<Compile Include="Processors\Brightness.cs" />
<Compile Include="Processors\Constrain.cs" />
<Compile Include="Processors\Contrast.cs" />
<Compile Include="Processors\ResizeBase.cs" />
<Compile Include="Processors\RoundedCorners.cs" />
<Compile Include="Processors\Saturate.cs" />
<Compile Include="Processors\Flip.cs" />

88
src/ImageProcessor/Processors/Constrain.cs

@ -0,0 +1,88 @@
using System.Collections.Generic;
using System.Drawing;
using System.Text.RegularExpressions;
using ImageProcessor.Helpers.Extensions;
namespace ImageProcessor.Processors
{
/// <summary>
/// Constrains an image to the given dimensions.
/// </summary>
public class Constrain : ResizeBase
{
private static readonly Regex QueryRegex = new Regex(@"constrain=\d+,\d+", RegexOptions.Compiled);
public override Regex RegexPattern
{
get
{
return QueryRegex;
}
}
public override dynamic DynamicParameter { get; set; }
public override int SortOrder { get; protected set; }
public override Dictionary<string, string> Settings { get; set; }
public override 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[] constraints = match.Value.ToPositiveIntegerArray();
int x = constraints[0];
int y = constraints[1];
this.DynamicParameter = new Size(x, y);
}
index += 1;
}
}
return this.SortOrder;
}
public override Image ProcessImage(ImageFactory factory)
{
double constrainedWidth = DynamicParameter.Width;
double constrainedHeight = DynamicParameter.Height;
var original = factory.Image;
double width = original.Width;
double height = original.Height;
if (width > constrainedWidth || height > constrainedHeight)
{
double constraintRatio = constrainedHeight / constrainedWidth;
double originalRatio = height / width;
Size newSize = originalRatio < constraintRatio
? new Size((int)constrainedWidth, 0)
: new Size(0, (int)constrainedHeight);
int defaultMaxWidth;
int defaultMaxHeight;
int.TryParse(this.Settings["MaxWidth"], out defaultMaxWidth);
int.TryParse(this.Settings["MaxHeight"], out defaultMaxHeight);
return ResizeImage(factory, newSize.Width, newSize.Height, defaultMaxWidth, defaultMaxHeight);
}
return factory.Image;
}
}
}

108
src/ImageProcessor/Processors/Resize.cs

@ -20,7 +20,7 @@ namespace ImageProcessor.Processors
/// <summary>
/// Resizes an image to the given dimensions.
/// </summary>
public class Resize : IGraphicsProcessor
public class Resize : ResizeBase
{
/// <summary>
/// The regular expression to search strings for.
@ -31,7 +31,7 @@ namespace ImageProcessor.Processors
/// <summary>
/// Gets the regular expression to search strings for.
/// </summary>
public Regex RegexPattern
public override Regex RegexPattern
{
get
{
@ -42,7 +42,7 @@ namespace ImageProcessor.Processors
/// <summary>
/// Gets or sets DynamicParameter.
/// </summary>
public dynamic DynamicParameter
public override dynamic DynamicParameter
{
get;
set;
@ -51,16 +51,16 @@ namespace ImageProcessor.Processors
/// <summary>
/// Gets the order in which this processor is to be used in a chain.
/// </summary>
public int SortOrder
public override int SortOrder
{
get;
private set;
protected set;
}
/// <summary>
/// Gets or sets any additional settings required by the processor.
/// </summary>
public Dictionary<string, string> Settings
public override Dictionary<string, string> Settings
{
get;
set;
@ -75,7 +75,7 @@ namespace ImageProcessor.Processors
/// <returns>
/// The zero-based starting position in the original string where the captured substring was found.
/// </returns>
public int MatchRegexIndex(string queryString)
public override int MatchRegexIndex(string queryString)
{
int index = 0;
@ -121,96 +121,20 @@ namespace ImageProcessor.Processors
/// <returns>
/// The processed image from the current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
public Image ProcessImage(ImageFactory factory)
public override Image ProcessImage(ImageFactory factory)
{
Bitmap newImage = null;
Image image = factory.Image;
try
{
int width = this.DynamicParameter.Width ?? 0;
int height = this.DynamicParameter.Height ?? 0;
int sourceWidth = image.Width;
int sourceHeight = image.Height;
int defaultMaxWidth;
int defaultMaxHeight;
int.TryParse(this.Settings["MaxWidth"], out defaultMaxWidth);
int.TryParse(this.Settings["MaxHeight"], out defaultMaxHeight);
int maxWidth = defaultMaxWidth > 0 ? defaultMaxWidth : int.MaxValue;
int maxHeight = defaultMaxHeight > 0 ? defaultMaxHeight : int.MaxValue;
// If height or width is not passed we assume that the standard ratio is to be kept.
if (height == 0)
{
// Bit of simple fractional maths here.
float percentWidth = Math.Abs(width / (float)sourceWidth);
height = (int)Math.Floor(sourceHeight * percentWidth);
}
if (width == 0)
{
float percentHeight = Math.Abs(height / (float)sourceHeight);
width = (int)Math.Floor(sourceWidth * percentHeight);
}
if (width > 0 && height > 0 && width <= maxWidth && height <= maxHeight)
{
// Dont use an object initializer here.
newImage = new Bitmap(width, height, PixelFormat.Format32bppPArgb);
newImage.Tag = image.Tag;
using (Graphics graphics = Graphics.FromImage(newImage))
{
// We want to use two different blending algorithms for enlargement/shrinking.
// Bicubic is better enlarging for whilst Bilinear is better for shrinking.
// http://www.codinghorror.com/blog/2007/07/better-image-resizing.html
if (image.Width < width && image.Height < height)
{
// We are making it larger.
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
}
else
{
// We are making it smaller.
graphics.SmoothingMode = SmoothingMode.None;
// Contrary to everything I have read bicubic is producing the best results.
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.None;
graphics.CompositingQuality = CompositingQuality.HighSpeed;
}
// An unwanted border appears when using InterpolationMode.HighQualityBicubic to resize the image
// as the algorithm appears to be pulling averaging detail from surFlooring pixels beyond the edge
// of the image. Using the ImageAttributes class to specify that the pixels beyond are simply mirror
// images of the pixels within solves this problem.
using (ImageAttributes wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
Rectangle destRect = new Rectangle(0, 0, width, height);
graphics.DrawImage(image, destRect, 0, 0, sourceWidth, sourceHeight, GraphicsUnit.Pixel, wrapMode);
}
int width = this.DynamicParameter.Width ?? 0;
int height = this.DynamicParameter.Height ?? 0;
// Reassign the image.
image.Dispose();
image = newImage;
}
}
}
catch
{
if (newImage != null)
{
newImage.Dispose();
}
}
int defaultMaxWidth;
int defaultMaxHeight;
int.TryParse(this.Settings["MaxWidth"], out defaultMaxWidth);
int.TryParse(this.Settings["MaxHeight"], out defaultMaxHeight);
return image;
return ResizeImage(factory, width, height, defaultMaxWidth, defaultMaxHeight);
}
#endregion
#endregion
}
}

104
src/ImageProcessor/Processors/ResizeBase.cs

@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Text.RegularExpressions;
namespace ImageProcessor.Processors
{
public abstract class ResizeBase : IGraphicsProcessor
{
public abstract Regex RegexPattern { get; }
public abstract dynamic DynamicParameter { get; set; }
public abstract int SortOrder { get; protected set; }
public abstract Dictionary<string, string> Settings { get; set; }
public abstract int MatchRegexIndex(string queryString);
public abstract Image ProcessImage(ImageFactory factory);
protected Image ResizeImage(ImageFactory factory, int width, int height, int defaultMaxWidth, int defaultMaxHeight)
{
Bitmap newImage = null;
Image image = factory.Image;
try
{
int sourceWidth = image.Width;
int sourceHeight = image.Height;
int maxWidth = defaultMaxWidth > 0 ? defaultMaxWidth : int.MaxValue;
int maxHeight = defaultMaxHeight > 0 ? defaultMaxHeight : int.MaxValue;
// If height or width is not passed we assume that the standard ratio is to be kept.
if (height == 0)
{
// Bit of simple fractional maths here.
float percentWidth = Math.Abs(width/(float) sourceWidth);
height = (int) Math.Floor(sourceHeight*percentWidth);
}
if (width == 0)
{
float percentHeight = Math.Abs(height/(float) sourceHeight);
width = (int) Math.Floor(sourceWidth*percentHeight);
}
if (width > 0 && height > 0 && width <= maxWidth && height <= maxHeight)
{
// Dont use an object initializer here.
newImage = new Bitmap(width, height, PixelFormat.Format32bppPArgb);
newImage.Tag = image.Tag;
using (Graphics graphics = Graphics.FromImage(newImage))
{
// We want to use two different blending algorithms for enlargement/shrinking.
// Bicubic is better enlarging for whilst Bilinear is better for shrinking.
// http://www.codinghorror.com/blog/2007/07/better-image-resizing.html
if (image.Width < width && image.Height < height)
{
// We are making it larger.
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
}
else
{
// We are making it smaller.
graphics.SmoothingMode = SmoothingMode.None;
// Contrary to everything I have read bicubic is producing the best results.
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.None;
graphics.CompositingQuality = CompositingQuality.HighSpeed;
}
// An unwanted border appears when using InterpolationMode.HighQualityBicubic to resize the image
// as the algorithm appears to be pulling averaging detail from surFlooring pixels beyond the edge
// of the image. Using the ImageAttributes class to specify that the pixels beyond are simply mirror
// images of the pixels within solves this problem.
using (ImageAttributes wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
Rectangle destRect = new Rectangle(0, 0, width, height);
graphics.DrawImage(image, destRect, 0, 0, sourceWidth, sourceHeight, GraphicsUnit.Pixel, wrapMode);
}
// Reassign the image.
image.Dispose();
image = newImage;
}
}
}
catch
{
if (newImage != null)
{
newImage.Dispose();
}
}
return image;
}
}
}
Loading…
Cancel
Save