Browse Source

Adding improved plugin and preset handling

Former-commit-id: 0b3fdc86725f777a98024b656114b192c31e138b
pull/17/head
James South 12 years ago
parent
commit
6dceb65da8
  1. 171
      src/ImageProcessor.Web/NET45/Config/ImageProcessingSection.cs
  2. 106
      src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs
  3. 11
      src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
  4. 37
      src/TestWebsites/NET4/config/imageprocessor/processing.config
  5. 8
      src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config
  6. 33
      src/TestWebsites/NET45/Test_Website_Webforms_NET45/config/imageprocessor/processing.config

171
src/ImageProcessor.Web/NET45/Config/ImageProcessingSection.cs

@ -1,9 +1,13 @@
// ----------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
// <copyright file="ImageProcessingSection.cs" company="James South"> // <copyright file="ImageProcessingSection.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // <summary>
// Represents an image processing section within a configuration file.
// Nested syntax adapted from <see cref="http://tneustaedter.blogspot.co.uk/2011/09/how-to-create-one-or-more-nested.html" />
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Web.Config namespace ImageProcessor.Web.Config
{ {
@ -19,6 +23,21 @@ namespace ImageProcessor.Web.Config
public sealed class ImageProcessingSection : ConfigurationSection public sealed class ImageProcessingSection : ConfigurationSection
{ {
#region Properties #region Properties
/// <summary>
/// Gets the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.PresetElementCollection"/>.
/// </summary>
/// <value>
/// The <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.PresetElementCollection"/>.
/// </value>
[ConfigurationProperty("presets", IsRequired = true)]
public PresetElementCollection Presets
{
get
{
return this["presets"] as PresetElementCollection;
}
}
/// <summary> /// <summary>
/// Gets the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.PluginElementCollection"/>. /// Gets the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.PluginElementCollection"/>.
/// </summary> /// </summary>
@ -54,6 +73,115 @@ namespace ImageProcessor.Web.Config
} }
#endregion #endregion
/// <summary>
/// Represents a PresetElement configuration element within the configuration.
/// </summary>
public class PresetElement : ConfigurationElement
{
/// <summary>
/// Gets or sets the name of the preset.
/// </summary>
/// <value>The name of the plugin.</value>
[ConfigurationProperty("name", DefaultValue = "", IsRequired = true)]
public string Name
{
get { return (string)this["name"]; }
set { this["name"] = value; }
}
/// <summary>
/// Gets or sets the value of the preset.
/// </summary>
/// <value>The full Type definition of the plugin</value>
[ConfigurationProperty("value", DefaultValue = "", IsRequired = true)]
public string Value
{
get { return (string)this["value"]; }
set { this["value"] = value; }
}
}
/// <summary>
/// Represents a PresetElementCollection collection configuration element within the configuration.
/// </summary>
public class PresetElementCollection : ConfigurationElementCollection
{
/// <summary>
/// Gets the type of the <see cref="T:System.Configuration.ConfigurationElementCollection"/>.
/// </summary>
/// <value>
/// The <see cref="T:System.Configuration.ConfigurationElementCollectionType"/> of this collection.
/// </value>
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMap; }
}
/// <summary>
/// Gets the name used to identify this collection of elements in the configuration file when overridden in a derived class.
/// </summary>
/// <value>
/// The name of the collection; otherwise, an empty string. The default is an empty string.
/// </value>
protected override string ElementName
{
get { return "preset"; }
}
/// <summary>
/// Gets or sets the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.PresetElement"/>
/// at the specified index within the collection.
/// </summary>
/// <param name="index">The index at which to get the specified object.</param>
/// <returns>
/// The the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.PresetElement"/>
/// at the specified index within the collection.
/// </returns>
public PresetElement this[int index]
{
get
{
return (PresetElement)BaseGet(index);
}
set
{
if (this.BaseGet(index) != null)
{
this.BaseRemoveAt(index);
}
this.BaseAdd(index, value);
}
}
/// <summary>
/// Creates a new Preset configuration element.
/// </summary>
/// <returns>
/// A new PluginConfig configuration element.
/// </returns>
protected override ConfigurationElement CreateNewElement()
{
return new PresetElement();
}
/// <summary>
/// Gets the element key for a specified PluginElement configuration element.
/// </summary>
/// <param name="element">
/// The <see cref="T:System.Configuration.ConfigurationElement">ConfigurationElement</see>
/// to return the key for.
/// </param>
/// <returns>The element key for a specified PluginElement configuration element.</returns>
protected override object GetElementKey(ConfigurationElement element)
{
return ((PresetElement)element).Name;
}
}
/// <summary> /// <summary>
/// Represents a PluginElement configuration element within the configuration. /// Represents a PluginElement configuration element within the configuration.
/// </summary> /// </summary>
@ -104,6 +232,19 @@ namespace ImageProcessor.Web.Config
/// </summary> /// </summary>
public class PluginElementCollection : ConfigurationElementCollection public class PluginElementCollection : ConfigurationElementCollection
{ {
/// <summary>
/// Gets or sets a value indicating whether to auto load all plugins.
/// <remarks>Defaults to <value>True</value>.</remarks>
/// </summary>
/// <value>If True plugins are auto discovered and loaded from all assemblies otherwise they must be defined in the configuration file</value>
[ConfigurationProperty("autoLoadPlugins", DefaultValue = true, IsRequired = false)]
public bool AutoLoadPlugins
{
get { return (bool)this["autoLoadPlugins"]; }
set { this["autoLoadPlugins"] = value; }
}
/// <summary> /// <summary>
/// Gets the type of the <see cref="T:System.Configuration.ConfigurationElementCollection"/>. /// Gets the type of the <see cref="T:System.Configuration.ConfigurationElementCollection"/>.
/// </summary> /// </summary>
@ -126,18 +267,6 @@ namespace ImageProcessor.Web.Config
get { return "plugin"; } get { return "plugin"; }
} }
/// <summary>
/// Gets or sets the autoLoadPlugins of the plugin file.
/// </summary>
/// <value>If True plugins are auto discovered and loaded from all assemblies otherwise they must be defined in the configuration file</value>
[ConfigurationProperty("autoLoadPlugins", DefaultValue = true, IsRequired = false)]
public bool AutoLoadPlugins
{
get { return (bool)this["autoLoadPlugins"]; }
set { this["autoLoadPlugins"] = value; }
}
/// <summary> /// <summary>
/// Gets or sets the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.PluginElement"/> /// Gets or sets the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.PluginElement"/>
/// at the specified index within the collection. /// at the specified index within the collection.
@ -161,15 +290,15 @@ namespace ImageProcessor.Web.Config
this.BaseRemoveAt(index); this.BaseRemoveAt(index);
} }
this.BaseAdd(index, value); this.BaseAdd(index, value);
} }
} }
/// <summary> /// <summary>
/// Creates a new PluginConfig configuration element. /// Creates a new Plugin configuration element.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A new PluginConfig configuration element. /// A new Plugin configuration element.
/// </returns> /// </returns>
protected override ConfigurationElement CreateNewElement() protected override ConfigurationElement CreateNewElement()
{ {
@ -279,10 +408,10 @@ namespace ImageProcessor.Web.Config
{ {
if (this.BaseGet(index) != null) if (this.BaseGet(index) != null)
{ {
this.BaseRemoveAt(index); this.BaseRemoveAt(index);
} }
this.BaseAdd(index, value); this.BaseAdd(index, value);
} }
} }

