使用vc顯示bmp位圖

 

 BMP 是一種與硬件設備無關的圖像文件格式,使用非常廣。它採用位映射存儲格式,除了圖像深度可選以外,不採用其他任何壓縮,因此,BMP文件所佔用的空間很大。BMP文件的

圖像深度可選lbit、4bit、8bit及24bit。BMP文件存儲數據時,圖像的掃描方式是按從左到右、從下到上的順序。

由於BMP文件格式是Windows環境中交換與圖有關的數據的一種標準,因此在Windows環境中運行的圖形圖像軟件都支持BMP圖像格式。
文件結構:

典型的BMP圖像文件由四部分組成:
1:位圖文件頭數據結構,它包含BMP圖像文件的類型、顯示內容等信息;
2:位圖信息數據結構,它包含有BMP圖像的寬、高、壓縮方法,以及定義顏色等信息;
3:調色板,這個部分是可選的,有些位圖需要調色板,有些位圖,比如真彩色圖(24位的BMP)就不需要調色板;
4:位圖數據,這部分的內容根據BMP位圖使用的位數不同而不同,在24位圖中直接使用RGB,而其他的小於24位的使用調色板中顏色索引值。

對應的數據結構:

1:BMP文件組成
BMP文件由文件頭、位圖信息頭、顏色信息和圖形數據四部分組成。
2:BMP文件頭
BMP文件頭數據結構含有BMP文件的類型、文件大小和位圖起始位置等信息。
其結構定義如下:
typedef struct tagBITMAPFILEHEADER
{
WORDbfType; // 位圖文件的類型,必須爲BM
DWORD bfSize; // 位圖文件的大小,以字節爲單位
WORDbfReserved1; // 位圖文件保留字,必須爲0
WORDbfReserved2; // 位圖文件保留字,必須爲0
DWORD bfOffBits; // 位圖數據的起始位置,以相對於位圖
// 文件頭的偏移量表示,以字節爲單位
} BITMAPFILEHEADER;
3:位圖信息頭
BMP位圖信息頭數據用於說明位圖的尺寸等信息。
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; // 本結構所佔用字節數
LONGbiWidth; // 位圖的寬度,以像素爲單位
LONGbiHeight; // 位圖的高度,以像素爲單位
WORD biPlanes; // 目標設備的級別,必須爲1
WORD biBitCount// 每個像素所需的位數,必須是1(雙色),
// 4(16色),8(256色)或24(真彩色)之一
DWORD biCompression; // 位圖壓縮類型,必須是 0(不壓縮),
// 1(BI_RLE8壓縮類型)或2(BI_RLE4壓縮類型)之一
DWORD biSizeImage; // 位圖的大小,以字節爲單位
LONGbiXPelsPerMeter; // 位圖水平分辨率,每米像素數
LONGbiYPelsPerMeter; // 位圖垂直分辨率,每米像素數
DWORD biClrUsed;// 位圖實際使用的顏色表中的顏色數
DWORD biClrImportant;// 位圖顯示過程中重要的顏色數
} BITMAPINFOHEADER;
4:顏色表
顏色表用於說明位圖中的顏色,它有若干個表項,每一個表項是一個RGBQUAD類型的結構,定義一種顏色。RGBQUAD結構的定義如下:
typedef struct tagRGBQUAD {
BYTErgbBlue;// 藍色的亮度(值範圍爲0-255)
BYTErgbGreen; // 綠色的亮度(值範圍爲0-255)
BYTErgbRed; // 紅色的亮度(值範圍爲0-255)
BYTErgbReserved;// 保留,必須爲0
} RGBQUAD;
顏色表中RGBQUAD結構數據的個數有biBitCount來確定:
當biBitCount=1,4,8時,分別有2,16,256個表項;
當biBitCount=24時,沒有顏色表項。
位圖信息頭和顏色表組成位圖信息,BITMAPINFO結構定義如下:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader; // 位圖信息頭
RGBQUAD bmiColors[1]; // 顏色表
} BITMAPINFO;

5:位圖數據
位圖數據記錄了位圖的每一個像素值,記錄順序是在掃描行內是從左到右,掃描行之間是從下到上。位圖的一個像素值所佔的字節數:
當biBitCount=1時,8個像素佔1個字節;
當biBitCount=4時,2個像素佔1個字節;
當biBitCount=8時,1個像素佔1個字節;
當biBitCount=24時,1個像素佔3個字節;
Windows規定一個掃描行所佔的字節數必須是
4的倍數(即以long爲單位),不足的以0填充,

biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;


具體數據舉例:
如某BMP文件開頭:
424D 4690 0000 0000 0000 4600 0000 2800 0000 8000 0000 9000 0000 0100*1000 0300 0000 0090 0000 A00F 0000 A00F 0000 0000 0000 0000 0000*00F8 0000 E007 0000

