?? cdib.cpp
字號:
*
* \說明:
* 如果顏色表存在的話,該函數將讀取它,并創建一個Windows調色板。
* HPALETTE存儲在一個數據成員中。
*
************************************************************************
*/
BOOL CDib::MakePalette()
{
// 如果不存在調色板,則返回FALSE
if(m_nColorTableEntries == 0) return FALSE;
if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
TRACE("CDib::MakePalette -- m_nColorTableEntries = %d\n", m_nColorTableEntries);
// 給邏輯調色板分配內存
LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) +
m_nColorTableEntries * sizeof(PALETTEENTRY)];
// 設置邏輯調色板的信息
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = m_nColorTableEntries;
// 拷貝DIB中的顏色表到邏輯調色板
LPRGBQUAD pDibQuad = (LPRGBQUAD) m_lpvColorTable;
for(int i = 0; i < m_nColorTableEntries; i++) {
pLogPal->palPalEntry[i].peRed = pDibQuad->rgbRed;
pLogPal->palPalEntry[i].peGreen = pDibQuad->rgbGreen;
pLogPal->palPalEntry[i].peBlue = pDibQuad->rgbBlue;
pLogPal->palPalEntry[i].peFlags = 0;
pDibQuad++;
}
// 創建邏輯調色板
m_hPalette = ::CreatePalette(pLogPal);
// 刪除臨時變量并返回TRUE
delete pLogPal;
return TRUE;
}
/*************************************************************************
*
* \函數名稱:
* SetSystemPalette()
*
* \輸入參數:
* CDC* pDC - 設備上下文指針
*
* \返回值:
* BOOL - 如果成功,則為TRUE,
*
* \說明:
* 如果16bpp、24bpp或32bppDIB不具備調色板,則該函數可以為CDib對象創建一個邏輯調色板,
* 它與由CreatehalftonePalette函數返回的調色板相匹配。如果程序在256色調色板顯示器上
* 運行,而你又沒有調用SetSystemPalette,那么,你將不具有任何調色板,只有20中標準的
* Windows顏色出現在DIB中
*
************************************************************************
*/
BOOL CDib::SetSystemPalette(CDC* pDC)
{
// 如果DIB不具備調色板,則需要利用系統的調色板
if(m_nColorTableEntries != 0) return FALSE;
// 為設備上下文創建中間調色板,并將其與CPalette對象連接
m_hPalette = ::CreateHalftonePalette(pDC->GetSafeHdc());
// 返回
return TRUE;
}
/*************************************************************************
*
* \函數名稱:
* CreateBitmap()
*
* \輸入參數:
* CDC* pDC - 設備上下文指針
*
* \返回值:
* HBITMAP - 到GDI位圖的句柄;如果不成功,則為NULL
* - 該句柄不是作為公共數據成員存儲的
*
* \說明:
* 從已有的DIB中創建DDB位圖。不要將這個函數與CreateSection
* 弄混了,后者的作用是生成DIB并保存句柄
*
************************************************************************
*/
HBITMAP CDib::CreateBitmap(CDC* pDC)
{
// 如果不存在圖象數據,則返回NULL
if (m_dwSizeImage == 0) return NULL;
// 用指定的DIB來創建DDB,并用DIB信息初始化位圖的圖象位
HBITMAP hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(), m_lpBMIH,
CBM_INIT, m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS);
ASSERT(hBitmap != NULL);
// 返回DDB位圖句柄
return hBitmap;
}
/*************************************************************************
*
* \函數名稱:
* ConvertDDBToDIB()
*
* \輸入參數:
* HBITMAP hBitmap - 指向源數據的BITMAP句柄
* CDib* pDibDst - 指向轉換目標的CDib對象指針
*
* \返回值:
* BOOL - 如果操作成功,則返回TRUE
*
* \說明:
* 該函數將源BITMAP類pDibSrc中的數據拷貝到pDibDst中,并對相應的數據成員賦值
*
*************************************************************************
*/
BOOL CDib::ConvertFromDDB(HBITMAP hBitmap, HPALETTE hPal)
{
// 聲明一個BITMAP結構
BITMAP bm;
// 設備上下文
HDC hDC;
// 象素位數
WORD biBitCount;
// 調色板表項數
int nColorTableEntries;
// 如果hBitmap句柄無效,則返回
if(!hBitmap){
return FALSE;
}
// 釋放已分配的內存
Empty();
// 填充圖象數據到bm中,其中最后一個參數表示接收這個指定的對象的指針
if(!GetObject(hBitmap,sizeof(BITMAP),(LPBYTE)&bm)){
return FALSE;
}
// 計算象素位數
biBitCount=bm.bmPlanes*bm.bmBitsPixel;
if(biBitCount<=1)
biBitCount=1;
else if(biBitCount<=4)
biBitCount=4;
else if(biBitCount<=8)
biBitCount=8;
else
biBitCount=24;
// 計算調色板的尺寸
// 如果biClrUsed為零,則用到的顏色數為2的biBitCount次方
switch(biBitCount) {
case 1:
nColorTableEntries = 2;
break;
case 4:
nColorTableEntries = 16;
break;
case 8:
nColorTableEntries = 256;
break;
case 16:
case 24:
case 32:
nColorTableEntries = 0;
break;
default:
ASSERT(FALSE);
}
ASSERT((nColorTableEntries >= 0) && (nColorTableEntries <= 256));
m_nColorTableEntries = nColorTableEntries;
// 分配DIB信息頭和調色板的內存
m_lpBMIH = (LPBITMAPINFOHEADER) new char
[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries];
m_nBmihAlloc = m_nImageAlloc = crtAlloc;
m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER);
m_lpBMIH->biWidth = bm.bmWidth;
m_lpBMIH->biHeight = bm.bmHeight;
m_lpBMIH->biPlanes = 1;
m_lpBMIH->biBitCount = biBitCount;
m_lpBMIH->biCompression = BI_RGB;
m_lpBMIH->biSizeImage = 0;
m_lpBMIH->biXPelsPerMeter = 0;
m_lpBMIH->biYPelsPerMeter = 0;
m_lpBMIH->biClrUsed = nColorTableEntries;
m_lpBMIH->biClrImportant = nColorTableEntries;
// 獲得設備上下文句柄
hDC=GetDC(NULL);
// 如果沒有指定調色板,則從系統中獲得當前的系統調色板
if(hPal==NULL){
hPal = GetSystemPalette();
}
hPal = SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);
// 調用GetDIBits填充信息頭,并獲得圖象數據的尺寸。注意這里圖象數據指針為NULL
GetDIBits( hDC, hBitmap, 0, (UINT)m_lpBMIH->biHeight, NULL, (LPBITMAPINFO)m_lpBMIH, DIB_RGB_COLORS);
// 如果沒有正確的獲得圖象數據尺寸,則重新計算
if( m_lpBMIH->biSizeImage == 0 ){
m_lpBMIH->biSizeImage=(((bm.bmWidth*biBitCount) + 31) / 32 * 4)*bm.bmHeight;
}
// 分配存放圖象數據的內存
m_lpImage = (LPBYTE) new char[m_lpBMIH->biSizeImage];
// 調用GetDIBits加載圖象數據,注意這里給出了圖象數據指針
// 如果加載圖象數據不成功,則釋放已經分配的內存,并返回FALSE
if( GetDIBits( hDC, hBitmap, 0, (UINT)m_lpBMIH->biHeight, (LPBYTE)m_lpImage,
(LPBITMAPINFO)m_lpBMIH, DIB_RGB_COLORS) == 0 ){
//clean up and return NULL
Empty();
SelectPalette( hDC, hPal, TRUE );
RealizePalette( hDC );
ReleaseDC( NULL, hDC );
return FALSE;
}
// 刪除臨時變量
SelectPalette(hDC, hPal, TRUE);
RealizePalette(hDC);
ReleaseDC(NULL, hDC);
return TRUE;
}
/*************************************************************************
*
* \函數名稱:
* Compress()
*
* \輸入參數:
* CDC* pDC - 設備上下文指針
* BOOL bCompress - TRUE對應于壓縮的DIB,FALSE對應于不壓縮的DIB
*
* \返回值:
* BOOL - 如果成功,則返回TRUE
*
* \說明:
* 該函數將DIB重新生成為壓縮或者不壓縮的DIB。在內部,它轉換已有的DIB為DDB位圖
* 然后生成一個新的壓縮或者不壓縮的DIB。壓縮僅為4bpp和8bpp的DIB所支持。不能
* 壓縮DIB段
*
************************************************************************
*/
BOOL CDib::Compress(CDC* pDC, BOOL bCompress /* = TRUE */)
{
// 判斷是否為4bpp或者8bpp位圖,否則,不進行壓縮,返回FALSE
if((m_lpBMIH->biBitCount != 4) && (m_lpBMIH->biBitCount != 8)) return FALSE;
// 如果為DIB段,也不能支持壓縮,返回FALSE
if(m_hBitmap) return FALSE;
TRACE("Compress: original palette size = %d\n", m_nColorTableEntries);
// 獲得設備上下文句柄
HDC hdc = pDC->GetSafeHdc();
// 將此DIB的調色板選入設備上下文,并保存以前的調色板句柄
HPALETTE hOldPalette = ::SelectPalette(hdc, m_hPalette, FALSE);
HBITMAP hBitmap;
// 創建一個DDB位圖,如果不成功,則返回FALSE
if((hBitmap = CreateBitmap(pDC)) == NULL) return FALSE;
// 計算信息頭加上調色板的大小尺寸,并給它們分配內存
int nSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) new char[nSize];
// 將信息頭和調色板拷貝到內存中
memcpy(lpBMIH, m_lpBMIH, nSize); // new header
// 如果需要進行壓縮,設置相應的信息,并創建壓縮格式的DIB
if(bCompress) {
switch (lpBMIH->biBitCount) {
case 4:
lpBMIH->biCompression = BI_RLE4;
break;
case 8:
lpBMIH->biCompression = BI_RLE8;
break;
default:
ASSERT(FALSE);
}
// 設置位圖數據指針為NULL,調用GetDIBits來得到壓縮格式的DIB的尺寸
// 如果不能創建DIB,則進行相應的錯誤處理。
if(!::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0, (UINT) lpBMIH->biHeight,
NULL, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS)) {
AfxMessageBox("Unable to compress this DIB");
// 刪除臨時變量,并釋放已分配內存
::DeleteObject(hBitmap);
delete [] lpBMIH;
// 重新將以前的調色板選入,并返回FALSE
::SelectPalette(hdc, hOldPalette, FALSE);
return FALSE;
}
// 如果位圖數據為空,則進行相應的錯誤處理
if (lpBMIH->biSizeImage == 0) {
AfxMessageBox("Driver can't do compression");
// 刪除臨時變量,并釋放已分配內存
::DeleteObject(hBitmap);
delete [] lpBMIH;
// 重新將以前的調色板選入,并返回FALSE
::SelectPalette(hdc, hOldPalette, FALSE);
return FALSE;
}
// 將位圖數據尺寸賦值給類的成員變量
else {
m_dwSizeImage = lpBMIH->biSizeImage;
}
}
// 如果是解壓縮,進行相應的處理
else {
// 設置壓縮格式為不壓縮
lpBMIH->biCompression = BI_RGB;
// 根據位圖的寬度和高度計算位圖數據內存的大小
DWORD dwBytes = ((DWORD) lpBMIH->biWidth * lpBMIH->biBitCount) / 32;
if(((DWORD) lpBMIH->biWidth * lpBMIH->biBitCount) % 32) {
dwBytes++;
}
dwBytes *= 4;
// 將得到位圖數據的大小尺寸保存在類的成員變量中
m_dwSizeImage = dwBytes * lpBMIH->biHeight;
// 將位圖數據內存的大小賦值給臨時的信息頭中的相應的變量
lpBMIH->biSizeImage = m_dwSizeImage;
}
// 再次調用GetDIBits來生成DIB數據
// 分配臨時存放位圖數據
LPBYTE lpImage = (LPBYTE) new char[m_dwSizeImage];
// 再次調用GetDIBits來生成DIB數據,注意此時位圖數據指針不為空
VERIFY(::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0, (UINT) lpBMIH->biHeight,
lpImage, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS));
TRACE("dib successfully created - height = %d\n", lpBMIH->biHeight);
// 壓縮轉換完畢,進行相應的其他處理
// 刪除臨時的DDB位圖
::DeleteObject(hBitmap);
// 釋放原來的DIB分配的內存
Empty();
// 重新設置圖象信息頭和圖象數據內存分配狀態
m_nBmihAlloc = m_nImageAlloc = crtAlloc;
// 重新定位信息頭和圖象數據指針
m_lpBMIH = lpBMIH;
m_lpImage = lpImage;
// 計算圖象數據尺寸,并設置DIB中調色板的指針
ComputeMetrics();
// 計算DIB中調色板的尺寸
ComputePaletteSize(m_lpBMIH->biBitCount);
// 如果DIB中調色板存在的話,讀取并創建一個Windows調色板
MakePalette();
// 恢復以前的調色板
::SelectPalette(hdc, hOldPalette, FALSE);
TRACE("Compress: new palette size = %d\n", m_nColorTableEntries);
// 返回
return TRUE;
}
/*************************************************************************
*
* \函數名稱:
* Read()
*
* \輸入參數:
* CFile* pFile - 指向CFile對象的指針
*
* \返回值:
* BOOL - 如果成功,則返回TRUE
*
* \說明:
* 該函數DIB從一個文件讀入CDib對象。該文件必須成功打開。如果該文件是BMP文件
* 讀取工作從文件頭開始。如果該文件是一個文檔,讀取工作則從當前文件指針處開始
*
************************************************************************
*/
BOOL CDib::Read(CFile* pFile)
{
// 釋放已經分配的內存
Empty();
// 臨時存放信息的變量
int nCount, nSize;
BITMAPFILEHEADER bmfh;
// 進行讀操作
try
{
// 讀取文件頭
nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
if(nCount != sizeof(BITMAPFILEHEADER)) {
throw new CException;
}
// 如果文件類型部位"BM",則返回并進行相應錯誤處理
if(bmfh.bfType != 0x4d42) {
throw new CException;
}
// 計算信息頭加上調色板的大小,并分配相應的內存
nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize];
m_nBmihAlloc = m_nImageAlloc = crtAlloc;
// 讀取信息頭和調色板
nCount = pFile->Read(m_lpBMIH, nSize);
// 計算圖象數據大小并設置調色板指針
ComputeMetrics();
// 計算調色板的表項數
ComputePaletteSize(m_lpBMIH->biBitCount);
// 如果DIB中存在調色板,則創建一個Windows調色板
MakePalette();
// 分配圖象數據內存,并從文件中讀取圖象數據
m_lpImage = (LPBYTE) new char[m_dwSizeImage];
nCount = pFile->Read(m_lpImage, m_dwSizeImage);
}
// 錯誤處理
catch(CException* pe)
{
AfxMessageBox("Read error");
pe->Delete();
return FALSE;
}
// 返回
return TRUE;
}
/*************************************************************************
*
* \函數名稱:
* ReadSection()
*
* \輸入參數:
* CFile* pFile - 指向CFile對象的指針;對應的磁盤
* - 文件中包含DIB
* CDC* pDC - 設備上下文指針
*
* \返回值:
* BOOL - 如果成功,則返回TRUE
*
* \說明:
* 該函數從BMP文件中讀取信息頭,調用CreateDIBSection來分配圖象內存,然后將
* 圖象從該文件讀入剛才分配的內存。如果你想從磁盤讀取一個DIB,然后通過調用
* GDI函數編輯它的話,可以使用該函數。你可以用Write或CopyToMapFile將DIB寫
* 回到磁盤
*
************************************************************************
*/
BOOL CDib::ReadSection(CFile* pFile, CDC* pDC /* = NULL */)
{
// 釋放已經分配的內存
Empty();
// 臨時變量
int nCount, nSize;
BITMAPFILEHEADER bmfh;
// 從文件中讀取數據
try {
// 讀取文件頭
nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
if(nCount != sizeof(BITMAPFILEHEADER)) {
throw new CException;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -