?? cdib.cpp
字號:
// cdib.cpp
#include "stdafx.h"
#include "math.h"
#include "process.h"
#include "cdib.h"
#include "GlobalApi.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// 聲明串行化過程
IMPLEMENT_SERIAL(CDib, CObject, 0);
/*************************************************************************
*
* \函數名稱:
* CDib()
*
* \輸入參數:
* 無
*
* \返回值:
* 無
*
* \說明:
* 構造函數
*
************************************************************************
*/
CDib::CDib()
{
m_hFile = NULL;
m_hBitmap = NULL;
m_hPalette = NULL;
m_nBmihAlloc = m_nImageAlloc = noAlloc;
Empty();
}
/*************************************************************************
*
* \函數名稱:
* CDib()
*
* \輸入參數:
* CSize size - 位圖尺寸
* int nBitCount - 象素位數
*
* \返回值:
* 無
*
* \說明:
* 構造函數
* 根據給定的位圖尺寸和象素位數構造CDib對象,并對信息頭和調色板分配內存
* 但并沒有給位圖數據分配內存
*
************************************************************************
*/
CDib::CDib(CSize size, int nBitCount)
{
m_hFile = NULL;
m_hBitmap = NULL;
m_hPalette = NULL;
m_nBmihAlloc = m_nImageAlloc = noAlloc;
Empty();
// 根據象素位數計算調色板尺寸
ComputePaletteSize(nBitCount);
// 分配DIB信息頭和調色板的內存
m_lpBMIH = (LPBITMAPINFOHEADER) new
char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries];
// 設置信息頭內存分配狀態
m_nBmihAlloc = crtAlloc;
// 設置信息頭中的信息
m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER);
m_lpBMIH->biWidth = size.cx;
m_lpBMIH->biHeight = size.cy;
m_lpBMIH->biPlanes = 1;
m_lpBMIH->biBitCount = nBitCount;
m_lpBMIH->biCompression = BI_RGB;
m_lpBMIH->biSizeImage = 0;
m_lpBMIH->biXPelsPerMeter = 0;
m_lpBMIH->biYPelsPerMeter = 0;
m_lpBMIH->biClrUsed = m_nColorTableEntries;
m_lpBMIH->biClrImportant= m_nColorTableEntries;
// 計算圖象數據內存的大小,并設置此DIB的調色板的指針
ComputeMetrics();
// 將此DIB的調色板初始化為0
memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorTableEntries);
// 暫時不分配圖象數據內存
m_lpImage = NULL;
}
/*************************************************************************
*
* \函數名稱:
* ~CDib()
*
* \輸入參數:
* 無
*
* \返回值:
* 無
*
* \說明:
* 析構函數,并釋放所有分配的DIB內存
*
************************************************************************
*/
CDib::~CDib()
{
Empty();
}
/*************************************************************************
*
* \函數名稱:
* GetDimensions()
*
* \輸入參數:
* 無
*
* \返回值:
* CSize - DIB的寬度和高度
*
* \說明:
* 返回以象素表示的DIB的寬度和高度
*
************************************************************************
*/
CSize CDib::GetDimensions()
{
if(m_lpBMIH == NULL) return CSize(0, 0);
return CSize((int) m_lpBMIH->biWidth, (int) m_lpBMIH->biHeight);
}
/*************************************************************************
*
* \函數名稱:
* AttachMapFile()
*
* \輸入參數:
* const char* strPathname - 映射文件的路徑名
* BOOL bShare - 如果文件以共享形式打開,設置為TRUE
* - 默認值為FALSE
*
* \返回值:
* BOOL - 如果成功,則為TRUE
*
* \說明:
* 以讀模式打開內存映射文件,并將其與CDib對象進行關聯。因為在文件使用之前并沒有讀入內存,
* 所以它立即返回。不過,當訪問這個DIB的時候,可能會有一些延遲,因為文件是分頁的。
* DetachMapFile函數可以釋放現有的已分配的內存,并關閉以前關聯的任何內存映射文件。
* 用內存中的DIB與已有的CDib對象關聯。此內存可能是程序的資源,或者是可能是剪貼板
* 或者OLE數據對象內存。內存可能已經由CRT堆棧用new運算符分配了,或者可能已經由
* Windows堆棧用GlobalAlloc分配了。
* 如果打開相同的文件兩次,則Windows以另一個文件來對待
*
************************************************************************
*/
BOOL CDib::AttachMapFile(const char* strPathname, BOOL bShare) // for reading
{
// 獲取文件句柄,并設置打開模式為共享
HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ,
bShare ? FILE_SHARE_READ : 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
ASSERT(hFile != INVALID_HANDLE_VALUE);
// 獲取文件的尺寸
DWORD dwFileSize = ::GetFileSize(hFile, NULL);
// 創建文件映射對象,并設置文件映射的模式為讀寫
HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
DWORD dwErr = ::GetLastError();
if(hMap == NULL) {
AfxMessageBox("Empty bitmap file");
return FALSE;
}
// 映射整個文件,注意FILE_MAP_WRITE為讀寫模式
LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); // map whole file
ASSERT(lpvFile != NULL);
// 確認為bmp格式文件
if(((LPBITMAPFILEHEADER) lpvFile)->bfType != 0x4d42) {
AfxMessageBox("Invalid bitmap file");
DetachMapFile();
return FALSE;
}
// 將內存中的DIB與已有的CDib對象關聯
AttachMemory((LPBYTE) lpvFile + sizeof(BITMAPFILEHEADER));
// 將這些有用的句柄設置為類數據成員
m_lpvFile = lpvFile;
m_hFile = hFile;
m_hMap = hMap;
// 返回
return TRUE;
}
/*************************************************************************
*
* \函數名稱:
* CopyToMapFile()
*
* \輸入參數:
* const char* strPathname - 映射文件的路徑名
*
* \返回值:
* BOOL - 如果成功,則為TRUE
*
* \說明:
* 該函數可以創建一個新的內存映射文件,并將現有的CDib數據復制到該文件的內存
* 釋放以前的所有內存。并關閉現有的所有內存映射文件。實際上,直到新文件
* 關閉的時候,才將這個數據寫到磁盤,但是,當CDib對象被重復使用或被破壞
* 時,也會發生寫磁盤操作
*
************************************************************************
*/
BOOL CDib::CopyToMapFile(const char* strPathname)
{
BITMAPFILEHEADER bmfh;
// 設置文件頭信息
bmfh.bfType = 0x4d42;
bmfh.bfSize = m_dwSizeImage + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries + sizeof(BITMAPFILEHEADER);
bmfh.bfReserved1= bmfh.bfReserved2 = 0;
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries;
// 創建接收數據的文件
HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
ASSERT(hFile != INVALID_HANDLE_VALUE);
// 計算文件的大小尺寸
int nSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries + m_dwSizeImage;
// 創建內存映射文件對象
HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, nSize, NULL);
DWORD dwErr = ::GetLastError();
ASSERT(hMap != NULL);
// 映射整個文件
LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
ASSERT(lpvFile != NULL);
// 臨時文件指針
LPBYTE lpbCurrent = (LPBYTE) lpvFile;
// 拷貝文件頭信息到內存映射文件中
memcpy(lpbCurrent, &bmfh, sizeof(BITMAPFILEHEADER));
// 計算信息頭在文件中的地址,并拷貝信息頭信息
lpbCurrent += sizeof(BITMAPFILEHEADER);
LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) lpbCurrent;
memcpy(lpbCurrent, m_lpBMIH,
sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries);
// 計算調色板在文件中的地址,并拷貝調色板
lpbCurrent += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
memcpy(lpbCurrent, m_lpImage, m_dwSizeImage);
// 暫時存放圖象數據尺寸變量
DWORD dwSizeImage = m_dwSizeImage;
// 釋放一起分配的所有內存
Empty();
// 設置圖象數據尺寸并設置內存分配狀態
m_dwSizeImage = dwSizeImage;
m_nBmihAlloc = m_nImageAlloc = noAlloc;
// 信息頭指針重新指向文件中的位置
m_lpBMIH = lpBMIH;
// 圖象數據指針重新指向文件中的數據地址
m_lpImage = lpbCurrent;
// 設置文件句柄
m_hFile = hFile;
// 設置映射對象句柄
m_hMap = hMap;
// 設置映射文件指針
m_lpvFile = lpvFile;
// 重新計算得到調色板尺寸
ComputePaletteSize(m_lpBMIH->biBitCount);
// 重新計算圖象數據塊大小,并設置調色板指針
ComputeMetrics();
// 如果調色板存在的話,讀取并創建一個Windows調色板
MakePalette();
// 返回
return TRUE;
}
/*************************************************************************
*
* \函數名稱:
* AttachMemory()
*
* \輸入參數:
* LPVOID lpvMem - 要關聯的內存地址
* BOOL bMustDelete - 如果CDib類負責刪除這個內存,標記為TRUE
* - 默認值為FALSE
* HGLOBAL hGlobal - 如果內存是通過Win32 GlobalAlloc得到的,
* - 則CDib對象必須保存該句柄,這樣,以后
* - 可以釋放句柄。這里假設bMustDelete設置為TRUE
*
* \返回值:
* BOOL - 如果成功,則為TRUE
*
* \說明:
* 用內存中的DIB與已有的CDib對象關聯。此內存可能是程序的資源,或者是可能是剪貼板
* 或者OLE數據對象內存。內存可能已經由CRT堆棧用new運算符分配了,或者可能已經由
* Windows堆棧用GlobalAlloc分配了。
*
************************************************************************
*/
BOOL CDib::AttachMemory(LPVOID lpvMem, BOOL bMustDelete, HGLOBAL hGlobal)
{
// 首先釋放已經分配的內存
Empty();
m_hGlobal = hGlobal;
// bMustDelete為TRUE表示此CDib類分配的內存,負責刪除
// 否則的設置信息頭分配狀態為noAlloc
if(bMustDelete == FALSE) {
m_nBmihAlloc = noAlloc;
}
else {
m_nBmihAlloc = ((hGlobal == NULL) ? crtAlloc : heapAlloc);
}
try {
// 設置信息頭指針
m_lpBMIH = (LPBITMAPINFOHEADER) lpvMem;
// 重新計算得到圖象數據塊的大小,并設置調色板的指針
ComputeMetrics();
// 計算調色板的尺寸
ComputePaletteSize(m_lpBMIH->biBitCount);
// 設置圖象數據指針
m_lpImage = (LPBYTE) m_lpvColorTable + sizeof(RGBQUAD) * m_nColorTableEntries;
// 如果調色板存在的話,讀取它,并創建一個Windows調色板,
// 并將調色板的句柄存放在數據成員中
MakePalette();
}
// 錯誤處理
catch(CException* pe) {
AfxMessageBox("AttachMemory error");
pe->Delete();
return FALSE;
}
// 返回
return TRUE;
}
/*************************************************************************
*
* \函數名稱:
* UsePalette()
*
* \輸入參數:
* CDC* pDC - 要實現調色板的設備上下文指針
* BOOL bBackground - 如果標記為FALSE(默認值),并且應用
* - 程序正在前臺運行,則Windows將把該調
* - 色板作為前臺調色板來實現(向系統調色
* - 板中復制盡可能多的顏色)。如果標記為
* - TURE,則Windows將把該調色板作為后臺
* - 調色板來實現(盡可能相系統調色板映射
* - 邏輯調色板)
*
* \返回值:
* UINT - 如果成功,則返回映射到系統調色板的邏
* - 輯調色板的表項數,否則返回GDI_ERROR
*
* \說明:
* 該函數將CDib對象的邏輯調色板選入設備上下文,然后實現該調色板。Draw成員函
* 數在繪制DIB之前調用UsePalette。
*
************************************************************************
*/
UINT CDib::UsePalette(CDC* pDC, BOOL bBackground /* = FALSE */)
{
// 判斷是否存在調色板
if(m_hPalette == NULL) return 0;
// 得到設備上下文句柄
HDC hdc = pDC->GetSafeHdc();
// 選擇調色板到設備上下文
::SelectPalette(hdc, m_hPalette, bBackground);
// 實現該調色板
return ::RealizePalette(hdc);
}
/*************************************************************************
*
* \函數名稱:
* Draw()
*
* \輸入參數:
* CDC* pDC - 指向將要接收DIB圖象的設備上下文指針
* CPoint origin - 顯示DIB的邏輯坐標
* CSize size - 顯示矩形的寬度和高度
*
* \返回值:
* BOOL - 如果成功,則為TRUE,
*
* \說明:
* 通過調用Win32 SDK的StretchDIBits函數將CDib對象輸出到顯示器(或者打印機)。
* 為了適合指定的矩形,位圖可以進行必要的拉伸
*
************************************************************************
*/
BOOL CDib::Draw(CDC* pDC, CPoint origin, CSize size)
{
// 如果信息頭為空,表示尚未有數據,返回FALSE
if(m_lpBMIH == NULL) return FALSE;
// 如果調色板不為空,則將調色板選入設備上下文
if(m_hPalette != NULL) {
::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);
}
// 設置顯示模式
pDC->SetStretchBltMode(COLORONCOLOR);
// 在設備的origin位置上畫出大小為size的圖象
::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y,size.cx,size.cy,
0, 0, m_lpBMIH->biWidth, m_lpBMIH->biHeight,
m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS, SRCCOPY);
// 返回
return TRUE;
}
/*************************************************************************
*
* \函數名稱:
* CreateSection()
*
* \輸入參數:
* CDC* pDC - 設備上下文指針
*
* \返回值:
* HBITMAP - 到GDI位圖的句柄。如果不成功,則為NULL。
* - 該句柄也是作為公共數據成員存儲的
*
* \說明:
* 通過調用Win32 SDK的CreateDIBSection函數創建一個DIB段。圖象內存將不被初始化
*
************************************************************************
*/
HBITMAP CDib::CreateSection(CDC* pDC /* = NULL */)
{
// 如果信息頭為空,不作任何處理
if(m_lpBMIH == NULL) return NULL;
// 如果圖象數據不存在,不作任何處理
if(m_lpImage != NULL) return NULL;
// 創建一個DIB段
m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH,
DIB_RGB_COLORS, (LPVOID*) &m_lpImage, NULL, 0);
ASSERT(m_lpImage != NULL);
// 返回HBIMAP句柄
return m_hBitmap;
}
/*************************************************************************
*
* \函數名稱:
* MakePalette()
*
* \輸入參數:
* 無
*
* \返回值:
* BOOL - 如果成功,則為TRUE
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -