一个图片加载与绘制类(使用GDI输出图片)

这是一个图片加载与绘制的类,使用GDI将图片文件绘制到DC上,可以用于图片显示,程序换肤等应用场合。
其中部分代码来源于互联网,代码作者不详,我只进行了改进和增补,如果来源作者看到,还望谅解。

一、头文件(CEnBitmap.h)

/**///////////////////////////////////////////////////////////////////////////
///   
///    @file    EnBitmap.h
///   
///    @brief    Inherite from CBitmap, expanding some draw features
///   
///    @author    XuYu
///    @version    1.0
///    @date    2007-07-26
///
//////////////////////////////////////////////////////////////////////////

#if !defined(AFX_ENBITMAP_H__76F269F6_895A_48EC_BA09_7D3BEF0438E7__INCLUDED_)
#define AFX_ENBITMAP_H__76F269F6_895A_48EC_BA09_7D3BEF0438E7__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CEnBitmap : public CBitmap
...{
public:
    CEnBitmap();
    virtual ~CEnBitmap();

    BOOL LoadImage(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst = NULL, COLORREF crBack = 0);
    BOOL LoadImage(LPCTSTR lpctImagePath, COLORREF crBack=0);
    BOOL LoadImage(HBITMAP hBitmap);
    BOOL LoadImage2(UINT uIDRes, LPCTSTR lpctResType, HMODULE hInst=NULL, COLORREF crBack=0);
    int GetWidth()
    ...{
        BITMAP bm;
        memset( &bm, 0, sizeof(bm) );
        GetBitmap(&bm);
        return bm.bmWidth;
    }
    int GetHeight()
    ...{
        BITMAP bm;
        memset( &bm, 0, sizeof(bm) );
        GetBitmap(&bm);
        return bm.bmHeight;
    }
    CRect GetRect()
    ...{
        return CRect(0, 0, GetWidth(), GetHeight());
    }
    BOOL ExtendDraw(CDC *pDC,CRect rc, int nX, int nY);
    BOOL ExtendDrawImage(CEnBitmap &bmp, CRect rc, int nX, int nY);
    BOOL StretchDraw(CDC *pDC, LPRECT r, LPRECT sr);
    BOOL StretchDraw(CDC *pDC, LPRECT r);
    BOOL Draw(CDC *pDC, LPRECT r);
   
private:
    static int GetImageType(LPCTSTR lpctImagePath);
    static HBITMAP ExtractBitmap(IPicture* pPicture, COLORREF crBack = 0);
    static HBITMAP LoadImageFile(LPCTSTR lpctImagePath, COLORREF crBack = 0);
    static HBITMAP LoadImageResource(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst = NULL, COLORREF crBack = 0);

    static BOOL GetResource(LPCTSTR lpctName, LPCTSTR lpctType, HMODULE hInst, void* pRes, int& nBufSize);
    static IPicture* LoadFromBuffer(BYTE* pBuff, int nSize);
    BOOL AttachEx(IPicture* pPicture, COLORREF crBack);
};

#endif // !defined(AFX_ENBITMAP_H__76F269F6_895A_48EC_BA09_7D3BEF0438E7__INCLUDED_)
二、源文件(CEnBitmap.cpp)

#include "stdafx.h"
#include "EnBitmap.h"

/**//// Definition of picture type
enum
...{
    FT_BMP,
    FT_JPG,
    FT_UNKNOWN
};

CEnBitmap::CEnBitmap()
...{

}

CEnBitmap::~CEnBitmap()
...{
}

