实现BMP图片的保存和自绘图形的BMP保存

之前做项目的时候早就在网上看到过一些关于BMP图片的操作,可是当时用完后自己又忘记了,所以这次来稍稍整理下,今后要是遇到更好的方法再来补充:

        一:VC++实现将客户区存为BMP

      

在view类中添加以下三个函数:

BOOL CTestestView::WriteWindowToDIB(LPTSTR szFile, CWnd *pWnd)

{

       CBitmap bitmap;

       CWindowDC dc(pWnd);

       CDC memDC;

       CRect rect;

       memDC.CreateCompatibleDC(&dc);

       pWnd->GetWindowRect(rect);

       bitmap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());

       CBitmap* pOldBitmap=memDC.SelectObject(&bitmap);

       memDC.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);

       CPalette pal;

       if(dc.GetDeviceCaps(RASTERCAPS)&RC_PALETTE)

       {

              UINT nSize=sizeof(LOGPALETTE)+(sizeof(PALETTEENTRY)*256);

              LOGPALETTE* pLP=(LOGPALETTE*)new BYTE[nSize];

              pLP->palVersion=0x300;

              pLP->palNumEntries=GetSystemPaletteEntries(dc,0,255,pLP->palPalEntry);

              pal.CreatePalette(pLP);

              delete[] pLP;

 

       }

       memDC.SelectObject(pOldBitmap);

       HANDLE hDIB=DDBToDIB(bitmap,BI_RGB,&pal);

       if(hDIB==NULL)

              return FALSE;

       WriteDIB(szFile,hDIB);

       GlobalFree(hDIB);

       return TRUE;

 

}

 

HANDLE CTestestView::DDBToDIB(CBitmap &bitmap, DWORD dwCompression, CPalette *pPal)

{

       BITMAP bm;

       BITMAPINFOHEADER bi;

       LPBITMAPINFOHEADER lpbi;

       DWORD dwLen;

       HANDLE hDIB;

       HANDLE handle;

       HDC hDC;

       HPALETTE hPal;

       ASSERT(bitmap.GetSafeHandle());

       if(dwCompression==BI_BITFIELDS)

              return NULL;

       hPal=(HPALETTE)pPal->GetSafeHandle();

       if(hPal==NULL)

              hPal=(HPALETTE)GetStockObject(DEFAULT_PALETTE);

       bitmap.GetObject(sizeof(bm),(LPSTR)&bm);

       bi.biSize=sizeof(BITMAPINFOHEADER);

       bi.biWidth=bm.bmWidth;

       bi.biHeight=bm.bmHeight;

       bi.biPlanes=1;

       bi.biBitCount=bm.bmPlanes*bm.bmBitsPixel;

       bi.biCompression=dwCompression;

       bi.biSizeImage=0;

       bi.biXPelsPerMeter=0;

       bi.biYPelsPerMeter=0;

       bi.biClrImportant=0;

       bi.biClrUsed=0;

 

       int nColors=(1<<bi.biBitCount);

       if(nColors>256)

              nColors=0;

       dwLen=bi.biSize+nColors*sizeof(RGBQUAD);

       hDC=::GetDC(NULL);

       hPal=SelectPalette(hDC,hPal,FALSE);

       RealizePalette(hDC);

       hDIB=GlobalAlloc(GMEM_FIXED,dwLen);

       if(!hDIB)

       {

              SelectPalette(hDC,hPal,FALSE);

                     ::ReleaseDC(NULL,hDC);

              return NULL;

 

       }

      

       lpbi=(LPBITMAPINFOHEADER)hDIB;

       *lpbi=bi;

       GetDIBits(hDC,(HBITMAP)bitmap.GetSafeHandle(),0L,(DWORD)bi.biHeight,(LPBYTE)NULL,(LPBITMAPINFO)lpbi,(DWORD)DIB_RGB_COLORS);

       bi=*lpbi;

       if(bi.biSizeImage==0)

       {

              bi.biSizeImage=((((bi.biWidth*bi.biBitCount)+31)& ~31)/8)*bi.biHeight;

              if(dwCompression!=BI_RGB)

                     bi.biSizeImage=(bi.biSizeImage*3)/2;

       }

 

       dwLen+=bi.biSizeImage;

       if(handle=GlobalReAlloc(hDIB,dwLen,GMEM_MOVEABLE))

              hDIB=handle;

       else

       {

              GlobalFree(hDIB);

              SelectPalette(hDC,hPal,FALSE);

              ::ReleaseDC(NULL,hDC);

              return NULL;

       }

       lpbi=(LPBITMAPINFOHEADER)hDIB;

       BOOL bGotBits=GetDIBits(hDC,(HBITMAP)bitmap.GetSafeHandle(),0L,(DWORD)bi.biHeight,(LPBYTE)lpbi+(bi.biSize+nColors*sizeof(RGBQUAD)),

              (LPBITMAPINFO)lpbi,(DWORD)DIB_RGB_COLORS);

       if(!bGotBits)

       {

              GlobalFree(hDIB);

              SelectPalette(hDC,hPal,FALSE);

              ::ReleaseDC(NULL,hDC);

              return NULL;

       }

       SelectPalette(hDC,hPal,FALSE);

       ::ReleaseDC(NULL,hDC);

       return hDIB;

}

 

