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 +