如何在vc++中旋转位图---任意角度

类别:VC语言 点击:0 评论:0 推荐:

    网上有很多关于位图旋转的资料,但是讲得很清楚的不多(我没有仔细查找).于是我也写了一个,希望能给向我这样的初学者一点帮助.

   第一步,你必须知道位图即BMP格式的文件的结构.

              位图(bmp)文件由以下几个部分组成:

                     1.BITMAPFILEHEADER,它的定义如下:

                         typedef struct tagBITMAPFILEHEADER { 
                            WORD    bfType;         //必须为'BM'
                            DWORD   bfSize;         //文件大小
                            WORD    bfReserved1; //必须为0
                            WORD    bfReserved2; //必须为0
                            DWORD   bfOffBits;    //从ITMAPFILEHEADER到存放bmp数据的偏移量                                  

                         } BITMAPFILEHEADER, *PBITMAPFILEHEADER;

                   2.BITMAPINFOHEADER,它的定义如下:

                       typedef struct tagBITMAPINFOHEADER{
                                   DWORD  biSize;  //此结构的大小,可用sizeof(BITMAPINFOHEAER)得到
                                   LONG   biWidth; //位图宽度,以象素为单位
                                   LONG   biHeight; //位图高度,以象素为单位
                                   WORD   biPlanes; //必须为1
                                   WORD   biBitCount;//位图象素位数,可为0,1,4,8,24,32 
                                   DWORD  biCompression; 
                                   DWORD  biSizeImage; //(仅用于压缩)
                                   LONG   biXPelsPerMeter; //一米横向象素数
                                   LONG   biYPelsPerMeter; //一米纵向象素数
                                   DWORD  biClrUsed;// (非零用语短颜色表)
                                   DWORD  biClrImportant; 
                      } BITMAPINFOHEADER, *PBITMAPINFOHEADER;

       由于以上信息可以直接从MSDN上查到,所以只做简单介绍,你可以自己查看NSDN帮助,上面有很详细的介绍.

              3.DIB位图像.这里放的是真正的位图数据.

        知道了位图的存放格式,下面我们就可以很容易的把它读如内存.

       第二步,读入bmp图像

       LPCTSTR lpszFileName4="untitled.bmp";   //文件路径
      CFile file;                                     //用于读取BMP文件
      BITMAPFILEHEADER bfhHeader;//bmp文件头

     BITMAPINFOHEADER bmiHeader; //bmp格式头 

      LPBITMAPINFO lpBitmapInfo;    //bmp格式具体信息
      int bmpWidth=0;                         //图片宽度
      int bmpHeight = 0;                      //图片高度           

      if(!file.Open(lpszFileName,CFile::modeRead))
              return ;                              //打开文件
      file.Read(&bfhHeader,sizeof(BITMAPFILEHEADER));//读取文件头
      if(bfhHeader.bfType!=((WORD) ('M'<<8)|'B'))           //判断是否是"BM"
              return ;
      if(bfhHeader.bfSize!=file.GetLength())
              return ;
                               
     if (file.Read((LPSTR)&bmiHeader, sizeof(bmiHeader)) != sizeof(bmiHeader))
              return ;
     bmpHeight = bmiHeader.biHeight;//得到高度和宽度
     bmpWidth = bmiHeader.biWidth;
     file.SeekToBegin();
     file.Read(&bfhHeader,sizeof(BITMAPFILEHEADER)); 
     UINT uBmpInfoLen=(UINT) bfhHeader.bfOffBits-sizeof(BITMAPFILEHEADER);
     lpBitmapInfo=(LPBITMAPINFO) new BYTE[uBmpInfoLen];
     file.Read((LPVOID) lpBitmapInfo,uBmpInfoLen);
     if((* (LPDWORD)(lpBitmapInfo))!=sizeof(BITMAPINFOHEADER))
              return ;
     DWORD dwBitlen=bfhHeader.bfSize - bfhHeader.bfOffBits;
     LPVOID lpSrcBits=new BYTE[dwBitlen];          //将数据读入lpSrcBits数组
     file.ReadHuge(lpSrcBits,dwBitlen);
     file.Close();                                                     //关闭文件

     下面我们将图片显示在屏幕上:

     第三步,显示图片

     CClientDC  hDC(this);
     StretchDIBits(hDC,0,0,bmpWidth,bmpHeight,0,0,bmpWidth,bmpHeight,

                          lpSrcBits,lpBitmapInfo,DIB_RGB_COLORS,SRCCOPY);

     第四步,将图片读入内存设备环境

      HDC dcSrc;
      HBITMAP bitmap;
      dcSrc=CreateCompatibleDC(hDC);//得到一个内存设备环境
      bitmap = CreateCompatibleBitmap(hDC,bmpWidth,bmpHeight);
      SelectObject(dcSrc,bitmap);
      BitBlt(dcSrc,0,0,bmpWidth,bmpHeight,hDC,0,0,SRCCOPY);//这一步很重要

      第五步,实现位图旋转

      我们假设旋转位图的函数原形如下:

      void RotateBitmap(HDC dcSrc,int SrcWidth,int SrcHeight,double angle,HDC pDC);

     /*参数解释如下://///////////////////////////////////////////////////////////////////////////

        HDC dcSrc:要旋转的位图的内存设备环境,就是第四步创建的

        int SrcWidth:要旋转位图的宽度

        int SrcHeight:要旋转位图的高度

       double angle:所要旋转的角度,以弧度为单位  

       HDC pDC:第三步得到的当前屏幕设备环境

*///////////////////////////////////////////////////////////////////////////////////////////////////////

//以下是函数实现细节

void RotateAnyAngle(HDC dcSrc,int SrcWidth,int SrcHeight,double angle)
{
 double x1,x2,x3;
 double y1,y2,y3;
 double maxWidth,maxHeight,minWidth,minHeight;
 double srcX,srcY;
 double sinA,cosA;
 double DstWidth;
 double DstHeight;
 HDC dcDst;//旋转后的内存设备环境
 HBITMAP newBitmap;
 sinA = sin(angle);
 cosA = cos(angle);
 x1 = -SrcHeight * sinA;
    y1 = SrcHeight * cosA;
    x2 = SrcWidth * cosA - SrcHeight * sinA;
    y2 = SrcHeight * cosA + SrcWidth * sinA;
    x3 = SrcWidth * cosA;
    y3 = SrcWidth * sinA;
 minWidth = x3>(x1>x2?x2:x1)?(x1>x2?x2:x1):x3;
 minWidth = minWidth>0?0:minWidth;
 minHeight = y3>(y1>y2?y2:y1)?(y1>y2?y2:y1):y3;
 minHeight = minHeight>0?0:minHeight;
 maxWidth = x3>(x1>x2?x1:x2)?x3:(x1>x2?x1:x2);
 maxWidth = maxWidth>0?maxWidth:0;
 maxHeight = y3>(y1>y2?y1:y2)?y3:(y1>y2?y1:y2);
 maxHeight = maxHeight>0?maxHeight:0;
 DstWidth = maxWidth - minWidth;
    DstHeight = maxHeight - minHeight;
 dcDst = CreateCompatibleDC(dcSrc);
 newBitmap = CreateCompatibleBitmap(dcSrc,(int)DstWidth,(int)DstHeight);
 SelectObject(dcDst,newBitmap);
 for( int I = 0 ;I<DstHeight;I++)
 {
    for(int J = 0 ;J< DstWidth;J++)
    {
       srcX = (J + minWidth) * cosA + (I + minHeight) * sinA;
       srcY = (I + minHeight) * cosA - (J + minWidth) * sinA;
       if( (srcX >= 0) && (srcX <= SrcWidth) &&(srcY >= 0) && (srcY <= SrcHeight))
      {
              BitBlt(dcDst, J, I, 1, 1, dcSrc,(int)srcX, (int)srcY, SRCCOPY);
      }
   }
 }

   //显示旋转后的位图

   BitBlt(hDC,200,200,(int)DstWidth,(int)DstHeight,dcDst,0,0,SRCCOPY);


   DeleteObject(newBitmap);

   DeleteDC(dcDst);

}

      最后我们调用就可以了:

      double angle = (45/180.0)*3.14159;//旋转45Degree,可为任意角度

      RotateAnyAngle(dcSrc,bmpWidth,bmpHeight,angle,);

     到这里就大功告成了.

本文地址:http://com.8s8s.com/it/it1249.htm