C/C++实现显示GIF动态图片
2017-10-17 14:49
786 查看
语言:C/C++ 编程软件:VS2015 字符集:UNICODE编码 说明:这里不使用MFC的任何类,全部为API
【1】实现步骤如下:
一、首先,去找一个GIF动态图片.
如:显示正在加载中(http://www.lanrentuku.com/gif/a/loading.html)
二、找一个在线GIF动态图片分解器(如:http://tool.chuanxincao.net/fenjie/)
分解GIF图片,bmp图片帧.
三、确保图片的格式是bmp格式的图片,如果你改个后缀(.bmp),但不是.bmp解析格式的,后面的函数加载将不成功.
使用画图软件对其他格式的图片转换成.bmp格式的图片.
四、实现代码如下:
//显示GIF动态图片 参数1:显示窗口,参数2:bmp图片帧所在的目录文件夹路径 BOOL ShowLoading(HWND hwnd,LPCTSTR path) { HBITMAP gif[12];//帧数,我这边只是12张bmp图片 TCHAR gifpath[MAX_PATH]; for (DWORD i = 0; i < 12; i++) {//加载图片文件 swprintf_s(gifpath, MAX_PATH, _T("%s\\%u.bmp"), path, i + 1); //如果不是.bmp格式(解析格式,不是换个后缀就行的)的图片,此函数加载将失败,而且GetLastError返回0,导致分析错误困难. gif[i] = (HBITMAP)::LoadImage(NULL, gifpath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_CREATEDIBSECTION); } //取一张图片的高宽信息 BITMAP obj; GetObject((HANDLE)gif[0], sizeof(BITMAP),&obj); //使用GDI画出来 HDC hdc = GetDC(hwnd); HDC hdcMem = ::CreateCompatibleDC(hdc); for (DWORD i = 0; TRUE;) { //每画一张图片,换一张,到尾部又回头部 if (i == 13) i = 0; ::SelectObject(hdcMem, gif[i]); //画出来 ::BitBlt(hdc, 50, 50, obj.bmWidth, obj.bmHeight, hdcMem, 0, 0, SRCCOPY); //动态图片的速度快慢,由Sleep控制. Sleep(40); i++; } return TRUE; }
【2】基于上面实现的基础,我写了一个类,方便调用:
类的头文件: //需包含Windows.h
/* 类:显示GIF类. 须知: 1)为了能够关闭显示又不要共享全局变量,要使用堆内存创建对象. 2)图片的名称必须为 1.bmp ~ *.bmp. 使用步骤: 1)堆内存来创建对象. 2)调用Initiative函数提供对象所需的参数(如:显示窗口等信息). 3)调用LoadBitmap函数加载GIF的位图帧. 4)调用Thread_Start函数使用显示GIF线程来跑. 5)主线程调用End函数结束显示 优点: 1)可以重复多次使用Thread_Start和End函数用显示GIF的线程,显示图片,无需重新加载图片文件 2)可以扩张或缩放显示GIF图片 */ class GIF { public: //初始化参数 void Initiative(HWND DisplayWindow, POINT point, DWORD BmpFrameCount, DWORD Width, DWORD Hight, DWORD DisplayWidth, DWORD DisplayHight, DWORD Speed = 40); //加载位图资源 BOOL LoadBitmap(LPCTSTR path); //开启显示线程 BOOL Thread_Start(); public: GIF(); ~GIF(); public: //结束显示GIF(这个函数给窗口线程使用) BOOL End(); //开始显示GIF图片 BOOL Start(); public: //释放位图资源 BOOL ReleaseBitmap(); //释放HDC BOOL ReleaseHdc(); public: //显示线程 static unsigned int _stdcall GIFThread(LPVOID data); HANDLE dwThread; //线程句柄 private: DWORD BmpCount; //图片总数 HBITMAP* gif; //图片资源 TCHAR gifpath[MAX_PATH];//图片目录 DWORD Width; //图片宽度 DWORD Hight; //图片高度 DWORD DisplayWidth; //显示宽度 DWORD DisplayHight; //显示高度 HDC Wndhdc; //窗口DC HDC Memdc; //存位图的内存DC DWORD Speed; //播放速度 HWND hwnd; //显示窗口 POINT point; //坐标 private: volatile ULONG Open; //显示开关 };
类的源文件:
/******************************************************** GIF动态图片类 *********************************************************/ GIF::GIF() { gif = NULL; Width = 0; Hight = 0; Wndhdc = NULL; Memdc = NULL; Open = FALSE; dwThread = NULL; DisplayWidth = 0; DisplayHight = 0; } //释放工作 GIF::~GIF() { //释放还存在的位图资源 ReleaseBitmap(); //释放线程计数 if (dwThread) { CloseHandle(dwThread); dwThread = NULL; } } //初始化参数 参数1:显示窗口 参数2:坐标 参数3:位图总数 参数4:图片宽度 参数5:图片高度 // 参数6:显示宽度 参数7:显示高度 参数8:播放速度(1000为1秒换一张图片) void GIF::Initiative(HWND DisplayWindow, POINT point, DWORD BmpFrameCount, DWORD Width,DWORD Hight,DWORD DisplayWidth,DWORD DisplayHight, DWORD Speed) { this->hwnd = DisplayWindow; this->point = point; this->BmpCount = BmpFrameCount; this->Width = Width; this->Hight = Hight; this->DisplayWidth = DisplayWidth; this->DisplayHight = DisplayHight; this->Speed = Speed; } //加载位图资源 BOOL GIF::LoadBitmap(LPCTSTR path) { gif = new HBITMAP[BmpCount]; if (gif == NULL) return FALSE; ZeroMemory(gif, sizeof(HBITMAP) * BmpCount); //加载图片 for (DWORD i = 0; i < BmpCount; i++) { swprintf_s(gifpath, MAX_PATH, _T("%s\\%u.bmp"), path, i + 1); gif[i] = (HBITMAP)::LoadImage(NULL, gifpath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_CREATEDIBSECTION); if (gif[i] == NULL) {//如果有一个没有加载成功,那么将全部释放 ReleaseBitmap(); return FALSE; } } //验证是否全部位图都是那个尺寸的 BITMAP obj; for (DWORD i = 0; i < BmpCount; i++) { GetObject((HANDLE)gif[i], sizeof(BITMAP), &obj); if (obj.bmWidth != this->Width || obj.bmHeight != this->Hight) {//图片大小不对,释放位图 ReleaseBitmap(); return FALSE; } } return TRUE; } //释放位图资源 BOOL GIF::ReleaseBitmap() { if (gif == NULL) return FALSE; //释放位图资源 for (DWORD i = 0; i < BmpCount; i++) { if (gif[i] != NULL) { if (!DeleteObject(gif[i])) return FALSE; gif[i] = NULL; } else { break; } } //释放堆内存 if (gif) { delete[]gif; gif = NULL; } return TRUE; } //开始 BOOL GIF::Start() { //使用GDI画出来 Wndhdc = GetDC(hwnd); if (Wndhdc == NULL) return FALSE; Memdc = CreateCompatibleDC(Wndhdc); if (Memdc == NULL) { ReleaseHdc(); return FALSE; } DWORD go = 0; DWORD Max = BmpCount + 1; //回0变量 //设置为开始显示 InterlockedExchange(&Open, TRUE); //设置拉伸或压缩的清晰度算法 SetStretchBltMode(Wndhdc, HALFTONE); while (TRUE) { //结束 if (!Open) break; //每画一张图片,换一张,到尾部又回头部 if (go == Max) go = 0; SelectObject(Memdc, gif[go]); //画出来 if (!StretchBlt(Wndhdc, point.x, point.y, DisplayWidth, DisplayHight, Memdc, 0, 0,Width,Hight ,SRCCOPY)) {//释放HDC和内存DC ReleaseHdc(); return FALSE; } //播放速度控制 Sleep(Speed); go++; } //清除窗口 InvalidateRect(hwnd, NULL, TRUE); //画完释放内存DC和HDC. if (!ReleaseHdc()) return FALSE; return TRUE; } /* 功能:结束 返回值:成功结束返回TRUE,如果暂未开启返回FALSE */ BOOL GIF::End() { //设置结束 ULONG Started = InterlockedExchange(&Open, FALSE); if (!Started) {//表示还未开始 return FALSE; } else {//成功设置,并等待10秒的GIF线程结束 DWORD Result = WaitForSingleObject(this->dwThread, 10000); switch (Result) { case WAIT_TIMEOUT: return FALSE; case WAIT_OBJECT_0: if (!GetExitCodeThread(this->dwThread, &Result)) return FALSE; if (CloseHandle(this->dwThread)) this->dwThread = NULL; if(Result == 0) break; else return FALSE; default: return FALSE; } return TRUE; } } //释放DC BOOL GIF::ReleaseHdc() { //释放窗口HDC if (Wndhdc) { ReleaseDC(hwnd, Wndhdc); Wndhdc = NULL; } //删除内存DC if (Memdc) { if (!DeleteDC(Memdc)) return FALSE; Memdc = NULL; } return TRUE; } //使用其他线程显示图片 BOOL GIF::Thread_Start() { dwThread = (HANDLE)_beginthreadex(NULL, 0, GIF::GIFThread, (LPVOID)this, 0, NULL); if (dwThread == NULL) return FALSE; return TRUE; } //显示GIF动态图片的线程 unsigned int _stdcall GIF::GIFThread(LPVOID Pgif) { GIF* pgif = (GIF*)Pgif; //对此对象进行Initiative函数初始化检查. if (pgif->hwnd == NULL|| pgif->BmpCount == 0 || pgif->Width == 0 || pgif->Hight == 0 || pgif->DisplayWidth == 0 || pgif->DisplayHight == 0 || pgif->Speed == 0 ) return -2; //如果成功显示,并调用了End关闭函数返回0,否则显示失败返回-1 if (pgif->Start()) return 0; else return -1; }
【3】调用例子:
//GIF图片帧的文件夹路径 #define LOADING_PATH _T("C:\\Users\\Aaron\\Desktop\\编程\\项目\\Gatherer\\res\\gif文件夹")
//显示坐标 POINT point; point.x = 50; point.y = 50; //创建对象 GIF* gif = new GIF; if (gif) { gif->Initiative(window.WndHwnd, point, 12,35,35,35,35, 40); if (!gif->LoadBitmap(LOADING_PATH)) delete gif; else if (gif->Thread_Start()) { Sleep(5000); if (gif->End()) MessageBox(window.WndHwnd, _T("结束显示GIF成功!"), _T("OK"), MB_OK); } } //清除对象 delete gif;
我使用的GIF素材:
bmp图片帧:
【效果】
相关文章推荐
- java实现gif动画效果(java显示动态图片)
- Java之简单的图片动态显示(实现类似GIF动画效果)
- C++ budilder 使用ImageOle.dll 实现richedit显示任意格式图片和连接 gif
- Label,PushButton,ToolButton 实现动态图片按钮,Label显示gif动画
- Java之简单的图片动态显示(实现类似GIF动画结果)
- java实现gif动画效果(java显示动态图片)
- 实现动态的GIF 图片显示到窗体中
- gif动态图片显示
- MFC实现静态和动态显示bmp图片
- jQuery动态改变图片显示大小(修改版)的实现思路及代码
- Android三步显示gif动态图片
- binbinyyang---Android实现显示GIF图片
- Android中动态显示gif图片
- android studio中使用android-gif-drawable开源项目实现gif图片的显示
- C++显示Gif图片(转)
- 【代码】PHP 生成GIF动画实现动态图片验证码
- binbinyang---Android实现显示GIF图片
- 用内核定时器实现动态显示图片
- Android 显示和控制gif动态图片的播放
- android开发 实现同时显示png/jpg 等bitmap图片还可以显示gif图片,有效防止OOM