/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Get picture type, only support JPG and BMP
///
///    @param [in] lpctImagePath    The picture full path
///
//////////////////////////////////////////////////////////////////////////
int CEnBitmap::GetImageType(LPCTSTR lpctImagePath)
...{
    size_t nLen = _tcslen(lpctImagePath);
    TCHAR* lptImagePath = new TCHAR[nLen+1];
    memset(lptImagePath,0,nLen+1);
    _tcscpy(lptImagePath, lpctImagePath);
   
    CharUpper(lptImagePath);
   
    TCHAR lptExtension[5] = ...{0};
    size_t i=nLen-4;
    size_t j=0;
    for(; i<nLen; i++,j++)
        lptExtension[j] = lptImagePath[i];
   
    delete[] lptImagePath;
   
    if(_tcscmp(lptExtension,_T(".BMP")) == 0)
        return FT_BMP;
    if(_tcscmp(lptExtension,_T(".JPG")) == 0)
        return FT_JPG;
   
    return FT_UNKNOWN;
}
/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Extract a picture use IPicture interface
///
///    @param [in] pPicture    IPicture interface pointer
///    @param [in] crBack        Mask color to make transparent
///
//////////////////////////////////////////////////////////////////////////
HBITMAP CEnBitmap::ExtractBitmap(IPicture* pPicture, COLORREF crBack /**//* = 0 */)
...{
    ATLASSERT(pPicture);
   
    if (!pPicture)
        return NULL;
   
    CBitmap bmMem;
    CDC dcMem;
    HWND hwndDesktopWnd = ::GetDesktopWindow();
    HDC hDesktopDC = ::GetDC(hwndDesktopWnd);
    CDC* pDC = new CDC(hDesktopDC);
   
    if (dcMem.CreateCompatibleDC(pDC->m_hDC))
    ...{
        long hmWidth;
        long hmHeight;
       
        pPicture->get_Width(&hmWidth);
        pPicture->get_Height(&hmHeight);
       
        int nWidth    = MulDiv(hmWidth, pDC->GetDeviceCaps(LOGPIXELSX), HIMETRIC_INCH);
        int nHeight    = MulDiv(hmHeight, pDC->GetDeviceCaps(LOGPIXELSY), HIMETRIC_INCH);
       
        if (bmMem.CreateCompatibleBitmap(pDC->m_hDC, nWidth, nHeight))
        ...{
            HBITMAP hOldBM = dcMem.SelectBitmap(bmMem.m_hBitmap);
           
            if (crBack != -1)
                dcMem.FillSolidRect(0, 0, nWidth, nHeight, crBack);
           
            HRESULT hr = pPicture->Render(dcMem, 0, 0, nWidth, nHeight, 0, hmHeight, hmWidth, -hmHeight, NULL);
            dcMem.SelectBitmap(hOldBM);
        }
    }
   
    ::ReleaseDC(hwndDesktopWnd, pDC->m_hDC);
    if(dcMem.m_hDC) ::DeleteDC(dcMem.Detach());
    ::DeleteObject(hDesktopDC);
    if(pDC->m_hDC) ::DeleteDC(pDC->Detach());
   
    return (HBITMAP)bmMem.Detach();
}

