private void GetWebpInfo(IntPtr ptrRawWebP, int webpDataSize, out int width, out int height, out bool has_alpha, out bool has_animation, out string format) { VP8StatusCode result; WebPBitstreamFeatures features = new WebPBitstreamFeatures(); result = WebPWrapper.WebPGetFeatures(ptrRawWebP, webpDataSize, ref features); if (result == 0) { width = features.Width; height = features.Height; has_alpha = (features.Has_alpha == 1); has_animation = (features.Has_animation == 1); switch (features.Format) { case 1: format = "lossy"; break; case 2: format = "lossless"; break; default: format = "undefined"; break; } } else { throw new Exception(result.ToString()); } }
private void decodeWebP(MemoryStream stream) { Bitmap bmp = null; Bitmap firstbmp = null; bool firstbitmap = true; BitmapData bmpData = null; IntPtr dec = (IntPtr)0; const int UintBytes = 4; byte [] rawWebP = stream.ToArray(); UIntPtr dataSize = (UIntPtr)rawWebP.Length; GCHandle pinnedWebP = GCHandle.Alloc(rawWebP, GCHandleType.Pinned); IntPtr ptrData = pinnedWebP.AddrOfPinnedObject(); try { //Get info about webp image GetWebpInfo(ptrData, rawWebP.Length, out int imgWidth, out int imgHeight, out bool hasAlpha, out bool hasAnimation, out string format); if (hasAnimation) { //demux the image WebPData webpdata = new WebPData() { bytes = ptrData, size = dataSize }; WebPAnimDecoderOptions dec_options = new WebPAnimDecoderOptions(); //init decoder options with default values WebPWrapper.WebPAnimDecoderOptionsInit(ref dec_options); //set color mode to blue green red alpha to match up with how the bitmap is formatted dec_options.color_mode = WEBP_CSP_MODE.MODE_BGRA; //create the decoder dec = WebPWrapper.WebPAnimDecoderNew(ref webpdata, ref dec_options); IntPtr buf; int timestamp; uint outputSize; WebPAnimInfo animinfo = new WebPAnimInfo(); //get animation info WebPWrapper.WebPAnimDecoderGetInfo(dec, ref animinfo); imgWidth = (int)animinfo.canvas_width; imgHeight = (int)animinfo.canvas_height; int prevtimestamp = 0; bool first = true; while (WebPWrapper.WebPAnimDecoderHasMoreFrames(dec) == 1) { //get next frame WebPWrapper.WebPAnimDecoderGetNext(dec, out buf, out timestamp); //copy frame into an Image (Bitmap) bmp = new Bitmap(imgWidth, imgHeight, PixelFormat.Format32bppArgb); bmpData = bmp.LockBits(new Rectangle(0, 0, imgWidth, imgHeight), ImageLockMode.WriteOnly, bmp.PixelFormat); outputSize = (uint)(bmpData.Stride * imgHeight); WebPWrapper.CopyMemory(bmpData.Scan0, buf, outputSize); bmp.UnlockBits(bmpData); //Add frame to the list AddFrame(bmp, (timestamp - prevtimestamp) / 10); prevtimestamp = timestamp; bmpData = null; if (first) { ActiveImage = bmp; Height = imgHeight; Width = imgWidth; first = false; } } WebPWrapper.WebPAnimDecoderReset(dec); WebPWrapper.WebPAnimDecoderDelete(dec); dec = (IntPtr)0; IsAnimated = true; } else { //Create a Bitmap 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; if (bmp.PixelFormat == PixelFormat.Format24bppRgb) { WebPWrapper.WebPDecodeBGRInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride); } else { WebPWrapper.WebPDecodeBGRAInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride); } ActiveImage = bmp; Height = imgHeight; Width = imgWidth; } } catch (Exception e) { GuiEngine.Current.log(e.ToString()); } finally { //Unlock the pixels if (bmpData != null) { bmp.UnlockBits(bmpData); } if (dec != (IntPtr)0) { WebPWrapper.WebPAnimDecoderDelete(dec); } //Free memory if (pinnedWebP.IsAllocated) { pinnedWebP.Free(); } } }