动态图(三) 动态WebP解码与播放
动态图(三) 动态WebP解码与播放
- 概述
- 环境
- 搭建工程
- libwebp
- 解码
- 播放
- GitHub
概述
WebP是谷歌定义的,如顾名思义(web picture),就是专门优化用于web显示的图片,大概就这样。
定义:
友(you)情(qiang)链接:https://developers.google.com/speed/webp/
无(wu)情(qiang)链接:https://developers.google.cn/speed/webp?hl=zh-cn
GitHub Mirror: https://github.com/webmproject/libwebp
环境
解码:libwebp
显示:GDI+ + Win32
开发环境: VS2015
搭建工程
libwebp
- Clone libwebp
- 用vs新建一个lib工程,名为 libwebp.vcxproj,把llibwebp\src\目录整个拷到工程目录,加入src*.*到工程去
解码
解码目标是使用libwebp把所有webp帧解析成BGRA流,用来构建后续用来显示的GDI+ Bitmap,部分代码:
//WebP解码
#include "stdafx.h"
#include "WebPLoader.h"
#include "StringUtil.hpp"BOOL CWebPLoader::LoadImage(const wstring& strImg)
{//借用了 https://github.com/webmproject/libwebp/blob/master/examples/anim_util.hreturn ReadAnimatedImage(CStringUtil::ToStringA(strImg).c_str(), &image);
}Bitmap* CWebPLoader::GetFrameAt(UINT32 nIndex, UINT32& nDelayMS)
{if (nIndex >= image.num_frames)return m_pBmp;DecodedFrame* pFrame = &image.frames[nIndex];if (!pFrame->rgba)return m_pBmp;Bitmap* pBmp = m_pBmp ? m_pBmp : new Bitmap(image.canvas_width, image.canvas_height);BitmapData bmd;Rect rc(0, 0, image.canvas_width, image.canvas_height);pBmp->LockBits(&rc, ImageLockModeRead | ImageLockModeWrite, PixelFormat32bppARGB, &bmd);LPBYTE pDst = (LPBYTE)bmd.Scan0;LPBYTE pSrc = pFrame->rgba;int rowsize = rc.Width * 4;for (int h = 0; h < rc.Height; ++h){memcpy(pDst, pSrc, rowsize);pSrc += rowsize;pDst += bmd.Stride;}pBmp->UnlockBits(&bmd);m_nCurFrame = nIndex;m_pBmp = pBmp;nDelayMS = pFrame->duration;return pBmp;
}
借用 https://github.com/webmproject/libwebp/blob/master/examples/anim_util.*,并作相应修改,部分代码:
// Read animated WebP bitstream 'webp_data' into 'AnimatedImage' struct.
static int ReadAnimatedWebP(const char filename[],const WebPData* const webp_data,AnimatedImage* const image) {int ok = 0;int dump_ok = 1;uint32_t frame_index = 0;int prev_frame_timestamp = 0;WebPAnimDecoder* dec;WebPAnimInfo anim_info;memset(image, 0, sizeof(*image));////We need BGRA, so we can build gdi+ bitmap directly.WebPAnimDecoderOptions opt;memset(&opt, 0, sizeof(opt));opt.color_mode = MODE_BGRA;opt.use_threads = 0;dec = WebPAnimDecoderNew(webp_data, &opt);if (dec == NULL) {//WFPRINTF(stderr, "Error parsing image: %s\n", (const W_CHAR*)filename);goto End;}// Main object storing the configuration for advanced decodingWebPDecoderConfig decoder_config;// Initialize the configuration as empty// This function must always be called first, unless WebPGetFeatures() is to be calledif (!WebPInitDecoderConfig(&decoder_config)) {goto End;}// Retrieve features from the bitstream// The bitstream structure is filled with information gathered from the bitstreamint webp_status = WebPGetFeatures(webp_data->bytes, webp_data->size, &decoder_config.input);if (webp_status != VP8_STATUS_OK) {goto End;}if (!WebPAnimDecoderGetInfo(dec, &anim_info)) {fprintf(stderr, "Error getting global info about the animation\n");goto End;}// Animation properties.image->canvas_width = anim_info.canvas_width;image->canvas_height = anim_info.canvas_height;image->loop_count = anim_info.loop_count;image->bgcolor = anim_info.bgcolor;// Allocate frames.if (!AllocateFrames(image, anim_info.frame_count)) return 0;// Decode frames.while (WebPAnimDecoderHasMoreFrames(dec)) {DecodedFrame* curr_frame;uint8_t* curr_rgba;uint8_t* frame_rgba;int timestamp;if (!WebPAnimDecoderGetNext(dec, &frame_rgba, ×tamp)) {fprintf(stderr, "Error decoding frame #%u\n", frame_index);goto End;}assert(frame_index < anim_info.frame_count);curr_frame = &image->frames[frame_index];curr_rgba = curr_frame->rgba;curr_frame->duration = timestamp - prev_frame_timestamp;curr_frame->is_key_frame = 0; // Unused.memcpy(curr_rgba, frame_rgba,image->canvas_width * kNumChannels * image->canvas_height);++frame_index;prev_frame_timestamp = timestamp;}ok = dump_ok;if (ok) image->format = ANIM_WEBP;End:WebPAnimDecoderDelete(dec);return ok;
}
播放
使用标准Win32工程模板,加个定时器驱动,so easy,部分代码:
#include "stdafx.h"
#include "WebPDemo.h"
#include "GdiplusAutoStartup.hpp"
#include "WebPLoader.h"// 全局变量:
CWebPLoader g_webpLoader;
UINT32 g_nCurrentFrameID = 0;int APIENTRY wWinMain(_In_ HINSTANCE hInstance,_In_opt_ HINSTANCE hPrevInstance,_In_ LPWSTR lpCmdLine,_In_ int nCmdShow)
{UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);// 解码GDIPLUS_AUTO_STARTUP;WCHAR szPath[MAX_PATH + 1];GetModuleFileName(NULL, szPath, _countof(szPath));PathRemoveFileSpec(szPath);PathAppend(szPath, L"\\..\\..\\..\\test\\rainbow_cat.webp");if (!g_webpLoader.LoadImage(szPath)){MessageBoxA(NULL, "Error decoding file! Aborting.\n", "Error", MB_ICONERROR|MB_OK);return 1;}//return 0;
}//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){case WM_CREATE://first frameSetTimer(hWnd, 1234, 500, NULL);break;case WM_PAINT:{PAINTSTRUCT ps;HDC hdc = BeginPaint(hWnd, &ps);// 绘图代码RECT rcWin;GetClientRect(hWnd, &rcWin);Rect rcBg(0, 0, rcWin.right - rcWin.left, rcWin.bottom - rcWin.top);// 双缓冲HDC hMemDC = ::CreateCompatibleDC(hdc);HBITMAP hBmpOffscreen = ::CreateCompatibleBitmap(hdc, rcBg.Width, rcBg.Height);HBITMAP hBmpOld = (HBITMAP)::SelectObject(hMemDC, hBmpOffscreen);Graphics gr(hMemDC);gr.Clear(0xFFFFFFFFu);UINT32 nDelayMS = 0;Bitmap* pBmp = g_webpLoader.GetFrameAt(g_nCurrentFrameID, nDelayMS);if (pBmp){Rect rc(0, 0, rcWin.right - rcWin.left, rcWin.bottom - rcWin.top);rc.Offset((rc.Width - (INT)pBmp->GetWidth()) / 2, (rc.Height - (INT)pBmp->GetHeight()) / 2);rc.Width = pBmp->GetWidth();rc.Height = pBmp->GetHeight();gr.DrawImage(pBmp, rc);}BitBlt(hdc, 0, 0, rcBg.Width, rcBg.Height, hMemDC, 0, 0, SRCCOPY);::SelectObject(hMemDC, hBmpOld);DeleteObject(hBmpOffscreen);DeleteDC(hMemDC);EndPaint(hWnd, &ps);//next frameSetTimer(hWnd, 1234, nDelayMS, NULL);}break;case WM_DESTROY:PostQuitMessage(0);break;case WM_ERASEBKGND:return 1;case WM_TIMER:if (wParam == 1234){g_nCurrentFrameID++;g_nCurrentFrameID %= g_webpLoader.GetFrameCount();RECT rc;GetClientRect(hWnd, &rc);InvalidateRect(hWnd, &rc, TRUE);}break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}
GitHub
https://github.com/conn-public/vs-proj/tree/master/project/WebPDemo
动态图(三) 动态WebP解码与播放相关推荐
- python简单动态图_python动态图的绘制和保存
前言 这段时间要做一个涉及排队论的数学建模,需要动态绘图.建好了模,却没想到在原以为简单的绘图上耗费了我大量时间.原因在于用python作动态绘图的参考资料过于琐碎.因此在我费了九牛二虎之力终于实现动 ...
- 动态图GIF动态图怎么做?上传动态效果图到你的csdn?
动态图GIF动态图怎么做?上传动态效果图到你的csdn? 微信订阅号.CSND.博客等等很多地方都会用到GIF图,如何自己制作.这里直接提供工具. GIF工具下载:http://download.cs ...
- Excel绘制动态图三种方式
目录 一.项目背景 二.实现过程 一.项目背景 Excel是一款强大的数据分析统计工具,当数据量不太大或者需要快捷处理数据时, 我们经常要用到它,在面试时也会被经常问到一些函数功能和绘制图形等问题.本 ...
- php换脸,gif动态图换脸 动态图如何换脸 怎样更换gif动态图的人脸头像
在网上我们经常能看到一些非常滑稽的图片,比如说:图片中的人物是电影主角,但是脸却是其他人的,关键是换脸之后还非常的有意思,让人忍不住捧腹大笑.很多动态的恶搞图片也是这样,明明是个很正常的gif动态图片 ...
- 怎么制作gif动态图 QQ动态表情包怎么制作
在平时的聊天中经常会使用到GIF动图,不仅仅可以缓解气氛,还很有趣,那这些动态图是如何制作的呢?没有想象的那么难,今天来看看怎么制作的吧! 1.先准备好素材,要制作什么样的动图,可以是图片也可以是视频 ...
- python和java打架动态图_Python动态图实例与实践,PYTHON
今天(3.8)是个特殊节日哈,针对妇女朋友.众所周知,世界上最早的程序员是女性哦,刚好有GITHUB一个超火的动态图项目:barrace(https://gist.githubusercontent. ...
- css如何插入动态图,css动态图(作业)
loading动画 .box{ width: 300px; height: 135px; border: 2px solid #000; margin: 200px auto 0; } .box p{ ...
- php 股票动态图,股票动态图,看懂了秒变高手!
技术面炒股的方法有很多种,主要包括K线技术.均线技术.趋势线技术和MACD.KDJ等各种指标技术. 但话说回来,技术面炒股主要是用于做短线和波段操作,要长线投资必须结合基本面.政策面等其他因素才能显示 ...
- python动态图的绘制和保存
前言 这段时间要做一个涉及排队论的数学建模,需要动态绘图.建好了模,却没想到在原以为简单的绘图上耗费了我大量时间.原因在于用python作动态绘图的参考资料过于琐碎.因此在我费了九牛二虎之力终于实现动 ...
最新文章
- 关于AxWebBrowser关闭网页时的关闭提示
- 让浏览器非阻塞加载javascript的几种方式
- 1.计算机的组成(冯诺依曼体系)
- 网络推广外包——网络推广外包专员浅析网站流量应该如何提升?
- 华为 鸿蒙只是物联网,“鸿蒙”不只是手机系统,任正非:是为物联网所打造的系统...
- 基本数据类型与String之间的转换
- Spring框架----Confinguration和Component-Scan注解
- 2019.7.19刷题统计
- 主成分分析(PCA)算法实现iris数据集降维
- Windows快速更改IP脚本
- C#学习笔记之线程安全
- win10安装ePLAN P8 2.7无法通过驱动精灵更新MultiUSB Key驱动问题的解决办法
- 服务器空间对SEO的影响有多大
- TensorFlow - 正弦曲线
- 神舟微型计算机系统重装步骤,电脑重装系统步骤,最简单安全的操作!
- 2021中国工业软件上市企业公司排行2021中国智能制造企业排名
- 月薪不过万郑州程序员的真实生活
- 导航星历的钟差,TGD问题
- 关系型数据库是什么?
- 老板无偿征用你的朋友圈,你愿意吗?