BOOL CTestestView::WriteDIB(LPTSTR szFile, HANDLE hDIB)

{

       BITMAPFILEHEADER hdr;

       LPBITMAPINFOHEADER lpbi;

       if(!hDIB)

              return FALSE;

       CFile file;

       if(!file.Open(szFile,CFile::modeWrite|CFile::modeCreate))

              return FALSE;

       lpbi=(LPBITMAPINFOHEADER)hDIB;

       int nColors=1<<lpbi->biBitCount;

       hdr.bfType=((WORD)('M'<<8)|'B');

       hdr.bfSize=::GlobalSize(hDIB)+sizeof(hdr);

       hdr.bfReserved1=0;

       hdr.bfReserved2=0;

       hdr.bfOffBits=(DWORD)(sizeof(hdr)+lpbi->biSize+nColors*sizeof(RGBQUAD));

       file.Write(&hdr,sizeof(hdr));

       file.Write(lpbi,GlobalSize(hDIB));

       return TRUE;

 

}

 在保存时调用函数WriteWindowToDIB()

void CTestestView::OnFileSave()

{

       // TODO: Add your command handler code here

       WriteWindowToDIB("D:\\My.bmp",this);    

}

本人测试过,确实直接加上就可以了,但是注意类名要改为和你的一致的

以上转载声明:http://wmnmtm.blog.163.com/blog/static/38245714200963032449/

二:VC实现自绘图形输出到bmp文件

在用vc做程序时候,经常需要把输出的文本和图形保存到位图文件,当然可以有现成的控件来实现,但总不能如自己所愿,还是自己动手写吧!如下图:


一、实现方法

  要把文本和图形保存到位图文件,只要对掌握位图结构有一定的了解,一切都ok呢。先必须要创建内存设备环境,然后内存设备环境创建的DIB区域,别忘了还要创建个CBitmap对象,CBitmap对象必须和DIB区域关联起来,把CBitmap对象选择到当前设备环境,然后在当前设备环境输出文本和图形就可以了。

二、具体实现代码如下


void CTestSaveBmpView::SaveAsBmp(CString filename)
{
 //定义图形大小
 int iWidth = 800;
 int iHeight = 600;
 int iPixel = 16;
 //图形格式参数
 LPBITMAPINFO lpbmih = new BITMAPINFO;
 lpbmih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 lpbmih->bmiHeader.biWidth = iWidth;
 lpbmih->bmiHeader.biHeight = iHeight;
 lpbmih->bmiHeader.biPlanes = 1;
 lpbmih->bmiHeader.biBitCount = iPixel;
 lpbmih->bmiHeader.biCompression = BI_RGB;
 lpbmih->bmiHeader.biSizeImage = 0;
 lpbmih->bmiHeader.biXPelsPerMeter = 0;
 lpbmih->bmiHeader.biYPelsPerMeter = 0;
 lpbmih->bmiHeader.biClrUsed = 0;
 lpbmih->bmiHeader.biClrImportant = 0;
 
 //创建位图数据
 HDC hdc,hdcMem;
 HBITMAP hBitMap = NULL;
 CBitmap *pBitMap = NULL;
 CDC *pMemDC = NULL;
 BYTE *pBits;
 
 hdc = CreateIC(TEXT("DISPLAY"),NULL,NULL,NULL);
 hdcMem = CreateCompatibleDC(hdc);
 hBitMap = CreateDIBSection(hdcMem,lpbmih,DIB_PAL_COLORS,(void **)&pBits,NULL,0);
 pBitMap = new CBitmap;
 pBitMap->Attach(hBitMap);
 pMemDC = new CDC;
 pMemDC->Attach(hdcMem);
 pMemDC->SelectObject(pBitMap);
 //
 CRect rc(0,0,iWidth,iHeight);
 pMemDC->SetBkMode(TRANSPARENT);
 //添加自绘图形 
 DrawCurve(pMemDC,rc);
 //保存到文件并创建位图结构
 BITMAPFILEHEADER bmfh;
 ZeroMemory(&bmfh,sizeof(BITMAPFILEHEADER));
 *((char *)&bmfh.bfType) = ''B'';
 *(((char *)&bmfh.bfType) + 1) = ''M'';
 bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
 bmfh.bfSize = bmfh.bfOffBits + (iWidth * iHeight) * iPixel / 8;
 
 TCHAR szBMPFileName[128];
 int iBMPBytes = iWidth * iHeight * iPixel / 8;
 strcpy(szBMPFileName,filename);
 CFile file;
 if(file.Open(szBMPFileName,CFile::modeWrite | CFile::modeCreate))
 {
  file.Write(&bmfh,sizeof(BITMAPFILEHEADER));
  file.Write(&(lpbmih->bmiHeader),sizeof(BITMAPINFOHEADER));
  file.Write(pBits,iBMPBytes);
  file.Close();
 }
 
 pMemDC->DeleteDC();
 delete pMemDC; pMemDC = NULL;
 delete pBitMap; pBitMap = NULL;
 delete lpbmih; lpbmih = NULL;
}

