- // GDIPlusHelper.h: interface for the CGDIPlusHelper class.
- //
- //////////////////////////////////////////////////////////////////////
- #if !defined(AFX_GDIPLUSHELPER_H__BD5F6266_5686_43E2_B146_5EA1217A56FE__INCLUDED_)
- #define AFX_GDIPLUSHELPER_H__BD5F6266_5686_43E2_B146_5EA1217A56FE__INCLUDED_
- #if _MSC_VER > 1000
- #pragma once
- #endif // _MSC_VER > 1000
- #include <windows.h>
- //注意:此类当创建的图像对象是多帧动画时,没有考虑线程同步问题,不能在其他地方使用,
- //比如所有的Graphics操作函数,以及从基类继承过来的接口函数,你只能使用ImageEx类的public接口函数;
- //而当创建的是单帧图像时,线程同步性等价于基类Image的同步性,
- //则你可以像以前使用Image类那样使用该类,包括所有的Graphics操作函数,以及从基类继承过来的接口函数。
- //其实你会发现下面的public成员函数操作的成员变量都是新增的成员变量。
- class ImageEx : public Image
- {
- public:
- //以长度为nSize的内存pBuff中的内容构造图像
- ImageEx(const void* pBuff, size_t nSize, BOOL useEmbeddedColorManagement = FALSE);
- //以类型为sResourceType,名称为sResource的资源构造图像
- ImageEx(LPCTSTR sResourceType, LPCTSTR sResource, BOOL useEmbeddedColorManagement = FALSE);
- //以文件构造图像
- ImageEx(LPCTSTR filename, BOOL useEmbeddedColorManagement = FALSE);
- //调用Destroy成员函数
- ~ImageEx();
- public:
- //如果已经构造的对象是动画,则创建动画线程,并返回true,
- //如果为静态图像或已经创建过动画线程,则也返回false
- // 图像将绘制在m_hWnd客户区的rect区域,会拉伸,支持镜像
- bool InitAnimation(HWND hWnd, RECT rect);
- //判断是否为动画
- bool IsAnimatedGIF() { return m_nFrameCount > 1; }
- //设置动画暂停与否
- void SetPause(bool bPause);
- //判断动画是否处于暂停状态
- bool IsPaused() { return m_bPause; }
- //关闭动画,事实上基类Image中还有的两个成员变量没有关闭,因为析构函数会调用基类析构函数进行关闭的
- void Destroy();
- protected:
- //测试图像是否为动画,是的话成员变量m_pPropertyItem将会malloc分配内存
- bool TestForAnimatedGIF();
- //给所有成员变量初始化,构造函数中调用
- void Initialize();
- //在客户区画出当前帧,返回值表示是否要退出线程函数
- bool DrawFrameGIF();
- //把长度为nSize的内存pBuff中的内容创建为IStream流保存在类的m_pStream成员变量中,
- //返回成功与否,不检查参数的非法性
- bool LoadFromBuffer(const void* pBuff, size_t nSize);
- //装载名称为lpName,类型为lpType的资源到pResource中,返回装载成功与否。
- //nBufSize表示pResource缓存的长度。pResource为NULL时,nBufSize返回所需内存大小,
- //不为NULL时,返回实际资源大小,长度不够时,相当于pResource为NULL时的作用,只是返回值为false。
- bool GetResource(LPCTSTR lpName, LPCTSTR lpType, void* pResource, size_t& nBufSize);
- //装载类型为sResourceType,名称为sResource的资源到流对象成员变量m_pStream中,返回装载成功与否,
- //m_pStream在该函数中装载成功与否保存在成员变量m_bIsInitialized中,
- //同时,如果该类的对象是以文件构造的,则m_bIsInitialized表示构造成功与否
- bool Load(LPCTSTR sResourceType, LPCTSTR sResource); //类型,名字
- //实际的线程函数
- void ThreadAnimation();
- //代理线程函数,实际调用ThreadAnimation成员函数
- static UINT WINAPI _ThreadAnimationProc(LPVOID pParam);
- protected:
- IStream* m_pStream; //记得Release
- HANDLE m_hThread; //线程创建时是挂起的,须调用ResumeThread
- HANDLE m_hPause; //手工重置,初始有信号
- HANDLE m_hExitEvent; //手工重置,初始无信号
- HINSTANCE m_hInst;
- HWND m_hWnd;
- UINT m_nFrameCount;
- UINT m_nFramePosition;
- bool m_bIsInitialized; //表示对象构造成功与否,不管是以资源还是文件的形式
- bool m_bPause;
- PropertyItem* m_pPropertyItem; //如果为动画,会malloc内存,记得free
- HDC m_hdcMem; //双缓存用,只在是多帧动画且创建了播放线程时才创建
- HBITMAP m_hbmpBack; //双缓存用,只在是多帧动画且创建了播放线程时才创建
- RECT m_rect; // 图像在m_hWnd客户区绘制的区域,会拉伸,支持镜像
- //另外,基类Image中还有两个成员变量:nativeImage(GpImage*类型)和lastResult(Status类型)
- };
- #endif // !defined(AFX_GDIPLUSHELPER_H__BD5F6266_5686_43E2_B146_5EA1217A56FE__INCLUDED_)
- // GDIPlusHelper.cpp: implementation of the CGDIPlusHelper class.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "ImageEx.h"
- #include <process.h>
- #include <string>
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- ////////////////////////////////////////////////////////////////////////////////
- int A2U(const char* szA,wchar_t* szU,size_t cnt)
- {
- return MultiByteToWideChar (CP_ACP, 0, szA, -1, szU, cnt) ;
- }
- std::wstring A2U(const char* szA)
- {
- int nRetCode=A2U(szA,0,0);
- if(0==nRetCode)
- return std::wstring();
- std::wstring str(nRetCode-1,'/0');
- A2U(szA,(wchar_t*)(str.c_str()),nRetCode);
- return str;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //以长度为nSize的内存pBuff中的内容构造图像
- ////////////////////////////////////////////////////////////////////////////////
- ImageEx::ImageEx(const void* pBuff, size_t nSize, BOOL useEmbeddedColorManagement)
- {
- Initialize();
- bool bResult = LoadFromBuffer(pBuff, nSize);
- m_bIsInitialized = bResult;
- if (m_bIsInitialized)
- {
- nativeImage = NULL;
- if (useEmbeddedColorManagement)
- lastResult = DllExports::GdipLoadImageFromStreamICM(m_pStream, &nativeImage);
- else
- lastResult = DllExports::GdipLoadImageFromStream(m_pStream, &nativeImage);
- TestForAnimatedGIF();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- //以类型为sResourceType,名称为sResource的资源构造图像
- ////////////////////////////////////////////////////////////////////////////////
- ImageEx::ImageEx(LPCTSTR sResourceType, LPCTSTR sResource, BOOL useEmbeddedColorManagement)
- {
- Initialize();
- if (Load(sResourceType, sResource))
- {
- nativeImage = NULL;
- if (useEmbeddedColorManagement)
- lastResult = DllExports::GdipLoadImageFromStreamICM(m_pStream, &nativeImage);
- else
- lastResult = DllExports::GdipLoadImageFromStream(m_pStream, &nativeImage);
- TestForAnimatedGIF();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- //以文件构造图像
- ////////////////////////////////////////////////////////////////////////////////
- ImageEx::ImageEx(LPCTSTR filename, BOOL useEmbeddedColorManagement) :
- #ifndef UNICODE
- Image(A2U(filename).c_str(), useEmbeddedColorManagement)
- #else
- Image(filename, useEmbeddedColorManagement)
- #endif
- {
- Initialize();
- m_bIsInitialized = (Ok == lastResult);
- if(m_bIsInitialized)
- TestForAnimatedGIF();
- }
- ////////////////////////////////////////////////////////////////////////////////
- //析构函数,调用Destroy成员函数
- ////////////////////////////////////////////////////////////////////////////////
- ImageEx::~ImageEx()
- {
- this->Destroy();
- }
- ////////////////////////////////////////////////////////////////////////////////
- //如果已经构造的对象是动画,则创建动画线程,并返回true,
- //如果为静态图像或已经创建过动画线程,则也返回false
- // 图像将绘制在m_hWnd客户区的rect区域,会拉伸,支持镜像
- ////////////////////////////////////////////////////////////////////////////////
- bool ImageEx::InitAnimation(HWND hWnd, RECT rect)
- {
- m_hWnd = hWnd;
- m_rect = rect;
- if (!m_bIsInitialized)
- return false;
- if (IsAnimatedGIF())
- {
- if (m_hThread == NULL)
- {
- unsigned int nTID = 0;
- HDC hDC = GetDC(m_hWnd);
- m_hdcMem = CreateCompatibleDC(hDC);
- m_hbmpBack = CreateCompatibleBitmap(hDC,GetWidth(),GetHeight());
- SelectObject(m_hdcMem,m_hbmpBack);
- ReleaseDC(m_hWnd, hDC);
- m_hThread = (HANDLE) _beginthreadex( NULL, 0, _ThreadAnimationProc, this, CREATE_SUSPENDED,&nTID);
- if (!m_hThread)
- return false;
- else
- {
- ResumeThread(m_hThread);
- return true;
- }
- }
- }
- return false;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //把长度为nSize的内存pBuff中的内容创建为IStream流保存在类的m_pStream成员变量中,
- //返回成功与否,不检查参数的非法性
- ////////////////////////////////////////////////////////////////////////////////
- bool ImageEx::LoadFromBuffer(const void* pBuff, size_t nSize)
- {
- bool bResult = false;
- HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, nSize);
- if (hGlobal)
- {
- void* pData = GlobalLock(hGlobal);
- if (pData)
- memcpy(pData, pBuff, nSize);
- GlobalUnlock(hGlobal);
- if (CreateStreamOnHGlobal(hGlobal, TRUE, &m_pStream) == S_OK)
- bResult = true;
- }
- return bResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //装载名称为lpName,类型为lpType的资源到pResource中,返回装载成功与否。
- //nBufSize表示pResource缓存的长度。pResource为NULL时,nBufSize返回所需内存大小,
- //不为NULL时,返回实际资源大小,长度不够时,相当于pResource为NULL时的作用,只是返回值为false。
- ////////////////////////////////////////////////////////////////////////////////
- bool ImageEx::GetResource(LPCTSTR lpName, LPCTSTR lpType, void* pResource, size_t& nBufSize)
- {
- HRSRC hResInfo;
- HGLOBAL hRes;
- void* lpRes = NULL;
- size_t nLen = 0;
- bool bResult = FALSE;
- // Find the resource
- hResInfo = FindResource(m_hInst , lpName, lpType);
- if (hResInfo == NULL)
- {
- DWORD dwErr = GetLastError();
- return false;
- }
- // Load the resource
- hRes = LoadResource(m_hInst , hResInfo);
- if (hRes == NULL)
- return false;
- // Lock the resource
- lpRes = LockResource(hRes);
- if (lpRes != NULL)
- {
- nLen = SizeofResource(m_hInst , hResInfo);
- if (pResource == NULL)
- {
- nBufSize = nLen;
- bResult = true;
- }
- else
- {
- if (nBufSize >= nLen)
- {
- memcpy(pResource, lpRes, nLen);
- bResult = true;
- }
- nBufSize = nLen;
- }
- UnlockResource(hRes);
- }
- // Free the resource
- FreeResource(hRes);
- return bResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //装载类型为sResourceType,名称为sResource的资源到流对象成员变量m_pStream中,返回装载成功与否,
- //m_pStream在该函数中装载成功与否保存在成员变量m_bIsInitialized中,
- //同时,如果该类的对象是以文件构造的,则m_bIsInitialized表示构造成功与否
- ////////////////////////////////////////////////////////////////////////////////
- bool ImageEx::Load(LPCTSTR sResourceType, LPCTSTR sResource)
- {
- bool bResult = false;
- BYTE* pBuff = NULL;
- size_t nSize = 0;
- if (GetResource(sResource, sResourceType, pBuff, nSize))
- {
- if (nSize > 0)
- {
- pBuff = new BYTE[nSize];
- if (GetResource(sResource, sResourceType, (void*)pBuff, nSize))
- {
- bResult = LoadFromBuffer((const void*)pBuff, nSize);
- }
- delete [] pBuff;
- }
- }
- m_bIsInitialized = bResult;
- return bResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //测试图像是否为动画,是的话成员变量m_pPropertyItem将会malloc分配内存
- ////////////////////////////////////////////////////////////////////////////////
- bool ImageEx::TestForAnimatedGIF()
- {
- UINT count = 0;
- count = GetFrameDimensionsCount();
- GUID* pDimensionIDs = new GUID[count];
- // Get the list of frame dimensions from the Image object.
- GetFrameDimensionsList(pDimensionIDs, count);
- // Get the number of frames in the first dimension.
- m_nFrameCount = GetFrameCount(&pDimensionIDs[0]);
- // Assume that the image has a property item of type PropertyItemEquipMake.
- // Get the size of that property item.
- if (m_nFrameCount > 1)
- {
- int nSize = GetPropertyItemSize(PropertyTagFrameDelay);
- // Allocate a buffer to receive the property item.
- m_pPropertyItem = (PropertyItem*) malloc(nSize);
- GetPropertyItem(PropertyTagFrameDelay, nSize, m_pPropertyItem);
- }
- delete pDimensionIDs;
- return m_nFrameCount > 1;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //给所有成员变量初始化,构造函数中调用
- ////////////////////////////////////////////////////////////////////////////////
- void ImageEx::Initialize()
- {
- m_pStream = NULL;
- m_hThread = NULL;
- m_hPause = CreateEvent(NULL,TRUE,TRUE,NULL); //手工重置,初始有信号
- m_hExitEvent = CreateEvent(NULL,TRUE,FALSE,NULL); //手工重置,初始无信号
- m_hInst = GetModuleHandle(NULL);
- m_hWnd = NULL;
- m_nFrameCount = 0;
- m_nFramePosition = 0;
- m_bIsInitialized = false;
- m_bPause = false;
- m_pPropertyItem = NULL;
- m_hdcMem = NULL;
- m_hbmpBack = NULL;
- SetRect(&m_rect,0,0,0,0);
- //以下两句不能有,因为Initialize函数是构造函数中调用,下面两个属于基类的成员变量不能再次被修改
- // nativeImage = NULL;
- // lastResult = InvalidParameter;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //代理线程函数,实际调用ThreadAnimation成员函数
- ////////////////////////////////////////////////////////////////////////////////
- UINT WINAPI ImageEx::_ThreadAnimationProc(LPVOID pParam)
- {
- ImageEx *pImage = reinterpret_cast<ImageEx *> (pParam);
- pImage->ThreadAnimation();
- return 0;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //实际的线程函数
- ////////////////////////////////////////////////////////////////////////////////
- void ImageEx::ThreadAnimation()
- {
- m_nFramePosition = 0;
- bool bExit = false;
- while (!bExit)
- {
- bExit = DrawFrameGIF();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- //在客户区画出当前帧,返回值表示是否要退出线程函数
- ////////////////////////////////////////////////////////////////////////////////
- bool ImageEx::DrawFrameGIF()
- {
- ::WaitForSingleObject(m_hPause, INFINITE); //m_hPause手工重置,初始有信号
- //pageGuid的值在显示GIF为FrameDimensionTime,显示TIF时为FrameDimensionPage
- GUID pageGuid = FrameDimensionTime;
- RECT rect;
- UINT width, height;
- HDC hDC = GetDC(m_hWnd);
- int BltMode = SetStretchBltMode (hDC, COLORONCOLOR) ;
- if (m_hdcMem)
- {
- width = GetWidth();
- height = GetHeight();
- SetRect(&rect, 0, 0, width, height);
- FillRect(m_hdcMem,&rect,(HBRUSH) (COLOR_WINDOW+1));
- Graphics graphics(m_hdcMem);
- graphics.DrawImage(this, 0, 0, width, height);
- StretchBlt(hDC, m_rect.left, m_rect.top,
- m_rect.right-m_rect.left, m_rect.bottom-m_rect.top,
- m_hdcMem, 0, 0, width, height, SRCCOPY);
- }
- SetStretchBltMode (hDC, BltMode) ;
- ReleaseDC(m_hWnd, hDC);
- long lPause = ((long*) m_pPropertyItem->value)[m_nFramePosition] * 10;
- if(lPause<10)
- lPause=80;
- else if(lPause>5000)
- lPause=80;
- DWORD dwErr = WaitForSingleObject(m_hExitEvent, lPause); //m_hExitEvent手工重置,初始无信号
- if(WAIT_OBJECT_0 != dwErr)
- {
- if(++m_nFramePosition == m_nFrameCount)
- m_nFramePosition = 0;
- SelectActiveFrame(&pageGuid, m_nFramePosition);
- return false;
- }
- else
- return true; // 如果在lPause时间内产生信号,则返回true,表示要退出线程
- }
- ////////////////////////////////////////////////////////////////////////////////
- //设置动画暂停与否
- ////////////////////////////////////////////////////////////////////////////////
- void ImageEx::SetPause(bool bPause)
- {
- if (!IsAnimatedGIF())
- return;
- if (!m_bPause && bPause) //本来没暂停且要设置为暂停
- {
- ResetEvent(m_hPause);
- }
- else
- {
- if (m_bPause && !bPause) //本来已暂停且要设置为非暂停
- {
- SetEvent(m_hPause);
- }
- }
- m_bPause = bPause;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //关闭动画,事实上基类Image中还有的两个成员变量没有关闭,因为析构函数会调用基类析构函数进行关闭的
- ////////////////////////////////////////////////////////////////////////////////
- void ImageEx::Destroy()
- {
- if (m_hThread)
- {
- this->SetPause(false);
- SetEvent(m_hExitEvent);
- WaitForSingleObject(m_hThread, INFINITE);
- CloseHandle(m_hThread);
- DeleteDC(m_hdcMem);
- DeleteObject(m_hbmpBack);
- m_hThread = NULL;
- m_hdcMem = NULL;
- m_hbmpBack = NULL;
- }
- if(m_hExitEvent)
- CloseHandle(m_hExitEvent);
- if(m_hPause)
- CloseHandle(m_hPause);
- free(m_pPropertyItem);
- m_hExitEvent = NULL;
- m_hPause = NULL;
- m_pPropertyItem = NULL;
- if (m_pStream)
- {
- m_pStream->Release();
- m_pStream = NULL;
- }
- }
使用GDI+库显示gif动态图片,该类接口如下:
可以看出,该ImageEx完全继承了基类的接口函数。
说明:
如果打开非多帧图片,该类几乎完全等价于基类,比如你可以把该类的对象代入Graphics类系列的成员函数中;
如果打开的是多帧的图片,你只要打开图片后不调用InitAnimation函数(它会创建线程),则上述做法依然可以;
但如果调用InitAnimation函数后(单帧图像没关系,因为不会创建线程),则不可以了,
所有的基类继承过来的接口成员函数和配合gdi+库其他类的函数调用都是不可以的,因为没有作线程同步,
你只能调用下面位数不多的几个public成员函数,调用Destroy成员函数后,则就可以了,因为它会关闭线程。
其实你会发现下面的public成员函数操作的成员变量都是新增的成员变量,没涉及到线程同步问题。
class ImageEx : public Image
{
public:
//以长度为nSize的内存pBuff中的内容构造图像
ImageEx(const void* pBuff, size_t nSize, BOOL useEmbeddedColorManagement = FALSE);
//以类型为sResourceType,名称为sResource的资源构造图像
ImageEx(LPCTSTR sResourceType, LPCTSTR sResource, BOOL useEmbeddedColorManagement = FALSE);
//以文件构造图像
ImageEx(LPCTSTR filename, BOOL useEmbeddedColorManagement = FALSE);
//调用Destroy成员函数
~ImageEx();
public:
//如果已经构造的对象是动画,则创建动画线程,并返回true,
//如果为静态图像或已经创建过动画线程,则也返回false
// 图像将绘制在m_hWnd客户区的rect区域,会拉伸,支持镜像
bool InitAnimation(HWND hWnd, RECT rect);
//判断是否为动画
bool IsAnimatedGIF() { return m_nFrameCount > 1; }
//设置动画暂停与否
void SetPause(bool bPause);
//判断动画是否处于暂停状态
bool IsPaused() { return m_bPause; }
//关闭动画,事实上基类Image中还有的两个成员变量没有关闭,因为析构函数会调用基类析构函数进行关闭的
void Destroy();
//另外的非public的东西省略..
};
用法:
MFC对话框程序在下面添加:
BOOL CTestDlgDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//其它的初始化代码
// GDI+
//m_image为ImageEx指针类型成员变量,"GIF"为资源类型,"HEARTS"为资源名称
m_image = new ImageEx( _T("GIF"), _T("HEARTS") );
RECT rc;
GetClientRect(&rc);
m_image->InitAnimation(this->m_hWnd, rc);//创建gif播放线程
return TRUE; // return TRUE unless you set the focus to a control
}
CTestDlgDlg::~CTestDlgDlg()
{
// GDI+
delete m_image;
}
其中的m_image = new ImageEx( _T("GIF"), _T("HEARTS") );你可以换成ImageEx类的另外两个构造函数
浙公网安备 33010602011771号