在VC5中顯示256色位圖
發表時間:2024-02-21 來源:明輝站整理相關軟件相關文章人氣:
[摘要]李欣 周學泳 ---- 在Windows的編程中,彩色圖像的顯示和處理一直是一個重要的課題,即使是在顯卡普遍支持真彩的今天,討論256色位圖的顯示也是有意義的。通過對這一課題的討論,可以了解如何在VC5中實現裝入圖像,創建和使用調色板,以及最后將圖像畫出來。 ---- 總的來說,要顯示一幅256色...
李欣 周學泳
---- 在Windows的編程中,彩色圖像的顯示和處理一直是一個重要的課題,即使是在顯卡普遍支持真彩的今天,討論256色位圖的顯示也是有意義的。通過對這一課題的討論,可以了解如何在VC5中實現裝入圖像,創建和使用調色板,以及最后將圖像畫出來。
---- 總的來說,要顯示一幅256色的位圖,首先應得到該圖的有關信息,通過位圖的顏色表創建一個邏輯調色板,然后將這個調色板選入設備環境,實現這個調色板,最后將位圖用BitBlt函數拷貝到設備環境就可以了。
---- 具體實現步驟如下:
---- 1、裝載位圖并創建調色板。
---- 首先裝入一幅位圖,該位圖既可以以資源的形式與程序綁在一起,也可以以文件的形式從外部裝入。然后將該位圖與一個Cbitmap對象聯系(Attach)起來。在這兒我們應使用API函數LoadImage(),而不是CBitmap類的成員函數CBitmap::LoadBitmap(),因為我們需要得到該位圖的DIBSECTION結構,從這個結構中我們可以得到該位圖的色彩信息,從而建立一個與這些色彩相匹配的邏輯調色板。使用CBitmap::LoadBitmap()將會失去我們所需的位圖的色彩信息。
---- 得到位圖后,下一步工作就是取得該位圖的色彩信息。通過CBitmap:GetObject()函數,我們可以訪問DIBSECTION結構,從中得到位圖的色彩數。一般來說,這些信息存在于BITMAPINFOHEAD結構中,不過,作為DIBSECTION結構的一部分,BITMAPINFOHEAD有時并未說明圖像用了多少種顏色;碰到這種情況,我們可以看看圖像的每一象素用了幾位(Bit)來描述顏色,如果是8位的話,因為8位二進制數可以表示256種不同的值,所以該圖像是256色的;同理,16Bit表明是64K色。得到了位圖所用的顏色數,就可以創建邏輯調色板了。色彩超過256色的位圖是沒有顏色表(Color Table)的,這時我們只用簡單地創建一個和設備環境兼容的半色調調色板(Halftone Palette)就行了,在半色調調色板中包含著所有不同顏色的樣本。這顯然不是最佳解決方案,但卻是最簡單的。
---- 而對于顏色數小于或等于256的位圖,我們就要從頭建立一個新的調色板。先分配足夠的內存空間來裝入圖像的顏色表,顏色表可以利用API函數GetDIBColorTable獲得;然后再分配足夠的內存給新建的邏輯調色板,將剛才得到的顏色表信息相應拷入新建調色板中的palPalEntry域,并將PalVersion域設為0X300。創建了調色板后,應將窗口刷新重畫。在具體的實現上,我們定義了一個函數GetBitmapandPalette()來實現位圖資源的裝入和邏輯調色板的創建,其功能實現框圖如下(略)
---- 函數具體實現如下:
BOOL GetBitmapandPalette(LPCTSTR lpszresource,
CBitmap &bitmap, CPalette &pal,long *w,long *h)
{
LPCTSTR lpszresourcename = (LPCTSTR)lpszresource;
HBITMAP hbmp = (HBITMAP)::LoadImage( AfxGetInstanceHandle(),
lpszresourcename,IMAGE_BITMAP,0,0,
LR_LOADFROMFILE); //裝入位圖
if( hbmp == NULL )
return FALSE;
bitmap.Attach( hbmp );
// 將該位圖與一個CBitmap對象聯系起來
DIBSECTION ds;
BITMAPINFOHEADER &bminfo = ds.dsBmih;
bitmap.GetObject( sizeof(ds), &ds );
// 得到位圖顏色數
int ncolors = bminfo.biClrUsed ?
bminfo.biClrUsed : 1 << bminfo.biBitCount; *w="bminfo.biWidth;" //得到位圖寬度值 *h="bminfo.biHeight;" //得到位圖高度值 CClientDC dc(NULL); // 創建邏輯調色板 if( ncolors> 256 )
pal.CreateHalftonePalette( &dc );
else
{
// 顏色數 <= 256 RGBQUAD *prgb="new" RGBQUAD[ncolors]; CDC memdc; memdc.CreateCompatibleDC(&dc); memdc.SelectObject( &bitmap ); ::GetDIBColorTable( memdc, 0, ncolors, prgb ); UINT nsize="sizeof(LOGPALETTE)" + (sizeof(PALETTEENTRY) * ncolors); LOGPALETTE *plp="(LOGPALETTE" *) new byte[nsize]; plp->palVersion = 0x300;
plp- >palNumEntries = ncolors;
for( int i=0; ipalPalEntry[i].peRed = prgb[i].rgbRed;
plp- >palPalEntry[i].peGreen = prgb[i].rgbGreen;
plp- >palPalEntry[i].peBlue = prgb[i].rgbBlue;
plp- >palPalEntry[i].peFlags = 0;
}
pal.CreatePalette( plp );
delete[] plp;
delete[] prgb;
}
return TRUE;
}
2.顯示位圖
在WM_PAINT消息的響應函數OnPaint()中實現。
void OnPaint()
{
CPaintDC dc(this); // device context for painting
// create a memory dc compatible with the paint dc
CDC memdc;
memdc.CreateCompatibleDC( &dc );
CBitmap bitmap;
CPalette palette;
long nWidth;
long nHeight;
//調用該函數
GetBitmapandPalette("e:\\project\\
showimage\\bitmap1.bmp",bitmap,palette ,
&nWidth,&nHeight);
memdc.SelectObject( &bitmap );
// select and realize the palette
if( dc.GetDeviceCaps(RASTERCAPS) &
RC_PALETTE && palette.m_hObject != NULL )
{
dc.SelectPalette( &palette, FALSE );
dc.RealizePalette();
}
//顯示位圖
dc.BitBlt(0, 0, nWidth,nHeight, &memdc, 0, 0,SRCCOPY);
}
---- 以上程序只是簡單的從一個固定路徑(e:\\project\\showimage\\bitmap1.bmp)裝入位圖,讀者可以將其功能擴充,如通過對話框選取等等,在此不多贅述。
---- 最后還要補充的一點是,如果要顯示的位圖是作為位圖資源與程序聯系在一起的,對以上程序稍作修改即可顯示出來,修改方法如下:
首先將GetBitmapandPalette()函數改為:
BOOL GetBitmapandPalette(UINT nidresource,
CBitmap &bitmap, CPalette &pal,long *w,long *h)
其中nidresource是該位圖的ID。
然后將GetBitmapandPalette()中的第一句改為:
LPCTSTR lpszresourcename = (LPCTSTR)nidresource;
并將LoadImage函數改為:
HBITMAP hbmp = (HBITMAP)::LoadImage( AfxGetInstanceHandle(),
nidresourcename,IMAGE_BITMAP,0,0,
LR_CREATEDIBSECTION);
最后,在OnPaint函數中調用GetBitmapandPalette()時,
將位圖的ID
通過nidresource傳入即可