📄 cdib.cpp
字号:
//cdib.cpp
#include "StdAfx.h"
#include "cdib.h"
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;
ComputeMetrics(); //计算图像数据内存的大小,并设置DIB的调色板的指针
//将此DIB的调色板初始化为0
memset(m_lpvColorTable,0,sizeof(RGBQUAD) * m_nColorTableEntries);
//暂时不分配图像数据内存
m_lpImage = NULL;
}
/***********************************************************
* \函数名称:
* ~CDib()
* \输入参数:
* 无
* \返回值:
* 无
* \说明:
* 析构函数,并释放所有分配的DIB内存
************************************************************
*/
CDib::~CDib()
{
Empty();
}
/***********************************************************
* \函数名称:
* Read()
* \输入参数:
* CFile* pFile -指向CFile对象的指针
* \返回值:
* BOOL -如果成功,则返回TRUE
* \说明:
* 该函数从一个文件读入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;
}
//如果文件类型部位"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("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)&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());
}
}
/***********************************************************
* \函数名称:
* 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;
}
/***********************************************************
* \函数名称:
* 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);
}
/***********************************************************
* \函数名称:
* GetPixel()
* \输入参数:
* int x -像素在X轴的坐标
* int y -像素在Y轴的坐标
* \返回值:
* RGBQUAD -返回DIB在该点真实的颜色
* \说明:
* 该函数得到DIB图像在该点真实的颜色
************************************************************
*/
RGBQUAD CDib::GetPixel(int x, int y)
{
RGBQUAD cColor;
//CPalette* pPaletteTemp;
switch(m_lpBMIH->biBitCount)
{
case 1:
if(1<<(7-x%8)&*(LPBYTE)(m_lpImage + GetPixelOffset(x,y)))
{
cColor.rgbBlue = 255;
cColor.rgbGreen = 255;
cColor.rgbRed = 255;
cColor.rgbReserved =0;
}
else
{
cColor.rgbBlue = 0;
cColor.rgbGreen = 0;
cColor.rgbRed = 0;
cColor.rgbReserved = 0;
}
break;
case 4:
{
int nIndex = (*(LPBYTE)(m_lpImage + GetPixelOffset(x,y))&
(x%2?0x0f:0xf0))>>(x%2?0:4);
LPRGBQUAD pDibQuad = (LPRGBQUAD)(m_lpvColorTable) + nIndex;
cColor.rgbBlue = pDibQuad->rgbBlue;
cColor.rgbGreen = pDibQuad->rgbGreen;
cColor.rgbRed = pDibQuad->rgbRed;
cColor.rgbReserved = 0;
}
break;
case 8:
{
int nIndex = *(BYTE*)(m_lpImage + GetPixelOffset(x,y));
LPRGBQUAD pDibQuad = (LPRGBQUAD)(m_lpvColorTable) + nIndex;
cColor.rgbBlue = pDibQuad->rgbBlue;
cColor.rgbGreen = pDibQuad->rgbGreen;
cColor.rgbRed = pDibQuad->rgbRed;
cColor.rgbReserved = 0;
}
break;
default:
int nIndex = *(BYTE*)(m_lpImage + GetPixelOffset(x,y));
cColor.rgbBlue = m_lpImage[nIndex];
cColor.rgbGreen = m_lpImage[nIndex+1];
cColor.rgbRed = m_lpImage[nIndex+2];
cColor.rgbReserved = 0;
break;
}
return cColor;
}
/***********************************************************
* \函数名称:
* GetPixelOffset()
* \输入参数:
* int x -像素在X轴的坐标
* int y -像素在Y轴的坐标
* \返回值:
* int -返回像素在图像数据块中的真实地址
* \说明:
* 由于DIB结构中对图像数据排列的方式从下到上,从左到右的,所以需要转换
************************************************************
*/
LONG CDib::GetPixelOffset(int x, int y)
{
CSize sizeSaveDim;
sizeSaveDim =GetDibSaveDim();
LONG lOffset = (LONG)(sizeSaveDim.cy - y - 1) * sizeSaveDim.cx +
x/(8/m_lpBMIH->biBitCount);
return lOffset;
}
/***********************************************************
* \函数名称:
* PaletteSize()
* \输入参数:
* 无
* \返回值:
* DWORD -返回调色板的尺寸
* \说明:
* 该函数计算调色板所需的尺寸
************************************************************
*/
WORD CDib::PaletteSize()
{
//临时变量
WORD NumColors;
LPBITMAPINFOHEADER lpbi = m_lpBMIH;
//如果biClrUsed为零,且图像像素位数<8,则计算调色板用到的表项数
NumColors = ((lpbi)->biClrUsed == 0&&(lpbi)->biBitCount<=8
?(int)(1<<(int)(lpbi)->biBitCount):(int)(lpbi)->biClrUsed);
//根据颜色表表示的字节数计算调色板的尺寸
if(lpbi->biSize == sizeof(BITMAPCOREHEADER))
return NumColors * sizeof(RGBTRIPLE);
else
return NumColors * sizeof(RGBQUAD);
}
/***********************************************************
* \函数名称:
* IsEmpty()
* \输入参数:
* 无
* \返回值:
* BOOL -如果为空,则返回TRUE
* \说明:
* 判断信息头和图像数据是否为空
************************************************************
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -