最近把位图的打开、保存、翻转代码给大家贴出来,供大家参考:
再本文中处理1位和24位bmp文件,其他的可以自行研究、、、
首先,你要做好准备工作,在View类中设置好对应的变量和函数:
private: CFile cFile; //文件打开
BITMAPINFOHEADER bmih; //位图信息头
BITMAPFILEHEADER bmfh; //位图文件头
LPBITMAPINFO bmif; //位图信息,其中包括位图信息头和色彩信息(主要针对有调色板的Bmp,如24位真彩没有色彩信息,即位图信息就等于位图信息头)如果你对这位图方面的东西海不是很了解的话可以看我的MFC中DDB (DEVICE-DEPENDENT BITMAP)详解
byte * bmData; //用来存放位图像素数据的数组指针。
void OnView(); //用来显示调用
void Oneddy(bool bLeft); //对24位的左右90度翻转,其中true 向左
void Ontrun(bool bLeftRight); //对24位的上下,左右镜面,true 左右对称
void OneddyOne(bool bLeft); //对1位的左右90度翻转,其中true 向左
void OntrunOne(bool bLeftRight); //对1位的上下,左右镜面,true 左右对称
下来我们看一下文件的打开:
voidCMFCView::OnFileOpen()
{
char* pFilter="位图(*.bmp)|*.bmp|/0";
CFileDialogopenFile(TRUE,"*.bmp",NULL,
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,pFilter);
if(IDOK != openFile.DoModal())
return;
oPenFileOk = true ;
CStringbitmapOpenPath = openFile.GetPathName();
oPenFileOk = true;
cFile.Open(bitmapOpenPath,CFile::modeRead);
cFile.SeekToBegin();
//读取文件头
cFile.Read(&bmfh,sizeof(bmfh));
//读取文件信息头
cFile.Read(&bmih,sizeof(bmih));
//读取文件信息
cFile.SeekToBegin(); //返回到文件开始位置
cFile.Read(&bmfh,sizeof(bmfh));
UINTuBmpInfoLen=(UINT) bmfh.bfOffBits-sizeof(BITMAPFILEHEADER);
bmif =(LPBITMAPINFO) newBYTE[uBmpInfoLen];
cFile.Read((LPVOID) bmif,uBmpInfoLen);
//读取数据
DWORDdwBitlen=bmfh.bfSize - bmfh.bfOffBits;
bmData = newbyte [dwBitlen];
cFile.Read(bmData,dwBitlen);
cFile.Close();
HBITMAPhBitmap;
CBitmapcBitmap;
hBitmap = ::CreateDIBitmap(GetDC()->m_hDC,&bmih,CBM_INIT,bmData,bmif,DIB_RGB_COLORS);
cBitmap.Attach(hBitmap);
CDCdcMemory;
dcMemory.CreateCompatibleDC(GetDC());
CBitmap * cUsedBitmap = dcMemory.SelectObject(&cBitmap);
HWNDsafeHwnd =GetSafeHwnd();
RECTwindowRect;
::GetClientRect(safeHwnd,&windowRect);
POINTpaintPoint;
paintPoint.x = (windowRect.right-bmif->bmiHeader.biWidth)/2;
paintPoint.y = (windowRect.bottom-bmif->bmiHeader.biHeight)/2;
GetDC()->BitBlt(paintPoint.x,paintPoint.y,bmif->bmiHeader.biWidth,bmif->bmiHeader.biHeight,&dcMemory,0,0,SRCCOPY);
dcMemory.SelectObject(cUsedBitmap);
cBitmap.Detach();
}
文件的保存:
voidCMFCView::OnFileSave()
{
if( !oPenFileOk )
{
AfxMessageBox("Place select one BitMap!");
return ;
}
char* pFilter="位图(*.bmp)|*.bmp||";
CFileDialogsaveFile(FALSE,"*.bmp",NULL,NULL,pFilter);
if(IDOK != saveFile.DoModal())
return;
CStringbitmapSavePath = saveFile.GetPathName();
CFilecf;
cf.Open(bitmapSavePath,CFile::modeCreate|CFile::modeReadWrite);
cf.Write(&bmfh,sizeof(bmfh));
if(bmih.biBitCount==1) //判断是否为一位,来去定是否要写调色板信息
cf.Write(bmif,(UINT) bmfh.bfOffBits-sizeof(BITMAPFILEHEADER));
else
cf.Write(&bmif->bmiHeader,(UINT) bmfh.bfOffBits-sizeof(BITMAPFILEHEADER));
cf.Write(bmData,bmfh.bfSize-bmfh.bfOffBits);
cf.Close();
}
对24位的左右90度翻转,其中true 向左
voidCMFCView::Oneddy(boolbLeft)
{
byte * bEddyData ;
intbyteCount =bmif->bmiHeader.biBitCount/8;
intiAddLineData = (4-(bmif->bmiHeader.biHeight*byteCount)%4)%4;
inteddySize =(bmif->bmiHeader.biHeight*byteCount+iAddLineData)*bmif->bmiHeader.biWidth;
bEddyData = newbyte[eddySize];
intiBmpAddLineData = (4-bmif->bmiHeader.biWidth*byteCount%4)%4;
//对数据进行操作
intiImageSize = (bmif->bmiHeader.biWidth*byteCount+iBmpAddLineData)*bmif->bmiHeader.biHeight;
intbEddyDataRowCount = bmif->bmiHeader.biHeight*byteCount+iAddLineData;
for( inti =0;i<bmif->bmiHeader.biHeight ;i++)
{
intm =0;
for( intj=0;j<bmif->bmiHeader.biWidth*byteCount;j+=byteCount)
{
intbmDataIndex;
intbEddyDataRowIndex;
intbEddyDataColIndex;
intlocIndex;
if(bLeft)
{
bmDataIndex = (bmif->bmiHeader.biWidth*byteCount+iBmpAddLineData)*i;
bEddyDataRowIndex = (bmif->bmiHeader.biWidth-1-(m))*(bmif->bmiHeader.biHeight*byteCount+iAddLineData);
bEddyDataColIndex = i*byteCount;
locIndex =bEddyDataRowIndex+bEddyDataColIndex;
}
else
{
bmDataIndex = (bmif->bmiHeader.biWidth*byteCount+iBmpAddLineData)*i;
bEddyDataRowIndex = m*(bmif->bmiHeader.biHeight*byteCount+iAddLineData);
bEddyDataColIndex = (bmif->bmiHeader.biHeight-1-i)*byteCount;
locIndex =bEddyDataRowIndex+bEddyDataColIndex;
}
bEddyData[locIndex] = bmData[j+bmDataIndex]; //B
bEddyData[locIndex+1] = bmData[j+bmDataIndex+1]; //G
bEddyData[locIndex+2] = bmData[j+bmDataIndex+2]; //R
m++;
}
}
byte * bTemp = bmData;
bmData = bEddyData;
//删除临时信息
deletebTemp;
////更改头文件信息
bmfh.bfSize = bmfh.bfOffBits +eddySize;
intiTemp;
iTemp = bmif->bmiHeader.biHeight;
bmif->bmiHeader.biHeight = bmif->bmiHeader.biWidth;
bmif->bmiHeader.biWidth = iTemp;
OnView();
}
对24位的上下,左右镜面,true 左右对称
voidCMFCView::Ontrun(boolbLeftRight)
{
byte * bEddyData ;
intbyteCount ;
byteCount = bmif->bmiHeader.biBitCount/8;
bEddyData = newbyte[bmfh.bfSize-bmfh.bfOffBits];
intiBmpAddLineData = (4-bmif->bmiHeader.biWidth*byteCount%4)%4;
//对数据进行操作
intiImageSize = (bmif->bmiHeader.biWidth*byteCount+iBmpAddLineData)*bmif->bmiHeader.biHeight;
for( inti =0;i<bmif->bmiHeader.biHeight ;i++)
{
intm =0;
for( intj=0;j<bmif->bmiHeader.biWidth*byteCount;j+=byteCount)
{
intbmDataIndex;
intbEddyDataRowIndex;
intbEddyDataColIndex;
intlocIndex;
if(bLeftRight)
{
bmDataIndex = (bmif->bmiHeader.biWidth*byteCount+iBmpAddLineData)*i;
bEddyDataRowIndex = i*((bmfh.bfSize-bmfh.bfOffBits)/bmif->bmiHeader.biHeight);
bEddyDataColIndex = (bmif->bmiHeader.biWidth-1-m)*byteCount;
locIndex =bEddyDataRowIndex+bEddyDataColIndex;
}
else
{
bmDataIndex = (bmif->bmiHeader.biWidth*byteCount+iBmpAddLineData)*i;
bEddyDataRowIndex = (bmif->bmiHeader.biHeight -1-i)*((bmfh.bfSize-bmfh.bfOffBits)/bmif->bmiHeader.biHeight);
bEddyDataColIndex = (m)*byteCount;
locIndex =bEddyDataRowIndex+bEddyDataColIndex;
}
bEddyData[locIndex] = bmData[j+bmDataIndex]; //B
bEddyData[locIndex+1] = bmData[j+bmDataIndex+1]; //G
bEddyData[locIndex+2] = bmData[j+bmDataIndex+2]; //R
m++;
}
}
byte * bTemp = bmData;
bmData = bEddyData;
//删除临时信息
deletebTemp;
////更改头文件信息
OnView();
}
对1位的左右90度翻转,其中true 向左
voidCMFCView::OneddyOne(boolbLeft)
{
intbmLineSizeByte=(bmif->bmiHeader.biWidth+((32 - (bmif->bmiHeader.biWidth%32)))%32)/8;
intedyLineSizeByte = (bmif->bmiHeader.biHeight+(32 -(bmif->bmiHeader.biHeight%32))%32)/8;
intiAddLineData = (32 -bmif->bmiHeader.biHeight%32)%32;
inteddySize =(bmif->bmiHeader.biHeight+iAddLineData)*bmif->bmiHeader.biWidth;
//int x= bmfh.bfSize - bmfh.bfOffBits;
byte * bEddyData = newbyte[eddySize*bmif->bmiHeader.biWidth/8];
for( intiSetZero = 0; iSetZero<eddySize*bmif->bmiHeader.biWidth/8; iSetZero++)
bEddyData[iSetZero] = 0;
for( inti =0;i<bmif->bmiHeader.biHeight ;i++)
{
for( intj=0;j<bmif->bmiHeader.biWidth;j++)
{
if(bLeft)
{
changeBit(&bEddyData[(bmif->bmiHeader.biWidth-j-1)*edyLineSizeByte+i/8],7-i%8,&bmData[i*bmLineSizeByte+j/8],7-j%8);
}
else
{
changeBit(&bEddyData[j*edyLineSizeByte+(bmif->bmiHeader.biHeight-1-i)/8],7-(bmif->bmiHeader.biHeight-1-i)%8,&bmData[i*bmLineSizeByte+j/8],7-j%8);
}
}
}
byte * bTemp = bmData;
bmData = bEddyData;
//删除临时信息
deletebTemp;
////更改头文件信息
bmfh.bfSize = bmfh.bfOffBits +eddySize/8;
intiTemp;
iTemp = bmif->bmiHeader.biHeight;
bmif->bmiHeader.biHeight = bmif->bmiHeader.biWidth;
bmif->bmiHeader.biWidth = iTemp;
OnView();
}
对1位的上下,左右镜面,true 左右对称
voidCTest8_MFCView::OntrunOne(boolbLeftRight)
{
intbmLineSizeByte=(bmif->bmiHeader.biWidth+(32 - (bmif->bmiHeader.biWidth%32))%32)/8;
intx= bmfh.bfSize - bmfh.bfOffBits;
byte * bEddyData = newbyte[bmLineSizeByte*bmif->bmiHeader.biHeight];
if(bLeftRight)
{
for( intj=0; j<bmif->bmiHeader.biHeight; j++)
{
intiToPos=0,iFromPos = bmif->bmiHeader.biWidth%8?8-bmif->bmiHeader.biWidth%8:0;
iToPos = 7;
intiByteToPos = 0;
intiByteFromPos = bmif->bmiHeader.biWidth%8?(bmif->bmiHeader.biWidth/8):(bmif->bmiHeader.biWidth/8-1);
for(inti =0; i<bmif->bmiHeader.biWidth; i++ )
{
if( iToPos==7 )
{
bEddyData[bmLineSizeByte*j+iByteToPos] = 0;
}
changeBit( &bEddyData[bmLineSizeByte*j+iByteToPos],iToPos,&bmData[bmLineSizeByte*j+iByteFromPos],iFromPos);
iToPos--;
iFromPos++;
if( iToPos == -1 )
{
iToPos=7;
iByteToPos++;
}
if( iFromPos == 8 )
{
iFromPos = 0;
iByteFromPos--;
}
}
}
}
else
{
for( intj=0;j<bmif->bmiHeader.biHeight;j++)
{
for(inti =0;i<bmLineSizeByte ;i++ )
{
bytex=0;
bEddyData[(bmif->bmiHeader.biHeight-1-j)*bmLineSizeByte+i]&=x;
bEddyData[(bmif->bmiHeader.biHeight-1-j)*bmLineSizeByte+i]|=bmData[j*bmLineSizeByte+i];
}
}
}
byte * bTemp = bmData;
bmData = bEddyData;
//删除临时信息
deletebTemp;
OnView();
}
最后你要用到一个函数用来对指定的两个字节的木一位进行赋值,代码如下:
voidchangeBit(byte * byteTo,intiToPos,byte * byteFrom ,intiFromPos)
{
intiToPos2 = iToPos;
intm =1;
m=m<<iFromPos;
m=m&(*byteFrom);
if( iToPos>iFromPos )
{
m = m<<(iToPos2-iFromPos);
}
else
{
m = m>>( iFromPos - iToPos2);
}
*byteTo = (*byteTo)|m;
}
在过程中你要明白位图的数据真正的存放格式,比如数据首先保存的是位图最下放数据的最右边的像素,然后向左到头->向上->向左到头->向上、、、
还要明白每一行数据都必须有32位,不足的要补足32位,哪怕是一位图像长只有一个像素点,那么它也要占用32bit,也就是4个byte来存放一行。如果你还有什么不懂,你可以留言我或是把代码发给你。