/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Load a picture from full path
///
///    @param [in] lpctImagePath    The full path of picture
///    @param [in] crBack        Mask color to make transparent
///
//////////////////////////////////////////////////////////////////////////
HBITMAP CEnBitmap::LoadImageFile(LPCTSTR lpctImagePath, COLORREF crBack /**//* = 0 */)
...{
    int nImgType = GetImageType(lpctImagePath);
    USES_CONVERSION;

    switch(nImgType)
    ...{
    case FT_BMP:
        return (HBITMAP)::LoadImage(NULL, lpctImagePath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    case FT_UNKNOWN:
        return NULL;
    default:
        ...{
            IPicture* pPic = NULL;
            HBITMAP hbm = NULL;
            HRESULT hr = OleLoadPicturePath(T2OLE((LPTSTR)lpctImagePath), NULL, 0, crBack, IID_IPicture, (LPVOID *)&pPic);
            if(pPic)
            ...{
                hbm = ExtractBitmap(pPic, crBack);
                pPic->Release();
            }
           
            return hbm;
        }
    }
   
    return NULL;
}
/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Load a picture from resource ID
///
///    @param [in] uIDRes    Resource ID
///    @param [in] szResourceType    Resource type
///    @param [in] hInst    Instance including resources
///    @param [in] crBack        Mask color to make transparent
///
///    @note This method need to valid
///
//////////////////////////////////////////////////////////////////////////
HBITMAP CEnBitmap::LoadImageResource(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst /**//* = NULL */, COLORREF crBack /**//* = 0 */)
...{
    BYTE* pBuff = NULL;
    int nSize = 0;
    HBITMAP hbm = NULL;
   
    // first call is to get buffer size
    if (GetResource(MAKEINTRESOURCE(uIDRes), szResourceType, hInst, 0, nSize))
    ...{
        if (nSize > 0)
        ...{
            pBuff = new BYTE[nSize];
           
            // this loads it
            if (GetResource(MAKEINTRESOURCE(uIDRes), szResourceType, hInst, pBuff, nSize))
            ...{
                IPicture* pPicture = LoadFromBuffer(pBuff, nSize);
               
                if (pPicture)
                ...{
                    hbm = ExtractBitmap(pPicture, crBack);
                    pPicture->Release();
                }
            }
           
            delete [] pBuff;
        }
    }
   
    return hbm;
}
/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Load a picture from full path of picture
///
///    @param [in] lpctImagePath    Full path of picture
///    @param [in] crBack        Mask color to make transparent
///
///    @note This is the entry method
///
//////////////////////////////////////////////////////////////////////////
BOOL CEnBitmap::LoadImage(LPCTSTR lpctImagePath, COLORREF crBack/**//* =0 */)
...{
    if(m_hBitmap != NULL)
    ...{
        DeleteObject();
        Detach();
    }
   
    Attach(LoadImageFile(lpctImagePath, crBack));
   
    return (m_hBitmap == NULL) ? FALSE : TRUE;
}
/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Load a picture from resource ID and type
///
///    @param [in] uIDRes    Resource ID
///    @param [in] szResourceType    Resource type
///    @param [in] hInst    Instance including resources
///    @param [in] crBack        Mask color to make transparent
///
///    @note This is the entry method
///
//////////////////////////////////////////////////////////////////////////
BOOL CEnBitmap::LoadImage(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst /**//* = NULL */, COLORREF crBack /**//* = 0 */)
...{
    ATLASSERT(m_hBitmap == NULL);
   
    if (m_hBitmap != NULL)
        return TRUE;
   
    Attach(LoadImageResource(uIDRes, szResourceType, hInst, crBack));

    return (m_hBitmap == NULL) ? FALSE : TRUE;
}

/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Load a bitmap from handle
///
///    @param [in] hBitmap    Handle of a bitmap
///
///    @note This method need to valid
///
//////////////////////////////////////////////////////////////////////////
BOOL CEnBitmap::LoadImage(HBITMAP hBitmap)
...{
    if(m_hBitmap != NULL)
    ...{
        DeleteObject();
        Detach();
    }

    Attach(hBitmap);

    return (m_hBitmap == NULL) ? FALSE : TRUE;
}

/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Load a picture from resource ID
///
///    @param [in] uIDRes    Resource ID
///    @param [in] szResourceType    Resource type
///    @param [in] hInst    Instance including resources
///    @param [in] crBack        Mask color to make transparent
///
///    @note This method is just for TESTING, DONT'T CALL this method before validation
///
//////////////////////////////////////////////////////////////////////////
BOOL CEnBitmap::LoadImage2(UINT uIDRes, LPCTSTR lpctResType, HMODULE hInst/**//* =NULL */, COLORREF crBack/**//* =0 */)
...{
    ATLASSERT(m_hBitmap == NULL);      // only attach once, detach on destroy
   
//     if (m_hBitmap != NULL)
//         return FALSE;
//     if( (m_hBitmap = ::LoadBitmap(_Module.m_hInst,MAKEINTRESOURCE(uIDRes)) ) != NULL)
//         return TRUE;
//
//     return FALSE;   

    BYTE*    pBuff = NULL;
    int        nSize = 0;
    BOOL bResult = FALSE;
   
    // first call is to get buffer size
    if (GetResource(MAKEINTRESOURCE(uIDRes), lpctResType, hInst, 0, nSize))
    ...{
        if (nSize > 0)
        ...{
            pBuff = new BYTE[nSize];
           
            // this loads it
            if (GetResource(MAKEINTRESOURCE(uIDRes), lpctResType, hInst, pBuff, nSize))
            ...{
                IPicture* pPicture = LoadFromBuffer(pBuff, nSize);
               
                if (pPicture)
                ...{
                    bResult = AttachEx(pPicture, crBack);
                    pPicture->Release();
                }
            }
           
            delete [] pBuff;
        }
    }
   
    return bResult;
}

/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Make a IPicture interface pointer from buffer stream
///
///    @param [in] pBuff    Picture buffer stream
///    @param [in] nSize    Size of pBuff
///
///    @note This method need to valid
///
//////////////////////////////////////////////////////////////////////////
IPicture* CEnBitmap::LoadFromBuffer(BYTE* pBuff, int nSize)
...{
    bool bResult = false;

    HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, nSize);
    void* pData = GlobalLock(hGlobal);
    memcpy(pData, pBuff, nSize);
    GlobalUnlock(hGlobal);

    IStream* pStream = NULL;
    IPicture* pPicture = NULL;

    if (CreateStreamOnHGlobal(hGlobal, TRUE, &pStream) == S_OK)
    ...{
        HRESULT hr = ::OleLoadPicture(pStream, nSize, FALSE, IID_IPicture, (LPVOID *)&pPicture);
        pStream->Release();
    }

    ::GlobalFree(hGlobal);

    return pPicture; // caller releases
}

