QQ登录

只需一步,快速开始

113上位机VC MFC任意角度旋转位图

[ 复制链接 ]

113上位机VC MFC任意角度旋转位图

113上位机VC MFC任意角度旋转位图

113上位机VC MFC任意角度旋转位图


功能展示

对位图的旋转操作涉及有一些旋转公式,可以自行编写程序实现有借助第三方库文件,我们当前例程通过自己编写函数ExeRotateBmp(nAngle)实现,只要传递一角度便可实现任意角度的旋转,效果如图
要点提示
旋转公式并不是我们关心和问题,我们只要知道,公式的计算用到了些三角函数,只要包含函数所在的头文件便可,也就是添加一句#include<math.h>,就可以在打开位图的发问下,调用例程中函数ExeRotateBmp(intnDegree = 45);//执行旋转位图;它所带参数角度单位为度,0到360度任意设置;





实现功能
1.新建基于对话框的应用程序
2.新建一对话框资源,用于显示打开的位图,设置资源属性子窗口,无边框标题带垂直水平滚动条,再添加位图控件,修改ID为IDC_BMP。
为此对话框资源关联类class CBmpDlg : public Cdialog,之后给位图控件IDC_BMP也关联一变量CStatic  m_Bmp;用于加载位图;
3.添加三变量private: BITMAPFILEHEADERm_bmFileHeader;  //位图文件头 BITMAPINFOHEADER m_bmInfoHeader; //位图信息头 BYTE  *m_pBmpData;//位图数据;再进行初始化 CRect rect; GetClientRect(rect);m_Bmp.MoveWindow(0,0,rect.Width(),rect.Height()); m_pBmpData = NULL;
4.添加四个函数,用于位图打开,保存,旋转操作public: CString LoadBmp(); //加载位图,返回位图路径
void SaveBmp();    //保存位图 voidRotateBmp(int nDegree=45);  //旋转位图 void ExeRotateBmp(int nDegree = 45);//执行旋转位图;  

函数体部份为:


  1. CString CBmpDlg::LoadBmp()
  2. {
  3.         CString filename;//用于保存加载的位图路径
  4.         CFileDialog dlg(TRUE,"","",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"位图文件(BMP)|*.bmp",this);
  5.         if (dlg.DoModal()==IDOK)
  6.         {
  7.                 HBITMAP hBmp=NULL;        
  8.                 filename = dlg.GetPathName();//获取位图路径加名称加后缀
  9.                 hBmp =  (HBITMAP)LoadImage(NULL,filename,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);//加载位图
  10.                 if(hBmp)m_Bmp.SetBitmap((HBITMAP)hBmp);//加载成功,设置位置
  11. //>< 读取位图信息
  12.                 CFile file;
  13.                 file.Open(filename,CFile::modeRead);//打开文件
  14.                 //读取位图文件头
  15.                 file.Read(&m_bmFileHeader,sizeof(BITMAPFILEHEADER));
  16.                 //读取位图信息头
  17.                 file.Read(&m_bmInfoHeader,sizeof(BITMAPINFOHEADER));
  18.                 //判断是否为真彩色位图
  19.                 if (m_bmInfoHeader.biBitCount != 24)
  20.                 {
  21.                         file.Close();
  22.                         MessageBox("请选择真彩色位图!","工控编程吧-提示");
  23.                         return filename;
  24.                 }
  25. //><读取位图实际数据大小        
  26.                 if (m_pBmpData != NULL)//如果之前加载了位图数据,则删除位图数据
  27.                 {
  28.                         delete []m_pBmpData;
  29.                         m_pBmpData = NULL;
  30.                 }
  31.                 m_pBmpData = new BYTE[m_bmInfoHeader.biSizeImage];//根据位图数据大小为位图数据分配空间
  32.                 file.ReadHuge(m_pBmpData,m_bmInfoHeader.biSizeImage);//读取位图数据到堆空间中
  33.                 file.Close();

  34. //><改为显示时的位图数据,位图每一个像素占用4个字节,这样每一行位图数据将是4的整数倍
  35.                 //计算修改后位图数据的大小
  36.                 int sizeofbuffer = m_bmInfoHeader.biWidth * m_bmInfoHeader.biHeight * 4;
  37.                 int externWidth;
  38.                 externWidth = m_bmInfoHeader.biWidth * 3;//计算源位图每行使用的字节数
  39.                
复制代码
  1. if(externWidth % 4 != 0)
  2.                         externWidth = 4 - externWidth % 4;
  3.                 else
  4.                         externWidth = 0;
  5.                 int k = 0;
  6.                
  7.                 BYTE* pImageTempBuffer = new BYTE[sizeofbuffer];//构建新位图数据的缓冲区

  8.                 //真彩色位图通常是倒序的,因此,从底部向上访问位图数据
  9.                 for (long n = m_bmInfoHeader.biHeight - 1; n >= 0; n--)
  10.                 {
  11.                         //遍历每一个位图数据
  12.                         for (long m = 0; m < m_bmInfoHeader.biWidth * 3; m += 3)
  13.                         {
  14.                                 //获取源位图数据中的像素颜色值(RGB值)
  15.                                 pImageTempBuffer[k]   = m_pBmpData[n*(m_bmInfoHeader.biWidth*3+externWidth)+m];        //blue
  16.                                 pImageTempBuffer[k+1] = m_pBmpData[n*(m_bmInfoHeader.biWidth*3+externWidth)+m+1];//green
  17.                                 pImageTempBuffer[k+2] = m_pBmpData[n*(m_bmInfoHeader.biWidth*3+externWidth)+m+2];//red
  18.                                 pImageTempBuffer[k+3] = 255;
  19.                                 k += 4;        //设置下一个像素颜色值
  20.                         }
  21.                 }
  22.               
  23.                 delete []m_pBmpData;//释放源位图数据
  24.                 m_pBmpData = new BYTE[sizeofbuffer];
  25.                 memcpy(m_pBmpData, pImageTempBuffer, sizeofbuffer);//复制新的位图数据
  26.                 delete []pImageTempBuffer;//释放pImageTempBuffer对象
  27.                
  28. //><设置滚动条信息               
  29.                 CRect bmprect;
  30.                 m_Bmp.GetClientRect(bmprect);
  31.         
  32.                 SCROLLINFO vinfo;
  33.                 vinfo.cbSize = sizeof(vinfo);
  34.                 vinfo.fMask = SIF_ALL;
  35.                 vinfo.nPage = 100;
  36.                 vinfo.nMax= bmprect.Height();
  37.                 vinfo.nMin = 0;
  38.                 vinfo.nTrackPos = 0;
  39.                
复制代码
  1. vinfo.nPos = 0;
  2.                 SetScrollInfo(SB_VERT,&vinfo);//设置垂直滚动条信息
  3. //
  4.                 vinfo.fMask = SIF_ALL;
  5.                 vinfo.nPage = 10;
  6.                 vinfo.nMax= bmprect.Width();
  7.                 vinfo.nMin = 0;
  8.                 vinfo.nPos  = 0;
  9.                 vinfo.nTrackPos = 0;
  10.                 vinfo.cbSize = sizeof(vinfo);
  11.                 SetScrollInfo(SB_HORZ,&vinfo);//设置水平滚动条信息
  12.         }
  13.         return filename;
  14. }
  15. void CBmpDlg::SaveBmp()
  16. {
  17.                
  18.         if (m_Bmp.GetBitmap())//已经加载过位图时
  19.         {
  20.                 //定义文件保存对话框
  21.                 CFileDialog flDlg(FALSE, "bmp", "Demo.bmp", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "位图文件|*.bmp||");
  22.                 if (flDlg.DoModal()==IDOK)        //打开文件保存对话框
  23.                 {
  24.                         try
  25.                         {
  26.                                 //获取保存的文件名称
  27.                                 CString csSaveName = flDlg.GetPathName();
  28.                                 CFile file;
  29.                                 file.Open(csSaveName,CFile::modeCreate|CFile::modeReadWrite);
  30.                                 file.Write(&m_bmFileHeader,sizeof(m_bmFileHeader));//写入位图文件信息头
  31.                                 file.Write(&m_bmInfoHeader,sizeof(m_bmInfoHeader));//写入位图信息头

  32.                                 //确定转换后的位图的宽度和高度
  33.                                 UINT outHeight = m_bmInfoHeader.biHeight;
  34.                                 UINT outWidth = m_bmInfoHeader.biWidth;
  35.                                 //定义一个指针,指向最后一行位图数据
  36.                                 BYTE * pListData = m_pBmpData+((DWORD)outHeight-1)*outWidth*4;

  37.                                 //计算字节对齐,如果每行位图数据字节数不是4的整数倍,需要进行补齐
  38.                                 BYTE byByteAlign;
  39.                                 if (outWidth % 4 != 0)
  40.                                        
复制代码
  1. byByteAlign = 4-((outWidth * 3L) % 4);
  2.                                 else
  3.                                         byByteAlign = 0;

  4.                                 BYTE byZeroData = 0;
  5.                                 //按行和列遍历位图数据
  6.                                 for (UINT y=0; y<outHeight; y++)
  7.                                 {
  8.                                         for (UINT x=0; x<outWidth; x++)
  9.                                         {
  10.                                                 //向文件中写入一个像素的位图数据
  11.                                                 file.Write(pListData, 3);
  12.                                                 pListData += 4;        //指向下一个像素
  13.                                         }
  14.                                         //如果需要字节补齐,在每一行结尾需要填充适当的字节数据
  15.                                         for (UINT i=0; i<byByteAlign; i++)
  16.                                         {
  17.                                                 file.Write(&byZeroData,1);
  18.                                         }
  19.                                         //指向上一行数据
  20.                                         pListData -= 2L*outWidth*4;
  21.                                 }        
  22.                                 file.Close();        //关闭文件
  23.                         }
  24.                         catch(...)
  25.                         {
  26.                                 MessageBox("文件保存失败!","工控编程吧-提示");
  27.                         }
  28.                 }        
  29.         }
  30. }
  31. void CBmpDlg::RotateBmp(int nDegree)
  32. {
  33.         if (!m_Bmp.GetBitmap())//未加载过位图
  34.                 return;

  35.         ExeRotateBmp(nDegree);//旋转位图
  36.         
  37.         //获取旋转后的位图大小
  38.         UINT outHeight = m_bmInfoHeader.biHeight;
  39.         UINT outWidth  = m_bmInfoHeader.biWidth;
  40.         BYTE* pBmpData  = new BYTE [m_bmInfoHeader.biSizeImage];//为新位图分配堆空间
  41.         
复制代码
  1. memset(pBmpData,0,m_bmInfoHeader.biSizeImage);//初始化堆空间
  2.         //获取位图数据中的最后以行数据
  3.         BYTE * pListData =m_pBmpData+((DWORD)outHeight-1)*outWidth*4;
  4.         
  5.         //计算位图数据每行补齐的字节数
  6.         BYTE byByteAlign ;        //位图行字节对齐
  7.         if (outWidth %4 != 0)
  8.                 byByteAlign = 4- ((outWidth*3L) % 4);
  9.         else
  10.                 byByteAlign = 0;
  11.         
  12.         BYTE byZeroData = 0;
  13.         BYTE* pTmpData = pBmpData;
  14.         //对旋转后的位图数据进行修改,使得使用3个字节表示一个像素数据
  15.         for (UINT y=0 ;y<outHeight;y++)
  16.         {
  17.                 for (UINT x=0;x<outWidth;x++)
  18.                 {
  19.                         memcpy(pTmpData,pListData,3);
  20.                         pTmpData += 3;
  21.                         pListData += 4;
  22.                 }
  23.                 for (UINT i=0; i<byByteAlign; i++)
  24.                 {
  25.                         memcpy(pTmpData,&byZeroData,1);
  26.                         pTmpData =pTmpData + 1;
  27.                 }
  28.                 pListData -= 2L*outWidth*4;
  29.         }
  30.         
  31.         CDC *pDC = m_Bmp.GetDC();
  32.         BITMAPINFO bInfo;
  33.         bInfo.bmiHeader = m_bmInfoHeader;
  34.         //在图像控件中显示旋转后的位图
  35.         m_Bmp.SetBitmap(CreateDIBitmap(pDC->m_hDC,&m_bmInfoHeader, CBM_INIT, pBmpData, &bInfo, DIB_RGB_COLORS));
  36.         delete [] pBmpData;
  37.         
  38. //设置滚动范围
  39.         CRect bmpRC,wndRC;
  40.         GetClientRect(wndRC);
  41.         m_Bmp.GetWindowRect(bmpRC);
  42.         
复制代码
  1. OnHScroll(SB_LEFT, 1, NULL);
  2.         OnVScroll(SB_LEFT, 1, NULL);
  3.         
  4.         SetScrollRange(SB_VERT,0,bmpRC.Height()-wndRC.Height()+100);
  5.         SetScrollRange(SB_HORZ,0,bmpRC.Width()-wndRC.Width());

  6. }
  7. void CBmpDlg::ExeRotateBmp(int nDegree)
  8. {
  9.         //源图像宽度和高度
  10.         UINT srcWidth = m_bmInfoHeader.biWidth;
  11.         UINT srcHeight = m_bmInfoHeader.biHeight;

  12.         double pi = 3.1415926535;
  13.         double dRadian =nDegree* (pi/180.0);//将角度转换为弧度
  14.         //计算目标图像宽度和高度
  15.         UINT desWidth = (abs)(srcHeight*sin(dRadian)) + (abs)(srcWidth*cos(dRadian))+1;
  16.         UINT desHeight = (abs)(srcHeight*cos(dRadian)) + (abs)(srcWidth*sin(dRadian))+1;



  17. //<>更新旋转后的文件头信息
  18.         UINT desLineBytes;
  19.         desLineBytes = desWidth * m_bmInfoHeader.biBitCount / 8;
  20.         int mod = desLineBytes % 4;
  21.         if (mod != 0)
  22.                 desLineBytes += 4 - mod;
  23.         m_bmInfoHeader.biSizeImage = desHeight*desLineBytes;        //设置图像数据大小
  24.         m_bmInfoHeader.biHeight = desHeight;
  25.         m_bmInfoHeader.biWidth  = desWidth;

  26. //<>进行图像数据部份旋转
  27.         //在堆中分配一个空间,用于存储旋转后的位图数据
  28.         BYTE* pDesData  = NULL;
  29.         pDesData = new BYTE[desWidth * desHeight * 4];
  30.         memset(pDesData, 255, desWidth * desHeight * 4);//初始堆空间中的数据

  31.         //计算dx和dy
  32.         double dSin = sin(dRadian);
  33.         double dCos = cos(dRadian);
  34.         double dX = -0.5*desWidth*dCos - 0.5*desHeight*dSin + 0.5*srcWidth;
  35.         double dY = 0.5*desWidth*dSin - 0.5*desHeight*dCos + 0.5*srcHeight;

  36.         
复制代码
  1. BYTE* pSrc = NULL;        
  2.         BYTE* pDes = NULL;        
  3.         int x = 0;                                
  4.         int        y = 0;                                
  5.         for (int h = 0; h < desHeight; h++)
  6.         {
  7.                 for (int w = 0; w < desWidth; w++)
  8.                 {
  9.                         //加0.5是为了向上取整
  10.                         //x,y表示目标区域w,h坐标点对应的源图像中的坐标
  11.                         x = (int)(w * dCos + h * dSin + dX + 0.5);
  12.                         y = (int)(-w * dSin + h * dCos + dY + 0.5);
  13.                         if (x == srcWidth)
  14.                         {
  15.                                 x--;
  16.                         }
  17.                         if (y == srcHeight)
  18.                         {
  19.                                 y--;
  20.                         }

  21.                         pSrc = m_pBmpData + y * srcWidth * 4 + x * 4;
  22.                         pDes = pDesData + h * desWidth * 4 + w * 4;
  23.                         //判断目标区域中的坐标是在源位图中存在坐标点,通常目标区域会比源位图区域大
  24.                         //因此,有些目标区域中的有些坐标在源位图中是没有对应的坐标点,程序过滤掉这些坐标点
  25.                         if (x >= 0 && x < srcWidth && y >= 0 && y < srcHeight)
  26.                         {
  27.                                 memcpy(pDes, pSrc, 4);
  28.                         }
  29.                 }
  30.         }

  31. //<> 更新保存旋转后数据到m_pBmpData

  32.         //如果m_pBmpData包含位图数据,则先释放位图数据
  33.         if (m_pBmpData != NULL)
  34.         {
  35.                 delete []m_pBmpData;
  36.                 m_pBmpData = NULL;
  37.         }
  38.         
复制代码
  1. //重新复制旋转之后的位图数据
  2.         m_pBmpData = new BYTE[desHeight*desWidth*4];
  3.         memset(m_pBmpData,255,desHeight*desWidth*4);
  4.         memcpy(m_pBmpData,pDesData,desHeight*desWidth*4);
  5.         //释放临时对象
  6.         delete [] pDesData;
  7.         pDesData = NULL;
  8. }
复制代码
4.水平垂直滚动条的操作部分,可参考例程,我们来使用自定义的类,在主对话框资源中拖拽一位图控件修改ID为IDC_RECT,用于定位位图显示位置;添加变量CBmpDlg m_BmpDlg;并初始化  m_BmpDlg.Create(IDD_DIALOG1,this);//创建显示位图用窗口
CRect rc;GetDlgItem(IDC_RECT)->GetWindowRect(rc); ScreenToClient(rc);
m_BmpDlg.MoveWindow(rc);m_BmpDlg.ShowWindow(SW_SHOW);
添加加载位图,旋转位置,保存位图按钮控件,关联函数分别调用 m_BmpDlg.LoadBmp();
m_BmpDlg.SaveBmp();  m_BmpDlg.RotateBmp(); 便可


我们来演示功能实现过程

  
请点击此处下载

请先注册会员后在进行下载

已注册会员,请先登录后下载

文件名称:113.上位机VC MFC任意角度旋转位图.rar 
文件大小:502.33 KB  售价:20金币
下载权限: 不限 以上或 VIP会员   [购买捐助会员]   [充值积分]   有问题联系我

  

您的支持是我们创作的动力!  

  

您可花点闲钱积分自助任意充值

  

成为VIP会员 全站资源任意下载永久更新!


回复

使用道具 举报

点击查看
快速回复 返回列表 客服中心 搜索