From 3f7341a8893b3b3b554452a0bb914ccefb18f81f Mon Sep 17 00:00:00 2001 From: James South Date: Wed, 22 Apr 2015 19:20:26 +0100 Subject: [PATCH] Final tweaks before release. Former-commit-id: 38082dbda2033c12d2663e60fdf3e7d573590cc9 Former-commit-id: a3011bb3974337d23d4ed916f2d2b65452ecbfd4 Former-commit-id: 60efdae1250100e6d85685f0471668a51ba0e68b --- .../ImageProcessor.Plugins.Cair.nuspec | 2 +- .../ImageProcessor.Plugins.WebP.nuspec | 2 +- .../NuSpecs/ImageProcessor.Web.Config.nuspec | 4 +- ...rocessor.Web.Plugins.AzureBlobCache.nuspec | 6 +-- .../ImageProcessor.Web.PostProcessor.nuspec | 4 +- build/NuSpecs/ImageProcessor.Web.nuspec | 4 +- build/build.xml | 22 +++++----- .../QueryParamParserUnitTests.cs | 27 +++++++++++- .../RegularExpressionUnitTests.cs | 43 ++++++++++++++++--- .../HttpModules/ImageProcessingModule.cs | 4 +- src/ImageProcessor.Web/Processors/Resize.cs | 16 ++++--- .../Processors/Watermark.cs | 33 +++++++++++++- 12 files changed, 128 insertions(+), 39 deletions(-) diff --git a/build/NuSpecs/ImageProcessor.Plugins.Cair.nuspec b/build/NuSpecs/ImageProcessor.Plugins.Cair.nuspec index 941a3d985c..fbd51688d8 100644 --- a/build/NuSpecs/ImageProcessor.Plugins.Cair.nuspec +++ b/build/NuSpecs/ImageProcessor.Plugins.Cair.nuspec @@ -21,7 +21,7 @@ Feedback is always welcome Image Resize Crop Rotate Quality Watermark Gif Jpg Jpeg Bitmap Png Tiff Cair Seam Carving - + diff --git a/build/NuSpecs/ImageProcessor.Plugins.WebP.nuspec b/build/NuSpecs/ImageProcessor.Plugins.WebP.nuspec index 35dfadfec7..daf9d61864 100644 --- a/build/NuSpecs/ImageProcessor.Plugins.WebP.nuspec +++ b/build/NuSpecs/ImageProcessor.Plugins.WebP.nuspec @@ -21,7 +21,7 @@ Feedback is always welcome Image Resize Crop Rotate Quality Watermark Gif Jpg Jpeg Bitmap Png Tiff WebP - + diff --git a/build/NuSpecs/ImageProcessor.Web.Config.nuspec b/build/NuSpecs/ImageProcessor.Web.Config.nuspec index 3084916e40..3d283d6119 100644 --- a/build/NuSpecs/ImageProcessor.Web.Config.nuspec +++ b/build/NuSpecs/ImageProcessor.Web.Config.nuspec @@ -21,8 +21,8 @@ Feedback is always welcome Image Resize Crop Rotate Quality Watermark Gif Jpg Jpeg Bitmap Png Tiff ASP Cache EXIF - - + + diff --git a/build/NuSpecs/ImageProcessor.Web.Plugins.AzureBlobCache.nuspec b/build/NuSpecs/ImageProcessor.Web.Plugins.AzureBlobCache.nuspec index 06a1b4efed..9f548dea3a 100644 --- a/build/NuSpecs/ImageProcessor.Web.Plugins.AzureBlobCache.nuspec +++ b/build/NuSpecs/ImageProcessor.Web.Plugins.AzureBlobCache.nuspec @@ -21,9 +21,9 @@ Feedback is always welcome Image Resize Crop Rotate Quality Watermark Gif Jpg Jpeg Bitmap Png Tiff Azure Cache Asp - - - + + + diff --git a/build/NuSpecs/ImageProcessor.Web.PostProcessor.nuspec b/build/NuSpecs/ImageProcessor.Web.PostProcessor.nuspec index 02246eafbd..bb5f649a56 100644 --- a/build/NuSpecs/ImageProcessor.Web.PostProcessor.nuspec +++ b/build/NuSpecs/ImageProcessor.Web.PostProcessor.nuspec @@ -21,8 +21,8 @@ Feedback is always welcome Image Resize Crop Rotate Quality Watermark Gif Jpg Jpeg Bitmap Png Tiff ASP Cache EXIF - - + + diff --git a/build/NuSpecs/ImageProcessor.Web.nuspec b/build/NuSpecs/ImageProcessor.Web.nuspec index 0fe93698f2..5c6c433859 100644 --- a/build/NuSpecs/ImageProcessor.Web.nuspec +++ b/build/NuSpecs/ImageProcessor.Web.nuspec @@ -2,7 +2,7 @@ ImageProcessor.Web - 4.2.1.0 + 4.3.0.0 ImageProcessor.Web James South James South @@ -23,7 +23,7 @@ Feedback is always welcome Image Resize Crop Rotate Quality Watermark Gif Jpg Jpeg Bitmap Png Tiff ASP Cache EXIF - + diff --git a/build/build.xml b/build/build.xml index 84b9865cb0..dd40840b8e 100644 --- a/build/build.xml +++ b/build/build.xml @@ -13,7 +13,7 @@ ImageProcessor Web - 4.2.1.0 + 4.3.0.0 ..\src\ImageProcessor.Web ImageProcessor.Web.csproj @@ -22,9 +22,15 @@ ImageProcessor.Web.nuspec + + ImageProcessor Web.config sample + 2.2.1.0 + ImageProcessor.Web.Config.nuspec + + ImageProcessor Web PostProcessor - 1.0.2.0 + 1.0.3.0 ..\src\ImageProcessor.Web.PostProcessor ImageProcessor.Web.PostProcessor.csproj @@ -33,15 +39,9 @@ ImageProcessor.Web.PostProcessor.nuspec - - ImageProcessor Web.config sample - 2.2.0.0 - ImageProcessor.Web.Config.nuspec - - ImageProcessor Web Azure Blob Cache plugin - 1.0.0.0 + 1.0.1.0 ..\src\Plugins\ImageProcessor.Web\ImageProcessor.Web.Plugins.AzureBlobCache ImageProcessor.Web.Plugins.AzureBlobCache.csproj @@ -52,7 +52,7 @@ ImageProcessor Cair plugin - 1.0.0.0 + 1.0.1.0 ..\src\Plugins\ImageProcessor\ImageProcessor.Plugins.Cair ImageProcessor.Plugins.Cair.csproj @@ -63,7 +63,7 @@ ImageProcessor WebP plugin - 1.0.1.0 + 1.0.2.0 ..\src\Plugins\ImageProcessor\ImageProcessor.Plugins.WebP ImageProcessor.Plugins.WebP.csproj diff --git a/src/ImageProcessor.Web.UnitTests/QueryParamParserUnitTests.cs b/src/ImageProcessor.Web.UnitTests/QueryParamParserUnitTests.cs index c0514770a8..2ab57c1f98 100644 --- a/src/ImageProcessor.Web.UnitTests/QueryParamParserUnitTests.cs +++ b/src/ImageProcessor.Web.UnitTests/QueryParamParserUnitTests.cs @@ -1,5 +1,16 @@ -namespace ImageProcessor.Web.UnitTests +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The query parameter parser unit tests. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.UnitTests { + using System; using System.Collections.Specialized; using System.Drawing; using System.Web; @@ -10,7 +21,7 @@ using NUnit.Framework; /// - /// The query param parser unit tests. + /// The query parameter parser unit tests. /// [TestFixture] public class QueryParamParserUnitTests @@ -44,6 +55,18 @@ Assert.IsNotNull(result); } + [TestCase("", "entropycrop", 0)] + [TestCase("entropycrop=0", "entropycrop", 0)] + [TestCase("entropycrop=128", "entropycrop", 128)] + [TestCase("entropycrop=128.4", "entropycrop", 128)] + [TestCase("entropycrop=128.5", "entropycrop", 129)] + public void IntRounded(string queryString, string parameter, int expected) + { + NameValueCollection query = HttpUtility.ParseQueryString(queryString); + int result = (int)Math.Round(QueryParamParser.Instance.ParseValue(query[parameter]), MidpointRounding.AwayFromZero); + Assert.AreEqual(result, expected); + } + [TestCase("", "entropycrop")] [TestCase("entropycrop=0", "entropycrop")] [TestCase("entropycrop=128", "entropycrop")] diff --git a/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs index ec1fe19ec8..eb5962dbb5 100644 --- a/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs +++ b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs @@ -106,14 +106,24 @@ namespace ImageProcessor.Web.UnitTests [Test] public void TestCropRegex() { - const string Querystring = "crop=0,0,150,300"; - CropLayer expected = new CropLayer(0, 0, 150, 300, CropMode.Pixels); + Dictionary data = new Dictionary + { + { + "crop=0,0,150,300", new CropLayer(0, 0, 150, 300, CropMode.Pixels) + }, + { + "crop=0.1,0.1,.2,.2&cropmode=percentage", new CropLayer(0.1f, 0.1f, 0.2f, 0.2f, CropMode.Percentage) + } + }; Processors.Crop crop = new Processors.Crop(); - crop.MatchRegexIndex(Querystring); - CropLayer actual = crop.Processor.DynamicParameter; - Assert.AreEqual(expected, actual); + foreach (KeyValuePair item in data) + { + crop.MatchRegexIndex(item.Key); + CropLayer result = crop.Processor.DynamicParameter; + Assert.AreEqual(item.Value, result); + } } /// @@ -252,12 +262,18 @@ namespace ImageProcessor.Web.UnitTests { "height=300", new ResizeLayer(new Size(0, 300)) }, + { + "height=300.6", new ResizeLayer(new Size(0, 301)) + }, { "height=300&mode=crop", new ResizeLayer(new Size(0, 300), ResizeMode.Crop) }, { "width=300&mode=crop", new ResizeLayer(new Size(300, 0), ResizeMode.Crop) }, + { + "width=300.2&mode=crop", new ResizeLayer(new Size(300, 0), ResizeMode.Crop) + }, { "width=600&heightratio=0.416", new ResizeLayer(new Size(600, 250)) }, @@ -289,6 +305,7 @@ namespace ImageProcessor.Web.UnitTests [TestCase("rotate=270", 270F)] [TestCase("rotate=-270", -270F)] [TestCase("rotate=28", 28F)] + [TestCase("rotate=28.7", 28.7F)] public void TestRotateRegex(string input, float expected) { Processors.Rotate rotate = new Processors.Rotate(); @@ -439,6 +456,22 @@ namespace ImageProcessor.Web.UnitTests DropShadow = true, FontFamily = new FontFamily("arial") } + }, + { + "watermark=لا أحد يحب الألم بذاته، يسعى ورائه أو يبتغيه، ببساطة لأنه الألم&color=fff&fontsize=36&fontstyle=italic&fontopacity=80&textposition=30,150&dropshadow=true&fontfamily=arial&vertical=true&rtl=true", + new TextLayer + { + Text = "لا أحد يحب الألم بذاته، يسعى ورائه أو يبتغيه، ببساطة لأنه الألم", + FontColor = ColorTranslator.FromHtml("#" + "ffffff"), + FontSize = 36, + Style = FontStyle.Italic, + Opacity = 80, + Position = new Point(30, 150), + DropShadow = true, + FontFamily = new FontFamily("arial"), + Vertical = true, + RightToLeft = true + } } }; diff --git a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs index 231cd7b236..15ebffb124 100644 --- a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs @@ -522,7 +522,7 @@ namespace ImageProcessor.Web.HttpModules { string origin = context.Request.Headers["Origin"]; - if (this.IsValidOriginRequest(origin)) + if (this.IsValidCorsRequest(origin)) { response.AddHeader("Access-Control-Allow-Origin", origin); } @@ -626,7 +626,7 @@ namespace ImageProcessor.Web.HttpModules /// /// True if the request is valid; otherwise, False. /// - private bool IsValidOriginRequest(string path) + private bool IsValidCorsRequest(string path) { ImageSecuritySection.CORSOriginElement origins = ImageProcessorConfiguration.Instance.GetImageSecuritySection().CORSOrigin; diff --git a/src/ImageProcessor.Web/Processors/Resize.cs b/src/ImageProcessor.Web/Processors/Resize.cs index e04c64e079..65ac74cb8c 100644 --- a/src/ImageProcessor.Web/Processors/Resize.cs +++ b/src/ImageProcessor.Web/Processors/Resize.cs @@ -124,23 +124,27 @@ namespace ImageProcessor.Web.Processors string heightRatio = queryCollection["heightratio"]; Size size = new Size(); + // Umbraco calls the API incorrectly so we have to deal with floats. + // We round up so that single pixel lines are not produced. + const MidpointRounding Rounding = MidpointRounding.AwayFromZero; + // First cater for single dimensions. if (width != null && height == null) { - size = new Size(QueryParamParser.Instance.ParseValue(width), 0); + size = new Size((int)Math.Round(QueryParamParser.Instance.ParseValue(width), Rounding), 0); } if (width == null && height != null) { - size = new Size(0, QueryParamParser.Instance.ParseValue(height)); + size = new Size(0, (int)Math.Round(QueryParamParser.Instance.ParseValue(height), Rounding)); } // Both supplied if (width != null && height != null) { size = new Size( - QueryParamParser.Instance.ParseValue(width), - QueryParamParser.Instance.ParseValue(height)); + (int)Math.Round(QueryParamParser.Instance.ParseValue(width), Rounding), + (int)Math.Round(QueryParamParser.Instance.ParseValue(height), Rounding)); } // Calculate any ratio driven sizes. @@ -149,13 +153,13 @@ namespace ImageProcessor.Web.Processors // Replace 0 width if (size.Width == 0 && size.Height > 0 && widthRatio != null && heightRatio == null) { - size.Width = Convert.ToInt32(QueryParamParser.Instance.ParseValue(widthRatio) * size.Height); + size.Width = (int)Math.Round(QueryParamParser.Instance.ParseValue(widthRatio) * size.Height, Rounding); } // Replace 0 height if (size.Width > 0 && size.Height == 0 && widthRatio == null && heightRatio != null) { - size.Height = Convert.ToInt32(QueryParamParser.Instance.ParseValue(heightRatio) * size.Width); + size.Height = (int)Math.Round(QueryParamParser.Instance.ParseValue(heightRatio) * size.Width, Rounding); } } diff --git a/src/ImageProcessor.Web/Processors/Watermark.cs b/src/ImageProcessor.Web/Processors/Watermark.cs index d6dec4f4df..e589550730 100644 --- a/src/ImageProcessor.Web/Processors/Watermark.cs +++ b/src/ImageProcessor.Web/Processors/Watermark.cs @@ -85,7 +85,9 @@ namespace ImageProcessor.Web.Processors FontSize = this.ParseFontSize(queryCollection), FontFamily = this.ParseFontFamily(queryCollection), Style = this.ParseFontStyle(queryCollection), - DropShadow = this.ParseDropShadow(queryCollection) + DropShadow = this.ParseDropShadow(queryCollection), + Vertical = this.ParseVertical(queryCollection), + RightToLeft = this.ParseRightToLeft(queryCollection) }; textLayer.Opacity = this.ParseOpacity(queryCollection, textLayer.FontColor); @@ -198,7 +200,7 @@ namespace ImageProcessor.Web.Processors /// The of query parameters. /// /// - /// The true if the watermark is to have a shadow; otherwise false. + /// True if the watermark is to have a shadow; otherwise false. /// private bool ParseDropShadow(NameValueCollection queryCollection) { @@ -229,6 +231,33 @@ namespace ImageProcessor.Web.Processors : 100; } + /// + /// Returns a value indicating whether the watermark is to be written right to left. + /// + /// + /// The of query parameters. + /// + /// + /// True if the watermark is to be written right to left; otherwise false. + /// + private bool ParseRightToLeft(NameValueCollection queryCollection) + { + return QueryParamParser.Instance.ParseValue(queryCollection["rtl"]); + } + + /// + /// Returns a value indicating whether the watermark is to be written vertically. + /// + /// + /// The of query parameters. + /// + /// + /// True if the watermark is to be written vertically; otherwise false. + /// + private bool ParseVertical(NameValueCollection queryCollection) + { + return QueryParamParser.Instance.ParseValue(queryCollection["vertical"]); + } #endregion } }