// GDIPlusHelper.cpp: implementation of the CGDIPlusHelper class.   
//   
//////////////////////////////////////////////////////////////////////   
  

#include "ImageEx.h"   
#include <process.h>   
#include <string>   
  
  
  
  
////////////////////////////////////////////////////////////////////////////////   
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;   
    }   
}   