106
src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs

@ -8,9 +8,6 @@
// <see cref="http://csharpindepth.com/Articles/General/Singleton.aspx" /> // <see cref="http://csharpindepth.com/Articles/General/Singleton.aspx" />
// </summary> // </summary>
// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
using System.Collections;
namespace ImageProcessor.Web.Config namespace ImageProcessor.Web.Config
{ {
#region Using #region Using
@ -45,6 +42,12 @@ namespace ImageProcessor.Web.Config
private static readonly Dictionary<string, Dictionary<string, string>> PluginSettings = private static readonly Dictionary<string, Dictionary<string, string>> PluginSettings =
new Dictionary<string, Dictionary<string, string>>(); new Dictionary<string, Dictionary<string, string>>();
/// <summary>
/// A collection of the processing presets defined in the configuration.
/// for available plugins.
/// </summary>
private static readonly Dictionary<string, string> PresetSettings = new Dictionary<string, string>();
/// <summary> /// <summary>
/// The processing configuration section from the current application configuration. /// The processing configuration section from the current application configuration.
/// </summary> /// </summary>
@ -183,6 +186,36 @@ namespace ImageProcessor.Web.Config
#endregion #endregion
#region Methods #region Methods
/// <summary>
/// Returns the collection of the processing presets defined in the configuration.
/// </summary>
/// <param name="name">
/// The name of the plugin to get the settings for.
/// </param>
/// <returns>
/// The <see cref="T:Systems.Collections.Generic.Dictionary{string, string}"/> containing the processing presets defined in the configuration.
/// </returns>
public string GetPresetSettings(string name)
{
if (!PresetSettings.ContainsKey(name))
{
var presetElement =
GetImageProcessingSection().Presets
.Cast<ImageProcessingSection.PresetElement>()
.FirstOrDefault(x => x.Name == name);
if (presetElement != null)
{
PresetSettings.Add(presetElement.Name, presetElement.Value);
}
}
string preset;
PresetSettings.TryGetValue(name, out preset);
return preset;
}
/// <summary> /// <summary>
/// Returns the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.SettingElementCollection"/> for the given plugin. /// Returns the <see cref="T:ImageProcessor.Web.Config.ImageProcessingSection.SettingElementCollection"/> for the given plugin.
/// </summary> /// </summary>
@ -255,12 +288,12 @@ namespace ImageProcessor.Web.Config
{ {
if (this.GraphicsProcessors == null) if (this.GraphicsProcessors == null)
{ {
if (GetImageProcessingSection().Plugins.AutoLoadPlugins) try
{ {
try if (GetImageProcessingSection().Plugins.AutoLoadPlugins)
{ {
// Build a list of native IGraphicsProcessor instances. // Build a list of native IGraphicsProcessor instances.
Type type = typeof (IGraphicsProcessor); Type type = typeof(IGraphicsProcessor);
IEnumerable<Type> types = IEnumerable<Type> types =
AppDomain.CurrentDomain.GetAssemblies() AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes()) .SelectMany(s => s.GetTypes())
@ -277,51 +310,52 @@ namespace ImageProcessor.Web.Config
processor.Settings = this.GetPluginSettings(processor.GetType().Name); processor.Settings = this.GetPluginSettings(processor.GetType().Name);
} }
} }
catch (ReflectionTypeLoadException ex) else
{ {
StringBuilder sb = new StringBuilder(); ImageProcessingSection.PluginElementCollection pluginConfigs = imageProcessingSection.Plugins;
foreach (Exception exception in ex.LoaderExceptions) this.GraphicsProcessors = new List<IGraphicsProcessor>();
foreach (ImageProcessingSection.PluginElement pluginConfig in pluginConfigs)
{ {
sb.AppendLine(exception.Message); Type type = Type.GetType(pluginConfig.Type);
if (exception is FileNotFoundException)
if (type == null)
{ {
FileNotFoundException fileNotFoundException = exception as FileNotFoundException; throw new ArgumentException("Couldn't load IGraphicsProcessor: " + pluginConfig.Type);
if (!string.IsNullOrEmpty(fileNotFoundException.FusionLog))
{
sb.AppendLine("Fusion Log:");
sb.AppendLine(fileNotFoundException.FusionLog);
}
} }
sb.AppendLine(); this.GraphicsProcessors.Add(Activator.CreateInstance(type) as IGraphicsProcessor);
} }
string errorMessage = sb.ToString(); // Add the available settings.
foreach (IGraphicsProcessor processor in this.GraphicsProcessors)
// Display or log the error based on your application. {
throw new Exception(errorMessage); processor.Settings = this.GetPluginSettings(processor.GetType().Name);
}
} }
} }
else catch (ReflectionTypeLoadException ex)
{ {
var pluginConfigs = imageProcessingSection.Plugins; StringBuilder stringBuilder = new StringBuilder();
this.GraphicsProcessors = new List<IGraphicsProcessor>(); foreach (Exception exception in ex.LoaderExceptions)
foreach (ImageProcessingSection.PluginElement pluginConfig in pluginConfigs)
{ {
var type = Type.GetType(pluginConfig.Type); stringBuilder.AppendLine(exception.Message);
if (exception is FileNotFoundException)
if (type == null)
{ {
throw new ArgumentException("Couldn't load IGraphicsProcessor: " + pluginConfig.Type); FileNotFoundException fileNotFoundException = exception as FileNotFoundException;
if (!string.IsNullOrEmpty(fileNotFoundException.FusionLog))
{
stringBuilder.AppendLine("Fusion Log:");
stringBuilder.AppendLine(fileNotFoundException.FusionLog);
}
} }
this.GraphicsProcessors.Add((Activator.CreateInstance(type) as IGraphicsProcessor));
}
// Add the available settings. stringBuilder.AppendLine();
foreach (IGraphicsProcessor processor in this.GraphicsProcessors)
{
processor.Settings = this.GetPluginSettings(processor.GetType().Name);
} }
string errorMessage = stringBuilder.ToString();
// Display or log the error based on your application.
throw new Exception(errorMessage);
} }
} }
} }

