Skip to content

Commit

Permalink
Fixes #21: Added 'defaultImageQuery' attribute support to the 'waterm…
Browse files Browse the repository at this point in the history
…arks' configuration. All image watermarks will have values from 'defaultImageQuery' applied to their 'imageQuery' except where 'imageQuery' has an explicit key/value. If the 'defaultImageQuery' attribute is not specified, it defaults to "scache=true".

Also added general-purpose "merge defaults" to NameValueCollectionExtensions and merging-constructors to ResizeSettings and added a unit test to verify the merging behavior.
  • Loading branch information
JaredReisinger committed Dec 12, 2013
1 parent f0b942c commit c61563d
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 12 deletions.
21 changes: 21 additions & 0 deletions Core/ExtensionMethods/NameValueCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,5 +243,26 @@ public static NameValueCollection Keep(NameValueCollection q, params string[] ke

return c;
}

/// <summary>
/// Creates and returns a new NameValueCollection instance that contains all of the
/// keys/values from 'q', and any keys/values from 'defaults' that 'q' does not already
/// contain.
/// </summary>
/// <param name="q">The settings specific to a particular query</param>
/// <param name="defaults">Default settings to use when not overridden by 'q'.</param>
/// <returns></returns>
public static NameValueCollection MergeDefaults(NameValueCollection q, NameValueCollection defaults)
{
// Start with the defaults, and then blindly copy the keys/values
// from 'q'. Any keys in both 'defaults' and 'q' will end up having
// the value from 'q', since that one is set last.
NameValueCollection c = new NameValueCollection(defaults);
foreach (string s in q.AllKeys) {
c[s] = q[s];
}

return c;
}
}
}
16 changes: 16 additions & 0 deletions Core/ResizeSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ public ResizeSettings(NameValueCollection col) : base(col) { }
/// </summary>
/// <param name="queryString"></param>
public ResizeSettings(string queryString) : base(PathUtils.ParseQueryStringFriendlyAllowSemicolons(queryString)) { }
/// <summary>
/// Merges the specified collection with a set of defaults into a new
/// ResizeSettings instance.
/// </summary>
/// <param name="col"></param>
/// <param name="defaultSettings"></param>
public ResizeSettings(NameValueCollection col, NameValueCollection defaultSettings)
: base(NameValueCollectionExtensions.MergeDefaults(col, defaultSettings)) { }
/// <summary>
/// Parses the specified querystring into name/value pairs and merges
/// it with defaultSettings in a new ResizeSettings instance.
/// </summary>
/// <param name="queryString"></param>
/// <param name="defaultSettings"></param>
public ResizeSettings(string queryString, NameValueCollection defaultSettings)
: this(PathUtils.ParseQueryStringFriendlyAllowSemicolons(queryString), defaultSettings) { }

/// <summary>
/// Creates a new resize settings object with the specified resizing settings
Expand Down
15 changes: 10 additions & 5 deletions Plugins/Watermark/ImageLayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@

