Advertisement
fortsoft

WebPWrapper

Mar 23rd, 2021 (edited)
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 108.08 KB | Source Code | 0 0
  1. /**
  2.  *  Wrapper for WebP format in C#. (MIT) Jose M. Piñeiro
  3.  **
  4.  *  Decode Functions:
  5.  *  Bitmap Load(string pathFileName) - Load a WebP file in bitmap.
  6.  *  Bitmap Decode(byte[] rawWebP) - Decode WebP data (rawWebP) to bitmap.
  7.  *  Bitmap Decode(byte[] rawWebP, WebPDecoderOptions options) - Decode WebP data
  8.  *          (rawWebP) to bitmap using 'options'.
  9.  *  Bitmap GetThumbnailFast(byte[] rawWebP, int width, int height) - Get a
  10.  *          thumbnail from WebP data (rawWebP) with dimensions 'width × height'.
  11.  *          Fast mode.
  12.  *  Bitmap GetThumbnailQuality(byte[] rawWebP, int width, int height) - Fast get
  13.  *          a thumbnail from WebP data (rawWebP) with dimensions 'width ×
  14.  *          height'. Quality mode.
  15.  *
  16.  *  Encode Functions:
  17.  *  Save(Bitmap bmp, string pathFileName, int quality) - Save bitmap with quality
  18.  *          lost to WebP file. Opcionally select 'quality'.
  19.  *  byte[] EncodeLossy(Bitmap bmp, int quality) - Encode bitmap with quality lost
  20.  *          to WebP byte array. Opcionally select 'quality'.
  21.  *  byte[] EncodeLossy(Bitmap bmp, int quality, int speed, bool info) - Encode
  22.  *          bitmap with quality lost to WebP byte array. Select 'quality',
  23.  *          'speed' and optionally select 'info'.
  24.  *  byte[] EncodeLossless(Bitmap bmp) - Encode bitmap without quality lost to
  25.  *          WebP byte array.
  26.  *  byte[] EncodeLossless(Bitmap bmp, int speed, bool info = false) - Encode
  27.  *          bitmap without quality lost to WebP byte array. Select 'speed'.
  28.  *  byte[] EncodeNearLossless(Bitmap bmp, int quality, int speed = 9, bool info =
  29.  *          false) - Encode bitmap with a near lossless method to WebP byte
  30.  *          array. Select 'quality', 'speed' and optionally select 'info'.
  31.  *
  32.  *  Another functions:
  33.  *  string GetVersion() - Get the library version
  34.  *  GetInfo(byte[] rawWebP, out int width, out int height, out bool has_alpha,
  35.  *          out bool has_animation, out string format) - Get information of WEBP
  36.  *          data
  37.  *  float[] PictureDistortion(Bitmap source, Bitmap reference, int metric_type) -
  38.  *          Get PSNR, SSIM or LSIM distortion metric between two pictures
  39.  **
  40.  * Modified 2023-04-04 by Petr Červinka - FortSoft <[email protected]>
  41.  * Reformatted to meet FortSoft codestyle.
  42.  **
  43.  * This is open-source software licensed under the terms of the MIT License.
  44.  *
  45.  * Copyright (c) 2020-2023 Jose M. Piñeiro
  46.  * Copyright (c) 2021-2023 Petr Červinka - FortSoft <[email protected]>
  47.  *
  48.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  49.  * of this software and associated documentation files (the "Software"), to deal
  50.  * in the Software without restriction, including without limitation the rights
  51.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  52.  * copies of the Software, and to permit persons to whom the Software is
  53.  * furnished to do so, subject to the following conditions:
  54.  *
  55.  * The above copyright notice and this permission notice shall be included in all
  56.  * copies or substantial portions of the Software.
  57.  *
  58.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  59.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  60.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  61.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  62.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  63.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  64.  * SOFTWARE.
  65.  **
  66.  * Version 1.1.1.0
  67.  */
  68.  
  69. using System;
  70. using System.Drawing;
  71. using System.Drawing.Imaging;
  72. using System.IO;
  73. using System.Runtime.InteropServices;
  74. using System.Security;
  75. using System.Text;
  76. using System.Windows.Forms;
  77.  
  78. namespace WebPWrapper {
  79.     public sealed class WebP : IDisposable {
  80.         private const int WEBP_MAX_DIMENSION = 16383;
  81.  
  82.         #region Public Decode Functions
  83.  
  84.         /// <summary>Read a WebP file.</summary>
  85.         /// <param name="pathFileName">WebP file to load.</param>
  86.         /// <returns>Bitmap with the WebP image.</returns>
  87.         public Bitmap Load(string pathFileName) {
  88.             try {
  89.                 byte[] rawWebP = File.ReadAllBytes(pathFileName);
  90.  
  91.                 return Decode(rawWebP);
  92.             } catch (Exception exception) {
  93.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.Load.");
  94.             }
  95.         }
  96.  
  97.         /// <summary>Decode a WebP image.</summary>
  98.         /// <param name="rawWebP">The data to uncompress.</param>
  99.         /// <returns>Bitmap with the WebP image.</returns>
  100.         public Bitmap Decode(byte[] rawWebP) {
  101.             Bitmap bmp = null;
  102.             BitmapData bmpData = null;
  103.             GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned);
  104.  
  105.             try {
  106.                 int imgWidth, imgHeight;
  107.                 bool hasAlpha, hasAnimation;
  108.                 string format;
  109.  
  110.                 // Get image width and height
  111.                 GetInfo(rawWebP, out imgWidth, out imgHeight, out hasAlpha, out hasAnimation, out format);
  112.  
  113.                 // Create a BitmapData and Lock all pixels to be written
  114.                 if (hasAlpha) {
  115.                     bmp = new Bitmap(imgWidth, imgHeight, PixelFormat.Format32bppArgb);
  116.                 } else {
  117.                     bmp = new Bitmap(imgWidth, imgHeight, PixelFormat.Format24bppRgb);
  118.                 }
  119.                 bmpData = bmp.LockBits(new Rectangle(0, 0, imgWidth, imgHeight), ImageLockMode.WriteOnly, bmp.PixelFormat);
  120.  
  121.                 // Uncompress the image
  122.                 int outputSize = bmpData.Stride * imgHeight;
  123.                 IntPtr ptrData = pinnedWebP.AddrOfPinnedObject();
  124.                 if (bmp.PixelFormat == PixelFormat.Format24bppRgb) {
  125.                     UnsafeNativeMethods.WebPDecodeBGRInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride);
  126.                 } else {
  127.                     UnsafeNativeMethods.WebPDecodeBGRAInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride);
  128.                 }
  129.                 return bmp;
  130.             } catch (Exception exception) {
  131.                 throw exception;
  132.             } finally {
  133.                 // Unlock the pixels
  134.                 if (bmpData != null) {
  135.                     bmp.UnlockBits(bmpData);
  136.                 }
  137.                 // Free memory
  138.                 if (pinnedWebP.IsAllocated) {
  139.                     pinnedWebP.Free();
  140.                 }
  141.             }
  142.         }
  143.  
  144.         /// <summary>Decode a WebP image.</summary>
  145.         /// <param name="rawWebP">the data to uncompress.</param>
  146.         /// <param name="options">Options for advanced decode.</param>
  147.         /// <returns>Bitmap with the WebP image.</returns>
  148.         public Bitmap Decode(byte[] rawWebP, WebPDecoderOptions options) {
  149.             GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned);
  150.             Bitmap bmp = null;
  151.             BitmapData bmpData = null;
  152.             VP8StatusCode result;
  153.             try {
  154.                 WebPDecoderConfig config = new WebPDecoderConfig();
  155.                 if (UnsafeNativeMethods.WebPInitDecoderConfig(ref config) == 0) {
  156.                     throw new Exception("WebPInitDecoderConfig failed. Wrong version?");
  157.                 }
  158.                 // Read the .webp input file information
  159.                 IntPtr ptrRawWebP = pinnedWebP.AddrOfPinnedObject();
  160.                 int height;
  161.                 int width;
  162.                 if (options.use_scaling == 0) {
  163.                     result = UnsafeNativeMethods.WebPGetFeatures(ptrRawWebP, rawWebP.Length, ref config.input);
  164.                     if (result != VP8StatusCode.VP8_STATUS_OK) {
  165.                         throw new Exception(string.Format("Failed WebPGetFeatures with error {0}.", result));
  166.                     }
  167.                     // Test cropping values
  168.                     if (options.use_cropping == 1) {
  169.                         if (options.crop_left + options.crop_width > config.input.Width || options.crop_top + options.crop_height > config.input.Height) {
  170.                             throw new Exception("Crop options exceeded WebP image dimensions.");
  171.                         }
  172.                         width = options.crop_width;
  173.                         height = options.crop_height;
  174.                     }
  175.                 } else {
  176.                     width = options.scaled_width;
  177.                     height = options.scaled_height;
  178.                 }
  179.  
  180.                 config.options.bypass_filtering = options.bypass_filtering;
  181.                 config.options.no_fancy_upsampling = options.no_fancy_upsampling;
  182.                 config.options.use_cropping = options.use_cropping;
  183.                 config.options.crop_left = options.crop_left;
  184.                 config.options.crop_top = options.crop_top;
  185.                 config.options.crop_width = options.crop_width;
  186.                 config.options.crop_height = options.crop_height;
  187.                 config.options.use_scaling = options.use_scaling;
  188.                 config.options.scaled_width = options.scaled_width;
  189.                 config.options.scaled_height = options.scaled_height;
  190.                 config.options.use_threads = options.use_threads;
  191.                 config.options.dithering_strength = options.dithering_strength;
  192.                 config.options.flip = options.flip;
  193.                 config.options.alpha_dithering_strength = options.alpha_dithering_strength;
  194.  
  195.                 // Create a BitmapData and Lock all pixels to be written
  196.                 if (config.input.Has_alpha == 1) {
  197.                     config.output.colorspace = WEBP_CSP_MODE.MODE_bgrA;
  198.                     bmp = new Bitmap(config.input.Width, config.input.Height, PixelFormat.Format32bppArgb);
  199.                 } else {
  200.                     config.output.colorspace = WEBP_CSP_MODE.MODE_BGR;
  201.                     bmp = new Bitmap(config.input.Width, config.input.Height, PixelFormat.Format24bppRgb);
  202.                 }
  203.                 bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
  204.  
  205.                 // Specify the output format
  206.                 config.output.u.RGBA.rgba = bmpData.Scan0;
  207.                 config.output.u.RGBA.stride = bmpData.Stride;
  208.                 config.output.u.RGBA.size = (UIntPtr)(bmp.Height * bmpData.Stride);
  209.                 config.output.height = bmp.Height;
  210.                 config.output.width = bmp.Width;
  211.                 config.output.is_external_memory = 1;
  212.  
  213.                 // Decode
  214.                 result = UnsafeNativeMethods.WebPDecode(ptrRawWebP, rawWebP.Length, ref config);
  215.                 if (result != VP8StatusCode.VP8_STATUS_OK) {
  216.                     throw new Exception(string.Format("Failed WebPDecode with error {0}.", result));
  217.                 }
  218.                 UnsafeNativeMethods.WebPFreeDecBuffer(ref config.output);
  219.  
  220.                 return bmp;
  221.             } catch (Exception exception) {
  222.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.Decode.");
  223.             } finally {
  224.                 // Unlock the pixels
  225.                 if (bmpData != null) {
  226.                     bmp.UnlockBits(bmpData);
  227.                 }
  228.                 // Free memory
  229.                 if (pinnedWebP.IsAllocated) {
  230.                     pinnedWebP.Free();
  231.                 }
  232.             }
  233.         }
  234.  
  235.         /// <summary>Get Thumbnail from webP in mode faster/low quality.</summary>
  236.         /// <param name="rawWebP">The data to uncompress.</param>
  237.         /// <param name="width">Wanted width of thumbnail.</param>
  238.         /// <param name="height">Wanted height of thumbnail.</param>
  239.         /// <returns>Bitmap with the WebP thumbnail in 24bpp.</returns>
  240.         public Bitmap GetThumbnailFast(byte[] rawWebP, int width, int height) {
  241.             GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned);
  242.             Bitmap bmp = null;
  243.             BitmapData bmpData = null;
  244.  
  245.             try {
  246.                 WebPDecoderConfig config = new WebPDecoderConfig();
  247.                 if (UnsafeNativeMethods.WebPInitDecoderConfig(ref config) == 0) {
  248.                     throw new Exception("WebPInitDecoderConfig failed. Wrong version?");
  249.                 }
  250.                 // Set up decode options
  251.                 config.options.bypass_filtering = 1;
  252.                 config.options.no_fancy_upsampling = 1;
  253.                 config.options.use_threads = 1;
  254.                 config.options.use_scaling = 1;
  255.                 config.options.scaled_width = width;
  256.                 config.options.scaled_height = height;
  257.  
  258.                 // Create a BitmapData and Lock all pixels to be written
  259.                 bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
  260.                 bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat);
  261.  
  262.                 // Specify the output format
  263.                 config.output.colorspace = WEBP_CSP_MODE.MODE_BGR;
  264.                 config.output.u.RGBA.rgba = bmpData.Scan0;
  265.                 config.output.u.RGBA.stride = bmpData.Stride;
  266.                 config.output.u.RGBA.size = (UIntPtr)(height * bmpData.Stride);
  267.                 config.output.height = height;
  268.                 config.output.width = width;
  269.                 config.output.is_external_memory = 1;
  270.  
  271.                 // Decode
  272.                 IntPtr ptrRawWebP = pinnedWebP.AddrOfPinnedObject();
  273.                 VP8StatusCode result = UnsafeNativeMethods.WebPDecode(ptrRawWebP, rawWebP.Length, ref config);
  274.                 if (result != VP8StatusCode.VP8_STATUS_OK) {
  275.                     throw new Exception(string.Format("Failed WebPDecode with error {0}.", result));
  276.                 }
  277.                 UnsafeNativeMethods.WebPFreeDecBuffer(ref config.output);
  278.  
  279.                 return bmp;
  280.             } catch (Exception exception) {
  281.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.Thumbnail.");
  282.             } finally {
  283.                 // Unlock the pixels
  284.                 if (bmpData != null) {
  285.                     bmp.UnlockBits(bmpData);
  286.                 }
  287.                 // Free memory
  288.                 if (pinnedWebP.IsAllocated) {
  289.                     pinnedWebP.Free();
  290.                 }
  291.             }
  292.         }
  293.  
  294.         /// <summary>Thumbnail from webP in mode slow/high quality.</summary>
  295.         /// <param name="rawWebP">The data to uncompress.</param>
  296.         /// <param name="width">Wanted width of thumbnail.</param>
  297.         /// <param name="height">Wanted height of thumbnail.</param>
  298.         /// <returns>Bitmap with the WebP thumbnail.</returns>
  299.         public Bitmap GetThumbnailQuality(byte[] rawWebP, int width, int height) {
  300.             GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned);
  301.             Bitmap bmp = null;
  302.             BitmapData bmpData = null;
  303.  
  304.             try {
  305.                 WebPDecoderConfig config = new WebPDecoderConfig();
  306.                 if (UnsafeNativeMethods.WebPInitDecoderConfig(ref config) == 0) {
  307.                     throw new Exception("WebPInitDecoderConfig failed. Wrong version?");
  308.                 }
  309.                 IntPtr ptrRawWebP = pinnedWebP.AddrOfPinnedObject();
  310.                 VP8StatusCode result = UnsafeNativeMethods.WebPGetFeatures(ptrRawWebP, rawWebP.Length, ref config.input);
  311.                 if (result != VP8StatusCode.VP8_STATUS_OK) {
  312.                     throw new Exception(string.Format("Failed WebPGetFeatures with error {0}.", result));
  313.                 }
  314.                 // Set up decode options
  315.                 config.options.bypass_filtering = 0;
  316.                 config.options.no_fancy_upsampling = 0;
  317.                 config.options.use_threads = 1;
  318.                 config.options.use_scaling = 1;
  319.                 config.options.scaled_width = width;
  320.                 config.options.scaled_height = height;
  321.  
  322.                 // Create a BitmapData and Lock all pixels to be written
  323.                 if (config.input.Has_alpha == 1) {
  324.                     config.output.colorspace = WEBP_CSP_MODE.MODE_bgrA;
  325.                     bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
  326.                 } else {
  327.                     config.output.colorspace = WEBP_CSP_MODE.MODE_BGR;
  328.                     bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
  329.                 }
  330.                 bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat);
  331.  
  332.                 // Specify the output format
  333.                 config.output.u.RGBA.rgba = bmpData.Scan0;
  334.                 config.output.u.RGBA.stride = bmpData.Stride;
  335.                 config.output.u.RGBA.size = (UIntPtr)(height * bmpData.Stride);
  336.                 config.output.height = height;
  337.                 config.output.width = width;
  338.                 config.output.is_external_memory = 1;
  339.  
  340.                 // Decode
  341.                 result = UnsafeNativeMethods.WebPDecode(ptrRawWebP, rawWebP.Length, ref config);
  342.                 if (result != VP8StatusCode.VP8_STATUS_OK) {
  343.                     throw new Exception(string.Format("Failed WebPDecode with error {0}.", result));
  344.                 }
  345.                 UnsafeNativeMethods.WebPFreeDecBuffer(ref config.output);
  346.  
  347.                 return bmp;
  348.             } catch (Exception exception) {
  349.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.Thumbnail.");
  350.             } finally {
  351.                 // Unlock the pixels
  352.                 if (bmpData != null) {
  353.                     bmp.UnlockBits(bmpData);
  354.                 }
  355.                 // Free memory
  356.                 if (pinnedWebP.IsAllocated) {
  357.                     pinnedWebP.Free();
  358.                 }
  359.             }
  360.         }
  361.  
  362.         #endregion
  363.  
  364.  
  365.         #region Public Encode Functions
  366.  
  367.         /// <summary>Save bitmap to file in WebP format.</summary>
  368.         /// <param name="bmp">Bitmap with the WebP image.</param>
  369.         /// <param name="pathFileName">The file to write.</param>
  370.         /// <param name="quality">Between 0 (lower quality, lowest file size) and 100 (highest quality,
  371.         /// higher file size).</param>
  372.         public void Save(Bitmap bmp, string pathFileName, int quality = 75) {
  373.             byte[] rawWebP;
  374.  
  375.             try {
  376.                 // Encode in webP format
  377.                 rawWebP = EncodeLossy(bmp, quality);
  378.  
  379.                 // Write webP file
  380.                 File.WriteAllBytes(pathFileName, rawWebP);
  381.             } catch (Exception exception) {
  382.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.Save.");
  383.             }
  384.         }
  385.  
  386.         /// <summary>Lossy encoding bitmap to WebP (Simple encoding API).</summary>
  387.         /// <param name="bmp">Bitmap with the image.</param>
  388.         /// <param name="quality">Between 0 (lower quality, lowest file size) and 100 (highest quality,
  389.         /// higher file size).</param>
  390.         /// <returns>Compressed data.</returns>
  391.         public byte[] EncodeLossy(Bitmap bmp, int quality = 75) {
  392.             // Test bmp
  393.             if (bmp.Width == 0 || bmp.Height == 0) {
  394.                 throw new ArgumentException("Bitmap contains no data.", "bmp");
  395.             }
  396.             if (bmp.Width > WEBP_MAX_DIMENSION || bmp.Height > WEBP_MAX_DIMENSION) {
  397.                 throw new NotSupportedException("Bitmap's dimension is too large. Max is " + WEBP_MAX_DIMENSION + "×" + WEBP_MAX_DIMENSION + " pixels.");
  398.             }
  399.             if (bmp.PixelFormat != PixelFormat.Format24bppRgb && bmp.PixelFormat != PixelFormat.Format32bppArgb) {
  400.                 throw new NotSupportedException("Only support Format24bppRgb and Format32bppArgb pixelFormat.");
  401.             }
  402.             BitmapData bmpData = null;
  403.             IntPtr unmanagedData = IntPtr.Zero;
  404.  
  405.             try {
  406.                 int size;
  407.  
  408.                 // Get bmp data
  409.                 bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
  410.  
  411.                 // Compress the bmp data
  412.                 if (bmp.PixelFormat == PixelFormat.Format24bppRgb) {
  413.                     size = UnsafeNativeMethods.WebPEncodeBGR(bmpData.Scan0, bmp.Width, bmp.Height, bmpData.Stride, quality, out unmanagedData);
  414.                 } else {
  415.                     size = UnsafeNativeMethods.WebPEncodeBGRA(bmpData.Scan0, bmp.Width, bmp.Height, bmpData.Stride, quality, out unmanagedData);
  416.                 }
  417.                 if (size == 0) {
  418.                     throw new Exception("Can't encode WebP.");
  419.                 }
  420.                 // Copy image compress data to output array
  421.                 byte[] rawWebP = new byte[size];
  422.                 Marshal.Copy(unmanagedData, rawWebP, 0, size);
  423.  
  424.                 return rawWebP;
  425.             } catch (Exception exception) {
  426.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.EncodeLossly.");
  427.             } finally {
  428.                 // Unlock the pixels
  429.                 if (bmpData != null) {
  430.                     bmp.UnlockBits(bmpData);
  431.                 }
  432.                 // Free memory
  433.                 if (unmanagedData != IntPtr.Zero) {
  434.                     UnsafeNativeMethods.WebPFree(unmanagedData);
  435.                 }
  436.             }
  437.         }
  438.  
  439.         /// <summary>Lossy encoding bitmap to WebP (Advanced encoding API).</summary>
  440.         /// <param name="bmp">Bitmap with the image.</param>
  441.         /// <param name="quality">Between 0 (lower quality, lowest file size) and 100 (highest quality,
  442.         /// higher file size).</param>
  443.         /// <param name="speed">Between 0 (fastest, lowest compression) and 9 (slower, best
  444.         /// compression).</param>
  445.         /// <returns>Compressed data.</returns>
  446.         public byte[] EncodeLossy(Bitmap bmp, int quality, int speed, bool info = false) {
  447.             // Initialize configuration structure
  448.             WebPConfig config = new WebPConfig();
  449.  
  450.             // Set compression parameters
  451.             if (UnsafeNativeMethods.WebPConfigInit(ref config, WebPPreset.WEBP_PRESET_DEFAULT, 75) == 0) {
  452.                 throw new Exception("Can't configure preset.");
  453.             }
  454.             // Add additional tuning:
  455.             config.method = speed;
  456.             if (config.method > 6) {
  457.                 config.method = 6;
  458.             }
  459.             config.quality = quality;
  460.             config.autofilter = 1;
  461.             config.pass = speed + 1;
  462.             config.segments = 4;
  463.             config.partitions = 3;
  464.             config.thread_level = 1;
  465.             config.alpha_quality = quality;
  466.             config.alpha_filtering = 2;
  467.             config.use_sharp_yuv = 1;
  468.  
  469.             // Old version does not support preprocessing 4
  470.             if (UnsafeNativeMethods.WebPGetDecoderVersion() > 1082) {
  471.                 config.preprocessing = 4;
  472.                 config.use_sharp_yuv = 1;
  473.             } else {
  474.                 config.preprocessing = 3;
  475.             }
  476.             return AdvancedEncode(bmp, config, info);
  477.         }
  478.  
  479.         /// <summary>Lossless encoding bitmap to WebP (Simple encoding API).</summary>
  480.         /// <param name="bmp">Bitmap with the image.</param>
  481.         /// <returns>Compressed data.</returns>
  482.         public byte[] EncodeLossless(Bitmap bmp) {
  483.             // Test bmp
  484.             if (bmp.Width == 0 || bmp.Height == 0) {
  485.                 throw new ArgumentException("Bitmap contains no data.", "bmp");
  486.             }
  487.             if (bmp.Width > WEBP_MAX_DIMENSION || bmp.Height > WEBP_MAX_DIMENSION) {
  488.                 throw new NotSupportedException("Bitmap's dimension is too large. Max is " + WEBP_MAX_DIMENSION + "×" + WEBP_MAX_DIMENSION + " pixels.");
  489.             }
  490.             if (bmp.PixelFormat != PixelFormat.Format24bppRgb && bmp.PixelFormat != PixelFormat.Format32bppArgb) {
  491.                 throw new NotSupportedException("Only support Format24bppRgb and Format32bppArgb pixelFormat.");
  492.             }
  493.             BitmapData bmpData = null;
  494.             IntPtr unmanagedData = IntPtr.Zero;
  495.             try {
  496.                 // Get bmp data
  497.                 bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
  498.  
  499.                 // Compress the bmp data
  500.                 int size;
  501.                 if (bmp.PixelFormat == PixelFormat.Format24bppRgb) {
  502.                     size = UnsafeNativeMethods.WebPEncodeLosslessBGR(bmpData.Scan0, bmp.Width, bmp.Height, bmpData.Stride, out unmanagedData);
  503.                 } else {
  504.                     size = UnsafeNativeMethods.WebPEncodeLosslessBGRA(bmpData.Scan0, bmp.Width, bmp.Height, bmpData.Stride, out unmanagedData);
  505.                 }
  506.                 // Copy image compress data to output array
  507.                 byte[] rawWebP = new byte[size];
  508.                 Marshal.Copy(unmanagedData, rawWebP, 0, size);
  509.  
  510.                 return rawWebP;
  511.             } catch (Exception exception) {
  512.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.EncodeLossless (Simple).");
  513.             } finally {
  514.                 // Unlock the pixels
  515.                 if (bmpData != null) {
  516.                     bmp.UnlockBits(bmpData);
  517.                 }
  518.                 // Free memory
  519.                 if (unmanagedData != IntPtr.Zero) {
  520.                     UnsafeNativeMethods.WebPFree(unmanagedData);
  521.                 }
  522.             }
  523.         }
  524.  
  525.         /// <summary>Lossless encoding image in bitmap (Advanced encoding API).</summary>
  526.         /// <param name="bmp">Bitmap with the image.</param>
  527.         /// <param name="speed">Between 0 (fastest, lowest compression) and 9 (slower, best
  528.         /// compression).</param>
  529.         /// <returns>Compressed data.</returns>
  530.         public byte[] EncodeLossless(Bitmap bmp, int speed) {
  531.             // Initialize configuration structure
  532.             WebPConfig config = new WebPConfig();
  533.  
  534.             // Set compression parameters
  535.             if (UnsafeNativeMethods.WebPConfigInit(ref config, WebPPreset.WEBP_PRESET_DEFAULT, (speed + 1) * 10) == 0) {
  536.                 throw new Exception("Can't config preset.");
  537.             }
  538.             // Old version of DLL does not support info and WebPConfigLosslessPreset
  539.             if (UnsafeNativeMethods.WebPGetDecoderVersion() > 1082) {
  540.                 if (UnsafeNativeMethods.WebPConfigLosslessPreset(ref config, speed) == 0) {
  541.                     throw new Exception("Can't configure lossless preset.");
  542.                 }
  543.             } else {
  544.                 config.lossless = 1;
  545.                 config.method = speed;
  546.                 if (config.method > 6) {
  547.                     config.method = 6;
  548.                 }
  549.                 config.quality = (speed + 1) * 10;
  550.             }
  551.             config.pass = speed + 1;
  552.             config.thread_level = 1;
  553.             config.alpha_filtering = 2;
  554.             config.use_sharp_yuv = 1;
  555.             config.exact = 0;
  556.  
  557.             return AdvancedEncode(bmp, config, false);
  558.         }
  559.  
  560.         /// <summary>Near lossless encoding image in bitmap.</summary>
  561.         /// <param name="bmp">Bitmap with the image.</param>
  562.         /// <param name="quality">Between 0 (lower quality, lowest file size) and 100 (highest quality,
  563.         /// higher file size).</param>
  564.         /// <param name="speed">Between 0 (fastest, lowest compression) and 9 (slower, best
  565.         /// compression).</param>
  566.         /// <returns>Compress data.</returns>
  567.         public byte[] EncodeNearLossless(Bitmap bmp, int quality, int speed = 9) {
  568.             // Test DLL version
  569.             if (UnsafeNativeMethods.WebPGetDecoderVersion() <= 1082) {
  570.                 throw new Exception("This DLL version not support EncodeNearLossless.");
  571.             }
  572.             // Initialize configuration structure
  573.             WebPConfig config = new WebPConfig();
  574.  
  575.             // Set compression parameters
  576.             if (UnsafeNativeMethods.WebPConfigInit(ref config, WebPPreset.WEBP_PRESET_DEFAULT, (speed + 1) * 10) == 0) {
  577.                 throw new Exception("Can't configure preset.");
  578.             }
  579.             if (UnsafeNativeMethods.WebPConfigLosslessPreset(ref config, speed) == 0) {
  580.                 throw new Exception("Can't configure lossless preset.");
  581.             }
  582.             config.pass = speed + 1;
  583.             config.near_lossless = quality;
  584.             config.thread_level = 1;
  585.             config.alpha_filtering = 2;
  586.             config.use_sharp_yuv = 1;
  587.             config.exact = 0;
  588.  
  589.             return AdvancedEncode(bmp, config, false);
  590.         }
  591.  
  592.         #endregion
  593.  
  594.  
  595.         #region Another Public Functions
  596.  
  597.         /// <summary>Get the libwebp version.</summary>
  598.         /// <returns>Version of library.</returns>
  599.         public string GetVersion() {
  600.             try {
  601.                 uint v = (uint)UnsafeNativeMethods.WebPGetDecoderVersion();
  602.                 uint revision = v % 256;
  603.                 uint minor = (v >> 8) % 256;
  604.                 uint major = (v >> 16) % 256;
  605.                 return major + "." + minor + "." + revision;
  606.             } catch (Exception exception) {
  607.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.GetVersion.");
  608.             }
  609.         }
  610.  
  611.         /// <summary>Get info of WEBP data.</summary>
  612.         /// <param name="rawWebP">The data of WebP.</param>
  613.         /// <param name="width">width of image.</param>
  614.         /// <param name="height">height of image.</param>
  615.         /// <param name="has_alpha">Image has alpha channel.</param>
  616.         /// <param name="has_animation">Image is a animation.</param>
  617.         /// <param name="format">Format of image: 0 = undefined (/mixed), 1 = lossy, 2 = lossless.
  618.         /// </param>
  619.         public void GetInfo(byte[] rawWebP, out int width, out int height, out bool has_alpha, out bool has_animation, out string format) {
  620.             VP8StatusCode result;
  621.             GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned);
  622.  
  623.             try {
  624.                 IntPtr ptrRawWebP = pinnedWebP.AddrOfPinnedObject();
  625.  
  626.                 WebPBitstreamFeatures features = new WebPBitstreamFeatures();
  627.                 result = UnsafeNativeMethods.WebPGetFeatures(ptrRawWebP, rawWebP.Length, ref features);
  628.  
  629.                 if (result != 0) {
  630.                     throw new Exception(result.ToString());
  631.                 }
  632.                 width = features.Width;
  633.                 height = features.Height;
  634.                 if (features.Has_alpha == 1) {
  635.                     has_alpha = true;
  636.                 } else {
  637.                     has_alpha = false;
  638.                 }
  639.                 if (features.Has_animation == 1) {
  640.                     has_animation = true;
  641.                 } else {
  642.                     has_animation = false;
  643.                 }
  644.                 switch (features.Format) {
  645.                     case 1:
  646.                         format = "lossy";
  647.                         break;
  648.                     case 2:
  649.                         format = "lossless";
  650.                         break;
  651.                     default:
  652.                         format = "undefined";
  653.                         break;
  654.                 }
  655.             } catch (Exception exception) {
  656.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.GetInfo.");
  657.             } finally {
  658.                 // Free memory
  659.                 if (pinnedWebP.IsAllocated) {
  660.                     pinnedWebP.Free();
  661.                 }
  662.             }
  663.         }
  664.  
  665.         /// <summary>Compute PSNR, SSIM or LSIM distortion metric between two pictures. Warning: this
  666.         /// function is rather CPU-intensive.</summary>
  667.         /// <param name="source">Picture to measure.</param>
  668.         /// <param name="reference">Reference picture.</param>
  669.         /// <param name="metric_type">0 = PSNR, 1 = SSIM, 2 = LSIM.</param>
  670.         /// <returns>dB in the Y/U/V/Alpha/All order.</returns>
  671.         public float[] GetPictureDistortion(Bitmap source, Bitmap reference, int metric_type) {
  672.             WebPPicture wpicSource = new WebPPicture();
  673.             WebPPicture wpicReference = new WebPPicture();
  674.             BitmapData sourceBmpData = null;
  675.             BitmapData referenceBmpData = null;
  676.             float[] result = new float[5];
  677.             GCHandle pinnedResult = GCHandle.Alloc(result, GCHandleType.Pinned);
  678.  
  679.             try {
  680.                 if (source == null) {
  681.                     throw new Exception("Source picture is void.");
  682.                 }
  683.                 if (reference == null) {
  684.                     throw new Exception("Reference picture is void.");
  685.                 }
  686.                 if (metric_type > 2) {
  687.                     throw new Exception("Bad metric_type. Use 0 = PSNR, 1 = SSIM, 2 = LSIM.");
  688.                 }
  689.                 if (source.Width != reference.Width || source.Height != reference.Height) {
  690.                     throw new Exception("Source and Reference pictures have different dimensions.");
  691.                 }
  692.                 // Setup the source picture data, allocating the bitmap, width and height
  693.                 sourceBmpData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat);
  694.                 wpicSource = new WebPPicture();
  695.                 if (UnsafeNativeMethods.WebPPictureInitInternal(ref wpicSource) != 1) {
  696.                     throw new Exception("Can't initialize WebPPictureInit.");
  697.                 }
  698.                 wpicSource.width = source.Width;
  699.                 wpicSource.height = source.Height;
  700.  
  701.                 // Put the source bitmap componets in wpic
  702.                 if (sourceBmpData.PixelFormat == PixelFormat.Format32bppArgb) {
  703.                     wpicSource.use_argb = 1;
  704.                     if (UnsafeNativeMethods.WebPPictureImportBGRA(ref wpicSource, sourceBmpData.Scan0, sourceBmpData.Stride) != 1) {
  705.                         throw new Exception("Can't allocate memory in WebPPictureImportBGR.");
  706.                     }
  707.                 } else {
  708.                     wpicSource.use_argb = 0;
  709.                     if (UnsafeNativeMethods.WebPPictureImportBGR(ref wpicSource, sourceBmpData.Scan0, sourceBmpData.Stride) != 1) {
  710.                         throw new Exception("Can't allocate memory in WebPPictureImportBGR.");
  711.                     }
  712.                 }
  713.  
  714.                 // Setup the reference picture data, allocating the bitmap, width and height
  715.                 referenceBmpData = reference.LockBits(new Rectangle(0, 0, reference.Width, reference.Height), ImageLockMode.ReadOnly, reference.PixelFormat);
  716.                 wpicReference = new WebPPicture();
  717.                 if (UnsafeNativeMethods.WebPPictureInitInternal(ref wpicReference) != 1) {
  718.                     throw new Exception("Can't initialize WebPPictureInit.");
  719.                 }
  720.                 wpicReference.width = reference.Width;
  721.                 wpicReference.height = reference.Height;
  722.                 wpicReference.use_argb = 1;
  723.  
  724.                 // Put the source bitmap contents in WebPPicture instance
  725.                 if (sourceBmpData.PixelFormat == PixelFormat.Format32bppArgb) {
  726.                     wpicSource.use_argb = 1;
  727.                     if (UnsafeNativeMethods.WebPPictureImportBGRA(ref wpicReference, referenceBmpData.Scan0, referenceBmpData.Stride) != 1) {
  728.                         throw new Exception("Can't allocate memory in WebPPictureImportBGR.");
  729.                     }
  730.                 } else {
  731.                     wpicSource.use_argb = 0;
  732.                     if (UnsafeNativeMethods.WebPPictureImportBGR(ref wpicReference, referenceBmpData.Scan0, referenceBmpData.Stride) != 1) {
  733.                         throw new Exception("Can't allocate memory in WebPPictureImportBGR.");
  734.                     }
  735.                 }
  736.  
  737.                 // Measure
  738.                 IntPtr ptrResult = pinnedResult.AddrOfPinnedObject();
  739.                 if (UnsafeNativeMethods.WebPPictureDistortion(ref wpicSource, ref wpicReference, metric_type, ptrResult) != 1) {
  740.                     throw new Exception("Can't measure.");
  741.                 }
  742.                 return result;
  743.             } catch (Exception exception) {
  744.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.GetPictureDistortion.");
  745.             } finally {
  746.                 // Unlock the pixels
  747.                 if (sourceBmpData != null) {
  748.                     source.UnlockBits(sourceBmpData);
  749.                 }
  750.                 if (referenceBmpData != null) {
  751.                     reference.UnlockBits(referenceBmpData);
  752.                 }
  753.                 // Free memory
  754.                 if (wpicSource.argb != IntPtr.Zero) {
  755.                     UnsafeNativeMethods.WebPPictureFree(ref wpicSource);
  756.                 }
  757.                 if (wpicReference.argb != IntPtr.Zero) {
  758.                     UnsafeNativeMethods.WebPPictureFree(ref wpicReference);
  759.                 }
  760.                 // Free memory
  761.                 if (pinnedResult.IsAllocated) {
  762.                     pinnedResult.Free();
  763.                 }
  764.             }
  765.         }
  766.  
  767.         #endregion
  768.  
  769.  
  770.         #region Private Methods
  771.  
  772.         /// <summary>Encoding image using Advanced encoding API.</summary>
  773.         /// <param name="bmp">Bitmap with the image.</param>
  774.         /// <param name="config">Configuration for encode.</param>
  775.         /// <param name="info">True if need encode info.</param>
  776.         /// <returns>Compressed data.</returns>
  777.         private byte[] AdvancedEncode(Bitmap bmp, WebPConfig config, bool info) {
  778.             byte[] rawWebP = null;
  779.             byte[] dataWebp = null;
  780.             WebPPicture wpic = new WebPPicture();
  781.             BitmapData bmpData = null;
  782.             WebPAuxStats stats = new WebPAuxStats();
  783.             IntPtr ptrStats = IntPtr.Zero;
  784.             GCHandle pinnedArrayHandle = new GCHandle();
  785.             int dataWebpSize;
  786.             try {
  787.                 //Validate the configuration
  788.                 if (UnsafeNativeMethods.WebPValidateConfig(ref config) != 1) {
  789.                     throw new Exception("Bad configuration parameters.");
  790.                 }
  791.                 // Test bmp
  792.                 if (bmp.Width == 0 || bmp.Height == 0) {
  793.                     throw new ArgumentException("Bitmap contains no data.", "bmp");
  794.                 }
  795.                 if (bmp.Width > WEBP_MAX_DIMENSION || bmp.Height > WEBP_MAX_DIMENSION) {
  796.                     throw new NotSupportedException("Bitmap's dimension is too large. Max is " + WEBP_MAX_DIMENSION + "×" + WEBP_MAX_DIMENSION + " pixels.");
  797.                 }
  798.                 if (bmp.PixelFormat != PixelFormat.Format24bppRgb && bmp.PixelFormat != PixelFormat.Format32bppArgb) {
  799.                     throw new NotSupportedException("Only support Format24bppRgb and Format32bppArgb pixelFormat.");
  800.                 }
  801.                 // Setup the input data, allocating a the bitmap, width and height
  802.                 bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
  803.                 if (UnsafeNativeMethods.WebPPictureInitInternal(ref wpic) != 1) {
  804.                     throw new Exception("Can't initialize WebPPictureInit.");
  805.                 }
  806.                 wpic.width = bmp.Width;
  807.                 wpic.height = bmp.Height;
  808.                 wpic.use_argb = 1;
  809.  
  810.                 if (bmp.PixelFormat == PixelFormat.Format32bppArgb) {
  811.                     // Put the bitmap componets in wpic
  812.                     int result = UnsafeNativeMethods.WebPPictureImportBGRA(ref wpic, bmpData.Scan0, bmpData.Stride);
  813.                     if (result != 1) {
  814.                         throw new Exception("Can't allocate memory in WebPPictureImportBGRA.");
  815.                     }
  816.                     wpic.colorspace = (uint)WEBP_CSP_MODE.MODE_bgrA;
  817.                     dataWebpSize = bmp.Width * bmp.Height * 32;
  818.                     // Memory for WebP output
  819.                     dataWebp = new byte[bmp.Width * bmp.Height * 32];
  820.                 } else {
  821.                     // Put the bitmap contents in WebPPicture instance
  822.                     int result = UnsafeNativeMethods.WebPPictureImportBGR(ref wpic, bmpData.Scan0, bmpData.Stride);
  823.                     if (result != 1) {
  824.                         throw new Exception("Can't allocate memory in WebPPictureImportBGR.");
  825.                     }
  826.                     dataWebpSize = bmp.Width * bmp.Height * 24;
  827.                 }
  828.  
  829.                 // Set up statistics of compression
  830.                 if (info) {
  831.                     stats = new WebPAuxStats();
  832.                     ptrStats = Marshal.AllocHGlobal(Marshal.SizeOf(stats));
  833.                     Marshal.StructureToPtr(stats, ptrStats, false);
  834.                     wpic.stats = ptrStats;
  835.                 }
  836.  
  837.                 // Memory for WebP output
  838.                 if (dataWebpSize > 2147483591) {
  839.                     dataWebpSize = 2147483591;
  840.                 }
  841.                 dataWebp = new byte[bmp.Width * bmp.Height * 32];
  842.                 pinnedArrayHandle = GCHandle.Alloc(dataWebp, GCHandleType.Pinned);
  843.                 IntPtr intPtr = pinnedArrayHandle.AddrOfPinnedObject();
  844.                 wpic.custom_ptr = intPtr;
  845.  
  846.                 // Set up a byte-writing method (write-to-memory, in this case)
  847.                 UnsafeNativeMethods.OnCallback = new UnsafeNativeMethods.WebPMemoryWrite(MyWriter);
  848.                 wpic.writer = Marshal.GetFunctionPointerForDelegate(UnsafeNativeMethods.OnCallback);
  849.  
  850.                 // Compress the input samples
  851.                 if (UnsafeNativeMethods.WebPEncode(ref config, ref wpic) != 1) {
  852.                     throw new Exception(string.Format("Encoding error: {0}.", (WebPEncodingError)wpic.error_code));
  853.                 }
  854.                 // Remove OnCallback
  855.                 UnsafeNativeMethods.OnCallback = null;
  856.  
  857.                 // Unlock the pixels
  858.                 bmp.UnlockBits(bmpData);
  859.                 bmpData = null;
  860.  
  861.                 // Copy webpData to rawWebP
  862.                 int size = (int)((long)wpic.custom_ptr - (long)intPtr);
  863.                 rawWebP = new byte[size];
  864.                 Array.Copy(dataWebp, rawWebP, size);
  865.  
  866.                 // Remove compression data
  867.                 pinnedArrayHandle.Free();
  868.                 dataWebp = null;
  869.  
  870.                 // Show statistics
  871.                 if (info) {
  872.                     stats = (WebPAuxStats)Marshal.PtrToStructure(ptrStats, typeof(WebPAuxStats));
  873.                     StringBuilder message = new StringBuilder()
  874.                         .Append("Dimension: ").Append(wpic.width).Append("×").Append(wpic.height).Append(" pixels").Append(Environment.NewLine)
  875.                         .Append("Output:    ").Append(stats.coded_size).Append(" bytes").Append(Environment.NewLine)
  876.                         .Append("PSNR Y:    ").Append(stats.PSNRY).Append(" db").Append(Environment.NewLine)
  877.                         .Append("PSNR u:    ").Append(stats.PSNRU).Append(" db").Append(Environment.NewLine)
  878.                         .Append("PSNR v:    ").Append(stats.PSNRV).Append(" db").Append(Environment.NewLine)
  879.                         .Append("PSNR ALL:  ").Append(stats.PSNRALL).Append(" db").Append(Environment.NewLine)
  880.                         .Append("Block intra4:  ").Append(stats.block_count_intra4).Append(Environment.NewLine)
  881.                         .Append("Block intra16: ").Append(stats.block_count_intra16).Append(Environment.NewLine)
  882.                         .Append("Block skipped: ").Append(stats.block_count_skipped).Append(Environment.NewLine)
  883.                         .Append("Header size:    ").Append(stats.header_bytes).Append(" bytes").Append(Environment.NewLine)
  884.                         .Append("Mode-partition: ").Append(stats.mode_partition_0).Append(" bytes").Append(Environment.NewLine)
  885.                         .Append("Macro-blocks 0: ").Append(stats.segment_size_segments0).Append(" residuals bytes").Append(Environment.NewLine)
  886.                         .Append("Macro-blocks 1: ").Append(stats.segment_size_segments1).Append(" residuals bytes").Append(Environment.NewLine)
  887.                         .Append("Macro-blocks 2: ").Append(stats.segment_size_segments2).Append(" residuals bytes").Append(Environment.NewLine)
  888.                         .Append("Macro-blocks 3: ").Append(stats.segment_size_segments3).Append(" residuals bytes").Append(Environment.NewLine)
  889.                         .Append("Quantizer    0: ").Append(stats.segment_quant_segments0).Append(" residuals bytes").Append(Environment.NewLine)
  890.                         .Append("Quantizer    1: ").Append(stats.segment_quant_segments1).Append(" residuals bytes").Append(Environment.NewLine)
  891.                         .Append("Quantizer    2: ").Append(stats.segment_quant_segments2).Append(" residuals bytes").Append(Environment.NewLine)
  892.                         .Append("Quantizer    3: ").Append(stats.segment_quant_segments3).Append(" residuals bytes").Append(Environment.NewLine)
  893.                         .Append("Filter level 0: ").Append(stats.segment_level_segments0).Append(" residuals bytes").Append(Environment.NewLine)
  894.                         .Append("Filter level 1: ").Append(stats.segment_level_segments1).Append(" residuals bytes").Append(Environment.NewLine)
  895.                         .Append("Filter level 2: ").Append(stats.segment_level_segments2).Append(" residuals bytes").Append(Environment.NewLine)
  896.                         .Append("Filter level 3: ").Append(stats.segment_level_segments3).Append(" residuals bytes");
  897.                     MessageBox.Show(message.ToString(), "Compression statistics", MessageBoxButtons.OK, MessageBoxIcon.Information);
  898.                 }
  899.  
  900.                 return rawWebP;
  901.             } catch (Exception exception) {
  902.                 throw new Exception(exception.Message + Environment.NewLine + "In WebP.AdvancedEncode.");
  903.             } finally {
  904.                 // Free temporal compress memory
  905.                 if (pinnedArrayHandle.IsAllocated) {
  906.                     pinnedArrayHandle.Free();
  907.                 }
  908.                 // Free statistics memory
  909.                 if (ptrStats != IntPtr.Zero) {
  910.                     Marshal.FreeHGlobal(ptrStats);
  911.                 }
  912.                 // Unlock the pixels
  913.                 if (bmpData != null) {
  914.                     bmp.UnlockBits(bmpData);
  915.                 }
  916.                 // Free memory
  917.                 if (wpic.argb != IntPtr.Zero) {
  918.                     UnsafeNativeMethods.WebPPictureFree(ref wpic);
  919.                 }
  920.             }
  921.         }
  922.  
  923.         private int MyWriter([In()] IntPtr data, UIntPtr data_size, ref WebPPicture picture) {
  924.             UnsafeNativeMethods.CopyMemory(picture.custom_ptr, data, (uint)data_size);
  925.             picture.custom_ptr = new IntPtr(picture.custom_ptr.ToInt64() + (int)data_size);
  926.             return 1;
  927.         }
  928.  
  929.         private delegate int MyWriterDelegate([In()] IntPtr data, UIntPtr data_size, ref WebPPicture picture);
  930.  
  931.         #endregion
  932.  
  933.  
  934.         #region Destruction
  935.  
  936.         /// <summary>Free memory.</summary>
  937.         public void Dispose() {
  938.             GC.SuppressFinalize(this);
  939.         }
  940.  
  941.         #endregion
  942.     }
  943.  
  944.  
  945.     #region Import libwebp functions
  946.  
  947.     [SuppressUnmanagedCodeSecurity]
  948.     internal static class UnsafeNativeMethods {
  949.  
  950.         [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
  951.         internal static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
  952.  
  953.         private static readonly int WEBP_DECODER_ABI_VERSION = 0x0208;
  954.  
  955.         /// <summary>This function will initialize the configuration according to a predefined set of
  956.         /// parameters (referred to by 'preset') and a given quality factor.</summary>
  957.         /// <param name="config">The WebPConfig structure.</param>
  958.         /// <param name="preset">Type of image.</param>
  959.         /// <param name="quality">Quality of compression.</param>
  960.         /// <returns>0 if error.</returns>
  961.         internal static int WebPConfigInit(ref WebPConfig config, WebPPreset preset, float quality) {
  962.             switch (IntPtr.Size) {
  963.                 case 4:
  964.                     return WebPConfigInitInternal_x86(ref config, preset, quality, WEBP_DECODER_ABI_VERSION);
  965.                 case 8:
  966.                     return WebPConfigInitInternal_x64(ref config, preset, quality, WEBP_DECODER_ABI_VERSION);
  967.                 default:
  968.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  969.             }
  970.         }
  971.  
  972.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPConfigInitInternal")]
  973.         private static extern int WebPConfigInitInternal_x86(ref WebPConfig config, WebPPreset preset, float quality, int WEBP_DECODER_ABI_VERSION);
  974.  
  975.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPConfigInitInternal")]
  976.         private static extern int WebPConfigInitInternal_x64(ref WebPConfig config, WebPPreset preset, float quality, int WEBP_DECODER_ABI_VERSION);
  977.  
  978.         /// <summary>Get info of WepP image.</summary>
  979.         /// <param name="rawWebP">Bytes[] of WebP image.</param>
  980.         /// <param name="data_size">Size of rawWebP.</param>
  981.         /// <param name="features">Features of WebP image.</param>
  982.         /// <returns>VP8StatusCode</returns>
  983.         internal static VP8StatusCode WebPGetFeatures(IntPtr rawWebP, int data_size, ref WebPBitstreamFeatures features) {
  984.             switch (IntPtr.Size) {
  985.                 case 4:
  986.                     return WebPGetFeaturesInternal_x86(rawWebP, (UIntPtr)data_size, ref features, WEBP_DECODER_ABI_VERSION);
  987.                 case 8:
  988.                     return WebPGetFeaturesInternal_x64(rawWebP, (UIntPtr)data_size, ref features, WEBP_DECODER_ABI_VERSION);
  989.                 default:
  990.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  991.             }
  992.         }
  993.  
  994.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetFeaturesInternal")]
  995.         private static extern VP8StatusCode WebPGetFeaturesInternal_x86([In()] IntPtr rawWebP, UIntPtr data_size, ref WebPBitstreamFeatures features, int WEBP_DECODER_ABI_VERSION);
  996.  
  997.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetFeaturesInternal")]
  998.         private static extern VP8StatusCode WebPGetFeaturesInternal_x64([In()] IntPtr rawWebP, UIntPtr data_size, ref WebPBitstreamFeatures features, int WEBP_DECODER_ABI_VERSION);
  999.  
  1000.         /// <summary>Activate the lossless compression mode with the desired efficiency.</summary>
  1001.         /// <param name="config">The WebPConfig struct.</param>
  1002.         /// <param name="level">Between 0 (fastest, lowest compression) and 9 (slower, best
  1003.         /// compression).</param>
  1004.         /// <returns>0 in case of parameter error.</returns>
  1005.         internal static int WebPConfigLosslessPreset(ref WebPConfig config, int level) {
  1006.             switch (IntPtr.Size) {
  1007.                 case 4:
  1008.                     return WebPConfigLosslessPreset_x86(ref config, level);
  1009.                 case 8:
  1010.                     return WebPConfigLosslessPreset_x64(ref config, level);
  1011.                 default:
  1012.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1013.             }
  1014.         }
  1015.  
  1016.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPConfigLosslessPreset")]
  1017.         private static extern int WebPConfigLosslessPreset_x86(ref WebPConfig config, int level);
  1018.  
  1019.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPConfigLosslessPreset")]
  1020.         private static extern int WebPConfigLosslessPreset_x64(ref WebPConfig config, int level);
  1021.  
  1022.         /// <summary>Check that configuration is non-NULL and all configuration parameters are within
  1023.         /// their valid ranges.</summary>
  1024.         /// <param name="config">The WebPConfig structure.</param>
  1025.         /// <returns>1 if configuration is OK.</returns>
  1026.         internal static int WebPValidateConfig(ref WebPConfig config) {
  1027.             switch (IntPtr.Size) {
  1028.                 case 4:
  1029.                     return WebPValidateConfig_x86(ref config);
  1030.                 case 8:
  1031.                     return WebPValidateConfig_x64(ref config);
  1032.                 default:
  1033.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1034.             }
  1035.         }
  1036.  
  1037.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPValidateConfig")]
  1038.         private static extern int WebPValidateConfig_x86(ref WebPConfig config);
  1039.  
  1040.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPValidateConfig")]
  1041.         private static extern int WebPValidateConfig_x64(ref WebPConfig config);
  1042.  
  1043.         /// <summary>Initialize the WebPPicture structure checking the DLL version.</summary>
  1044.         /// <param name="wpic">The WebPPicture structure.</param>
  1045.         /// <returns>1 if not error.</returns>
  1046.         internal static int WebPPictureInitInternal(ref WebPPicture wpic) {
  1047.             switch (IntPtr.Size) {
  1048.                 case 4:
  1049.                     return WebPPictureInitInternal_x86(ref wpic, WEBP_DECODER_ABI_VERSION);
  1050.                 case 8:
  1051.                     return WebPPictureInitInternal_x64(ref wpic, WEBP_DECODER_ABI_VERSION);
  1052.                 default:
  1053.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1054.             }
  1055.         }
  1056.  
  1057.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureInitInternal")]
  1058.         private static extern int WebPPictureInitInternal_x86(ref WebPPicture wpic, int WEBP_DECODER_ABI_VERSION);
  1059.  
  1060.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureInitInternal")]
  1061.         private static extern int WebPPictureInitInternal_x64(ref WebPPicture wpic, int WEBP_DECODER_ABI_VERSION);
  1062.  
  1063.         /// <summary>Colorspace conversion function to import RGB samples.</summary>
  1064.         /// <param name="wpic">The WebPPicture structure.</param>
  1065.         /// <param name="bgr">Point to BGR data.</param>
  1066.         /// <param name="stride">Stride of BGR data.</param>
  1067.         /// <returns>Returns 0 in case of memory error.</returns>
  1068.         internal static int WebPPictureImportBGR(ref WebPPicture wpic, IntPtr bgr, int stride) {
  1069.             switch (IntPtr.Size) {
  1070.                 case 4:
  1071.                     return WebPPictureImportBGR_x86(ref wpic, bgr, stride);
  1072.                 case 8:
  1073.                     return WebPPictureImportBGR_x64(ref wpic, bgr, stride);
  1074.                 default:
  1075.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1076.             }
  1077.         }
  1078.  
  1079.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGR")]
  1080.         private static extern int WebPPictureImportBGR_x86(ref WebPPicture wpic, IntPtr bgr, int stride);
  1081.  
  1082.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGR")]
  1083.         private static extern int WebPPictureImportBGR_x64(ref WebPPicture wpic, IntPtr bgr, int stride);
  1084.  
  1085.         /// <summary>Color-space conversion function to import RGB samples.</summary>
  1086.         /// <param name="wpic">The WebPPicture structure</param>
  1087.         /// <param name="bgra">Point to BGRA data</param>
  1088.         /// <param name="stride">stride of BGRA data</param>
  1089.         /// <returns>Returns 0 in case of memory error.</returns>
  1090.         internal static int WebPPictureImportBGRA(ref WebPPicture wpic, IntPtr bgra, int stride) {
  1091.             switch (IntPtr.Size) {
  1092.                 case 4:
  1093.                     return WebPPictureImportBGRA_x86(ref wpic, bgra, stride);
  1094.                 case 8:
  1095.                     return WebPPictureImportBGRA_x64(ref wpic, bgra, stride);
  1096.                 default:
  1097.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1098.             }
  1099.         }
  1100.  
  1101.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGRA")]
  1102.         private static extern int WebPPictureImportBGRA_x86(ref WebPPicture wpic, IntPtr bgra, int stride);
  1103.  
  1104.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGRA")]
  1105.         private static extern int WebPPictureImportBGRA_x64(ref WebPPicture wpic, IntPtr bgra, int stride);
  1106.  
  1107.         /// <summary>Color-space conversion function to import RGB samples.</summary>
  1108.         /// <param name="wpic">The WebPPicture structure.</param>
  1109.         /// <param name="bgr">Point to BGR data.</param>
  1110.         /// <param name="stride">stride of BGR data.</param>
  1111.         /// <returns>Returns 0 in case of memory error.</returns>
  1112.         internal static int WebPPictureImportBGRX(ref WebPPicture wpic, IntPtr bgr, int stride) {
  1113.             switch (IntPtr.Size) {
  1114.                 case 4:
  1115.                     return WebPPictureImportBGRX_x86(ref wpic, bgr, stride);
  1116.                 case 8:
  1117.                     return WebPPictureImportBGRX_x64(ref wpic, bgr, stride);
  1118.                 default:
  1119.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1120.             }
  1121.         }
  1122.  
  1123.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGRX")]
  1124.         private static extern int WebPPictureImportBGRX_x86(ref WebPPicture wpic, IntPtr bgr, int stride);
  1125.  
  1126.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureImportBGRX")]
  1127.         private static extern int WebPPictureImportBGRX_x64(ref WebPPicture wpic, IntPtr bgr, int stride);
  1128.  
  1129.         /// <summary>The writer type for output compress data.</summary>
  1130.         /// <param name="data">Data returned.</param>
  1131.         /// <param name="data_size">Size of data returned.</param>
  1132.         /// <param name="wpic">Picture structure.</param>
  1133.         /// <returns></returns>
  1134.         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  1135.         internal delegate int WebPMemoryWrite([In()] IntPtr data, UIntPtr data_size, ref WebPPicture wpic);
  1136.         internal static WebPMemoryWrite OnCallback;
  1137.  
  1138.         /// <summary>Compress to WebP format.</summary>
  1139.         /// <param name="config">The configuration structure for compression parameters.</param>
  1140.         /// <param name="picture">'picture' hold the source samples in both YUV(A) or ARGB input.
  1141.         /// </param>
  1142.         /// <returns>Returns 0 in case of error, 1 otherwise. In case of error, picture->error_code is
  1143.         /// updated accordingly.</returns>
  1144.         internal static int WebPEncode(ref WebPConfig config, ref WebPPicture picture) {
  1145.             switch (IntPtr.Size) {
  1146.                 case 4:
  1147.                     return WebPEncode_x86(ref config, ref picture);
  1148.                 case 8:
  1149.                     return WebPEncode_x64(ref config, ref picture);
  1150.                 default:
  1151.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1152.             }
  1153.         }
  1154.  
  1155.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncode")]
  1156.         private static extern int WebPEncode_x86(ref WebPConfig config, ref WebPPicture picture);
  1157.  
  1158.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncode")]
  1159.         private static extern int WebPEncode_x64(ref WebPConfig config, ref WebPPicture picture);
  1160.  
  1161.         /// <summary>Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*().
  1162.         /// Note that this function does _not_ free the memory used by the 'picture' object itself.
  1163.         /// Besides memory (which is reclaimed) all other fields of 'picture' are preserved.</summary>
  1164.         /// <param name="picture">Picture structure</param>
  1165.         internal static void WebPPictureFree(ref WebPPicture picture) {
  1166.             switch (IntPtr.Size) {
  1167.                 case 4:
  1168.                     WebPPictureFree_x86(ref picture);
  1169.                     break;
  1170.                 case 8:
  1171.                     WebPPictureFree_x64(ref picture);
  1172.                     break;
  1173.                 default:
  1174.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1175.             }
  1176.         }
  1177.  
  1178.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureFree")]
  1179.         private static extern void WebPPictureFree_x86(ref WebPPicture wpic);
  1180.  
  1181.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureFree")]
  1182.         private static extern void WebPPictureFree_x64(ref WebPPicture wpic);
  1183.  
  1184.         /// <summary>Validate the WebP image header and retrieve the image height and width. Pointer
  1185.         /// *width and *height can be passed NULL if deemed irrelevant.</summary>
  1186.         /// <param name="data">Pointer to WebP image data.</param>
  1187.         /// <param name="data_size">This is the size of the memory block pointed to by data containing
  1188.         /// the image data.</param>
  1189.         /// <param name="width">The range is limited currently from 1 to 16383.</param>
  1190.         /// <param name="height">The range is limited currently from 1 to 16383.</param>
  1191.         /// <returns>1 if success, otherwise error code returned in the case of (a) formatting
  1192.         /// error(s).</returns>
  1193.         internal static int WebPGetInfo(IntPtr data, int data_size, out int width, out int height) {
  1194.             switch (IntPtr.Size) {
  1195.                 case 4:
  1196.                     return WebPGetInfo_x86(data, (UIntPtr)data_size, out width, out height);
  1197.                 case 8:
  1198.                     return WebPGetInfo_x64(data, (UIntPtr)data_size, out width, out height);
  1199.                 default:
  1200.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1201.             }
  1202.         }
  1203.  
  1204.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetInfo")]
  1205.         private static extern int WebPGetInfo_x86([In()] IntPtr data, UIntPtr data_size, out int width, out int height);
  1206.  
  1207.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetInfo")]
  1208.         private static extern int WebPGetInfo_x64([In()] IntPtr data, UIntPtr data_size, out int width, out int height);
  1209.  
  1210.         /// <summary>
  1211.         /// Decode WEBP image pointed to by *data and returns BGR samples into a preallocated buffer.
  1212.         /// </summary>
  1213.         /// <param name="data">Pointer to WebP image data.</param>
  1214.         /// <param name="data_size">This is the size of the memory block pointed to by data containing
  1215.         /// the image data.</param>
  1216.         /// <param name="output_buffer">Pointer to decoded WebP image.</param>
  1217.         /// <param name="output_buffer_size">Size of allocated buffer.</param>
  1218.         /// <param name="output_stride">Specifies the distance between scan lines.</param>
  1219.         internal static void WebPDecodeBGRInto(IntPtr data, int data_size, IntPtr output_buffer, int output_buffer_size, int output_stride) {
  1220.             switch (IntPtr.Size) {
  1221.                 case 4:
  1222.                     if (WebPDecodeBGRInto_x86(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)
  1223.                         throw new InvalidOperationException("Cannot decode WebP.");
  1224.                     break;
  1225.                 case 8:
  1226.                     if (WebPDecodeBGRInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)
  1227.                         throw new InvalidOperationException("Cannot decode WebP.");
  1228.                     break;
  1229.                 default:
  1230.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1231.             }
  1232.         }
  1233.  
  1234.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRInto")]
  1235.         private static extern IntPtr WebPDecodeBGRInto_x86([In()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride);
  1236.  
  1237.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRInto")]
  1238.         private static extern IntPtr WebPDecodeBGRInto_x64([In()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride);
  1239.  
  1240.         /// <summary>
  1241.         /// Decode WEBP image pointed to by *data and returns BGRA samples into a preallocated buffer.
  1242.         /// </summary>
  1243.         /// <param name="data">Pointer to WebP image data.</param>
  1244.         /// <param name="data_size">This is the size of the memory block pointed to by data containing
  1245.         /// the image data.</param>
  1246.         /// <param name="output_buffer">Pointer to decoded WebP image.</param>
  1247.         /// <param name="output_buffer_size">Size of allocated buffer.</param>
  1248.         /// <param name="output_stride">Specifies the distance between scan lines.</param>
  1249.         internal static void WebPDecodeBGRAInto(IntPtr data, int data_size, IntPtr output_buffer, int output_buffer_size, int output_stride) {
  1250.             switch (IntPtr.Size) {
  1251.                 case 4:
  1252.                     if (WebPDecodeBGRAInto_x86(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)
  1253.                         throw new InvalidOperationException("Cannot decode WebP.");
  1254.                     break;
  1255.                 case 8:
  1256.                     if (WebPDecodeBGRAInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)
  1257.                         throw new InvalidOperationException("Cannot decode WebP.");
  1258.                     break;
  1259.                 default:
  1260.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1261.             }
  1262.         }
  1263.  
  1264.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")]
  1265.         private static extern IntPtr WebPDecodeBGRAInto_x86([In()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride);
  1266.  
  1267.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")]
  1268.         private static extern IntPtr WebPDecodeBGRAInto_x64([In()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride);
  1269.  
  1270.         /// <summary>
  1271.         /// Decode WEBP image pointed to by *data and returns ARGB samples into a preallocated buffer.
  1272.         /// </summary>
  1273.         /// <param name="data">Pointer to WebP image data.</param>
  1274.         /// <param name="data_size">This is the size of the memory block pointed to by data containing
  1275.         /// the image data.</param>
  1276.         /// <param name="output_buffer">Pointer to decoded WebP image.</param>
  1277.         /// <param name="output_buffer_size">Size of allocated buffer.</param>
  1278.         /// <param name="output_stride">Specifies the distance between scan lines.</param>
  1279.         internal static void WebPDecodeARGBInto(IntPtr data, int data_size, IntPtr output_buffer, int output_buffer_size, int output_stride) {
  1280.             switch (IntPtr.Size) {
  1281.                 case 4:
  1282.                     if (WebPDecodeARGBInto_x86(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)
  1283.                         throw new InvalidOperationException("Can not decode WebP.");
  1284.                     break;
  1285.                 case 8:
  1286.                     if (WebPDecodeARGBInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)
  1287.                         throw new InvalidOperationException("Can not decode WebP.");
  1288.                     break;
  1289.                 default:
  1290.                     throw new InvalidOperationException("Invalid platform. Can not find proper function.");
  1291.             }
  1292.         }
  1293.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeARGBInto")]
  1294.         private static extern IntPtr WebPDecodeARGBInto_x86([In()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride);
  1295.  
  1296.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeARGBInto")]
  1297.         private static extern IntPtr WebPDecodeARGBInto_x64([In()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride);
  1298.  
  1299.         /// <summary>Initialize the configuration as empty. This function must always be called first,
  1300.         /// unless WebPGetFeatures() is to be called.</summary>
  1301.         /// <param name="webPDecoderConfig">Configuration structure.</param>
  1302.         /// <returns>False in case of mismatched version.</returns>
  1303.         internal static int WebPInitDecoderConfig(ref WebPDecoderConfig webPDecoderConfig) {
  1304.             switch (IntPtr.Size) {
  1305.                 case 4:
  1306.                     return WebPInitDecoderConfigInternal_x86(ref webPDecoderConfig, WEBP_DECODER_ABI_VERSION);
  1307.                 case 8:
  1308.                     return WebPInitDecoderConfigInternal_x64(ref webPDecoderConfig, WEBP_DECODER_ABI_VERSION);
  1309.                 default:
  1310.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1311.             }
  1312.         }
  1313.  
  1314.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPInitDecoderConfigInternal")]
  1315.         private static extern int WebPInitDecoderConfigInternal_x86(ref WebPDecoderConfig webPDecoderConfig, int WEBP_DECODER_ABI_VERSION);
  1316.  
  1317.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPInitDecoderConfigInternal")]
  1318.         private static extern int WebPInitDecoderConfigInternal_x64(ref WebPDecoderConfig webPDecoderConfig, int WEBP_DECODER_ABI_VERSION);
  1319.  
  1320.         /// <summary>Decodes the full data at once, taking configuration into account.</summary>
  1321.         /// <param name="data">WebP raw data to decode.</param>
  1322.         /// <param name="data_size">Size of WebP data.</param>
  1323.         /// <param name="webPDecoderConfig">Configuration structure.</param>
  1324.         /// <returns>VP8_STATUS_OK if the decoding was successful.</returns>
  1325.         internal static VP8StatusCode WebPDecode(IntPtr data, int data_size, ref WebPDecoderConfig webPDecoderConfig) {
  1326.             switch (IntPtr.Size) {
  1327.                 case 4:
  1328.                     return WebPDecode_x86(data, (UIntPtr)data_size, ref webPDecoderConfig);
  1329.                 case 8:
  1330.                     return WebPDecode_x64(data, (UIntPtr)data_size, ref webPDecoderConfig);
  1331.                 default:
  1332.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1333.             }
  1334.         }
  1335.  
  1336.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecode")]
  1337.         private static extern VP8StatusCode WebPDecode_x86(IntPtr data, UIntPtr data_size, ref WebPDecoderConfig config);
  1338.  
  1339.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecode")]
  1340.         private static extern VP8StatusCode WebPDecode_x64(IntPtr data, UIntPtr data_size, ref WebPDecoderConfig config);
  1341.  
  1342.         /// <summary>Free any memory associated with the buffer. Must always be called last. Doesn't
  1343.         /// free the 'buffer' structure itself.</summary>
  1344.         /// <param name="buffer">WebPDecBuffer</param>
  1345.         internal static void WebPFreeDecBuffer(ref WebPDecBuffer buffer) {
  1346.             switch (IntPtr.Size) {
  1347.                 case 4:
  1348.                     WebPFreeDecBuffer_x86(ref buffer);
  1349.                     break;
  1350.                 case 8:
  1351.                     WebPFreeDecBuffer_x64(ref buffer);
  1352.                     break;
  1353.                 default:
  1354.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1355.             }
  1356.         }
  1357.  
  1358.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFreeDecBuffer")]
  1359.         private static extern void WebPFreeDecBuffer_x86(ref WebPDecBuffer buffer);
  1360.  
  1361.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFreeDecBuffer")]
  1362.         private static extern void WebPFreeDecBuffer_x64(ref WebPDecBuffer buffer);
  1363.  
  1364.         /// <summary>Lossy encoding images.</summary>
  1365.         /// <param name="bgr">Pointer to BGR image data.</param>
  1366.         /// <param name="width">The range is limited currently from 1 to 16383.</param>
  1367.         /// <param name="height">The range is limited currently from 1 to 16383.</param>
  1368.         /// <param name="stride">Specifies the distance between scanlines.</param>
  1369.         /// <param name="quality_factor">Ranges from 0 (lower quality) to 100 (highest quality).
  1370.         /// Controls the loss and quality during compression.</param>
  1371.         /// <param name="output">Output_buffer with WebP image.</param>
  1372.         /// <returns>Size of WebP Image or 0 if an error occurred.</returns>
  1373.         internal static int WebPEncodeBGR(IntPtr bgr, int width, int height, int stride, float quality_factor, out IntPtr output) {
  1374.             switch (IntPtr.Size) {
  1375.                 case 4:
  1376.                     return WebPEncodeBGR_x86(bgr, width, height, stride, quality_factor, out output);
  1377.                 case 8:
  1378.                     return WebPEncodeBGR_x64(bgr, width, height, stride, quality_factor, out output);
  1379.                 default:
  1380.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1381.             }
  1382.         }
  1383.  
  1384.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGR")]
  1385.         private static extern int WebPEncodeBGR_x86([In()] IntPtr bgr, int width, int height, int stride, float quality_factor, out IntPtr output);
  1386.  
  1387.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGR")]
  1388.         private static extern int WebPEncodeBGR_x64([In()] IntPtr bgr, int width, int height, int stride, float quality_factor, out IntPtr output);
  1389.  
  1390.         /// <summary>Lossy encoding images.</summary>
  1391.         /// <param name="bgr">Pointer to BGRA image data.</param>
  1392.         /// <param name="width">The range is limited currently from 1 to 16383.</param>
  1393.         /// <param name="height">The range is limited currently from 1 to 16383.</param>
  1394.         /// <param name="stride">Specifies the distance between scan lines.</param>
  1395.         /// <param name="quality_factor">Ranges from 0 (lower quality) to 100 (highest quality).
  1396.         /// Controls the loss and quality during compression.</param>
  1397.         /// <param name="output">Output_buffer with WebP image.</param>
  1398.         /// <returns>Size of WebP Image or 0 if an error occurred.</returns>
  1399.         internal static int WebPEncodeBGRA(IntPtr bgra, int width, int height, int stride, float quality_factor, out IntPtr output) {
  1400.             switch (IntPtr.Size) {
  1401.                 case 4:
  1402.                     return WebPEncodeBGRA_x86(bgra, width, height, stride, quality_factor, out output);
  1403.                 case 8:
  1404.                     return WebPEncodeBGRA_x64(bgra, width, height, stride, quality_factor, out output);
  1405.                 default:
  1406.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1407.             }
  1408.         }
  1409.  
  1410.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGRA")]
  1411.         private static extern int WebPEncodeBGRA_x86([In()] IntPtr bgra, int width, int height, int stride, float quality_factor, out IntPtr output);
  1412.  
  1413.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeBGRA")]
  1414.         private static extern int WebPEncodeBGRA_x64([In()] IntPtr bgra, int width, int height, int stride, float quality_factor, out IntPtr output);
  1415.  
  1416.         /// <summary>Lossless encoding images pointed to by *data in WebP format.</summary>
  1417.         /// <param name="bgr">Pointer to BGR image data.</param>
  1418.         /// <param name="width">The range is limited currently from 1 to 16383.</param>
  1419.         /// <param name="height">The range is limited currently from 1 to 16383.</param>
  1420.         /// <param name="stride">Specifies the distance between scan lines.</param>
  1421.         /// <param name="output">Output_buffer with WebP image.</param>
  1422.         /// <returns>Size of WebP Image or 0 if an error occurred.</returns>
  1423.         internal static int WebPEncodeLosslessBGR(IntPtr bgr, int width, int height, int stride, out IntPtr output) {
  1424.             switch (IntPtr.Size) {
  1425.                 case 4:
  1426.                     return WebPEncodeLosslessBGR_x86(bgr, width, height, stride, out output);
  1427.                 case 8:
  1428.                     return WebPEncodeLosslessBGR_x64(bgr, width, height, stride, out output);
  1429.                 default:
  1430.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1431.             }
  1432.         }
  1433.  
  1434.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeLosslessBGR")]
  1435.         private static extern int WebPEncodeLosslessBGR_x86([In()] IntPtr bgr, int width, int height, int stride, out IntPtr output);
  1436.  
  1437.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeLosslessBGR")]
  1438.         private static extern int WebPEncodeLosslessBGR_x64([In()] IntPtr bgr, int width, int height, int stride, out IntPtr output);
  1439.  
  1440.         /// <summary>Lossless encoding images pointed to by *data in WebP format.</summary>
  1441.         /// <param name="bgra">Pointer to BGRA image data.</param>
  1442.         /// <param name="width">The range is limited currently from 1 to 16383.</param>
  1443.         /// <param name="height">The range is limited currently from 1 to 16383.</param>
  1444.         /// <param name="stride">Specifies the distance between scan lines.</param>
  1445.         /// <param name="output">Output_buffer with WebP image.</param>
  1446.         /// <returns>Size of WebP Image or 0 if an error occurred.</returns>
  1447.         internal static int WebPEncodeLosslessBGRA(IntPtr bgra, int width, int height, int stride, out IntPtr output) {
  1448.             switch (IntPtr.Size) {
  1449.                 case 4:
  1450.                     return WebPEncodeLosslessBGRA_x86(bgra, width, height, stride, out output);
  1451.                 case 8:
  1452.                     return WebPEncodeLosslessBGRA_x64(bgra, width, height, stride, out output);
  1453.                 default:
  1454.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1455.             }
  1456.         }
  1457.  
  1458.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeLosslessBGRA")]
  1459.         private static extern int WebPEncodeLosslessBGRA_x86([In()] IntPtr bgra, int width, int height, int stride, out IntPtr output);
  1460.  
  1461.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPEncodeLosslessBGRA")]
  1462.         private static extern int WebPEncodeLosslessBGRA_x64([In()] IntPtr bgra, int width, int height, int stride, out IntPtr output);
  1463.  
  1464.         /// <summary>Releases memory returned by the WebPEncode.</summary>
  1465.         /// <param name="p">Pointer to memory.</param>
  1466.         internal static void WebPFree(IntPtr p) {
  1467.             switch (IntPtr.Size) {
  1468.                 case 4:
  1469.                     WebPFree_x86(p);
  1470.                     break;
  1471.                 case 8:
  1472.                     WebPFree_x64(p);
  1473.                     break;
  1474.                 default:
  1475.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1476.             }
  1477.         }
  1478.  
  1479.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")]
  1480.         private static extern void WebPFree_x86(IntPtr p);
  1481.  
  1482.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPFree")]
  1483.         private static extern void WebPFree_x64(IntPtr p);
  1484.  
  1485.         /// <summary>Get the WebP version library.</summary>
  1486.         /// <returns>8bits for each of major/minor/revision packet in integer. E.g: v2.5.7 is 0x020507.
  1487.         /// </returns>
  1488.         internal static int WebPGetDecoderVersion() {
  1489.             switch (IntPtr.Size) {
  1490.                 case 4:
  1491.                     return WebPGetDecoderVersion_x86();
  1492.                 case 8:
  1493.                     return WebPGetDecoderVersion_x64();
  1494.                 default:
  1495.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1496.             }
  1497.         }
  1498.  
  1499.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetDecoderVersion")]
  1500.         private static extern int WebPGetDecoderVersion_x86();
  1501.  
  1502.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPGetDecoderVersion")]
  1503.         private static extern int WebPGetDecoderVersion_x64();
  1504.  
  1505.         /// <summary>Compute PSNR, SSIM or LSIM distortion metric between two pictures.</summary>
  1506.         /// <param name="srcPicture">Picture to measure.</param>
  1507.         /// <param name="refPicture">Reference picture.</param>
  1508.         /// <param name="metric_type">0 = PSNR, 1 = SSIM, 2 = LSIM.</param>
  1509.         /// <param name="pResult">dB in the Y/U/V/Alpha/All order.</param>
  1510.         /// <returns>False in case of error (the two pictures don't have same dimension, ...).
  1511.         /// </returns>
  1512.         internal static int WebPPictureDistortion(ref WebPPicture srcPicture, ref WebPPicture refPicture, int metric_type, IntPtr pResult) {
  1513.             switch (IntPtr.Size) {
  1514.                 case 4:
  1515.                     return WebPPictureDistortion_x86(ref srcPicture, ref refPicture, metric_type, pResult);
  1516.                 case 8:
  1517.                     return WebPPictureDistortion_x64(ref srcPicture, ref refPicture, metric_type, pResult);
  1518.                 default:
  1519.                     throw new InvalidOperationException("Invalid platform. Cannot find proper function.");
  1520.             }
  1521.         }
  1522.  
  1523.         [DllImport("libwebp_x86.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureDistortion")]
  1524.         private static extern int WebPPictureDistortion_x86(ref WebPPicture srcPicture, ref WebPPicture refPicture, int metric_type, IntPtr pResult);
  1525.  
  1526.         [DllImport("libwebp_x64.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPPictureDistortion")]
  1527.         private static extern int WebPPictureDistortion_x64(ref WebPPicture srcPicture, ref WebPPicture refPicture, int metric_type, IntPtr pResult);
  1528.     }
  1529.  
  1530.     #endregion
  1531.  
  1532.  
  1533.     #region Predefined
  1534.  
  1535.     /// <summary>
  1536.     /// Enumerate some predefined settings for WebPConfig, depending on the type of source picture.
  1537.     /// These presets are used when calling WebPConfigPreset().
  1538.     /// </summary>
  1539.     internal enum WebPPreset {
  1540.         /// <summary>Default preset.</summary>
  1541.         WEBP_PRESET_DEFAULT = 0,
  1542.         /// <summary>Digital picture, like portrait, inner shot.</summary>
  1543.         WEBP_PRESET_PICTURE,
  1544.         /// <summary>Outdoor photograph, with natural lighting.</summary>
  1545.         WEBP_PRESET_PHOTO,
  1546.         /// <summary>Hand or line drawing, with high-contrast details.</summary>
  1547.         WEBP_PRESET_DRAWING,
  1548.         /// <summary>Small-sized colorful images.</summary>
  1549.         WEBP_PRESET_ICON,
  1550.         /// <summary>Text-like.</summary>
  1551.         WEBP_PRESET_TEXT
  1552.     }
  1553.  
  1554.     /// <summary>Encoding error conditions.</summary>
  1555.     internal enum WebPEncodingError {
  1556.         /// <summary>No error.</summary>
  1557.         VP8_ENC_OK = 0,
  1558.         /// <summary>Memory error allocating objects.</summary>
  1559.         VP8_ENC_ERROR_OUT_OF_MEMORY,
  1560.         /// <summary>Memory error while flushing bits.</summary>
  1561.         VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY,
  1562.         /// <summary>A pointer parameter is NULL.</summary>
  1563.         VP8_ENC_ERROR_NULL_PARAMETER,
  1564.         /// <summary>Configuration is invalid.</summary>
  1565.         VP8_ENC_ERROR_INVALID_CONFIGURATION,
  1566.         /// <summary>Picture has invalid width/height.</summary>
  1567.         VP8_ENC_ERROR_BAD_DIMENSION,
  1568.         /// <summary>Partition is bigger than 512k.</summary>
  1569.         VP8_ENC_ERROR_PARTITION0_OVERFLOW,
  1570.         /// <summary>Partition is bigger than 16M.</summary>
  1571.         VP8_ENC_ERROR_PARTITION_OVERFLOW,
  1572.         /// <summary>Error while flushing bytes.</summary>
  1573.         VP8_ENC_ERROR_BAD_WRITE,
  1574.         /// <summary>File is bigger than 4G.</summary>
  1575.         VP8_ENC_ERROR_FILE_TOO_BIG,
  1576.         /// <summary>Abort request by user.</summary>
  1577.         VP8_ENC_ERROR_USER_ABORT,
  1578.         /// <summary>List terminator. Always last.</summary>
  1579.         VP8_ENC_ERROR_LAST,
  1580.     }
  1581.  
  1582.     /// <summary>Enumeration of the status codes.</summary>
  1583.     internal enum VP8StatusCode {
  1584.         /// <summary>No error.</summary>
  1585.         VP8_STATUS_OK = 0,
  1586.         /// <summary>Memory error allocating objects.</summary>
  1587.         VP8_STATUS_OUT_OF_MEMORY,
  1588.         /// <summary>Configuration is invalid.</summary>
  1589.         VP8_STATUS_INVALID_PARAM,
  1590.         VP8_STATUS_BITSTREAM_ERROR,
  1591.         /// <summary>Configuration is invalid.</summary>
  1592.         VP8_STATUS_UNSUPPORTED_FEATURE,
  1593.         VP8_STATUS_SUSPENDED,
  1594.         /// <summary>Abort request by user.</summary>
  1595.         VP8_STATUS_USER_ABORT,
  1596.         VP8_STATUS_NOT_ENOUGH_DATA,
  1597.     }
  1598.  
  1599.     /// <summary>Image characteristics hint for the underlying encoder.</summary>
  1600.     internal enum WebPImageHint {
  1601.         /// <summary>Default preset.</summary>
  1602.         WEBP_HINT_DEFAULT = 0,
  1603.         /// <summary>Digital picture, like portrait, inner shot.</summary>
  1604.         WEBP_HINT_PICTURE,
  1605.         /// <summary>Outdoor photograph, with natural lighting.</summary>
  1606.         WEBP_HINT_PHOTO,
  1607.         /// <summary>Discrete tone image (graph, map-tile etc).</summary>
  1608.         WEBP_HINT_GRAPH,
  1609.         /// <summary>List terminator. Always last.</summary>
  1610.         WEBP_HINT_LAST
  1611.     }
  1612.  
  1613.     /// <summary>Describes the byte-ordering of packed samples in memory.</summary>
  1614.     internal enum WEBP_CSP_MODE {
  1615.         /// <summary>Byte-order: R, G, B, R, G, B, ...</summary>
  1616.         MODE_RGB = 0,
  1617.         /// <summary>Byte-order: R, G, B, A, R, G, B, A, ...</summary>
  1618.         MODE_RGBA = 1,
  1619.         /// <summary>Byte-order: B, G, R, B, G, R, ...</summary>
  1620.         MODE_BGR = 2,
  1621.         /// <summary>Byte-order: B, G, R, A, B, G, R, A, ...</summary>
  1622.         MODE_BGRA = 3,
  1623.         /// <summary>Byte-order: A, R, G, B, A, R, G, B, ...</summary>
  1624.         MODE_ARGB = 4,
  1625.         /// <summary>Byte-order: RGB-565: [a4 a3 a2 a1 a0 r5 r4 r3], [r2 r1 r0 g4 g3 g2 g1 g0], ...
  1626.         /// WEBP_SWAP_16BITS_CSP is defined,
  1627.         /// Byte-order: RGB-565: [a4 a3 a2 a1 a0 b5 b4 b3], [b2 b1 b0 g4 g3 g2 g1 g0], ...</summary>
  1628.         MODE_RGBA_4444 = 5,
  1629.         /// <summary>Byte-order: RGB-565: [r4 r3 r2 r1 r0 g5 g4 g3], [g2 g1 g0 b4 b3 b2 b1 b0], ...
  1630.         /// WEBP_SWAP_16BITS_CSP is defined,
  1631.         /// Byte-order: [b3 b2 b1 b0 a3 a2 a1 a0], [r3 r2 r1 r0 g3 g2 g1 g0], ...</summary>
  1632.         MODE_RGB_565 = 6,
  1633.         /// <summary>RGB-premultiplied transparent modes (alpha value is preserved).</summary>
  1634.         MODE_rgbA = 7,
  1635.         /// <summary>RGB-premultiplied transparent modes (alpha value is preserved).</summary>
  1636.         MODE_bgrA = 8,
  1637.         /// <summary>RGB-premultiplied transparent modes (alpha value is preserved).</summary>
  1638.         MODE_Argb = 9,
  1639.         /// <summary>RGB-premultiplied transparent modes (alpha value is preserved).</summary>
  1640.         MODE_rgbA_4444 = 10,
  1641.         /// <summary>YUV 4:2:0.</summary>
  1642.         MODE_YUV = 11,
  1643.         /// <summary>YUV 4:2:0.</summary>
  1644.         MODE_YUVA = 12,
  1645.         /// <summary>MODE_LAST -> 13.</summary>
  1646.         MODE_LAST = 13,
  1647.     }
  1648.  
  1649.     /// <summary>
  1650.     /// Decoding states. State normally flows as:
  1651.     /// WEBP_HEADER->VP8_HEADER->VP8_PARTS0->VP8_DATA->DONE for a lossy image, and
  1652.     /// WEBP_HEADER->VP8L_HEADER->VP8L_DATA->DONE for a lossless image.
  1653.     /// If there is any error the decoder goes into state ERROR.
  1654.     /// </summary>
  1655.     internal enum DecState {
  1656.         STATE_WEBP_HEADER,  // All the data before that of the VP8/VP8L chunk.
  1657.         STATE_VP8_HEADER,   // The VP8 Frame header (within the VP8 chunk).
  1658.         STATE_VP8_PARTS0,
  1659.         STATE_VP8_DATA,
  1660.         STATE_VP8L_HEADER,
  1661.         STATE_VP8L_DATA,
  1662.         STATE_DONE,
  1663.         STATE_ERROR
  1664.     }
  1665.  
  1666.     #endregion
  1667.  
  1668.  
  1669.     #region libwebp structs
  1670.  
  1671.     /// <summary>Features gathered from the bit stream.</summary>
  1672.     [StructLayout(LayoutKind.Sequential)]
  1673.     internal struct WebPBitstreamFeatures {
  1674.         /// <summary>Width in pixels, as read from the bit stream.</summary>
  1675.         public int Width;
  1676.         /// <summary>Height in pixels, as read from the bit stream.</summary>
  1677.         public int Height;
  1678.         /// <summary>True if the bit stream contains an alpha channel.</summary>
  1679.         public int Has_alpha;
  1680.         /// <summary>True if the bit stream is an animation.</summary>
  1681.         public int Has_animation;
  1682.         /// <summary>0 = undefined (/mixed), 1 = lossy, 2 = lossless.</summary>
  1683.         public int Format;
  1684.         /// <summary>Padding for later use.</summary>
  1685.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5, ArraySubType = UnmanagedType.U4)]
  1686.         private readonly uint[] pad;
  1687.     }
  1688.  
  1689.     /// <summary>Compression parameters.</summary>
  1690.     [StructLayout(LayoutKind.Sequential)]
  1691.     internal struct WebPConfig {
  1692.         /// <summary>Lossless encoding (0 = lossy(default), 1 = lossless).</summary>
  1693.         public int lossless;
  1694.         /// <summary>Between 0 (smallest file) and 100 (biggest).</summary>
  1695.         public float quality;
  1696.         /// <summary>Quality / speed trade-off (0 = fast, 6 = slower-better).</summary>
  1697.         public int method;
  1698.         /// <summary>Hint for image type (lossless only for now).</summary>
  1699.         public WebPImageHint image_hint;
  1700.         /// <summary>If non-zero, set the desired target size in bytes. Takes precedence over the
  1701.         /// 'compression' parameter.</summary>
  1702.         public int target_size;
  1703.         /// <summary>If non-zero, specifies the minimal distortion to try to achieve. Takes precedence
  1704.         /// over target_size.</summary>
  1705.         public float target_PSNR;
  1706.         /// <summary>Maximum number of segments to use, in [1-4].</summary>
  1707.         public int segments;
  1708.         /// <summary>Spatial Noise Shaping. 0 = off, 100 = maximum.</summary>
  1709.         public int sns_strength;
  1710.         /// <summary>Range: [0 = off ... 100 = strongest].</summary>
  1711.         public int filter_strength;
  1712.         /// <summary>Range: [0 = off ... 7 = least sharp].</summary>
  1713.         public int filter_sharpness;
  1714.         /// <summary>Filtering type: 0 = simple, 1 = strong (only used if filter_strength > 0 or
  1715.         /// auto-filter > 0).</summary>
  1716.         public int filter_type;
  1717.         /// <summary>Auto adjust filter's strength [0 = off, 1 = on].</summary>
  1718.         public int autofilter;
  1719.         /// <summary>Algorithm for encoding the alpha plane (0 = none, 1 = compressed with WebP
  1720.         /// lossless). Default is 1.</summary>
  1721.         public int alpha_compression;
  1722.         /// <summary>Predictive filtering method for alpha plane. 0 = none, 1 = fast, 2 = best. Default
  1723.         /// if 1.</summary>
  1724.         public int alpha_filtering;
  1725.         /// <summary>Between 0 (smallest size) and 100 (lossless). Default is 100.</summary>
  1726.         public int alpha_quality;
  1727.         /// <summary>Number of entropy-analysis passes (in [1-10]).</summary>
  1728.         public int pass;
  1729.         /// <summary>If true, export the compressed picture back. In-loop filtering is not applied.
  1730.         /// </summary>
  1731.         public int show_compressed;
  1732.         /// <summary>Preprocessing filter (0 = none, 1 = segment-smooth, 2 = pseudo-random dithering).
  1733.         /// </summary>
  1734.         public int preprocessing;
  1735.         /// <summary>Log2(number of token partitions) in [0-3] Default is set to 0 for easier
  1736.         /// progressive decoding.</summary>
  1737.         public int partitions;
  1738.         /// <summary>Quality degradation allowed to fit the 512k limit on prediction modes coding
  1739.         /// (0: no degradation, 100: maximum possible degradation).</summary>
  1740.         public int partition_limit;
  1741.         /// <summary>If true, compression parameters will be remapped to better match the expected
  1742.         /// output size from JPEG compression. Generally, the output size will be similar but the
  1743.         /// degradation will be lower.</summary>
  1744.         public int emulate_jpeg_size;
  1745.         /// <summary>If non-zero, try and use multi-threaded encoding.</summary>
  1746.         public int thread_level;
  1747.         /// <summary>If set, reduce memory usage (but increase CPU use).</summary>
  1748.         public int low_memory;
  1749.         /// <summary>Near lossless encoding [0 = max loss ... 100 = off (default)].</summary>
  1750.         public int near_lossless;
  1751.         /// <summary>If non-zero, preserve the exact RGB values under transparent area. Otherwise,
  1752.         /// discard this invisible RGB information for better compression. The default value is 0.
  1753.         /// </summary>
  1754.         public int exact;
  1755.         /// <summary>Reserved for future lossless feature.</summary>
  1756.         public int delta_palettization;
  1757.         /// <summary>If needed, use sharp (and slow) RGB->YUV conversion.</summary>
  1758.         public int use_sharp_yuv;
  1759.         /// <summary>Padding for later use.</summary>
  1760.         private readonly int pad1;
  1761.         private readonly int pad2;
  1762.     }
  1763.  
  1764.     /// <summary>Main exchange structure (input samples, output bytes, statistics).</summary>
  1765.     [StructLayout(LayoutKind.Sequential)]
  1766.     internal struct WebPPicture {
  1767.         /// <summary>Main flag for encoder selecting between ARGB or YUV input. Recommended to use ARGB
  1768.         /// input (*argb, argb_stride) for lossless, and YUV input (*y, *u, *v, etc.) for lossy.
  1769.         /// </summary>
  1770.         public int use_argb;
  1771.         /// <summary>Color-space: should be YUV420 for now (= Y'CbCr). Value = 0.</summary>
  1772.         public uint colorspace;
  1773.         /// <summary>Width of picture (less or equal to WEBP_MAX_DIMENSION).</summary>
  1774.         public int width;
  1775.         /// <summary>Height of picture (less or equal to WEBP_MAX_DIMENSION).</summary>
  1776.         public int height;
  1777.         /// <summary>Pointer to luma plane.</summary>
  1778.         public IntPtr y;
  1779.         /// <summary>Pointer to chroma U plane.</summary>
  1780.         public IntPtr u;
  1781.         /// <summary>Pointer to chroma V plane.</summary>
  1782.         public IntPtr v;
  1783.         /// <summary>Luma stride.</summary>
  1784.         public int y_stride;
  1785.         /// <summary>Chroma stride.</summary>
  1786.         public int uv_stride;
  1787.         /// <summary>Pointer to the alpha plane.</summary>
  1788.         public IntPtr a;
  1789.         /// <summary>stride of the alpha plane.</summary>
  1790.         public int a_stride;
  1791.         /// <summary>Padding for later use.</summary>
  1792.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.U4)]
  1793.         private readonly uint[] pad1;
  1794.         /// <summary>Pointer to ARGB (32 bit) plane.</summary>
  1795.         public IntPtr argb;
  1796.         /// <summary>This is stride in pixels units, not bytes.</summary>
  1797.         public int argb_stride;
  1798.         /// <summary>Padding for later use.</summary>
  1799.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U4)]
  1800.         private readonly uint[] pad2;
  1801.         /// <summary>Byte-emission hook, to store compressed bytes as they are ready.</summary>
  1802.         public IntPtr writer;
  1803.         /// <summary>Can be used by the writer.</summary>
  1804.         public IntPtr custom_ptr;
  1805.  
  1806.         // Map for extra information (only for lossy compression mode)
  1807.  
  1808.         /// <summary>1: intra type, 2: segment, 3: quant, 4: intra-16 prediction mode, 5: chroma
  1809.         /// prediction mode, 6: bit cost, 7: distortion.</summary>
  1810.         public int extra_info_type;
  1811.         /// <summary>If not NULL, points to an array of size ((width + 15) / 16) * ((height + 15) / 16)
  1812.         /// that will be filled with a macroblock map, depending on extra_info_type.</summary>
  1813.         public IntPtr extra_info;
  1814.         /// <summary>Pointer to side statistics (updated only if not NULL).</summary>
  1815.         public IntPtr stats;
  1816.         /// <summary>Error code for the latest error encountered during encoding.</summary>
  1817.         public uint error_code;
  1818.         /// <summary>If not NULL, report progress during encoding.</summary>
  1819.         public IntPtr progress_hook;
  1820.         /// <summary>This field is free to be set to any value and used during callbacks (like
  1821.         /// progress-report e.g.).</summary>
  1822.         public IntPtr user_data;
  1823.         /// <summary>Padding for later use.</summary>
  1824.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13, ArraySubType = UnmanagedType.U4)]
  1825.         private readonly uint[] pad3;
  1826.         /// <summary>Row chunk of memory for YUVA planes.</summary>
  1827.         private readonly IntPtr memory_;
  1828.         /// <summary>Row chunk of memory for ARGB planes.</summary>
  1829.         private readonly IntPtr memory_argb_;
  1830.         /// <summary>Padding for later use.</summary>
  1831.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.U4)]
  1832.         private readonly uint[] pad4;
  1833.     }
  1834.  
  1835.     /// <summary>Structure for storing auxiliary statistics (mostly for lossy encoding).</summary>
  1836.     [StructLayout(LayoutKind.Sequential)]
  1837.     internal struct WebPAuxStats {
  1838.         /// <summary>Final size.</summary>
  1839.         public int coded_size;
  1840.         /// <summary>Peak-signal-to-noise ratio for Y.</summary>
  1841.         public float PSNRY;
  1842.         /// <summary>Peak-signal-to-noise ratio for U.</summary>
  1843.         public float PSNRU;
  1844.         /// <summary>Peak-signal-to-noise ratio for V.</summary>
  1845.         public float PSNRV;
  1846.         /// <summary>Peak-signal-to-noise ratio for All.</summary>
  1847.         public float PSNRALL;
  1848.         /// <summary>Peak-signal-to-noise ratio for Alpha.</summary>
  1849.         public float PSNRAlpha;
  1850.         /// <summary>Number of intra4.</summary>
  1851.         public int block_count_intra4;
  1852.         /// <summary>Number of intra16.</summary>
  1853.         public int block_count_intra16;
  1854.         /// <summary>Number of skipped macro-blocks.</summary>
  1855.         public int block_count_skipped;
  1856.         /// <summary>Approximate number of bytes spent for header.</summary>
  1857.         public int header_bytes;
  1858.         /// <summary>Approximate number of bytes spent for  mode-partition #0</summary>
  1859.         public int mode_partition_0;
  1860.         /// <summary>Approximate number of bytes spent for DC coefficients for segment 0.</summary>
  1861.         public int residual_bytes_DC_segments0;
  1862.         /// <summary>Approximate number of bytes spent for AC coefficients for segment 0.</summary>
  1863.         public int residual_bytes_AC_segments0;
  1864.         /// <summary>Approximate number of bytes spent for UV coefficients for segment 0</summary>
  1865.         public int residual_bytes_uv_segments0;
  1866.         /// <summary>Approximate number of bytes spent for DC coefficients for segment 1.</summary>
  1867.         public int residual_bytes_DC_segments1;
  1868.         /// <summary>Approximate number of bytes spent for AC coefficients for segment 1.</summary>
  1869.         public int residual_bytes_AC_segments1;
  1870.         /// <summary>Approximate number of bytes spent for UV coefficients for segment 1</summary>
  1871.         public int residual_bytes_uv_segments1;
  1872.         /// <summary>Approximate number of bytes spent for DC coefficients for segment 2.</summary>
  1873.         public int residual_bytes_DC_segments2;
  1874.         /// <summary>Approximate number of bytes spent for AC coefficients for segment 2.</summary>
  1875.         public int residual_bytes_AC_segments2;
  1876.         /// <summary>Approximate number of bytes spent for UV coefficients for segment 2</summary>
  1877.         public int residual_bytes_uv_segments2;
  1878.         /// <summary>Approximate number of bytes spent for DC coefficients for segment 3.</summary>
  1879.         public int residual_bytes_DC_segments3;
  1880.         /// <summary>Approximate number of bytes spent for AC coefficients for segment 3.</summary>
  1881.         public int residual_bytes_AC_segments3;
  1882.         /// <summary>Approximate number of bytes spent for UV coefficients for segment 3.</summary>
  1883.         public int residual_bytes_uv_segments3;
  1884.         /// <summary>Number of macro-blocks in segments 0.</summary>
  1885.         public int segment_size_segments0;
  1886.         /// <summary>Number of macro-blocks in segments 1.</summary>
  1887.         public int segment_size_segments1;
  1888.         /// <summary>Number of macro-blocks in segments 2.</summary>
  1889.         public int segment_size_segments2;
  1890.         /// <summary>Number of macro-blocks in segments 3.</summary>
  1891.         public int segment_size_segments3;
  1892.         /// <summary>Quantizer values for segment 0.</summary>
  1893.         public int segment_quant_segments0;
  1894.         /// <summary>Quantizer values for segment 1.</summary>
  1895.         public int segment_quant_segments1;
  1896.         /// <summary>Quantizer values for segment 2.</summary>
  1897.         public int segment_quant_segments2;
  1898.         /// <summary>Quantizer values for segment 3.</summary>
  1899.         public int segment_quant_segments3;
  1900.         /// <summary>Filtering strength for segment 0 [0-63].</summary>
  1901.         public int segment_level_segments0;
  1902.         /// <summary>Filtering strength for segment 1 [0-63].</summary>
  1903.         public int segment_level_segments1;
  1904.         /// <summary>Filtering strength for segment 2 [0-63].</summary>
  1905.         public int segment_level_segments2;
  1906.         /// <summary>Filtering strength for segment 3 [0-63].</summary>
  1907.         public int segment_level_segments3;
  1908.         /// <summary>Size of the transparency data.</summary>
  1909.         public int alpha_data_size;
  1910.         /// <summary>Size of the enhancement layer data.</summary>
  1911.         public int layer_data_size;
  1912.  
  1913.         // Lossless encoder statistics
  1914.  
  1915.         /// <summary>bit0:predictor bit1:cross-color transform bit2:subtract-green bit3:color indexing.
  1916.         /// </summary>
  1917.         public int lossless_features;
  1918.         /// <summary>Number of precision bits of histogram.</summary>
  1919.         public int histogram_bits;
  1920.         /// <summary>Precision bits for transform.</summary>
  1921.         public int transform_bits;
  1922.         /// <summary>Number of bits for color cache lookup.</summary>
  1923.         public int cache_bits;
  1924.         /// <summary>Number of color in palette, if used.</summary>
  1925.         public int palette_size;
  1926.         /// <summary>Final lossless size</summary>
  1927.         public int lossless_size;
  1928.         /// <summary>Lossless header (transform, Huffman, etc) size.</summary>
  1929.         public int lossless_hdr_size;
  1930.         /// <summary>Lossless image data size.</summary>
  1931.         public int lossless_data_size;
  1932.         /// <summary>Padding for later use.</summary>
  1933.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.U4)]
  1934.         private readonly uint[] pad;
  1935.     }
  1936.  
  1937.     [StructLayout(LayoutKind.Sequential)]
  1938.     internal struct WebPDecoderConfig {
  1939.         /// <summary>Immutable bit stream features (optional).</summary>
  1940.         public WebPBitstreamFeatures input;
  1941.         /// <summary>Output buffer (can point to external memory).</summary>
  1942.         public WebPDecBuffer output;
  1943.         /// <summary>Decoding options.</summary>
  1944.         public WebPDecoderOptions options;
  1945.     }
  1946.  
  1947.     /// <summary>Output buffer.</summary>
  1948.     [StructLayout(LayoutKind.Sequential)]
  1949.     internal struct WebPDecBuffer {
  1950.         /// <summary>Color space.</summary>
  1951.         public WEBP_CSP_MODE colorspace;
  1952.         /// <summary>Width of image.</summary>
  1953.         public int width;
  1954.         /// <summary>Height of image.</summary>
  1955.         public int height;
  1956.         /// <summary>If non-zero, 'internal_memory' pointer is not used. If value is '2' or more, the
  1957.         /// external memory is considered 'slow' and multiple read/write will be avoided.</summary>
  1958.         public int is_external_memory;
  1959.         /// <summary>Output buffer parameters.</summary>
  1960.         public RGBA_YUVA_Buffer u;
  1961.         /// <summary>Padding for later use.</summary>
  1962.         private readonly uint pad1;
  1963.         /// <summary>Padding for later use.</summary>
  1964.         private readonly uint pad2;
  1965.         /// <summary>Padding for later use.</summary>
  1966.         private readonly uint pad3;
  1967.         /// <summary>Padding for later use.</summary>
  1968.         private readonly uint pad4;
  1969.         /// <summary>Internally allocated memory (only when is_external_memory is 0). Should not be
  1970.         /// used externally, but accessed via WebPRGBABuffer.</summary>
  1971.         public IntPtr private_memory;
  1972.     }
  1973.  
  1974.     /// <summary>Union of buffer parameters</summary>
  1975.     [StructLayout(LayoutKind.Explicit)]
  1976.     internal struct RGBA_YUVA_Buffer {
  1977.         [FieldOffset(0)]
  1978.         public WebPRGBABuffer RGBA;
  1979.  
  1980.         [FieldOffset(0)]
  1981.         public WebPYUVABuffer YUVA;
  1982.     }
  1983.  
  1984.     [StructLayout(LayoutKind.Sequential)]
  1985.     internal struct WebPYUVABuffer {
  1986.         /// <summary>Pointer to luma samples.</summary>
  1987.         public IntPtr y;
  1988.         /// <summary>Pointer to chroma U samples.</summary>
  1989.         public IntPtr u;
  1990.         /// <summary>Pointer to chroma V samples.</summary>
  1991.         public IntPtr v;
  1992.         /// <summary>Pointer to alpha samples.</summary>
  1993.         public IntPtr a;
  1994.         /// <summary>Luma stride.</summary>
  1995.         public int y_stride;
  1996.         /// <summary>Chroma U stride.</summary>
  1997.         public int u_stride;
  1998.         /// <summary>Chroma V stride.</summary>
  1999.         public int v_stride;
  2000.         /// <summary>Alpha stride.</summary>
  2001.         public int a_stride;
  2002.         /// <summary>Luma plane size.</summary>
  2003.         public UIntPtr y_size;
  2004.         /// <summary>Chroma plane U size.</summary>
  2005.         public UIntPtr u_size;
  2006.         /// <summary>Chroma plane V size.</summary>
  2007.         public UIntPtr v_size;
  2008.         /// <summary>Alpha plane size.</summary>
  2009.         public UIntPtr a_size;
  2010.     }
  2011.  
  2012.     /// <summary>Generic structure for describing the output sample buffer.</summary>
  2013.     [StructLayout(LayoutKind.Sequential)]
  2014.     internal struct WebPRGBABuffer {
  2015.         /// <summary>Pointer to RGBA samples.</summary>
  2016.         public IntPtr rgba;
  2017.         /// <summary>Stride in bytes from one scanline to the next.</summary>
  2018.         public int stride;
  2019.         /// <summary>Total size of the RGBA buffer.</summary>
  2020.         public UIntPtr size;
  2021.     }
  2022.  
  2023.     /// <summary>Decoding options.</summary>
  2024.     [StructLayout(LayoutKind.Sequential)]
  2025.     public struct WebPDecoderOptions {
  2026.         /// <summary>If true, skip the in-loop filtering.</summary>
  2027.         public int bypass_filtering;
  2028.         /// <summary>If true, use faster point-wise up-sampler.</summary>
  2029.         public int no_fancy_upsampling;
  2030.         /// <summary>If true, cropping is applied _first_.</summary>
  2031.         public int use_cropping;
  2032.         /// <summary>Left position for cropping. Will be snapped to even values.</summary>
  2033.         public int crop_left;
  2034.         /// <summary>Top position for cropping. Will be snapped to even values.</summary>
  2035.         public int crop_top;
  2036.         /// <summary>Width of the cropping area.</summary>
  2037.         public int crop_width;
  2038.         /// <summary>Height of the cropping area.</summary>
  2039.         public int crop_height;
  2040.         /// <summary>If true, scaling is applied _afterward_.</summary>
  2041.         public int use_scaling;
  2042.         /// <summary>Final width.</summary>
  2043.         public int scaled_width;
  2044.         /// <summary>Final height.</summary>
  2045.         public int scaled_height;
  2046.         /// <summary>If true, use multi-threaded decoding.</summary>
  2047.         public int use_threads;
  2048.         /// <summary>Dithering strength (0 = Off, 100 = full).</summary>
  2049.         public int dithering_strength;
  2050.         /// <summary>Flip output vertically.</summary>
  2051.         public int flip;
  2052.         /// <summary>Alpha dithering strength in [0-100].</summary>
  2053.         public int alpha_dithering_strength;
  2054.         /// <summary>Padding for later use.</summary>
  2055.         private readonly uint pad1;
  2056.         /// <summary>Padding for later use.</summary>
  2057.         private readonly uint pad2;
  2058.         /// <summary>Padding for later use.</summary>
  2059.         private readonly uint pad3;
  2060.         /// <summary>Padding for later use.</summary>
  2061.         private readonly uint pad4;
  2062.         /// <summary>Padding for later use.</summary>
  2063.         private readonly uint pad5;
  2064.     }
  2065.  
  2066.     #endregion
  2067. }
  2068.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement