diff --git a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs index 56fb6e850..d1564391c 100644 --- a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs +++ b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.2.0")] -[assembly: AssemblyFileVersion("1.0.2.0")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 69b0a7556..69fd0fc91 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -312,15 +312,33 @@ namespace ImageProcessor /// /// Rotates the current image by the given angle. /// - /// The angle by which to rotate the image. + /// + /// The angle by which to rotate the image. + /// + /// + /// The background Colour. + /// /// /// The current instance of the class. /// - public ImageFactory Rotate(int angle) + public ImageFactory Rotate(int angle, Color backgroundColour = default(Color)) { if (this.ShouldProcess) { - Rotate rotate = new Rotate { DynamicParameter = angle }; + // Sanitize the input. + if (angle > 360 || angle < 0) + { + angle = 0; + } + + RotateLayer rotateLayer = new RotateLayer { Angle = angle }; + + if (backgroundColour != default(Color)) + { + rotateLayer.BackgroundColor = backgroundColour; + } + + Rotate rotate = new Rotate { DynamicParameter = rotateLayer }; this.Image = rotate.ProcessImage(this); } @@ -385,7 +403,7 @@ namespace ImageProcessor // Fix the colour palette of gif images. this.FixGifs(); - if (this.ImageFormat == ImageFormat.Jpeg) + if (object.Equals(this.ImageFormat, ImageFormat.Jpeg)) { // Jpegs can be saved with different settings to include a quality setting for the JPEG compression. // This improves output compression and quality. @@ -418,7 +436,7 @@ namespace ImageProcessor // Fix the colour palette of gif images. this.FixGifs(); - if (this.ImageFormat == ImageFormat.Jpeg) + if (object.Equals(this.ImageFormat, ImageFormat.Jpeg)) { // Jpegs can be saved with different settings to include a quality setting for the JPEG compression. // This improves output compression and quality. @@ -500,7 +518,7 @@ namespace ImageProcessor { // Fix the colour palette of gif images. // TODO: Why does the palette not get fixed when resized to the same dimensions. - if (this.ImageFormat == ImageFormat.Gif) + if (object.Equals(this.ImageFormat, ImageFormat.Gif)) { OctreeQuantizer quantizer = new OctreeQuantizer(255, 8); this.Image = quantizer.Quantize(this.Image); diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 5eee94bd0..56c0e84a7 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -76,6 +76,7 @@ + diff --git a/src/ImageProcessor/ImageProcessor.sln b/src/ImageProcessor/ImageProcessor.sln index 35a90a6e6..a6b3bf630 100644 --- a/src/ImageProcessor/ImageProcessor.sln +++ b/src/ImageProcessor/ImageProcessor.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "..\Test\Test\Test.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}" diff --git a/src/ImageProcessor/Imaging/RotateLayer.cs b/src/ImageProcessor/Imaging/RotateLayer.cs new file mode 100644 index 000000000..80cc52168 --- /dev/null +++ b/src/ImageProcessor/Imaging/RotateLayer.cs @@ -0,0 +1,40 @@ +// ----------------------------------------------------------------------- +// +// TODO: Update copyright text. +// +// ----------------------------------------------------------------------- + +namespace ImageProcessor.Imaging +{ + #region Using + using System.Drawing; + #endregion + + /// + /// Enacapsulates the properties required to rotate an image. + /// + internal class RotateLayer + { + #region Constructors + /// + /// Initializes a new instance of the class. + /// + public RotateLayer() + { + this.BackgroundColor = Color.Transparent; + } + #endregion + + #region Properties + /// + /// Gets or sets the angle at which to rotate the image. + /// + public int Angle { get; set; } + + /// + /// Gets or sets the background color. + /// + public Color BackgroundColor { get; set; } + #endregion + } +} diff --git a/src/ImageProcessor/Processors/Filter.cs b/src/ImageProcessor/Processors/Filter.cs index f1aec4f94..bad5e7552 100644 --- a/src/ImageProcessor/Processors/Filter.cs +++ b/src/ImageProcessor/Processors/Filter.cs @@ -7,18 +7,11 @@ namespace ImageProcessor.Processors { #region Using - - using System; using System.Collections.Generic; using System.Drawing; - using System.Drawing.Drawing2D; using System.Drawing.Imaging; - using System.IO; using System.Text.RegularExpressions; - using System.Web; - using System.Web.Hosting; using ImageProcessor.Imaging.Filters; - #endregion /// @@ -183,8 +176,10 @@ namespace ImageProcessor.Processors break; } - return matrix.ProcessImage(factory, image, newImage); - + if (matrix != null) + { + return matrix.ProcessImage(factory, image, newImage); + } } catch { diff --git a/src/ImageProcessor/Processors/Rotate.cs b/src/ImageProcessor/Processors/Rotate.cs index e8161ef30..560d110f6 100644 --- a/src/ImageProcessor/Processors/Rotate.cs +++ b/src/ImageProcessor/Processors/Rotate.cs @@ -7,13 +7,12 @@ namespace ImageProcessor.Processors { #region Using + using System; using System.Collections.Generic; using System.Drawing; - using System.Drawing.Imaging; - using System.Text.RegularExpressions; - using ImageProcessor.Helpers.Extensions; - using System; using System.Drawing.Drawing2D; + using System.Text.RegularExpressions; + using ImageProcessor.Imaging; #endregion /// @@ -24,24 +23,18 @@ namespace ImageProcessor.Processors /// /// The regular expression to search strings for. /// - //private static readonly Regex QueryRegex = new Regex(@"rotate=-*([1-9][0-7][0-9]|\d{1,2}(?!\d)|180)|rotate=[^&]*", RegexOptions.Compiled); - private static readonly Regex QueryRegex = new Regex(@"rotate=-*([1-2][0-9][0-9]|3[0-5][0-9]|\d{1}(?!\d)|\d{1,2}(?!\d)|360)|rotate=[^&]*", RegexOptions.Compiled); + private static readonly Regex QueryRegex = new Regex(@"rotate=([1-2][0-9][0-9]|3[0-5][0-9]|\d{1}(?!\d)|\d{1,2}(?!\d)|360)|rotate=[^&]*", RegexOptions.Compiled); /// /// The regular expression to search strings for the angle attribute. /// - private static readonly Regex AngleRegex = new Regex(@"rotate=\[-*([1-9][0-7][0-9]|\d{1,2}(?!\d)|180)\]", RegexOptions.Compiled); + private static readonly Regex AngleRegex = new Regex(@"rotate=angle-\[([1-2][0-9][0-9]|3[0-5][0-9]|\d{1}(?!\d)|\d{1,2}(?!\d)|360)\]", RegexOptions.Compiled); /// /// The regular expression to search strings for the color attribute. /// private static readonly Regex ColorRegex = new Regex(@"bgcolor-([0-9a-fA-F]{3}){1,2}", RegexOptions.Compiled); - /// - /// The format of the image to rotate. - /// - private ImageFormat imageFormat; - #region IGraphicsProcessor Members /// /// Gets the name. @@ -127,11 +120,25 @@ namespace ImageProcessor.Processors { // Set the index on the first instance only. this.SortOrder = match.Index; - int degrees; - int.TryParse(match.Value.Split('=')[1], out degrees); + RotateLayer rotateLayer = new RotateLayer(); + + string toParse = match.Value; + + if (toParse.Contains("bgcolor")) + { + rotateLayer.Angle = this.ParseAngle(toParse); + rotateLayer.BackgroundColor = this.ParseColor(toParse); + } + else + { + int degrees; + int.TryParse(match.Value.Split('=')[1], out degrees); + + rotateLayer.Angle = degrees; + } - this.DynamicParameter = degrees; + this.DynamicParameter = rotateLayer; } index += 1; @@ -158,21 +165,20 @@ namespace ImageProcessor.Processors try { - int angle = this.DynamicParameter; + RotateLayer rotateLayer = this.DynamicParameter; + int angle = rotateLayer.Angle; + Color backgroundColor = rotateLayer.BackgroundColor; // Center of the image - float rotateAtX = image.Width / 2; - float rotateAtY = image.Height / 2; - - this.imageFormat = factory.ImageFormat; + float rotateAtX = Math.Abs(image.Width / 2); + float rotateAtY = Math.Abs(image.Height / 2); // Create a rotated image. - newImage = RotateImage(image, rotateAtX, rotateAtY, angle); + newImage = this.RotateImage(image, rotateAtX, rotateAtY, angle, backgroundColor); newImage.Tag = image.Tag; image.Dispose(); image = newImage; - } catch { @@ -186,67 +192,71 @@ namespace ImageProcessor.Processors } #endregion + #region Private Methods /// - /// + /// Rotates an image to the given angle at the given position. /// - /// - /// - /// - /// - /// - /// Based on http://www.codeproject.com/Articles/58815/C-Image-PictureBox-Rotations?msg=4155374#xx4155374xx - private Bitmap RotateImage(Image image, float rotateAtX, float rotateAtY, float angle) + /// The image to rotate + /// The horizontal pixel coordinate at which to rotate the image. + /// The vertical pixel coordinate at which to rotate the image. + /// The angle in degress at which to rotate the image. + /// The background color to fill an image with. + /// The image rotated to the given angle at the given position. + /// + /// Based on http://www.codeproject.com/Articles/58815/C-Image-PictureBox-Rotations?msg=4155374#xx4155374xx + /// + private Bitmap RotateImage(Image image, float rotateAtX, float rotateAtY, float angle, Color backgroundColor) { - int width, height, X, Y; + int width, height, x, y; // Degrees to radians according to Google. - const double degreeToRadian = 0.0174532925; + const double DegreeToRadian = 0.0174532925; - double widthAsDouble = (double)image.Width; - double heightAsDouble = (double)image.Height; + double widthAsDouble = image.Width; + double heightAsDouble = image.Height; // Allow for angles over 180 if (angle > 180) { angle = angle - 360; - } + } - double degrees = Math.Abs(angle); + double degrees = Math.Abs(angle); if (degrees <= 90) { - double radians = degreeToRadian * degrees; + double radians = DegreeToRadian * degrees; double radiansSin = Math.Sin(radians); double radiansCos = Math.Cos(radians); - width = (int)(heightAsDouble * radiansSin + widthAsDouble * radiansCos); - height = (int)(widthAsDouble * radiansSin + heightAsDouble * radiansCos); - X = (width - image.Width) / 2; - Y = (height - image.Height) / 2; + width = (int)((heightAsDouble * radiansSin) + (widthAsDouble * radiansCos)); + height = (int)((widthAsDouble * radiansSin) + (heightAsDouble * radiansCos)); + x = (width - image.Width) / 2; + y = (height - image.Height) / 2; } else { degrees -= 90; - double radians = degreeToRadian * degrees; + double radians = DegreeToRadian * degrees; double radiansSin = Math.Sin(radians); double radiansCos = Math.Cos(radians); - // Fix the 270 bug - if (radiansCos == -1) + // Fix the 270 error + if (Math.Abs(radiansCos - -1.0D) < 0.00001) { - radiansCos = -1 * -1; + radiansCos = 1; } - width = (int)(widthAsDouble * radiansSin + heightAsDouble * radiansCos); - height = (int)(heightAsDouble * radiansSin + widthAsDouble * radiansCos); - X = (width - image.Width) / 2; - Y = (height - image.Height) / 2; + width = (int)((widthAsDouble * radiansSin) + (heightAsDouble * radiansCos)); + height = (int)((heightAsDouble * radiansSin) + (widthAsDouble * radiansCos)); + x = (width - image.Width) / 2; + y = (height - image.Height) / 2; } - //create a new empty bitmap to hold rotated image + // Create a new empty bitmap to hold rotated image Bitmap newImage = new Bitmap(width, height); newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); - //make a graphics object from the empty bitmap + // Make a graphics object from the empty bitmap using (Graphics graphics = Graphics.FromImage(newImage)) { // Reduce the jagged edge. @@ -257,26 +267,67 @@ namespace ImageProcessor.Processors graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.CompositingQuality = CompositingQuality.HighSpeed; - // Fill the background TODO: Set a color - if (this.imageFormat == ImageFormat.Jpeg) - { - graphics.Clear(Color.White); - } + // Fill the background. + graphics.Clear(backgroundColor); // Put the rotation point in the "center" of the image - graphics.TranslateTransform(rotateAtX + X, rotateAtY + Y); + graphics.TranslateTransform(rotateAtX + x, rotateAtY + y); // Rotate the image graphics.RotateTransform(angle); // Move the image back - graphics.TranslateTransform(-rotateAtX - X, -rotateAtY - Y); + graphics.TranslateTransform(-rotateAtX - x, -rotateAtY - y); // Draw passed in image onto graphics object - graphics.DrawImage(image, new PointF(0 + X, 0 + Y)); - + graphics.DrawImage(image, new PointF(0 + x, 0 + y)); } + return newImage; } + + /// + /// Returns the correct containing the angle for the given string. + /// + /// + /// The input string containing the value to parse. + /// + /// + /// The correct containing the angle for the given string. + /// + private int ParseAngle(string input) + { + foreach (Match match in AngleRegex.Matches(input)) + { + // Split on angle- + int angle; + int.TryParse(match.Value.Replace("[", string.Empty).Replace("]", string.Empty).Split('-')[1], out angle); + return angle; + } + + // No rotate - matches the RotateLayer default. + return 0; + } + + /// + /// Returns the correct for the given string. + /// + /// + /// The input string containing the value to parse. + /// + /// + /// The correct + /// + private Color ParseColor(string input) + { + foreach (Match match in ColorRegex.Matches(input)) + { + // split on color-hex + return ColorTranslator.FromHtml("#" + match.Value.Split('-')[1]); + } + + return Color.Transparent; + } + #endregion } } diff --git a/src/ImageProcessor/Processors/Watermark.cs b/src/ImageProcessor/Processors/Watermark.cs index 147ee9fe9..8046545ee 100644 --- a/src/ImageProcessor/Processors/Watermark.cs +++ b/src/ImageProcessor/Processors/Watermark.cs @@ -452,7 +452,7 @@ namespace ImageProcessor.Processors /// The input string containing the value to parse. /// /// - /// The correct containing the font family for the given string. + /// The correct containing the opacity for the given string. /// private int ParseOpacity(string input) { diff --git a/src/ImageProcessor/Properties/AssemblyInfo.cs b/src/ImageProcessor/Properties/AssemblyInfo.cs index f783823f2..ecc917a5c 100644 --- a/src/ImageProcessor/Properties/AssemblyInfo.cs +++ b/src/ImageProcessor/Properties/AssemblyInfo.cs @@ -32,6 +32,6 @@ using System.Security; // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.2.0")] -[assembly: AssemblyFileVersion("1.0.2.0")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] diff --git a/src/ImageProcessor/UpgradeLog.htm.REMOVED.git-id b/src/ImageProcessor/UpgradeLog.htm.REMOVED.git-id new file mode 100644 index 000000000..9d6aad2d1 --- /dev/null +++ b/src/ImageProcessor/UpgradeLog.htm.REMOVED.git-id @@ -0,0 +1 @@ +41192c06780bda40794dac2731a4105f1efe0311 \ No newline at end of file diff --git a/src/Nuget/ImageProcessor.1.1.0.0.nupkg b/src/Nuget/ImageProcessor.1.1.0.0.nupkg new file mode 100644 index 000000000..6113d379b Binary files /dev/null and b/src/Nuget/ImageProcessor.1.1.0.0.nupkg differ diff --git a/src/Nuget/ImageProcessor.Web.1.1.0.0.nupkg b/src/Nuget/ImageProcessor.Web.1.1.0.0.nupkg new file mode 100644 index 000000000..e759b155a Binary files /dev/null and b/src/Nuget/ImageProcessor.Web.1.1.0.0.nupkg differ diff --git a/src/Test/Test/Test.csproj b/src/Test/Test/Test.csproj index 45cf111ad..c629e6249 100644 --- a/src/Test/Test/Test.csproj +++ b/src/Test/Test/Test.csproj @@ -1,5 +1,6 @@  + Debug AnyCPU @@ -15,6 +16,11 @@ v4.0 false false + + + + + 4.0 true @@ -149,8 +155,13 @@ + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + - + +