From fedc490f14d9a63e11e6b0a9eb0738a452af25d9 Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 15 Jun 2014 00:14:55 +0200 Subject: [PATCH] Adding Autorotate Former-commit-id: d32cd0082a0ef28e721b37eadb650dfb55776694 --- .../NET45/Config/Resources/processing.config | 1 + src/ImageProcessor/ImageFactory.cs | 91 ++++++---- src/ImageProcessor/ImageProcessor.csproj | 1 + src/ImageProcessor/Processors/AutoRotate.cs | 158 ++++++++++++++++++ src/Images/rotate.jpg.REMOVED.git-id | 1 + 5 files changed, 223 insertions(+), 29 deletions(-) create mode 100644 src/ImageProcessor/Processors/AutoRotate.cs create mode 100644 src/Images/rotate.jpg.REMOVED.git-id diff --git a/src/ImageProcessor.Web/NET45/Config/Resources/processing.config b/src/ImageProcessor.Web/NET45/Config/Resources/processing.config index 562cafcb89..e792c39505 100644 --- a/src/ImageProcessor.Web/NET45/Config/Resources/processing.config +++ b/src/ImageProcessor.Web/NET45/Config/Resources/processing.config @@ -3,6 +3,7 @@ + diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index b88c3d3bf5..31665c2a63 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -182,12 +182,10 @@ namespace ImageProcessor this.backupImageFormat = this.ImageFormat; this.isIndexed = ImageUtils.IsIndexed(this.Image); - if (this.PreserveExifData) + // Always load the data. + foreach (PropertyItem propertyItem in this.Image.PropertyItems) { - foreach (PropertyItem propertyItem in this.Image.PropertyItems) - { - this.ExifPropertyItems[propertyItem.Id] = propertyItem; - } + this.ExifPropertyItems[propertyItem.Id] = propertyItem; } this.ShouldProcess = true; @@ -244,12 +242,10 @@ namespace ImageProcessor this.ImageFormat = imageFormat; this.isIndexed = ImageUtils.IsIndexed(this.Image); - if (this.PreserveExifData) + // Always load the data. + foreach (PropertyItem propertyItem in this.Image.PropertyItems) { - foreach (PropertyItem propertyItem in this.Image.PropertyItems) - { - this.ExifPropertyItems[propertyItem.Id] = propertyItem; - } + this.ExifPropertyItems[propertyItem.Id] = propertyItem; } this.ShouldProcess = true; @@ -347,6 +343,24 @@ namespace ImageProcessor return this; } + /// + /// Performs auto-rotation to ensure that EXIF defined rotation is reflected in + /// the final image. + /// + /// + /// The current instance of the class. + /// + public ImageFactory AutoRotate() + { + if (this.ShouldProcess) + { + AutoRotate autoRotate = new AutoRotate(); + this.ApplyProcessor(autoRotate.ProcessImage); + } + + return this; + } + /// /// Changes the brightness of the current image. /// @@ -868,6 +882,25 @@ namespace ImageProcessor // Fix the colour palette of indexed images. this.FixIndexedPallete(); + // Set the property item information from any Exif metadata. + // We do this here so that they can be changed between processor methods. + if (this.PreserveExifData) + { + foreach (KeyValuePair propertItem in this.ExifPropertyItems) + { + try + { + this.Image.SetPropertyItem(propertItem.Value); + } + // ReSharper disable once EmptyGeneralCatchClause + catch + { + // Do nothing. The image format does not handle EXIF data. + // TODO: empty catch is fierce code smell. + } + } + } + // ReSharper disable once AssignNullToNotNullAttribute DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(filePath)); @@ -944,6 +977,25 @@ namespace ImageProcessor // Fix the colour palette of gif and png8 images. this.FixIndexedPallete(); + // Set the property item information from any Exif metadata. + // We do this here so that they can be changed between processor methods. + if (this.PreserveExifData) + { + foreach (KeyValuePair propertItem in this.ExifPropertyItems) + { + try + { + this.Image.SetPropertyItem(propertItem.Value); + } + // ReSharper disable once EmptyGeneralCatchClause + catch + { + // Do nothing. The image format does not handle EXIF data. + // TODO: empty catch is fierce code smell. + } + } + } + if (this.ImageFormat.Equals(ImageFormat.Jpeg)) { // Jpegs can be saved with different settings to include a quality setting for the JPEG compression. @@ -1074,25 +1126,6 @@ namespace ImageProcessor { this.Image = processor.Invoke(this); } - - // Set the property item information from any Exif metadata. - // We do this here so that they can be changed between processor methods. - if (this.PreserveExifData) - { - foreach (KeyValuePair propertItem in this.ExifPropertyItems) - { - try - { - this.Image.SetPropertyItem(propertItem.Value); - } - // ReSharper disable once EmptyGeneralCatchClause - catch - { - // Do nothing. The image format does not handle EXIF data. - // TODO: empty catch is fierce code smell. - } - } - } } #endregion } diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 54aa058bb2..026c166c4b 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -100,6 +100,7 @@ + diff --git a/src/ImageProcessor/Processors/AutoRotate.cs b/src/ImageProcessor/Processors/AutoRotate.cs new file mode 100644 index 0000000000..e99f6c905c --- /dev/null +++ b/src/ImageProcessor/Processors/AutoRotate.cs @@ -0,0 +1,158 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Performs auto-rotation to ensure that EXIF defined rotation is reflected in +// the final image. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + using System.Collections.Generic; + using System.Drawing; + using System.Text.RegularExpressions; + using ImageProcessor.Imaging; + + /// + /// Performs auto-rotation to ensure that EXIF defined rotation is reflected in + /// the final image. + /// + public class AutoRotate : IGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"autorotate=true", RegexOptions.Compiled); + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets or sets DynamicParameter. + /// + public dynamic DynamicParameter + { + get; + set; + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder + { + get; + private set; + } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings + { + get; + set; + } + + /// + /// The position in the original string where the first character of the captured substring was found. + /// + /// + /// The query string to search. + /// + /// + /// The zero-based starting position in the original string where the captured substring was found. + /// + public int MatchRegexIndex(string queryString) + { + int index = 0; + + // Set the sort order to max to allow filtering. + this.SortOrder = int.MaxValue; + + foreach (Match match in this.RegexPattern.Matches(queryString)) + { + if (match.Success) + { + if (index == 0) + { + // Set the index on the first instance only. + this.SortOrder = match.Index; + } + + index += 1; + } + } + + return this.SortOrder; + } + + /// + /// Processes the image. + /// + /// The the current instance of the + /// class containing + /// the image to process. + /// + /// The processed image from the current instance of the class. + /// + public Image ProcessImage(ImageFactory factory) + { + Bitmap newImage = null; + Image image = factory.Image; + + try + { + const int Orientation = (int)ExifPropertyTag.Orientation; + if (!factory.PreserveExifData && factory.ExifPropertyItems.ContainsKey(Orientation)) + { + newImage = new Bitmap(image); + + int rotationValue = factory.ExifPropertyItems[Orientation].Value[0]; + switch (rotationValue) + { + case 1: // Landscape, do nothing + break; + + case 8: // Rotated 90 right + // De-rotate: + newImage.RotateFlip(RotateFlipType.Rotate270FlipNone); + break; + + case 3: // Bottoms up + newImage.RotateFlip(RotateFlipType.Rotate180FlipNone); + break; + + case 6: // Rotated 90 left + newImage.RotateFlip(RotateFlipType.Rotate90FlipNone); + break; + } + + // Reassign the image. + image.Dispose(); + image = newImage; + } + } + catch + { + if (newImage != null) + { + newImage.Dispose(); + } + } + + return image; + } + } +} \ No newline at end of file diff --git a/src/Images/rotate.jpg.REMOVED.git-id b/src/Images/rotate.jpg.REMOVED.git-id new file mode 100644 index 0000000000..bf0538b247 --- /dev/null +++ b/src/Images/rotate.jpg.REMOVED.git-id @@ -0,0 +1 @@ +406a6a7916628c0c0bea8243565a7162ebd5a505 \ No newline at end of file