///////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Wrapper for WebP format in C#. (MIT) Jose M. Piñeiro ///////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Decode Functions: /// Bitmap Load(string pathFileName) - Load a WebP file in bitmap. /// Bitmap Decode(byte[] rawWebP) - Decode WebP data (rawWebP) to bitmap. /// Bitmap Decode(byte[] rawWebP, WebPDecoderOptions options) - Decode WebP data (rawWebP) to bitmap using 'options'. /// Bitmap GetThumbnailFast(byte[] rawWebP, int width, int height) - Get a thumbnail from WebP data (rawWebP) with dimensions 'width x height'. Fast mode. /// Bitmap GetThumbnailQuality(byte[] rawWebP, int width, int height) - Fast get a thumbnail from WebP data (rawWebP) with dimensions 'width x height'. Quality mode. /// /// Encode Functions: /// Save(Bitmap bmp, string pathFileName, int quality) - Save bitmap with quality lost to WebP file. Opcionally select 'quality'. /// byte[] EncodeLossy(Bitmap bmp, int quality) - Encode bitmap with quality lost to WebP byte array. Opcionally select 'quality'. /// byte[] EncodeLossy(Bitmap bmp, int quality, int speed, bool info) - Encode bitmap with quality lost to WebP byte array. Select 'quality', 'speed' and optionally select 'info'. /// byte[] EncodeLossless(Bitmap bmp) - Encode bitmap without quality lost to WebP byte array. /// byte[] EncodeLossless(Bitmap bmp, int speed, bool info = false) - Encode bitmap without quality lost to WebP byte array. Select 'speed'. /// byte[] EncodeNearLossless(Bitmap bmp, int quality, int speed = 9, bool info = false) - Encode bitmap with a near lossless method to WebP byte array. Select 'quality', 'speed' and optionally select 'info'. /// /// Another functions: /// string GetVersion() - Get the library version /// GetInfo(byte[] rawWebP, out int width, out int height, out bool has_alpha, out bool has_animation, out string format) - Get information of WEBP data /// float[] PictureDistortion(Bitmap source, Bitmap reference, int metric_type) - Get PSNR, SSIM or LSIM distortion metric between two pictures ///////////////////////////////////////////////////////////////////////////////////////////////////////////// using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; using System.Security; using System.Windows.Forms; namespace Wabbajack { public sealed class WebP : IDisposable { private const int WEBP_MAX_DIMENSION = 16383; #region | Public Decode Functions | /// Read a WebP file /// WebP file to load /// Bitmap with the WebP image public Bitmap Load(string pathFileName) { try { byte[] rawWebP = File.ReadAllBytes(pathFileName); return Decode(rawWebP); } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.Load"); } } /// Decode a WebP image /// The data to uncompress /// Bitmap with the WebP image public Bitmap Decode(byte[] rawWebP) { Bitmap bmp = null; BitmapData bmpData = null; GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned); try { //Get image width and height GetInfo(rawWebP, out int imgWidth, out int imgHeight, out bool hasAlpha, out bool hasAnimation, out string format); //Create a BitmapData and Lock all pixels to be written if (hasAlpha) bmp = new Bitmap(imgWidth, imgHeight, PixelFormat.Format32bppArgb); else bmp = new Bitmap(imgWidth, imgHeight, PixelFormat.Format24bppRgb); bmpData = bmp.LockBits(new Rectangle(0, 0, imgWidth, imgHeight), ImageLockMode.WriteOnly, bmp.PixelFormat); //Uncompress the image int outputSize = bmpData.Stride * imgHeight; IntPtr ptrData = pinnedWebP.AddrOfPinnedObject(); if (bmp.PixelFormat == PixelFormat.Format24bppRgb) UnsafeNativeMethods.WebPDecodeBGRInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride); else UnsafeNativeMethods.WebPDecodeBGRAInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride); return bmp; } catch (Exception) { throw; } finally { //Unlock the pixels if (bmpData != null) bmp.UnlockBits(bmpData); //Free memory if (pinnedWebP.IsAllocated) pinnedWebP.Free(); } } /// Decode a WebP image /// the data to uncompress /// Options for advanced decode /// Bitmap with the WebP image public Bitmap Decode(byte[] rawWebP, WebPDecoderOptions options, PixelFormat pixelFormat = PixelFormat.DontCare) { GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned); Bitmap bmp = null; BitmapData bmpData = null; VP8StatusCode result; try { WebPDecoderConfig config = new WebPDecoderConfig(); if (UnsafeNativeMethods.WebPInitDecoderConfig(ref config) == 0) { throw new Exception("WebPInitDecoderConfig failed. Wrong version?"); } // Read the .webp input file information IntPtr ptrRawWebP = pinnedWebP.AddrOfPinnedObject(); int height; int width; if (options.use_scaling == 0) { result = UnsafeNativeMethods.WebPGetFeatures(ptrRawWebP, rawWebP.Length, ref config.input); if (result != VP8StatusCode.VP8_STATUS_OK) throw new Exception("Failed WebPGetFeatures with error " + result); //Test cropping values if (options.use_cropping == 1) { if (options.crop_left + options.crop_width > config.input.Width || options.crop_top + options.crop_height > config.input.Height) throw new Exception("Crop options exceeded WebP image dimensions"); width = options.crop_width; height = options.crop_height; } } else { width = options.scaled_width; height = options.scaled_height; } config.options.bypass_filtering = options.bypass_filtering; config.options.no_fancy_upsampling = options.no_fancy_upsampling; config.options.use_cropping = options.use_cropping; config.options.crop_left = options.crop_left; config.options.crop_top = options.crop_top; config.options.crop_width = options.crop_width; config.options.crop_height = options.crop_height; config.options.use_scaling = options.use_scaling; config.options.scaled_width = options.scaled_width; config.options.scaled_height = options.scaled_height; config.options.use_threads = options.use_threads; config.options.dithering_strength = options.dithering_strength; config.options.flip = options.flip; config.options.alpha_dithering_strength = options.alpha_dithering_strength; //Create a BitmapData and Lock all pixels to be written if (config.input.Has_alpha == 1) { config.output.colorspace = WEBP_CSP_MODE.MODE_bgrA; bmp = new Bitmap(config.input.Width, config.input.Height, PixelFormat.Format32bppArgb); } else { config.output.colorspace = WEBP_CSP_MODE.MODE_BGR; bmp = new Bitmap(config.input.Width, config.input.Height, PixelFormat.Format24bppRgb); } bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); // Specify the output format config.output.u.RGBA.rgba = bmpData.Scan0; config.output.u.RGBA.stride = bmpData.Stride; config.output.u.RGBA.size = (UIntPtr)(bmp.Height * bmpData.Stride); config.output.height = bmp.Height; config.output.width = bmp.Width; config.output.is_external_memory = 1; // Decode result = UnsafeNativeMethods.WebPDecode(ptrRawWebP, rawWebP.Length, ref config); if (result != VP8StatusCode.VP8_STATUS_OK) { throw new Exception("Failed WebPDecode with error " + result); } UnsafeNativeMethods.WebPFreeDecBuffer(ref config.output); return bmp; } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.Decode"); } finally { //Unlock the pixels if (bmpData != null) bmp.UnlockBits(bmpData); //Free memory if (pinnedWebP.IsAllocated) pinnedWebP.Free(); } } /// Get Thumbnail from webP in mode faster/low quality /// The data to uncompress /// Wanted width of thumbnail /// Wanted height of thumbnail /// Bitmap with the WebP thumbnail in 24bpp public Bitmap GetThumbnailFast(byte[] rawWebP, int width, int height) { GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned); Bitmap bmp = null; BitmapData bmpData = null; try { WebPDecoderConfig config = new WebPDecoderConfig(); if (UnsafeNativeMethods.WebPInitDecoderConfig(ref config) == 0) throw new Exception("WebPInitDecoderConfig failed. Wrong version?"); // Set up decode options config.options.bypass_filtering = 1; config.options.no_fancy_upsampling = 1; config.options.use_threads = 1; config.options.use_scaling = 1; config.options.scaled_width = width; config.options.scaled_height = height; // Create a BitmapData and Lock all pixels to be written bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb); bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat); // Specify the output format config.output.colorspace = WEBP_CSP_MODE.MODE_BGR; config.output.u.RGBA.rgba = bmpData.Scan0; config.output.u.RGBA.stride = bmpData.Stride; config.output.u.RGBA.size = (UIntPtr)(height * bmpData.Stride); config.output.height = height; config.output.width = width; config.output.is_external_memory = 1; // Decode IntPtr ptrRawWebP = pinnedWebP.AddrOfPinnedObject(); VP8StatusCode result = UnsafeNativeMethods.WebPDecode(ptrRawWebP, rawWebP.Length, ref config); if (result != VP8StatusCode.VP8_STATUS_OK) throw new Exception("Failed WebPDecode with error " + result); UnsafeNativeMethods.WebPFreeDecBuffer(ref config.output); return bmp; } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.Thumbnail"); } finally { //Unlock the pixels if (bmpData != null) bmp.UnlockBits(bmpData); //Free memory if (pinnedWebP.IsAllocated) pinnedWebP.Free(); } } /// Thumbnail from webP in mode slow/high quality /// The data to uncompress /// Wanted width of thumbnail /// Wanted height of thumbnail /// Bitmap with the WebP thumbnail public Bitmap GetThumbnailQuality(byte[] rawWebP, int width, int height) { GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned); Bitmap bmp = null; BitmapData bmpData = null; try { WebPDecoderConfig config = new WebPDecoderConfig(); if (UnsafeNativeMethods.WebPInitDecoderConfig(ref config) == 0) throw new Exception("WebPInitDecoderConfig failed. Wrong version?"); IntPtr ptrRawWebP = pinnedWebP.AddrOfPinnedObject(); VP8StatusCode result = UnsafeNativeMethods.WebPGetFeatures(ptrRawWebP, rawWebP.Length, ref config.input); if (result != VP8StatusCode.VP8_STATUS_OK) throw new Exception("Failed WebPGetFeatures with error " + result); // Set up decode options config.options.bypass_filtering = 0; config.options.no_fancy_upsampling = 0; config.options.use_threads = 1; config.options.use_scaling = 1; config.options.scaled_width = width; config.options.scaled_height = height; //Create a BitmapData and Lock all pixels to be written if (config.input.Has_alpha == 1) { config.output.colorspace = WEBP_CSP_MODE.MODE_bgrA; bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); } else { config.output.colorspace = WEBP_CSP_MODE.MODE_BGR; bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb); } bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat); // Specify the output format config.output.u.RGBA.rgba = bmpData.Scan0; config.output.u.RGBA.stride = bmpData.Stride; config.output.u.RGBA.size = (UIntPtr)(height * bmpData.Stride); config.output.height = height; config.output.width = width; config.output.is_external_memory = 1; // Decode result = UnsafeNativeMethods.WebPDecode(ptrRawWebP, rawWebP.Length, ref config); if (result != VP8StatusCode.VP8_STATUS_OK) throw new Exception("Failed WebPDecode with error " + result); UnsafeNativeMethods.WebPFreeDecBuffer(ref config.output); return bmp; } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.Thumbnail"); } finally { //Unlock the pixels if (bmpData != null) bmp.UnlockBits(bmpData); //Free memory if (pinnedWebP.IsAllocated) pinnedWebP.Free(); } } #endregion #region | Public Encode Functions | /// Save bitmap to file in WebP format /// Bitmap with the WebP image /// The file to write /// Between 0 (lower quality, lowest file size) and 100 (highest quality, higher file size) public void Save(Bitmap bmp, string pathFileName, int quality = 75) { byte[] rawWebP; try { //Encode in webP format rawWebP = EncodeLossy(bmp, quality); //Write webP file File.WriteAllBytes(pathFileName, rawWebP); } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.Save"); } } /// Lossy encoding bitmap to WebP (Simple encoding API) /// Bitmap with the image /// Between 0 (lower quality, lowest file size) and 100 (highest quality, higher file size) /// Compressed data public byte[] EncodeLossy(Bitmap bmp, int quality = 75) { //test bmp if (bmp.Width == 0 || bmp.Height == 0) throw new ArgumentException("Bitmap contains no data.", "bmp"); if (bmp.Width > WEBP_MAX_DIMENSION || bmp.Height > WEBP_MAX_DIMENSION) throw new NotSupportedException("Bitmap's dimension is too large. Max is " + WEBP_MAX_DIMENSION + "x" + WEBP_MAX_DIMENSION + " pixels."); if (bmp.PixelFormat != PixelFormat.Format24bppRgb && bmp.PixelFormat != PixelFormat.Format32bppArgb) throw new NotSupportedException("Only support Format24bppRgb and Format32bppArgb pixelFormat."); BitmapData bmpData = null; IntPtr unmanagedData = IntPtr.Zero; try { int size; //Get bmp data bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); //Compress the bmp data if (bmp.PixelFormat == PixelFormat.Format24bppRgb) size = UnsafeNativeMethods.WebPEncodeBGR(bmpData.Scan0, bmp.Width, bmp.Height, bmpData.Stride, quality, out unmanagedData); else size = UnsafeNativeMethods.WebPEncodeBGRA(bmpData.Scan0, bmp.Width, bmp.Height, bmpData.Stride, quality, out unmanagedData); if (size == 0) throw new Exception("Can´t encode WebP"); //Copy image compress data to output array byte[] rawWebP = new byte[size]; Marshal.Copy(unmanagedData, rawWebP, 0, size); return rawWebP; } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.EncodeLossly"); } finally { //Unlock the pixels if (bmpData != null) bmp.UnlockBits(bmpData); //Free memory if (unmanagedData != IntPtr.Zero) UnsafeNativeMethods.WebPFree(unmanagedData); } } /// Lossy encoding bitmap to WebP (Advanced encoding API) /// Bitmap with the image /// Between 0 (lower quality, lowest file size) and 100 (highest quality, higher file size) /// Between 0 (fastest, lowest compression) and 9 (slower, best compression) /// Compressed data public byte[] EncodeLossy(Bitmap bmp, int quality, int speed, bool info = false) { //Initialize configuration structure WebPConfig config = new WebPConfig(); //Set compression parameters if (UnsafeNativeMethods.WebPConfigInit(ref config, WebPPreset.WEBP_PRESET_DEFAULT, 75) == 0) throw new Exception("Can´t configure preset"); // Add additional tuning: config.method = speed; if (config.method > 6) config.method = 6; config.quality = quality; config.autofilter = 1; config.pass = speed + 1; config.segments = 4; config.partitions = 3; config.thread_level = 1; config.alpha_quality = quality; config.alpha_filtering = 2; config.use_sharp_yuv = 1; if (UnsafeNativeMethods.WebPGetDecoderVersion() > 1082) //Old version does not support preprocessing 4 { config.preprocessing = 4; config.use_sharp_yuv = 1; } else config.preprocessing = 3; return AdvancedEncode(bmp, config, info); } /// Lossless encoding bitmap to WebP (Simple encoding API) /// Bitmap with the image /// Compressed data public byte[] EncodeLossless(Bitmap bmp) { //test bmp if (bmp.Width == 0 || bmp.Height == 0) throw new ArgumentException("Bitmap contains no data.", "bmp"); if (bmp.Width > WEBP_MAX_DIMENSION || bmp.Height > WEBP_MAX_DIMENSION) throw new NotSupportedException("Bitmap's dimension is too large. Max is " + WEBP_MAX_DIMENSION + "x" + WEBP_MAX_DIMENSION + " pixels."); if (bmp.PixelFormat != PixelFormat.Format24bppRgb && bmp.PixelFormat != PixelFormat.Format32bppArgb) throw new NotSupportedException("Only support Format24bppRgb and Format32bppArgb pixelFormat."); BitmapData bmpData = null; IntPtr unmanagedData = IntPtr.Zero; try { //Get bmp data bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); //Compress the bmp data int size; if (bmp.PixelFormat == PixelFormat.Format24bppRgb) size = UnsafeNativeMethods.WebPEncodeLosslessBGR(bmpData.Scan0, bmp.Width, bmp.Height, bmpData.Stride, out unmanagedData); else size = UnsafeNativeMethods.WebPEncodeLosslessBGRA(bmpData.Scan0, bmp.Width, bmp.Height, bmpData.Stride, out unmanagedData); //Copy image compress data to output array byte[] rawWebP = new byte[size]; Marshal.Copy(unmanagedData, rawWebP, 0, size); return rawWebP; } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.EncodeLossless (Simple)"); } finally { //Unlock the pixels if (bmpData != null) bmp.UnlockBits(bmpData); //Free memory if (unmanagedData != IntPtr.Zero) UnsafeNativeMethods.WebPFree(unmanagedData); } } /// Lossless encoding image in bitmap (Advanced encoding API) /// Bitmap with the image /// Between 0 (fastest, lowest compression) and 9 (slower, best compression) /// Compressed data public byte[] EncodeLossless(Bitmap bmp, int speed) { //Initialize configuration structure WebPConfig config = new WebPConfig(); //Set compression parameters if (UnsafeNativeMethods.WebPConfigInit(ref config, WebPPreset.WEBP_PRESET_DEFAULT, (speed + 1) * 10) == 0) throw new Exception("Can´t config preset"); //Old version of DLL does not support info and WebPConfigLosslessPreset if (UnsafeNativeMethods.WebPGetDecoderVersion() > 1082) { if (UnsafeNativeMethods.WebPConfigLosslessPreset(ref config, speed) == 0) throw new Exception("Can´t configure lossless preset"); } else { config.lossless = 1; config.method = speed; if (config.method > 6) config.method = 6; config.quality = (speed + 1) * 10; } config.pass = speed + 1; config.thread_level = 1; config.alpha_filtering = 2; config.use_sharp_yuv = 1; config.exact = 0; return AdvancedEncode(bmp, config, false); } /// Near lossless encoding image in bitmap /// Bitmap with the image /// Between 0 (lower quality, lowest file size) and 100 (highest quality, higher file size) /// Between 0 (fastest, lowest compression) and 9 (slower, best compression) /// Compress data public byte[] EncodeNearLossless(Bitmap bmp, int quality, int speed = 9) { //test DLL version if (UnsafeNativeMethods.WebPGetDecoderVersion() <= 1082) throw new Exception("This DLL version not support EncodeNearLossless"); //Inicialize config struct WebPConfig config = new WebPConfig(); //Set compression parameters if (UnsafeNativeMethods.WebPConfigInit(ref config, WebPPreset.WEBP_PRESET_DEFAULT, (speed + 1) * 10) == 0) throw new Exception("Can´t configure preset"); if (UnsafeNativeMethods.WebPConfigLosslessPreset(ref config, speed) == 0) throw new Exception("Can´t configure lossless preset"); config.pass = speed + 1; config.near_lossless = quality; config.thread_level = 1; config.alpha_filtering = 2; config.use_sharp_yuv = 1; config.exact = 0; return AdvancedEncode(bmp, config, false); } #endregion #region | Another Public Functions | /// Get the libwebp version /// Version of library public string GetVersion() { try { uint v = (uint)UnsafeNativeMethods.WebPGetDecoderVersion(); var revision = v % 256; var minor = (v >> 8) % 256; var major = (v >> 16) % 256; return major + "." + minor + "." + revision; } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.GetVersion"); } } /// Get info of WEBP data /// The data of WebP /// width of image /// height of image /// Image has alpha channel /// Image is a animation /// Format of image: 0 = undefined (/mixed), 1 = lossy, 2 = lossless public void GetInfo(byte[] rawWebP, out int width, out int height, out bool has_alpha, out bool has_animation, out string format) { VP8StatusCode result; GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned); try { IntPtr ptrRawWebP = pinnedWebP.AddrOfPinnedObject(); WebPBitstreamFeatures features = new WebPBitstreamFeatures(); result = UnsafeNativeMethods.WebPGetFeatures(ptrRawWebP, rawWebP.Length, ref features); if (result != 0) throw new Exception(result.ToString()); width = features.Width; height = features.Height; if (features.Has_alpha == 1) has_alpha = true; else has_alpha = false; if (features.Has_animation == 1) has_animation = true; else has_animation = false; switch (features.Format) { case 1: format = "lossy"; break; case 2: format = "lossless"; break; default: format = "undefined"; break; } } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.GetInfo"); } finally { //Free memory if (pinnedWebP.IsAllocated) pinnedWebP.Free(); } } /// Compute PSNR, SSIM or LSIM distortion metric between two pictures. Warning: this function is rather CPU-intensive /// Picture to measure /// Reference picture /// 0 = PSNR, 1 = SSIM, 2 = LSIM /// dB in the Y/U/V/Alpha/All order public float[] GetPictureDistortion(Bitmap source, Bitmap reference, int metric_type) { WebPPicture wpicSource = new WebPPicture(); WebPPicture wpicReference = new WebPPicture(); BitmapData sourceBmpData = null; BitmapData referenceBmpData = null; float[] result = new float[5]; GCHandle pinnedResult = GCHandle.Alloc(result, GCHandleType.Pinned); try { if (source == null) throw new Exception("Source picture is void"); if (reference == null) throw new Exception("Reference picture is void"); if (metric_type > 2) throw new Exception("Bad metric_type. Use 0 = PSNR, 1 = SSIM, 2 = LSIM"); if (source.Width != reference.Width || source.Height != reference.Height) throw new Exception("Source and Reference pictures have different dimensions"); // Setup the source picture data, allocating the bitmap, width and height sourceBmpData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat); wpicSource = new WebPPicture(); if (UnsafeNativeMethods.WebPPictureInitInternal(ref wpicSource) != 1) throw new Exception("Can´t initialize WebPPictureInit"); wpicSource.width = (int)source.Width; wpicSource.height = (int)source.Height; //Put the source bitmap componets in wpic if (sourceBmpData.PixelFormat == PixelFormat.Format32bppArgb) { wpicSource.use_argb = 1; if (UnsafeNativeMethods.WebPPictureImportBGRA(ref wpicSource, sourceBmpData.Scan0, sourceBmpData.Stride) != 1) throw new Exception("Can´t allocate memory in WebPPictureImportBGR"); } else { wpicSource.use_argb = 0; if (UnsafeNativeMethods.WebPPictureImportBGR(ref wpicSource, sourceBmpData.Scan0, sourceBmpData.Stride) != 1) throw new Exception("Can´t allocate memory in WebPPictureImportBGR"); } // Setup the reference picture data, allocating the bitmap, width and height referenceBmpData = reference.LockBits(new Rectangle(0, 0, reference.Width, reference.Height), ImageLockMode.ReadOnly, reference.PixelFormat); wpicReference = new WebPPicture(); if (UnsafeNativeMethods.WebPPictureInitInternal(ref wpicReference) != 1) throw new Exception("Can´t initialize WebPPictureInit"); wpicReference.width = (int)reference.Width; wpicReference.height = (int)reference.Height; wpicReference.use_argb = 1; //Put the source bitmap contents in WebPPicture instance if (sourceBmpData.PixelFormat == PixelFormat.Format32bppArgb) { wpicSource.use_argb = 1; if (UnsafeNativeMethods.WebPPictureImportBGRA(ref wpicReference, referenceBmpData.Scan0, referenceBmpData.Stride) != 1) throw new Exception("Can´t allocate memory in WebPPictureImportBGR"); } else { wpicSource.use_argb = 0; if (UnsafeNativeMethods.WebPPictureImportBGR(ref wpicReference, referenceBmpData.Scan0, referenceBmpData.Stride) != 1) throw new Exception("Can´t allocate memory in WebPPictureImportBGR"); } //Measure IntPtr ptrResult = pinnedResult.AddrOfPinnedObject(); if (UnsafeNativeMethods.WebPPictureDistortion(ref wpicSource, ref wpicReference, metric_type, ptrResult) != 1) throw new Exception("Can´t measure."); return result; } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.GetPictureDistortion"); } finally { //Unlock the pixels if (sourceBmpData != null) source.UnlockBits(sourceBmpData); if (referenceBmpData != null) reference.UnlockBits(referenceBmpData); //Free memory if (wpicSource.argb != IntPtr.Zero) UnsafeNativeMethods.WebPPictureFree(ref wpicSource); if (wpicReference.argb != IntPtr.Zero) UnsafeNativeMethods.WebPPictureFree(ref wpicReference); //Free memory if (pinnedResult.IsAllocated) pinnedResult.Free(); } } #endregion #region | Private Methods | /// Encoding image using Advanced encoding API /// Bitmap with the image /// Configuration for encode /// True if need encode info. /// Compressed data private byte[] AdvancedEncode(Bitmap bmp, WebPConfig config, bool info) { byte[] rawWebP = null; byte[] dataWebp = null; WebPPicture wpic = new WebPPicture(); BitmapData bmpData = null; WebPAuxStats stats = new WebPAuxStats(); IntPtr ptrStats = IntPtr.Zero; GCHandle pinnedArrayHandle = new GCHandle(); int dataWebpSize; try { //Validate the configuration if (UnsafeNativeMethods.WebPValidateConfig(ref config) != 1) throw new Exception("Bad configuration parameters"); //test bmp if (bmp.Width == 0 || bmp.Height == 0) throw new ArgumentException("Bitmap contains no data.", "bmp"); if (bmp.Width > WEBP_MAX_DIMENSION || bmp.Height > WEBP_MAX_DIMENSION) throw new NotSupportedException("Bitmap's dimension is too large. Max is " + WEBP_MAX_DIMENSION + "x" + WEBP_MAX_DIMENSION + " pixels."); if (bmp.PixelFormat != PixelFormat.Format24bppRgb && bmp.PixelFormat != PixelFormat.Format32bppArgb) throw new NotSupportedException("Only support Format24bppRgb and Format32bppArgb pixelFormat."); // Setup the input data, allocating a the bitmap, width and height bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); if (UnsafeNativeMethods.WebPPictureInitInternal(ref wpic) != 1) throw new Exception("Can´t initialize WebPPictureInit"); wpic.width = (int)bmp.Width; wpic.height = (int)bmp.Height; wpic.use_argb = 1; if (bmp.PixelFormat == PixelFormat.Format32bppArgb) { //Put the bitmap componets in wpic int result = UnsafeNativeMethods.WebPPictureImportBGRA(ref wpic, bmpData.Scan0, bmpData.Stride); if (result != 1) throw new Exception("Can´t allocate memory in WebPPictureImportBGRA"); wpic.colorspace = (uint)WEBP_CSP_MODE.MODE_bgrA; dataWebpSize = bmp.Width * bmp.Height * 32; dataWebp = new byte[bmp.Width * bmp.Height * 32]; //Memory for WebP output } else { //Put the bitmap contents in WebPPicture instance int result = UnsafeNativeMethods.WebPPictureImportBGR(ref wpic, bmpData.Scan0, bmpData.Stride); if (result != 1) throw new Exception("Can´t allocate memory in WebPPictureImportBGR"); dataWebpSize = bmp.Width * bmp.Height * 24; } //Set up statistics of compression if (info) { stats = new WebPAuxStats(); ptrStats = Marshal.AllocHGlobal(Marshal.SizeOf(stats)); Marshal.StructureToPtr(stats, ptrStats, false); wpic.stats = ptrStats; } //Memory for WebP output if (dataWebpSize > 2147483591) dataWebpSize = 2147483591; dataWebp = new byte[bmp.Width * bmp.Height * 32]; pinnedArrayHandle = GCHandle.Alloc(dataWebp, GCHandleType.Pinned); IntPtr initPtr = pinnedArrayHandle.AddrOfPinnedObject(); wpic.custom_ptr = initPtr; //Set up a byte-writing method (write-to-memory, in this case) UnsafeNativeMethods.OnCallback = new UnsafeNativeMethods.WebPMemoryWrite(MyWriter); wpic.writer = Marshal.GetFunctionPointerForDelegate(UnsafeNativeMethods.OnCallback); //compress the input samples if (UnsafeNativeMethods.WebPEncode(ref config, ref wpic) != 1) throw new Exception("Encoding error: " + ((WebPEncodingError)wpic.error_code).ToString()); //Remove OnCallback UnsafeNativeMethods.OnCallback = null; //Unlock the pixels bmp.UnlockBits(bmpData); bmpData = null; //Copy webpData to rawWebP int size = (int)((long)wpic.custom_ptr - (long)initPtr); rawWebP = new byte[size]; Array.Copy(dataWebp, rawWebP, size); //Remove compression data pinnedArrayHandle.Free(); dataWebp = null; //Show statistics if (info) { stats = (WebPAuxStats)Marshal.PtrToStructure(ptrStats, typeof(WebPAuxStats)); MessageBox.Show("Dimension: " + wpic.width + " x " + wpic.height + " pixels\n" + "Output: " + stats.coded_size + " bytes\n" + "PSNR Y: " + stats.PSNRY + " db\n" + "PSNR u: " + stats.PSNRU + " db\n" + "PSNR v: " + stats.PSNRV + " db\n" + "PSNR ALL: " + stats.PSNRALL + " db\n" + "Block intra4: " + stats.block_count_intra4 + "\n" + "Block intra16: " + stats.block_count_intra16 + "\n" + "Block skipped: " + stats.block_count_skipped + "\n" + "Header size: " + stats.header_bytes + " bytes\n" + "Mode-partition: " + stats.mode_partition_0 + " bytes\n" + "Macro-blocks 0: " + stats.segment_size_segments0 + " residuals bytes\n" + "Macro-blocks 1: " + stats.segment_size_segments1 + " residuals bytes\n" + "Macro-blocks 2: " + stats.segment_size_segments2 + " residuals bytes\n" + "Macro-blocks 3: " + stats.segment_size_segments3 + " residuals bytes\n" + "Quantizer 0: " + stats.segment_quant_segments0 + " residuals bytes\n" + "Quantizer 1: " + stats.segment_quant_segments1 + " residuals bytes\n" + "Quantizer 2: " + stats.segment_quant_segments2 + " residuals bytes\n" + "Quantizer 3: " + stats.segment_quant_segments3 + " residuals bytes\n" + "Filter level 0: " + stats.segment_level_segments0 + " residuals bytes\n" + "Filter level 1: " + stats.segment_level_segments1 + " residuals bytes\n" + "Filter level 2: " + stats.segment_level_segments2 + " residuals bytes\n" + "Filter level 3: " + stats.segment_level_segments3 + " residuals bytes\n", "Compression statistics"); } return rawWebP; } catch (Exception ex) { throw new Exception(ex.Message + "\r\nIn WebP.AdvancedEncode"); } finally { //Free temporal compress memory if (pinnedArrayHandle.IsAllocated) { pinnedArrayHandle.Free(); } //Free statistics memory if (ptrStats != IntPtr.Zero) { Marshal.FreeHGlobal(ptrStats); } //Unlock the pixels if (bmpData != null) { bmp.UnlockBits(bmpData); } //Free memory if (wpic.argb != IntPtr.Zero) { UnsafeNativeMethods.WebPPictureFree(ref wpic); } } } private int MyWriter([InAttribute()] IntPtr data, UIntPtr data_size, ref WebPPicture picture) { UnsafeNativeMethods.CopyMemory(picture.custom_ptr, data, (uint)data_size); //picture.custom_ptr = IntPtr.Add(picture.custom_ptr, (int)data_size); //Only in .NET > 4.0 picture.custom_ptr = new IntPtr(picture.custom_ptr.ToInt64() + (int)data_size); return 1; } private delegate int MyWriterDelegate([InAttribute()] IntPtr data, UIntPtr data_size, ref WebPPicture picture); #endregion #region | Destruction | /// Free memory public void Dispose() { GC.SuppressFinalize(this); } #endregion } #region | Import libwebp functions | [SuppressUnmanagedCodeSecurityAttribute] internal sealed partial class UnsafeNativeMethods { [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] internal static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); private static readonly int WEBP_DECODER_ABI_VERSION = 0x0208; /// This function will initialize the configuration according to a predefined set of parameters (referred to by 'preset') and a given quality factor /// The WebPConfig structure /// Type of image /// Quality of compression /// 0 if error internal static int WebPConfigInit(ref WebPConfig config, WebPPreset preset, float quality) { switch (IntPtr.Size) { case 4: return WebPConfigInitInternal_x86(ref config, preset, quality, WEBP_DECODER_ABI_VERSION); case 8: return WebPConfigInitInternal_x64(ref config, preset, quality, WEBP_DECODER_ABI_VERSION); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPConfigInitInternal")] private static extern int WebPConfigInitInternal_x86(ref WebPConfig config, WebPPreset preset, float quality, int WEBP_DECODER_ABI_VERSION); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPConfigInitInternal")] private static extern int WebPConfigInitInternal_x64(ref WebPConfig config, WebPPreset preset, float quality, int WEBP_DECODER_ABI_VERSION); /// Get info of WepP image /// Bytes[] of WebP image /// Size of rawWebP /// Features of WebP image /// VP8StatusCode internal static VP8StatusCode WebPGetFeatures(IntPtr rawWebP, int data_size, ref WebPBitstreamFeatures features) { switch (IntPtr.Size) { case 4: return WebPGetFeaturesInternal_x86(rawWebP, (UIntPtr)data_size, ref features, WEBP_DECODER_ABI_VERSION); case 8: return WebPGetFeaturesInternal_x64(rawWebP, (UIntPtr)data_size, ref features, WEBP_DECODER_ABI_VERSION); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetFeaturesInternal")] private static extern VP8StatusCode WebPGetFeaturesInternal_x86([InAttribute()] IntPtr rawWebP, UIntPtr data_size, ref WebPBitstreamFeatures features, int WEBP_DECODER_ABI_VERSION); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetFeaturesInternal")] private static extern VP8StatusCode WebPGetFeaturesInternal_x64([InAttribute()] IntPtr rawWebP, UIntPtr data_size, ref WebPBitstreamFeatures features, int WEBP_DECODER_ABI_VERSION); /// Activate the lossless compression mode with the desired efficiency /// The WebPConfig struct /// between 0 (fastest, lowest compression) and 9 (slower, best compression) /// 0 in case of parameter error internal static int WebPConfigLosslessPreset(ref WebPConfig config, int level) { switch (IntPtr.Size) { case 4: return WebPConfigLosslessPreset_x86(ref config, level); case 8: return WebPConfigLosslessPreset_x64(ref config, level); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPConfigLosslessPreset")] private static extern int WebPConfigLosslessPreset_x86(ref WebPConfig config, int level); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPConfigLosslessPreset")] private static extern int WebPConfigLosslessPreset_x64(ref WebPConfig config, int level); /// Check that configuration is non-NULL and all configuration parameters are within their valid ranges /// The WebPConfig structure /// 1 if configuration is OK internal static int WebPValidateConfig(ref WebPConfig config) { switch (IntPtr.Size) { case 4: return WebPValidateConfig_x86(ref config); case 8: return WebPValidateConfig_x64(ref config); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPValidateConfig")] private static extern int WebPValidateConfig_x86(ref WebPConfig config); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPValidateConfig")] private static extern int WebPValidateConfig_x64(ref WebPConfig config); /// Initialize the WebPPicture structure checking the DLL version /// The WebPPicture structure /// 1 if not error internal static int WebPPictureInitInternal(ref WebPPicture wpic) { switch (IntPtr.Size) { case 4: return WebPPictureInitInternal_x86(ref wpic, WEBP_DECODER_ABI_VERSION); case 8: return WebPPictureInitInternal_x64(ref wpic, WEBP_DECODER_ABI_VERSION); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureInitInternal")] private static extern int WebPPictureInitInternal_x86(ref WebPPicture wpic, int WEBP_DECODER_ABI_VERSION); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureInitInternal")] private static extern int WebPPictureInitInternal_x64(ref WebPPicture wpic, int WEBP_DECODER_ABI_VERSION); /// Colorspace conversion function to import RGB samples /// The WebPPicture structure /// Point to BGR data /// stride of BGR data /// Returns 0 in case of memory error. internal static int WebPPictureImportBGR(ref WebPPicture wpic, IntPtr bgr, int stride) { switch (IntPtr.Size) { case 4: return WebPPictureImportBGR_x86(ref wpic, bgr, stride); case 8: return WebPPictureImportBGR_x64(ref wpic, bgr, stride); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGR")] private static extern int WebPPictureImportBGR_x86(ref WebPPicture wpic, IntPtr bgr, int stride); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGR")] private static extern int WebPPictureImportBGR_x64(ref WebPPicture wpic, IntPtr bgr, int stride); /// Color-space conversion function to import RGB samples /// The WebPPicture structure /// Point to BGRA data /// stride of BGRA data /// Returns 0 in case of memory error. internal static int WebPPictureImportBGRA(ref WebPPicture wpic, IntPtr bgra, int stride) { switch (IntPtr.Size) { case 4: return WebPPictureImportBGRA_x86(ref wpic, bgra, stride); case 8: return WebPPictureImportBGRA_x64(ref wpic, bgra, stride); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGRA")] private static extern int WebPPictureImportBGRA_x86(ref WebPPicture wpic, IntPtr bgra, int stride); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGRA")] private static extern int WebPPictureImportBGRA_x64(ref WebPPicture wpic, IntPtr bgra, int stride); /// Color-space conversion function to import RGB samples /// The WebPPicture structure /// Point to BGR data /// stride of BGR data /// Returns 0 in case of memory error. internal static int WebPPictureImportBGRX(ref WebPPicture wpic, IntPtr bgr, int stride) { switch (IntPtr.Size) { case 4: return WebPPictureImportBGRX_x86(ref wpic, bgr, stride); case 8: return WebPPictureImportBGRX_x64(ref wpic, bgr, stride); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGRX")] private static extern int WebPPictureImportBGRX_x86(ref WebPPicture wpic, IntPtr bgr, int stride); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGRX")] private static extern int WebPPictureImportBGRX_x64(ref WebPPicture wpic, IntPtr bgr, int stride); /// The writer type for output compress data /// Data returned /// Size of data returned /// Picture structure /// [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int WebPMemoryWrite([In()] IntPtr data, UIntPtr data_size, ref WebPPicture wpic); internal static WebPMemoryWrite OnCallback; /// Compress to WebP format /// The configuration structure for compression parameters /// 'picture' hold the source samples in both YUV(A) or ARGB input /// Returns 0 in case of error, 1 otherwise. In case of error, picture->error_code is updated accordingly. internal static int WebPEncode(ref WebPConfig config, ref WebPPicture picture) { switch (IntPtr.Size) { case 4: return WebPEncode_x86(ref config, ref picture); case 8: return WebPEncode_x64(ref config, ref picture); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncode")] private static extern int WebPEncode_x86(ref WebPConfig config, ref WebPPicture picture); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncode")] private static extern int WebPEncode_x64(ref WebPConfig config, ref WebPPicture picture); /// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*() /// Note that this function does _not_ free the memory used by the 'picture' object itself. /// Besides memory (which is reclaimed) all other fields of 'picture' are preserved /// Picture structure internal static void WebPPictureFree(ref WebPPicture picture) { switch (IntPtr.Size) { case 4: WebPPictureFree_x86(ref picture); break; case 8: WebPPictureFree_x64(ref picture); break; default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureFree")] private static extern void WebPPictureFree_x86(ref WebPPicture wpic); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureFree")] private static extern void WebPPictureFree_x64(ref WebPPicture wpic); /// Validate the WebP image header and retrieve the image height and width. Pointers *width and *height can be passed NULL if deemed irrelevant /// Pointer to WebP image data /// This is the size of the memory block pointed to by data containing the image data /// The range is limited currently from 1 to 16383 /// The range is limited currently from 1 to 16383 /// 1 if success, otherwise error code returned in the case of (a) formatting error(s). internal static int WebPGetInfo(IntPtr data, int data_size, out int width, out int height) { switch (IntPtr.Size) { case 4: return WebPGetInfo_x86(data, (UIntPtr)data_size, out width, out height); case 8: return WebPGetInfo_x64(data, (UIntPtr)data_size, out width, out height); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetInfo")] private static extern int WebPGetInfo_x86([InAttribute()] IntPtr data, UIntPtr data_size, out int width, out int height); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetInfo")] private static extern int WebPGetInfo_x64([InAttribute()] IntPtr data, UIntPtr data_size, out int width, out int height); /// Decode WEBP image pointed to by *data and returns BGR samples into a preallocated buffer /// Pointer to WebP image data /// This is the size of the memory block pointed to by data containing the image data /// Pointer to decoded WebP image /// Size of allocated buffer /// Specifies the distance between scan lines internal static void WebPDecodeBGRInto(IntPtr data, int data_size, IntPtr output_buffer, int output_buffer_size, int output_stride) { switch (IntPtr.Size) { case 4: if (WebPDecodeBGRInto_x86(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null) throw new InvalidOperationException("Can not decode WebP"); break; case 8: if (WebPDecodeBGRInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null) throw new InvalidOperationException("Can not decode WebP"); break; default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRInto")] private static extern IntPtr WebPDecodeBGRInto_x86([InAttribute()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRInto")] private static extern IntPtr WebPDecodeBGRInto_x64([InAttribute()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride); /// Decode WEBP image pointed to by *data and returns BGRA samples into a preallocated buffer /// Pointer to WebP image data /// This is the size of the memory block pointed to by data containing the image data /// Pointer to decoded WebP image /// Size of allocated buffer /// Specifies the distance between scan lines internal static void WebPDecodeBGRAInto(IntPtr data, int data_size, IntPtr output_buffer, int output_buffer_size, int output_stride) { switch (IntPtr.Size) { case 4: if (WebPDecodeBGRAInto_x86(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null) throw new InvalidOperationException("Can not decode WebP"); break; case 8: if (WebPDecodeBGRAInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null) throw new InvalidOperationException("Can not decode WebP"); break; default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")] private static extern IntPtr WebPDecodeBGRAInto_x86([InAttribute()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")] private static extern IntPtr WebPDecodeBGRAInto_x64([InAttribute()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride); /// Decode WEBP image pointed to by *data and returns ARGB samples into a preallocated buffer /// Pointer to WebP image data /// This is the size of the memory block pointed to by data containing the image data /// Pointer to decoded WebP image /// Size of allocated buffer /// Specifies the distance between scan lines internal static void WebPDecodeARGBInto(IntPtr data, int data_size, IntPtr output_buffer, int output_buffer_size, int output_stride) { switch (IntPtr.Size) { case 4: if (WebPDecodeARGBInto_x86(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null) throw new InvalidOperationException("Can not decode WebP"); break; case 8: if (WebPDecodeARGBInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null) throw new InvalidOperationException("Can not decode WebP"); break; default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeARGBInto")] private static extern IntPtr WebPDecodeARGBInto_x86([InAttribute()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeARGBInto")] private static extern IntPtr WebPDecodeARGBInto_x64([InAttribute()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride); /// Initialize the configuration as empty. This function must always be called first, unless WebPGetFeatures() is to be called /// Configuration structure /// False in case of mismatched version. internal static int WebPInitDecoderConfig(ref WebPDecoderConfig webPDecoderConfig) { switch (IntPtr.Size) { case 4: return WebPInitDecoderConfigInternal_x86(ref webPDecoderConfig, WEBP_DECODER_ABI_VERSION); case 8: return WebPInitDecoderConfigInternal_x64(ref webPDecoderConfig, WEBP_DECODER_ABI_VERSION); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPInitDecoderConfigInternal")] private static extern int WebPInitDecoderConfigInternal_x86(ref WebPDecoderConfig webPDecoderConfig, int WEBP_DECODER_ABI_VERSION); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPInitDecoderConfigInternal")] private static extern int WebPInitDecoderConfigInternal_x64(ref WebPDecoderConfig webPDecoderConfig, int WEBP_DECODER_ABI_VERSION); /// Decodes the full data at once, taking configuration into account /// WebP raw data to decode /// Size of WebP data /// Configuration structure /// VP8_STATUS_OK if the decoding was successful internal static VP8StatusCode WebPDecode(IntPtr data, int data_size, ref WebPDecoderConfig webPDecoderConfig) { switch (IntPtr.Size) { case 4: return WebPDecode_x86(data, (UIntPtr)data_size, ref webPDecoderConfig); case 8: return WebPDecode_x64(data, (UIntPtr)data_size, ref webPDecoderConfig); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecode")] private static extern VP8StatusCode WebPDecode_x86(IntPtr data, UIntPtr data_size, ref WebPDecoderConfig config); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecode")] private static extern VP8StatusCode WebPDecode_x64(IntPtr data, UIntPtr data_size, ref WebPDecoderConfig config); /// Free any memory associated with the buffer. Must always be called last. Doesn't free the 'buffer' structure itself /// WebPDecBuffer internal static void WebPFreeDecBuffer(ref WebPDecBuffer buffer) { switch (IntPtr.Size) { case 4: WebPFreeDecBuffer_x86(ref buffer); break; case 8: WebPFreeDecBuffer_x64(ref buffer); break; default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFreeDecBuffer")] private static extern void WebPFreeDecBuffer_x86(ref WebPDecBuffer buffer); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFreeDecBuffer")] private static extern void WebPFreeDecBuffer_x64(ref WebPDecBuffer buffer); /// Lossy encoding images /// Pointer to BGR image data /// The range is limited currently from 1 to 16383 /// The range is limited currently from 1 to 16383 /// Specifies the distance between scanlines /// Ranges from 0 (lower quality) to 100 (highest quality). Controls the loss and quality during compression /// output_buffer with WebP image /// Size of WebP Image or 0 if an error occurred internal static int WebPEncodeBGR(IntPtr bgr, int width, int height, int stride, float quality_factor, out IntPtr output) { switch (IntPtr.Size) { case 4: return WebPEncodeBGR_x86(bgr, width, height, stride, quality_factor, out output); case 8: return WebPEncodeBGR_x64(bgr, width, height, stride, quality_factor, out output); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGR")] private static extern int WebPEncodeBGR_x86([InAttribute()] IntPtr bgr, int width, int height, int stride, float quality_factor, out IntPtr output); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGR")] private static extern int WebPEncodeBGR_x64([InAttribute()] IntPtr bgr, int width, int height, int stride, float quality_factor, out IntPtr output); /// Lossy encoding images /// Pointer to BGRA image data /// The range is limited currently from 1 to 16383 /// The range is limited currently from 1 to 16383 /// Specifies the distance between scan lines /// Ranges from 0 (lower quality) to 100 (highest quality). Controls the loss and quality during compression /// output_buffer with WebP image /// Size of WebP Image or 0 if an error occurred internal static int WebPEncodeBGRA(IntPtr bgra, int width, int height, int stride, float quality_factor, out IntPtr output) { switch (IntPtr.Size) { case 4: return WebPEncodeBGRA_x86(bgra, width, height, stride, quality_factor, out output); case 8: return WebPEncodeBGRA_x64(bgra, width, height, stride, quality_factor, out output); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGRA")] private static extern int WebPEncodeBGRA_x86([InAttribute()] IntPtr bgra, int width, int height, int stride, float quality_factor, out IntPtr output); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGRA")] private static extern int WebPEncodeBGRA_x64([InAttribute()] IntPtr bgra, int width, int height, int stride, float quality_factor, out IntPtr output); /// Lossless encoding images pointed to by *data in WebP format /// Pointer to BGR image data /// The range is limited currently from 1 to 16383 /// The range is limited currently from 1 to 16383 /// Specifies the distance between scan lines /// output_buffer with WebP image /// Size of WebP Image or 0 if an error occurred internal static int WebPEncodeLosslessBGR(IntPtr bgr, int width, int height, int stride, out IntPtr output) { switch (IntPtr.Size) { case 4: return WebPEncodeLosslessBGR_x86(bgr, width, height, stride, out output); case 8: return WebPEncodeLosslessBGR_x64(bgr, width, height, stride, out output); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeLosslessBGR")] private static extern int WebPEncodeLosslessBGR_x86([InAttribute()] IntPtr bgr, int width, int height, int stride, out IntPtr output); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeLosslessBGR")] private static extern int WebPEncodeLosslessBGR_x64([InAttribute()] IntPtr bgr, int width, int height, int stride, out IntPtr output); /// Lossless encoding images pointed to by *data in WebP format /// Pointer to BGRA image data /// The range is limited currently from 1 to 16383 /// The range is limited currently from 1 to 16383 /// Specifies the distance between scan lines /// output_buffer with WebP image /// Size of WebP Image or 0 if an error occurred internal static int WebPEncodeLosslessBGRA(IntPtr bgra, int width, int height, int stride, out IntPtr output) { switch (IntPtr.Size) { case 4: return WebPEncodeLosslessBGRA_x86(bgra, width, height, stride, out output); case 8: return WebPEncodeLosslessBGRA_x64(bgra, width, height, stride, out output); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeLosslessBGRA")] private static extern int WebPEncodeLosslessBGRA_x86([InAttribute()] IntPtr bgra, int width, int height, int stride, out IntPtr output); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeLosslessBGRA")] private static extern int WebPEncodeLosslessBGRA_x64([InAttribute()] IntPtr bgra, int width, int height, int stride, out IntPtr output); /// Releases memory returned by the WebPEncode /// Pointer to memory internal static void WebPFree(IntPtr p) { switch (IntPtr.Size) { case 4: WebPFree_x86(p); break; case 8: WebPFree_x64(p); break; default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")] private static extern void WebPFree_x86(IntPtr p); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")] private static extern void WebPFree_x64(IntPtr p); /// Get the WebP version library /// 8bits for each of major/minor/revision packet in integer. E.g: v2.5.7 is 0x020507 internal static int WebPGetDecoderVersion() { switch (IntPtr.Size) { case 4: return WebPGetDecoderVersion_x86(); case 8: return WebPGetDecoderVersion_x64(); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetDecoderVersion")] private static extern int WebPGetDecoderVersion_x86(); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetDecoderVersion")] private static extern int WebPGetDecoderVersion_x64(); /// Compute PSNR, SSIM or LSIM distortion metric between two pictures /// Picture to measure /// Reference picture /// 0 = PSNR, 1 = SSIM, 2 = LSIM /// dB in the Y/U/V/Alpha/All order /// False in case of error (the two pictures don't have same dimension, ...) internal static int WebPPictureDistortion(ref WebPPicture srcPicture, ref WebPPicture refPicture, int metric_type, IntPtr pResult) { switch (IntPtr.Size) { case 4: return WebPPictureDistortion_x86(ref srcPicture, ref refPicture, metric_type, pResult); case 8: return WebPPictureDistortion_x64(ref srcPicture, ref refPicture, metric_type, pResult); default: throw new InvalidOperationException("Invalid platform. Can not find proper function"); } } [DllImport("Resources/libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureDistortion")] private static extern int WebPPictureDistortion_x86(ref WebPPicture srcPicture, ref WebPPicture refPicture, int metric_type, IntPtr pResult); [DllImport("Resources/libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureDistortion")] private static extern int WebPPictureDistortion_x64(ref WebPPicture srcPicture, ref WebPPicture refPicture, int metric_type, IntPtr pResult); } #endregion #region | Predefined | /// Enumerate some predefined settings for WebPConfig, depending on the type of source picture. These presets are used when calling WebPConfigPreset() internal enum WebPPreset { /// Default preset WEBP_PRESET_DEFAULT = 0, /// Digital picture, like portrait, inner shot WEBP_PRESET_PICTURE, /// Outdoor photograph, with natural lighting WEBP_PRESET_PHOTO, /// Hand or line drawing, with high-contrast details WEBP_PRESET_DRAWING, /// Small-sized colorful images WEBP_PRESET_ICON, /// Text-like WEBP_PRESET_TEXT }; /// Encoding error conditions internal enum WebPEncodingError { /// No error VP8_ENC_OK = 0, /// Memory error allocating objects VP8_ENC_ERROR_OUT_OF_MEMORY, /// Memory error while flushing bits VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY, /// A pointer parameter is NULL VP8_ENC_ERROR_NULL_PARAMETER, /// Configuration is invalid VP8_ENC_ERROR_INVALID_CONFIGURATION, /// Picture has invalid width/height VP8_ENC_ERROR_BAD_DIMENSION, /// Partition is bigger than 512k VP8_ENC_ERROR_PARTITION0_OVERFLOW, /// Partition is bigger than 16M VP8_ENC_ERROR_PARTITION_OVERFLOW, /// Error while flushing bytes VP8_ENC_ERROR_BAD_WRITE, /// File is bigger than 4G VP8_ENC_ERROR_FILE_TOO_BIG, /// Abort request by user VP8_ENC_ERROR_USER_ABORT, /// List terminator. Always last VP8_ENC_ERROR_LAST, } /// Enumeration of the status codes internal enum VP8StatusCode { /// No error VP8_STATUS_OK = 0, /// Memory error allocating objects VP8_STATUS_OUT_OF_MEMORY, /// Configuration is invalid VP8_STATUS_INVALID_PARAM, VP8_STATUS_BITSTREAM_ERROR, /// Configuration is invalid VP8_STATUS_UNSUPPORTED_FEATURE, VP8_STATUS_SUSPENDED, /// Abort request by user VP8_STATUS_USER_ABORT, VP8_STATUS_NOT_ENOUGH_DATA, } /// Image characteristics hint for the underlying encoder internal enum WebPImageHint { /// Default preset WEBP_HINT_DEFAULT = 0, /// Digital picture, like portrait, inner shot WEBP_HINT_PICTURE, /// Outdoor photograph, with natural lighting WEBP_HINT_PHOTO, /// Discrete tone image (graph, map-tile etc) WEBP_HINT_GRAPH, /// List terminator. Always last WEBP_HINT_LAST }; /// Describes the byte-ordering of packed samples in memory internal enum WEBP_CSP_MODE { /// Byte-order: R,G,B,R,G,B,.. MODE_RGB = 0, /// Byte-order: R,G,B,A,R,G,B,A,.. MODE_RGBA = 1, /// Byte-order: B,G,R,B,G,R,.. MODE_BGR = 2, /// Byte-order: B,G,R,A,B,G,R,A,.. MODE_BGRA = 3, /// Byte-order: A,R,G,B,A,R,G,B,.. MODE_ARGB = 4, /// Byte-order: RGB-565: [a4 a3 a2 a1 a0 r5 r4 r3], [r2 r1 r0 g4 g3 g2 g1 g0], ... /// WEBP_SWAP_16BITS_CSP is defined, /// Byte-order: RGB-565: [a4 a3 a2 a1 a0 b5 b4 b3], [b2 b1 b0 g4 g3 g2 g1 g0], .. MODE_RGBA_4444 = 5, /// Byte-order: RGB-565: [r4 r3 r2 r1 r0 g5 g4 g3], [g2 g1 g0 b4 b3 b2 b1 b0], ... /// WEBP_SWAP_16BITS_CSP is defined, /// Byte-order: [b3 b2 b1 b0 a3 a2 a1 a0], [r3 r2 r1 r0 g3 g2 g1 g0], .. MODE_RGB_565 = 6, /// RGB-premultiplied transparent modes (alpha value is preserved) MODE_rgbA = 7, /// RGB-premultiplied transparent modes (alpha value is preserved) MODE_bgrA = 8, /// RGB-premultiplied transparent modes (alpha value is preserved) MODE_Argb = 9, /// RGB-premultiplied transparent modes (alpha value is preserved) MODE_rgbA_4444 = 10, /// YUV 4:2:0 MODE_YUV = 11, /// YUV 4:2:0 MODE_YUVA = 12, /// MODE_LAST -> 13 MODE_LAST = 13, } /// /// Decoding states. State normally flows as: /// WEBP_HEADER->VP8_HEADER->VP8_PARTS0->VP8_DATA->DONE for a lossy image, and /// WEBP_HEADER->VP8L_HEADER->VP8L_DATA->DONE for a lossless image. /// If there is any error the decoder goes into state ERROR. /// internal enum DecState { STATE_WEBP_HEADER, // All the data before that of the VP8/VP8L chunk. STATE_VP8_HEADER, // The VP8 Frame header (within the VP8 chunk). STATE_VP8_PARTS0, STATE_VP8_DATA, STATE_VP8L_HEADER, STATE_VP8L_DATA, STATE_DONE, STATE_ERROR }; #endregion #region | libwebp structs | /// Features gathered from the bit stream [StructLayoutAttribute(LayoutKind.Sequential)] internal struct WebPBitstreamFeatures { /// Width in pixels, as read from the bit stream public int Width; /// Height in pixels, as read from the bit stream public int Height; /// True if the bit stream contains an alpha channel public int Has_alpha; /// True if the bit stream is an animation public int Has_animation; /// 0 = undefined (/mixed), 1 = lossy, 2 = lossless public int Format; /// Padding for later use [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 5, ArraySubType = UnmanagedType.U4)] private readonly uint[] pad; }; /// Compression parameters [StructLayoutAttribute(LayoutKind.Sequential)] internal struct WebPConfig { /// Lossless encoding (0=lossy(default), 1=lossless) public int lossless; /// Between 0 (smallest file) and 100 (biggest) public float quality; /// Quality/speed trade-off (0=fast, 6=slower-better) public int method; /// Hint for image type (lossless only for now) public WebPImageHint image_hint; /// If non-zero, set the desired target size in bytes. Takes precedence over the 'compression' parameter public int target_size; /// If non-zero, specifies the minimal distortion to try to achieve. Takes precedence over target_size public float target_PSNR; /// Maximum number of segments to use, in [1..4] public int segments; /// Spatial Noise Shaping. 0=off, 100=maximum public int sns_strength; /// Range: [0 = off .. 100 = strongest] public int filter_strength; /// Range: [0 = off .. 7 = least sharp] public int filter_sharpness; /// Filtering type: 0 = simple, 1 = strong (only used if filter_strength > 0 or auto-filter > 0) public int filter_type; /// Auto adjust filter's strength [0 = off, 1 = on] public int autofilter; /// Algorithm for encoding the alpha plane (0 = none, 1 = compressed with WebP lossless). Default is 1 public int alpha_compression; /// Predictive filtering method for alpha plane. 0: none, 1: fast, 2: best. Default if 1 public int alpha_filtering; /// Between 0 (smallest size) and 100 (lossless). Default is 100 public int alpha_quality; /// Number of entropy-analysis passes (in [1..10]) public int pass; /// If true, export the compressed picture back. In-loop filtering is not applied public int show_compressed; /// Preprocessing filter (0=none, 1=segment-smooth, 2=pseudo-random dithering) public int preprocessing; /// Log2(number of token partitions) in [0..3] Default is set to 0 for easier progressive decoding public int partitions; /// Quality degradation allowed to fit the 512k limit on prediction modes coding (0: no degradation, 100: maximum possible degradation) public int partition_limit; /// If true, compression parameters will be remapped to better match the expected output size from JPEG compression. Generally, the output size will be similar but the degradation will be lower public int emulate_jpeg_size; /// If non-zero, try and use multi-threaded encoding public int thread_level; /// If set, reduce memory usage (but increase CPU use) public int low_memory; /// Near lossless encoding [0 = max loss .. 100 = off (default)] public int near_lossless; /// If non-zero, preserve the exact RGB values under transparent area. Otherwise, discard this invisible RGB information for better compression. The default value is 0 public int exact; /// Reserved for future lossless feature public int delta_palettization; /// If needed, use sharp (and slow) RGB->YUV conversion public int use_sharp_yuv; /// Padding for later use private readonly int pad1; private readonly int pad2; }; /// Main exchange structure (input samples, output bytes, statistics) [StructLayoutAttribute(LayoutKind.Sequential)] internal struct WebPPicture { /// Main flag for encoder selecting between ARGB or YUV input. Recommended to use ARGB input (*argb, argb_stride) for lossless, and YUV input (*y, *u, *v, etc.) for lossy public int use_argb; /// Color-space: should be YUV420 for now (=Y'CbCr). Value = 0 public UInt32 colorspace; /// Width of picture (less or equal to WEBP_MAX_DIMENSION) public int width; /// Height of picture (less or equal to WEBP_MAX_DIMENSION) public int height; /// Pointer to luma plane public IntPtr y; /// Pointer to chroma U plane public IntPtr u; /// Pointer to chroma V plane public IntPtr v; /// Luma stride public int y_stride; /// Chroma stride public int uv_stride; /// Pointer to the alpha plane public IntPtr a; /// stride of the alpha plane public int a_stride; /// Padding for later use [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.U4)] private readonly uint[] pad1; /// Pointer to ARGB (32 bit) plane public IntPtr argb; /// This is stride in pixels units, not bytes public int argb_stride; /// Padding for later use [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U4)] private readonly uint[] pad2; /// Byte-emission hook, to store compressed bytes as they are ready public IntPtr writer; /// Can be used by the writer public IntPtr custom_ptr; // map for extra information (only for lossy compression mode) /// 1: intra type, 2: segment, 3: quant, 4: intra-16 prediction mode, 5: chroma prediction mode, 6: bit cost, 7: distortion public int extra_info_type; /// If not NULL, points to an array of size ((width + 15) / 16) * ((height + 15) / 16) that will be filled with a macroblock map, depending on extra_info_type public IntPtr extra_info; /// Pointer to side statistics (updated only if not NULL) public IntPtr stats; /// Error code for the latest error encountered during encoding public UInt32 error_code; /// If not NULL, report progress during encoding public IntPtr progress_hook; /// This field is free to be set to any value and used during callbacks (like progress-report e.g.) public IntPtr user_data; /// Padding for later use [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 13, ArraySubType = UnmanagedType.U4)] private readonly uint[] pad3; /// Row chunk of memory for YUVA planes private readonly IntPtr memory_; /// Row chunk of memory for ARGB planes private readonly IntPtr memory_argb_; /// Padding for later use [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.U4)] private readonly uint[] pad4; }; /// Structure for storing auxiliary statistics (mostly for lossy encoding) [StructLayoutAttribute(LayoutKind.Sequential)] internal struct WebPAuxStats { /// Final size public int coded_size; /// Peak-signal-to-noise ratio for Y public float PSNRY; /// Peak-signal-to-noise ratio for U public float PSNRU; /// Peak-signal-to-noise ratio for V public float PSNRV; /// Peak-signal-to-noise ratio for All public float PSNRALL; /// Peak-signal-to-noise ratio for Alpha public float PSNRAlpha; /// Number of intra4 public int block_count_intra4; /// Number of intra16 public int block_count_intra16; /// Number of skipped macro-blocks public int block_count_skipped; /// Approximate number of bytes spent for header public int header_bytes; /// Approximate number of bytes spent for mode-partition #0 public int mode_partition_0; /// Approximate number of bytes spent for DC coefficients for segment 0 public int residual_bytes_DC_segments0; /// Approximate number of bytes spent for AC coefficients for segment 0 public int residual_bytes_AC_segments0; /// Approximate number of bytes spent for UV coefficients for segment 0 public int residual_bytes_uv_segments0; /// Approximate number of bytes spent for DC coefficients for segment 1 public int residual_bytes_DC_segments1; /// Approximate number of bytes spent for AC coefficients for segment 1 public int residual_bytes_AC_segments1; /// Approximate number of bytes spent for UV coefficients for segment 1 public int residual_bytes_uv_segments1; /// Approximate number of bytes spent for DC coefficients for segment 2 public int residual_bytes_DC_segments2; /// Approximate number of bytes spent for AC coefficients for segment 2 public int residual_bytes_AC_segments2; /// Approximate number of bytes spent for UV coefficients for segment 2 public int residual_bytes_uv_segments2; /// Approximate number of bytes spent for DC coefficients for segment 3 public int residual_bytes_DC_segments3; /// Approximate number of bytes spent for AC coefficients for segment 3 public int residual_bytes_AC_segments3; /// Approximate number of bytes spent for UV coefficients for segment 3 public int residual_bytes_uv_segments3; /// Number of macro-blocks in segments 0 public int segment_size_segments0; /// Number of macro-blocks in segments 1 public int segment_size_segments1; /// Number of macro-blocks in segments 2 public int segment_size_segments2; /// Number of macro-blocks in segments 3 public int segment_size_segments3; /// Quantizer values for segment 0 public int segment_quant_segments0; /// Quantizer values for segment 1 public int segment_quant_segments1; /// Quantizer values for segment 2 public int segment_quant_segments2; /// Quantizer values for segment 3 public int segment_quant_segments3; /// Filtering strength for segment 0 [0..63] public int segment_level_segments0; /// Filtering strength for segment 1 [0..63] public int segment_level_segments1; /// Filtering strength for segment 2 [0..63] public int segment_level_segments2; /// Filtering strength for segment 3 [0..63] public int segment_level_segments3; /// Size of the transparency data public int alpha_data_size; /// Size of the enhancement layer data public int layer_data_size; // lossless encoder statistics /// bit0:predictor bit1:cross-color transform bit2:subtract-green bit3:color indexing public Int32 lossless_features; /// Number of precision bits of histogram public int histogram_bits; /// Precision bits for transform public int transform_bits; /// Number of bits for color cache lookup public int cache_bits; /// Number of color in palette, if used public int palette_size; /// Final lossless size public int lossless_size; /// Lossless header (transform, Huffman, etc) size public int lossless_hdr_size; /// Lossless image data size public int lossless_data_size; /// Padding for later use [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.U4)] private readonly uint[] pad; }; [StructLayoutAttribute(LayoutKind.Sequential)] internal struct WebPDecoderConfig { /// Immutable bit stream features (optional) public WebPBitstreamFeatures input; /// Output buffer (can point to external memory) public WebPDecBuffer output; /// Decoding options public WebPDecoderOptions options; } /// Output buffer [StructLayoutAttribute(LayoutKind.Sequential)] internal struct WebPDecBuffer { /// Color space public WEBP_CSP_MODE colorspace; /// Width of image public int width; /// Height of image public int height; /// If non-zero, 'internal_memory' pointer is not used. If value is '2' or more, the external memory is considered 'slow' and multiple read/write will be avoided public int is_external_memory; /// Output buffer parameters public RGBA_YUVA_Buffer u; /// Padding for later use private readonly UInt32 pad1; /// Padding for later use private readonly UInt32 pad2; /// Padding for later use private readonly UInt32 pad3; /// Padding for later use private readonly UInt32 pad4; /// Internally allocated memory (only when is_external_memory is 0). Should not be used externally, but accessed via WebPRGBABuffer public IntPtr private_memory; } /// Union of buffer parameters [StructLayoutAttribute(LayoutKind.Explicit)] internal struct RGBA_YUVA_Buffer { [FieldOffsetAttribute(0)] public WebPRGBABuffer RGBA; [FieldOffsetAttribute(0)] public WebPYUVABuffer YUVA; } [StructLayoutAttribute(LayoutKind.Sequential)] internal struct WebPYUVABuffer { /// Pointer to luma samples public IntPtr y; /// Pointer to chroma U samples public IntPtr u; /// Pointer to chroma V samples public IntPtr v; /// Pointer to alpha samples public IntPtr a; /// Luma stride public int y_stride; /// Chroma U stride public int u_stride; /// Chroma V stride public int v_stride; /// Alpha stride public int a_stride; /// Luma plane size public UIntPtr y_size; /// Chroma plane U size public UIntPtr u_size; /// Chroma plane V size public UIntPtr v_size; /// Alpha plane size public UIntPtr a_size; } /// Generic structure for describing the output sample buffer [StructLayoutAttribute(LayoutKind.Sequential)] internal struct WebPRGBABuffer { /// Pointer to RGBA samples public IntPtr rgba; /// Stride in bytes from one scanline to the next public int stride; /// Total size of the RGBA buffer public UIntPtr size; } /// Decoding options [StructLayout(LayoutKind.Sequential)] public struct WebPDecoderOptions { /// If true, skip the in-loop filtering public int bypass_filtering; /// If true, use faster point-wise up-sampler public int no_fancy_upsampling; /// If true, cropping is applied _first_ public int use_cropping; /// Left position for cropping. Will be snapped to even values public int crop_left; /// Top position for cropping. Will be snapped to even values public int crop_top; /// Width of the cropping area public int crop_width; /// Height of the cropping area public int crop_height; /// If true, scaling is applied _afterward_ public int use_scaling; /// Final width public int scaled_width; /// Final height public int scaled_height; /// If true, use multi-threaded decoding public int use_threads; /// Dithering strength (0=Off, 100=full) public int dithering_strength; /// Flip output vertically public int flip; /// Alpha dithering strength in [0..100] public int alpha_dithering_strength; /// Padding for later use private readonly UInt32 pad1; /// Padding for later use private readonly UInt32 pad2; /// Padding for later use private readonly UInt32 pad3; /// Padding for later use private readonly UInt32 pad4; /// Padding for later use private readonly UInt32 pad5; }; #endregion }