From 37c242816a0f2865f3e5f3247f441e82dd81f4ea Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 10 Jun 2014 00:42:30 +0200 Subject: [PATCH 001/155] Initial commit THIS WON'T BUILD JUST NOW. Former-commit-id: 89c0a9c493cd0adb90638b5ebc79ef5b82f8a902 --- .../NET45/Caching/DiskCache.cs | 8 +- .../NET45/Config/ImageCacheSection.cs | 4 +- .../NET45/Config/ImageProcessingSection.cs | 2 +- ...nfig.cs => ImageProcessorConfiguration.cs} | 12 +- .../NET45/Config/ImageSecuritySection.cs | 2 +- .../NET45/Helpers/ParameterParserUtilities.cs | 90 +++++ .../NET45/Helpers/RemoteFile.cs | 12 +- .../HttpModules/ImageProcessingModule.cs | 13 +- .../NET45/ImageFactoryExtensions.cs | 71 +--- .../NET45/ImageProcessor.Web_NET45.csproj | 6 +- .../NET45/Processors/BackgroundColor.cs | 88 +++++ .../NET45/Processors/IWebGraphicsProcessor.cs | 51 +++ .../NET45/Processors/Rotate.cs | 96 +++++ .../NET45/Processors/RoundedCorners.cs | 24 ++ .../ImageProcessorBootstrapper.cs | 81 +++++ .../Common/Exceptions/ImageFormatException.cs | 39 ++ .../Exceptions/ImageProcessingException.cs | 39 ++ .../Common}/Extensions/DoubleExtensions.cs | 2 +- .../Common}/Extensions/ImageExtensions.cs | 3 +- .../Extensions/ImageFormatExtensions.cs | 4 +- .../{ => Core/Common}/Extensions/ImageInfo.cs | 3 +- .../Common}/Extensions/IntegerExtensions.cs | 2 +- .../Common}/Extensions/StringExtensions.cs | 4 +- src/ImageProcessor/ImageFactory.cs | 332 +++++------------- src/ImageProcessor/ImageProcessor.csproj | 24 +- src/ImageProcessor/Imaging/Convolution.cs | 3 +- .../Imaging/Filters/ComicMatrixFilter.cs | 2 +- .../Imaging/Formats/BitmapFormat.cs | 65 ++++ .../Imaging/Formats/FormatBase.cs | 123 +++++++ .../Imaging/Formats/FormatUtilities.cs | 88 +++++ .../Imaging/Formats/GifFormat.cs | 149 ++++++++ .../Imaging/Formats/ISupportedImageFormat.cs | 113 ++++++ .../Imaging/Formats/JpegFormat.cs | 155 ++++++++ .../Imaging/Formats/PngFormat.cs | 103 ++++++ .../Imaging/Formats/TiffFormat.cs | 96 +++++ .../Processors/BackgroundColor.cs | 74 ++++ src/ImageProcessor/Processors/Crop.cs | 2 +- src/ImageProcessor/Processors/Format.cs | 3 +- .../Processors/IGraphicsProcessor.cs | 27 +- src/ImageProcessor/Processors/Quality.cs | 2 +- src/ImageProcessor/Processors/Resize.cs | 3 +- src/ImageProcessor/Processors/Rotate.cs | 150 +------- src/ImageProcessor/Processors/Tint.cs | 3 +- src/ImageProcessor/Processors/Watermark.cs | 2 +- src/ImageProcessor/Settings.StyleCop | 2 + src/ImageProcessorConsole/Program.cs | 4 +- .../images/output/120430.gif.REMOVED.git-id | 2 +- .../images/output/nLpfllv.gif.REMOVED.git-id | 2 +- 48 files changed, 1659 insertions(+), 526 deletions(-) rename src/ImageProcessor.Web/NET45/Config/{ImageProcessorConfig.cs => ImageProcessorConfiguration.cs} (97%) create mode 100644 src/ImageProcessor.Web/NET45/Helpers/ParameterParserUtilities.cs create mode 100644 src/ImageProcessor.Web/NET45/Processors/BackgroundColor.cs create mode 100644 src/ImageProcessor.Web/NET45/Processors/IWebGraphicsProcessor.cs create mode 100644 src/ImageProcessor.Web/NET45/Processors/Rotate.cs create mode 100644 src/ImageProcessor.Web/NET45/Processors/RoundedCorners.cs create mode 100644 src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs create mode 100644 src/ImageProcessor/Core/Common/Exceptions/ImageFormatException.cs create mode 100644 src/ImageProcessor/Core/Common/Exceptions/ImageProcessingException.cs rename src/ImageProcessor/{ => Core/Common}/Extensions/DoubleExtensions.cs (96%) rename src/ImageProcessor/{ => Core/Common}/Extensions/ImageExtensions.cs (98%) rename src/ImageProcessor/{ => Core/Common}/Extensions/ImageFormatExtensions.cs (98%) rename src/ImageProcessor/{ => Core/Common}/Extensions/ImageInfo.cs (97%) rename src/ImageProcessor/{ => Core/Common}/Extensions/IntegerExtensions.cs (97%) rename src/ImageProcessor/{ => Core/Common}/Extensions/StringExtensions.cs (99%) create mode 100644 src/ImageProcessor/Imaging/Formats/BitmapFormat.cs create mode 100644 src/ImageProcessor/Imaging/Formats/FormatBase.cs create mode 100644 src/ImageProcessor/Imaging/Formats/FormatUtilities.cs create mode 100644 src/ImageProcessor/Imaging/Formats/GifFormat.cs create mode 100644 src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs create mode 100644 src/ImageProcessor/Imaging/Formats/JpegFormat.cs create mode 100644 src/ImageProcessor/Imaging/Formats/PngFormat.cs create mode 100644 src/ImageProcessor/Imaging/Formats/TiffFormat.cs create mode 100644 src/ImageProcessor/Processors/BackgroundColor.cs diff --git a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs index 8052e0540..5b0562dc6 100644 --- a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs @@ -21,8 +21,8 @@ namespace ImageProcessor.Web.Caching using System.Web; using System.Web.Hosting; - using ImageProcessor.Extensions; - using ImageProcessor.Web.Config; + using ImageProcessor.Core.Common.Extensions; + using ImageProcessor.Web.Configuration; using ImageProcessor.Web.Helpers; #endregion @@ -35,7 +35,7 @@ namespace ImageProcessor.Web.Caching /// /// The maximum number of days to cache files on the system for. /// - internal static readonly int MaxFileCachedDuration = ImageProcessorConfig.Instance.MaxCacheDays; + internal static readonly int MaxFileCachedDuration = ImageProcessorConfiguration.Instance.MaxCacheDays; /// /// The maximum number of files allowed in the directory. @@ -53,7 +53,7 @@ namespace ImageProcessor.Web.Caching /// The absolute path to virtual cache path on the server. /// private static readonly string AbsoluteCachePath = - HostingEnvironment.MapPath(ImageProcessorConfig.Instance.VirtualCachePath); + HostingEnvironment.MapPath(ImageProcessorConfiguration.Instance.VirtualCachePath); /// /// The request for the image. diff --git a/src/ImageProcessor.Web/NET45/Config/ImageCacheSection.cs b/src/ImageProcessor.Web/NET45/Config/ImageCacheSection.cs index 6bda16a44..27e5320c3 100644 --- a/src/ImageProcessor.Web/NET45/Config/ImageCacheSection.cs +++ b/src/ImageProcessor.Web/NET45/Config/ImageCacheSection.cs @@ -8,14 +8,14 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Web.Config +namespace ImageProcessor.Web.Configuration { #region Using using System.Configuration; using System.IO; using System.Xml; - using ImageProcessor.Extensions; + using ImageProcessor.Core.Common.Extensions; using ImageProcessor.Web.Helpers; #endregion diff --git a/src/ImageProcessor.Web/NET45/Config/ImageProcessingSection.cs b/src/ImageProcessor.Web/NET45/Config/ImageProcessingSection.cs index d1018ba89..3942280f6 100644 --- a/src/ImageProcessor.Web/NET45/Config/ImageProcessingSection.cs +++ b/src/ImageProcessor.Web/NET45/Config/ImageProcessingSection.cs @@ -9,7 +9,7 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Web.Config +namespace ImageProcessor.Web.Configuration { #region Using using System.Configuration; diff --git a/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs b/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfiguration.cs similarity index 97% rename from src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs rename to src/ImageProcessor.Web/NET45/Config/ImageProcessorConfiguration.cs index c85c25039..2bcf73d78 100644 --- a/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfig.cs +++ b/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfiguration.cs @@ -8,7 +8,7 @@ // // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Web.Config +namespace ImageProcessor.Web.Configuration { #region Using using System; @@ -24,15 +24,15 @@ namespace ImageProcessor.Web.Config /// Encapsulates methods to allow the retrieval of ImageProcessor settings. /// /// - public sealed class ImageProcessorConfig + public sealed class ImageProcessorConfiguration { #region Fields /// /// A new instance Initializes a new instance of the class. /// with lazy initialization. /// - private static readonly Lazy Lazy = - new Lazy(() => new ImageProcessorConfig()); + private static readonly Lazy Lazy = + new Lazy(() => new ImageProcessorConfiguration()); /// /// A collection of the elements @@ -67,7 +67,7 @@ namespace ImageProcessor.Web.Config /// /// Prevents a default instance of the class from being created. /// - private ImageProcessorConfig() + private ImageProcessorConfiguration() { this.LoadGraphicsProcessors(); } @@ -77,7 +77,7 @@ namespace ImageProcessor.Web.Config /// /// Gets the current instance of the class. /// - public static ImageProcessorConfig Instance + public static ImageProcessorConfiguration Instance { get { diff --git a/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs b/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs index 824cf8277..29079fdc2 100644 --- a/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs +++ b/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs @@ -8,7 +8,7 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Web.Config +namespace ImageProcessor.Web.Configuration { #region Using using System; diff --git a/src/ImageProcessor.Web/NET45/Helpers/ParameterParserUtilities.cs b/src/ImageProcessor.Web/NET45/Helpers/ParameterParserUtilities.cs new file mode 100644 index 000000000..eb6af4357 --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Helpers/ParameterParserUtilities.cs @@ -0,0 +1,90 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates methods to correctly parse querystring parameters. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Helpers +{ + using System.Drawing; + using System.Globalization; + using System.Text.RegularExpressions; + using ImageProcessor.Core.Common.Extensions; + + /// + /// Encapsulates methods to correctly parse querystring parameters. + /// + public static class ParameterParserUtilities + { + /// + /// The regular expression to search strings for colors. + /// + private static readonly Regex ColorRegex = new Regex(@"(bgcolor|color)(=|-)(\d+,\d+,\d+,\d+|([0-9a-fA-F]{3}){1,2})", RegexOptions.Compiled); + + /// + /// The regular expression to search strings for angles. + /// + private static readonly Regex AngleRegex = new Regex(@"(rotate|angle)(=|-)(?:3[0-5][0-9]|[12][0-9]{2}|[1-9][0-9]?)", RegexOptions.Compiled); + + /// + /// 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. + /// + public static int ParseAngle(string input) + { + foreach (Match match in AngleRegex.Matches(input)) + { + // Split on angle + int angle; + string value = match.Value.Split(new[] { '=', '-' })[1]; + int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, 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 + /// + public static Color ParseColor(string input) + { + foreach (Match match in ColorRegex.Matches(input)) + { + string value = match.Value.Split(new[] { '=', '-' })[1]; + + if (value.Contains(",")) + { + int[] split = value.ToPositiveIntegerArray(); + byte red = split[0].ToByte(); + byte green = split[1].ToByte(); + byte blue = split[2].ToByte(); + byte alpha = split[3].ToByte(); + + return Color.FromArgb(alpha, red, green, blue); + } + + // Split on color-hex + return ColorTranslator.FromHtml("#" + value); + } + + return Color.Transparent; + } + } +} diff --git a/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs b/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs index 05c2f9753..1fa38568c 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs @@ -19,7 +19,7 @@ namespace ImageProcessor.Web.Helpers using System.Security; using System.Text; using System.Threading.Tasks; - using ImageProcessor.Web.Config; + using ImageProcessor.Web.Configuration; #endregion /// @@ -48,27 +48,27 @@ namespace ImageProcessor.Web.Helpers /// /// The white-list of url[s] from which to download remote files. /// - public static readonly ImageSecuritySection.SafeUrl[] RemoteFileWhiteListExtensions = ImageProcessorConfig.Instance.RemoteFileWhiteListExtensions; + public static readonly ImageSecuritySection.SafeUrl[] RemoteFileWhiteListExtensions = ImageProcessorConfiguration.Instance.RemoteFileWhiteListExtensions; /// /// The white-list of url[s] from which to download remote files. /// - private static readonly Uri[] RemoteFileWhiteList = ImageProcessorConfig.Instance.RemoteFileWhiteList; + private static readonly Uri[] RemoteFileWhiteList = ImageProcessorConfiguration.Instance.RemoteFileWhiteList; /// /// The length of time, in milliseconds, that a remote file download attempt can last before timing out. /// - private static readonly int TimeoutMilliseconds = ImageProcessorConfig.Instance.Timeout; + private static readonly int TimeoutMilliseconds = ImageProcessorConfiguration.Instance.Timeout; /// /// The maximum size, in bytes, that a remote file download attempt can download. /// - private static readonly int MaxBytes = ImageProcessorConfig.Instance.MaxBytes; + private static readonly int MaxBytes = ImageProcessorConfiguration.Instance.MaxBytes; /// /// Whether to allow remote downloads. /// - private static readonly bool AllowRemoteDownloads = ImageProcessorConfig.Instance.AllowRemoteDownloads; + private static readonly bool AllowRemoteDownloads = ImageProcessorConfiguration.Instance.AllowRemoteDownloads; /// /// Whether this RemoteFile instance is ignoring remote download rules set in the current application diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index efcbdc2ed..6d10a49ee 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -28,9 +28,10 @@ namespace ImageProcessor.Web.HttpModules using System.Web; using System.Web.Hosting; using System.Web.Security; - using ImageProcessor.Extensions; + + using ImageProcessor.Core.Common.Extensions; using ImageProcessor.Web.Caching; - using ImageProcessor.Web.Config; + using ImageProcessor.Web.Configuration; using ImageProcessor.Web.Helpers; #endregion @@ -117,12 +118,12 @@ namespace ImageProcessor.Web.HttpModules { if (remotePrefix == null) { - remotePrefix = ImageProcessorConfig.Instance.RemotePrefix; + remotePrefix = ImageProcessorConfiguration.Instance.RemotePrefix; } if (preserveExifMetaData == null) { - preserveExifMetaData = ImageProcessorConfig.Instance.PreserveExifMetaData; + preserveExifMetaData = ImageProcessorConfiguration.Instance.PreserveExifMetaData; } #if NET45 @@ -453,7 +454,7 @@ namespace ImageProcessor.Web.HttpModules imageFactory.Load(fullPath).AutoProcess().Save(cachedPath); // Store the response type in the context for later retrieval. - context.Items[CachedResponseTypeKey] = imageFactory.MimeType; + context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType; // Ensure that the LastWriteTime property of the source and cached file match. Tuple creationAndLastWriteDateTimes = await cache.SetCachedLastWriteTimeAsync(); @@ -555,7 +556,7 @@ namespace ImageProcessor.Web.HttpModules string preset = match.Value.Split('=')[1]; // We use the processor config system to store the preset values. - string replacements = ImageProcessorConfig.Instance.GetPresetSettings(preset); + string replacements = ImageProcessorConfiguration.Instance.GetPresetSettings(preset); queryString = Regex.Replace(queryString, preset, replacements ?? string.Empty); } } diff --git a/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs b/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs index 0c8788cd9..c677149fb 100644 --- a/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs +++ b/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs @@ -11,17 +11,10 @@ namespace ImageProcessor.Web { #region Using - - using System; using System.Collections.Generic; - using System.Drawing; - using System.Drawing.Imaging; - using System.IO; using System.Linq; - using ImageProcessor.Extensions; - using ImageProcessor.Imaging; using ImageProcessor.Processors; - using ImageProcessor.Web.Config; + using ImageProcessor.Web.Configuration; #endregion /// @@ -53,7 +46,7 @@ namespace ImageProcessor.Web { // Get a list of all graphics processors that have parsed and matched the query string. List graphicsProcessors = - ImageProcessorConfig.Instance.GraphicsProcessors + ImageProcessorConfiguration.Instance.GraphicsProcessors .Where(x => x.MatchRegexIndex(factory.QueryString) != int.MaxValue) .OrderBy(y => y.SortOrder) .ToList(); @@ -61,70 +54,12 @@ namespace ImageProcessor.Web // Loop through and process the image. foreach (IGraphicsProcessor graphicsProcessor in graphicsProcessors) { - ApplyProcessor(graphicsProcessor.ProcessImage, factory); + factory.CurrentImageFormat.ApplyProcessor(graphicsProcessor.ProcessImage, factory); } } } return factory; } - - /// - /// Processes the image. - /// - /// - /// The processor. - /// - /// - /// The factory. - /// - private static void ApplyProcessor(Func processor, ImageFactory factory) - { - ImageInfo imageInfo = factory.Image.GetImageInfo(factory.ImageFormat); - - if (imageInfo.IsAnimated) - { - OctreeQuantizer quantizer = new OctreeQuantizer(255, 8); - - // We don't dispose of the memory stream as that is disposed when a new image is created and doing so - // beforehand will cause an exception. - MemoryStream stream = new MemoryStream(); - using (GifEncoder encoder = new GifEncoder(stream, null, null, imageInfo.LoopCount)) - { - foreach (GifFrame frame in imageInfo.GifFrames) - { - factory.Update(frame.Image); - frame.Image = quantizer.Quantize(processor.Invoke(factory)); - encoder.AddFrame(frame); - } - } - - stream.Position = 0; - factory.Update(Image.FromStream(stream)); - } - else - { - factory.Update(processor.Invoke(factory)); - } - - // Set the property item information from any Exif metadata. - // We do this here so that they can be changed between processor methods. - if (factory.PreserveExifData) - { - foreach (KeyValuePair propertItem in factory.ExifPropertyItems) - { - try - { - factory.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. - } - } - } - } } } diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index 23cc45e96..bdf8ba8dc 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -51,14 +51,18 @@ - + + + + + diff --git a/src/ImageProcessor.Web/NET45/Processors/BackgroundColor.cs b/src/ImageProcessor.Web/NET45/Processors/BackgroundColor.cs new file mode 100644 index 000000000..7fc0a49a5 --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/BackgroundColor.cs @@ -0,0 +1,88 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Changes the background color of an image. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System.Text.RegularExpressions; + using ImageProcessor.Processors; + using ImageProcessor.Web.Helpers; + + /// + /// Changes the background color of an image. + /// + public class BackgroundColor : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"bgcolor(=|-)[^&|,]*", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public BackgroundColor() + { + this.Processor = new ImageProcessor.Processors.BackgroundColor(); + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder { get; private set; } + + /// + /// Gets the associated graphics processor. + /// + public IGraphicsProcessor Processor { get; private 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; + this.Processor.DynamicParameter = ParameterParserUtilities.ParseColor(match.Value); + } + + index += 1; + } + } + + return this.SortOrder; + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET45/Processors/IWebGraphicsProcessor.cs b/src/ImageProcessor.Web/NET45/Processors/IWebGraphicsProcessor.cs new file mode 100644 index 000000000..b15d86d30 --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/IWebGraphicsProcessor.cs @@ -0,0 +1,51 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Defines properties and methods for ImageProcessor.Web Plugins. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System.Text.RegularExpressions; + using ImageProcessor.Processors; + + /// + /// Defines properties and methods for ImageProcessor.Web Plugins. + /// + public interface IWebGraphicsProcessor + { + #region Properties + /// + /// Gets the regular expression to search strings for. + /// + Regex RegexPattern { get; } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + int SortOrder { get; } + + /// + /// Gets the associated graphics processor. + /// + IGraphicsProcessor Processor { get; } + #endregion + + #region Methods + /// + /// 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. + /// + int MatchRegexIndex(string queryString); + #endregion + } +} diff --git a/src/ImageProcessor.Web/NET45/Processors/Rotate.cs b/src/ImageProcessor.Web/NET45/Processors/Rotate.cs new file mode 100644 index 000000000..58375b179 --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/Rotate.cs @@ -0,0 +1,96 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates methods to rotate an image. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System.Text.RegularExpressions; + using ImageProcessor.Processors; + using ImageProcessor.Web.Helpers; + + /// + /// Encapsulates methods to rotate an image. + /// + public class Rotate : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"(rotate|angle)(=|-)[^&|,]*", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public Rotate() + { + this.Processor = new ImageProcessor.Processors.Rotate(); + } + + #region IGraphicsProcessor Members + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder + { + get; + private set; + } + + /// + /// Gets the associated graphics processor. + /// + public IGraphicsProcessor Processor { get; private 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; + this.Processor.DynamicParameter = ParameterParserUtilities.ParseAngle(match.Value); + } + + index += 1; + } + } + + return this.SortOrder; + } + #endregion + } +} diff --git a/src/ImageProcessor.Web/NET45/Processors/RoundedCorners.cs b/src/ImageProcessor.Web/NET45/Processors/RoundedCorners.cs new file mode 100644 index 000000000..d09d19bba --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/RoundedCorners.cs @@ -0,0 +1,24 @@ + +namespace ImageProcessor.Web.Processors +{ + using System; + using System.Text.RegularExpressions; + using ImageProcessor.Processors; + + /// + /// Encapsulates methods to add rounded corners to an image. + /// + public class RoundedCorners : IWebGraphicsProcessor + { + public Regex RegexPattern { get; private set; } + + public int SortOrder { get; private set; } + + public IGraphicsProcessor Processor { get; private set; } + + public int MatchRegexIndex(string queryString) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs new file mode 100644 index 000000000..594ce5185 --- /dev/null +++ b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs @@ -0,0 +1,81 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The image processor bootstrapper. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Configuration +{ + using System; + using System.Collections.Generic; + using System.Linq; + using ImageProcessor.Core.Common.Exceptions; + using ImageProcessor.Imaging.Formats; + + /// + /// The image processor bootstrapper. + /// + public class ImageProcessorBootstrapper + { + /// + /// A new instance Initializes a new instance of the class. + /// with lazy initialization. + /// + private static readonly Lazy Lazy = + new Lazy(() => new ImageProcessorBootstrapper()); + + /// + /// Prevents a default instance of the class from being created. + /// + private ImageProcessorBootstrapper() + { + this.LoadSupportedImageFormats(); + } + + /// + /// Gets the current instance of the class. + /// + public static ImageProcessorBootstrapper Instance + { + get + { + return Lazy.Value; + } + } + + /// + /// Gets the supported image formats. + /// + public IEnumerable SupportedImageFormats { get; private set; } + + /// + /// Creates a list, using reflection, of supported image formats that ImageProcessor can run. + /// + private void LoadSupportedImageFormats() + { + if (this.SupportedImageFormats == null) + { + try + { + Type type = typeof(ISupportedImageFormat); + List availableTypes = AppDomain.CurrentDomain + .GetAssemblies() + .SelectMany(s => s.GetTypes()) + .Where(t => t != null && type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract) + .ToList(); + + this.SupportedImageFormats = availableTypes + .Select(x => (Activator.CreateInstance(x) as ISupportedImageFormat)).ToList(); + } + catch (Exception ex) + { + throw new ImageFormatException(ex.Message, ex.InnerException); + } + } + } + } +} diff --git a/src/ImageProcessor/Core/Common/Exceptions/ImageFormatException.cs b/src/ImageProcessor/Core/Common/Exceptions/ImageFormatException.cs new file mode 100644 index 000000000..0469e33d4 --- /dev/null +++ b/src/ImageProcessor/Core/Common/Exceptions/ImageFormatException.cs @@ -0,0 +1,39 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The exception that is thrown when loading the supported image format types has failed. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Core.Common.Exceptions +{ + using System; + + /// + /// The exception that is thrown when loading the supported image format types has failed. + /// + public sealed class ImageFormatException : Exception + { + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public ImageFormatException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + public ImageFormatException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/src/ImageProcessor/Core/Common/Exceptions/ImageProcessingException.cs b/src/ImageProcessor/Core/Common/Exceptions/ImageProcessingException.cs new file mode 100644 index 000000000..db1adf2a6 --- /dev/null +++ b/src/ImageProcessor/Core/Common/Exceptions/ImageProcessingException.cs @@ -0,0 +1,39 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The exception that is thrown when processing an image has failed. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Core.Common.Exceptions +{ + using System; + + /// + /// The exception that is thrown when processing an image has failed. + /// + public sealed class ImageProcessingException : Exception + { + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public ImageProcessingException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + public ImageProcessingException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/src/ImageProcessor/Extensions/DoubleExtensions.cs b/src/ImageProcessor/Core/Common/Extensions/DoubleExtensions.cs similarity index 96% rename from src/ImageProcessor/Extensions/DoubleExtensions.cs rename to src/ImageProcessor/Core/Common/Extensions/DoubleExtensions.cs index a21817df1..a8980c5c6 100644 --- a/src/ImageProcessor/Extensions/DoubleExtensions.cs +++ b/src/ImageProcessor/Core/Common/Extensions/DoubleExtensions.cs @@ -8,7 +8,7 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Extensions +namespace ImageProcessor.Core.Common.Extensions { /// /// Encapsulates a series of time saving extension methods to the class. diff --git a/src/ImageProcessor/Extensions/ImageExtensions.cs b/src/ImageProcessor/Core/Common/Extensions/ImageExtensions.cs similarity index 98% rename from src/ImageProcessor/Extensions/ImageExtensions.cs rename to src/ImageProcessor/Core/Common/Extensions/ImageExtensions.cs index a4134016e..cff34a9f8 100644 --- a/src/ImageProcessor/Extensions/ImageExtensions.cs +++ b/src/ImageProcessor/Core/Common/Extensions/ImageExtensions.cs @@ -8,12 +8,13 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Extensions +namespace ImageProcessor.Core.Common.Extensions { using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; + using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor/Extensions/ImageFormatExtensions.cs b/src/ImageProcessor/Core/Common/Extensions/ImageFormatExtensions.cs similarity index 98% rename from src/ImageProcessor/Extensions/ImageFormatExtensions.cs rename to src/ImageProcessor/Core/Common/Extensions/ImageFormatExtensions.cs index 036a4153e..dcdaa4550 100644 --- a/src/ImageProcessor/Extensions/ImageFormatExtensions.cs +++ b/src/ImageProcessor/Core/Common/Extensions/ImageFormatExtensions.cs @@ -9,11 +9,13 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Extensions +namespace ImageProcessor.Core.Common.Extensions { #region + using System.Drawing.Imaging; using System.Linq; + #endregion /// diff --git a/src/ImageProcessor/Extensions/ImageInfo.cs b/src/ImageProcessor/Core/Common/Extensions/ImageInfo.cs similarity index 97% rename from src/ImageProcessor/Extensions/ImageInfo.cs rename to src/ImageProcessor/Core/Common/Extensions/ImageInfo.cs index 720eb5a20..41ef6f5b0 100644 --- a/src/ImageProcessor/Extensions/ImageInfo.cs +++ b/src/ImageProcessor/Core/Common/Extensions/ImageInfo.cs @@ -9,9 +9,10 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Extensions +namespace ImageProcessor.Core.Common.Extensions { using System.Collections.Generic; + using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor/Extensions/IntegerExtensions.cs b/src/ImageProcessor/Core/Common/Extensions/IntegerExtensions.cs similarity index 97% rename from src/ImageProcessor/Extensions/IntegerExtensions.cs rename to src/ImageProcessor/Core/Common/Extensions/IntegerExtensions.cs index d969e780e..c4aa90bd8 100644 --- a/src/ImageProcessor/Extensions/IntegerExtensions.cs +++ b/src/ImageProcessor/Core/Common/Extensions/IntegerExtensions.cs @@ -8,7 +8,7 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Extensions +namespace ImageProcessor.Core.Common.Extensions { using System.Globalization; diff --git a/src/ImageProcessor/Extensions/StringExtensions.cs b/src/ImageProcessor/Core/Common/Extensions/StringExtensions.cs similarity index 99% rename from src/ImageProcessor/Extensions/StringExtensions.cs rename to src/ImageProcessor/Core/Common/Extensions/StringExtensions.cs index 318146a9b..a60590f66 100644 --- a/src/ImageProcessor/Extensions/StringExtensions.cs +++ b/src/ImageProcessor/Core/Common/Extensions/StringExtensions.cs @@ -8,15 +8,17 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Extensions +namespace ImageProcessor.Core.Common.Extensions { #region Using + using System; using System.Globalization; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; + #endregion /// diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index b88c3d3bf..8d9b34f75 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -14,15 +14,15 @@ namespace ImageProcessor using System; using System.Collections.Concurrent; using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; - using System.Threading; - using ImageProcessor.Extensions; + + using ImageProcessor.Core.Common.Exceptions; using ImageProcessor.Imaging; using ImageProcessor.Imaging.Filters; + using ImageProcessor.Imaging.Formats; using ImageProcessor.Processors; #endregion @@ -33,24 +33,14 @@ namespace ImageProcessor { #region Fields /// - /// The default quality for jpeg files. - /// - private const int DefaultJpegQuality = 90; - - /// - /// The backup image format. - /// - private ImageFormat backupImageFormat; - - /// - /// The memory stream for storing any input stream to prevent disposal. + /// The default quality for image files. /// - private MemoryStream inputStream; + private const int DefaultQuality = 90; /// - /// Whether the image is indexed. + /// The backup supported image format. /// - private bool isIndexed; + private ISupportedImageFormat backupFormat; /// /// A value indicating whether this instance of the given entity has been disposed. @@ -122,20 +112,9 @@ namespace ImageProcessor public bool ShouldProcess { get; private set; } /// - /// Gets the file format of the image. + /// Gets the supported image format. /// - public ImageFormat ImageFormat { get; private set; } - - /// - /// Gets the mime type. - /// - public string MimeType - { - get - { - return this.ImageFormat.GetMimeType(); - } - } + public ISupportedImageFormat CurrentImageFormat { get; private set; } /// /// Gets or sets a value indicating whether to preserve exif metadata. @@ -153,9 +132,9 @@ namespace ImageProcessor internal string OriginalExtension { get; set; } /// - /// Gets or sets the quality of output for jpeg images as a percentile. + /// Gets or sets the memory stream for storing any input stream to prevent disposal. /// - internal int JpegQuality { get; set; } + internal MemoryStream InputStream { get; set; } #endregion #region Methods @@ -170,17 +149,25 @@ namespace ImageProcessor /// public ImageFactory Load(MemoryStream memoryStream) { + ISupportedImageFormat format = FormatUtilities.GetFormat(memoryStream); + + if (format == null) + { + throw new ImageFormatException("Input stream is not a supported format."); + } + + this.backupFormat = format; + this.CurrentImageFormat = format; + // Set our image as the memory stream value. - this.Image = Image.FromStream(memoryStream, true); + this.Image = format.Load(memoryStream); // Store the stream so we can dispose of it later. - this.inputStream = memoryStream; + this.InputStream = memoryStream; // Set the other properties. - this.JpegQuality = DefaultJpegQuality; - this.ImageFormat = this.Image.RawFormat; - this.backupImageFormat = this.ImageFormat; - this.isIndexed = ImageUtils.IsIndexed(this.Image); + format.Quality = DefaultQuality; + format.IsIndexed = ImageUtils.IsIndexed(this.Image); if (this.PreserveExifData) { @@ -222,6 +209,16 @@ namespace ImageProcessor // Open a file stream to prevent the need for lock. using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)) { + ISupportedImageFormat format = FormatUtilities.GetFormat(fileStream); + + if (format == null) + { + throw new ImageFormatException("Input stream is not a supported format."); + } + + this.backupFormat = format; + this.CurrentImageFormat = format; + MemoryStream memoryStream = new MemoryStream(); // Copy the stream. @@ -231,18 +228,16 @@ namespace ImageProcessor fileStream.Position = memoryStream.Position = 0; // Set our image as the memory stream value. - this.Image = Image.FromStream(memoryStream, true); + this.Image = format.Load(memoryStream); // Store the stream so we can dispose of it later. - this.inputStream = memoryStream; + this.InputStream = memoryStream; // Set the other properties. - this.JpegQuality = DefaultJpegQuality; - ImageFormat imageFormat = this.Image.RawFormat; - this.backupImageFormat = imageFormat; + format.Quality = DefaultQuality; + format.IsIndexed = ImageUtils.IsIndexed(this.Image); + this.OriginalExtension = Path.GetExtension(this.ImagePath); - this.ImageFormat = imageFormat; - this.isIndexed = ImageUtils.IsIndexed(this.Image); if (this.PreserveExifData) { @@ -271,6 +266,16 @@ namespace ImageProcessor if (this.ShouldProcess) { this.Image = image; + + // Get the correct image format for the image. + using (MemoryStream stream = new MemoryStream()) + { + image.Save(stream, image.RawFormat); + stream.Position = 0; + int quality = this.CurrentImageFormat.Quality; + this.CurrentImageFormat = FormatUtilities.GetFormat(stream); + this.CurrentImageFormat.Quality = quality; + } } return this; @@ -287,16 +292,15 @@ namespace ImageProcessor if (this.ShouldProcess) { // Set our new image as the memory stream value. - Image newImage = Image.FromStream(this.inputStream, true); + Image newImage = Image.FromStream(this.InputStream, true); // Dispose and reassign the image. this.Image.Dispose(); this.Image = newImage; // Set the other properties. - this.JpegQuality = DefaultJpegQuality; - this.ImageFormat = this.backupImageFormat; - this.isIndexed = ImageUtils.IsIndexed(this.Image); + this.CurrentImageFormat = this.backupFormat; + this.CurrentImageFormat.Quality = DefaultQuality; } return this; @@ -312,6 +316,7 @@ namespace ImageProcessor /// public ImageFactory AddQueryString(string query) { + // TODO: Remove this. if (this.ShouldProcess) { this.QueryString = query; @@ -341,7 +346,7 @@ namespace ImageProcessor } Alpha alpha = new Alpha { DynamicParameter = percentage }; - this.ApplyProcessor(alpha.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(alpha.ProcessImage, this); } return this; @@ -368,7 +373,7 @@ namespace ImageProcessor } Brightness brightness = new Brightness { DynamicParameter = percentage }; - this.ApplyProcessor(brightness.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(brightness.ProcessImage, this); } return this; @@ -416,7 +421,7 @@ namespace ImageProcessor } Contrast contrast = new Contrast { DynamicParameter = percentage }; - this.ApplyProcessor(contrast.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(contrast.ProcessImage, this); } return this; @@ -456,7 +461,7 @@ namespace ImageProcessor if (this.ShouldProcess) { Crop crop = new Crop { DynamicParameter = cropLayer }; - this.ApplyProcessor(crop.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(crop.ProcessImage, this); } return this; @@ -477,7 +482,7 @@ namespace ImageProcessor if (this.ShouldProcess) { Filter filter = new Filter { DynamicParameter = filterName }; - this.ApplyProcessor(filter.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(filter.ProcessImage, this); } return this; @@ -498,7 +503,7 @@ namespace ImageProcessor if (this.ShouldProcess) { Filter filter = new Filter { DynamicParameter = matrixFilter }; - this.ApplyProcessor(filter.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(filter.ProcessImage, this); } return this; @@ -522,7 +527,7 @@ namespace ImageProcessor : RotateFlipType.RotateNoneFlipY; Flip flip = new Flip { DynamicParameter = rotateFlipType }; - this.ApplyProcessor(flip.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(flip.ProcessImage, this); } return this; @@ -531,18 +536,15 @@ namespace ImageProcessor /// /// Sets the output format of the current image to the matching . /// - /// The . to set the image to. - /// Whether the pixel format of the image should be indexed. Used for generating Png8 images. + /// The . to set the image to. /// /// The current instance of the class. /// - [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")] - public ImageFactory Format(ImageFormat imageFormat, bool indexedFormat = false) + public ImageFactory Format(ISupportedImageFormat format) { if (this.ShouldProcess) { - this.isIndexed = indexedFormat; - this.ImageFormat = imageFormat; + this.CurrentImageFormat = format; } return this; @@ -589,7 +591,7 @@ namespace ImageProcessor if (this.ShouldProcess) { GaussianBlur gaussianBlur = new GaussianBlur { DynamicParameter = gaussianLayer }; - this.ApplyProcessor(gaussianBlur.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(gaussianBlur.ProcessImage, this); } return this; @@ -636,7 +638,7 @@ namespace ImageProcessor if (this.ShouldProcess) { GaussianSharpen gaussianSharpen = new GaussianSharpen { DynamicParameter = gaussianLayer }; - this.ApplyProcessor(gaussianSharpen.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(gaussianSharpen.ProcessImage, this); } return this; @@ -656,7 +658,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - this.JpegQuality = percentage; + this.CurrentImageFormat.Quality = percentage; } return this; @@ -701,7 +703,7 @@ namespace ImageProcessor var resizeSettings = new Dictionary { { "MaxWidth", resizeLayer.Size.Width.ToString("G") }, { "MaxHeight", resizeLayer.Size.Height.ToString("G") } }; Resize resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings }; - this.ApplyProcessor(resize.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(resize.ProcessImage, this); } return this; @@ -710,24 +712,24 @@ namespace ImageProcessor /// /// Rotates the current image by the given angle. /// - /// - /// The containing the properties to rotate the image. + /// + /// The angle at which to rotate the image in degrees. /// /// /// The current instance of the class. /// - public ImageFactory Rotate(RotateLayer rotateLayer) + public ImageFactory Rotate(int degrees) { if (this.ShouldProcess) { // Sanitize the input. - if (rotateLayer.Angle > 360 || rotateLayer.Angle < 0) + if (degrees > 360 || degrees < 0) { - rotateLayer.Angle = 0; + degrees = 0; } - Rotate rotate = new Rotate { DynamicParameter = rotateLayer }; - this.ApplyProcessor(rotate.ProcessImage); + Rotate rotate = new Rotate { DynamicParameter = degrees }; + this.CurrentImageFormat.ApplyProcessor(rotate.ProcessImage, this); } return this; @@ -752,7 +754,7 @@ namespace ImageProcessor } RoundedCorners roundedCorners = new RoundedCorners { DynamicParameter = roundedCornerLayer }; - this.ApplyProcessor(roundedCorners.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(roundedCorners.ProcessImage, this); } return this; @@ -779,7 +781,7 @@ namespace ImageProcessor } Saturation saturate = new Saturation { DynamicParameter = percentage }; - this.ApplyProcessor(saturate.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(saturate.ProcessImage, this); } return this; @@ -799,7 +801,7 @@ namespace ImageProcessor if (this.ShouldProcess) { Tint tint = new Tint { DynamicParameter = color }; - this.ApplyProcessor(tint.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(tint.ProcessImage, this); } return this; @@ -816,7 +818,7 @@ namespace ImageProcessor if (this.ShouldProcess) { Vignette vignette = new Vignette(); - this.ApplyProcessor(vignette.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(vignette.ProcessImage, this); } return this; @@ -837,7 +839,7 @@ namespace ImageProcessor if (this.ShouldProcess) { Watermark watermark = new Watermark { DynamicParameter = textLayer }; - this.ApplyProcessor(watermark.ProcessImage); + this.CurrentImageFormat.ApplyProcessor(watermark.ProcessImage, this); } return this; @@ -845,7 +847,9 @@ namespace ImageProcessor #endregion /// - /// Saves the current image to the specified file path. + /// Saves the current image to the specified file path. If the extension does not + /// match the correct extension for the current format it will be replaced by the + /// correct default value. /// /// The path to save the image to. /// @@ -858,71 +862,24 @@ namespace ImageProcessor // We need to check here if the path has an extension and remove it if so. // This is so we can add the correct image format. int length = filePath.LastIndexOf(".", StringComparison.Ordinal); - string extension = this.ImageFormat.GetFileExtension(this.OriginalExtension); + string extension = Path.GetExtension(filePath).TrimStart('.'); + string fallback = this.CurrentImageFormat.DefaultExtension; - if (!string.IsNullOrWhiteSpace(extension)) + if (extension != fallback && !this.CurrentImageFormat.FileExtensions.Contains(extension)) { - filePath = length == -1 ? filePath + extension : filePath.Substring(0, length) + extension; + filePath = length == -1 + ? string.Format("{0}.{1}", filePath, fallback) + : filePath.Substring(0, length + 1) + fallback; } - // Fix the colour palette of indexed images. - this.FixIndexedPallete(); - // ReSharper disable once AssignNullToNotNullAttribute DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(filePath)); - - if (this.ImageFormat.Equals(ImageFormat.Jpeg)) + if (!directoryInfo.Exists) { - // Jpegs can be saved with different settings to include a quality setting for the JPEG compression. - // This improves output compression and quality. - using (EncoderParameters encoderParameters = ImageUtils.GetEncodingParameters(this.JpegQuality)) - { - ImageCodecInfo imageCodecInfo = - ImageCodecInfo.GetImageEncoders() - .FirstOrDefault(ici => ici.MimeType.Equals(this.MimeType, StringComparison.OrdinalIgnoreCase)); - - if (imageCodecInfo != null) - { - for (int i = 0; i < 3; i++) - { - try - { - if (!directoryInfo.Exists) - { - directoryInfo.Create(); - } - - this.Image.Save(filePath, imageCodecInfo, encoderParameters); - break; - } - catch (Exception) - { - Thread.Sleep(200); - } - } - } - } + directoryInfo.Create(); } - else - { - for (int i = 0; i < 3; i++) - { - try - { - if (!directoryInfo.Exists) - { - directoryInfo.Create(); - } - this.Image.Save(filePath, this.ImageFormat); - break; - } - catch (Exception) - { - Thread.Sleep(200); - } - } - } + this.Image = this.CurrentImageFormat.Save(filePath, this.Image); } return this; @@ -941,29 +898,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - // Fix the colour palette of gif and png8 images. - this.FixIndexedPallete(); - - if (this.ImageFormat.Equals(ImageFormat.Jpeg)) - { - // Jpegs can be saved with different settings to include a quality setting for the JPEG compression. - // This improves output compression and quality. - using (EncoderParameters encoderParameters = ImageUtils.GetEncodingParameters(this.JpegQuality)) - { - ImageCodecInfo imageCodecInfo = - ImageCodecInfo.GetImageEncoders().FirstOrDefault( - ici => ici.MimeType.Equals(this.MimeType, StringComparison.OrdinalIgnoreCase)); - - if (imageCodecInfo != null) - { - this.Image.Save(memoryStream, imageCodecInfo, encoderParameters); - } - } - } - else - { - this.Image.Save(memoryStream, this.ImageFormat); - } + this.Image = this.CurrentImageFormat.Save(memoryStream, this.Image); } return this; @@ -1002,10 +937,10 @@ namespace ImageProcessor if (this.Image != null) { // Dispose of the memory stream from Load and the image. - if (this.inputStream != null) + if (this.InputStream != null) { - this.inputStream.Dispose(); - this.inputStream = null; + this.InputStream.Dispose(); + this.InputStream = null; } this.Image.Dispose(); @@ -1019,81 +954,6 @@ namespace ImageProcessor this.isDisposed = true; } #endregion - - /// - /// Uses the - /// to fix the color palette of gif images. - /// - private void FixIndexedPallete() - { - ImageFormat format = this.ImageFormat; - - // Fix the colour palette of indexed images. - if (this.isIndexed || format.Equals(ImageFormat.Gif)) - { - ImageInfo imageInfo = this.Image.GetImageInfo(format, false); - - if (!imageInfo.IsAnimated) - { - this.Image = new OctreeQuantizer(255, 8).Quantize(this.Image); - } - } - } - - /// - /// Applies the given processor the current image. - /// - /// - /// The processor delegate. - /// - private void ApplyProcessor(Func processor) - { - ImageInfo imageInfo = this.Image.GetImageInfo(this.ImageFormat); - - if (imageInfo.IsAnimated) - { - OctreeQuantizer quantizer = new OctreeQuantizer(255, 8); - - // We don't dispose of the memory stream as that is disposed when a new image is created and doing so - // beforehand will cause an exception. - MemoryStream stream = new MemoryStream(); - using (GifEncoder encoder = new GifEncoder(stream, null, null, imageInfo.LoopCount)) - { - foreach (GifFrame frame in imageInfo.GifFrames) - { - this.Image = frame.Image; - frame.Image = quantizer.Quantize(processor.Invoke(this)); - encoder.AddFrame(frame); - } - } - - stream.Position = 0; - this.Image = Image.FromStream(stream); - } - else - { - 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 54aa058bb..68f6e06bd 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -60,12 +60,15 @@ - - - - - - + + + + + + + + + @@ -75,6 +78,14 @@ + + + + + + + + @@ -100,6 +111,7 @@ + diff --git a/src/ImageProcessor/Imaging/Convolution.cs b/src/ImageProcessor/Imaging/Convolution.cs index be3f585e9..1d8088970 100644 --- a/src/ImageProcessor/Imaging/Convolution.cs +++ b/src/ImageProcessor/Imaging/Convolution.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Imaging using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; - using ImageProcessor.Extensions; + + using ImageProcessor.Core.Common.Extensions; /// /// Provides methods for applying blurring and sharpening effects to an image.. diff --git a/src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs b/src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs index 2f46693cb..7c7feab83 100644 --- a/src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs +++ b/src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs @@ -18,7 +18,7 @@ namespace ImageProcessor.Imaging.Filters using System.Drawing.Imaging; using System.Runtime.InteropServices; - using ImageProcessor.Extensions; + using ImageProcessor.Core.Common.Extensions; #endregion diff --git a/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs b/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs new file mode 100644 index 000000000..b971f276e --- /dev/null +++ b/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs @@ -0,0 +1,65 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides the necessary information to support bitmap images. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Formats +{ + using System.Drawing.Imaging; + using System.Text; + + /// + /// Provides the necessary information to support bitmap images. + /// + public class BitmapFormat : FormatBase + { + /// + /// Gets the file header. + /// + public override byte[] FileHeader + { + get + { + return Encoding.ASCII.GetBytes("BM"); + } + } + + /// + /// Gets the list of file extensions. + /// + public override string[] FileExtensions + { + get + { + return new[] { "bmp" }; + } + } + + /// + /// Gets the standard identifier used on the Internet to indicate the type of data that a file contains. + /// + public override string MimeType + { + get + { + return "image/bmp"; + } + } + + /// + /// Gets the . + /// + public override ImageFormat ImageFormat + { + get + { + return ImageFormat.Bmp; + } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Imaging/Formats/FormatBase.cs b/src/ImageProcessor/Imaging/Formats/FormatBase.cs new file mode 100644 index 000000000..79c90a12b --- /dev/null +++ b/src/ImageProcessor/Imaging/Formats/FormatBase.cs @@ -0,0 +1,123 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The supported format base implement this class when building a supported format. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Formats +{ + using System; + using System.Drawing; + using System.Drawing.Imaging; + using System.IO; + + /// + /// The supported format base. Implement this class when building a supported format. + /// + public abstract class FormatBase : ISupportedImageFormat + { + /// + /// Gets the file header. + /// + public abstract byte[] FileHeader { get; } + + /// + /// Gets the list of file extensions. + /// + public abstract string[] FileExtensions { get; } + + /// + /// Gets the standard identifier used on the Internet to indicate the type of data that a file contains. + /// + public abstract string MimeType { get; } + + /// + /// Gets the default file extension. + /// + public string DefaultExtension + { + get + { + return this.MimeType.Replace("image/", string.Empty); + } + } + + /// + /// Gets the file format of the image. + /// + public abstract ImageFormat ImageFormat { get; } + + /// + /// Gets or sets a value indicating whether the image format is indexed. + /// + public bool IsIndexed { get; set; } + + /// + /// Gets or sets a value indicating whether the image format is animated. + /// + public bool IsAnimated { get; set; } + + /// + /// Gets or sets the quality of output for images. + /// + public int Quality { get; set; } + + /// + /// Applies the given processor the current image. + /// + /// The processor delegate. + /// The . + public virtual void ApplyProcessor(Func processor, ImageFactory factory) + { + processor.Invoke(factory); + } + + /// + /// Decodes the image to process. + /// + /// + /// The containing the image information. + /// + /// + /// The the . + /// + public virtual Image Load(Stream stream) + { + return Image.FromStream(stream, true); + } + + /// + /// Saves the current image to the specified output stream. + /// + /// The to save the image information to. + /// The to save. + /// + /// The . + /// + public virtual Image Save(MemoryStream memoryStream, Image image) + { + image.Save(memoryStream, this.ImageFormat); + memoryStream.Position = 0; + return image; + } + + /// + /// Saves the current image to the specified file path. + /// + /// The path to save the image to. + /// The + /// to save. + /// + /// The . + /// + public virtual Image Save(string path, Image image) + { + image.Save(path, this.ImageFormat); + return image; + } + } +} diff --git a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs new file mode 100644 index 000000000..d3b6f9c56 --- /dev/null +++ b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs @@ -0,0 +1,88 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Utility methods for working with supported image formats. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Formats +{ + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Imaging; + using System.IO; + using System.Linq; + using ImageProcessor.Configuration; + + /// + /// Utility methods for working with supported image formats. + /// + public static class FormatUtilities + { + /// + /// Gets the correct from the given stream. + /// + /// + /// + /// The to read from. + /// + /// + /// The . + /// + public static ISupportedImageFormat GetFormat(Stream stream) + { + IEnumerable supportedImageFormats = + ImageProcessorBootstrapper.Instance.SupportedImageFormats; + + byte[] buffer = new byte[4]; + stream.Read(buffer, 0, buffer.Length); + + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (ISupportedImageFormat supportedImageFormat in supportedImageFormats) + { + byte[] header = supportedImageFormat.FileHeader; + if (header.SequenceEqual(buffer.Take(header.Length))) + { + stream.Position = 0; + return supportedImageFormat; + } + } + + stream.Position = 0; + return null; + } + + /// + /// Returns a value indicating whether the given image is indexed. + /// + /// + /// The to test. + /// + /// + /// The true if the image is indexed; otherwise, false. + /// + public static bool IsIndexed(Image image) + { + // Test value of flags using bitwise AND. + // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags + return (image.PixelFormat & PixelFormat.Indexed) != 0; + } + + /// + /// Returns a value indicating whether the given image is indexed. + /// + /// + /// The to test. + /// + /// + /// The true if the image is animated; otherwise, false. + /// + public static bool IsAnimated(Image image) + { + return ImageAnimator.CanAnimate(image); + } + } +} diff --git a/src/ImageProcessor/Imaging/Formats/GifFormat.cs b/src/ImageProcessor/Imaging/Formats/GifFormat.cs new file mode 100644 index 000000000..b2b3cb413 --- /dev/null +++ b/src/ImageProcessor/Imaging/Formats/GifFormat.cs @@ -0,0 +1,149 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides the necessary information to support gif images. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Formats +{ + using System; + using System.Drawing; + using System.Drawing.Imaging; + using System.IO; + using System.Text; + using ImageProcessor.Core.Common.Extensions; + + /// + /// Provides the necessary information to support gif images. + /// + public class GifFormat : FormatBase + { + /// + /// Gets the file header. + /// + public override byte[] FileHeader + { + get + { + return Encoding.ASCII.GetBytes("GIF"); + } + } + + /// + /// Gets the list of file extensions. + /// + public override string[] FileExtensions + { + get + { + return new[] { "gif" }; + } + } + + /// + /// Gets the standard identifier used on the Internet to indicate the type of data that a file contains. + /// + public override string MimeType + { + get + { + return "image/gif"; + } + } + + /// + /// Gets the . + /// + public override ImageFormat ImageFormat + { + get + { + return ImageFormat.Gif; + } + } + + /// + /// Applies the given processor the current image. + /// + /// The processor delegate. + /// The . + public override void ApplyProcessor(Func processor, ImageFactory factory) + { + ImageInfo imageInfo = factory.Image.GetImageInfo(this.ImageFormat); + + if (imageInfo.IsAnimated) + { + OctreeQuantizer quantizer = new OctreeQuantizer(255, 8); + + // We don't dispose of the memory stream as that is disposed when a new image is created and doing so + // beforehand will cause an exception. + MemoryStream stream = new MemoryStream(); + using (GifEncoder encoder = new GifEncoder(stream, null, null, imageInfo.LoopCount)) + { + foreach (GifFrame frame in imageInfo.GifFrames) + { + factory.Update(frame.Image); + frame.Image = quantizer.Quantize(processor.Invoke(factory)); + encoder.AddFrame(frame); + } + } + + stream.Position = 0; + factory.Update(Image.FromStream(stream)); + } + else + { + base.ApplyProcessor(processor, factory); + } + } + + /// + /// Saves the current image to the specified output stream. + /// + /// + /// The to save the image information to. + /// + /// The to save. + /// + /// The . + /// + public override Image Save(MemoryStream memoryStream, Image image) + { + // TODO: Move this in here. It doesn't need to be anywhere else. + ImageInfo imageInfo = image.GetImageInfo(this.ImageFormat, false); + + if (!imageInfo.IsAnimated) + { + image = new OctreeQuantizer(255, 8).Quantize(image); + } + + return base.Save(memoryStream, image); + } + + /// + /// Saves the current image to the specified file path. + /// + /// The path to save the image to. + /// The + /// to save. + /// + /// The . + /// + public override Image Save(string path, Image image) + { + // TODO: Move this in here. It doesn't need to be anywhere else. + ImageInfo imageInfo = image.GetImageInfo(this.ImageFormat, false); + + if (!imageInfo.IsAnimated) + { + image = new OctreeQuantizer(255, 8).Quantize(image); + } + + return base.Save(path, image); + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs b/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs new file mode 100644 index 000000000..8ad4e0763 --- /dev/null +++ b/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs @@ -0,0 +1,113 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The SupportedImageFormat interface providing information about image formats to ImageProcessor. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Formats +{ + using System; + using System.Drawing; + using System.Drawing.Imaging; + using System.IO; + + /// + /// The SupportedImageFormat interface providing information about image formats to ImageProcessor. + /// + public interface ISupportedImageFormat + { + /// + /// Gets the file header. + /// + byte[] FileHeader { get; } + + /// + /// Gets the list of file extensions. + /// + string[] FileExtensions { get; } + + /// + /// Gets the standard identifier used on the Internet to indicate the type of data that a file contains. + /// + string MimeType { get; } + + /// + /// Gets the default file extension. + /// + string DefaultExtension { get; } + + /// + /// Gets the file format of the image. + /// + ImageFormat ImageFormat { get; } + + /// + /// Gets or sets a value indicating whether the image format is indexed. + /// + bool IsIndexed { get; set; } + + /// + /// Gets or sets a value indicating whether the image format is animated. + /// + bool IsAnimated { get; set; } + + /// + /// Gets or sets the quality of output for images. + /// + int Quality { get; set; } + + #region Methods + /// + /// Applies the given processor the current image. + /// + /// + /// The processor delegate. + /// + /// + /// The . + /// + void ApplyProcessor(Func processor, ImageFactory factory); + + /// + /// Loads the image to process. + /// + /// + /// The containing the image information. + /// + /// + /// The . + /// + Image Load(Stream stream); + + /// + /// Saves the current image to the specified output stream. + /// + /// + /// The to save the image information to. + /// + /// + /// The to save. + /// + /// + /// The . + /// + Image Save(MemoryStream memoryStream, Image image); + + /// + /// Saves the current image to the specified file path. + /// + /// The path to save the image to. + /// + /// The to save. + /// + /// + /// The . + /// + Image Save(string path, Image image); + #endregion + } +} diff --git a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs new file mode 100644 index 000000000..761088ddc --- /dev/null +++ b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs @@ -0,0 +1,155 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides the necessary information to support jpeg images. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Formats +{ + using System; + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Imaging; + using System.IO; + using System.Linq; + + /// + /// Provides the necessary information to support jpeg images. + /// + public sealed class JpegFormat : FormatBase + { + /// + /// Gets the file header. + /// + public override byte[] FileHeader + { + get + { + return new byte[] { 255, 216, 255, 224 }; + } + } + + /// + /// Gets the list of file extensions. + /// + public override string[] FileExtensions + { + get + { + return new[] { "jpeg", "jpg" }; + } + } + + /// + /// Gets the standard identifier used on the Internet to indicate the type of data that a file contains. + /// + public override string MimeType + { + get + { + return "image/jpeg"; + } + } + + /// + /// Gets the . + /// + public override ImageFormat ImageFormat + { + get + { + return ImageFormat.Jpeg; + } + } + + /// + /// Applies the given processor the current image. + /// + /// The processor delegate. + /// The . + public override void ApplyProcessor(Func processor, ImageFactory factory) + { + base.ApplyProcessor(processor, factory); + + // Set the property item information from any Exif metadata. + // We do this here so that they can be changed between processor methods. + if (factory.PreserveExifData) + { + foreach (KeyValuePair propertItem in factory.ExifPropertyItems) + { + try + { + factory.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. + } + } + } + } + + /// + /// Saves the current image to the specified output stream. + /// + /// + /// The to save the image information to. + /// + /// The to save. + /// + /// The . + /// + public override Image Save(MemoryStream memoryStream, Image image) + { + // Jpegs can be saved with different settings to include a quality setting for the JPEG compression. + // This improves output compression and quality. + using (EncoderParameters encoderParameters = ImageUtils.GetEncodingParameters(this.Quality)) + { + ImageCodecInfo imageCodecInfo = + ImageCodecInfo.GetImageEncoders() + .FirstOrDefault(ici => ici.MimeType.Equals(this.MimeType, StringComparison.OrdinalIgnoreCase)); + + if (imageCodecInfo != null) + { + image.Save(memoryStream, imageCodecInfo, encoderParameters); + } + } + + return image; + } + + /// + /// Saves the current image to the specified file path. + /// + /// The path to save the image to. + /// The + /// to save. + /// + /// The . + /// + public override Image Save(string path, Image image) + { + // Jpegs can be saved with different settings to include a quality setting for the JPEG compression. + // This improves output compression and quality. + using (EncoderParameters encoderParameters = ImageUtils.GetEncodingParameters(this.Quality)) + { + ImageCodecInfo imageCodecInfo = + ImageCodecInfo.GetImageEncoders() + .FirstOrDefault(ici => ici.MimeType.Equals(this.MimeType, StringComparison.OrdinalIgnoreCase)); + + if (imageCodecInfo != null) + { + image.Save(path, imageCodecInfo, encoderParameters); + } + } + + return image; + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Imaging/Formats/PngFormat.cs b/src/ImageProcessor/Imaging/Formats/PngFormat.cs new file mode 100644 index 000000000..da6b4dc5f --- /dev/null +++ b/src/ImageProcessor/Imaging/Formats/PngFormat.cs @@ -0,0 +1,103 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides the necessary information to support png images. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Formats +{ + using System.Drawing; + using System.Drawing.Imaging; + using System.IO; + + /// + /// Provides the necessary information to support png images. + /// + public class PngFormat : FormatBase + { + /// + /// Gets the file header. + /// + public override byte[] FileHeader + { + get + { + return new byte[] { 137, 80, 78, 71 }; + } + } + + /// + /// Gets the list of file extensions. + /// + public override string[] FileExtensions + { + get + { + return new[] { "png" }; + } + } + + /// + /// Gets the standard identifier used on the Internet to indicate the type of data that a file contains. + /// + public override string MimeType + { + get + { + return "image/png"; + } + } + + /// + /// Gets the . + /// + public override ImageFormat ImageFormat + { + get + { + return ImageFormat.Png; + } + } + + /// + /// Saves the current image to the specified output stream. + /// + /// The to save the image information to. + /// The to save. + /// + /// The . + /// + public override Image Save(MemoryStream memoryStream, Image image) + { + if (FormatUtilities.IsIndexed(image)) + { + image = new OctreeQuantizer(255, 8).Quantize(image); + } + + return base.Save(memoryStream, image); + } + + /// + /// Saves the current image to the specified file path. + /// + /// The path to save the image to. + /// The + /// to save. + /// + /// The . + /// + public override Image Save(string path, Image image) + { + if (FormatUtilities.IsIndexed(image)) + { + image = new OctreeQuantizer(255, 8).Quantize(image); + } + + return base.Save(path, image); + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Imaging/Formats/TiffFormat.cs b/src/ImageProcessor/Imaging/Formats/TiffFormat.cs new file mode 100644 index 000000000..226c0efab --- /dev/null +++ b/src/ImageProcessor/Imaging/Formats/TiffFormat.cs @@ -0,0 +1,96 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides the necessary information to support tiff images. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Formats +{ + using System; + using System.Collections.Generic; + using System.Drawing; + using System.Drawing.Imaging; + + /// + /// Provides the necessary information to support tiff images. + /// + public class TiffFormat : FormatBase + { + /// + /// Gets the file header. + /// + public override byte[] FileHeader + { + get + { + return new byte[] { 77, 77, 42 }; + } + } + + /// + /// Gets the list of file extensions. + /// + public override string[] FileExtensions + { + get + { + return new[] { "tif", "tiff" }; + } + } + + /// + /// Gets the standard identifier used on the Internet to indicate the type of data that a file contains. + /// + public override string MimeType + { + get + { + return "image/tiff"; + } + } + + /// + /// Gets the . + /// + public override ImageFormat ImageFormat + { + get + { + return ImageFormat.Tiff; + } + } + + /// + /// Applies the given processor the current image. + /// + /// The processor delegate. + /// The . + public override void ApplyProcessor(Func processor, ImageFactory factory) + { + base.ApplyProcessor(processor, factory); + + // Set the property item information from any Exif metadata. + // We do this here so that they can be changed between processor methods. + if (factory.PreserveExifData) + { + foreach (KeyValuePair propertItem in factory.ExifPropertyItems) + { + try + { + factory.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. + } + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Processors/BackgroundColor.cs b/src/ImageProcessor/Processors/BackgroundColor.cs new file mode 100644 index 000000000..357b08014 --- /dev/null +++ b/src/ImageProcessor/Processors/BackgroundColor.cs @@ -0,0 +1,74 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Changes the background color of an image. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Processors +{ + using System.Collections.Generic; + using System.Drawing; + + /// + /// Changes the background color of an image. + /// + public class BackgroundColor : IGraphicsProcessor + { + /// + /// Gets or sets the DynamicParameter. + /// + public dynamic DynamicParameter { get; set; } + + /// + /// Gets or sets any additional settings required by the processor. + /// + public Dictionary Settings { get; set; } + + /// + /// 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 + { + Color backgroundColor = this.DynamicParameter; + newImage = new Bitmap(image.Width, image.Height); + + // Make a graphics object from the empty bitmap. + using (Graphics graphics = Graphics.FromImage(newImage)) + { + // Fill the background. + graphics.Clear(backgroundColor); + + // Draw passed in image onto graphics object. + graphics.DrawImage(image, 0, 0); + } + + image.Dispose(); + image = newImage; + } + catch + { + if (newImage != null) + { + newImage.Dispose(); + } + } + + return image; + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Processors/Crop.cs b/src/ImageProcessor/Processors/Crop.cs index fa4f20ccf..0124b0f61 100644 --- a/src/ImageProcessor/Processors/Crop.cs +++ b/src/ImageProcessor/Processors/Crop.cs @@ -18,7 +18,7 @@ namespace ImageProcessor.Processors using System.Text; using System.Text.RegularExpressions; - using ImageProcessor.Extensions; + using ImageProcessor.Core.Common.Extensions; using ImageProcessor.Imaging; #endregion diff --git a/src/ImageProcessor/Processors/Format.cs b/src/ImageProcessor/Processors/Format.cs index 97173b836..4879c9d11 100644 --- a/src/ImageProcessor/Processors/Format.cs +++ b/src/ImageProcessor/Processors/Format.cs @@ -146,7 +146,8 @@ namespace ImageProcessor.Processors // Set the internal property. factory.OriginalExtension = string.Format(".{0}", format); - factory.Format(imageFormat, isIndexed); + // TODO: Fix this. + //factory.Format(imageFormat); return factory.Image; } diff --git a/src/ImageProcessor/Processors/IGraphicsProcessor.cs b/src/ImageProcessor/Processors/IGraphicsProcessor.cs index 148c7a7e4..a3c06c050 100644 --- a/src/ImageProcessor/Processors/IGraphicsProcessor.cs +++ b/src/ImageProcessor/Processors/IGraphicsProcessor.cs @@ -23,38 +23,17 @@ namespace ImageProcessor.Processors { #region Properties /// - /// Gets the regular expression to search strings for. + /// Gets or sets the DynamicParameter. /// - Regex RegexPattern { get; } - - /// - /// Gets DynamicParameter. - /// - dynamic DynamicParameter { get; } - - /// - /// Gets the order in which this processor is to be used in a chain. - /// - int SortOrder { get; } + dynamic DynamicParameter { get; set; } /// /// Gets or sets any additional settings required by the processor. /// - Dictionary Settings { get; set; } + Dictionary Settings { get; set; } #endregion #region Methods - /// - /// 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. - /// - int MatchRegexIndex(string queryString); - /// /// Processes the image. /// diff --git a/src/ImageProcessor/Processors/Quality.cs b/src/ImageProcessor/Processors/Quality.cs index 97b4b7651..21995cd3c 100644 --- a/src/ImageProcessor/Processors/Quality.cs +++ b/src/ImageProcessor/Processors/Quality.cs @@ -115,7 +115,7 @@ namespace ImageProcessor.Processors public Image ProcessImage(ImageFactory factory) { // Set the internal property. - factory.JpegQuality = this.DynamicParameter; + factory.CurrentImageFormat.Quality = this.DynamicParameter; return factory.Image; } diff --git a/src/ImageProcessor/Processors/Resize.cs b/src/ImageProcessor/Processors/Resize.cs index 3a95203f7..072848ee6 100644 --- a/src/ImageProcessor/Processors/Resize.cs +++ b/src/ImageProcessor/Processors/Resize.cs @@ -20,7 +20,8 @@ namespace ImageProcessor.Processors using System.Linq; using System.Text; using System.Text.RegularExpressions; - using ImageProcessor.Extensions; + + using ImageProcessor.Core.Common.Extensions; using ImageProcessor.Imaging; #endregion diff --git a/src/ImageProcessor/Processors/Rotate.cs b/src/ImageProcessor/Processors/Rotate.cs index da3e85e63..1ce5fd416 100644 --- a/src/ImageProcessor/Processors/Rotate.cs +++ b/src/ImageProcessor/Processors/Rotate.cs @@ -15,9 +15,6 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; - using System.Globalization; - using System.Text.RegularExpressions; - using ImageProcessor.Imaging; #endregion /// @@ -25,33 +22,7 @@ namespace ImageProcessor.Processors /// public class Rotate : IGraphicsProcessor { - /// - /// The regular expression to search strings for. - /// - private static readonly Regex QueryRegex = new Regex(@"rotate=((?:3[0-5][0-9]|[12][0-9]{2}|[1-9][0-9]?)|angle-(?:3[0-5][0-9]|[12][0-9]{2}|[1-9][0-9]?)[\|,]bgcolor-([0-9a-fA-F]{3}){1,2})", RegexOptions.Compiled); - - /// - /// The regular expression to search strings for the angle attribute. - /// - private static readonly Regex AngleRegex = new Regex(@"angle-(?:3[0-5][0-9]|[12][0-9]{2}|[1-9][0-9]?)", 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); - - #region IGraphicsProcessor Members - /// - /// Gets the regular expression to search strings for. - /// - public Regex RegexPattern - { - get - { - return QueryRegex; - } - } - + #region IGraphicsProcessor members /// /// Gets or sets DynamicParameter. /// @@ -61,15 +32,6 @@ namespace ImageProcessor.Processors 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. /// @@ -79,57 +41,6 @@ namespace ImageProcessor.Processors 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; - - RotateLayer rotateLayer; - - string toParse = match.Value; - - if (toParse.Contains("bgcolor")) - { - rotateLayer = new RotateLayer(this.ParseAngle(toParse), this.ParseColor(toParse)); - } - else - { - int degrees; - int.TryParse(match.Value.Split('=')[1], NumberStyles.Any, CultureInfo.InvariantCulture, out degrees); - - rotateLayer = new RotateLayer(degrees); - } - - this.DynamicParameter = rotateLayer; - } - - index += 1; - } - } - - return this.SortOrder; - } - /// /// Processes the image. /// @@ -147,16 +58,14 @@ namespace ImageProcessor.Processors try { - RotateLayer rotateLayer = this.DynamicParameter; - int angle = rotateLayer.Angle; - Color backgroundColor = rotateLayer.BackgroundColor; + int 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, backgroundColor); + newImage = this.RotateImage(image, rotateAtX, rotateAtY, angle); image.Dispose(); image = newImage; @@ -181,12 +90,11 @@ namespace ImageProcessor.Processors /// The horizontal pixel coordinate at which to rotate the image. /// The vertical pixel coordinate at which to rotate the image. /// The angle in degrees 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 /// - private Bitmap RotateImage(Image image, float rotateAtX, float rotateAtY, float angle, Color backgroundColor) + private Bitmap RotateImage(Image image, float rotateAtX, float rotateAtY, float angle) { int width, height, x, y; @@ -242,14 +150,9 @@ namespace ImageProcessor.Processors { // Reduce the jagged edge. graphics.SmoothingMode = SmoothingMode.HighQuality; - - // Contrary to everything I have read bicubic is producing the best results. graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighSpeed; - - // Fill the background. - graphics.Clear(backgroundColor); + graphics.CompositingQuality = CompositingQuality.HighQuality; // Put the rotation point in the "center" of the image graphics.TranslateTransform(rotateAtX + x, rotateAtY + y); @@ -266,49 +169,6 @@ namespace ImageProcessor.Processors 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.Split('-')[1], NumberStyles.Any, CultureInfo.InvariantCulture, 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/Tint.cs b/src/ImageProcessor/Processors/Tint.cs index 37341552e..166789f63 100644 --- a/src/ImageProcessor/Processors/Tint.cs +++ b/src/ImageProcessor/Processors/Tint.cs @@ -10,13 +10,12 @@ namespace ImageProcessor.Processors { - using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Text.RegularExpressions; - using ImageProcessor.Extensions; + using ImageProcessor.Core.Common.Extensions; /// /// Tints an image with the given colour. diff --git a/src/ImageProcessor/Processors/Watermark.cs b/src/ImageProcessor/Processors/Watermark.cs index 586f04404..e911a443f 100644 --- a/src/ImageProcessor/Processors/Watermark.cs +++ b/src/ImageProcessor/Processors/Watermark.cs @@ -20,7 +20,7 @@ namespace ImageProcessor.Processors using System.Linq; using System.Text.RegularExpressions; - using ImageProcessor.Extensions; + using ImageProcessor.Core.Common.Extensions; using ImageProcessor.Imaging; #endregion diff --git a/src/ImageProcessor/Settings.StyleCop b/src/ImageProcessor/Settings.StyleCop index ceca99cde..6f5d9d4ab 100644 --- a/src/ImageProcessor/Settings.StyleCop +++ b/src/ImageProcessor/Settings.StyleCop @@ -2,6 +2,7 @@ behaviour + bootstrapper chrominance colour enum @@ -9,6 +10,7 @@ halftoning lomograph octree + png quantizer diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index 070afe2d8..fd5492fa8 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -38,9 +38,7 @@ namespace ImageProcessorConsole // Load, resize, set the format and quality and save an image. imageFactory.Load(inStream) .Constrain(size) - .Tint(Color.FromArgb(255, 106, 166, 204)) - .Format(format) - .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); + .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name.TrimEnd(".gif".ToCharArray()) + ".jpg"))); } } } diff --git a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id index 0d2234d4e..71ce555c1 100644 --- a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id @@ -1 +1 @@ -17e154964bfb4da80c1e0aec623cd2486d493b47 \ No newline at end of file +30ec5c05548fd350f9b7c699715848b9fbfb8ca9 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id index e57ebffe4..4487aede0 100644 --- a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id @@ -1 +1 @@ -069f8472ed7b83ea57f4cf511f83396e1a0b8877 \ No newline at end of file +23a1c81a2d1422076373796e0c47f5d968c56d0b \ No newline at end of file From 5c8bdd83d556a917c43b75c53190914855651dfd Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 10 Jun 2014 16:38:38 +0200 Subject: [PATCH 002/155] Moar conversions! Former-commit-id: f812ee5350b737eb4df0bccae42025c44d133065 --- .../ImageCacheSection.cs | 0 .../ImageProcessingSection.cs | 0 .../ImageProcessorConfiguration.cs | 29 +-- .../ImageSecuritySection.cs | 0 .../Resources/cache.config | 0 .../Resources/processing - Copy.config} | 0 .../Configuration/Resources/processing.config | 40 +++++ .../Resources/security.config | 0 ...ies.cs => CommonParameterParserUtility.cs} | 29 ++- .../HttpModules/ImageProcessingModule.cs | 2 +- .../NET45/ImageFactoryExtensions.cs | 8 +- .../NET45/ImageProcessor.Web_NET45.csproj | 27 ++- .../NET45/Processors/Alpha.cs | 80 +++++++++ .../NET45/Processors/BackgroundColor.cs | 2 +- .../NET45/Processors/Brightness.cs | 89 ++++++++++ .../NET45/Processors/Contrast.cs | 89 ++++++++++ .../NET45/Processors/Crop.cs | 166 ++++++++++++++++++ .../NET45/Processors/Quality.cs | 90 ++++++++++ .../NET45/Processors/Rotate.cs | 2 +- .../NET45/Processors/Saturation.cs | 92 ++++++++++ src/ImageProcessor/ImageFactory.cs | 37 +--- .../Imaging/Filters/GothamMatrixFilter.cs | 8 +- .../Imaging/Filters/LomographMatrixFilter.cs | 5 +- .../Imaging/Filters/PolaroidMatrixFilter.cs | 2 +- .../Imaging/Formats/FormatBase.cs | 2 +- .../Imaging/Formats/GifFormat.cs | 4 +- src/ImageProcessor/Processors/Alpha.cs | 68 ------- src/ImageProcessor/Processors/Brightness.cs | 98 ++--------- src/ImageProcessor/Processors/Contrast.cs | 80 +-------- src/ImageProcessor/Processors/Crop.cs | 144 +-------------- src/ImageProcessor/Processors/Quality.cs | 67 ------- src/ImageProcessor/Processors/Saturation.cs | 75 +------- .../NET45/Test_Website_NET45/Web.config | 6 +- .../config/imageprocessor/processing.config | 44 +++-- 34 files changed, 783 insertions(+), 602 deletions(-) rename src/ImageProcessor.Web/NET45/{Config => Configuration}/ImageCacheSection.cs (100%) rename src/ImageProcessor.Web/NET45/{Config => Configuration}/ImageProcessingSection.cs (100%) rename src/ImageProcessor.Web/NET45/{Config => Configuration}/ImageProcessorConfiguration.cs (91%) rename src/ImageProcessor.Web/NET45/{Config => Configuration}/ImageSecuritySection.cs (100%) rename src/ImageProcessor.Web/NET45/{Config => Configuration}/Resources/cache.config (100%) rename src/ImageProcessor.Web/NET45/{Config/Resources/processing.config => Configuration/Resources/processing - Copy.config} (100%) create mode 100644 src/ImageProcessor.Web/NET45/Configuration/Resources/processing.config rename src/ImageProcessor.Web/NET45/{Config => Configuration}/Resources/security.config (100%) rename src/ImageProcessor.Web/NET45/Helpers/{ParameterParserUtilities.cs => CommonParameterParserUtility.cs} (76%) create mode 100644 src/ImageProcessor.Web/NET45/Processors/Alpha.cs create mode 100644 src/ImageProcessor.Web/NET45/Processors/Brightness.cs create mode 100644 src/ImageProcessor.Web/NET45/Processors/Contrast.cs create mode 100644 src/ImageProcessor.Web/NET45/Processors/Crop.cs create mode 100644 src/ImageProcessor.Web/NET45/Processors/Quality.cs create mode 100644 src/ImageProcessor.Web/NET45/Processors/Saturation.cs diff --git a/src/ImageProcessor.Web/NET45/Config/ImageCacheSection.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Config/ImageCacheSection.cs rename to src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs diff --git a/src/ImageProcessor.Web/NET45/Config/ImageProcessingSection.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Config/ImageProcessingSection.cs rename to src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs diff --git a/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfiguration.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs similarity index 91% rename from src/ImageProcessor.Web/NET45/Config/ImageProcessorConfiguration.cs rename to src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs index 2bcf73d78..e871a5c35 100644 --- a/src/ImageProcessor.Web/NET45/Config/ImageProcessorConfiguration.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs @@ -1,5 +1,5 @@ // -------------------------------------------------------------------------------------------------------------------- -// +// // Copyright (c) James South. // Licensed under the Apache License, Version 2.0. // @@ -18,6 +18,8 @@ namespace ImageProcessor.Web.Configuration using System.Reflection; using System.Web.Compilation; using ImageProcessor.Processors; + using ImageProcessor.Web.Processors; + #endregion /// @@ -64,8 +66,9 @@ namespace ImageProcessor.Web.Configuration #endregion #region Constructors + /// - /// Prevents a default instance of the class from being created. + /// Prevents a default instance of the class from being created. /// private ImageProcessorConfiguration() { @@ -75,7 +78,7 @@ namespace ImageProcessor.Web.Configuration #region Properties /// - /// Gets the current instance of the class. + /// Gets the current instance of the class. /// public static ImageProcessorConfiguration Instance { @@ -88,7 +91,7 @@ namespace ImageProcessor.Web.Configuration /// /// Gets the list of available GraphicsProcessors. /// - public IList GraphicsProcessors { get; private set; } + public IList GraphicsProcessors { get; private set; } /// /// Gets a value indicating whether to preserve exif meta data. @@ -292,7 +295,7 @@ namespace ImageProcessor.Web.Configuration { if (GetImageProcessingSection().Plugins.AutoLoadPlugins) { - Type type = typeof(IGraphicsProcessor); + Type type = typeof(IWebGraphicsProcessor); try { // Build a list of native IGraphicsProcessor instances. @@ -303,12 +306,12 @@ namespace ImageProcessor.Web.Configuration .ToList(); // Create them and add. - this.GraphicsProcessors = availableTypes.Select(x => (Activator.CreateInstance(x) as IGraphicsProcessor)).ToList(); + this.GraphicsProcessors = availableTypes.Select(x => (Activator.CreateInstance(x) as IWebGraphicsProcessor)).ToList(); // Add the available settings. - foreach (IGraphicsProcessor processor in this.GraphicsProcessors) + foreach (IWebGraphicsProcessor webProcessor in this.GraphicsProcessors) { - processor.Settings = this.GetPluginSettings(processor.GetType().Name); + webProcessor.Processor.Settings = this.GetPluginSettings(webProcessor.GetType().Name); } } catch (ReflectionTypeLoadException) @@ -332,23 +335,23 @@ namespace ImageProcessor.Web.Configuration private void LoadGraphicsProcessorsFromConfiguration() { ImageProcessingSection.PluginElementCollection pluginConfigs = imageProcessingSection.Plugins; - this.GraphicsProcessors = new List(); + this.GraphicsProcessors = new List(); foreach (ImageProcessingSection.PluginElement pluginConfig in pluginConfigs) { Type type = Type.GetType(pluginConfig.Type); if (type == null) { - throw new TypeLoadException("Couldn't load IGraphicsProcessor: " + pluginConfig.Type); + throw new TypeLoadException("Couldn't load IWebGraphicsProcessor: " + pluginConfig.Type); } - this.GraphicsProcessors.Add(Activator.CreateInstance(type) as IGraphicsProcessor); + this.GraphicsProcessors.Add(Activator.CreateInstance(type) as IWebGraphicsProcessor); } // Add the available settings. - foreach (IGraphicsProcessor processor in this.GraphicsProcessors) + foreach (IWebGraphicsProcessor webProcessor in this.GraphicsProcessors) { - processor.Settings = this.GetPluginSettings(processor.GetType().Name); + webProcessor.Processor.Settings = this.GetPluginSettings(webProcessor.GetType().Name); } } #endregion diff --git a/src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageSecuritySection.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Config/ImageSecuritySection.cs rename to src/ImageProcessor.Web/NET45/Configuration/ImageSecuritySection.cs diff --git a/src/ImageProcessor.Web/NET45/Config/Resources/cache.config b/src/ImageProcessor.Web/NET45/Configuration/Resources/cache.config similarity index 100% rename from src/ImageProcessor.Web/NET45/Config/Resources/cache.config rename to src/ImageProcessor.Web/NET45/Configuration/Resources/cache.config diff --git a/src/ImageProcessor.Web/NET45/Config/Resources/processing.config b/src/ImageProcessor.Web/NET45/Configuration/Resources/processing - Copy.config similarity index 100% rename from src/ImageProcessor.Web/NET45/Config/Resources/processing.config rename to src/ImageProcessor.Web/NET45/Configuration/Resources/processing - Copy.config diff --git a/src/ImageProcessor.Web/NET45/Configuration/Resources/processing.config b/src/ImageProcessor.Web/NET45/Configuration/Resources/processing.config new file mode 100644 index 000000000..c29cd5db1 --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Configuration/Resources/processing.config @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET45/Config/Resources/security.config b/src/ImageProcessor.Web/NET45/Configuration/Resources/security.config similarity index 100% rename from src/ImageProcessor.Web/NET45/Config/Resources/security.config rename to src/ImageProcessor.Web/NET45/Configuration/Resources/security.config diff --git a/src/ImageProcessor.Web/NET45/Helpers/ParameterParserUtilities.cs b/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs similarity index 76% rename from src/ImageProcessor.Web/NET45/Helpers/ParameterParserUtilities.cs rename to src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs index eb6af4357..d4039acdd 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/ParameterParserUtilities.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs @@ -1,5 +1,5 @@ // -------------------------------------------------------------------------------------------------------------------- -// +// // Copyright (c) James South. // Licensed under the Apache License, Version 2.0. // @@ -18,7 +18,7 @@ namespace ImageProcessor.Web.Helpers /// /// Encapsulates methods to correctly parse querystring parameters. /// - public static class ParameterParserUtilities + public static class CommonParameterParserUtility { /// /// The regular expression to search strings for colors. @@ -30,6 +30,11 @@ namespace ImageProcessor.Web.Helpers /// private static readonly Regex AngleRegex = new Regex(@"(rotate|angle)(=|-)(?:3[0-5][0-9]|[12][0-9]{2}|[1-9][0-9]?)", RegexOptions.Compiled); + /// + /// The regular expression to search strings for values between 1 and 100. + /// + private static readonly Regex In100RangeRegex = new Regex(@"(-?(?:100)|-?([1-9]?[0-9]))", RegexOptions.Compiled); + /// /// Returns the correct containing the angle for the given string. /// @@ -86,5 +91,25 @@ namespace ImageProcessor.Web.Helpers return Color.Transparent; } + + /// + /// Returns the correct for the given string. + /// + /// + /// The input string containing the value to parse. + /// + /// + /// The correct between -100 and 100. + /// + public static int ParseIn100Range(string input) + { + int value = 0; + foreach (Match match in In100RangeRegex.Matches(input)) + { + value = int.Parse(match.Value, CultureInfo.InvariantCulture); + } + + return value; + } } } diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index 6d10a49ee..213d35b2a 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -414,7 +414,7 @@ namespace ImageProcessor.Web.HttpModules .Save(cachedPath); // Store the response type in the context for later retrieval. - context.Items[CachedResponseTypeKey] = imageFactory.MimeType; + context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType; // Ensure that the LastWriteTime property of the source and cached file match. Tuple creationAndLastWriteDateTimes = await cache.SetCachedLastWriteTimeAsync(); diff --git a/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs b/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs index c677149fb..704373a55 100644 --- a/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs +++ b/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs @@ -13,8 +13,8 @@ namespace ImageProcessor.Web #region Using using System.Collections.Generic; using System.Linq; - using ImageProcessor.Processors; using ImageProcessor.Web.Configuration; + using ImageProcessor.Web.Processors; #endregion /// @@ -45,16 +45,16 @@ namespace ImageProcessor.Web lock (SyncRoot) { // Get a list of all graphics processors that have parsed and matched the query string. - List graphicsProcessors = + List graphicsProcessors = ImageProcessorConfiguration.Instance.GraphicsProcessors .Where(x => x.MatchRegexIndex(factory.QueryString) != int.MaxValue) .OrderBy(y => y.SortOrder) .ToList(); // Loop through and process the image. - foreach (IGraphicsProcessor graphicsProcessor in graphicsProcessors) + foreach (IWebGraphicsProcessor graphicsProcessor in graphicsProcessors) { - factory.CurrentImageFormat.ApplyProcessor(graphicsProcessor.ProcessImage, factory); + factory.CurrentImageFormat.ApplyProcessor(graphicsProcessor.Processor.ProcessImage, factory); } } } diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index bdf8ba8dc..40d4d8fdd 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -49,20 +49,26 @@ - - - - - + + + + + + + + + + + @@ -72,13 +78,18 @@ - + Designer - + + Designer + + + + + Designer - diff --git a/src/ImageProcessor.Web/NET45/Processors/Alpha.cs b/src/ImageProcessor.Web/NET45/Processors/Alpha.cs new file mode 100644 index 000000000..75993a702 --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/Alpha.cs @@ -0,0 +1,80 @@ +namespace ImageProcessor.Web.Processors +{ + using System; + using System.Text.RegularExpressions; + using ImageProcessor.Processors; + using ImageProcessor.Web.Helpers; + + /// + /// Encapsulates methods to change the alpha component of the image to effect its transparency. + /// + public class Alpha : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"alpha=[^&|,]*", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public Alpha() + { + this.Processor = new ImageProcessor.Processors.Alpha(); + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder { get; private set; } + + /// + /// Gets the associated graphics processor. + /// + public IGraphicsProcessor Processor { get; private 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; + int percentage = Math.Abs(CommonParameterParserUtility.ParseIn100Range(match.Value)); + this.Processor.DynamicParameter = percentage; + } + + index += 1; + } + } + + return this.SortOrder; + } + } +} diff --git a/src/ImageProcessor.Web/NET45/Processors/BackgroundColor.cs b/src/ImageProcessor.Web/NET45/Processors/BackgroundColor.cs index 7fc0a49a5..80df3959c 100644 --- a/src/ImageProcessor.Web/NET45/Processors/BackgroundColor.cs +++ b/src/ImageProcessor.Web/NET45/Processors/BackgroundColor.cs @@ -75,7 +75,7 @@ namespace ImageProcessor.Web.Processors { // Set the index on the first instance only. this.SortOrder = match.Index; - this.Processor.DynamicParameter = ParameterParserUtilities.ParseColor(match.Value); + this.Processor.DynamicParameter = CommonParameterParserUtility.ParseColor(match.Value); } index += 1; diff --git a/src/ImageProcessor.Web/NET45/Processors/Brightness.cs b/src/ImageProcessor.Web/NET45/Processors/Brightness.cs new file mode 100644 index 000000000..602d34b1c --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/Brightness.cs @@ -0,0 +1,89 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates methods to change the brightness component of the image. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System.Text.RegularExpressions; + using ImageProcessor.Processors; + using ImageProcessor.Web.Helpers; + + /// + /// Encapsulates methods to change the brightness component of the image. + /// + public class Brightness : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"brightness=[^&|,]*", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public Brightness() + { + this.Processor = new ImageProcessor.Processors.Brightness(); + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder { get; private set; } + + /// + /// Gets the associated graphics processor. + /// + public IGraphicsProcessor Processor { get; private 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; + int percentage = CommonParameterParserUtility.ParseIn100Range(match.Value); + this.Processor.DynamicParameter = percentage; + } + + index += 1; + } + } + + return this.SortOrder; + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET45/Processors/Contrast.cs b/src/ImageProcessor.Web/NET45/Processors/Contrast.cs new file mode 100644 index 000000000..09ec2808c --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/Contrast.cs @@ -0,0 +1,89 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates methods to change the contrast component of the image. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System.Text.RegularExpressions; + using ImageProcessor.Processors; + using ImageProcessor.Web.Helpers; + + /// + /// Encapsulates methods to change the contrast component of the image. + /// + public class Contrast : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"contrast=[^&|,]*", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public Contrast() + { + this.Processor = new ImageProcessor.Processors.Contrast(); + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder { get; private set; } + + /// + /// Gets the associated graphics processor. + /// + public IGraphicsProcessor Processor { get; private 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; + int percentage = CommonParameterParserUtility.ParseIn100Range(match.Value); + this.Processor.DynamicParameter = percentage; + } + + index += 1; + } + } + + return this.SortOrder; + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET45/Processors/Crop.cs b/src/ImageProcessor.Web/NET45/Processors/Crop.cs new file mode 100644 index 000000000..4ca186d5c --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/Crop.cs @@ -0,0 +1,166 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Crops an image to the given directions. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System.Text; + using System.Text.RegularExpressions; + using ImageProcessor.Core.Common.Extensions; + using ImageProcessor.Imaging; + using ImageProcessor.Processors; + + /// + /// Crops an image to the given directions. + /// + public class Crop : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + /// + private static readonly Regex QueryRegex = new Regex(@"(crop=|cropmode=)[^&]*", RegexOptions.Compiled); + + /// + /// The coordinate regex. + /// + private static readonly Regex CoordinateRegex = new Regex(@"crop=\d+(.\d+)?[,-]\d+(.\d+)?[,-]\d+(.\d+)?[,-]\d+(.\d+)?", RegexOptions.Compiled); + + /// + /// The mode regex. + /// + private static readonly Regex ModeRegex = new Regex(@"cropmode=(pixels|percent)", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public Crop() + { + this.Processor = new ImageProcessor.Processors.Crop(); + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder { get; private set; } + + /// + /// Gets the associated graphics processor. + /// + public IGraphicsProcessor Processor { get; private 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; + + // First merge the matches so we can parse . + StringBuilder stringBuilder = new StringBuilder(); + + 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; + } + + stringBuilder.Append(match.Value); + + index += 1; + } + } + + if (this.SortOrder < int.MaxValue) + { + // Match syntax + string toParse = stringBuilder.ToString(); + + float[] coordinates = this.ParseCoordinates(toParse); + CropMode cropMode = this.ParseMode(toParse); + + CropLayer cropLayer = new CropLayer(coordinates[0], coordinates[1], coordinates[2], coordinates[3], cropMode); + this.Processor.DynamicParameter = cropLayer; + } + + return this.SortOrder; + } + + /// + /// Returns the correct for the given string. + /// + /// + /// The input string containing the value to parse. + /// + /// + /// The correct . + /// + private CropMode ParseMode(string input) + { + foreach (Match match in ModeRegex.Matches(input)) + { + // Split on = + string mode = match.Value.Split('=')[1]; + + switch (mode) + { + case "percent": + return CropMode.Percentage; + case "pixels": + return CropMode.Pixels; + } + } + + return CropMode.Pixels; + } + + /// + /// Returns the correct for the given string. + /// + /// + /// The input string containing the value to parse. + /// + /// + /// The correct . + /// + private float[] ParseCoordinates(string input) + { + float[] floats = { }; + + foreach (Match match in CoordinateRegex.Matches(input)) + { + floats = match.Value.ToPositiveFloatArray(); + } + + return floats; + } + } +} diff --git a/src/ImageProcessor.Web/NET45/Processors/Quality.cs b/src/ImageProcessor.Web/NET45/Processors/Quality.cs new file mode 100644 index 000000000..fa11777db --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/Quality.cs @@ -0,0 +1,90 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates methods to change the quality component of the image. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System; + using System.Text.RegularExpressions; + using ImageProcessor.Processors; + using ImageProcessor.Web.Helpers; + + /// + /// Encapsulates methods to change the quality component of the image. + /// + public class Quality : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"quality=[^&|,]*", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public Quality() + { + this.Processor = new ImageProcessor.Processors.Quality(); + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder { get; private set; } + + /// + /// Gets the associated graphics processor. + /// + public IGraphicsProcessor Processor { get; private 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; + int percentage = Math.Abs(CommonParameterParserUtility.ParseIn100Range(match.Value)); + this.Processor.DynamicParameter = percentage; + } + + index += 1; + } + } + + return this.SortOrder; + } + } +} diff --git a/src/ImageProcessor.Web/NET45/Processors/Rotate.cs b/src/ImageProcessor.Web/NET45/Processors/Rotate.cs index 58375b179..74a707d36 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Rotate.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Rotate.cs @@ -82,7 +82,7 @@ namespace ImageProcessor.Web.Processors { // Set the index on the first instance only. this.SortOrder = match.Index; - this.Processor.DynamicParameter = ParameterParserUtilities.ParseAngle(match.Value); + this.Processor.DynamicParameter = CommonParameterParserUtility.ParseAngle(match.Value); } index += 1; diff --git a/src/ImageProcessor.Web/NET45/Processors/Saturation.cs b/src/ImageProcessor.Web/NET45/Processors/Saturation.cs new file mode 100644 index 000000000..469a19ba6 --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/Saturation.cs @@ -0,0 +1,92 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates methods to change the saturation component of the image. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System.Text.RegularExpressions; + using ImageProcessor.Processors; + using ImageProcessor.Web.Helpers; + + /// + /// Encapsulates methods to change the saturation component of the image. + /// + /// + /// + /// + public class Saturation : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"saturation=[^&|,]*", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public Saturation() + { + this.Processor = new ImageProcessor.Processors.Saturation(); + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder { get; private set; } + + /// + /// Gets the associated graphics processor. + /// + public IGraphicsProcessor Processor { get; private 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; + int percentage = CommonParameterParserUtility.ParseIn100Range(match.Value); + this.Processor.DynamicParameter = percentage; + } + + index += 1; + } + } + + return this.SortOrder; + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 8d9b34f75..c0ac9062b 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -91,11 +91,6 @@ namespace ImageProcessor #endregion #region Properties - /// - /// Gets the local image for manipulation. - /// - public Image Image { get; private set; } - /// /// Gets the path to the local image for manipulation. /// @@ -126,6 +121,11 @@ namespace ImageProcessor /// public ConcurrentDictionary ExifPropertyItems { get; set; } + /// + /// Gets or sets the local image for manipulation. + /// + internal Image Image { get; set; } + /// /// Gets or sets the original extension. /// @@ -254,33 +254,6 @@ namespace ImageProcessor return this; } - /// - /// Updates the specified image. Used by the various IProcessors. - /// - /// The image. - /// - /// The current instance of the class. - /// - public ImageFactory Update(Image image) - { - if (this.ShouldProcess) - { - this.Image = image; - - // Get the correct image format for the image. - using (MemoryStream stream = new MemoryStream()) - { - image.Save(stream, image.RawFormat); - stream.Position = 0; - int quality = this.CurrentImageFormat.Quality; - this.CurrentImageFormat = FormatUtilities.GetFormat(stream); - this.CurrentImageFormat.Quality = quality; - } - } - - return this; - } - /// /// Resets the current image to its original loaded state. /// diff --git a/src/ImageProcessor/Imaging/Filters/GothamMatrixFilter.cs b/src/ImageProcessor/Imaging/Filters/GothamMatrixFilter.cs index ddbb92128..abeaedf5c 100644 --- a/src/ImageProcessor/Imaging/Filters/GothamMatrixFilter.cs +++ b/src/ImageProcessor/Imaging/Filters/GothamMatrixFilter.cs @@ -79,13 +79,13 @@ namespace ImageProcessor.Imaging.Filters } // Add brightness and contrast to finish the effect. - factory.Update(newImage); + factory.Image = newImage; Brightness brightness = new Brightness { DynamicParameter = 5 }; - newImage = (Bitmap)brightness.ProcessImage(factory); + newImage = brightness.ProcessImage(factory); - factory.Update(newImage); + factory.Image = newImage; Contrast contrast = new Contrast { DynamicParameter = 85 }; - newImage = (Bitmap)contrast.ProcessImage(factory); + newImage = contrast.ProcessImage(factory); // Reassign the image. image.Dispose(); diff --git a/src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs b/src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs index c44bce5c8..253bb419a 100644 --- a/src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs +++ b/src/ImageProcessor/Imaging/Filters/LomographMatrixFilter.cs @@ -50,15 +50,14 @@ namespace ImageProcessor.Imaging.Filters attributes.SetColorMatrix(this.Matrix); Rectangle rectangle = new Rectangle(0, 0, image.Width, image.Height); - graphics.DrawImage(image, rectangle, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes); } } // Add a vignette to finish the effect. - factory.Update(newImage); + factory.Image = newImage; Vignette vignette = new Vignette(); - newImage = (Bitmap)vignette.ProcessImage(factory); + newImage = vignette.ProcessImage(factory); // Reassign the image. image.Dispose(); diff --git a/src/ImageProcessor/Imaging/Filters/PolaroidMatrixFilter.cs b/src/ImageProcessor/Imaging/Filters/PolaroidMatrixFilter.cs index 947c79f25..af4c5fd4f 100644 --- a/src/ImageProcessor/Imaging/Filters/PolaroidMatrixFilter.cs +++ b/src/ImageProcessor/Imaging/Filters/PolaroidMatrixFilter.cs @@ -85,7 +85,7 @@ namespace ImageProcessor.Imaging.Filters } // Add a vignette to finish the effect. - factory.Update(newImage); + factory.Image = newImage; Vignette vignette = new Vignette(); newImage = vignette.ProcessImage(factory); diff --git a/src/ImageProcessor/Imaging/Formats/FormatBase.cs b/src/ImageProcessor/Imaging/Formats/FormatBase.cs index 79c90a12b..de590aea2 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatBase.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatBase.cs @@ -73,7 +73,7 @@ namespace ImageProcessor.Imaging.Formats /// The . public virtual void ApplyProcessor(Func processor, ImageFactory factory) { - processor.Invoke(factory); + factory.Image = processor.Invoke(factory); } /// diff --git a/src/ImageProcessor/Imaging/Formats/GifFormat.cs b/src/ImageProcessor/Imaging/Formats/GifFormat.cs index b2b3cb413..87c9a0d30 100644 --- a/src/ImageProcessor/Imaging/Formats/GifFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/GifFormat.cs @@ -86,14 +86,14 @@ namespace ImageProcessor.Imaging.Formats { foreach (GifFrame frame in imageInfo.GifFrames) { - factory.Update(frame.Image); + factory.Image = frame.Image; frame.Image = quantizer.Quantize(processor.Invoke(factory)); encoder.AddFrame(frame); } } stream.Position = 0; - factory.Update(Image.FromStream(stream)); + factory.Image = Image.FromStream(stream); } else { diff --git a/src/ImageProcessor/Processors/Alpha.cs b/src/ImageProcessor/Processors/Alpha.cs index 70ff57a65..6301c0e97 100644 --- a/src/ImageProcessor/Processors/Alpha.cs +++ b/src/ImageProcessor/Processors/Alpha.cs @@ -10,37 +10,15 @@ namespace ImageProcessor.Processors { - #region Using using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; - using System.Globalization; - using System.Text.RegularExpressions; - #endregion /// /// Encapsulates methods to change the alpha component of the image to effect its transparency. /// public class Alpha : IGraphicsProcessor { - /// - /// The regular expression to search strings for. - /// - /// - private static readonly Regex QueryRegex = new Regex(@"alpha=(?:100|[1-9]?[0-9])", RegexOptions.Compiled); - - #region IGraphicsProcessor Members - /// - /// Gets the regular expression to search strings for. - /// - public Regex RegexPattern - { - get - { - return QueryRegex; - } - } - /// /// Gets or sets DynamicParameter. /// @@ -50,15 +28,6 @@ namespace ImageProcessor.Processors 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. /// @@ -68,42 +37,6 @@ namespace ImageProcessor.Processors 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; - int percentage = int.Parse(match.Value.Split('=')[1], CultureInfo.InvariantCulture); - - this.DynamicParameter = percentage; - } - - index += 1; - } - } - - return this.SortOrder; - } - /// /// Processes the image. /// @@ -152,6 +85,5 @@ namespace ImageProcessor.Processors return image; } - #endregion } } diff --git a/src/ImageProcessor/Processors/Brightness.cs b/src/ImageProcessor/Processors/Brightness.cs index 6671ec373..56a17cc2b 100644 --- a/src/ImageProcessor/Processors/Brightness.cs +++ b/src/ImageProcessor/Processors/Brightness.cs @@ -10,37 +10,15 @@ namespace ImageProcessor.Processors { - #region Using using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; - using System.Globalization; - using System.Text.RegularExpressions; - #endregion /// /// Encapsulates methods to change the brightness component of the image. /// public class Brightness : IGraphicsProcessor { - /// - /// The regular expression to search strings for. - /// - /// - private static readonly Regex QueryRegex = new Regex(@"brightness=(-?(?:100)|-?([1-9]?[0-9]))", RegexOptions.Compiled); - - #region IGraphicsProcessor Members - /// - /// Gets the regular expression to search strings for. - /// - public Regex RegexPattern - { - get - { - return QueryRegex; - } - } - /// /// Gets or sets DynamicParameter. /// @@ -50,15 +28,6 @@ namespace ImageProcessor.Processors 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. /// @@ -68,42 +37,6 @@ namespace ImageProcessor.Processors 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; - int percentage = int.Parse(match.Value.Split('=')[1], CultureInfo.InvariantCulture); - - this.DynamicParameter = percentage; - } - - index += 1; - } - } - - return this.SortOrder; - } - /// /// Processes the image. /// @@ -125,16 +58,14 @@ namespace ImageProcessor.Processors newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb); - ColorMatrix colorMatrix = new ColorMatrix( - new float[][] - { - new float[] { 1, 0, 0, 0, 0 }, - new float[] { 0, 1, 0, 0, 0 }, - new float[] { 0, 0, 1, 0, 0 }, - new float[] { 0, 0, 0, 1, 0 }, - new float[] { brightnessFactor, brightnessFactor, brightnessFactor, 0, 1 } - }); - + ColorMatrix colorMatrix = + new ColorMatrix( + new[] + { + new float[] { 1, 0, 0, 0, 0 }, new float[] { 0, 1, 0, 0, 0 }, + new float[] { 0, 0, 1, 0, 0 }, new float[] { 0, 0, 0, 1, 0 }, + new[] { brightnessFactor, brightnessFactor, brightnessFactor, 0, 1 } + }); using (Graphics graphics = Graphics.FromImage(newImage)) { @@ -142,7 +73,15 @@ namespace ImageProcessor.Processors { imageAttributes.SetColorMatrix(colorMatrix); - graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, imageAttributes); + graphics.DrawImage( + image, + new Rectangle(0, 0, image.Width, image.Height), + 0, + 0, + image.Width, + image.Height, + GraphicsUnit.Pixel, + imageAttributes); image.Dispose(); image = newImage; @@ -159,6 +98,5 @@ namespace ImageProcessor.Processors return image; } - #endregion } -} +} \ No newline at end of file diff --git a/src/ImageProcessor/Processors/Contrast.cs b/src/ImageProcessor/Processors/Contrast.cs index 4d057d6d5..ee4557517 100644 --- a/src/ImageProcessor/Processors/Contrast.cs +++ b/src/ImageProcessor/Processors/Contrast.cs @@ -10,37 +10,15 @@ namespace ImageProcessor.Processors { - #region Using using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; - using System.Globalization; - using System.Text.RegularExpressions; - #endregion /// /// Encapsulates methods to change the contrast component of the image. /// public class Contrast : IGraphicsProcessor { - /// - /// The regular expression to search strings for. - /// - /// - private static readonly Regex QueryRegex = new Regex(@"contrast=(-?(?:100)|-?([1-9]?[0-9]))", RegexOptions.Compiled); - - #region IGraphicsProcessor Members - /// - /// Gets the regular expression to search strings for. - /// - public Regex RegexPattern - { - get - { - return QueryRegex; - } - } - /// /// Gets or sets DynamicParameter. /// @@ -50,15 +28,6 @@ namespace ImageProcessor.Processors 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. /// @@ -68,42 +37,6 @@ namespace ImageProcessor.Processors 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; - int percentage = int.Parse(match.Value.Split('=')[1], CultureInfo.InvariantCulture); - - this.DynamicParameter = percentage; - } - - index += 1; - } - } - - return this.SortOrder; - } - /// /// Processes the image. /// @@ -130,13 +63,13 @@ namespace ImageProcessor.Processors newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb); ColorMatrix colorMatrix = new ColorMatrix( - new float[][] + new[] { - new float[] { contrastFactor, 0, 0, 0, 0 }, - new float[] { 0, contrastFactor, 0, 0, 0 }, - new float[] { 0, 0, contrastFactor, 0, 0 }, + new[] { contrastFactor, 0, 0, 0, 0 }, + new[] { 0, contrastFactor, 0, 0, 0 }, + new[] { 0, 0, contrastFactor, 0, 0 }, new float[] { 0, 0, 0, 1, 0 }, - new float[] { factorTransform, factorTransform, factorTransform, 0, 1 } + new[] { factorTransform, factorTransform, factorTransform, 0, 1 } }); using (Graphics graphics = Graphics.FromImage(newImage)) @@ -162,6 +95,5 @@ namespace ImageProcessor.Processors return image; } - #endregion } -} +} \ No newline at end of file diff --git a/src/ImageProcessor/Processors/Crop.cs b/src/ImageProcessor/Processors/Crop.cs index 0124b0f61..abf9483ef 100644 --- a/src/ImageProcessor/Processors/Crop.cs +++ b/src/ImageProcessor/Processors/Crop.cs @@ -15,12 +15,7 @@ namespace ImageProcessor.Processors using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; - using System.Text; - using System.Text.RegularExpressions; - - using ImageProcessor.Core.Common.Extensions; using ImageProcessor.Imaging; - #endregion /// @@ -28,34 +23,6 @@ namespace ImageProcessor.Processors /// public class Crop : IGraphicsProcessor { - /// - /// The regular expression to search strings for. - /// - /// - private static readonly Regex QueryRegex = new Regex(@"crop=\d+(.\d+)?[,-]\d+(.\d+)?[,-]\d+(.\d+)?[,-]\d+(.\d+)?|cropmode=(pixels|percent)", RegexOptions.Compiled); - - /// - /// The coordinate regex. - /// - private static readonly Regex CoordinateRegex = new Regex(@"crop=\d+(.\d+)?[,-]\d+(.\d+)?[,-]\d+(.\d+)?[,-]\d+(.\d+)?", RegexOptions.Compiled); - - /// - /// The mode regex. - /// - private static readonly Regex ModeRegex = new Regex(@"cropmode=(pixels|percent)", RegexOptions.Compiled); - - #region IGraphicsProcessor Members - /// - /// Gets the regular expression to search strings for. - /// - public Regex RegexPattern - { - get - { - return QueryRegex; - } - } - /// /// Gets or sets DynamicParameter. /// @@ -65,15 +32,6 @@ namespace ImageProcessor.Processors 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. /// @@ -83,56 +41,6 @@ namespace ImageProcessor.Processors 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; - - // First merge the matches so we can parse . - StringBuilder stringBuilder = new StringBuilder(); - - 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; - } - - stringBuilder.Append(match.Value); - - index += 1; - } - } - - if (this.SortOrder < int.MaxValue) - { - // Match syntax - string toParse = stringBuilder.ToString(); - - float[] coordinates = this.ParseCoordinates(toParse); - CropMode cropMode = this.ParseMode(toParse); - - CropLayer cropLayer = new CropLayer(coordinates[0], coordinates[1], coordinates[2], coordinates[3], cropMode); - this.DynamicParameter = cropLayer; - } - - return this.SortOrder; - } - /// /// Processes the image. /// @@ -159,7 +67,7 @@ namespace ImageProcessor.Processors // Work out the percentages. float left = cropLayer.Left * sourceWidth; float top = cropLayer.Top * sourceHeight; - float width = (1 - cropLayer.Left - cropLayer.Right) * sourceWidth; + float width = (1 - cropLayer.Left - cropLayer.Right) * sourceWidth; float height = (1 - cropLayer.Top - cropLayer.Bottom) * sourceHeight; rectangleF = new RectangleF(left, top, width, height); @@ -226,55 +134,5 @@ namespace ImageProcessor.Processors return image; } - #endregion - - /// - /// Returns the correct for the given string. - /// - /// - /// The input string containing the value to parse. - /// - /// - /// The correct . - /// - private CropMode ParseMode(string input) - { - foreach (Match match in ModeRegex.Matches(input)) - { - // Split on = - string mode = match.Value.Split('=')[1]; - - switch (mode) - { - case "percent": - return CropMode.Percentage; - case "pixels": - return CropMode.Pixels; - } - } - - return CropMode.Pixels; - } - - /// - /// Returns the correct for the given string. - /// - /// - /// The input string containing the value to parse. - /// - /// - /// The correct . - /// - private float[] ParseCoordinates(string input) - { - float[] floats = { }; - - foreach (Match match in CoordinateRegex.Matches(input)) - { - floats = match.Value.ToPositiveFloatArray(); - } - - return floats; - } } } diff --git a/src/ImageProcessor/Processors/Quality.cs b/src/ImageProcessor/Processors/Quality.cs index 21995cd3c..6d4d10743 100644 --- a/src/ImageProcessor/Processors/Quality.cs +++ b/src/ImageProcessor/Processors/Quality.cs @@ -13,8 +13,6 @@ namespace ImageProcessor.Processors #region Using using System.Collections.Generic; using System.Drawing; - using System.Globalization; - using System.Text.RegularExpressions; #endregion /// @@ -22,23 +20,6 @@ namespace ImageProcessor.Processors /// public class Quality : IGraphicsProcessor { - /// - /// The regular expression to search strings for. - /// - private static readonly Regex QueryRegex = new Regex(@"quality=(?:100|[1-9]?[0-9])", RegexOptions.Compiled); - - #region IGraphicsProcessor Members - /// - /// Gets the regular expression to search strings for. - /// - public Regex RegexPattern - { - get - { - return QueryRegex; - } - } - /// /// Gets or sets DynamicParameter. /// @@ -48,15 +29,6 @@ namespace ImageProcessor.Processors 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. /// @@ -66,42 +38,6 @@ namespace ImageProcessor.Processors 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; - int percentage = int.Parse(match.Value.Split('=')[1], CultureInfo.InvariantCulture); - - this.DynamicParameter = percentage; - } - - index += 1; - } - } - - return this.SortOrder; - } - /// /// Processes the image. /// @@ -114,11 +50,8 @@ namespace ImageProcessor.Processors /// public Image ProcessImage(ImageFactory factory) { - // Set the internal property. factory.CurrentImageFormat.Quality = this.DynamicParameter; - return factory.Image; } - #endregion } } diff --git a/src/ImageProcessor/Processors/Saturation.cs b/src/ImageProcessor/Processors/Saturation.cs index 268de2f4a..9e07ecbfe 100644 --- a/src/ImageProcessor/Processors/Saturation.cs +++ b/src/ImageProcessor/Processors/Saturation.cs @@ -14,9 +14,6 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; - using System.Globalization; - using System.Text.RegularExpressions; - #endregion /// @@ -27,24 +24,7 @@ namespace ImageProcessor.Processors /// public class Saturation : IGraphicsProcessor { - /// - /// The regular expression to search strings for. - /// - /// - private static readonly Regex QueryRegex = new Regex(@"saturation=(-?(?:100)|-?([1-9]?[0-9]))", RegexOptions.Compiled); - #region IGraphicsProcessor Members - /// - /// Gets the regular expression to search strings for. - /// - public Regex RegexPattern - { - get - { - return QueryRegex; - } - } - /// /// Gets or sets DynamicParameter. /// @@ -54,15 +34,6 @@ namespace ImageProcessor.Processors 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. /// @@ -72,42 +43,6 @@ namespace ImageProcessor.Processors 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; - int percentage = int.Parse(match.Value.Split('=')[1], CultureInfo.InvariantCulture); - - this.DynamicParameter = percentage; - } - - index += 1; - } - } - - return this.SortOrder; - } - /// /// Processes the image. /// @@ -142,19 +77,19 @@ namespace ImageProcessor.Processors ColorMatrix colorMatrix = new ColorMatrix( - new float[][] + new[] { - new float[] + new[] { saturationComplementR + saturationFactor, saturationComplementR, saturationComplementR, 0, 0 }, - new float[] + new[] { saturationComplementG, saturationComplementG + saturationFactor, saturationComplementG, 0, 0 }, - new float[] + new[] { saturationComplementB, saturationComplementB, saturationComplementB + saturationFactor, 0, 0 @@ -196,4 +131,4 @@ namespace ImageProcessor.Processors } #endregion } -} +} \ No newline at end of file diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Web.config b/src/TestWebsites/NET45/Test_Website_NET45/Web.config index a11127fee..db3f37806 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/Web.config +++ b/src/TestWebsites/NET45/Test_Website_NET45/Web.config @@ -7,9 +7,9 @@ -
-
-
+
+
+
diff --git a/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config b/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config index 6aa5af4ea..6d9f621d1 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config +++ b/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config @@ -1,44 +1,40 @@ - - + - - - - - - - - - + + + + + + + + - + - - + + - - - + + - - - - - - + + + + + + - From 8ba72548ce2ec832c8ee00a71475a8692382a732 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 10 Jun 2014 18:02:56 +0200 Subject: [PATCH 003/155] Improving header detection Former-commit-id: 860df41b20473a0f1f9f2eb8efaa759f02f7734c --- .../NET45/ImageProcessor.Web_NET45.csproj | 1 + .../NET45/Processors/Resize.cs | 324 ++++++++++++++++ src/ImageProcessor/ImageFactory.cs | 2 +- .../Imaging/Formats/FormatBase.cs | 2 +- .../Imaging/Formats/FormatUtilities.cs | 12 +- .../Imaging/Formats/ISupportedImageFormat.cs | 2 +- src/ImageProcessor/Imaging/ResizeLayer.cs | 15 +- src/ImageProcessor/Processors/Resize.cs | 348 +----------------- 8 files changed, 343 insertions(+), 363 deletions(-) create mode 100644 src/ImageProcessor.Web/NET45/Processors/Resize.cs diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index 40d4d8fdd..322a8fc66 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -67,6 +67,7 @@ + diff --git a/src/ImageProcessor.Web/NET45/Processors/Resize.cs b/src/ImageProcessor.Web/NET45/Processors/Resize.cs new file mode 100644 index 000000000..7d4a06ceb --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Processors/Resize.cs @@ -0,0 +1,324 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Resizes an image to the given dimensions. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Processors +{ + using System; + using System.Collections.Generic; + using System.Drawing; + using System.Linq; + using System.Text; + using System.Text.RegularExpressions; + using ImageProcessor.Core.Common.Extensions; + using ImageProcessor.Imaging; + using ImageProcessor.Processors; + + /// + /// Resizes an image to the given dimensions. + /// + public class Resize : IWebGraphicsProcessor + { + /// + /// The regular expression to search strings for. + /// + private static readonly Regex QueryRegex = new Regex(@"(width|height)=|(width|height)ratio=|mode=|anchor=|center=|upscale=", RegexOptions.Compiled); + + /// + /// The regular expression to search strings for the size attribute. + /// + private static readonly Regex SizeRegex = new Regex(@"(width|height)=\d+", RegexOptions.Compiled); + + /// + /// The regular expression to search strings for the ratio attribute. + /// + private static readonly Regex RatioRegex = new Regex(@"(width|height)ratio=\d+(.\d+)?", RegexOptions.Compiled); + + /// + /// The regular expression to search strings for the mode attribute. + /// + private static readonly Regex ModeRegex = new Regex(@"mode=(pad|stretch|crop|max)", RegexOptions.Compiled); + + /// + /// The regular expression to search strings for the anchor attribute. + /// + private static readonly Regex AnchorRegex = new Regex(@"anchor=(top|bottom|left|right|center)", RegexOptions.Compiled); + + /// + /// The regular expression to search strings for the center attribute. + /// + private static readonly Regex CenterRegex = new Regex(@"center=\d+(.\d+)?[,-]\d+(.\d+)", RegexOptions.Compiled); + + /// + /// The regular expression to search strings for the upscale attribute. + /// + private static readonly Regex UpscaleRegex = new Regex(@"upscale=false", RegexOptions.Compiled); + + /// + /// Initializes a new instance of the class. + /// + public Resize() + { + this.Processor = new ImageProcessor.Processors.Resize(); + } + + /// + /// Gets the regular expression to search strings for. + /// + public Regex RegexPattern + { + get + { + return QueryRegex; + } + } + + /// + /// Gets the order in which this processor is to be used in a chain. + /// + public int SortOrder { get; private set; } + + /// + /// Gets the associated graphics processor. + /// + public IGraphicsProcessor Processor { get; private 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; + + // First merge the matches so we can parse . + StringBuilder stringBuilder = new StringBuilder(); + + 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; + stringBuilder.Append(queryString); + } + + index += 1; + } + } + + // Match syntax + string toParse = stringBuilder.ToString(); + + Size size = this.ParseSize(toParse); + ResizeLayer resizeLayer = new ResizeLayer(size) + { + ResizeMode = this.ParseMode(toParse), + AnchorPosition = this.ParsePosition(toParse), + Upscale = !UpscaleRegex.IsMatch(toParse), + CenterCoordinates = this.ParseCoordinates(toParse), + }; + + this.Processor.DynamicParameter = resizeLayer; + + // Correctly parse any restrictions. + string restrictions; + this.Processor.Settings.TryGetValue("RestrictTo", out restrictions); + ((ImageProcessor.Processors.Resize)this.Processor).RestrictedSizes = this.ParseRestrictions(restrictions); + return this.SortOrder; + } + + /// + /// Returns the correct for the given string. + /// + /// + /// The input string containing the value to parse. + /// + /// + /// The . + /// + private Size ParseSize(string input) + { + const string Width = "width="; + const string Height = "height="; + const string WidthRatio = "widthratio="; + const string HeightRatio = "heightratio="; + Size size = new Size(); + + // First merge the matches so we can parse . + StringBuilder stringBuilder = new StringBuilder(); + foreach (Match match in SizeRegex.Matches(input)) + { + stringBuilder.Append(match.Value); + } + + // First cater for single dimensions. + string value = stringBuilder.ToString(); + + if (input.Contains(Width) && !input.Contains(Height)) + { + size = new Size(value.ToPositiveIntegerArray()[0], 0); + } + + if (input.Contains(Height) && !input.Contains(Width)) + { + size = new Size(0, value.ToPositiveIntegerArray()[0]); + } + + // Both dimensions supplied. + if (input.Contains(Height) && input.Contains(Width)) + { + int[] dimensions = value.ToPositiveIntegerArray(); + + // Check the order in which they have been supplied. + size = input.IndexOf(Width, StringComparison.Ordinal) < input.IndexOf(Height, StringComparison.Ordinal) + ? new Size(dimensions[0], dimensions[1]) + : new Size(dimensions[1], dimensions[0]); + } + + // Calculate any ratio driven sizes. + if (size.Width == 0 || size.Height == 0) + { + stringBuilder.Clear(); + foreach (Match match in RatioRegex.Matches(input)) + { + stringBuilder.Append(match.Value); + } + + value = stringBuilder.ToString(); + + // Replace 0 width + if (size.Width == 0 && size.Height > 0 && input.Contains(WidthRatio) && !input.Contains(HeightRatio)) + { + size.Width = (int)(value.ToPositiveFloatArray()[0] * size.Height); + } + + // Replace 0 height + if (size.Height == 0 && size.Width > 0 && input.Contains(HeightRatio) && !input.Contains(WidthRatio)) + { + size.Height = (int)(value.ToPositiveFloatArray()[0] * size.Width); + } + } + + return size; + } + + /// + /// Returns the correct for the given string. + /// + /// + /// The input string containing the value to parse. + /// + /// + /// The correct . + /// + private ResizeMode ParseMode(string input) + { + foreach (Match match in ModeRegex.Matches(input)) + { + // Split on = + string mode = match.Value.Split('=')[1]; + + switch (mode) + { + case "stretch": + return ResizeMode.Stretch; + case "crop": + return ResizeMode.Crop; + case "max": + return ResizeMode.Max; + default: + return ResizeMode.Pad; + } + } + + return ResizeMode.Pad; + } + + /// + /// Returns the correct for the given string. + /// + /// + /// The input string containing the value to parse. + /// + /// + /// The correct . + /// + private AnchorPosition ParsePosition(string input) + { + foreach (Match match in AnchorRegex.Matches(input)) + { + // Split on = + string anchor = match.Value.Split('=')[1]; + + switch (anchor) + { + case "top": + return AnchorPosition.Top; + case "bottom": + return AnchorPosition.Bottom; + case "left": + return AnchorPosition.Left; + case "right": + return AnchorPosition.Right; + default: + return AnchorPosition.Center; + } + } + + return AnchorPosition.Center; + } + + /// + /// Parses the coordinates. + /// + /// The input. + /// The array containing the coordinates + private float[] ParseCoordinates(string input) + { + float[] floats = { }; + + foreach (Match match in CenterRegex.Matches(input)) + { + floats = match.Value.ToPositiveFloatArray(); + } + + return floats; + } + + /// + /// Returns a of sizes to restrict resizing to. + /// + /// + /// The input. + /// + /// + /// The to restrict resizing to. + /// + private List ParseRestrictions(string input) + { + List sizes = new List(); + + if (!string.IsNullOrWhiteSpace(input)) + { + sizes.AddRange(input.Split(',').Select(this.ParseSize)); + } + + return sizes; + } + } +} diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index c0ac9062b..1112c2e22 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -365,7 +365,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - ResizeLayer layer = new ResizeLayer(size, Color.Transparent, ResizeMode.Max); + ResizeLayer layer = new ResizeLayer(size, ResizeMode.Max); return this.Resize(layer); } diff --git a/src/ImageProcessor/Imaging/Formats/FormatBase.cs b/src/ImageProcessor/Imaging/Formats/FormatBase.cs index de590aea2..0f317ba0c 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatBase.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatBase.cs @@ -23,7 +23,7 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public abstract byte[] FileHeader { get; } + public abstract byte[][] FileHeaders { get; } /// /// Gets the list of file extensions. diff --git a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs index d3b6f9c56..7a87ad400 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs @@ -43,11 +43,15 @@ namespace ImageProcessor.Imaging.Formats // ReSharper disable once LoopCanBeConvertedToQuery foreach (ISupportedImageFormat supportedImageFormat in supportedImageFormats) { - byte[] header = supportedImageFormat.FileHeader; - if (header.SequenceEqual(buffer.Take(header.Length))) + byte[][] headers = supportedImageFormat.FileHeaders; + + foreach (byte[] header in headers) { - stream.Position = 0; - return supportedImageFormat; + if (header.SequenceEqual(buffer.Take(header.Length))) + { + stream.Position = 0; + return supportedImageFormat; + } } } diff --git a/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs b/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs index 8ad4e0763..4296b1e58 100644 --- a/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs @@ -23,7 +23,7 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - byte[] FileHeader { get; } + byte[][] FileHeaders { get; } /// /// Gets the list of file extensions. diff --git a/src/ImageProcessor/Imaging/ResizeLayer.cs b/src/ImageProcessor/Imaging/ResizeLayer.cs index 4fe81645b..dc5185922 100644 --- a/src/ImageProcessor/Imaging/ResizeLayer.cs +++ b/src/ImageProcessor/Imaging/ResizeLayer.cs @@ -26,10 +26,6 @@ namespace ImageProcessor.Imaging /// /// The containing the width and height to set the image to. /// - /// - /// The to set as the background color. - /// Used for image formats that do not support transparency (Default transparent) - /// /// /// The resize mode to apply to resized image. (Default ResizeMode.Pad) /// @@ -41,14 +37,12 @@ namespace ImageProcessor.Imaging /// public ResizeLayer( Size size, - Color? backgroundColor = null, ResizeMode resizeMode = ResizeMode.Pad, AnchorPosition anchorPosition = AnchorPosition.Center, bool upscale = true) { this.Size = size; this.Upscale = upscale; - this.BackgroundColor = backgroundColor ?? Color.Transparent; this.ResizeMode = resizeMode; this.AnchorPosition = anchorPosition; } @@ -60,11 +54,6 @@ namespace ImageProcessor.Imaging /// public Size Size { get; set; } - /// - /// Gets or sets the background color. - /// - public Color BackgroundColor { get; set; } - /// /// Gets or sets the resize mode. /// @@ -111,7 +100,6 @@ namespace ImageProcessor.Imaging return this.Size == resizeLayer.Size && this.ResizeMode == resizeLayer.ResizeMode && this.AnchorPosition == resizeLayer.AnchorPosition - && this.BackgroundColor == resizeLayer.BackgroundColor && this.Upscale == resizeLayer.Upscale; } @@ -126,8 +114,7 @@ namespace ImageProcessor.Imaging return this.Size.GetHashCode() + this.ResizeMode.GetHashCode() + this.AnchorPosition.GetHashCode() + - this.BackgroundColor.GetHashCode() + this.Upscale.GetHashCode(); } } -} +} \ No newline at end of file diff --git a/src/ImageProcessor/Processors/Resize.cs b/src/ImageProcessor/Processors/Resize.cs index 072848ee6..5cbfc2f92 100644 --- a/src/ImageProcessor/Processors/Resize.cs +++ b/src/ImageProcessor/Processors/Resize.cs @@ -18,10 +18,6 @@ namespace ImageProcessor.Processors using System.Drawing.Imaging; using System.Globalization; using System.Linq; - using System.Text; - using System.Text.RegularExpressions; - - using ImageProcessor.Core.Common.Extensions; using ImageProcessor.Imaging; #endregion @@ -30,58 +26,7 @@ namespace ImageProcessor.Processors /// public class Resize : IGraphicsProcessor { - /// - /// The regular expression to search strings for. - /// - private static readonly Regex QueryRegex = new Regex(@"(width|height)=|(width|height)ratio=|mode=|anchor=|center=|bgcolor=|upscale=", RegexOptions.Compiled); - - /// - /// The regular expression to search strings for the size attribute. - /// - private static readonly Regex SizeRegex = new Regex(@"(width|height)=\d+", RegexOptions.Compiled); - - /// - /// The regular expression to search strings for the ratio attribute. - /// - private static readonly Regex RatioRegex = new Regex(@"(width|height)ratio=\d+(.\d+)?", RegexOptions.Compiled); - - /// - /// The regular expression to search strings for the mode attribute. - /// - private static readonly Regex ModeRegex = new Regex(@"mode=(pad|stretch|crop|max)", RegexOptions.Compiled); - - /// - /// The regular expression to search strings for the anchor attribute. - /// - private static readonly Regex AnchorRegex = new Regex(@"anchor=(top|bottom|left|right|center)", RegexOptions.Compiled); - - /// - /// The regular expression to search strings for the center attribute. - /// - private static readonly Regex CenterRegex = new Regex(@"center=\d+(.\d+)?[,-]\d+(.\d+)", RegexOptions.Compiled); - - /// - /// The regular expression to search strings for the color attribute. - /// - private static readonly Regex ColorRegex = new Regex(@"bgcolor=(transparent|\d+,\d+,\d+,\d+|([0-9a-fA-F]{3}){1,2})", RegexOptions.Compiled); - - /// - /// The regular expression to search strings for the upscale attribute. - /// - private static readonly Regex UpscaleRegex = new Regex(@"upscale=false", RegexOptions.Compiled); - #region IGraphicsProcessor Members - /// - /// Gets the regular expression to search strings for. - /// - public Regex RegexPattern - { - get - { - return QueryRegex; - } - } - /// /// Gets or sets DynamicParameter. /// @@ -91,15 +36,6 @@ namespace ImageProcessor.Processors 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. /// @@ -110,56 +46,9 @@ namespace ImageProcessor.Processors } /// - /// The position in the original string where the first character of the captured substring was found. + /// Gets or sets the list of sizes to restrict resizing methods to. /// - /// - /// 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; - - // First merge the matches so we can parse . - StringBuilder stringBuilder = new StringBuilder(); - - 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; - stringBuilder.Append(queryString); - } - - index += 1; - } - } - - // Match syntax - string toParse = stringBuilder.ToString(); - - Size size = this.ParseSize(toParse); - ResizeLayer resizeLayer = new ResizeLayer(size) - { - ResizeMode = this.ParseMode(toParse), - AnchorPosition = this.ParsePosition(toParse), - BackgroundColor = this.ParseColor(toParse), - Upscale = !UpscaleRegex.IsMatch(toParse), - CenterCoordinates = this.ParseCoordinates(toParse), - }; - - this.DynamicParameter = resizeLayer; - - return this.SortOrder; - } + public List RestrictedSizes { get; set; } /// /// Processes the image. @@ -177,19 +66,16 @@ namespace ImageProcessor.Processors int height = this.DynamicParameter.Size.Height ?? 0; ResizeMode mode = this.DynamicParameter.ResizeMode; AnchorPosition anchor = this.DynamicParameter.AnchorPosition; - Color backgroundColor = this.DynamicParameter.BackgroundColor; bool upscale = this.DynamicParameter.Upscale; float[] centerCoordinates = this.DynamicParameter.CenterCoordinates; int defaultMaxWidth; int defaultMaxHeight; - string restrictions; - this.Settings.TryGetValue("RestrictTo", out restrictions); + int.TryParse(this.Settings["MaxWidth"], NumberStyles.Any, CultureInfo.InvariantCulture, out defaultMaxWidth); int.TryParse(this.Settings["MaxHeight"], NumberStyles.Any, CultureInfo.InvariantCulture, out defaultMaxHeight); - List restrictedSizes = this.ParseRestrictions(restrictions); - return this.ResizeImage(factory, width, height, defaultMaxWidth, defaultMaxHeight, restrictedSizes, backgroundColor, mode, anchor, upscale, centerCoordinates); + return this.ResizeImage(factory, width, height, defaultMaxWidth, defaultMaxHeight, this.RestrictedSizes, mode, anchor, upscale, centerCoordinates); } #endregion @@ -215,9 +101,6 @@ namespace ImageProcessor.Processors /// /// A containing image resizing restrictions. /// - /// - /// The background color to pad the image with. - /// /// /// The mode with which to resize the image. /// @@ -240,7 +123,6 @@ namespace ImageProcessor.Processors int defaultMaxWidth, int defaultMaxHeight, List restrictedSizes, - Color backgroundColor, ResizeMode resizeMode = ResizeMode.Pad, AnchorPosition anchorPosition = AnchorPosition.Center, bool upscale = true, @@ -404,7 +286,7 @@ namespace ImageProcessor.Processors } // Restrict sizes - if (restrictedSizes.Any()) + if (restrictedSizes != null && restrictedSizes.Any()) { bool reject = true; foreach (Size restrictedSize in restrictedSizes) @@ -463,7 +345,6 @@ namespace ImageProcessor.Processors using (ImageAttributes wrapMode = new ImageAttributes()) { wrapMode.SetWrapMode(WrapMode.TileFlipXY); - graphics.Clear(backgroundColor); Rectangle destRect = new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight); graphics.DrawImage(image, destRect, 0, 0, sourceWidth, sourceHeight, GraphicsUnit.Pixel, wrapMode); } @@ -484,222 +365,5 @@ namespace ImageProcessor.Processors return image; } - - /// - /// Returns the correct for the given string. - /// - /// - /// The input string containing the value to parse. - /// - /// - /// The . - /// - private Size ParseSize(string input) - { - const string Width = "width="; - const string Height = "height="; - const string WidthRatio = "widthratio="; - const string HeightRatio = "heightratio="; - Size size = new Size(); - - // First merge the matches so we can parse . - StringBuilder stringBuilder = new StringBuilder(); - foreach (Match match in SizeRegex.Matches(input)) - { - stringBuilder.Append(match.Value); - } - - // First cater for single dimensions. - string value = stringBuilder.ToString(); - - if (input.Contains(Width) && !input.Contains(Height)) - { - size = new Size(value.ToPositiveIntegerArray()[0], 0); - } - - if (input.Contains(Height) && !input.Contains(Width)) - { - size = new Size(0, value.ToPositiveIntegerArray()[0]); - } - - // Both dimensions supplied. - if (input.Contains(Height) && input.Contains(Width)) - { - int[] dimensions = value.ToPositiveIntegerArray(); - - // Check the order in which they have been supplied. - size = input.IndexOf(Width, StringComparison.Ordinal) < input.IndexOf(Height, StringComparison.Ordinal) - ? new Size(dimensions[0], dimensions[1]) - : new Size(dimensions[1], dimensions[0]); - } - - // Calculate any ratio driven sizes. - if (size.Width == 0 || size.Height == 0) - { - stringBuilder.Clear(); - foreach (Match match in RatioRegex.Matches(input)) - { - stringBuilder.Append(match.Value); - } - - value = stringBuilder.ToString(); - - // Replace 0 width - if (size.Width == 0 && size.Height > 0 && input.Contains(WidthRatio) && !input.Contains(HeightRatio)) - { - size.Width = (int)(value.ToPositiveFloatArray()[0] * size.Height); - } - - // Replace 0 height - if (size.Height == 0 && size.Width > 0 && input.Contains(HeightRatio) && !input.Contains(WidthRatio)) - { - size.Height = (int)(value.ToPositiveFloatArray()[0] * size.Width); - } - } - - return size; - } - - /// - /// Returns the correct for the given string. - /// - /// - /// The input string containing the value to parse. - /// - /// - /// The correct . - /// - private ResizeMode ParseMode(string input) - { - foreach (Match match in ModeRegex.Matches(input)) - { - // Split on = - string mode = match.Value.Split('=')[1]; - - switch (mode) - { - case "stretch": - return ResizeMode.Stretch; - case "crop": - return ResizeMode.Crop; - case "max": - return ResizeMode.Max; - default: - return ResizeMode.Pad; - } - } - - return ResizeMode.Pad; - } - - /// - /// Returns the correct for the given string. - /// - /// - /// The input string containing the value to parse. - /// - /// - /// The correct . - /// - private AnchorPosition ParsePosition(string input) - { - foreach (Match match in AnchorRegex.Matches(input)) - { - // Split on = - string anchor = match.Value.Split('=')[1]; - - switch (anchor) - { - case "top": - return AnchorPosition.Top; - case "bottom": - return AnchorPosition.Bottom; - case "left": - return AnchorPosition.Left; - case "right": - return AnchorPosition.Right; - default: - return AnchorPosition.Center; - } - } - - return AnchorPosition.Center; - } - - /// - /// 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)) - { - string value = match.Value.Split('=')[1]; - - if (value == "transparent") - { - return Color.Transparent; - } - - if (value.Contains(",")) - { - int[] split = value.ToPositiveIntegerArray(); - byte red = split[0].ToByte(); - byte green = split[1].ToByte(); - byte blue = split[2].ToByte(); - byte alpha = split[3].ToByte(); - - return Color.FromArgb(alpha, red, green, blue); - } - - // Split on color-hex - return ColorTranslator.FromHtml("#" + value); - } - - return Color.Transparent; - } - - /// - /// Returns a of sizes to restrict resizing to. - /// - /// - /// The input. - /// - /// - /// The to restrict resizing to. - /// - private List ParseRestrictions(string input) - { - List sizes = new List(); - - if (!string.IsNullOrWhiteSpace(input)) - { - sizes.AddRange(input.Split(',').Select(this.ParseSize)); - } - - return sizes; - } - - /// - /// Parses the coordinates. - /// - /// The input. - /// The array containing the coordinates - private float[] ParseCoordinates(string input) - { - float[] floats = { }; - - foreach (Match match in CenterRegex.Matches(input)) - { - floats = match.Value.ToPositiveFloatArray(); - } - - return floats; - } } -} +} \ No newline at end of file From df07e4815cabc8ffd83d39bb27506219e1dfb3b1 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 10 Jun 2014 18:03:27 +0200 Subject: [PATCH 004/155] Adding missing files Former-commit-id: e75715cbed7b9118d9e52905b051d98915db4ef2 --- src/ImageProcessor/Imaging/Formats/BitmapFormat.cs | 4 ++-- src/ImageProcessor/Imaging/Formats/GifFormat.cs | 4 ++-- src/ImageProcessor/Imaging/Formats/JpegFormat.cs | 11 +++++++++-- src/ImageProcessor/Imaging/Formats/PngFormat.cs | 4 ++-- src/ImageProcessor/Imaging/Formats/TiffFormat.cs | 4 ++-- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs b/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs index b971f276e..cf754e202 100644 --- a/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs @@ -21,11 +21,11 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public override byte[] FileHeader + public override byte[][] FileHeaders { get { - return Encoding.ASCII.GetBytes("BM"); + return new[] { Encoding.ASCII.GetBytes("BM") }; } } diff --git a/src/ImageProcessor/Imaging/Formats/GifFormat.cs b/src/ImageProcessor/Imaging/Formats/GifFormat.cs index 87c9a0d30..45d966f8f 100644 --- a/src/ImageProcessor/Imaging/Formats/GifFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/GifFormat.cs @@ -25,11 +25,11 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public override byte[] FileHeader + public override byte[][] FileHeaders { get { - return Encoding.ASCII.GetBytes("GIF"); + return new[] { Encoding.ASCII.GetBytes("GIF") }; } } diff --git a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs index 761088ddc..161ebe2e2 100644 --- a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs @@ -25,11 +25,18 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public override byte[] FileHeader + public override byte[][] FileHeaders { get { - return new byte[] { 255, 216, 255, 224 }; + return new[] + { + new byte[] { 255, 216, 255, 232 }, + new byte[] { 255, 216, 255, 227 }, + new byte[] { 255, 216, 255, 226 }, + new byte[] { 255, 216, 255, 224 }, + new byte[] { 255, 216, 255, 225 } + }; } } diff --git a/src/ImageProcessor/Imaging/Formats/PngFormat.cs b/src/ImageProcessor/Imaging/Formats/PngFormat.cs index da6b4dc5f..b3c13cc37 100644 --- a/src/ImageProcessor/Imaging/Formats/PngFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/PngFormat.cs @@ -22,11 +22,11 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public override byte[] FileHeader + public override byte[][] FileHeaders { get { - return new byte[] { 137, 80, 78, 71 }; + return new[] { new byte[] { 137, 80, 78, 71 } }; } } diff --git a/src/ImageProcessor/Imaging/Formats/TiffFormat.cs b/src/ImageProcessor/Imaging/Formats/TiffFormat.cs index 226c0efab..1b12cc80a 100644 --- a/src/ImageProcessor/Imaging/Formats/TiffFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/TiffFormat.cs @@ -23,11 +23,11 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public override byte[] FileHeader + public override byte[][] FileHeaders { get { - return new byte[] { 77, 77, 42 }; + return new[] { new byte[] { 77, 77, 42 } }; } } From ac2e5fae13a149c1044740a5bda0d6b032303d6e Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 12 Jun 2014 10:00:02 +0200 Subject: [PATCH 005/155] Tidying up file detection Former-commit-id: d8bb807d08a118f2ba387eae4d75bb9959b9b6f3 --- src/ImageProcessor/Imaging/Formats/BitmapFormat.cs | 4 ++-- src/ImageProcessor/Imaging/Formats/FormatBase.cs | 2 +- .../Imaging/Formats/FormatUtilities.cs | 12 ++++-------- src/ImageProcessor/Imaging/Formats/GifFormat.cs | 4 ++-- .../Imaging/Formats/ISupportedImageFormat.cs | 2 +- src/ImageProcessor/Imaging/Formats/JpegFormat.cs | 11 ++--------- src/ImageProcessor/Imaging/Formats/PngFormat.cs | 4 ++-- src/ImageProcessor/Imaging/Formats/TiffFormat.cs | 4 ++-- 8 files changed, 16 insertions(+), 27 deletions(-) diff --git a/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs b/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs index cf754e202..b971f276e 100644 --- a/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/BitmapFormat.cs @@ -21,11 +21,11 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public override byte[][] FileHeaders + public override byte[] FileHeader { get { - return new[] { Encoding.ASCII.GetBytes("BM") }; + return Encoding.ASCII.GetBytes("BM"); } } diff --git a/src/ImageProcessor/Imaging/Formats/FormatBase.cs b/src/ImageProcessor/Imaging/Formats/FormatBase.cs index 0f317ba0c..de590aea2 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatBase.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatBase.cs @@ -23,7 +23,7 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public abstract byte[][] FileHeaders { get; } + public abstract byte[] FileHeader { get; } /// /// Gets the list of file extensions. diff --git a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs index 7a87ad400..d3b6f9c56 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs @@ -43,15 +43,11 @@ namespace ImageProcessor.Imaging.Formats // ReSharper disable once LoopCanBeConvertedToQuery foreach (ISupportedImageFormat supportedImageFormat in supportedImageFormats) { - byte[][] headers = supportedImageFormat.FileHeaders; - - foreach (byte[] header in headers) + byte[] header = supportedImageFormat.FileHeader; + if (header.SequenceEqual(buffer.Take(header.Length))) { - if (header.SequenceEqual(buffer.Take(header.Length))) - { - stream.Position = 0; - return supportedImageFormat; - } + stream.Position = 0; + return supportedImageFormat; } } diff --git a/src/ImageProcessor/Imaging/Formats/GifFormat.cs b/src/ImageProcessor/Imaging/Formats/GifFormat.cs index 45d966f8f..87c9a0d30 100644 --- a/src/ImageProcessor/Imaging/Formats/GifFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/GifFormat.cs @@ -25,11 +25,11 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public override byte[][] FileHeaders + public override byte[] FileHeader { get { - return new[] { Encoding.ASCII.GetBytes("GIF") }; + return Encoding.ASCII.GetBytes("GIF"); } } diff --git a/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs b/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs index 4296b1e58..8ad4e0763 100644 --- a/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/ISupportedImageFormat.cs @@ -23,7 +23,7 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - byte[][] FileHeaders { get; } + byte[] FileHeader { get; } /// /// Gets the list of file extensions. diff --git a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs index 161ebe2e2..78265d458 100644 --- a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs @@ -25,18 +25,11 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public override byte[][] FileHeaders + public override byte[] FileHeader { get { - return new[] - { - new byte[] { 255, 216, 255, 232 }, - new byte[] { 255, 216, 255, 227 }, - new byte[] { 255, 216, 255, 226 }, - new byte[] { 255, 216, 255, 224 }, - new byte[] { 255, 216, 255, 225 } - }; + return new byte[] { 255, 216, 255 }; } } diff --git a/src/ImageProcessor/Imaging/Formats/PngFormat.cs b/src/ImageProcessor/Imaging/Formats/PngFormat.cs index b3c13cc37..da6b4dc5f 100644 --- a/src/ImageProcessor/Imaging/Formats/PngFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/PngFormat.cs @@ -22,11 +22,11 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public override byte[][] FileHeaders + public override byte[] FileHeader { get { - return new[] { new byte[] { 137, 80, 78, 71 } }; + return new byte[] { 137, 80, 78, 71 }; } } diff --git a/src/ImageProcessor/Imaging/Formats/TiffFormat.cs b/src/ImageProcessor/Imaging/Formats/TiffFormat.cs index 1b12cc80a..226c0efab 100644 --- a/src/ImageProcessor/Imaging/Formats/TiffFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/TiffFormat.cs @@ -23,11 +23,11 @@ namespace ImageProcessor.Imaging.Formats /// /// Gets the file header. /// - public override byte[][] FileHeaders + public override byte[] FileHeader { get { - return new[] { new byte[] { 77, 77, 42 } }; + return new byte[] { 77, 77, 42 }; } } From aa3c0701166dd7229871a04f21e3103eda5711e7 Mon Sep 17 00:00:00 2001 From: James South Date: Wed, 18 Jun 2014 22:21:12 +0100 Subject: [PATCH 006/155] Updating cache checker. Original method was too processor intensive Former-commit-id: 689734e40fcd1a41d219e7b7e720c76943d179ba --- .../NET45/ImageProcessor.Web_NET45.csproj | 7 +- .../NET45/Processors/Filter.cs | 161 ++++++++++++++++++ .../Filters/MatrixFilterRegexAttribute.cs | 37 ---- .../Imaging/Filters/MatrixFilters.cs | 32 ++-- src/ImageProcessor/Processors/Filter.cs | 130 +------------- 5 files changed, 175 insertions(+), 192 deletions(-) create mode 100644 src/ImageProcessor.Web/NET45/Processors/Filter.cs delete mode 100644 src/ImageProcessor/Imaging/Filters/MatrixFilterRegexAttribute.cs diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index 322a8fc66..694840487 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -61,10 +61,12 @@ + + @@ -87,11 +89,6 @@ - - - Designer - - -
-
-
+
+
+
From e10b58a7b9f6a03409cab045b449f3d769f9c8d6 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 24 Jun 2014 23:32:06 +0100 Subject: [PATCH 027/155] Adding transparent webp support Former-commit-id: bde73846512628e8364d54420c2f1dac7af748e4 --- .../HttpModules/ImageProcessingModule.cs | 5 +- .../Imaging/Formats/WebPFormat.cs | 71 +++++++++++++----- src/ImageProcessorConsole/Program.cs | 27 +++++-- .../images/input/circle.png | Bin 0 -> 6957 bytes .../images/input/rotate.jpg.REMOVED.git-id | 1 + .../images/output/circle.webp | Bin 0 -> 1228 bytes .../images/output/rotate.webp | Bin 0 -> 1812 bytes 7 files changed, 76 insertions(+), 28 deletions(-) create mode 100644 src/ImageProcessorConsole/images/input/circle.png create mode 100644 src/ImageProcessorConsole/images/input/rotate.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/circle.webp create mode 100644 src/ImageProcessorConsole/images/output/rotate.webp diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index 91ec40aab..f2bd71ad3 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -359,13 +359,14 @@ namespace ImageProcessor.Web.HttpModules IPrincipal user = context.User ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]); // Do we have permission to call UrlAuthorizationModule.CheckUrlAccessForPrincipal? - PermissionSet permission = new PermissionSet(PermissionState.None); + PermissionSet permission = new PermissionSet(PermissionState.Unrestricted); permission.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted)); bool hasPermission = permission.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet); bool isAllowed = true; - // Run the rewritten path past the auth system again, using the result as the default "AllowAccess" value + // Run the rewritten path past the authorization system again. + // We can then use the result as the default "AllowAccess" value if (hasPermission && !context.SkipAuthorization) { isAllowed = UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualCachedPath, user, "GET"); diff --git a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs index 5253983e3..15e4e4313 100644 --- a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs @@ -13,6 +13,7 @@ namespace ImageProcessor.Imaging.Formats { using System; + using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Drawing.Imaging; @@ -20,6 +21,8 @@ namespace ImageProcessor.Imaging.Formats using System.Runtime.InteropServices; using System.Text; + using ImageProcessor.Core.Common.Exceptions; + /// /// Provides the necessary information to support webp images. /// Adapted from @@ -72,6 +75,35 @@ namespace ImageProcessor.Imaging.Formats } } + /// + /// Applies the given processor the current image. + /// + /// The processor delegate. + /// The . + public override void ApplyProcessor(Func processor, ImageFactory factory) + { + base.ApplyProcessor(processor, factory); + + // Set the property item information from any Exif metadata. + // We do this here so that they can be changed between processor methods. + if (factory.PreserveExifData) + { + foreach (KeyValuePair propertItem in factory.ExifPropertyItems) + { + try + { + factory.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. + } + } + } + } + /// /// Decodes the image to process. /// @@ -151,49 +183,48 @@ namespace ImageProcessor.Imaging.Formats IntPtr ptrData = pinnedWebP.AddrOfPinnedObject(); uint dataSize = (uint)webpData.Length; - int imgWidth; - int imgHeight; + int width; + int height; - if (WebPGetInfo(ptrData, dataSize, out imgWidth, out imgHeight) != 1) + if (WebPGetInfo(ptrData, dataSize, out width, out height) != 1) { - // TODO: Throw error? - return null; + throw new ImageFormatException("WebP image is corrupted."); } // Create a BitmapData and Lock all pixels to be written - Bitmap bmp = new Bitmap(imgWidth, imgHeight, PixelFormat.Format24bppRgb); - BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); + Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); + BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat); // Allocate memory for uncompress image - int outputBufferSize = bmpData.Stride * imgHeight; + int outputBufferSize = bitmapData.Stride * height; IntPtr outputBuffer = Marshal.AllocHGlobal(outputBufferSize); // Uncompress the image - outputBuffer = WebPDecodeBGRInto(ptrData, dataSize, outputBuffer, outputBufferSize, bmpData.Stride); + outputBuffer = WebPDecodeBGRAInto(ptrData, dataSize, outputBuffer, outputBufferSize, bitmapData.Stride); // Write image to bitmap using Marshal byte[] buffer = new byte[outputBufferSize]; Marshal.Copy(outputBuffer, buffer, 0, outputBufferSize); - Marshal.Copy(buffer, 0, bmpData.Scan0, outputBufferSize); + Marshal.Copy(buffer, 0, bitmapData.Scan0, outputBufferSize); // Unlock the pixels - bmp.UnlockBits(bmpData); + bitmap.UnlockBits(bitmapData); // Free memory pinnedWebP.Free(); Marshal.FreeHGlobal(outputBuffer); - return bmp; + return bitmap; } /// - /// Lossly encodes the image in bitmap. + /// Lossy encodes the image in bitmap. /// /// /// Bitmap with the image /// /// - /// Quality. 0 = minimum ... 100 = maximimun quality + /// Quality. 0 = minimum ... 100 = maximum quality /// /// /// The byte array containing the encoded image data. @@ -207,9 +238,9 @@ namespace ImageProcessor.Imaging.Formats try { - BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); + BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); IntPtr unmanagedData; - int size = WebPEncodeBGR(bmpData.Scan0, bitmap.Width, bitmap.Height, bmpData.Stride, quality, out unmanagedData); + int size = WebPEncodeBGRA(bmpData.Scan0, bitmap.Width, bitmap.Height, bmpData.Stride, quality, out unmanagedData); // Copy image compress data to output array webpData = new byte[size]; @@ -266,16 +297,16 @@ namespace ImageProcessor.Imaging.Formats /// Size of allocated buffer /// /// - /// Specifies the distance between scanlines + /// Specifies the distance between scan-lines /// /// /// output_buffer if function succeeds; NULL otherwise /// [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr WebPDecodeBGRInto(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride); + private static extern IntPtr WebPDecodeBGRAInto(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride); /// - /// Lossless encoding images pointed to by *data in WebP format + /// Lossy encoding images pointed to by *data in WebP format /// /// /// Pointer to RGB image data @@ -299,7 +330,7 @@ namespace ImageProcessor.Imaging.Formats /// Size of WebP Image /// [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern int WebPEncodeBGR(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output); + private static extern int WebPEncodeBGRA(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output); /// /// Frees the unmanaged memory. diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index cb33aef79..20e92e803 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -10,8 +10,11 @@ namespace ImageProcessorConsole { using System; + using System.Collections.Generic; using System.Drawing; using System.IO; + using System.Linq; + using ImageProcessor; using ImageProcessor.Imaging.Formats; @@ -37,8 +40,10 @@ namespace ImageProcessorConsole di.Create(); } - //FileInfo[] files = di.GetFiles("*.gif"); - FileInfo[] files = di.GetFiles(); + FileInfo[] files = di.GetFiles("*.jpg"); + //FileInfo[] files = di.GetFiles(); + //var files = GetFilesByExtensions(di, ".gif", ".webp"); + foreach (FileInfo fileInfo in files) { @@ -47,20 +52,30 @@ namespace ImageProcessorConsole // ImageProcessor using (MemoryStream inStream = new MemoryStream(photoBytes)) { - using (ImageFactory imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory(true)) { Size size = new Size(200, 200); // Load, resize, set the format and quality and save an image. imageFactory.Load(inStream) + .AutoRotate() .Constrain(size) - //.Format(new JpegFormat()) + .Format(new WebPFormat()) + .Quality(5) // ReSharper disable once AssignNullToNotNullAttribute - // .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".jpg"))); - .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); + .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".webp"))); + //.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); } } } } + + public static IEnumerable GetFilesByExtensions(DirectoryInfo dir, params string[] extensions) + { + if (extensions == null) + throw new ArgumentNullException("extensions"); + IEnumerable files = dir.EnumerateFiles(); + return files.Where(f => extensions.Contains(f.Extension, StringComparer.OrdinalIgnoreCase)); + } } } diff --git a/src/ImageProcessorConsole/images/input/circle.png b/src/ImageProcessorConsole/images/input/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..029091dbc72bf71881302caf881721fa18a235ad GIT binary patch literal 6957 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 literal 0 HcmV?d00001 diff --git a/src/ImageProcessorConsole/images/input/rotate.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/rotate.jpg.REMOVED.git-id new file mode 100644 index 000000000..bf0538b24 --- /dev/null +++ b/src/ImageProcessorConsole/images/input/rotate.jpg.REMOVED.git-id @@ -0,0 +1 @@ +406a6a7916628c0c0bea8243565a7162ebd5a505 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/circle.webp b/src/ImageProcessorConsole/images/output/circle.webp new file mode 100644 index 0000000000000000000000000000000000000000..ef0281087a99eab7de16954d2dfa362028c4127a GIT binary patch literal 1228 zcmV;-1T*_mNk&G*1ONb6MM6+kP&il$0000G0002T0074T06|PpNZA7b00FnApluuJ zlJV!=%M>kRI3)5i{4Ayzc?jA9AQ_Ua zIJRxuwr$(CZQHhO+qi2Ze&~89qFy(m|B3AXv!gB9r0?WayN+GBarfS>E2j>upEsm! zl{^S+(Uz0;-u<1J`o3Yr(^eOPfBtopxZ4EowQf-)b}YPm|Devs+%TS!Mx}ElVY`ZAkE+2l=XT1y ztq;eXdnx$2A^dXeq2!l(u-in@x0PYGn6ghwz-knQ&*yv$?}fKS z+XyDJDF3JcESe-ze+?Y++@V2QTNuow#p8UCuNqB{Igmd{lc>rNZ=Ft;9T2}no0JBS z?nkiJZ#l!g#)lS!xD5I#by*vgQto_Cs_F?S7Vk zWPuO#8vx0+G~5lzWi)(W0E#zgn9&@9Wuxgh6@oozc@%;RX!#-+^iI$+sRrb7KBH$h z$W@4?=M2cTrs+1w^{43>$jzYX(;QG+L(|Viptgsmf0TpTahfL7fZ9cxX4Hq;O}aLL z+FiP~fZ9E}wt(6#x;BH_Rk}8U+8LUr)PmYUnnqWG+9sNQFA23pG<}^1Y9nZR4RW1n zx*u|NQt7!2as@xrb1?L-(K53s^fu7)dr{~Or{xt0)=i<~N(knCMaSMy+(W~tGEf{s z!wZlsA49+C&^$}KsSWK)2`@ zIt_;MY#Kew3*}XYHpCzIMo;Io9%&x*n5D24y152vDcD4W&;Ugcg=btK$sf1>6L_%-}W z#kp{7^pSdV;92uI#WE(swd{3D#SVgR!F?3^&BFwvfphU*XT(B>DhyrhV zAqd01GSb^hArKXIq%o2Yx+5U%E-_-?rsYFe2Hs^v{#a2C!O1=N2DAL@(h3MumqRhk z%KMW_BV5&H-pypzeA(VHCj!@e@y$5?-*-Fv6hjcJ4&8b;n*TB7&GG3i3L>QCJ4{%2 z;^D{N@frLxIqKWAy^C* zFuBMUSY7ZNV#olQj71_P%e@SX^TZ1*D&RS5jkJsPVmKGF6U00VE9#KY@1_7^gu3sVvM8B8y)i qMWUyzLkvUQ?iiyX>+LP4G&gQGqev8-o4qC3!qqv0UQ?*30000XdQ!pw literal 0 HcmV?d00001 diff --git a/src/ImageProcessorConsole/images/output/rotate.webp b/src/ImageProcessorConsole/images/output/rotate.webp new file mode 100644 index 0000000000000000000000000000000000000000..ca786888a0deb517cac3db1fb29b03564a0fec4c GIT binary patch literal 1812 zcmV+v2kZD!Nk&Et2LJ$9MM6+kP&gm}2LJ$YHvpXhD#!qq06&?+*JU{{Dyb*6D7?ZXOJ~Jb@>@|KXOp0)kn(YZMY@XYT;)oYvHGCn zBmNPiq9qO5PqjX6WPi#}wR>w-(GvdQ_tN(ftl;WgB|{KzN_Tdc%RPkyK&u%ZQpxS= z+mj1Ae%9A0ooFtoVmIcM(?ebPkS<21zi`Q6O(h5T$u7hCWKr~?4wgKx5L^-{o2#$0 zu#bHwtOeQdwi-`UbASZ+(&uht6K?0$*aXKw+2?ZnXAPaH=1PQxO6XWWwl-iEk(I9; zwVG(^8x=ely=UppHR2$_-}P(k$pAsI@dc}uE4S*i+O`3VnDjAVUH#KND#PyAPKdSK z+2a`UX(|57^XYTYE~U|)Gt!4_d(l16=HTq>lRVI!|CKPiNn$Uefk%;Med0o3N ze(Ed2WlAyVH>ofH{@Oo9^9FYkV=X+JbsaR`wUb(b1QvP?F)iS6&Tw%qhW*cHB@@S| zdp=gkhGe{Bf#0;TBF4g&*n1**HcVI`8XbkloPPdgu@_}DdqAWpO0CR2JdB7x6DeAi zFGMg&VRyktJC{HBX7PPqBwU1W-Kf0a5P*B&>cX(7!>~UWoH1oEaL{i1{jdg=be-SK z_k~ar8_zfn?7kUK=RH&WoN4CB#Xt3LNg?aaf`HwlxP2bkB9Z)4Ez7+)P}U7f zPbMqM2vfxHsiDhd;KDYT#eoG&Ubq zkkAqnn)@#~#+uI;mLurWCNv1te+g05UsP}&6NT=zUGP^ULHc3PTOp50=y=f~` zY9N6W1`Qlj`h(Kz*!*|279Pp)lY1Nb5&J8n{aYtWHl6t>g*?YQj&`$+YSKrJ%?}75 z&HEfes6VvB$ZIaFl zON->0oBPA420(KdA%HFPtH)La@Nv*1DOU#&Cf})aP#9oV%E4HYFv53?i!C-narKpT z2pTJhVmRQX9yMR+q42$j_*N#)I6@)oM{FEVwyB@R!H%pMj`h25%v6|)#O_yifg&6y zNCy{2RCQeL|5LQ#G&A#eIidLmUr}@=6trBDhMPnBn88b?3azH=O8irEpzR6XtchUV zG3gn*LeD16Yt&kngei6I1P3P4Gyu$9j{A#8sV2oH+sXNmZ>tv=6N~QmZ2h zIgaF_{}_L4q4ZFzWe2Rc_GV}ZsjmKLW6Ne8+eKA zc7Y@^YFo+C%La$f@n_4=Bo_uF@I1X)+5DzD&laaTJ1eX{N*zI--k9IeNNzX@sam&b zhET9}=_GA9{w`5UaE<{0*5Mt3Fz$y)dHXk+h>L_w&+ounrmM#DhfV(<{xIxvAON`0PWdwPXOr_OsD)afKc$7<6X9bu|77Jltyi)bz`F#SWZ*f zq-!Oh*9SXGpka*!(LqfM<#?Br{EvCkZ3SXwHMFB zXe%=ZfjbB&bqI}S;)}dr?`>;`>xl>gnLH?(wV5%7fa{7)a#s_4ow zV}tSF+IwcI<55GH@~G@teR=r9I4fiUPPp7@tUO7Nt%U8&!g(0&lb#DnSw z4FL^p`m+dfGvlUu&cC@2Oj6<@Ojw-Zxs2Z%yGSVBI`x80001L Cv3s)s literal 0 HcmV?d00001 From edd4b59da0ce719e1ed1ecabdc208c8021ba18cf Mon Sep 17 00:00:00 2001 From: James South Date: Wed, 25 Jun 2014 14:23:42 +0100 Subject: [PATCH 028/155] Refactoring and sense checking Former-commit-id: 152ad831191fe1413038822f39a0a4fcdcda8ab2 --- build/Build.bat | 6 +- .../NuSpecs/ImageProcessor.Web.Config.nuspec | 14 +-- build/NuSpecs/ImageProcessor.Web.nuspec | 4 +- build/NuSpecs/ImageProcessor.nuspec | 1 + .../web.config.transform | 10 +-- .../ImageProcessor.Web/web.config.transform | 4 + .../NET45/Caching/DiskCache.cs | 3 +- .../NET45/Configuration/ImageCacheSection.cs | 2 +- .../Configuration/Resources/processing.config | 3 +- .../Helpers/CommonParameterParserUtility.cs | 3 +- .../HttpModules/ImageProcessingModule.cs | 2 +- .../NET45/Processors/Crop.cs | 3 +- .../NET45/Processors/Format.cs | 8 +- .../NET45/Processors/Resize.cs | 3 +- .../NET45/Processors/Watermark.cs | 3 +- .../NET45/Properties/AssemblyInfo.cs | 4 +- .../Common/Exceptions/ImageFormatException.cs | 3 +- .../Exceptions/ImageProcessingException.cs | 2 +- .../Common/Extensions/DoubleExtensions.cs | 2 +- .../Common/Extensions/IntegerExtensions.cs | 2 +- .../Common/Extensions/StringExtensions.cs | 6 +- .../ImageProcessorBootstrapper.cs | 3 +- src/ImageProcessor/ImageFactory.cs | 3 +- src/ImageProcessor/ImageProcessor.csproj | 10 +-- src/ImageProcessor/Imaging/Convolution.cs | 2 +- .../Imaging/Filters/ComicMatrixFilter.cs | 4 +- .../Imaging/Formats/WebPFormat.cs | 85 ++++++++++++------- src/ImageProcessor/Processors/Alpha.cs | 3 +- src/ImageProcessor/Processors/AutoRotate.cs | 3 +- .../Processors/BackgroundColor.cs | 3 +- src/ImageProcessor/Processors/Brightness.cs | 3 +- src/ImageProcessor/Processors/Contrast.cs | 3 +- src/ImageProcessor/Processors/Crop.cs | 3 +- src/ImageProcessor/Processors/Filter.cs | 3 +- src/ImageProcessor/Processors/Flip.cs | 3 +- src/ImageProcessor/Processors/Format.cs | 3 +- src/ImageProcessor/Processors/GaussianBlur.cs | 3 +- .../Processors/GaussianSharpen.cs | 3 +- src/ImageProcessor/Processors/Quality.cs | 3 +- src/ImageProcessor/Processors/Resize.cs | 3 +- src/ImageProcessor/Processors/Rotate.cs | 3 +- .../Processors/RoundedCorners.cs | 3 +- src/ImageProcessor/Processors/Saturation.cs | 3 +- src/ImageProcessor/Processors/Tint.cs | 3 +- src/ImageProcessor/Processors/Vignette.cs | 3 +- src/ImageProcessor/Processors/Watermark.cs | 3 +- src/ImageProcessor/Properties/AssemblyInfo.cs | 4 +- .../config/imageprocessor/processing.config | 41 ++++----- .../NET45/Test_Website_NET45/Views/Web.config | 2 +- .../NET45/Test_Website_NET45/Web.config | 5 ++ .../config/imageprocessor/processing.config | 2 + .../config/imageprocessor/security.config | 4 +- 52 files changed, 186 insertions(+), 124 deletions(-) rename src/ImageProcessor/{Core => }/Common/Exceptions/ImageFormatException.cs (94%) rename src/ImageProcessor/{Core => }/Common/Exceptions/ImageProcessingException.cs (97%) rename src/ImageProcessor/{Core => }/Common/Extensions/DoubleExtensions.cs (96%) rename src/ImageProcessor/{Core => }/Common/Extensions/IntegerExtensions.cs (97%) rename src/ImageProcessor/{Core => }/Common/Extensions/StringExtensions.cs (98%) diff --git a/build/Build.bat b/build/Build.bat index 61973a204..f39a94e86 100644 --- a/build/Build.bat +++ b/build/Build.bat @@ -1,7 +1,7 @@ @ECHO OFF -SET version=1.9.3.0 -SET webversion=3.2.7.0 -SET webconfigversion=1.1.2.0 +SET version=2.0.0.0 +SET webversion=4.0.0.0 +SET webconfigversion=2.0.0.0 ECHO Building ImageProcessor %version%, ImageProcess.Web %webversion% and ImageProcess.Web.Config %webconfigversion% diff --git a/build/NuSpecs/ImageProcessor.Web.Config.nuspec b/build/NuSpecs/ImageProcessor.Web.Config.nuspec index cb27a3fb2..eb605f2b8 100644 --- a/build/NuSpecs/ImageProcessor.Web.Config.nuspec +++ b/build/NuSpecs/ImageProcessor.Web.Config.nuspec @@ -21,19 +21,19 @@ Feedback is always welcome Image Imaging ASP Performance Processing HttpModule Cache Resize Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated - - + + - - + + - - - + + + \ No newline at end of file diff --git a/build/NuSpecs/ImageProcessor.Web.nuspec b/build/NuSpecs/ImageProcessor.Web.nuspec index 5e640a422..840d438a2 100644 --- a/build/NuSpecs/ImageProcessor.Web.nuspec +++ b/build/NuSpecs/ImageProcessor.Web.nuspec @@ -27,10 +27,10 @@ Feedback is always welcome - + - + diff --git a/build/NuSpecs/ImageProcessor.nuspec b/build/NuSpecs/ImageProcessor.nuspec index 80bdd79a1..85b661b2e 100644 --- a/build/NuSpecs/ImageProcessor.nuspec +++ b/build/NuSpecs/ImageProcessor.nuspec @@ -25,5 +25,6 @@ Feedback is always welcome. + \ No newline at end of file diff --git a/build/content/ImageProcessor.Web.Config/web.config.transform b/build/content/ImageProcessor.Web.Config/web.config.transform index c2ed6d5a1..3c88a71b1 100644 --- a/build/content/ImageProcessor.Web.Config/web.config.transform +++ b/build/content/ImageProcessor.Web.Config/web.config.transform @@ -2,9 +2,9 @@ -
-
-
+
+
+
@@ -13,8 +13,4 @@ - - - - diff --git a/build/content/ImageProcessor.Web/web.config.transform b/build/content/ImageProcessor.Web/web.config.transform index a541ff10e..7d02ee462 100644 --- a/build/content/ImageProcessor.Web/web.config.transform +++ b/build/content/ImageProcessor.Web/web.config.transform @@ -7,6 +7,10 @@ + + + + diff --git a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs index f64fad546..23612916b 100644 --- a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs @@ -19,7 +19,8 @@ namespace ImageProcessor.Web.Caching using System.Threading.Tasks; using System.Web; using System.Web.Hosting; - using ImageProcessor.Core.Common.Extensions; + + using ImageProcessor.Common.Extensions; using ImageProcessor.Web.Configuration; using ImageProcessor.Web.Helpers; #endregion diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs index 27e5320c3..04a550729 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs @@ -15,7 +15,7 @@ namespace ImageProcessor.Web.Configuration using System.IO; using System.Xml; - using ImageProcessor.Core.Common.Extensions; + using ImageProcessor.Common.Extensions; using ImageProcessor.Web.Helpers; #endregion diff --git a/src/ImageProcessor.Web/NET45/Configuration/Resources/processing.config b/src/ImageProcessor.Web/NET45/Configuration/Resources/processing.config index 3d3aec8f8..e1ecdfa59 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/Resources/processing.config +++ b/src/ImageProcessor.Web/NET45/Configuration/Resources/processing.config @@ -4,12 +4,13 @@ + - + diff --git a/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs b/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs index 88f935076..ae71ca7ef 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Web.Helpers using System.Drawing; using System.Globalization; using System.Text.RegularExpressions; - using ImageProcessor.Core.Common.Extensions; + + using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index f2bd71ad3..67f3aee5d 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -29,7 +29,7 @@ namespace ImageProcessor.Web.HttpModules using System.Web.Hosting; using System.Web.Security; - using ImageProcessor.Core.Common.Extensions; + using ImageProcessor.Common.Extensions; using ImageProcessor.Web.Caching; using ImageProcessor.Web.Configuration; using ImageProcessor.Web.Helpers; diff --git a/src/ImageProcessor.Web/NET45/Processors/Crop.cs b/src/ImageProcessor.Web/NET45/Processors/Crop.cs index a446e37b8..372d277c3 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Crop.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Crop.cs @@ -12,7 +12,8 @@ namespace ImageProcessor.Web.Processors { using System.Text; using System.Text.RegularExpressions; - using ImageProcessor.Core.Common.Extensions; + + using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging; using ImageProcessor.Processors; diff --git a/src/ImageProcessor.Web/NET45/Processors/Format.cs b/src/ImageProcessor.Web/NET45/Processors/Format.cs index 436361175..b419f211f 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Format.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Format.cs @@ -11,9 +11,12 @@ namespace ImageProcessor.Web.Processors { using System; + using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; + using System.Web; + using ImageProcessor.Configuration; using ImageProcessor.Imaging.Formats; using ImageProcessor.Processors; @@ -135,13 +138,14 @@ namespace ImageProcessor.Web.Processors identifier = identifier.ToLowerInvariant(); string finalIdentifier = identifier.Equals("png8") ? "png" : identifier; ISupportedImageFormat newFormat = null; - ISupportedImageFormat format = ImageProcessorBootstrapper.Instance.SupportedImageFormats - .FirstOrDefault(f => f.FileExtensions.Any(e => e.Equals(finalIdentifier, StringComparison.InvariantCultureIgnoreCase))); + List formats = ImageProcessorBootstrapper.Instance.SupportedImageFormats.ToList(); + ISupportedImageFormat format = formats.FirstOrDefault(f => f.FileExtensions.Any(e => e.Equals(finalIdentifier, StringComparison.InvariantCultureIgnoreCase))); if (format != null) { // Return a new instance as we want to use instance properties. newFormat = Activator.CreateInstance(format.GetType()) as ISupportedImageFormat; + if (newFormat != null) { // I wish this wasn't hard-coded but there's no way I can diff --git a/src/ImageProcessor.Web/NET45/Processors/Resize.cs b/src/ImageProcessor.Web/NET45/Processors/Resize.cs index 7d4a06ceb..95d962958 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Resize.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Resize.cs @@ -16,7 +16,8 @@ namespace ImageProcessor.Web.Processors using System.Linq; using System.Text; using System.Text.RegularExpressions; - using ImageProcessor.Core.Common.Extensions; + + using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging; using ImageProcessor.Processors; diff --git a/src/ImageProcessor.Web/NET45/Processors/Watermark.cs b/src/ImageProcessor.Web/NET45/Processors/Watermark.cs index 641131761..27e83e288 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Watermark.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Watermark.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Web.Processors using System.Globalization; using System.Linq; using System.Text.RegularExpressions; - using ImageProcessor.Core.Common.Extensions; + + using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging; using ImageProcessor.Processors; using ImageProcessor.Web.Helpers; diff --git a/src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs index 8763d6242..d5ad131ff 100644 --- a/src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs +++ b/src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using ImageProcessor.Web.HttpModules; // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("3.2.7.0")] -[assembly: AssemblyFileVersion("3.2.7.0")] \ No newline at end of file +[assembly: AssemblyVersion("4.0.0.0")] +[assembly: AssemblyFileVersion("4.0.0.0")] \ No newline at end of file diff --git a/src/ImageProcessor/Core/Common/Exceptions/ImageFormatException.cs b/src/ImageProcessor/Common/Exceptions/ImageFormatException.cs similarity index 94% rename from src/ImageProcessor/Core/Common/Exceptions/ImageFormatException.cs rename to src/ImageProcessor/Common/Exceptions/ImageFormatException.cs index e858b6fcc..992bd9737 100644 --- a/src/ImageProcessor/Core/Common/Exceptions/ImageFormatException.cs +++ b/src/ImageProcessor/Common/Exceptions/ImageFormatException.cs @@ -8,10 +8,9 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Core.Common.Exceptions +namespace ImageProcessor.Common.Exceptions { using System; - using System.Runtime.Serialization; /// /// The exception that is thrown when loading the supported image format types has failed. diff --git a/src/ImageProcessor/Core/Common/Exceptions/ImageProcessingException.cs b/src/ImageProcessor/Common/Exceptions/ImageProcessingException.cs similarity index 97% rename from src/ImageProcessor/Core/Common/Exceptions/ImageProcessingException.cs rename to src/ImageProcessor/Common/Exceptions/ImageProcessingException.cs index db1adf2a6..44579604a 100644 --- a/src/ImageProcessor/Core/Common/Exceptions/ImageProcessingException.cs +++ b/src/ImageProcessor/Common/Exceptions/ImageProcessingException.cs @@ -8,7 +8,7 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Core.Common.Exceptions +namespace ImageProcessor.Common.Exceptions { using System; diff --git a/src/ImageProcessor/Core/Common/Extensions/DoubleExtensions.cs b/src/ImageProcessor/Common/Extensions/DoubleExtensions.cs similarity index 96% rename from src/ImageProcessor/Core/Common/Extensions/DoubleExtensions.cs rename to src/ImageProcessor/Common/Extensions/DoubleExtensions.cs index a8980c5c6..acc5b12c3 100644 --- a/src/ImageProcessor/Core/Common/Extensions/DoubleExtensions.cs +++ b/src/ImageProcessor/Common/Extensions/DoubleExtensions.cs @@ -8,7 +8,7 @@ //
// -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Core.Common.Extensions +namespace ImageProcessor.Common.Extensions { /// /// Encapsulates a series of time saving extension methods to the class. diff --git a/src/ImageProcessor/Core/Common/Extensions/IntegerExtensions.cs b/src/ImageProcessor/Common/Extensions/IntegerExtensions.cs similarity index 97% rename from src/ImageProcessor/Core/Common/Extensions/IntegerExtensions.cs rename to src/ImageProcessor/Common/Extensions/IntegerExtensions.cs index c4aa90bd8..e04798c0b 100644 --- a/src/ImageProcessor/Core/Common/Extensions/IntegerExtensions.cs +++ b/src/ImageProcessor/Common/Extensions/IntegerExtensions.cs @@ -8,7 +8,7 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Core.Common.Extensions +namespace ImageProcessor.Common.Extensions { using System.Globalization; diff --git a/src/ImageProcessor/Core/Common/Extensions/StringExtensions.cs b/src/ImageProcessor/Common/Extensions/StringExtensions.cs similarity index 98% rename from src/ImageProcessor/Core/Common/Extensions/StringExtensions.cs rename to src/ImageProcessor/Common/Extensions/StringExtensions.cs index a60590f66..fd7d54139 100644 --- a/src/ImageProcessor/Core/Common/Extensions/StringExtensions.cs +++ b/src/ImageProcessor/Common/Extensions/StringExtensions.cs @@ -8,10 +8,8 @@ //
// -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Core.Common.Extensions +namespace ImageProcessor.Common.Extensions { - #region Using - using System; using System.Globalization; using System.Linq; @@ -19,8 +17,6 @@ namespace ImageProcessor.Core.Common.Extensions using System.Text; using System.Text.RegularExpressions; - #endregion - /// /// Encapsulates a series of time saving extension methods to the class. /// diff --git a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs index 594ce5185..e1d59b7f6 100644 --- a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs +++ b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs @@ -13,7 +13,8 @@ namespace ImageProcessor.Configuration using System; using System.Collections.Generic; using System.Linq; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging.Formats; /// diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 97e749cbc..db5e38beb 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -17,7 +17,8 @@ namespace ImageProcessor using System.Drawing; using System.Drawing.Imaging; using System.IO; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging; using ImageProcessor.Imaging.Filters; using ImageProcessor.Imaging.Formats; diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 7e0c0b4f4..cab9513c1 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -60,12 +60,12 @@ - - + + - - - + + + diff --git a/src/ImageProcessor/Imaging/Convolution.cs b/src/ImageProcessor/Imaging/Convolution.cs index 26ff21f6f..bc8496ab2 100644 --- a/src/ImageProcessor/Imaging/Convolution.cs +++ b/src/ImageProcessor/Imaging/Convolution.cs @@ -15,7 +15,7 @@ namespace ImageProcessor.Imaging using System.Drawing.Imaging; using System.Runtime.InteropServices; - using ImageProcessor.Core.Common.Extensions; + using ImageProcessor.Common.Extensions; /// /// Provides methods for applying blurring and sharpening effects to an image.. diff --git a/src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs b/src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs index 872551b56..7d90d0bf9 100644 --- a/src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs +++ b/src/ImageProcessor/Imaging/Filters/ComicMatrixFilter.cs @@ -17,7 +17,9 @@ namespace ImageProcessor.Imaging.Filters using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Runtime.InteropServices; - using ImageProcessor.Core.Common.Extensions; + + using ImageProcessor.Common.Extensions; + #endregion /// diff --git a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs index 15e4e4313..d0bff7a19 100644 --- a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs @@ -21,7 +21,7 @@ namespace ImageProcessor.Imaging.Formats using System.Runtime.InteropServices; using System.Text; - using ImageProcessor.Core.Common.Exceptions; + using ImageProcessor.Common.Exceptions; /// /// Provides the necessary information to support webp images. @@ -163,6 +163,10 @@ namespace ImageProcessor.Imaging.Formats memoryStream.Position = stream.Position = 0; } } + else + { + throw new ImageFormatException("Unable to encode WebP image."); + } return image; } @@ -183,36 +187,52 @@ namespace ImageProcessor.Imaging.Formats IntPtr ptrData = pinnedWebP.AddrOfPinnedObject(); uint dataSize = (uint)webpData.Length; + Bitmap bitmap = null; + BitmapData bitmapData = null; + IntPtr outputBuffer = IntPtr.Zero; int width; int height; if (WebPGetInfo(ptrData, dataSize, out width, out height) != 1) { - throw new ImageFormatException("WebP image is corrupted."); + throw new ImageFormatException("WebP image header is corrupted."); } - // Create a BitmapData and Lock all pixels to be written - Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); - BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat); + try + { + // Create a BitmapData and Lock all pixels to be written + bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); + bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat); - // Allocate memory for uncompress image - int outputBufferSize = bitmapData.Stride * height; - IntPtr outputBuffer = Marshal.AllocHGlobal(outputBufferSize); + // Allocate memory for uncompress image + int outputBufferSize = bitmapData.Stride * height; + outputBuffer = Marshal.AllocHGlobal(outputBufferSize); - // Uncompress the image - outputBuffer = WebPDecodeBGRAInto(ptrData, dataSize, outputBuffer, outputBufferSize, bitmapData.Stride); + // Uncompress the image + outputBuffer = WebPDecodeBGRAInto(ptrData, dataSize, outputBuffer, outputBufferSize, bitmapData.Stride); - // Write image to bitmap using Marshal - byte[] buffer = new byte[outputBufferSize]; - Marshal.Copy(outputBuffer, buffer, 0, outputBufferSize); - Marshal.Copy(buffer, 0, bitmapData.Scan0, outputBufferSize); + if (bitmapData.Scan0 != outputBuffer) + { + throw new ImageFormatException("Failed to decode WebP image with error " + (long)outputBuffer); + } - // Unlock the pixels - bitmap.UnlockBits(bitmapData); + // Write image to bitmap using Marshal + byte[] buffer = new byte[outputBufferSize]; + Marshal.Copy(outputBuffer, buffer, 0, outputBufferSize); + Marshal.Copy(buffer, 0, bitmapData.Scan0, outputBufferSize); + } + finally + { + // Unlock the pixels + if (bitmap != null) + { + bitmap.UnlockBits(bitmapData); + } - // Free memory - pinnedWebP.Free(); - Marshal.FreeHGlobal(outputBuffer); + // Free memory + pinnedWebP.Free(); + Marshal.FreeHGlobal(outputBuffer); + } return bitmap; } @@ -235,29 +255,34 @@ namespace ImageProcessor.Imaging.Formats private static bool EncodeLossly(Bitmap bitmap, int quality, out byte[] webpData) { webpData = null; + BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + IntPtr unmanagedData = IntPtr.Zero; + bool encoded; try { - BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); - IntPtr unmanagedData; + // Attempt to lossy encode the image. int size = WebPEncodeBGRA(bmpData.Scan0, bitmap.Width, bitmap.Height, bmpData.Stride, quality, out unmanagedData); // Copy image compress data to output array webpData = new byte[size]; Marshal.Copy(unmanagedData, webpData, 0, size); - + encoded = true; + } + catch + { + encoded = false; + } + finally + { // Unlock the pixels bitmap.UnlockBits(bmpData); // Free memory WebPFree(unmanagedData); - - return true; - } - catch - { - return false; } + + return encoded; } /// @@ -335,13 +360,13 @@ namespace ImageProcessor.Imaging.Formats /// /// Frees the unmanaged memory. /// - /// + /// /// The pointer. /// /// /// 1 if success, otherwise error code returned in the case of (a) error(s). /// [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern int WebPFree(IntPtr p); + private static extern int WebPFree(IntPtr pointer); } } \ No newline at end of file diff --git a/src/ImageProcessor/Processors/Alpha.cs b/src/ImageProcessor/Processors/Alpha.cs index e921233e8..a27e5f6f9 100644 --- a/src/ImageProcessor/Processors/Alpha.cs +++ b/src/ImageProcessor/Processors/Alpha.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; /// /// Encapsulates methods to change the alpha component of the image to effect its transparency. diff --git a/src/ImageProcessor/Processors/AutoRotate.cs b/src/ImageProcessor/Processors/AutoRotate.cs index 1fcf81f48..7368d2574 100644 --- a/src/ImageProcessor/Processors/AutoRotate.cs +++ b/src/ImageProcessor/Processors/AutoRotate.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Processors using System; using System.Collections.Generic; using System.Drawing; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor/Processors/BackgroundColor.cs b/src/ImageProcessor/Processors/BackgroundColor.cs index 6d785f1f3..a41396f90 100644 --- a/src/ImageProcessor/Processors/BackgroundColor.cs +++ b/src/ImageProcessor/Processors/BackgroundColor.cs @@ -13,7 +13,8 @@ namespace ImageProcessor.Processors using System; using System.Collections.Generic; using System.Drawing; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; /// /// Changes the background color of an image. diff --git a/src/ImageProcessor/Processors/Brightness.cs b/src/ImageProcessor/Processors/Brightness.cs index 4df039a07..51fb2be41 100644 --- a/src/ImageProcessor/Processors/Brightness.cs +++ b/src/ImageProcessor/Processors/Brightness.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; /// /// Encapsulates methods to change the brightness component of the image. diff --git a/src/ImageProcessor/Processors/Contrast.cs b/src/ImageProcessor/Processors/Contrast.cs index a6fec199d..8289b4537 100644 --- a/src/ImageProcessor/Processors/Contrast.cs +++ b/src/ImageProcessor/Processors/Contrast.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; /// /// Encapsulates methods to change the contrast component of the image. diff --git a/src/ImageProcessor/Processors/Crop.cs b/src/ImageProcessor/Processors/Crop.cs index 2b0f3c417..d0b8cb9ae 100644 --- a/src/ImageProcessor/Processors/Crop.cs +++ b/src/ImageProcessor/Processors/Crop.cs @@ -15,7 +15,8 @@ namespace ImageProcessor.Processors using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor/Processors/Filter.cs b/src/ImageProcessor/Processors/Filter.cs index f98a041c0..e8130afa3 100644 --- a/src/ImageProcessor/Processors/Filter.cs +++ b/src/ImageProcessor/Processors/Filter.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging.Filters; /// diff --git a/src/ImageProcessor/Processors/Flip.cs b/src/ImageProcessor/Processors/Flip.cs index 5f57e5c9c..839edc34d 100644 --- a/src/ImageProcessor/Processors/Flip.cs +++ b/src/ImageProcessor/Processors/Flip.cs @@ -13,7 +13,8 @@ namespace ImageProcessor.Processors using System; using System.Collections.Generic; using System.Drawing; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; /// /// Flips an image horizontally or vertically. diff --git a/src/ImageProcessor/Processors/Format.cs b/src/ImageProcessor/Processors/Format.cs index 2f3af85a1..2695180af 100644 --- a/src/ImageProcessor/Processors/Format.cs +++ b/src/ImageProcessor/Processors/Format.cs @@ -13,7 +13,8 @@ namespace ImageProcessor.Processors using System; using System.Collections.Generic; using System.Drawing; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging.Formats; /// diff --git a/src/ImageProcessor/Processors/GaussianBlur.cs b/src/ImageProcessor/Processors/GaussianBlur.cs index 3e2959094..1ddf9e787 100644 --- a/src/ImageProcessor/Processors/GaussianBlur.cs +++ b/src/ImageProcessor/Processors/GaussianBlur.cs @@ -13,7 +13,8 @@ namespace ImageProcessor.Processors using System; using System.Collections.Generic; using System.Drawing; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor/Processors/GaussianSharpen.cs b/src/ImageProcessor/Processors/GaussianSharpen.cs index 2949a899a..8aaf84e5d 100644 --- a/src/ImageProcessor/Processors/GaussianSharpen.cs +++ b/src/ImageProcessor/Processors/GaussianSharpen.cs @@ -13,7 +13,8 @@ namespace ImageProcessor.Processors using System; using System.Collections.Generic; using System.Drawing; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor/Processors/Quality.cs b/src/ImageProcessor/Processors/Quality.cs index 9d53ccb9e..015c519eb 100644 --- a/src/ImageProcessor/Processors/Quality.cs +++ b/src/ImageProcessor/Processors/Quality.cs @@ -13,7 +13,8 @@ namespace ImageProcessor.Processors using System; using System.Collections.Generic; using System.Drawing; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; /// /// Encapsulates methods to change the quality component of the image. diff --git a/src/ImageProcessor/Processors/Resize.cs b/src/ImageProcessor/Processors/Resize.cs index f52587492..3495dd3a0 100644 --- a/src/ImageProcessor/Processors/Resize.cs +++ b/src/ImageProcessor/Processors/Resize.cs @@ -17,7 +17,8 @@ namespace ImageProcessor.Processors using System.Drawing.Imaging; using System.Globalization; using System.Linq; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor/Processors/Rotate.cs b/src/ImageProcessor/Processors/Rotate.cs index 4e1bd8142..70fabd1cc 100644 --- a/src/ImageProcessor/Processors/Rotate.cs +++ b/src/ImageProcessor/Processors/Rotate.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; /// /// Encapsulates methods to rotate an image. diff --git a/src/ImageProcessor/Processors/RoundedCorners.cs b/src/ImageProcessor/Processors/RoundedCorners.cs index ebd26ef24..5df2367fe 100644 --- a/src/ImageProcessor/Processors/RoundedCorners.cs +++ b/src/ImageProcessor/Processors/RoundedCorners.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor/Processors/Saturation.cs b/src/ImageProcessor/Processors/Saturation.cs index f0e245821..b8d2a0819 100644 --- a/src/ImageProcessor/Processors/Saturation.cs +++ b/src/ImageProcessor/Processors/Saturation.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; /// /// Encapsulates methods to change the saturation component of the image. diff --git a/src/ImageProcessor/Processors/Tint.cs b/src/ImageProcessor/Processors/Tint.cs index 9943a0cc3..603c7fd11 100644 --- a/src/ImageProcessor/Processors/Tint.cs +++ b/src/ImageProcessor/Processors/Tint.cs @@ -15,7 +15,8 @@ namespace ImageProcessor.Processors using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; /// /// Tints an image with the given color. diff --git a/src/ImageProcessor/Processors/Vignette.cs b/src/ImageProcessor/Processors/Vignette.cs index 9d4f12241..3be2beee1 100644 --- a/src/ImageProcessor/Processors/Vignette.cs +++ b/src/ImageProcessor/Processors/Vignette.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; /// /// Encapsulates methods with which to add a vignette image effect to an image. diff --git a/src/ImageProcessor/Processors/Watermark.cs b/src/ImageProcessor/Processors/Watermark.cs index 9ce4771ff..e06eb812a 100644 --- a/src/ImageProcessor/Processors/Watermark.cs +++ b/src/ImageProcessor/Processors/Watermark.cs @@ -14,7 +14,8 @@ namespace ImageProcessor.Processors using System.Collections.Generic; using System.Drawing; using System.Drawing.Text; - using ImageProcessor.Core.Common.Exceptions; + + using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging; /// diff --git a/src/ImageProcessor/Properties/AssemblyInfo.cs b/src/ImageProcessor/Properties/AssemblyInfo.cs index bea6c1401..840a38ec8 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.9.3.0")] -[assembly: AssemblyFileVersion("1.9.3.0")] +[assembly: AssemblyVersion("2.0.0.0")] +[assembly: AssemblyFileVersion("2.0.0.0")] diff --git a/src/TestWebsites/NET4/config/imageprocessor/processing.config b/src/TestWebsites/NET4/config/imageprocessor/processing.config index 85283e9f2..9628cf652 100644 --- a/src/TestWebsites/NET4/config/imageprocessor/processing.config +++ b/src/TestWebsites/NET4/config/imageprocessor/processing.config @@ -4,41 +4,42 @@ - - - - - - - - - + + + + + + + + + + - + - - + + - - - + + - - - - - + + + + + + diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Web.config b/src/TestWebsites/NET45/Test_Website_NET45/Views/Web.config index 826ce19e8..3d9efc26a 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/Views/Web.config +++ b/src/TestWebsites/NET45/Test_Website_NET45/Views/Web.config @@ -45,11 +45,11 @@ + - diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Web.config b/src/TestWebsites/NET45/Test_Website_NET45/Web.config index d20021463..7f87cedd1 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/Web.config +++ b/src/TestWebsites/NET45/Test_Website_NET45/Web.config @@ -44,10 +44,15 @@ + + + + + diff --git a/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config b/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config index 6d9f621d1..2dc2d374e 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config +++ b/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config @@ -3,6 +3,8 @@ + + diff --git a/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/security.config b/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/security.config index 78b957605..d4781f99c 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/security.config +++ b/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/security.config @@ -1,9 +1,9 @@  - + - + From 8f3163957cf713a55aafbb2de08180ecc67efa26 Mon Sep 17 00:00:00 2001 From: James South Date: Wed, 25 Jun 2014 15:11:10 +0100 Subject: [PATCH 029/155] FxCop tidy up Former-commit-id: 0a41cfb5d46dc42fc0e7140800b1972f5b6cc205 --- .../Common/Exceptions/ImageFormatException.cs | 1 + .../Exceptions/ImageProcessingException.cs | 1 + src/ImageProcessor/ImageProcessor.csproj | 1 + .../Imaging/Formats/JpegFormat.cs | 11 +- .../Imaging/Formats/NativeMethods.cs | 107 ++++++++++++++++++ .../Imaging/Formats/TiffFormat.cs | 11 +- .../Imaging/Formats/WebPFormat.cs | 103 +---------------- src/ImageProcessor/Settings.StyleCop | 1 + 8 files changed, 118 insertions(+), 118 deletions(-) create mode 100644 src/ImageProcessor/Imaging/Formats/NativeMethods.cs diff --git a/src/ImageProcessor/Common/Exceptions/ImageFormatException.cs b/src/ImageProcessor/Common/Exceptions/ImageFormatException.cs index 992bd9737..1d4169a88 100644 --- a/src/ImageProcessor/Common/Exceptions/ImageFormatException.cs +++ b/src/ImageProcessor/Common/Exceptions/ImageFormatException.cs @@ -15,6 +15,7 @@ namespace ImageProcessor.Common.Exceptions /// /// The exception that is thrown when loading the supported image format types has failed. /// + [Serializable] public sealed class ImageFormatException : Exception { /// diff --git a/src/ImageProcessor/Common/Exceptions/ImageProcessingException.cs b/src/ImageProcessor/Common/Exceptions/ImageProcessingException.cs index 44579604a..02b6be4f2 100644 --- a/src/ImageProcessor/Common/Exceptions/ImageProcessingException.cs +++ b/src/ImageProcessor/Common/Exceptions/ImageProcessingException.cs @@ -15,6 +15,7 @@ namespace ImageProcessor.Common.Exceptions /// /// The exception that is thrown when processing an image has failed. /// + [Serializable] public sealed class ImageProcessingException : Exception { /// diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index cab9513c1..68702ed09 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -76,6 +76,7 @@ + diff --git a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs index 0111ee1d6..ae5fd05c3 100644 --- a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs @@ -81,16 +81,7 @@ namespace ImageProcessor.Imaging.Formats { foreach (KeyValuePair propertItem in factory.ExifPropertyItems) { - try - { - factory.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. - } + factory.Image.SetPropertyItem(propertItem.Value); } } } diff --git a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs b/src/ImageProcessor/Imaging/Formats/NativeMethods.cs new file mode 100644 index 000000000..eb9062e91 --- /dev/null +++ b/src/ImageProcessor/Imaging/Formats/NativeMethods.cs @@ -0,0 +1,107 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides access to unmanaged native methods. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Formats +{ + using System; + using System.Runtime.InteropServices; + + /// + /// Provides access to unmanaged native methods. + /// + internal static class NativeMethods + { + #region WebP + /// + /// Validate the WebP image header and retrieve the image height and width. Pointers *width and *height can be passed NULL if deemed irrelevant + /// + /// + /// Pointer to WebP image data + /// + /// + /// This is the size of the memory block pointed to by data containing the image data + /// + /// + /// The width range is limited currently from 1 to 16383 + /// + /// + /// The height range is limited currently from 1 to 16383 + /// + /// + /// 1 if success, otherwise error code returned in the case of (a) formatting error(s). + /// + [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int WebPGetInfo(IntPtr data, uint dataSize, out int width, out int height); + + /// + /// Decode WEBP image pointed to by *data and returns BGR samples into a pre-allocated buffer + /// + /// + /// Pointer to WebP image data + /// + /// + /// This is the size of the memory block pointed to by data containing the image data + /// + /// + /// Pointer to decoded WebP image + /// + /// + /// Size of allocated buffer + /// + /// + /// Specifies the distance between scan-lines + /// + /// + /// output_buffer if function succeeds; NULL otherwise + /// + [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr WebPDecodeBGRAInto(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride); + + /// + /// Lossy encoding images pointed to by *data in WebP format + /// + /// + /// Pointer to RGB image data + /// + /// + /// The width range is limited currently from 1 to 16383 + /// + /// + /// The height range is limited currently from 1 to 16383 + /// + /// + /// The stride. + /// + /// + /// Ranges from 0 (lower quality) to 100 (highest quality). Controls the loss and quality during compression + /// + /// + /// output_buffer with WebP image + /// + /// + /// Size of WebP Image + /// + [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int WebPEncodeBGRA(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output); + + /// + /// Frees the unmanaged memory. + /// + /// + /// The pointer. + /// + /// + /// 1 if success, otherwise error code returned in the case of (a) error(s). + /// + [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int WebPFree(IntPtr pointer); + #endregion + } +} diff --git a/src/ImageProcessor/Imaging/Formats/TiffFormat.cs b/src/ImageProcessor/Imaging/Formats/TiffFormat.cs index b708abd7d..e761bc4b3 100644 --- a/src/ImageProcessor/Imaging/Formats/TiffFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/TiffFormat.cs @@ -83,16 +83,7 @@ namespace ImageProcessor.Imaging.Formats { foreach (KeyValuePair propertItem in factory.ExifPropertyItems) { - try - { - factory.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. - } + factory.Image.SetPropertyItem(propertItem.Value); } } } diff --git a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs index d0bff7a19..d8c9bbf33 100644 --- a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs @@ -90,16 +90,7 @@ namespace ImageProcessor.Imaging.Formats { foreach (KeyValuePair propertItem in factory.ExifPropertyItems) { - try - { - factory.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. - } + factory.Image.SetPropertyItem(propertItem.Value); } } } @@ -193,7 +184,7 @@ namespace ImageProcessor.Imaging.Formats int width; int height; - if (WebPGetInfo(ptrData, dataSize, out width, out height) != 1) + if (NativeMethods.WebPGetInfo(ptrData, dataSize, out width, out height) != 1) { throw new ImageFormatException("WebP image header is corrupted."); } @@ -209,7 +200,7 @@ namespace ImageProcessor.Imaging.Formats outputBuffer = Marshal.AllocHGlobal(outputBufferSize); // Uncompress the image - outputBuffer = WebPDecodeBGRAInto(ptrData, dataSize, outputBuffer, outputBufferSize, bitmapData.Stride); + outputBuffer = NativeMethods.WebPDecodeBGRAInto(ptrData, dataSize, outputBuffer, outputBufferSize, bitmapData.Stride); if (bitmapData.Scan0 != outputBuffer) { @@ -262,7 +253,7 @@ namespace ImageProcessor.Imaging.Formats try { // Attempt to lossy encode the image. - int size = WebPEncodeBGRA(bmpData.Scan0, bitmap.Width, bitmap.Height, bmpData.Stride, quality, out unmanagedData); + int size = NativeMethods.WebPEncodeBGRA(bmpData.Scan0, bitmap.Width, bitmap.Height, bmpData.Stride, quality, out unmanagedData); // Copy image compress data to output array webpData = new byte[size]; @@ -279,94 +270,10 @@ namespace ImageProcessor.Imaging.Formats bitmap.UnlockBits(bmpData); // Free memory - WebPFree(unmanagedData); + NativeMethods.WebPFree(unmanagedData); } return encoded; } - - /// - /// Validate the WebP image header and retrieve the image height and width. Pointers *width and *height can be passed NULL if deemed irrelevant - /// - /// - /// Pointer to WebP image data - /// - /// - /// This is the size of the memory block pointed to by data containing the image data - /// - /// - /// The width range is limited currently from 1 to 16383 - /// - /// - /// The height range is limited currently from 1 to 16383 - /// - /// - /// 1 if success, otherwise error code returned in the case of (a) formatting error(s). - /// - [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern int WebPGetInfo(IntPtr data, uint dataSize, out int width, out int height); - - /// - /// Decode WEBP image pointed to by *data and returns BGR samples into a pre-allocated buffer - /// - /// - /// Pointer to WebP image data - /// - /// - /// This is the size of the memory block pointed to by data containing the image data - /// - /// - /// Pointer to decoded WebP image - /// - /// - /// Size of allocated buffer - /// - /// - /// Specifies the distance between scan-lines - /// - /// - /// output_buffer if function succeeds; NULL otherwise - /// - [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr WebPDecodeBGRAInto(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride); - - /// - /// Lossy encoding images pointed to by *data in WebP format - /// - /// - /// Pointer to RGB image data - /// - /// - /// The width range is limited currently from 1 to 16383 - /// - /// - /// The height range is limited currently from 1 to 16383 - /// - /// - /// The stride. - /// - /// - /// Ranges from 0 (lower quality) to 100 (highest quality). Controls the loss and quality during compression - /// - /// - /// output_buffer with WebP image - /// - /// - /// Size of WebP Image - /// - [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern int WebPEncodeBGRA(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output); - - /// - /// Frees the unmanaged memory. - /// - /// - /// The pointer. - /// - /// - /// 1 if success, otherwise error code returned in the case of (a) error(s). - /// - [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern int WebPFree(IntPtr pointer); } } \ No newline at end of file diff --git a/src/ImageProcessor/Settings.StyleCop b/src/ImageProcessor/Settings.StyleCop index d643471e4..a8aa884a1 100644 --- a/src/ImageProcessor/Settings.StyleCop +++ b/src/ImageProcessor/Settings.StyleCop @@ -10,6 +10,7 @@ halftoning lomograph Lomograph + lossy octree png quantizer From de3d06f207a2c2d2b71754bde09c0465355c5358 Mon Sep 17 00:00:00 2001 From: James South Date: Wed, 25 Jun 2014 19:02:07 +0100 Subject: [PATCH 030/155] Funky Nuget stuff Still can't copy unmanaged binaries across. Former-commit-id: 7e31a7b715087b080fb5d38c225d662dd6cb91bb --- build/NuSpecs/ImageProcessor.nuspec | 4 +- .../ImageProcessor/imageprocessor.targets | 10 ++ src/ImageProcessor/ImageProcessor.csproj | 5 +- .../Imaging/Formats/NativeMethods.cs | 100 ++++++++++++++++-- .../Imaging/Formats/WebPFormat.cs | 60 +++++++++-- src/ImageProcessor/libwebp.dll.REMOVED.git-id | 1 - .../x64/libwebp.dll.REMOVED.git-id | 1 + .../x86/libwebp.dll.REMOVED.git-id | 1 + src/ImageProcessorConsole/Program.cs | 2 +- .../images/output/120430.gif.REMOVED.git-id | 1 - .../images/output/4.sm.webp | Bin 12162 -> 0 bytes .../images/output/Tl4Yb.gif.REMOVED.git-id | 1 - .../images/output/circle.webp | Bin 1228 -> 0 bytes .../images/output/nLpfllv.gif.REMOVED.git-id | 1 - .../images/output/rotate.webp | Bin 1812 -> 1792 bytes .../images/output/test.webp | Bin 5590 -> 0 bytes 16 files changed, 164 insertions(+), 23 deletions(-) create mode 100644 build/content/ImageProcessor/imageprocessor.targets delete mode 100644 src/ImageProcessor/libwebp.dll.REMOVED.git-id create mode 100644 src/ImageProcessor/x64/libwebp.dll.REMOVED.git-id create mode 100644 src/ImageProcessor/x86/libwebp.dll.REMOVED.git-id delete mode 100644 src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id delete mode 100644 src/ImageProcessorConsole/images/output/4.sm.webp delete mode 100644 src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id delete mode 100644 src/ImageProcessorConsole/images/output/circle.webp delete mode 100644 src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id delete mode 100644 src/ImageProcessorConsole/images/output/test.webp diff --git a/build/NuSpecs/ImageProcessor.nuspec b/build/NuSpecs/ImageProcessor.nuspec index 85b661b2e..30e157086 100644 --- a/build/NuSpecs/ImageProcessor.nuspec +++ b/build/NuSpecs/ImageProcessor.nuspec @@ -25,6 +25,8 @@ Feedback is always welcome. - + + + \ No newline at end of file diff --git a/build/content/ImageProcessor/imageprocessor.targets b/build/content/ImageProcessor/imageprocessor.targets new file mode 100644 index 000000000..6922fa306 --- /dev/null +++ b/build/content/ImageProcessor/imageprocessor.targets @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 68702ed09..802dadb56 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -130,7 +130,10 @@ - + + PreserveNewest + + PreserveNewest diff --git a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs b/src/ImageProcessor/Imaging/Formats/NativeMethods.cs index eb9062e91..059c5259a 100644 --- a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs +++ b/src/ImageProcessor/Imaging/Formats/NativeMethods.cs @@ -37,8 +37,53 @@ namespace ImageProcessor.Imaging.Formats /// /// 1 if success, otherwise error code returned in the case of (a) formatting error(s). /// - [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int WebPGetInfo(IntPtr data, uint dataSize, out int width, out int height); + [DllImport("x86\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetInfo")] + public static extern int WebPGetInfo86(IntPtr data, uint dataSize, out int width, out int height); + + /// + /// Validate the WebP image header and retrieve the image height and width. Pointers *width and *height can be passed NULL if deemed irrelevant + /// + /// + /// Pointer to WebP image data + /// + /// + /// This is the size of the memory block pointed to by data containing the image data + /// + /// + /// The width range is limited currently from 1 to 16383 + /// + /// + /// The height range is limited currently from 1 to 16383 + /// + /// + /// 1 if success, otherwise error code returned in the case of (a) formatting error(s). + /// + [DllImport("x64\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetInfo")] + public static extern int WebPGetInfo64(IntPtr data, uint dataSize, out int width, out int height); + + /// + /// Decode WEBP image pointed to by *data and returns BGR samples into a pre-allocated buffer + /// + /// + /// Pointer to WebP image data + /// + /// + /// This is the size of the memory block pointed to by data containing the image data + /// + /// + /// Pointer to decoded WebP image + /// + /// + /// Size of allocated buffer + /// + /// + /// Specifies the distance between scan-lines + /// + /// + /// output_buffer if function succeeds; NULL otherwise + /// + [DllImport("x86\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")] + public static extern IntPtr WebPDecodeBGRAInto86(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride); /// /// Decode WEBP image pointed to by *data and returns BGR samples into a pre-allocated buffer @@ -61,8 +106,35 @@ namespace ImageProcessor.Imaging.Formats /// /// output_buffer if function succeeds; NULL otherwise /// - [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr WebPDecodeBGRAInto(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride); + [DllImport("x64\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")] + public static extern IntPtr WebPDecodeBGRAInto64(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride); + + /// + /// Lossy encoding images pointed to by *data in WebP format + /// + /// + /// Pointer to RGB image data + /// + /// + /// The width range is limited currently from 1 to 16383 + /// + /// + /// The height range is limited currently from 1 to 16383 + /// + /// + /// The stride. + /// + /// + /// Ranges from 0 (lower quality) to 100 (highest quality). Controls the loss and quality during compression + /// + /// + /// output_buffer with WebP image + /// + /// + /// Size of WebP Image + /// + [DllImport("x86\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGRA")] + public static extern int WebPEncodeBGRA86(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output); /// /// Lossy encoding images pointed to by *data in WebP format @@ -88,8 +160,20 @@ namespace ImageProcessor.Imaging.Formats /// /// Size of WebP Image /// - [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int WebPEncodeBGRA(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output); + [DllImport("x64\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGRA")] + public static extern int WebPEncodeBGRA64(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output); + + /// + /// Frees the unmanaged memory. + /// + /// + /// The pointer. + /// + /// + /// 1 if success, otherwise error code returned in the case of (a) error(s). + /// + [DllImport("x86\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")] + public static extern int WebPFree86(IntPtr pointer); /// /// Frees the unmanaged memory. @@ -100,8 +184,8 @@ namespace ImageProcessor.Imaging.Formats /// /// 1 if success, otherwise error code returned in the case of (a) error(s). /// - [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] - public static extern int WebPFree(IntPtr pointer); + [DllImport("x64\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")] + public static extern int WebPFree64(IntPtr pointer); #endregion } } diff --git a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs index d8c9bbf33..1617d37be 100644 --- a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs @@ -31,6 +31,12 @@ namespace ImageProcessor.Imaging.Formats [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")] public class WebPFormat : FormatBase { + /// + /// Whether the process is running in 63bit mode. Used for calling the correct dllimport method. + /// Clunky I know but I couldn't get dynamic methods to work. + /// + private static readonly bool Is64Bit = Environment.Is64BitProcess; + /// /// Gets the file headers. /// @@ -184,9 +190,19 @@ namespace ImageProcessor.Imaging.Formats int width; int height; - if (NativeMethods.WebPGetInfo(ptrData, dataSize, out width, out height) != 1) + if (Is64Bit) + { + if (NativeMethods.WebPGetInfo64(ptrData, dataSize, out width, out height) != 1) + { + throw new ImageFormatException("WebP image header is corrupted."); + } + } + else { - throw new ImageFormatException("WebP image header is corrupted."); + if (NativeMethods.WebPGetInfo86(ptrData, dataSize, out width, out height) != 1) + { + throw new ImageFormatException("WebP image header is corrupted."); + } } try @@ -199,8 +215,17 @@ namespace ImageProcessor.Imaging.Formats int outputBufferSize = bitmapData.Stride * height; outputBuffer = Marshal.AllocHGlobal(outputBufferSize); - // Uncompress the image - outputBuffer = NativeMethods.WebPDecodeBGRAInto(ptrData, dataSize, outputBuffer, outputBufferSize, bitmapData.Stride); + // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression + if (Is64Bit) + { + // Uncompress the image + outputBuffer = NativeMethods.WebPDecodeBGRAInto64(ptrData, dataSize, outputBuffer, outputBufferSize, bitmapData.Stride); + } + else + { + // Uncompress the image + outputBuffer = NativeMethods.WebPDecodeBGRAInto86(ptrData, dataSize, outputBuffer, outputBufferSize, bitmapData.Stride); + } if (bitmapData.Scan0 != outputBuffer) { @@ -252,8 +277,19 @@ namespace ImageProcessor.Imaging.Formats try { - // Attempt to lossy encode the image. - int size = NativeMethods.WebPEncodeBGRA(bmpData.Scan0, bitmap.Width, bitmap.Height, bmpData.Stride, quality, out unmanagedData); + int size; + + // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression + if (Is64Bit) + { + // Attempt to lossy encode the image. + size = NativeMethods.WebPEncodeBGRA64(bmpData.Scan0, bitmap.Width, bitmap.Height, bmpData.Stride, quality, out unmanagedData); + } + else + { + // Attempt to lossy encode the image. + size = NativeMethods.WebPEncodeBGRA86(bmpData.Scan0, bitmap.Width, bitmap.Height, bmpData.Stride, quality, out unmanagedData); + } // Copy image compress data to output array webpData = new byte[size]; @@ -269,8 +305,16 @@ namespace ImageProcessor.Imaging.Formats // Unlock the pixels bitmap.UnlockBits(bmpData); - // Free memory - NativeMethods.WebPFree(unmanagedData); + if (Is64Bit) + { + // Free memory + NativeMethods.WebPFree64(unmanagedData); + } + else + { + // Free memory + NativeMethods.WebPFree86(unmanagedData); + } } return encoded; diff --git a/src/ImageProcessor/libwebp.dll.REMOVED.git-id b/src/ImageProcessor/libwebp.dll.REMOVED.git-id deleted file mode 100644 index e05b4f051..000000000 --- a/src/ImageProcessor/libwebp.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -ed0333da619a813e8337d77ba7ee206ea5f20a51 \ No newline at end of file diff --git a/src/ImageProcessor/x64/libwebp.dll.REMOVED.git-id b/src/ImageProcessor/x64/libwebp.dll.REMOVED.git-id new file mode 100644 index 000000000..35684c541 --- /dev/null +++ b/src/ImageProcessor/x64/libwebp.dll.REMOVED.git-id @@ -0,0 +1 @@ +dcadab1b5b86469758707bff22558b33e5c51552 \ No newline at end of file diff --git a/src/ImageProcessor/x86/libwebp.dll.REMOVED.git-id b/src/ImageProcessor/x86/libwebp.dll.REMOVED.git-id new file mode 100644 index 000000000..129db9826 --- /dev/null +++ b/src/ImageProcessor/x86/libwebp.dll.REMOVED.git-id @@ -0,0 +1 @@ +ad47008dd1e64ea220bc745e28f568277434d661 \ No newline at end of file diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index 20e92e803..64053c5ed 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -52,7 +52,7 @@ namespace ImageProcessorConsole // ImageProcessor using (MemoryStream inStream = new MemoryStream(photoBytes)) { - using (ImageFactory imageFactory = new ImageFactory(true)) + using (ImageFactory imageFactory = new ImageFactory()) { Size size = new Size(200, 200); diff --git a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id deleted file mode 100644 index 71ce555c1..000000000 --- a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -30ec5c05548fd350f9b7c699715848b9fbfb8ca9 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/4.sm.webp b/src/ImageProcessorConsole/images/output/4.sm.webp deleted file mode 100644 index 90a6308640402286dc34d6e178063681eb985089..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12162 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 E0HyKO%>V!Z diff --git a/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id deleted file mode 100644 index 6515d65a0..000000000 --- a/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -fdc62fc2d056ab885eb9e8fd12b9155ee86d7c43 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/circle.webp b/src/ImageProcessorConsole/images/output/circle.webp deleted file mode 100644 index ef0281087a99eab7de16954d2dfa362028c4127a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1228 zcmV;-1T*_mNk&G*1ONb6MM6+kP&il$0000G0002T0074T06|PpNZA7b00FnApluuJ zlJV!=%M>kRI3)5i{4Ayzc?jA9AQ_Ua zIJRxuwr$(CZQHhO+qi2Ze&~89qFy(m|B3AXv!gB9r0?WayN+GBarfS>E2j>upEsm! zl{^S+(Uz0;-u<1J`o3Yr(^eOPfBtopxZ4EowQf-)b}YPm|Devs+%TS!Mx}ElVY`ZAkE+2l=XT1y ztq;eXdnx$2A^dXeq2!l(u-in@x0PYGn6ghwz-knQ&*yv$?}fKS z+XyDJDF3JcESe-ze+?Y++@V2QTNuow#p8UCuNqB{Igmd{lc>rNZ=Ft;9T2}no0JBS z?nkiJZ#l!g#)lS!xD5I#by*vgQto_Cs_F?S7Vk zWPuO#8vx0+G~5lzWi)(W0E#zgn9&@9Wuxgh6@oozc@%;RX!#-+^iI$+sRrb7KBH$h z$W@4?=M2cTrs+1w^{43>$jzYX(;QG+L(|Viptgsmf0TpTahfL7fZ9cxX4Hq;O}aLL z+FiP~fZ9E}wt(6#x;BH_Rk}8U+8LUr)PmYUnnqWG+9sNQFA23pG<}^1Y9nZR4RW1n zx*u|NQt7!2as@xrb1?L-(K53s^fu7)dr{~Or{xt0)=i<~N(knCMaSMy+(W~tGEf{s z!wZlsA49+C&^$}KsSWK)2`@ zIt_;MY#Kew3*}XYHpCzIMo;Io9%&x*n5D24y152vDcD4W&;Ugcg=btK$sf1>6L_%-}W z#kp{7^pSdV;92uI#WE(swd{3D#SVgR!F?3^&BFwvfphU*XT(B>DhyrhV zAqd01GSb^hArKXIq%o2Yx+5U%E-_-?rsYFe2Hs^v{#a2C!O1=N2DAL@(h3MumqRhk z%KMW_BV5&H-pypzeA(VHCj!@e@y$5?-*-Fv6hjcJ4&8b;n*TB7&GG3i3L>QCJ4{%2 z;^D{N@frLxIqKWAy^C* zFuBMUSY7ZNV#olQj71_P%e@SX^TZ1*D&RS5jkJsPVmKGF6U00VE9#KY@1_7^gu3sVvM8B8y)i qMWUyzLkvUQ?iiyX>+LP4G&gQGqev8-o4qC3!qqv0UQ?*30000XdQ!pw diff --git a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id deleted file mode 100644 index 4487aede0..000000000 --- a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -23a1c81a2d1422076373796e0c47f5d968c56d0b \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/rotate.webp b/src/ImageProcessorConsole/images/output/rotate.webp index ca786888a0deb517cac3db1fb29b03564a0fec4c..3cc93f14973b480cd6270b3d3ec61cf86e4d1135 100644 GIT binary patch literal 1792 zcmV+b2mkm|Nk&Ha1^@t8MM6+kP&gp$1^@tXIRKpjD#!qq06&?;)nmCaE2gKltXm*6 z31e&3Uwu12@pYUxv9tO^7{%9@PvE<2^^K}ds+-BwTc0X#mf*8Q{BXhf@1XP21ha1R z&Rhz&J9QJ2A;I9vUTk}jXc0*$)MGHQ!ux{>7s0Dtz&iMx*kP7=iItI-3&0o3zwObg z8_ppO(=Y$faA}3B6kojQ$6C8EehUcJw931$(x79qDo1Ytw_oR@zs>ZqdwjO3N1!*2~%@-NGseIwdLi1P&3MFoq>u5CP3DvH;DZ-I&&sq3( z{x_j|hX)ifOq1Jy9~l;nGgBJ116yt7z`;#Qi;+b7$BT`7O~eVszvf+|FZLDw zIy)o?2Yp(phIpGohOIuB? zz9=607mv;5u?+a5EeZNhZf@9Q${?VOkPlD*{_4|e>1V71-|eAqPE$~ERYSt+m1AIT zhm0~^-!yp>E0gMb<>c2@NoXr!4LaEq$q1Cs8~$k_w$ylGf%f*MMb;=u?h|yohgG7u zTVlEktFqDtuD=zI2aIrkO(jwF*#ho~gUCm4ALf_R)d|NH7F+{-!}O{=$w_V5cLvt> zIUN{qiTPjt-c&J-gffM(&YJm1JZ{cQcH>S@z4WW*q!_g+=r?bbV-RHc}5`w$KOChyv+$kHY{rSHNpJn`i zWerg3EJO1wO{pi97q;@1$zcTWMEHBa%mH;cmm0)A&`V!mA&x~>+Qd-fG#5p4SwM1= zlT+e@1bnNVgEJryk{Ki&S@VVRQN;r@YtL#nYHXsM{Z)XLg9FU{CB|6c46M0N1d`@+ z-%O%3s;g0MPn?!6^P{I?sn2!Wm$f$gMs0KYWrYo`MqRpP73J0x9|x!=qd=7^(V{3X zzt55@sMAREviL*vaa!Q5%Y>sNXV%hFIl$8HbOUx-2UY#TudV4gQB>WlFQ*jln%%;| zlcP8&9T_z}569gAM#NGVM@9kD@KFL;3HDY^Fct)|b8$}36eEaLr1Fr`SPehOX7$bM zk*#fp7q!vaeUTcELM8*c{KHYQtCxRT)nNB2vCqx+st{p#Dp&(@x<5~jS~7}s$OysJ z?3#SPQCkjNlUZ)Y5B1tee@G@sP14ZTNu6B;>f--vn_VHZb$Q-M?CbbQ|!)~$vizpd5@=wfOEREJAp z0=Y0oE{tfJkZX8%D@1VtdXdAJDfu=2@=K%sj=dbN#D^mE%-P%;({98>ETYIbsNczsI}smAxL7ce~*5O#-?`kkydByfj4yei&98MmCg9L zo;hlP;TW72pv?Uox)CIGznIRgGr4JujuRA0*fs zRMvzUsFnPzPF-`hqmb$pccCzP=qjyhz@E)WG+{*rxt)T^y(_UeSIx^rsik@A!lB}n z)~jFLizqLj z2j?bUqQ?T2*2jh}yzlpEIjSoxT)Rjx7~>G)Biz~Ra>qijP)vS066>1xueUlYYu`9O zPsV{r1V*~Up%V4uS!2yf!@Af9VMf-b66nIW{3a}by5P<;>lyOBaNS1KwMqGd(uDt? zR-4L891vax=5EYl?D5O3#k}t4sX5RI*=7}%(@N2p#R{pnu!s$sKt|nCJr1c&JNfNr zPz2zG^)gC(i`Q;EM1U|THwE89-JD&(c)+Nh9N&Y2r_h^Wad_9>&Dm0h&3}W}FcVU0 ih!#}2)=Tn&I3iC4$Tqk!@#W|b_ISadJzM0~4*&oTZ-5p6 literal 1812 zcmV+v2kZD!Nk&Et2LJ$9MM6+kP&gm}2LJ$YHvpXhD#!qq06&?+*JU{{Dyb*6D7?ZXOJ~Jb@>@|KXOp0)kn(YZMY@XYT;)oYvHGCn zBmNPiq9qO5PqjX6WPi#}wR>w-(GvdQ_tN(ftl;WgB|{KzN_Tdc%RPkyK&u%ZQpxS= z+mj1Ae%9A0ooFtoVmIcM(?ebPkS<21zi`Q6O(h5T$u7hCWKr~?4wgKx5L^-{o2#$0 zu#bHwtOeQdwi-`UbASZ+(&uht6K?0$*aXKw+2?ZnXAPaH=1PQxO6XWWwl-iEk(I9; zwVG(^8x=ely=UppHR2$_-}P(k$pAsI@dc}uE4S*i+O`3VnDjAVUH#KND#PyAPKdSK z+2a`UX(|57^XYTYE~U|)Gt!4_d(l16=HTq>lRVI!|CKPiNn$Uefk%;Med0o3N ze(Ed2WlAyVH>ofH{@Oo9^9FYkV=X+JbsaR`wUb(b1QvP?F)iS6&Tw%qhW*cHB@@S| zdp=gkhGe{Bf#0;TBF4g&*n1**HcVI`8XbkloPPdgu@_}DdqAWpO0CR2JdB7x6DeAi zFGMg&VRyktJC{HBX7PPqBwU1W-Kf0a5P*B&>cX(7!>~UWoH1oEaL{i1{jdg=be-SK z_k~ar8_zfn?7kUK=RH&WoN4CB#Xt3LNg?aaf`HwlxP2bkB9Z)4Ez7+)P}U7f zPbMqM2vfxHsiDhd;KDYT#eoG&Ubq zkkAqnn)@#~#+uI;mLurWCNv1te+g05UsP}&6NT=zUGP^ULHc3PTOp50=y=f~` zY9N6W1`Qlj`h(Kz*!*|279Pp)lY1Nb5&J8n{aYtWHl6t>g*?YQj&`$+YSKrJ%?}75 z&HEfes6VvB$ZIaFl zON->0oBPA420(KdA%HFPtH)La@Nv*1DOU#&Cf})aP#9oV%E4HYFv53?i!C-narKpT z2pTJhVmRQX9yMR+q42$j_*N#)I6@)oM{FEVwyB@R!H%pMj`h25%v6|)#O_yifg&6y zNCy{2RCQeL|5LQ#G&A#eIidLmUr}@=6trBDhMPnBn88b?3azH=O8irEpzR6XtchUV zG3gn*LeD16Yt&kngei6I1P3P4Gyu$9j{A#8sV2oH+sXNmZ>tv=6N~QmZ2h zIgaF_{}_L4q4ZFzWe2Rc_GV}ZsjmKLW6Ne8+eKA zc7Y@^YFo+C%La$f@n_4=Bo_uF@I1X)+5DzD&laaTJ1eX{N*zI--k9IeNNzX@sam&b zhET9}=_GA9{w`5UaE<{0*5Mt3Fz$y)dHXk+h>L_w&+ounrmM#DhfV(<{xIxvAON`0PWdwPXOr_OsD)afKc$7<6X9bu|77Jltyi)bz`F#SWZ*f zq-!Oh*9SXGpka*!(LqfM<#?Br{EvCkZ3SXwHMFB zXe%=ZfjbB&bqI}S;)}dr?`>;`>xl>gnLH?(wV5%7fa{7)a#s_4ow zV}tSF+IwcI<55GH@~G@teR=r9I4fiUPPp7@tUO7Nt%U8&!g(0&lb#DnSw z4FL^p`m+dfGvlUu&cC@2Oj6<@Ojw-Zxs2Z%yGSVBI`x80001L Cv3s)s diff --git a/src/ImageProcessorConsole/images/output/test.webp b/src/ImageProcessorConsole/images/output/test.webp deleted file mode 100644 index 549fb9c6bfaba16b8249fc25324416aa3bfa02cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5590 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 From 7a51f822d01d8e7d8542da71d374d75a50c4dd11 Mon Sep 17 00:00:00 2001 From: James South Date: Wed, 25 Jun 2014 19:15:05 +0100 Subject: [PATCH 031/155] A poor man's attempt at powershell Former-commit-id: 16299f097898120fc12e1998872db7316fa8007d --- build/NuSpecs/ImageProcessor.nuspec | 11 ++++++++--- build/tools/imageprocessor.ps1 | 12 ++++++++++++ build/tools/install.ps1 | 11 +++++++++++ build/tools/uninstall.ps1 | 9 +++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 build/tools/imageprocessor.ps1 create mode 100644 build/tools/install.ps1 create mode 100644 build/tools/uninstall.ps1 diff --git a/build/NuSpecs/ImageProcessor.nuspec b/build/NuSpecs/ImageProcessor.nuspec index 30e157086..f0d5f134e 100644 --- a/build/NuSpecs/ImageProcessor.nuspec +++ b/build/NuSpecs/ImageProcessor.nuspec @@ -22,11 +22,16 @@ Feedback is always welcome. James South en-GB Image Imaging ASP Performance Processing Resize AutoRotate Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF + + + - - - + + + + + \ No newline at end of file diff --git a/build/tools/imageprocessor.ps1 b/build/tools/imageprocessor.ps1 new file mode 100644 index 000000000..7b8be180f --- /dev/null +++ b/build/tools/imageprocessor.ps1 @@ -0,0 +1,12 @@ +$solutionDir = [System.IO.Path]::GetDirectoryName($dte.Solution.FullName) + "\" +$path = $installPath.Replace($solutionDir, "`$(SolutionDir)") + +$NativeAssembliesDir = Join-Path $path "lib" +$x86 = $(Join-Path $NativeAssembliesDir "x86\*.*") +$x64 = $(Join-Path $NativeAssembliesDir "x64\*.*") + +$ImageProcessorPostBuildCmd = " +if not exist `"`$(TargetDir)x86`" md `"`$(TargetDir)x86`" +xcopy /s /y `"$x86`" `"`$(TargetDir)x86`" +if not exist `"`$(TargetDir)amd64`" md `"`$(TargetDir)x64`" +xcopy /s /y `"$x64`" `"`$(TargetDir)x64`"" \ No newline at end of file diff --git a/build/tools/install.ps1 b/build/tools/install.ps1 new file mode 100644 index 000000000..567ea0276 --- /dev/null +++ b/build/tools/install.ps1 @@ -0,0 +1,11 @@ +param($installPath, $toolsPath, $package, $project) + +. (Join-Path $toolsPath "imageprocessor.ps1") + +# Get the current Post Build Event cmd +$currentPostBuildCmd = $project.Properties.Item("PostBuildEvent").Value + +# Append our post build command if it's not already there +if (!$currentPostBuildCmd.Contains($ImageProcessorPostBuildCmd)) { + $project.Properties.Item("PostBuildEvent").Value += $ImageProcessorPostBuildCmd +} \ No newline at end of file diff --git a/build/tools/uninstall.ps1 b/build/tools/uninstall.ps1 new file mode 100644 index 000000000..4fa6c12ca --- /dev/null +++ b/build/tools/uninstall.ps1 @@ -0,0 +1,9 @@ +param($installPath, $toolsPath, $package, $project) + +. (Join-Path $toolsPath "imageprocessor.ps1") + +# Get the current Post Build Event cmd +$currentPostBuildCmd = $project.Properties.Item("PostBuildEvent").Value + +# Remove our post build command from it (if it's there) +$project.Properties.Item("PostBuildEvent").Value = $currentPostBuildCmd.Replace($ImageProcessorPostBuildCmd, "") From 13fc8bdabc2dd1969bd61f03717227502cbc7199 Mon Sep 17 00:00:00 2001 From: James South Date: Wed, 25 Jun 2014 22:10:03 +0100 Subject: [PATCH 032/155] Yay! Nuget win! Former-commit-id: 985bf753a90ce3f31fe7b29781d6279be869044f --- build/NuSpecs/ImageProcessor.nuspec | 11 +++------ .../ImageProcessor/imageprocessor.targets | 23 ++++++++++++++----- build/tools/imageprocessor.ps1 | 12 ---------- build/tools/install.ps1 | 11 --------- build/tools/uninstall.ps1 | 9 -------- 5 files changed, 20 insertions(+), 46 deletions(-) delete mode 100644 build/tools/imageprocessor.ps1 delete mode 100644 build/tools/install.ps1 delete mode 100644 build/tools/uninstall.ps1 diff --git a/build/NuSpecs/ImageProcessor.nuspec b/build/NuSpecs/ImageProcessor.nuspec index f0d5f134e..8041f5dfc 100644 --- a/build/NuSpecs/ImageProcessor.nuspec +++ b/build/NuSpecs/ImageProcessor.nuspec @@ -22,16 +22,11 @@ Feedback is always welcome. James South en-GB Image Imaging ASP Performance Processing Resize AutoRotate Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF - - - - - - - - + + + \ No newline at end of file diff --git a/build/content/ImageProcessor/imageprocessor.targets b/build/content/ImageProcessor/imageprocessor.targets index 6922fa306..0b161e3c5 100644 --- a/build/content/ImageProcessor/imageprocessor.targets +++ b/build/content/ImageProcessor/imageprocessor.targets @@ -1,10 +1,21 @@ - - - - - - + + + + + + + + + $(PrepareForRunDependsOn); + CopyNativeBinaries + + + + + + \ No newline at end of file diff --git a/build/tools/imageprocessor.ps1 b/build/tools/imageprocessor.ps1 deleted file mode 100644 index 7b8be180f..000000000 --- a/build/tools/imageprocessor.ps1 +++ /dev/null @@ -1,12 +0,0 @@ -$solutionDir = [System.IO.Path]::GetDirectoryName($dte.Solution.FullName) + "\" -$path = $installPath.Replace($solutionDir, "`$(SolutionDir)") - -$NativeAssembliesDir = Join-Path $path "lib" -$x86 = $(Join-Path $NativeAssembliesDir "x86\*.*") -$x64 = $(Join-Path $NativeAssembliesDir "x64\*.*") - -$ImageProcessorPostBuildCmd = " -if not exist `"`$(TargetDir)x86`" md `"`$(TargetDir)x86`" -xcopy /s /y `"$x86`" `"`$(TargetDir)x86`" -if not exist `"`$(TargetDir)amd64`" md `"`$(TargetDir)x64`" -xcopy /s /y `"$x64`" `"`$(TargetDir)x64`"" \ No newline at end of file diff --git a/build/tools/install.ps1 b/build/tools/install.ps1 deleted file mode 100644 index 567ea0276..000000000 --- a/build/tools/install.ps1 +++ /dev/null @@ -1,11 +0,0 @@ -param($installPath, $toolsPath, $package, $project) - -. (Join-Path $toolsPath "imageprocessor.ps1") - -# Get the current Post Build Event cmd -$currentPostBuildCmd = $project.Properties.Item("PostBuildEvent").Value - -# Append our post build command if it's not already there -if (!$currentPostBuildCmd.Contains($ImageProcessorPostBuildCmd)) { - $project.Properties.Item("PostBuildEvent").Value += $ImageProcessorPostBuildCmd -} \ No newline at end of file diff --git a/build/tools/uninstall.ps1 b/build/tools/uninstall.ps1 deleted file mode 100644 index 4fa6c12ca..000000000 --- a/build/tools/uninstall.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -param($installPath, $toolsPath, $package, $project) - -. (Join-Path $toolsPath "imageprocessor.ps1") - -# Get the current Post Build Event cmd -$currentPostBuildCmd = $project.Properties.Item("PostBuildEvent").Value - -# Remove our post build command from it (if it's there) -$project.Properties.Item("PostBuildEvent").Value = $currentPostBuildCmd.Replace($ImageProcessorPostBuildCmd, "") From 656d51762b05122ef138ff238fa150f23f14331f Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Wed, 25 Jun 2014 23:59:37 +0200 Subject: [PATCH 033/155] Creates a new Mono project so it can at least build (not yet run) on Xamarin/Mono Former-commit-id: 96e8b233cd5d9f20c13b1691cfe2ff187c51267d --- .../HttpModules/ImageProcessingModule.cs | 4 +- .../ImageProcessorConsole.csproj | 6 +- src/ImageProcessor_Mono.sln | 132 ++++++++++++++++++ 3 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 src/ImageProcessor_Mono.sln diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index 22c03bef7..154038d54 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -125,7 +125,7 @@ namespace ImageProcessor.Web.HttpModules preserveExifMetaData = ImageProcessorConfig.Instance.PreserveExifMetaData; } -#if NET45 +#if NET45 && !__MonoCS__ EventHandlerTaskAsyncHelper wrapper = new EventHandlerTaskAsyncHelper(this.PostAuthorizeRequest); context.AddOnPostAuthorizeRequestAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler); #else @@ -194,7 +194,7 @@ namespace ImageProcessor.Web.HttpModules } #endregion -#if NET45 +#if NET45 && !__MonoCS__ /// /// Occurs when the user for the current request has been authorized. diff --git a/src/ImageProcessorConsole/ImageProcessorConsole.csproj b/src/ImageProcessorConsole/ImageProcessorConsole.csproj index 39b66751b..9cf9bf603 100644 --- a/src/ImageProcessorConsole/ImageProcessorConsole.csproj +++ b/src/ImageProcessorConsole/ImageProcessorConsole.csproj @@ -1,5 +1,5 @@  - + Debug @@ -9,7 +9,7 @@ Properties ImageProcessorConsole ImageProcessorConsole - v4.5.1 + v4.5 512 true @@ -51,7 +51,7 @@ - {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} ImageProcessor diff --git a/src/ImageProcessor_Mono.sln b/src/ImageProcessor_Mono.sln new file mode 100644 index 000000000..d7e1410a8 --- /dev/null +++ b/src/ImageProcessor_Mono.sln @@ -0,0 +1,132 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +VisualStudioVersion = 12.0.30110.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C427A497-74DC-49B1-8420-D6E68354F29B}" + ProjectSection(SolutionItems) = preProject + ImageProcessor.vsmdi = ImageProcessor.vsmdi + Local.testsettings = Local.testsettings + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E656CDE-124D-4FAF-837C-0EF1E192D418}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.Config = .nuget\NuGet.Config + .nuget\NuGet.exe = .nuget\NuGet.exe + .nuget\NuGet.targets = .nuget\NuGet.targets + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor\ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_MVC_NET4", "TestWebsites\NET4\Test_Website_MVC_NET4.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET4", "ImageProcessor.Web\NET4\ImageProcessor.Web_NET4.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", "ImageProcessor.Web\NET45\ImageProcessor.Web_NET45.csproj", "{D011A778-59C8-4BFA-A770-C350216BF161}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessorConsole", "ImageProcessorConsole\ImageProcessorConsole.csproj", "{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + All|Any CPU = All|Any CPU + All|Mixed Platforms = All|Mixed Platforms + All|x86 = All|x86 + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.ActiveCfg = All|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.Build.0 = All|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.ActiveCfg = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.Build.0 = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.ActiveCfg = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.Build.0 = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.ActiveCfg = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.Build.0 = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.Build.0 = Release|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.Build.0 = Release|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86 + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.Build.0 = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|x86.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|x86.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.Build.0 = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|x86.ActiveCfg = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.ActiveCfg = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.Build.0 = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.ActiveCfg = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.Build.0 = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|x86.ActiveCfg = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|x86.ActiveCfg = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.Build.0 = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|x86.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|x86.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|x86.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|x86.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.Build.0 = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.Build.0 = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.All|x86.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Debug|x86.ActiveCfg = Debug|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Any CPU.Build.0 = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = ImageProcessor\ImageProcessor.csproj + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = ImageProcessor.vsmdi + EndGlobalSection +EndGlobal From 6fefdb7a00e2ce91380c9bb47bcee01303a94a48 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Wed, 25 Jun 2014 23:59:58 +0200 Subject: [PATCH 034/155] Ignores Xamarin files Former-commit-id: fe9740cac43f2c1a4bf827cde89239dd6dde00fc --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 6b6928926..2fc43e4a1 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,9 @@ local.properties .builds **/*.dotCover +# Xamarin +*.userprefs + ## TODO: If you have NuGet Package Restore enabled, uncomment this packages/ From dbc3d831301183739fe4b3b712d6914d0eafcaed Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Thu, 26 Jun 2014 00:08:55 +0200 Subject: [PATCH 035/155] Removes MVC test project from Mono solution because of heavy dependencies Former-commit-id: 3e6881f9bdaa8a0f53ab4f580565f9092b27f739 --- src/ImageProcessor_Mono.sln | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/ImageProcessor_Mono.sln b/src/ImageProcessor_Mono.sln index d7e1410a8..7d47a2ca6 100644 --- a/src/ImageProcessor_Mono.sln +++ b/src/ImageProcessor_Mono.sln @@ -18,8 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E656C EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor\ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_MVC_NET4", "TestWebsites\NET4\Test_Website_MVC_NET4.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET4", "ImageProcessor.Web\NET4\ImageProcessor.Web_NET4.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", "ImageProcessor.Web\NET45\ImageProcessor.Web_NET45.csproj", "{D011A778-59C8-4BFA-A770-C350216BF161}" @@ -39,24 +37,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.ActiveCfg = All|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.Build.0 = All|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.ActiveCfg = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.Build.0 = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.ActiveCfg = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.Build.0 = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.Build.0 = Debug|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.ActiveCfg = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.Build.0 = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.ActiveCfg = Release|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.Build.0 = Release|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.Build.0 = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86 {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU From b2cb7bc4dbcc6ad4017ae6d666dfc521fa72e45b Mon Sep 17 00:00:00 2001 From: James South Date: Wed, 25 Jun 2014 23:50:23 +0100 Subject: [PATCH 036/155] Fixing issue #59 Former-commit-id: ac374bb3f3acd7ff84cde23959bcfa134f79dbae --- src/ImageProcessor.Web/NET45/Caching/DiskCache.cs | 6 +++--- .../NET45/Configuration/ImageProcessingSection.cs | 4 ++-- .../NET45/Configuration/ImageProcessorConfiguration.cs | 4 ++-- src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs | 2 +- src/ImageProcessor.Web/NET45/Processors/Crop.cs | 2 +- src/ImageProcessor.Web/NET45/Processors/Saturation.cs | 2 +- src/ImageProcessor/Imaging/ExifPropertyTag.cs | 2 +- src/ImageProcessor/Imaging/ExifPropertyTagType.cs | 4 ++-- src/ImageProcessor/Imaging/Formats/FormatUtilities.cs | 2 +- src/ImageProcessor/Imaging/Formats/GifEncoder.cs | 4 ++-- src/ImageProcessor/Imaging/Formats/GifInfo.cs | 4 ++-- src/ImageProcessor/Imaging/Formats/WebPFormat.cs | 4 ++-- src/ImageProcessor/Processors/Rotate.cs | 2 +- src/ImageProcessor/Processors/Saturation.cs | 2 +- 14 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs index 23612916b..f1cefc657 100644 --- a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs @@ -42,9 +42,9 @@ namespace ImageProcessor.Web.Caching /// /// NTFS directories can handle up to 10,000 files in the directory before slowing down. /// This will help us to ensure that don't go over that limit. - /// - /// - /// + /// + /// + /// /// private const int MaxFilesCount = 100; diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs index 3942280f6..3332080b9 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs @@ -5,7 +5,7 @@ // // // Represents an image processing section within a configuration file. -// Nested syntax adapted from +// Nested syntax adapted from // // -------------------------------------------------------------------------------------------------------------------- @@ -21,7 +21,7 @@ namespace ImageProcessor.Web.Configuration /// /// Represents an image processing section within a configuration file. - /// Nested syntax adapted from + /// Nested syntax adapted from /// public sealed class ImageProcessingSection : ConfigurationSection { diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs index e871a5c35..be4966966 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs @@ -5,7 +5,7 @@ // // // Encapsulates methods to allow the retrieval of ImageProcessor settings. -// +// // // -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Web.Configuration @@ -24,7 +24,7 @@ namespace ImageProcessor.Web.Configuration /// /// Encapsulates methods to allow the retrieval of ImageProcessor settings. - /// + /// /// public sealed class ImageProcessorConfiguration { diff --git a/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs b/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs index 1fa38568c..6845d8453 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs @@ -40,7 +40,7 @@ namespace ImageProcessor.Web.Helpers /// There shouldn't be any security issues there, as the internal WebRequest instance is still calling it remotely. /// Any local files that shouldn't be accessed by this won't be allowed by the remote call. /// - /// Adapted from BlogEngine.Net + /// Adapted from BlogEngine.Net /// internal sealed class RemoteFile { diff --git a/src/ImageProcessor.Web/NET45/Processors/Crop.cs b/src/ImageProcessor.Web/NET45/Processors/Crop.cs index 372d277c3..c621ebd1a 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Crop.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Crop.cs @@ -24,7 +24,7 @@ namespace ImageProcessor.Web.Processors { /// /// The regular expression to search strings for. - /// + /// /// private static readonly Regex QueryRegex = new Regex(@"(crop=|cropmode=)[^&]+", RegexOptions.Compiled); diff --git a/src/ImageProcessor.Web/NET45/Processors/Saturation.cs b/src/ImageProcessor.Web/NET45/Processors/Saturation.cs index 3a98bde7e..02a750ab1 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Saturation.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Saturation.cs @@ -18,7 +18,7 @@ namespace ImageProcessor.Web.Processors /// Encapsulates methods to change the saturation component of the image. /// /// - /// + /// /// public class Saturation : IWebGraphicsProcessor { diff --git a/src/ImageProcessor/Imaging/ExifPropertyTag.cs b/src/ImageProcessor/Imaging/ExifPropertyTag.cs index 3af48741d..3e714d03c 100644 --- a/src/ImageProcessor/Imaging/ExifPropertyTag.cs +++ b/src/ImageProcessor/Imaging/ExifPropertyTag.cs @@ -12,7 +12,7 @@ namespace ImageProcessor.Imaging { /// /// The following enum gives descriptions of the property items supported by Windows GDI+. - /// + /// /// TODO: Add more XML descriptions. /// public enum ExifPropertyTag diff --git a/src/ImageProcessor/Imaging/ExifPropertyTagType.cs b/src/ImageProcessor/Imaging/ExifPropertyTagType.cs index 2c3a1b352..1d0d470f7 100644 --- a/src/ImageProcessor/Imaging/ExifPropertyTagType.cs +++ b/src/ImageProcessor/Imaging/ExifPropertyTagType.cs @@ -5,7 +5,7 @@ // // // Specifies the data type of the values stored in the value data member of that same PropertyItem object. -// +// // // -------------------------------------------------------------------------------------------------------------------- @@ -13,7 +13,7 @@ namespace ImageProcessor.Imaging { /// /// Specifies the data type of the values stored in the value data member of that same PropertyItem object. - /// + /// /// public enum ExifPropertyTagType : short { diff --git a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs index a382e6449..36d2e3c07 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs @@ -27,7 +27,7 @@ namespace ImageProcessor.Imaging.Formats { /// /// Gets the correct from the given stream. - /// + /// /// /// /// The to read from. diff --git a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs index d667f35f5..612a453bf 100644 --- a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs +++ b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs @@ -9,7 +9,7 @@ // Always wire this up in a using block. // Disposing the encoder will complete the file. // Uses default .NET GIF encoding and adds animation headers. -// Adapted from +// Adapted from // // // -------------------------------------------------------------------------------------------------------------------- @@ -27,7 +27,7 @@ namespace ImageProcessor.Imaging.Formats /// Always wire this up in a using block. /// Disposing the encoder will complete the file. /// Uses default .NET GIF encoding and adds animation headers. - /// Adapted from + /// Adapted from /// /// public class GifEncoder : IDisposable diff --git a/src/ImageProcessor/Imaging/Formats/GifInfo.cs b/src/ImageProcessor/Imaging/Formats/GifInfo.cs index c0b75bae3..2fdc1d715 100644 --- a/src/ImageProcessor/Imaging/Formats/GifInfo.cs +++ b/src/ImageProcessor/Imaging/Formats/GifInfo.cs @@ -5,7 +5,7 @@ // // // Provides information about an image. -// +// // // -------------------------------------------------------------------------------------------------------------------- @@ -16,7 +16,7 @@ namespace ImageProcessor.Imaging.Formats /// /// Provides information about an image. - /// + /// /// public class GifInfo { diff --git a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs index 1617d37be..25b0205e3 100644 --- a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs @@ -5,7 +5,7 @@ // // // Provides the necessary information to support webp images. -// Adapted from +// Adapted from // by Jose M. Piñeiro // // -------------------------------------------------------------------------------------------------------------------- @@ -25,7 +25,7 @@ namespace ImageProcessor.Imaging.Formats /// /// Provides the necessary information to support webp images. - /// Adapted from + /// Adapted from /// by Jose M. Piñeiro /// [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")] diff --git a/src/ImageProcessor/Processors/Rotate.cs b/src/ImageProcessor/Processors/Rotate.cs index 70fabd1cc..2e5931dcc 100644 --- a/src/ImageProcessor/Processors/Rotate.cs +++ b/src/ImageProcessor/Processors/Rotate.cs @@ -100,7 +100,7 @@ namespace ImageProcessor.Processors /// The angle in degrees at which to rotate the image. /// The image rotated to the given angle at the given position. /// - /// Based on + /// Based on /// private Bitmap RotateImage(Image image, float rotateAtX, float rotateAtY, float angle) { diff --git a/src/ImageProcessor/Processors/Saturation.cs b/src/ImageProcessor/Processors/Saturation.cs index b8d2a0819..341d287f3 100644 --- a/src/ImageProcessor/Processors/Saturation.cs +++ b/src/ImageProcessor/Processors/Saturation.cs @@ -21,7 +21,7 @@ namespace ImageProcessor.Processors /// Encapsulates methods to change the saturation component of the image. /// /// - /// + /// /// public class Saturation : IGraphicsProcessor { From 0121106933860eb812ebbe70dd9533f4865dc385 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 26 Jun 2014 13:57:03 +0100 Subject: [PATCH 037/155] Fixing embedded resource reference Former-commit-id: c735cd18a0a6f6b73bc98bcae1c32cd6e04cbd38 --- .../NET45/Configuration/ImageCacheSection.cs | 2 +- .../NET45/Configuration/ImageProcessingSection.cs | 2 +- .../NET45/Configuration/ImageSecuritySection.cs | 2 +- src/TestWebsites/NET45/Test_Website_NET45/Web.config | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs index 04a550729..8e5abad95 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs @@ -79,7 +79,7 @@ namespace ImageProcessor.Web.Configuration return imageCacheSection; } - string section = ResourceHelpers.ResourceAsString("ImageProcessor.Web.Config.Resources.cache.config"); + string section = ResourceHelpers.ResourceAsString("ImageProcessor.Web.Configuration.Resources.cache.config"); XmlReader reader = new XmlTextReader(new StringReader(section)); imageCacheSection = new ImageCacheSection(); imageCacheSection.DeserializeSection(reader); diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs index 3332080b9..23f8bc9ca 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs @@ -83,7 +83,7 @@ namespace ImageProcessor.Web.Configuration return imageProcessingSection; } - string section = ResourceHelpers.ResourceAsString("ImageProcessor.Web.Config.Resources.processing.config"); + string section = ResourceHelpers.ResourceAsString("ImageProcessor.Web.Configuration.Resources.processing.config"); XmlReader reader = new XmlTextReader(new StringReader(section)); imageProcessingSection = new ImageProcessingSection(); imageProcessingSection.DeserializeSection(reader); diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageSecuritySection.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageSecuritySection.cs index 29079fdc2..c58b07579 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageSecuritySection.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageSecuritySection.cs @@ -116,7 +116,7 @@ namespace ImageProcessor.Web.Configuration return imageSecuritySection; } - string section = ResourceHelpers.ResourceAsString("ImageProcessor.Web.Config.Resources.security.config"); + string section = ResourceHelpers.ResourceAsString("ImageProcessor.Web.Configuration.Resources.security.config"); XmlReader reader = new XmlTextReader(new StringReader(section)); imageSecuritySection = new ImageSecuritySection(); imageSecuritySection.DeserializeSection(reader); diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Web.config b/src/TestWebsites/NET45/Test_Website_NET45/Web.config index 7f87cedd1..1b2a7cfde 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/Web.config +++ b/src/TestWebsites/NET45/Test_Website_NET45/Web.config @@ -6,17 +6,17 @@ - + - + From 92bfcac7929d2ffa81ad77a3b89e44842c025a47 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 26 Jun 2014 22:30:08 +0100 Subject: [PATCH 038/155] Separating Unit Tests Hopefully rebuilding the projects will fix the AppVeyor issues. Former-commit-id: 2beec9222b2fc35ed26d6bbd6b6b12bd2a95f780 --- .../ImageProcessor.UnitTests.csproj | 282 ++++++++++-------- .../Properties/AssemblyInfo.cs | 36 +++ src/ImageProcessor.UnitTests/packages.config | 2 +- .../ImageProcessor.Web.UnitTests.csproj | 106 +++++++ .../Properties/AssemblyInfo.cs | 36 +++ .../RegularExpressionUnitTests.cs | 26 +- .../packages.config | 4 + src/ImageProcessor.sln | 182 +++++------ src/packages/repositories.config | 2 + 9 files changed, 458 insertions(+), 218 deletions(-) create mode 100644 src/ImageProcessor.UnitTests/Properties/AssemblyInfo.cs create mode 100644 src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj create mode 100644 src/ImageProcessor.Web.UnitTests/Properties/AssemblyInfo.cs rename src/{ImageProcessor.UnitTests => ImageProcessor.Web.UnitTests}/RegularExpressionUnitTests.cs (87%) create mode 100644 src/ImageProcessor.Web.UnitTests/packages.config diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index afce9a1d2..2be742cb4 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -1,178 +1,215 @@  - + Debug AnyCPU - {03CA9055-F997-428C-BF28-F50F991777C6} + {633B1C4C-4823-47BE-9A01-A665F3118C8C} Library + Properties ImageProcessor.UnitTests ImageProcessor.UnitTests - - + v4.0 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest ..\ true - v4.5 + true full false - bin\Debug - DEBUG; + bin\Debug\ + DEBUG;TRACE prompt 4 - false - false - full + pdbonly true - bin\Release + bin\Release\ + TRACE prompt 4 - false - false - - ..\packages\NUnit.2.6.3\lib\nunit.framework.dll - - + + + + + + + + + + - + - - - {d011a778-59c8-4bfa-a770-c350216bf161} - ImageProcessor.Web_NET45 - - - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} - ImageProcessor - + - - + + Images\1182076_e8c402e938_z.jpg + + + Images\bus.jpg + + Images\Chrysanthemum.jpg - PreserveNewest - - + + + Images\circle.png + + + Images\cmyk.jpg + + + Images\cmyk.png + + + Images\color-vision-test.gif + + Images\Desert.jpg - PreserveNewest - - + + + Images\emma.jpg + + + Images\falahill_design__160p.jpg + + + Images\fid11246.jpg + + + Images\fid9141.jpg + + + Images\header_1.jpg + + Images\Hydrangeas.jpg - PreserveNewest - - + + Images\Jellyfish.jpg - PreserveNewest - - + + + Images\jrt.jpg + + Images\Koala.jpg - PreserveNewest - - + + Images\Lighthouse.jpg - PreserveNewest - - + + + Images\lomo.jpg + + + Images\meter.gif + + + Images\negative.png + + + Images\negative2.png + + Images\Penguins-200.jpg - PreserveNewest - - + + Images\Penguins-8.png - PreserveNewest - - + + Images\Penguins.bmp - PreserveNewest - - + + Images\Penguins.gif - PreserveNewest - - + + Images\Penguins.jpg - PreserveNewest - - + + Images\Penguins.png - PreserveNewest - - + + Images\Penguins.tif - PreserveNewest - - - Images\Tulips.jpg - PreserveNewest - - - Images\bus.jpg - PreserveNewest - - - Images\cmyk.jpg - PreserveNewest - - - Images\cmyk.png - PreserveNewest - - - Images\jrt.jpg - PreserveNewest - - - Images\meter.gif - PreserveNewest - - + + Images\rocks.jpg - PreserveNewest - - + + Images\rotate.jpg - PreserveNewest - - + + Images\sample1.jpg - PreserveNewest - - + + Images\srgb.jpg - PreserveNewest - - + + Images\srgb.png - PreserveNewest - - + + Images\text.png - PreserveNewest - - + + Images\thor.jpg - PreserveNewest - - + + + Images\Tulips.jpg + + Images\udendørs-374.jpg - PreserveNewest - - + + Images\udendørs.jpg - PreserveNewest - + + + Images\war_horse_quad.jpg + + + Images\WP_000009.jpg + - + + + {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} + ImageProcessor + + + + + + + False + + + False + + + False + + + False + + + + + + @@ -180,4 +217,11 @@ + \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Properties/AssemblyInfo.cs b/src/ImageProcessor.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..fb042a1d3 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ImageProcessor.UnitTests2")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ImageProcessor.UnitTests2")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3003f5a6-eb11-4eee-bfaa-448deb3a31d9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// 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.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/ImageProcessor.UnitTests/packages.config b/src/ImageProcessor.UnitTests/packages.config index 5a3253fcb..a18b325a4 100644 --- a/src/ImageProcessor.UnitTests/packages.config +++ b/src/ImageProcessor.UnitTests/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj new file mode 100644 index 000000000..17c54d202 --- /dev/null +++ b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj @@ -0,0 +1,106 @@ + + + + Debug + AnyCPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260} + Library + Properties + ImageProcessor.Web.UnitTests + ImageProcessor.Web.UnitTests + v4.5.1 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + ..\packages\NUnit.2.6.3\lib\nunit.framework.dll + + + + + + + + + + + + + + + + + + + + + + {d011a778-59c8-4bfa-a770-c350216bf161} + ImageProcessor.Web_NET45 + + + {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} + ImageProcessor + + + + + + + False + + + False + + + False + + + False + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/src/ImageProcessor.Web.UnitTests/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..db6aa3c94 --- /dev/null +++ b/src/ImageProcessor.Web.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ImageProcessor.Web.UnitTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ImageProcessor.Web.UnitTests")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("74919969-6a75-4d26-b1b8-0626aa10af6d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// 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.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/ImageProcessor.UnitTests/RegularExpressionUnitTests.cs b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs similarity index 87% rename from src/ImageProcessor.UnitTests/RegularExpressionUnitTests.cs rename to src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs index 417e94f8c..c41454563 100644 --- a/src/ImageProcessor.UnitTests/RegularExpressionUnitTests.cs +++ b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs @@ -8,7 +8,7 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.UnitTests +namespace ImageProcessor.Web.UnitTests { using System.Drawing; using ImageProcessor.Imaging; @@ -31,7 +31,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "alpha=56"; const int Expected = 56; - Web.Processors.Alpha alpha = new Web.Processors.Alpha(); + Processors.Alpha alpha = new Processors.Alpha(); alpha.MatchRegexIndex(Querystring); int actual = alpha.Processor.DynamicParameter; @@ -48,7 +48,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "brightness=56"; const int Expected = 56; - Web.Processors.Brightness brightness = new Web.Processors.Brightness(); + Processors.Brightness brightness = new Processors.Brightness(); brightness.MatchRegexIndex(Querystring); int actual = brightness.Processor.DynamicParameter; @@ -65,7 +65,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "contrast=56"; const int Expected = 56; - Web.Processors.Contrast contrast = new Web.Processors.Contrast(); + Processors.Contrast contrast = new Processors.Contrast(); contrast.MatchRegexIndex(Querystring); int actual = contrast.Processor.DynamicParameter; @@ -82,7 +82,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "crop=0,0,150,300"; CropLayer expected = new CropLayer(0, 0, 150, 300, CropMode.Pixels); - Web.Processors.Crop crop = new Web.Processors.Crop(); + Processors.Crop crop = new Processors.Crop(); crop.MatchRegexIndex(Querystring); CropLayer actual = crop.Processor.DynamicParameter; @@ -99,7 +99,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "filter=lomograph"; IMatrixFilter expected = MatrixFilters.Lomograph; - Web.Processors.Filter filter = new Web.Processors.Filter(); + Processors.Filter filter = new Processors.Filter(); filter.MatchRegexIndex(Querystring); IMatrixFilter actual = filter.Processor.DynamicParameter; @@ -116,7 +116,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "format=gif"; ISupportedImageFormat expected = new GifFormat(); - Web.Processors.Format format = new Web.Processors.Format(); + Processors.Format format = new Processors.Format(); format.MatchRegexIndex(Querystring); ISupportedImageFormat actual = format.Processor.DynamicParameter; @@ -133,7 +133,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "quality=56"; const int Expected = 56; - Web.Processors.Quality quality = new Web.Processors.Quality(); + Processors.Quality quality = new Processors.Quality(); quality.MatchRegexIndex(Querystring); int actual = quality.Processor.DynamicParameter; @@ -150,7 +150,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "width=300"; ResizeLayer expected = new ResizeLayer(new Size(300, 0)); - Web.Processors.Resize resize = new Web.Processors.Resize(); + Processors.Resize resize = new Processors.Resize(); resize.MatchRegexIndex(Querystring); ResizeLayer actual = resize.Processor.DynamicParameter; @@ -167,7 +167,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "rotate=270"; const int Expected = 270; - Web.Processors.Rotate rotate = new Web.Processors.Rotate(); + Processors.Rotate rotate = new Processors.Rotate(); rotate.MatchRegexIndex(Querystring); int actual = rotate.Processor.DynamicParameter; @@ -183,7 +183,7 @@ namespace ImageProcessor.UnitTests { const string Querystring = "roundedcorners=30"; RoundedCornerLayer expected = new RoundedCornerLayer(30, true, true, true, true); - Web.Processors.RoundedCorners roundedCorners = new Web.Processors.RoundedCorners(); + Processors.RoundedCorners roundedCorners = new Processors.RoundedCorners(); roundedCorners.MatchRegexIndex(Querystring); RoundedCornerLayer actual = roundedCorners.Processor.DynamicParameter; @@ -202,12 +202,12 @@ namespace ImageProcessor.UnitTests Color expectedHex = ColorTranslator.FromHtml("#" + "6aa6cc"); Color expectedRgba = Color.FromArgb(255, 106, 166, 204); - Web.Processors.Tint tint = new Web.Processors.Tint(); + Processors.Tint tint = new Processors.Tint(); tint.MatchRegexIndex(HexQuerystring); Color actualHex = tint.Processor.DynamicParameter; Assert.AreEqual(expectedHex, actualHex); - tint = new Web.Processors.Tint(); + tint = new Processors.Tint(); tint.MatchRegexIndex(RgbaQuerystring); Color actualRgba = tint.Processor.DynamicParameter; Assert.AreEqual(expectedRgba, actualRgba); diff --git a/src/ImageProcessor.Web.UnitTests/packages.config b/src/ImageProcessor.Web.UnitTests/packages.config new file mode 100644 index 000000000..139d5138c --- /dev/null +++ b/src/ImageProcessor.Web.UnitTests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/ImageProcessor.sln b/src/ImageProcessor.sln index 186a446c7..a12d17c68 100644 --- a/src/ImageProcessor.sln +++ b/src/ImageProcessor.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -VisualStudioVersion = 12.0.30110.0 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C427A497-74DC-49B1-8420-D6E68354F29B}" ProjectSection(SolutionItems) = preProject @@ -32,7 +32,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_Webforms_NET45 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessorConsole", "ImageProcessorConsole\ImageProcessorConsole.csproj", "{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.UnitTests", "ImageProcessor.UnitTests\ImageProcessor.UnitTests.csproj", "{03CA9055-F997-428C-BF28-F50F991777C6}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web.UnitTests", "ImageProcessor.Web.UnitTests\ImageProcessor.Web.UnitTests.csproj", "{961340C8-8C93-401D-A0A2-FF9EC61E5260}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.UnitTests", "ImageProcessor.UnitTests\ImageProcessor.UnitTests.csproj", "{633B1C4C-4823-47BE-9A01-A665F3118C8C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -47,24 +49,21 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {03CA9055-F997-428C-BF28-F50F991777C6}.All|Any CPU.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.All|Any CPU.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.All|Mixed Platforms.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.All|Mixed Platforms.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.All|x86.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.All|x86.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|x86.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|x86.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Any CPU.Build.0 = Release|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|x86.ActiveCfg = Release|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|x86.Build.0 = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.Build.0 = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|x86.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|x86.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.Build.0 = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|x86.ActiveCfg = Release|Any CPU {23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.All|Any CPU.ActiveCfg = Release|Any CPU {23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.All|Any CPU.Build.0 = Release|Any CPU {23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.All|Mixed Platforms.ActiveCfg = Release|Any CPU @@ -97,21 +96,21 @@ Global {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.Build.0 = Release|x86 {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86 {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86 - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.Build.0 = All|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|x86.ActiveCfg = All|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|x86.ActiveCfg = Debug|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.Build.0 = Release|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|x86.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.Build.0 = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.Build.0 = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|x86.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|x86.ActiveCfg = Debug|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Any CPU.Build.0 = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|x86.ActiveCfg = Release|Any CPU {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.ActiveCfg = All|Any CPU {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.Build.0 = All|Any CPU {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.ActiveCfg = All|Any CPU @@ -127,36 +126,6 @@ Global {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.Build.0 = Release|Any CPU {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|x86.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.Build.0 = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.Build.0 = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|x86.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|x86.ActiveCfg = Debug|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.Build.0 = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|x86.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Any CPU.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Any CPU.Build.0 = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Mixed Platforms.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Mixed Platforms.Build.0 = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|x86.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|x86.ActiveCfg = Debug|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Any CPU.Build.0 = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|x86.ActiveCfg = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.ActiveCfg = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.Build.0 = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.ActiveCfg = Release|Any CPU @@ -172,30 +141,73 @@ Global {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.Build.0 = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.Release|x86.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.Build.0 = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.Build.0 = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|x86.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|x86.ActiveCfg = Debug|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Any CPU.Build.0 = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|x86.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Any CPU.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Any CPU.Build.0 = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Mixed Platforms.Build.0 = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|x86.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|x86.ActiveCfg = Debug|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Any CPU.Build.0 = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|x86.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|x86.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|x86.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|x86.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.All|Any CPU.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.All|Any CPU.Build.0 = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.All|Mixed Platforms.Build.0 = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.All|x86.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Debug|Any CPU.Build.0 = Debug|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Debug|x86.ActiveCfg = Debug|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Release|Any CPU.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Release|Any CPU.Build.0 = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Release|x86.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.All|Any CPU.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.All|Any CPU.Build.0 = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.All|Mixed Platforms.Build.0 = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.All|x86.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Debug|x86.ActiveCfg = Debug|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Any CPU.Build.0 = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection - GlobalSection(NestedProjects) = preSolution + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = ImageProcessorConsole\ImageProcessorConsole.csproj EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = ImageProcessor.vsmdi EndGlobalSection diff --git a/src/packages/repositories.config b/src/packages/repositories.config index 73ccce20c..14108b962 100644 --- a/src/packages/repositories.config +++ b/src/packages/repositories.config @@ -1,6 +1,8 @@  + + From 7a7a36c520ffd379d53de8d03a421b02c29b1972 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 26 Jun 2014 22:59:30 +0100 Subject: [PATCH 039/155] Moving Images in unit test Former-commit-id: 2df5d6efd190867743f5a3f13ee70bc11257e614 --- .../ImageFactoryUnitTests.cs | 2 +- .../ImageProcessor.UnitTests.csproj | 133 ++---------------- .../Images/Chrysanthemum.jpg.REMOVED.git-id | 1 + .../Images/Desert.jpg.REMOVED.git-id | 1 + .../Images/Penguins.bmp.REMOVED.git-id | 1 + .../Images/Penguins.gif.REMOVED.git-id | 1 + .../Images/cmyk.png.REMOVED.git-id | 1 + 7 files changed, 14 insertions(+), 126 deletions(-) create mode 100644 src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 940702f9c..a63f95ff2 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -42,7 +42,7 @@ namespace ImageProcessor.UnitTests [TestCase("Penguins.gif", "image/gif")] public void TestLoadImageFromFile(string fileName, string expectedMime) { - var testPhoto = Path.Combine(this.localPath, string.Format("Images/{0}", fileName)); + string testPhoto = Path.Combine(this.localPath, string.Format("../../Images/{0}", fileName)); using (ImageFactory imageFactory = new ImageFactory()) { imageFactory.Load(testPhoto); diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 2be742cb4..81516b4b6 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -59,137 +59,20 @@ - - - Images\1182076_e8c402e938_z.jpg - - - Images\bus.jpg - - - Images\Chrysanthemum.jpg - - - Images\circle.png - - - Images\cmyk.jpg - - - Images\cmyk.png - - - Images\color-vision-test.gif - - - Images\Desert.jpg - - - Images\emma.jpg - - - Images\falahill_design__160p.jpg - - - Images\fid11246.jpg - - - Images\fid9141.jpg - - - Images\header_1.jpg - - - Images\Hydrangeas.jpg - - - Images\Jellyfish.jpg - - - Images\jrt.jpg - - - Images\Koala.jpg - - - Images\Lighthouse.jpg - - - Images\lomo.jpg - - - Images\meter.gif - - - Images\negative.png - - - Images\negative2.png - - - Images\Penguins-200.jpg - - - Images\Penguins-8.png - - - Images\Penguins.bmp - - - Images\Penguins.gif - - - Images\Penguins.jpg - - - Images\Penguins.png - - - Images\Penguins.tif - - - Images\rocks.jpg - - - Images\rotate.jpg - - - Images\sample1.jpg - - - Images\srgb.jpg - - - Images\srgb.png - - - Images\text.png - - - Images\thor.jpg - - - Images\Tulips.jpg - - - Images\udendørs-374.jpg - - - Images\udendørs.jpg - - - Images\war_horse_quad.jpg - - - Images\WP_000009.jpg - - {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} ImageProcessor + + + + + + + + diff --git a/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id new file mode 100644 index 000000000..d067665c9 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id @@ -0,0 +1 @@ +757c2a628dd03b1cbe4b3ef07c153897a702b57a \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id new file mode 100644 index 000000000..228aac3ab --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id @@ -0,0 +1 @@ +0b88c91336ff8073f34d21ccd683a01f0e0995da \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id new file mode 100644 index 000000000..74f69293c --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id @@ -0,0 +1 @@ +8150b46ab27c62ba51aaba551eef3f1a30f08de9 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id new file mode 100644 index 000000000..ce873d473 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id @@ -0,0 +1 @@ +6ad3b846d4697584ff601ac481b14a4d3bbb5736 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id new file mode 100644 index 000000000..aeca7b93c --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id @@ -0,0 +1 @@ +db4d55a332254cd6b41336c06f207682bf5a966f \ No newline at end of file From dd7ee325670a770bb9a502b5809ca2cc5213c0f6 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 26 Jun 2014 23:31:00 +0100 Subject: [PATCH 040/155] No client profile in NET 4.5+ http://msdn.microsoft.com/en-us/library/cc656912(v=vs.110).aspx Former-commit-id: 762f547b5b64681e0ec0cd383d5bfd30f9c6de71 --- src/ImageProcessorConsole/App.config | 6 +++--- src/ImageProcessorConsole/ImageProcessorConsole.csproj | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ImageProcessorConsole/App.config b/src/ImageProcessorConsole/App.config index 9c05822ff..d1428ad71 100644 --- a/src/ImageProcessorConsole/App.config +++ b/src/ImageProcessorConsole/App.config @@ -1,6 +1,6 @@ - + - + - \ No newline at end of file + diff --git a/src/ImageProcessorConsole/ImageProcessorConsole.csproj b/src/ImageProcessorConsole/ImageProcessorConsole.csproj index df60cf14b..fba366b0c 100644 --- a/src/ImageProcessorConsole/ImageProcessorConsole.csproj +++ b/src/ImageProcessorConsole/ImageProcessorConsole.csproj @@ -1,5 +1,5 @@  - + Debug @@ -12,7 +12,8 @@ v4.5 512 true - Client + + AnyCPU From 65f06da1bf9328a64fbaa70265bfb4ce51c141f5 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Wed, 25 Jun 2014 23:59:37 +0200 Subject: [PATCH 041/155] Creates a new Mono project so it can at least build (not yet run) on Xamarin/Mono Former-commit-id: b625d699fc6c68456157f8509e8e219d67c6c204 --- .../HttpModules/ImageProcessingModule.cs | 4 +- .../ImageProcessorConsole.csproj | 1 + src/ImageProcessor_Mono.sln | 132 ++++++++++++++++++ 3 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 src/ImageProcessor_Mono.sln diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index 67f3aee5d..33877e15b 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -126,7 +126,7 @@ namespace ImageProcessor.Web.HttpModules preserveExifMetaData = ImageProcessorConfiguration.Instance.PreserveExifMetaData; } -#if NET45 +#if NET45 && !__MonoCS__ EventHandlerTaskAsyncHelper wrapper = new EventHandlerTaskAsyncHelper(this.PostAuthorizeRequest); context.AddOnPostAuthorizeRequestAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler); #else @@ -194,7 +194,7 @@ namespace ImageProcessor.Web.HttpModules } #endregion -#if NET45 +#if NET45 && !__MonoCS__ /// /// Occurs when the user for the current request has been authorized. diff --git a/src/ImageProcessorConsole/ImageProcessorConsole.csproj b/src/ImageProcessorConsole/ImageProcessorConsole.csproj index 09423698e..df60cf14b 100644 --- a/src/ImageProcessorConsole/ImageProcessorConsole.csproj +++ b/src/ImageProcessorConsole/ImageProcessorConsole.csproj @@ -9,6 +9,7 @@ Properties ImageProcessorConsole ImageProcessorConsole + v4.5 512 true Client diff --git a/src/ImageProcessor_Mono.sln b/src/ImageProcessor_Mono.sln new file mode 100644 index 000000000..d7e1410a8 --- /dev/null +++ b/src/ImageProcessor_Mono.sln @@ -0,0 +1,132 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +VisualStudioVersion = 12.0.30110.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C427A497-74DC-49B1-8420-D6E68354F29B}" + ProjectSection(SolutionItems) = preProject + ImageProcessor.vsmdi = ImageProcessor.vsmdi + Local.testsettings = Local.testsettings + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E656CDE-124D-4FAF-837C-0EF1E192D418}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.Config = .nuget\NuGet.Config + .nuget\NuGet.exe = .nuget\NuGet.exe + .nuget\NuGet.targets = .nuget\NuGet.targets + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor\ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_MVC_NET4", "TestWebsites\NET4\Test_Website_MVC_NET4.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET4", "ImageProcessor.Web\NET4\ImageProcessor.Web_NET4.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", "ImageProcessor.Web\NET45\ImageProcessor.Web_NET45.csproj", "{D011A778-59C8-4BFA-A770-C350216BF161}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessorConsole", "ImageProcessorConsole\ImageProcessorConsole.csproj", "{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + All|Any CPU = All|Any CPU + All|Mixed Platforms = All|Mixed Platforms + All|x86 = All|x86 + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.ActiveCfg = All|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.Build.0 = All|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.ActiveCfg = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.Build.0 = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.ActiveCfg = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.Build.0 = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.ActiveCfg = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.Build.0 = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.Build.0 = Release|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.Build.0 = Release|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86 + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.Build.0 = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|x86.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|x86.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.Build.0 = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|x86.ActiveCfg = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.ActiveCfg = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.Build.0 = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.ActiveCfg = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.Build.0 = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|x86.ActiveCfg = All|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|x86.ActiveCfg = Debug|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.Build.0 = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|x86.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|x86.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|x86.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|x86.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.Build.0 = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.Build.0 = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.All|x86.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Debug|x86.ActiveCfg = Debug|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Any CPU.Build.0 = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D011A778-59C8-4BFA-A770-C350216BF161}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = ImageProcessor\ImageProcessor.csproj + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = ImageProcessor.vsmdi + EndGlobalSection +EndGlobal From afddc3e659dbfe014ff33076ff75909ed077cf9b Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Thu, 26 Jun 2014 00:08:55 +0200 Subject: [PATCH 042/155] Removes MVC test project from Mono solution because of heavy dependencies Former-commit-id: 659283d5017efeda799e0bf5227ed07e2ce41c15 --- src/ImageProcessor_Mono.sln | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/ImageProcessor_Mono.sln b/src/ImageProcessor_Mono.sln index d7e1410a8..7d47a2ca6 100644 --- a/src/ImageProcessor_Mono.sln +++ b/src/ImageProcessor_Mono.sln @@ -18,8 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E656C EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor\ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_MVC_NET4", "TestWebsites\NET4\Test_Website_MVC_NET4.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET4", "ImageProcessor.Web\NET4\ImageProcessor.Web_NET4.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", "ImageProcessor.Web\NET45\ImageProcessor.Web_NET45.csproj", "{D011A778-59C8-4BFA-A770-C350216BF161}" @@ -39,24 +37,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.ActiveCfg = All|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.Build.0 = All|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.ActiveCfg = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.Build.0 = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.ActiveCfg = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.Build.0 = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.Build.0 = Debug|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.ActiveCfg = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.Build.0 = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.ActiveCfg = Release|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.Build.0 = Release|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.Build.0 = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86 {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU From bdfd4a1c49cbd8249b50a353b61118bf69c57b84 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 26 Jun 2014 22:30:08 +0100 Subject: [PATCH 043/155] Separating Unit Tests Hopefully rebuilding the projects will fix the AppVeyor issues. Former-commit-id: 3fe1413372e450bc1a33be212c36687cd85d7678 --- .../ImageProcessor.UnitTests.csproj | 282 ++++++++++-------- .../Properties/AssemblyInfo.cs | 36 +++ src/ImageProcessor.UnitTests/packages.config | 2 +- .../ImageProcessor.Web.UnitTests.csproj | 106 +++++++ .../Properties/AssemblyInfo.cs | 36 +++ .../RegularExpressionUnitTests.cs | 26 +- .../packages.config | 4 + src/ImageProcessor.sln | 182 +++++------ src/packages/repositories.config | 2 + 9 files changed, 458 insertions(+), 218 deletions(-) create mode 100644 src/ImageProcessor.UnitTests/Properties/AssemblyInfo.cs create mode 100644 src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj create mode 100644 src/ImageProcessor.Web.UnitTests/Properties/AssemblyInfo.cs rename src/{ImageProcessor.UnitTests => ImageProcessor.Web.UnitTests}/RegularExpressionUnitTests.cs (87%) create mode 100644 src/ImageProcessor.Web.UnitTests/packages.config diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index afce9a1d2..2be742cb4 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -1,178 +1,215 @@  - + Debug AnyCPU - {03CA9055-F997-428C-BF28-F50F991777C6} + {633B1C4C-4823-47BE-9A01-A665F3118C8C} Library + Properties ImageProcessor.UnitTests ImageProcessor.UnitTests - - + v4.0 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest ..\ true - v4.5 + true full false - bin\Debug - DEBUG; + bin\Debug\ + DEBUG;TRACE prompt 4 - false - false - full + pdbonly true - bin\Release + bin\Release\ + TRACE prompt 4 - false - false - - ..\packages\NUnit.2.6.3\lib\nunit.framework.dll - - + + + + + + + + + + - + - - - {d011a778-59c8-4bfa-a770-c350216bf161} - ImageProcessor.Web_NET45 - - - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} - ImageProcessor - + - - + + Images\1182076_e8c402e938_z.jpg + + + Images\bus.jpg + + Images\Chrysanthemum.jpg - PreserveNewest - - + + + Images\circle.png + + + Images\cmyk.jpg + + + Images\cmyk.png + + + Images\color-vision-test.gif + + Images\Desert.jpg - PreserveNewest - - + + + Images\emma.jpg + + + Images\falahill_design__160p.jpg + + + Images\fid11246.jpg + + + Images\fid9141.jpg + + + Images\header_1.jpg + + Images\Hydrangeas.jpg - PreserveNewest - - + + Images\Jellyfish.jpg - PreserveNewest - - + + + Images\jrt.jpg + + Images\Koala.jpg - PreserveNewest - - + + Images\Lighthouse.jpg - PreserveNewest - - + + + Images\lomo.jpg + + + Images\meter.gif + + + Images\negative.png + + + Images\negative2.png + + Images\Penguins-200.jpg - PreserveNewest - - + + Images\Penguins-8.png - PreserveNewest - - + + Images\Penguins.bmp - PreserveNewest - - + + Images\Penguins.gif - PreserveNewest - - + + Images\Penguins.jpg - PreserveNewest - - + + Images\Penguins.png - PreserveNewest - - + + Images\Penguins.tif - PreserveNewest - - - Images\Tulips.jpg - PreserveNewest - - - Images\bus.jpg - PreserveNewest - - - Images\cmyk.jpg - PreserveNewest - - - Images\cmyk.png - PreserveNewest - - - Images\jrt.jpg - PreserveNewest - - - Images\meter.gif - PreserveNewest - - + + Images\rocks.jpg - PreserveNewest - - + + Images\rotate.jpg - PreserveNewest - - + + Images\sample1.jpg - PreserveNewest - - + + Images\srgb.jpg - PreserveNewest - - + + Images\srgb.png - PreserveNewest - - + + Images\text.png - PreserveNewest - - + + Images\thor.jpg - PreserveNewest - - + + + Images\Tulips.jpg + + Images\udendørs-374.jpg - PreserveNewest - - + + Images\udendørs.jpg - PreserveNewest - + + + Images\war_horse_quad.jpg + + + Images\WP_000009.jpg + - + + + {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} + ImageProcessor + + + + + + + False + + + False + + + False + + + False + + + + + + @@ -180,4 +217,11 @@ + \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Properties/AssemblyInfo.cs b/src/ImageProcessor.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..fb042a1d3 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ImageProcessor.UnitTests2")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ImageProcessor.UnitTests2")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3003f5a6-eb11-4eee-bfaa-448deb3a31d9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// 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.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/ImageProcessor.UnitTests/packages.config b/src/ImageProcessor.UnitTests/packages.config index 5a3253fcb..a18b325a4 100644 --- a/src/ImageProcessor.UnitTests/packages.config +++ b/src/ImageProcessor.UnitTests/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj new file mode 100644 index 000000000..17c54d202 --- /dev/null +++ b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj @@ -0,0 +1,106 @@ + + + + Debug + AnyCPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260} + Library + Properties + ImageProcessor.Web.UnitTests + ImageProcessor.Web.UnitTests + v4.5.1 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + ..\packages\NUnit.2.6.3\lib\nunit.framework.dll + + + + + + + + + + + + + + + + + + + + + + {d011a778-59c8-4bfa-a770-c350216bf161} + ImageProcessor.Web_NET45 + + + {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} + ImageProcessor + + + + + + + False + + + False + + + False + + + False + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/src/ImageProcessor.Web.UnitTests/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..db6aa3c94 --- /dev/null +++ b/src/ImageProcessor.Web.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ImageProcessor.Web.UnitTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ImageProcessor.Web.UnitTests")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("74919969-6a75-4d26-b1b8-0626aa10af6d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// 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.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/ImageProcessor.UnitTests/RegularExpressionUnitTests.cs b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs similarity index 87% rename from src/ImageProcessor.UnitTests/RegularExpressionUnitTests.cs rename to src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs index 417e94f8c..c41454563 100644 --- a/src/ImageProcessor.UnitTests/RegularExpressionUnitTests.cs +++ b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs @@ -8,7 +8,7 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.UnitTests +namespace ImageProcessor.Web.UnitTests { using System.Drawing; using ImageProcessor.Imaging; @@ -31,7 +31,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "alpha=56"; const int Expected = 56; - Web.Processors.Alpha alpha = new Web.Processors.Alpha(); + Processors.Alpha alpha = new Processors.Alpha(); alpha.MatchRegexIndex(Querystring); int actual = alpha.Processor.DynamicParameter; @@ -48,7 +48,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "brightness=56"; const int Expected = 56; - Web.Processors.Brightness brightness = new Web.Processors.Brightness(); + Processors.Brightness brightness = new Processors.Brightness(); brightness.MatchRegexIndex(Querystring); int actual = brightness.Processor.DynamicParameter; @@ -65,7 +65,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "contrast=56"; const int Expected = 56; - Web.Processors.Contrast contrast = new Web.Processors.Contrast(); + Processors.Contrast contrast = new Processors.Contrast(); contrast.MatchRegexIndex(Querystring); int actual = contrast.Processor.DynamicParameter; @@ -82,7 +82,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "crop=0,0,150,300"; CropLayer expected = new CropLayer(0, 0, 150, 300, CropMode.Pixels); - Web.Processors.Crop crop = new Web.Processors.Crop(); + Processors.Crop crop = new Processors.Crop(); crop.MatchRegexIndex(Querystring); CropLayer actual = crop.Processor.DynamicParameter; @@ -99,7 +99,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "filter=lomograph"; IMatrixFilter expected = MatrixFilters.Lomograph; - Web.Processors.Filter filter = new Web.Processors.Filter(); + Processors.Filter filter = new Processors.Filter(); filter.MatchRegexIndex(Querystring); IMatrixFilter actual = filter.Processor.DynamicParameter; @@ -116,7 +116,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "format=gif"; ISupportedImageFormat expected = new GifFormat(); - Web.Processors.Format format = new Web.Processors.Format(); + Processors.Format format = new Processors.Format(); format.MatchRegexIndex(Querystring); ISupportedImageFormat actual = format.Processor.DynamicParameter; @@ -133,7 +133,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "quality=56"; const int Expected = 56; - Web.Processors.Quality quality = new Web.Processors.Quality(); + Processors.Quality quality = new Processors.Quality(); quality.MatchRegexIndex(Querystring); int actual = quality.Processor.DynamicParameter; @@ -150,7 +150,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "width=300"; ResizeLayer expected = new ResizeLayer(new Size(300, 0)); - Web.Processors.Resize resize = new Web.Processors.Resize(); + Processors.Resize resize = new Processors.Resize(); resize.MatchRegexIndex(Querystring); ResizeLayer actual = resize.Processor.DynamicParameter; @@ -167,7 +167,7 @@ namespace ImageProcessor.UnitTests const string Querystring = "rotate=270"; const int Expected = 270; - Web.Processors.Rotate rotate = new Web.Processors.Rotate(); + Processors.Rotate rotate = new Processors.Rotate(); rotate.MatchRegexIndex(Querystring); int actual = rotate.Processor.DynamicParameter; @@ -183,7 +183,7 @@ namespace ImageProcessor.UnitTests { const string Querystring = "roundedcorners=30"; RoundedCornerLayer expected = new RoundedCornerLayer(30, true, true, true, true); - Web.Processors.RoundedCorners roundedCorners = new Web.Processors.RoundedCorners(); + Processors.RoundedCorners roundedCorners = new Processors.RoundedCorners(); roundedCorners.MatchRegexIndex(Querystring); RoundedCornerLayer actual = roundedCorners.Processor.DynamicParameter; @@ -202,12 +202,12 @@ namespace ImageProcessor.UnitTests Color expectedHex = ColorTranslator.FromHtml("#" + "6aa6cc"); Color expectedRgba = Color.FromArgb(255, 106, 166, 204); - Web.Processors.Tint tint = new Web.Processors.Tint(); + Processors.Tint tint = new Processors.Tint(); tint.MatchRegexIndex(HexQuerystring); Color actualHex = tint.Processor.DynamicParameter; Assert.AreEqual(expectedHex, actualHex); - tint = new Web.Processors.Tint(); + tint = new Processors.Tint(); tint.MatchRegexIndex(RgbaQuerystring); Color actualRgba = tint.Processor.DynamicParameter; Assert.AreEqual(expectedRgba, actualRgba); diff --git a/src/ImageProcessor.Web.UnitTests/packages.config b/src/ImageProcessor.Web.UnitTests/packages.config new file mode 100644 index 000000000..139d5138c --- /dev/null +++ b/src/ImageProcessor.Web.UnitTests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/ImageProcessor.sln b/src/ImageProcessor.sln index 186a446c7..a12d17c68 100644 --- a/src/ImageProcessor.sln +++ b/src/ImageProcessor.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -VisualStudioVersion = 12.0.30110.0 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C427A497-74DC-49B1-8420-D6E68354F29B}" ProjectSection(SolutionItems) = preProject @@ -32,7 +32,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_Webforms_NET45 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessorConsole", "ImageProcessorConsole\ImageProcessorConsole.csproj", "{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.UnitTests", "ImageProcessor.UnitTests\ImageProcessor.UnitTests.csproj", "{03CA9055-F997-428C-BF28-F50F991777C6}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web.UnitTests", "ImageProcessor.Web.UnitTests\ImageProcessor.Web.UnitTests.csproj", "{961340C8-8C93-401D-A0A2-FF9EC61E5260}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.UnitTests", "ImageProcessor.UnitTests\ImageProcessor.UnitTests.csproj", "{633B1C4C-4823-47BE-9A01-A665F3118C8C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -47,24 +49,21 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {03CA9055-F997-428C-BF28-F50F991777C6}.All|Any CPU.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.All|Any CPU.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.All|Mixed Platforms.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.All|Mixed Platforms.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.All|x86.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.All|x86.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|x86.ActiveCfg = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|x86.Build.0 = Debug|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Any CPU.Build.0 = Release|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|x86.ActiveCfg = Release|Any CPU - {03CA9055-F997-428C-BF28-F50F991777C6}.Release|x86.Build.0 = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.Build.0 = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|x86.ActiveCfg = All|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|x86.ActiveCfg = Debug|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.Build.0 = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|x86.ActiveCfg = Release|Any CPU {23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.All|Any CPU.ActiveCfg = Release|Any CPU {23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.All|Any CPU.Build.0 = Release|Any CPU {23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.All|Mixed Platforms.ActiveCfg = Release|Any CPU @@ -97,21 +96,21 @@ Global {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.Build.0 = Release|x86 {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86 {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86 - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.Build.0 = All|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|x86.ActiveCfg = All|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Debug|x86.ActiveCfg = Debug|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Any CPU.Build.0 = Release|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.Release|x86.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.Build.0 = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.Build.0 = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|x86.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|x86.ActiveCfg = Debug|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Any CPU.Build.0 = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|x86.ActiveCfg = Release|Any CPU {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.ActiveCfg = All|Any CPU {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.Build.0 = All|Any CPU {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.ActiveCfg = All|Any CPU @@ -127,36 +126,6 @@ Global {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.Build.0 = Release|Any CPU {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|x86.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.Build.0 = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.Build.0 = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|x86.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|x86.ActiveCfg = Debug|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.Build.0 = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|x86.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Any CPU.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Any CPU.Build.0 = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Mixed Platforms.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Mixed Platforms.Build.0 = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|x86.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|x86.ActiveCfg = Debug|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Any CPU.Build.0 = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|x86.ActiveCfg = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.ActiveCfg = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.Build.0 = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.ActiveCfg = Release|Any CPU @@ -172,30 +141,73 @@ Global {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.Release|Mixed Platforms.Build.0 = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.Release|x86.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.Build.0 = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.Build.0 = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|x86.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Debug|x86.ActiveCfg = Debug|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Any CPU.Build.0 = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|x86.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Any CPU.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Any CPU.Build.0 = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|Mixed Platforms.Build.0 = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.All|x86.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Debug|x86.ActiveCfg = Debug|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Any CPU.Build.0 = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}.Release|x86.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Any CPU.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|Mixed Platforms.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.All|x86.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Debug|x86.ActiveCfg = Debug|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Any CPU.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}.Release|x86.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.All|Any CPU.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.All|Any CPU.Build.0 = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.All|Mixed Platforms.Build.0 = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.All|x86.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Debug|Any CPU.Build.0 = Debug|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Debug|x86.ActiveCfg = Debug|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Release|Any CPU.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Release|Any CPU.Build.0 = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {961340C8-8C93-401D-A0A2-FF9EC61E5260}.Release|x86.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.All|Any CPU.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.All|Any CPU.Build.0 = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.All|Mixed Platforms.Build.0 = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.All|x86.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Debug|x86.ActiveCfg = Debug|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Any CPU.Build.0 = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection - GlobalSection(NestedProjects) = preSolution + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = ImageProcessorConsole\ImageProcessorConsole.csproj EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = ImageProcessor.vsmdi EndGlobalSection diff --git a/src/packages/repositories.config b/src/packages/repositories.config index 73ccce20c..14108b962 100644 --- a/src/packages/repositories.config +++ b/src/packages/repositories.config @@ -1,6 +1,8 @@  + + From d9860636b5383ee9f3e8da8f7d8462dd3d3dec9d Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 26 Jun 2014 22:59:30 +0100 Subject: [PATCH 044/155] Moving Images in unit test Former-commit-id: fbac18062ba6e6102eb2437bfbd830022ce1885b --- .../ImageFactoryUnitTests.cs | 2 +- .../ImageProcessor.UnitTests.csproj | 133 ++---------------- .../Images/Chrysanthemum.jpg.REMOVED.git-id | 1 + .../Images/Desert.jpg.REMOVED.git-id | 1 + .../Images/Penguins.bmp.REMOVED.git-id | 1 + .../Images/Penguins.gif.REMOVED.git-id | 1 + .../Images/cmyk.png.REMOVED.git-id | 1 + 7 files changed, 14 insertions(+), 126 deletions(-) create mode 100644 src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 940702f9c..a63f95ff2 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -42,7 +42,7 @@ namespace ImageProcessor.UnitTests [TestCase("Penguins.gif", "image/gif")] public void TestLoadImageFromFile(string fileName, string expectedMime) { - var testPhoto = Path.Combine(this.localPath, string.Format("Images/{0}", fileName)); + string testPhoto = Path.Combine(this.localPath, string.Format("../../Images/{0}", fileName)); using (ImageFactory imageFactory = new ImageFactory()) { imageFactory.Load(testPhoto); diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 2be742cb4..81516b4b6 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -59,137 +59,20 @@ - - - Images\1182076_e8c402e938_z.jpg - - - Images\bus.jpg - - - Images\Chrysanthemum.jpg - - - Images\circle.png - - - Images\cmyk.jpg - - - Images\cmyk.png - - - Images\color-vision-test.gif - - - Images\Desert.jpg - - - Images\emma.jpg - - - Images\falahill_design__160p.jpg - - - Images\fid11246.jpg - - - Images\fid9141.jpg - - - Images\header_1.jpg - - - Images\Hydrangeas.jpg - - - Images\Jellyfish.jpg - - - Images\jrt.jpg - - - Images\Koala.jpg - - - Images\Lighthouse.jpg - - - Images\lomo.jpg - - - Images\meter.gif - - - Images\negative.png - - - Images\negative2.png - - - Images\Penguins-200.jpg - - - Images\Penguins-8.png - - - Images\Penguins.bmp - - - Images\Penguins.gif - - - Images\Penguins.jpg - - - Images\Penguins.png - - - Images\Penguins.tif - - - Images\rocks.jpg - - - Images\rotate.jpg - - - Images\sample1.jpg - - - Images\srgb.jpg - - - Images\srgb.png - - - Images\text.png - - - Images\thor.jpg - - - Images\Tulips.jpg - - - Images\udendørs-374.jpg - - - Images\udendørs.jpg - - - Images\war_horse_quad.jpg - - - Images\WP_000009.jpg - - {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} ImageProcessor + + + + + + + + diff --git a/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id new file mode 100644 index 000000000..d067665c9 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id @@ -0,0 +1 @@ +757c2a628dd03b1cbe4b3ef07c153897a702b57a \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id new file mode 100644 index 000000000..228aac3ab --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id @@ -0,0 +1 @@ +0b88c91336ff8073f34d21ccd683a01f0e0995da \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id new file mode 100644 index 000000000..74f69293c --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id @@ -0,0 +1 @@ +8150b46ab27c62ba51aaba551eef3f1a30f08de9 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id new file mode 100644 index 000000000..ce873d473 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id @@ -0,0 +1 @@ +6ad3b846d4697584ff601ac481b14a4d3bbb5736 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id new file mode 100644 index 000000000..aeca7b93c --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id @@ -0,0 +1 @@ +db4d55a332254cd6b41336c06f207682bf5a966f \ No newline at end of file From dc098cf8953c1cbf440254752f06015623ce740d Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 26 Jun 2014 23:31:00 +0100 Subject: [PATCH 045/155] No client profile in NET 4.5+ http://msdn.microsoft.com/en-us/library/cc656912(v=vs.110).aspx Former-commit-id: 52b2d9d854666e730273f6ee15c5aa3acbcdd228 --- src/ImageProcessorConsole/App.config | 6 +++--- src/ImageProcessorConsole/ImageProcessorConsole.csproj | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ImageProcessorConsole/App.config b/src/ImageProcessorConsole/App.config index 9c05822ff..d1428ad71 100644 --- a/src/ImageProcessorConsole/App.config +++ b/src/ImageProcessorConsole/App.config @@ -1,6 +1,6 @@ - + - + - \ No newline at end of file + diff --git a/src/ImageProcessorConsole/ImageProcessorConsole.csproj b/src/ImageProcessorConsole/ImageProcessorConsole.csproj index df60cf14b..fba366b0c 100644 --- a/src/ImageProcessorConsole/ImageProcessorConsole.csproj +++ b/src/ImageProcessorConsole/ImageProcessorConsole.csproj @@ -1,5 +1,5 @@  - + Debug @@ -12,7 +12,8 @@ v4.5 512 true - Client + + AnyCPU From f206d23ce96944144e8296571dba219f2d144694 Mon Sep 17 00:00:00 2001 From: James South Date: Fri, 27 Jun 2014 12:20:41 +0100 Subject: [PATCH 046/155] Hopefully fixing reflection load exceptions. Former-commit-id: ed1f13eef59d53031687c4c0bdc4ebb4fcf21e77 --- build/Build.bat | 2 +- .../ImageProcessorConfiguration.cs | 9 ++-- .../Common/Extensions/AssemblyExtensions.cs | 41 +++++++++++++++++++ .../ImageProcessorBootstrapper.cs | 6 +-- src/ImageProcessor/ImageProcessor.csproj | 1 + 5 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs diff --git a/build/Build.bat b/build/Build.bat index 0f1c369bb..513d111e3 100644 --- a/build/Build.bat +++ b/build/Build.bat @@ -8,7 +8,7 @@ ECHO Building ImageProcessor %version%, ImageProcess.Web %webversion% and ImageP ECHO Installing the Microsoft.Bcl.Build package before anything else, otherwise you'd have to run build.cmd twice SET nuGetFolder=%CD%\..\src\packages\ -..\src\.nuget\NuGet.exe install ..\src\ImageProcessor.Web\NET45\packages.config -OutputDirectory %nuGetFolder% +..\src\.nuget\NuGet.exe install ..\src\ImageProcessor.Web\NET4\packages.config -OutputDirectory %nuGetFolder% ECHO Removing _BuildOutput directory so everything is nice and clean RD _BuildOutput /q /s diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs index be4966966..89bcf39d7 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs @@ -10,18 +10,17 @@ // -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Web.Configuration { - #region Using using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Web.Compilation; + + using ImageProcessor.Common.Extensions; using ImageProcessor.Processors; using ImageProcessor.Web.Processors; - #endregion - /// /// Encapsulates methods to allow the retrieval of ImageProcessor settings. /// @@ -301,8 +300,8 @@ namespace ImageProcessor.Web.Configuration // Build a list of native IGraphicsProcessor instances. List availableTypes = BuildManager.GetReferencedAssemblies() .Cast() - .SelectMany(s => s.GetTypes()) - .Where(t => t != null && type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract) + .SelectMany(s => s.GetLoadableTypes()) + .Where(t => type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract) .ToList(); // Create them and add. diff --git a/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs b/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs new file mode 100644 index 000000000..763697ef0 --- /dev/null +++ b/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs @@ -0,0 +1,41 @@ + +namespace ImageProcessor.Common.Extensions +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + /// + /// Encapsulates a series of time saving extension methods to the class. + /// + public static class AssemblyExtensions + { + /// + /// Gets a collection of loadable types from the given assembly. + /// Adapted from + /// + /// + /// The to load the types from. + /// + /// + /// The loadable . + /// + public static IEnumerable GetLoadableTypes(this Assembly assembly) + { + if (assembly == null) + { + throw new ArgumentNullException("assembly"); + } + + try + { + return assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + return ex.Types.Where(t => t != null); + } + } + } +} diff --git a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs index e1d59b7f6..e6a7f1962 100644 --- a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs +++ b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs @@ -13,8 +13,8 @@ namespace ImageProcessor.Configuration using System; using System.Collections.Generic; using System.Linq; - using ImageProcessor.Common.Exceptions; + using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging.Formats; /// @@ -65,8 +65,8 @@ namespace ImageProcessor.Configuration Type type = typeof(ISupportedImageFormat); List availableTypes = AppDomain.CurrentDomain .GetAssemblies() - .SelectMany(s => s.GetTypes()) - .Where(t => t != null && type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract) + .SelectMany(s => s.GetLoadableTypes()) + .Where(t => type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract) .ToList(); this.SupportedImageFormats = availableTypes diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 34f818362..4521b06eb 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -59,6 +59,7 @@ + From 4658134682ad0624c6fed9371ebf73aef82de5a6 Mon Sep 17 00:00:00 2001 From: James South Date: Fri, 27 Jun 2014 15:53:51 +0100 Subject: [PATCH 047/155] Adding build status badge Former-commit-id: d7d78e4c731a7c1d945add87ed6d3c96137a7829 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 14d8451e7..ec07138b5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ ImageProcessor =============== +[![Build status](https://ci.appveyor.com/api/projects/status/8ypr7527dnao04yr)](https://ci.appveyor.com/project/JamesSouth/imageprocessor) + Imageprocessor is a lightweight library written in C# that allows you to manipulate images on-the-fly using .NET 4.0. It's fast, extensible, easy to use, comes bundled with some great features and is fully open source. From df955958e59e4580d7c5ce4d59095ae27d15fb96 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 15:42:31 +0200 Subject: [PATCH 048/155] Adds new test of factory for loading an image from a memory stream Former-commit-id: 98343f28edb50392fcad4d871451559a441e3152 --- .../ImageFactoryUnitTests.cs | 33 +++ .../ImageProcessor.UnitTests.csproj | 202 ++++++++++++------ src/ImageProcessor_Mono.sln | 26 ++- 3 files changed, 190 insertions(+), 71 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index a63f95ff2..1fc782073 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -51,5 +51,38 @@ namespace ImageProcessor.UnitTests Assert.IsNotNull(imageFactory.Image); } } + + /// > + /// Tests the loading of image from a memory stream + /// + /// + /// The file Name. + /// + /// + /// The expected mime type. + /// + [Test] + [TestCase("Chrysanthemum.jpg", "image/jpeg")] + [TestCase("Desert.jpg", "image/jpeg")] + [TestCase("cmyk.png", "image/png")] + [TestCase("Penguins.bmp", "image/bmp")] + [TestCase("Penguins.gif", "image/gif")] + public void TestLoadImageFromMemory(string fileName, string expectedMime) + { + string testPhoto = Path.Combine(this.localPath, string.Format("../../Images/{0}", fileName)); + byte[] photoBytes = File.ReadAllBytes(testPhoto); + + // ImageProcessor + using (MemoryStream inStream = new MemoryStream(photoBytes)) + { + using (ImageFactory imageFactory = new ImageFactory()) + { + imageFactory.Load(inStream); + Assert.AreEqual(null, imageFactory.ImagePath); + Assert.AreEqual(expectedMime, imageFactory.CurrentImageFormat.MimeType); + Assert.IsNotNull(imageFactory.Image); + } + } + } } } \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 81516b4b6..d5841e6c2 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -1,98 +1,177 @@  - + Debug AnyCPU - {633B1C4C-4823-47BE-9A01-A665F3118C8C} + {03CA9055-F997-428C-BF28-F50F991777C6} Library - Properties ImageProcessor.UnitTests ImageProcessor.UnitTests - v4.0 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest + + ..\ true - + v4.5 true full false - bin\Debug\ - DEBUG;TRACE + bin\Debug + DEBUG; prompt 4 + false + false - pdbonly + full true - bin\Release\ - TRACE + bin\Release prompt 4 + false + false + + ..\packages\NUnit.2.6.3\lib\nunit.framework.dll - - + + - - - - - - - - - - - - + + + {D011A778-59C8-4BFA-A770-C350216BF161} + ImageProcessor.Web_NET45 + - {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} ImageProcessor - - - - - - + + + Images\Chrysanthemum.jpg + PreserveNewest + + + Images\Desert.jpg + PreserveNewest + + + Images\Hydrangeas.jpg + PreserveNewest + + + Images\Jellyfish.jpg + PreserveNewest + + + Images\Koala.jpg + PreserveNewest + + + Images\Lighthouse.jpg + PreserveNewest + + + Images\Penguins-200.jpg + PreserveNewest + + + Images\Penguins-8.png + PreserveNewest + + + Images\Penguins.bmp + PreserveNewest + + + Images\Penguins.gif + PreserveNewest + + + Images\Penguins.jpg + PreserveNewest + + + Images\Penguins.png + PreserveNewest + + + Images\Penguins.tif + PreserveNewest + + + Images\Tulips.jpg + PreserveNewest + + + Images\bus.jpg + PreserveNewest + + + Images\cmyk.jpg + PreserveNewest + + + Images\cmyk.png + PreserveNewest + + + Images\jrt.jpg + PreserveNewest + + + Images\meter.gif + PreserveNewest + + + Images\rocks.jpg + PreserveNewest + + + Images\rotate.jpg + PreserveNewest + + + Images\sample1.jpg + PreserveNewest + + + Images\srgb.jpg + PreserveNewest + + + Images\srgb.png + PreserveNewest + + + Images\text.png + PreserveNewest + + + Images\thor.jpg + PreserveNewest + + + Images\udendørs-374.jpg + PreserveNewest + + + Images\udendørs.jpg + PreserveNewest + - - - - - False - - - False - - - False - - - False - - - - - - + @@ -100,11 +179,4 @@ - \ No newline at end of file diff --git a/src/ImageProcessor_Mono.sln b/src/ImageProcessor_Mono.sln index 7d47a2ca6..8b1e0fb37 100644 --- a/src/ImageProcessor_Mono.sln +++ b/src/ImageProcessor_Mono.sln @@ -3,12 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 VisualStudioVersion = 12.0.30110.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C427A497-74DC-49B1-8420-D6E68354F29B}" - ProjectSection(SolutionItems) = preProject - ImageProcessor.vsmdi = ImageProcessor.vsmdi - Local.testsettings = Local.testsettings - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E656CDE-124D-4FAF-837C-0EF1E192D418}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.Config = .nuget\NuGet.Config @@ -24,6 +18,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessorConsole", "ImageProcessorConsole\ImageProcessorConsole.csproj", "{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.UnitTests", "ImageProcessor.UnitTests\ImageProcessor.UnitTests.csproj", "{03CA9055-F997-428C-BF28-F50F991777C6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Any CPU = All|Any CPU @@ -37,6 +33,24 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {03CA9055-F997-428C-BF28-F50F991777C6}.All|Any CPU.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.All|Any CPU.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.All|Mixed Platforms.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.All|Mixed Platforms.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.All|x86.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.All|x86.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|x86.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|x86.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Any CPU.Build.0 = Release|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|x86.ActiveCfg = Release|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|x86.Build.0 = Release|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU From b989e58e4102de84c7391c5646bb1c65ecfbe46f Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 18:03:26 +0200 Subject: [PATCH 049/155] Loads all the test images + tests a few filters as well (failing for gif images) Former-commit-id: 193b0354b1e8f9e227919084076d6fd1776425d1 --- .../ImageFactoryUnitTests.cs | 106 +++++++++++------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 1fc782073..7cd124b19 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -12,6 +12,7 @@ namespace ImageProcessor.UnitTests { using System; using System.IO; + using System.Collections.Generic; using NUnit.Framework; /// @@ -25,62 +26,89 @@ namespace ImageProcessor.UnitTests /// private readonly string localPath = Path.GetDirectoryName(new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath); + /// + /// Lists the input files in the Images folder + /// + /// The list of files. + private static IEnumerable ListInputFiles() + { + return Directory.GetFiles("./Images"); + } + /// /// Tests the loading of image from a file /// - /// - /// The file Name. - /// - /// - /// The expected mime type. - /// [Test] - [TestCase("Chrysanthemum.jpg", "image/jpeg")] - [TestCase("Desert.jpg", "image/jpeg")] - [TestCase("cmyk.png", "image/png")] - [TestCase("Penguins.bmp", "image/bmp")] - [TestCase("Penguins.gif", "image/gif")] - public void TestLoadImageFromFile(string fileName, string expectedMime) + public void TestLoadImageFromFile() { - string testPhoto = Path.Combine(this.localPath, string.Format("../../Images/{0}", fileName)); - using (ImageFactory imageFactory = new ImageFactory()) + foreach (var fileName in ListInputFiles()) { - imageFactory.Load(testPhoto); - Assert.AreEqual(testPhoto, imageFactory.ImagePath); - Assert.AreEqual(expectedMime, imageFactory.CurrentImageFormat.MimeType); - Assert.IsNotNull(imageFactory.Image); + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + Assert.AreEqual(fileName, imageFactory.ImagePath); + Assert.IsNotNull(imageFactory.Image); + } } + } /// > /// Tests the loading of image from a memory stream /// - /// - /// The file Name. - /// - /// - /// The expected mime type. - /// [Test] - [TestCase("Chrysanthemum.jpg", "image/jpeg")] - [TestCase("Desert.jpg", "image/jpeg")] - [TestCase("cmyk.png", "image/png")] - [TestCase("Penguins.bmp", "image/bmp")] - [TestCase("Penguins.gif", "image/gif")] - public void TestLoadImageFromMemory(string fileName, string expectedMime) + public void TestLoadImageFromMemory() { - string testPhoto = Path.Combine(this.localPath, string.Format("../../Images/{0}", fileName)); - byte[] photoBytes = File.ReadAllBytes(testPhoto); + foreach (var fileName in ListInputFiles()) + { + byte[] photoBytes = File.ReadAllBytes(fileName); - // ImageProcessor - using (MemoryStream inStream = new MemoryStream(photoBytes)) + using (var inStream = new MemoryStream(photoBytes)) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(inStream); + Assert.AreEqual(null, imageFactory.ImagePath); + Assert.IsNotNull(imageFactory.Image); + } + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void ApplyEffectAlpha() + { + foreach (var fileName in ListInputFiles()) { - using (ImageFactory imageFactory = new ImageFactory()) + using (var imageFactory = new ImageFactory()) { - imageFactory.Load(inStream); - Assert.AreEqual(null, imageFactory.ImagePath); - Assert.AreEqual(expectedMime, imageFactory.CurrentImageFormat.MimeType); - Assert.IsNotNull(imageFactory.Image); + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Alpha(50); + var modified = imageFactory.Image.Clone(); + Assert.AreNotEqual(original, modified); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void ApplyEffectBrightness() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Brightness(50); + var modified = imageFactory.Image.Clone(); + Assert.AreNotEqual(original, modified); } } } From 985ef8abad586b0c8e6ee19125a189ea03ded007 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 18:13:23 +0200 Subject: [PATCH 050/155] Adds test for constraints resize Former-commit-id: a30d4df7acc83a74eab1ed881a010fe14b42dd1f --- .../ImageFactoryUnitTests.cs | 24 +++++++++++++++---- .../ImageProcessor.UnitTests.csproj | 4 ---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 7cd124b19..b81cff068 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -21,11 +21,6 @@ namespace ImageProcessor.UnitTests [TestFixture] public class ImageFactoryUnitTests { - /// - /// The path to the binary's folder - /// - private readonly string localPath = Path.GetDirectoryName(new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath); - /// /// Lists the input files in the Images folder /// @@ -112,5 +107,24 @@ namespace ImageProcessor.UnitTests } } } + + /// + /// Tests that the image is well resized using constraints + /// + [Test] + public void ApplyConstraints() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Constrain(new System.Drawing.Size(200, 200)); + var modified = imageFactory.Image.Clone(); + Assert.AreNotEqual(original, modified); + } + } + } } } \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index d5841e6c2..4bb9bf77f 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -82,10 +82,6 @@ Images\Lighthouse.jpg PreserveNewest - - Images\Penguins-200.jpg - PreserveNewest - Images\Penguins-8.png PreserveNewest From 62d774378131c278311b6e46a487ce4501fc588a Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 18:16:34 +0200 Subject: [PATCH 051/155] Checks that the image is actually resized Former-commit-id: cf8a8931b6b28c4825283f3a6af4e8c4d087ca9e --- .../ImageFactoryUnitTests.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index b81cff068..936c32345 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -83,8 +83,7 @@ namespace ImageProcessor.UnitTests imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); imageFactory.Alpha(50); - var modified = imageFactory.Image.Clone(); - Assert.AreNotEqual(original, modified); + Assert.AreNotEqual(original, imageFactory.Image); } } } @@ -102,8 +101,7 @@ namespace ImageProcessor.UnitTests imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); imageFactory.Brightness(50); - var modified = imageFactory.Image.Clone(); - Assert.AreNotEqual(original, modified); + Assert.AreNotEqual(original, imageFactory.Image); } } } @@ -114,15 +112,17 @@ namespace ImageProcessor.UnitTests [Test] public void ApplyConstraints() { + const int maxSize = 200; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); - imageFactory.Constrain(new System.Drawing.Size(200, 200)); - var modified = imageFactory.Image.Clone(); - Assert.AreNotEqual(original, modified); + imageFactory.Constrain(new System.Drawing.Size(maxSize, maxSize)); + Assert.AreNotEqual(original, imageFactory.Image); + Assert.LessOrEqual(maxSize, imageFactory.Image.Width); + Assert.LessOrEqual(maxSize, imageFactory.Image.Height); } } } From 777ade778a8098c152112ba59d9354289c64547a Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 18:52:29 +0200 Subject: [PATCH 052/155] First fix of an animated gif problem on Mono Former-commit-id: 43eebfe02b5974def03fbf40962c787c2c6cdf0a --- src/ImageProcessor/Imaging/Formats/FormatUtilities.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs index 36d2e3c07..3c6e3b3e0 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs @@ -135,12 +135,14 @@ namespace ImageProcessor.Imaging.Formats int frameCount = image.GetFrameCount(frameDimension); int last = frameCount - 1; int delay = 0; - int index = 0; List gifFrames = new List(); for (int i = 0; i < frameCount; i++) { - int thisDelay = BitConverter.ToInt32(image.GetPropertyItem(20736).Value, index); + // GDI returns a single array with all delays, while Mono returns a different array for each frame + image.SelectActiveFrame(frameDimension, i); + var times = image.GetPropertyItem(20736).Value; + int thisDelay = BitConverter.ToInt32(times, 4*i % times.Length); int toAddDelay = thisDelay * 10 < 20 ? 20 : thisDelay * 10; // Minimum delay is 20 ms // Find the frame @@ -156,7 +158,6 @@ namespace ImageProcessor.Imaging.Formats } delay += toAddDelay; - index += 4; } info.GifFrames = gifFrames; From 21e771e4d1bdb83a324c8c40fb7783966bedbf12 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 20:48:03 +0200 Subject: [PATCH 053/155] Fixes a unit test (wrong parameters order) Former-commit-id: bcfb1caf15531d47653132153ad26cef59668c0e --- src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 936c32345..f81fd1c5b 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -121,8 +121,8 @@ namespace ImageProcessor.UnitTests var original = imageFactory.Image.Clone(); imageFactory.Constrain(new System.Drawing.Size(maxSize, maxSize)); Assert.AreNotEqual(original, imageFactory.Image); - Assert.LessOrEqual(maxSize, imageFactory.Image.Width); - Assert.LessOrEqual(maxSize, imageFactory.Image.Height); + Assert.LessOrEqual(imageFactory.Image.Width, maxSize); + Assert.LessOrEqual(imageFactory.Image.Height, maxSize); } } } From a2853ce1c23e05b9a9a78a5e599ed86158fe923a Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 22:25:54 +0200 Subject: [PATCH 054/155] Re-fix of a Mono problem + modify some 'var' usage Former-commit-id: 1a96ba18689b8aa25607f3b699971f39c16132f9 --- src/ImageProcessor/ImageFactory.cs | 62 ++++++++++++++++-------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 540e34c9a..4a68a5e86 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -177,13 +177,13 @@ namespace ImageProcessor /// public ImageFactory Load(string imagePath) { - FileInfo fileInfo = new FileInfo(imagePath); + var fileInfo = new FileInfo(imagePath); if (fileInfo.Exists) { this.ImagePath = imagePath; // Open a file stream to prevent the need for lock. - using (FileStream fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read)) + using (var fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read)) { ISupportedImageFormat format = FormatUtilities.GetFormat(fileStream); @@ -192,7 +192,7 @@ namespace ImageProcessor throw new ImageFormatException("Input stream is not a supported format."); } - MemoryStream memoryStream = new MemoryStream(); + var memoryStream = new MemoryStream(); // Copy the stream. fileStream.CopyTo(memoryStream); @@ -240,7 +240,11 @@ namespace ImageProcessor if (this.ShouldProcess) { // Set our new image as the memory stream value. + #if !__MonoCS__ Image newImage = Image.FromStream(this.InputStream, true); + #else + Image newImage = Image.FromStream(this.InputStream); + #endif // Dispose and reassign the image. this.Image.Dispose(); @@ -275,7 +279,7 @@ namespace ImageProcessor percentage = 0; } - Alpha alpha = new Alpha { DynamicParameter = percentage }; + var alpha = new Alpha { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(alpha.ProcessImage, this); } @@ -293,7 +297,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - AutoRotate autoRotate = new AutoRotate(); + var autoRotate = new AutoRotate(); this.CurrentImageFormat.ApplyProcessor(autoRotate.ProcessImage, this); } @@ -320,7 +324,7 @@ namespace ImageProcessor percentage = 0; } - Brightness brightness = new Brightness { DynamicParameter = percentage }; + var brightness = new Brightness { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(brightness.ProcessImage, this); } @@ -340,7 +344,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - ResizeLayer layer = new ResizeLayer(size, ResizeMode.Max); + var layer = new ResizeLayer(size, ResizeMode.Max); return this.Resize(layer); } @@ -368,7 +372,7 @@ namespace ImageProcessor percentage = 0; } - Contrast contrast = new Contrast { DynamicParameter = percentage }; + var contrast = new Contrast { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(contrast.ProcessImage, this); } @@ -388,7 +392,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - CropLayer cropLayer = new CropLayer(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, CropMode.Pixels); + var cropLayer = new CropLayer(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, CropMode.Pixels); return this.Crop(cropLayer); } @@ -399,7 +403,7 @@ namespace ImageProcessor /// Crops the current image to the given location and size. /// /// - /// The containing the coordinates and mode to crop the image with. + /// The containing the coordinates and mode to crop the image with. /// /// /// The current instance of the class. @@ -408,7 +412,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - Crop crop = new Crop { DynamicParameter = cropLayer }; + var crop = new Crop { DynamicParameter = cropLayer }; this.CurrentImageFormat.ApplyProcessor(crop.ProcessImage, this); } @@ -429,7 +433,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - Filter filter = new Filter { DynamicParameter = matrixFilter }; + var filter = new Filter { DynamicParameter = matrixFilter }; this.CurrentImageFormat.ApplyProcessor(filter.ProcessImage, this); } @@ -449,11 +453,11 @@ namespace ImageProcessor { if (this.ShouldProcess) { - RotateFlipType rotateFlipType = flipVertically == false - ? RotateFlipType.RotateNoneFlipX - : RotateFlipType.RotateNoneFlipY; + RotateFlipType rotateFlipType = flipVertically + ? RotateFlipType.RotateNoneFlipY + : RotateFlipType.RotateNoneFlipX; - Flip flip = new Flip { DynamicParameter = rotateFlipType }; + var flip = new Flip { DynamicParameter = rotateFlipType }; this.CurrentImageFormat.ApplyProcessor(flip.ProcessImage, this); } @@ -496,7 +500,7 @@ namespace ImageProcessor { if (this.ShouldProcess && size > 0) { - GaussianLayer layer = new GaussianLayer(size); + var layer = new GaussianLayer(size); return this.GaussianBlur(layer); } @@ -517,7 +521,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - GaussianBlur gaussianBlur = new GaussianBlur { DynamicParameter = gaussianLayer }; + var gaussianBlur = new GaussianBlur { DynamicParameter = gaussianLayer }; this.CurrentImageFormat.ApplyProcessor(gaussianBlur.ProcessImage, this); } @@ -543,7 +547,7 @@ namespace ImageProcessor { if (this.ShouldProcess && size > 0) { - GaussianLayer layer = new GaussianLayer(size); + var layer = new GaussianLayer(size); return this.GaussianSharpen(layer); } @@ -564,7 +568,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - GaussianSharpen gaussianSharpen = new GaussianSharpen { DynamicParameter = gaussianLayer }; + var gaussianSharpen = new GaussianSharpen { DynamicParameter = gaussianLayer }; this.CurrentImageFormat.ApplyProcessor(gaussianSharpen.ProcessImage, this); } @@ -607,7 +611,7 @@ namespace ImageProcessor int width = size.Width; int height = size.Height; - ResizeLayer resizeLayer = new ResizeLayer(new Size(width, height)); + var resizeLayer = new ResizeLayer(new Size(width, height)); return this.Resize(resizeLayer); } @@ -629,7 +633,7 @@ namespace ImageProcessor { var resizeSettings = new Dictionary { { "MaxWidth", resizeLayer.Size.Width.ToString("G") }, { "MaxHeight", resizeLayer.Size.Height.ToString("G") } }; - Resize resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings }; + var resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings }; this.CurrentImageFormat.ApplyProcessor(resize.ProcessImage, this); } @@ -655,7 +659,7 @@ namespace ImageProcessor degrees = 0; } - Rotate rotate = new Rotate { DynamicParameter = degrees }; + var rotate = new Rotate { DynamicParameter = degrees }; this.CurrentImageFormat.ApplyProcessor(rotate.ProcessImage, this); } @@ -680,7 +684,7 @@ namespace ImageProcessor roundedCornerLayer.Radius = 0; } - RoundedCorners roundedCorners = new RoundedCorners { DynamicParameter = roundedCornerLayer }; + var roundedCorners = new RoundedCorners { DynamicParameter = roundedCornerLayer }; this.CurrentImageFormat.ApplyProcessor(roundedCorners.ProcessImage, this); } @@ -707,7 +711,7 @@ namespace ImageProcessor percentage = 0; } - Saturation saturate = new Saturation { DynamicParameter = percentage }; + var saturate = new Saturation { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(saturate.ProcessImage, this); } @@ -727,7 +731,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - Tint tint = new Tint { DynamicParameter = color }; + var tint = new Tint { DynamicParameter = color }; this.CurrentImageFormat.ApplyProcessor(tint.ProcessImage, this); } @@ -747,7 +751,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - Vignette vignette = new Vignette + var vignette = new Vignette { DynamicParameter = color.HasValue && !color.Equals(Color.Transparent) ? color.Value @@ -774,7 +778,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - Watermark watermark = new Watermark { DynamicParameter = textLayer }; + var watermark = new Watermark { DynamicParameter = textLayer }; this.CurrentImageFormat.ApplyProcessor(watermark.ProcessImage, this); } @@ -796,7 +800,7 @@ namespace ImageProcessor if (this.ShouldProcess) { // ReSharper disable once AssignNullToNotNullAttribute - DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(filePath)); + var directoryInfo = new DirectoryInfo(Path.GetDirectoryName(filePath)); if (!directoryInfo.Exists) { directoryInfo.Create(); From e5b6a3481f2911b84b023bfafbb61e8ef9e66678 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 22:53:25 +0200 Subject: [PATCH 055/155] Adds a few more unit tests Former-commit-id: c782e8168d8b9b186cc0855e46bd0478019ec5d9 --- .../ImageFactoryUnitTests.cs | 122 +++++++++++++++++- 1 file changed, 119 insertions(+), 3 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index f81fd1c5b..ac5de24a4 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -74,7 +74,7 @@ namespace ImageProcessor.UnitTests /// Tests that a filter is really applied by checking that the image is modified /// [Test] - public void ApplyEffectAlpha() + public void TestApplyEffectAlpha() { foreach (var fileName in ListInputFiles()) { @@ -92,7 +92,7 @@ namespace ImageProcessor.UnitTests /// Tests that a filter is really applied by checking that the image is modified /// [Test] - public void ApplyEffectBrightness() + public void TestApplyEffectBrightness() { foreach (var fileName in ListInputFiles()) { @@ -106,11 +106,85 @@ namespace ImageProcessor.UnitTests } } + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectContrast() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Contrast(50); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that all filters can be applied + /// + [Test] + public void TestApplyEffectFilter() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.BlackWhite); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Comic); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Gotham); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.GreyScale); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.HiSatch); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Invert); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Lomograph); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.LoSatch); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Polaroid); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Sepia); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + } + } + } + /// /// Tests that the image is well resized using constraints /// [Test] - public void ApplyConstraints() + public void TestResizeConstraints() { const int maxSize = 200; foreach (var fileName in ListInputFiles()) @@ -126,5 +200,47 @@ namespace ImageProcessor.UnitTests } } } + + /// + /// Tests that the image is well cropped + /// + [Test] + public void TestCrop() + { + const int maxSize = 20; + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Crop(new System.Drawing.Rectangle(0, 0, maxSize, maxSize)); + Assert.AreNotEqual(original, imageFactory.Image); + Assert.AreEqual(maxSize, imageFactory.Image.Width); + Assert.LessOrEqual(maxSize, imageFactory.Image.Height); + } + } + } + + /// + /// Tests that the image is well cropped + /// + [Test] + public void TestCropWithCropLayer() + { + const int maxSize = 20; + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Crop(new Imaging.CropLayer(0, 0, maxSize, maxSize, Imaging.CropMode.Pixels)); + Assert.AreNotEqual(original, imageFactory.Image); + Assert.AreEqual(maxSize, imageFactory.Image.Width); + Assert.LessOrEqual(maxSize, imageFactory.Image.Height); + } + } + } } } \ No newline at end of file From 1ddb67078367c5f3d74499be588411993e9801ff Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 23:11:58 +0200 Subject: [PATCH 056/155] Adds a few more unit tests Former-commit-id: bca6ad3548ecf57e56eb416dcfbfd002b725b733 --- .../ImageFactoryUnitTests.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index ac5de24a4..7dd09e078 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -124,6 +124,42 @@ namespace ImageProcessor.UnitTests } } + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectBlur() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.GaussianBlur(5); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectBlurWithLayer() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.GaussianBlur(new Imaging.GaussianLayer() { Sigma = 10, Size = 5, Threshold = 2 }); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + /// /// Tests that all filters can be applied /// @@ -242,5 +278,31 @@ namespace ImageProcessor.UnitTests } } } + + /// + /// Tests that the image is flipped + /// + [Test] + public void TestFlip() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = (System.Drawing.Image)imageFactory.Image.Clone(); + imageFactory.Flip(true); + Assert.AreNotEqual(original, imageFactory.Image); + Assert.AreEqual(original.Width, imageFactory.Image.Width); + Assert.AreEqual(original.Height, imageFactory.Image.Height); + imageFactory.Reset(); + + imageFactory.Flip(false); + Assert.AreNotEqual(original, imageFactory.Image); + Assert.AreEqual(original.Width, imageFactory.Image.Width); + Assert.AreEqual(original.Height, imageFactory.Image.Height); + } + } + } } } \ No newline at end of file From 71a4fbf6ffdecbf7317a7314b36ccd3da4a9c648 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 23:22:35 +0200 Subject: [PATCH 057/155] Adds a few more unit tests Former-commit-id: ccb39e91e174833342bf502d6f12dc75b149c0bf --- .../ImageFactoryUnitTests.cs | 82 ++++++++++++++++++- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 7dd09e078..60db9a8ee 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -154,7 +154,43 @@ namespace ImageProcessor.UnitTests { imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); - imageFactory.GaussianBlur(new Imaging.GaussianLayer() { Sigma = 10, Size = 5, Threshold = 2 }); + imageFactory.GaussianBlur(new Imaging.GaussianLayer { Sigma = 10, Size = 5, Threshold = 2 }); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectSharpen() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.GaussianSharpen(5); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectSharpenWithLayer() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.GaussianSharpen(new Imaging.GaussianLayer { Sigma = 10, Size = 5, Threshold = 2 }); Assert.AreNotEqual(original, imageFactory.Image); } } @@ -228,9 +264,7 @@ namespace ImageProcessor.UnitTests using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); imageFactory.Constrain(new System.Drawing.Size(maxSize, maxSize)); - Assert.AreNotEqual(original, imageFactory.Image); Assert.LessOrEqual(imageFactory.Image.Width, maxSize); Assert.LessOrEqual(imageFactory.Image.Height, maxSize); } @@ -304,5 +338,47 @@ namespace ImageProcessor.UnitTests } } } + + /// + /// Tests that the image is resized + /// + [Test] + public void TestResize() + { + const int newSize = 150; + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + imageFactory.Resize(new System.Drawing.Size(newSize, newSize)); + Assert.AreEqual(newSize, imageFactory.Image.Width); + Assert.AreEqual(newSize, imageFactory.Image.Height); + } + } + } + + /// + /// Tests that the image is resized + /// + [Test] + public void TestResizeWithLayer() + { + const int newSize = 150; + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + imageFactory.Resize(new Imaging.ResizeLayer( + new System.Drawing.Size(newSize, newSize), + Imaging.ResizeMode.Stretch, + Imaging.AnchorPosition.Left, + true)); + Assert.AreEqual(newSize, imageFactory.Image.Width); + Assert.AreEqual(newSize, imageFactory.Image.Height); + } + } + } } } \ No newline at end of file From 8f1480cff62b05ed683e576b1a8bb3fca28233e3 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 00:37:38 +0200 Subject: [PATCH 058/155] Yet a few other unit tests Former-commit-id: cfc586b9f02332ec65eaea1ba0c89b6b4be6b27e --- .../ImageFactoryUnitTests.cs | 182 ++++++++++++++---- 1 file changed, 146 insertions(+), 36 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 60db9a8ee..d868b2245 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -11,8 +11,8 @@ namespace ImageProcessor.UnitTests { using System; - using System.IO; using System.Collections.Generic; + using System.IO; using NUnit.Framework; /// @@ -21,15 +21,6 @@ namespace ImageProcessor.UnitTests [TestFixture] public class ImageFactoryUnitTests { - /// - /// Lists the input files in the Images folder - /// - /// The list of files. - private static IEnumerable ListInputFiles() - { - return Directory.GetFiles("./Images"); - } - /// /// Tests the loading of image from a file /// @@ -45,10 +36,9 @@ namespace ImageProcessor.UnitTests Assert.IsNotNull(imageFactory.Image); } } - } - /// > + /// /// Tests the loading of image from a memory stream /// [Test] @@ -124,6 +114,84 @@ namespace ImageProcessor.UnitTests } } + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectSaturation() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Saturation(50); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectTint() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Tint(System.Drawing.Color.FromKnownColor(System.Drawing.KnownColor.AliceBlue)); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectVignette() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Vignette(System.Drawing.Color.FromKnownColor(System.Drawing.KnownColor.AliceBlue)); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectWatermark() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Watermark(new Imaging.TextLayer + { + Font = "Arial", + FontSize = 10, + Position = new System.Drawing.Point(10, 10), + Text = "Lorem ipsum dolor" + }); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + /// /// Tests that a filter is really applied by checking that the image is modified /// @@ -252,21 +320,39 @@ namespace ImageProcessor.UnitTests } } + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestRoundedCorners() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.RoundedCorners(new Imaging.RoundedCornerLayer(5, true, true, true, true)); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + /// /// Tests that the image is well resized using constraints /// [Test] public void TestResizeConstraints() { - const int maxSize = 200; + const int MaxSize = 200; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); - imageFactory.Constrain(new System.Drawing.Size(maxSize, maxSize)); - Assert.LessOrEqual(imageFactory.Image.Width, maxSize); - Assert.LessOrEqual(imageFactory.Image.Height, maxSize); + imageFactory.Constrain(new System.Drawing.Size(MaxSize, MaxSize)); + Assert.LessOrEqual(imageFactory.Image.Width, MaxSize); + Assert.LessOrEqual(imageFactory.Image.Height, MaxSize); } } } @@ -277,17 +363,17 @@ namespace ImageProcessor.UnitTests [Test] public void TestCrop() { - const int maxSize = 20; + const int MaxSize = 20; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); - imageFactory.Crop(new System.Drawing.Rectangle(0, 0, maxSize, maxSize)); + imageFactory.Crop(new System.Drawing.Rectangle(0, 0, MaxSize, MaxSize)); Assert.AreNotEqual(original, imageFactory.Image); - Assert.AreEqual(maxSize, imageFactory.Image.Width); - Assert.LessOrEqual(maxSize, imageFactory.Image.Height); + Assert.AreEqual(MaxSize, imageFactory.Image.Width); + Assert.LessOrEqual(MaxSize, imageFactory.Image.Height); } } } @@ -298,17 +384,17 @@ namespace ImageProcessor.UnitTests [Test] public void TestCropWithCropLayer() { - const int maxSize = 20; + const int MaxSize = 20; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); - imageFactory.Crop(new Imaging.CropLayer(0, 0, maxSize, maxSize, Imaging.CropMode.Pixels)); + imageFactory.Crop(new Imaging.CropLayer(0, 0, MaxSize, MaxSize, Imaging.CropMode.Pixels)); Assert.AreNotEqual(original, imageFactory.Image); - Assert.AreEqual(maxSize, imageFactory.Image.Width); - Assert.LessOrEqual(maxSize, imageFactory.Image.Height); + Assert.AreEqual(MaxSize, imageFactory.Image.Width); + Assert.LessOrEqual(MaxSize, imageFactory.Image.Height); } } } @@ -345,15 +431,15 @@ namespace ImageProcessor.UnitTests [Test] public void TestResize() { - const int newSize = 150; + const int NewSize = 150; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); - imageFactory.Resize(new System.Drawing.Size(newSize, newSize)); - Assert.AreEqual(newSize, imageFactory.Image.Width); - Assert.AreEqual(newSize, imageFactory.Image.Height); + imageFactory.Resize(new System.Drawing.Size(NewSize, NewSize)); + Assert.AreEqual(NewSize, imageFactory.Image.Width); + Assert.AreEqual(NewSize, imageFactory.Image.Height); } } } @@ -364,21 +450,45 @@ namespace ImageProcessor.UnitTests [Test] public void TestResizeWithLayer() { - const int newSize = 150; + const int NewSize = 150; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); - imageFactory.Resize(new Imaging.ResizeLayer( - new System.Drawing.Size(newSize, newSize), - Imaging.ResizeMode.Stretch, - Imaging.AnchorPosition.Left, - true)); - Assert.AreEqual(newSize, imageFactory.Image.Width); - Assert.AreEqual(newSize, imageFactory.Image.Height); + imageFactory.Resize(new Imaging.ResizeLayer(new System.Drawing.Size(NewSize, NewSize), Imaging.ResizeMode.Stretch, Imaging.AnchorPosition.Left)); + Assert.AreEqual(NewSize, imageFactory.Image.Width); + Assert.AreEqual(NewSize, imageFactory.Image.Height); } } } + + /// + /// Tests that the image is resized + /// + [Test] + public void TestRotate() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = (System.Drawing.Image)imageFactory.Image.Clone(); + imageFactory.Rotate(90); + Assert.AreEqual(original.Height, imageFactory.Image.Width); + Assert.AreEqual(original.Width, imageFactory.Image.Height); + } + } + } + + /// + /// Lists the input files in the Images folder + /// + /// The list of files. + private static IEnumerable ListInputFiles() + { + return Directory.GetFiles("./Images"); + } } } \ No newline at end of file From f3a5cc25ba71d64355c15a65d7b877cab7ec489d Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 00:41:53 +0200 Subject: [PATCH 059/155] Adds tests for saving the files Former-commit-id: 7893eb70f8315cf13da030fde6a4a3c9884f59aa --- .../ImageFactoryUnitTests.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index d868b2245..880871cc7 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -60,6 +60,45 @@ namespace ImageProcessor.UnitTests } } + /// + /// Tests that the save method actually saves a file + /// + [Test] + public void TestSaveToDisk() + { + foreach (var fileName in ListInputFiles()) + { + var outputFileName = string.Format("./output/{0}", Path.GetFileName(fileName)); + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + imageFactory.Save(outputFileName); + Assert.AreEqual(true, File.Exists(outputFileName)); + } + } + } + + /// + /// Tests that the save method actually writes to memory + /// + [Test] + public void TestSaveToMemory() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + using (var s = new MemoryStream()) + { + imageFactory.Save(s); + s.Seek(0, SeekOrigin.Begin); + Assert.AreEqual(true, s.Capacity > 0); + } + } + } + } + /// /// Tests that a filter is really applied by checking that the image is modified /// From 913beeaa1b7edbb19e99b5c5ddd8d4cd0c441654 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 11:09:25 +0200 Subject: [PATCH 060/155] Removes unnecessary images Former-commit-id: b7abba38c2ce512bdd6706af08fdabd25537f8b7 --- .../Images/Chrysanthemum.jpg.REMOVED.git-id | 1 - src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id | 1 - src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id | 1 - src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id | 1 - src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id | 1 - 5 files changed, 5 deletions(-) delete mode 100644 src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id delete mode 100644 src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id delete mode 100644 src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id delete mode 100644 src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id delete mode 100644 src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id diff --git a/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id deleted file mode 100644 index d067665c9..000000000 --- a/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -757c2a628dd03b1cbe4b3ef07c153897a702b57a \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id deleted file mode 100644 index 228aac3ab..000000000 --- a/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -0b88c91336ff8073f34d21ccd683a01f0e0995da \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id deleted file mode 100644 index 74f69293c..000000000 --- a/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -8150b46ab27c62ba51aaba551eef3f1a30f08de9 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id deleted file mode 100644 index ce873d473..000000000 --- a/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -6ad3b846d4697584ff601ac481b14a4d3bbb5736 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id deleted file mode 100644 index aeca7b93c..000000000 --- a/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -db4d55a332254cd6b41336c06f207682bf5a966f \ No newline at end of file From d0d48a0f329d5a978beb5241a1014bd231d2f897 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 11:33:05 +0200 Subject: [PATCH 061/155] Filters the source images a bit, in order to speed up the unit tests + descriptive name Former-commit-id: eb53b2d6eef84df94cefa75642ac5be52af4e9e2 --- .../ImageProcessor.UnitTests.csproj | 132 ++++-------------- .../Images/autorotate.jpg.REMOVED.git-id | 1 + .../cmyk-profile-euroscale.jpg.REMOVED.git-id | 1 + .../Images/cmyk.jpg.REMOVED.git-id | 1 + .../color-vision-test.gif.REMOVED.git-id | 1 + .../Images/exif-Tulips.jpg.REMOVED.git-id | 1 + .../Images/exif-rocks.jpg.REMOVED.git-id | 1 + .../format-Penguins-8bit.png.REMOVED.git-id | 1 + .../Images/format-Penguins.bmp.REMOVED.git-id | 1 + .../Images/format-Penguins.gif.REMOVED.git-id | 1 + .../Images/format-Penguins.jpg.REMOVED.git-id | 1 + .../Images/format-Penguins.png.REMOVED.git-id | 1 + .../Images/format-Penguins.tif.REMOVED.git-id | 1 + .../Images/format-animated.gif | Bin 0 -> 22525 bytes .../Images/hi-color.png | Bin 0 -> 1539 bytes .../Images/hi-contrast.jpg | Bin 0 -> 51058 bytes .../Images/hi-saturation.jpg | Bin 0 -> 33850 bytes .../profile-adobe-rgb.jpg.REMOVED.git-id | 1 + .../Images/profile-srgb.jpg.REMOVED.git-id | 1 + .../Images/size-Penguins-200.jpg | Bin 0 -> 10119 bytes .../Images/text-over-transparent.png | Bin 0 -> 7317 bytes .../Images/udendørs.jpg.REMOVED.git-id | 1 + 22 files changed, 39 insertions(+), 108 deletions(-) create mode 100644 src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins.tif.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-animated.gif create mode 100644 src/ImageProcessor.UnitTests/Images/hi-color.png create mode 100644 src/ImageProcessor.UnitTests/Images/hi-contrast.jpg create mode 100644 src/ImageProcessor.UnitTests/Images/hi-saturation.jpg create mode 100644 src/ImageProcessor.UnitTests/Images/profile-adobe-rgb.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/profile-srgb.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/size-Penguins-200.jpg create mode 100644 src/ImageProcessor.UnitTests/Images/text-over-transparent.png create mode 100644 src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 4bb9bf77f..726d0988e 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -58,114 +58,27 @@ - - Images\Chrysanthemum.jpg - PreserveNewest - - - Images\Desert.jpg - PreserveNewest - - - Images\Hydrangeas.jpg - PreserveNewest - - - Images\Jellyfish.jpg - PreserveNewest - - - Images\Koala.jpg - PreserveNewest - - - Images\Lighthouse.jpg - PreserveNewest - - - Images\Penguins-8.png - PreserveNewest - - - Images\Penguins.bmp - PreserveNewest - - - Images\Penguins.gif - PreserveNewest - - - Images\Penguins.jpg - PreserveNewest - - - Images\Penguins.png - PreserveNewest - - - Images\Penguins.tif - PreserveNewest - - - Images\Tulips.jpg - PreserveNewest - - - Images\bus.jpg - PreserveNewest - - - Images\cmyk.jpg - PreserveNewest - - - Images\cmyk.png - PreserveNewest - - - Images\jrt.jpg - PreserveNewest - - - Images\meter.gif - PreserveNewest - - - Images\rocks.jpg - PreserveNewest - - - Images\rotate.jpg - PreserveNewest - - - Images\sample1.jpg - PreserveNewest - - - Images\srgb.jpg - PreserveNewest - - - Images\srgb.png - PreserveNewest - - - Images\text.png - PreserveNewest - - - Images\thor.jpg - PreserveNewest - - - Images\udendørs-374.jpg - PreserveNewest - - - Images\udendørs.jpg - PreserveNewest - + + + + + + + + + + + + + + + + + + + + + @@ -175,4 +88,7 @@ + + + \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id new file mode 100644 index 000000000..19785c8e5 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id @@ -0,0 +1 @@ +85a8ae18f9955def2b42ba9240bce4de1bfe5781 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id new file mode 100644 index 000000000..7747bdaae --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id @@ -0,0 +1 @@ +13492524f9d984c12adfe6183a4c1d92fb11ec4e \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id new file mode 100644 index 000000000..30b05146b --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id @@ -0,0 +1 @@ +ed725726e4ac1ffeac821664af14865a66fa933f \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id new file mode 100644 index 000000000..5c4f4195d --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id @@ -0,0 +1 @@ +35a926115b13b61dc37308f8d903b42d14f92924 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id new file mode 100644 index 000000000..84b9aff85 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id @@ -0,0 +1 @@ +54c51eb6a86f31a42433b8167470fb18dad32c7d \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id new file mode 100644 index 000000000..41c6c25df --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id @@ -0,0 +1 @@ +33b6912af301bf216ee81d82b2c3ce6c49e03021 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id new file mode 100644 index 000000000..aa9a70e0f --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id @@ -0,0 +1 @@ +c3d556d9d486b8b8b49cdbcc9c12a9d3a2db4c1f \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id new file mode 100644 index 000000000..74f69293c --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id @@ -0,0 +1 @@ +8150b46ab27c62ba51aaba551eef3f1a30f08de9 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id new file mode 100644 index 000000000..ce873d473 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id @@ -0,0 +1 @@ +6ad3b846d4697584ff601ac481b14a4d3bbb5736 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id new file mode 100644 index 000000000..ad4371113 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id @@ -0,0 +1 @@ +030ab8a685bebb796c24cc710edd9e69859164f6 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id new file mode 100644 index 000000000..78062a0e7 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id @@ -0,0 +1 @@ +a2c796fbb7de948230a22982ab74892891dd5198 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.tif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.tif.REMOVED.git-id new file mode 100644 index 000000000..5f7b97e71 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.tif.REMOVED.git-id @@ -0,0 +1 @@ +c789aaec248568c24394b05c02db4233e0c5a4eb \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-animated.gif b/src/ImageProcessor.UnitTests/Images/format-animated.gif new file mode 100644 index 0000000000000000000000000000000000000000..03fce3f3a5b70ca8463cefdd94c00e9c7fdbab0f GIT binary patch literal 22525 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 *EHnj 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 literal 0 HcmV?d00001 diff --git a/src/ImageProcessor.UnitTests/Images/hi-contrast.jpg b/src/ImageProcessor.UnitTests/Images/hi-contrast.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd2c9b90248231317b880634eac8f98f2dbdf6a7 GIT binary patch literal 51058 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 literal 0 HcmV?d00001 diff --git a/src/ImageProcessor.UnitTests/Images/hi-saturation.jpg b/src/ImageProcessor.UnitTests/Images/hi-saturation.jpg new file mode 100644 index 0000000000000000000000000000000000000000..909fa4fc55d43e54c2e4ef54021b1fb7275676a0 GIT binary patch literal 33850 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 literal 0 HcmV?d00001 diff --git a/src/ImageProcessor.UnitTests/Images/text-over-transparent.png b/src/ImageProcessor.UnitTests/Images/text-over-transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..21ebe3883c94844039cc07ad91487339b3ed1f34 GIT binary patch literal 7317 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 P0Kj7nJ@snU7ZLvfNs}N= literal 0 HcmV?d00001 diff --git a/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id new file mode 100644 index 000000000..0db1445a2 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id @@ -0,0 +1 @@ +4d040d9aa3519b3d2303419d1f03eebebf88e956 \ No newline at end of file From a8c29c35cd8475bd826c66b1ead7d9e337d1189e Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 11:57:53 +0200 Subject: [PATCH 062/155] Fixes test image includes Former-commit-id: ece5f07535519335d8e992d5831440c9ed9600be --- .../ImageProcessor.UnitTests.csproj | 84 ++++++++++++++----- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 726d0988e..4fbcc99b6 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -43,7 +43,9 @@ - + + PreserveNewest + @@ -59,26 +61,66 @@ - - - - - - - - - - - - - - - - - - - - + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + From b656a71168d2ebfed34dc3b38e754f657fa3637a Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Wed, 25 Jun 2014 23:59:37 +0200 Subject: [PATCH 063/155] Creates a new Mono project so it can at least build (not yet run) on Xamarin/Mono Former-commit-id: 73972cac708c4e8958f0c40a99a86a0c9884eebb --- src/ImageProcessor_Mono.sln | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/ImageProcessor_Mono.sln b/src/ImageProcessor_Mono.sln index 7d47a2ca6..d7e1410a8 100644 --- a/src/ImageProcessor_Mono.sln +++ b/src/ImageProcessor_Mono.sln @@ -18,6 +18,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E656C EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor\ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_MVC_NET4", "TestWebsites\NET4\Test_Website_MVC_NET4.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET4", "ImageProcessor.Web\NET4\ImageProcessor.Web_NET4.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", "ImageProcessor.Web\NET45\ImageProcessor.Web_NET45.csproj", "{D011A778-59C8-4BFA-A770-C350216BF161}" @@ -37,6 +39,24 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.ActiveCfg = All|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.Build.0 = All|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.ActiveCfg = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.Build.0 = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.ActiveCfg = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.Build.0 = All|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.ActiveCfg = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.Build.0 = Debug|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.Build.0 = Release|Any CPU + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.Build.0 = Release|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86 + {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86 {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU From 68131ae9b3f067df5777afe450a503c826caecd6 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Thu, 26 Jun 2014 00:08:55 +0200 Subject: [PATCH 064/155] Removes MVC test project from Mono solution because of heavy dependencies Former-commit-id: c4a57569c8eec272ba8ea994022eb937ef6e4d8a --- src/ImageProcessor_Mono.sln | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/ImageProcessor_Mono.sln b/src/ImageProcessor_Mono.sln index d7e1410a8..7d47a2ca6 100644 --- a/src/ImageProcessor_Mono.sln +++ b/src/ImageProcessor_Mono.sln @@ -18,8 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E656C EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor\ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_MVC_NET4", "TestWebsites\NET4\Test_Website_MVC_NET4.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET4", "ImageProcessor.Web\NET4\ImageProcessor.Web_NET4.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", "ImageProcessor.Web\NET45\ImageProcessor.Web_NET45.csproj", "{D011A778-59C8-4BFA-A770-C350216BF161}" @@ -39,24 +37,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.ActiveCfg = All|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.Build.0 = All|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.ActiveCfg = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.Build.0 = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.ActiveCfg = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.Build.0 = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.Build.0 = Debug|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.ActiveCfg = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.Build.0 = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.ActiveCfg = Release|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.Build.0 = Release|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.Build.0 = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86 {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU From 28432df6c65a6121206d3e7ab7d9a8d095c72efa Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 26 Jun 2014 22:30:08 +0100 Subject: [PATCH 065/155] Separating Unit Tests Hopefully rebuilding the projects will fix the AppVeyor issues. Former-commit-id: 61a12987b4f4c9324580f15b8f23b35c03876726 --- .../ImageProcessor.UnitTests.csproj | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 81516b4b6..96dfb17a2 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -65,6 +65,9 @@ ImageProcessor + + + @@ -72,6 +75,136 @@ + + + Images\1182076_e8c402e938_z.jpg + + + Images\bus.jpg + + + Images\Chrysanthemum.jpg + + + Images\circle.png + + + Images\cmyk.jpg + + + Images\cmyk.png + + + Images\color-vision-test.gif + + + Images\Desert.jpg + + + Images\emma.jpg + + + Images\falahill_design__160p.jpg + + + Images\fid11246.jpg + + + Images\fid9141.jpg + + + Images\header_1.jpg + + + Images\Hydrangeas.jpg + + + Images\Jellyfish.jpg + + + Images\jrt.jpg + + + Images\Koala.jpg + + + Images\Lighthouse.jpg + + + Images\lomo.jpg + + + Images\meter.gif + + + Images\negative.png + + + Images\negative2.png + + + Images\Penguins-200.jpg + + + Images\Penguins-8.png + + + Images\Penguins.bmp + + + Images\Penguins.gif + + + Images\Penguins.jpg + + + Images\Penguins.png + + + Images\Penguins.tif + + + Images\rocks.jpg + + + Images\rotate.jpg + + + Images\sample1.jpg + + + Images\srgb.jpg + + + Images\srgb.png + + + Images\text.png + + + Images\thor.jpg + + + Images\Tulips.jpg + + + Images\udendørs-374.jpg + + + Images\udendørs.jpg + + + Images\war_horse_quad.jpg + + + Images\WP_000009.jpg + + + + + {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} + ImageProcessor + From aca2f6e25353c2c5dc997922f602c6a0f490118e Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 26 Jun 2014 22:59:30 +0100 Subject: [PATCH 066/155] Moving Images in unit test Former-commit-id: 0448d1ccf9fad7e431636cbed45e6e7a3bf28cd2 --- .../ImageProcessor.UnitTests.csproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 96dfb17a2..981d8ded5 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -206,6 +206,14 @@ ImageProcessor + + + + + + + + From 2078cdcd289f331ebb462cd68e02d7b9f7f0ee92 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 15:42:31 +0200 Subject: [PATCH 067/155] Adds new test of factory for loading an image from a memory stream Former-commit-id: d97f8846fc92eaf59c5595b9af871b246bf71b9f --- .../ImageFactoryUnitTests.cs | 33 +++ .../ImageProcessor.UnitTests.csproj | 201 ++++++++++++------ src/ImageProcessor_Mono.sln | 26 ++- 3 files changed, 190 insertions(+), 70 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index a63f95ff2..1fc782073 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -51,5 +51,38 @@ namespace ImageProcessor.UnitTests Assert.IsNotNull(imageFactory.Image); } } + + /// > + /// Tests the loading of image from a memory stream + /// + /// + /// The file Name. + /// + /// + /// The expected mime type. + /// + [Test] + [TestCase("Chrysanthemum.jpg", "image/jpeg")] + [TestCase("Desert.jpg", "image/jpeg")] + [TestCase("cmyk.png", "image/png")] + [TestCase("Penguins.bmp", "image/bmp")] + [TestCase("Penguins.gif", "image/gif")] + public void TestLoadImageFromMemory(string fileName, string expectedMime) + { + string testPhoto = Path.Combine(this.localPath, string.Format("../../Images/{0}", fileName)); + byte[] photoBytes = File.ReadAllBytes(testPhoto); + + // ImageProcessor + using (MemoryStream inStream = new MemoryStream(photoBytes)) + { + using (ImageFactory imageFactory = new ImageFactory()) + { + imageFactory.Load(inStream); + Assert.AreEqual(null, imageFactory.ImagePath); + Assert.AreEqual(expectedMime, imageFactory.CurrentImageFormat.MimeType); + Assert.IsNotNull(imageFactory.Image); + } + } + } } } \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 981d8ded5..111f5e03c 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -1,67 +1,58 @@  - + Debug AnyCPU - {633B1C4C-4823-47BE-9A01-A665F3118C8C} + {03CA9055-F997-428C-BF28-F50F991777C6} Library - Properties ImageProcessor.UnitTests ImageProcessor.UnitTests - v4.0 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest + + ..\ true - + v4.5 true full false - bin\Debug\ - DEBUG;TRACE + bin\Debug + DEBUG; prompt 4 + false + false - pdbonly + full true - bin\Release\ - TRACE + bin\Release prompt 4 + false + false + + ..\packages\NUnit.2.6.3\lib\nunit.framework.dll - - + + - - - - - - - - - - - - + + + {D011A778-59C8-4BFA-A770-C350216BF161} + ImageProcessor.Web_NET45 + - {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} + {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} ImageProcessor @@ -208,32 +199,121 @@ - - - - - + + + Images\Chrysanthemum.jpg + PreserveNewest + + + Images\Desert.jpg + PreserveNewest + + + Images\Hydrangeas.jpg + PreserveNewest + + + Images\Jellyfish.jpg + PreserveNewest + + + Images\Koala.jpg + PreserveNewest + + + Images\Lighthouse.jpg + PreserveNewest + + + Images\Penguins-200.jpg + PreserveNewest + + + Images\Penguins-8.png + PreserveNewest + + + Images\Penguins.bmp + PreserveNewest + + + Images\Penguins.gif + PreserveNewest + + + Images\Penguins.jpg + PreserveNewest + + + Images\Penguins.png + PreserveNewest + + + Images\Penguins.tif + PreserveNewest + + + Images\Tulips.jpg + PreserveNewest + + + Images\bus.jpg + PreserveNewest + + + Images\cmyk.jpg + PreserveNewest + + + Images\cmyk.png + PreserveNewest + + + Images\jrt.jpg + PreserveNewest + + + Images\meter.gif + PreserveNewest + + + Images\rocks.jpg + PreserveNewest + + + Images\rotate.jpg + PreserveNewest + + + Images\sample1.jpg + PreserveNewest + + + Images\srgb.jpg + PreserveNewest + + + Images\srgb.png + PreserveNewest + + + Images\text.png + PreserveNewest + + + Images\thor.jpg + PreserveNewest + + + Images\udendørs-374.jpg + PreserveNewest + + + Images\udendørs.jpg + PreserveNewest + - - - - - False - - - False - - - False - - - False - - - - - - + @@ -241,11 +321,4 @@ - \ No newline at end of file diff --git a/src/ImageProcessor_Mono.sln b/src/ImageProcessor_Mono.sln index 7d47a2ca6..8b1e0fb37 100644 --- a/src/ImageProcessor_Mono.sln +++ b/src/ImageProcessor_Mono.sln @@ -3,12 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 VisualStudioVersion = 12.0.30110.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C427A497-74DC-49B1-8420-D6E68354F29B}" - ProjectSection(SolutionItems) = preProject - ImageProcessor.vsmdi = ImageProcessor.vsmdi - Local.testsettings = Local.testsettings - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E656CDE-124D-4FAF-837C-0EF1E192D418}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.Config = .nuget\NuGet.Config @@ -24,6 +18,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessorConsole", "ImageProcessorConsole\ImageProcessorConsole.csproj", "{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.UnitTests", "ImageProcessor.UnitTests\ImageProcessor.UnitTests.csproj", "{03CA9055-F997-428C-BF28-F50F991777C6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Any CPU = All|Any CPU @@ -37,6 +33,24 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {03CA9055-F997-428C-BF28-F50F991777C6}.All|Any CPU.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.All|Any CPU.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.All|Mixed Platforms.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.All|Mixed Platforms.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.All|x86.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.All|x86.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|x86.ActiveCfg = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Debug|x86.Build.0 = Debug|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Any CPU.Build.0 = Release|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|x86.ActiveCfg = Release|Any CPU + {03CA9055-F997-428C-BF28-F50F991777C6}.Release|x86.Build.0 = Release|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.ActiveCfg = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Any CPU.Build.0 = All|Any CPU {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}.All|Mixed Platforms.ActiveCfg = All|Any CPU From 91948689d3b313b68e08f50b3be07d4b3939a215 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 18:03:26 +0200 Subject: [PATCH 068/155] Loads all the test images + tests a few filters as well (failing for gif images) Former-commit-id: a0aacc78aeb810580ff7c3e0979502c3f60c5cd3 --- .../ImageFactoryUnitTests.cs | 106 +++++++++++------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 1fc782073..7cd124b19 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -12,6 +12,7 @@ namespace ImageProcessor.UnitTests { using System; using System.IO; + using System.Collections.Generic; using NUnit.Framework; /// @@ -25,62 +26,89 @@ namespace ImageProcessor.UnitTests /// private readonly string localPath = Path.GetDirectoryName(new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath); + /// + /// Lists the input files in the Images folder + /// + /// The list of files. + private static IEnumerable ListInputFiles() + { + return Directory.GetFiles("./Images"); + } + /// /// Tests the loading of image from a file /// - /// - /// The file Name. - /// - /// - /// The expected mime type. - /// [Test] - [TestCase("Chrysanthemum.jpg", "image/jpeg")] - [TestCase("Desert.jpg", "image/jpeg")] - [TestCase("cmyk.png", "image/png")] - [TestCase("Penguins.bmp", "image/bmp")] - [TestCase("Penguins.gif", "image/gif")] - public void TestLoadImageFromFile(string fileName, string expectedMime) + public void TestLoadImageFromFile() { - string testPhoto = Path.Combine(this.localPath, string.Format("../../Images/{0}", fileName)); - using (ImageFactory imageFactory = new ImageFactory()) + foreach (var fileName in ListInputFiles()) { - imageFactory.Load(testPhoto); - Assert.AreEqual(testPhoto, imageFactory.ImagePath); - Assert.AreEqual(expectedMime, imageFactory.CurrentImageFormat.MimeType); - Assert.IsNotNull(imageFactory.Image); + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + Assert.AreEqual(fileName, imageFactory.ImagePath); + Assert.IsNotNull(imageFactory.Image); + } } + } /// > /// Tests the loading of image from a memory stream /// - /// - /// The file Name. - /// - /// - /// The expected mime type. - /// [Test] - [TestCase("Chrysanthemum.jpg", "image/jpeg")] - [TestCase("Desert.jpg", "image/jpeg")] - [TestCase("cmyk.png", "image/png")] - [TestCase("Penguins.bmp", "image/bmp")] - [TestCase("Penguins.gif", "image/gif")] - public void TestLoadImageFromMemory(string fileName, string expectedMime) + public void TestLoadImageFromMemory() { - string testPhoto = Path.Combine(this.localPath, string.Format("../../Images/{0}", fileName)); - byte[] photoBytes = File.ReadAllBytes(testPhoto); + foreach (var fileName in ListInputFiles()) + { + byte[] photoBytes = File.ReadAllBytes(fileName); - // ImageProcessor - using (MemoryStream inStream = new MemoryStream(photoBytes)) + using (var inStream = new MemoryStream(photoBytes)) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(inStream); + Assert.AreEqual(null, imageFactory.ImagePath); + Assert.IsNotNull(imageFactory.Image); + } + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void ApplyEffectAlpha() + { + foreach (var fileName in ListInputFiles()) { - using (ImageFactory imageFactory = new ImageFactory()) + using (var imageFactory = new ImageFactory()) { - imageFactory.Load(inStream); - Assert.AreEqual(null, imageFactory.ImagePath); - Assert.AreEqual(expectedMime, imageFactory.CurrentImageFormat.MimeType); - Assert.IsNotNull(imageFactory.Image); + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Alpha(50); + var modified = imageFactory.Image.Clone(); + Assert.AreNotEqual(original, modified); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void ApplyEffectBrightness() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Brightness(50); + var modified = imageFactory.Image.Clone(); + Assert.AreNotEqual(original, modified); } } } From 7bab9971295809172d9c9e36b18f126c53dc3c4e Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 18:13:23 +0200 Subject: [PATCH 069/155] Adds test for constraints resize Former-commit-id: dca011a62587c43e6a59054c4949f09df14dbbf1 --- .../ImageFactoryUnitTests.cs | 24 +++++++++++++++---- .../ImageProcessor.UnitTests.csproj | 4 ---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 7cd124b19..b81cff068 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -21,11 +21,6 @@ namespace ImageProcessor.UnitTests [TestFixture] public class ImageFactoryUnitTests { - /// - /// The path to the binary's folder - /// - private readonly string localPath = Path.GetDirectoryName(new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath); - /// /// Lists the input files in the Images folder /// @@ -112,5 +107,24 @@ namespace ImageProcessor.UnitTests } } } + + /// + /// Tests that the image is well resized using constraints + /// + [Test] + public void ApplyConstraints() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Constrain(new System.Drawing.Size(200, 200)); + var modified = imageFactory.Image.Clone(); + Assert.AreNotEqual(original, modified); + } + } + } } } \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 111f5e03c..c0311d476 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -224,10 +224,6 @@ Images\Lighthouse.jpg PreserveNewest - - Images\Penguins-200.jpg - PreserveNewest - Images\Penguins-8.png PreserveNewest From 042294249307327c291fb5e73eb093faed9b611a Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 18:16:34 +0200 Subject: [PATCH 070/155] Checks that the image is actually resized Former-commit-id: c13de5b788d5fbd4f2d2224ed575cd667c8af838 --- .../ImageFactoryUnitTests.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index b81cff068..936c32345 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -83,8 +83,7 @@ namespace ImageProcessor.UnitTests imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); imageFactory.Alpha(50); - var modified = imageFactory.Image.Clone(); - Assert.AreNotEqual(original, modified); + Assert.AreNotEqual(original, imageFactory.Image); } } } @@ -102,8 +101,7 @@ namespace ImageProcessor.UnitTests imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); imageFactory.Brightness(50); - var modified = imageFactory.Image.Clone(); - Assert.AreNotEqual(original, modified); + Assert.AreNotEqual(original, imageFactory.Image); } } } @@ -114,15 +112,17 @@ namespace ImageProcessor.UnitTests [Test] public void ApplyConstraints() { + const int maxSize = 200; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); - imageFactory.Constrain(new System.Drawing.Size(200, 200)); - var modified = imageFactory.Image.Clone(); - Assert.AreNotEqual(original, modified); + imageFactory.Constrain(new System.Drawing.Size(maxSize, maxSize)); + Assert.AreNotEqual(original, imageFactory.Image); + Assert.LessOrEqual(maxSize, imageFactory.Image.Width); + Assert.LessOrEqual(maxSize, imageFactory.Image.Height); } } } From 8871af86b25a0ebe6bdaba7b77c3dcc9a4c49e0a Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 18:52:29 +0200 Subject: [PATCH 071/155] First fix of an animated gif problem on Mono Former-commit-id: 03c0f1246530ecead97e5346cebd197f77a72401 --- src/ImageProcessor/Imaging/Formats/FormatUtilities.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs index 36d2e3c07..3c6e3b3e0 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs @@ -135,12 +135,14 @@ namespace ImageProcessor.Imaging.Formats int frameCount = image.GetFrameCount(frameDimension); int last = frameCount - 1; int delay = 0; - int index = 0; List gifFrames = new List(); for (int i = 0; i < frameCount; i++) { - int thisDelay = BitConverter.ToInt32(image.GetPropertyItem(20736).Value, index); + // GDI returns a single array with all delays, while Mono returns a different array for each frame + image.SelectActiveFrame(frameDimension, i); + var times = image.GetPropertyItem(20736).Value; + int thisDelay = BitConverter.ToInt32(times, 4*i % times.Length); int toAddDelay = thisDelay * 10 < 20 ? 20 : thisDelay * 10; // Minimum delay is 20 ms // Find the frame @@ -156,7 +158,6 @@ namespace ImageProcessor.Imaging.Formats } delay += toAddDelay; - index += 4; } info.GifFrames = gifFrames; From ee654520687e9c45a48ef47c506f3164760350f5 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 20:48:03 +0200 Subject: [PATCH 072/155] Fixes a unit test (wrong parameters order) Former-commit-id: b691dc9582d00c8ef9b0160d69c59914a63ecb18 --- src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 936c32345..f81fd1c5b 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -121,8 +121,8 @@ namespace ImageProcessor.UnitTests var original = imageFactory.Image.Clone(); imageFactory.Constrain(new System.Drawing.Size(maxSize, maxSize)); Assert.AreNotEqual(original, imageFactory.Image); - Assert.LessOrEqual(maxSize, imageFactory.Image.Width); - Assert.LessOrEqual(maxSize, imageFactory.Image.Height); + Assert.LessOrEqual(imageFactory.Image.Width, maxSize); + Assert.LessOrEqual(imageFactory.Image.Height, maxSize); } } } From d4914a9a7fc5d60ab6aa2b038c3c41d85f7fd759 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 22:25:54 +0200 Subject: [PATCH 073/155] Re-fix of a Mono problem + modify some 'var' usage Former-commit-id: bbd7b29020665345032768961c448c64605620f9 --- src/ImageProcessor/ImageFactory.cs | 62 ++++++++++++++++-------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 540e34c9a..4a68a5e86 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -177,13 +177,13 @@ namespace ImageProcessor /// public ImageFactory Load(string imagePath) { - FileInfo fileInfo = new FileInfo(imagePath); + var fileInfo = new FileInfo(imagePath); if (fileInfo.Exists) { this.ImagePath = imagePath; // Open a file stream to prevent the need for lock. - using (FileStream fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read)) + using (var fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read)) { ISupportedImageFormat format = FormatUtilities.GetFormat(fileStream); @@ -192,7 +192,7 @@ namespace ImageProcessor throw new ImageFormatException("Input stream is not a supported format."); } - MemoryStream memoryStream = new MemoryStream(); + var memoryStream = new MemoryStream(); // Copy the stream. fileStream.CopyTo(memoryStream); @@ -240,7 +240,11 @@ namespace ImageProcessor if (this.ShouldProcess) { // Set our new image as the memory stream value. + #if !__MonoCS__ Image newImage = Image.FromStream(this.InputStream, true); + #else + Image newImage = Image.FromStream(this.InputStream); + #endif // Dispose and reassign the image. this.Image.Dispose(); @@ -275,7 +279,7 @@ namespace ImageProcessor percentage = 0; } - Alpha alpha = new Alpha { DynamicParameter = percentage }; + var alpha = new Alpha { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(alpha.ProcessImage, this); } @@ -293,7 +297,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - AutoRotate autoRotate = new AutoRotate(); + var autoRotate = new AutoRotate(); this.CurrentImageFormat.ApplyProcessor(autoRotate.ProcessImage, this); } @@ -320,7 +324,7 @@ namespace ImageProcessor percentage = 0; } - Brightness brightness = new Brightness { DynamicParameter = percentage }; + var brightness = new Brightness { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(brightness.ProcessImage, this); } @@ -340,7 +344,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - ResizeLayer layer = new ResizeLayer(size, ResizeMode.Max); + var layer = new ResizeLayer(size, ResizeMode.Max); return this.Resize(layer); } @@ -368,7 +372,7 @@ namespace ImageProcessor percentage = 0; } - Contrast contrast = new Contrast { DynamicParameter = percentage }; + var contrast = new Contrast { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(contrast.ProcessImage, this); } @@ -388,7 +392,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - CropLayer cropLayer = new CropLayer(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, CropMode.Pixels); + var cropLayer = new CropLayer(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, CropMode.Pixels); return this.Crop(cropLayer); } @@ -399,7 +403,7 @@ namespace ImageProcessor /// Crops the current image to the given location and size. /// /// - /// The containing the coordinates and mode to crop the image with. + /// The containing the coordinates and mode to crop the image with. /// /// /// The current instance of the class. @@ -408,7 +412,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - Crop crop = new Crop { DynamicParameter = cropLayer }; + var crop = new Crop { DynamicParameter = cropLayer }; this.CurrentImageFormat.ApplyProcessor(crop.ProcessImage, this); } @@ -429,7 +433,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - Filter filter = new Filter { DynamicParameter = matrixFilter }; + var filter = new Filter { DynamicParameter = matrixFilter }; this.CurrentImageFormat.ApplyProcessor(filter.ProcessImage, this); } @@ -449,11 +453,11 @@ namespace ImageProcessor { if (this.ShouldProcess) { - RotateFlipType rotateFlipType = flipVertically == false - ? RotateFlipType.RotateNoneFlipX - : RotateFlipType.RotateNoneFlipY; + RotateFlipType rotateFlipType = flipVertically + ? RotateFlipType.RotateNoneFlipY + : RotateFlipType.RotateNoneFlipX; - Flip flip = new Flip { DynamicParameter = rotateFlipType }; + var flip = new Flip { DynamicParameter = rotateFlipType }; this.CurrentImageFormat.ApplyProcessor(flip.ProcessImage, this); } @@ -496,7 +500,7 @@ namespace ImageProcessor { if (this.ShouldProcess && size > 0) { - GaussianLayer layer = new GaussianLayer(size); + var layer = new GaussianLayer(size); return this.GaussianBlur(layer); } @@ -517,7 +521,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - GaussianBlur gaussianBlur = new GaussianBlur { DynamicParameter = gaussianLayer }; + var gaussianBlur = new GaussianBlur { DynamicParameter = gaussianLayer }; this.CurrentImageFormat.ApplyProcessor(gaussianBlur.ProcessImage, this); } @@ -543,7 +547,7 @@ namespace ImageProcessor { if (this.ShouldProcess && size > 0) { - GaussianLayer layer = new GaussianLayer(size); + var layer = new GaussianLayer(size); return this.GaussianSharpen(layer); } @@ -564,7 +568,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - GaussianSharpen gaussianSharpen = new GaussianSharpen { DynamicParameter = gaussianLayer }; + var gaussianSharpen = new GaussianSharpen { DynamicParameter = gaussianLayer }; this.CurrentImageFormat.ApplyProcessor(gaussianSharpen.ProcessImage, this); } @@ -607,7 +611,7 @@ namespace ImageProcessor int width = size.Width; int height = size.Height; - ResizeLayer resizeLayer = new ResizeLayer(new Size(width, height)); + var resizeLayer = new ResizeLayer(new Size(width, height)); return this.Resize(resizeLayer); } @@ -629,7 +633,7 @@ namespace ImageProcessor { var resizeSettings = new Dictionary { { "MaxWidth", resizeLayer.Size.Width.ToString("G") }, { "MaxHeight", resizeLayer.Size.Height.ToString("G") } }; - Resize resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings }; + var resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings }; this.CurrentImageFormat.ApplyProcessor(resize.ProcessImage, this); } @@ -655,7 +659,7 @@ namespace ImageProcessor degrees = 0; } - Rotate rotate = new Rotate { DynamicParameter = degrees }; + var rotate = new Rotate { DynamicParameter = degrees }; this.CurrentImageFormat.ApplyProcessor(rotate.ProcessImage, this); } @@ -680,7 +684,7 @@ namespace ImageProcessor roundedCornerLayer.Radius = 0; } - RoundedCorners roundedCorners = new RoundedCorners { DynamicParameter = roundedCornerLayer }; + var roundedCorners = new RoundedCorners { DynamicParameter = roundedCornerLayer }; this.CurrentImageFormat.ApplyProcessor(roundedCorners.ProcessImage, this); } @@ -707,7 +711,7 @@ namespace ImageProcessor percentage = 0; } - Saturation saturate = new Saturation { DynamicParameter = percentage }; + var saturate = new Saturation { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(saturate.ProcessImage, this); } @@ -727,7 +731,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - Tint tint = new Tint { DynamicParameter = color }; + var tint = new Tint { DynamicParameter = color }; this.CurrentImageFormat.ApplyProcessor(tint.ProcessImage, this); } @@ -747,7 +751,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - Vignette vignette = new Vignette + var vignette = new Vignette { DynamicParameter = color.HasValue && !color.Equals(Color.Transparent) ? color.Value @@ -774,7 +778,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - Watermark watermark = new Watermark { DynamicParameter = textLayer }; + var watermark = new Watermark { DynamicParameter = textLayer }; this.CurrentImageFormat.ApplyProcessor(watermark.ProcessImage, this); } @@ -796,7 +800,7 @@ namespace ImageProcessor if (this.ShouldProcess) { // ReSharper disable once AssignNullToNotNullAttribute - DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(filePath)); + var directoryInfo = new DirectoryInfo(Path.GetDirectoryName(filePath)); if (!directoryInfo.Exists) { directoryInfo.Create(); From 0712c08c594448ae0932349b0f7b9459b7f96ee9 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 22:53:25 +0200 Subject: [PATCH 074/155] Adds a few more unit tests Former-commit-id: e7407d2bc753aac4bf9f3f0acf55d160149efb68 --- .../ImageFactoryUnitTests.cs | 122 +++++++++++++++++- 1 file changed, 119 insertions(+), 3 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index f81fd1c5b..ac5de24a4 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -74,7 +74,7 @@ namespace ImageProcessor.UnitTests /// Tests that a filter is really applied by checking that the image is modified /// [Test] - public void ApplyEffectAlpha() + public void TestApplyEffectAlpha() { foreach (var fileName in ListInputFiles()) { @@ -92,7 +92,7 @@ namespace ImageProcessor.UnitTests /// Tests that a filter is really applied by checking that the image is modified /// [Test] - public void ApplyEffectBrightness() + public void TestApplyEffectBrightness() { foreach (var fileName in ListInputFiles()) { @@ -106,11 +106,85 @@ namespace ImageProcessor.UnitTests } } + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectContrast() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Contrast(50); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that all filters can be applied + /// + [Test] + public void TestApplyEffectFilter() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.BlackWhite); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Comic); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Gotham); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.GreyScale); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.HiSatch); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Invert); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Lomograph); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.LoSatch); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Polaroid); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + + imageFactory.Filter(Imaging.Filters.MatrixFilters.Sepia); + Assert.AreNotEqual(original, imageFactory.Image); + imageFactory.Reset(); + } + } + } + /// /// Tests that the image is well resized using constraints /// [Test] - public void ApplyConstraints() + public void TestResizeConstraints() { const int maxSize = 200; foreach (var fileName in ListInputFiles()) @@ -126,5 +200,47 @@ namespace ImageProcessor.UnitTests } } } + + /// + /// Tests that the image is well cropped + /// + [Test] + public void TestCrop() + { + const int maxSize = 20; + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Crop(new System.Drawing.Rectangle(0, 0, maxSize, maxSize)); + Assert.AreNotEqual(original, imageFactory.Image); + Assert.AreEqual(maxSize, imageFactory.Image.Width); + Assert.LessOrEqual(maxSize, imageFactory.Image.Height); + } + } + } + + /// + /// Tests that the image is well cropped + /// + [Test] + public void TestCropWithCropLayer() + { + const int maxSize = 20; + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Crop(new Imaging.CropLayer(0, 0, maxSize, maxSize, Imaging.CropMode.Pixels)); + Assert.AreNotEqual(original, imageFactory.Image); + Assert.AreEqual(maxSize, imageFactory.Image.Width); + Assert.LessOrEqual(maxSize, imageFactory.Image.Height); + } + } + } } } \ No newline at end of file From f9561cead061b903479231882efa56399f5e464e Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 23:11:58 +0200 Subject: [PATCH 075/155] Adds a few more unit tests Former-commit-id: dbb26885a48c55480ce771d885a46d7726af0576 --- .../ImageFactoryUnitTests.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index ac5de24a4..7dd09e078 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -124,6 +124,42 @@ namespace ImageProcessor.UnitTests } } + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectBlur() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.GaussianBlur(5); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectBlurWithLayer() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.GaussianBlur(new Imaging.GaussianLayer() { Sigma = 10, Size = 5, Threshold = 2 }); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + /// /// Tests that all filters can be applied /// @@ -242,5 +278,31 @@ namespace ImageProcessor.UnitTests } } } + + /// + /// Tests that the image is flipped + /// + [Test] + public void TestFlip() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = (System.Drawing.Image)imageFactory.Image.Clone(); + imageFactory.Flip(true); + Assert.AreNotEqual(original, imageFactory.Image); + Assert.AreEqual(original.Width, imageFactory.Image.Width); + Assert.AreEqual(original.Height, imageFactory.Image.Height); + imageFactory.Reset(); + + imageFactory.Flip(false); + Assert.AreNotEqual(original, imageFactory.Image); + Assert.AreEqual(original.Width, imageFactory.Image.Width); + Assert.AreEqual(original.Height, imageFactory.Image.Height); + } + } + } } } \ No newline at end of file From eba58ebf8e0b4f004b093812d17f5aa873355978 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sat, 28 Jun 2014 23:22:35 +0200 Subject: [PATCH 076/155] Adds a few more unit tests Former-commit-id: f0987ec15552263ee8b2915d25d51514b5db2c31 --- .../ImageFactoryUnitTests.cs | 82 ++++++++++++++++++- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 7dd09e078..60db9a8ee 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -154,7 +154,43 @@ namespace ImageProcessor.UnitTests { imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); - imageFactory.GaussianBlur(new Imaging.GaussianLayer() { Sigma = 10, Size = 5, Threshold = 2 }); + imageFactory.GaussianBlur(new Imaging.GaussianLayer { Sigma = 10, Size = 5, Threshold = 2 }); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectSharpen() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.GaussianSharpen(5); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectSharpenWithLayer() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.GaussianSharpen(new Imaging.GaussianLayer { Sigma = 10, Size = 5, Threshold = 2 }); Assert.AreNotEqual(original, imageFactory.Image); } } @@ -228,9 +264,7 @@ namespace ImageProcessor.UnitTests using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); imageFactory.Constrain(new System.Drawing.Size(maxSize, maxSize)); - Assert.AreNotEqual(original, imageFactory.Image); Assert.LessOrEqual(imageFactory.Image.Width, maxSize); Assert.LessOrEqual(imageFactory.Image.Height, maxSize); } @@ -304,5 +338,47 @@ namespace ImageProcessor.UnitTests } } } + + /// + /// Tests that the image is resized + /// + [Test] + public void TestResize() + { + const int newSize = 150; + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + imageFactory.Resize(new System.Drawing.Size(newSize, newSize)); + Assert.AreEqual(newSize, imageFactory.Image.Width); + Assert.AreEqual(newSize, imageFactory.Image.Height); + } + } + } + + /// + /// Tests that the image is resized + /// + [Test] + public void TestResizeWithLayer() + { + const int newSize = 150; + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + imageFactory.Resize(new Imaging.ResizeLayer( + new System.Drawing.Size(newSize, newSize), + Imaging.ResizeMode.Stretch, + Imaging.AnchorPosition.Left, + true)); + Assert.AreEqual(newSize, imageFactory.Image.Width); + Assert.AreEqual(newSize, imageFactory.Image.Height); + } + } + } } } \ No newline at end of file From e4a74e2e5aa23ac8a2578670cbd34d34463ff517 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 00:37:38 +0200 Subject: [PATCH 077/155] Yet a few other unit tests Former-commit-id: bd37755a47b8159d62b6eeb906fe8514ec51aad2 --- .../ImageFactoryUnitTests.cs | 182 ++++++++++++++---- 1 file changed, 146 insertions(+), 36 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 60db9a8ee..d868b2245 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -11,8 +11,8 @@ namespace ImageProcessor.UnitTests { using System; - using System.IO; using System.Collections.Generic; + using System.IO; using NUnit.Framework; /// @@ -21,15 +21,6 @@ namespace ImageProcessor.UnitTests [TestFixture] public class ImageFactoryUnitTests { - /// - /// Lists the input files in the Images folder - /// - /// The list of files. - private static IEnumerable ListInputFiles() - { - return Directory.GetFiles("./Images"); - } - /// /// Tests the loading of image from a file /// @@ -45,10 +36,9 @@ namespace ImageProcessor.UnitTests Assert.IsNotNull(imageFactory.Image); } } - } - /// > + /// /// Tests the loading of image from a memory stream /// [Test] @@ -124,6 +114,84 @@ namespace ImageProcessor.UnitTests } } + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectSaturation() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Saturation(50); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectTint() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Tint(System.Drawing.Color.FromKnownColor(System.Drawing.KnownColor.AliceBlue)); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectVignette() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Vignette(System.Drawing.Color.FromKnownColor(System.Drawing.KnownColor.AliceBlue)); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestApplyEffectWatermark() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.Watermark(new Imaging.TextLayer + { + Font = "Arial", + FontSize = 10, + Position = new System.Drawing.Point(10, 10), + Text = "Lorem ipsum dolor" + }); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + /// /// Tests that a filter is really applied by checking that the image is modified /// @@ -252,21 +320,39 @@ namespace ImageProcessor.UnitTests } } + /// + /// Tests that a filter is really applied by checking that the image is modified + /// + [Test] + public void TestRoundedCorners() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = imageFactory.Image.Clone(); + imageFactory.RoundedCorners(new Imaging.RoundedCornerLayer(5, true, true, true, true)); + Assert.AreNotEqual(original, imageFactory.Image); + } + } + } + /// /// Tests that the image is well resized using constraints /// [Test] public void TestResizeConstraints() { - const int maxSize = 200; + const int MaxSize = 200; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); - imageFactory.Constrain(new System.Drawing.Size(maxSize, maxSize)); - Assert.LessOrEqual(imageFactory.Image.Width, maxSize); - Assert.LessOrEqual(imageFactory.Image.Height, maxSize); + imageFactory.Constrain(new System.Drawing.Size(MaxSize, MaxSize)); + Assert.LessOrEqual(imageFactory.Image.Width, MaxSize); + Assert.LessOrEqual(imageFactory.Image.Height, MaxSize); } } } @@ -277,17 +363,17 @@ namespace ImageProcessor.UnitTests [Test] public void TestCrop() { - const int maxSize = 20; + const int MaxSize = 20; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); - imageFactory.Crop(new System.Drawing.Rectangle(0, 0, maxSize, maxSize)); + imageFactory.Crop(new System.Drawing.Rectangle(0, 0, MaxSize, MaxSize)); Assert.AreNotEqual(original, imageFactory.Image); - Assert.AreEqual(maxSize, imageFactory.Image.Width); - Assert.LessOrEqual(maxSize, imageFactory.Image.Height); + Assert.AreEqual(MaxSize, imageFactory.Image.Width); + Assert.LessOrEqual(MaxSize, imageFactory.Image.Height); } } } @@ -298,17 +384,17 @@ namespace ImageProcessor.UnitTests [Test] public void TestCropWithCropLayer() { - const int maxSize = 20; + const int MaxSize = 20; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); var original = imageFactory.Image.Clone(); - imageFactory.Crop(new Imaging.CropLayer(0, 0, maxSize, maxSize, Imaging.CropMode.Pixels)); + imageFactory.Crop(new Imaging.CropLayer(0, 0, MaxSize, MaxSize, Imaging.CropMode.Pixels)); Assert.AreNotEqual(original, imageFactory.Image); - Assert.AreEqual(maxSize, imageFactory.Image.Width); - Assert.LessOrEqual(maxSize, imageFactory.Image.Height); + Assert.AreEqual(MaxSize, imageFactory.Image.Width); + Assert.LessOrEqual(MaxSize, imageFactory.Image.Height); } } } @@ -345,15 +431,15 @@ namespace ImageProcessor.UnitTests [Test] public void TestResize() { - const int newSize = 150; + const int NewSize = 150; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); - imageFactory.Resize(new System.Drawing.Size(newSize, newSize)); - Assert.AreEqual(newSize, imageFactory.Image.Width); - Assert.AreEqual(newSize, imageFactory.Image.Height); + imageFactory.Resize(new System.Drawing.Size(NewSize, NewSize)); + Assert.AreEqual(NewSize, imageFactory.Image.Width); + Assert.AreEqual(NewSize, imageFactory.Image.Height); } } } @@ -364,21 +450,45 @@ namespace ImageProcessor.UnitTests [Test] public void TestResizeWithLayer() { - const int newSize = 150; + const int NewSize = 150; foreach (var fileName in ListInputFiles()) { using (var imageFactory = new ImageFactory()) { imageFactory.Load(fileName); - imageFactory.Resize(new Imaging.ResizeLayer( - new System.Drawing.Size(newSize, newSize), - Imaging.ResizeMode.Stretch, - Imaging.AnchorPosition.Left, - true)); - Assert.AreEqual(newSize, imageFactory.Image.Width); - Assert.AreEqual(newSize, imageFactory.Image.Height); + imageFactory.Resize(new Imaging.ResizeLayer(new System.Drawing.Size(NewSize, NewSize), Imaging.ResizeMode.Stretch, Imaging.AnchorPosition.Left)); + Assert.AreEqual(NewSize, imageFactory.Image.Width); + Assert.AreEqual(NewSize, imageFactory.Image.Height); } } } + + /// + /// Tests that the image is resized + /// + [Test] + public void TestRotate() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + var original = (System.Drawing.Image)imageFactory.Image.Clone(); + imageFactory.Rotate(90); + Assert.AreEqual(original.Height, imageFactory.Image.Width); + Assert.AreEqual(original.Width, imageFactory.Image.Height); + } + } + } + + /// + /// Lists the input files in the Images folder + /// + /// The list of files. + private static IEnumerable ListInputFiles() + { + return Directory.GetFiles("./Images"); + } } } \ No newline at end of file From ad744d5ab6d562dc602859c3c864529fc28cba44 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 00:41:53 +0200 Subject: [PATCH 078/155] Adds tests for saving the files Former-commit-id: bab7f1273663d36a546e323f680cac1d7c622284 --- .../ImageFactoryUnitTests.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index d868b2245..880871cc7 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -60,6 +60,45 @@ namespace ImageProcessor.UnitTests } } + /// + /// Tests that the save method actually saves a file + /// + [Test] + public void TestSaveToDisk() + { + foreach (var fileName in ListInputFiles()) + { + var outputFileName = string.Format("./output/{0}", Path.GetFileName(fileName)); + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + imageFactory.Save(outputFileName); + Assert.AreEqual(true, File.Exists(outputFileName)); + } + } + } + + /// + /// Tests that the save method actually writes to memory + /// + [Test] + public void TestSaveToMemory() + { + foreach (var fileName in ListInputFiles()) + { + using (var imageFactory = new ImageFactory()) + { + imageFactory.Load(fileName); + using (var s = new MemoryStream()) + { + imageFactory.Save(s); + s.Seek(0, SeekOrigin.Begin); + Assert.AreEqual(true, s.Capacity > 0); + } + } + } + } + /// /// Tests that a filter is really applied by checking that the image is modified /// From 2b748ce683502cfb4be9aebd760007fd41a16e44 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 11:09:25 +0200 Subject: [PATCH 079/155] Removes unnecessary images Former-commit-id: 2b75ccda89d49667260a2d21b0c5ea7754107f3a --- .../Images/Chrysanthemum.jpg.REMOVED.git-id | 1 - src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id | 1 - src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id | 1 - src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id | 1 - src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id | 1 - 5 files changed, 5 deletions(-) delete mode 100644 src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id delete mode 100644 src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id delete mode 100644 src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id delete mode 100644 src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id delete mode 100644 src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id diff --git a/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id deleted file mode 100644 index d067665c9..000000000 --- a/src/ImageProcessor.UnitTests/Images/Chrysanthemum.jpg.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -757c2a628dd03b1cbe4b3ef07c153897a702b57a \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id deleted file mode 100644 index 228aac3ab..000000000 --- a/src/ImageProcessor.UnitTests/Images/Desert.jpg.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -0b88c91336ff8073f34d21ccd683a01f0e0995da \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id deleted file mode 100644 index 74f69293c..000000000 --- a/src/ImageProcessor.UnitTests/Images/Penguins.bmp.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -8150b46ab27c62ba51aaba551eef3f1a30f08de9 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id deleted file mode 100644 index ce873d473..000000000 --- a/src/ImageProcessor.UnitTests/Images/Penguins.gif.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -6ad3b846d4697584ff601ac481b14a4d3bbb5736 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id deleted file mode 100644 index aeca7b93c..000000000 --- a/src/ImageProcessor.UnitTests/Images/cmyk.png.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -db4d55a332254cd6b41336c06f207682bf5a966f \ No newline at end of file From 6ffa901479968d83ada5d48e0eaa40bbaaf89f68 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 11:33:05 +0200 Subject: [PATCH 080/155] Filters the source images a bit, in order to speed up the unit tests + descriptive name Former-commit-id: bcdb5097fee49ef671a3150815e1a7b4f11721fd --- .../ImageProcessor.UnitTests.csproj | 24 ++++++++++++++++++ .../Images/autorotate.jpg.REMOVED.git-id | 1 + .../cmyk-profile-euroscale.jpg.REMOVED.git-id | 1 + .../Images/cmyk.jpg.REMOVED.git-id | 1 + .../color-vision-test.gif.REMOVED.git-id | 1 + .../Images/exif-Tulips.jpg.REMOVED.git-id | 1 + .../Images/exif-rocks.jpg.REMOVED.git-id | 1 + .../format-Penguins-8bit.png.REMOVED.git-id | 1 + .../Images/format-Penguins.bmp.REMOVED.git-id | 1 + .../Images/format-Penguins.gif.REMOVED.git-id | 1 + .../Images/format-Penguins.jpg.REMOVED.git-id | 1 + .../Images/format-Penguins.png.REMOVED.git-id | 1 + .../Images/format-Penguins.tif.REMOVED.git-id | 1 + .../Images/format-animated.gif | Bin 0 -> 22525 bytes .../Images/hi-color.png | Bin 0 -> 1539 bytes .../Images/hi-contrast.jpg | Bin 0 -> 51058 bytes .../Images/hi-saturation.jpg | Bin 0 -> 33850 bytes .../profile-adobe-rgb.jpg.REMOVED.git-id | 1 + .../Images/profile-srgb.jpg.REMOVED.git-id | 1 + .../Images/size-Penguins-200.jpg | Bin 0 -> 10119 bytes .../Images/text-over-transparent.png | Bin 0 -> 7317 bytes .../Images/udendørs.jpg.REMOVED.git-id | 1 + 22 files changed, 39 insertions(+) create mode 100644 src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-Penguins.tif.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/format-animated.gif create mode 100644 src/ImageProcessor.UnitTests/Images/hi-color.png create mode 100644 src/ImageProcessor.UnitTests/Images/hi-contrast.jpg create mode 100644 src/ImageProcessor.UnitTests/Images/hi-saturation.jpg create mode 100644 src/ImageProcessor.UnitTests/Images/profile-adobe-rgb.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/profile-srgb.jpg.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/size-Penguins-200.jpg create mode 100644 src/ImageProcessor.UnitTests/Images/text-over-transparent.png create mode 100644 src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index c0311d476..4d47bb062 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -308,6 +308,27 @@ Images\udendørs.jpg PreserveNewest + + + + + + + + + + + + + + + + + + + + + @@ -317,4 +338,7 @@ + + + \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id new file mode 100644 index 000000000..19785c8e5 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id @@ -0,0 +1 @@ +85a8ae18f9955def2b42ba9240bce4de1bfe5781 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id new file mode 100644 index 000000000..7747bdaae --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id @@ -0,0 +1 @@ +13492524f9d984c12adfe6183a4c1d92fb11ec4e \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id new file mode 100644 index 000000000..30b05146b --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id @@ -0,0 +1 @@ +ed725726e4ac1ffeac821664af14865a66fa933f \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id new file mode 100644 index 000000000..5c4f4195d --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id @@ -0,0 +1 @@ +35a926115b13b61dc37308f8d903b42d14f92924 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id new file mode 100644 index 000000000..84b9aff85 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id @@ -0,0 +1 @@ +54c51eb6a86f31a42433b8167470fb18dad32c7d \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id new file mode 100644 index 000000000..41c6c25df --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id @@ -0,0 +1 @@ +33b6912af301bf216ee81d82b2c3ce6c49e03021 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id new file mode 100644 index 000000000..aa9a70e0f --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id @@ -0,0 +1 @@ +c3d556d9d486b8b8b49cdbcc9c12a9d3a2db4c1f \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id new file mode 100644 index 000000000..74f69293c --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id @@ -0,0 +1 @@ +8150b46ab27c62ba51aaba551eef3f1a30f08de9 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id new file mode 100644 index 000000000..ce873d473 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id @@ -0,0 +1 @@ +6ad3b846d4697584ff601ac481b14a4d3bbb5736 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id new file mode 100644 index 000000000..ad4371113 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id @@ -0,0 +1 @@ +030ab8a685bebb796c24cc710edd9e69859164f6 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id new file mode 100644 index 000000000..78062a0e7 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id @@ -0,0 +1 @@ +a2c796fbb7de948230a22982ab74892891dd5198 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.tif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.tif.REMOVED.git-id new file mode 100644 index 000000000..5f7b97e71 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.tif.REMOVED.git-id @@ -0,0 +1 @@ +c789aaec248568c24394b05c02db4233e0c5a4eb \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-animated.gif b/src/ImageProcessor.UnitTests/Images/format-animated.gif new file mode 100644 index 0000000000000000000000000000000000000000..03fce3f3a5b70ca8463cefdd94c00e9c7fdbab0f GIT binary patch literal 22525 zcmX7PWmFUH`}a0h^hik^xlu}sgpBU)l7S$tqZLW2VQLjocq1AKx)BJPCvhDU_Q zL=|W#4XZ0Is>|k@sr4CLd#E@9vcn6V?;#GiPDA>0~nH=lsOQ zb2d2OIM^#D(K#k5CWmk%J2SGbG_0y7zO63yMOsu?d}35eN@`|WL3VmpepYcwW_nJ3 zdSPL4MR8qaPGwDbV?#;F{pz}^rqcSlhSrAe_QtlZ_MYCBmWQ1!J>9*-gR6O2+a(2y zJwiI> z#TT!hQ|4bTt*oscuPnXYe7n2*cJ1Bf{>J9U_U6Zf-IK$;FUN=9zJEUWdi?9lx6h~F z|Ni|0004x3fx(df-TyI~>)G1qXj$sXUzVi<{wqoUJAnT^697iTCnO~kQc_bQo$Q^m z?Q-lK9dq&u^79LF%L>bgB}Ju`)s=a5_4n(m%J0_@TiSD*Ivd)m?R&~gy6PVG*EWwh zIt?|oHa;0E>+2uRb+WUuo2VXanyAZOeKs>Qu<)XJ+$kV3ZTG|8{;nw>4DcCnbo}l6 z$?1=uXTQ#W|M^S%4?xEtVAw$#PyPcI?Kl!K8%jew;|)H#U6q&xW$~SyVZ#Ffpbzx2 z2y1sE!msN;)FeptcsfzHp=HDF4~byq0CBQks1K-2=E|I|QBTv0TEp%8U|9?uM+jSO z)v!XRa3USEfbTP+R`SXtw?R*eabMe;Zr_(JZu5QZ>-{v`c3%*&NZPGE>|jo29jWzh z4FCJQ?jY1>u|f^kas|7JMlXXoyGqSEE!!wYwA&fQg7Ga-#vFTYH-ly*dX z#nUnIVF(zjy1u;ifq)fpZ7?L0gPhEG>GHs)x(*z`E}!og~9czksn_^WWe4(ycm7_?1uxf>23UQf&YxAZp8}~ zBDb>@CwxSLXXRk-;g64tMWWt&tUMtudo=RjHWa5d*X0j!X}M&Y=toxsS!ri@71(IM z*(r9t=m#!xu+H!<@w(+BP&SzN%c~&ZwQ^m74&NKGJTwol8(YZJjK+$kDL*gPpoBL& z^hjTflOCTRAT8}9;V1{l;%liLgeGA3fx?+Q77bt=m_xrcMeFakK$D@D4n2h0XI2@4BT~T~xc`b3f?2%^N;d%M0fImVGUty%5@LsR=uHzmFSvvcTr&m;W41u8TMygC4(4-fy~6o&#;- z&-|laWMMIIy2?s;G$m_PW&WB5#abqPdQ=|tCF!RW8zD}ay{sOZt;wJ^&a3_TBc zkw)vjGpTvNjB$X> zQAwwT9su|QQ1uFg+9SQ|>_bN>vg+_rG!_8yB_sSu=_j6N<1s+YU3Dhm>xyJxL_H31 z5yz}X7*IrBhFr8Toz9z{5mmaxPIwru8;8usfgy#+P6L$QAgi<1aRG@SCarO8UN4g%_Oew_ zkDaI>HgGFmZ_w}&Mfjm7-}llPCdS?c?ZjKE1)u;w@!q;JpszK?@%ci7a{n9C9>}BPK`n*zqFIQN|_xnfLDAm?qrjbb;<@4Vb+}SBJN#43)EL8lZ>$odP z-gTEZgjW(S+6plM_p1^2nsmQE5eAu^)bKoO(!V-qMMKEd!1J5*uANgd^H1s!;rn+l zu05b1Tz18d`_KWR5pF~JtbFMGIRPT&Q502+@h{pq&3L(n@3hIlO~U%Bs&$QOVI7CR zuZhbi+NBanc*Abx$31}#4&@!r(%*0apa-9AkY0E*uLd!(GV^txy`2^1hE$iBa; zM_bTL!lYu3M8~|}&e_#s&|PF#4w}5_%!}t*1?t|d43wu&YW6}^AbZdET)F2C?<&SV zTx~k-W@7l9gb7$#y0P39qbFngtHpNY{8df6hK#$`(8?$SyrVz9B`CvJ2rdLK*VOU? zp*;x?B@WZR@!WR!#!;}%a1$`|M1-X?(_z8$tS)Nuinv6^ z>6~lCY)Ke}u2S9g32=*=c3s{xFI&5fKeOoLjG=i~e#yd)xZ1B-%bc#lMpJJw{y{i- zJS6M8j^~S_ka4C(xphQqqS7f<-^c%3P%-&~^6;-`xSa0FJ<~na^^R~;DJg>R%oH)U`{Oq=! z+UDD@ufr>2p9P9?9?$>5_r(9FHwCq%f(I9sx^27;oFmKWUvi)JHXa29s{GkR+*RQd zzmY0k2xPu6rou-iLUKYY*|6}z8NI6D>|s`-7u~)b<@0NNV2O;LwMz)Ay1B8&BVSte)x0rJ?-sRJnIM* zW)U^YK|6|{9^P^p{W+#EdMq&(`}V?E$h6Ci$ozvSEQf-uKbet+CCs8H>?xCC~qS zQ2Xx}C3p0sG53!m<}UMV3mRY3^S@tW|NA|6W%O*?BH@_z(oq=ewMmWoaljywqJi6!s*WPu10P3$KfpT&?r2-6wfe#XIjOxoZ%5XiR?UycVrW} zqY`;a6Zx9(&wUb7`h!31;r5Ed^)SFJ8$_4G-F#)?;Vpn375>IDh)4qjS6_%)FNx!a z!$PolH8kvcQ?lxQvbG8#1PhC>BH5Wi%(NqgB`?c@UM>7fd@6Y#T#? ztC4i@M2-FAP$Vo82}_HDWv`~^oTU?aGV)b23LP_wqcTcM(<6u(_o4{;GZ`eF%o>%< zf`JTTI^jW6s>d0AW-l=Vmb6Mrumk9W6Vra|Vm%8a;z}W&xR_3rVC8{$CdZUeOy<+5 z?3vQ+*;3ftYWCt;c4ZU6aTOof5kGYys$n`<2z!%;_BHrXl660yi;oH(X^QOhO}^6s zW%f;{_-03wv$Ns3)n_?hSJO|Ta?hf2>(IHyGr75rxu4;gw6k0QFA;bRmZowqXg@O^ z1@$CCo$#PI+pGv%fRrI%%NK$@B1WU2f~fSFtJ#OX#2@?V3sLz$n_w|VImx7a>lZ?) z)cmIEe0d4@<>ve|ILr?K-KN0ei7=InT+L|MS2)ax?B@i4=^7O#5Ocrs6kh*Wkbo($ z{aA=GDsqf2kfLXEdQ)_RxA0tr__>tGP=;qJgR+)EG-UHYY@B@9yco2w{CDNuRbtW% z^uRH@2Avycl&hPOe=?AtFqp4vL@TgqR`>uYP>SY@#=`IM7DW>wA`}^G94y`vE*o8@ z`38ow1iK|7^{}uKBbLlJr8Xb)<2zvGA7Sx;0+}~O>AV#LWU2jNA;d4=L?RO|L11*e zm$aH?Cv>-kkmhN?S}tFLvMfgco*92v^jf`3+)Arak>I9r~^Tci1_ z(0@%RFs4Y-xh_l+9!Z4mP+;oD;L~Upz16}ixV!{tKW0C?~qcggxySOeU#;jd%qj!{LyTw&>(!bkq) z-4d2RBuRAV z$uxK=$&uVVVZ?d~Sp8t_>V5eVAprD(Ki;OiCDSqERdlIx^nF|2f}@uE-PayveQX;v z=5jlRrV}BCAz)LoegXiNGNG1olry^q^QCg088_lS6@6K2K`=Hp(iay-wOdIxtbg(a z9k(9>O8$J1?PQm5!adwCZ;3I=IB{e-nd|z=S8!#$<8v7l6w5a;1a&$BYa7F@u@cpO z@SJ@Z)C-2Daz2Y`v?ha@N+K=gAbfa;yh&YVbU`C;=NJD{)_~r^mX>*5-W<}cx}Efk4`=#%|ykTj^$!M_dX z>Wg5r4Q^|V?uZ~2ILSgRsEBw=*FSUUcpQwYsmY4Jla;^wj!S1KaRvM%t)zH0sgR;%F%{$3|47a9*KpD)shVPTvHKZ}7!cBq?RVamVx z=jQv(=ZBMr2fKN@(}{c00S!^4i)%%AiyGz|cF7zL;;{yqiFaAt5FRkU+=N)nCwjJoMRbL@7T4uo3UL-A2mZLAqn*oU|m& zk5qOC0YXt{n>MGUG9mnjLgtLU$(XrNrUhE~&|L9QMTe_mw}AZ-S;8vY-4r{M=8C__ zl(7&sz05Rb91Y)d8vH20HRH6ixnGLKgH^wjKE%nzw6b4)Mne$_e0YXk4exywAYWK9|NAOSav*QVI9&{E*y+vfnDsOwv^x({Y=lmWhwJ|m^R;|sEd&#i z9XpE#oe6ODSIbFeyUoV(EoxkO&Ai}P_9~Rx^H>8h#{4qbbTrU%(ddxk!~Ei(iWq^v z{NnLoB(d^H0F=c198Gz9F(1YOgZ=#sGnHCS0X#JYtjzr_mn?e~LVkDe^W}Ac(Ji%& zosIOV_Ln8kUWSZN|b=xAnX6pSqr05yFJgIwf_u-tBxt6h`ncEW)M0x_u-+fmsC z7XBL}_cxnD0os>mLS}8uEnh#qw?k>(v47lAxPV4i8L$GM1|Yc5vd<7e7>cy@5!=R| zz~_&EW!F$LFtfuhV9)Cx2p`kwVm|clvk3Nl_#->RhuM(e-!d}aQ;&!6)+(3+Krw>P zgs|JJ<6syQThiPoMDV9D97~llml&3s-nwP`5SVuP!=Twm_^;=@Ge#w+~`i*zN#8Z)gZd@h7nuuuP7Q#XLGWpzSTo zp`rwd=ORVIkfQTt$P`~PkubV=`9p>*1T+jrS{|r&e{MDV@}7pUIr`)!{l)qPOd^D3 z^YTH8?DMX&wNct3qx4r(b;N1aRe_wZ=LtK15{hWFfk4^DBG0Y84)F9JgvR``+v2kN z&@QVM43xm)i2wAV-x#^g^sv|P?vKR}Td{4pi+jSCKL|4SJQJ!IHd#sq zK#@lWyB*)1@4&UQKU?QPFUo!);JwGxYVD8}>kol-?Z=LP>-4`KSIun-j*h!YZHe5V zEkz=j_?ST-Z?JGYnvK9!nIM=Bp#IOHC_QpuaR}%WHZ^7bNBqM#b(tuE>ITxZbkA^utRNzM%160$?ua4&28ckC+AHEeY(}>7Jq~ zDJkM8pU9GxJ=8TLi8qna(UCs=si|VUUW#ybP)+rCAtbWVAp`Qw-bjMh&?#qAd&-rD zT0b~I!G5Zlx(3GmX>Dw4Y|dzOs(*n6SO&%4yU&b8Vv$Lt`({XU426Q1yt=ZmSXI)P zEvVaT5r(va+QTM0!W7i|8bexu!mz$Mt!;}Tk zBu|6RB=js%=<3IDty^PB$lb1r5-@p>(*I`8L6u)9Xrg7;SLbLb0OeNxfmZ00Z| zkL2CF+V)&Mgly^&Qo~uzBu)4Jv#du0BY&aCJ|zXl${?AfMvE2iGi_2Zb5b$Q;wx%S zZER{bhgiM>*vq;M$K3n*>kSJ@!Qb z2GzBhL7&OV74b}F!YNRiX%`rN;wL&yZ_RX*z!v?-df5n#mrY``X?szTd>WJl(g#}Um2n52|O{~1PWpW8-+E_{A%6{{t?=BR|cpmVXYsTIW28;y z#!5VNGJzoOJow_I@nNHxAn~?}-M#MaA{w7wFT1;C$Op$&Ls*nvHy!sV?~tZ=6|n~|IWuMD{*AEL@zdK|Uk0-;$|)#J4Jx_o z+yk0x>Ah-Fckq_vc9xu>K4z_bBW_^mD?8!A-h5iXre}L~4=zBEy)^4M+_oSPjFTfU zVbku5Omk4kCVj*2gmy|$J*Tn@(bT$J#aMR{z;N}}pWDrjyo+-bcQ=^_P!rvJ*!_A= zHYG(*_QFQ` z{Tg!G`Gj3~f`DcS&Y7Y-;gS3?F6#V2oNw?6e@BN*`U#fVq1$c$;f&~?cm@a))pjvL zUrf$ZjIqqvZp%>#rC_IhT@UH#ln?@w&emlptgV%}SDmI3#+-3^00@_;z5YXJn?;|3 zfuc!37804>4~xxXa+;z^-Rd-gVMU*hz$*;PB^gh6o9-&jW;>LZN6%{1 zYvmlXO>N|8p@L#UtG~@)r_2pT@42NCrlNG%ZoRr(p$?_*r$sNV`j*3h!-l&1?sc$On8lck)@dz=8fHd1%tIrZL zHUyh$7@o+|$_u$1!VT<)e+eYbZN*#{X!Vd$O1r`&bTdU8#k7nnVFa>y&STi62uU*y z36fyys!LI^1V-bemsc`gT##|A+QW7ejGmb=VGUUI4m68v+i>(2Ut_c~Q?$KowTpyZ1*=@28Yq%kNC}@NWc_yb?o0KF|Hr}5H5=9N$jC~Z!4D#X16lr z5R8>_82M=44MQXvW(9DCk*axT<0nIuw)$**NxiRwC*V{G`gq+v(wfZCm7^ob+NeAs zD_@seoeZ|ADdGAQgukWfP59YzfMzK*qkM8%dvG!iXP8~=s>8e8TdmefG@=V=^`Y`y zpoy@!k+p8Va4M^40)kOdGOgn34%Cs-Rm5PwPMvoB7{Q(|J7g5&oNAZ(aWQ%e~M>6`A*H z$>lw|-;K0lFtRGl=coX*HvApmL7-9af1n48#<-25*?NKDx(vMk{v;A7A`u&oh3X?*+!@LCeDa%XdtT+snzzT`meUhGhHu~82l*wb{Buc>HD|P#` z>PY5cpKPa`8B56IRkOLi$f|pCmDcD-VmKbQb%D(mzyF>Dp#XIAkFIB53k1Rhvzr*D zbwa&tfy@E2p!jTiVeN0aZ_mrZ>H{MDZtjKe7yjvaq4$?jI+=?lSHWgNG$e_Gr2T42 zCF@ORPL$5wO;0w+mD_opP+8rYYXwA|G&m4PIdpB-iC5du$=s2AHoQ;!vO1t%N)pgK z(PH^y$=I=aqFnTI=PJQsq_4o%PU1b3Jq)#55Xj{t-w=^0m3NSF;#*zvV|gzP2krm{Zv?(dTLdCQy0U9tPsAlVK`fSmxE3N1h~1m*+BeMFg7 znFI%J?Dsp(?p-48C|oE_tb^PYtCf=C23cQa{iomQTgIZJ!fEqF?0=Ew!?0xeRYtZN zaYH;;a({$+6a9w}O{IUb;#JANwgf;Cp&P7ur!E;sjDFk!g;w9SMdO-v1G0)!+#4aT zj`VE#7&{{HVNqJXWkOxAE$j&2o~LQKrhsDf-)x zR$r`)0hIu6UUn}rjRUD6E z5{$fJg9rIL(Ayo|nM4?)h?vFn+~-XY$JHeKDlM}G1rflTppX0+S6M=lP=)Tx!yJjf zymEAWRMHBpqxKkaR4`a44LQNuv!9b+l6$E+_YY5~6gl&8hk0ibTh|`PJ2YoB0LIXq zrG+Nw48%>|G~&Ew7O21)4}hX{u;zHsMf&_pys91_!euECj2%o73q9Su_v|QNbB3se zj#QjYP&U%}W(l$X$+~o!Q9+0?S1DX<3jc2}?ebZ?C>VC>2DW?`Z%SeoOa z-o%ye^GaHQykEd(tx8kr^FupweP|gMWi9D~F%UMbOL>02+69+F-q<3i0Ct0^GsRp* zx;p%ZNfE@n&Lkd3+0q1~@@F$aO5f7tJAvGQES4pgZr&U@C)56G8Bt{=eESt2Q@sVR zx_4Tmkl4y;qhhz4*FS`!IgmgNjNlKes|C>sHcqCcWe%&+1(jtoMno=sgn_<|&kj8) zAD=0(1CpeGIAnpEr2N;%Rli;!bnME$WmqWuy6j+dl#W23eg)rPzwbQ* z)j$@Vh5-~wsYg!}9P{tf3>|9&#-X_dKwc8CZn75m3BpYQdRj{8IqL;lny?^q+JgbS z+%Y<^`k#X(B(FS_2ZJ8P#6`6@0thq0+Uhct5H=-m&E3!^15SQjhJ91;3X8nM(CG9} z3&k?5D5pe7Ht+l_3?yx6E@ zd*K>asH|<7su!<*Tarj?ua$nLBu^y1)eaAG_ypj^p?Kxm4^)|$*O)>np|_ucljoYB zmWzWp>leLftx0k%HaHM3#e;_gd?5sJz_I;v+7DYguF#c?FSiscLs$T<8=n-aiXUZk zKQdc>gamX5egN>`>Nlzj80Q}{58JM`)HwlaPs;=C2-VX|Yy;#nq}y&^#=n?x)l!qO6!Dc>#bj$_5N8sE0T}kfSwz=cHza3N>u6x z*}840=0;L|f)P>XYRx6qsW!hmaMNJ>`R3~d&<6}HmpQui@IVu(K4TN^5&yo$^gb&o zFJr#W8u>&UrLf@PUY-EVT0SsZs*e*7iCgcVacVAOABcF>=g_J!f7M-);o0F*9oX+F&6=Ng1esV+Ab5=$`8DlW`DNv?RcX@2@=oe1E~eRSpM>K}JDxf?8=) zQiBOdw$@^}rdOY(i(b#{4FhDSw2M#Arv}GuHX-8h9xix~3J9*FH%78;w<1(T*+?q> z+fG6|E~EbuN4_DA52Z#XW$TK_*=PGBN5;K}T(D1#aa{*pD*+fkJlL?J$6mV|3AifK z1?FLs5UCa)4-iCSz)vlO(ur{U?NKC>RZ1>1tQ4Y4zS$x^?mjX8l!!o0hAghL{ZdyI?g5h4>P%kfFsNvy}@$;{1BOQBV6 zEW6y8FkL%ZV5$$*P{tm7Tf9k5I_!t4dxp!^2OJTjB1<32^*F$`_Kimi~o(ZY2KGX02TYg1wLPpAi%z~J$ zDi{&IIiEnC^gd?b*vTRNVHByMM|M0N>lob`Mg&RIe{&TYJ)}+MAB{>06@S}cyd%ws zjU5kHS9@5As7;4RbqbLeZcexgy*uWfb)`(o&wKVRuthdB1p_oKbDXnTG *EHnj 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 literal 0 HcmV?d00001 diff --git a/src/ImageProcessor.UnitTests/Images/hi-contrast.jpg b/src/ImageProcessor.UnitTests/Images/hi-contrast.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd2c9b90248231317b880634eac8f98f2dbdf6a7 GIT binary patch literal 51058 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 literal 0 HcmV?d00001 diff --git a/src/ImageProcessor.UnitTests/Images/hi-saturation.jpg b/src/ImageProcessor.UnitTests/Images/hi-saturation.jpg new file mode 100644 index 0000000000000000000000000000000000000000..909fa4fc55d43e54c2e4ef54021b1fb7275676a0 GIT binary patch literal 33850 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 literal 0 HcmV?d00001 diff --git a/src/ImageProcessor.UnitTests/Images/text-over-transparent.png b/src/ImageProcessor.UnitTests/Images/text-over-transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..21ebe3883c94844039cc07ad91487339b3ed1f34 GIT binary patch literal 7317 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 P0Kj7nJ@snU7ZLvfNs}N= literal 0 HcmV?d00001 diff --git a/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id new file mode 100644 index 000000000..0db1445a2 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id @@ -0,0 +1 @@ +4d040d9aa3519b3d2303419d1f03eebebf88e956 \ No newline at end of file From 7c5627cd1dd8a9ff108f0a1a6aa5395b633b2f77 Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 29 Jun 2014 11:53:20 +0100 Subject: [PATCH 081/155] Fixing tests to work on Windows. Former-commit-id: 23664e1cac0916c0cc493769b7f9ebe0de78e981 --- build/Build.bat | 2 +- .../ImageFactoryUnitTests.cs | 248 ++++++++++-------- .../ImageProcessor.UnitTests.csproj | 6 +- src/ImageProcessor/ImageFactory.cs | 4 +- .../Imaging/Formats/FormatUtilities.cs | 2 +- 5 files changed, 147 insertions(+), 115 deletions(-) diff --git a/build/Build.bat b/build/Build.bat index 513d111e3..21c4eb0a4 100644 --- a/build/Build.bat +++ b/build/Build.bat @@ -20,7 +20,7 @@ ECHO Packing the NuGet release files ..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.nuspec -Version %version% ..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.Web.nuspec -Version %webversion% ..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.Web.Config.nuspec -Version %webconfigversion% - +PAUSE IF ERRORLEVEL 1 GOTO :showerror diff --git a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs index 880871cc7..c5f569a39 100644 --- a/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs +++ b/src/ImageProcessor.UnitTests/ImageFactoryUnitTests.cs @@ -12,7 +12,9 @@ namespace ImageProcessor.UnitTests { using System; using System.Collections.Generic; + using System.Drawing; using System.IO; + using System.Linq; using NUnit.Framework; /// @@ -21,18 +23,23 @@ namespace ImageProcessor.UnitTests [TestFixture] public class ImageFactoryUnitTests { + /// + /// The list of images. Designed to speed up the tests a little. + /// + private IEnumerable images; + /// /// Tests the loading of image from a file /// [Test] public void TestLoadImageFromFile() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - Assert.AreEqual(fileName, imageFactory.ImagePath); + imageFactory.Load(file.FullName); + Assert.AreEqual(file.FullName, imageFactory.ImagePath); Assert.IsNotNull(imageFactory.Image); } } @@ -44,13 +51,13 @@ namespace ImageProcessor.UnitTests [Test] public void TestLoadImageFromMemory() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - byte[] photoBytes = File.ReadAllBytes(fileName); + byte[] photoBytes = File.ReadAllBytes(file.FullName); - using (var inStream = new MemoryStream(photoBytes)) + using (MemoryStream inStream = new MemoryStream(photoBytes)) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { imageFactory.Load(inStream); Assert.AreEqual(null, imageFactory.ImagePath); @@ -66,12 +73,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestSaveToDisk() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - var outputFileName = string.Format("./output/{0}", Path.GetFileName(fileName)); - using (var imageFactory = new ImageFactory()) + string outputFileName = string.Format("./output/{0}", file.Name); + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); + imageFactory.Load(file.FullName); imageFactory.Save(outputFileName); Assert.AreEqual(true, File.Exists(outputFileName)); } @@ -84,12 +91,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestSaveToMemory() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - using (var s = new MemoryStream()) + imageFactory.Load(file.FullName); + using (MemoryStream s = new MemoryStream()) { imageFactory.Save(s); s.Seek(0, SeekOrigin.Begin); @@ -105,12 +112,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectAlpha() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.Alpha(50); Assert.AreNotEqual(original, imageFactory.Image); } @@ -123,12 +130,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectBrightness() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.Brightness(50); Assert.AreNotEqual(original, imageFactory.Image); } @@ -141,12 +148,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectContrast() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.Contrast(50); Assert.AreNotEqual(original, imageFactory.Image); } @@ -159,12 +166,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectSaturation() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.Saturation(50); Assert.AreNotEqual(original, imageFactory.Image); } @@ -177,13 +184,13 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectTint() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); - imageFactory.Tint(System.Drawing.Color.FromKnownColor(System.Drawing.KnownColor.AliceBlue)); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); + imageFactory.Tint(Color.FromKnownColor(KnownColor.AliceBlue)); Assert.AreNotEqual(original, imageFactory.Image); } } @@ -195,13 +202,13 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectVignette() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); - imageFactory.Vignette(System.Drawing.Color.FromKnownColor(System.Drawing.KnownColor.AliceBlue)); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); + imageFactory.Vignette(Color.FromKnownColor(KnownColor.AliceBlue)); Assert.AreNotEqual(original, imageFactory.Image); } } @@ -213,19 +220,19 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectWatermark() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.Watermark(new Imaging.TextLayer - { - Font = "Arial", - FontSize = 10, - Position = new System.Drawing.Point(10, 10), - Text = "Lorem ipsum dolor" - }); + { + Font = "Arial", + FontSize = 10, + Position = new Point(10, 10), + Text = "Lorem ipsum dolor" + }); Assert.AreNotEqual(original, imageFactory.Image); } } @@ -237,12 +244,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectBlur() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.GaussianBlur(5); Assert.AreNotEqual(original, imageFactory.Image); } @@ -255,12 +262,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectBlurWithLayer() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.GaussianBlur(new Imaging.GaussianLayer { Sigma = 10, Size = 5, Threshold = 2 }); Assert.AreNotEqual(original, imageFactory.Image); } @@ -273,12 +280,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectSharpen() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.GaussianSharpen(5); Assert.AreNotEqual(original, imageFactory.Image); } @@ -291,12 +298,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectSharpenWithLayer() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.GaussianSharpen(new Imaging.GaussianLayer { Sigma = 10, Size = 5, Threshold = 2 }); Assert.AreNotEqual(original, imageFactory.Image); } @@ -309,12 +316,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestApplyEffectFilter() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.Filter(Imaging.Filters.MatrixFilters.BlackWhite); Assert.AreNotEqual(original, imageFactory.Image); @@ -365,12 +372,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestRoundedCorners() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.RoundedCorners(new Imaging.RoundedCornerLayer(5, true, true, true, true)); Assert.AreNotEqual(original, imageFactory.Image); } @@ -384,12 +391,12 @@ namespace ImageProcessor.UnitTests public void TestResizeConstraints() { const int MaxSize = 200; - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - imageFactory.Constrain(new System.Drawing.Size(MaxSize, MaxSize)); + imageFactory.Load(file.FullName); + imageFactory.Constrain(new Size(MaxSize, MaxSize)); Assert.LessOrEqual(imageFactory.Image.Width, MaxSize); Assert.LessOrEqual(imageFactory.Image.Height, MaxSize); } @@ -403,13 +410,13 @@ namespace ImageProcessor.UnitTests public void TestCrop() { const int MaxSize = 20; - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); - imageFactory.Crop(new System.Drawing.Rectangle(0, 0, MaxSize, MaxSize)); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); + imageFactory.Crop(new Rectangle(0, 0, MaxSize, MaxSize)); Assert.AreNotEqual(original, imageFactory.Image); Assert.AreEqual(MaxSize, imageFactory.Image.Width); Assert.LessOrEqual(MaxSize, imageFactory.Image.Height); @@ -424,12 +431,12 @@ namespace ImageProcessor.UnitTests public void TestCropWithCropLayer() { const int MaxSize = 20; - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.Crop(new Imaging.CropLayer(0, 0, MaxSize, MaxSize, Imaging.CropMode.Pixels)); Assert.AreNotEqual(original, imageFactory.Image); Assert.AreEqual(MaxSize, imageFactory.Image.Width); @@ -444,12 +451,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestFlip() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = (System.Drawing.Image)imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.Flip(true); Assert.AreNotEqual(original, imageFactory.Image); Assert.AreEqual(original.Width, imageFactory.Image.Width); @@ -471,12 +478,12 @@ namespace ImageProcessor.UnitTests public void TestResize() { const int NewSize = 150; - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - imageFactory.Resize(new System.Drawing.Size(NewSize, NewSize)); + imageFactory.Load(file.FullName); + imageFactory.Resize(new Size(NewSize, NewSize)); Assert.AreEqual(NewSize, imageFactory.Image.Width); Assert.AreEqual(NewSize, imageFactory.Image.Height); } @@ -490,12 +497,12 @@ namespace ImageProcessor.UnitTests public void TestResizeWithLayer() { const int NewSize = 150; - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - imageFactory.Resize(new Imaging.ResizeLayer(new System.Drawing.Size(NewSize, NewSize), Imaging.ResizeMode.Stretch, Imaging.AnchorPosition.Left)); + imageFactory.Load(file.FullName); + imageFactory.Resize(new Imaging.ResizeLayer(new Size(NewSize, NewSize), Imaging.ResizeMode.Stretch, Imaging.AnchorPosition.Left)); Assert.AreEqual(NewSize, imageFactory.Image.Width); Assert.AreEqual(NewSize, imageFactory.Image.Height); } @@ -508,12 +515,12 @@ namespace ImageProcessor.UnitTests [Test] public void TestRotate() { - foreach (var fileName in ListInputFiles()) + foreach (FileInfo file in this.ListInputFiles()) { - using (var imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory()) { - imageFactory.Load(fileName); - var original = (System.Drawing.Image)imageFactory.Image.Clone(); + imageFactory.Load(file.FullName); + Image original = (Image)imageFactory.Image.Clone(); imageFactory.Rotate(90); Assert.AreEqual(original.Height, imageFactory.Image.Width); Assert.AreEqual(original.Width, imageFactory.Image.Height); @@ -521,13 +528,40 @@ namespace ImageProcessor.UnitTests } } + /// + /// Gets the files matching the given extensions. + /// + /// The . + /// The extensions. + /// A collection of + /// The extensions variable is null. + private static IEnumerable GetFilesByExtensions(DirectoryInfo dir, params string[] extensions) + { + if (extensions == null) + { + throw new ArgumentNullException("extensions"); + } + + IEnumerable files = dir.EnumerateFiles(); + return files.Where(f => extensions.Contains(f.Extension, StringComparer.OrdinalIgnoreCase)); + } + /// /// Lists the input files in the Images folder /// /// The list of files. - private static IEnumerable ListInputFiles() + private IEnumerable ListInputFiles() { - return Directory.GetFiles("./Images"); + if (this.images != null) + { + return this.images; + } + + DirectoryInfo directoryInfo = new DirectoryInfo("./Images"); + + this.images = GetFilesByExtensions(directoryInfo, new[] { ".jpg", ".jpeg", ".png", ".gif", ".tiff", ".bmp", ".webp" }); + + return this.images; } } } \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 4d47bb062..b020e2858 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -3,7 +3,7 @@ Debug AnyCPU - {03CA9055-F997-428C-BF28-F50F991777C6} + {633B1C4C-4823-47BE-9A01-A665F3118C8C} Library ImageProcessor.UnitTests ImageProcessor.UnitTests @@ -338,7 +338,5 @@ - - - + \ No newline at end of file diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 4a68a5e86..03e92fdde 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -183,7 +183,7 @@ namespace ImageProcessor this.ImagePath = imagePath; // Open a file stream to prevent the need for lock. - using (var fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read)) + using (FileStream fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read)) { ISupportedImageFormat format = FormatUtilities.GetFormat(fileStream); @@ -192,7 +192,7 @@ namespace ImageProcessor throw new ImageFormatException("Input stream is not a supported format."); } - var memoryStream = new MemoryStream(); + MemoryStream memoryStream = new MemoryStream(); // Copy the stream. fileStream.CopyTo(memoryStream); diff --git a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs index 3c6e3b3e0..3ee8cf6cb 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs @@ -142,7 +142,7 @@ namespace ImageProcessor.Imaging.Formats // GDI returns a single array with all delays, while Mono returns a different array for each frame image.SelectActiveFrame(frameDimension, i); var times = image.GetPropertyItem(20736).Value; - int thisDelay = BitConverter.ToInt32(times, 4*i % times.Length); + int thisDelay = BitConverter.ToInt32(times, (4 * i) % times.Length); int toAddDelay = thisDelay * 10 < 20 ? 20 : thisDelay * 10; // Minimum delay is 20 ms // Find the frame From aab05b75db866b65cc3e476e4f74ea5a747b7e8b Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 29 Jun 2014 12:35:41 +0100 Subject: [PATCH 082/155] fixing unit test project file. Former-commit-id: b3947dcf2bd94e7f2b96dc4c5f952e072e7f46ff --- .../ImageProcessor.UnitTests.csproj | 349 +++--------------- 1 file changed, 57 insertions(+), 292 deletions(-) diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index b020e2858..4cc93cb0f 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -1,336 +1,95 @@  - + Debug AnyCPU {633B1C4C-4823-47BE-9A01-A665F3118C8C} Library + Properties ImageProcessor.UnitTests ImageProcessor.UnitTests - - + v4.0 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest ..\ true - v4.5 + true full false - bin\Debug - DEBUG; + bin\Debug\ + DEBUG;TRACE prompt 4 - false - false - full + pdbonly true - bin\Release + bin\Release\ + TRACE prompt 4 - false - false - - ..\packages\NUnit.2.6.3\lib\nunit.framework.dll - - + + + + + + + + + + - - - - - {D011A778-59C8-4BFA-A770-C350216BF161} - ImageProcessor.Web_NET45 - - - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} - ImageProcessor - + - - - - - - - - - - Images\1182076_e8c402e938_z.jpg - - - Images\bus.jpg - - - Images\Chrysanthemum.jpg - - - Images\circle.png - - - Images\cmyk.jpg - - - Images\cmyk.png - - - Images\color-vision-test.gif - - - Images\Desert.jpg - - - Images\emma.jpg - - - Images\falahill_design__160p.jpg - - - Images\fid11246.jpg - - - Images\fid9141.jpg - - - Images\header_1.jpg - - - Images\Hydrangeas.jpg - - - Images\Jellyfish.jpg - - - Images\jrt.jpg - - - Images\Koala.jpg - - - Images\Lighthouse.jpg - - - Images\lomo.jpg - - - Images\meter.gif - - - Images\negative.png - - - Images\negative2.png - - - Images\Penguins-200.jpg - - - Images\Penguins-8.png - - - Images\Penguins.bmp - - - Images\Penguins.gif - - - Images\Penguins.jpg - - - Images\Penguins.png - - - Images\Penguins.tif - - - Images\rocks.jpg - - - Images\rotate.jpg - - - Images\sample1.jpg - - - Images\srgb.jpg - - - Images\srgb.png - - - Images\text.png - - - Images\thor.jpg - - - Images\Tulips.jpg - - - Images\udendørs-374.jpg - - - Images\udendørs.jpg - - - Images\war_horse_quad.jpg - - - Images\WP_000009.jpg - - {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} ImageProcessor - - - - Images\Chrysanthemum.jpg - PreserveNewest - - - Images\Desert.jpg - PreserveNewest - - - Images\Hydrangeas.jpg - PreserveNewest - - - Images\Jellyfish.jpg - PreserveNewest - - - Images\Koala.jpg - PreserveNewest - - - Images\Lighthouse.jpg - PreserveNewest - - - Images\Penguins-8.png - PreserveNewest - - - Images\Penguins.bmp - PreserveNewest - - - Images\Penguins.gif - PreserveNewest - - - Images\Penguins.jpg - PreserveNewest - - - Images\Penguins.png - PreserveNewest - - - Images\Penguins.tif - PreserveNewest - - - Images\Tulips.jpg - PreserveNewest - - - Images\bus.jpg - PreserveNewest - - - Images\cmyk.jpg - PreserveNewest - - - Images\cmyk.png - PreserveNewest - - - Images\jrt.jpg - PreserveNewest - - - Images\meter.gif - PreserveNewest - - - Images\rocks.jpg - PreserveNewest - - - Images\rotate.jpg - PreserveNewest - - - Images\sample1.jpg - PreserveNewest - - - Images\srgb.jpg - PreserveNewest - - - Images\srgb.png - PreserveNewest - - - Images\text.png - PreserveNewest - - - Images\thor.jpg - PreserveNewest - - - Images\udendørs-374.jpg - PreserveNewest - - - Images\udendørs.jpg - PreserveNewest - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + + @@ -338,5 +97,11 @@ - + \ No newline at end of file From 30ce011d55029c462c9eda0d3f4a0229386ae73e Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 29 Jun 2014 18:58:07 +0100 Subject: [PATCH 083/155] Stylistic changes to help me sleep at night :) Former-commit-id: 0ce83dcee663eee4da75da749a43034a1435fb5c --- src/ImageProcessor/ImageFactory.cs | 62 +++++++++---------- .../Imaging/Formats/FormatUtilities.cs | 4 +- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 4a68a5e86..f2f573268 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -177,13 +177,13 @@ namespace ImageProcessor /// public ImageFactory Load(string imagePath) { - var fileInfo = new FileInfo(imagePath); + FileInfo fileInfo = new FileInfo(imagePath); if (fileInfo.Exists) { this.ImagePath = imagePath; // Open a file stream to prevent the need for lock. - using (var fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read)) + using (FileStream fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read)) { ISupportedImageFormat format = FormatUtilities.GetFormat(fileStream); @@ -192,7 +192,7 @@ namespace ImageProcessor throw new ImageFormatException("Input stream is not a supported format."); } - var memoryStream = new MemoryStream(); + MemoryStream memoryStream = new MemoryStream(); // Copy the stream. fileStream.CopyTo(memoryStream); @@ -279,7 +279,7 @@ namespace ImageProcessor percentage = 0; } - var alpha = new Alpha { DynamicParameter = percentage }; + Alpha alpha = new Alpha { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(alpha.ProcessImage, this); } @@ -297,7 +297,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var autoRotate = new AutoRotate(); + AutoRotate autoRotate = new AutoRotate(); this.CurrentImageFormat.ApplyProcessor(autoRotate.ProcessImage, this); } @@ -324,7 +324,7 @@ namespace ImageProcessor percentage = 0; } - var brightness = new Brightness { DynamicParameter = percentage }; + Brightness brightness = new Brightness { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(brightness.ProcessImage, this); } @@ -344,7 +344,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var layer = new ResizeLayer(size, ResizeMode.Max); + ResizeLayer layer = new ResizeLayer(size, ResizeMode.Max); return this.Resize(layer); } @@ -372,7 +372,7 @@ namespace ImageProcessor percentage = 0; } - var contrast = new Contrast { DynamicParameter = percentage }; + Contrast contrast = new Contrast { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(contrast.ProcessImage, this); } @@ -392,7 +392,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var cropLayer = new CropLayer(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, CropMode.Pixels); + CropLayer cropLayer = new CropLayer(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, CropMode.Pixels); return this.Crop(cropLayer); } @@ -412,7 +412,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var crop = new Crop { DynamicParameter = cropLayer }; + Crop crop = new Crop { DynamicParameter = cropLayer }; this.CurrentImageFormat.ApplyProcessor(crop.ProcessImage, this); } @@ -433,7 +433,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var filter = new Filter { DynamicParameter = matrixFilter }; + Filter filter = new Filter { DynamicParameter = matrixFilter }; this.CurrentImageFormat.ApplyProcessor(filter.ProcessImage, this); } @@ -457,7 +457,7 @@ namespace ImageProcessor ? RotateFlipType.RotateNoneFlipY : RotateFlipType.RotateNoneFlipX; - var flip = new Flip { DynamicParameter = rotateFlipType }; + Flip flip = new Flip { DynamicParameter = rotateFlipType }; this.CurrentImageFormat.ApplyProcessor(flip.ProcessImage, this); } @@ -500,7 +500,7 @@ namespace ImageProcessor { if (this.ShouldProcess && size > 0) { - var layer = new GaussianLayer(size); + GaussianLayer layer = new GaussianLayer(size); return this.GaussianBlur(layer); } @@ -521,7 +521,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var gaussianBlur = new GaussianBlur { DynamicParameter = gaussianLayer }; + GaussianBlur gaussianBlur = new GaussianBlur { DynamicParameter = gaussianLayer }; this.CurrentImageFormat.ApplyProcessor(gaussianBlur.ProcessImage, this); } @@ -547,7 +547,7 @@ namespace ImageProcessor { if (this.ShouldProcess && size > 0) { - var layer = new GaussianLayer(size); + GaussianLayer layer = new GaussianLayer(size); return this.GaussianSharpen(layer); } @@ -568,7 +568,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var gaussianSharpen = new GaussianSharpen { DynamicParameter = gaussianLayer }; + GaussianSharpen gaussianSharpen = new GaussianSharpen { DynamicParameter = gaussianLayer }; this.CurrentImageFormat.ApplyProcessor(gaussianSharpen.ProcessImage, this); } @@ -611,7 +611,7 @@ namespace ImageProcessor int width = size.Width; int height = size.Height; - var resizeLayer = new ResizeLayer(new Size(width, height)); + ResizeLayer resizeLayer = new ResizeLayer(new Size(width, height)); return this.Resize(resizeLayer); } @@ -631,9 +631,9 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var resizeSettings = new Dictionary { { "MaxWidth", resizeLayer.Size.Width.ToString("G") }, { "MaxHeight", resizeLayer.Size.Height.ToString("G") } }; + Dictionary resizeSettings = new Dictionary { { "MaxWidth", resizeLayer.Size.Width.ToString("G") }, { "MaxHeight", resizeLayer.Size.Height.ToString("G") } }; - var resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings }; + Resize resize = new Resize { DynamicParameter = resizeLayer, Settings = resizeSettings }; this.CurrentImageFormat.ApplyProcessor(resize.ProcessImage, this); } @@ -659,7 +659,7 @@ namespace ImageProcessor degrees = 0; } - var rotate = new Rotate { DynamicParameter = degrees }; + Rotate rotate = new Rotate { DynamicParameter = degrees }; this.CurrentImageFormat.ApplyProcessor(rotate.ProcessImage, this); } @@ -684,7 +684,7 @@ namespace ImageProcessor roundedCornerLayer.Radius = 0; } - var roundedCorners = new RoundedCorners { DynamicParameter = roundedCornerLayer }; + RoundedCorners roundedCorners = new RoundedCorners { DynamicParameter = roundedCornerLayer }; this.CurrentImageFormat.ApplyProcessor(roundedCorners.ProcessImage, this); } @@ -711,7 +711,7 @@ namespace ImageProcessor percentage = 0; } - var saturate = new Saturation { DynamicParameter = percentage }; + Saturation saturate = new Saturation { DynamicParameter = percentage }; this.CurrentImageFormat.ApplyProcessor(saturate.ProcessImage, this); } @@ -731,7 +731,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var tint = new Tint { DynamicParameter = color }; + Tint tint = new Tint { DynamicParameter = color }; this.CurrentImageFormat.ApplyProcessor(tint.ProcessImage, this); } @@ -751,12 +751,12 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var vignette = new Vignette - { - DynamicParameter = color.HasValue && !color.Equals(Color.Transparent) - ? color.Value - : Color.Black - }; + Vignette vignette = new Vignette + { + DynamicParameter = color.HasValue && !color.Equals(Color.Transparent) + ? color.Value + : Color.Black + }; this.CurrentImageFormat.ApplyProcessor(vignette.ProcessImage, this); } @@ -778,7 +778,7 @@ namespace ImageProcessor { if (this.ShouldProcess) { - var watermark = new Watermark { DynamicParameter = textLayer }; + Watermark watermark = new Watermark { DynamicParameter = textLayer }; this.CurrentImageFormat.ApplyProcessor(watermark.ProcessImage, this); } @@ -800,7 +800,7 @@ namespace ImageProcessor if (this.ShouldProcess) { // ReSharper disable once AssignNullToNotNullAttribute - var directoryInfo = new DirectoryInfo(Path.GetDirectoryName(filePath)); + DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(filePath)); if (!directoryInfo.Exists) { directoryInfo.Create(); diff --git a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs index 3ee8cf6cb..a72485a19 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs @@ -139,9 +139,9 @@ namespace ImageProcessor.Imaging.Formats for (int i = 0; i < frameCount; i++) { - // GDI returns a single array with all delays, while Mono returns a different array for each frame + // GDI returns a single array with all delays, while Mono returns a different array for each frame. image.SelectActiveFrame(frameDimension, i); - var times = image.GetPropertyItem(20736).Value; + byte[] times = image.GetPropertyItem(20736).Value; int thisDelay = BitConverter.ToInt32(times, (4 * i) % times.Length); int toAddDelay = thisDelay * 10 < 20 ? 20 : thisDelay * 10; // Minimum delay is 20 ms From 673048f7bdfc448e52829b90be2c2d62e41c97da Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 22:54:11 +0200 Subject: [PATCH 084/155] Adds unit tests for double extension methods + Fixes a build problem on Mono Former-commit-id: 599a7c107767d137d1d6ff38085bc42bf4c11015 --- .../Extensions/DoubleExtensionsUnitTests.cs | 55 +++++++++++++++++++ .../ImageProcessor.UnitTests.csproj | 4 ++ src/ImageProcessor/ImageProcessor.csproj | 6 +- 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs new file mode 100644 index 000000000..108a9a246 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs @@ -0,0 +1,55 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Runs unit tests on the extension methods +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.UnitTests +{ + using System; + using System.Collections.Generic; + using Common.Extensions; + using NUnit.Framework; + + /// + /// Test harness for the DoubleExtensions extension methods + /// + [TestFixture] + public class DoubleExtensionsUnitTests + { + /// + /// Stores the values to test for the ToByte() extension method + /// + private Dictionary doubleToByteTests; + + /// + /// Sets up the values for the tests + /// + [TestFixtureSetUp] + public void Init() + { + this.doubleToByteTests = new Dictionary(); + this.doubleToByteTests.Add(-10, 0x0); + this.doubleToByteTests.Add(1.5, 0x1); + this.doubleToByteTests.Add(25.7, 0x19); + this.doubleToByteTests.Add(1289047, 0xFF); + } + + /// + /// Tests the double to byte conversion + /// + [Test] + public void TestDoubleToByte() + { + foreach (var item in this.doubleToByteTests) + { + var result = item.Key.ToByte(); + Assert.AreEqual(item.Value, result); + } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index c872dbbb8..e715df657 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -46,6 +46,7 @@ PreserveNewest + @@ -127,4 +128,7 @@ + + + \ No newline at end of file diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 4521b06eb..331690773 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -3,8 +3,6 @@ Debug AnyCPU - 8.0.30703 - 2.0 {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} Library Properties @@ -25,7 +23,6 @@ prompt 4 bin\Debug\ImageProcessor.XML - false pdbonly @@ -46,6 +43,8 @@ prompt false true + 4 + false @@ -57,6 +56,7 @@ + From 27191ed6e3e14b61a2e7c5deafb2852fa6643b3d Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 23:41:33 +0200 Subject: [PATCH 085/155] Adds a few unit tests for integer extension methods Former-commit-id: c587d0b1373ced2470459836d5814afe0e7e31e8 --- .../Extensions/IntegerExtensionsUnitTests.cs | 38 +++++++++++++++++++ .../ImageProcessor.UnitTests.csproj | 1 + 2 files changed, 39 insertions(+) create mode 100644 src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs new file mode 100644 index 000000000..1e85e633b --- /dev/null +++ b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs @@ -0,0 +1,38 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Runs unit tests on the extension methods +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.UnitTests +{ + using System; + using Common.Extensions; + using NUnit.Framework; + + /// + /// Provides a test harness for the integer extension class + /// + [TestFixture] + public class IntegerExtensionsUnitTests + { + /// + /// Tests the "ToByte" extension + /// + /// Integer input + /// Expected result + [Test] + [TestCase(21, 0x15)] + [TestCase(190, 0xBE)] + [TestCase(3156, 0xFF)] + public void ToByteTest(int input, byte expected) + { + var result = input.ToByte(); + Assert.AreEqual(expected, result); + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index e715df657..b545a11d9 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -47,6 +47,7 @@ PreserveNewest + From 62f230ce2a0c8598a3188c35c923d797d058618a Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 30 Jun 2014 00:25:26 +0100 Subject: [PATCH 086/155] Fixing asp native binary loading Former-commit-id: b50aa19ade3d337a0b258c9165ba06c95be52ea0 --- build/NuSpecs/ImageProcessor.nuspec | 4 +- .../ImageProcessor/imageprocessor.targets | 2 +- .../ImageProcessorConfiguration.cs | 43 +++++++++++++++++ .../NET45/Helpers/NativeMethods.cs | 44 ++++++++++++++++++ .../NET45/ImageProcessor.Web_NET45.csproj | 1 + .../NET45/Settings.StyleCop | 7 +++ .../ImageProcessorBootstrapper.cs | 3 ++ src/ImageProcessor/ImageProcessor.csproj | 4 +- .../Imaging/Formats/NativeMethods.cs | 16 +++---- .../Imaging/Formats/WebPFormat.cs | 7 +-- ...ED.git-id => libwebp32.dll.REMOVED.git-id} | 0 ...ED.git-id => libwebp64.dll.REMOVED.git-id} | 0 src/ImageProcessorConsole/Program.cs | 12 ++--- .../images/output/rotate.webp | Bin 1792 -> 0 bytes 14 files changed, 118 insertions(+), 25 deletions(-) create mode 100644 src/ImageProcessor.Web/NET45/Helpers/NativeMethods.cs create mode 100644 src/ImageProcessor.Web/NET45/Settings.StyleCop rename src/ImageProcessor/{x86/libwebp.dll.REMOVED.git-id => libwebp32.dll.REMOVED.git-id} (100%) rename src/ImageProcessor/{x64/libwebp.dll.REMOVED.git-id => libwebp64.dll.REMOVED.git-id} (100%) delete mode 100644 src/ImageProcessorConsole/images/output/rotate.webp diff --git a/build/NuSpecs/ImageProcessor.nuspec b/build/NuSpecs/ImageProcessor.nuspec index 8041f5dfc..557d85150 100644 --- a/build/NuSpecs/ImageProcessor.nuspec +++ b/build/NuSpecs/ImageProcessor.nuspec @@ -25,8 +25,8 @@ Feedback is always welcome. - - + + \ No newline at end of file diff --git a/build/content/ImageProcessor/imageprocessor.targets b/build/content/ImageProcessor/imageprocessor.targets index 0b161e3c5..f8de1a74b 100644 --- a/build/content/ImageProcessor/imageprocessor.targets +++ b/build/content/ImageProcessor/imageprocessor.targets @@ -14,7 +14,7 @@ + DestinationFiles="@(NativeBinaries->'$(OutDir)\%(RecursiveDir)\%(Filename)%(Extension)')"> diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs index 89bcf39d7..9d3ea6be9 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs @@ -13,12 +13,16 @@ namespace ImageProcessor.Web.Configuration using System; using System.Collections.Concurrent; using System.Collections.Generic; + using System.Diagnostics; + using System.IO; using System.Linq; using System.Reflection; + using System.Web; using System.Web.Compilation; using ImageProcessor.Common.Extensions; using ImageProcessor.Processors; + using ImageProcessor.Web.Helpers; using ImageProcessor.Web.Processors; /// @@ -28,6 +32,12 @@ namespace ImageProcessor.Web.Configuration public sealed class ImageProcessorConfiguration { #region Fields + /// + /// Whether the process is running in 64bit mode. Used for calling the correct dllimport method. + /// Clunky I know but I couldn't get dynamic methods to work. + /// + private static readonly bool Is64Bit = Environment.Is64BitProcess; + /// /// A new instance Initializes a new instance of the class. /// with lazy initialization. @@ -71,6 +81,7 @@ namespace ImageProcessor.Web.Configuration /// private ImageProcessorConfiguration() { + this.EnsureNativeBinariesLoaded(); this.LoadGraphicsProcessors(); } #endregion @@ -353,6 +364,38 @@ namespace ImageProcessor.Web.Configuration webProcessor.Processor.Settings = this.GetPluginSettings(webProcessor.GetType().Name); } } + + /// + /// Ensures that the native binaries are loaded. + /// + private void EnsureNativeBinariesLoaded() + { + string binary = Is64Bit ? "libwebp64.dll" : "libwebp32.dll"; + string sourcePath = HttpContext.Current.Server.MapPath("~/bin"); + string targetPath = new Uri(Assembly.GetExecutingAssembly().Location).LocalPath; + IntPtr pointer = IntPtr.Zero; + + // Shadow copy the native binaries. + sourcePath = Path.Combine(sourcePath, binary); + targetPath = Path.GetFullPath(Path.Combine(targetPath, "..\\" + binary)); + + File.Copy(sourcePath, targetPath, true); + + try + { + // Load the binary into memory. + pointer = NativeMethods.LoadLibrary(targetPath); + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + } + + if (pointer == IntPtr.Zero) + { + throw new ApplicationException("Cannot open " + binary); + } + } #endregion } } diff --git a/src/ImageProcessor.Web/NET45/Helpers/NativeMethods.cs b/src/ImageProcessor.Web/NET45/Helpers/NativeMethods.cs new file mode 100644 index 000000000..9e983438c --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Helpers/NativeMethods.cs @@ -0,0 +1,44 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides access to unmanaged native methods. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Helpers +{ + using System; + using System.Runtime.InteropServices; + + /// + /// Provides access to unmanaged native methods. + /// + internal class NativeMethods + { + /// + /// Loads the specified module into the address space of the calling process. + /// The specified module may cause other modules to be loaded. + /// + /// + /// The name of the module. This can be either a library module or + /// an executable module. + /// + /// If the function succeeds, the return value is a handle to the module; otherwise null. + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr LoadLibrary(string libname); + + /// + /// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. + /// When the reference count reaches zero, the module is unloaded from the address space of the calling + /// process and the handle is no longer valid. + /// + /// A handle to the loaded library module. + /// The LoadLibrary, LoadLibraryEx, GetModuleHandle, or GetModuleHandleEx function returns this handle. + /// If the function succeeds, the return value is nonzero; otherwise zero. + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public static extern bool FreeLibrary(IntPtr hModule); + } +} diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index 7ca861264..ac434afe5 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -54,6 +54,7 @@ + diff --git a/src/ImageProcessor.Web/NET45/Settings.StyleCop b/src/ImageProcessor.Web/NET45/Settings.StyleCop new file mode 100644 index 000000000..09dd1de03 --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Settings.StyleCop @@ -0,0 +1,7 @@ + + + + dllimport + + + \ No newline at end of file diff --git a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs index e6a7f1962..a9d9c5542 100644 --- a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs +++ b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs @@ -12,7 +12,10 @@ namespace ImageProcessor.Configuration { using System; using System.Collections.Generic; + using System.IO; using System.Linq; + using System.Reflection; + using ImageProcessor.Common.Exceptions; using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging.Formats; diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 4521b06eb..1c5b26e80 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -130,10 +130,10 @@ - + PreserveNewest - + PreserveNewest diff --git a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs b/src/ImageProcessor/Imaging/Formats/NativeMethods.cs index 059c5259a..8aaff3432 100644 --- a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs +++ b/src/ImageProcessor/Imaging/Formats/NativeMethods.cs @@ -37,7 +37,7 @@ namespace ImageProcessor.Imaging.Formats /// /// 1 if success, otherwise error code returned in the case of (a) formatting error(s). /// - [DllImport("x86\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetInfo")] + [DllImport("libwebp32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetInfo")] public static extern int WebPGetInfo86(IntPtr data, uint dataSize, out int width, out int height); /// @@ -58,7 +58,7 @@ namespace ImageProcessor.Imaging.Formats /// /// 1 if success, otherwise error code returned in the case of (a) formatting error(s). /// - [DllImport("x64\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetInfo")] + [DllImport("libwebp64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetInfo")] public static extern int WebPGetInfo64(IntPtr data, uint dataSize, out int width, out int height); /// @@ -82,7 +82,7 @@ namespace ImageProcessor.Imaging.Formats /// /// output_buffer if function succeeds; NULL otherwise /// - [DllImport("x86\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")] + [DllImport("libwebp32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")] public static extern IntPtr WebPDecodeBGRAInto86(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride); /// @@ -106,7 +106,7 @@ namespace ImageProcessor.Imaging.Formats /// /// output_buffer if function succeeds; NULL otherwise /// - [DllImport("x64\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")] + [DllImport("libwebp64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")] public static extern IntPtr WebPDecodeBGRAInto64(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride); /// @@ -133,7 +133,7 @@ namespace ImageProcessor.Imaging.Formats /// /// Size of WebP Image /// - [DllImport("x86\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGRA")] + [DllImport("libwebp32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGRA")] public static extern int WebPEncodeBGRA86(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output); /// @@ -160,7 +160,7 @@ namespace ImageProcessor.Imaging.Formats /// /// Size of WebP Image /// - [DllImport("x64\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGRA")] + [DllImport("libwebp64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGRA")] public static extern int WebPEncodeBGRA64(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output); /// @@ -172,7 +172,7 @@ namespace ImageProcessor.Imaging.Formats /// /// 1 if success, otherwise error code returned in the case of (a) error(s). /// - [DllImport("x86\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")] + [DllImport("libwebp32.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")] public static extern int WebPFree86(IntPtr pointer); /// @@ -184,7 +184,7 @@ namespace ImageProcessor.Imaging.Formats /// /// 1 if success, otherwise error code returned in the case of (a) error(s). /// - [DllImport("x64\\libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")] + [DllImport("libwebp64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")] public static extern int WebPFree64(IntPtr pointer); #endregion } diff --git a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs index 25b0205e3..03f195122 100644 --- a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/WebPFormat.cs @@ -32,7 +32,7 @@ namespace ImageProcessor.Imaging.Formats public class WebPFormat : FormatBase { /// - /// Whether the process is running in 63bit mode. Used for calling the correct dllimport method. + /// Whether the process is running in 64bit mode. Used for calling the correct dllimport method. /// Clunky I know but I couldn't get dynamic methods to work. /// private static readonly bool Is64Bit = Environment.Is64BitProcess; @@ -227,11 +227,6 @@ namespace ImageProcessor.Imaging.Formats outputBuffer = NativeMethods.WebPDecodeBGRAInto86(ptrData, dataSize, outputBuffer, outputBufferSize, bitmapData.Stride); } - if (bitmapData.Scan0 != outputBuffer) - { - throw new ImageFormatException("Failed to decode WebP image with error " + (long)outputBuffer); - } - // Write image to bitmap using Marshal byte[] buffer = new byte[outputBufferSize]; Marshal.Copy(outputBuffer, buffer, 0, outputBufferSize); diff --git a/src/ImageProcessor/x86/libwebp.dll.REMOVED.git-id b/src/ImageProcessor/libwebp32.dll.REMOVED.git-id similarity index 100% rename from src/ImageProcessor/x86/libwebp.dll.REMOVED.git-id rename to src/ImageProcessor/libwebp32.dll.REMOVED.git-id diff --git a/src/ImageProcessor/x64/libwebp.dll.REMOVED.git-id b/src/ImageProcessor/libwebp64.dll.REMOVED.git-id similarity index 100% rename from src/ImageProcessor/x64/libwebp.dll.REMOVED.git-id rename to src/ImageProcessor/libwebp64.dll.REMOVED.git-id diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index 64053c5ed..b08b9440b 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -40,9 +40,9 @@ namespace ImageProcessorConsole di.Create(); } - FileInfo[] files = di.GetFiles("*.jpg"); + //FileInfo[] files = di.GetFiles("*.jpg"); //FileInfo[] files = di.GetFiles(); - //var files = GetFilesByExtensions(di, ".gif", ".webp"); + IEnumerable files = GetFilesByExtensions(di, ".gif", ".webp"); foreach (FileInfo fileInfo in files) @@ -60,11 +60,11 @@ namespace ImageProcessorConsole imageFactory.Load(inStream) .AutoRotate() .Constrain(size) - .Format(new WebPFormat()) - .Quality(5) + //.Format(new WebPFormat()) + //.Quality(5) // ReSharper disable once AssignNullToNotNullAttribute - .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".webp"))); - //.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); + // .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".webp"))); + .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); } } } diff --git a/src/ImageProcessorConsole/images/output/rotate.webp b/src/ImageProcessorConsole/images/output/rotate.webp deleted file mode 100644 index 3cc93f14973b480cd6270b3d3ec61cf86e4d1135..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1792 zcmV+b2mkm|Nk&Ha1^@t8MM6+kP&gp$1^@tXIRKpjD#!qq06&?;)nmCaE2gKltXm*6 z31e&3Uwu12@pYUxv9tO^7{%9@PvE<2^^K}ds+-BwTc0X#mf*8Q{BXhf@1XP21ha1R z&Rhz&J9QJ2A;I9vUTk}jXc0*$)MGHQ!ux{>7s0Dtz&iMx*kP7=iItI-3&0o3zwObg z8_ppO(=Y$faA}3B6kojQ$6C8EehUcJw931$(x79qDo1Ytw_oR@zs>ZqdwjO3N1!*2~%@-NGseIwdLi1P&3MFoq>u5CP3DvH;DZ-I&&sq3( z{x_j|hX)ifOq1Jy9~l;nGgBJ116yt7z`;#Qi;+b7$BT`7O~eVszvf+|FZLDw zIy)o?2Yp(phIpGohOIuB? zz9=607mv;5u?+a5EeZNhZf@9Q${?VOkPlD*{_4|e>1V71-|eAqPE$~ERYSt+m1AIT zhm0~^-!yp>E0gMb<>c2@NoXr!4LaEq$q1Cs8~$k_w$ylGf%f*MMb;=u?h|yohgG7u zTVlEktFqDtuD=zI2aIrkO(jwF*#ho~gUCm4ALf_R)d|NH7F+{-!}O{=$w_V5cLvt> zIUN{qiTPjt-c&J-gffM(&YJm1JZ{cQcH>S@z4WW*q!_g+=r?bbV-RHc}5`w$KOChyv+$kHY{rSHNpJn`i zWerg3EJO1wO{pi97q;@1$zcTWMEHBa%mH;cmm0)A&`V!mA&x~>+Qd-fG#5p4SwM1= zlT+e@1bnNVgEJryk{Ki&S@VVRQN;r@YtL#nYHXsM{Z)XLg9FU{CB|6c46M0N1d`@+ z-%O%3s;g0MPn?!6^P{I?sn2!Wm$f$gMs0KYWrYo`MqRpP73J0x9|x!=qd=7^(V{3X zzt55@sMAREviL*vaa!Q5%Y>sNXV%hFIl$8HbOUx-2UY#TudV4gQB>WlFQ*jln%%;| zlcP8&9T_z}569gAM#NGVM@9kD@KFL;3HDY^Fct)|b8$}36eEaLr1Fr`SPehOX7$bM zk*#fp7q!vaeUTcELM8*c{KHYQtCxRT)nNB2vCqx+st{p#Dp&(@x<5~jS~7}s$OysJ z?3#SPQCkjNlUZ)Y5B1tee@G@sP14ZTNu6B;>f--vn_VHZb$Q-M?CbbQ|!)~$vizpd5@=wfOEREJAp z0=Y0oE{tfJkZX8%D@1VtdXdAJDfu=2@=K%sj=dbN#D^mE%-P%;({98>ETYIbsNczsI}smAxL7ce~*5O#-?`kkydByfj4yei&98MmCg9L zo;hlP;TW72pv?Uox)CIGznIRgGr4JujuRA0*fs zRMvzUsFnPzPF-`hqmb$pccCzP=qjyhz@E)WG+{*rxt)T^y(_UeSIx^rsik@A!lB}n z)~jFLizqLj z2j?bUqQ?T2*2jh}yzlpEIjSoxT)Rjx7~>G)Biz~Ra>qijP)vS066>1xueUlYYu`9O zPsV{r1V*~Up%V4uS!2yf!@Af9VMf-b66nIW{3a}by5P<;>lyOBaNS1KwMqGd(uDt? zR-4L891vax=5EYl?D5O3#k}t4sX5RI*=7}%(@N2p#R{pnu!s$sKt|nCJr1c&JNfNr zPz2zG^)gC(i`Q;EM1U|THwE89-JD&(c)+Nh9N&Y2r_h^Wad_9>&Dm0h&3}W}FcVU0 ih!#}2)=Tn&I3iC4$Tqk!@#W|b_ISadJzM0~4*&oTZ-5p6 From b0c0724774a6c4d010f6cbf220e859d4cf67471c Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 30 Jun 2014 00:40:15 +0100 Subject: [PATCH 087/155] Fixing missing reference Former-commit-id: f058eb260906ca174aacb18b525974734de40548 --- src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj | 3 +++ .../NET45/Configuration/ImageProcessorConfiguration.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj index ccda9415f..2a149236a 100644 --- a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj +++ b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj @@ -101,6 +101,9 @@ ImageHelpers.cs + + NativeMethods.cs + ResourceHelpers.cs diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs index 9d3ea6be9..b0977a962 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs @@ -22,8 +22,8 @@ namespace ImageProcessor.Web.Configuration using ImageProcessor.Common.Extensions; using ImageProcessor.Processors; - using ImageProcessor.Web.Helpers; using ImageProcessor.Web.Processors; + using ImageProcessor.Web.Helpers; /// /// Encapsulates methods to allow the retrieval of ImageProcessor settings. From b15e115974bf4f72b1db9cbd3ef26d54a1d6f1c6 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 1 Jul 2014 17:54:37 +0100 Subject: [PATCH 088/155] Tweaking gif frame creation and fixing unc folder access issue Former-commit-id: badfd2f22a0f209cd9f913804260dce56b0037e4 --- .../NET4/ImageProcessor.Web_NET4.csproj | 3 + .../NET45/Caching/DiskCache.cs | 56 +++++++++++-------- .../ImageProcessorConfiguration.cs | 2 +- .../HttpModules/ImageProcessingModule.cs | 2 +- .../NET45/ImageProcessor.Web_NET45.csproj | 1 + .../Imaging/Formats/FormatUtilities.cs | 28 +++++----- .../Imaging/Formats/GifEncoder.cs | 18 +++--- src/ImageProcessorConsole/Program.cs | 5 +- 8 files changed, 65 insertions(+), 50 deletions(-) diff --git a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj index 2a149236a..d830257ae 100644 --- a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj +++ b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj @@ -95,6 +95,9 @@ ImageSecuritySection.cs + + DirectoryInfoExtensions.cs + CommonParameterParserUtility.cs diff --git a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs index f1cefc657..6a23d48ad 100644 --- a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs @@ -22,6 +22,7 @@ namespace ImageProcessor.Web.Caching using ImageProcessor.Common.Extensions; using ImageProcessor.Web.Configuration; + using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; #endregion @@ -212,37 +213,44 @@ namespace ImageProcessor.Web.Caching /// private void TrimCachedFolders(string path) { - // ReSharper disable once AssignNullToNotNullAttribute - DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(path)); - DirectoryInfo parentDirectoryInfo = directoryInfo.Parent; + string directory = Path.GetDirectoryName(path); - // ReSharper disable once PossibleNullReferenceException - foreach (DirectoryInfo enumerateDirectory in parentDirectoryInfo.EnumerateDirectories()) + if (directory != null) { - IEnumerable files = enumerateDirectory.EnumerateFiles().OrderBy(f => f.CreationTimeUtc); - int count = files.Count(); + DirectoryInfo directoryInfo = new DirectoryInfo(directory); + DirectoryInfo parentDirectoryInfo = directoryInfo.Parent; - foreach (FileInfo fileInfo in files) + if (parentDirectoryInfo != null) { - try + // UNC folders can throw exceptions if the file doesn't exist. + foreach (DirectoryInfo enumerateDirectory in parentDirectoryInfo.SafeEnumerateDirectories()) { - // If the group count is equal to the max count minus 1 then we know we - // have reduced the number of items below the maximum allowed. - // We'll cleanup any orphaned expired files though. - if (!this.IsExpired(fileInfo.CreationTimeUtc) && count <= MaxFilesCount - 1) + IEnumerable files = enumerateDirectory.EnumerateFiles().OrderBy(f => f.CreationTimeUtc); + int count = files.Count(); + + foreach (FileInfo fileInfo in files) { - break; + try + { + // If the group count is equal to the max count minus 1 then we know we + // have reduced the number of items below the maximum allowed. + // We'll cleanup any orphaned expired files though. + if (!this.IsExpired(fileInfo.CreationTimeUtc) && count <= MaxFilesCount - 1) + { + break; + } + + // Remove from the cache and delete each CachedImage. + CacheIndexer.Remove(fileInfo.Name); + fileInfo.Delete(); + count -= 1; + } + // ReSharper disable once EmptyGeneralCatchClause + catch + { + // Do nothing; skip to the next file. + } } - - // Remove from the cache and delete each CachedImage. - CacheIndexer.Remove(fileInfo.Name); - fileInfo.Delete(); - count -= 1; - } - // ReSharper disable once EmptyGeneralCatchClause - catch - { - // Do nothing; skip to the next file. } } } diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs index b0977a962..9d3ea6be9 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs @@ -22,8 +22,8 @@ namespace ImageProcessor.Web.Configuration using ImageProcessor.Common.Extensions; using ImageProcessor.Processors; - using ImageProcessor.Web.Processors; using ImageProcessor.Web.Helpers; + using ImageProcessor.Web.Processors; /// /// Encapsulates methods to allow the retrieval of ImageProcessor settings. diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index 33877e15b..d70e71867 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -359,7 +359,7 @@ namespace ImageProcessor.Web.HttpModules IPrincipal user = context.User ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]); // Do we have permission to call UrlAuthorizationModule.CheckUrlAccessForPrincipal? - PermissionSet permission = new PermissionSet(PermissionState.Unrestricted); + PermissionSet permission = new PermissionSet(PermissionState.None); permission.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted)); bool hasPermission = permission.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet); diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index ac434afe5..2f5e77f23 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -53,6 +53,7 @@ + diff --git a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs index a72485a19..53025bf42 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatUtilities.cs @@ -131,40 +131,42 @@ namespace ImageProcessor.Imaging.Formats if (fetchFrames) { - FrameDimension frameDimension = new FrameDimension(image.FrameDimensionsList[0]); - int frameCount = image.GetFrameCount(frameDimension); + int frameCount = image.GetFrameCount(FrameDimension.Time); int last = frameCount - 1; - int delay = 0; + int length = 0; + List gifFrames = new List(); + // Get the times stored in the gif. + byte[] times = image.GetPropertyItem((int)ExifPropertyTag.FrameDelay).Value; + for (int i = 0; i < frameCount; i++) { + // Convert each 4-byte chunk into an integer. // GDI returns a single array with all delays, while Mono returns a different array for each frame. - image.SelectActiveFrame(frameDimension, i); - byte[] times = image.GetPropertyItem(20736).Value; - int thisDelay = BitConverter.ToInt32(times, (4 * i) % times.Length); - int toAddDelay = thisDelay * 10 < 20 ? 20 : thisDelay * 10; // Minimum delay is 20 ms + int delay = BitConverter.ToInt32(times, (4 * i) % times.Length); + delay = delay * 10 < 20 ? 20 : delay * 10; // Minimum delay is 20 ms // Find the frame - image.SelectActiveFrame(frameDimension, i); + image.SelectActiveFrame(FrameDimension.Time, i); // TODO: Get positions. - gifFrames.Add(new GifFrame { Delay = toAddDelay, Image = (Image)image.Clone() }); + gifFrames.Add(new GifFrame { Delay = delay, Image = (Image)image.Clone() }); // Reset the position. if (i == last) { - image.SelectActiveFrame(frameDimension, 0); + image.SelectActiveFrame(FrameDimension.Time, 0); } - delay += toAddDelay; + length += delay; } info.GifFrames = gifFrames; - info.AnimationLength = delay; + info.AnimationLength = length; // Loop info is stored at byte 20737. - info.LoopCount = BitConverter.ToInt16(image.GetPropertyItem(20737).Value, 0); + info.LoopCount = BitConverter.ToInt16(image.GetPropertyItem((int)ExifPropertyTag.LoopCount).Value, 0); info.IsLooped = info.LoopCount != 1; } } diff --git a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs index 612a453bf..662ad314c 100644 --- a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs +++ b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs @@ -193,13 +193,6 @@ namespace ImageProcessor.Imaging.Formats } #endregion - #region Properties - /// - /// Gets or sets the frame delay. - /// - public TimeSpan FrameDelay { get; set; } - #endregion - #region Public Methods and Operators /// /// Adds a frame to the gif. @@ -289,13 +282,18 @@ namespace ImageProcessor.Imaging.Formats { int count = this.repeatCount.GetValueOrDefault(0); - // File Header + // File Header sinature and version. this.WriteString(FileType); this.WriteString(FileVersion); + + // Write the logical screen descriptor. this.WriteShort(this.width.GetValueOrDefault(w)); // Initial Logical Width this.WriteShort(this.height.GetValueOrDefault(h)); // Initial Logical Height + + // Read the global color table info. sourceGif.Position = SourceGlobalColorInfoPosition; - this.WriteByte(sourceGif.ReadByte()); // Global Color Table Info + this.WriteByte(sourceGif.ReadByte()); + this.WriteByte(0); // Background Color Index this.WriteByte(0); // Pixel aspect ratio this.WriteColorTable(sourceGif); @@ -387,6 +385,7 @@ namespace ImageProcessor.Imaging.Formats /// private void WriteImageBlock(Stream sourceGif, bool includeColorTable, int x, int y, int h, int w) { + // Local Image Descriptor sourceGif.Position = SourceImageBlockPosition; // Locating the image block byte[] header = new byte[SourceImageBlockHeaderLength]; sourceGif.Read(header, 0, header.Length); @@ -435,6 +434,7 @@ namespace ImageProcessor.Imaging.Formats /// private void WriteShort(int value) { + // Leave only one significant byte. this.inputStream.WriteByte(Convert.ToByte(value & 0xff)); this.inputStream.WriteByte(Convert.ToByte((value >> 8) & 0xff)); } diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index b08b9440b..248fe1d7f 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -1,6 +1,7 @@ // -------------------------------------------------------------------------------------------------------------------- // -// Copyright James South +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. // // // The program. @@ -58,7 +59,7 @@ namespace ImageProcessorConsole // Load, resize, set the format and quality and save an image. imageFactory.Load(inStream) - .AutoRotate() + //.AutoRotate() .Constrain(size) //.Format(new WebPFormat()) //.Quality(5) From 6379bf2400fcc602735705333ca5b1152ca3b4ae Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 1 Jul 2014 17:55:06 +0100 Subject: [PATCH 089/155] Adding missed files Former-commit-id: b0d6ff1d22691f4944b6408816c14ecbe8d16856 --- .../Extensions/DirectoryInfoExtensions.cs | 56 ++++++++++++++++++ .../images/output/120430.gif.REMOVED.git-id | 1 + .../images/output/4.sm.webp | Bin 0 -> 12162 bytes .../images/output/Tl4Yb.gif.REMOVED.git-id | 1 + .../images/output/nLpfllv.gif.REMOVED.git-id | 1 + .../images/output/test.webp | Bin 0 -> 5590 bytes 6 files changed, 59 insertions(+) create mode 100644 src/ImageProcessor.Web/NET45/Extensions/DirectoryInfoExtensions.cs create mode 100644 src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/4.sm.webp create mode 100644 src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/test.webp diff --git a/src/ImageProcessor.Web/NET45/Extensions/DirectoryInfoExtensions.cs b/src/ImageProcessor.Web/NET45/Extensions/DirectoryInfoExtensions.cs new file mode 100644 index 000000000..2ec477257 --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Extensions/DirectoryInfoExtensions.cs @@ -0,0 +1,56 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides extension methods to the type. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Extensions +{ + using System.Collections.Generic; + using System.IO; + using System.Linq; + + /// + /// Provides extension methods to the type. + /// + public static class DirectoryInfoExtensions + { + /// + /// Returns an enumerable collection of directory information that matches a specified search pattern and search subdirectory option. + /// Will return an empty enumerable on exception. Quick and dirty but does what I need just now. + /// + /// + /// The that this method extends. + /// + /// + /// The search string to match against the names of directories. This parameter can contain a combination of valid literal path + /// and wildcard (* and ?) characters (see Remarks), but doesn't support regular expressions. The default pattern is "*", which returns all files. + /// + /// + /// One of the enumeration values that specifies whether the search operation should include only + /// the current directory or all subdirectories. The default value is TopDirectoryOnly. + /// + /// + /// An enumerable collection of directories that matches searchPattern and searchOption. + /// + public static IEnumerable SafeEnumerateDirectories(this DirectoryInfo directoryInfo, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly) + { + IEnumerable directories; + + try + { + directories = directoryInfo.EnumerateDirectories(searchPattern, searchOption); + } + catch + { + return Enumerable.Empty(); + } + + return directories; + } + } +} diff --git a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id new file mode 100644 index 000000000..71ce555c1 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id @@ -0,0 +1 @@ +30ec5c05548fd350f9b7c699715848b9fbfb8ca9 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/4.sm.webp b/src/ImageProcessorConsole/images/output/4.sm.webp new file mode 100644 index 0000000000000000000000000000000000000000..90a6308640402286dc34d6e178063681eb985089 GIT binary patch literal 12162 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 E0HyKO%>V!Z literal 0 HcmV?d00001 diff --git a/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id new file mode 100644 index 000000000..6515d65a0 --- /dev/null +++ b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id @@ -0,0 +1 @@ +fdc62fc2d056ab885eb9e8fd12b9155ee86d7c43 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id new file mode 100644 index 000000000..c07be0b0f --- /dev/null +++ b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id @@ -0,0 +1 @@ +77cce70db3722920d60f4b17a45a5e390a09838a \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/test.webp b/src/ImageProcessorConsole/images/output/test.webp new file mode 100644 index 0000000000000000000000000000000000000000..549fb9c6bfaba16b8249fc25324416aa3bfa02cf GIT binary patch literal 5590 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 literal 0 HcmV?d00001 From e008f57d8e5c99351aed25a9cb633ed5f478f77f Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 22:54:11 +0200 Subject: [PATCH 090/155] Adds unit tests for double extension methods + Fixes a build problem on Mono Former-commit-id: 0173a90054d91a5e80b0eb8765e10ddcb8a28085 --- .../Extensions/DoubleExtensionsUnitTests.cs | 55 +++++++++++++++++++ .../ImageProcessor.UnitTests.csproj | 4 ++ src/ImageProcessor/ImageProcessor.csproj | 6 +- 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs new file mode 100644 index 000000000..108a9a246 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs @@ -0,0 +1,55 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Runs unit tests on the extension methods +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.UnitTests +{ + using System; + using System.Collections.Generic; + using Common.Extensions; + using NUnit.Framework; + + /// + /// Test harness for the DoubleExtensions extension methods + /// + [TestFixture] + public class DoubleExtensionsUnitTests + { + /// + /// Stores the values to test for the ToByte() extension method + /// + private Dictionary doubleToByteTests; + + /// + /// Sets up the values for the tests + /// + [TestFixtureSetUp] + public void Init() + { + this.doubleToByteTests = new Dictionary(); + this.doubleToByteTests.Add(-10, 0x0); + this.doubleToByteTests.Add(1.5, 0x1); + this.doubleToByteTests.Add(25.7, 0x19); + this.doubleToByteTests.Add(1289047, 0xFF); + } + + /// + /// Tests the double to byte conversion + /// + [Test] + public void TestDoubleToByte() + { + foreach (var item in this.doubleToByteTests) + { + var result = item.Key.ToByte(); + Assert.AreEqual(item.Value, result); + } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index c872dbbb8..e715df657 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -46,6 +46,7 @@ PreserveNewest + @@ -127,4 +128,7 @@ + + + \ No newline at end of file diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 1c5b26e80..c21b78194 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -3,8 +3,6 @@ Debug AnyCPU - 8.0.30703 - 2.0 {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} Library Properties @@ -25,7 +23,6 @@ prompt 4 bin\Debug\ImageProcessor.XML - false pdbonly @@ -46,6 +43,8 @@ prompt false true + 4 + false @@ -57,6 +56,7 @@ + From 8f238310ea4d7804fc945a6d7869646f6027a4a5 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 23:41:33 +0200 Subject: [PATCH 091/155] Adds a few unit tests for integer extension methods Former-commit-id: 456bf78a23c676691a90f7bfe1149673e5e0d79d --- .../Extensions/IntegerExtensionsUnitTests.cs | 38 +++++++++++++++++++ .../ImageProcessor.UnitTests.csproj | 1 + 2 files changed, 39 insertions(+) create mode 100644 src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs new file mode 100644 index 000000000..1e85e633b --- /dev/null +++ b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs @@ -0,0 +1,38 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Runs unit tests on the extension methods +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.UnitTests +{ + using System; + using Common.Extensions; + using NUnit.Framework; + + /// + /// Provides a test harness for the integer extension class + /// + [TestFixture] + public class IntegerExtensionsUnitTests + { + /// + /// Tests the "ToByte" extension + /// + /// Integer input + /// Expected result + [Test] + [TestCase(21, 0x15)] + [TestCase(190, 0xBE)] + [TestCase(3156, 0xFF)] + public void ToByteTest(int input, byte expected) + { + var result = input.ToByte(); + Assert.AreEqual(expected, result); + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index e715df657..b545a11d9 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -47,6 +47,7 @@ PreserveNewest + From e54765c81bf875c2e1139e3fcc24f56a8c648f30 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 22:54:11 +0200 Subject: [PATCH 092/155] Adds unit tests for double extension methods + Fixes a build problem on Mono Former-commit-id: e8f60511fcccad4fd1f9e38d4d33cfdcb8a7020d --- .../Extensions/DoubleExtensionsUnitTests.cs | 55 +++++++++++++++++++ .../ImageProcessor.UnitTests.csproj | 4 ++ src/ImageProcessor/ImageProcessor.csproj | 6 +- 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs new file mode 100644 index 000000000..108a9a246 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs @@ -0,0 +1,55 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Runs unit tests on the extension methods +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.UnitTests +{ + using System; + using System.Collections.Generic; + using Common.Extensions; + using NUnit.Framework; + + /// + /// Test harness for the DoubleExtensions extension methods + /// + [TestFixture] + public class DoubleExtensionsUnitTests + { + /// + /// Stores the values to test for the ToByte() extension method + /// + private Dictionary doubleToByteTests; + + /// + /// Sets up the values for the tests + /// + [TestFixtureSetUp] + public void Init() + { + this.doubleToByteTests = new Dictionary(); + this.doubleToByteTests.Add(-10, 0x0); + this.doubleToByteTests.Add(1.5, 0x1); + this.doubleToByteTests.Add(25.7, 0x19); + this.doubleToByteTests.Add(1289047, 0xFF); + } + + /// + /// Tests the double to byte conversion + /// + [Test] + public void TestDoubleToByte() + { + foreach (var item in this.doubleToByteTests) + { + var result = item.Key.ToByte(); + Assert.AreEqual(item.Value, result); + } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index c872dbbb8..e715df657 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -46,6 +46,7 @@ PreserveNewest + @@ -127,4 +128,7 @@ + + + \ No newline at end of file diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 1c5b26e80..c21b78194 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -3,8 +3,6 @@ Debug AnyCPU - 8.0.30703 - 2.0 {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} Library Properties @@ -25,7 +23,6 @@ prompt 4 bin\Debug\ImageProcessor.XML - false pdbonly @@ -46,6 +43,8 @@ prompt false true + 4 + false @@ -57,6 +56,7 @@ + From d2e13160342c9a576e10df96412977d926b92fec Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 23:41:33 +0200 Subject: [PATCH 093/155] Adds a few unit tests for integer extension methods Former-commit-id: e90275cd32600a9a68010f0fb1aeebbb6d092598 --- .../Extensions/IntegerExtensionsUnitTests.cs | 38 +++++++++++++++++++ .../ImageProcessor.UnitTests.csproj | 1 + 2 files changed, 39 insertions(+) create mode 100644 src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs new file mode 100644 index 000000000..1e85e633b --- /dev/null +++ b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs @@ -0,0 +1,38 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Runs unit tests on the extension methods +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.UnitTests +{ + using System; + using Common.Extensions; + using NUnit.Framework; + + /// + /// Provides a test harness for the integer extension class + /// + [TestFixture] + public class IntegerExtensionsUnitTests + { + /// + /// Tests the "ToByte" extension + /// + /// Integer input + /// Expected result + [Test] + [TestCase(21, 0x15)] + [TestCase(190, 0xBE)] + [TestCase(3156, 0xFF)] + public void ToByteTest(int input, byte expected) + { + var result = input.ToByte(); + Assert.AreEqual(expected, result); + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index e715df657..b545a11d9 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -47,6 +47,7 @@ PreserveNewest + From 49850747b2651de6cf199f14c8d8c564f9f43ff4 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 4 Jul 2014 22:01:17 +0200 Subject: [PATCH 094/155] Unit tests some string extensions Former-commit-id: 86a9c83b1ecc00e2f966372a77c6956676b1d7fb --- .../Extensions/StringExtensionsUnitTests.cs | 91 +++++++++++++++++++ .../ImageProcessor.UnitTests.csproj | 1 + 2 files changed, 92 insertions(+) create mode 100644 src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs new file mode 100644 index 000000000..d1fefa395 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -0,0 +1,91 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides a test harness for the string extensions +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.UnitTests +{ + using System; + using Common.Extensions; + using NUnit.Framework; + + /// + /// Test harness for the string extensions + /// + [TestFixture] + public class StringExtensionsUnitTests + { + /// + /// Tests the MD5 fingerprint + /// + /// The input value + /// The expexted output of the hash + [Test] + [TestCase("test input", "2e7f7a62eabf0993239ca17c78c464d9")] + [TestCase("lorem ipsum dolor", "96ee002fee25e8b675a477c9750fa360")] + [TestCase("LoReM IpSuM DoLoR", "41e201da794c7fbdb8ce5526a71c8c83")] + [TestCase("1234567890", "e15e31c3d8898c92ab172a4311be9e84")] + public void TestToMd5Fingerprint(string input, string expected) + { + var result = input.ToMD5Fingerprint(); + var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + + /// + /// Tests the SHA-1 fingerprint + /// + /// The input value + /// The expexted output of the hash + [Test] + [TestCase("test input", "49883b34e5a0f48224dd6230f471e9dc1bdbeaf5")] + [TestCase("lorem ipsum dolor", "75899ad8827a32493928903aecd6e931bf36f967")] + [TestCase("LoReM IpSuM DoLoR", "2f44519afae72fc0837b72c6b53cb11338a1f916")] + [TestCase("1234567890", "01b307acba4f54f55aafc33bb06bbbf6ca803e9a")] + public void TestToSHA1Fingerprint(string input, string expected) + { + var result = input.ToSHA1Fingerprint(); + var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + + /// + /// Tests the SHA-256 fingerprint + /// + /// The input value + /// The expexted output of the hash + [Test] + [TestCase("test input", "9dfe6f15d1ab73af898739394fd22fd72a03db01834582f24bb2e1c66c7aaeae")] + [TestCase("lorem ipsum dolor", "ed03353266c993ea9afb9900a3ca688ddec1656941b1ca15ee1650a022616dfa")] + [TestCase("LoReM IpSuM DoLoR", "55f6cb90ba5cd8eeb6f5f16f083ebcd48ea06c34cc5aed8e33246fc3153d3898")] + [TestCase("1234567890", "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646")] + public void TestToSHA256Fingerprint(string input, string expected) + { + var result = input.ToSHA256Fingerprint(); + var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + + /// + /// Tests the SHA-512 fingerprint + /// + /// The input value + /// The expexted output of the hash + [Test] + [TestCase("test input", "40aa1b203c9d8ee150b21c3c7cda8261492e5420c5f2b9f7380700e094c303b48e62f319c1da0e32eb40d113c5f1749cc61aeb499167890ab82f2cc9bb706971")] + [TestCase("lorem ipsum dolor", "cd813e13d1d3919cdccc31c19d8f8b70bd25e9819f8770a011c8c7a6228536e6c9427b338cd732f2da3c0444dfebef838b745cdaf3fd5dcba8db24fc83a3f6ef")] + [TestCase("LoReM IpSuM DoLoR", "3e4704d31f838456c0a5f0892afd392fbc79649a029d017b8104ebd00e2816d94ab4629f731765bf655088b130c51f6f47ca2f8b047749dbd992cf45e89ff431")] + [TestCase("1234567890", "12b03226a6d8be9c6e8cd5e55dc6c7920caaa39df14aab92d5e3ea9340d1c8a4d3d0b8e4314f1f6ef131ba4bf1ceb9186ab87c801af0d5c95b1befb8cedae2b9")] + public void TestToSHA512Fingerprint(string input, string expected) + { + var result = input.ToSHA512Fingerprint(); + var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index b545a11d9..5b6bc12d1 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -48,6 +48,7 @@ + From aca285a315670eaf872dbcdb6810c3e4a48aebf1 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 4 Jul 2014 22:31:53 +0200 Subject: [PATCH 095/155] Adds unit tests for some more string extensions Former-commit-id: 1af9789d4c15050ae0c9234e1101083c0884bb25 --- .../Extensions/StringExtensionsUnitTests.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs index d1fefa395..17cc4c753 100644 --- a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -11,6 +11,7 @@ namespace ImageProcessor.UnitTests { using System; + using System.Collections.Generic; using Common.Extensions; using NUnit.Framework; @@ -87,5 +88,41 @@ namespace ImageProcessor.UnitTests var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); Assert.True(comparison); } + + /// + /// Tests the pasing to an integer array + /// + [Test] + public void TestToIntegerArray() + { + Dictionary data = new Dictionary(); + data.Add("123-456,78-90", new int[] { 123, 456, 78, 90 }); + data.Add("87390174,741897498,74816,748297,57355", new int[] { 87390174, 741897498, 74816, 748297, 57355 }); + data.Add("1-2-3", new int[] { 1, 2, 3 }); + + foreach (var item in data) + { + var result = item.Key.ToPositiveIntegerArray(); + Assert.AreEqual(item.Value, result); + } + } + + /// + /// Tests the pasing to an float array + /// + [Test] + public void TestToFloatArray() + { + Dictionary data = new Dictionary(); + data.Add("12.3-4.56,78-9.0", new float[] { 12.3F, 4.56F, 78, 9 }); + data.Add("87390.174,7.41897498,748.16,748297,5.7355", new float[] { 87390.174F, 7.41897498F, 748.16F, 748297, 5.7355F }); + data.Add("1-2-3", new float[] { 1, 2, 3 }); + + foreach (var item in data) + { + var result = item.Key.ToPositiveFloatArray(); + Assert.AreEqual(item.Value, result); + } + } } } \ No newline at end of file From 7e06bbb25a347d2b7f5fc734bdff25f8563bb78d Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 4 Jul 2014 22:49:13 +0200 Subject: [PATCH 096/155] Tests a few more string extensions Former-commit-id: c442263a29c5247ec0c9cb568f64e4a85eb9c0f1 --- .../Extensions/StringExtensionsUnitTests.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs index 17cc4c753..70f3e83db 100644 --- a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -124,5 +124,45 @@ namespace ImageProcessor.UnitTests Assert.AreEqual(item.Value, result); } } + + /// + /// Tests if the value is a valid URI + /// + /// The value to test + /// Whether the value is correct + /// + /// The full RFC3986 does not seem to pass the test with the square brackets + /// + [Test] + [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", true)] + [TestCase("-", true)] + [TestCase(".", true)] + [TestCase("_", true)] + [TestCase("~", true)] + [TestCase(":", true)] + [TestCase("/", true)] + [TestCase("?", true)] + [TestCase("#", true)] + [TestCase("[", false)] + [TestCase("]", false)] + [TestCase("@", true)] + [TestCase("!", true)] + [TestCase("$", true)] + [TestCase("&", true)] + [TestCase("'", true)] + [TestCase("(", true)] + [TestCase(")", true)] + [TestCase("*", true)] + [TestCase("+", true)] + [TestCase(",", true)] + [TestCase(";", true)] + [TestCase("=", true)] + [TestCase("lorem ipsum", false)] + [TestCase("é", false)] + public void TestIsValidUri(string input, bool expected) + { + var result = input.IsValidVirtualPathName(); + Assert.AreEqual(expected, result); + } } } \ No newline at end of file From 64bb53b42e84b83121654e979c58eaa0813906a4 Mon Sep 17 00:00:00 2001 From: James South Date: Sat, 5 Jul 2014 10:24:13 +0100 Subject: [PATCH 097/155] Making project build on Mono Former-commit-id: b42a4bfe055f7e9c19adc27d347302da372ecb83 --- src/ImageProcessor/ImageProcessor.csproj | 6 +++--- src/ImageProcessor/Imaging/Formats/FormatBase.cs | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 1c5b26e80..b28b102e3 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -3,8 +3,6 @@ Debug AnyCPU - 8.0.30703 - 2.0 {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} Library Properties @@ -15,6 +13,7 @@ ..\ true Client + False true @@ -25,7 +24,6 @@ prompt 4 bin\Debug\ImageProcessor.XML - false pdbonly @@ -46,6 +44,8 @@ prompt false true + 4 + false diff --git a/src/ImageProcessor/Imaging/Formats/FormatBase.cs b/src/ImageProcessor/Imaging/Formats/FormatBase.cs index ea00e82a2..189bad8c3 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatBase.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatBase.cs @@ -90,7 +90,11 @@ namespace ImageProcessor.Imaging.Formats /// public virtual Image Load(Stream stream) { +#if !__MonoCS__ return Image.FromStream(stream, true); +#else + return Image.FromStream(stream); +#endif } /// From 2e292b6ded7b49411f85e69d0aa3a4bae60a47b4 Mon Sep 17 00:00:00 2001 From: James South Date: Sat, 5 Jul 2014 13:31:06 +0100 Subject: [PATCH 098/155] Adding updated tests and reducing image sizes. Former-commit-id: a218abcd82c75f27d13c7662d5585d850158cd6f --- .../Extensions/DoubleExtensionsUnitTests.cs | 15 +-- .../Extensions/IntegerExtensionsUnitTests.cs | 5 +- .../Extensions/StringExtensionsUnitTests.cs | 90 +++++++++++------- .../Images/autorotate.jpg.REMOVED.git-id | 2 +- .../cmyk-profile-euroscale.jpg.REMOVED.git-id | 2 +- .../Images/cmyk.jpg.REMOVED.git-id | 2 +- .../color-vision-test.gif.REMOVED.git-id | 2 +- .../Images/exif-Tulips.jpg.REMOVED.git-id | 2 +- .../Images/exif-rocks.jpg.REMOVED.git-id | 2 +- .../format-Penguins-8bit.png.REMOVED.git-id | 2 +- .../Images/format-Penguins.bmp.REMOVED.git-id | 2 +- .../Images/format-Penguins.gif.REMOVED.git-id | 2 +- .../Images/format-Penguins.jpg.REMOVED.git-id | 2 +- .../Images/format-Penguins.png.REMOVED.git-id | 2 +- .../Images/format-animated.gif | Bin 22525 -> 0 bytes .../Images/format-animated.gif.REMOVED.git-id | 1 + .../Images/hi-color.png | Bin 1539 -> 23922 bytes .../Images/hi-contrast.jpg | Bin 51058 -> 34996 bytes .../Images/hi-saturation.jpg | Bin 33850 -> 51300 bytes .../profile-adobe-rgb.jpg.REMOVED.git-id | 2 +- .../Images/profile-srgb.jpg.REMOVED.git-id | 2 +- .../Images/size-Penguins-200.jpg | Bin 10119 -> 37476 bytes .../Images/text-over-transparent.png | Bin 7317 -> 7680 bytes .../Images/udendørs.jpg | Bin 0 -> 55987 bytes .../Images/udendørs.jpg.REMOVED.git-id | 1 - src/ImageProcessor/ImageFactory.cs | 5 +- .../Imaging/Formats/GifEncoder.cs | 10 +- .../Imaging/Formats/JpegFormat.cs | 2 +- src/ImageProcessorConsole/Program.cs | 19 ++-- .../images/output/120430.gif.REMOVED.git-id | 2 +- .../images/output/Tl4Yb.gif.REMOVED.git-id | 2 +- .../images/output/circle.png | Bin 0 -> 2905 bytes .../images/output/nLpfllv.gif.REMOVED.git-id | 2 +- 33 files changed, 100 insertions(+), 80 deletions(-) delete mode 100644 src/ImageProcessor.UnitTests/Images/format-animated.gif create mode 100644 src/ImageProcessor.UnitTests/Images/format-animated.gif.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/udendørs.jpg delete mode 100644 src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/circle.png diff --git a/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs index 108a9a246..cba1c07bc 100644 --- a/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs @@ -8,9 +8,8 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.UnitTests +namespace ImageProcessor.UnitTests.Extensions { - using System; using System.Collections.Generic; using Common.Extensions; using NUnit.Framework; @@ -32,11 +31,13 @@ namespace ImageProcessor.UnitTests [TestFixtureSetUp] public void Init() { - this.doubleToByteTests = new Dictionary(); - this.doubleToByteTests.Add(-10, 0x0); - this.doubleToByteTests.Add(1.5, 0x1); - this.doubleToByteTests.Add(25.7, 0x19); - this.doubleToByteTests.Add(1289047, 0xFF); + this.doubleToByteTests = new Dictionary + { + { -10, 0x0 }, + { 1.5, 0x1 }, + { 25.7, 0x19 }, + { 1289047, 0xFF } + }; } /// diff --git a/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs index 1e85e633b..2adbe3b17 100644 --- a/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs @@ -8,9 +8,8 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.UnitTests +namespace ImageProcessor.UnitTests.Extensions { - using System; using Common.Extensions; using NUnit.Framework; @@ -31,7 +30,7 @@ namespace ImageProcessor.UnitTests [TestCase(3156, 0xFF)] public void ToByteTest(int input, byte expected) { - var result = input.ToByte(); + byte result = input.ToByte(); Assert.AreEqual(expected, result); } } diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs index 70f3e83db..c89c09dcd 100644 --- a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -8,11 +8,11 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.UnitTests +namespace ImageProcessor.UnitTests.Extensions { using System; using System.Collections.Generic; - using Common.Extensions; + using ImageProcessor.Common.Extensions; using NUnit.Framework; /// @@ -25,7 +25,7 @@ namespace ImageProcessor.UnitTests /// Tests the MD5 fingerprint /// /// The input value - /// The expexted output of the hash + /// The expected output of the hash [Test] [TestCase("test input", "2e7f7a62eabf0993239ca17c78c464d9")] [TestCase("lorem ipsum dolor", "96ee002fee25e8b675a477c9750fa360")] @@ -33,8 +33,8 @@ namespace ImageProcessor.UnitTests [TestCase("1234567890", "e15e31c3d8898c92ab172a4311be9e84")] public void TestToMd5Fingerprint(string input, string expected) { - var result = input.ToMD5Fingerprint(); - var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + string result = input.ToMD5Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); Assert.True(comparison); } @@ -42,7 +42,7 @@ namespace ImageProcessor.UnitTests /// Tests the SHA-1 fingerprint /// /// The input value - /// The expexted output of the hash + /// The expected output of the hash [Test] [TestCase("test input", "49883b34e5a0f48224dd6230f471e9dc1bdbeaf5")] [TestCase("lorem ipsum dolor", "75899ad8827a32493928903aecd6e931bf36f967")] @@ -50,8 +50,8 @@ namespace ImageProcessor.UnitTests [TestCase("1234567890", "01b307acba4f54f55aafc33bb06bbbf6ca803e9a")] public void TestToSHA1Fingerprint(string input, string expected) { - var result = input.ToSHA1Fingerprint(); - var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + string result = input.ToSHA1Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); Assert.True(comparison); } @@ -59,7 +59,7 @@ namespace ImageProcessor.UnitTests /// Tests the SHA-256 fingerprint /// /// The input value - /// The expexted output of the hash + /// The expected output of the hash [Test] [TestCase("test input", "9dfe6f15d1ab73af898739394fd22fd72a03db01834582f24bb2e1c66c7aaeae")] [TestCase("lorem ipsum dolor", "ed03353266c993ea9afb9900a3ca688ddec1656941b1ca15ee1650a022616dfa")] @@ -67,8 +67,8 @@ namespace ImageProcessor.UnitTests [TestCase("1234567890", "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646")] public void TestToSHA256Fingerprint(string input, string expected) { - var result = input.ToSHA256Fingerprint(); - var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + string result = input.ToSHA256Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); Assert.True(comparison); } @@ -76,7 +76,7 @@ namespace ImageProcessor.UnitTests /// Tests the SHA-512 fingerprint /// /// The input value - /// The expexted output of the hash + /// The expected output of the hash [Test] [TestCase("test input", "40aa1b203c9d8ee150b21c3c7cda8261492e5420c5f2b9f7380700e094c303b48e62f319c1da0e32eb40d113c5f1749cc61aeb499167890ab82f2cc9bb706971")] [TestCase("lorem ipsum dolor", "cd813e13d1d3919cdccc31c19d8f8b70bd25e9819f8770a011c8c7a6228536e6c9427b338cd732f2da3c0444dfebef838b745cdaf3fd5dcba8db24fc83a3f6ef")] @@ -84,49 +84,73 @@ namespace ImageProcessor.UnitTests [TestCase("1234567890", "12b03226a6d8be9c6e8cd5e55dc6c7920caaa39df14aab92d5e3ea9340d1c8a4d3d0b8e4314f1f6ef131ba4bf1ceb9186ab87c801af0d5c95b1befb8cedae2b9")] public void TestToSHA512Fingerprint(string input, string expected) { - var result = input.ToSHA512Fingerprint(); - var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + string result = input.ToSHA512Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); Assert.True(comparison); } /// - /// Tests the pasing to an integer array + /// Tests the passing to an integer array /// [Test] public void TestToIntegerArray() { - Dictionary data = new Dictionary(); - data.Add("123-456,78-90", new int[] { 123, 456, 78, 90 }); - data.Add("87390174,741897498,74816,748297,57355", new int[] { 87390174, 741897498, 74816, 748297, 57355 }); - data.Add("1-2-3", new int[] { 1, 2, 3 }); + Dictionary data = new Dictionary + { + { + "123-456,78-90", + new[] { 123, 456, 78, 90 } + }, + { + "87390174,741897498,74816,748297,57355", + new[] + { + 87390174, 741897498, 74816, + 748297, 57355 + } + }, + { "1-2-3", new[] { 1, 2, 3 } } + }; - foreach (var item in data) + foreach (KeyValuePair item in data) { - var result = item.Key.ToPositiveIntegerArray(); + int[] result = item.Key.ToPositiveIntegerArray(); Assert.AreEqual(item.Value, result); } } /// - /// Tests the pasing to an float array + /// Tests the passing to an float array /// [Test] public void TestToFloatArray() { - Dictionary data = new Dictionary(); - data.Add("12.3-4.56,78-9.0", new float[] { 12.3F, 4.56F, 78, 9 }); - data.Add("87390.174,7.41897498,748.16,748297,5.7355", new float[] { 87390.174F, 7.41897498F, 748.16F, 748297, 5.7355F }); - data.Add("1-2-3", new float[] { 1, 2, 3 }); + Dictionary data = new Dictionary + { + { + "12.3-4.56,78-9.0", + new[] { 12.3F, 4.56F, 78, 9 } + }, + { + "87390.174,7.41897498,748.16,748297,5.7355", + new[] + { + 87390.174F, 7.41897498F, + 748.16F, 748297, 5.7355F + } + }, + { "1-2-3", new float[] { 1, 2, 3 } } + }; - foreach (var item in data) + foreach (KeyValuePair item in data) { - var result = item.Key.ToPositiveFloatArray(); + float[] result = item.Key.ToPositiveFloatArray(); Assert.AreEqual(item.Value, result); } } /// - /// Tests if the value is a valid URI + /// Tests if the value is a valid URI path name. I.E the path part of a uri. /// /// The value to test /// Whether the value is correct @@ -139,10 +163,10 @@ namespace ImageProcessor.UnitTests [TestCase(".", true)] [TestCase("_", true)] [TestCase("~", true)] - [TestCase(":", true)] + [TestCase(":", false)] [TestCase("/", true)] [TestCase("?", true)] - [TestCase("#", true)] + [TestCase("#", false)] [TestCase("[", false)] [TestCase("]", false)] [TestCase("@", true)] @@ -159,9 +183,9 @@ namespace ImageProcessor.UnitTests [TestCase("=", true)] [TestCase("lorem ipsum", false)] [TestCase("é", false)] - public void TestIsValidUri(string input, bool expected) + public void TestIsValidUriPathName(string input, bool expected) { - var result = input.IsValidVirtualPathName(); + bool result = input.IsValidVirtualPathName(); Assert.AreEqual(expected, result); } } diff --git a/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id index 19785c8e5..1b5e335ff 100644 --- a/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id @@ -1 +1 @@ -85a8ae18f9955def2b42ba9240bce4de1bfe5781 \ No newline at end of file +75b37593bb2e505bf4fbe874eaf30debd6161c2e \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id index 7747bdaae..11eb19931 100644 --- a/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id @@ -1 +1 @@ -13492524f9d984c12adfe6183a4c1d92fb11ec4e \ No newline at end of file +d0a1a39a6729e826098ae5e987c22c34c989b7e3 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id index 30b05146b..9ba0b9f39 100644 --- a/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id @@ -1 +1 @@ -ed725726e4ac1ffeac821664af14865a66fa933f \ No newline at end of file +9160894da31fedebb1fcd64eb57ca173187c63a6 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id index 5c4f4195d..ed1d0b80b 100644 --- a/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id @@ -1 +1 @@ -35a926115b13b61dc37308f8d903b42d14f92924 \ No newline at end of file +b169fac4f1591e81e91c0bb6fed6dcf62a34c80e \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id index 84b9aff85..20704f4a9 100644 --- a/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id @@ -1 +1 @@ -54c51eb6a86f31a42433b8167470fb18dad32c7d \ No newline at end of file +9d7e7964a2285363171929315b15ec69f14831ef \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id index 41c6c25df..2e03e238f 100644 --- a/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id @@ -1 +1 @@ -33b6912af301bf216ee81d82b2c3ce6c49e03021 \ No newline at end of file +be31c9c0dea90586e2965208611fad024f6a5b08 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id index aa9a70e0f..c48cdc177 100644 --- a/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id @@ -1 +1 @@ -c3d556d9d486b8b8b49cdbcc9c12a9d3a2db4c1f \ No newline at end of file +51ccec74a0351599de104f166b32d2860acaf089 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id index 74f69293c..9ba53bc67 100644 --- a/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id @@ -1 +1 @@ -8150b46ab27c62ba51aaba551eef3f1a30f08de9 \ No newline at end of file +d7adbea2db4e3388541e31a229e5741677aaa7fd \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id index ce873d473..225d59af3 100644 --- a/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id @@ -1 +1 @@ -6ad3b846d4697584ff601ac481b14a4d3bbb5736 \ No newline at end of file +b301e58d431a78d3f17be53be1cdc94c86286389 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id index ad4371113..06482dbd9 100644 --- a/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id @@ -1 +1 @@ -030ab8a685bebb796c24cc710edd9e69859164f6 \ No newline at end of file +ee5a15e7f8fc2655d5c1fc736a05857ab3d885bd \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id index 78062a0e7..4ab6b372b 100644 --- a/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id @@ -1 +1 @@ -a2c796fbb7de948230a22982ab74892891dd5198 \ No newline at end of file +b6434b5a35e989d4fa71ede1a8316fedeee7ae5f \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-animated.gif b/src/ImageProcessor.UnitTests/Images/format-animated.gif deleted file mode 100644 index 03fce3f3a5b70ca8463cefdd94c00e9c7fdbab0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22525 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 *EHnj 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 literal 1539 zcmeAS@N?(olHy`uVBq!ia0vp^_ks8^2NRI&QVv@Sq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1Ffc1+hD4M^`1)8S=jZArg4F0$^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&i0B&qvF*KNf0j6J(SfFpHX8`gNOrftYexnUy@&(kzb(T9Bihb5uTZsl3!k| z30CjxYvq|&T#}fVoa*Ufs{}MbFEca6%E-vr&DGS&$e6sFfDKe;qFHLnDwHwB^B8K+)QQpha;+U$~Alv$RV;#QQOs{r=0RVHq?SmHDf zsy79&@MZxrY@bS_4uF~aS4i!;cjdEf z+`YLsZi3Z7Yy?`2Zids92Qh*AD-SxZWVAC*Z%)(Oo}O3y>gPLRbejEY`e|FfX7{a{ zWl3>@Wo201<_Pof1XG*vl)Ce_-0Mx}ubdg)GFKMpa=0u!I07I(3sg_xJtsQzesR{r z&eO5kc9#>0vB3glL+5GJ`7i&U(LQvJ4>_FS27`kP6e^pxT@*j_erNLCtIv!@KX+}| z+zbv^u(N=Q(8H`{&BL8apR3N$b9Rps!C1*ISa;&jykKtsn0Ha1XYvta!>w=2 ncQ=&7f&lJPs9UamRzJXSYG=z6wgaz4LB+DCtDnm{r-UW|>o!Sj diff --git a/src/ImageProcessor.UnitTests/Images/hi-contrast.jpg b/src/ImageProcessor.UnitTests/Images/hi-contrast.jpg index bd2c9b90248231317b880634eac8f98f2dbdf6a7..a425cbc9e9215ddd019dfa69c37d8a73ee3e100c 100644 GIT binary patch literal 34996 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 diff --git a/src/ImageProcessor.UnitTests/Images/hi-saturation.jpg b/src/ImageProcessor.UnitTests/Images/hi-saturation.jpg index 909fa4fc55d43e54c2e4ef54021b1fb7275676a0..e4c58f3edf5c6d492473fd005275603ae996b8a6 100644 GIT binary patch delta 44329 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 delta 9586 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 diff --git a/src/ImageProcessor.UnitTests/Images/text-over-transparent.png b/src/ImageProcessor.UnitTests/Images/text-over-transparent.png index 21ebe3883c94844039cc07ad91487339b3ed1f34..7435dc6bacbb6f2942b3236030cbaf7a60a9c9c2 100644 GIT binary patch literal 7680 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 LJ>!~NZn6IZT~>i5 literal 7317 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 P0Kj7nJ@snU7ZLvfNs}N= diff --git a/src/ImageProcessor.UnitTests/Images/udendørs.jpg b/src/ImageProcessor.UnitTests/Images/udendørs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..48af69a24ac46fa672ec8f109e00cd378b99b1f8 GIT binary patch literal 55987 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 /// The program. @@ -33,6 +31,7 @@ namespace ImageProcessorConsole public static void Main(string[] args) { string path = new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath; + // ReSharper disable once AssignNullToNotNullAttribute string resolvedPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\input")); DirectoryInfo di = new DirectoryInfo(resolvedPath); @@ -41,10 +40,8 @@ namespace ImageProcessorConsole di.Create(); } - //FileInfo[] files = di.GetFiles("*.jpg"); - //FileInfo[] files = di.GetFiles(); - IEnumerable files = GetFilesByExtensions(di, ".gif", ".webp"); - + IEnumerable files = GetFilesByExtensions(di, ".gif"); + //IEnumerable files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png"); foreach (FileInfo fileInfo in files) { @@ -53,18 +50,13 @@ namespace ImageProcessorConsole // ImageProcessor using (MemoryStream inStream = new MemoryStream(photoBytes)) { - using (ImageFactory imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory(true)) { Size size = new Size(200, 200); // Load, resize, set the format and quality and save an image. imageFactory.Load(inStream) - //.AutoRotate() .Constrain(size) - //.Format(new WebPFormat()) - //.Quality(5) - // ReSharper disable once AssignNullToNotNullAttribute - // .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".webp"))); .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); } } @@ -74,7 +66,10 @@ namespace ImageProcessorConsole public static IEnumerable GetFilesByExtensions(DirectoryInfo dir, params string[] extensions) { if (extensions == null) + { throw new ArgumentNullException("extensions"); + } + IEnumerable files = dir.EnumerateFiles(); return files.Where(f => extensions.Contains(f.Extension, StringComparer.OrdinalIgnoreCase)); } diff --git a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id index 71ce555c1..4767fd13d 100644 --- a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id @@ -1 +1 @@ -30ec5c05548fd350f9b7c699715848b9fbfb8ca9 \ No newline at end of file +6f3f997e323adb1fce142930d86338efacffc3fd \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id index 6515d65a0..f0f194a2b 100644 --- a/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id @@ -1 +1 @@ -fdc62fc2d056ab885eb9e8fd12b9155ee86d7c43 \ No newline at end of file +3ab082661fc5d88f88643c47409e196d66e26d4b \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/circle.png b/src/ImageProcessorConsole/images/output/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..41fdcd72af59ba2158b19120e7ba11f4cad0180d GIT binary patch literal 2905 zcmbVO`#Teg8=q?-w;J7C3v(BmT*6$&-0yR2?gw9#TtcCm#E?#R>puEfm`g5&ES?;$VJP0RV|tzri;c+ZYA_ zh<wV|-W2buBpOameE+y`x3$8753+ukYuuzZ0`hvWq8*|&++tT|)zFa6du-fqA#oc7^ zdRO!YlDI}+dFP<_`O|^9fx)^avyaroW^mHV>T6wgdMz1i2~p+yth)!-(|2ps%v}jT zO`<30rk~VS8RIS^m58;iOZ)pf%wk&R+ddB>{CHu0{>VnR@aXA}XmG{RXh)XBYC*+V z0nvpW#e8>}$8+Os$FK*BlYAR4eAS06l{ag|H=X*PEDx&iU0cjvZJ&KI-euk9N_xjw z4M80NFhdzK(a)~dZpQyu&;cIuyn#ykL|W!*#=MwXkrY#s7Z4DzfAr$*hiBKDU^S5q z#_Fckw7D)Q$?bcNNZimH_p_BcF`B985OiP(o3;fk^+3G=94La{bhpc=jGxk|4Sv?7 zp^n1pjv1}P^!WM-9_qp}16kX74eOr;t~0uctIFOpowLwhE*gIOyXYHs#oS!4yOwM(?I&g*Rj6ax;!xWF1ja zs=V)lajaVxo3h12N*wF1z3$O?`CgtUn|vRuxb94Zf5?C{9gUxBwQM!8g@-h_iC@Y7 zCD(#vrF5LT6ED6er}rp7)K!xs7rPY=&cDzm39e_rTe1w66fYA~wUD^;l$K-*G*`@BydQBi3ZBTT#WNF2~4V#;V@_)`C}Jftw&8fuxf zT(C<${)ELg;>b?0_A#G}P!um)`~ChVWaBi5F#U7lWX3uuXz127*Q(+DM(3T+9&$V& zlVXSnz#)hV1U#!7Ljnsdcy-`3l!B5@*LXD!X_YHbie02rNX)4(bYkY?R;+I0c*Wy! zqA+fkdZW1Xc_kXG`87?%K0drSh;ha;!A$wmd3?*CX+HkU+4}Td7lm~-Nxz5qx1NxW zb5^-J$Z5wqnmrpnBuc!P$C8ngaq1PAzIMj%VY>edZqs&~e0nlJszd%ZQp^vR?)-!- zYR5f^&YMKQsMFKIP=W*sD0BBR2q*OIBI!5{AE&JtqARK{heLc`~JM+;}^DTPHAh>w-o!x3n}yEI(JH zPoiryCcAdqtevD|pxLaggxJ0kSD~!&Ku$3vH4{{=wADF+2A+Q9kIMleH|AFr!`4E? z8}{{;`B_ANjf| z?u-Qll5w9L8Gjoo?%*!1xJDNiQeTyleNIOU2Hbh9suc42Mn0aSLOO-P$wbKWiFhp% zI{pw;5!akQ#ecN^jqj?|)FRyGsCR#mG&)W-mN(8hudcN9T^nA8A*Ch${q6S*ViBqX z;c=rIn)NUJHbvrI}%V{3^YL9RbVD z<@Juu;%BL{=0cel+FbLvk76Qv86z7{?*XPJ$LP~jJY=4=XgC=GyR+&e z0*jjf1r4%8VRv%7a>X{|!tyH3DQ4HcPMTcNueGA=3LaCDOMxgPq$%rYE|&e%dh^6h zR>s57;cEiE&&lZ0*4EZ?O^%`n?1X{hLv_=U)hz8%;LONrespY$8g(IIe#}}nl44RU z;(4PhXRDitmU*D?3XxI;QlXTt@+X?7+-8aT;nOFnMuc%s-1m2!AdUjYAjGUab z;{d5xz3Q3_OIKK~>JKNxtdTY7edE3y>+$SR53PMJHcY-+h$g<`gVWso;9L|sblh;C z`>-Msx^vV^7OUsJ4bPqTRVdhO zi?(~E&(SmpEkFA^la^?OIU|0cq>!t#n84 zib4n?4ol%P=;X#Rv7QZg!7rOTa%o0c=tNgpiGZss^!P_u`CQv}#Qj2>io*`v_2CdC z!7Zh$=5Az`Szz`)<;`XANmVZ|W8Dn{o1&s}(9rn*%2Ynfuaq&o@k*>(9_K$V#|$- zI#>0c$56Ex5^fu`=(l%Cu7H19`k_!_3{3vGw?`!V5WKlL{G%q(?GyUZFY_+{teflY zlunZ`TXg4i+_W9Yr==xge`O652-d?!mqz*O2%bMn6B}{)l0TtOv80BPk}RueYY|Z= zQD-H(Y>;IS!9Etc0kI#T6H)o6FT`JslTd?<1Tl8Zf!XG?h`oDeNk94bR*DlXSl>h; z`yPgpgm`S@ZOfKLvYiVGyJ1!tOJ6gIa%{sUtsEEbCN82p9+Xtk8L=Pxn9KMpV_QGl znzLLPeT8cq+JX*`yi+U519iXujg*f2T%XS%6ytI`K5JlKG@;j<&LCSIh%u!8dsqYn cgibs=08DFl4wva{Y5hLr0Clx(whqqtKN+=SzW@LL literal 0 HcmV?d00001 diff --git a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id index c07be0b0f..b8684cd60 100644 --- a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id @@ -1 +1 @@ -77cce70db3722920d60f4b17a45a5e390a09838a \ No newline at end of file +e2c2fbac64987ad26e19f5d2721fcaa60fee843d \ No newline at end of file From bb4301ab3c0fac41204ca5407e82402f190cf399 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 22:54:11 +0200 Subject: [PATCH 099/155] Adds unit tests for double extension methods + Fixes a build problem on Mono Former-commit-id: 8207e6dc22d5d71288274a2ca58e3346c59224b8 --- .../Extensions/DoubleExtensionsUnitTests.cs | 55 +++++++++++++++++++ .../ImageProcessor.UnitTests.csproj | 4 ++ src/ImageProcessor/ImageProcessor.csproj | 6 +- 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs new file mode 100644 index 000000000..108a9a246 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs @@ -0,0 +1,55 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Runs unit tests on the extension methods +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.UnitTests +{ + using System; + using System.Collections.Generic; + using Common.Extensions; + using NUnit.Framework; + + /// + /// Test harness for the DoubleExtensions extension methods + /// + [TestFixture] + public class DoubleExtensionsUnitTests + { + /// + /// Stores the values to test for the ToByte() extension method + /// + private Dictionary doubleToByteTests; + + /// + /// Sets up the values for the tests + /// + [TestFixtureSetUp] + public void Init() + { + this.doubleToByteTests = new Dictionary(); + this.doubleToByteTests.Add(-10, 0x0); + this.doubleToByteTests.Add(1.5, 0x1); + this.doubleToByteTests.Add(25.7, 0x19); + this.doubleToByteTests.Add(1289047, 0xFF); + } + + /// + /// Tests the double to byte conversion + /// + [Test] + public void TestDoubleToByte() + { + foreach (var item in this.doubleToByteTests) + { + var result = item.Key.ToByte(); + Assert.AreEqual(item.Value, result); + } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index c872dbbb8..e715df657 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -46,6 +46,7 @@ PreserveNewest + @@ -127,4 +128,7 @@ + + + \ No newline at end of file diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 1c5b26e80..c21b78194 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -3,8 +3,6 @@ Debug AnyCPU - 8.0.30703 - 2.0 {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} Library Properties @@ -25,7 +23,6 @@ prompt 4 bin\Debug\ImageProcessor.XML - false pdbonly @@ -46,6 +43,8 @@ prompt false true + 4 + false @@ -57,6 +56,7 @@ + From 0dc3264d08f06a8da3ab5f47c1ff9241aff6af3a Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Sun, 29 Jun 2014 23:41:33 +0200 Subject: [PATCH 100/155] Adds a few unit tests for integer extension methods Former-commit-id: a188cb5d3f7458ed0c76a01c774fab95f19d3871 --- .../Extensions/IntegerExtensionsUnitTests.cs | 38 +++++++++++++++++++ .../ImageProcessor.UnitTests.csproj | 1 + 2 files changed, 39 insertions(+) create mode 100644 src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs new file mode 100644 index 000000000..1e85e633b --- /dev/null +++ b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs @@ -0,0 +1,38 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Runs unit tests on the extension methods +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.UnitTests +{ + using System; + using Common.Extensions; + using NUnit.Framework; + + /// + /// Provides a test harness for the integer extension class + /// + [TestFixture] + public class IntegerExtensionsUnitTests + { + /// + /// Tests the "ToByte" extension + /// + /// Integer input + /// Expected result + [Test] + [TestCase(21, 0x15)] + [TestCase(190, 0xBE)] + [TestCase(3156, 0xFF)] + public void ToByteTest(int input, byte expected) + { + var result = input.ToByte(); + Assert.AreEqual(expected, result); + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index e715df657..b545a11d9 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -47,6 +47,7 @@ PreserveNewest + From d02be122fdc9cb396e134e1b642d487565a1b075 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 4 Jul 2014 22:01:17 +0200 Subject: [PATCH 101/155] Unit tests some string extensions Former-commit-id: 86f7663ed5656b3241f9a7ea8b1e532140399e7b --- .../Extensions/StringExtensionsUnitTests.cs | 91 +++++++++++++++++++ .../ImageProcessor.UnitTests.csproj | 1 + 2 files changed, 92 insertions(+) create mode 100644 src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs new file mode 100644 index 000000000..d1fefa395 --- /dev/null +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -0,0 +1,91 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides a test harness for the string extensions +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.UnitTests +{ + using System; + using Common.Extensions; + using NUnit.Framework; + + /// + /// Test harness for the string extensions + /// + [TestFixture] + public class StringExtensionsUnitTests + { + /// + /// Tests the MD5 fingerprint + /// + /// The input value + /// The expexted output of the hash + [Test] + [TestCase("test input", "2e7f7a62eabf0993239ca17c78c464d9")] + [TestCase("lorem ipsum dolor", "96ee002fee25e8b675a477c9750fa360")] + [TestCase("LoReM IpSuM DoLoR", "41e201da794c7fbdb8ce5526a71c8c83")] + [TestCase("1234567890", "e15e31c3d8898c92ab172a4311be9e84")] + public void TestToMd5Fingerprint(string input, string expected) + { + var result = input.ToMD5Fingerprint(); + var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + + /// + /// Tests the SHA-1 fingerprint + /// + /// The input value + /// The expexted output of the hash + [Test] + [TestCase("test input", "49883b34e5a0f48224dd6230f471e9dc1bdbeaf5")] + [TestCase("lorem ipsum dolor", "75899ad8827a32493928903aecd6e931bf36f967")] + [TestCase("LoReM IpSuM DoLoR", "2f44519afae72fc0837b72c6b53cb11338a1f916")] + [TestCase("1234567890", "01b307acba4f54f55aafc33bb06bbbf6ca803e9a")] + public void TestToSHA1Fingerprint(string input, string expected) + { + var result = input.ToSHA1Fingerprint(); + var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + + /// + /// Tests the SHA-256 fingerprint + /// + /// The input value + /// The expexted output of the hash + [Test] + [TestCase("test input", "9dfe6f15d1ab73af898739394fd22fd72a03db01834582f24bb2e1c66c7aaeae")] + [TestCase("lorem ipsum dolor", "ed03353266c993ea9afb9900a3ca688ddec1656941b1ca15ee1650a022616dfa")] + [TestCase("LoReM IpSuM DoLoR", "55f6cb90ba5cd8eeb6f5f16f083ebcd48ea06c34cc5aed8e33246fc3153d3898")] + [TestCase("1234567890", "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646")] + public void TestToSHA256Fingerprint(string input, string expected) + { + var result = input.ToSHA256Fingerprint(); + var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + + /// + /// Tests the SHA-512 fingerprint + /// + /// The input value + /// The expexted output of the hash + [Test] + [TestCase("test input", "40aa1b203c9d8ee150b21c3c7cda8261492e5420c5f2b9f7380700e094c303b48e62f319c1da0e32eb40d113c5f1749cc61aeb499167890ab82f2cc9bb706971")] + [TestCase("lorem ipsum dolor", "cd813e13d1d3919cdccc31c19d8f8b70bd25e9819f8770a011c8c7a6228536e6c9427b338cd732f2da3c0444dfebef838b745cdaf3fd5dcba8db24fc83a3f6ef")] + [TestCase("LoReM IpSuM DoLoR", "3e4704d31f838456c0a5f0892afd392fbc79649a029d017b8104ebd00e2816d94ab4629f731765bf655088b130c51f6f47ca2f8b047749dbd992cf45e89ff431")] + [TestCase("1234567890", "12b03226a6d8be9c6e8cd5e55dc6c7920caaa39df14aab92d5e3ea9340d1c8a4d3d0b8e4314f1f6ef131ba4bf1ceb9186ab87c801af0d5c95b1befb8cedae2b9")] + public void TestToSHA512Fingerprint(string input, string expected) + { + var result = input.ToSHA512Fingerprint(); + var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index b545a11d9..5b6bc12d1 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -48,6 +48,7 @@ + From af71ce4730de9dd63810f7718ba1694e93c08989 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 4 Jul 2014 22:31:53 +0200 Subject: [PATCH 102/155] Adds unit tests for some more string extensions Former-commit-id: fe3875fa22e329b54839fd95ef8bcd245fb50e2e --- .../Extensions/StringExtensionsUnitTests.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs index d1fefa395..17cc4c753 100644 --- a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -11,6 +11,7 @@ namespace ImageProcessor.UnitTests { using System; + using System.Collections.Generic; using Common.Extensions; using NUnit.Framework; @@ -87,5 +88,41 @@ namespace ImageProcessor.UnitTests var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); Assert.True(comparison); } + + /// + /// Tests the pasing to an integer array + /// + [Test] + public void TestToIntegerArray() + { + Dictionary data = new Dictionary(); + data.Add("123-456,78-90", new int[] { 123, 456, 78, 90 }); + data.Add("87390174,741897498,74816,748297,57355", new int[] { 87390174, 741897498, 74816, 748297, 57355 }); + data.Add("1-2-3", new int[] { 1, 2, 3 }); + + foreach (var item in data) + { + var result = item.Key.ToPositiveIntegerArray(); + Assert.AreEqual(item.Value, result); + } + } + + /// + /// Tests the pasing to an float array + /// + [Test] + public void TestToFloatArray() + { + Dictionary data = new Dictionary(); + data.Add("12.3-4.56,78-9.0", new float[] { 12.3F, 4.56F, 78, 9 }); + data.Add("87390.174,7.41897498,748.16,748297,5.7355", new float[] { 87390.174F, 7.41897498F, 748.16F, 748297, 5.7355F }); + data.Add("1-2-3", new float[] { 1, 2, 3 }); + + foreach (var item in data) + { + var result = item.Key.ToPositiveFloatArray(); + Assert.AreEqual(item.Value, result); + } + } } } \ No newline at end of file From c8b90a92a90f4f2d54312dd87b589a557ce7df93 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 4 Jul 2014 22:49:13 +0200 Subject: [PATCH 103/155] Tests a few more string extensions Former-commit-id: df69ccf584bf3b30433e2ee51808aeaf471d2fb3 --- .../Extensions/StringExtensionsUnitTests.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs index 17cc4c753..70f3e83db 100644 --- a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -124,5 +124,45 @@ namespace ImageProcessor.UnitTests Assert.AreEqual(item.Value, result); } } + + /// + /// Tests if the value is a valid URI + /// + /// The value to test + /// Whether the value is correct + /// + /// The full RFC3986 does not seem to pass the test with the square brackets + /// + [Test] + [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", true)] + [TestCase("-", true)] + [TestCase(".", true)] + [TestCase("_", true)] + [TestCase("~", true)] + [TestCase(":", true)] + [TestCase("/", true)] + [TestCase("?", true)] + [TestCase("#", true)] + [TestCase("[", false)] + [TestCase("]", false)] + [TestCase("@", true)] + [TestCase("!", true)] + [TestCase("$", true)] + [TestCase("&", true)] + [TestCase("'", true)] + [TestCase("(", true)] + [TestCase(")", true)] + [TestCase("*", true)] + [TestCase("+", true)] + [TestCase(",", true)] + [TestCase(";", true)] + [TestCase("=", true)] + [TestCase("lorem ipsum", false)] + [TestCase("é", false)] + public void TestIsValidUri(string input, bool expected) + { + var result = input.IsValidVirtualPathName(); + Assert.AreEqual(expected, result); + } } } \ No newline at end of file From 883f7a5b9d02458ff880be25e5835e001ad568d1 Mon Sep 17 00:00:00 2001 From: James South Date: Sat, 5 Jul 2014 10:24:13 +0100 Subject: [PATCH 104/155] Making project build on Mono Former-commit-id: 78fbbc22918ba951d74ac2b16a1c996b0ca21661 --- src/ImageProcessor/ImageProcessor.csproj | 1 + src/ImageProcessor/Imaging/Formats/FormatBase.cs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index c21b78194..274b3e76d 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -13,6 +13,7 @@ ..\ true Client + False true diff --git a/src/ImageProcessor/Imaging/Formats/FormatBase.cs b/src/ImageProcessor/Imaging/Formats/FormatBase.cs index ea00e82a2..189bad8c3 100644 --- a/src/ImageProcessor/Imaging/Formats/FormatBase.cs +++ b/src/ImageProcessor/Imaging/Formats/FormatBase.cs @@ -90,7 +90,11 @@ namespace ImageProcessor.Imaging.Formats /// public virtual Image Load(Stream stream) { +#if !__MonoCS__ return Image.FromStream(stream, true); +#else + return Image.FromStream(stream); +#endif } /// From a848505ad6c61c0532a4126c3b5dcc9fa48b2365 Mon Sep 17 00:00:00 2001 From: James South Date: Sat, 5 Jul 2014 13:31:06 +0100 Subject: [PATCH 105/155] Adding updated tests and reducing image sizes. Former-commit-id: 03d98f7b9239cc7c688f6ec07f4b39375ce52d85 --- .../Extensions/DoubleExtensionsUnitTests.cs | 15 +-- .../Extensions/IntegerExtensionsUnitTests.cs | 5 +- .../Extensions/StringExtensionsUnitTests.cs | 90 +++++++++++------- .../Images/autorotate.jpg.REMOVED.git-id | 2 +- .../cmyk-profile-euroscale.jpg.REMOVED.git-id | 2 +- .../Images/cmyk.jpg.REMOVED.git-id | 2 +- .../color-vision-test.gif.REMOVED.git-id | 2 +- .../Images/exif-Tulips.jpg.REMOVED.git-id | 2 +- .../Images/exif-rocks.jpg.REMOVED.git-id | 2 +- .../format-Penguins-8bit.png.REMOVED.git-id | 2 +- .../Images/format-Penguins.bmp.REMOVED.git-id | 2 +- .../Images/format-Penguins.gif.REMOVED.git-id | 2 +- .../Images/format-Penguins.jpg.REMOVED.git-id | 2 +- .../Images/format-Penguins.png.REMOVED.git-id | 2 +- .../Images/format-animated.gif | Bin 22525 -> 0 bytes .../Images/format-animated.gif.REMOVED.git-id | 1 + .../Images/hi-color.png | Bin 1539 -> 23922 bytes .../Images/hi-contrast.jpg | Bin 51058 -> 34996 bytes .../Images/hi-saturation.jpg | Bin 33850 -> 51300 bytes .../profile-adobe-rgb.jpg.REMOVED.git-id | 2 +- .../Images/profile-srgb.jpg.REMOVED.git-id | 2 +- .../Images/size-Penguins-200.jpg | Bin 10119 -> 37476 bytes .../Images/text-over-transparent.png | Bin 7317 -> 7680 bytes .../Images/udendørs.jpg | Bin 0 -> 55987 bytes .../Images/udendørs.jpg.REMOVED.git-id | 1 - src/ImageProcessor/ImageFactory.cs | 5 +- .../Imaging/Formats/GifEncoder.cs | 10 +- .../Imaging/Formats/JpegFormat.cs | 2 +- src/ImageProcessorConsole/Program.cs | 19 ++-- .../images/output/120430.gif.REMOVED.git-id | 2 +- .../images/output/Tl4Yb.gif.REMOVED.git-id | 2 +- .../images/output/circle.png | Bin 0 -> 2905 bytes .../images/output/nLpfllv.gif.REMOVED.git-id | 2 +- 33 files changed, 100 insertions(+), 80 deletions(-) delete mode 100644 src/ImageProcessor.UnitTests/Images/format-animated.gif create mode 100644 src/ImageProcessor.UnitTests/Images/format-animated.gif.REMOVED.git-id create mode 100644 src/ImageProcessor.UnitTests/Images/udendørs.jpg delete mode 100644 src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id create mode 100644 src/ImageProcessorConsole/images/output/circle.png diff --git a/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs index 108a9a246..cba1c07bc 100644 --- a/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs @@ -8,9 +8,8 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.UnitTests +namespace ImageProcessor.UnitTests.Extensions { - using System; using System.Collections.Generic; using Common.Extensions; using NUnit.Framework; @@ -32,11 +31,13 @@ namespace ImageProcessor.UnitTests [TestFixtureSetUp] public void Init() { - this.doubleToByteTests = new Dictionary(); - this.doubleToByteTests.Add(-10, 0x0); - this.doubleToByteTests.Add(1.5, 0x1); - this.doubleToByteTests.Add(25.7, 0x19); - this.doubleToByteTests.Add(1289047, 0xFF); + this.doubleToByteTests = new Dictionary + { + { -10, 0x0 }, + { 1.5, 0x1 }, + { 25.7, 0x19 }, + { 1289047, 0xFF } + }; } /// diff --git a/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs index 1e85e633b..2adbe3b17 100644 --- a/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/IntegerExtensionsUnitTests.cs @@ -8,9 +8,8 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.UnitTests +namespace ImageProcessor.UnitTests.Extensions { - using System; using Common.Extensions; using NUnit.Framework; @@ -31,7 +30,7 @@ namespace ImageProcessor.UnitTests [TestCase(3156, 0xFF)] public void ToByteTest(int input, byte expected) { - var result = input.ToByte(); + byte result = input.ToByte(); Assert.AreEqual(expected, result); } } diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs index 70f3e83db..c89c09dcd 100644 --- a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -8,11 +8,11 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.UnitTests +namespace ImageProcessor.UnitTests.Extensions { using System; using System.Collections.Generic; - using Common.Extensions; + using ImageProcessor.Common.Extensions; using NUnit.Framework; /// @@ -25,7 +25,7 @@ namespace ImageProcessor.UnitTests /// Tests the MD5 fingerprint /// /// The input value - /// The expexted output of the hash + /// The expected output of the hash [Test] [TestCase("test input", "2e7f7a62eabf0993239ca17c78c464d9")] [TestCase("lorem ipsum dolor", "96ee002fee25e8b675a477c9750fa360")] @@ -33,8 +33,8 @@ namespace ImageProcessor.UnitTests [TestCase("1234567890", "e15e31c3d8898c92ab172a4311be9e84")] public void TestToMd5Fingerprint(string input, string expected) { - var result = input.ToMD5Fingerprint(); - var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + string result = input.ToMD5Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); Assert.True(comparison); } @@ -42,7 +42,7 @@ namespace ImageProcessor.UnitTests /// Tests the SHA-1 fingerprint ///

SNvLWO-4E?ea^7+w$l;bX&K-w#;Bnura{eK) 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 ZFWzs)rjzfj6jECOZa=zcqKcuT|JgE5#Mb}- literal 0 HcmV?d00001 diff --git a/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id deleted file mode 100644 index 0db1445a2..000000000 --- a/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -4d040d9aa3519b3d2303419d1f03eebebf88e956 \ No newline at end of file diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index f2f573268..7e37983c3 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -158,9 +158,10 @@ namespace ImageProcessor this.CurrentImageFormat = format; // Always load the data. - foreach (PropertyItem propertyItem in this.Image.PropertyItems) + // TODO. Some custom data doesn't seem to get copied by default methods. + foreach (int id in this.Image.PropertyIdList) { - this.ExifPropertyItems[propertyItem.Id] = propertyItem; + this.ExifPropertyItems[id] = this.Image.GetPropertyItem(id); } this.ShouldProcess = true; diff --git a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs index 662ad314c..b7650d099 100644 --- a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs +++ b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs @@ -282,17 +282,17 @@ namespace ImageProcessor.Imaging.Formats { int count = this.repeatCount.GetValueOrDefault(0); - // File Header sinature and version. + // File Header signature and version. this.WriteString(FileType); this.WriteString(FileVersion); // Write the logical screen descriptor. this.WriteShort(this.width.GetValueOrDefault(w)); // Initial Logical Width this.WriteShort(this.height.GetValueOrDefault(h)); // Initial Logical Height - + // Read the global color table info. sourceGif.Position = SourceGlobalColorInfoPosition; - this.WriteByte(sourceGif.ReadByte()); + this.WriteByte(sourceGif.ReadByte()); this.WriteByte(0); // Background Color Index this.WriteByte(0); // Pixel aspect ratio @@ -301,7 +301,7 @@ namespace ImageProcessor.Imaging.Formats // The different browsers interpret the spec differently when adding a loop. // If the loop count is one IE and FF < 3 (incorrectly) loop an extra number of times. // Removing the Netscape header should fix this. - if (count != 1) + if (count > -1 && count != 1) { // Application Extension Header this.WriteShort(ApplicationExtensionBlockIdentifier); @@ -357,7 +357,7 @@ namespace ImageProcessor.Imaging.Formats this.WriteShort(GraphicControlExtensionBlockIdentifier); // Identifier this.WriteByte(GraphicControlExtensionBlockSize); // Block Size this.WriteByte(blockhead[3] & 0xf7 | 0x08); // Setting disposal flag - this.WriteShort(Convert.ToInt32(frameDelay / 10)); // Setting frame delay + this.WriteShort(Convert.ToInt32(frameDelay / 10.0f)); // Setting frame delay this.WriteByte(blockhead[6]); // Transparent color index this.WriteByte(0); // Terminator } diff --git a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs index ae5fd05c3..f7ff73c66 100644 --- a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs @@ -75,7 +75,7 @@ namespace ImageProcessor.Imaging.Formats { base.ApplyProcessor(processor, factory); - // Set the property item information from any Exif metadata. + // Set the property item information from any Exif metadata. // We do this here so that they can be changed between processor methods. if (factory.PreserveExifData) { diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index 248fe1d7f..5bacb50dd 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -15,9 +15,7 @@ namespace ImageProcessorConsole using System.Drawing; using System.IO; using System.Linq; - using ImageProcessor; - using ImageProcessor.Imaging.Formats; ///

/// The input value - /// The expexted output of the hash + /// The expected output of the hash [Test] [TestCase("test input", "49883b34e5a0f48224dd6230f471e9dc1bdbeaf5")] [TestCase("lorem ipsum dolor", "75899ad8827a32493928903aecd6e931bf36f967")] @@ -50,8 +50,8 @@ namespace ImageProcessor.UnitTests [TestCase("1234567890", "01b307acba4f54f55aafc33bb06bbbf6ca803e9a")] public void TestToSHA1Fingerprint(string input, string expected) { - var result = input.ToSHA1Fingerprint(); - var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + string result = input.ToSHA1Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); Assert.True(comparison); } @@ -59,7 +59,7 @@ namespace ImageProcessor.UnitTests /// Tests the SHA-256 fingerprint ///
/// The input value - /// The expexted output of the hash + /// The expected output of the hash [Test] [TestCase("test input", "9dfe6f15d1ab73af898739394fd22fd72a03db01834582f24bb2e1c66c7aaeae")] [TestCase("lorem ipsum dolor", "ed03353266c993ea9afb9900a3ca688ddec1656941b1ca15ee1650a022616dfa")] @@ -67,8 +67,8 @@ namespace ImageProcessor.UnitTests [TestCase("1234567890", "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646")] public void TestToSHA256Fingerprint(string input, string expected) { - var result = input.ToSHA256Fingerprint(); - var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + string result = input.ToSHA256Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); Assert.True(comparison); } @@ -76,7 +76,7 @@ namespace ImageProcessor.UnitTests /// Tests the SHA-512 fingerprint ///
/// The input value - /// The expexted output of the hash + /// The expected output of the hash [Test] [TestCase("test input", "40aa1b203c9d8ee150b21c3c7cda8261492e5420c5f2b9f7380700e094c303b48e62f319c1da0e32eb40d113c5f1749cc61aeb499167890ab82f2cc9bb706971")] [TestCase("lorem ipsum dolor", "cd813e13d1d3919cdccc31c19d8f8b70bd25e9819f8770a011c8c7a6228536e6c9427b338cd732f2da3c0444dfebef838b745cdaf3fd5dcba8db24fc83a3f6ef")] @@ -84,49 +84,73 @@ namespace ImageProcessor.UnitTests [TestCase("1234567890", "12b03226a6d8be9c6e8cd5e55dc6c7920caaa39df14aab92d5e3ea9340d1c8a4d3d0b8e4314f1f6ef131ba4bf1ceb9186ab87c801af0d5c95b1befb8cedae2b9")] public void TestToSHA512Fingerprint(string input, string expected) { - var result = input.ToSHA512Fingerprint(); - var comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + string result = input.ToSHA512Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); Assert.True(comparison); } /// - /// Tests the pasing to an integer array + /// Tests the passing to an integer array /// [Test] public void TestToIntegerArray() { - Dictionary data = new Dictionary(); - data.Add("123-456,78-90", new int[] { 123, 456, 78, 90 }); - data.Add("87390174,741897498,74816,748297,57355", new int[] { 87390174, 741897498, 74816, 748297, 57355 }); - data.Add("1-2-3", new int[] { 1, 2, 3 }); + Dictionary data = new Dictionary + { + { + "123-456,78-90", + new[] { 123, 456, 78, 90 } + }, + { + "87390174,741897498,74816,748297,57355", + new[] + { + 87390174, 741897498, 74816, + 748297, 57355 + } + }, + { "1-2-3", new[] { 1, 2, 3 } } + }; - foreach (var item in data) + foreach (KeyValuePair item in data) { - var result = item.Key.ToPositiveIntegerArray(); + int[] result = item.Key.ToPositiveIntegerArray(); Assert.AreEqual(item.Value, result); } } /// - /// Tests the pasing to an float array + /// Tests the passing to an float array /// [Test] public void TestToFloatArray() { - Dictionary data = new Dictionary(); - data.Add("12.3-4.56,78-9.0", new float[] { 12.3F, 4.56F, 78, 9 }); - data.Add("87390.174,7.41897498,748.16,748297,5.7355", new float[] { 87390.174F, 7.41897498F, 748.16F, 748297, 5.7355F }); - data.Add("1-2-3", new float[] { 1, 2, 3 }); + Dictionary data = new Dictionary + { + { + "12.3-4.56,78-9.0", + new[] { 12.3F, 4.56F, 78, 9 } + }, + { + "87390.174,7.41897498,748.16,748297,5.7355", + new[] + { + 87390.174F, 7.41897498F, + 748.16F, 748297, 5.7355F + } + }, + { "1-2-3", new float[] { 1, 2, 3 } } + }; - foreach (var item in data) + foreach (KeyValuePair item in data) { - var result = item.Key.ToPositiveFloatArray(); + float[] result = item.Key.ToPositiveFloatArray(); Assert.AreEqual(item.Value, result); } } /// - /// Tests if the value is a valid URI + /// Tests if the value is a valid URI path name. I.E the path part of a uri. /// /// The value to test /// Whether the value is correct @@ -139,10 +163,10 @@ namespace ImageProcessor.UnitTests [TestCase(".", true)] [TestCase("_", true)] [TestCase("~", true)] - [TestCase(":", true)] + [TestCase(":", false)] [TestCase("/", true)] [TestCase("?", true)] - [TestCase("#", true)] + [TestCase("#", false)] [TestCase("[", false)] [TestCase("]", false)] [TestCase("@", true)] @@ -159,9 +183,9 @@ namespace ImageProcessor.UnitTests [TestCase("=", true)] [TestCase("lorem ipsum", false)] [TestCase("é", false)] - public void TestIsValidUri(string input, bool expected) + public void TestIsValidUriPathName(string input, bool expected) { - var result = input.IsValidVirtualPathName(); + bool result = input.IsValidVirtualPathName(); Assert.AreEqual(expected, result); } } diff --git a/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id index 19785c8e5..1b5e335ff 100644 --- a/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/autorotate.jpg.REMOVED.git-id @@ -1 +1 @@ -85a8ae18f9955def2b42ba9240bce4de1bfe5781 \ No newline at end of file +75b37593bb2e505bf4fbe874eaf30debd6161c2e \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id index 7747bdaae..11eb19931 100644 --- a/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/cmyk-profile-euroscale.jpg.REMOVED.git-id @@ -1 +1 @@ -13492524f9d984c12adfe6183a4c1d92fb11ec4e \ No newline at end of file +d0a1a39a6729e826098ae5e987c22c34c989b7e3 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id index 30b05146b..9ba0b9f39 100644 --- a/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/cmyk.jpg.REMOVED.git-id @@ -1 +1 @@ -ed725726e4ac1ffeac821664af14865a66fa933f \ No newline at end of file +9160894da31fedebb1fcd64eb57ca173187c63a6 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id index 5c4f4195d..ed1d0b80b 100644 --- a/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/color-vision-test.gif.REMOVED.git-id @@ -1 +1 @@ -35a926115b13b61dc37308f8d903b42d14f92924 \ No newline at end of file +b169fac4f1591e81e91c0bb6fed6dcf62a34c80e \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id index 84b9aff85..20704f4a9 100644 --- a/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/exif-Tulips.jpg.REMOVED.git-id @@ -1 +1 @@ -54c51eb6a86f31a42433b8167470fb18dad32c7d \ No newline at end of file +9d7e7964a2285363171929315b15ec69f14831ef \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id index 41c6c25df..2e03e238f 100644 --- a/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/exif-rocks.jpg.REMOVED.git-id @@ -1 +1 @@ -33b6912af301bf216ee81d82b2c3ce6c49e03021 \ No newline at end of file +be31c9c0dea90586e2965208611fad024f6a5b08 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id index aa9a70e0f..c48cdc177 100644 --- a/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins-8bit.png.REMOVED.git-id @@ -1 +1 @@ -c3d556d9d486b8b8b49cdbcc9c12a9d3a2db4c1f \ No newline at end of file +51ccec74a0351599de104f166b32d2860acaf089 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id index 74f69293c..9ba53bc67 100644 --- a/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.bmp.REMOVED.git-id @@ -1 +1 @@ -8150b46ab27c62ba51aaba551eef3f1a30f08de9 \ No newline at end of file +d7adbea2db4e3388541e31a229e5741677aaa7fd \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id index ce873d473..225d59af3 100644 --- a/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.gif.REMOVED.git-id @@ -1 +1 @@ -6ad3b846d4697584ff601ac481b14a4d3bbb5736 \ No newline at end of file +b301e58d431a78d3f17be53be1cdc94c86286389 \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id index ad4371113..06482dbd9 100644 --- a/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.jpg.REMOVED.git-id @@ -1 +1 @@ -030ab8a685bebb796c24cc710edd9e69859164f6 \ No newline at end of file +ee5a15e7f8fc2655d5c1fc736a05857ab3d885bd \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id index 78062a0e7..4ab6b372b 100644 --- a/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id +++ b/src/ImageProcessor.UnitTests/Images/format-Penguins.png.REMOVED.git-id @@ -1 +1 @@ -a2c796fbb7de948230a22982ab74892891dd5198 \ No newline at end of file +b6434b5a35e989d4fa71ede1a8316fedeee7ae5f \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/Images/format-animated.gif b/src/ImageProcessor.UnitTests/Images/format-animated.gif deleted file mode 100644 index 03fce3f3a5b70ca8463cefdd94c00e9c7fdbab0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22525 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 *EHnj zn;dZqHdL@VS-fW5gD9D~z0UphU~&Q}&m}F7I+63oQzMteln*M#2s6Sc-XcO9|s%fYf4g|VI~5rZW;A5 zc28D71MamtSwiYJIt3fZzCB>6<0X`|JPg=30YHsbj*AF0`4PwImnj+4$sjgkUUkGD zQz7o9Rm|VX!j9Q}CRp-Ye)H@gg?5hOd(V%*GceNFq7q~^ZY518-^19yFJp)a@}VZa4#8%$=Ss^g>E zQcNx~Y{L_)-w#(`GrtK{c(Z)UK#`$ud%bAXX7o0Gw5M{~Oe1r*V#QuVZT>B}Dd?>p z^&Kp4LcVw`1i7yB~JnR{_RVJu@kM4@eEAuABG^g zxyM#-AH}`pxy-aJ&8W{j$C@AnmtlNau)ttDl8<=x2NYF+oamfbjC{d=Dzmt6I=?70 z)iE`3_PFm;2tW||IyGSZ0N457XAQXkSw7jPG{IuvteM)KxYa^Ll-$KASP^1VhTcYI zn)eHTo9oL(Gw|b0*7xe{fU6g*4p}2f^F5A262cQ~hpSxQj3PVOr-ioLAMbKWZ$pc> z3&h)Q&%f}#*EZnxBr8ilX~pARKsG$#g7X(os}c69%H5Z#uO8zz&Ei?1FGm%=?4$mS zD&2E~oowh5qp#fN-eg8G2E&A<-&X`~7vL96I_A9d_8!SpSkCSp7J)l{6Z-`B({*+( zh%U{(7%=|g|7YvT%Ldkhz@aW8e3Wwd7`ZyUD^MzZ83$l6!H7OLpLfJetJuz!23A%p z`dW#88Li$pvi+hG_W2?Y)={>K3DSE&rrow*xFMv}sTGUFe;MS>QWAE9c(?3ei-yjm z8e~Sc@5?`+i~#sBcU)R?n8cPQGlnm^fOXZ6q*kWCe_2QvJz&J8J9*CB5Ll{RYvOqC zp^M47kQ+W9cffJATKe}f%YO%|4u(*(HZ@-aAj$D{5K1wXZgLi#+6gQiV4@o z^RxGw=fbSVwV%KqtzJk=Xa_y~|7UH}(lau%vhU^O67%v4(qf9EBg@J|ZTOf0P(V#> zU426hgDJeRtseXc%FOE&5*k__*12)KooD8=d45R$|H8J~Z%%Lr zA3j#t4y85 z-bD^RytTXDZ{#rQ;loB7l=ATQ%k0L=)r=b7F3;_ z^BR<|rxi*2QOUDjqhqJ@~UGSd#n3YQe zrCluEDVN8nUaf{AdE}-N)a|FY)b5jK?$g<-5J}jY-2qEWJN+#Y_~Q7fzNatGI1qA4 zUcyInR zCrsD8WR_^!i7@Y@w8hJIV7{@O-+8?i>TFFUdeTuz8&)6nq5bKvtn}OwP;(-ij;gi+ z$|PopX+&s=abg;oCJ^#iP?GWUO^(LInkUl0KRLG^Uc`eyN^7M@6HJ<=h46t_(s<&UfDGOz!+k+gpwbNd zT1W&Lx{FsnNb36{{AHW9-z*TCCy@`8hedH^0^2T;hvfA%E3OpqUbr7g2d#UD`PBCF zi`v0q;&scF{P#j>5wXFM__uG1|H>@ZD@p%BKD`iX+WpWQq0OCk7@Puqn0hx82$qGM zoV;?qmL||a-ju4kFd$w(KLpzpe2eX0X~-k5n2=>;fJ!+YO)q!hE`ae%xnucMH(tE znsy|W+f0LG$sGG{En)<1;c&gE%i@Sy_$*x-AVLH$RxZrx&7mi)NKCm-#z{_vT7eGa#pIM12B(0rN&K}f-iY|Fk*-~&gz8MvTh4K^JCvelQO58@^|GzYDh3WOp?CR z99Udsoc^L&lHmi4wGez0rU?KctQo*U>RNT?QQD^7=Pz>26YG#>AograLKSy4OoY1k z9CZFb+89IC) zyt3cb1tLzcJ>IWAI^H7^a`Fr5L&IAU_G_;%^}KGENs%#XMy?Mp{h|JxT`kAm{lfE@tOyDx_!D&$V&>@gb|hCw4b#jb|uDm(CHE`XWvad0SDng2Q>Dl{g^JNQcNH0Wi+5qu;8cuM0z$%hHzX=PA_yYoRZSgv z9o!M@GEu$n@e)q+NH(0J<`*L@QY-K}J#M{;%$&wVwYCZDrS-rXL=1~PvUglZp7Vzv zAa?HyPg;6uHd8ixPPRGwVF?@%emvLf&aM=hoW`}Be4@*gP!u50dEiNV{KzrD8} z-1$MF>2ObMfd6=TOlj_4i_vsGOj<}(BHX>8SAAl~NhIClB>~d3v4n;K&R2U%AbAoR zz%Xh1M$jB_fhH>pR-0RrY1`?=foEsg*Sn;`THAQeub`656~6xp8D|i?Mc0 z3lF5?oV>uifH>zD`U_qPJSW(-TRa=Ln4^dxqIgi>RfrK5EZ^t(E)AqLBvk>eC*;Ydb-17fhN4n(BZ|XC&O70`({{gAq4J^l@X# zcykQ?(KI^_>0pEdYaV$UQNZ>`VAHesqcBNsheS@QE;tD!O!d03gH`d={7#|C+f$Qv zi@>7PsPE#=szqQNKCUw@zMU;pC@J|0+Pda6-dF{++aIcqBG73wuwZZL`v7OyL8d$) zPD>GR2UE?Sm4co7m_2SR)rZU-2sOmAqinuMfW1mXenh5fl6_=s)I%tAU{Ul*Ph#j9 z)=JM?MhJRyH(nnLVfJ;trRUGl#O?=(xzf)$!!9g9b=uMMyfd&5?70q)x#r_+ zO0;W40-zWmpP02MAcm6yL`?dd_n7dJ0(VQoPttLt9|9sE)=0YqK?%eg53pRlXPLp> z1+;bYK&pQUW8fa(_Kctq2K`OMm^Fj#hmMC#Vu&9ZYA)dr`7~4_Dhn#X9EuYS;>>@4 zV&^G#Cz~f#TQ31r;v+y*zgz}bz{c{-riofYJVk(R)g~}9u*?VYz8@T3eA9s^FuD(H ziqC?nK3C;2edv#`ZLC<+j#a?0{IjynKr9Yfz*pXw+DRY`v{P~A98Vh7c0ufYyZY-ov z7Q;dXn##I_rn-lS7oG~;y7K-od;QnV9q~N8#opOYVA=eC38o_9p;nq&?)9Rfj|{>{fb*zO|L- z?!96E8?KEud`kAW!I|^P;O8Y}x{(dHe$XkBtd%V3mbjgM7w z0gjOQeog_*LmtK&QA*~QYQyt%uy~DHSF~c(KEU`+b{)gKsHwk^?I}Boo%Ake&T!?bb`3*gMIB7(KgRDWMO{7f zt`o!coc0P~4Xo>|b`1PKH?*CuwA?DbH>wu!&rw*p2B`Ax(X_sSqmUO&xPfZCDjIo74VH((;+mT>h zI1AZl{E3R+3FXl?sNx3!{G%~U5MVLu+=aOoZbzID!AoCp7zoI6{;cOIF+xk*ElK+L z8?1xqm%{PH`*?H%7~)O#AJ6Vh>(< zdT)@WHV$lj$NdkTR!5%b!f?M2V+=927!T`1LtiZ;>@&Ez$77OLsFvqEN z`$)ksn2jY#mtoQZ0kxoj_j~dx1{VWK&@XM#N3IKsm@We(ND&hj`im~;>FsYOpzll; zp-Kw}Iz0Y(Qpo?lz`|N9=e&JmLyN$NqV^Yxz?qCX+I`FwG)lyV$1~5`o~&0z8%#-V zwML*xLJUvE!N{U!2T%?Gw!m2*Mx?4ZCcS_q9^Oj*>6%niv>2jy2Oa)A?3~Uj60Eae zHTycv0%Lz(nk2dlso;$`$j)PRHTP|ueAP-HMPy79N3-Lw<5A;3l3~22OGdl{~-%xhwY8|hwbolURNKzihBk`MAqLMcU+JU1%xS|gZ1>^cw#{8SfEA6 z>wsqv66(r42qf6mUj=!A5wll3iWVf_>Jh)0^ttay*Iej`&X&9(AP>SGiTf_B3X<-> z3Szu@L>KjE>JEF1wd`Z*?YB;X@9vp$Fmh*O5qXT8&ji6RgNdje6trF)7EFaGQUOTU z_W>F(SB$*ytdRbZokOMtSatGTJ%IQB8o95irnW9#;5&^Z1TX=lgGmTosvu200V$zL zK#(SyAV_Z^NCbq08mgfvC@mBL2}tNoJqUUzHb6Wyj{+isSWvNR&dv9E$M4j%^|`c8HP zYQ5E+Uk7xa9&cokV$k#)8SoeAmu%WZ%Wwc`G`Qi!tFY|J1a8BAWJyV`&@;<40?5G8R|5+ZT9|c+qD6{1pLzxg|^LAvC?NIuq2n76+ZF%H&=ht-~B{Y7>Ute{&@7UtlzPP+$8*%iUDNG}DM+v__GjwDXH4capTei~ zPc3s+V%^ug>2)i70H7>$r$=wq)>=&?TW(=i$zjv-Gt*X`i&jM(rcdBYukfV23f|D& zrL7+*rQ1<5vu_8G`{3ystf{6C%%wT6bK>Mw91R0wd7&SXK$%uTF zm4*KFHV6^a?vZAbON^Jpj97yq;x-CJs`^b2sy^gyPC$&$SDQyvUhiZ}`vRExZnc7S z@h5!{iO$la348xBuQ@Q3_{$e{1d$|fWM;rwxs7oB8m3~#(VW$iz&3*n(Q@rqx);8bYkFB` zJxDaZ$D3Ndn-;Ri1-F-K*HBc%nYp&2+LgBKj zA13p1pme7>AgUNRx<)DPFdm8Apm<)1&WL)2QVM4kgCZ~O3ZUFI!<1bG;w z2(Rn%OdCxJM=1&D?yh;_%w-b6ZUn#3lYAlokC7*Tcoha;4$6Rc%^;7o-*BHgyzBb+ z?>vZ7j7Zc-uXM#@rGVB<*XDMWZAkarug656giuaasgH8W)kaa2PLu}ZQ_%2@!X5NP z4?PqZ@ilhw^17j#n=Xu(b~D<2_{_s6L_jqcfLjwmKpG~k@TczRK#t+Xxch}>01}U- zRCT+VFI(*!3vydjzLRlI%+NXA&&Xf3S<78@Z}#vlWO5k)jLV~{WhUFT?NWTo%%(F! zJ?K(4QdCtA*?sy7wg9RdZ0aHqvt&3w$ih?xKDoz($g#i;B+%zMH5F&NtQ1TkU2**M z9}lkfS1`FU0g5%e6t$MC_LQjC(Xa6Na1Abk;TRl+r)-&0$x($xC;;x(-Yz{sz}BS4;$&ky#sERJp_PvZ^5{`HxEl=og4RKMTMx-EhPk zt~XTL+rWb{F^s)xh2TutFhqMq)oxE=YkHSTK17u7N#->RXTPY}Rfxu=Xpkf*WDG<3n0p!prUkHuOoXMAyom7>)TH%!*&mgat~P(&ea2@& z>qr4=B^RNpSXP`tXci=QnRV0Qlr_N`N;CS*D{-!4om|U;6rQa$IUyp2$wj>`HIr1m zZCEMT4jm(Jqv1LnrZjk&%3Xci0Mt6P1<&Nu2w{JHN4Epo*6AD%b|>9$91-Mvb#gRs(@`<^-Yn__*LzpHZ+ZR7t*&2jcv8aE6C0p_{kjKokO-rVIzk#1; z7g^dVlyiAfWTRC55@)rBOJ(;Ca`x+9E;DX6DzS;FHy3|x7o@vjsahOfYGC z%Jpc(e13+;fl@ODRn*?wDPX4o#13Je_#`?kLPk^axbX(cBkk7Ob<367J4lalYlWMw zB4+&{iCFBuV;RQT7CYqoLF(vB&w*g@orU{RSzT4nmpf)%9^CriB&e$C^EnP5b0sBY z9afm-X6XmBkTzdW&Z(%%ZyDPl-M9Z?*1yNcFc=Eo=8ePM1Iv)-j4TU69yf+slLrmX z|7C8XRaH-y_=6N>+Ib?Izc!YA{J_^+*H=1zcACP?ns1>zC?mUyi4WkJ#`=sceE`h$ z{wJVFG3y>GtgXW6CA|)U+vx2(Y%m?2TCt?K@frR=H!3<|8S>&t-_Q-+G{%^p*Uq)R z8}H6VD{zU=23HeqRQSD%+GV^4MS5s!v|m}>IO&4X(`&{6SUoRLEcRFO`xGZzoQLPS z3fEiz<%Uc89=1|0S!rP0{>Xl!yr1LOXu&b+%$N`T(0P52jW{cN3Yu|T?iPw+B>lYg-EwgNe zML$t~u=>7x9c~MEA1JNh)MQA0BhnYivfZ?f15e0>j9>CkmyDqPoaLj8mkysNiRWYT zqpv^T^N#S>pK3Da+poV+j{e;0rUt=L_8V0l1Te&fWcL)&;~(o}Z+e7pek5Q_BVI%} zkEv+MBs$XTO5`un>!6O5k(|#Ae2dh?-c8(I_eiWcrXBv9HjI|(Ix$Z#tBiBtLa&hux2 zpXZbR{dX4=7-vYwNGh9xTkb%G1zeR5AkoVQ19va(kaS&1NK3#h7U`W@!TtzNHS3i8 zMoIl*AP;Jm2Zf}qQqPnc%4_$h>5$~LNGhkx%(NID0ZmE#(TJ*^b8B;^^=CqzO*Q1m zU?%`(+YH6bMn*`BeggLOt!21=%~1Xl;)2+xNzL?PXZkc}`t@hT}kWn~EzBS}UlgZ46^JY4dz)dO3;*dsSL@`>cXy=&a2FaoHww-?o=<$rd`+M@UuwdAMRMx^H=tK8cfdOZeCa)b7s?kuS5k z<7YA8*D0I*2n)Q=-ZT8jb+?8hHnvO)BAd=cKobyIfXes2)Q_gAAVk_Hcx--fDwchz z%rrI3JLic3@CT7o^D(_ChhVsQnWiNd>F#sJ=b|pOf*~o_VUPxL!0+xW>Cmbib*NnO zGU53oM)*|Tov6I8C7wBIqgqFR^RwO|Ykp{PpO{twWY!W|HBG)8 zGRggM7NF$hM4CjZJm&6x74c<2dPTs|vs_6X&>`K@ zIt|hKyXJsB5QJYm_RhS*u%(_oR_h9qEebss?w*uCP;aYUc`_6lgyaT?HrT!*>bI0c zuEadt^oK1rcv;{P+faLS(A$M7RRylMZ`DQ|@@N=xe;9XydL>}8@j;ew>JAn%*buka z2>I@ym)oe<-xxpHq*@0A#K7a#$^g+4!eWz#=oOz*qa3aBDN1#==v8@9c=Gny69UI3 zs>0P*1GN~2%!{+tmqc6URshB_{DL+m6;~21-=ZECBZEPeKThOn^JGAgJ!o)*NqO_- zmO%@ivSWj6e_GNakCO;!l2Ne=TH!e@OnK4i`OT;*A}^8Y{E1kdk@$8I`ImG3+fw&UegG29^|z+wu2qd z$gJZ3U2KIAVSO?1Mqkd*tAL1+Rw$|i<5Ur6-O|SeO-%C4a|w^MJCwINk^@`&IU?g< zobTo;@A}c9#p`rk0q}Gbju@#?(WY{tLnpk;)K6cPkHRGy8p@XofZQ%Co$l^3TfZwP z10BT>pTlN@?IxDpuBZ;&5DKZNB|6)l<$IXS>%ke#EE+j&~2PlnZdi^G4k*h_J2%Ai+yTlS?UT~0m)eG9;AOoOB+``8uLDX9K} zt%&Klp0^xW)>i+8q%Mxmu23%j;@tu5Ex^J}#4(Cvw>@+xsae9Hf0zXyHy`{feBZ}c*Bw>> zXD+tnZlWO3aN4hAap)YJ2yRC02{jmcVwp7MbaRHgAGCZ|HK1eQC9l16<)+l(-9Fp8 zp%nW2yg%>dAVY_Z6F9KSkIHo(TqyU9Z`q#@@~;0x$*}&5A;MsQA%GJkd4z< z(uM0-Djgd_r^i_6>n9{6=*9nMtKO;TNGv^Ccw|%{Haeb;jf|!R>47|t9wi@k@c{O^ z0%w6FAO^_%ZD9%_%-{Z{5WEy>m;a+Ke><1Ih0Fi(mcMOFp-(BqDgOsj{y!R}kfIbi zl)n+m|0_`bm!A}3lfPZb-=gGiPEu$|{w5@ac%;yb6oQ@qaUuWz9udKC`4n!i!ujzA z+C+p!%~S}cx5&4BzV*zeWLobs-}{M0&!PH`#QS!Gq$a5+GuM`G@#bGhLyF{t?FLsp zytpKRfK@^oD*C4v73-^ItL{M}5Mt`Z)oBL$8sY^|q%2Z=52vOr+`vFh0x3f>l-uS3uq#&vaTwBDHT;`2w;u;Q?**zw7~$@lbV%3_y=AHdw|yuk=9A9fjy9eVzj zw4g(iLqdg;j0!5n-W2yEZ#}n_5Fhd&F@B*;Jzfp;~_H`hsBus>8!15EBP(*7IMqU$|sklFOTJUos9AG_-Z8JP{ zAX4Rr`Hq~JK@2(O;7H)x6Vw~tMa)}xB0RJgVXy)NpWKEcGO`W36k5Q()xZ%4P1k{h~PE_AmKB1b_7J+yK4{d;NJ{kx@lP*W@ew8_C%; z(s1dVHb%b9c7D;JZ`%W*#}Yw4T%%T zn%A)t^gC$coe#-qsk>N3H;FR(O2qAeFBd=BN;R$>kd@3X3^bMm#F!6f901DX8L}*h z2_VT7x}FNEXjqur5U0f=<eCi}rY~ z+Y8R#(M`Z8;@;!N=}G@E7j5b2uQ%w57nl$^B^-;FZ&~PxsnKZdacj&_0nZjdIsGfv i0Mm8DTt^ow`J{C&>c^Y@m)Cy0z5eB?CBzBAe>ffvq$V36UB=1wrY(hbr9)(gma_0fK;p9zj6q zAWeGjozUA|f&V%8+z_=zL7{Tt`zWKn-c&YMfqVCkYs@(eP!lCc8wZ~c0Z)!x4YrZg#U`|hp z>VR7brQOussq4&th&XLhNf7Waf%?fs`-WJf@ zYa6JnUh1c=q~9*~>CL}7f>_Ghs+v#K={C^S69{;F|L*mSMQJ)D@$s!ZhE$FC_$5Ra zbq74&-@=mf5g!}b5$J2+@$TL;( zVb?qjii0KEpY)IaP|;V-c{(`EIkk<@rOQp1dt>wLLvh#d?U=Vf( z5=LS5Wf@+aw$GwIheaN((4V)!;`dyUk42SjFrWC$B4|_7bI;8Z%q{X>gcQFR2_#-3 z>T9O}x$4(nD*74|TM|#nax-$@T69J(6~!Tb;VLuWDET%MmNwI>fb9#(YJ$`HyAZCc zydL7b3BUbGt<%+p9vaZmZQSqb-4W^MwJ~YxY1h|ZX_jGLqAw|YTKIOvpj$3FFQTd> zZD`yjM#N8C&X+yKphNRGc9;i#0og%j6deDV&d`T$-db(weJ;21&(8bJaYkX1CfgJH zD=}t2XEJ_ZqDKZkFU(!p6Y&1^isRS2qWJoy=bb!d{yyp>ALL>Myb@ZoGQ@0buS0M# zGq&F*8F}nufaNsk^wv&b;cf5H zU#JgL=O6Y;r%zwWuA2%taQl^Fy*5r!j67667)BVW9N*2)ij{SMdq?-Q<0>`uRcG2^ zv#3VLxf<))34$YYNy%H1121jKN&9wdh>xf%AJ2}Pk*>b`2*nc#1idut4aL;RdZVTH0nPL?pLx!V16 zZ5gobp%S+0U1#~DtwEW$xz}&%d0vz#y3H{gz4GP)lme3(443IQ7z^E8K-*9FtsI}} zv*K0UTBaPdgJ9k6m}+x*spo&J<;AO&_k8pKtHA+i@8jTy!A1dlsAGLbCw(XEEO*j zNUHXt>mDjd8~yGKSqwidGWZ_q{3~X1j1Uj@(g*yPAkwA_f$dO~#@C6O^CU!aOP8aMPX_0k7 z%1PiR6L%796d&5Tx_8!@0jV=5?Ig=wf>U-)*G5%pfjhQ>fvhJ3FIoN5{3nQ{Y%V`0 zFrpM*4>6BV9$KKeS`FW)P!;q^>shPT^deB{ovvp zCZv(FrL7}7@?Bir5W0I9Kj52Z=bY4DM)lr~WA#wMo?#%be2K)c39tYCP;TvVWb$*9 zR1ncre}#4#q2!gcPNJlN%!}4^5G56oNDj70Q7p+naTb0W8?(M%G@KgTXA#5hsONk1 zrslOC&whxfQ6zOWU<^irLfBg;c8=Vi6;e{?(CiB_+A_tdc8m)g(T+A~%@yy;ZB0=I zTbHe>5#W<+w7FAplW7XiG6maHrqFD=TJ}u_Zxt&hVKW_@>??oCMJG3Jcs5;ir;>CM z7j-{^8pSj$mv0b*>ng9w&xtGx$+1sdU;RqXS@Wpf(<@-zjGM}CrZ-ovCG~op5LqH6 zn%F#&V=qxvc1bbRCju_VyBp{(I$$W}>{O z1OkIZ*Vn5E%!jD7I{7k% zMSbRQ?KhFOZ!cuhBa7cPbr=>fKaVTsZW5@82#&S0Se7vKN8|c_8uo~s^)=q2t*@>k z)l#ICtddJ*O&Qt}na^jWGW057$+4}Zb2RZ~6YTEtvz8HV<9JAKevR{T2=9*IV0Qpp zEJ?-$I&K4PAv;bl`LuQt+FaqtxymEC8#kUU0GlorLnKn=U zsY}8w)NTtswlZH7#iz9?Bs3)0ikbeLd7RBBc+=eI;=FYt6k#+)KFQPA{_fL_r!ETY zwmTH9ElHua4lXVtFlTRS-$tVl*La1S-tvQeQohptDnsF|RSjokR~GAAbu@1-)KaIX zV&I0qLfys8IVa}t9_7!rXf4lw^RoTm{a5<|b8PcrTSiN~QC!^wwPIAt!48+)>xyux zwbfechNY5`sJd_lM{Px~R;Hi3Bq0f9aiX$5VRv%1%ypHViDPzlcJJyDOU?WoL3!W* zbJ&%mk?~`b*g%PH{CqYyOynV^v9&IMGQC64RqCsQnCw^+jx-kas$`_p*yL;kGs$90 zh~Yuj`RB}shoK$myXH@ynrc(uPVsbqm#kWv&fE4;@Sb8d+nb+{SMifDJ2#VI3U|&* zT$4cg=zLCoeT93KLZxEt224|sxE53={*em}=|DHuWU{|l4$|mr*AMRheCffebWF>$ z%V_bcF-_J4S%)`j&wQ(*@>o>V{kfD3wB}>JD}{C=&Ki>@!-4vq=m# z^G~9bP2|w3Sd!mh7=4V$=lm>?oG*j!sA4^gs)9~v_iy+2eRdq0KQ|kC5;X*irgrIP zcnm|Mg)JsFH*3~2;Ftlw6}ILXRt_g)x%Gcgi%8T`e@zW60$kDae^s>k~saS>)-O&Wa<-Cr&jw5eEA;WNZxv7e~v?Sk#M#_V(?9j{oB zvn%m`CQtDAD>`b6Q%wAADyKmWj%WTz4QlUwsS$-1|6~f+Y@)<}JsHz={BVzCqFx$~nU!3Db{cVSJB?|IdFU?F&2wXUc!ll9ZzsBq zhn_AYKL{26#l@?uzb#VeBsRa@YTZmclpgGANo_|EP^SR|M^GedDI&N&l zC%ni<(x%rSAxS?;O}_nkj`zhTAe=Ui{sk8S|cd|*DlW3z9X+l z(HEi#6Jf=5a7=>V;nrAT6t%3NO8$=_Z^?W5`p7N_NbFPuKMdSI3A<__>=qY27%c!{ zSGZyIB<$KQRmlcZvxU7r4ZBR!!udymLj}BAA5-QU+ymcCxuwct@pvm!l&&zgkqODP zjn?gELsCmbsEiC!OO$@!vQTZk(aIOa>n0>@C57!x_G(?bIa9ad!@wxtZ;H~$Qp_6c zcxTbhFbkaz*xG_~YWbY;-e+&U`m_86P4({_hG1$Yf5GV%-e>ax@7{--;>btvt#Yq? zrq8u1CEkrJa{r#!;FfTEGw))Z zauXBMl|+@5Y_aGK2Mm6uJ{s1OJMr511?d9Yp6A~4MtLI~i;RpwO)%xJj?ULgqTqC@ zrdH@S`Rb?CQW3|-KkEYH-<7E3X??3U5nk)NGX*8IIX)4}I1n8(7>lp>T@;&5bH>i}^iZSbM zz%oltJoT|Ks?(XXuxS|%E19W`toN0u7qn?VP=jM!nUKnG3>=aZgVwFZH`YtuJ*Pu~ ziEq5rrH8qp^n{G3unyV3dVRR9GSb(<*j~i8ry{h?IOixrWkN?3 zt!KP8fq95;e0Rf|HYLT*y>A@_6U}Wzf|Vg4HjpSDVBEOREQCmGl}df z7%5gx=nG^gV#JF@Vn?{aTSj&_iLr8i;(W4Vkmsx5JLwPZEw zcs)iT6noXD6 z?obe07A->zy@~pmtnm47^^UHyavN~F^`COD<=z+%+Q_2X|HA*a_@=F~k_Nk%H&?&X zF8o$Y(B!tSjNo3~MDEkUacGNe9e%zIACJfDx8NH^vHgiKghb&-S*(QE17U1hN)em3 zN<&BO(`GWs1qCs3jP8RMEjMV9ZSpX1vWWh>?IVM0|9RY^$mm2gMYzmmrF6W^dvJd9 ziB?fm(z~Zup&|HDwi8!J+0TaL62-FfpGCxO;KPQmU>a$itCjl(U*1&B3o<#ciplD* z2#-z`W*Ef4I=Hc6pDrYzXC;?2HOX3~VSO$JrxRPoE954$dbCeGj~?>5a2=9N#oI*q zxKzdFW#+xVBbYJr;bbD^Aq(ozp0_myfk~|+R|dtf@yv}K$>BaJogFhKX?Twp?5gGh zxQFQ+V7xqOx1K>kOqHM<;((9%c%ELVYQG*I<}*@5W75uzt*Cr|ti((fQ_iq4k`cfi zpy*;BFzxyXl~jlKFhoy5i0aL$`ol<$`HKhp`U6mJ=uXuiAO+nfLtG+CN&YA5k2yEi zA4oy|KuUUWs{X*q5Etl>cZgCF`HA`y0R)dUQr`1KDe2~k6eUcHya}YBn?Oq9IhCS- zF7<*O^EXjSB0G_y>hGb*fG&0R&tU${%>VW^!zhFmfny|muCZPu>j@xOGCO{2@%Sr} z)S8LTOcaYoZ`M2*&9Z&x#5tK)Xz@^V zaXh-a?#NOH_4^t*MwoDqIQ0Gm6?Abhd4V+d*&e1Wu(POp*q5{Ug+q72xhkfBgBWG} zJ07E2K2)cfq=67qB#YHVp)>}~NUg6!z`vY8;``E7X2oRaDl~VU(b@T1D#v@m^S9>W zVsB{7EB@@mY+8D{f=wx=tu~4wu6Xa%p5dL1y{R@kU`xG6YaRp;b2Uj+mc70r(dvL9WQFA&= z@^^X1k#Eiuy`x{g88LnbVxM)MW!*1d`rGtT`b$5$Nt_ycG)dcw+DGi0jZE2WSs7 zls>ja;1No`1-}QWzLeGZ#{0c&v{nhsk4#PC2oX%vTZN<78akqdCM#axO7Z%_0;6V+ zc={_d^~>vx4%@P*&{pe zD^{~J4L!(o^l2T7$(uGzL`w=s8rbyVFfbVrue>2@);iD2Z68@YH%WuxBp~zVn-3}_ z+}(3-lpkU|49cI4mfG_WSA;7bm0N*>fO&-$D(w;O83zl?Lm+S`k!l3uJNJ zQ>2ZhH=oRY)psnrzcKt%HHn5=c2Q{1u}vOXSl^bfsv`NWSGsz95kHnG@Wi^+SERtW zZlp9LT@TC5>!-SllHIZ-esXK$$)2RO!6X#)wDg-bUcgxjaL|%uSL5oOjcxT>9YJ?L za3jkZ^hO=Fm7LQWjr}%Y5U8hZVS6!#uXZWjMm0sj`*aSx_qXc$3e1hFly?lGs!PuK zj;-+5JR9S$A%VCNS9N%YL11l&tatdT%={96&717nl5>s*T?T>nDc|~I>W%EeReXi+ zrhNO7w%vwWsv(Y=tF>A&fbNiqT+;0j-a`VDI)=xTD5lP@iXwOUmqn4}eBs>K#SeIq zVA3W=az0*eEG?1~WCdW?hm*yCT_14|bseh?l8b#2leCUzdbDDOiIMH=6nxu=LREPac1=B1LE zEw6B0x1afbHCl>vJDMqAUEKOaIdxry`h-)g=>ox7c);=K%?5Q;4*qlQ8BTdpf?{&X zg<+)%-1aayF=AEI{#yG^>cKx04q^jvmoj`vdCM4FoF!6A?ZeMw9H5Aprq;)($S0`7 zmnMO@@aNrvztm>;yQmj>8HBMatI59;wlx)&6WxB?gpHwPS8jU)bzFyfQkW%wTvCeK zU_;#_zEDcg&XBAp7%sF+@U^^$%$`OxV$L1LH`^N2NL0CCdoZ}0a{J~6Bp zooCT+x@Vy4Pp;7LC61pHyKIJ1W)NRCGuX@_+?Pq%GhOO8gZ60j*;ZG&uS}-5hK6j; z1;CceD2iK2t?7+xgQPeH#?`=CcludtIIAAITc1R3>n}Tkc16%C`#4a=A;DD6jL41I zl-azuo@E6b-hq1*n6ELBXx)d)3fLZDVirdR$DD^_OjapY*~;=MWM!jO%qRYNB(iZ) zzOZuVXy0UXYv9=bjpp9Ptsz$v$z=QGQk?7hBQJeps=T?H?ut(pFSdmlYwZ|)@H%tm zdz1U4pJQ@X5mN@1g3qH(hSMl=(6D3jL{Adi%N5aX_V_cS$)0}WW&(4eS3I~Phwo1$ zYd*8yzxFxjxSk`^+AM`cqQ!iupYy@n*aF47eQe5I&r$pqs9ZDDJBOcbOvqnM$nA}B zW7UvS?58;wKEs_$$)0(%=JohU*O8>U=Or!pNXg-F)7s!t`yB}N=+?tRJ1rwNTqey1 zW8|g5h?(6aXHl(;Xr>MYQmuD#LD!Cv{;m766Z9o>l^XbLYV<|w4f>k>7YwS=P-AcL zJueaNswQ2LhJ*T4!c4n)%(2HzoE`a)d@Z}_CsJN{ZN-hT3x-Gr7;XRv|IPt+da zN^^?hNTeXYQ5Xv^?^?QH-agGacDXR)Kxl;O^(Pae$#*#lvCfwfmBr+nN(-+PIXS8; zl(pv11S3e=VpmT_9Lx8cQ7<>wu#=`k;qlx3HA4^k;fg6n@z2az$^94i;n>-NhUv8i zMX|A|>R8jm{!32JxNlkO2wUZhpQc z5ZtIg_gyzWcLDGB4d)LNgr44F>dAY8nhI|po>st0c$4K++PQmQsPx~&Ls(3bBdSLw zhJ24B(Zy!U0Gzq)o66-uX6*_rZa4Bs<8M}}HZP37c_b&_nTYv1-%4=!tcU&njm^k4BpQw99fbRY??r#EVO9QsGyfHlqWUffZ^FY)He@d4yBh*}xC(`A9tisp zMf*xNF_0WmpHUIQ#_)knI52uH#gY&)5pN?Gs+kH96K#~dRvQuhC}ud6Pf{Y1XFjl< zAzL&!4H6NP00Y~khB-y6nu#|Q=w>=!!a>}Ecd=PqRZEN=VT-FlV}Vd{*KgAZB< zWF_;<;3&d~OmS4y^7<#;VnCA^A}wWJm62mO_u%qz#0a@G`*xuxf=5MB>5UUJOWU_MArA&6Y}bf9t$igsNWi73ndA`EVU z;x~SX>^k4Ui}d|aejg~jBu*lL&1vfpwH)k395PoXsuT-;e=;6Wf*vvY&LL4hE(@%-XFAIbe!60qcE_WO$9rZ z)`;I)$)kexNILxMYc_@lbqu(yGG;|9TUf8tm?^=b=SLH_5+rQb1P~ax%6JxQw4wy5 zVsnF_ZF|&&>^({3iJJxPaL!F ziQLH2VBV}PzAFPi+qyGF*)R8*DP?%;I_HQ;+{vh;SR|=LpETd# zd^48j!#z{+jfsejOviLy$1Ry`2wAB&9hV&&Y_`g}3wmXqPw_Df4%@tDX~TWX+z2=f zYmt{~x=3^K9LOXdV3brdS*^cNtQyw-eIT*TOBnO&{mDAe!J)KZ)4*%ZfZBDy*>5)M zW>+0vp4613*jaWR>T?-(|DmvU7V$1N03a{XB3^#bK|f8xRJENRwF?`S7$r$hH6_L} z+FbM4sb%}c=Dve8Z5;0)LOUFwD#vtdnH2+w8J5L}Gl zwP%_(cNrV#IBy-cd-Yojo@BqSvg3L0tn*~~%CwI)dAP@4dxc#2zf3x3X}Sh~Mb5Ox zW~YoqeX{(F-%)KyA1OFI9bHM)CcmNQQZW*Xx@oGz(L4hmTWlrHts83qmk>$r4|<8s z8%~1HZdp4r)qXzvZmPoqU-A;~fi)G|o1z+-yfl!Kk5V;6t6|Tr*j7{-BTc^JnW+|s z656B{W-Hv$DNi!qk?z3h`r~bK1ffI5D0x3;HToDeXJzHM``R7t24e^XZ!s)v4FJwE&A?fnkgcPQ2ch50E(l za7qvgtJ|34B|e*qXt&nW>b^yj&|f93%HXAXb`_@7<}jAB^L zmLxwxdx^^S7z?ea75sdy1sjKp@!~+QJ8ClxFli>KN2I(7hps5fe{mu!)zu65{%GP( zdxzB(UH3bUG$%cc^~a+E9$AKHvB3Zu2US~#(4{tk#3pGDJHvvq_h|7;JFO&MJ!__b z$nfRBZ5yLn;)(DZ>4Ni~b=lRaWP!opBiNzrCJmC3lFp6L5n?xJ-*9To+iovMj`bRa zjFVA-Q2OEAhCN%}P1_@(7BB$&#Lz^(28tmx85E&&`F{e2z)rys!om)A zV;l`5O;?3vWCSV810dOH&#{rs$Q|m9w)vo7Y1@WcpWL_a(ym|t{>@rKrHARx%gZ}v z!xc4|3dqn>#^9WtbixT85|S7q^^R5Wz!g<2jQz}rTu6fTWZGWTw8SxRO+^h5ca$M% zJ-cZz4QAIN3lgKF0Xru+qADv%1k=PS9Y%6a8JzGu%j`Uvl_wOlQ}nP_Ry@K_JFm`; z9J`&y?ly&e)OSir)LKnYkcRiFH2tWDVR+>UZ-;k(JF(1PLj^@l(67>)5{VC8jI!qw z`JN{X;~BwRYYl@d?hp4}tHEZ_`ZFm&I8GQ@;U-+B7(7*{$M{!?BGtiSFF053u63%R zXHsB1Jh+bxY52Xss5HgQ!Cz=2qpS~Qdz^d*TM7zCI5rLd58Ks8=tr>aQyaRCy*s4= z7dKjKTWB~(>!zB_ZLcG|FE*`N$ORTM?E@mvu-lIAsB}FgJHddV8hA<^!dQA>c?e^9 z7?It;Rmei?>OAxh4trIr8>y8i+u zW2o+S+SN~4ZT=KGw*^HM_WA7kpPoV=_Nt>_n*6lVT%Fl2dOz3`*fS#P3>PY+_jZlS zNjoTpI|SKnRZrYjUT9A!9CHVb0UxLU6p=vMBydcHQ940AN}kdplNBfg)Yn$BaER!+{aM!ZzsF;ghpa zz{n1Cb$Xu&}5e2Y-nm((>7zB`h&eP7Er9+wbDxKt(@X)yR!aIF)p1enKR*#Ily#%5|jTICt~{+;!Z1yqSp z)9;kleSa0SvlMW94=w{Qo6fne-08y5yLx^AJw?GWg^b8(UaZ$2xZ@9L@?VU>fxr+H z)t91PkXp;h$J86z6|&z3;8Z36r}P0iMV{zLg&lH{ivdx4@VVsZHsD50fGnYnip*5} z07`7Mg@%=kpgkFc1Tmt2?utSsl`50bGc@y=5>4~RpmgWpu2fpYuvR*UqZt6RwllO* z%B~uhC14u(krYVlp71GZw#Q@la|+)aP3|dUN>&-^6AMr?6-Dden|k+&s9Bmx<_Z2q z2U(zn_N1Riwk_3!eZ0QmISjxFPEeASbZ<){&c+UKHcLft4LC+GnZ(EI(#bWdi}+U) zZhBR<@Gi~;P7$7zQ4`@0pPq;sVe)_Unm;hK<1!)v&DJ1_<)kI$T_Fm~;db(noL45H zn#`52r|_GEF}d~>n_A!XD*?iaBGGwuMzizlj}=yCMg7RugT{hwG7Cy6bWCPzd=L1d z*<2@yb(o{<2V+xV-`p#X*;m-)qKyyyhwD~yuez}VP$v50_L`?PUEALbo90eO0uz;X zu16L`ro}f1?JNOV2<0E=ueo%BOpu>Q_zDo-y+<<%1WFD>HSC~}5tm6N6>vQHecD9a ze2SlU?VBUVC~!&aCRBkT)Y*BzsJPf(Tk(M-z2h*@1sFE+zm}|y?x&138t~fp{5Fyb z05Vwh!9yzFQXhVWl=bVt$qA7vI5^y1J6NB>eJK!Ljxp=u?RfE&`zExbFudHu{$kq* zPGt1J@BobR_$^x8AHB%~v1S8IBf9$s;6+ay625xfIxA?8KD6fwvG?w}sr2@y%WnRSgYFhRvIVMqOIHH&S|b zxKH7wA16c%^<>!1Em|Aiw7HBv1^cpQ!k}ODN@8f(Wmn*mc)p-X2&SwZfBI`RU)*}! z=K7OEhPwr4+tSbXo}ekb%V!n5sNeT95_6t55$rGu<=u+su|RbTW32|EJz#p7AUXbM z@f7qX1GFdZ;O_0}uh>HB@+#P59wc6YWPVpm(@?=zdYR2xFlx>d4pbWp$z+Gd>ux(^ zA=(J~Ll=K)aL4>CeO)L>1b^f=D%TRW&~B-_;*S;_vu8>PsMb+u2Z2%oGbPM+ z4B65U31U6z8GBqt&MtLgsN^bXi4$Q!xb#0*n}d%TK-~}8y;Y$yx|Bdwd?6QN+V zC6xP70Tld53t{z{kh*X_g@(@}2I{DxpZG8VD?oqD>pdkj+TC?<9noQ!iaC%~$L zsmM-!Rc^-P+iZv5vTgP|RV`!oMynw?85fXK%MfdM2FxQ=i#ckj0YI*TwLN0X{ssgC z!d;n=J=3}M4BYds=TbYKuv7RX8Wi|Mu*uR}_vZ0Gvr3uGT<7H48|>^Q0z`{HcF9_6 z71u;$J2~bqwC8)MSJfIxgXmm6gzAh+#2JNs3^tn~4ONl6tW}!DqLumP zQ#ujll@P+t(;+nB|5&1;2NPEG9{t_h z+yoDnSjKY(E`>gYR7QO8t7Dpw1(`BI5Jn%3P6&fipEOTXRZkiN^MB`4raE1Pu~Fj; zmx+XkwbO+pjYF)m@L(dCR!P~cz??^6Jf%X&JLcTtx+JepLzG>yeY9AlM#rO>4AHO(@ zir=PwB}(qf5qzL_NB1121CHTXrMTc)kXv?@?H>zJLA!y9Visow`aRca6mN5_4u`2k ztE3m=<0I#GD1BOK=B!&sEAYSZ_DY`6_XlU%x9v{AJ+pjc{L9OWuekq_6OL6`xxc6m z;#c$s>W;hfL6PWp)&q=4x`iRwf8TS@Ko*>QNUAhl9ZVH`|LPwINy}X_7n7`w45tT- z$WYMLC@FH;rJ^@1`_znn1rrVCyJgO!@dD4rHKuec0@T(#3H2rJJl@SViQ%Avhd}x3 zmG#d$LEDZ_zSSR(MnUz?2}nULPm9|`jBd1*e&nL>NSM9+)>EdSa6|oB-|FA``k#S2 zCDD>zkb2%(oMq$+<}`o zdkIRLM3KkxHswpoaAq;unH1kD7FaYRS~gRw;Z1ip7-wQ5p1Caqzv;%vFzzb%PGNdH zDqPrRNvin}B_LzG_yW*0TD=h0wljHV5v%HDYtg=ElRcwI=H|M`UUU68 zmg!b+m|*oFBN6%t7n~N}NaEz<=TVZ-@el65($z~_sCbHeARfHr1!yo11=f%bv}d3K zclZkx=d1>bN=4Sqk{j#)%+ulzR3@`u9s`MAHbR+sd?j!6mXD zN3p%i_W+$?_O9O%*%Jo5{@T_6K8S%-cKOG@++pd`^KUqar8)pEA@J9LGOr9^KVyC5 zg?!}fnuUq>GmNbWlm|sWaJ#Y>w2(>|Ao|>@gzL=S`rj#AoOt9zJobE#E*wf{d?R@C ze1Bp#tv(8*N?Wgh6Hk4>Hl^XAg~V9sb#MpW&e|_ICrL?U@SJ)H8|>b+NNV}BtgePc zKm8lb7LG}qEli5qc?;ws$*FjO!FUzHb-6p%pIFii>cl(*hKT%2#}H7gs*aqJh3d;! zNCTh++e`=cU^Ok{%-I#CbIxliK+{)ZD;_cf5 zZr>4-a>DqDR`GRU+P*$IVfFi4P+JUmm>*AKK1h_4mIhn>r3WBBOG5y}P#mmcPawW( zO2Y>HUPTc$n?@l`uRUJ}guRK`^rGOh)KCSrbdLyPFR9KZO90qiNC=G{CWRg`_xZ@4 z;&t|&p&D+_?w@dc&UC4j8tBI{)7;qlGa($zt_4ebxx+zteI1}RadgfO#pP>*_covV zdtL;qnM&+=1(SKf1E9Uh2_^uzk_>oOHgHTJs3PRGNgp_Rv;YkfXRIO|6gG2Ra-9_W_Z-!x*gv3XuMW@H35?7_$* zf5p-R%E)Yp?~AcgCsPXV3=-T6#dn*nMDQgqpuBx6M53z_(Qx7kSX)`O4-Q5|MNxsS zDO8%E@gC8R%i-vn2+J8*HA-#(y=IiR`+1{H4!@jlJ1&Mlw!YimZ5&9+55SkqFJ~#~ zcst(jlG6RY;?*O>a@<%M*dR>yCaL+VbK6*ytHO72SA>f%sy$rtuz>v-=X|**+V|pn zx!;jFChlau1{I9G8#nRdLsImQ-v>Oj{3d!J2wIO&YLPmQkksdsKwaxVac>W=egUCP zP1t+T>BPm7a-M(CoFrQ!TO_C5vKuJ+jyPi6<9xI4G}joLe}s8Lkxr|la`lnVYdl4p zUS8+DY2bJunm95t8a3{AGqBtOJ{+%FNS z*!dZ5U9h*6)$VX~V|4P(P@j~W5JEE{IGTs|o4C;q`#LhP^v9^c5#~_mh{AOfH4}GZ z3xQgL;W1kP*wL4*q(5fe(1J5b1)cyqM|-{1_35CX=N+$}gSH}ORDJXyj5z#j&b>~m z2*O>&An2J=_+(1h*O&&8%STL)%I2?hA?O;m?r?*0=CVdQ%Y06kQgsZ zVlw`0>e1HZ0g2vN`m)xxRN5mZp?McTtl}igmikKsg^&tWtn&ayA=GiKQ z7+_{vwuz?}RKdl6Us6G6Z<~m`Sa@^qUsz5iIkBieHdwY@ayvjnpx|&<#05{s_@b@y zP@9EaJpy1b#jq4-uReF-y?q*@b(-uWFG7x)Bg_yf7&!BxFov=V78eCyPVrLov7;r5 z8pey=ps*g!Z~tmkShl@NYm)UM{>?_gXfRBLAn(mu7LhLWF=x=<`Q_i}vdcweT0+9WmQBde3-2h8spq7Q>X4p}YStijDHaq|k z>X_B*!evpUE2c6ZzU!#gQOrl_iXlc*RXJ)p8rWM-ZlCQzM=dyu1e}7Nj~n18yNNl{ zo>PR!di1`tM^hfO13^lQGP53 zEof?zW_PvKxqE#pY_%%U3b zWlIvH9|Hc>Qsso*;KN=4JykmLwZV`@Q2Z#AQMhSe0&(X!&*-PR_P!859&N@FUy}GA+G_38%i62&ze+GP+b^W43R4q4 zR~U!PLpI{~Hd^q;o*NGvLXsG&dttZ*c2rAQO`5S=fborzR6s>q{Hp#%H6PH}$j9zw zCueZXeX=ot7M;t%sY>~E{$wZQp90N7G^4*QN-y~zMMv7bv5V@DjCC0#Hg9_71)+<5 znkXBxwFTYJ{Ef4LEpynKbi8CBO;3_6pI!=tLIv6@D2Rc9a2ylTI8n$E7bFBWJs$z)cVWD zn)+ewj_yDk)^|psuY6-bU~$0xtj#=YRA~}NdQRa`bW?2V!coDj%+%jbONY-DlfCK7 zI5lqcmWi)L}h&GFR}NA<@w90t&_&oLvVc5Y4GJJwB)_?|!X>xp4jj1f>;XwvEM z7_cic-j!7xcBjxcIfm)?`d+Lqd8n91{VRvqQwz0sCP||ZbgT7z!rP0Q9>_Oq_C5~E zapSC%TF+cq?WAZM52sTz+x|M=7*qGYXPwr@hKU}?FY|pdva7~T3)xl=S;|Xv6PQJ^ za~=+{A+-&4b@?Kfz(!7w6n}SZDBnyOfuJ{k+|BjgKpwIpQk2%WKDrq1Yii%}43q!R ze=q*NVvL}YcZX{B@u+xL^`@($&kl4x*2jM@Yzj=NllWm`m8uC?P(gyf;s~N;Vf9Nk zZ9K!&dNIv)SsZP6bwF_VtR6Yh@+SwZe;Mzq%+)v6iAal=-udvvgE*lnJ|T~=lQA|x`$SZD*F!vXW}M(K*w8g8DHKx9?&v}ap}_1Hq6I`S#su*LXC9T4V^;l$1QVTdt_a zx(&x#d1k^R;{@*|U5^?X_7!m tzje|zn_uJquO`|5mwSHCiyZhqWi2)GX&Ao+`lO$^qpW#5?-t7czXA6;w=Mtx literal 1539 zcmeAS@N?(olHy`uVBq!ia0vp^_ks8^2NRI&QVv@Sq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1Ffc1+hD4M^`1)8S=jZArg4F0$^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&i0B&qvF*KNf0j6J(SfFpHX8`gNOrftYexnUy@&(kzb(T9Bihb5uTZsl3!k| z30CjxYvq|&T#}fVoa*Ufs{}MbFEca6%E-vr&DGS&$e6sFfDKe;qFHLnDwHwB^B8K+)QQpha;+U$~Alv$RV;#QQOs{r=0RVHq?SmHDf zsy79&@MZxrY@bS_4uF~aS4i!;cjdEf z+`YLsZi3Z7Yy?`2Zids92Qh*AD-SxZWVAC*Z%)(Oo}O3y>gPLRbejEY`e|FfX7{a{ zWl3>@Wo201<_Pof1XG*vl)Ce_-0Mx}ubdg)GFKMpa=0u!I07I(3sg_xJtsQzesR{r z&eO5kc9#>0vB3glL+5GJ`7i&U(LQvJ4>_FS27`kP6e^pxT@*j_erNLCtIv!@KX+}| z+zbv^u(N=Q(8H`{&BL8apR3N$b9Rps!C1*ISa;&jykKtsn0Ha1XYvta!>w=2 ncQ=&7f&lJPs9UamRzJXSYG=z6wgaz4LB+DCtDnm{r-UW|>o!Sj diff --git a/src/ImageProcessor.UnitTests/Images/hi-contrast.jpg b/src/ImageProcessor.UnitTests/Images/hi-contrast.jpg index bd2c9b90248231317b880634eac8f98f2dbdf6a7..a425cbc9e9215ddd019dfa69c37d8a73ee3e100c 100644 GIT binary patch literal 34996 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 diff --git a/src/ImageProcessor.UnitTests/Images/hi-saturation.jpg b/src/ImageProcessor.UnitTests/Images/hi-saturation.jpg index 909fa4fc55d43e54c2e4ef54021b1fb7275676a0..e4c58f3edf5c6d492473fd005275603ae996b8a6 100644 GIT binary patch delta 44329 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 delta 9586 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 diff --git a/src/ImageProcessor.UnitTests/Images/text-over-transparent.png b/src/ImageProcessor.UnitTests/Images/text-over-transparent.png index 21ebe3883c94844039cc07ad91487339b3ed1f34..7435dc6bacbb6f2942b3236030cbaf7a60a9c9c2 100644 GIT binary patch literal 7680 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 LJ>!~NZn6IZT~>i5 literal 7317 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 P0Kj7nJ@snU7ZLvfNs}N= diff --git a/src/ImageProcessor.UnitTests/Images/udendørs.jpg b/src/ImageProcessor.UnitTests/Images/udendørs.jpg new file mode 100644 index 0000000000000000000000000000000000000000..48af69a24ac46fa672ec8f109e00cd378b99b1f8 GIT binary patch literal 55987 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

SNvLWO-4E?ea^7+w$l;bX&K-w#;Bnura{eK) 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 ZFWzs)rjzfj6jECOZa=zcqKcuT|JgE5#Mb}- literal 0 HcmV?d00001 diff --git a/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id b/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id deleted file mode 100644 index 0db1445a2..000000000 --- a/src/ImageProcessor.UnitTests/Images/udendørs.jpg.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -4d040d9aa3519b3d2303419d1f03eebebf88e956 \ No newline at end of file diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index f2f573268..7e37983c3 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -158,9 +158,10 @@ namespace ImageProcessor this.CurrentImageFormat = format; // Always load the data. - foreach (PropertyItem propertyItem in this.Image.PropertyItems) + // TODO. Some custom data doesn't seem to get copied by default methods. + foreach (int id in this.Image.PropertyIdList) { - this.ExifPropertyItems[propertyItem.Id] = propertyItem; + this.ExifPropertyItems[id] = this.Image.GetPropertyItem(id); } this.ShouldProcess = true; diff --git a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs index 662ad314c..b7650d099 100644 --- a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs +++ b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs @@ -282,17 +282,17 @@ namespace ImageProcessor.Imaging.Formats { int count = this.repeatCount.GetValueOrDefault(0); - // File Header sinature and version. + // File Header signature and version. this.WriteString(FileType); this.WriteString(FileVersion); // Write the logical screen descriptor. this.WriteShort(this.width.GetValueOrDefault(w)); // Initial Logical Width this.WriteShort(this.height.GetValueOrDefault(h)); // Initial Logical Height - + // Read the global color table info. sourceGif.Position = SourceGlobalColorInfoPosition; - this.WriteByte(sourceGif.ReadByte()); + this.WriteByte(sourceGif.ReadByte()); this.WriteByte(0); // Background Color Index this.WriteByte(0); // Pixel aspect ratio @@ -301,7 +301,7 @@ namespace ImageProcessor.Imaging.Formats // The different browsers interpret the spec differently when adding a loop. // If the loop count is one IE and FF < 3 (incorrectly) loop an extra number of times. // Removing the Netscape header should fix this. - if (count != 1) + if (count > -1 && count != 1) { // Application Extension Header this.WriteShort(ApplicationExtensionBlockIdentifier); @@ -357,7 +357,7 @@ namespace ImageProcessor.Imaging.Formats this.WriteShort(GraphicControlExtensionBlockIdentifier); // Identifier this.WriteByte(GraphicControlExtensionBlockSize); // Block Size this.WriteByte(blockhead[3] & 0xf7 | 0x08); // Setting disposal flag - this.WriteShort(Convert.ToInt32(frameDelay / 10)); // Setting frame delay + this.WriteShort(Convert.ToInt32(frameDelay / 10.0f)); // Setting frame delay this.WriteByte(blockhead[6]); // Transparent color index this.WriteByte(0); // Terminator } diff --git a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs index ae5fd05c3..f7ff73c66 100644 --- a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs @@ -75,7 +75,7 @@ namespace ImageProcessor.Imaging.Formats { base.ApplyProcessor(processor, factory); - // Set the property item information from any Exif metadata. + // Set the property item information from any Exif metadata. // We do this here so that they can be changed between processor methods. if (factory.PreserveExifData) { diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index 248fe1d7f..5bacb50dd 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -15,9 +15,7 @@ namespace ImageProcessorConsole using System.Drawing; using System.IO; using System.Linq; - using ImageProcessor; - using ImageProcessor.Imaging.Formats; ///

/// The program. @@ -33,6 +31,7 @@ namespace ImageProcessorConsole public static void Main(string[] args) { string path = new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath; + // ReSharper disable once AssignNullToNotNullAttribute string resolvedPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\input")); DirectoryInfo di = new DirectoryInfo(resolvedPath); @@ -41,10 +40,8 @@ namespace ImageProcessorConsole di.Create(); } - //FileInfo[] files = di.GetFiles("*.jpg"); - //FileInfo[] files = di.GetFiles(); - IEnumerable files = GetFilesByExtensions(di, ".gif", ".webp"); - + IEnumerable files = GetFilesByExtensions(di, ".gif"); + //IEnumerable files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png"); foreach (FileInfo fileInfo in files) { @@ -53,18 +50,13 @@ namespace ImageProcessorConsole // ImageProcessor using (MemoryStream inStream = new MemoryStream(photoBytes)) { - using (ImageFactory imageFactory = new ImageFactory()) + using (ImageFactory imageFactory = new ImageFactory(true)) { Size size = new Size(200, 200); // Load, resize, set the format and quality and save an image. imageFactory.Load(inStream) - //.AutoRotate() .Constrain(size) - //.Format(new WebPFormat()) - //.Quality(5) - // ReSharper disable once AssignNullToNotNullAttribute - // .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".webp"))); .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); } } @@ -74,7 +66,10 @@ namespace ImageProcessorConsole public static IEnumerable GetFilesByExtensions(DirectoryInfo dir, params string[] extensions) { if (extensions == null) + { throw new ArgumentNullException("extensions"); + } + IEnumerable files = dir.EnumerateFiles(); return files.Where(f => extensions.Contains(f.Extension, StringComparer.OrdinalIgnoreCase)); } diff --git a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id index 71ce555c1..4767fd13d 100644 --- a/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/120430.gif.REMOVED.git-id @@ -1 +1 @@ -30ec5c05548fd350f9b7c699715848b9fbfb8ca9 \ No newline at end of file +6f3f997e323adb1fce142930d86338efacffc3fd \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id index 6515d65a0..f0f194a2b 100644 --- a/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/Tl4Yb.gif.REMOVED.git-id @@ -1 +1 @@ -fdc62fc2d056ab885eb9e8fd12b9155ee86d7c43 \ No newline at end of file +3ab082661fc5d88f88643c47409e196d66e26d4b \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/circle.png b/src/ImageProcessorConsole/images/output/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..41fdcd72af59ba2158b19120e7ba11f4cad0180d GIT binary patch literal 2905 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 literal 0 HcmV?d00001 diff --git a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id index c07be0b0f..b8684cd60 100644 --- a/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/nLpfllv.gif.REMOVED.git-id @@ -1 +1 @@ -77cce70db3722920d60f4b17a45a5e390a09838a \ No newline at end of file +e2c2fbac64987ad26e19f5d2721fcaa60fee843d \ No newline at end of file From fe3c1cfb76f4f0ead026cce7c6c0638b46734cc0 Mon Sep 17 00:00:00 2001 From: James South Date: Sat, 5 Jul 2014 14:49:35 +0100 Subject: [PATCH 106/155] Fixing unit test Former-commit-id: f13854941670288564cf8e80aceccb91e47a67bc --- .../Extensions/StringExtensionsUnitTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs index c89c09dcd..a3c5ea794 100644 --- a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -156,6 +156,7 @@ namespace ImageProcessor.UnitTests.Extensions /// Whether the value is correct /// /// The full RFC3986 does not seem to pass the test with the square brackets + /// ':' is failing for some reason in VS but not elsewhere. Could be a build issue. /// [Test] [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", true)] @@ -163,7 +164,7 @@ namespace ImageProcessor.UnitTests.Extensions [TestCase(".", true)] [TestCase("_", true)] [TestCase("~", true)] - [TestCase(":", false)] + [TestCase(":", true)] [TestCase("/", true)] [TestCase("?", true)] [TestCase("#", false)] From dcfade6c28599858dfe03fa5e9440995d4451af7 Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 6 Jul 2014 12:11:52 +0100 Subject: [PATCH 107/155] Refactoring extensions Former-commit-id: 4987805685fb6ec8bad708809ddf0ae6f239f1d4 --- .../Extensions/StringExtensionsUnitTests.cs | 110 -------------- .../Extensions/StringExtensionsUnitTests.cs | 98 ++++++++++++ .../ImageProcessor.Web.UnitTests.csproj | 1 + .../NET45/Configuration/ImageCacheSection.cs | 5 +- .../NET45/Extensions/StringExtensions.cs | 143 ++++++++++++++++++ .../HttpModules/ImageProcessingModule.cs | 2 +- .../NET45/ImageProcessor.Web_NET45.csproj | 1 + .../Common/Extensions/AssemblyExtensions.cs | 13 +- .../Common/Extensions/StringExtensions.cs | 105 ------------- .../Imaging/Formats/GifEncoder.cs | 22 +-- .../Imaging/Formats/JpegFormat.cs | 2 +- .../Imaging/Formats/NativeMethods.cs | 6 + src/ImageProcessor/Settings.StyleCop | 1 + 13 files changed, 272 insertions(+), 237 deletions(-) create mode 100644 src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs create mode 100644 src/ImageProcessor.Web/NET45/Extensions/StringExtensions.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs index a3c5ea794..ab43bd92b 100644 --- a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -10,7 +10,6 @@ namespace ImageProcessor.UnitTests.Extensions { - using System; using System.Collections.Generic; using ImageProcessor.Common.Extensions; using NUnit.Framework; @@ -21,74 +20,6 @@ namespace ImageProcessor.UnitTests.Extensions [TestFixture] public class StringExtensionsUnitTests { - /// - /// Tests the MD5 fingerprint - /// - /// The input value - /// The expected output of the hash - [Test] - [TestCase("test input", "2e7f7a62eabf0993239ca17c78c464d9")] - [TestCase("lorem ipsum dolor", "96ee002fee25e8b675a477c9750fa360")] - [TestCase("LoReM IpSuM DoLoR", "41e201da794c7fbdb8ce5526a71c8c83")] - [TestCase("1234567890", "e15e31c3d8898c92ab172a4311be9e84")] - public void TestToMd5Fingerprint(string input, string expected) - { - string result = input.ToMD5Fingerprint(); - bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); - Assert.True(comparison); - } - - /// - /// Tests the SHA-1 fingerprint - /// - /// The input value - /// The expected output of the hash - [Test] - [TestCase("test input", "49883b34e5a0f48224dd6230f471e9dc1bdbeaf5")] - [TestCase("lorem ipsum dolor", "75899ad8827a32493928903aecd6e931bf36f967")] - [TestCase("LoReM IpSuM DoLoR", "2f44519afae72fc0837b72c6b53cb11338a1f916")] - [TestCase("1234567890", "01b307acba4f54f55aafc33bb06bbbf6ca803e9a")] - public void TestToSHA1Fingerprint(string input, string expected) - { - string result = input.ToSHA1Fingerprint(); - bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); - Assert.True(comparison); - } - - /// - /// Tests the SHA-256 fingerprint - /// - /// The input value - /// The expected output of the hash - [Test] - [TestCase("test input", "9dfe6f15d1ab73af898739394fd22fd72a03db01834582f24bb2e1c66c7aaeae")] - [TestCase("lorem ipsum dolor", "ed03353266c993ea9afb9900a3ca688ddec1656941b1ca15ee1650a022616dfa")] - [TestCase("LoReM IpSuM DoLoR", "55f6cb90ba5cd8eeb6f5f16f083ebcd48ea06c34cc5aed8e33246fc3153d3898")] - [TestCase("1234567890", "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646")] - public void TestToSHA256Fingerprint(string input, string expected) - { - string result = input.ToSHA256Fingerprint(); - bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); - Assert.True(comparison); - } - - /// - /// Tests the SHA-512 fingerprint - /// - /// The input value - /// The expected output of the hash - [Test] - [TestCase("test input", "40aa1b203c9d8ee150b21c3c7cda8261492e5420c5f2b9f7380700e094c303b48e62f319c1da0e32eb40d113c5f1749cc61aeb499167890ab82f2cc9bb706971")] - [TestCase("lorem ipsum dolor", "cd813e13d1d3919cdccc31c19d8f8b70bd25e9819f8770a011c8c7a6228536e6c9427b338cd732f2da3c0444dfebef838b745cdaf3fd5dcba8db24fc83a3f6ef")] - [TestCase("LoReM IpSuM DoLoR", "3e4704d31f838456c0a5f0892afd392fbc79649a029d017b8104ebd00e2816d94ab4629f731765bf655088b130c51f6f47ca2f8b047749dbd992cf45e89ff431")] - [TestCase("1234567890", "12b03226a6d8be9c6e8cd5e55dc6c7920caaa39df14aab92d5e3ea9340d1c8a4d3d0b8e4314f1f6ef131ba4bf1ceb9186ab87c801af0d5c95b1befb8cedae2b9")] - public void TestToSHA512Fingerprint(string input, string expected) - { - string result = input.ToSHA512Fingerprint(); - bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); - Assert.True(comparison); - } - /// /// Tests the passing to an integer array /// @@ -148,46 +79,5 @@ namespace ImageProcessor.UnitTests.Extensions Assert.AreEqual(item.Value, result); } } - - /// - /// Tests if the value is a valid URI path name. I.E the path part of a uri. - /// - /// The value to test - /// Whether the value is correct - /// - /// The full RFC3986 does not seem to pass the test with the square brackets - /// ':' is failing for some reason in VS but not elsewhere. Could be a build issue. - /// - [Test] - [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", true)] - [TestCase("-", true)] - [TestCase(".", true)] - [TestCase("_", true)] - [TestCase("~", true)] - [TestCase(":", true)] - [TestCase("/", true)] - [TestCase("?", true)] - [TestCase("#", false)] - [TestCase("[", false)] - [TestCase("]", false)] - [TestCase("@", true)] - [TestCase("!", true)] - [TestCase("$", true)] - [TestCase("&", true)] - [TestCase("'", true)] - [TestCase("(", true)] - [TestCase(")", true)] - [TestCase("*", true)] - [TestCase("+", true)] - [TestCase(",", true)] - [TestCase(";", true)] - [TestCase("=", true)] - [TestCase("lorem ipsum", false)] - [TestCase("é", false)] - public void TestIsValidUriPathName(string input, bool expected) - { - bool result = input.IsValidVirtualPathName(); - Assert.AreEqual(expected, result); - } } } \ No newline at end of file diff --git a/src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs new file mode 100644 index 000000000..57c261c7b --- /dev/null +++ b/src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -0,0 +1,98 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Test harness for the string extensions +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.UnitTests.Extensions +{ + using System; + using ImageProcessor.Web.Extensions; + using NUnit.Framework; + + /// + /// Test harness for the string extensions + /// + [TestFixture] + public class StringExtensionsUnitTests + { + /// + /// Tests the MD5 fingerprint + /// + /// The input value + /// The expected output of the hash + [Test] + [TestCase("test input", "2e7f7a62eabf0993239ca17c78c464d9")] + [TestCase("lorem ipsum dolor", "96ee002fee25e8b675a477c9750fa360")] + [TestCase("LoReM IpSuM DoLoR", "41e201da794c7fbdb8ce5526a71c8c83")] + [TestCase("1234567890", "e15e31c3d8898c92ab172a4311be9e84")] + public void TestToMd5Fingerprint(string input, string expected) + { + string result = input.ToMD5Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + + /// + /// Tests the SHA-1 fingerprint + /// + /// The input value + /// The expected output of the hash + [Test] + [TestCase("test input", "49883b34e5a0f48224dd6230f471e9dc1bdbeaf5")] + [TestCase("lorem ipsum dolor", "75899ad8827a32493928903aecd6e931bf36f967")] + [TestCase("LoReM IpSuM DoLoR", "2f44519afae72fc0837b72c6b53cb11338a1f916")] + [TestCase("1234567890", "01b307acba4f54f55aafc33bb06bbbf6ca803e9a")] + public void TestToSHA1Fingerprint(string input, string expected) + { + string result = input.ToSHA1Fingerprint(); + bool comparison = result.Equals(expected, StringComparison.InvariantCultureIgnoreCase); + Assert.True(comparison); + } + + /// + /// Tests if the value is a valid URI path name. I.E the path part of a uri. + /// + /// The value to test + /// Whether the value is correct + /// + /// The full RFC3986 does not seem to pass the test with the square brackets + /// ':' is failing for some reason in VS but not elsewhere. Could be a build issue. + /// + [Test] + [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", true)] + [TestCase("-", true)] + [TestCase(".", true)] + [TestCase("_", true)] + [TestCase("~", true)] + [TestCase(":", true)] + [TestCase("/", true)] + [TestCase("?", true)] + [TestCase("#", false)] + [TestCase("[", false)] + [TestCase("]", false)] + [TestCase("@", true)] + [TestCase("!", true)] + [TestCase("$", true)] + [TestCase("&", true)] + [TestCase("'", true)] + [TestCase("(", true)] + [TestCase(")", true)] + [TestCase("*", true)] + [TestCase("+", true)] + [TestCase(",", true)] + [TestCase(";", true)] + [TestCase("=", true)] + [TestCase("lorem ipsum", false)] + [TestCase("é", false)] + public void TestIsValidUriPathName(string input, bool expected) + { + bool result = input.IsValidVirtualPathName(); + Assert.AreEqual(expected, result); + } + } +} diff --git a/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj index 17c54d202..460e329b9 100644 --- a/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj +++ b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj @@ -53,6 +53,7 @@ + diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs index 8e5abad95..1f868fc04 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs @@ -10,16 +10,13 @@ namespace ImageProcessor.Web.Configuration { - #region Using using System.Configuration; using System.IO; using System.Xml; - using ImageProcessor.Common.Extensions; + using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; - #endregion - /// /// Represents an image cache section within a configuration file. /// diff --git a/src/ImageProcessor.Web/NET45/Extensions/StringExtensions.cs b/src/ImageProcessor.Web/NET45/Extensions/StringExtensions.cs new file mode 100644 index 000000000..5ec1fdf4b --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Extensions/StringExtensions.cs @@ -0,0 +1,143 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates a series of time saving extension methods to the class. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.Extensions +{ + using System; + using System.Globalization; + using System.Linq; + using System.Security.Cryptography; + using System.Text; + using System.Text.RegularExpressions; + + /// + /// Encapsulates a series of time saving extension methods to the class. + /// + public static class StringExtensions + { + #region Cryptography + /// + /// Creates an MD5 fingerprint of the String. + /// + /// The String instance that this method extends. + /// An MD5 fingerprint of the String. + public static string ToMD5Fingerprint(this string expression) + { + byte[] bytes = Encoding.Unicode.GetBytes(expression.ToCharArray()); + + using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()) + { + byte[] hash = md5.ComputeHash(bytes); + + // Concatenate the hash bytes into one long String. + return hash.Aggregate( + new StringBuilder(32), + (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) + .ToString().ToLowerInvariant(); + } + } + + /// + /// Creates an SHA1 fingerprint of the String. + /// + /// The String instance that this method extends. + /// An SHA1 fingerprint of the String. + public static string ToSHA1Fingerprint(this string expression) + { + byte[] bytes = Encoding.ASCII.GetBytes(expression.ToCharArray()); + + using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) + { + byte[] hash = sha1.ComputeHash(bytes); + + // Concatenate the hash bytes into one long String. + return hash.Aggregate( + new StringBuilder(40), + (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) + .ToString().ToLowerInvariant(); + } + } + #endregion + + #region Numbers + /// + /// Creates an array of integers scraped from the String. + /// + /// The String instance that this method extends. + /// An array of integers scraped from the String. + public static int[] ToPositiveIntegerArray(this string expression) + { + if (string.IsNullOrWhiteSpace(expression)) + { + throw new ArgumentNullException("expression"); + } + + Regex regex = new Regex(@"[\d+]+(?=[,-])|[\d+]+(?![,-])", RegexOptions.Compiled); + + MatchCollection matchCollection = regex.Matches(expression); + + // Get the collections. + int count = matchCollection.Count; + int[] matches = new int[count]; + + // Loop and parse the int values. + for (int i = 0; i < count; i++) + { + matches[i] = int.Parse(matchCollection[i].Value, CultureInfo.InvariantCulture); + } + + return matches; + } + + /// + /// Creates an array of floats scraped from the String. + /// + /// The String instance that this method extends. + /// An array of floats scraped from the String. + public static float[] ToPositiveFloatArray(this string expression) + { + if (string.IsNullOrWhiteSpace(expression)) + { + throw new ArgumentNullException("expression"); + } + + Regex regex = new Regex(@"[\d+\.]+(?=[,-])|[\d+\.]+(?![,-])", RegexOptions.Compiled); + + MatchCollection matchCollection = regex.Matches(expression); + + // Get the collections. + int count = matchCollection.Count; + float[] matches = new float[count]; + + // Loop and parse the int values. + for (int i = 0; i < count; i++) + { + matches[i] = float.Parse(matchCollection[i].Value, CultureInfo.InvariantCulture); + } + + return matches; + } + #endregion + + #region Files and Paths + /// + /// Checks the string to see whether the value is a valid virtual path name. + /// + /// The String instance that this method extends. + /// True if the given string is a valid virtual path name + public static bool IsValidVirtualPathName(this string expression) + { + Uri uri; + + return Uri.TryCreate(expression, UriKind.Relative, out uri) && uri.IsWellFormedOriginalString(); + } + #endregion + } +} diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index d70e71867..db378fae4 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -29,9 +29,9 @@ namespace ImageProcessor.Web.HttpModules using System.Web.Hosting; using System.Web.Security; - using ImageProcessor.Common.Extensions; using ImageProcessor.Web.Caching; using ImageProcessor.Web.Configuration; + using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; #endregion diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index 2f5e77f23..40bd16bc7 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -54,6 +54,7 @@ + diff --git a/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs b/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs index 763697ef0..e37480ff0 100644 --- a/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs +++ b/src/ImageProcessor/Common/Extensions/AssemblyExtensions.cs @@ -1,4 +1,13 @@ - +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates a series of time saving extension methods to the class. +// +// -------------------------------------------------------------------------------------------------------------------- + namespace ImageProcessor.Common.Extensions { using System; @@ -38,4 +47,4 @@ namespace ImageProcessor.Common.Extensions } } } -} +} \ No newline at end of file diff --git a/src/ImageProcessor/Common/Extensions/StringExtensions.cs b/src/ImageProcessor/Common/Extensions/StringExtensions.cs index fd7d54139..f315df797 100644 --- a/src/ImageProcessor/Common/Extensions/StringExtensions.cs +++ b/src/ImageProcessor/Common/Extensions/StringExtensions.cs @@ -12,9 +12,6 @@ namespace ImageProcessor.Common.Extensions { using System; using System.Globalization; - using System.Linq; - using System.Security.Cryptography; - using System.Text; using System.Text.RegularExpressions; /// @@ -22,93 +19,6 @@ namespace ImageProcessor.Common.Extensions /// public static class StringExtensions { - #region Cryptography - /// - /// Creates an MD5 fingerprint of the String. - /// - /// The String instance that this method extends. - /// An MD5 fingerprint of the String. - public static string ToMD5Fingerprint(this string expression) - { - byte[] bytes = Encoding.Unicode.GetBytes(expression.ToCharArray()); - - using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()) - { - byte[] hash = md5.ComputeHash(bytes); - - // Concatenate the hash bytes into one long String. - return hash.Aggregate( - new StringBuilder(32), - (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) - .ToString().ToLowerInvariant(); - } - } - - /// - /// Creates an SHA1 fingerprint of the String. - /// - /// The String instance that this method extends. - /// An SHA1 fingerprint of the String. - public static string ToSHA1Fingerprint(this string expression) - { - byte[] bytes = Encoding.ASCII.GetBytes(expression.ToCharArray()); - - using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) - { - byte[] hash = sha1.ComputeHash(bytes); - - // Concatenate the hash bytes into one long String. - return hash.Aggregate( - new StringBuilder(40), - (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) - .ToString().ToLowerInvariant(); - } - } - - /// - /// Creates an SHA256 fingerprint of the String. - /// - /// The String instance that this method extends. - /// An SHA256 fingerprint of the String. - public static string ToSHA256Fingerprint(this string expression) - { - byte[] bytes = Encoding.ASCII.GetBytes(expression.ToCharArray()); - - using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider()) - { - byte[] hash = sha256.ComputeHash(bytes); - - // Concatenate the hash bytes into one long String. - return hash.Aggregate( - new StringBuilder(64), - (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) - .ToString().ToLowerInvariant(); - } - } - - /// - /// Creates an SHA512 fingerprint of the String. - /// - /// The String instance that this method extends. - /// An SHA256 fingerprint of the String. - public static string ToSHA512Fingerprint(this string expression) - { - byte[] bytes = Encoding.ASCII.GetBytes(expression.ToCharArray()); - - using (SHA512CryptoServiceProvider sha512 = new SHA512CryptoServiceProvider()) - { - byte[] hash = sha512.ComputeHash(bytes); - - // Concatenate the hash bytes into one long String. - return hash.Aggregate( - new StringBuilder(70), - (sb, b) => sb.Append(b.ToString("X2", CultureInfo.InvariantCulture))) - .ToString().ToLowerInvariant(); - } - } - #endregion - - #region Numbers /// /// Creates an array of integers scraped from the String. /// @@ -166,20 +76,5 @@ namespace ImageProcessor.Common.Extensions return matches; } - #endregion - - #region Files and Paths - /// - /// Checks the string to see whether the value is a valid virtual path name. - /// - /// The String instance that this method extends. - /// True if the given string is a valid virtual path name - public static bool IsValidVirtualPathName(this string expression) - { - Uri uri; - - return Uri.TryCreate(expression, UriKind.Relative, out uri) && uri.IsWellFormedOriginalString(); - } - #endregion } } diff --git a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs index b7650d099..826ddf42f 100644 --- a/src/ImageProcessor/Imaging/Formats/GifEncoder.cs +++ b/src/ImageProcessor/Imaging/Formats/GifEncoder.cs @@ -298,20 +298,14 @@ namespace ImageProcessor.Imaging.Formats this.WriteByte(0); // Pixel aspect ratio this.WriteColorTable(sourceGif); - // The different browsers interpret the spec differently when adding a loop. - // If the loop count is one IE and FF < 3 (incorrectly) loop an extra number of times. - // Removing the Netscape header should fix this. - if (count > -1 && count != 1) - { - // Application Extension Header - this.WriteShort(ApplicationExtensionBlockIdentifier); - this.WriteByte(ApplicationBlockSize); - this.WriteString(ApplicationIdentification); - this.WriteByte(3); // Application block length - this.WriteByte(1); - this.WriteShort(count); // Repeat count for images. - this.WriteByte(0); // Terminator - } + // Application Extension Header + this.WriteShort(ApplicationExtensionBlockIdentifier); + this.WriteByte(ApplicationBlockSize); + this.WriteString(ApplicationIdentification); + this.WriteByte(3); // Application block length + this.WriteByte(1); + this.WriteShort(count); // Repeat count for images. + this.WriteByte(0); // Terminator } /// diff --git a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs index f7ff73c66..ae5fd05c3 100644 --- a/src/ImageProcessor/Imaging/Formats/JpegFormat.cs +++ b/src/ImageProcessor/Imaging/Formats/JpegFormat.cs @@ -75,7 +75,7 @@ namespace ImageProcessor.Imaging.Formats { base.ApplyProcessor(processor, factory); - // Set the property item information from any Exif metadata. + // Set the property item information from any Exif metadata. // We do this here so that they can be changed between processor methods. if (factory.PreserveExifData) { diff --git a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs b/src/ImageProcessor/Imaging/Formats/NativeMethods.cs index 8aaff3432..574bd1e8f 100644 --- a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs +++ b/src/ImageProcessor/Imaging/Formats/NativeMethods.cs @@ -18,6 +18,12 @@ namespace ImageProcessor.Imaging.Formats /// internal static class NativeMethods { + /// + /// Whether the process is running in 64bit mode. Used for calling the correct dllimport method. + /// Clunky I know but I couldn't get dynamic methods to work. + /// + private static readonly bool Is64Bit = Environment.Is64BitProcess; + #region WebP /// /// Validate the WebP image header and retrieve the image height and width. Pointers *width and *height can be passed NULL if deemed irrelevant diff --git a/src/ImageProcessor/Settings.StyleCop b/src/ImageProcessor/Settings.StyleCop index 29b381707..085067600 100644 --- a/src/ImageProcessor/Settings.StyleCop +++ b/src/ImageProcessor/Settings.StyleCop @@ -4,6 +4,7 @@ bitstream dd ddd + dllimport gps mmmm orig From 86d5a91d3732a0430cbe83006cde633014e5768d Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 6 Jul 2014 18:58:51 +0100 Subject: [PATCH 108/155] Fixing references. Former-commit-id: cd32f8c955b3fd8ca70862231135ee52a4b97e3a --- .../Extensions/StringExtensionsUnitTests.cs | 83 ------------------- .../ImageProcessor.UnitTests.csproj | 5 +- .../Extensions/StringExtensionsUnitTests.cs | 62 ++++++++++++++ .../NET4/ImageProcessor.Web_NET4.csproj | 3 + .../NET45/Caching/DiskCache.cs | 3 +- .../Helpers/CommonParameterParserUtility.cs | 1 + .../NET45/Processors/Crop.cs | 2 +- .../NET45/Processors/Resize.cs | 2 +- .../NET45/Processors/Watermark.cs | 2 +- .../Common/Extensions/StringExtensions.cs | 80 ------------------ src/ImageProcessor/ImageProcessor.csproj | 1 - 11 files changed, 71 insertions(+), 173 deletions(-) delete mode 100644 src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs delete mode 100644 src/ImageProcessor/Common/Extensions/StringExtensions.cs diff --git a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs deleted file mode 100644 index ab43bd92b..000000000 --- a/src/ImageProcessor.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ /dev/null @@ -1,83 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) James South. -// Licensed under the Apache License, Version 2.0. -// -// -// Provides a test harness for the string extensions -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace ImageProcessor.UnitTests.Extensions -{ - using System.Collections.Generic; - using ImageProcessor.Common.Extensions; - using NUnit.Framework; - - /// - /// Test harness for the string extensions - /// - [TestFixture] - public class StringExtensionsUnitTests - { - /// - /// Tests the passing to an integer array - /// - [Test] - public void TestToIntegerArray() - { - Dictionary data = new Dictionary - { - { - "123-456,78-90", - new[] { 123, 456, 78, 90 } - }, - { - "87390174,741897498,74816,748297,57355", - new[] - { - 87390174, 741897498, 74816, - 748297, 57355 - } - }, - { "1-2-3", new[] { 1, 2, 3 } } - }; - - foreach (KeyValuePair item in data) - { - int[] result = item.Key.ToPositiveIntegerArray(); - Assert.AreEqual(item.Value, result); - } - } - - /// - /// Tests the passing to an float array - /// - [Test] - public void TestToFloatArray() - { - Dictionary data = new Dictionary - { - { - "12.3-4.56,78-9.0", - new[] { 12.3F, 4.56F, 78, 9 } - }, - { - "87390.174,7.41897498,748.16,748297,5.7355", - new[] - { - 87390.174F, 7.41897498F, - 748.16F, 748297, 5.7355F - } - }, - { "1-2-3", new float[] { 1, 2, 3 } } - }; - - foreach (KeyValuePair item in data) - { - float[] result = item.Key.ToPositiveFloatArray(); - Assert.AreEqual(item.Value, result); - } - } - } -} \ No newline at end of file diff --git a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj index 5b6bc12d1..930267a63 100644 --- a/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj +++ b/src/ImageProcessor.UnitTests/ImageProcessor.UnitTests.csproj @@ -48,7 +48,6 @@ - @@ -130,7 +129,5 @@ - - - + \ No newline at end of file diff --git a/src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs b/src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs index 57c261c7b..3e9053aed 100644 --- a/src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs +++ b/src/ImageProcessor.Web.UnitTests/Extensions/StringExtensionsUnitTests.cs @@ -11,6 +11,8 @@ namespace ImageProcessor.Web.UnitTests.Extensions { using System; + using System.Collections.Generic; + using ImageProcessor.Web.Extensions; using NUnit.Framework; @@ -20,6 +22,66 @@ namespace ImageProcessor.Web.UnitTests.Extensions [TestFixture] public class StringExtensionsUnitTests { + /// + /// Tests the passing to an integer array + /// + [Test] + public void TestToIntegerArray() + { + Dictionary data = new Dictionary + { + { + "123-456,78-90", + new[] { 123, 456, 78, 90 } + }, + { + "87390174,741897498,74816,748297,57355", + new[] + { + 87390174, 741897498, 74816, + 748297, 57355 + } + }, + { "1-2-3", new[] { 1, 2, 3 } } + }; + + foreach (KeyValuePair item in data) + { + int[] result = item.Key.ToPositiveIntegerArray(); + Assert.AreEqual(item.Value, result); + } + } + + /// + /// Tests the passing to an float array + /// + [Test] + public void TestToFloatArray() + { + Dictionary data = new Dictionary + { + { + "12.3-4.56,78-9.0", + new[] { 12.3F, 4.56F, 78, 9 } + }, + { + "87390.174,7.41897498,748.16,748297,5.7355", + new[] + { + 87390.174F, 7.41897498F, + 748.16F, 748297, 5.7355F + } + }, + { "1-2-3", new float[] { 1, 2, 3 } } + }; + + foreach (KeyValuePair item in data) + { + float[] result = item.Key.ToPositiveFloatArray(); + Assert.AreEqual(item.Value, result); + } + } + /// /// Tests the MD5 fingerprint /// diff --git a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj index d830257ae..82d3986a7 100644 --- a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj +++ b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj @@ -98,6 +98,9 @@ DirectoryInfoExtensions.cs + + StringExtensions.cs + CommonParameterParserUtility.cs diff --git a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs index 6a23d48ad..be6b88744 100644 --- a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs @@ -20,7 +20,6 @@ namespace ImageProcessor.Web.Caching using System.Web; using System.Web.Hosting; - using ImageProcessor.Common.Extensions; using ImageProcessor.Web.Configuration; using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; @@ -245,7 +244,7 @@ namespace ImageProcessor.Web.Caching fileInfo.Delete(); count -= 1; } - // ReSharper disable once EmptyGeneralCatchClause + // ReSharper disable once EmptyGeneralCatchClause catch { // Do nothing; skip to the next file. diff --git a/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs b/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs index ae71ca7ef..505d80d99 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs @@ -17,6 +17,7 @@ namespace ImageProcessor.Web.Helpers using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging; + using ImageProcessor.Web.Extensions; /// /// Encapsulates methods to correctly parse querystring parameters. diff --git a/src/ImageProcessor.Web/NET45/Processors/Crop.cs b/src/ImageProcessor.Web/NET45/Processors/Crop.cs index c621ebd1a..c669c8e1b 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Crop.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Crop.cs @@ -13,9 +13,9 @@ namespace ImageProcessor.Web.Processors using System.Text; using System.Text.RegularExpressions; - using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging; using ImageProcessor.Processors; + using ImageProcessor.Web.Extensions; /// /// Crops an image to the given directions. diff --git a/src/ImageProcessor.Web/NET45/Processors/Resize.cs b/src/ImageProcessor.Web/NET45/Processors/Resize.cs index 95d962958..09ce9bc3c 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Resize.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Resize.cs @@ -17,9 +17,9 @@ namespace ImageProcessor.Web.Processors using System.Text; using System.Text.RegularExpressions; - using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging; using ImageProcessor.Processors; + using ImageProcessor.Web.Extensions; /// /// Resizes an image to the given dimensions. diff --git a/src/ImageProcessor.Web/NET45/Processors/Watermark.cs b/src/ImageProcessor.Web/NET45/Processors/Watermark.cs index 27e83e288..d87f09388 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Watermark.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Watermark.cs @@ -15,9 +15,9 @@ namespace ImageProcessor.Web.Processors using System.Linq; using System.Text.RegularExpressions; - using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging; using ImageProcessor.Processors; + using ImageProcessor.Web.Extensions; using ImageProcessor.Web.Helpers; /// diff --git a/src/ImageProcessor/Common/Extensions/StringExtensions.cs b/src/ImageProcessor/Common/Extensions/StringExtensions.cs deleted file mode 100644 index f315df797..000000000 --- a/src/ImageProcessor/Common/Extensions/StringExtensions.cs +++ /dev/null @@ -1,80 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) James South. -// Licensed under the Apache License, Version 2.0. -// -// -// Encapsulates a series of time saving extension methods to the class. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace ImageProcessor.Common.Extensions -{ - using System; - using System.Globalization; - using System.Text.RegularExpressions; - - /// - /// Encapsulates a series of time saving extension methods to the class. - /// - public static class StringExtensions - { - /// - /// Creates an array of integers scraped from the String. - /// - /// The String instance that this method extends. - /// An array of integers scraped from the String. - public static int[] ToPositiveIntegerArray(this string expression) - { - if (string.IsNullOrWhiteSpace(expression)) - { - throw new ArgumentNullException("expression"); - } - - Regex regex = new Regex(@"[\d+]+(?=[,-])|[\d+]+(?![,-])", RegexOptions.Compiled); - - MatchCollection matchCollection = regex.Matches(expression); - - // Get the collections. - int count = matchCollection.Count; - int[] matches = new int[count]; - - // Loop and parse the int values. - for (int i = 0; i < count; i++) - { - matches[i] = int.Parse(matchCollection[i].Value, CultureInfo.InvariantCulture); - } - - return matches; - } - - /// - /// Creates an array of floats scraped from the String. - /// - /// The String instance that this method extends. - /// An array of floats scraped from the String. - public static float[] ToPositiveFloatArray(this string expression) - { - if (string.IsNullOrWhiteSpace(expression)) - { - throw new ArgumentNullException("expression"); - } - - Regex regex = new Regex(@"[\d+\.]+(?=[,-])|[\d+\.]+(?![,-])", RegexOptions.Compiled); - - MatchCollection matchCollection = regex.Matches(expression); - - // Get the collections. - int count = matchCollection.Count; - float[] matches = new float[count]; - - // Loop and parse the int values. - for (int i = 0; i < count; i++) - { - matches[i] = float.Parse(matchCollection[i].Value, CultureInfo.InvariantCulture); - } - - return matches; - } - } -} diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 274b3e76d..0e0d276bb 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -66,7 +66,6 @@ - From 3f862bda853fdcce1fa5b4ad8fd576004759ff22 Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 7 Jul 2014 08:21:28 +0100 Subject: [PATCH 109/155] Reorganizing native binaries Former-commit-id: 1cf486d20dbf4b385d58002a39328d25bc0138ac --- build/NuSpecs/ImageProcessor.nuspec | 4 +- .../ImageProcessor.Web/web.config.transform | 2 + .../NET4/ImageProcessor.Web_NET4.csproj | 3 + .../ImageProcessorConfiguration.cs | 29 +--- .../ImageProcessorNativeBinaryModule.cs | 159 ++++++++++++++++++ .../NET45/ImageProcessor.Web_NET45.csproj | 1 + src/ImageProcessor.sln.DotSettings | 1 + src/ImageProcessor/ImageProcessor.csproj | 5 +- .../Imaging/Formats/NativeMethods.cs | 127 ++++++++++++-- .../Imaging/Formats/WebPFormat.cs | 60 +------ ...imageprocessor.libwebp.dll.REMOVED.git-id} | 0 ...imageprocessor.libwebp.dll.REMOVED.git-id} | 0 src/ImageProcessorConsole/Program.cs | 4 +- .../images/output/120430.gif.REMOVED.git-id | 2 +- .../images/output/Tl4Yb.gif.REMOVED.git-id | 2 +- .../images/output/nLpfllv.gif.REMOVED.git-id | 2 +- .../images/output/rotate.jpg | Bin 0 -> 22990 bytes .../NET45/Test_Website_NET45/Web.config | 4 +- 18 files changed, 305 insertions(+), 100 deletions(-) create mode 100644 src/ImageProcessor.Web/NET45/HttpModules/ImageProcessorNativeBinaryModule.cs rename src/ImageProcessor/{libwebp64.dll.REMOVED.git-id => x64/imageprocessor.libwebp.dll.REMOVED.git-id} (100%) rename src/ImageProcessor/{libwebp32.dll.REMOVED.git-id => x86/imageprocessor.libwebp.dll.REMOVED.git-id} (100%) create mode 100644 src/ImageProcessorConsole/images/output/rotate.jpg diff --git a/build/NuSpecs/ImageProcessor.nuspec b/build/NuSpecs/ImageProcessor.nuspec index 557d85150..f12daba8f 100644 --- a/build/NuSpecs/ImageProcessor.nuspec +++ b/build/NuSpecs/ImageProcessor.nuspec @@ -25,8 +25,8 @@ Feedback is always welcome. - - + + \ No newline at end of file diff --git a/build/content/ImageProcessor.Web/web.config.transform b/build/content/ImageProcessor.Web/web.config.transform index 7d02ee462..5c3edb967 100644 --- a/build/content/ImageProcessor.Web/web.config.transform +++ b/build/content/ImageProcessor.Web/web.config.transform @@ -3,6 +3,7 @@ + @@ -13,6 +14,7 @@ + \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj index 82d3986a7..12c43700b 100644 --- a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj +++ b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj @@ -116,6 +116,9 @@ + + ImageProcessorNativeBinaryModule.cs + Alpha.cs diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs index 9d3ea6be9..95c3123e2 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs +++ b/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs @@ -23,6 +23,7 @@ namespace ImageProcessor.Web.Configuration using ImageProcessor.Common.Extensions; using ImageProcessor.Processors; using ImageProcessor.Web.Helpers; + using ImageProcessor.Web.HttpModules; using ImageProcessor.Web.Processors; /// @@ -370,30 +371,14 @@ namespace ImageProcessor.Web.Configuration /// private void EnsureNativeBinariesLoaded() { - string binary = Is64Bit ? "libwebp64.dll" : "libwebp32.dll"; - string sourcePath = HttpContext.Current.Server.MapPath("~/bin"); - string targetPath = new Uri(Assembly.GetExecutingAssembly().Location).LocalPath; - IntPtr pointer = IntPtr.Zero; + // Load the correct method from the native binary module. + // We do it here as on init will cause an UnauthorizedAccessException. + HttpModuleCollection modules = HttpContext.Current.ApplicationInstance.Modules; + ImageProcessorNativeBinaryModule nativeBinaryModule = modules.Get("ImageProcessorNativeBinaryModule") as ImageProcessorNativeBinaryModule; - // Shadow copy the native binaries. - sourcePath = Path.Combine(sourcePath, binary); - targetPath = Path.GetFullPath(Path.Combine(targetPath, "..\\" + binary)); - - File.Copy(sourcePath, targetPath, true); - - try - { - // Load the binary into memory. - pointer = NativeMethods.LoadLibrary(targetPath); - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); - } - - if (pointer == IntPtr.Zero) + if (nativeBinaryModule != null) { - throw new ApplicationException("Cannot open " + binary); + nativeBinaryModule.LoadNativeBinaries(); } } #endregion diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessorNativeBinaryModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessorNativeBinaryModule.cs new file mode 100644 index 000000000..87120a77b --- /dev/null +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessorNativeBinaryModule.cs @@ -0,0 +1,159 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The image processing native binary module. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Web.HttpModules +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Web; + + using ImageProcessor.Web.Helpers; + + /// + /// Controls the loading and unloading of any native binaries required by ImageProcessor.Web. + /// + public sealed class ImageProcessorNativeBinaryModule : IHttpModule + { + /// + /// Whether the process is running in 64bit mode. Used for calling the correct dllimport method. + /// + private static readonly bool Is64Bit = Environment.Is64BitProcess; + + /// + /// The object to lock against. + /// + private static readonly object SyncRoot = new object(); + + /// + /// The native binaries. + /// + private static readonly List NativeBinaries = new List(); + + /// + /// A value indicating whether this instance of the given entity has been disposed. + /// + /// if this instance has been disposed; otherwise, . + /// + /// If the entity is disposed, it must not be disposed a second + /// time. The isDisposed field is set the first time the entity + /// is disposed. If the isDisposed field is true, then the Dispose() + /// method will not dispose again. This help not to prolong the entity's + /// life in the Garbage Collector. + /// + private bool isDisposed; + + /// + /// Disposes of the resources (other than memory) used by the module that implements + /// . + /// + public void Dispose() + { + if (this.isDisposed) + { + return; + } + + // Call the appropriate methods to clean up + // unmanaged resources here. + lock (SyncRoot) + { + this.FreeNativeBinaries(); + } + + // Note disposing is done. + this.isDisposed = true; + } + + /// + /// Initializes a module and prepares it to handle requests. + /// + /// An that provides access to + /// the methods, properties, and events common to all application objects within an ASP.NET application + public void Init(HttpApplication context) + { + } + + /// + /// Loads any native ImageProcessor binaries. + /// + public void LoadNativeBinaries() + { + lock (SyncRoot) + { + this.RegisterNativeBinaries(); + } + } + + /// + /// Registers any native binaries. + /// + /// + /// Thrown when a native binary cannot be loaded. + /// + private void RegisterNativeBinaries() + { + if (NativeBinaries.Any()) + { + return; + } + + string folder = Is64Bit ? "x64" : "x86"; + string sourcePath = HttpContext.Current.Server.MapPath("~/bin/" + folder); + string targetBasePath = new Uri(Assembly.GetExecutingAssembly().Location).LocalPath; + + DirectoryInfo directoryInfo = new DirectoryInfo(sourcePath); + if (directoryInfo.Exists) + { + foreach (FileInfo fileInfo in directoryInfo.EnumerateFiles("*.dll")) + { + if (fileInfo.Name.ToUpperInvariant().StartsWith("IMAGEPROCESSOR")) + { + IntPtr pointer; + string targetPath = Path.GetFullPath(Path.Combine(targetBasePath, "..\\" + folder + "\\" + fileInfo.Name)); + File.Copy(sourcePath, targetPath, true); + + try + { + // Load the binary into memory. + pointer = NativeMethods.LoadLibrary(targetPath); + } + catch (Exception ex) + { + throw new ApplicationException(ex.Message); + } + + if (pointer == IntPtr.Zero) + { + throw new ApplicationException("Cannot load " + fileInfo.Name); + } + + NativeBinaries.Add(pointer); + } + } + } + } + + /// + /// Frees the reference to the native binaries. + /// + private void FreeNativeBinaries() + { + foreach (IntPtr nativeBinary in NativeBinaries) + { + // According to http://stackoverflow.com/a/2445558/427899 you need to call this twice. + NativeMethods.FreeLibrary(nativeBinary); + NativeMethods.FreeLibrary(nativeBinary); + } + } + } +} diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index 40bd16bc7..47bd96a17 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -62,6 +62,7 @@ + diff --git a/src/ImageProcessor.sln.DotSettings b/src/ImageProcessor.sln.DotSettings index 94cb9dbcb..4970d0c6c 100644 --- a/src/ImageProcessor.sln.DotSettings +++ b/src/ImageProcessor.sln.DotSettings @@ -1,4 +1,5 @@  + BGRA BPP DT FPX diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 0e0d276bb..73ac24ef7 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -130,13 +130,14 @@ - + PreserveNewest - + PreserveNewest + + - + From c51dc0014d8481dacc3f7881144883cf0b56df78 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 17 Jul 2014 17:20:38 +0100 Subject: [PATCH 117/155] Removing disposal code. Former-commit-id: 6952c37add20141569f77f9820ac5f4a2ffde853 --- .../NET45/HttpModules/ImageProcessingModule.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index d93f8ab77..c1ee8355e 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -13,7 +13,6 @@ namespace ImageProcessor.Web.HttpModules #region Using using System; using System.Collections.Concurrent; - using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -178,12 +177,6 @@ namespace ImageProcessor.Web.HttpModules if (disposing) { // Dispose of any managed resources here. - foreach (KeyValuePair semaphore in SemaphoreSlims) - { - semaphore.Value.Dispose(); - } - - SemaphoreSlims.Clear(); } // Call the appropriate methods to clean up @@ -385,7 +378,7 @@ namespace ImageProcessor.Web.HttpModules if (isRemote) { SemaphoreSlim semaphore = GetSemaphoreSlim(cachedPath); -#if NET45 +#if NET45 && !__MonoCS__ await semaphore.WaitAsync(); #else semaphore.Wait(); @@ -437,7 +430,7 @@ namespace ImageProcessor.Web.HttpModules else { SemaphoreSlim semaphore = GetSemaphoreSlim(cachedPath); -#if NET45 +#if NET45 && !__MonoCS__ await semaphore.WaitAsync(); #else semaphore.Wait(); From daed9d1ec27812cee5ad01179e64f34cadba4cc1 Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 27 Jul 2014 23:07:11 +0100 Subject: [PATCH 118/155] Adding Linux native dll loading Former-commit-id: b717cc2c643ea66a4ded51211a6efa96217a58dc --- .../Configuration/NativeBinaryFactory.cs | 11 ++++++- .../Configuration/NativeMethods.cs | 28 ++++++++++++++++++ .../images/output/rotate.jpg | Bin 0 -> 26227 bytes 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/ImageProcessorConsole/images/output/rotate.jpg diff --git a/src/ImageProcessor/Configuration/NativeBinaryFactory.cs b/src/ImageProcessor/Configuration/NativeBinaryFactory.cs index 741da61e2..e210aa036 100644 --- a/src/ImageProcessor/Configuration/NativeBinaryFactory.cs +++ b/src/ImageProcessor/Configuration/NativeBinaryFactory.cs @@ -94,7 +94,7 @@ namespace ImageProcessor.Configuration Assembly assembly = Assembly.GetExecutingAssembly(); string targetBasePath = new Uri(assembly.Location).LocalPath; string targetPath = Path.GetFullPath(Path.Combine(targetBasePath, "..\\" + folder + "\\" + name)); - + // Copy the file across if necessary. FileInfo fileInfo = new FileInfo(targetPath); bool rewrite = true; @@ -122,8 +122,13 @@ namespace ImageProcessor.Configuration try { +#if !__MonoCS__ // Load the binary into memory. pointer = NativeMethods.LoadLibrary(targetPath); +#else + // Load the binary into memory. The second parameter forces it to load immediately. + pointer = NativeMethods.dlopen(targetPath, 2); +#endif } catch (Exception ex) { @@ -187,9 +192,13 @@ namespace ImageProcessor.Configuration { IntPtr pointer = nativeBinary.Value; +#if !__MonoCS__ // According to http://stackoverflow.com/a/2445558/427899 you need to call this twice. NativeMethods.FreeLibrary(pointer); NativeMethods.FreeLibrary(pointer); +#else + NativeMethods.dlclose(pointer); +#endif } } } diff --git a/src/ImageProcessor/Configuration/NativeMethods.cs b/src/ImageProcessor/Configuration/NativeMethods.cs index a20b5a86f..6c1ab9805 100644 --- a/src/ImageProcessor/Configuration/NativeMethods.cs +++ b/src/ImageProcessor/Configuration/NativeMethods.cs @@ -40,5 +40,33 @@ namespace ImageProcessor.Configuration /// If the function succeeds, the return value is nonzero; otherwise zero. [DllImport("kernel32", CharSet = CharSet.Auto)] public static extern bool FreeLibrary(IntPtr hModule); + + /// + /// Loads the specified module into the address space of the calling process. + /// The specified module may cause other modules to be loaded. + /// + /// + /// The name of the module. This can be either a library module or + /// an executable module. + /// + /// + /// The flag indicating whether to load the library immediately or lazily. + /// + /// + /// If the function succeeds, the return value is a handle to the module; otherwise null. + /// + [System.Runtime.InteropServices.DllImport("libdl")] + public static extern IntPtr dlopen(string libname, int flags); + + /// + /// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. + /// When the reference count reaches zero, the module is unloaded from the address space of the calling + /// process and the handle is no longer valid. + /// + /// A handle to the loaded library module. + /// The LoadLibrary, LoadLibraryEx, GetModuleHandle, or GetModuleHandleEx function returns this handle. + /// If the function succeeds, the return value is nonzero; otherwise zero. + [System.Runtime.InteropServices.DllImport("libdl")] + public static extern int dlclose(IntPtr hModule); } } diff --git a/src/ImageProcessorConsole/images/output/rotate.jpg b/src/ImageProcessorConsole/images/output/rotate.jpg new file mode 100644 index 0000000000000000000000000000000000000000..45c192cd422f3cd55f26d6228d15f75ffc467851 GIT binary patch literal 26227 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 literal 0 HcmV?d00001 From bebc108ea4cbc922f3c9bd14d2005db685a5bf4f Mon Sep 17 00:00:00 2001 From: Jeavon Leopold Date: Mon, 28 Jul 2014 17:40:38 +0100 Subject: [PATCH 119/155] Fix for #70 - Height and width ratio should round up to nearest pixel Former-commit-id: d7f54db5301d84a633ee50faeddc22973d4203e8 --- src/ImageProcessor.Web/NET45/Processors/Resize.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageProcessor.Web/NET45/Processors/Resize.cs b/src/ImageProcessor.Web/NET45/Processors/Resize.cs index 09ce9bc3c..3c1772911 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Resize.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Resize.cs @@ -205,13 +205,13 @@ namespace ImageProcessor.Web.Processors // Replace 0 width if (size.Width == 0 && size.Height > 0 && input.Contains(WidthRatio) && !input.Contains(HeightRatio)) { - size.Width = (int)(value.ToPositiveFloatArray()[0] * size.Height); + size.Width = (int)Math.Ceiling(value.ToPositiveFloatArray()[0] * size.Height); } // Replace 0 height if (size.Height == 0 && size.Width > 0 && input.Contains(HeightRatio) && !input.Contains(WidthRatio)) { - size.Height = (int)(value.ToPositiveFloatArray()[0] * size.Width); + size.Height = (int)Math.Ceiling(value.ToPositiveFloatArray()[0] * size.Width); } } From 6e0b0b03c7a1396f3901883699e7ca441ab733b8 Mon Sep 17 00:00:00 2001 From: James South Date: Fri, 1 Aug 2014 15:42:50 +0100 Subject: [PATCH 120/155] Fixing virtual directory mapping issue Former-commit-id: 1adc402cdb870e1399e0d8c297268371237aafa2 --- .../NET45/Caching/DiskCache.cs | 77 +++++++++---------- .../HttpModules/ImageProcessingModule.cs | 6 +- 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs index be6b88744..c6300c64d 100644 --- a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs @@ -49,14 +49,14 @@ namespace ImageProcessor.Web.Caching private const int MaxFilesCount = 100; /// - /// The absolute path to virtual cache path on the server. + /// The virtual cache path. /// - private static readonly string AbsoluteCachePath = HostingEnvironment.MapPath(ImageProcessorConfiguration.Instance.VirtualCachePath); + private static readonly string VirtualCachePath = ImageProcessorConfiguration.Instance.VirtualCachePath; /// - /// The request for the image. + /// The absolute path to virtual cache path on the server. /// - private readonly HttpRequest request; + private static readonly string AbsoluteCachePath = HostingEnvironment.MapPath(ImageProcessorConfiguration.Instance.VirtualCachePath); /// /// The request path for the image. @@ -72,15 +72,22 @@ namespace ImageProcessor.Web.Caching /// The image name /// private readonly string imageName; + + /// + /// The physical cached path. + /// + private string physicalCachedPath; + + /// + /// The virtual cached path. + /// + private string virtualCachedPath; #endregion #region Constructors /// /// Initializes a new instance of the class. /// - /// - /// The request for the image. - /// /// /// The request path for the image. /// @@ -90,53 +97,41 @@ namespace ImageProcessor.Web.Caching /// /// The image name. /// - public DiskCache(HttpRequest request, string requestPath, string fullPath, string imageName) + public DiskCache(string requestPath, string fullPath, string imageName) { - this.request = request; this.requestPath = requestPath; this.fullPath = fullPath; this.imageName = imageName; + + // Get the physical and virtual paths. + this.GetCachePaths(); } #endregion - #region Methods - #region Internal /// - /// Gets the full transformed cached path for the image. - /// The images are stored in paths that are based upon the SHA1 of their full request path - /// taking the individual characters of the hash to determine their location. - /// This allows us to store millions of images. + /// Gets the cached path. /// - /// The full cached path for the image. - internal Task GetCachePathAsync() + public string CachedPath { - return TaskHelpers.Run(this.GetCachePath); + get + { + return this.physicalCachedPath; + } } /// - /// Gets the virtual path to the cached processed image. + /// Gets the cached path. /// - /// - /// The path to the cached image. - /// - /// - /// The virtual path to the cached processed image. - /// - internal string GetVirtualCachedPath(string cachedPath) + public string VirtualCachedPath { - string applicationPath = this.request.PhysicalApplicationPath; - string virtualDir = this.request.ApplicationPath; - virtualDir = virtualDir == "/" ? virtualDir : (virtualDir + "/"); - - if (applicationPath != null) + get { - return cachedPath.Replace(applicationPath, virtualDir).Replace(@"\", "/"); + return this.virtualCachedPath; } - - throw new InvalidOperationException( - "We can only map an absolute back to a relative path if the application path is available."); } + #region Methods + #region Internal /// /// Adds an image to the cache. /// @@ -256,15 +251,13 @@ namespace ImageProcessor.Web.Caching } /// - /// Gets the full transformed cached path for the image. + /// Gets the full transformed cached paths for the image. /// The images are stored in paths that are based upon the SHA1 of their full request path /// taking the individual characters of the hash to determine their location. /// This allows us to store millions of images. /// - /// The full cached path for the image. - private string GetCachePath() + private void GetCachePaths() { - string cachedPath = string.Empty; string streamHash = string.Empty; if (AbsoluteCachePath != null) @@ -302,16 +295,16 @@ namespace ImageProcessor.Web.Caching // Collision rate of about 1 in 10000 for the folder structure. string pathFromKey = string.Join("\\", encryptedName.ToCharArray().Take(6)); + string virtualPathFromKey = pathFromKey.Replace(@"\", "/"); string cachedFileName = string.Format( "{0}.{1}", encryptedName, !string.IsNullOrWhiteSpace(parsedExtension) ? parsedExtension.Replace(".", string.Empty) : fallbackExtension); - cachedPath = Path.Combine(AbsoluteCachePath, pathFromKey, cachedFileName); + this.physicalCachedPath = Path.Combine(AbsoluteCachePath, pathFromKey, cachedFileName); + this.virtualCachedPath = Path.Combine(VirtualCachePath, virtualPathFromKey, cachedFileName).Replace(@"\", "/"); } - - return cachedPath; } /// diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index c1ee8355e..0f4db86f3 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -338,15 +338,15 @@ namespace ImageProcessor.Web.HttpModules } // Create a new cache to help process and cache the request. - DiskCache cache = new DiskCache(request, requestPath, fullPath, imageName); - string cachedPath = await cache.GetCachePathAsync(); + DiskCache cache = new DiskCache(requestPath, fullPath, imageName); + string cachedPath = cache.CachedPath; // Since we are now rewriting the path we need to check again that the current user has access // to the rewritten path. // Get the user for the current request // If the user is anonymous or authentication doesn't work for this suffix avoid a NullReferenceException // in the UrlAuthorizationModule by creating a generic identity. - string virtualCachedPath = cache.GetVirtualCachedPath(cachedPath); + string virtualCachedPath = cache.VirtualCachedPath; IPrincipal user = context.User ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]); From 08547cc8213dc98e75cb59eb415ae3dadd98922e Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 4 Aug 2014 15:51:44 +0100 Subject: [PATCH 121/155] Adding AsyncDeDuper Former-commit-id: 30973a9ce646ad5301c4c68fbd66ddb2d37b8f29 --- .../NET4/ImageProcessor.Web_NET4.csproj | 3 + .../NET45/Helpers/AsyncDeDuperLock.cs | 134 ++++++++++++++++++ .../HttpModules/ImageProcessingModule.cs | 40 +----- .../NET45/ImageProcessor.Web_NET45.csproj | 1 + 4 files changed, 144 insertions(+), 34 deletions(-) create mode 100644 src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs diff --git a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj index 82d3986a7..601953a5e 100644 --- a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj +++ b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj @@ -101,6 +101,9 @@ StringExtensions.cs + + AsyncDeDuperLock.cs + CommonParameterParserUtility.cs diff --git a/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs b/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs new file mode 100644 index 000000000..7d6fbf0cd --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs @@ -0,0 +1,134 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Throttles duplicate requests. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace ImageProcessor.Web.Helpers +{ + using System; + using System.Collections.Concurrent; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Throttles duplicate requests. + /// Based loosely on + /// + public sealed class AsyncDeDuperLock + { + /// + /// The semaphore slims. + /// + private static readonly ConcurrentDictionary SemaphoreSlims = new ConcurrentDictionary(); + + /// + /// The lock. + /// + /// + /// The hash. + /// + /// + /// The . + /// + public IDisposable Lock(string key) + { + DisposableScope releaser = new DisposableScope( + key, + s => + { + SemaphoreSlim locker; + if (SemaphoreSlims.TryRemove(s, out locker)) + { + locker.Release(); + locker.Dispose(); + } + }); + + SemaphoreSlim semaphore = SemaphoreSlims.GetOrAdd(key, new SemaphoreSlim(1, 1)); + semaphore.Wait(); + return releaser; + } + +#if NET45 && !__MonoCS__ + /// + /// The lock async. + /// + /// + /// The key. + /// + /// + /// The . + /// + public Task LockAsync(string key) + { + DisposableScope releaser = new DisposableScope( + key, + s => + { + SemaphoreSlim locker; + if (SemaphoreSlims.TryRemove(s, out locker)) + { + locker.Release(); + locker.Dispose(); + } + }); + + Task releaserTask = Task.FromResult(releaser as IDisposable); + SemaphoreSlim semaphore = SemaphoreSlims.GetOrAdd(key, new SemaphoreSlim(1, 1)); + + Task waitTask = semaphore.WaitAsync(); + + return waitTask.IsCompleted + ? releaserTask + : waitTask.ContinueWith( + (_, r) => (IDisposable)r, + releaser, + CancellationToken.None, + TaskContinuationOptions.ExecuteSynchronously, + TaskScheduler.Default); + } +#endif + /// + /// The disposable scope. + /// + internal sealed class DisposableScope : IDisposable + { + /// + /// The key + /// + private readonly string key; + + /// + /// The close scope action. + /// + private readonly Action closeScopeAction; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The key. + /// + /// + /// The close scope action. + /// + public DisposableScope(string key, Action closeScopeAction) + { + this.key = key; + this.closeScopeAction = closeScopeAction; + } + + /// + /// The dispose. + /// + public void Dispose() + { + this.closeScopeAction(this.key); + } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index 0f4db86f3..2fe0a275d 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -12,7 +12,6 @@ namespace ImageProcessor.Web.HttpModules { #region Using using System; - using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -22,7 +21,6 @@ namespace ImageProcessor.Web.HttpModules using System.Security.Permissions; using System.Security.Principal; using System.Text.RegularExpressions; - using System.Threading; using System.Threading.Tasks; using System.Web; using System.Web.Hosting; @@ -56,9 +54,9 @@ namespace ImageProcessor.Web.HttpModules private static readonly string AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); /// - /// The collection of SemaphoreSlims for identifying given locking individual queries. + /// The locker for preventing duplicate requests. /// - private static readonly ConcurrentDictionary SemaphoreSlims = new ConcurrentDictionary(); + private static readonly AsyncDeDuperLock Locker = new AsyncDeDuperLock(); /// /// The value to prefix any remote image requests with to ensure they get captured. @@ -149,20 +147,6 @@ namespace ImageProcessor.Web.HttpModules GC.SuppressFinalize(this); } - /// - /// Gets the specific for the given id. - /// - /// - /// The id representing the . - /// - /// - /// The for the given id. - /// - private static SemaphoreSlim GetSemaphoreSlim(string id) - { - return SemaphoreSlims.GetOrAdd(id, new SemaphoreSlim(1, 1)); - } - /// /// Disposes the object and frees resources for the Garbage Collector. /// @@ -377,13 +361,11 @@ namespace ImageProcessor.Web.HttpModules { if (isRemote) { - SemaphoreSlim semaphore = GetSemaphoreSlim(cachedPath); #if NET45 && !__MonoCS__ - await semaphore.WaitAsync(); + using (await Locker.LockAsync(cachedPath)) #else - semaphore.Wait(); + using (Locker.Lock(cachedPath)) #endif - try { Uri uri = new Uri(requestPath + "?" + urlParameters); RemoteFile remoteFile = new RemoteFile(uri, false); @@ -422,20 +404,14 @@ namespace ImageProcessor.Web.HttpModules } } } - finally - { - semaphore.Release(); - } } else { - SemaphoreSlim semaphore = GetSemaphoreSlim(cachedPath); #if NET45 && !__MonoCS__ - await semaphore.WaitAsync(); + using (await Locker.LockAsync(cachedPath)) #else - semaphore.Wait(); + using (Locker.Lock(cachedPath)) #endif - try { // Check to see if the file exists. // ReSharper disable once AssignNullToNotNullAttribute @@ -460,10 +436,6 @@ namespace ImageProcessor.Web.HttpModules // Trim the cache. await cache.TrimCachedFolderAsync(cachedPath); } - finally - { - semaphore.Release(); - } } } } diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index 40bd16bc7..6d4694400 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -56,6 +56,7 @@ + From 66b09cc3cbc7a7904a618783ee56696795b32ea9 Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 4 Aug 2014 20:40:41 +0100 Subject: [PATCH 122/155] Make DisposalScope private Former-commit-id: 37dfbb252936c81d0b2014fa4e01809564505451 --- src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs b/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs index 7d6fbf0cd..c6896c3a0 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs @@ -23,7 +23,8 @@ namespace ImageProcessor.Web.Helpers /// /// The semaphore slims. /// - private static readonly ConcurrentDictionary SemaphoreSlims = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary SemaphoreSlims + = new ConcurrentDictionary(); /// /// The lock. @@ -79,7 +80,7 @@ namespace ImageProcessor.Web.Helpers Task releaserTask = Task.FromResult(releaser as IDisposable); SemaphoreSlim semaphore = SemaphoreSlims.GetOrAdd(key, new SemaphoreSlim(1, 1)); - + Task waitTask = semaphore.WaitAsync(); return waitTask.IsCompleted @@ -95,7 +96,7 @@ namespace ImageProcessor.Web.Helpers /// /// The disposable scope. /// - internal sealed class DisposableScope : IDisposable + private sealed class DisposableScope : IDisposable { /// /// The key From 9e67f4b9819063352ed0e1ace04a956f973ae865 Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 27 Jul 2014 23:07:11 +0100 Subject: [PATCH 123/155] Adding Linux native dll loading Former-commit-id: bf4c36486c3e3db4883d766162c4cf5c3c32da74 --- .../Configuration/NativeBinaryFactory.cs | 11 ++++++- .../Configuration/NativeMethods.cs | 28 ++++++++++++++++++ .../images/output/rotate.jpg | Bin 0 -> 26227 bytes 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/ImageProcessorConsole/images/output/rotate.jpg diff --git a/src/ImageProcessor/Configuration/NativeBinaryFactory.cs b/src/ImageProcessor/Configuration/NativeBinaryFactory.cs index 741da61e2..e210aa036 100644 --- a/src/ImageProcessor/Configuration/NativeBinaryFactory.cs +++ b/src/ImageProcessor/Configuration/NativeBinaryFactory.cs @@ -94,7 +94,7 @@ namespace ImageProcessor.Configuration Assembly assembly = Assembly.GetExecutingAssembly(); string targetBasePath = new Uri(assembly.Location).LocalPath; string targetPath = Path.GetFullPath(Path.Combine(targetBasePath, "..\\" + folder + "\\" + name)); - + // Copy the file across if necessary. FileInfo fileInfo = new FileInfo(targetPath); bool rewrite = true; @@ -122,8 +122,13 @@ namespace ImageProcessor.Configuration try { +#if !__MonoCS__ // Load the binary into memory. pointer = NativeMethods.LoadLibrary(targetPath); +#else + // Load the binary into memory. The second parameter forces it to load immediately. + pointer = NativeMethods.dlopen(targetPath, 2); +#endif } catch (Exception ex) { @@ -187,9 +192,13 @@ namespace ImageProcessor.Configuration { IntPtr pointer = nativeBinary.Value; +#if !__MonoCS__ // According to http://stackoverflow.com/a/2445558/427899 you need to call this twice. NativeMethods.FreeLibrary(pointer); NativeMethods.FreeLibrary(pointer); +#else + NativeMethods.dlclose(pointer); +#endif } } } diff --git a/src/ImageProcessor/Configuration/NativeMethods.cs b/src/ImageProcessor/Configuration/NativeMethods.cs index a20b5a86f..6c1ab9805 100644 --- a/src/ImageProcessor/Configuration/NativeMethods.cs +++ b/src/ImageProcessor/Configuration/NativeMethods.cs @@ -40,5 +40,33 @@ namespace ImageProcessor.Configuration /// If the function succeeds, the return value is nonzero; otherwise zero. [DllImport("kernel32", CharSet = CharSet.Auto)] public static extern bool FreeLibrary(IntPtr hModule); + + /// + /// Loads the specified module into the address space of the calling process. + /// The specified module may cause other modules to be loaded. + /// + /// + /// The name of the module. This can be either a library module or + /// an executable module. + /// + /// + /// The flag indicating whether to load the library immediately or lazily. + /// + /// + /// If the function succeeds, the return value is a handle to the module; otherwise null. + /// + [System.Runtime.InteropServices.DllImport("libdl")] + public static extern IntPtr dlopen(string libname, int flags); + + /// + /// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. + /// When the reference count reaches zero, the module is unloaded from the address space of the calling + /// process and the handle is no longer valid. + /// + /// A handle to the loaded library module. + /// The LoadLibrary, LoadLibraryEx, GetModuleHandle, or GetModuleHandleEx function returns this handle. + /// If the function succeeds, the return value is nonzero; otherwise zero. + [System.Runtime.InteropServices.DllImport("libdl")] + public static extern int dlclose(IntPtr hModule); } } diff --git a/src/ImageProcessorConsole/images/output/rotate.jpg b/src/ImageProcessorConsole/images/output/rotate.jpg new file mode 100644 index 0000000000000000000000000000000000000000..45c192cd422f3cd55f26d6228d15f75ffc467851 GIT binary patch literal 26227 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 literal 0 HcmV?d00001 From 238374ceeae5335917d589b4c315bc36bd241ef1 Mon Sep 17 00:00:00 2001 From: Jeavon Leopold Date: Mon, 28 Jul 2014 17:40:38 +0100 Subject: [PATCH 124/155] Fix for #70 - Height and width ratio should round up to nearest pixel Former-commit-id: 9d7ccd05efaed9b5d4b15196d8062672b26a2d6e --- src/ImageProcessor.Web/NET45/Processors/Resize.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageProcessor.Web/NET45/Processors/Resize.cs b/src/ImageProcessor.Web/NET45/Processors/Resize.cs index 09ce9bc3c..3c1772911 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Resize.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Resize.cs @@ -205,13 +205,13 @@ namespace ImageProcessor.Web.Processors // Replace 0 width if (size.Width == 0 && size.Height > 0 && input.Contains(WidthRatio) && !input.Contains(HeightRatio)) { - size.Width = (int)(value.ToPositiveFloatArray()[0] * size.Height); + size.Width = (int)Math.Ceiling(value.ToPositiveFloatArray()[0] * size.Height); } // Replace 0 height if (size.Height == 0 && size.Width > 0 && input.Contains(HeightRatio) && !input.Contains(WidthRatio)) { - size.Height = (int)(value.ToPositiveFloatArray()[0] * size.Width); + size.Height = (int)Math.Ceiling(value.ToPositiveFloatArray()[0] * size.Width); } } From 577ffa581389615ef5e7a49baf5533a830241243 Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 4 Aug 2014 15:51:44 +0100 Subject: [PATCH 125/155] Adding AsyncDeDuper Former-commit-id: a5e1f827c161642d6de2b164dcd3224195975ac9 --- .../NET4/ImageProcessor.Web_NET4.csproj | 3 + .../NET45/Helpers/AsyncDeDuperLock.cs | 134 ++++++++++++++++++ .../HttpModules/ImageProcessingModule.cs | 40 +----- .../NET45/ImageProcessor.Web_NET45.csproj | 1 + 4 files changed, 144 insertions(+), 34 deletions(-) create mode 100644 src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs diff --git a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj index 82d3986a7..601953a5e 100644 --- a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj +++ b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj @@ -101,6 +101,9 @@ StringExtensions.cs + + AsyncDeDuperLock.cs + CommonParameterParserUtility.cs diff --git a/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs b/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs new file mode 100644 index 000000000..7d6fbf0cd --- /dev/null +++ b/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs @@ -0,0 +1,134 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Throttles duplicate requests. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace ImageProcessor.Web.Helpers +{ + using System; + using System.Collections.Concurrent; + using System.Threading; + using System.Threading.Tasks; + + /// + /// Throttles duplicate requests. + /// Based loosely on + /// + public sealed class AsyncDeDuperLock + { + /// + /// The semaphore slims. + /// + private static readonly ConcurrentDictionary SemaphoreSlims = new ConcurrentDictionary(); + + /// + /// The lock. + /// + /// + /// The hash. + /// + /// + /// The . + /// + public IDisposable Lock(string key) + { + DisposableScope releaser = new DisposableScope( + key, + s => + { + SemaphoreSlim locker; + if (SemaphoreSlims.TryRemove(s, out locker)) + { + locker.Release(); + locker.Dispose(); + } + }); + + SemaphoreSlim semaphore = SemaphoreSlims.GetOrAdd(key, new SemaphoreSlim(1, 1)); + semaphore.Wait(); + return releaser; + } + +#if NET45 && !__MonoCS__ + /// + /// The lock async. + /// + /// + /// The key. + /// + /// + /// The . + /// + public Task LockAsync(string key) + { + DisposableScope releaser = new DisposableScope( + key, + s => + { + SemaphoreSlim locker; + if (SemaphoreSlims.TryRemove(s, out locker)) + { + locker.Release(); + locker.Dispose(); + } + }); + + Task releaserTask = Task.FromResult(releaser as IDisposable); + SemaphoreSlim semaphore = SemaphoreSlims.GetOrAdd(key, new SemaphoreSlim(1, 1)); + + Task waitTask = semaphore.WaitAsync(); + + return waitTask.IsCompleted + ? releaserTask + : waitTask.ContinueWith( + (_, r) => (IDisposable)r, + releaser, + CancellationToken.None, + TaskContinuationOptions.ExecuteSynchronously, + TaskScheduler.Default); + } +#endif + /// + /// The disposable scope. + /// + internal sealed class DisposableScope : IDisposable + { + /// + /// The key + /// + private readonly string key; + + /// + /// The close scope action. + /// + private readonly Action closeScopeAction; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The key. + /// + /// + /// The close scope action. + /// + public DisposableScope(string key, Action closeScopeAction) + { + this.key = key; + this.closeScopeAction = closeScopeAction; + } + + /// + /// The dispose. + /// + public void Dispose() + { + this.closeScopeAction(this.key); + } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index 0f4db86f3..2fe0a275d 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -12,7 +12,6 @@ namespace ImageProcessor.Web.HttpModules { #region Using using System; - using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -22,7 +21,6 @@ namespace ImageProcessor.Web.HttpModules using System.Security.Permissions; using System.Security.Principal; using System.Text.RegularExpressions; - using System.Threading; using System.Threading.Tasks; using System.Web; using System.Web.Hosting; @@ -56,9 +54,9 @@ namespace ImageProcessor.Web.HttpModules private static readonly string AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); /// - /// The collection of SemaphoreSlims for identifying given locking individual queries. + /// The locker for preventing duplicate requests. /// - private static readonly ConcurrentDictionary SemaphoreSlims = new ConcurrentDictionary(); + private static readonly AsyncDeDuperLock Locker = new AsyncDeDuperLock(); /// /// The value to prefix any remote image requests with to ensure they get captured. @@ -149,20 +147,6 @@ namespace ImageProcessor.Web.HttpModules GC.SuppressFinalize(this); } - /// - /// Gets the specific for the given id. - /// - /// - /// The id representing the . - /// - /// - /// The for the given id. - /// - private static SemaphoreSlim GetSemaphoreSlim(string id) - { - return SemaphoreSlims.GetOrAdd(id, new SemaphoreSlim(1, 1)); - } - /// /// Disposes the object and frees resources for the Garbage Collector. /// @@ -377,13 +361,11 @@ namespace ImageProcessor.Web.HttpModules { if (isRemote) { - SemaphoreSlim semaphore = GetSemaphoreSlim(cachedPath); #if NET45 && !__MonoCS__ - await semaphore.WaitAsync(); + using (await Locker.LockAsync(cachedPath)) #else - semaphore.Wait(); + using (Locker.Lock(cachedPath)) #endif - try { Uri uri = new Uri(requestPath + "?" + urlParameters); RemoteFile remoteFile = new RemoteFile(uri, false); @@ -422,20 +404,14 @@ namespace ImageProcessor.Web.HttpModules } } } - finally - { - semaphore.Release(); - } } else { - SemaphoreSlim semaphore = GetSemaphoreSlim(cachedPath); #if NET45 && !__MonoCS__ - await semaphore.WaitAsync(); + using (await Locker.LockAsync(cachedPath)) #else - semaphore.Wait(); + using (Locker.Lock(cachedPath)) #endif - try { // Check to see if the file exists. // ReSharper disable once AssignNullToNotNullAttribute @@ -460,10 +436,6 @@ namespace ImageProcessor.Web.HttpModules // Trim the cache. await cache.TrimCachedFolderAsync(cachedPath); } - finally - { - semaphore.Release(); - } } } } diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj index 40bd16bc7..6d4694400 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj @@ -56,6 +56,7 @@ + From ac6921b4b6c5139d69f42e4d0f7b490cbaae49fb Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 4 Aug 2014 20:40:41 +0100 Subject: [PATCH 126/155] Make DisposalScope private Former-commit-id: b0d20c38ada344b0d457db7b78a7680366b3e696 --- src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs b/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs index 7d6fbf0cd..c6896c3a0 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs @@ -23,7 +23,8 @@ namespace ImageProcessor.Web.Helpers /// /// The semaphore slims. /// - private static readonly ConcurrentDictionary SemaphoreSlims = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary SemaphoreSlims + = new ConcurrentDictionary(); /// /// The lock. @@ -79,7 +80,7 @@ namespace ImageProcessor.Web.Helpers Task releaserTask = Task.FromResult(releaser as IDisposable); SemaphoreSlim semaphore = SemaphoreSlims.GetOrAdd(key, new SemaphoreSlim(1, 1)); - + Task waitTask = semaphore.WaitAsync(); return waitTask.IsCompleted @@ -95,7 +96,7 @@ namespace ImageProcessor.Web.Helpers /// /// The disposable scope. /// - internal sealed class DisposableScope : IDisposable + private sealed class DisposableScope : IDisposable { /// /// The key From c068dd012423b8f1d451f202abc1aef6f4504069 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 5 Aug 2014 00:28:03 +0100 Subject: [PATCH 127/155] WebP is now a separate plugin Former-commit-id: 072872be821a4ac73038dec5a99de6ae2552a713 --- .../HttpModules/ImageProcessingModule.cs | 41 +++++-- src/ImageProcessor.sln | 17 +++ .../ImageProcessorBootstrapper.cs | 85 ++++++++++++++- src/ImageProcessor/ImageProcessor.csproj | 6 -- .../ImageProcessorConsole.csproj | 4 + .../images/output/4.sm.webp | Bin 0 -> 12162 bytes .../images/output/test.webp | Bin 0 -> 5590 bytes .../ImageProcessor.Plugins.WebP.csproj | 67 ++++++++++++ .../Imaging/Formats/NativeMethods.cs | 6 +- .../Imaging/Formats/WebPFormat.cs | 3 +- .../Properties/AssemblyInfo.cs | 36 +++++++ .../Unmanaged/x64/libwebp.dll.REMOVED.git-id | 0 .../Unmanaged/x86/libwebp.dll.REMOVED.git-id | 0 .../Controllers/HomeController.cs | 5 + .../Test_Website_MVC_NET45.csproj | 7 ++ .../Test_Website_NET45/Views/Home/WebP.cshtml | 100 ++++++++++++++++++ .../Views/Shared/_Layout.cshtml | 1 + 17 files changed, 355 insertions(+), 23 deletions(-) create mode 100644 src/ImageProcessorConsole/images/output/4.sm.webp create mode 100644 src/ImageProcessorConsole/images/output/test.webp create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/ImageProcessor.Plugins.WebP.csproj rename src/{ImageProcessor => Plugins/ImageProcessor/ImageProcessor.Plugins.WebP}/Imaging/Formats/NativeMethods.cs (96%) rename src/{ImageProcessor => Plugins/ImageProcessor/ImageProcessor.Plugins.WebP}/Imaging/Formats/WebPFormat.cs (98%) create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs rename src/{ImageProcessor => Plugins/ImageProcessor/ImageProcessor.Plugins.WebP}/Resources/Unmanaged/x64/libwebp.dll.REMOVED.git-id (100%) rename src/{ImageProcessor => Plugins/ImageProcessor/ImageProcessor.Plugins.WebP}/Resources/Unmanaged/x86/libwebp.dll.REMOVED.git-id (100%) create mode 100644 src/TestWebsites/NET45/Test_Website_NET45/Views/Home/WebP.cshtml diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs index 2fe0a275d..d7b15e7e1 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs @@ -43,6 +43,11 @@ namespace ImageProcessor.Web.HttpModules /// private const string CachedResponseTypeKey = "CACHED_IMAGE_RESPONSE_TYPE_054F217C-11CF-49FF-8D2F-698E8E6EB58F"; + /// + /// The key for storing the file dependency of the current image. + /// + private const string CachedResponseFileDependency = "CACHED_IMAGE_DEPENDENCY_054F217C-11CF-49FF-8D2F-698E8E6EB58F"; + /// /// The regular expression to search strings for. /// @@ -215,15 +220,18 @@ namespace ImageProcessor.Web.HttpModules HttpContext context = ((HttpApplication)sender).Context; object responseTypeObject = context.Items[CachedResponseTypeKey]; + object dependencyFileObject = context.Items[CachedResponseFileDependency]; - if (responseTypeObject != null) + if (responseTypeObject != null && dependencyFileObject != null) { string responseType = (string)responseTypeObject; + string dependencyFile = (string)dependencyFileObject; // Set the headers - this.SetHeaders(context, responseType); + this.SetHeaders(context, responseType, dependencyFile); context.Items[CachedResponseTypeKey] = null; + context.Items[CachedResponseFileDependency] = null; } } @@ -440,7 +448,15 @@ namespace ImageProcessor.Web.HttpModules } } - string incomingEtag = context.Request.Headers["If-None-Match"]; + // Image is from the cache so the mime-type will need to be set. + if (context.Items[CachedResponseTypeKey] == null) + { + context.Items[CachedResponseTypeKey] = ImageHelpers.GetExtension(cachedPath).Replace(".", "image/"); + } + + context.Items[CachedResponseFileDependency] = cachedPath; + + string incomingEtag = context.Request.Headers["If" + "-None-Match"]; if (incomingEtag != null && !isNewOrUpdated) { @@ -449,8 +465,7 @@ namespace ImageProcessor.Web.HttpModules context.Response.AddHeader("Content-Length", "0"); context.Response.StatusCode = (int)HttpStatusCode.NotModified; context.Response.SuppressContent = true; - context.Response.AddFileDependency(context.Server.MapPath(virtualCachedPath)); - this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey]); + this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey], cachedPath); if (!isRemote) { @@ -482,18 +497,28 @@ namespace ImageProcessor.Web.HttpModules /// the HttpContext object that provides /// references to the intrinsic server objects /// - /// The HTTP MIME type to to send. - private void SetHeaders(HttpContext context, string responseType) + /// + /// The HTTP MIME type to to send. + /// + /// + /// The dependency path for the cache dependency. + /// + private void SetHeaders(HttpContext context, string responseType, string dependencyPath) { HttpResponse response = context.Response; response.ContentType = responseType; - response.AddHeader("Image-Served-By", "ImageProcessor.Web/" + AssemblyVersion); + if (response.Headers["Image-Served-By"] == null) + { + response.AddHeader("Image-Served-By", "ImageProcessor.Web/" + AssemblyVersion); + } HttpCachePolicy cache = response.Cache; cache.SetCacheability(HttpCacheability.Public); cache.VaryByHeaders["Accept-Encoding"] = true; + + context.Response.AddFileDependency(dependencyPath); cache.SetLastModifiedFromFileDependencies(); int maxDays = DiskCache.MaxFileCachedDuration; diff --git a/src/ImageProcessor.sln b/src/ImageProcessor.sln index a12d17c68..8ad0ed4e9 100644 --- a/src/ImageProcessor.sln +++ b/src/ImageProcessor.sln @@ -36,6 +36,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web.UnitTest EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.UnitTests", "ImageProcessor.UnitTests\ImageProcessor.UnitTests.csproj", "{633B1C4C-4823-47BE-9A01-A665F3118C8C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Plugins.WebP", "Plugins\ImageProcessor\ImageProcessor.Plugins.WebP\ImageProcessor.Plugins.WebP.csproj", "{2CF69699-959A-44DC-A281-4E2596C25043}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Any CPU = All|Any CPU @@ -201,6 +203,21 @@ Global {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Mixed Platforms.Build.0 = Release|Any CPU {633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|x86.ActiveCfg = Release|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.All|Any CPU.ActiveCfg = Release|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.All|Any CPU.Build.0 = Release|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.All|Mixed Platforms.ActiveCfg = Release|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.All|Mixed Platforms.Build.0 = Release|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.All|x86.ActiveCfg = Release|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.Debug|x86.ActiveCfg = Debug|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.Release|Any CPU.Build.0 = Release|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2CF69699-959A-44DC-A281-4E2596C25043}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs index 09b772455..59f975fb3 100644 --- a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs +++ b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs @@ -4,22 +4,25 @@ // Licensed under the Apache License, Version 2.0. // // -// The image processor bootstrapper. +// The ImageProcessor bootstrapper. // // -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Configuration { using System; + using System.Collections; using System.Collections.Generic; + using System.IO; using System.Linq; + using System.Reflection; using ImageProcessor.Common.Exceptions; using ImageProcessor.Common.Extensions; using ImageProcessor.Imaging.Formats; /// - /// The image processor bootstrapper. + /// The ImageProcessor bootstrapper. /// public class ImageProcessorBootstrapper { @@ -35,8 +38,8 @@ namespace ImageProcessor.Configuration /// private ImageProcessorBootstrapper() { - this.LoadSupportedImageFormats(); this.NativeBinaryFactory = new NativeBinaryFactory(); + this.LoadSupportedImageFormats(); } /// @@ -70,14 +73,42 @@ namespace ImageProcessor.Configuration try { Type type = typeof(ISupportedImageFormat); + HashSet found = new HashSet(); + + // Get any references and used assemblies. + foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + this.LoadReferencedAssemblies(found, assembly); + } + + // Get any referenced but not used assemblies. + Assembly executingAssembly = Assembly.GetExecutingAssembly(); + string targetBasePath = Path.GetDirectoryName(new Uri(executingAssembly.Location).LocalPath); + + // ReSharper disable once AssignNullToNotNullAttribute + FileInfo[] files = new DirectoryInfo(targetBasePath).GetFiles("*.dll", SearchOption.AllDirectories); + + foreach (FileInfo fileInfo in files) + { + AssemblyName assemblyName = AssemblyName.GetAssemblyName(fileInfo.FullName); + + if (!AppDomain.CurrentDomain.GetAssemblies() + .Any(a => AssemblyName.ReferenceMatchesDefinition(assemblyName, a.GetName()))) + { + // In a web app, this assembly will automatically be bound from the + // Asp.Net Temporary folder from where the site actually runs. + this.LoadReferencedAssemblies(found, Assembly.Load(assemblyName)); + } + } + List availableTypes = AppDomain.CurrentDomain .GetAssemblies() - .SelectMany(s => s.GetLoadableTypes()) + .SelectMany(a => a.GetLoadableTypes()) .Where(t => type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract) .ToList(); this.SupportedImageFormats = availableTypes - .Select(x => (Activator.CreateInstance(x) as ISupportedImageFormat)).ToList(); + .Select(f => (Activator.CreateInstance(f) as ISupportedImageFormat)).ToList(); } catch (Exception ex) { @@ -85,5 +116,49 @@ namespace ImageProcessor.Configuration } } } + + /// + /// Loads any referenced assemblies into the current application domain. + /// + /// + /// The collection containing the name of already found assemblies. + /// + /// + /// The assembly to load from. + /// + private void LoadReferencedAssemblies(HashSet found, Assembly assembly) + { + // Used to avoid duplicates + ArrayList results = new ArrayList(); + + // Resulting info + Stack stack = new Stack(); + + // Stack of names + // Store root assembly (level 0) directly into results list + stack.Push(assembly.ToString()); + + // Do a preorder, non-recursive traversal + while (stack.Count > 0) + { + string info = (string)stack.Pop(); + + // Get next assembly + if (!found.Contains(info)) + { + found.Add(info); + results.Add(info); + + // Store it to results ArrayList + Assembly child = Assembly.Load(info); + AssemblyName[] subchild = child.GetReferencedAssemblies(); + + for (int i = subchild.Length - 1; i >= 0; --i) + { + stack.Push(subchild[i].ToString()); + } + } + } + } } } diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index ad69d127b..ed1aa9c64 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -79,7 +79,6 @@ - @@ -87,7 +86,6 @@ - @@ -131,10 +129,6 @@ - - - - diff --git a/src/ImageProcessorConsole/ImageProcessorConsole.csproj b/src/ImageProcessorConsole/ImageProcessorConsole.csproj index fba366b0c..1afd8ef0e 100644 --- a/src/ImageProcessorConsole/ImageProcessorConsole.csproj +++ b/src/ImageProcessorConsole/ImageProcessorConsole.csproj @@ -56,6 +56,10 @@ {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} ImageProcessor + + {2cf69699-959a-44dc-a281-4e2596c25043} + ImageProcessor.Plugins.WebP + + \ No newline at end of file diff --git a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/NativeMethods.cs similarity index 96% rename from src/ImageProcessor/Imaging/Formats/NativeMethods.cs rename to src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/NativeMethods.cs index 0c42710b0..936b58256 100644 --- a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/NativeMethods.cs @@ -8,7 +8,7 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Imaging.Formats +namespace ImageProcessor.Plugins.WebP.Imaging.Formats { using System; using System.IO; @@ -23,7 +23,7 @@ namespace ImageProcessor.Imaging.Formats internal static class NativeMethods { /// - /// Whether the process is running in 64bit mode. Used for calling the correct dllimport method. + /// Whether the process is running in 64bit mode. Used for calling the correct method. /// Clunky I know but I couldn't get dynamic methods to work. /// private static readonly bool Is64Bit = Environment.Is64BitProcess; @@ -34,7 +34,7 @@ namespace ImageProcessor.Imaging.Formats static NativeMethods() { string folder = Is64Bit ? "x64" : "x86"; - string name = string.Format("ImageProcessor.Resources.Unmanaged.{0}.libwebp.dll", folder); + string name = string.Format("ImageProcessor.Plugins.WebP.Resources.Unmanaged.{0}.libwebp.dll", folder); Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name); using (MemoryStream memoryStream = new MemoryStream()) diff --git a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/WebPFormat.cs similarity index 98% rename from src/ImageProcessor/Imaging/Formats/WebPFormat.cs rename to src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/WebPFormat.cs index 9f350c5c0..0bc2e2b7b 100644 --- a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/WebPFormat.cs @@ -10,7 +10,7 @@ // // -------------------------------------------------------------------------------------------------------------------- -namespace ImageProcessor.Imaging.Formats +namespace ImageProcessor.Plugins.WebP.Imaging.Formats { using System; using System.Collections.Generic; @@ -22,6 +22,7 @@ namespace ImageProcessor.Imaging.Formats using System.Text; using ImageProcessor.Common.Exceptions; + using ImageProcessor.Imaging.Formats; /// /// Provides the necessary information to support webp images. diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..d9aa6f985 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ImageProcessor.Plugins.WebP")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("James South")] +[assembly: AssemblyProduct("ImageProcessor.Plugins.WebP")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("bf160db5-2ea7-4c85-9b0e-f1ddf2595e37")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// 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.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/ImageProcessor/Resources/Unmanaged/x64/libwebp.dll.REMOVED.git-id b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x64/libwebp.dll.REMOVED.git-id similarity index 100% rename from src/ImageProcessor/Resources/Unmanaged/x64/libwebp.dll.REMOVED.git-id rename to src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x64/libwebp.dll.REMOVED.git-id diff --git a/src/ImageProcessor/Resources/Unmanaged/x86/libwebp.dll.REMOVED.git-id b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x86/libwebp.dll.REMOVED.git-id similarity index 100% rename from src/ImageProcessor/Resources/Unmanaged/x86/libwebp.dll.REMOVED.git-id rename to src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x86/libwebp.dll.REMOVED.git-id diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Controllers/HomeController.cs b/src/TestWebsites/NET45/Test_Website_NET45/Controllers/HomeController.cs index 02fc35575..1eae92d44 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/Controllers/HomeController.cs +++ b/src/TestWebsites/NET45/Test_Website_NET45/Controllers/HomeController.cs @@ -41,6 +41,11 @@ namespace Test_Website_NET45.Controllers return View(); } + public ActionResult WebP() + { + return View(); + } + public ActionResult External() { return this.View(); diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj b/src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj index 96f09d69b..c2118914f 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj +++ b/src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj @@ -159,6 +159,10 @@ {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} ImageProcessor + + {2cf69699-959a-44dc-a281-4e2596c25043} + ImageProcessor.Plugins.WebP + @@ -191,6 +195,9 @@ + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/WebP.cshtml b/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/WebP.cshtml new file mode 100644 index 000000000..ff03d1240 --- /dev/null +++ b/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/WebP.cshtml @@ -0,0 +1,100 @@ +@{ + ViewBag.Title = "WebP"; +} + +
+

WebP

+
+
+
+

Resized

+ +
+
+

Cropped

+ +
+
+
+
+

Filter

+
+
+

blackwhite

+ +
+
+

comic

+ +
+
+
+
+

lomograph

+ +
+
+

greyscale

+ +
+
+
+
+

polaroid

+ +
+
+

sepia

+ +
+
+
+
+

gotham

+ +
+
+

hisatch

+ +
+
+
+
+

losatch

+ +
+
+
+
+
+
+

Watermark

+ +
+
+

Format

+ +
+
+
+
+
+
+

Rotate

+ +
+
+

Quality

+ +
+
+
+
+
+
+

Alpha

+ +
+
+
+
diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Shared/_Layout.cshtml b/src/TestWebsites/NET45/Test_Website_NET45/Views/Shared/_Layout.cshtml index 74af019a2..5f8255ea4 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/Views/Shared/_Layout.cshtml +++ b/src/TestWebsites/NET45/Test_Website_NET45/Views/Shared/_Layout.cshtml @@ -29,6 +29,7 @@
  • @Html.ActionLink("Png8", "Png8")
  • @Html.ActionLink("Bmp", "Bmp")
  • @Html.ActionLink("Tiff", "Tiff")
  • +
  • @Html.ActionLink("WebP", "WebP")
  • @Html.ActionLink("External", "External")
  • From 98b68b1ac8c38d41acc31af3976b71d66a0a42f1 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 5 Aug 2014 13:32:14 +0100 Subject: [PATCH 128/155] Fix dll load plus regex tests Former-commit-id: 2778a682ce325c1739e49f1e88ab7c5a8fa9f431 --- .../Extensions/DoubleExtensionsUnitTests.cs | 36 +--- .../ImageProcessor.Web.UnitTests.csproj | 4 + .../RegularExpressionUnitTests.cs | 201 +++++++++++++----- .../Helpers/CommonParameterParserUtility.cs | 2 +- .../ImageProcessorBootstrapper.cs | 8 +- 5 files changed, 161 insertions(+), 90 deletions(-) diff --git a/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs index cba1c07bc..91b62d74f 100644 --- a/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs +++ b/src/ImageProcessor.UnitTests/Extensions/DoubleExtensionsUnitTests.cs @@ -10,7 +10,6 @@ namespace ImageProcessor.UnitTests.Extensions { - using System.Collections.Generic; using Common.Extensions; using NUnit.Framework; @@ -20,37 +19,20 @@ namespace ImageProcessor.UnitTests.Extensions [TestFixture] public class DoubleExtensionsUnitTests { - /// - /// Stores the values to test for the ToByte() extension method - /// - private Dictionary doubleToByteTests; - - /// - /// Sets up the values for the tests - /// - [TestFixtureSetUp] - public void Init() - { - this.doubleToByteTests = new Dictionary - { - { -10, 0x0 }, - { 1.5, 0x1 }, - { 25.7, 0x19 }, - { 1289047, 0xFF } - }; - } - /// /// Tests the double to byte conversion /// + /// Double input + /// Expected result [Test] - public void TestDoubleToByte() + [TestCase(-10, 0x0)] + [TestCase(1.5, 0x1)] + [TestCase(25.7, 0x19)] + [TestCase(1289047, 0xFF)] + public void TestDoubleToByte(double input, byte expected) { - foreach (var item in this.doubleToByteTests) - { - var result = item.Key.ToByte(); - Assert.AreEqual(item.Value, result); - } + byte result = input.ToByte(); + Assert.AreEqual(expected, result); } } } \ No newline at end of file diff --git a/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj index 460e329b9..357f3b11d 100644 --- a/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj +++ b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj @@ -69,6 +69,10 @@ {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} ImageProcessor + + {2cf69699-959a-44dc-a281-4e2596c25043} + ImageProcessor.Plugins.WebP +
    diff --git a/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs index c41454563..86c346e38 100644 --- a/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs +++ b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs @@ -10,10 +10,14 @@ namespace ImageProcessor.Web.UnitTests { + using System; + using System.Collections.Generic; using System.Drawing; using ImageProcessor.Imaging; using ImageProcessor.Imaging.Filters; using ImageProcessor.Imaging.Formats; + using ImageProcessor.Plugins.WebP.Imaging.Formats; + using NUnit.Framework; ///
    @@ -40,37 +44,55 @@ namespace ImageProcessor.Web.UnitTests } /// - /// The brightness regex unit test. + /// The contrast regex unit test. /// + /// + /// The input string. + /// + /// + /// The expected result. + /// [Test] - public void TestBrightnessRegex() + [TestCase("brightness=56", 56)] + [TestCase("brightness=84", 84)] + [TestCase("brightness=66", 66)] + [TestCase("brightness=101", 1)] + [TestCase("brightness=00001", 1)] + [TestCase("brightness=-50", -50)] + [TestCase("brightness=0", 0)] + public void TestBrightnesstRegex(string input, int expected) { - const string Querystring = "brightness=56"; - const int Expected = 56; - Processors.Brightness brightness = new Processors.Brightness(); - brightness.MatchRegexIndex(Querystring); + brightness.MatchRegexIndex(input); + int result = brightness.Processor.DynamicParameter; - int actual = brightness.Processor.DynamicParameter; - - Assert.AreEqual(Expected, actual); + Assert.AreEqual(expected, result); } /// /// The contrast regex unit test. /// + /// + /// The input string. + /// + /// + /// The expected result. + /// [Test] - public void TestContrastRegex() + [TestCase("contrast=56", 56)] + [TestCase("contrast=84", 84)] + [TestCase("contrast=66", 66)] + [TestCase("contrast=101", 1)] + [TestCase("contrast=00001", 1)] + [TestCase("contrast=-50", -50)] + [TestCase("contrast=0", 0)] + public void TestContrastRegex(string input, int expected) { - const string Querystring = "contrast=56"; - const int Expected = 56; - Processors.Contrast contrast = new Processors.Contrast(); - contrast.MatchRegexIndex(Querystring); - - int actual = contrast.Processor.DynamicParameter; + contrast.MatchRegexIndex(input); + int result = contrast.Processor.DynamicParameter; - Assert.AreEqual(Expected, actual); + Assert.AreEqual(expected, result); } /// @@ -93,52 +115,102 @@ namespace ImageProcessor.Web.UnitTests /// The filter regex unit test. /// [Test] + public void TestFilterRegex() { - // Should really write more for the other filters. - const string Querystring = "filter=lomograph"; - IMatrixFilter expected = MatrixFilters.Lomograph; + Dictionary data = new Dictionary + { + { + "filter=lomograph", MatrixFilters.Lomograph + }, + { + "filter=polaroid", MatrixFilters.Polaroid + }, + { + "filter=comic", MatrixFilters.Comic + }, + { + "filter=greyscale", MatrixFilters.GreyScale + }, + { + "filter=blackwhite", MatrixFilters.BlackWhite + }, + { + "filter=invert", MatrixFilters.Invert + }, + { + "filter=gotham", MatrixFilters.Gotham + }, + { + "filter=hisatch", MatrixFilters.HiSatch + }, + { + "filter=losatch", MatrixFilters.LoSatch + }, + { + "filter=sepia", MatrixFilters.Sepia + } + }; Processors.Filter filter = new Processors.Filter(); - filter.MatchRegexIndex(Querystring); - - IMatrixFilter actual = filter.Processor.DynamicParameter; - - Assert.AreEqual(expected, actual); + foreach (KeyValuePair item in data) + { + filter.MatchRegexIndex(item.Key); + IMatrixFilter result = filter.Processor.DynamicParameter; + Assert.AreEqual(item.Value, result); + } } /// /// The format regex unit test. /// + /// + /// The input querystring. + /// + /// + /// The expected type. + /// [Test] - public void TestFormatRegex() + [TestCase("format=bmp", typeof(BitmapFormat))] + [TestCase("format=png", typeof(PngFormat))] + [TestCase("format=png8", typeof(PngFormat))] + [TestCase("format=jpeg", typeof(JpegFormat))] + [TestCase("format=jpg", typeof(JpegFormat))] + [TestCase("format=gif", typeof(GifFormat))] + [TestCase("format=webp", typeof(WebPFormat))] + public void TestFormatRegex(string input, Type expected) { - const string Querystring = "format=gif"; - ISupportedImageFormat expected = new GifFormat(); - Processors.Format format = new Processors.Format(); - format.MatchRegexIndex(Querystring); - - ISupportedImageFormat actual = format.Processor.DynamicParameter; + format.MatchRegexIndex(input); + Type result = format.Processor.DynamicParameter.GetType(); - Assert.AreEqual(expected, actual); + Assert.AreEqual(expected, result); } /// /// The quality regex unit test. /// + /// + /// The input. + /// + /// + /// The expected result. + /// [Test] - public void TestQualityRegex() + [TestCase("quality=56", 56)] + [TestCase("quality=84", 84)] + [TestCase("quality=66", 66)] + [TestCase("quality=101", 1)] + [TestCase("quality=00001", 1)] + [TestCase("quality=-50", 50)] + [TestCase("quality=0", 0)] + public void TestQualityRegex(string input, int expected) { - const string Querystring = "quality=56"; - const int Expected = 56; - Processors.Quality quality = new Processors.Quality(); - quality.MatchRegexIndex(Querystring); - - int actual = quality.Processor.DynamicParameter; + quality.MatchRegexIndex(input); + int result = quality.Processor.DynamicParameter; - Assert.AreEqual(Expected, actual); + Assert.AreEqual(expected, result); } /// @@ -161,18 +233,25 @@ namespace ImageProcessor.Web.UnitTests /// /// The rotate regex unit test. /// + /// + /// The input string. + /// + /// + /// The expected result. + /// [Test] - public void TestRotateRegex() + [TestCase("rotate=0", 0)] + [TestCase("rotate=270", 270)] + [TestCase("rotate=-270", 0)] + [TestCase("rotate=angle-28", 28)] + public void TestRotateRegex(string input, int expected) { - const string Querystring = "rotate=270"; - const int Expected = 270; - Processors.Rotate rotate = new Processors.Rotate(); - rotate.MatchRegexIndex(Querystring); + rotate.MatchRegexIndex(input); - int actual = rotate.Processor.DynamicParameter; + int result = rotate.Processor.DynamicParameter; - Assert.AreEqual(Expected, actual); + Assert.AreEqual(expected, result); } /// @@ -181,14 +260,26 @@ namespace ImageProcessor.Web.UnitTests [Test] public void TestRoundedCornersRegex() { - const string Querystring = "roundedcorners=30"; - RoundedCornerLayer expected = new RoundedCornerLayer(30, true, true, true, true); - Processors.RoundedCorners roundedCorners = new Processors.RoundedCorners(); - roundedCorners.MatchRegexIndex(Querystring); + Dictionary data = new Dictionary + { + { + "roundedcorners=30", new RoundedCornerLayer(30, true, true, true, true) + }, + { + "roundedcorners=radius-26|tl-true|tr-false|bl-true|br-false", new RoundedCornerLayer(26, true, false, true, false) + }, + { + "roundedcorners=26,tl=true,tr=false,bl=true,br=false", new RoundedCornerLayer(26, true, false, true, false) + } + }; - RoundedCornerLayer actual = roundedCorners.Processor.DynamicParameter; - - Assert.AreEqual(expected, actual); + Processors.RoundedCorners roundedCorners = new Processors.RoundedCorners(); + foreach (KeyValuePair item in data) + { + roundedCorners.MatchRegexIndex(item.Key); + RoundedCornerLayer result = roundedCorners.Processor.DynamicParameter; + Assert.AreEqual(item.Value, result); + } } /// diff --git a/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs b/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs index 505d80d99..22c266a85 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs @@ -37,7 +37,7 @@ namespace ImageProcessor.Web.Helpers /// /// The regular expression to search strings for values between 1 and 100. /// - private static readonly Regex In100RangeRegex = new Regex(@"(-?(?:100)|-?([1-9]?[0-9]))", RegexOptions.Compiled); + private static readonly Regex In100RangeRegex = new Regex(@"(-?(0*(?:[1-9][0-9]?|100)))", RegexOptions.Compiled); /// /// The sharpen regex. diff --git a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs index 59f975fb3..4cffe51eb 100644 --- a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs +++ b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs @@ -73,13 +73,6 @@ namespace ImageProcessor.Configuration try { Type type = typeof(ISupportedImageFormat); - HashSet found = new HashSet(); - - // Get any references and used assemblies. - foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - this.LoadReferencedAssemblies(found, assembly); - } // Get any referenced but not used assemblies. Assembly executingAssembly = Assembly.GetExecutingAssembly(); @@ -88,6 +81,7 @@ namespace ImageProcessor.Configuration // ReSharper disable once AssignNullToNotNullAttribute FileInfo[] files = new DirectoryInfo(targetBasePath).GetFiles("*.dll", SearchOption.AllDirectories); + HashSet found = new HashSet(); foreach (FileInfo fileInfo in files) { AssemblyName assemblyName = AssemblyName.GetAssemblyName(fileInfo.FullName); From 72a3e8eed8b78351bdf607c6c453158e30622cb7 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 5 Aug 2014 14:43:07 +0100 Subject: [PATCH 129/155] Moar tests plus known colours! Former-commit-id: 38f02083c8cae1bf549c0863c4842e196a0b90f5 --- .../RegularExpressionUnitTests.cs | 82 ++++++++++++++----- .../Helpers/CommonParameterParserUtility.cs | 42 +++++++++- .../NET45/Processors/Format.cs | 1 - 3 files changed, 103 insertions(+), 22 deletions(-) diff --git a/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs index 86c346e38..db81f4533 100644 --- a/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs +++ b/src/ImageProcessor.Web.UnitTests/RegularExpressionUnitTests.cs @@ -29,18 +29,25 @@ namespace ImageProcessor.Web.UnitTests /// /// The alpha regex unit test. /// + /// + /// The input string. + /// + /// + /// The expected result. + /// [Test] - public void TestAlphaRegex() + [TestCase("alpha=66", 66)] + [TestCase("alpha=-66", 66)] + [TestCase("alpha=101", 1)] + [TestCase("alpha=-101", 1)] + [TestCase("alpha=000053", 53)] + public void TestAlphaRegex(string input, int expected) { - const string Querystring = "alpha=56"; - const int Expected = 56; - Processors.Alpha alpha = new Processors.Alpha(); - alpha.MatchRegexIndex(Querystring); - - int actual = alpha.Processor.DynamicParameter; + alpha.MatchRegexIndex(input); + int result = alpha.Processor.DynamicParameter; - Assert.AreEqual(Expected, actual); + Assert.AreEqual(expected, result); } /// @@ -95,6 +102,32 @@ namespace ImageProcessor.Web.UnitTests Assert.AreEqual(expected, result); } + /// + /// The saturation regex unit test. + /// + /// + /// The input string. + /// + /// + /// The expected result. + /// + [Test] + [TestCase("saturation=56", 56)] + [TestCase("saturation=84", 84)] + [TestCase("saturation=66", 66)] + [TestCase("saturation=101", 1)] + [TestCase("saturation=00001", 1)] + [TestCase("saturation=-50", -50)] + [TestCase("saturation=0", 0)] + public void TestSaturationRegex(string input, int expected) + { + Processors.Saturation saturation = new Processors.Saturation(); + saturation.MatchRegexIndex(input); + int result = saturation.Processor.DynamicParameter; + + Assert.AreEqual(expected, result); + } + /// /// The rotate regex unit test. /// @@ -288,20 +321,29 @@ namespace ImageProcessor.Web.UnitTests [Test] public void TestTintRegex() { - const string HexQuerystring = "tint=6aa6cc"; - const string RgbaQuerystring = "tint=106,166,204,255"; - Color expectedHex = ColorTranslator.FromHtml("#" + "6aa6cc"); - Color expectedRgba = Color.FromArgb(255, 106, 166, 204); + Dictionary data = new Dictionary + { + { + "tint=6aa6cc", ColorTranslator.FromHtml("#" + "6aa6cc") + }, + { + "tint=106,166,204,255", Color.FromArgb(255, 106, 166, 204) + }, + { + "tint=fff", Color.FromArgb(255, 255, 255, 255) + }, + { + "tint=white", Color.White + } + }; Processors.Tint tint = new Processors.Tint(); - tint.MatchRegexIndex(HexQuerystring); - Color actualHex = tint.Processor.DynamicParameter; - Assert.AreEqual(expectedHex, actualHex); - - tint = new Processors.Tint(); - tint.MatchRegexIndex(RgbaQuerystring); - Color actualRgba = tint.Processor.DynamicParameter; - Assert.AreEqual(expectedRgba, actualRgba); + foreach (KeyValuePair item in data) + { + tint.MatchRegexIndex(item.Key); + Color result = tint.Processor.DynamicParameter; + Assert.AreEqual(item.Value, result); + } } } } \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs b/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs index 22c266a85..3e8362d08 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs +++ b/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs @@ -11,8 +11,10 @@ namespace ImageProcessor.Web.Helpers { using System; + using System.Collections.Generic; using System.Drawing; using System.Globalization; + using System.Text; using System.Text.RegularExpressions; using ImageProcessor.Common.Extensions; @@ -24,10 +26,15 @@ namespace ImageProcessor.Web.Helpers /// public static class CommonParameterParserUtility { + /// + /// The collection of known colors. + /// + private static readonly Dictionary KnownColors = new Dictionary(); + /// /// The regular expression to search strings for colors. /// - private static readonly Regex ColorRegex = new Regex(@"(bgcolor|color|tint|vignette)(=|-)(\d+,\d+,\d+,\d+|([0-9a-fA-F]{3}){1,2})", RegexOptions.Compiled); + private static readonly Regex ColorRegex = BuildColorRegex(); /// /// The regular expression to search strings for angles. @@ -93,6 +100,11 @@ namespace ImageProcessor.Web.Helpers { string value = match.Value.Split(new[] { '=', '-' })[1]; + if (KnownColors.ContainsKey(value)) + { + return Color.FromKnownColor(KnownColors[value]); + } + if (value.Contains(",")) { int[] split = value.ToPositiveIntegerArray(); @@ -224,5 +236,33 @@ namespace ImageProcessor.Web.Helpers return 0; } + + /// + /// Builds a regular expression for the three main colour types. + /// + /// + /// The to match colors. + /// + private static Regex BuildColorRegex() + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(@"(bgcolor|color|tint|vignette)(=|-)(\d+,\d+,\d+,\d+|([0-9a-fA-F]{3}){1,2}|("); + + KnownColor[] knownColors = (KnownColor[])Enum.GetValues(typeof(KnownColor)); + + for (int i = 0; i < knownColors.Length; i++) + { + KnownColor knownColor = knownColors[i]; + string name = knownColor.ToString().ToLowerInvariant(); + + KnownColors.Add(name, knownColor); + + stringBuilder.Append(i > 0 ? "|" + name : name); + } + + stringBuilder.Append("))"); + + return new Regex(stringBuilder.ToString(), RegexOptions.IgnoreCase); + } } } diff --git a/src/ImageProcessor.Web/NET45/Processors/Format.cs b/src/ImageProcessor.Web/NET45/Processors/Format.cs index b419f211f..7b57d7ddd 100644 --- a/src/ImageProcessor.Web/NET45/Processors/Format.cs +++ b/src/ImageProcessor.Web/NET45/Processors/Format.cs @@ -15,7 +15,6 @@ namespace ImageProcessor.Web.Processors using System.Linq; using System.Text; using System.Text.RegularExpressions; - using System.Web; using ImageProcessor.Configuration; using ImageProcessor.Imaging.Formats; From fbf62bacb0f9cb7d08ca0f280be5d42b021d12c3 Mon Sep 17 00:00:00 2001 From: Ryan Clark Date: Sat, 9 Aug 2014 10:33:43 -0400 Subject: [PATCH 130/155] Changed maxDays default value from 356 to 365. Former-commit-id: 44e15fda4a56359a7bbf90e39af352c05bd8443d --- .../NET45/Configuration/Resources/cache.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageProcessor.Web/NET45/Configuration/Resources/cache.config b/src/ImageProcessor.Web/NET45/Configuration/Resources/cache.config index 1caab6358..c9b64a68a 100644 --- a/src/ImageProcessor.Web/NET45/Configuration/Resources/cache.config +++ b/src/ImageProcessor.Web/NET45/Configuration/Resources/cache.config @@ -1 +1 @@ - \ No newline at end of file + From 19c21a85af444914ad4381e5fed5f45ef3e88ddb Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 14 Aug 2014 21:56:27 +0100 Subject: [PATCH 131/155] Move everything to NET4.5 Former-commit-id: 634684bd47347d7375415a638c2f64c81db1805b --- build/Build.ImageProcessor.Web.proj | 39 ++- build/Build.ImageProcessor.proj | 34 +-- build/Build.bat | 4 - .../NuSpecs/ImageProcessor.Web.Config.nuspec | 12 +- build/NuSpecs/ImageProcessor.Web.nuspec | 10 +- build/NuSpecs/ImageProcessor.nuspec | 7 +- .../ImageProcessor.Web.UnitTests.csproj | 7 +- .../{NET45 => }/Caching/CacheIndexer.cs | 0 .../{NET45 => }/Caching/CachedImage.cs | 0 .../{NET45 => }/Caching/DiskCache.cs | 1 - .../{NET45 => }/Caching/MemCache.cs | 0 .../Configuration/ImageCacheSection.cs | 0 .../Configuration/ImageProcessingSection.cs | 0 .../ImageProcessorConfiguration.cs | 0 .../Configuration/ImageSecuritySection.cs | 0 .../Configuration/Resources/cache.config | 0 .../Configuration/Resources/processing.config | 0 .../Configuration/Resources/security.config | 0 .../Extensions/DirectoryInfoExtensions.cs | 0 .../Extensions/StringExtensions.cs | 0 .../{NET45 => }/Helpers/AsyncDeDuperLock.cs | 3 +- .../Helpers/CommonParameterParserUtility.cs | 0 .../{NET45 => }/Helpers/ImageHelpers.cs | 0 .../{NET45 => }/Helpers/NativeMethods.cs | 0 .../{NET45 => }/Helpers/RemoteFile.cs | 0 .../{NET45 => }/Helpers/ResourceHelpers.cs | 0 .../{NET45 => }/Helpers/TaskHelpers.cs | 0 .../HttpModules/ImageProcessingModule.cs | 17 -- .../{NET45 => }/ImageFactoryExtensions.cs | 0 ...NET45.csproj => ImageProcessor.Web.csproj} | 2 +- .../NET4/ImageProcessor.Web_NET4.csproj | 226 ---------------- src/ImageProcessor.Web/NET4/app.config | 15 -- src/ImageProcessor.Web/NET4/packages.config | 6 - .../{NET45 => }/Processors/Alpha.cs | 0 .../{NET45 => }/Processors/AutoRotate.cs | 0 .../{NET45 => }/Processors/BackgroundColor.cs | 0 .../{NET45 => }/Processors/Brightness.cs | 0 .../{NET45 => }/Processors/Contrast.cs | 0 .../{NET45 => }/Processors/Crop.cs | 0 .../{NET45 => }/Processors/Filter.cs | 0 .../{NET45 => }/Processors/Flip.cs | 0 .../{NET45 => }/Processors/Format.cs | 0 .../{NET45 => }/Processors/GaussianBlur.cs | 0 .../{NET45 => }/Processors/GaussianSharpen.cs | 0 .../Processors/IWebGraphicsProcessor.cs | 0 .../{NET45 => }/Processors/Quality.cs | 0 .../{NET45 => }/Processors/Resize.cs | 0 .../{NET45 => }/Processors/Rotate.cs | 0 .../{NET45 => }/Processors/RoundedCorners.cs | 0 .../{NET45 => }/Processors/Saturation.cs | 0 .../{NET45 => }/Processors/Tint.cs | 0 .../{NET45 => }/Processors/Vignette.cs | 0 .../{NET45 => }/Processors/Watermark.cs | 0 .../{NET45 => }/Properties/AssemblyInfo.cs | 0 .../{NET45 => }/Settings.StyleCop | 0 src/ImageProcessor.sln | 52 +--- src/ImageProcessor.sln.DotSettings | 1 + .../ImageProcessorBootstrapper.cs | 2 +- src/ImageProcessor/ImageProcessor.csproj | 12 +- .../ImageProcessor.Plugins.WebP.csproj | 7 +- .../App_Start/FilterConfig.cs | 0 .../App_Start/RouteConfig.cs | 0 .../App_Start/WebApiConfig.cs | 0 .../Content/responsive.min.css.REMOVED.git-id | 0 .../Controllers/HomeController.cs | 0 .../Test_Website_NET45 => MVC}/Global.asax | 0 .../Test_Website_NET45 => MVC}/Global.asax.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../Test_Website_MVC.csproj} | 8 +- .../{NET4 => MVC}/Views/Home/Bmp.cshtml | 0 .../Views/Home/External.cshtml | 0 .../Views/Home/Gif.cshtml | 0 .../Views/Home/Index.cshtml | 0 .../Views/Home/Png.cshtml | 0 .../{NET4 => MVC}/Views/Home/Png8.cshtml | 0 .../{NET4 => MVC}/Views/Home/Tiff.cshtml | 0 .../Views/Home/WebP.cshtml | 0 .../Views/Shared/_Layout.cshtml | 0 .../Views/Web.config | 0 .../{NET4 => MVC}/Views/_ViewStart.cshtml | 0 .../Web.Debug.config | 0 .../Web.Release.config | 0 .../Test_Website_NET45 => MVC}/Web.config | 0 .../config/imageprocessor/cache.config | 0 .../config/imageprocessor/processing.config | 0 .../config/imageprocessor/security.config | 0 .../packages.config | 0 .../NET4/Controllers/HomeController.cs | 50 ---- src/TestWebsites/NET4/Global.asax | 1 - src/TestWebsites/NET4/Global.asax.cs | 40 --- .../NET4/Properties/AssemblyInfo.cs | 35 --- .../NET4/Scripts/img.srcsect.pollyfill.js | 103 -------- .../NET4/Test_Website_MVC_NET4.csproj | 246 ------------------ .../NET4/Views/Home/External.cshtml | 14 - src/TestWebsites/NET4/Views/Home/Gif.cshtml | 99 ------- src/TestWebsites/NET4/Views/Home/Index.cshtml | 191 -------------- src/TestWebsites/NET4/Views/Home/Png.cshtml | 99 ------- .../NET4/Views/Shared/_Layout.cshtml | 40 --- src/TestWebsites/NET4/Views/Web.config | 58 ----- src/TestWebsites/NET4/Web.Debug.config | 30 --- src/TestWebsites/NET4/Web.Release.config | 31 --- src/TestWebsites/NET4/Web.config | 76 ------ .../config/imageprocessor/processing.config | 45 ---- .../config/imageprocessor/security.config | 8 - src/TestWebsites/NET4/packages.config | 6 - .../Content/responsive.min.css.REMOVED.git-id | 1 - .../Test_Website_NET45/Views/Home/Bmp.cshtml | 100 ------- .../Test_Website_NET45/Views/Home/Png8.cshtml | 100 ------- .../Test_Website_NET45/Views/Home/Tiff.cshtml | 99 ------- .../Views/_ViewStart.cshtml | 3 - .../config/imageprocessor/cache.config | 3 - .../About.aspx | 0 .../About.aspx.cs | 0 .../About.aspx.designer.cs | 0 .../Account/Login.aspx | 0 .../Account/Login.aspx.cs | 0 .../Account/Login.aspx.designer.cs | 0 .../Account/Manage.aspx | 0 .../Account/Manage.aspx.cs | 0 .../Account/Manage.aspx.designer.cs | 0 .../Account/OpenAuthProviders.ascx | 0 .../Account/OpenAuthProviders.ascx.cs | 0 .../OpenAuthProviders.ascx.designer.cs | 0 .../Account/Register.aspx | 0 .../Account/Register.aspx.cs | 0 .../Account/Register.aspx.designer.cs | 0 .../Account/RegisterExternalLogin.aspx | 0 .../Account/RegisterExternalLogin.aspx.cs | 0 .../RegisterExternalLogin.aspx.designer.cs | 0 .../Account/Web.config | 0 .../App_Start/AuthConfig.cs | 0 .../App_Start/BundleConfig.cs | 0 .../App_Start/RouteConfig.cs | 0 .../Bundle.config | 0 .../Contact.aspx | 0 .../Contact.aspx.cs | 0 .../Contact.aspx.designer.cs | 0 .../Content/Site.css | 0 .../Default.aspx | 0 .../Default.aspx.cs | 0 .../Default.aspx.designer.cs | 0 .../Global.asax | 0 .../Global.asax.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../Scripts/WebForms/DetailsView.js | 0 .../Scripts/WebForms/Focus.js | 0 .../Scripts/WebForms/GridView.js | 0 .../MSAjax/MicrosoftAjax.js.REMOVED.git-id | 0 .../MicrosoftAjaxApplicationServices.js | 0 .../MSAjax/MicrosoftAjaxComponentModel.js | 0 .../WebForms/MSAjax/MicrosoftAjaxCore.js | 0 .../MSAjax/MicrosoftAjaxGlobalization.js | 0 .../WebForms/MSAjax/MicrosoftAjaxHistory.js | 0 .../WebForms/MSAjax/MicrosoftAjaxNetwork.js | 0 .../MSAjax/MicrosoftAjaxSerialization.js | 0 .../WebForms/MSAjax/MicrosoftAjaxTimer.js | 0 .../WebForms/MSAjax/MicrosoftAjaxWebForms.js | 0 .../MSAjax/MicrosoftAjaxWebServices.js | 0 .../Scripts/WebForms/Menu.js | 0 .../Scripts/WebForms/MenuStandards.js | 0 .../Scripts/WebForms/SmartNav.js | 0 .../Scripts/WebForms/TreeView.js | 0 .../Scripts/WebForms/WebForms.js | 0 .../Scripts/WebForms/WebParts.js | 0 .../Scripts/WebForms/WebUIValidation.js | 0 .../Scripts/_references.js | Bin ...query-1.8.2.intellisense.js.REMOVED.git-id | 0 .../Scripts/modernizr-2.6.2.js | 0 .../Site.Master | 0 .../Site.Master.cs | 0 .../Site.Master.designer.cs | 0 .../Site.Mobile.Master | 0 .../Site.Mobile.Master.cs | 0 .../Site.Mobile.Master.designer.cs | 0 .../Test_Website_Webforms.csproj} | 6 +- .../ViewSwitcher.ascx | 0 .../ViewSwitcher.ascx.cs | 0 .../ViewSwitcher.ascx.designer.cs | 0 .../Web.Debug.config | 0 .../Web.Release.config | 0 .../Web.config | 0 .../config/imageprocessor/cache.config | 0 .../config/imageprocessor/processing.config | 0 .../config/imageprocessor/security.config | 0 .../favicon.ico | Bin .../packages.config | 0 src/packages/repositories.config | 2 + 187 files changed, 81 insertions(+), 1870 deletions(-) rename src/ImageProcessor.Web/{NET45 => }/Caching/CacheIndexer.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Caching/CachedImage.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Caching/DiskCache.cs (99%) rename src/ImageProcessor.Web/{NET45 => }/Caching/MemCache.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Configuration/ImageCacheSection.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Configuration/ImageProcessingSection.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Configuration/ImageProcessorConfiguration.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Configuration/ImageSecuritySection.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Configuration/Resources/cache.config (100%) rename src/ImageProcessor.Web/{NET45 => }/Configuration/Resources/processing.config (100%) rename src/ImageProcessor.Web/{NET45 => }/Configuration/Resources/security.config (100%) rename src/ImageProcessor.Web/{NET45 => }/Extensions/DirectoryInfoExtensions.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Extensions/StringExtensions.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Helpers/AsyncDeDuperLock.cs (99%) rename src/ImageProcessor.Web/{NET45 => }/Helpers/CommonParameterParserUtility.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Helpers/ImageHelpers.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Helpers/NativeMethods.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Helpers/RemoteFile.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Helpers/ResourceHelpers.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Helpers/TaskHelpers.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/HttpModules/ImageProcessingModule.cs (97%) rename src/ImageProcessor.Web/{NET45 => }/ImageFactoryExtensions.cs (100%) rename src/ImageProcessor.Web/{NET45/ImageProcessor.Web_NET45.csproj => ImageProcessor.Web.csproj} (98%) delete mode 100644 src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj delete mode 100644 src/ImageProcessor.Web/NET4/app.config delete mode 100644 src/ImageProcessor.Web/NET4/packages.config rename src/ImageProcessor.Web/{NET45 => }/Processors/Alpha.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/AutoRotate.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/BackgroundColor.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Brightness.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Contrast.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Crop.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Filter.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Flip.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Format.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/GaussianBlur.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/GaussianSharpen.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/IWebGraphicsProcessor.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Quality.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Resize.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Rotate.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/RoundedCorners.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Saturation.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Tint.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Vignette.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Processors/Watermark.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Properties/AssemblyInfo.cs (100%) rename src/ImageProcessor.Web/{NET45 => }/Settings.StyleCop (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/App_Start/FilterConfig.cs (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/App_Start/RouteConfig.cs (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/App_Start/WebApiConfig.cs (100%) rename src/TestWebsites/{NET4 => MVC}/Content/responsive.min.css.REMOVED.git-id (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Controllers/HomeController.cs (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Global.asax (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Global.asax.cs (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Properties/AssemblyInfo.cs (100%) rename src/TestWebsites/{NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj => MVC/Test_Website_MVC.csproj} (97%) rename src/TestWebsites/{NET4 => MVC}/Views/Home/Bmp.cshtml (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Views/Home/External.cshtml (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Views/Home/Gif.cshtml (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Views/Home/Index.cshtml (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Views/Home/Png.cshtml (100%) rename src/TestWebsites/{NET4 => MVC}/Views/Home/Png8.cshtml (100%) rename src/TestWebsites/{NET4 => MVC}/Views/Home/Tiff.cshtml (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Views/Home/WebP.cshtml (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Views/Shared/_Layout.cshtml (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Views/Web.config (100%) rename src/TestWebsites/{NET4 => MVC}/Views/_ViewStart.cshtml (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Web.Debug.config (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Web.Release.config (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/Web.config (100%) rename src/TestWebsites/{NET4 => MVC}/config/imageprocessor/cache.config (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/config/imageprocessor/processing.config (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/config/imageprocessor/security.config (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => MVC}/packages.config (100%) delete mode 100644 src/TestWebsites/NET4/Controllers/HomeController.cs delete mode 100644 src/TestWebsites/NET4/Global.asax delete mode 100644 src/TestWebsites/NET4/Global.asax.cs delete mode 100644 src/TestWebsites/NET4/Properties/AssemblyInfo.cs delete mode 100644 src/TestWebsites/NET4/Scripts/img.srcsect.pollyfill.js delete mode 100644 src/TestWebsites/NET4/Test_Website_MVC_NET4.csproj delete mode 100644 src/TestWebsites/NET4/Views/Home/External.cshtml delete mode 100644 src/TestWebsites/NET4/Views/Home/Gif.cshtml delete mode 100644 src/TestWebsites/NET4/Views/Home/Index.cshtml delete mode 100644 src/TestWebsites/NET4/Views/Home/Png.cshtml delete mode 100644 src/TestWebsites/NET4/Views/Shared/_Layout.cshtml delete mode 100644 src/TestWebsites/NET4/Views/Web.config delete mode 100644 src/TestWebsites/NET4/Web.Debug.config delete mode 100644 src/TestWebsites/NET4/Web.Release.config delete mode 100644 src/TestWebsites/NET4/Web.config delete mode 100644 src/TestWebsites/NET4/config/imageprocessor/processing.config delete mode 100644 src/TestWebsites/NET4/config/imageprocessor/security.config delete mode 100644 src/TestWebsites/NET4/packages.config delete mode 100644 src/TestWebsites/NET45/Test_Website_NET45/Content/responsive.min.css.REMOVED.git-id delete mode 100644 src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Bmp.cshtml delete mode 100644 src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Png8.cshtml delete mode 100644 src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Tiff.cshtml delete mode 100644 src/TestWebsites/NET45/Test_Website_NET45/Views/_ViewStart.cshtml delete mode 100644 src/TestWebsites/NET45/Test_Website_Webforms_NET45/config/imageprocessor/cache.config rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/About.aspx (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/About.aspx.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/About.aspx.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/Login.aspx (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/Login.aspx.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/Login.aspx.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/Manage.aspx (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/Manage.aspx.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/Manage.aspx.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/OpenAuthProviders.ascx (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/OpenAuthProviders.ascx.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/OpenAuthProviders.ascx.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/Register.aspx (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/Register.aspx.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/Register.aspx.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/RegisterExternalLogin.aspx (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/RegisterExternalLogin.aspx.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/RegisterExternalLogin.aspx.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Account/Web.config (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/App_Start/AuthConfig.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/App_Start/BundleConfig.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/App_Start/RouteConfig.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Bundle.config (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Contact.aspx (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Contact.aspx.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Contact.aspx.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Content/Site.css (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Default.aspx (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Default.aspx.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Default.aspx.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Global.asax (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Global.asax.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Properties/AssemblyInfo.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/DetailsView.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/Focus.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/GridView.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjax.js.REMOVED.git-id (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjaxApplicationServices.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjaxComponentModel.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjaxCore.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjaxGlobalization.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjaxHistory.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjaxNetwork.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjaxSerialization.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjaxTimer.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjaxWebForms.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MSAjax/MicrosoftAjaxWebServices.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/Menu.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/MenuStandards.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/SmartNav.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/TreeView.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/WebForms.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/WebParts.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/WebForms/WebUIValidation.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/_references.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/jquery-1.8.2.intellisense.js.REMOVED.git-id (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Scripts/modernizr-2.6.2.js (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Site.Master (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Site.Master.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Site.Master.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Site.Mobile.Master (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Site.Mobile.Master.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Site.Mobile.Master.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45/Test_Website_Webforms_NET45.csproj => WebForms/Test_Website_Webforms.csproj} (98%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/ViewSwitcher.ascx (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/ViewSwitcher.ascx.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/ViewSwitcher.ascx.designer.cs (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Web.Debug.config (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Web.Release.config (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/Web.config (100%) rename src/TestWebsites/{NET45/Test_Website_NET45 => WebForms}/config/imageprocessor/cache.config (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/config/imageprocessor/processing.config (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/config/imageprocessor/security.config (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/favicon.ico (100%) rename src/TestWebsites/{NET45/Test_Website_Webforms_NET45 => WebForms}/packages.config (100%) diff --git a/build/Build.ImageProcessor.Web.proj b/build/Build.ImageProcessor.Web.proj index ab35a64e4..ae6936faf 100644 --- a/build/Build.ImageProcessor.Web.proj +++ b/build/Build.ImageProcessor.Web.proj @@ -2,15 +2,15 @@ .\ - - - - - + Release _BuildOutput\ @@ -19,42 +19,39 @@ $(MSBuildProjectDirectory)\$(BuildFolder) $(BuildFolder)bin\ $(BuildFolderRelativeToProjects)bin\ - $(BuildFolderAbsolutePath)ImageProcessor.Web\lib\net40 - $(BuildFolderAbsolutePath)ImageProcessor.Web\lib\net45 + $(BuildFolderAbsolutePath)ImageProcessor.Web\lib\net45 ..\src\ImageProcessor.Web\ - - + - - - - + + - + - - - + + + - + - \ No newline at end of file + diff --git a/build/Build.ImageProcessor.proj b/build/Build.ImageProcessor.proj index 930275286..134c1ed9f 100644 --- a/build/Build.ImageProcessor.proj +++ b/build/Build.ImageProcessor.proj @@ -2,53 +2,53 @@ .\ - - - - - + Release _BuildOutput\ False $(MSBuildProjectDirectory)\$(BuildFolder) - $(BuildFolderAbsolutePath)ImageProcessor\lib\ + $(BuildFolderAbsolutePath)ImageProcessor\lib\net45 ..\src\ImageProcessor\ - - + - + - + - + - - + + - + - \ No newline at end of file + diff --git a/build/Build.bat b/build/Build.bat index 21c4eb0a4..a1c73ad56 100644 --- a/build/Build.bat +++ b/build/Build.bat @@ -6,10 +6,6 @@ SET webconfigversion=2.0.0.0 ECHO Building ImageProcessor %version%, ImageProcess.Web %webversion% and ImageProcess.Web.Config %webconfigversion% -ECHO Installing the Microsoft.Bcl.Build package before anything else, otherwise you'd have to run build.cmd twice -SET nuGetFolder=%CD%\..\src\packages\ -..\src\.nuget\NuGet.exe install ..\src\ImageProcessor.Web\NET4\packages.config -OutputDirectory %nuGetFolder% - ECHO Removing _BuildOutput directory so everything is nice and clean RD _BuildOutput /q /s diff --git a/build/NuSpecs/ImageProcessor.Web.Config.nuspec b/build/NuSpecs/ImageProcessor.Web.Config.nuspec index f2c7f8412..f2fb1aeb8 100644 --- a/build/NuSpecs/ImageProcessor.Web.Config.nuspec +++ b/build/NuSpecs/ImageProcessor.Web.Config.nuspec @@ -20,10 +20,6 @@ Feedback is always welcome en-GB Image Imaging ASP Performance Processing HttpModule Cache Resize Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png WebP Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated - - - - @@ -31,9 +27,9 @@ Feedback is always welcome - - - + + + - \ No newline at end of file + diff --git a/build/NuSpecs/ImageProcessor.Web.nuspec b/build/NuSpecs/ImageProcessor.Web.nuspec index f9421c49f..7ce0d9848 100644 --- a/build/NuSpecs/ImageProcessor.Web.nuspec +++ b/build/NuSpecs/ImageProcessor.Web.nuspec @@ -13,8 +13,6 @@ Methods include: Resize, Rotate, Rounded Corners, Flip, Crop, Watermark, Filter, Saturation, Brightness, Contrast, Quality, Format, Vignette, Gaussian Blur, Gaussian Sharpen, and Transparency. -This package also requires Microsoft.Bcl.Async on .NET 4.0 which will be added on install if applicable. - If you use ImageProcessor please get in touch via my twitter @james_m_south Feedback is always welcome @@ -24,11 +22,6 @@ Feedback is always welcome en-GB Image Imaging ASP Performance Processing HttpModule Cache Resize AutoRotate Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png WebP Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF - - - - - @@ -36,7 +29,6 @@ Feedback is always welcome - - \ No newline at end of file + diff --git a/build/NuSpecs/ImageProcessor.nuspec b/build/NuSpecs/ImageProcessor.nuspec index 8fd164479..2b9c8af53 100644 --- a/build/NuSpecs/ImageProcessor.nuspec +++ b/build/NuSpecs/ImageProcessor.nuspec @@ -9,13 +9,12 @@ http://imageprocessor.org http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png false - Image Processor is an easy to use and extend processing library written in C#. Its fluent API makes common imaging tasks very simple to perform. + Image Processor is an easy to use and extend processing library written in C#. Its fluent API makes common imaging tasks very simple to perform. Methods include; Resize, Rotate, Rounded Corners, Flip, Crop, Watermark, Filter, Saturation, Brightness, Contrast, Quality, Format, Vignette, Gaussian Blur, Gaussian Sharpen, and Transparency. If you use ImageProcessor please get in touch on my twitter @james_m_south. - Feedback is always welcome. A library for manipulating image files written in C#. @@ -24,6 +23,6 @@ Feedback is always welcome. Image Imaging ASP Performance Processing Resize AutoRotate Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png WebP Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF - + - \ No newline at end of file + diff --git a/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj index 357f3b11d..d89506079 100644 --- a/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj +++ b/src/ImageProcessor.Web.UnitTests/ImageProcessor.Web.UnitTests.csproj @@ -8,7 +8,7 @@ Properties ImageProcessor.Web.UnitTests ImageProcessor.Web.UnitTests - v4.5.1 + v4.5 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10.0 @@ -18,6 +18,7 @@ UnitTest ..\ true + true @@ -61,9 +62,9 @@ - + {d011a778-59c8-4bfa-a770-c350216bf161} - ImageProcessor.Web_NET45 + ImageProcessor.Web {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} diff --git a/src/ImageProcessor.Web/NET45/Caching/CacheIndexer.cs b/src/ImageProcessor.Web/Caching/CacheIndexer.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Caching/CacheIndexer.cs rename to src/ImageProcessor.Web/Caching/CacheIndexer.cs diff --git a/src/ImageProcessor.Web/NET45/Caching/CachedImage.cs b/src/ImageProcessor.Web/Caching/CachedImage.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Caching/CachedImage.cs rename to src/ImageProcessor.Web/Caching/CachedImage.cs diff --git a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs b/src/ImageProcessor.Web/Caching/DiskCache.cs similarity index 99% rename from src/ImageProcessor.Web/NET45/Caching/DiskCache.cs rename to src/ImageProcessor.Web/Caching/DiskCache.cs index c6300c64d..21fdc974a 100644 --- a/src/ImageProcessor.Web/NET45/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/Caching/DiskCache.cs @@ -17,7 +17,6 @@ namespace ImageProcessor.Web.Caching using System.IO; using System.Linq; using System.Threading.Tasks; - using System.Web; using System.Web.Hosting; using ImageProcessor.Web.Configuration; diff --git a/src/ImageProcessor.Web/NET45/Caching/MemCache.cs b/src/ImageProcessor.Web/Caching/MemCache.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Caching/MemCache.cs rename to src/ImageProcessor.Web/Caching/MemCache.cs diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs b/src/ImageProcessor.Web/Configuration/ImageCacheSection.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Configuration/ImageCacheSection.cs rename to src/ImageProcessor.Web/Configuration/ImageCacheSection.cs diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs b/src/ImageProcessor.Web/Configuration/ImageProcessingSection.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Configuration/ImageProcessingSection.cs rename to src/ImageProcessor.Web/Configuration/ImageProcessingSection.cs diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs b/src/ImageProcessor.Web/Configuration/ImageProcessorConfiguration.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Configuration/ImageProcessorConfiguration.cs rename to src/ImageProcessor.Web/Configuration/ImageProcessorConfiguration.cs diff --git a/src/ImageProcessor.Web/NET45/Configuration/ImageSecuritySection.cs b/src/ImageProcessor.Web/Configuration/ImageSecuritySection.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Configuration/ImageSecuritySection.cs rename to src/ImageProcessor.Web/Configuration/ImageSecuritySection.cs diff --git a/src/ImageProcessor.Web/NET45/Configuration/Resources/cache.config b/src/ImageProcessor.Web/Configuration/Resources/cache.config similarity index 100% rename from src/ImageProcessor.Web/NET45/Configuration/Resources/cache.config rename to src/ImageProcessor.Web/Configuration/Resources/cache.config diff --git a/src/ImageProcessor.Web/NET45/Configuration/Resources/processing.config b/src/ImageProcessor.Web/Configuration/Resources/processing.config similarity index 100% rename from src/ImageProcessor.Web/NET45/Configuration/Resources/processing.config rename to src/ImageProcessor.Web/Configuration/Resources/processing.config diff --git a/src/ImageProcessor.Web/NET45/Configuration/Resources/security.config b/src/ImageProcessor.Web/Configuration/Resources/security.config similarity index 100% rename from src/ImageProcessor.Web/NET45/Configuration/Resources/security.config rename to src/ImageProcessor.Web/Configuration/Resources/security.config diff --git a/src/ImageProcessor.Web/NET45/Extensions/DirectoryInfoExtensions.cs b/src/ImageProcessor.Web/Extensions/DirectoryInfoExtensions.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Extensions/DirectoryInfoExtensions.cs rename to src/ImageProcessor.Web/Extensions/DirectoryInfoExtensions.cs diff --git a/src/ImageProcessor.Web/NET45/Extensions/StringExtensions.cs b/src/ImageProcessor.Web/Extensions/StringExtensions.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Extensions/StringExtensions.cs rename to src/ImageProcessor.Web/Extensions/StringExtensions.cs diff --git a/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs b/src/ImageProcessor.Web/Helpers/AsyncDeDuperLock.cs similarity index 99% rename from src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs rename to src/ImageProcessor.Web/Helpers/AsyncDeDuperLock.cs index c6896c3a0..f436b5442 100644 --- a/src/ImageProcessor.Web/NET45/Helpers/AsyncDeDuperLock.cs +++ b/src/ImageProcessor.Web/Helpers/AsyncDeDuperLock.cs @@ -54,7 +54,6 @@ namespace ImageProcessor.Web.Helpers return releaser; } -#if NET45 && !__MonoCS__ /// /// The lock async. /// @@ -92,7 +91,7 @@ namespace ImageProcessor.Web.Helpers TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } -#endif + /// /// The disposable scope. /// diff --git a/src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs b/src/ImageProcessor.Web/Helpers/CommonParameterParserUtility.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Helpers/CommonParameterParserUtility.cs rename to src/ImageProcessor.Web/Helpers/CommonParameterParserUtility.cs diff --git a/src/ImageProcessor.Web/NET45/Helpers/ImageHelpers.cs b/src/ImageProcessor.Web/Helpers/ImageHelpers.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Helpers/ImageHelpers.cs rename to src/ImageProcessor.Web/Helpers/ImageHelpers.cs diff --git a/src/ImageProcessor.Web/NET45/Helpers/NativeMethods.cs b/src/ImageProcessor.Web/Helpers/NativeMethods.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Helpers/NativeMethods.cs rename to src/ImageProcessor.Web/Helpers/NativeMethods.cs diff --git a/src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs b/src/ImageProcessor.Web/Helpers/RemoteFile.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Helpers/RemoteFile.cs rename to src/ImageProcessor.Web/Helpers/RemoteFile.cs diff --git a/src/ImageProcessor.Web/NET45/Helpers/ResourceHelpers.cs b/src/ImageProcessor.Web/Helpers/ResourceHelpers.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Helpers/ResourceHelpers.cs rename to src/ImageProcessor.Web/Helpers/ResourceHelpers.cs diff --git a/src/ImageProcessor.Web/NET45/Helpers/TaskHelpers.cs b/src/ImageProcessor.Web/Helpers/TaskHelpers.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Helpers/TaskHelpers.cs rename to src/ImageProcessor.Web/Helpers/TaskHelpers.cs diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs similarity index 97% rename from src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs rename to src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs index d7b15e7e1..82f82d012 100644 --- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs @@ -175,8 +175,6 @@ namespace ImageProcessor.Web.HttpModules } #endregion -#if NET45 && !__MonoCS__ - /// /// Occurs when the user for the current request has been authorized. /// @@ -195,21 +193,6 @@ namespace ImageProcessor.Web.HttpModules return this.ProcessImageAsync(context); } -#else - - /// - /// Occurs when the user for the current request has been authorized. - /// - /// The source of the event. - /// An EventArgs that contains the event data. - private async void PostAuthorizeRequest(object sender, EventArgs e) - { - HttpContext context = ((HttpApplication)sender).Context; - await this.ProcessImageAsync(context); - } - -#endif - /// /// Occurs just before ASP.NET send HttpHeaders to the client. /// diff --git a/src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs b/src/ImageProcessor.Web/ImageFactoryExtensions.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/ImageFactoryExtensions.cs rename to src/ImageProcessor.Web/ImageFactoryExtensions.cs diff --git a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj b/src/ImageProcessor.Web/ImageProcessor.Web.csproj similarity index 98% rename from src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj rename to src/ImageProcessor.Web/ImageProcessor.Web.csproj index 6d4694400..7b6612b12 100644 --- a/src/ImageProcessor.Web/NET45/ImageProcessor.Web_NET45.csproj +++ b/src/ImageProcessor.Web/ImageProcessor.Web.csproj @@ -87,7 +87,7 @@ - + {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} ImageProcessor diff --git a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj b/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj deleted file mode 100644 index 601953a5e..000000000 --- a/src/ImageProcessor.Web/NET4/ImageProcessor.Web_NET4.csproj +++ /dev/null @@ -1,226 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43} - Library - Properties - ImageProcessor.Web - ImageProcessor.Web - v4.0 - 512 - ..\..\ - true - - - true - full - false - bin\Debug\ - TRACE;DEBUG;USE_CSHARP_SQLITE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE;USE_CSHARP_SQLITE - prompt - 4 - - - true - bin\All\ - TRACE;DEBUG;USE_CSHARP_SQLITE - full - AnyCPU - prompt - - - - - False - ..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll - - - False - ..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll - - - False - ..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll - - - - - - - ..\..\packages\Microsoft.Bcl.1.1.9\lib\net40\System.IO.dll - True - - - - ..\..\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Runtime.dll - - - - ..\..\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Threading.Tasks.dll - - - - - - - - - CacheIndexer.cs - - - - MemCache.cs - - - ImageCacheSection.cs - - - ImageProcessingSection.cs - - - ImageProcessorConfiguration.cs - - - ImageSecuritySection.cs - - - DirectoryInfoExtensions.cs - - - StringExtensions.cs - - - AsyncDeDuperLock.cs - - - CommonParameterParserUtility.cs - - - ImageHelpers.cs - - - NativeMethods.cs - - - - ResourceHelpers.cs - - - - - - Alpha.cs - - - AutoRotate.cs - - - BackgroundColor.cs - - - Brightness.cs - - - Contrast.cs - - - Crop.cs - - - Filter.cs - - - Flip.cs - - - Format.cs - - - GaussianBlur.cs - - - GaussianSharpen.cs - - - IWebGraphicsProcessor.cs - - - Quality.cs - - - Resize.cs - - - Rotate.cs - - - RoundedCorners.cs - - - Saturation.cs - - - Tint.cs - - - Vignette.cs - - - Watermark.cs - - - - - - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} - ImageProcessor - - - - - Configuration\Resources\cache.config - - - Configuration\Resources\processing.config - - - Configuration\Resources\security.config - - - Designer - - - Designer - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET4/app.config b/src/ImageProcessor.Web/NET4/app.config deleted file mode 100644 index 31d365ae5..000000000 --- a/src/ImageProcessor.Web/NET4/app.config +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET4/packages.config b/src/ImageProcessor.Web/NET4/packages.config deleted file mode 100644 index c7068f590..000000000 --- a/src/ImageProcessor.Web/NET4/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/ImageProcessor.Web/NET45/Processors/Alpha.cs b/src/ImageProcessor.Web/Processors/Alpha.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Alpha.cs rename to src/ImageProcessor.Web/Processors/Alpha.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/AutoRotate.cs b/src/ImageProcessor.Web/Processors/AutoRotate.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/AutoRotate.cs rename to src/ImageProcessor.Web/Processors/AutoRotate.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/BackgroundColor.cs b/src/ImageProcessor.Web/Processors/BackgroundColor.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/BackgroundColor.cs rename to src/ImageProcessor.Web/Processors/BackgroundColor.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Brightness.cs b/src/ImageProcessor.Web/Processors/Brightness.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Brightness.cs rename to src/ImageProcessor.Web/Processors/Brightness.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Contrast.cs b/src/ImageProcessor.Web/Processors/Contrast.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Contrast.cs rename to src/ImageProcessor.Web/Processors/Contrast.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Crop.cs b/src/ImageProcessor.Web/Processors/Crop.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Crop.cs rename to src/ImageProcessor.Web/Processors/Crop.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Filter.cs b/src/ImageProcessor.Web/Processors/Filter.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Filter.cs rename to src/ImageProcessor.Web/Processors/Filter.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Flip.cs b/src/ImageProcessor.Web/Processors/Flip.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Flip.cs rename to src/ImageProcessor.Web/Processors/Flip.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Format.cs b/src/ImageProcessor.Web/Processors/Format.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Format.cs rename to src/ImageProcessor.Web/Processors/Format.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/GaussianBlur.cs b/src/ImageProcessor.Web/Processors/GaussianBlur.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/GaussianBlur.cs rename to src/ImageProcessor.Web/Processors/GaussianBlur.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/GaussianSharpen.cs b/src/ImageProcessor.Web/Processors/GaussianSharpen.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/GaussianSharpen.cs rename to src/ImageProcessor.Web/Processors/GaussianSharpen.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/IWebGraphicsProcessor.cs b/src/ImageProcessor.Web/Processors/IWebGraphicsProcessor.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/IWebGraphicsProcessor.cs rename to src/ImageProcessor.Web/Processors/IWebGraphicsProcessor.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Quality.cs b/src/ImageProcessor.Web/Processors/Quality.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Quality.cs rename to src/ImageProcessor.Web/Processors/Quality.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Resize.cs b/src/ImageProcessor.Web/Processors/Resize.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Resize.cs rename to src/ImageProcessor.Web/Processors/Resize.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Rotate.cs b/src/ImageProcessor.Web/Processors/Rotate.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Rotate.cs rename to src/ImageProcessor.Web/Processors/Rotate.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/RoundedCorners.cs b/src/ImageProcessor.Web/Processors/RoundedCorners.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/RoundedCorners.cs rename to src/ImageProcessor.Web/Processors/RoundedCorners.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Saturation.cs b/src/ImageProcessor.Web/Processors/Saturation.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Saturation.cs rename to src/ImageProcessor.Web/Processors/Saturation.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Tint.cs b/src/ImageProcessor.Web/Processors/Tint.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Tint.cs rename to src/ImageProcessor.Web/Processors/Tint.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Vignette.cs b/src/ImageProcessor.Web/Processors/Vignette.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Vignette.cs rename to src/ImageProcessor.Web/Processors/Vignette.cs diff --git a/src/ImageProcessor.Web/NET45/Processors/Watermark.cs b/src/ImageProcessor.Web/Processors/Watermark.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Processors/Watermark.cs rename to src/ImageProcessor.Web/Processors/Watermark.cs diff --git a/src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs similarity index 100% rename from src/ImageProcessor.Web/NET45/Properties/AssemblyInfo.cs rename to src/ImageProcessor.Web/Properties/AssemblyInfo.cs diff --git a/src/ImageProcessor.Web/NET45/Settings.StyleCop b/src/ImageProcessor.Web/Settings.StyleCop similarity index 100% rename from src/ImageProcessor.Web/NET45/Settings.StyleCop rename to src/ImageProcessor.Web/Settings.StyleCop diff --git a/src/ImageProcessor.sln b/src/ImageProcessor.sln index 8ad0ed4e9..23483c741 100644 --- a/src/ImageProcessor.sln +++ b/src/ImageProcessor.sln @@ -18,17 +18,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1E656C EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor", "ImageProcessor\ImageProcessor.csproj", "{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web.Tests", "Web.Test\Web.Tests.csproj", "{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_MVC_NET4", "TestWebsites\NET4\Test_Website_MVC_NET4.csproj", "{30327C08-7574-4D7E-AC95-6A58753C6855}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_MVC_NET45", "TestWebsites\NET45\Test_Website_NET45\Test_Website_MVC_NET45.csproj", "{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET4", "ImageProcessor.Web\NET4\ImageProcessor.Web_NET4.csproj", "{4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web_NET45", "ImageProcessor.Web\NET45\ImageProcessor.Web_NET45.csproj", "{D011A778-59C8-4BFA-A770-C350216BF161}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web", "ImageProcessor.Web\ImageProcessor.Web.csproj", "{D011A778-59C8-4BFA-A770-C350216BF161}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_Webforms_NET45", "TestWebsites\NET45\Test_Website_Webforms_NET45\Test_Website_Webforms_NET45.csproj", "{8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Plugins.WebP", "Plugins\ImageProcessor\ImageProcessor.Plugins.WebP\ImageProcessor.Plugins.WebP.csproj", "{2CF69699-959A-44DC-A281-4E2596C25043}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessorConsole", "ImageProcessorConsole\ImageProcessorConsole.csproj", "{7BF5274B-56A7-4B62-8105-E9BDF25BAFE7}" EndProject @@ -36,8 +28,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web.UnitTest EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.UnitTests", "ImageProcessor.UnitTests\ImageProcessor.UnitTests.csproj", "{633B1C4C-4823-47BE-9A01-A665F3118C8C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Plugins.WebP", "Plugins\ImageProcessor\ImageProcessor.Plugins.WebP\ImageProcessor.Plugins.WebP.csproj", "{2CF69699-959A-44DC-A281-4E2596C25043}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web.Tests", "Web.Test\Web.Tests.csproj", "{23CE0FC0-9E59-4C93-A604-A4A98A6284D1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_MVC", "TestWebsites\MVC\Test_Website_MVC.csproj", "{F6A208E9-C18F-43E9-B051-3C6EED30FDAF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Website_Webforms", "TestWebsites\WebForms\Test_Website_Webforms.csproj", "{8DA47D8C-DB1A-4D82-843F-896AB9C3B3D2}" EndProject + Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Any CPU = All|Any CPU @@ -80,24 +77,6 @@ Global {23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU {23CE0FC0-9E59-4C93-A604-A4A98A6284D1}.Release|x86.ActiveCfg = Release|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.ActiveCfg = All|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Any CPU.Build.0 = All|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.ActiveCfg = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|Mixed Platforms.Build.0 = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.ActiveCfg = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.All|x86.Build.0 = All|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Any CPU.Build.0 = Debug|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.ActiveCfg = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Debug|x86.Build.0 = Debug|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.ActiveCfg = Release|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Any CPU.Build.0 = Release|Any CPU - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|Mixed Platforms.Build.0 = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.ActiveCfg = Release|x86 - {30327C08-7574-4D7E-AC95-6A58753C6855}.Release|x86.Build.0 = Release|x86 {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.ActiveCfg = Release|Any CPU {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Any CPU.Build.0 = Release|Any CPU {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.All|Mixed Platforms.ActiveCfg = Release|Any CPU @@ -113,21 +92,6 @@ Global {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|Mixed Platforms.Build.0 = Release|Any CPU {F6A208E9-C18F-43E9-B051-3C6EED30FDAF}.Release|x86.ActiveCfg = Release|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.ActiveCfg = All|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Any CPU.Build.0 = All|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.ActiveCfg = All|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|Mixed Platforms.Build.0 = All|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.All|x86.ActiveCfg = All|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Debug|x86.ActiveCfg = Debug|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Any CPU.Build.0 = Release|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {4F7050F2-465F-4E10-8DB2-2FB97AC6AA43}.Release|x86.ActiveCfg = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.ActiveCfg = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.All|Any CPU.Build.0 = Release|Any CPU {D011A778-59C8-4BFA-A770-C350216BF161}.All|Mixed Platforms.ActiveCfg = Release|Any CPU diff --git a/src/ImageProcessor.sln.DotSettings b/src/ImageProcessor.sln.DotSettings index 4970d0c6c..824137ce2 100644 --- a/src/ImageProcessor.sln.DotSettings +++ b/src/ImageProcessor.sln.DotSettings @@ -11,6 +11,7 @@ JPEGDC JPEGQ LPI + MD OECF REF SRGB diff --git a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs index 4cffe51eb..e2d61b54a 100644 --- a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs +++ b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs @@ -132,7 +132,7 @@ namespace ImageProcessor.Configuration // Store root assembly (level 0) directly into results list stack.Push(assembly.ToString()); - // Do a preorder, non-recursive traversal + // Do a pre-order, non-recursive traversal while (stack.Count > 0) { string info = (string)stack.Pop(); diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index ed1aa9c64..9d163d5c7 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -1,5 +1,6 @@  - + + Debug AnyCPU @@ -8,12 +9,12 @@ Properties ImageProcessor ImageProcessor - v4.0 + v4.5 512 ..\ true - Client - False + + true @@ -24,6 +25,7 @@ prompt 4 bin\Debug\ImageProcessor.XML + false pdbonly @@ -33,6 +35,7 @@ prompt 4 bin\Release\ImageProcessor.XML + false true @@ -46,6 +49,7 @@ true 4 false + false diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/ImageProcessor.Plugins.WebP.csproj b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/ImageProcessor.Plugins.WebP.csproj index 0c8976d8f..c1721713e 100644 --- a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/ImageProcessor.Plugins.WebP.csproj +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/ImageProcessor.Plugins.WebP.csproj @@ -9,9 +9,10 @@ Properties ImageProcessor.Plugins.WebP ImageProcessor.Plugins.WebP - v4.0 + v4.5 512 - Client + + true @@ -21,6 +22,7 @@ DEBUG;TRACE prompt 4 + false pdbonly @@ -29,6 +31,7 @@ TRACE prompt 4 + false diff --git a/src/TestWebsites/NET45/Test_Website_NET45/App_Start/FilterConfig.cs b/src/TestWebsites/MVC/App_Start/FilterConfig.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/App_Start/FilterConfig.cs rename to src/TestWebsites/MVC/App_Start/FilterConfig.cs diff --git a/src/TestWebsites/NET45/Test_Website_NET45/App_Start/RouteConfig.cs b/src/TestWebsites/MVC/App_Start/RouteConfig.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/App_Start/RouteConfig.cs rename to src/TestWebsites/MVC/App_Start/RouteConfig.cs diff --git a/src/TestWebsites/NET45/Test_Website_NET45/App_Start/WebApiConfig.cs b/src/TestWebsites/MVC/App_Start/WebApiConfig.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/App_Start/WebApiConfig.cs rename to src/TestWebsites/MVC/App_Start/WebApiConfig.cs diff --git a/src/TestWebsites/NET4/Content/responsive.min.css.REMOVED.git-id b/src/TestWebsites/MVC/Content/responsive.min.css.REMOVED.git-id similarity index 100% rename from src/TestWebsites/NET4/Content/responsive.min.css.REMOVED.git-id rename to src/TestWebsites/MVC/Content/responsive.min.css.REMOVED.git-id diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Controllers/HomeController.cs b/src/TestWebsites/MVC/Controllers/HomeController.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Controllers/HomeController.cs rename to src/TestWebsites/MVC/Controllers/HomeController.cs diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Global.asax b/src/TestWebsites/MVC/Global.asax similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Global.asax rename to src/TestWebsites/MVC/Global.asax diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Global.asax.cs b/src/TestWebsites/MVC/Global.asax.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Global.asax.cs rename to src/TestWebsites/MVC/Global.asax.cs diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Properties/AssemblyInfo.cs b/src/TestWebsites/MVC/Properties/AssemblyInfo.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Properties/AssemblyInfo.cs rename to src/TestWebsites/MVC/Properties/AssemblyInfo.cs diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj b/src/TestWebsites/MVC/Test_Website_MVC.csproj similarity index 97% rename from src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj rename to src/TestWebsites/MVC/Test_Website_MVC.csproj index c2118914f..9cdaaaad9 100644 --- a/src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj +++ b/src/TestWebsites/MVC/Test_Website_MVC.csproj @@ -151,15 +151,15 @@ - + {d011a778-59c8-4bfa-a770-c350216bf161} - ImageProcessor.Web_NET45 + ImageProcessor.Web - + {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} ImageProcessor - + {2cf69699-959a-44dc-a281-4e2596c25043} ImageProcessor.Plugins.WebP diff --git a/src/TestWebsites/NET4/Views/Home/Bmp.cshtml b/src/TestWebsites/MVC/Views/Home/Bmp.cshtml similarity index 100% rename from src/TestWebsites/NET4/Views/Home/Bmp.cshtml rename to src/TestWebsites/MVC/Views/Home/Bmp.cshtml diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/External.cshtml b/src/TestWebsites/MVC/Views/Home/External.cshtml similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Views/Home/External.cshtml rename to src/TestWebsites/MVC/Views/Home/External.cshtml diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Gif.cshtml b/src/TestWebsites/MVC/Views/Home/Gif.cshtml similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Gif.cshtml rename to src/TestWebsites/MVC/Views/Home/Gif.cshtml diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Index.cshtml b/src/TestWebsites/MVC/Views/Home/Index.cshtml similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Index.cshtml rename to src/TestWebsites/MVC/Views/Home/Index.cshtml diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Png.cshtml b/src/TestWebsites/MVC/Views/Home/Png.cshtml similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Png.cshtml rename to src/TestWebsites/MVC/Views/Home/Png.cshtml diff --git a/src/TestWebsites/NET4/Views/Home/Png8.cshtml b/src/TestWebsites/MVC/Views/Home/Png8.cshtml similarity index 100% rename from src/TestWebsites/NET4/Views/Home/Png8.cshtml rename to src/TestWebsites/MVC/Views/Home/Png8.cshtml diff --git a/src/TestWebsites/NET4/Views/Home/Tiff.cshtml b/src/TestWebsites/MVC/Views/Home/Tiff.cshtml similarity index 100% rename from src/TestWebsites/NET4/Views/Home/Tiff.cshtml rename to src/TestWebsites/MVC/Views/Home/Tiff.cshtml diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/WebP.cshtml b/src/TestWebsites/MVC/Views/Home/WebP.cshtml similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Views/Home/WebP.cshtml rename to src/TestWebsites/MVC/Views/Home/WebP.cshtml diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Shared/_Layout.cshtml b/src/TestWebsites/MVC/Views/Shared/_Layout.cshtml similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Views/Shared/_Layout.cshtml rename to src/TestWebsites/MVC/Views/Shared/_Layout.cshtml diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Web.config b/src/TestWebsites/MVC/Views/Web.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Views/Web.config rename to src/TestWebsites/MVC/Views/Web.config diff --git a/src/TestWebsites/NET4/Views/_ViewStart.cshtml b/src/TestWebsites/MVC/Views/_ViewStart.cshtml similarity index 100% rename from src/TestWebsites/NET4/Views/_ViewStart.cshtml rename to src/TestWebsites/MVC/Views/_ViewStart.cshtml diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Web.Debug.config b/src/TestWebsites/MVC/Web.Debug.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Web.Debug.config rename to src/TestWebsites/MVC/Web.Debug.config diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Web.Release.config b/src/TestWebsites/MVC/Web.Release.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Web.Release.config rename to src/TestWebsites/MVC/Web.Release.config diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Web.config b/src/TestWebsites/MVC/Web.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/Web.config rename to src/TestWebsites/MVC/Web.config diff --git a/src/TestWebsites/NET4/config/imageprocessor/cache.config b/src/TestWebsites/MVC/config/imageprocessor/cache.config similarity index 100% rename from src/TestWebsites/NET4/config/imageprocessor/cache.config rename to src/TestWebsites/MVC/config/imageprocessor/cache.config diff --git a/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config b/src/TestWebsites/MVC/config/imageprocessor/processing.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/processing.config rename to src/TestWebsites/MVC/config/imageprocessor/processing.config diff --git a/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/security.config b/src/TestWebsites/MVC/config/imageprocessor/security.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/security.config rename to src/TestWebsites/MVC/config/imageprocessor/security.config diff --git a/src/TestWebsites/NET45/Test_Website_NET45/packages.config b/src/TestWebsites/MVC/packages.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/packages.config rename to src/TestWebsites/MVC/packages.config diff --git a/src/TestWebsites/NET4/Controllers/HomeController.cs b/src/TestWebsites/NET4/Controllers/HomeController.cs deleted file mode 100644 index 88b37915f..000000000 --- a/src/TestWebsites/NET4/Controllers/HomeController.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Mvc; - -namespace Test.Controllers -{ - public class HomeController : Controller - { - // - // GET: /Home/ - - public ActionResult Index() - { - return this.View(); - } - - public ActionResult Png() - { - return this.View(); - } - - public ActionResult Png8() - { - return this.View(); - } - - public ActionResult Gif() - { - return this.View(); - } - - public ActionResult Bmp() - { - return View(); - } - - public ActionResult Tiff() - { - return View(); - } - - public ActionResult External() - { - return this.View(); - } - - } -} diff --git a/src/TestWebsites/NET4/Global.asax b/src/TestWebsites/NET4/Global.asax deleted file mode 100644 index 5798265d5..000000000 --- a/src/TestWebsites/NET4/Global.asax +++ /dev/null @@ -1 +0,0 @@ -<%@ Application Codebehind="Global.asax.cs" Inherits="Test.MvcApplication" Language="C#" %> diff --git a/src/TestWebsites/NET4/Global.asax.cs b/src/TestWebsites/NET4/Global.asax.cs deleted file mode 100644 index 1d151b372..000000000 --- a/src/TestWebsites/NET4/Global.asax.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; - -namespace Test -{ - // Note: For instructions on enabling IIS6 or IIS7 classic mode, - // visit http://go.microsoft.com/?LinkId=9394801 - - public class MvcApplication : System.Web.HttpApplication - { - public static void RegisterGlobalFilters(GlobalFilterCollection filters) - { - filters.Add(new HandleErrorAttribute()); - } - - public static void RegisterRoutes(RouteCollection routes) - { - routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); - - routes.MapRoute( - "Default", // Route name - "{controller}/{action}/{id}", // URL with parameters - new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults - ); - - } - - protected void Application_Start() - { - AreaRegistration.RegisterAllAreas(); - - RegisterGlobalFilters(GlobalFilters.Filters); - RegisterRoutes(RouteTable.Routes); - } - } -} \ No newline at end of file diff --git a/src/TestWebsites/NET4/Properties/AssemblyInfo.cs b/src/TestWebsites/NET4/Properties/AssemblyInfo.cs deleted file mode 100644 index 499251b9f..000000000 --- a/src/TestWebsites/NET4/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Test")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Test")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("34f4c859-67cc-40d2-97ae-27e8c7157052")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/TestWebsites/NET4/Scripts/img.srcsect.pollyfill.js b/src/TestWebsites/NET4/Scripts/img.srcsect.pollyfill.js deleted file mode 100644 index 9eaa4e2ed..000000000 --- a/src/TestWebsites/NET4/Scripts/img.srcsect.pollyfill.js +++ /dev/null @@ -1,103 +0,0 @@ -(function ($) { - // http: //www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-1.html#attr-img-srcset - - // Regexes for matching queries. - var rSrc = /[^\s]+/, - rWidth = /(\d+)w/, - rRatio = /(\d+)x/; - - // Detect retina display - // http: //www.quirksmode.org/blog/archives/2012/06/devicepixelrati.html - var pixelRatio = (window.devicePixelRatio || 1); - - // Cache the images as theres no point querying them twice. - var imageList = []; - - // http://lodash.com/docs/#debounce - var debounce = function (func, wait, immediate) { - var args, - result, - thisArg, - timeoutId; - - function delayed() { - timeoutId = null; - if (!immediate) { - func.apply(thisArg, args); - } - } - - return function () { - var isImmediate = immediate && !timeoutId; - args = arguments; - thisArg = this; - - clearTimeout(timeoutId); - timeoutId = setTimeout(delayed, wait); - - if (isImmediate) { - result = func.apply(thisArg, args); - } - return result; - }; - }; - - var getImgSrc = function (image) { - var imgSrc = null, imgWidth = 0, i, - imgSrcParts = image.attributes["srcset"].nodeValue.split(","), - len = imgSrcParts.length, - width = $(window).width(); - - for (i = 0; i < len; i += 1) { - - // This is just a rough play on the algorithm. - var newImgSrc = imgSrcParts[i].match(rSrc)[0], - newImgWidth = rWidth.test(imgSrcParts[i]) ? parseInt(imgSrcParts[i].match(rWidth)[1], 10) : 1, // Use 1 for truthy - newPixelRatio = rRatio.test(imgSrcParts[i]) ? parseInt(imgSrcParts[i].match(rRatio)[1], 10) : 1; - - if ((newImgWidth > imgWidth && width > newImgWidth && newPixelRatio === pixelRatio)) { - - imgWidth = newImgWidth || imgWidth; - imgSrc = newImgSrc; - } - } - - // Return null - return imgSrc; - }; - - $(window).resize(function () { - - $.each(imageList, function () { - var self = this, - checkImage = function () { - var src = getImgSrc(self); - - if (src) { - self.src = src; - } - - }, - lazyCheck = debounce(checkImage, 100); - - // Run debounced - lazyCheck(); - - }); - - }); - - $(window).load(function () { - $("img[srcset]").each(function () { - - var src = getImgSrc(this); - - if (src) { - this.src = src; - } - - imageList.push(this); - }); - }); - -} (jQuery)); \ No newline at end of file diff --git a/src/TestWebsites/NET4/Test_Website_MVC_NET4.csproj b/src/TestWebsites/NET4/Test_Website_MVC_NET4.csproj deleted file mode 100644 index 6158a3bce..000000000 --- a/src/TestWebsites/NET4/Test_Website_MVC_NET4.csproj +++ /dev/null @@ -1,246 +0,0 @@ - - - - - Debug - AnyCPU - - - 2.0 - {30327C08-7574-4D7E-AC95-6A58753C6855} - {E53F8FEA-EAE0-44A6-8774-FFD645390401};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - Test - Test - v4.0 - false - false - - - - - 4.0 - - - - - ..\..\ - true - true - - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\ - TRACE - prompt - 4 - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - - - - - False - ..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll - - - False - ..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll - - - False - ..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll - - - - ..\..\packages\Microsoft.Bcl.1.1.9\lib\net40\System.IO.dll - - - - ..\..\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Runtime.dll - - - ..\..\packages\Microsoft.Bcl.1.1.9\lib\net40\System.Threading.Tasks.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - Global.asax - - - - - - - - - Designer - - - Web.config - - - Web.config - - - - - - - - - - - - {4f7050f2-465f-4e10-8db2-2fb97ac6aa43} - ImageProcessor.Web_NET4 - - - {3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E} - ImageProcessor - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - true - bin\ - DEBUG;TRACE - full - x86 - prompt - MinimumRecommendedRules.ruleset - - - bin\ - TRACE - true - pdbonly - x86 - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - x86 - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - False - True - 21961 - / - - - False - False - - - False - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/TestWebsites/NET4/Views/Home/External.cshtml b/src/TestWebsites/NET4/Views/Home/External.cshtml deleted file mode 100644 index 220d6a0a9..000000000 --- a/src/TestWebsites/NET4/Views/Home/External.cshtml +++ /dev/null @@ -1,14 +0,0 @@ -@{ - ViewBag.Title = "External"; -} -

    External

    -
    -
    -
    - -
    -
    - -
    -
    -
    diff --git a/src/TestWebsites/NET4/Views/Home/Gif.cshtml b/src/TestWebsites/NET4/Views/Home/Gif.cshtml deleted file mode 100644 index cb7c3ba25..000000000 --- a/src/TestWebsites/NET4/Views/Home/Gif.cshtml +++ /dev/null @@ -1,99 +0,0 @@ -@{ - ViewBag.Title = "Gif"; -} -
    -

    Gif

    -
    -
    -
    -

    Resized

    - -
    -
    -

    Cropped

    - -
    -
    -
    -
    -

    Filter

    -
    -
    -

    blackwhite

    - -
    -
    -

    comic

    - -
    -
    -
    -
    -

    lomograph

    - -
    -
    -

    greyscale

    - -
    -
    -
    -
    -

    polaroid

    - -
    -
    -

    sepia

    - -
    -
    -
    -
    -

    gotham

    - -
    -
    -

    hisatch

    - -
    -
    -
    -
    -

    losatch

    - -
    -
    -
    -
    -
    -
    -

    Watermark

    - -
    -
    -

    Format

    - -
    -
    -
    -
    -
    -
    -

    Rotate

    - -
    -
    -

    Quality

    - -
    -
    -
    -
    -
    -
    -

    Alpha

    - -
    -
    -
    -
    diff --git a/src/TestWebsites/NET4/Views/Home/Index.cshtml b/src/TestWebsites/NET4/Views/Home/Index.cshtml deleted file mode 100644 index adde1b4a6..000000000 --- a/src/TestWebsites/NET4/Views/Home/Index.cshtml +++ /dev/null @@ -1,191 +0,0 @@ -@{ - ViewBag.Title = "Home Page"; -} -
    -

    Jpg

    -
    -
    -
    -

    Resized

    - -

    Foreign language test.

    - - -
    -
    -

    Cropped

    - -
    -
    -
    -
    -
    -

    Reside Pad

    -
    - -
    -
    - -
    -
    -
    -
    -
    -

    Resize Crop

    -
    - -
    -
    - -
    -
    -
    -
    -
    -

    Resize Max

    -
    - -
    -
    - -
    -
    -
    -
    -
    -

    Resize Stretch

    -
    - -
    -
    - -
    -
    -
    -
    -

    Filter

    -
    -
    -

    blackwhite

    - -
    -
    -

    comic

    - -
    -
    -
    -
    -

    lomograph

    - -
    -
    -

    greyscale

    - -
    -
    -
    -
    -

    polaroid

    - -
    -
    -

    sepia

    - -
    -
    -
    -
    -

    gotham

    - -
    -
    -

    hisatch

    - -
    -
    -
    -
    -

    losatch

    - -
    -
    -
    -
    -
    -
    -

    Watermark

    - -
    -
    -

    Format

    - -
    -
    -
    -
    -
    -
    -

    Rotate

    - -
    -
    -

    Quality

    - -
    -
    -
    -
    -
    -
    -

    Alpha

    - -
    -
    -

    Remote

    -
    -
    -
    -
    -
    -
    -

    Flip - horizontal

    - -
    -
    -

    Flip - vertical

    - -
    -
    -
    -
    - - -
    -

    Color Profiles

    - @*
    -
    -
    -

    CMYK original jpg

    - -
    -
    -

    sRGB original jpg

    - -
    -
    -
    *@ -
    -
    -
    -

    CMYK resized jpg

    - -
    - -
    -

    sRGB resized jpg

    - -
    -
    -
    -
    diff --git a/src/TestWebsites/NET4/Views/Home/Png.cshtml b/src/TestWebsites/NET4/Views/Home/Png.cshtml deleted file mode 100644 index d01e7ae8c..000000000 --- a/src/TestWebsites/NET4/Views/Home/Png.cshtml +++ /dev/null @@ -1,99 +0,0 @@ -@{ - ViewBag.Title = "Png"; -} -
    -

    Png

    -
    -
    -
    -

    Resized

    - -
    -
    -

    Cropped

    - -
    -
    -
    -
    -

    Filter

    -
    -
    -

    blackwhite

    - -
    -
    -

    comic

    - -
    -
    -
    -
    -

    lomograph

    - -
    -
    -

    greyscale

    - -
    -
    -
    -
    -

    polaroid

    - -
    -
    -

    sepia

    - -
    -
    -
    -
    -

    gotham

    - -
    -
    -

    hisatch

    - -
    -
    -
    -
    -

    losatch

    - -
    -
    -
    -
    -
    -
    -

    Watermark

    - -
    -
    -

    Format

    - -
    -
    -
    -
    -
    -
    -

    Rotate

    - -
    -
    -

    Quality

    - -
    -
    -
    -
    -
    -
    -

    Alpha

    - -
    -
    -
    -
    diff --git a/src/TestWebsites/NET4/Views/Shared/_Layout.cshtml b/src/TestWebsites/NET4/Views/Shared/_Layout.cshtml deleted file mode 100644 index 2a812b676..000000000 --- a/src/TestWebsites/NET4/Views/Shared/_Layout.cshtml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - @ViewBag.Title - - - - -
    -
    -

    ImageProcessor NET4

    -
    - -
    - @RenderBody() -
    -
    - - diff --git a/src/TestWebsites/NET4/Views/Web.config b/src/TestWebsites/NET4/Views/Web.config deleted file mode 100644 index a4def2a3d..000000000 --- a/src/TestWebsites/NET4/Views/Web.config +++ /dev/null @@ -1,58 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/TestWebsites/NET4/Web.Debug.config b/src/TestWebsites/NET4/Web.Debug.config deleted file mode 100644 index 2c6dd51a7..000000000 --- a/src/TestWebsites/NET4/Web.Debug.config +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/src/TestWebsites/NET4/Web.Release.config b/src/TestWebsites/NET4/Web.Release.config deleted file mode 100644 index 4122d79bf..000000000 --- a/src/TestWebsites/NET4/Web.Release.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/TestWebsites/NET4/Web.config b/src/TestWebsites/NET4/Web.config deleted file mode 100644 index 52384bc51..000000000 --- a/src/TestWebsites/NET4/Web.config +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/TestWebsites/NET4/config/imageprocessor/processing.config b/src/TestWebsites/NET4/config/imageprocessor/processing.config deleted file mode 100644 index 9628cf652..000000000 --- a/src/TestWebsites/NET4/config/imageprocessor/processing.config +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/TestWebsites/NET4/config/imageprocessor/security.config b/src/TestWebsites/NET4/config/imageprocessor/security.config deleted file mode 100644 index 44fbb5d64..000000000 --- a/src/TestWebsites/NET4/config/imageprocessor/security.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/TestWebsites/NET4/packages.config b/src/TestWebsites/NET4/packages.config deleted file mode 100644 index c7068f590..000000000 --- a/src/TestWebsites/NET4/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Content/responsive.min.css.REMOVED.git-id b/src/TestWebsites/NET45/Test_Website_NET45/Content/responsive.min.css.REMOVED.git-id deleted file mode 100644 index bcf841f2a..000000000 --- a/src/TestWebsites/NET45/Test_Website_NET45/Content/responsive.min.css.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -e0fbb23ec0c6b4a6980ac29f0c71b82ff900eebc \ No newline at end of file diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Bmp.cshtml b/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Bmp.cshtml deleted file mode 100644 index 26b21ad46..000000000 --- a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Bmp.cshtml +++ /dev/null @@ -1,100 +0,0 @@ -@{ - ViewBag.Title = "Bmp"; -} - -
    -

    Bmp

    -
    -
    -
    -

    Resized

    - -
    -
    -

    Cropped

    - -
    -
    -
    -
    -

    Filter

    -
    -
    -

    blackwhite

    - -
    -
    -

    comic

    - -
    -
    -
    -
    -

    lomograph

    - -
    -
    -

    greyscale

    - -
    -
    -
    -
    -

    polaroid

    - -
    -
    -

    sepia

    - -
    -
    -
    -
    -

    gotham

    - -
    -
    -

    hisatch

    - -
    -
    -
    -
    -

    losatch

    - -
    -
    -
    -
    -
    -
    -

    Watermark

    - -
    -
    -

    Format

    - -
    -
    -
    -
    -
    -
    -

    Rotate

    - -
    -
    -

    Quality

    - -
    -
    -
    -
    -
    -
    -

    Alpha

    - -
    -
    -
    -
    diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Png8.cshtml b/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Png8.cshtml deleted file mode 100644 index 8784c836f..000000000 --- a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Png8.cshtml +++ /dev/null @@ -1,100 +0,0 @@ -@{ - ViewBag.Title = "Png8"; -} - -
    -

    Png8

    -
    -
    -
    -

    Resized

    - -
    -
    -

    Cropped

    - -
    -
    -
    -
    -

    Filter

    -
    -
    -

    blackwhite

    - -
    -
    -

    comic

    - -
    -
    -
    -
    -

    lomograph

    - -
    -
    -

    greyscale

    - -
    -
    -
    -
    -

    polaroid

    - -
    -
    -

    sepia

    - -
    -
    -
    -
    -

    gotham

    - -
    -
    -

    hisatch

    - -
    -
    -
    -
    -

    losatch

    - -
    -
    -
    -
    -
    -
    -

    Watermark

    - -
    -
    -

    Format

    - -
    -
    -
    -
    -
    -
    -

    Rotate

    - -
    -
    -

    Quality

    - -
    -
    -
    -
    -
    -
    -

    Alpha

    - -
    -
    -
    -
    diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Tiff.cshtml b/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Tiff.cshtml deleted file mode 100644 index 091e068fb..000000000 --- a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/Tiff.cshtml +++ /dev/null @@ -1,99 +0,0 @@ -@{ - ViewBag.Title = "Tiff"; -} -
    -

    Tiff

    -
    -
    -
    -

    Resized

    - -
    -
    -

    Cropped

    - -
    -
    -
    -
    -

    Filter

    -
    -
    -

    blackwhite

    - -
    -
    -

    comic

    - -
    -
    -
    -
    -

    lomograph

    - -
    -
    -

    greyscale

    - -
    -
    -
    -
    -

    polaroid

    - -
    -
    -

    sepia

    - -
    -
    -
    -
    -

    gotham

    - -
    -
    -

    hisatch

    - -
    -
    -
    -
    -

    losatch

    - -
    -
    -
    -
    -
    -
    -

    Watermark

    - -
    -
    -

    Format

    - -
    -
    -
    -
    -
    -
    -

    Rotate

    - -
    -
    -

    Quality

    - -
    -
    -
    -
    -
    -
    -

    Alpha

    - -
    -
    -
    -
    diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/_ViewStart.cshtml b/src/TestWebsites/NET45/Test_Website_NET45/Views/_ViewStart.cshtml deleted file mode 100644 index efda124b1..000000000 --- a/src/TestWebsites/NET45/Test_Website_NET45/Views/_ViewStart.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@{ - Layout = "~/Views/Shared/_Layout.cshtml"; -} \ No newline at end of file diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/config/imageprocessor/cache.config b/src/TestWebsites/NET45/Test_Website_Webforms_NET45/config/imageprocessor/cache.config deleted file mode 100644 index e4a9c5e9a..000000000 --- a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/config/imageprocessor/cache.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/About.aspx b/src/TestWebsites/WebForms/About.aspx similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/About.aspx rename to src/TestWebsites/WebForms/About.aspx diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/About.aspx.cs b/src/TestWebsites/WebForms/About.aspx.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/About.aspx.cs rename to src/TestWebsites/WebForms/About.aspx.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/About.aspx.designer.cs b/src/TestWebsites/WebForms/About.aspx.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/About.aspx.designer.cs rename to src/TestWebsites/WebForms/About.aspx.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Login.aspx b/src/TestWebsites/WebForms/Account/Login.aspx similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Login.aspx rename to src/TestWebsites/WebForms/Account/Login.aspx diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Login.aspx.cs b/src/TestWebsites/WebForms/Account/Login.aspx.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Login.aspx.cs rename to src/TestWebsites/WebForms/Account/Login.aspx.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Login.aspx.designer.cs b/src/TestWebsites/WebForms/Account/Login.aspx.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Login.aspx.designer.cs rename to src/TestWebsites/WebForms/Account/Login.aspx.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Manage.aspx b/src/TestWebsites/WebForms/Account/Manage.aspx similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Manage.aspx rename to src/TestWebsites/WebForms/Account/Manage.aspx diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Manage.aspx.cs b/src/TestWebsites/WebForms/Account/Manage.aspx.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Manage.aspx.cs rename to src/TestWebsites/WebForms/Account/Manage.aspx.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Manage.aspx.designer.cs b/src/TestWebsites/WebForms/Account/Manage.aspx.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Manage.aspx.designer.cs rename to src/TestWebsites/WebForms/Account/Manage.aspx.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/OpenAuthProviders.ascx b/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/OpenAuthProviders.ascx rename to src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/OpenAuthProviders.ascx.cs b/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/OpenAuthProviders.ascx.cs rename to src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/OpenAuthProviders.ascx.designer.cs b/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/OpenAuthProviders.ascx.designer.cs rename to src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Register.aspx b/src/TestWebsites/WebForms/Account/Register.aspx similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Register.aspx rename to src/TestWebsites/WebForms/Account/Register.aspx diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Register.aspx.cs b/src/TestWebsites/WebForms/Account/Register.aspx.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Register.aspx.cs rename to src/TestWebsites/WebForms/Account/Register.aspx.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Register.aspx.designer.cs b/src/TestWebsites/WebForms/Account/Register.aspx.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Register.aspx.designer.cs rename to src/TestWebsites/WebForms/Account/Register.aspx.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/RegisterExternalLogin.aspx b/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/RegisterExternalLogin.aspx rename to src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/RegisterExternalLogin.aspx.cs b/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/RegisterExternalLogin.aspx.cs rename to src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/RegisterExternalLogin.aspx.designer.cs b/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/RegisterExternalLogin.aspx.designer.cs rename to src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Web.config b/src/TestWebsites/WebForms/Account/Web.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Account/Web.config rename to src/TestWebsites/WebForms/Account/Web.config diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/App_Start/AuthConfig.cs b/src/TestWebsites/WebForms/App_Start/AuthConfig.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/App_Start/AuthConfig.cs rename to src/TestWebsites/WebForms/App_Start/AuthConfig.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/App_Start/BundleConfig.cs b/src/TestWebsites/WebForms/App_Start/BundleConfig.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/App_Start/BundleConfig.cs rename to src/TestWebsites/WebForms/App_Start/BundleConfig.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/App_Start/RouteConfig.cs b/src/TestWebsites/WebForms/App_Start/RouteConfig.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/App_Start/RouteConfig.cs rename to src/TestWebsites/WebForms/App_Start/RouteConfig.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Bundle.config b/src/TestWebsites/WebForms/Bundle.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Bundle.config rename to src/TestWebsites/WebForms/Bundle.config diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Contact.aspx b/src/TestWebsites/WebForms/Contact.aspx similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Contact.aspx rename to src/TestWebsites/WebForms/Contact.aspx diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Contact.aspx.cs b/src/TestWebsites/WebForms/Contact.aspx.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Contact.aspx.cs rename to src/TestWebsites/WebForms/Contact.aspx.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Contact.aspx.designer.cs b/src/TestWebsites/WebForms/Contact.aspx.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Contact.aspx.designer.cs rename to src/TestWebsites/WebForms/Contact.aspx.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Content/Site.css b/src/TestWebsites/WebForms/Content/Site.css similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Content/Site.css rename to src/TestWebsites/WebForms/Content/Site.css diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Default.aspx b/src/TestWebsites/WebForms/Default.aspx similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Default.aspx rename to src/TestWebsites/WebForms/Default.aspx diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Default.aspx.cs b/src/TestWebsites/WebForms/Default.aspx.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Default.aspx.cs rename to src/TestWebsites/WebForms/Default.aspx.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Default.aspx.designer.cs b/src/TestWebsites/WebForms/Default.aspx.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Default.aspx.designer.cs rename to src/TestWebsites/WebForms/Default.aspx.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Global.asax b/src/TestWebsites/WebForms/Global.asax similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Global.asax rename to src/TestWebsites/WebForms/Global.asax diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Global.asax.cs b/src/TestWebsites/WebForms/Global.asax.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Global.asax.cs rename to src/TestWebsites/WebForms/Global.asax.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Properties/AssemblyInfo.cs b/src/TestWebsites/WebForms/Properties/AssemblyInfo.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Properties/AssemblyInfo.cs rename to src/TestWebsites/WebForms/Properties/AssemblyInfo.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/DetailsView.js b/src/TestWebsites/WebForms/Scripts/WebForms/DetailsView.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/DetailsView.js rename to src/TestWebsites/WebForms/Scripts/WebForms/DetailsView.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/Focus.js b/src/TestWebsites/WebForms/Scripts/WebForms/Focus.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/Focus.js rename to src/TestWebsites/WebForms/Scripts/WebForms/Focus.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/GridView.js b/src/TestWebsites/WebForms/Scripts/WebForms/GridView.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/GridView.js rename to src/TestWebsites/WebForms/Scripts/WebForms/GridView.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjax.js.REMOVED.git-id b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjax.js.REMOVED.git-id similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjax.js.REMOVED.git-id rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjax.js.REMOVED.git-id diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxApplicationServices.js b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxApplicationServices.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxApplicationServices.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxApplicationServices.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxComponentModel.js b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxComponentModel.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxComponentModel.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxComponentModel.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxCore.js b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxCore.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxCore.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxCore.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxGlobalization.js b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxGlobalization.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxGlobalization.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxGlobalization.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxHistory.js b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxHistory.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxHistory.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxHistory.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxNetwork.js b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxNetwork.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxNetwork.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxNetwork.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxSerialization.js b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxSerialization.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxSerialization.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxSerialization.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxTimer.js b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxTimer.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxTimer.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxTimer.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxWebForms.js b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxWebForms.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxWebForms.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxWebForms.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxWebServices.js b/src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxWebServices.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MSAjax/MicrosoftAjaxWebServices.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MSAjax/MicrosoftAjaxWebServices.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/Menu.js b/src/TestWebsites/WebForms/Scripts/WebForms/Menu.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/Menu.js rename to src/TestWebsites/WebForms/Scripts/WebForms/Menu.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MenuStandards.js b/src/TestWebsites/WebForms/Scripts/WebForms/MenuStandards.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/MenuStandards.js rename to src/TestWebsites/WebForms/Scripts/WebForms/MenuStandards.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/SmartNav.js b/src/TestWebsites/WebForms/Scripts/WebForms/SmartNav.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/SmartNav.js rename to src/TestWebsites/WebForms/Scripts/WebForms/SmartNav.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/TreeView.js b/src/TestWebsites/WebForms/Scripts/WebForms/TreeView.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/TreeView.js rename to src/TestWebsites/WebForms/Scripts/WebForms/TreeView.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/WebForms.js b/src/TestWebsites/WebForms/Scripts/WebForms/WebForms.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/WebForms.js rename to src/TestWebsites/WebForms/Scripts/WebForms/WebForms.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/WebParts.js b/src/TestWebsites/WebForms/Scripts/WebForms/WebParts.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/WebParts.js rename to src/TestWebsites/WebForms/Scripts/WebForms/WebParts.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/WebUIValidation.js b/src/TestWebsites/WebForms/Scripts/WebForms/WebUIValidation.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/WebForms/WebUIValidation.js rename to src/TestWebsites/WebForms/Scripts/WebForms/WebUIValidation.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/_references.js b/src/TestWebsites/WebForms/Scripts/_references.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/_references.js rename to src/TestWebsites/WebForms/Scripts/_references.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/jquery-1.8.2.intellisense.js.REMOVED.git-id b/src/TestWebsites/WebForms/Scripts/jquery-1.8.2.intellisense.js.REMOVED.git-id similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/jquery-1.8.2.intellisense.js.REMOVED.git-id rename to src/TestWebsites/WebForms/Scripts/jquery-1.8.2.intellisense.js.REMOVED.git-id diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/modernizr-2.6.2.js b/src/TestWebsites/WebForms/Scripts/modernizr-2.6.2.js similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Scripts/modernizr-2.6.2.js rename to src/TestWebsites/WebForms/Scripts/modernizr-2.6.2.js diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Master b/src/TestWebsites/WebForms/Site.Master similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Master rename to src/TestWebsites/WebForms/Site.Master diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Master.cs b/src/TestWebsites/WebForms/Site.Master.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Master.cs rename to src/TestWebsites/WebForms/Site.Master.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Master.designer.cs b/src/TestWebsites/WebForms/Site.Master.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Master.designer.cs rename to src/TestWebsites/WebForms/Site.Master.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Mobile.Master b/src/TestWebsites/WebForms/Site.Mobile.Master similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Mobile.Master rename to src/TestWebsites/WebForms/Site.Mobile.Master diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Mobile.Master.cs b/src/TestWebsites/WebForms/Site.Mobile.Master.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Mobile.Master.cs rename to src/TestWebsites/WebForms/Site.Mobile.Master.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Mobile.Master.designer.cs b/src/TestWebsites/WebForms/Site.Mobile.Master.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Site.Mobile.Master.designer.cs rename to src/TestWebsites/WebForms/Site.Mobile.Master.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Test_Website_Webforms_NET45.csproj b/src/TestWebsites/WebForms/Test_Website_Webforms.csproj similarity index 98% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Test_Website_Webforms_NET45.csproj rename to src/TestWebsites/WebForms/Test_Website_Webforms.csproj index 424aabccd..ddb6983ea 100644 --- a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Test_Website_Webforms_NET45.csproj +++ b/src/TestWebsites/WebForms/Test_Website_Webforms.csproj @@ -271,11 +271,11 @@ - + {d011a778-59c8-4bfa-a770-c350216bf161} - ImageProcessor.Web_NET45 + ImageProcessor.Web - + {3b5dd734-fb7a-487d-8ce6-55e7af9aea7e} ImageProcessor diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/ViewSwitcher.ascx b/src/TestWebsites/WebForms/ViewSwitcher.ascx similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/ViewSwitcher.ascx rename to src/TestWebsites/WebForms/ViewSwitcher.ascx diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/ViewSwitcher.ascx.cs b/src/TestWebsites/WebForms/ViewSwitcher.ascx.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/ViewSwitcher.ascx.cs rename to src/TestWebsites/WebForms/ViewSwitcher.ascx.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/ViewSwitcher.ascx.designer.cs b/src/TestWebsites/WebForms/ViewSwitcher.ascx.designer.cs similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/ViewSwitcher.ascx.designer.cs rename to src/TestWebsites/WebForms/ViewSwitcher.ascx.designer.cs diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Web.Debug.config b/src/TestWebsites/WebForms/Web.Debug.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Web.Debug.config rename to src/TestWebsites/WebForms/Web.Debug.config diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Web.Release.config b/src/TestWebsites/WebForms/Web.Release.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Web.Release.config rename to src/TestWebsites/WebForms/Web.Release.config diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/Web.config b/src/TestWebsites/WebForms/Web.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/Web.config rename to src/TestWebsites/WebForms/Web.config diff --git a/src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/cache.config b/src/TestWebsites/WebForms/config/imageprocessor/cache.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_NET45/config/imageprocessor/cache.config rename to src/TestWebsites/WebForms/config/imageprocessor/cache.config diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/config/imageprocessor/processing.config b/src/TestWebsites/WebForms/config/imageprocessor/processing.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/config/imageprocessor/processing.config rename to src/TestWebsites/WebForms/config/imageprocessor/processing.config diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/config/imageprocessor/security.config b/src/TestWebsites/WebForms/config/imageprocessor/security.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/config/imageprocessor/security.config rename to src/TestWebsites/WebForms/config/imageprocessor/security.config diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/favicon.ico b/src/TestWebsites/WebForms/favicon.ico similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/favicon.ico rename to src/TestWebsites/WebForms/favicon.ico diff --git a/src/TestWebsites/NET45/Test_Website_Webforms_NET45/packages.config b/src/TestWebsites/WebForms/packages.config similarity index 100% rename from src/TestWebsites/NET45/Test_Website_Webforms_NET45/packages.config rename to src/TestWebsites/WebForms/packages.config diff --git a/src/packages/repositories.config b/src/packages/repositories.config index 14108b962..3406fa91f 100644 --- a/src/packages/repositories.config +++ b/src/packages/repositories.config @@ -4,7 +4,9 @@ + + \ No newline at end of file From 7b1c5161d08a184a52751e2ad43f18abde1d2d95 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 14 Aug 2014 21:57:28 +0100 Subject: [PATCH 132/155] Adding webforms project Former-commit-id: 95ac43679849712a131a8bb7cf36e5f907ccf75d --- src/TestWebsites/WebForms/config/imageprocessor/cache.config | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/TestWebsites/WebForms/config/imageprocessor/cache.config diff --git a/src/TestWebsites/WebForms/config/imageprocessor/cache.config b/src/TestWebsites/WebForms/config/imageprocessor/cache.config new file mode 100644 index 000000000..e4a9c5e9a --- /dev/null +++ b/src/TestWebsites/WebForms/config/imageprocessor/cache.config @@ -0,0 +1,3 @@ + + + From 43c45ae90b31319254d8ed4c4b7c3b0245079d85 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 14 Aug 2014 22:18:57 +0100 Subject: [PATCH 133/155] Removing auth stuff to lighten test Former-commit-id: 69ca89e8a6ba95cb47197930ec4d9aa01db9f9f5 --- src/TestWebsites/WebForms/Account/Login.aspx | 47 ------ .../WebForms/Account/Login.aspx.cs | 24 --- .../WebForms/Account/Login.aspx.designer.cs | 35 ---- src/TestWebsites/WebForms/Account/Manage.aspx | 126 --------------- .../WebForms/Account/Manage.aspx.cs | 95 ----------- .../WebForms/Account/Manage.aspx.designer.cs | 66 -------- .../WebForms/Account/OpenAuthProviders.ascx | 21 --- .../Account/OpenAuthProviders.ascx.cs | 43 ----- .../OpenAuthProviders.ascx.designer.cs | 27 ---- .../WebForms/Account/Register.aspx | 62 ------- .../WebForms/Account/Register.aspx.cs | 31 ---- .../Account/Register.aspx.designer.cs | 35 ---- .../Account/RegisterExternalLogin.aspx | 35 ---- .../Account/RegisterExternalLogin.aspx.cs | 151 ------------------ .../RegisterExternalLogin.aspx.designer.cs | 39 ----- src/TestWebsites/WebForms/Account/Web.config | 12 -- .../WebForms/App_Start/AuthConfig.cs | 31 ---- src/TestWebsites/WebForms/Global.asax.cs | 1 - .../WebForms/Test_Website_Webforms.csproj | 76 --------- src/TestWebsites/WebForms/packages.config | 8 - 20 files changed, 965 deletions(-) delete mode 100644 src/TestWebsites/WebForms/Account/Login.aspx delete mode 100644 src/TestWebsites/WebForms/Account/Login.aspx.cs delete mode 100644 src/TestWebsites/WebForms/Account/Login.aspx.designer.cs delete mode 100644 src/TestWebsites/WebForms/Account/Manage.aspx delete mode 100644 src/TestWebsites/WebForms/Account/Manage.aspx.cs delete mode 100644 src/TestWebsites/WebForms/Account/Manage.aspx.designer.cs delete mode 100644 src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx delete mode 100644 src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.cs delete mode 100644 src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.designer.cs delete mode 100644 src/TestWebsites/WebForms/Account/Register.aspx delete mode 100644 src/TestWebsites/WebForms/Account/Register.aspx.cs delete mode 100644 src/TestWebsites/WebForms/Account/Register.aspx.designer.cs delete mode 100644 src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx delete mode 100644 src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.cs delete mode 100644 src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.designer.cs delete mode 100644 src/TestWebsites/WebForms/Account/Web.config delete mode 100644 src/TestWebsites/WebForms/App_Start/AuthConfig.cs diff --git a/src/TestWebsites/WebForms/Account/Login.aspx b/src/TestWebsites/WebForms/Account/Login.aspx deleted file mode 100644 index 9a04e8149..000000000 --- a/src/TestWebsites/WebForms/Account/Login.aspx +++ /dev/null @@ -1,47 +0,0 @@ -<%@ Page Title="Log in" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="Test_Website_Webforms_NET45.Account.Login" %> -<%@ Register Src="~/Account/OpenAuthProviders.ascx" TagPrefix="uc" TagName="OpenAuthProviders" %> - - -
    -

    <%: Title %>.

    -
    -
    -

    Use a local account to log in.

    - - -

    - -

    -
    - Log in Form -
      -
    1. - User name - - -
    2. -
    3. - Password - - -
    4. -
    5. - - Remember me? -
    6. -
    - -
    -
    -
    -

    - Register - if you don't have an account. -

    -
    - -
    -

    Use another service to log in.

    - -
    -
    diff --git a/src/TestWebsites/WebForms/Account/Login.aspx.cs b/src/TestWebsites/WebForms/Account/Login.aspx.cs deleted file mode 100644 index 234c882fe..000000000 --- a/src/TestWebsites/WebForms/Account/Login.aspx.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; - -namespace Test_Website_Webforms_NET45.Account -{ - public partial class Login : Page - { - protected void Page_Load(object sender, EventArgs e) - { - RegisterHyperLink.NavigateUrl = "Register"; - OpenAuthLogin.ReturnUrl = Request.QueryString["ReturnUrl"]; - - var returnUrl = HttpUtility.UrlEncode(Request.QueryString["ReturnUrl"]); - if (!String.IsNullOrEmpty(returnUrl)) - { - RegisterHyperLink.NavigateUrl += "?ReturnUrl=" + returnUrl; - } - } - } -} \ No newline at end of file diff --git a/src/TestWebsites/WebForms/Account/Login.aspx.designer.cs b/src/TestWebsites/WebForms/Account/Login.aspx.designer.cs deleted file mode 100644 index b021637f7..000000000 --- a/src/TestWebsites/WebForms/Account/Login.aspx.designer.cs +++ /dev/null @@ -1,35 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Test_Website_Webforms_NET45.Account -{ - - - public partial class Login - { - - /// - /// RegisterHyperLink control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.HyperLink RegisterHyperLink; - - /// - /// OpenAuthLogin control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::Test_Website_Webforms_NET45.Account.OpenAuthProviders OpenAuthLogin; - } -} diff --git a/src/TestWebsites/WebForms/Account/Manage.aspx b/src/TestWebsites/WebForms/Account/Manage.aspx deleted file mode 100644 index 4675b60af..000000000 --- a/src/TestWebsites/WebForms/Account/Manage.aspx +++ /dev/null @@ -1,126 +0,0 @@ -<%@ Page Title="Manage Account" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Manage.aspx.cs" Inherits="Test_Website_Webforms_NET45.Account.Manage" %> -<%@ Register Src="~/Account/OpenAuthProviders.ascx" TagPrefix="uc" TagName="OpenAuthProviders" %> - - -
    -

    <%: Title %>.

    -
    - -
    - -

    <%: SuccessMessage %>

    -
    - -

    You're logged in as <%: User.Identity.Name %>.

    - - -

    - You do not have a local password for this site. Add a local - password so you can log in without an external login. -

    -
    - Set Password Form -
      -
    1. - Password - - - - - -
    2. -
    3. - Confirm password - - - -
    4. -
    - -
    -
    - - -

    Change password

    - - -

    - -

    -
    - Change password details -
      -
    1. - Current password - - -
    2. -
    3. - New password - - -
    4. -
    5. - Confirm new password - - - -
    6. -
    - -
    -
    -
    -
    -
    - -
    - - - - -

    Registered external logins

    - - - - - -
    ServiceUser NameLast Used 
    -
    - - - - <%#: Item.ProviderDisplayName %> - <%#: Item.ProviderUserName %> - <%#: ConvertToDisplayDateTime(Item.LastUsedUtc) %> - - - - - - -
    - -

    Add an external login

    - -
    -
    diff --git a/src/TestWebsites/WebForms/Account/Manage.aspx.cs b/src/TestWebsites/WebForms/Account/Manage.aspx.cs deleted file mode 100644 index 311c127ff..000000000 --- a/src/TestWebsites/WebForms/Account/Manage.aspx.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using Microsoft.AspNet.Membership.OpenAuth; - -namespace Test_Website_Webforms_NET45.Account -{ - public partial class Manage : System.Web.UI.Page - { - protected string SuccessMessage - { - get; - private set; - } - - protected bool CanRemoveExternalLogins - { - get; - private set; - } - - protected void Page_Load() - { - if (!IsPostBack) - { - // Determine the sections to render - var hasLocalPassword = OpenAuth.HasLocalPassword(User.Identity.Name); - setPassword.Visible = !hasLocalPassword; - changePassword.Visible = hasLocalPassword; - - CanRemoveExternalLogins = hasLocalPassword; - - // Render success message - var message = Request.QueryString["m"]; - if (message != null) - { - // Strip the query string from action - Form.Action = ResolveUrl("~/Account/Manage"); - - SuccessMessage = - message == "ChangePwdSuccess" ? "Your password has been changed." - : message == "SetPwdSuccess" ? "Your password has been set." - : message == "RemoveLoginSuccess" ? "The external login was removed." - : String.Empty; - successMessage.Visible = !String.IsNullOrEmpty(SuccessMessage); - } - } - - } - - protected void setPassword_Click(object sender, EventArgs e) - { - if (IsValid) - { - var result = OpenAuth.AddLocalPassword(User.Identity.Name, password.Text); - if (result.IsSuccessful) - { - Response.Redirect("~/Account/Manage?m=SetPwdSuccess"); - } - else - { - - ModelState.AddModelError("NewPassword", result.ErrorMessage); - - } - } - } - - - public IEnumerable GetExternalLogins() - { - var accounts = OpenAuth.GetAccountsForUser(User.Identity.Name); - CanRemoveExternalLogins = CanRemoveExternalLogins || accounts.Count() > 1; - return accounts; - } - - public void RemoveExternalLogin(string providerName, string providerUserId) - { - var m = OpenAuth.DeleteAccount(User.Identity.Name, providerName, providerUserId) - ? "?m=RemoveLoginSuccess" - : String.Empty; - Response.Redirect("~/Account/Manage" + m); - } - - - protected static string ConvertToDisplayDateTime(DateTime? utcDateTime) - { - // You can change this method to convert the UTC date time into the desired display - // offset and format. Here we're converting it to the server timezone and formatting - // as a short date and a long time string, using the current thread culture. - return utcDateTime.HasValue ? utcDateTime.Value.ToLocalTime().ToString("G") : "[never]"; - } - } -} \ No newline at end of file diff --git a/src/TestWebsites/WebForms/Account/Manage.aspx.designer.cs b/src/TestWebsites/WebForms/Account/Manage.aspx.designer.cs deleted file mode 100644 index f746b03b4..000000000 --- a/src/TestWebsites/WebForms/Account/Manage.aspx.designer.cs +++ /dev/null @@ -1,66 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Test_Website_Webforms_NET45.Account -{ - - - public partial class Manage - { - - /// - /// successMessage control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder successMessage; - - /// - /// setPassword control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder setPassword; - - /// - /// password control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox password; - - - - /// - /// confirmPassword control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox confirmPassword; - - /// - /// changePassword control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder changePassword; - - - } -} diff --git a/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx b/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx deleted file mode 100644 index 27fe593c0..000000000 --- a/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx +++ /dev/null @@ -1,21 +0,0 @@ -<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="OpenAuthProviders.ascx.cs" Inherits="Test_Website_Webforms_NET45.Account.OpenAuthProviders" %> - -
    - Log in using another service - - - - - - - -
    -

    There are no external authentication services configured. See this article for details on setting up this ASP.NET application to support logging in via external services.

    -
    -
    -
    -
    \ No newline at end of file diff --git a/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.cs b/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.cs deleted file mode 100644 index 98ac696ba..000000000 --- a/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web; -using Microsoft.AspNet.Membership.OpenAuth; - -namespace Test_Website_Webforms_NET45.Account -{ - public partial class OpenAuthProviders : System.Web.UI.UserControl - { - protected void Page_Load(object sender, EventArgs e) - { - - if (IsPostBack) - { - var provider = Request.Form["provider"]; - if (provider == null) - { - return; - } - - var redirectUrl = "~/Account/RegisterExternalLogin"; - if (!String.IsNullOrEmpty(ReturnUrl)) - { - var resolvedReturnUrl = ResolveUrl(ReturnUrl); - redirectUrl += "?ReturnUrl=" + HttpUtility.UrlEncode(resolvedReturnUrl); - } - - OpenAuth.RequestAuthentication(provider, redirectUrl); - } - } - - - - public string ReturnUrl { get; set; } - - - public IEnumerable GetProviderNames() - { - return OpenAuth.AuthenticationClients.GetAll(); - } - - } -} \ No newline at end of file diff --git a/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.designer.cs b/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.designer.cs deleted file mode 100644 index 4433c3d0c..000000000 --- a/src/TestWebsites/WebForms/Account/OpenAuthProviders.ascx.designer.cs +++ /dev/null @@ -1,27 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Test_Website_Webforms_NET45.Account -{ - - - public partial class OpenAuthProviders - { - - /// - /// providerDetails control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ListView providerDetails; - - } -} diff --git a/src/TestWebsites/WebForms/Account/Register.aspx b/src/TestWebsites/WebForms/Account/Register.aspx deleted file mode 100644 index 74a7221d5..000000000 --- a/src/TestWebsites/WebForms/Account/Register.aspx +++ /dev/null @@ -1,62 +0,0 @@ -<%@ Page Title="Register" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Register.aspx.cs" Inherits="Test_Website_Webforms_NET45.Account.Register" %> - - -
    -

    <%: Title %>.

    -

    Use the form below to create a new account.

    -
    - - - - - - - - - -

    - Passwords are required to be a minimum of <%: Membership.MinRequiredPasswordLength %> characters in length. -

    - -

    - -

    - -
    - Registration Form -
      -
    1. - User name - - -
    2. -
    3. - Email address - - -
    4. -
    5. - Password - - -
    6. -
    7. - Confirm password - - - -
    8. -
    - -
    -
    - -
    -
    -
    -
    \ No newline at end of file diff --git a/src/TestWebsites/WebForms/Account/Register.aspx.cs b/src/TestWebsites/WebForms/Account/Register.aspx.cs deleted file mode 100644 index e36cc3174..000000000 --- a/src/TestWebsites/WebForms/Account/Register.aspx.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Security; -using System.Web.UI; -using System.Web.UI.WebControls; -using Microsoft.AspNet.Membership.OpenAuth; - -namespace Test_Website_Webforms_NET45.Account -{ - public partial class Register : Page - { - protected void Page_Load(object sender, EventArgs e) - { - RegisterUser.ContinueDestinationPageUrl = Request.QueryString["ReturnUrl"]; - } - - protected void RegisterUser_CreatedUser(object sender, EventArgs e) - { - FormsAuthentication.SetAuthCookie(RegisterUser.UserName, createPersistentCookie: false); - - string continueUrl = RegisterUser.ContinueDestinationPageUrl; - if (!OpenAuth.IsLocalUrl(continueUrl)) - { - continueUrl = "~/"; - } - Response.Redirect(continueUrl); - } - } -} \ No newline at end of file diff --git a/src/TestWebsites/WebForms/Account/Register.aspx.designer.cs b/src/TestWebsites/WebForms/Account/Register.aspx.designer.cs deleted file mode 100644 index af06bbb97..000000000 --- a/src/TestWebsites/WebForms/Account/Register.aspx.designer.cs +++ /dev/null @@ -1,35 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Test_Website_Webforms_NET45.Account -{ - - - public partial class Register - { - - /// - /// RegisterUser control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CreateUserWizard RegisterUser; - - /// - /// RegisterUserWizardStep control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CreateUserWizardStep RegisterUserWizardStep; - } -} diff --git a/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx b/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx deleted file mode 100644 index a5914d591..000000000 --- a/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx +++ /dev/null @@ -1,35 +0,0 @@ -<%@ Page Language="C#" Title="Register an external login" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="RegisterExternalLogin.aspx.cs" Inherits="Test_Website_Webforms_NET45.Account.RegisterExternalLogin" %> - -
    -

    Register with your <%: ProviderDisplayName %> account

    -

    <%: ProviderUserName %>.

    -
    - - - - - - -
    - Association Form -

    - You've authenticated with <%: ProviderDisplayName %> as - <%: ProviderUserName %>. Please enter a user name below for the current site - and click the Log in button. -

    -
      - -
    - - -
    -
    -
    diff --git a/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.cs b/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.cs deleted file mode 100644 index 18b667b12..000000000 --- a/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System; -using System.Web; -using System.Web.Security; -using DotNetOpenAuth.AspNet; -using Microsoft.AspNet.Membership.OpenAuth; - -namespace Test_Website_Webforms_NET45.Account -{ - public partial class RegisterExternalLogin : System.Web.UI.Page - { - protected string ProviderName - { - get { return (string)ViewState["ProviderName"] ?? String.Empty; } - private set { ViewState["ProviderName"] = value; } - } - - protected string ProviderDisplayName - { - get { return (string)ViewState["ProviderDisplayName"] ?? String.Empty; } - private set { ViewState["ProviderDisplayName"] = value; } - } - - protected string ProviderUserId - { - get { return (string)ViewState["ProviderUserId"] ?? String.Empty; } - private set { ViewState["ProviderUserId"] = value; } - } - - protected string ProviderUserName - { - get { return (string)ViewState["ProviderUserName"] ?? String.Empty; } - private set { ViewState["ProviderUserName"] = value; } - } - - protected void Page_Load() - { - if (!IsPostBack) - { - ProcessProviderResult(); - } - } - - protected void logIn_Click(object sender, EventArgs e) - { - CreateAndLoginUser(); - } - - protected void cancel_Click(object sender, EventArgs e) - { - RedirectToReturnUrl(); - } - - private void ProcessProviderResult() - { - // Process the result from an auth provider in the request - ProviderName = OpenAuth.GetProviderNameFromCurrentRequest(); - - if (String.IsNullOrEmpty(ProviderName)) - { - Response.Redirect(FormsAuthentication.LoginUrl); - } - - // Build the redirect url for OpenAuth verification - var redirectUrl = "~/Account/RegisterExternalLogin"; - var returnUrl = Request.QueryString["ReturnUrl"]; - if (!String.IsNullOrEmpty(returnUrl)) - { - redirectUrl += "?ReturnUrl=" + HttpUtility.UrlEncode(returnUrl); - } - - // Verify the OpenAuth payload - var authResult = OpenAuth.VerifyAuthentication(redirectUrl); - ProviderDisplayName = OpenAuth.GetProviderDisplayName(ProviderName); - if (!authResult.IsSuccessful) - { - Title = "External login failed"; - userNameForm.Visible = false; - - ModelState.AddModelError("Provider", String.Format("External login {0} failed.", ProviderDisplayName)); - - // To view this error, enable page tracing in web.config () and visit ~/Trace.axd - Trace.Warn("OpenAuth", String.Format("There was an error verifying authentication with {0})", ProviderDisplayName), authResult.Error); - return; - } - - // User has logged in with provider successfully - // Check if user is already registered locally - if (OpenAuth.Login(authResult.Provider, authResult.ProviderUserId, createPersistentCookie: false)) - { - RedirectToReturnUrl(); - } - - // Store the provider details in ViewState - ProviderName = authResult.Provider; - ProviderUserId = authResult.ProviderUserId; - ProviderUserName = authResult.UserName; - - // Strip the query string from action - Form.Action = ResolveUrl(redirectUrl); - - if (User.Identity.IsAuthenticated) - { - // User is already authenticated, add the external login and redirect to return url - OpenAuth.AddAccountToExistingUser(ProviderName, ProviderUserId, ProviderUserName, User.Identity.Name); - RedirectToReturnUrl(); - } - else - { - // User is new, ask for their desired membership name - userName.Text = authResult.UserName; - } - } - - private void CreateAndLoginUser() - { - if (!IsValid) - { - return; - } - - var createResult = OpenAuth.CreateUser(ProviderName, ProviderUserId, ProviderUserName, userName.Text); - if (!createResult.IsSuccessful) - { - - ModelState.AddModelError("UserName", createResult.ErrorMessage); - - } - else - { - // User created & associated OK - if (OpenAuth.Login(ProviderName, ProviderUserId, createPersistentCookie: false)) - { - RedirectToReturnUrl(); - } - } - } - - private void RedirectToReturnUrl() - { - var returnUrl = Request.QueryString["ReturnUrl"]; - if (!String.IsNullOrEmpty(returnUrl) && OpenAuth.IsLocalUrl(returnUrl)) - { - Response.Redirect(returnUrl); - } - else - { - Response.Redirect("~/"); - } - } - } -} \ No newline at end of file diff --git a/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.designer.cs b/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.designer.cs deleted file mode 100644 index d3bd505c4..000000000 --- a/src/TestWebsites/WebForms/Account/RegisterExternalLogin.aspx.designer.cs +++ /dev/null @@ -1,39 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Test_Website_Webforms_NET45.Account -{ - - - public partial class RegisterExternalLogin - { - - - - /// - /// userNameForm control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder userNameForm; - - /// - /// userName control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox userName; - - - } -} diff --git a/src/TestWebsites/WebForms/Account/Web.config b/src/TestWebsites/WebForms/Account/Web.config deleted file mode 100644 index 90fe314f6..000000000 --- a/src/TestWebsites/WebForms/Account/Web.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/src/TestWebsites/WebForms/App_Start/AuthConfig.cs b/src/TestWebsites/WebForms/App_Start/AuthConfig.cs deleted file mode 100644 index 24093ce83..000000000 --- a/src/TestWebsites/WebForms/App_Start/AuthConfig.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using Microsoft.AspNet.Membership.OpenAuth; - -namespace Test_Website_Webforms_NET45 -{ - internal static class AuthConfig - { - public static void RegisterOpenAuth() - { - // See http://go.microsoft.com/fwlink/?LinkId=252803 for details on setting up this ASP.NET - // application to support logging in via external services. - - //OpenAuth.AuthenticationClients.AddTwitter( - // consumerKey: "your Twitter consumer key", - // consumerSecret: "your Twitter consumer secret"); - - //OpenAuth.AuthenticationClients.AddFacebook( - // appId: "your Facebook app id", - // appSecret: "your Facebook app secret"); - - //OpenAuth.AuthenticationClients.AddMicrosoft( - // clientId: "your Microsoft account client id", - // clientSecret: "your Microsoft account client secret"); - - //OpenAuth.AuthenticationClients.AddGoogle(); - } - } -} \ No newline at end of file diff --git a/src/TestWebsites/WebForms/Global.asax.cs b/src/TestWebsites/WebForms/Global.asax.cs index 0ce814eed..21e6fd992 100644 --- a/src/TestWebsites/WebForms/Global.asax.cs +++ b/src/TestWebsites/WebForms/Global.asax.cs @@ -15,7 +15,6 @@ namespace Test_Website_Webforms_NET45 { // Code that runs on application startup BundleConfig.RegisterBundles(BundleTable.Bundles); - AuthConfig.RegisterOpenAuth(); RouteConfig.RegisterRoutes(RouteTable.Routes); } diff --git a/src/TestWebsites/WebForms/Test_Website_Webforms.csproj b/src/TestWebsites/WebForms/Test_Website_Webforms.csproj index ddb6983ea..67fe7fb43 100644 --- a/src/TestWebsites/WebForms/Test_Website_Webforms.csproj +++ b/src/TestWebsites/WebForms/Test_Website_Webforms.csproj @@ -73,46 +73,12 @@ ..\..\..\packages\Microsoft.AspNet.ScriptManager.WebForms.4.5.6\lib\net45\Microsoft.ScriptManager.WebForms.dll - - ..\..\..\packages\EntityFramework.5.0.0\lib\net45\EntityFramework.dll - ..\..\..\packages\Microsoft.AspNet.Web.Optimization.1.0.0\lib\net40\System.Web.Optimization.dll ..\..\..\packages\Microsoft.AspNet.Providers.Core.1.2\lib\net40\System.Web.Providers.dll - - False - ..\..\..\packages\DotNetOpenAuth.Core.4.1.4.12333\lib\net40-full\DotNetOpenAuth.Core.dll - - - False - ..\..\..\packages\DotNetOpenAuth.OAuth.Core.4.1.4.12333\lib\net40-full\DotNetOpenAuth.OAuth.dll - - - False - ..\..\..\packages\DotNetOpenAuth.OAuth.Consumer.4.1.4.12333\lib\net40-full\DotNetOpenAuth.OAuth.Consumer.dll - - - False - ..\..\..\packages\DotNetOpenAuth.OpenId.Core.4.1.4.12333\lib\net40-full\DotNetOpenAuth.OpenId.dll - - - False - ..\..\..\packages\DotNetOpenAuth.OpenId.RelyingParty.4.1.4.12333\lib\net40-full\DotNetOpenAuth.OpenId.RelyingParty.dll - - - False - ..\..\..\packages\DotNetOpenAuth.AspNet.4.1.4.12333\lib\net40-full\DotNetOpenAuth.AspNet.dll - - - ..\..\..\packages\Microsoft.AspNet.Membership.OpenAuth.1.0.1\lib\net45\Microsoft.AspNet.Membership.OpenAuth.dll - - - True - ..\..\..\packages\Microsoft.AspNet.Web.Optimization.WebForms.1.0.0\lib\net45\Microsoft.AspNet.Web.Optimization.WebForms.dll - ..\..\..\packages\Microsoft.AspNet.FriendlyUrls.Core.1.0.0\lib\net45\Microsoft.AspNet.FriendlyUrls.dll @@ -123,11 +89,6 @@
    - - - - - @@ -179,7 +140,6 @@ - About.aspx ASPXCodeBehind @@ -187,41 +147,6 @@ About.aspx - - Login.aspx - ASPXCodeBehind - - - Login.aspx - - - Manage.aspx - ASPXCodeBehind - - - Manage.aspx - - - OpenAuthProviders.ascx - ASPXCodeBehind - - - OpenAuthProviders.ascx - - - Register.aspx - ASPXCodeBehind - - - Register.aspx - - - RegisterExternalLogin.aspx - ASPXCodeBehind - - - RegisterExternalLogin.aspx - Contact.aspx @@ -267,7 +192,6 @@ - diff --git a/src/TestWebsites/WebForms/packages.config b/src/TestWebsites/WebForms/packages.config index 319f73f4f..d689bdfcd 100644 --- a/src/TestWebsites/WebForms/packages.config +++ b/src/TestWebsites/WebForms/packages.config @@ -1,15 +1,7 @@  - - - - - - - - From 25e8579746993d7941297bf7e0d95d2529a299f4 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 14 Aug 2014 22:32:46 +0100 Subject: [PATCH 134/155] Removing unnecessary references Former-commit-id: 95844a4fa76b2edb1d2fc15bc483ca9efaa6c1fd --- .../WebForms/App_Start/BundleConfig.cs | 36 --------------- src/TestWebsites/WebForms/Bundle.config | 20 --------- src/TestWebsites/WebForms/Global.asax.cs | 1 - src/TestWebsites/WebForms/Site.Master | 41 ----------------- .../WebForms/Test_Website_Webforms.csproj | 2 - src/TestWebsites/WebForms/Web.config | 15 ++----- .../config/imageprocessor/processing.config | 45 +++++++++---------- .../config/imageprocessor/security.config | 20 ++++++--- src/TestWebsites/WebForms/packages.config | 3 -- 9 files changed, 39 insertions(+), 144 deletions(-) delete mode 100644 src/TestWebsites/WebForms/App_Start/BundleConfig.cs delete mode 100644 src/TestWebsites/WebForms/Bundle.config diff --git a/src/TestWebsites/WebForms/App_Start/BundleConfig.cs b/src/TestWebsites/WebForms/App_Start/BundleConfig.cs deleted file mode 100644 index 6e3260970..000000000 --- a/src/TestWebsites/WebForms/App_Start/BundleConfig.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Optimization; - -namespace Test_Website_Webforms_NET45 -{ - public class BundleConfig - { - // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254726 - public static void RegisterBundles(BundleCollection bundles) - { - bundles.Add(new ScriptBundle("~/bundles/WebFormsJs").Include( - "~/Scripts/WebForms/WebForms.js", - "~/Scripts/WebForms/WebUIValidation.js", - "~/Scripts/WebForms/MenuStandards.js", - "~/Scripts/WebForms/Focus.js", - "~/Scripts/WebForms/GridView.js", - "~/Scripts/WebForms/DetailsView.js", - "~/Scripts/WebForms/TreeView.js", - "~/Scripts/WebForms/WebParts.js")); - - bundles.Add(new ScriptBundle("~/bundles/MsAjaxJs").Include( - "~/Scripts/WebForms/MsAjax/MicrosoftAjax.js", - "~/Scripts/WebForms/MsAjax/MicrosoftAjaxApplicationServices.js", - "~/Scripts/WebForms/MsAjax/MicrosoftAjaxTimer.js", - "~/Scripts/WebForms/MsAjax/MicrosoftAjaxWebForms.js")); - - // Use the Development version of Modernizr to develop with and learn from. Then, when you’re - // ready for production, use the build tool at http://modernizr.com to pick only the tests you need - bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( - "~/Scripts/modernizr-*")); - } - } -} \ No newline at end of file diff --git a/src/TestWebsites/WebForms/Bundle.config b/src/TestWebsites/WebForms/Bundle.config deleted file mode 100644 index 669a33e5b..000000000 --- a/src/TestWebsites/WebForms/Bundle.config +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/src/TestWebsites/WebForms/Global.asax.cs b/src/TestWebsites/WebForms/Global.asax.cs index 21e6fd992..57ad56372 100644 --- a/src/TestWebsites/WebForms/Global.asax.cs +++ b/src/TestWebsites/WebForms/Global.asax.cs @@ -14,7 +14,6 @@ namespace Test_Website_Webforms_NET45 void Application_Start(object sender, EventArgs e) { // Code that runs on application startup - BundleConfig.RegisterBundles(BundleTable.Bundles); RouteConfig.RegisterRoutes(RouteTable.Routes); } diff --git a/src/TestWebsites/WebForms/Site.Master b/src/TestWebsites/WebForms/Site.Master index ba076a8eb..4c342877f 100644 --- a/src/TestWebsites/WebForms/Site.Master +++ b/src/TestWebsites/WebForms/Site.Master @@ -5,35 +5,11 @@ <%: Page.Title %> - My ASP.NET Application - - <%: Scripts.Render("~/bundles/modernizr") %> - - -
    - - - <%--To learn more about bundling scripts in ScriptManager see http://go.microsoft.com/fwlink/?LinkID=272931&clcid=0x409 --%> - <%--Framework Scripts--%> - - - - - - - - - - - - <%--Site Scripts--%> - - -
    @@ -42,23 +18,6 @@

    -
    - - - - - -

    - Hello, - ! - -

    - - -