GDI+ 显示GIF图像

2023-11-10

头文件定义:

#pragma once

#include <gdiplus.h>
#pragma comment(lib, "gdiplus.lib")

class CGifImage
{
public:
	CGifImage(void);
	~CGifImage(void);

public:
	BOOL LoadFromFile(LPCTSTR pszFileName);
	BOOL LoadFromIStream(IStream* pStream);
	BOOL LoadFromBuffer(const BYTE* lpBuf, DWORD dwSize);
	BOOL LoadFromResource(HINSTANCE hInstance, LPCTSTR pszResourceName, LPCTSTR pszResType);
	BOOL LoadFromResource(HINSTANCE hInstance, UINT nIDResource, LPCTSTR pszResType);
	BOOL SaveAsFile(LPCTSTR pszFileName);
	void Destroy();
	BOOL IsAnimatedGif();
	UINT GetFrameCount();
	long GetFrameDelay(int nFramePos = -1);
	void ActiveNextFrame();
	void SelectActiveFrame(int nFramePos);
	BOOL Draw(HDC hDestDC, int xDest, int yDest, int nFramePos = -1);
	BOOL Draw(HDC hDestDC, const RECT& rectDest, int nFramePos = -1);
	int GetWidth();
	int GetHeight();
	UINT GetCurFramePos();
	BOOL GetRawFormat(GUID * lpGuid);

private:
	CLSID GetEncoderClsidByExtension(const WCHAR * lpExtension);

private:
	Gdiplus::Image* m_pImage;		// 图片对象指针
	UINT m_nFrameCnt;				// GIF动画总帧数
	UINT m_nFramePos;				// 当前帧
	long *m_pFrameDelay;			// 每帧切换延时时间
};

源代码实现:

#include "StdAfx.h"
#include "GifImage.h"

CGifImage::CGifImage(void)
{
	m_pImage = NULL;
	m_nFrameCnt = 0;
	m_nFramePos = 0;
	m_pFrameDelay = NULL;
}

CGifImage::~CGifImage(void)
{
	Destroy();
}

BOOL CGifImage::LoadFromFile(LPCTSTR pszFileName)
{
	Destroy();

	if (NULL == pszFileName || NULL == *pszFileName)
		return FALSE;

	m_pImage = new Gdiplus::Image(pszFileName);
	if (NULL == m_pImage)
		return FALSE;
	
	if (m_pImage->GetLastStatus() != Gdiplus::Ok)
	{
		delete m_pImage;
		m_pImage = NULL;
		return FALSE;
	}

	UINT nCount = 0;
	nCount = m_pImage->GetFrameDimensionsCount();
	if (nCount <= 0)
		return FALSE;

	GUID* pDimensionIDs = new GUID[nCount];
	if (pDimensionIDs != NULL)
	{
		m_pImage->GetFrameDimensionsList(pDimensionIDs, nCount);
		m_nFrameCnt = m_pImage->GetFrameCount(&pDimensionIDs[0]);
		delete pDimensionIDs;
	}

	if (m_nFrameCnt <= 1)
		return TRUE;

	UINT nSize = m_pImage->GetPropertyItemSize(PropertyTagFrameDelay);
	if (nSize <= 0)
		return FALSE;

	Gdiplus::PropertyItem * pPropertyItem = (Gdiplus::PropertyItem *)malloc(nSize);
	if (pPropertyItem != NULL)
	{
		m_pImage->GetPropertyItem(PropertyTagFrameDelay, nSize, pPropertyItem);

		m_pFrameDelay = new long[m_nFrameCnt];
		if (m_pFrameDelay != NULL)
		{
			for (int i = 0; i < (int)m_nFrameCnt; i++)
			{
				m_pFrameDelay[i] = ((long*)pPropertyItem->value)[i] * 10;	// 帧切换延迟时间,以1/100秒为单位
				if (m_pFrameDelay[i] < 100)
					m_pFrameDelay[i] = 100;
			}
		}
		free(pPropertyItem);
	}

	return TRUE;
}

BOOL CGifImage::LoadFromIStream(IStream* pStream)
{
	return TRUE;
}

BOOL CGifImage::LoadFromBuffer(const BYTE* lpBuf, DWORD dwSize)
{
	return TRUE;
}

BOOL CGifImage::LoadFromResource(HINSTANCE hInstance, LPCTSTR pszResourceName, LPCTSTR pszResType)
{
	return TRUE;
}

BOOL CGifImage::LoadFromResource(HINSTANCE hInstance, UINT nIDResource, LPCTSTR pszResType)
{
	return TRUE;
}

BOOL CGifImage::SaveAsFile(LPCTSTR pszFileName)
{
	if (NULL == pszFileName || NULL == m_pImage)
		return FALSE;

	LPCTSTR lpExtension = _tcsrchr(pszFileName, _T('.'));
	if (NULL == lpExtension)
		return FALSE;

	CLSID clsid = GetEncoderClsidByExtension(lpExtension);
	if (CLSID_NULL == clsid)
		return FALSE;

	Gdiplus::Status status = m_pImage->Save(pszFileName, &clsid, NULL);
	return (status != Gdiplus::Ok) ? FALSE : TRUE;
}

void CGifImage::Destroy()
{
	m_nFrameCnt = 0;
	m_nFramePos = 0;

	if (m_pFrameDelay != NULL)
	{
		delete []m_pFrameDelay;
		m_pFrameDelay = NULL;
	}

	if (m_pImage != NULL)
	{
		delete m_pImage;
		m_pImage = NULL;
	}
}

UINT CGifImage::GetFrameCount()
{
	return m_nFrameCnt;
}

BOOL CGifImage::IsAnimatedGif()
{
	return m_nFrameCnt > 1;
}

long CGifImage::GetFrameDelay(int nFramePos/* = -1*/)
{
	if (!IsAnimatedGif() || NULL == m_pFrameDelay)
		return 0;

	int nFramePos2;
	if (nFramePos != -1)
		nFramePos2 = nFramePos;
	else
		nFramePos2 = m_nFramePos;

	if (nFramePos2 >= 0 && nFramePos2 < (int)m_nFrameCnt)
		return m_pFrameDelay[nFramePos2];
	else
		return 0;
}

void CGifImage::ActiveNextFrame()
{
	if (m_pImage != NULL && IsAnimatedGif())
	{
		m_nFramePos++;
		if (m_nFramePos == m_nFrameCnt)
			m_nFramePos = 0;

		if (m_nFramePos >= 0 && m_nFramePos < m_nFrameCnt)
		{
			static GUID Guid = Gdiplus::FrameDimensionTime;
			Gdiplus::Status status = m_pImage->SelectActiveFrame(&Guid, m_nFramePos);
		}
	}
}

void CGifImage::SelectActiveFrame(int nFramePos)
{
	if (m_pImage != NULL && IsAnimatedGif() 
		&& nFramePos >= 0 && nFramePos < (int)m_nFrameCnt)
	{
		static GUID Guid = Gdiplus::FrameDimensionTime;
		Gdiplus::Status status = m_pImage->SelectActiveFrame(&Guid, nFramePos);
		m_nFramePos = nFramePos;
	}
}

BOOL CGifImage::Draw(HDC hDestDC, int xDest, int yDest, int nFramePos/* = -1*/)
{
	if (NULL == m_pImage)
		return FALSE;

	if (nFramePos != -1)
		SelectActiveFrame(nFramePos);

 	Gdiplus::Graphics graphics(hDestDC);
 	Gdiplus::Status status = graphics.DrawImage(m_pImage, xDest, yDest);
 	if(status != Gdiplus::Ok)
 		return FALSE;
 	else
 		return TRUE;
}

BOOL CGifImage::Draw(HDC hDestDC, const RECT& rectDest, int nFramePos/* = -1*/)
{
	if (NULL == m_pImage)
		return FALSE;

	if (nFramePos != -1)
		SelectActiveFrame(nFramePos);

	int nWidth = rectDest.right-rectDest.left;
	int nHeight = rectDest.bottom-rectDest.top;

 	Gdiplus::Graphics graphics(hDestDC);
 	Gdiplus::Status status = graphics.DrawImage(m_pImage, 
 		Gdiplus::Rect(rectDest.left, rectDest.top, nWidth, nHeight));
 	if(status != Gdiplus::Ok)
 		return FALSE;
 	else
 		return TRUE;
}

int CGifImage::GetWidth()
{
	if (m_pImage != NULL)
		return m_pImage->GetWidth();
	else
		return 0;
}

int CGifImage::GetHeight()
{
	if (m_pImage != NULL)
		return m_pImage->GetHeight();
	else
		return 0;
}

UINT CGifImage::GetCurFramePos()
{
	return m_nFramePos;
}

BOOL CGifImage::GetRawFormat(GUID * lpGuid)
{
	Gdiplus::Status status = m_pImage->GetRawFormat(lpGuid);
	return (Gdiplus::Ok == status) ? TRUE : FALSE;
}

CLSID CGifImage::GetEncoderClsidByExtension(const WCHAR * lpExtension)
{
	CLSID clsid = CLSID_NULL;

	if (NULL == lpExtension)
		return clsid;

	UINT numEncoders = 0, size = 0;
	Gdiplus::Status status = Gdiplus::GetImageEncodersSize(&numEncoders, &size);  
	if (status != Gdiplus::Ok)
		return clsid;

	Gdiplus::ImageCodecInfo* lpEncoders = (Gdiplus::ImageCodecInfo*)(malloc(size));
	if (NULL == lpEncoders)
		return clsid;

	status = Gdiplus::GetImageEncoders(numEncoders, size, lpEncoders);
	if (Gdiplus::Ok == status)
	{
		for (UINT i = 0; i < numEncoders; i++)
		{
			BOOL bFind = FALSE;
			const WCHAR * pStart = lpEncoders[i].FilenameExtension;
			const WCHAR * pEnd = wcschr(pStart, L';');
			do 
			{
				if (NULL == pEnd)
				{
					LPCWSTR lpExt = ::wcsrchr(pStart, L'.');
					if ((lpExt != NULL) && (wcsicmp(lpExt, lpExtension) == 0))
					{
						clsid = lpEncoders[i].Clsid;
						bFind = TRUE;
					}
					break;
				}

				int nLen = pEnd-pStart;
				if (nLen < MAX_PATH)
				{
					WCHAR cBuf[MAX_PATH] = {0};
					wcsncpy(cBuf, pStart, nLen);
					LPCWSTR lpExt = ::wcsrchr(cBuf, L'.');
					if ((lpExt != NULL) && (wcsicmp(lpExt, lpExtension) == 0))
					{
						clsid = lpEncoders[i].Clsid;
						bFind = TRUE;
						break;
					}
				}
				pStart = pEnd+1;
				if (L'\0' == *pStart)
					break;
				pEnd = wcschr(pStart, L';');
			} while (1);
			if (bFind)
				break;
		}
	}

	free(lpEncoders);

	return clsid;
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GDI+ 显示GIF图像 的相关文章

  • VC++ MapWinGis篇(创建图层)

    MapWinGis控件的引用 import MapWinGIS ocx rename IImage gisIImage rename ImageType gisImageType rename Point gisPoint using na
  • C++ 多语言切换

    如果设置UI资源文件非重点不做介绍 设置英文版接口 SetThreadUILanguage MAKELANGID LANG ENGLISH SUBLANG ENGLISH US 此时如果操作系统的语言选择的是简体中文 那么掉系统的AfxMe
  • OpenGL GLFW入门篇 - 画凸多边形

    效果图 主体代码 void DrawPolygon void glPushMatrix glLoadIdentity glTranslatef 0 0 0 0 0 f 蓝色 glColor3f 0 f 0 f 1 f glBegin GL
  • C++类上使用属性(__declspec property)

    原始代码如下 class A private int m nIndex public int getIndex return m nIndex void setIndex int value m nIndex value 如果采用属性方式实
  • C++之xlsx文件操作之写操作

    采用xlsxwriter开源库的实现 声明如下 include xlsxwriter include xmlwriter h include xlsxwriter include workbook h include xlsxwriter
  • VC++ 程序启动即隐藏

    所谓的隐藏是程序启动后不显示主窗体 网上介绍了很多方法 是否达到效果 众说纷纭 这里只介绍一种在项目中实际应用到的切实可行的方法 这里假设主窗体为CMainDialog 1 变量声明 BOOL m bShowWindow 2 给变量赋初始值
  • C++ 内存共享/软件守护

    功能描述 在无人看守的情况下 防止软件意外退出 接口调用简单 只需要简单声明就行 int main int argc char argv QShareProcess shareProcess 共享内存名称随意 下面实现自己的主体代码即可 类
  • C++ 标准库中数据类型转换

    头文件引用
  • VC++ 源码实现通达信公式管理器

    效果图 前段时间 因业务需要 写了这样一个软件 同样的页面已经是第2次写了 第1次大约5年前的事情了 因为代码遗失 于是重新写 页面看似复杂 实现起来非常简单 第一步 参照通达信的公式管理器核心文件TCalc dll 导出资源文件 TCal
  • sapi 实现语音朗读

    头文件定义 CSpeechSpeekImpl h pragma once include sphelper h class CSpeechSpeekImpl public CSpeechSpeekImpl void CSpeechSpeek
  • VC++ 在任务栏图标上显示进度条效果

    该功能主要是通过COM接口ITaskbarList3 来实现进度效果显示功能 头文件定义 CSWTaskBarList h pragma once include
  • OpenGL GLFW入门篇 - 画矩形

    效果图 主体代码 void DrawRectangle void GLfloat xl yt xr yb w h glPushMatrix glLoadIdentity glTranslatef 0 0 0 0 0 f w 1 2 h 1
  • C++ 可扩展的内存缓冲区

    类声明 CMemBuffer h pragma once class CMemBuffer public CMemBuffer DWORD dwSize 0 CMemBuffer void 申请内存 BOOL Realloc DWORD d
  • TightVNC H264编解码(二)之硬编码库的编译

    AVCodec codec avcodec find encoder by name nvenc h264 如果是默认的ffmpeg库 返回结果是NULL 看来是不带有硬编码功能的 重新编译分支ffnvcodec 不到半个小时编译完成 返回
  • VC++ CSWDirectoryListCtrl磁盘文件列表

    效果图 头文件定义 CSWDirectoryListCtrl h pragma once include afxwin h include
  • OpenSSL RSA加密和解密

    rsa加密的密钥格式常见的有两种 一种是PKCS 1 密钥头为 BEGIN RSA PUBLIC KEY 一种是PKCS 8 密钥头为 BEGIN PUBLIC KEY 以字符串公钥为例 对PKCS 1格式的密钥加载使用的函数是PEM re
  • EAN13条形码绘制(Delphi版)

    单元声明 unit UnitEAN https wenku baidu com view d61eec0dc4da50e2524de518964bcf84b9d52d0d html 共有95 18 113条数据模块 1表示黑 0表示白 左侧
  • VC++ 源码实现通达信公式管理器2

    前面我们介绍了如何加载显示公式列表 本篇章介绍如何格式化显示公式内容 常用的CEdit或CRichEdit是不支持这种格式显示的 这里需要借助第三方控件SciLexer 没错 Notepad 就是使用的这个控件 它支持不同的文本内容支持不同
  • VC++ FTP文件下传(断点续传)

    include
  • VC++ OpenCV+ZBar二维码识别

    利用OpenCV处理图像的优势 结合ZBar提高二维码识别结果 接口定义 include

随机推荐

  • STM32 基础系列教程 36 - Lwip_dns

    前言 域名系统 英文 DomainNameSystem 缩写 DNS 是互联网的一项服务 它作为将域名和IP地址相互映射的一个分布式数据库 能够使人更方便地访问互联网 DNS使用TCP和UDP端口53 当前 对于每一级域名长度的限制是63个
  • 内存泄漏

    2017 09 23 有一件事情 以后也一定要注意 那就是注意释放内存 这次的教训就是 哈希表每次清理的时候 直接就是计数清零了 但是却忘了把拉出来的链表给好好清理一下 2018 03 27 在写控制端口服务端的时候 使用了链表来进行控制
  • 制作ghost镜像

    本篇主要是制作镜像步骤 后面会有ghost镜像安装系统的博文出来 敬请关注 准备工作 1 使用正常的系统 一般c盘作为系统盘 2 下载PE工具 并安装 老毛桃 大白菜 u深度均可 3 一个空U盘 制作成PE盘 制作老毛桃PE为例 选择默认模
  • Conclusion about Scene Change Detection

    Refer to error concealment there are lost of research paper Today I want to conclude some paper about scene change detec
  • stm32f103最小系统

    STM32F103 最小系统是指使用 STM32F103 系列微控制器构建的最简单的系统 它通常包括 STM32F103 微控制器 外部存储器 如 flash 存储器或 EEPROM 外部晶振以及最少的电路元件 如电阻 电容和开关 最小系统
  • 【华为OD机试 2023 B卷

    华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一修改为OD统一考试 A卷 和OD统一考试 B卷 你收到的链接上面会标注A卷还是B卷 请注意 根据反馈 目前大部分收到的都是
  • 7_spring-cloud-config-center

    文章目录 配置中心 使用 匹配规则 具体节点从配置中心读取配置 刷新配置 单个刷新 批量刷新 bus 使用 配置中心 spirng cloud config github 搭建 服务比较多 下发配置文件比较麻烦 服务启动时 从公共服务拉取配
  • 属于服务器操作系统的有,属于服务器操作系统的有

    属于服务器操作系统的有 内容精选 换一换 将外部镜像文件注册成云平台的私有镜像后 您可以使用该镜像创建新的云服务器 或对已有云服务器的系统进行重装和更换 本节介绍使用镜像创建云服务器的操作 您可以按照通过镜像创建云服务器中的操作指导创建弹性
  • MySQL中如何正确存储IP地址

    一 IP地址应该怎么存 在MySQL中 当存储IPv4地址时 应该使用32位的无符号整数 UNSIGNED INT 来存储IP地址 而不是使用字符串 用UNSIGNED INT类型存储IP 地址是一个4字节长的整数 如果是字符串存储IP 地
  • Firefox打不开https(SSL)加密链接的原因之一

    直接上图 firefox出现此种提示很多次了 在网上搜了很多方法 什么改配置参数 什么重新安装都没用 打开官方帮助说明一样没解决问题 后来 终于发现原来是卡巴斯基 KIS 2016 的原因 如图 KIS 设置中 附加 网络设置 扫描加密连接
  • 交叉编译工具链中GUN常用命令简介

    一 交叉编译工具链前缀 arm none linux gnueabi 二 常用命令 注 此处以汇编点亮led灯代码为例 重点掌握 1 gcc 编译命令 arm none linux gnueabi gcc c S或 c o o eg arm
  • ansible的脚本和playbook剧本

    playbooks 概述 Playbook介绍 playbook是ansible用于配置 部署 和管理被控节点的剧本 通过playbook的详细描述 执行其中的tasks 可以让远端主机达到预期的状态 playbook是由一个或多个 pla
  • python停车时间计算,时分秒计算

    小蓝将自己的车停在路边 在同一天将车开走 给定停车时间和开走时间 请问小蓝停了多长时间 输入格式 输入两行 第一行包含停车时间 第二行包含开走时间 每个时间的格式为 HH MM SS 其中 HH 表示时 值为 0 到 23 的整数 如果小于
  • 2022美赛备赛资料大全

    目录 1 美赛比赛网址及其介绍 2 美赛摘要页说明 3 美赛常用词语与语句 4 美赛翻译注意事项 5 美赛论文写作一些建议 5 1 团队方面准备 5 2 摘要表部分 5 3 评委关注点 6 组队要求 7 软件与一些建模网址参考 1 写一篇建
  • c++比double更大的数据类型_数据类型、变量和运算符

    一 数据类型 1 1 数据类型图示 java中的数据类型分为两大种类 基本数据类型和引用数据类型 整体数据类型如下图 1 2 基本数据类型 整形 字节类型 byte 短整形 short 整形 init 长整形 long 浮点型 单精度浮点型
  • 初识python 视频_#python day02 初识python 学习视频来源于 太白金星

    python day02 初识python 学习视频来源于 太白金星 知识点 安装PyCharm 设置鼠标条件字体大小 file gt settings 搜索mouse Editor gt general gt Change font si
  • Git 分支操作&存储原理浅谈

    相信大家对于 git 版本控制系统都不陌生 大部分同学在工作中都会使用到 git 他帮助我们管理我们的代码 让我们能够随心所欲的提交代码 进行不同的实验而不用担心将项目毁掉 同学们可以在工作中熟练的使用 git 进行代码提交 但是部分同学对
  • c语言 函数编程四个数相加,C语言第四章课后编程题

    1 编写程序 从键盘上输入4个整数 输出最小值 此题较为简单 只需定义一个桥梁最小值min就可以来着次比较他们的大小 2 编写一个程序 从键盘输入一个四位整数n 输出它的各位数字之和 例如n 1308 则输出12 n 3204 则输出9 这
  • UnityVR--PoolManager--对象池1

    本篇中使用的API gameObject CompareTag 标签 UnityEvent 事件管理 ObjectPool
  • GDI+ 显示GIF图像

    头文件定义 pragma once include