/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Get resource from a module
///
///    @param [in] lpName    Resource name
///    @param [in] lpType    Resource type
///    @param [in] hInst    Handle of module
///    @param [out] pResource    Resource pointer
///    @param [in] nBufSize    Size of resource
///
///    @note This method need to valid
///
//////////////////////////////////////////////////////////////////////////
BOOL CEnBitmap::GetResource(LPCTSTR lpName, LPCTSTR lpType, HMODULE hInst, void* pResource, int& nBufSize)
...{
    HRSRC        hResInfo;
    HANDLE        hRes;
    LPSTR        lpRes    = NULL;
    int            nLen    = 0;
    bool        bResult    = FALSE;

    // Find the resource
    hResInfo = FindResource(hInst, lpName, lpType);

    if (hResInfo == NULL)
        return false;

    // Load the resource
    hRes = LoadResource(hInst, hResInfo);

    if (hRes == NULL)
        return false;

    // Lock the resource
    lpRes = (char*)LockResource(hRes);

    if (lpRes != NULL)
    ...{
        if (pResource == NULL)
        ...{
            nBufSize = SizeofResource(hInst, hResInfo);
            bResult = true;
        }
        else
        ...{
            if (nBufSize >= (int)SizeofResource(hInst, hResInfo))
            ...{
                memcpy(pResource, lpRes, nBufSize);
                bResult = true;
            }
        }

        UnlockResource(hRes); 
    }

    // Free the resource
    FreeResource(hRes);

    return bResult;
}

