diff --git a/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs b/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs
index 8d050226a..1243bd327 100644
--- a/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs
+++ b/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs
@@ -60,7 +60,7 @@ namespace ImageProcessor.Web
// Loop through and process the image.
foreach (IGraphicsProcessor graphicsProcessor in graphicsProcessors)
{
- ProcessImage(graphicsProcessor.ProcessImage, factory);
+ ApplyProcessor(graphicsProcessor.ProcessImage, factory);
}
}
}
@@ -77,13 +77,16 @@ namespace ImageProcessor.Web
///
/// The factory.
///
- private static void ProcessImage(Func processor, ImageFactory factory)
+ private static void ApplyProcessor(Func 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))
{
@@ -96,7 +99,7 @@ namespace ImageProcessor.Web
}
stream.Position = 0;
- factory.Update(new Bitmap(stream));
+ factory.Update(Image.FromStream(stream));
}
else
{
diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs
index 002093e61..3875ce72c 100644
--- a/src/ImageProcessor/ImageFactory.cs
+++ b/src/ImageProcessor/ImageFactory.cs
@@ -22,6 +22,7 @@ namespace ImageProcessor
using ImageProcessor.Extensions;
using ImageProcessor.Imaging;
+ using ImageProcessor.Imaging.Filters;
using ImageProcessor.Processors;
#endregion
@@ -298,8 +299,7 @@ namespace ImageProcessor
}
Alpha alpha = new Alpha { DynamicParameter = percentage };
-
- this.Image = alpha.ProcessImage(this);
+ this.ApplyProcessor(alpha.ProcessImage);
}
return this;
@@ -326,8 +326,7 @@ namespace ImageProcessor
}
Brightness brightness = new Brightness { DynamicParameter = percentage };
-
- this.Image = brightness.ProcessImage(this);
+ this.ApplyProcessor(brightness.ProcessImage);
}
return this;
@@ -375,8 +374,7 @@ namespace ImageProcessor
}
Contrast contrast = new Contrast { DynamicParameter = percentage };
-
- this.Image = contrast.ProcessImage(this);
+ this.ApplyProcessor(contrast.ProcessImage);
}
return this;
@@ -396,10 +394,7 @@ namespace ImageProcessor
if (this.ShouldProcess)
{
CropLayer cropLayer = new CropLayer(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom, CropMode.Pixels);
-
- Crop crop = new Crop { DynamicParameter = cropLayer };
-
- this.Image = crop.ProcessImage(this);
+ return this.Crop(cropLayer);
}
return this;
@@ -419,13 +414,12 @@ namespace ImageProcessor
if (this.ShouldProcess)
{
Crop crop = new Crop { DynamicParameter = cropLayer };
-
- this.Image = crop.ProcessImage(this);
+ this.ApplyProcessor(crop.ProcessImage);
}
return this;
}
-
+
///
/// Applies a filter to the current image.
///
@@ -435,13 +429,34 @@ namespace ImageProcessor
///
/// The current instance of the class.
///
+ [Obsolete("Will be removed in next major version. Filter(IMatrixFilter matrixFilter) instead.")]
public ImageFactory Filter(string filterName)
{
if (this.ShouldProcess)
{
Filter filter = new Filter { DynamicParameter = filterName };
+ this.ApplyProcessor(filter.ProcessImage);
+ }
+
+ return this;
+ }
- this.Image = filter.ProcessImage(this);
+ ///
+ /// Applies a filter to the current image. Use the class to
+ /// assign the correct filter.
+ ///
+ ///
+ /// The of the filter to add to the image.
+ ///
+ ///
+ /// The current instance of the class.
+ ///
+ public ImageFactory Filter(IMatrixFilter matrixFilter)
+ {
+ if (this.ShouldProcess)
+ {
+ Filter filter = new Filter { DynamicParameter = matrixFilter };
+ this.ApplyProcessor(filter.ProcessImage);
}
return this;
@@ -465,8 +480,7 @@ namespace ImageProcessor
: RotateFlipType.RotateNoneFlipY;
Flip flip = new Flip { DynamicParameter = rotateFlipType };
-
- this.Image = flip.ProcessImage(this);
+ this.ApplyProcessor(flip.ProcessImage);
}
return this;
@@ -512,8 +526,7 @@ namespace ImageProcessor
if (this.ShouldProcess && size > 0)
{
GaussianLayer layer = new GaussianLayer(size);
- GaussianBlur gaussianBlur = new GaussianBlur { DynamicParameter = layer };
- this.Image = gaussianBlur.ProcessImage(this);
+ return this.GaussianBlur(layer);
}
return this;
@@ -534,7 +547,7 @@ namespace ImageProcessor
if (this.ShouldProcess)
{
GaussianBlur gaussianBlur = new GaussianBlur { DynamicParameter = gaussianLayer };
- this.Image = gaussianBlur.ProcessImage(this);
+ this.ApplyProcessor(gaussianBlur.ProcessImage);
}
return this;
@@ -560,8 +573,7 @@ namespace ImageProcessor
if (this.ShouldProcess && size > 0)
{
GaussianLayer layer = new GaussianLayer(size);
- GaussianSharpen gaussianSharpen = new GaussianSharpen { DynamicParameter = layer };
- this.Image = gaussianSharpen.ProcessImage(this);
+ return this.GaussianSharpen(layer);
}
return this;
@@ -582,7 +594,7 @@ namespace ImageProcessor
if (this.ShouldProcess)
{
GaussianSharpen gaussianSharpen = new GaussianSharpen { DynamicParameter = gaussianLayer };
- this.Image = gaussianSharpen.ProcessImage(this);
+ this.ApplyProcessor(gaussianSharpen.ProcessImage);
}
return this;
@@ -625,7 +637,6 @@ namespace ImageProcessor
int height = size.Height;
ResizeLayer resizeLayer = new ResizeLayer(new Size(width, height));
-
return this.Resize(resizeLayer);
}
@@ -648,8 +659,7 @@ namespace ImageProcessor
var resizeSettings = new Dictionary { { "MaxWidth", resizeLayer.Size.Width.ToString("G") }, { "MaxHeight", resizeLayer.Size.Height.ToString("G") } };
Resize resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings };
-
- this.ProcessImage(resize.ProcessImage, resizeLayer.Size.Width, resizeLayer.Size.Height);
+ this.ApplyProcessor(resize.ProcessImage);
}
return this;
@@ -675,8 +685,7 @@ namespace ImageProcessor
}
Rotate rotate = new Rotate { DynamicParameter = rotateLayer };
-
- this.Image = rotate.ProcessImage(this);
+ this.ApplyProcessor(rotate.ProcessImage);
}
return this;
@@ -701,8 +710,7 @@ namespace ImageProcessor
}
RoundedCorners roundedCorners = new RoundedCorners { DynamicParameter = roundedCornerLayer };
-
- this.Image = roundedCorners.ProcessImage(this);
+ this.ApplyProcessor(roundedCorners.ProcessImage);
}
return this;
@@ -729,8 +737,7 @@ namespace ImageProcessor
}
Saturation saturate = new Saturation { DynamicParameter = percentage };
-
- this.Image = saturate.ProcessImage(this);
+ this.ApplyProcessor(saturate.ProcessImage);
}
return this;
@@ -747,8 +754,7 @@ namespace ImageProcessor
if (this.ShouldProcess)
{
Vignette vignette = new Vignette();
-
- this.Image = vignette.ProcessImage(this);
+ this.ApplyProcessor(vignette.ProcessImage);
}
return this;
@@ -769,8 +775,7 @@ namespace ImageProcessor
if (this.ShouldProcess)
{
Watermark watermark = new Watermark { DynamicParameter = textLayer };
-
- this.Image = watermark.ProcessImage(this);
+ this.ApplyProcessor(watermark.ProcessImage);
}
return this;
@@ -974,26 +979,23 @@ namespace ImageProcessor
}
///
- /// The process image.
+ /// Applies the given processor the current image.
///
///
- /// The processor.
- ///
- ///
- /// The width.
+ /// The processor delegate.
///
- ///
- /// The height.
- ///
- private void ProcessImage(Func processor, int width, int height)
+ private void ApplyProcessor(Func processor)
{
ImageInfo imageInfo = this.Image.GetImageInfo(this.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, width, height, imageInfo.LoopCount))
+ using (GifEncoder encoder = new GifEncoder(stream, null, null, imageInfo.LoopCount))
{
foreach (GifFrame frame in imageInfo.GifFrames)
{
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index f1251eb08..45ad36bc2 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -70,6 +70,8 @@
+
+
diff --git a/src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs b/src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs
index 7d9b4ff1f..c44bce5c8 100644
--- a/src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs
+++ b/src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs
@@ -11,10 +11,6 @@
namespace ImageProcessor.Imaging.Filters
{
#region Using
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using ImageProcessor.Processors;
diff --git a/src/ImageProcessor/Imaging/Filters/MatrixFilterRegexAttribute.cs b/src/ImageProcessor/Imaging/Filters/MatrixFilterRegexAttribute.cs
new file mode 100644
index 000000000..ebd5db379
--- /dev/null
+++ b/src/ImageProcessor/Imaging/Filters/MatrixFilterRegexAttribute.cs
@@ -0,0 +1,37 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// Copyright (c) James South.
+// Licensed under the Apache License, Version 2.0.
+//
+//
+// The filter attribute for identifying matrix filter properties.
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace ImageProcessor.Imaging.Filters
+{
+ using System;
+
+ ///
+ /// The filter attribute for identifying matrix filter properties.
+ ///
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
+ public class MatrixFilterRegexAttribute : Attribute
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The regex identifier.
+ ///
+ public MatrixFilterRegexAttribute(string regexIdentifier)
+ {
+ this.RegexIdentifier = regexIdentifier;
+ }
+
+ ///
+ /// Gets the regex identifier.
+ ///
+ public string RegexIdentifier { get; private set; }
+ }
+}
diff --git a/src/ImageProcessor/Imaging/Filters/MatrixFilters.cs b/src/ImageProcessor/Imaging/Filters/MatrixFilters.cs
new file mode 100644
index 000000000..8159a4c03
--- /dev/null
+++ b/src/ImageProcessor/Imaging/Filters/MatrixFilters.cs
@@ -0,0 +1,140 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// Copyright (c) James South.
+// Licensed under the Apache License, Version 2.0.
+//
+//
+// The filters available to the Filter .
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace ImageProcessor.Imaging.Filters
+{
+ using ImageProcessor.Processors;
+
+ ///
+ /// The filters available to the Filter .
+ ///
+ public static class MatrixFilters
+ {
+ ///
+ /// Gets the black white filter.
+ ///
+ [MatrixFilterRegex("blackwhite")]
+ public static IMatrixFilter BlackWhite
+ {
+ get
+ {
+ return new BlackWhiteMatrixFilter();
+ }
+ }
+
+ ///
+ /// Gets the comic filter.
+ ///
+ [MatrixFilterRegex("comic")]
+ public static IMatrixFilter Comic
+ {
+ get
+ {
+ return new ComicMatrixFilter();
+ }
+ }
+
+ ///
+ /// Gets the gotham filter.
+ ///
+ [MatrixFilterRegex("gotham")]
+ public static IMatrixFilter Gotham
+ {
+ get
+ {
+ return new GothamMatrixFilter();
+ }
+ }
+
+ ///
+ /// Gets the greyscale filter.
+ ///
+ [MatrixFilterRegex("greyscale")]
+ public static IMatrixFilter GreyScale
+ {
+ get
+ {
+ return new GreyScaleMatrixFilter();
+ }
+ }
+
+ ///
+ /// Gets the high saturation filter.
+ ///
+ [MatrixFilterRegex("hisatch")]
+ public static IMatrixFilter HiSatch
+ {
+ get
+ {
+ return new HiSatchMatrixFilter();
+ }
+ }
+
+ ///
+ /// Gets the invert filter.
+ ///
+ [MatrixFilterRegex("invert")]
+ public static IMatrixFilter Invert
+ {
+ get
+ {
+ return new InvertMatrixFilter();
+ }
+ }
+
+ ///
+ /// Gets the lomograph filter.
+ ///
+ [MatrixFilterRegex("lomograph")]
+ public static IMatrixFilter Lomograph
+ {
+ get
+ {
+ return new LomographMatrixFilter();
+ }
+ }
+
+ ///
+ /// Gets the low saturation filter.
+ ///
+ [MatrixFilterRegex("losatch")]
+ public static IMatrixFilter LoSatch
+ {
+ get
+ {
+ return new LomographMatrixFilter();
+ }
+ }
+
+ ///
+ /// Gets the polaroid filter.
+ ///
+ [MatrixFilterRegex("polaroid")]
+ public static IMatrixFilter Polaroid
+ {
+ get
+ {
+ return new PolaroidMatrixFilter();
+ }
+ }
+
+ ///
+ /// Gets the sepia filter.
+ ///
+ [MatrixFilterRegex("sepia")]
+ public static IMatrixFilter Sepia
+ {
+ get
+ {
+ return new SepiaMatrixFilter();
+ }
+ }
+ }
+}
diff --git a/src/ImageProcessor/Imaging/GifEncoder.cs b/src/ImageProcessor/Imaging/GifEncoder.cs
index 09cb1aea9..20a8ba0f0 100644
--- a/src/ImageProcessor/Imaging/GifEncoder.cs
+++ b/src/ImageProcessor/Imaging/GifEncoder.cs
@@ -9,6 +9,7 @@
// Always wire this up in a using block.
// Disposing the encoder will complete the file.
// Uses default .NET GIF encoding and adds animation headers.
+// Adapted from
//
//
// --------------------------------------------------------------------------------------------------------------------
@@ -17,7 +18,6 @@ namespace ImageProcessor.Imaging
{
#region Using
using System;
- using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
@@ -29,6 +29,7 @@ namespace ImageProcessor.Imaging
/// Always wire this up in a using block.
/// Disposing the encoder will complete the file.
/// Uses default .NET GIF encoding and adds animation headers.
+ /// Adapted from
///
///
public class GifEncoder : IDisposable
diff --git a/src/ImageProcessor/Processors/Filter.cs b/src/ImageProcessor/Processors/Filter.cs
index 8f1b8d5b4..2673c7a29 100644
--- a/src/ImageProcessor/Processors/Filter.cs
+++ b/src/ImageProcessor/Processors/Filter.cs
@@ -11,9 +11,13 @@
namespace ImageProcessor.Processors
{
#region Using
+ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
+ using System.Linq;
+ using System.Reflection;
+ using System.Text;
using System.Text.RegularExpressions;
using ImageProcessor.Imaging.Filters;
#endregion
@@ -26,7 +30,7 @@ namespace ImageProcessor.Processors
///
/// The regular expression to search strings for.
///
- private static readonly Regex QueryRegex = new Regex(@"filter=(lomograph|polaroid|blackwhite|sepia|greyscale|gotham|invert|hisatch|losatch|comic)", RegexOptions.Compiled);
+ private static readonly Regex QueryRegex = BuildRegex();
#region IGraphicsProcessor Members
///
@@ -115,45 +119,12 @@ namespace ImageProcessor.Processors
{
Bitmap newImage = null;
Image image = factory.Image;
- IMatrixFilter matrix = null;
try
{
newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb);
- switch ((string)this.DynamicParameter)
- {
- case "polaroid":
- matrix = new PolaroidMatrixFilter();
- break;
- case "lomograph":
- matrix = new LomographMatrixFilter();
- break;
- case "sepia":
- matrix = new SepiaMatrixFilter();
- break;
- case "blackwhite":
- matrix = new BlackWhiteMatrixFilter();
- break;
- case "greyscale":
- matrix = new GreyScaleMatrixFilter();
- break;
- case "gotham":
- matrix = new GothamMatrixFilter();
- break;
- case "invert":
- matrix = new InvertMatrixFilter();
- break;
- case "hisatch":
- matrix = new HiSatchMatrixFilter();
- break;
- case "losatch":
- matrix = new LoSatchMatrixFilter();
- break;
- case "comic":
- matrix = new ComicMatrixFilter();
- break;
- }
+ IMatrixFilter matrix = this.DynamicParameter as IMatrixFilter ?? this.ParseFilter((string)this.DynamicParameter);
if (matrix != null)
{
@@ -171,5 +142,66 @@ namespace ImageProcessor.Processors
return image;
}
#endregion
+
+ ///
+ /// Builds a regular expression from the type, this allows extensibility.
+ ///
+ ///
+ /// The to match matrix filters.
+ ///
+ private static Regex BuildRegex()
+ {
+ const BindingFlags Flags = BindingFlags.Public | BindingFlags.Static;
+ Type type = typeof(MatrixFilters);
+ IEnumerable filters = type.GetProperties(Flags)
+ .Where(p => p.IsDefined(typeof(MatrixFilterRegexAttribute), false))
+ .ToList();
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.Append("filter=(");
+ int counter = 0;
+
+ foreach (PropertyInfo filter in filters)
+ {
+ MatrixFilterRegexAttribute attribute = (MatrixFilterRegexAttribute)filter.GetCustomAttributes(typeof(MatrixFilterRegexAttribute), false).First();
+
+ if (counter == 0)
+ {
+ stringBuilder.Append(attribute.RegexIdentifier);
+ }
+ else
+ {
+ stringBuilder.AppendFormat("|{0}", attribute.RegexIdentifier);
+ }
+
+ counter++;
+ }
+
+ stringBuilder.Append(")");
+
+ return new Regex(stringBuilder.ToString(), RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ }
+
+ ///
+ /// Parses the filter.
+ ///
+ ///
+ /// The identifier.
+ ///
+ ///
+ /// The .
+ ///
+ private IMatrixFilter ParseFilter(string identifier)
+ {
+ const BindingFlags Flags = BindingFlags.Public | BindingFlags.Static;
+
+ Type type = typeof(MatrixFilters);
+ PropertyInfo filter =
+ type.GetProperties(Flags)
+ .Where(p => p.IsDefined(typeof(MatrixFilterRegexAttribute), false))
+ .First(p => ((MatrixFilterRegexAttribute)p.GetCustomAttributes(typeof(MatrixFilterRegexAttribute), false).First()).RegexIdentifier == identifier);
+
+ return filter.GetValue(null, null) as IMatrixFilter;
+ }
}
}
diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs
index 7e71a5b38..7c95ad1ce 100644
--- a/src/ImageProcessorConsole/Program.cs
+++ b/src/ImageProcessorConsole/Program.cs
@@ -11,6 +11,7 @@ namespace ImageProcessorConsole
using System.IO;
using ImageProcessor;
+ using ImageProcessor.Imaging.Filters;
class Program
{
@@ -42,6 +43,7 @@ namespace ImageProcessorConsole
// Load, resize, set the format and quality and save an image.
imageFactory.Load(inStream)
.Constrain(size)
+ .Filter(MatrixFilters.Comic)
.Format(format)
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name)));
}
diff --git a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id
index 71ce555c1..361dec973 100644
--- a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id
+++ b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id
@@ -1 +1 @@
-30ec5c05548fd350f9b7c699715848b9fbfb8ca9
\ No newline at end of file
+7880376ac9108d4e74412efb31f544484079ce16
\ No newline at end of file
diff --git a/src/ImageProcessorConsole/images/output/nLpfllv .gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/nLpfllv .gif.REMOVED.git-id
new file mode 100644
index 000000000..3e0788875
--- /dev/null
+++ b/src/ImageProcessorConsole/images/output/nLpfllv .gif.REMOVED.git-id
@@ -0,0 +1 @@
+673e6c6d9223e0906fe342a17496168b8d9017fb
\ No newline at end of file
diff --git a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id
deleted file mode 100644
index 4487aede0..000000000
--- a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-23a1c81a2d1422076373796e0c47f5d968c56d0b
\ No newline at end of file