📄 hdib.cpp
字号:
// HDib.cpp: implementation of the CDib class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "HDib.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CDib::CDib()
{
m_BmpLoaded=FALSE;
m_Buffer=0;
m_Buffer1=0;
m_BmpInfo=0;
m_Quad=0;
m_hPal=0;
BmpMarker=('M'<<8)|'B';
Width=0;
Height=0;
}
CDib::~CDib()
{
Free();
}
//释放所有动态分配的内存:
void CDib::Free()
{
if(m_Buffer)
{
delete [] m_Buffer;
m_Buffer=0;
}
if(m_Buffer1)
{
delete [] m_Buffer1;
m_Buffer1=0;
}
if(m_BmpInfo)
{
delete [] m_BmpInfo;
m_BmpInfo=0;
}
if(m_Quad)
{
delete [] m_Quad;
m_Quad=0;
}
}
void CDib::Resize(int sz)
{
if(m_Buffer)
{
delete [] m_Buffer;
m_Buffer=0;
}
if(m_Buffer1)
{
delete [] m_Buffer1;
m_Buffer1=0;
}
m_Buffer=new BYTE[sz];
m_Buffer1=new BYTE[sz];
//位图每一行占据的字节数:
Bpl=(DWORD)WIDTHBYTES(BPP*Width); //一种使bpl为4的整数倍的技巧
//位图数据区尺寸(字节):
BufferSize=Bpl*Height;
}
//从文件中读取位图:
BOOL CDib::LoadBmp(LPCTSTR fn)
{
int j;
if(fn=="")
{
return FALSE;
}
Free();
arcFileName=fn;
//打开bmp文件:
ifstream files(fn,ios::binary|ios::nocreate);
if(!files.is_open())
{
return FALSE;
}
//读入BITMAPFILEHEADER:
files.read((LPSTR)&m_BmpFH, sizeof(BITMAPFILEHEADER));
//判断是否是bmp文件:
if (m_BmpFH.bfType != BmpMarker)
{
return FALSE;
}
//读入BITMAPINFO:
DWORD bmpinfosz;
bmpinfosz=m_BmpFH.bfOffBits-sizeof(BITMAPFILEHEADER)
+256*sizeof(RGBQUAD); //40+256*4
m_BmpInfo=(LPBITMAPINFO) new BYTE[bmpinfosz];
files.read((char *)m_BmpInfo,m_BmpFH.bfOffBits-sizeof(BITMAPFILEHEADER)); //m_BmpFH.bfOffBits-sizeof(BITMAPFILEHEADER)=40
//计算位图的相关数据信息:
CalBmpData();
//只支持8位以上的位图:
if(BPP>32)
{
Free();
return FALSE;
}
//读入位图数据:
m_Buffer=new BYTE[BufferSize];
m_Buffer1=new BYTE[BufferSize];
files.read((char *)m_Buffer,BufferSize);
if(m_BmpInfo->bmiHeader.biCompression!=BI_RGB)
{
Free();
return FALSE;
}
if(!CreatePalette())
{
Free();
return FALSE;
}
for ( j=0;j<(int)BufferSize;j++)
{
*(m_Buffer1+j)=*(m_Buffer+j);
}
m_BmpLoaded=TRUE;
return TRUE;
}
//将内存中的位图存入文件:
BOOL CDib::SaveBmp(LPCTSTR fn)
{
if(fn=="")
{
return FALSE;
}
if(!m_BmpLoaded)
{
return FALSE;
}
if(m_BmpInfo==0||m_Buffer==0)
{
return FALSE;
}
//1. 更改m_BmpInfo->bmiHeader.biSizeImage:
//1. biSizeImage=位图数据的大小:
m_BmpInfo->bmiHeader.biSizeImage=BufferSize;
//2. 填充bmpfh结构;
BITMAPFILEHEADER bmpfh;
memset(&bmpfh,0,sizeof(BITMAPFILEHEADER));
bmpfh.bfType=BmpMarker;
//bmpfh.bfSize=BITMAPFILEHEADER+BITMAPINFO+调色板+BufferSize:
bmpfh.bfSize=sizeof(BITMAPFILEHEADER)+
sizeof(BITMAPINFO)+
(NumberOfColors-1)*sizeof(RGBQUAD)+
BufferSize;
bmpfh.bfReserved1=0;
bmpfh.bfReserved2=0;
bmpfh.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+
m_BmpInfo->bmiHeader.biSize+
PaletteSize();
//3. 写文件:
FILE * fp;
size_t sz;
if((fp=fopen(fn,"wb"))==NULL)
{
return FALSE;
}
//1). 写入BITMAPFILEHEADER:
sz=fwrite((void *)&bmpfh,sizeof(BITMAPFILEHEADER),1,fp);
if(sz!=1)
{
fclose(fp);
return FALSE;
}
//2). 写入BITMAPINFO:
sz=fwrite((void *)m_BmpInfo,sizeof(BITMAPINFO)+(NumberOfColors-1)*sizeof(RGBQUAD),1,fp);
if(sz!=1)
{
fclose(fp);
return FALSE;
}
//3). 写入位图数据:
sz=fwrite(m_Buffer,1,BufferSize,fp);
if(sz!=BufferSize)
{
fclose(fp);
return FALSE;
}
fclose(fp);
return TRUE;
}
//获取位图内存地址:
BYTE * CDib::GetBuffer()
{
return m_Buffer;
}
//根据像素在位图中的位置求像素在内存中的地址:
BYTE * CDib::FindPos(DWORD x, DWORD y)
{
BYTE * pos;
if(!m_BmpLoaded)
{
return 0;
}
pos=m_Buffer+Bpl*(Height-1-y)+x*BPP/8;
return pos;
}
//将位图的子画面存入文件:
BOOL CDib::PickBitmapToFile(LPCTSTR fn, DWORD xt, DWORD yt,
DWORD xb, DWORD yb)
{
BYTE * buf;
DWORD w,h,bpl,bufsize,n0;
if(!m_BmpLoaded)
{
return FALSE;
}
if(m_BmpInfo==0||m_Buffer==0)
{
return FALSE;
}
if(fn=="")
{
return FALSE;
}
//1. 计算基本参数:
Sort(xt,xb);
Sort(yt,yb);
if(xt>Width)
{
return FALSE;
}
if(yt>Width)
{
return FALSE;
}
if(xb>Width)
{
xb=Width;
}
if(yb>Height)
{
yb=Height;
}
w=xb-xt;//子画面宽度;
h=yb-yt;//子画面高度;
bpl=(w*(BPP/8)+3)&~3;//每一行大小;
n0=bpl-w*BPP/8;//需要在每一行末尾添加的0的数目;
bufsize=bpl*h;//位图数据区大小;
//2. 填写位图区:
BYTE * pos,* bufpos;
pos=FindPos(xt,yt);//找到(xt,yt)像素在内存中的位置;
buf=new BYTE[bufsize];
memset((void *)buf,0,bufsize);
UINT i;
bufpos=buf+bpl*(h-1);
for(i=0;i<h;i++)
{
memcpy(bufpos,pos,w*BPP/8);
bufpos-=bpl;
pos-=Bpl;
}
//3. 填写位图结构:
BITMAPFILEHEADER fh;
BITMAPINFO info;
memset(&fh ,0,sizeof(BITMAPFILEHEADER));
memset(&info,0,sizeof(BITMAPINFO));
//1. 填充BITMAPINFO结构:
info.bmiHeader.biBitCount=(WORD)BPP;
info.bmiHeader.biClrImportant=m_BmpInfo->bmiHeader.biClrImportant;
info.bmiHeader.biClrUsed=m_BmpInfo->bmiHeader.biClrUsed;
info.bmiHeader.biCompression=BI_RGB;
info.bmiHeader.biHeight=h;
info.bmiHeader.biPlanes=m_BmpInfo->bmiHeader.biPlanes;
info.bmiHeader.biSize=m_BmpInfo->bmiHeader.biSize;
info.bmiHeader.biSizeImage=bufsize;
info.bmiHeader.biWidth=w;
info.bmiHeader.biXPelsPerMeter=m_BmpInfo->bmiHeader.biXPelsPerMeter;
info.bmiHeader.biYPelsPerMeter=m_BmpInfo->bmiHeader.biYPelsPerMeter;
info.bmiColors[0]=m_BmpInfo->bmiColors[0];
//2. 填充bmpfh结构;
fh.bfType=BmpMarker;
//bmpfh.bfSize=BITMAPFILEHEADER+BITMAPINFO+调色板+BufferSize:
fh.bfSize=sizeof(BITMAPFILEHEADER)+
sizeof(BITMAPINFO)+
(NumberOfColors-1)*sizeof(RGBQUAD)+
bufsize;
fh.bfReserved1=0;
fh.bfReserved2=0;
fh.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+
m_BmpInfo->bmiHeader.biSize+
PaletteSize();
//4. 写文件:
FILE * fp;
if((fp=fopen(fn,"wb"))==NULL)
{
return FALSE;
}
//1). 写入BITMAPFILEHEADER:
fwrite((char *)&fh,sizeof(BITMAPFILEHEADER),1,fp);
//2). 写入BITMAPINFOHEADER部分:
fwrite((char *)&info.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
//3). //写入彩色表部分:
if(BPP<16)
{
fwrite((char *)&m_Quad[0],NumberOfColors*sizeof(RGBQUAD),1,fp);
}
//4). 写入位图数据:
fwrite((char *)buf,bufsize,1,fp);
delete buf;
fclose(fp);
return TRUE;
}
void CDib::CalBmpData()
{
if(m_BmpInfo==0)
{
return;
}
//1. 位图宽度(像素):
Width=m_BmpInfo->bmiHeader.biWidth;
//位图高度(像素):
Height=m_BmpInfo->bmiHeader.biHeight;
//位图色彩深度:
BPP=m_BmpInfo->bmiHeader.biBitCount; //取值可为1,4,8,16,24,32,如取值16,24,32,则彩色表不是必须的
//位图每一行占据的字节数:
Bpl=(DWORD)WIDTHBYTES(BPP*Width); //一种使bpl为4的整数倍的技巧
//位图数据区尺寸(字节):
BufferSize=Bpl*Height;
//为m_Quad分配内存:
//如果色彩数目大于8 则返回:
if(m_BmpInfo->bmiHeader.biBitCount>=16)
{
NumberOfColors=0;
return;
}
if(m_BmpInfo->bmiHeader.biClrUsed!=0)
{
NumberOfColors=m_BmpInfo->bmiHeader.biClrUsed;
}
else
{
switch(BPP){
case 1:
NumberOfColors=2;
break;
case 4:
NumberOfColors=16;
break;
case 8:
NumberOfColors=256;
break;
default:
return;
}
}
//读取 logical palette
m_Quad=new RGBQUAD[NumberOfColors];
for(DWORD i=0;i<NumberOfColors;i++)
{
m_Quad[i]=m_BmpInfo->bmiColors[i];
}
}
void CDib::SetBmpMarker(DWORD b, DWORD m)
{
BmpMarker=(WORD)((m<<8)|b); //'m'左移8位 and 'b' 再强制类型转换
}
DWORD CDib::PaletteSize()
{
if (m_BmpInfo==0)
{
return 0;
}
return (DWORD)NumberOfColors*sizeof(RGBQUAD);//256*4
}
//using bmp file's QUAD to change phisical palette
BOOL CDib::CreatePalette()
{
if (m_BmpInfo==0)
{
return FALSE;
}
//16位以下的位图均需要 logical palette
if(BPP>=16)
{
return TRUE;
}
DWORD i;
// allocate memory block for 逻辑彩色区logical palette
LPLOGPALETTE lpPal = (LPLOGPALETTE) new BYTE[sizeof(LOGPALETTE) + sizeof(PALETTEENTRY)*NumberOfColors]; //sizeof(PALETTEENTRY)*NumberOfColors=4*256 bytes
// if not enough memory, clean up and return NULL
if (lpPal == 0)
{
return FALSE;
}
// set version and number of palette entries
lpPal->palVersion = PALVERSION;
lpPal->palNumEntries = (WORD)NumberOfColors;
for (i=0;i<NumberOfColors;i++)
{
lpPal->palPalEntry[i].peRed = m_Quad[i].rgbRed;
lpPal->palPalEntry[i].peGreen = m_Quad[i].rgbGreen;
lpPal->palPalEntry[i].peBlue = m_Quad[i].rgbBlue;
lpPal->palPalEntry[i].peFlags = 0;
}
/* according to bmp file palette table,create the palette and
get handle to it */
if (m_hPal)
{
::DeleteObject((HGDIOBJ)m_hPal); //删除老的逻辑调色对象
}
m_hPal=::CreatePalette(lpPal); //创建新的逻辑调色对象
if(!m_hPal)
{
return FALSE;
}
delete [] lpPal; //作用完即destroy logical Palette
return TRUE;
}
BOOL CDib::Draw(HDC hDC, LPRECT rcDest, LPRECT rcSrc)
{
if (!m_BmpLoaded)
{
return FALSE;
}
HPALETTE hOldPal = 0; // Previous palette
// Get the DIB's palette, then select it into DC
if (m_hPal!=0)
{
// Select as background since we have
// already realized in forground if needed
hOldPal = ::SelectPalette(hDC,m_hPal,TRUE); //selects the specified logical palette into a device context
}
/* Make sure to use the stretching mode best for color pictures */
::SetStretchBltMode(hDC, COLORONCOLOR);
/* Determine whether to call StretchDIBits() or SetDIBitsToDevice() */
BOOL Ok;
if ((RECTWIDTH(rcDest) == RECTWIDTH(rcSrc)) &&
(RECTHEIGHT(rcDest) == RECTHEIGHT(rcSrc)))
{
Ok = ::SetDIBitsToDevice(hDC, // hDC
rcDest->left, // DestX
rcDest->top, // DestY
RECTWIDTH(rcDest), // nDestWidth
RECTHEIGHT(rcDest), // nDestHeight
rcSrc->left, // SrcX
Height-rcSrc->top -RECTHEIGHT(rcSrc),// SrcY
0, // nStartScan
(WORD)Height, // nNumScans
m_Buffer, // lpBits
m_BmpInfo, // lpBitsInfo
DIB_RGB_COLORS); // wUsage
}
else
{
Ok = ::StretchDIBits(hDC, // hDC
rcDest->left, // DestX
rcDest->top, // DestY
RECTWIDTH(rcDest), // nDestWidth
RECTHEIGHT(rcDest), // nDestHeight
rcSrc->left, // SrcX
rcSrc->top, // SrcY
RECTWIDTH(rcSrc), // wSrcWidth
RECTHEIGHT(rcSrc), // wSrcHeight
m_Buffer, // lpBits
m_BmpInfo, // lpBitsInfo
DIB_RGB_COLORS, // wUsage
SRCCOPY); // dwROP
}
/* Reselect old palette */
if (hOldPal != 0)
{
::SelectPalette(hDC, hOldPal, TRUE); //恢复老的调色板
}
return Ok;
}
void CDib::Sort(DWORD &x0, DWORD &x1)
{
DWORD t;
if(x0>x1)
{
t=x1;
x1=x0;
x0=t;
}
}
BITMAPINFOHEADER CDib::GetImageInfo(LPCTSTR fn, DWORD &w, DWORD &h)
{
BITMAPFILEHEADER bmpfilehdr;
BITMAPINFOHEADER bmpinfohdr;
w=0;
h=0;
memset(&bmpfilehdr,0,sizeof(BITMAPFILEHEADER)); //初始化内存并得到内存指针;
memset(&bmpinfohdr,0,sizeof(BITMAPINFOHEADER));
ifstream file( fn, ios::binary | ios::nocreate ); //打开已存在的且二进制的文件;
if (!file.is_open())
{
return bmpinfohdr;
}
file.read( (char*)&bmpfilehdr, sizeof(bmpfilehdr) );
if (bmpfilehdr.bfType!=(WORD)BmpMarker)
{
return bmpinfohdr;
}
file.read( (char*)&bmpinfohdr, sizeof(bmpinfohdr) );
w=bmpinfohdr.biWidth;
h=bmpinfohdr.biHeight;
return bmpinfohdr;
}
void CDib::restoreimage()
{
int j;
for ( j=0;j<(int)BufferSize;j++)
{
*(m_Buffer+j)=*(m_Buffer1+j);
}
}
BOOL CDib::GetBlueImg()
{
if (BPP<=8)
return FALSE;
int i,j;
for(i=0;i<(int)Height;i++)
{
for ( j=0;j<(int)Bpl-2;j=j+3)
{
*(m_Buffer+i*Bpl+j+1)=0;
*(m_Buffer+i*Bpl+j+2)=0;
}
}
return TRUE;
}
BOOL CDib::GetGreenImg()
{
if (BPP<=8)
return FALSE;
int i,j;
for(i=0;i<(int)Height;i++)
{
for ( j=0;j<(int)Bpl-2;j=j+3)
{
*(m_Buffer+i*Bpl+j)=0;
*(m_Buffer+i*Bpl+j+2)=0;
}
}
return TRUE;
}
BOOL CDib::GetRedImg()
{
if (BPP<=8)
return FALSE;
int i,j;
for(i=0;i<(int)Height;i++)
{
for ( j=0;j<(int)Bpl-2;j=j+3)
{
*(m_Buffer+i*Bpl+j)=0;
*(m_Buffer+i*Bpl+j+1)=0;
}
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -