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 8bc9002cd..000000000 --- a/src/ImageProcessorConsole/images/output/rotate.webp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:37d346c1cc3fe9635397d508ee332740f1043f942d940871e4cfc3b616cf5279 -size 1792