📄 cdib.cpp
字号:
// 分配临时存放位图数据
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);
// 为DIB分配内存
m_hDib = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, bmfh.bfSize);
if (m_hDib == 0)
{
// 内存分配失败,返回NULL。
return NULL;
}
// 锁定
m_lpDib = (LPSTR) ::GlobalLock((HGLOBAL) m_hDib);
pFile->Seek(sizeof(BITMAPFILEHEADER),CFile::begin);
// 读象素
nSize = bmfh.bfSize - sizeof(BITMAPFILEHEADER);
nCount = pFile->Read(m_lpDib, nSize);
if (nCount != nSize )
{
// 大小不对。
// 解除锁定
::GlobalUnlock((HGLOBAL) m_hDib);
// 释放内存
::GlobalFree((HGLOBAL) m_hDib);
throw new CException;
}
// 解除锁定
::GlobalUnlock((HGLOBAL) m_hDib);
}
// 错误处理
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;
}
// 如果文件类型部位"BM",则返回并进行相应错误处理
if(bmfh.bfType != 0x4d42)
{
throw new CException;
}
// 计算信息头加上调色板的大小,并分配相应的内存
nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize];
m_nBmihAlloc = crtAlloc;
m_nImageAlloc = noAlloc;
// 读取信息头和调色板
nCount = pFile->Read(m_lpBMIH, nSize);
// 如果图象为压缩格式,则不进行后续处理
if(m_lpBMIH->biCompression != BI_RGB)
{
throw new CException;
}
// 计算图象数据大小并设置调色板指针
ComputeMetrics();
// 计算调色板的表项数
ComputePaletteSize(m_lpBMIH->biBitCount);
// 如果DIB中存在调色板,则创建一个Windows调色板
MakePalette();
// 将CDib对象的逻辑调色板选入设备上下文
UsePalette(pDC);
// 创建一个DIB段,并分配图象内存
m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH,
DIB_RGB_COLORS, (LPVOID*) &m_lpImage, NULL, 0);
ASSERT(m_lpImage != NULL);
// 从文件中读取图象数据
nCount = pFile->Read(m_lpImage, m_dwSizeImage);
}
// 错误处理
catch(CException* pe)
{
AfxMessageBox("ReadSection error");
pe->Delete();
return FALSE;
}
return TRUE;
}
/*************************************************************************
*
* \函数名称:
* Write()
*
* \输入参数:
* CFile* pFile - 指向CFile对象的指针
*
* \返回值:
* BOOL - 如果成功,则返回TRUE
*
* \说明:
* 该函数把DIB从CDib对象写进文件中。该文件必须成功打开或者创建
*
************************************************************************
*/
BOOL CDib::Write(CFile* pFile)
{
BITMAPFILEHEADER bmfh;
// 设置文件头中文件类型为"BM"
bmfh.bfType = 0x4d42;
// 计算信息头和调色板的大小尺寸
int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
// 设置文件头信息
bmfh.bfSize = sizeof(BITMAPFILEHEADER) + nSizeHdr + m_dwSizeImage;
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries;
// 进行写操作
try
{
pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
pFile->Write((LPVOID) m_lpBMIH, nSizeHdr);
pFile->Write((LPVOID) m_lpImage, m_dwSizeImage);
}
// 错误处理
catch(CException* pe)
{
pe->Delete();
AfxMessageBox("write error");
return FALSE;
}
// 返回
return TRUE;
}
/*************************************************************************
*
* \函数名称:
* Serialize()
*
* \输入参数:
* CArchive& ar - 指向应用程序归档对象
*
* \返回值:
* 无
*
* \说明:
* 该函数进行串行化过程,将CDib数据进行读入或者写出
*
************************************************************************
*/
void CDib::Serialize(CArchive& ar)
{
DWORD dwPos;
// 获得此归档文件的CFile对象指针
dwPos = ar.GetFile()->GetPosition();
TRACE("CDib::Serialize -- pos = %d\n", dwPos);
// 从归档文件缓冲区中冲掉未写入数据
ar.Flush();
// 重新获得此归档文件的CFile对象指针
dwPos = ar.GetFile()->GetPosition();
TRACE("CDib::Serialize -- pos = %d\n", dwPos);
// 确定归档文件是否被存储,是则进行存储
if(ar.IsStoring())
{
Write(ar.GetFile());
}
// 否则进行加载
else
{
Read(ar.GetFile());
}
}
/*************************************************************************
*
* \函数名称:
* ComputePaletteSize()
*
* \输入参数:
* int nBitCount - 指向CFile对象的指针
*
* \返回值:
* 无
*
* \说明:
* 该函数根据位图象素位数计算调色板的尺寸
*
************************************************************************
*/
void CDib::ComputePaletteSize(int nBitCount)
{
// 如果biClrUsed为零,则用到的颜色数为2的biBitCount次方
if((m_lpBMIH == NULL) || (m_lpBMIH->biClrUsed == 0)) {
switch(nBitCount) {
case 1:
m_nColorTableEntries = 2;
break;
case 4:
m_nColorTableEntries = 16;
break;
case 8:
m_nColorTableEntries = 256;
break;
case 16:
case 24:
case 32:
m_nColorTableEntries = 0;
break;
default:
ASSERT(FALSE);
}
}
// 否则调色板的表项数就是用到的颜色数目
else {
m_nColorTableEntries = m_lpBMIH->biClrUsed;
}
ASSERT((m_nColorTableEntries >= 0) && (m_nColorTableEntries <= 256));
}
/*************************************************************************
*
* \函数名称:
* ComputeMetrics()
*
* \输入参数:
* 无
*
* \返回值:
* 无
*
* \说明:
* 该函数计算图象位图的尺寸,并对DIB中的调色板的指针进行赋值
*
************************************************************************
*/
void CDib::ComputeMetrics()
{
// 如果结构的长度不对,则进行错误处理
if(m_lpBMIH->biSize != sizeof(BITMAPINFOHEADER))
{
TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmap\n");
throw new CException;
}
// 保存图象数据内存大小到CDib对象的数据成员中
m_dwSizeImage = m_lpBMIH->biSizeImage;
// 如果图象数据内存大小为0,则重新计算
if(m_dwSizeImage == 0)
{
DWORD dwBytes = ((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) / 32;
if(((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) % 32)
{
dwBytes++;
}
dwBytes *= 4;
m_dwSizeImage = dwBytes * m_lpBMIH->biHeight;
}
// 设置DIB中的调色板指针
m_lpvColorTable = (LPBYTE) m_lpBMIH + sizeof(BITMAPINFOHEADER);
}
/*************************************************************************
*
* \函数名称:
* Empty()
*
* \输入参数:
* 无
*
* \返回值:
* 无
*
* \说明:
* 该函数清空DIB,释放已分配的内存,并且必要的时候关闭映射文件
*
************************************************************************
*/
void CDib::Empty()
{
// 关闭内存映射文件的连接
DetachMapFile();
// 根据内存分配的状态,调用相应的函数释放信息头
if(m_nBmihAlloc == crtAlloc)
{
delete [] m_lpBMIH;
}
else if(m_nBmihAlloc == heapAlloc)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -