diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs
index 9f42ba3f3..870f22855 100644
--- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs
+++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs
@@ -466,6 +466,19 @@ namespace ImageProcessor.UnitTests
}
}
+ [Test]
+ public void ImageIsRotatedInside()
+ {
+ foreach (ImageFactory imageFactory in this.ListInputImages())
+ {
+ Image original = (Image)imageFactory.Image.Clone();
+ imageFactory.RotateInside(45);
+
+ imageFactory.Image.Width.Should().Be(original.Width, "because the rotated image dimensions should not have changed");
+ imageFactory.Image.Height.Should().Be(original.Height, "because the rotated image dimensions should not have changed");
+ }
+ }
+
///
/// Tests that the images hue has been altered.
///
diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj
index b1ae1daaf..b47e4b5bc 100644
--- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj
+++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj
@@ -64,6 +64,8 @@
+
+
diff --git a/src/ImageProcessor.UnitTests/Imaging/RotationUnitTests.cs b/src/ImageProcessor.UnitTests/Imaging/RotationUnitTests.cs
new file mode 100644
index 000000000..32eb72e3e
--- /dev/null
+++ b/src/ImageProcessor.UnitTests/Imaging/RotationUnitTests.cs
@@ -0,0 +1,22 @@
+namespace ImageProcessor.UnitTests.Imaging
+{
+ using System.Drawing;
+ using FluentAssertions;
+ using ImageProcessor.Imaging;
+ using NUnit.Framework;
+
+ public class RotationUnitTests
+ {
+ [Test]
+ [TestCase(100, 100, 45, 141, 141)]
+ [TestCase(100, 100, 30, 137, 137)]
+ [TestCase(100, 200, 50, 217, 205)]
+ public void NewSizeAfterRotationIsCalculated(int width, int height, float angle, int expectedWidth, int expectedHeight)
+ {
+ Size result = Rotation.NewSizeAfterRotation(width, height, angle);
+
+ result.Width.Should().Be(expectedWidth, "because the rotated width should have been calculated");
+ result.Height.Should().Be(expectedHeight, "because the rotated height should have been calculated");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageProcessor.UnitTests/Processors/RotateInsideUnitTests.cs b/src/ImageProcessor.UnitTests/Processors/RotateInsideUnitTests.cs
new file mode 100644
index 000000000..36fe5fdcc
--- /dev/null
+++ b/src/ImageProcessor.UnitTests/Processors/RotateInsideUnitTests.cs
@@ -0,0 +1,16 @@
+namespace ImageProcessor.UnitTests.Processors
+{
+ using System.Collections.Generic;
+ using ImageProcessor.Processors;
+ using NUnit.Framework;
+
+ public class RotateInsideUnitTests
+ {
+ [Test]
+ [TestCase(100, 100, 15, 150)]
+ public void ZoomIsCalculated(int width, int height, float angle, float expected)
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index c5187d3ed..94848c1a8 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -214,6 +214,7 @@
+
diff --git a/src/ImageProcessor/Imaging/Rotation.cs b/src/ImageProcessor/Imaging/Rotation.cs
new file mode 100644
index 000000000..8ae02f719
--- /dev/null
+++ b/src/ImageProcessor/Imaging/Rotation.cs
@@ -0,0 +1,43 @@
+namespace ImageProcessor.Imaging
+{
+ using System;
+ using System.Drawing;
+
+ ///
+ /// Provides rotation calculation methods
+ ///
+ internal class Rotation
+ {
+ ///
+ /// Calculates the new size after rotation.
+ ///
+ /// The width of the image.
+ /// The height of the image.
+ /// The angle of rotation.
+ /// The new size of the image
+ public static Size NewSizeAfterRotation(int width, int height, float angle)
+ {
+ double widthAsDouble = width;
+ double heightAsDouble = height;
+
+ double radians = angle * Math.PI / 180d;
+ double radiansSin = Math.Sin(radians);
+ double radiansCos = Math.Cos(radians);
+ double width1 = (heightAsDouble * radiansSin) + (widthAsDouble * radiansCos);
+ double height1 = (widthAsDouble * radiansSin) + (heightAsDouble * radiansCos);
+
+ // Find dimensions in the other direction
+ radiansSin = Math.Sin(-radians);
+ radiansCos = Math.Cos(-radians);
+ double width2 = (heightAsDouble * radiansSin) + (widthAsDouble * radiansCos);
+ double height2 = (widthAsDouble * radiansSin) + (heightAsDouble * radiansCos);
+
+ // Get the external vertex for the rotation
+ Size result = new Size();
+ result.Width = Convert.ToInt32(Math.Max(Math.Abs(width1), Math.Abs(width2)));
+ result.Height = Convert.ToInt32(Math.Max(Math.Abs(height1), Math.Abs(height2)));
+
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageProcessor/Processors/Rotate.cs b/src/ImageProcessor/Processors/Rotate.cs
index 2cd57a665..d0715884f 100644
--- a/src/ImageProcessor/Processors/Rotate.cs
+++ b/src/ImageProcessor/Processors/Rotate.cs
@@ -104,30 +104,13 @@ namespace ImageProcessor.Processors
///
private Bitmap RotateImage(Image image, float rotateAtX, float rotateAtY, float angle)
{
- double widthAsDouble = image.Width;
- double heightAsDouble = image.Height;
+ Size newSize = Imaging.Rotation.NewSizeAfterRotation(image.Width, image.Height, angle);
- double radians = angle * Math.PI / 180d;
- double radiansSin = Math.Sin(radians);
- double radiansCos = Math.Cos(radians);
- double width1 = (heightAsDouble * radiansSin) + (widthAsDouble * radiansCos);
- double height1 = (widthAsDouble * radiansSin) + (heightAsDouble * radiansCos);
-
- // Find dimensions in the other direction
- radiansSin = Math.Sin(-radians);
- radiansCos = Math.Cos(-radians);
- double width2 = (heightAsDouble * radiansSin) + (widthAsDouble * radiansCos);
- double height2 = (widthAsDouble * radiansSin) + (heightAsDouble * radiansCos);
-
- // Get the external vertex for the rotation
- int width = Convert.ToInt32(Math.Max(Math.Abs(width1), Math.Abs(width2)));
- int height = Convert.ToInt32(Math.Max(Math.Abs(height1), Math.Abs(height2)));
-
- int x = (width - image.Width) / 2;
- int y = (height - image.Height) / 2;
+ int x = (newSize.Width - image.Width) / 2;
+ int y = (newSize.Height - image.Height) / 2;
// Create a new empty bitmap to hold rotated image
- Bitmap newImage = new Bitmap(width, height);
+ Bitmap newImage = new Bitmap(newSize.Width, newSize.Height);
newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
// Make a graphics object from the empty bitmap
diff --git a/src/ImageProcessor/Processors/RotateInside.cs b/src/ImageProcessor/Processors/RotateInside.cs
index 919f846b4..f958db8d7 100644
--- a/src/ImageProcessor/Processors/RotateInside.cs
+++ b/src/ImageProcessor/Processors/RotateInside.cs
@@ -13,6 +13,8 @@ namespace ImageProcessor.Processors
using System;
using System.Collections.Generic;
using System.Drawing;
+ using System.Drawing.Drawing2D;
+ using ImageProcessor.Common.Exceptions;
///
/// Encapsulates the methods to rotate the inside of an image
@@ -37,10 +39,92 @@ namespace ImageProcessor.Processors
///
/// The processed image from the current instance of the class.
///
+ ///
+ /// Based on
+ ///
public Image ProcessImage(ImageFactory factory)
{
- // TODO: Implement this method
- throw new NotImplementedException();
+ Bitmap newImage = null;
+ Image image = factory.Image;
+
+ try
+ {
+ float angle = this.DynamicParameter;
+
+ // Center of the image
+ float rotateAtX = Math.Abs(image.Width / 2);
+ float rotateAtY = Math.Abs(image.Height / 2);
+
+ // Create a rotated image.
+ newImage = this.RotateImage(image, rotateAtX, rotateAtY, angle);
+
+ image.Dispose();
+ image = newImage;
+ }
+ catch (Exception ex)
+ {
+ if (newImage != null)
+ {
+ newImage.Dispose();
+ }
+
+ throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex);
+ }
+
+ return image;
+ }
+
+ private Bitmap RotateImage(Image image, float rotateAtX, float rotateAtY, float angle)
+ {
+ double widthAsDouble = image.Width;
+ double heightAsDouble = image.Height;
+
+ double radians = angle * Math.PI / 180d;
+ double radiansSin = Math.Sin(radians);
+ double radiansCos = Math.Cos(radians);
+ double width1 = (heightAsDouble * radiansSin) + (widthAsDouble * radiansCos);
+ double height1 = (widthAsDouble * radiansSin) + (heightAsDouble * radiansCos);
+
+ // Find dimensions in the other direction
+ radiansSin = Math.Sin(-radians);
+ radiansCos = Math.Cos(-radians);
+ double width2 = (heightAsDouble * radiansSin) + (widthAsDouble * radiansCos);
+ double height2 = (widthAsDouble * radiansSin) + (heightAsDouble * radiansCos);
+
+ // Get the external vertex for the rotation
+ int width = Convert.ToInt32(Math.Max(Math.Abs(width1), Math.Abs(width2)));
+ int height = Convert.ToInt32(Math.Max(Math.Abs(height1), Math.Abs(height2)));
+
+ int x = (width - image.Width) / 2;
+ int y = (height - image.Height) / 2;
+
+ // 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
+ using (Graphics graphics = Graphics.FromImage(newImage))
+ {
+ // Reduce the jagged edge.
+ graphics.SmoothingMode = SmoothingMode.AntiAlias;
+ graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ graphics.CompositingQuality = CompositingQuality.HighQuality;
+
+ // Put the rotation point in the "center" of the image
+ graphics.TranslateTransform(rotateAtX + x, rotateAtY + y);
+
+ // Rotate the image
+ graphics.RotateTransform(angle);
+
+ // Move the image back
+ graphics.TranslateTransform(-rotateAtX - x, -rotateAtY - y);
+
+ // Draw passed in image onto graphics object
+ graphics.DrawImage(image, new PointF(x, y));
+ }
+
+ return newImage;
}
}
}
\ No newline at end of file
diff --git a/src/ImageProcessor/Properties/AssemblyInfo.cs b/src/ImageProcessor/Properties/AssemblyInfo.cs
index 2f753e3b7..e198b5672 100644
--- a/src/ImageProcessor/Properties/AssemblyInfo.cs
+++ b/src/ImageProcessor/Properties/AssemblyInfo.cs
@@ -9,6 +9,7 @@
// --------------------------------------------------------------------------------------------------------------------
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@@ -42,3 +43,5 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
[assembly: AssemblyVersion("2.2.0.0")]
[assembly: AssemblyFileVersion("2.2.0.0")]
+
+[assembly: InternalsVisibleTo("ImageProcessor.UnitTests")]
\ No newline at end of file