11
src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs

@ -542,17 +542,14 @@ namespace ImageProcessor.Web.HttpModules
/// </returns> /// </returns>
private string ReplacePresetsInQueryString(string queryString) private string ReplacePresetsInQueryString(string queryString)
{ {
// We use the processor config system to store the preset values.
Dictionary<string, string> presets = ImageProcessorConfig.Instance.GetPluginSettings("Preset");
foreach (Match match in PresetRegex.Matches(queryString)) foreach (Match match in PresetRegex.Matches(queryString))
{ {
if (match.Success) if (match.Success)
{ {
// Set the index on the first instance only. string preset = match.Value.Split('=')[1];
string preset = match.Value;
string replacements; // We use the processor config system to store the preset values.
presets.TryGetValue(preset.Split('=')[1], out replacements); string replacements = ImageProcessorConfig.Instance.GetPresetSettings(preset);
queryString = Regex.Replace(queryString, preset, replacements ?? string.Empty); queryString = Regex.Replace(queryString, preset, replacements ?? string.Empty);
} }
} }

37
src/TestWebsites/NET4/config/imageprocessor/processing.config

@ -1,17 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<processing> <processing>
<plugins> <presets>
<plugin name="Resize"> <preset name="demo" value="width=300&#038;height=150&#038;bgcolor=transparent"/>
</presets>
<plugins autoLoadPlugins="false">
<plugin name="Alpha" type="ImageProcessor.Processors.Alpha, 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> <settings>
<setting key="MaxWidth" value="3000"/> <setting key="MaxSize" value="22"/>
<setting key="MaxHeight" value="3000"/> <setting key="MaxSigma" value="5.1"/>
<setting key="MaxThreshold" value="100"/>
</settings> </settings>
</plugin> </plugin>
<plugin name="Preset"> <plugin name="GaussianSharpen" type="ImageProcessor.Processors.GaussianSharpen, ImageProcessor">
<settings> <settings>
<setting key="a" value="width=300&#038;height=150"/> <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="3000"/>
<setting key="MaxHeight" value="3000"/>
</settings> </settings>
</plugin> </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="Vignette" type="ImageProcessor.Processors.Vignette, ImageProcessor"/>
<plugin name="Watermark" type="ImageProcessor.Processors.Watermark, ImageProcessor"/>
</plugins> </plugins>
</processing> </processing>

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

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<processing> <processing>
<presets>
<preset name="demo" value="width=300&#038;height=150&#038;bgcolor=transparent"/>
</presets>
<plugins autoLoadPlugins="false"> <plugins autoLoadPlugins="false">
<plugin name="Alpha" type="ImageProcessor.Processors.Alpha, ImageProcessor"/> <plugin name="Alpha" type="ImageProcessor.Processors.Alpha, ImageProcessor"/>
<plugin name="Brightness" type="ImageProcessor.Processors.Brightness, ImageProcessor"/> <plugin name="Brightness" type="ImageProcessor.Processors.Brightness, ImageProcessor"/>
@ -34,11 +37,6 @@
<plugin name="Saturation" type="ImageProcessor.Processors.Saturation, ImageProcessor"/> <plugin name="Saturation" type="ImageProcessor.Processors.Saturation, ImageProcessor"/>
<plugin name="Vignette" type="ImageProcessor.Processors.Vignette, ImageProcessor"/> <plugin name="Vignette" type="ImageProcessor.Processors.Vignette, ImageProcessor"/>
<plugin name="Watermark" type="ImageProcessor.Processors.Watermark, ImageProcessor"/> <plugin name="Watermark" type="ImageProcessor.Processors.Watermark, ImageProcessor"/>
<plugin name="Preset" type="ImageProcessor.Web.Preset, ImageProcessor">
<settings>
<setting key="demo" value="width=300&#038;height=150&#038;&#038;bgcolor=transparent"/>
</settings>
</plugin>
</plugins> </plugins>
</processing> </processing>

33
src/TestWebsites/NET45/Test_Website_Webforms_NET45/config/imageprocessor/processing.config

@ -1,31 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<processing> <processing>
<plugins> <presets>
<plugin name="Resize"> <preset name="demo" value="width=300&#038;height=150&#038;bgcolor=transparent"/>
<settings> </presets>
<setting key="MaxWidth" value="3000"/> <plugins autoLoadPlugins="false">
<setting key="MaxHeight" value="3000"/> <plugin name="Alpha" type="ImageProcessor.Processors.Alpha, ImageProcessor"/>
</settings> <plugin name="Brightness" type="ImageProcessor.Processors.Brightness, ImageProcessor"/>
</plugin> <plugin name="Contrast" type="ImageProcessor.Processors.Contrast, ImageProcessor"/>
<plugin name="GaussianBlur"> <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> <settings>
<setting key="MaxSize" value="22"/> <setting key="MaxSize" value="22"/>
<setting key="MaxSigma" value="5.1"/> <setting key="MaxSigma" value="5.1"/>
<setting key="MaxThreshold" value="100"/> <setting key="MaxThreshold" value="100"/>
</settings> </settings>
</plugin> </plugin>
<plugin name="GaussianSharpen"> <plugin name="GaussianSharpen" type="ImageProcessor.Processors.GaussianSharpen, ImageProcessor">
<settings> <settings>
<setting key="MaxSize" value="22"/> <setting key="MaxSize" value="22"/>
<setting key="MaxSigma" value="5.1"/> <setting key="MaxSigma" value="5.1"/>
<setting key="MaxThreshold" value="100"/> <setting key="MaxThreshold" value="100"/>
</settings> </settings>
</plugin> </plugin>
<plugin name="Preset"> <plugin name="Quality" type="ImageProcessor.Processors.Quality, ImageProcessor"/>
<plugin name="Resize" type="ImageProcessor.Processors.Resize, ImageProcessor">
<settings> <settings>
<setting key="demo" value="width=300&#038;height=150"/> <setting key="MaxWidth" value="3000"/>
<setting key="MaxHeight" value="3000"/>
</settings> </settings>
</plugin> </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="Vignette" type="ImageProcessor.Processors.Vignette, ImageProcessor"/>
<plugin name="Watermark" type="ImageProcessor.Processors.Watermark, ImageProcessor"/>
</plugins> </plugins>
</processing> </processing>

Loading…
Cancel
Save