今天做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图片的更多相关文章

  1. 最简单的视音频播放示例2:GDI播放YUV, RGB

    前一篇文章对“Simplest Media Play”工程作了概括性介绍.后续几篇文章打算详细介绍每个子工程中的几种技术.在记录Direct3D,OpenGL这两种相对复杂的技术之前,打算先记录一种和 ...

  2. 【C++自绘控件】如何用GDI+来显示图片

    在我们制作一个应用软件的时候往往需要在窗口或控件中添加背景图.而图片不仅有BMP格式的,还有JPEG.PNG.TIFF.GIF等其它的格式.那么如何用jpg格式的图片来当背景呢? 这里用到了GDI+, ...

  3. Android 播放gif图片

    Android的原生控件并不支持播放GIF格式的图片.我们都知道,在Android中如果想要显示一张图片,可以借助ImageView控件来完成,但是如果将一张GIF图片设置到ImageView里,它只 ...

  4. 非常优秀的swiper插件————幻灯片播放、图片轮播

    http://www.idangero.us/ http://www.swiper.com.cn/ Swiper中文网 2015-10-15 SuperSlide2: (这是个PC用的滚屏插件,看着不 ...

  5. GDI+用PNG图片做半透明异型窗口

    {*******************************************************} {                                          ...

  6. 53、Gif 控件GifView 的使用,播放gif图片

    GifView 是一个为了解决android中现在没有直接显示gif的view,只能通过mediaplay来显示这个问题的项目,其用法和 ImageView一样,支持gif图片.可监视GIF是否加载成 ...

  7. win32用GDI+加载png图片作为背景图

    #include <windows.h> #include <gdiplus.h> /* GDI+ startup token */ ULONG_PTR gdiplusStar ...

  8. GDI+中GIF图片的显示

    某位网友曾经问过我GDI+中Gif图像显示的问题,一直没时间给你写,在此致歉.我把这篇文章送给他. 一.GIF格式介绍 1.概述 GIF(Graphics Interchange Format,图形交 ...

  9. GDI+ 支持的图片文件格式

    您可以使用许多标准格式将位图储存在磁盘文件中.GDI+ 支持以下各种图片文件格式. o 位图 (BMP) 位图是 Windows 用来储存设备无关和与应用程序无关的图片的标准格式.文件头决定了指定的位 ...

  10. windows api(GDI)实现图片旋转

    GDI实现图片旋转,博主在网上找了好多资料,都不太如意. 并且在尝试中发现,如果先用SetViewportOrgEx将HDC上的坐标原点移动到图片中心:再在HDC上的获取每个点,用三角函数进行变换,算 ...

随机推荐

  1. [转帖]Linux系统下cpio命令详解

    简介 cpio主要是解压或者将文件压缩到指定文件中即copy-in和copy-out模式. 参数说明 参数 参数说明 -i copy-in模式,解压文件 -o copy-out模式,即压缩文件 -d ...

  2. [转帖]关于gdb相关的几个工具的说明

    https://phpor.net/blog/post/846 使用rpm命名查看gdb的rpm包,主要由下面几个程序:/usr/bin/gcore/usr/bin/gdb/usr/bin/gdbse ...

  3. [转帖]记录几个常用linux命令的使用方法——find、grep、file、which、whereis和压缩命令gzip、bzip2、tar

    一.命令1: find.grep.file.which.whereis 1.find 目的:查找符合条件的文件 1)在哪些目录中查找 2)查找的内容 格式: find 目录名 选项 查找条件 举例: ...

  4. [转帖]diskspd的使用

    https://www.cnblogs.com/tcicy/p/10005374.html 参数翻译 可测试目标: file_path 文件abc.file #<physical drive n ...

  5. Nginx反向代理总结

    反向代理的种类 1. LVS的方案 2. DNS轮询的方案 3. Nginx的4层代理 4. Nginx的7层代理 5. 网络NAT的处理 Nginx的反向代理-四层` 编译时增加 --with-st ...

  6. 麒麟信安V3.4 安装PG15的过程V2.0

    改版说明 上一次进行了PG的安装当时发现自己少加了一部分ossp的处理. 这里补充上...不然挺浪费时间的. 背景 发现基于OpenEuler的几个系统使用CentOS的rpm包 安装PG数据库时有问 ...

  7. expect 的简单学习与使用

    背景 最近工作中总有很多重复的事项. 比较繁琐,想着能够简单一点是一点的角度 准备采用expect来建华部分工作量. 其实还可以使用其他方式来处理. 但是感觉expect还是能够简单明了的. 所以暂时 ...

  8. [置顶] Gin--Begoo框架快速指南

    Gin篇 第一篇: Gin-官方文档 第二篇: Gin-安装,修改启动端口,get/post 请求参数,模型绑定shouldbind,自定义验证器/表单验证 第三篇: Gin-上传文件/返回前端.中间 ...

  9. Why gRPC ?

    gRPC(gRPC Remote Procedure Call)是由 Google 开发的开源 RPC 框架,它基于 HTTP/2 标准,使用 Protocol Buffers 作为接口定义语言(ID ...

  10. 深入探索OCR技术:前沿算法与工业级部署方案揭秘

    深入探索OCR技术:前沿算法与工业级部署方案揭秘 注:以上图片来自网络 1. OCR技术背景 1.1 OCR技术的应用场景 OCR是什么 OCR(Optical Character Recogniti ...