📄 cdib.cpp
字号:
BOOL CDib::IsEmpty()
{
if(m_lpBMIH == NULL && m_lpImage == NULL)
return TRUE;
else
return FALSE;
}
/***********************************************************
* \函数名称:
* 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;
}
/***********************************************************
* \函数名称:
* Compress()
* \输入参数:
* CDC* pDC -指向将要接收DIB图像的设备上下文指针
* BOOL bCompress -TRUE对应于压缩的DIB,FALSE对应于不压缩的DIB
* \返回值:
* BOOL -如果成功,则返回TRUE
* \说明:
* 该函数将DIB重新生成为压缩或者不压缩的DIB,在内部,它转换已有的DIB为DDB位图
* 然后生成一个新的DIB。压缩仅为4bpp和8bpp的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);
//如需要压缩,设置相应的信息,并创建压缩格式的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 create-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;
}
/***********************************************************
* \函数名称:
* AttachMapFile()
* \输入参数:
* const char* strPathname -映射文件的路径名
* BOOL bShare -如果文件以共享形式打开,设置为TRUE; 默认值为FALSE
* \返回值:
* BOOL -如果成功,则返回TRUE
* \说明:
* 以读模式打开内存映射文件,并将其与CDib对象关联,因为在文件使用前并没有读入内存
* 故它立即返回,因为文件是分页的,所以当访问这个DIB的时候,可能会有一些延迟
************************************************************
*/
BOOL CDib::AttachMapFile(const char* strPathname,BOOL bShare)
{
//获取文件句柄,并设置打开模式为共享
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);
ASSERT(lpvFile!=NULL);
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;
}
/***********************************************************
* \函数名称:
* 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;
}
/***********************************************************
* \函数名称:
* CopyToMapFile()
* \输入参数:
* const char* strPathname -映射文件的路径名
* \返回值:
* BOOL -如果成功,则返回TRUE
* \说明:
* 该函数创建一个新的内存映射文件,并将现有的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(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) +
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 = m_dwSizeImage + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries + sizeof(BITMAPFILEHEADER);
//创建内存映射文件对象
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;
}
/***********************************************************
* \函数名称:
* DetachMapFile()
* \输入参数:
* 无
* \返回值:
* 无
* \说明:
* 函数可以释放现有的已分配的内存,并关闭以前关联的任何内存映射文件
************************************************************
*/
void CDib::DetachMapFile()
{
//如果没有进行内存映射,则不进行处理
if(m_hFile == NULL) return;
//关闭内存映射
::UnmapViewOfFile(m_lpvFile);
//关闭内存映射对象和文件
::CloseHandle(m_hMap);
::CloseHandle(m_hFile);
m_hFile = NULL;
}
/***********************************************************
* \函数名称:
* MakePalette()
* \输入参数:
* 无
* \返回值:
* BOOL -如果成功,则返回TRUE
* \说明:
* 如果颜色表存在的话,该函数读取它,并创建一个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函数返回的调色板相匹配
************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -