www.pudn.com > hongmoyuan.rar > 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; // BITMAP结构指针
m_hPalette = NULL; //调色板指针
m_nBmihAlloc = m_nImageAlloc = noAlloc; //内存分配的情况
Empty(); // 清空DIB,释放已经分配的内存,并且关闭映射文件
}
/*************************************************************************
*
* \函数名称:
* 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; //表示分配了DIB信息头和调色板的内存,但是没有像素数据
// 设置信息头中的信息
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; //压缩方式为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);
}
/*************************************************************************
*
* \函数名称:
* 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;
}
/*************************************************************************
*
* \函数名称:
* 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;
}
/*************************************************************************
*
* \函数名称:
* 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) &amt;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;
}
/*************************************************************************
*
* \函数名称:
* 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) &amt;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&amt; ar - 指向应用程序归档对象
*
* \返回值:
* 无
*
* \说明:
* 该函数进行串行化过程,将CDib数据进行读入或者写出
*
************************************************************************
*/
void CDib::Serialize(CArchive&amt; 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) &amt;&amt; (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) {
::GlobalUnlock(m_hGlobal);
::GlobalFree(m_hGlobal);
}
// 释放图象数据内存
if(m_nImageAlloc == crtAlloc) delete [] m_lpImage;
// 释放调色板句柄
if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
// 如果创建了BITMAP,则进行释放
if(m_hBitmap != NULL) ::DeleteObject(m_hBitmap);
// 重新设置内存分配状态
m_nBmihAlloc = m_nImageAlloc = noAlloc;
// 释放内存后,还需要将指针设置为NULL并将相应的数据设置为0
m_hGlobal = NULL;
m_lpBMIH = NULL;
m_lpImage = NULL;
m_lpvColorTable = NULL;
m_nColorTableEntries = 0;
m_dwSizeImage = 0;
m_lpvFile = NULL;
m_hMap = NULL;
m_hFile = NULL;
m_hBitmap = NULL;
m_hPalette = NULL;
}
/*************************************************************************
*
* \函数名称:
* DetachMapFile()
*
* \输入参数:
* 无
*
* \返回值:
* 无
*
* \说明:
* 函数可以释放现有的已分配的内存,并关闭以前关联的任何内存映射文件。
*
************************************************************************
*/
void CDib::DetachMapFile()
{
// 如果没有进行内存映射,则不进行处理
if(m_hFile == NULL) return;
// 关闭内存映射
::UnmapViewOfFile(m_lpvFile);
// 关闭内存映射对象和文件
::CloseHandle(m_hMap);
::CloseHandle(m_hFile);
m_hFile = NULL;
}
/*************************************************************************
*
* \函数名称:
* IsEmpty()
*
* \输入参数:
* 无
*
* \返回值:
* BOOL - 如果信息头和图象数据为空,则返回TRUE
*
* \说明:
* 判断信息头和图象数据是否为空
*
************************************************************************
*/
BOOL CDib::IsEmpty()
{
if( m_lpBMIH == NULL&amt;&amt;m_lpImage == NULL)
return TRUE;
else
return FALSE;
}
/*************************************************************************
*
* \函数名称:
* GetDibSaveDim()
*
* \输入参数:
* 无
*
* \返回值:
* CSize - DIB实际存储的高度和宽度
*
* \说明:
* 该函数函数用来得到dib的实际存储宽度(DWORD对齐)
*
************************************************************************
*/
CSize CDib::GetDibSaveDim()
{
CSize sizeSaveDim;
sizeSaveDim.cx = ( m_lpBMIH->biWidth * m_lpBMIH->biBitCount + 31)/32 * 4;
sizeSaveDim.cy = m_lpBMIH->biHeight;
return sizeSaveDim;
}