//输出文本和图形

void CTestSaveBmpView::DrawCurve(CDC *pDC, CRect rcClient)
{
 //页面背景色
 CBrush brushCtl;
 brushCtl.CreateSolidBrush(RGB(255,255,255));
 pDC->Rectangle(rcClient);
 pDC->FillRect(rcClient,&brushCtl) ;
 brushCtl.DeleteObject();
 
 CPen pen;
 pen.CreatePen(PS_SOLID, 1, RGB(255,0,0));
 CPen *oldPen = pDC->SelectObject(&pen); 
 
 double xMin = 10.00f, xMax = 100.00f;
 double yMin = 10.00f, yMax = 200.00f;
 
 double dbX1 = (xMax- xMin)/100 + xMin;
 double dbY1 = 600/dbX1 ;
 for (int i=1; i<100; i++) //曲线
 {
  double dbX2 = (xMax- xMin)*i/100 + xMin;
  double dbY2 = 600/dbX2 ;
  
  pDC->MoveTo(int(rcClient.left+(dbX1 - xMin)*rcClient.Width()/(xMax- xMin)), 
   int(rcClient.bottom-(dbY1- yMin)*rcClient.Height()/(yMax- yMin)));
  pDC->LineTo(int(rcClient.left+(dbX2 - xMin)*rcClient.Width()/(xMax- xMin)), 
   int(rcClient.bottom-(dbY2- yMin)*rcClient.Height()/(yMax- yMin))); 
  
  dbX1=dbX2;
  dbY1=dbY2;
 }
 pDC->SelectObject(oldPen); 
 pen.DeleteObject();
 oldPen = NULL;
}

//保存的实现
void CTestSaveBmpView::OnRButtonDown(UINT nFlags, CPoint point) 
{
 
 CFileDialog dlg(false,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
  "位图文件(*.bmp)|*.bmp|",
  NULL);
 if (dlg.DoModal()!= IDOK) return;
 CString filename = dlg.GetFileName() + ".bmp";
 SaveAsBmp(filename); 
 
 CView::OnRButtonDown(nFlags, point);
}

自己的实际应用时就把上面举例的画曲线的代码换成自己的画图程序就可以了,这个我自己试过,是成功的

第二部分转载声明:http://blog.csdn.net/ithomer/article/details/4991219

三:实现BMP信息的读取以及改写数据并保存

   typedef struct

{
     BYTE b;
     BYTE g;
     BYTE r;
}RGB;

 BITMAPFILEHEADER fileHeader;
       BITMAPINFOHEADER infoHeader;
      FILE* pfin =fopen("原始图像.bmp","rb");
      FILE* pfout = fopen( "修改后的图像.bmp" , "wb");
      //Read the Bitmap file header;
      fread(&fileHeader,sizeof(BITMAPFILEHEADER),1,pfin);
     //Read the Bitmap info header;
     fread(&infoHeader,sizeof(BITMAPINFOHEADER),1,pfin);
    //为简化代码,只处理24位彩色
    if( infoHeader.biBitCount == 24 )
    {
       int size = infoHeader.biWidth*infoHeader.biHeight;
       RGB img[infoHeader.biHeight][infoHeader.biWidth];//此处地方实现有问题,RGB img[][]要给定具体的图片长和宽
      fread( img , sizeof(RGB) , size , pfin );
      //把第50行染成黑色
      int i = 0;
      for( ; i < infoHeader.biWidth ; i++ )
      {
          img[50][i].b =img[50][i].g=img[50][i].r= 0;
      }
      //将修改后的图片保存到文件
      fwrite( &fileHeader , sizeof(fileHeader) , 1 , pfout );
      fwrite( &infoHeader , sizeof(infoHeader) , 1 , pfout );
      fwrite( img , sizeof(RGB) , size , pfout );
}
fclose(pfin);
fclose(pfout);

四:得到BMP图像的像素数据

//下面这个函数式写入BMP图像的基本信息

void CSaveBmpDlg::Snapshot(BYTE *pData, int width, int height, const char *filename)
{
int size = width*height*3; // 每个像素点3个字节

// 位图第一部分,文件信息

BITMAPFILEHEADER bfh;

bfh.bfType = 0x4d42; //bm

bfh.bfSize = size // data size

+ sizeof( BITMAPFILEHEADER ) // first section size

+ sizeof( BITMAPINFOHEADER ) // second section size

;

bfh.bfReserved1 = 0; // reserved

bfh.bfReserved2 = 0; // reserved

bfh.bfOffBits = bfh.bfSize - size;

// 位图第二部分,数据信息

BITMAPINFOHEADER bih;

bih.biSize = sizeof(BITMAPINFOHEADER);

bih.biWidth = width;

bih.biHeight = height;

bih.biPlanes = 1;

bih.biBitCount = 24;

bih.biCompression = 0;

bih.biSizeImage = size;

bih.biXPelsPerMeter = 0;

bih.biYPelsPerMeter = 0;

bih.biClrUsed = 0;

bih.biClrImportant = 0;



FILE * fp = fopen( filename, "wb" );//w+

if( !fp ) return;

fwrite( &bfh, 1, sizeof(BITMAPFILEHEADER), fp );//返回值:返回实际写入的数据块数目

fwrite( &bih, 1, sizeof(BITMAPINFOHEADER), fp );

fwrite( pData, 1, size, fp );

    fclose( fp );
}

//下面这个函数就是在自己建立的一个BMP图文件里输入数据

void CSaveBmpDlg::GenerateBMP()
{
int i=0, j=0;

struct {

BYTE b;

BYTE g;

BYTE r;

} pRGB[420][420]; // 定义位图数据

memset( pRGB, 0, sizeof(pRGB) ); // 设置背景为黑色

// 在中间画一个100*100的矩形

for(  i=70;i<170;i++ ){

for(  j=110;j<210;j++ ){

pRGB[i][j].r = 0xff;

}

}

// 生成BMP图片

Snapshot( (BYTE *)pRGB, 420, 420, "C:\\rgb.bmp" );

}

GenerateBMP()函数里的画矩形部分可以改成:

pRGB img[420][420];

int size = infoHeader.biWidth*infoHeader.biHeight;

fread( img , sizeof(RGB) , size , pfin );

Snapshot( (BYTE *)pRGB, 420, 420, "C:\\rgb.bmp" );

这样就实现了你打开图形的原样输出,保存在C:\\rgb.bmp下,如果你只是要得到数据,那么像素的数据就在img这个数组里

五:BMP图片的静态控件显示

自己有尝试很多的方法,可是都觉得比较麻烦,而且尝试着得到BMP文件的数据然后在静态控件里画出来,我觉得理论上肯定是可以的,只是自己尝试未果,不过我还是不会放弃尝试的,要是弄出来了我再跟新进博客。或者有看到这篇博文的人有知道的也可以留言给我,谢谢合作!下面我将我在网上看到的比较少的代码实现打开BMP图片并显示的代码附上,大家一起学习学习

void CSaveBmpDlg::OnOpenbmp() 
{
// TODO: Add your control notification handler code here
CFileDialog dlg(true,".bmp",m_szFilePathName,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"Bitmap Files(*.bmp)|*.bmp||");
if(dlg.DoModal()==IDOK)
{
// m_szFileName=dlg.GetFileName();
m_szFilePathName=dlg.GetPathName();
}
else
       return;
CStatic* opYuanTu=NULL;
opYuanTu=(CStatic*)GetDlgItem(IDC_STATIC);
    ShowBmp(opYuanTu,m_szFilePathName);
}


void CSaveBmpDlg::ShowBmp(CStatic *pStatic, CString s)
{
HBITMAP hbitmap;
//pStatic=NULL;
//pStatic=(CStatic*)GetDlgItem(IDC_BMP);
hbitmap=(HBITMAP)::LoadImage(::AfxGetInstanceHandle(),s,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
CBitmap hbmp;
hbmp.Attach(hbitmap);

BITMAP bm;
hbmp.GetBitmap(&bm);

CDC dcMem;
dcMem.CreateCompatibleDC(GetDC());

CBitmap *pOldBitmap=(CBitmap*)dcMem.SelectObject(hbmp);
CRect IRect;

pStatic->GetClientRect(&IRect);
pStatic->GetDC()->StretchBlt(IRect.left,IRect.top,IRect.Width(),IRect.Height(),&dcMem,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
dcMem.SelectObject(&pOldBitmap);
}

关于第五点自己遗留的问题,经过自己的一番实验,还是让我给实现了,现在也把代码分享在下面,就是打开一张BMP图,得到它的数据后,自己将它的数据重新在编辑框上画出来,其实如果是显示的话我觉得这篇博文里有更好的方法,但是如果作为测试图片数据,尤其是在只有图像数据的时候还是比较有实际的用途的,代码很简单:基本思想就是遍历数据数组,在里面找满足每个条件的数据,然后得到这些像素值对应的坐标,再将其画出来就可以了

BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER infoHeader;
FILE* pfin =fopen("D:\\ztlk.bmp","rb");
//Read the Bitmap file header;
fread(&fileHeader,sizeof(BITMAPFILEHEADER),1,pfin);
//Read the Bitmap info header;
fread(&infoHeader,sizeof(BITMAPINFOHEADER),1,pfin);
RGB img[420][420];
//为简化代码,只处理24位彩色
if( infoHeader.biBitCount == 24 )
{
int size = infoHeader.biWidth*infoHeader.biHeight;

fread( img , sizeof(RGB) , size , pfin );

}
     /*   typedef struct{
            int x;
            int y;
            }point;*/
point  zuobiao,Staticpoint; //point 如上定义的一个结构体
CPen pen(PS_SOLID,2,RGB(255,0,0));
CRect rect;
CDC *pDC =GetDlgItem(IDC_STATIC)->GetDC();
CPen* pOldPen=pDC->SelectObject(&pen);
        GetDlgItem(IDC_STATIC)->GetClientRect(&rect);
float f,f1;
f=rect.Width()/420.0;
        f1=rect.Height()/420.0;
for(int i=infoHeader.biHeight;i>0;i--)
for(int j=infoHeader.biWidth;j>0;j--)
{
if(img[i][j].b==0&&img[i][j].g==0&&img[i][j].r==0)
{
zuobiao.x=j;
zuobiao.y=i;
Staticpoint.x=zuobiao.x*f;
Staticpoint.y=zuobiao.y*f1;
pDC->MoveTo(Staticpoint.x,rect.Height()-Staticpoint.y);
pDC->LineTo(Staticpoint.x,rect.Height()-Staticpoint.y);
}
}
        pDC->DeleteDC();
fclose(pfin);

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC是微软的一种图用户界面编程框架,用于开发Windows应用程序。下面是打开和保存一幅BMP图片的编程流程: 打开图片: 1. 创建一个CFileDialog对象,设置其属性为打开文件对话框,指定文件类型为BMP图片。 2. 调用CFileDialog对象的DoModal()方法显示文件对话框并等待用户选择文件。 3. 如果用户选择了文件并点击了打开按钮,可以通过调用CFileDialog对象的GetPathName()方法获取选择的文件路径。 4. 创建一个CImage对象,调用其Load()方法并传入文件路径,即可将图片加载到内存中。 保存图片: 1. 创建一个CFileDialog对象,设置其属性为保存文件对话框,指定文件类型为BMP图片。 2. 调用CFileDialog对象的DoModal()方法显示文件对话框并等待用户选择保存路径。 3. 如果用户选择了保存路径并点击了保存按钮,可以通过调用CFileDialog对象的GetPathName()方法获取保存的文件路径。 4. 创建一个CImage对象,调用其Save()方法并传入保存路径,即可将图片保存到指定路径。 以上是基本的流程,具体的代码实现可以参考以下示例: 打开图片的示例代码: ```cpp CFileDialog fileDlg(TRUE, _T("bmp"), NULL, OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, _T("BMP Files(*.bmp)|*.bmp||"), NULL); if (fileDlg.DoModal() == IDOK) { CString filePath = fileDlg.GetPathName(); CImage image; image.Load(filePath); } ``` 保存图片的示例代码: ```cpp CFileDialog fileDlg(FALSE, _T("bmp"), NULL, OFN_OVERWRITEPROMPT, _T("BMP Files(*.bmp)|*.bmp||"), NULL); if (fileDlg.DoModal() == IDOK) { CString filePath = fileDlg.GetPathName(); // 假设有一个名为image的CImage对象保存了待保存图片 image.Save(filePath); } ``` 以上示例代码仅供参考,具体的实现需要根据具体需求和业务逻辑进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值