1F00 0000 0000 0000*02F1 84F1 04F1 84F1 84F1 06F2 84F1 06F2 04F2 86F2 06F2 86F2 86F2 .... ....

BMP文件可分爲四個部分:位圖文件頭、位圖信息頭、彩色板、圖像數據陣列,在上圖中已用*分隔。

一、圖像文件頭
1)1:(這裏的數字代表的是"字",即兩個字節,下同)圖像文件頭。424Dh=’BM’,表示是Windows支持的BMP格式。
2)2-3:整個文件大小。4690 0000,爲00009046h=36934。
3)4-5:保留,必須設置爲0。
4)6-7:從文件開始到位圖數據之間的偏移量。4600 0000,爲00000046h=70,上面的文件頭就是35字=70字節。
二、位圖信息頭
5)8-9:位圖圖信息頭長度。
6)10-11:位圖寬度,以像素爲單位。8000 0000,爲00000080h=128。
7)12-13:位圖高度,以像素爲單位。9000 0000,爲00000090h=144。
8)14:位圖的位面數,該值總是1。0100,爲0001h=1。
9)15:每個像素的位數。有1(單色),4(16色),8(256色),16(64K色,高彩色),24(16M色,真彩色),32(4096M色,增強型真彩色)。1000爲0010h=16。
10)16-17:壓縮說明:有0(不壓縮),1(RLE 8,8位RLE壓縮),2(RLE 4,4位RLE壓縮,3(Bitfields,位域存放)。RLE簡單地說是採用像素數+像素值的方式進行壓縮

。T408採用的是位域存放方式,用兩個字節表示一個像素,位域分配爲r5b6g5。圖中0300 0000爲00000003h=3。
11)18-19:用字節數表示的位圖數據的大小,該數必須是4的倍數,數值上等於位圖寬度×位圖高度×每個像素位數。0090 0000爲00009000h=80×90×2h=36864。
12)20-21:用象素/米表示的水平分辨率。A00F 0000爲0000 0FA0h=4000。
13)22-23:用象素/米表示的垂直分辨率。A00F 0000爲0000 0FA0h=4000。
14)24-25:位圖使用的顏色索引數。設爲0的話,則說明使用所有調色板項。
15)26-27:對圖象顯示有重要影響的顏色索引的數目。如果是0,表示都重要。

三、彩色板
16)28-35:彩色板規範。對於調色板中的每個表項,用下述方法來描述RGB的值:
1字節用於藍色分量
1字節用於綠色分量
1字節用於紅色分量
1字節用於填充符(設置爲0)
對於24-位真彩色圖像就不使用彩色板,因爲位圖中的RGB值就代表了每個象素的顏色。
如,彩色板爲00F8 0000 E007 0000 1F00 0000 0000 0000,其中:
00FB 0000爲FB00h=1111100000000000(二進制),是紅色分量的掩碼。
E007 0000爲 07E0h=0000011111100000(二進制),是綠色分量的掩碼。
1F00 0000爲001Fh=0000000000011111(二進制),是紅色分量的掩碼。
0000 0000總設置爲0。
將掩碼跟像素值進行“與”運算再進行移位操作就可以得到各色分量值。看看掩碼,就可以明白事實上在每個像素值的兩個字節16位中,按從高到低取5、 6、5位分別就是r、

g、b分量值。取出分量值後把r、g、b值分別乘以8、4、8就可以補齊第個分量爲一個字節,再把這三個字節按rgb組合,放入存儲器(同樣要反序),就可以轉換爲24位標準BMP格

式了。

四、圖像數據陣列
17)17-...:每兩個字節表示一個像素。陣列中的第一個字節表示位圖左下角的象素,而最後一個字節表示位圖右上角的象素。

五、存儲算法
BMP文件通常是不壓縮的,所以它們通常比同一幅圖像的壓縮圖像文件格式要大很多。例如,一個800×600的24位幾乎佔據1.4MB空間。因此它們通常不適合在因特網或者其它低速

或者有容量限制的媒介上進行傳輸。根據顏色深度的不同,圖像上的一個像素可以用一個或者多個字節表示,它由n/8所確定(n是位深度,1字節包含8個數據位)。圖片瀏覽器等

基於字節的 ASCII值計算像素的顏色,然後從調色板中讀出相應的值。更爲詳細的信息請參閱下面關於位圖文件的部分。 n位2n種顏色的位圖近似字節數可以用下面的公式計算:

BMP文件大小約等於 54+4*2的n次方+(w*h*n)/8
,其中高度和寬度都是像素數。需要注意的是上面公式中的54是位圖文件的文件頭,是彩色調色板的大小。另外需要注意的是這是一個近似值,對於n位的位圖圖像來說,儘管可能

有最多2n中顏色,一個特定的圖像可能並不會使用這些所有的顏色。由於彩色調色板僅僅定義了圖像所用的顏色,所以實際的彩色調色板將小於。如果想知道這些值是如何得到的

,請參考下面文件格式的部分。由於存儲算法本身決定的因素,根據幾個圖像參數的不同計算出的大小與實際的文件大小將會有一些細小的差別。

顯示所有種類bmp位圖的程序ShowDIB過程詳解

1.新建一個基於多文檔的項目ShowDIB,CShowDIBView類的基類是CscrollView類。
2.將事先寫好的DIBAPI.H和DIBAPI.CPP兩個文件增加到項目中。這兩個文件聲明和定義了DIB處理函數。
3.String Table中的字符串資源IDR_DISPLATYPE修改爲:(爲了能打開.bmp格式的文件)
\nDib\nDib\nDib Files (*.bmp; *.dib)\n.bmp\nShowDIB.Document\nShowDIB Document
/*本人理解爲修改打開時的文件類型,如建立的是一單文檔的話就把IIDR_MAINFRAME做以上修改×/
4.在ShowDIBDoc.h文件中增加如下語句:(此類中增加成員變量表示DIB數據塊內存句柄)
public:
HANDLE m_hDIB;
一定要在構造函數中對它初始化:m_hDIB=NULL;否則就讓你死都不知道怎麼死的
5.在ShowDIBDoc.h中增加如下語句:
public:
        virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
virtual BOOL OnSaveDocument(LPCTSTR lpszPathName);
在ShowDIBDoc.cpp中添加如下語句
#include "dibapi.h"
BOOL CShowDIBDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
   return FALSE;

m_hDIB = LoadDIB(lpszPathName);
if (m_hDIB == NULL)
{
   // may not be DIB format
   return FALSE;
}
SetPathName(lpszPathName);
SetModifiedFlag(FALSE);     // start off with unmodified

return TRUE;
}

BOOL CShowDIBDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
return SaveDIB(m_hDIB, lpszPathName);
}
以上語句的作用是重載了成員函數OnOpenDocument和OnSaveDocument,分別調用了我們定義的LoadDIB和SaveDIB來讀寫DIB文件,所以還要包含頭文件"dibapi.h"。
6.在ShowDIBView.h中添加:
public:
CRect m_rcDIB;即爲此類添加一個成員變量
將CShowDIBView類中的函數OnInitialUpdate()修改爲:
void CShowDIBView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();

CShowDIBDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

CSize sizeTotal;
if (pDoc->m_hDIB != NULL)
{
   LPBITMAPINFOHEADER lpDIB = (LPBITMAPINFOHEADER)GlobalLock(pDoc->m_hDIB);
   m_rcDIB.left = 0;
   m_rcDIB.top = 0;
   sizeTotal.cx = m_rcDIB.right = ((LPBITMAPINFOHEADER)lpDIB)->biWidth;
   sizeTotal.cy = m_rcDIB.bottom = ((LPBITMAPINFOHEADER)lpDIB)->biHeight;
   GlobalUnlock(pDoc->m_hDIB);
}
else
{
   m_rcDIB.SetRectEmpty();
   sizeTotal.cx = sizeTotal.cy = 100;
}

SetScrollSizes(MM_TEXT, sizeTotal);
}
裝入DIB文件時,OnInitialUpdate函數會首先調用
7.ShowDIBView.cpp文件中添加語句
#include "dibapi.h"
View類的OnDraw函數修改爲:
void CShowDIBView::OnDraw(CDC* pDC)
{
CShowDIBDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

if (pDoc->m_hDIB == NULL)
   return;

PaintDIB(pDC->GetSafeHdc(),
       m_rcDIB,
    pDoc->m_hDIB,
    m_rcDIB,
    NULL,
    SRCCOPY);
}

8.MainFrm.h中定義:“#define WM_REALIZEPAL     (WM_USER + 0x100)”。當系統調色板已被修改時,主框窗口將向視發送WM_REALIZEPAL消息。在CShowDIBView類
中增加響應該消息的函數OnRealizePal和相應的消息映射,代碼如下
LRESULT CShowDIBView::OnRealizePal(WPARAM wParam, LPARAM lParam)
{
ASSERT(wParam != NULL);
CShowDIBDoc* pDoc = GetDocument();

if (pDoc->m_hDIB == NULL)
   return 0L; // must be a new document

LPBYTE lpbi = (LPBYTE)GlobalLock(pDoc->m_hDIB);
CPalette* pPal = CPalette::FromHandle(CreateDIBPalette(lpbi));
GlobalUnlock(pDoc->m_hDIB);
if (pPal != NULL)
{
   CWnd* pAppFrame = AfxGetApp()->m_pMainWnd;

   CClientDC appDC(pAppFrame);
   // All views but one should be a background palette.
   // wParam contains a handle to the active view, so the SelectPalette
   // bForceBackground flag is FALSE only if wParam == m_hWnd (this view)
   CPalette* oldPalette = appDC.SelectPalette(pPal, ((HWND)wParam) != m_hWnd);

   if (oldPalette != NULL)
   {
    UINT nColorsChanged = appDC.RealizePalette();
    if (nColorsChanged > 0)
     GetDocument()->UpdateAllViews(NULL);
    appDC.SelectPalette(oldPalette, TRUE);
   }
   else
   {
    TRACE0("\tSelectPalette failed!\n");
   }
}

return 0L;
}
在 ShowDIBView.h添加如下代碼
protected:
   afx_msg LRESULT OnRealizePal(WPARAM wParam, LPARAM lParam);

當系統調色板被修改時,主框收到系統的WM_PALETECHANGED和WM_QUERYNEWPALETTE消息,主框窗口通過下面的函數將向視發送WM_REALIZEPAL消息,OnRealizePal函數響應

WM_REALIZEPAL消息。
9.添加響應WM_PALETECHANGED和WM_QUERYNEWPALETTE消息的函數,當系統察覺調色板發生變化時,會向程序的主框窗口發送這兩個消息,然後由主框窗口通知各視窗。
在MainFrm.cpp中添加如下代碼:
void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd)
{
CMDIFrameWnd::OnPaletteChanged(pFocusWnd);

// always realize the palette for the active view
CMDIChildWnd* pMDIChildWnd = MDIGetActive();
if (pMDIChildWnd == NULL)
   return; // no active MDI child frame
CView* pView = pMDIChildWnd->GetActiveView();
ASSERT(pView != NULL);

// notify all child windows that the palette has changed
SendMessageToDescendants(WM_REALIZEPAL, (WPARAM)pView->m_hWnd);
}

BOOL CMainFrame::OnQueryNewPalette()
{
// always realize the palette for the active view
CMDIChildWnd* pMDIChildWnd = MDIGetActive();
if (pMDIChildWnd == NULL)
   return FALSE; // no active MDI child frame (no new palette)
CView* pView = pMDIChildWnd->GetActiveView();
ASSERT(pView != NULL);

// just notify the target view
pView->SendMessage(WM_REALIZEPAL, (WPARAM)pView->m_hWnd);
return TRUE;
}
在MainFrm.h中添加如下代碼
protected:
afx_msg void OnPaletteChanged(CWnd* pFocusWnd);
afx_msg BOOL OnQueryNewPalette();

打開三種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文件則還要加上位圖文件頭。

其次,Win32中提供了一個新函數CreateDIBSection,通過它可以創建一個存儲DIB位的內存區域,既可以執行相應的GDI操作,又可以直接通過指向DIB位區域的指針方位DIB位區域

。這是一個非常有用的函數,通過它我們可以用DIB替代DDB。

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

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

在BitmapFile.h文件中定義類CBitmapFile,首先必須聲明類CBitmapFile是從類CGdiObject中公有派生。然後在類中首先使用宏DECLARE_DYNAMIC(CBitmapFile)表明新類的最高父

類是類CObject,是符合MFC的類庫規範。緊接着宏 DECLARE_DYNAMIC的是聲明靜態函數FromHandle,這兩個聲明必須放在類定義的最前面。
在BitmapFile.cpp文件中類的成員函數的實現前加上IMPLEMENT_DYNAMIC(CBitmapFile,CGdiObject);表明類CBitmapFile直接派生於類CGdiObject。
在類CBitmapFile的聲明中有三個函數與類Cbitmap中的定義稍有不同:

在類CbitmapFile中LoadBitmap函數的參數是LPCTSTR型,保存的是BMP文件的文件名。
在類CbitmapFile中CreateBitmap函數的參數中少了參數nPlanes,在函數內部默認爲1。
在類CbitmapFile中CreateBitmapIndirect函數的參數中多了參數lpBits,它指向指定位圖DIB位的內存區域。
在成員函數中最重要的是函數CreateBitmapIndirect和函數LoadBitmap:

在函數CreateBitmapIndirect中使用函數CreateDIBSection創建了一個以兼容DC爲基礎的HBITMAP句柄,並用繼承自類CGdiObject 的函數Attach把它與類CGdiObject的句柄

m_hObject關聯起來。然後將指定位圖的DIB位圖數據拷貝到由函數 CreateDIBSection創建的DIB位的內存區域。
在函數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編寫中的一些要點和使用時一些要注意的問題就介紹這麼多了。

附源文件

//

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

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

// 文件名: BitmapFile.h

// 時間: 1999-2-11

// 作者: 賈暾

//

#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

// 時間: 1999-2-11

// 作者: 賈暾

//

#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();

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章