<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 495,comments - 227,trackbacks - 0

    VC 中自建操作 BMP 位圖文件的類

    ?

    ?????? 作者: ??? 賈暾

    西安萬山軟件有限公司

    ??????

    有編程經驗的程序員都知道:要使應用程序的界面美觀不可避免的要使用大量位圖。現在流行的可視化編程工具對位圖的使用提供了很好的支持,被稱為三大可視化開發工具的 VB VC Delphi 通過封裝位圖對象對位圖使用提供了很好的支持: VB 提供了兩個功能很強的對象: PictureBox Image ,通過使用它們,裝載、顯示位圖變得非常容易。 Delphi 中也提供了一個位圖對象: TImage ,它的功能與用法與 VB 中的 Image 類似。在 VC 中通過使用設備相關類 CDC GDI 對象類 CBitmap 來完成位圖的操作。

    然而在 VC 中使用 CBitmap 類必須將 BMP 位圖裝入資源中,然后通過類 CBitmap 的成員函數使用它,在通過 CDC 類的成員函數操作它。這樣做有兩點缺陷:將位圖裝入資源導致可執行文件增大,不利于軟件發行;只能使用資源中有限的位圖,無法選取其它位圖。而且 BMP 位圖文件是以 DIB (設備無關位圖)方式保存, BMP 位圖裝入資源后被轉換為 DDB (設備相關位圖),類 CBitmap 就是對一系列 DDB 操作的 API 函數進行了封裝,使用起來有一定的局限性,不如 DIB 可以獨立于平臺特性。

    要彌補使用資源位圖的兩點不足,就必須直接使用 BMP 位圖文件。 VC 的示例中提供了一種方法讀取并顯示 BMP 位圖文件,但使用起來相當的麻煩。首先使用 API 函數 GlobalAlloc 分配內存并創建 HDIB 位圖句柄,所有操作只能直接讀寫內存,然后通過 StrechDIBits SetDIBsToDevice 函數來顯示于屏幕上,操作起來費時費力。

    因此筆者通過研究類 CBitmap 的封裝與 DIB 結構,使用 Win32 中提供的新函數,建立了一個專用于操作 BMP 文件的類,而且完全仿照類 CBitmap 的實現:從類 CGdiObject 派生,新類的所有接口與類 CBitmap 的部分接口完全相同。這樣對于習慣使用 CBitmap 類接口用法的程序員來說兩者的接口在使用上沒有什么分別。

    首先我們先簡單介紹一下 DIB 的結構。 DIB 位圖既可以存在于內存,也可以以文件形式保存在磁盤上( BMP 文件)。所有 DIB 都包含兩部分信息:位圖信息( BITMAPINFO ),包括位圖信息頭和顏色表;位圖數據。對于內存中 DIB 的只要有上述兩部分就行,而對于 DIB 文件則還要加上位圖文件頭。兩種結構如圖所示:

    ?DIB?????????? ???????????????????????????????????????????????????????????????????????? ??DIB 文件

    ?

    ????????????????????????????????????????????????????????????????????????????????????

    ??????????????????????????????????????????? 位圖信息頭(BITMAPINFOHEADER
    位圖文件頭(
    BITMAPFILEHEADER )????????? ??位圖信息頭(BITMAPINFOHEADER

    ?顏色表(RGBQUAD)?????????????????????????顏色表(RGBQUAD

    位圖數據??????????????????????????????????????????????????????????????????????? 位圖數據

    ?

    ?

    ?


    其次, Win32 中提供了一個新函數 CreateDIBSection ,通過它可以創建一個存儲 DIB 位的內存區域,既可以執行相應的 GDI 操作,又可以直接通過指向 DIB 位區域的指針方位 DIB 位區域。這是一個非常有用的函數,通過它我們可以用 DIB 替代 DDB

    在了解了相應的知識后,我們可以自己由類 CGdiObject 派生一個操作 BMP 文件的類: CBitmapFile

    在自己編寫類時有兩點值得注意:

    1.??? BitmapFile.h 文件中定義類 CBitmapFile, 首先必須聲明類 CBitmapFile 是從類 CGdiObject 中公有派生。然后在類中首先使用宏 DECLARE_DYNAMIC CBitmapFile )表明新類的最高父類是類 CObject ,是符合 MFC 的類庫規范。緊接著宏 DECLARE_DYNAMIC 的是聲明靜態函數 FromHandle ,這兩個聲明必須放在類定義的最前面。

    2.??? BitmapFile.cpp 文件中類的成員函數的實現前加上 IMPLEMENT_DYNAMIC(CBitmapFile,CGdiObject); 表明類 CBitmapFile 直接派生于類 CGdiObject

    在類 CBitmapFile 的聲明中有三個函數與類 Cbitmap 中的定義稍有不同:

    1. 在類 CbitmapFile LoadBitmap 函數的參數是 LPCTSTR 型,保存的是 BMP 文件的文件名。

    2. 在類 CbitmapFile CreateBitmap 函數的參數中少了參數 nPlanes ,在函數內部默認為 1

    3. 在類 CbitmapFile CreateBitmapIndirect 函數的參數中多了參數 lpBits ,它指向指定位圖 DIB 位的內存區域。

    在成員函數中最重要的是函數 CreateBitmapIndirect 和函數 LoadBitmap

    1. 在函數 CreateBitmapIndirect 中使用函數 CreateDIBSection 創建了一個以兼容 DC 為基礎的 HBITMAP 句柄,并用繼承自類 CGdiObject 的函數 Attach 把它與類 CGdiObject 的句柄 m_hObject 關聯起來。然后將指定位圖的 DIB 位圖數據拷貝到由函數 CreateDIBSection 創建的 DIB 位的內存區域。

    2. 在函數 LoadBitmap 中首先從指定文件名的文件中讀取以結構 BITMAPFILEHEADER 為大小的數據塊,然后由文件頭標志判斷文件是否為 BMP 位圖文件,然后由 BITMAPFILEHEADER bfSize 保存的文件大小與文件的真實大小比較文件是否有損壞,再由 BITMAPFILEHEADER bfOffBits BITMAPFILEHEADER 結構大小相減計算出位圖信息頭和顏色表一共的大小,動態申請一塊空間保存位圖信息頭和顏色表信息,再由 BITMAPFILEHEADER bfSize bfOffBits 相減計算出 DIB 位圖數據的大小,動態申請一塊空間保存 DIB 位圖數據,最后調用成員函數 CreateBitmapIndirect 來創建 DIB 位圖。

    在應用程序的 OnPaint ()事件中繪制 DIB 位圖的方法與使用類 CBitmap 時繪制位圖的方法完全相同,但有一點要注意的是由于 CDC 類沒有提供返回新類 CBitmapFile 指針類型的將 DIB 位圖選入內存的 SelectObject 函數,所以在使用 SelectObject 時要將返回類型強制轉換為 CbitmapFile * 類型。

    ?

    附源文件

    //??? 文件描述:定義類 CBitmapFile ,此類是用于讀取 BMP 文件,涉及讀取、

    //??????????? ?? 建立及一系列常用的操作。

    //??? 文件名: ? BitmapFile.h

    #ifndef _CBITMAPFILE_H_

    #define _CBITMAPFILE_H_

    ?

    class CBitmapFile : public CGdiObject

    {

    ?????? DECLARE_DYNAMIC(CBitmapFile)

    ?

    public:

    ?????? static CBitmapFile* PASCAL FromHandle(HBITMAP hBitmap);

    ?

    // Constructors

    ?????? CBitmapFile();

    ?

    ?????? BOOL LoadBitmap(LPCTSTR lpszFileName);

    ?????? BOOL CreateBitmap(int nWidth, int nHeight, UINT nBitCount, const void* lpBits);

    ?????? BOOL CreateBitmapIndirect(LPBITMAPINFO lpBitmapInfo, const void* lpBits);

    ?

    // Attributes

    ?????? operator HBITMAP() const;

    ?????? int GetBitmap(BITMAP* pBitMap);

    ?

    protected:

    // Attributes

    ?????? int GetColorNumber(WORD wBitCount);

    ?

    public:

    // Operations

    ?????? DWORD SetBitmapBits(DWORD dwCount, const void* lpBits);

    ?????? DWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits);

    ?

    // Implementation

    public:

    ?????? virtual ~CBitmapFile();

    };

    ?

    #endif

    ?

    //

    //??? 文件描述:類 CBitmapFile 內成員函數的實現

    //??? 文件名: ? BitmapFile.cpp

    //?????????????????????????????????????????????????????????????????

    ?

    #include "BitmapFile.h"

    #include <memory.h>

    ?

    IMPLEMENT_DYNAMIC(CBitmapFile,CGdiObject);

    ?

    CBitmapFile* PASCAL CBitmapFile::FromHandle(HBITMAP hBitmap)

    {

    ?????? return (CBitmapFile*) CGdiObject::FromHandle(hBitmap);

    }

    ?

    CBitmapFile::CBitmapFile()

    {

    }

    ?

    BOOL CBitmapFile::LoadBitmap(LPCTSTR lpszFileName)

    {

    ?????? CFile file;

    ?????? if(!file.Open(lpszFileName,CFile::modeRead|CFile::shareDenyWrite))

    ?????? {

    ????????????? MessageBox(NULL,"BMP file open error!","warning",MB_OK);

    ????????????? return FALSE;

    ?????? }

    ?

    ?????? BITMAPFILEHEADER bfhHeader;

    ?????? file.Read(&bfhHeader,sizeof(BITMAPFILEHEADER));

    ?

    ?????? if(bfhHeader.bfType!=((WORD) ('M'<<8)|'B'))

    ?????? {

    ????????????? MessageBox(NULL,"The file is not a BMP file!","warning",MB_OK);

    ????????????? return FALSE;

    ?????? }

    ?

    ?????? if(bfhHeader.bfSize!=file.GetLength())

    ?????? {

    ????????????? MessageBox(NULL,"The BMP file header error!","warning",MB_OK);

    ????????????? return FALSE;

    ?????? }

    ?

    ?????? UINT uBmpInfoLen=(UINT) bfhHeader.bfOffBits-sizeof(BITMAPFILEHEADER);

    ?????? LPBITMAPINFO lpBitmap=(LPBITMAPINFO) new BYTE[uBmpInfoLen];

    ?????? file.Read((LPVOID) lpBitmap,uBmpInfoLen);

    ?

    ?????? if((* (LPDWORD)(lpBitmap))!=sizeof(BITMAPINFOHEADER))

    ?????? {

    ????????????? MessageBox(NULL,"The BMP is not Windows 3.0 format!","warning",MB_OK);

    ????????????? return FALSE;

    ?????? }

    ?

    ?????? DWORD dwBitlen=bfhHeader.bfSize - bfhHeader.bfOffBits;

    ?????? LPVOID lpBits=new BYTE[dwBitlen];

    ?????? file.ReadHuge(lpBits,dwBitlen);

    ?????? file.Close();

    ??????

    ?????? BOOL bSuccess=CreateBitmapIndirect(lpBitmap, lpBits);

    ?????? delete lpBitmap;

    ?????? delete lpBits;

    ?

    ?????? if(!bSuccess)

    ????????????? return FALSE;

    ?

    ?????? return TRUE;

    }

    ?

    BOOL CBitmapFile::CreateBitmap(int nWidth, int nHeight, UINT nBitCount,

    ???????????????????????????? const void* lpSrcBits)

    {

    ?????? ASSERT(nBitCount==1||nBitCount==4||nBitCount==8

    ???????????????????? ||nBitCount==16||nBitCount==24||nBitCount==32);

    ?

    ?????? LPBITMAPINFO lpBitmap;

    ?????? lpBitmap=(BITMAPINFO*) new BYTE[sizeof(BITMAPINFOHEADER) +

    ?? ??????????????????????????????????????????? ????GetColorNumber(nBitCount) * sizeof(RGBQUAD)];

    ??????

    ?????? lpBitmap->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);

    ?????? lpBitmap->bmiHeader.biWidth=nWidth;

    ?????? lpBitmap->bmiHeader.biHeight=nHeight;

    ?????? lpBitmap->bmiHeader.biBitCount=nBitCount;

    ?????? lpBitmap->bmiHeader.biPlanes=1;

    ?????? lpBitmap->bmiHeader.biCompression=BI_RGB;

    ?????? lpBitmap->bmiHeader.biSizeImage=0;

    ?????? lpBitmap->bmiHeader.biClrUsed=0;

    ?

    ?????? BOOL bSuccess=CreateBitmapIndirect(lpBitmap, lpSrcBits);

    ?????? delete lpBitmap;

    ??????

    ?????? if(!bSuccess)

    ????????????? return FALSE;

    ??????

    ?????? return TRUE;

    }

    ?

    BOOL CBitmapFile::CreateBitmapIndirect(LPBITMAPINFO lpBitmapInfo, const void* lpSrcBits)

    {

    ?????? DeleteObject();

    ?

    ?????? LPVOID lpBits;

    ?????? CDC *dc=new CDC;

    ?????? dc->CreateCompatibleDC(NULL);

    ?????? HBITMAP hBitmap=::CreateDIBSection(dc->m_hDC,lpBitmapInfo,DIB_RGB_COLORS,

    ????????????????????????????????????? &lpBits,NULL,0);

    ?

    ?????? ASSERT(hBitmap!=NULL);

    ??????

    ?????? delete dc;

    ??????

    ?????? Attach(hBitmap);

    ??????

    ?????? BITMAP bmp;

    ?????? GetBitmap(&bmp);

    ?????? DWORD dwCount=(DWORD) bmp.bmWidthBytes * bmp.bmHeight;

    ?

    ?????? if(SetBitmapBits(dwCount,lpSrcBits)!=dwCount)

    ?????? {

    ????????????? MessageBox(NULL,"DIB build error!","warning",MB_OK);

    ????????????? return FALSE;

    ?????? }

    ?

    ?????? return TRUE;

    }

    ?

    CBitmapFile::operator HBITMAP() const

    {

    ?????? return (HBITMAP)(this == NULL ? NULL : m_hObject);

    }

    ?

    int CBitmapFile::GetBitmap(BITMAP* pBitMap)

    {

    ?????? ASSERT(m_hObject != NULL);

    ?????? return ::GetObject(m_hObject, sizeof(BITMAP), pBitMap);

    }

    ?

    int CBitmapFile::GetColorNumber(WORD wBitCount)

    {

    ?????? ASSERT(wBitCount==1||wBitCount==4||wBitCount==8

    ???????????????????? ||wBitCount==16||wBitCount==24||wBitCount==32);

    ?

    ?????? switch(wBitCount)

    ?????? {

    ?????? case 1:

    ????????????? return 2;

    ?????? case 4:

    ????????????? return 16;

    ?????? case 8:

    ????????????? return 256;

    ?????? default:

    ????????????? return 0;

    ?????? }

    }

    ?

    DWORD CBitmapFile::SetBitmapBits(DWORD dwCount, const void* lpBits)

    {

    ?????? if(lpBits!=NULL)

    ?????? {

    BITMAP bmp;

    ?????? GetBitmap(&bmp);

    memcpy(bmp.bmBits,lpBits,dwCount);

    ?????? return dwCount;

    ?????? }

    ?????? else

    ????????????? return 0;

    }

    ?

    DWORD CBitmapFile::GetBitmapBits(DWORD dwCount, LPVOID lpBits)

    {

    ?????? if(lpBits!=NULL)

    ?????? {

    ????????????? BITMAP bmp;

    ????????????? GetBitmap(&bmp);

    ????????????? memcpy(lpBits,bmp.bmBits,dwCount);

    ????????????? return dwCount;

    ?????? }

    ?????? else

    ????????????? return 0;

    }

    ?

    CBitmapFile::~CBitmapFile()

    {

    ?????? CGdiObject::DeleteObject();

    }

    posted on 2007-03-09 16:32 SIMONE 閱讀(1734) 評論(0)  編輯  收藏 所屬分類: C++
    主站蜘蛛池模板: 久久一本岛在免费线观看2020| 亚洲精品无码久久久久YW| 中文字幕av免费专区| 免费日韩在线视频| 国产精品观看在线亚洲人成网| 日韩一区二区在线免费观看 | 无人在线观看免费高清视频 | 卡一卡二卡三在线入口免费| 亚洲导航深夜福利| 我要看免费的毛片| 狠狠入ady亚洲精品| 免费看国产一级片| 一个人晚上在线观看的免费视频| 久久久久亚洲AV综合波多野结衣| 国产一级a毛一级a看免费人娇 | 亚洲国产成人久久综合一区| 99在线精品免费视频九九视| 亚洲熟妇无码AV不卡在线播放 | 免费看www视频| 一区二区三区免费精品视频| 国产亚洲精品一品区99热| 日韩精品内射视频免费观看 | 国产亚洲精品久久久久秋霞| 麻豆精品不卡国产免费看| 亚洲高清资源在线观看| 国内一级一级毛片a免费| 免费人妻精品一区二区三区| 亚洲AV中文无码字幕色三| 18禁免费无码无遮挡不卡网站| 亚洲精品无码aⅴ中文字幕蜜桃| 亚洲AV中文无码乱人伦| 国产免费一区二区视频| 亚洲xxxx18| 亚洲精品亚洲人成人网| 免费看黄视频网站| 无码 免费 国产在线观看91| 亚洲综合精品香蕉久久网97| 国产一级大片免费看| 午夜理伦剧场免费| 久久精品亚洲日本波多野结衣| 人人狠狠综合久久亚洲88|