From 8ceafbda80d6f4b30b02642e81ae9cd5ecd282b1 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 1 Jul 2014 17:54:37 +0100 Subject: [PATCH] Tweaking gif frame creation and fixing unc folder access issue Former-commit-id: e0a7b73bc547b65651a848695000c26072401e31 --- .../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)