namespace ImageResizer.Plugins.Watermark {
public class ImageLayer:Layer {
public ImageLayer(NameValueCollection attrs, Config c)
public ImageLayer(NameValueCollection attrs, ResizeSettings defaultImageQuery, Config c)
: base(attrs) {
Path = attrs["path"];
this.c = c;
if (!string.IsNullOrEmpty(attrs["imageQuery"])) ImageQuery = new ResizeSettings(attrs["imageQuery"]);
Path = attrs["path"];
this.c = c;
if (!string.IsNullOrEmpty(attrs["imageQuery"])) {
ImageQuery = new ResizeSettings(attrs["imageQuery"], defaultImageQuery);
} else {
ImageQuery = new ResizeSettings(defaultImageQuery);
}
}

public ImageLayer(Config c) {
public ImageLayer(Config c)
{
this.c = c;
}
protected string _path = null;
Expand Down
32 changes: 25 additions & 7 deletions Plugins/Watermark/Watermark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,24 @@ public class WatermarkPlugin : LegacyWatermarkFeatures, IPlugin, IQuerystringPlu
public WatermarkPlugin() {
}


private ResizeSettings _defaultImageQuery = new ResizeSettings("scache=true");
/// <summary>
/// Default querystring parameters for all image watermarks.
/// If not specified in the watermark configuration, defaults to
/// "scache=true".
/// </summary>
public ResizeSettings DefaultImageQuery
{
get { return _defaultImageQuery; }
set { _defaultImageQuery = value; }
}

ImageLayer _otherImages = new ImageLayer(null);
/// <summary>
/// When a &amp;watermark command does not specify a named preset, it is assumed to be a file name.
/// Set OtherImages.Path to the search folder. All watermark images (except for presets) must be in the root of the search folder.
/// The remainder of the settings affect how each watermrak will be positioned and displayed.
/// The remainder of the settings affect how each watermark will be positioned and displayed.
/// </summary>
public ImageLayer OtherImages {
get { return _otherImages; }
Expand All @@ -45,7 +58,7 @@ public IPlugin Install(Configuration.Config c) {
c.Plugins.add_plugin(this);
this.c = c;
this.OtherImages.ConfigInstance = c;
_namedWatermarks = ParseWatermarks(c.getConfigXml().queryFirst("watermarks"), ref _otherImages);
_namedWatermarks = ParseWatermarks(c.getConfigXml().queryFirst("watermarks"), ref _defaultImageQuery, ref _otherImages);
c.Pipeline.PostRewrite += Pipeline_PostRewrite;
return this;
}
Expand All @@ -60,7 +73,13 @@ public IEnumerable<string> GetSupportedQuerystringKeys() {
return new string[] { "watermark" };
}

protected Dictionary<string, IEnumerable<Layer>> ParseWatermarks(Node n, ref ImageLayer otherImageDefaults) {
protected Dictionary<string, IEnumerable<Layer>> ParseWatermarks(Node n, ref ResizeSettings defaultImageQuery, ref ImageLayer otherImageDefaults) {
// Grab the defaultImageQuery value (if it exists) from the watermarks
// node, so that we can apply them to any subsequent image watermarks.
if (n != null && !string.IsNullOrEmpty(n.Attrs["defaultImageQuery"])) {
defaultImageQuery = new ResizeSettings(n.Attrs["defaultImageQuery"]);
}

Dictionary<string, IEnumerable<Layer>> dict = new Dictionary<string, IEnumerable<Layer>>(StringComparer.OrdinalIgnoreCase);
if (n == null || n.Children == null) return dict;
foreach (Node c in n.Children) {
Expand All @@ -77,16 +96,15 @@ protected Dictionary<string, IEnumerable<Layer>> ParseWatermarks(Node n, ref Ima
}



if (c.Name.Equals("otherimages", StringComparison.OrdinalIgnoreCase)) otherImageDefaults = new ImageLayer(c.Attrs, this.c);
if (c.Name.Equals("image", StringComparison.OrdinalIgnoreCase)) dict.Add(name, new Layer[]{new ImageLayer(c.Attrs, this.c)});
if (c.Name.Equals("otherimages", StringComparison.OrdinalIgnoreCase)) otherImageDefaults = new ImageLayer(c.Attrs, defaultImageQuery, this.c);
if (c.Name.Equals("image", StringComparison.OrdinalIgnoreCase)) dict.Add(name, new Layer[] { new ImageLayer(c.Attrs, defaultImageQuery, this.c) });
if (c.Name.Equals("text", StringComparison.OrdinalIgnoreCase)) dict.Add(name, new Layer[] {new TextLayer(c.Attrs) });
if (c.Name.Equals("group", StringComparison.OrdinalIgnoreCase)) {

List<Layer> layers = new List<Layer>();
if (c.Children != null) {
foreach (Node layer in c.Children) {
if (layer.Name.Equals("image", StringComparison.OrdinalIgnoreCase)) layers.Add(new ImageLayer(layer.Attrs, this.c));
if (layer.Name.Equals("image", StringComparison.OrdinalIgnoreCase)) layers.Add(new ImageLayer(layer.Attrs, defaultImageQuery, this.c));
if (layer.Name.Equals("text", StringComparison.OrdinalIgnoreCase)) layers.Add(new TextLayer(layer.Attrs));
}
}
Expand Down
18 changes: 18 additions & 0 deletions Tests/Core.Tests/ResizeSettingsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,23 @@ public void TestRoundTripColor(string from, string expected)
Color? parsed = ParseUtils.ParseColor(from).Value;
Assert.AreEqual(expected, ParseUtils.SerializeColor(parsed.Value), StringComparison.InvariantCultureIgnoreCase);
}

[Test]
[Row("a=1", "", "?a=1")]
[Row("", "b=2", "?b=2")]
[Row("a=1", "b=2", "?a=1&b=2")]
[Row("b=1", "b=2", "?b=1")]
public void TestMergingConstructor(string q, string defaults, string expected)
{
ResizeSettings defaultSettings = new ResizeSettings(defaults);
ResizeSettings mergedSettings = new ResizeSettings(q, defaultSettings);
ResizeSettings expectedSettings = new ResizeSettings(expected);

Assert.AreEqual(expectedSettings.Count, mergedSettings.Count);
foreach (string key in expectedSettings.AllKeys)
{
Assert.AreEqual(expectedSettings[key], mergedSettings[key]);
}
}
}
}

0 comments on commit c61563d

Please sign in to comment.