/**///////////////////////////////////////////////////////////////////////////
///
///    @brief    Attach a picture from IPicture interface pointer
///
///    @param [in] pPicture    IPicture interface pointer
///    @param [in] crBack    Mask color for making transparent
///
///    @note    This method is called by LoadImage2, a TESTING function,
///            so DON'T USE THIS METHOD before validation
///
//////////////////////////////////////////////////////////////////////////
BOOL CEnBitmap::AttachEx(IPicture* pPicture, COLORREF crBack)
...{
    ATLASSERT(m_hBitmap == NULL);      // only attach once, detach on destroy

    if (m_hBitmap != NULL)
        return FALSE;

    ATLASSERT(pPicture);

    if (!pPicture)
        return FALSE;

    BOOL bResult = FALSE;

    CDC dcMem;
    CWindowDC dc(GetDesktopWindow());
    CDC* pDC = &dc;

    if (dcMem.CreateCompatibleDC(pDC->m_hDC))
    ...{
        long hmWidth;
        long hmHeight;

        pPicture->get_Width(&hmWidth);
        pPicture->get_Height(&hmHeight);
       
        int nWidth    = MulDiv(hmWidth,    pDC->GetDeviceCaps(LOGPIXELSX), HIMETRIC_INCH);
        int nHeight    = MulDiv(hmHeight,    pDC->GetDeviceCaps(LOGPIXELSY), HIMETRIC_INCH);

        CBitmap bmMem;

        if (bmMem.CreateCompatibleBitmap(pDC->m_hDC, nWidth, nHeight))
        ...{
            HBITMAP hOldBM = dcMem.SelectBitmap(bmMem.m_hBitmap);

            if (crBack != -1)
                dcMem.FillSolidRect(0, 0, nWidth, nHeight, crBack);
           
            HRESULT hr = pPicture->Render(dcMem, 0, 0, nWidth, nHeight, 0, hmHeight, hmWidth, -hmHeight, NULL);
            dcMem.SelectBitmap(hOldBM);

            if (hr == S_OK)
                /**//*bResult = */CBitmap::Attach(bmMem.Detach());   
        }

        if(bmMem.m_hBitmap) bmMem.DeleteObject();
    }

    ReleaseDC(GetDesktopWindow(),pDC->m_hDC);
    if(dcMem.m_hDC) ::DeleteDC(dcMem.Detach());

    return bResult;
}

BOOL CEnBitmap::ExtendDraw(CDC *pDC, CRect rc, int nX, int nY)
...{
    CEnBitmap bmp;
    if (ExtendDrawImage(bmp,rc,nX,nY))
    ...{
        bmp.Draw(pDC, &rc);
        return TRUE;
    }
    return FALSE;
}

BOOL CEnBitmap::ExtendDrawImage(CEnBitmap &bmp, CRect rc, int nX, int nY)
...{
    HBITMAP hOldBmp;
    CDC memDC;
    CClientDC cdc(0);
   
    memDC.CreateCompatibleDC(cdc.m_hDC);
    bmp.CreateCompatibleBitmap(cdc.m_hDC, rc.Width() , rc.Height() );
    hOldBmp = memDC.SelectBitmap( bmp.m_hBitmap );
   
    if (nX==0 && nY==0)
    ...{
        StretchDraw(&memDC, &rc, GetRect());
        return TRUE;
    }

    CDC dc;
    dc.CreateCompatibleDC(memDC.m_hDC);
    HBITMAP hBmp = dc.SelectBitmap( m_hBitmap );
    //dc.SetStretchBltMode(COLORONCOLOR);
    if (nX!=0 && nY==0)
    ...{
       
        //左上角
        memDC.BitBlt( 0, 0, nX, rc.Height(), dc.m_hDC, 0, 0, SRCCOPY );
        memDC.StretchBlt(nX, 0, rc.Width()-GetWidth(), rc.Height(), dc.m_hDC,nX, 0, 1, GetHeight(), SRCCOPY );
        //右上角
        memDC.BitBlt(rc.right-(GetWidth()-nX), 0, GetWidth()-nX, rc.Height(), dc.m_hDC,nX, 0, SRCCOPY );
       
    }
    else if (nX==0 && nY!=0)
    ...{
        //上角
        memDC.BitBlt( 0, 0, rc.Width(), nY, dc.m_hDC, 0, 0, SRCCOPY );
        memDC.StretchBlt(0, nY, GetWidth(), rc.Height()-GetHeight(), dc.m_hDC,0, nY, GetWidth(), 1, SRCCOPY );
        //右上角
        memDC.BitBlt(0, rc.bottom-(GetHeight()-nY), GetWidth(), GetHeight()-nY, dc.m_hDC,0, nY, SRCCOPY );
       
    }
    else
    ...{
        //左上角
        memDC.StretchBlt( 0, 0, nX, nY, dc.m_hDC, 0, 0, nX, nY, SRCCOPY );
        //上中
        memDC.StretchBlt(nX, 0, rc.Width()-GetWidth(),nY, dc.m_hDC, nX, 0, 1, nY , SRCCOPY );
        //右上角
        memDC.StretchBlt(rc.Width()-(GetWidth()-nX), 0, GetWidth()-nX, nY ,  dc.m_hDC,nX, 0, GetWidth()-nX, nY, SRCCOPY );
        //左中
        memDC.StretchBlt(0, nY, nX,rc.Height()-GetHeight(), dc.m_hDC, 0, nY, nX, 1, SRCCOPY );
        //正中
        memDC.StretchBlt(nX, nY, rc.Width()-GetWidth(),rc.Height()-GetHeight(), dc.m_hDC, nX, nY, 1, 1, SRCCOPY );
        //右中
        memDC.StretchBlt(rc.Width()-(GetWidth()-nX), nY, GetWidth()-nX,rc.Height()-GetHeight(), dc.m_hDC, nX, nY, GetWidth()-nX, 1, SRCCOPY );
        //左下角
        memDC.StretchBlt( 0, rc.Height()-(GetHeight()-nY), nX, GetHeight()-nY, dc.m_hDC, 0, nY, nX,GetHeight()-nY , SRCCOPY );
        //下中
        memDC.StretchBlt(nX, rc.Height()-(GetHeight()-nY), rc.Width()-GetWidth(),GetHeight()-nY, dc.m_hDC, nX, nY, 1, GetHeight()-nY, SRCCOPY );
        //右下角
        memDC.StretchBlt( rc.Width()-(GetWidth()-nX), rc.Height()-(GetHeight()-nY), GetWidth()-nX, GetHeight()-nY, dc.m_hDC, nX, nY, GetWidth()-nX, GetHeight()-nY, SRCCOPY );
    }
    dc.SelectBitmap( hBmp );   
    memDC.SelectBitmap(hOldBmp);

    memDC.Detach();
    //cdc.Detach();
    dc.Detach();
   
    return TRUE;
}

