From 78f041d2224f656ddedf2ecda2d9adc38cd87d67 Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 30 Jun 2014 00:25:26 +0100 Subject: [PATCH] Fixing asp native binary loading Former-commit-id: e8e15db739bca8b30b9450e75a52588236364e85 --- 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