win32 - 使用GDI+播放gif图片
今天做case的时候遇到一个这样的问题,故记录下来。
Codeproject有类似的案例,不过是使用的MFC模板编译的。 因为我们只需要win32程序,所以就....代码如下:
CodeProject: Play GIF using GDI+
另一个是使用双缓冲实现的,我没尝试:win32双缓冲实现gif图片的动态显示 (有兴趣的可以尝试一下)
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")
#define ID_TIMER 101 //Image* m_pImage; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS wndClass;
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken; // Initialize GDI+.
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = TEXT("GettingStarted"); RegisterClass(&wndClass); hWnd = CreateWindow(
TEXT("GettingStarted"), // window class name
TEXT("Getting Started"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} GdiplusShutdown(gdiplusToken);
return msg.wParam;
} // WinMain PropertyItem* m_pItem = 0;
UINT m_iCurrentFrame = 0;
UINT m_FrameCount = 0; LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
Image* m_pImage = new Image(L"Your_Gif.gif"); switch (message)
{
case WM_CREATE:
{
//First of all we should get the number of frame dimensions
//Images considered by GDI+ as:
//frames[animation_frame_index][how_many_animation];
UINT count = m_pImage->GetFrameDimensionsCount(); //Now we should get the identifiers for the frame dimensions
GUID* m_pDimensionIDs = new GUID[count];
m_pImage->GetFrameDimensionsList(m_pDimensionIDs, count); //For gif image , we only care about animation set#0
WCHAR strGuid[40];
StringFromGUID2(m_pDimensionIDs[0], strGuid, 40);
m_FrameCount = m_pImage->GetFrameCount(&m_pDimensionIDs[0]); //PropertyTagFrameDelay is a pre-defined identifier
//to present frame-delays by GDI+
UINT TotalBuffer = m_pImage->GetPropertyItemSize(PropertyTagFrameDelay);
m_pItem = (PropertyItem*)malloc(TotalBuffer);
m_pImage->GetPropertyItem(PropertyTagFrameDelay, TotalBuffer, m_pItem);
}
break;
case WM_TIMER: {
//Because there will be a new delay value
KillTimer(hWnd, ID_TIMER);
//Change Active frame
GUID Guid = FrameDimensionTime;
m_pImage->SelectActiveFrame(&Guid, m_iCurrentFrame);
//New timer
SetTimer(hWnd, ID_TIMER, ((UINT*)m_pItem[0].value)[m_iCurrentFrame] * 10, NULL);
//Again move to the next
m_iCurrentFrame = (++m_iCurrentFrame) % m_FrameCount;
InvalidateRect(hWnd, NULL, FALSE);
break;
}
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps); Graphics graphics(hdc); //Set Current Frame at #0
GUID Guid = FrameDimensionTime;
m_pImage->SelectActiveFrame(&Guid, m_iCurrentFrame); //Use Timer
//NOTE HERE: frame-delay values should be multiply by 10
SetTimer(hWnd, ID_TIMER, ((UINT*)m_pItem[0].value)[m_iCurrentFrame] * 10, (TIMERPROC)NULL); //Move to the next frame
++m_iCurrentFrame;
InvalidateRect(hWnd, NULL, FALSE); //Finally simply draw
graphics.DrawImage(m_pImage, 120, 120, 800, 600); EndPaint(hWnd, &ps);
break;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
} // WndProc
步骤: 创建一个win32的空项目, 然后把代码复制进去。
代码中你们唯一需要改的就是gif文件路径: Image* m_pImage = new Image(L"Your_Gif.gif"); =》这一行
也可以根据需
要改变显示图片的大小: graphics.DrawImage(m_pImage, 120, 120, 800, 600);
更新:
gif循环播放代码,
#include <memory>
#include <vector>
#include <algorithm>
#include <windows.h>
#include <objidl.h>
#include <GdiPlus.h>
#include <gdiplusimaging.h>
#include <tchar.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib") #define TIMER_ID 101 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
ULONG_PTR m_gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL); Image gif(_T("spinner.gif")); MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = NULL; // <= Do not provide a background brush.
wc.lpszClassName = L"anim_gif_player";
if (!RegisterClass(&wc))
return -1; if (!CreateWindow(wc.lpszClassName,
L"Animated GIF player",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 1080, 800, 0, 0, hInstance, &gif))
return -2; while (GetMessage(&msg, NULL, 0, 0) > 0)
DispatchMessage(&msg); return 0;
} std::vector<unsigned int> LoadGifFrameInfo(Image* image)
{
// I think animated gifs will always only have 1 frame dimension...
// the "dimension" being the frame count, but I could be wrong about this
int count = image->GetFrameDimensionsCount();
if (count != 1)
return std::vector<unsigned int>(); GUID guid;
if (image->GetFrameDimensionsList(&guid, 1) != 0)
return std::vector<unsigned int>();
int frame_count = image->GetFrameCount(&guid); auto sz = image->GetPropertyItemSize(PropertyTagFrameDelay);
if (sz == 0)
return std::vector<unsigned int>(); // copy the frame delay property into the buffer backing an std::vector
// of bytes and then get a pointer to its value, which will be an array of
// unsigned ints
std::vector<unsigned char> buffer(sz);
PropertyItem* property_item = reinterpret_cast<PropertyItem*>(&buffer[0]);
image->GetPropertyItem(PropertyTagFrameDelay, sz, property_item);
unsigned int* frame_delay_array = (unsigned int*)property_item[0].value; // copy the delay values into an std::vector while converting to milliseconds.
std::vector<unsigned int> frame_delays(frame_count);
std::transform(frame_delay_array, frame_delay_array + frame_count, frame_delays.begin(),
[](unsigned int n) {return n * 10; }
); return frame_delays;
} void GenerateFrame(Bitmap* bmp, Image* gif)
{
Graphics dest(bmp); SolidBrush white(Color::White);
dest.FillRectangle(&white, 0, 0, bmp->GetWidth(), bmp->GetHeight()); if (gif)
dest.DrawImage(gif, 0, 0);
} std::unique_ptr<Bitmap> CreateBackBuffer(HWND hWnd)
{
RECT r;
GetClientRect(hWnd, &r);
return std::make_unique<Bitmap>(r.right - r.left, r.bottom - r.top);
} LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static Image* animated_gif;
static std::unique_ptr<Bitmap> back_buffer;
static std::vector<unsigned int> frame_delays;
static int current_frame; switch (message) {
case WM_CREATE: {
animated_gif = reinterpret_cast<Image*>(
reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams
); if (!animated_gif || animated_gif->GetLastStatus() != 0) {
MessageBox(hWnd, _T("Unable to load animated gif"), _T("error"), MB_ICONERROR);
return 0;
} // Create a bitmap the size of the window's clent area
back_buffer = CreateBackBuffer(hWnd); // get the frame delays and thereby test that this is really an animated gif
frame_delays = LoadGifFrameInfo(animated_gif);
if (frame_delays.empty()) {
MessageBox(hWnd, _T("Invalid gif or not an animated gif"), _T("error"), MB_ICONERROR);
return 0;
} current_frame = 0;
animated_gif->SelectActiveFrame(&FrameDimensionTime, current_frame); GenerateFrame(back_buffer.get(), animated_gif); SetTimer(hWnd, TIMER_ID, frame_delays[0], nullptr);
InvalidateRect(hWnd, nullptr, FALSE);
}
break; case WM_TIMER: {
KillTimer(hWnd, TIMER_ID);
current_frame = (current_frame + 1) % frame_delays.size();
animated_gif->SelectActiveFrame(&FrameDimensionTime, current_frame);
GenerateFrame(back_buffer.get(), animated_gif);
SetTimer(hWnd, TIMER_ID, frame_delays[current_frame], nullptr);
InvalidateRect(hWnd, nullptr, FALSE);
} break; case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
Graphics g(hdc);
g.DrawImage(back_buffer.get(), 0, 0);
EndPaint(hWnd, &ps);
} break; case WM_SIZE: {
back_buffer = CreateBackBuffer(hWnd);
GenerateFrame(back_buffer.get(), animated_gif);
} break; case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
win32 - 使用GDI+播放gif图片的更多相关文章
- 最简单的视音频播放示例2:GDI播放YUV, RGB
前一篇文章对“Simplest Media Play”工程作了概括性介绍.后续几篇文章打算详细介绍每个子工程中的几种技术.在记录Direct3D,OpenGL这两种相对复杂的技术之前,打算先记录一种和 ...
- 【C++自绘控件】如何用GDI+来显示图片
在我们制作一个应用软件的时候往往需要在窗口或控件中添加背景图.而图片不仅有BMP格式的,还有JPEG.PNG.TIFF.GIF等其它的格式.那么如何用jpg格式的图片来当背景呢? 这里用到了GDI+, ...
- Android 播放gif图片
Android的原生控件并不支持播放GIF格式的图片.我们都知道,在Android中如果想要显示一张图片,可以借助ImageView控件来完成,但是如果将一张GIF图片设置到ImageView里,它只 ...
- 非常优秀的swiper插件————幻灯片播放、图片轮播
http://www.idangero.us/ http://www.swiper.com.cn/ Swiper中文网 2015-10-15 SuperSlide2: (这是个PC用的滚屏插件,看着不 ...
- GDI+用PNG图片做半透明异型窗口
{*******************************************************} { ...
- 53、Gif 控件GifView 的使用,播放gif图片
GifView 是一个为了解决android中现在没有直接显示gif的view,只能通过mediaplay来显示这个问题的项目,其用法和 ImageView一样,支持gif图片.可监视GIF是否加载成 ...
- win32用GDI+加载png图片作为背景图
#include <windows.h> #include <gdiplus.h> /* GDI+ startup token */ ULONG_PTR gdiplusStar ...
- GDI+中GIF图片的显示
某位网友曾经问过我GDI+中Gif图像显示的问题,一直没时间给你写,在此致歉.我把这篇文章送给他. 一.GIF格式介绍 1.概述 GIF(Graphics Interchange Format,图形交 ...
- GDI+ 支持的图片文件格式
您可以使用许多标准格式将位图储存在磁盘文件中.GDI+ 支持以下各种图片文件格式. o 位图 (BMP) 位图是 Windows 用来储存设备无关和与应用程序无关的图片的标准格式.文件头决定了指定的位 ...
- windows api(GDI)实现图片旋转
GDI实现图片旋转,博主在网上找了好多资料,都不太如意. 并且在尝试中发现,如果先用SetViewportOrgEx将HDC上的坐标原点移动到图片中心:再在HDC上的获取每个点,用三角函数进行变换,算 ...
随机推荐
- [转帖]Windows设置WiFi走外网,有线网卡走内网。
https://www.itblogcn.com/article/1844.html 文章目录 设置笔记本 WIFI 走外网,网线走内网: 1.查看路由表: 2.删除默认路由: 3.添加 WiFi ...
- [转帖]TiDB之修改root密码
https://www.modb.pro/db/337530 当忘记TiDB root 密码时,可以通过设置skip-grant-table参数来跳过密码验证,登录成功以后再修改root密码. 方法一 ...
- [转帖]理解 postgresql.conf 的work_mem 参数配置
https://developer.aliyun.com/article/401250 简介: 主要是通过具体的实验来理解 work_mem 今天我们着重来了解 postgresql.conf 中的 ...
- [转帖] 在Linux上查看活跃线程数与连接数
https://www.cnblogs.com/codelogs/p/17178675.html 原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,非公众号转载保留此声明. 简介# 现 ...
- [转帖]一次 Java 进程 OOM 的排查分析(glibc 篇)
https://juejin.cn/post/6854573220733911048 遇到了一个 glibc 导致的内存回收问题,查找原因和实验的的过程是比较有意思的,主要会涉及到下面这些: Linu ...
- [转帖]讨论在 Linux Control Groups 中运行 Java 应用程序的暂停问题原创
https://heapdump.cn/article/1930426 说明 本篇原文来自 LinkedIn 的 Zhenyun Zhuang,原文:Application Pauses When R ...
- 简单进行Springboot Beans归属模块单元的统计分析方法
简单进行Springboot Beans归属模块单元的统计分析方法 背景 基于Springboot的产品变的复杂之后 启动速度会越来越慢. 公司同事得出一个结论. beans 数量过多会导致启动速度逐 ...
- 程序员必备!10款实用便捷的Git可视化管理工具
前言 俗话说得好"工欲善其事,必先利其器",合理的选择和使用可视化的管理工具可以降低技术入门和使用的门槛.我们在团队开发中统一某个开发工具的使用能够大大降低沟通成本,提高协作沟通效 ...
- mysql系列基础篇01---通用的语法及分类
通用语法及分类 DDL: 数据定义语言,用来定义数据库对象(数据库.表.字段) DML: 数据操作语言,用来对数据库表中的数据进行增删改 DQL: 数据查询语言,用来查询数据库中表的记录 DCL: 数 ...
- 树状数组(区间修改&&区间查询)
#include<bits/stdc++.h> #define int long long using namespace std; int n,m,x,x1,y,z; int a[100 ...