BOOL CEnBitmap::StretchDraw(CDC *pDC, LPRECT r, LPRECT sr )
...{
    if ( !r )
        return FALSE;
    CDC dc;
    dc.CreateCompatibleDC( pDC->m_hDC );
    HBITMAP hOldBitmap = dc.SelectBitmap( m_hBitmap );
    pDC->SetStretchBltMode(COLORONCOLOR);
   
    if ( !sr )
        pDC->StretchBlt( r->left, r->top, r->right, r->bottom, dc.m_hDC, 0, 0, GetWidth(), GetHeight(), SRCCOPY );
    else
        pDC->StretchBlt( r->left, r->top,
        r->right - r->left,
        r->bottom - r->top,
        dc.m_hDC,
        sr->left,
        sr->top,
        sr->right - sr->left,
        sr->bottom - sr->top,
        SRCCOPY );
   
    dc.SelectBitmap( hOldBitmap );
    if(dc.m_hDC) ::DeleteDC(dc.Detach());
    ::DeleteObject(hOldBitmap);
    hOldBitmap = NULL;

    return TRUE;   
}

BOOL CEnBitmap::StretchDraw(CDC *pDC, LPRECT r)
...{
    CDC dc;
    dc.CreateCompatibleDC( pDC->m_hDC );
    HBITMAP bmp = dc.SelectBitmap( m_hBitmap );
   
    pDC->StretchBlt( r->left, r->top, r->right, r->bottom, dc.m_hDC, 0, 0, GetWidth(), GetHeight(), SRCCOPY );
   
    dc.SelectBitmap( bmp );
    if(dc.m_hDC) ::DeleteDC(dc.Detach());
    ::DeleteObject(bmp);
    bmp = NULL;

    return TRUE;   
}

BOOL CEnBitmap::Draw(CDC *pDC, LPRECT r)
...{
    CDC dc;
    dc.CreateCompatibleDC( pDC->m_hDC );
    HBITMAP bmp = dc.SelectBitmap( m_hBitmap );   
    pDC->BitBlt( r->left, r->top, r->right - r->left, r->bottom - r->top, dc.m_hDC, 0, 0, SRCCOPY );
   
    dc.SelectBitmap( bmp );   
    ::DeleteDC(dc.Detach());

    return TRUE;
}

原文地址:https://www.cnblogs.com/lzjsky/p/1795665.html