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