在将普通图片格式转换成webp格式时,之前一直是使用命令行的方式调用cwebp.exe,cwebp.exe下载地址.本文将尝试在C#中直接调用libwebp.dll的方式来生成webp格式的图片 编译或下载libwebp.dll 由于谷歌只提供了libwebp.lib,目前最新的版本是0.6.0,需要我们自行编译成libwebp.dll以便C#调用,或者从以下地址直接下载: x86_64/libwebp.dll x86/libwebp.dll 调用libwebp.dll的中间类 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Warper for WebP format in c#. (GPL) ///////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Main functions: /// Save - Save a bitmap in WebP file. /// Load - Load a WebP file in bitmap. /// Decode - Decode WebP data (in byte array) to bitmap. /// Encode - Encode bitmap to WebP (return a byte array). /// /// Another functions: /// EncodeLossly - Encode bitmap to WebP with quality lost (return a byte array). /// EncodeLossless - Encode bitmap to WebP without quality lost (return a byte array). ///////////////////////////////////////////////////////////////////////////////////////////////////////////// using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; namespace WebP { class clsWebP { /// <summary>Save bitmap to file in WebP format</summary> /// <param name="bmp">Bitmap with the WebP image</param> /// <param name="quality">Quality. 0 = minumin ... 100 = maximimun quality</param> /// <param name="pathFileName">The file to write</param> /// <returns>True if success; False otherwise</returns> public static bool Save(Bitmap bmp, int quality, string pathFileName) { byte[] dataWebP; try { //Encode in webP format if (!EncodeLossly(bmp, quality, out dataWebP)) return false; //Write webP file File.WriteAllBytes(pathFileName, dataWebP); return true; } catch (Exception ex) { return false; } } /// <summary>Read a WebP file</summary> /// <param name="pathFileName">WebP file to load</param> /// <param name="bmp">Bitmap with the WebP image</param> /// <returns>True if success; False otherwise</returns> public static bool Load(string pathFileName, out Bitmap bmp) { bool result; byte[] dataWebP; bmp = null; try { //Read webP file dataWebP = File.ReadAllBytes(pathFileName); result = Decode(dataWebP, out bmp); return result; } catch (Exception ex) { return false; } } /// <summary>Decode a WebP image</summary> /// <param name="webpData">the data to uncompress</param> /// <param name="bmp">Bitmap whit the image</param> /// <returns>True if success; False otherwise</returns> public static bool Decode(byte[] webpData, out Bitmap bmp) { int imgWidth; int imgHeight; IntPtr outputBuffer; int outputBufferSize; bmp = null; try { //Get image width and height GCHandle pinnedWebP = GCHandle.Alloc(webpData, GCHandleType.Pinned); IntPtr ptrData = pinnedWebP.AddrOfPinnedObject(); UInt32 dataSize = (uint)webpData.Length; if (WebPGetInfo(ptrData, dataSize, out imgWidth, out imgHeight) != 1) return false; //Create a BitmapData and Lock all pixels to be written bmp = new Bitmap(imgWidth, imgHeight, PixelFormat.Format24bppRgb); BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); //Allocate memory for uncompress image outputBufferSize = bmpData.Stride * imgHeight; outputBuffer = Marshal.AllocHGlobal(outputBufferSize); //Uncompress the image outputBuffer = WebPDecodeBGRInto(ptrData, dataSize, outputBuffer, outputBufferSize, bmpData.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); //Write image to bitmap using CopyMemory. Faster than Marshall, but only work in windows //CopyMemory(bmpData.Scan0, outputBuffer, (uint)outputBufferSize); //Unlock the pixels bmp.UnlockBits(bmpData); //Free memory pinnedWebP.Free(); Marshal.FreeHGlobal(outputBuffer); return true; } catch (Exception ex) { return false; } } /// <summary>Write a WebP file in minimun size</summary> /// <param name="webpData">Bitmap to encode</param> /// <param name="quality">Quality. 0 = minumin ... 100 = maximimun quality</param> /// <param name="bmp">Bitmap with the image</param> /// <returns>True if success; False otherwise</returns> public static bool Encode(Bitmap bmp, int quality, out byte[] webpData) { byte[] lossly; byte[] lossless; webpData = null; try { //compress in two metods if (!EncodeLossly(bmp, quality, out lossly)) return false; if (!EncodeLossless(bmp, out lossless)) return false; if (lossly.Length >= lossless.Length) webpData = lossless; else webpData = lossly; return true; } catch (Exception ex) { return false; } } /// <summary>Lossly encoding image in bitmap</summary> /// <param name="bmp">Bitmap with the image</param> /// <param name="quality">Quality. 0 = minumin ... 100 = maximimun quality</param> /// <param name="webpData">Compress data</param> /// <returns>True if success; False otherwise</returns> public static bool EncodeLossly(Bitmap bmp, int quality, out byte[] webpData) { BitmapData bmpData; IntPtr unmanagedData; int size; webpData = null; try { bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); size = WebPEncodeBGR(bmpData.Scan0, bmp.Width, bmp.Height, bmpData.Stride, quality, out unmanagedData); //Copy image compress data to output array webpData = new byte[size]; Marshal.Copy(unmanagedData, webpData, 0, size); //Unlock the pixels bmp.UnlockBits(bmpData); //Free memory WebPFree(unmanagedData); return true; } catch (Exception ex) { return false; } } /// <summary>Lossless encoding image in bitmap</summary> /// <param name="bmp">Bitmap with the image</param> /// <param name="webpData">Compress data</param> /// <returns>True if success; False otherwise</returns> public static bool EncodeLossless(Bitmap bmp, out byte[] webpData) { BitmapData bmpData; IntPtr unmanagedData; int size; webpData = null; try { //Get bmp data bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); //Compress the bmp data size = WebPEncodeLosslessBGR(bmpData.Scan0, bmp.Width, bmp.Height, bmpData.Stride, out unmanagedData); //Copy image compress data to output array webpData = new byte[size]; Marshal.Copy(unmanagedData, webpData, 0, size); //Unlock the pixels bmp.UnlockBits(bmpData); //Free memory WebPFree(unmanagedData); return true; } catch (Exception ex) { return false; } } /// <summary>Validate the WebP image header and retrieve the image height and width. Pointers *width and *height can be passed NULL if deemed irrelevant</summary> /// <param name="data">Pointer to WebP image data</param> /// <param name="data_size">This is the size of the memory block pointed to by data containing the image data</param> /// <param name="width">The range is limited currently from 1 to 16383</param> /// <param name="height">The range is limited currently from 1 to 16383</param> /// <returns>1 if success, otherwise error code returned in the case of (a) formatting error(s).</returns> [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int WebPGetInfo(IntPtr data, UInt32 data_size, out int width, out int height); /// <summary>Decode a WebP image pointed to by data</summary> /// <param name="data">Pointer to WebP image data</param> /// <param name="data_size">This is the size of the memory block pointed to by data containing the image data</param> /// <param name="width">The range is limited currently from 1 to 16383</param> /// <param name="height">The range is limited currently from 1 to 16383</param> /// <returns>output_buffer if function succeeds; NULL otherwise</returns> [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr WebPDecodeBGR(IntPtr data, UInt32 data_size, ref int width, ref int height); /// <summary>Decode WEBP image pointed to by *data and returns BGR samples into a pre-allocated buffer</summary> /// <param name="data">Pointer to WebP image data</param> /// <param name="data_size">This is the size of the memory block pointed to by data containing the image data</param> /// <param name="output_buffer">Pointer to decoded WebP image</param> /// <param name="output_buffer_size">Size of allocated buffer</param> /// <param name="output_stride">Specifies the distance between scanlines</param> /// <returns>output_buffer if function succeeds; NULL otherwise</returns> [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr WebPDecodeBGRInto(IntPtr data, UInt32 data_size, IntPtr output_buffer, int output_buffer_size, int output_stride); /// <summary>Lossless encoding images pointed to by *data in WebP format</summary> /// <param name="rgb">Pointer to RGB image data</param> /// <param name="width">The range is limited currently from 1 to 16383</param> /// <param name="height">The range is limited currently from 1 to 16383</param> /// <param name="output_stride">Specifies the distance between scanlines</param> /// <param name="quality_factor">Ranges from 0 (lower quality) to 100 (highest quality). Controls the loss and quality during compression</param> /// <param name="output">output_buffer with WebP image</param> /// <returns>Size of WebP Image</returns> [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int WebPEncodeBGR(IntPtr rgb, int width, int height, int stride, float quality_factor, out IntPtr output); /// <summary>Lossless encoding images pointed to by *data in WebP format</summary> /// <param name="rgb">Pointer to RGB image data</param> /// <param name="width">The range is limited currently from 1 to 16383</param> /// <param name="height">The range is limited currently from 1 to 16383</param> /// <param name="output_stride">Specifies the distance between scanlines</param> /// <param name="quality_factor">Ranges from 0 (lower quality) to 100 (highest quality). Controls the loss and quality during compression</param> /// <param name="output">output_buffer with WebP image</param> /// <returns>Size of WebP Image</returns> [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int WebPEncodeLosslessBGR(IntPtr rgb, int width, int height, int stride, out IntPtr output); [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int WebPFree(IntPtr p); //Faster copy, but only work in windows //[DllImport("kernel32.dll", EntryPoint = "CopyMemory")] //private static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length); } } Console Demo class Program { static void Main(string[] args) { //Test JPG to WebP Bitmap bmp1 = new Bitmap("test.jpg"); clsWebP.Save(bmp1, 80, "test.webp"); //Test WebP to PNG Bitmap bmp2; clsWebP.Load("test.webp", out bmp2); bmp2.Save("test.png", ImageFormat.Png); //Test JPG to WebP in lossless mode. Using compress in memory byte[] webpImageData1; Bitmap bmp3 = new Bitmap("test.jpg"); clsWebP.EncodeLossless(bmp3, out webpImageData1); File.WriteAllBytes("lossless.webp", webpImageData1); //Test JPG to WebP in lossly mode. Using encode in memory byte[] webpImageData2; Bitmap bmp4 = new Bitmap("test.jpg"); clsWebP.EncodeLossly(bmp4, 80, out webpImageData2); File.WriteAllBytes("lossly.webp", webpImageData2); //Test WebP to PNG. Using decode in memory Bitmap bmp5; byte[] webpImageData3 = File.ReadAllBytes("lossless.webp"); clsWebP.Decode(webpImageData3, out bmp5); bmp4.Save("test2.png", ImageFormat.Png); //Test WebP to pictureBox Bitmap bmp6; clsWebP.Load("test.webp", out bmp6); pictureBox.Image = bmp6; } } C++ Redistributable 在部署至服务器上时,如果服务器上没有安装Visual C++ 库的运行时组件,将无法调用libwebp.dll,具体会报如下的错误: System.DllNotFoundException: Unable to load DLL 'libwebp': The specified module could not be found. (Exception from HRESULT: 0x8007007E) 因此需要下载并安装Visual C++ Redistributable