zoukankan      html  css  js  c++  java
  • 任意角度图片旋转

    void S_PicXZ(Graphics::TBitmap *Source,Graphics::TBitmap *NewPic,int angle)//
        {
        if(angle>180)angle=360-angle;
        if(angle<-180)angle=360+angle;

      float radians=(2*3.1416*angle)/360;
        float cosine=(float)cos(radians);
        float sine=(float)sin(radians);
        float Point1x=(-Source->Height*sine);
        float Point1y=(Source->Height*cosine);
        float Point2x=(Source->Width*cosine-Source->Height*sine);
        float Point2y=(Source->Height*cosine+Source->Width*sine);
        float Point3x=(Source->Width*cosine);
        float Point3y=(Source->Width*sine);
        float minx=min((float)0,min(Point1x,min(Point2x,Point3x)));
        float miny=min((float)0,min(Point1y,min(Point2y,Point3y)));
        float maxx=max(Point1x,max(Point2x,Point3x));
        float maxy=max(Point1y,max(Point2y,Point3y));
        int DestBitmapWidth,DestBitmapHeight;
        if(angle>90&&angle<180)
          DestBitmapWidth=(int)ceil(-minx);
        else
          DestBitmapWidth=(int)ceil(maxx-minx);

      if(angle>-180&&angle<-90)
          DestBitmapHeight=(int)ceil(-miny);
        else
          DestBitmapHeight=(int)ceil(maxy-miny);

      NewPic->Height=DestBitmapHeight;
        NewPic->Width=DestBitmapWidth;
        for(int x=0;x<DestBitmapWidth;x++)
          {
          for(int y=0;y<DestBitmapHeight;y++)
            {
            int SrcBitmapx=(int)((x+minx)*cosine+(y+miny)*sine);
            int SrcBitmapy=(int)((y+miny)*cosine-(x+minx)*sine);
            if(SrcBitmapx>=0&&SrcBitmapx<Source->Width&&SrcBitmapy>=0&&
            SrcBitmapy<Source->Height)
              {
              NewPic->Canvas->Pixels[x][y]=Source->Canvas->Pixels[SrcBitmapx][SrcBitmapy];
              }
            }
          }
        }

    转自:http://hi.baidu.com/sweetpigss/blog/item/0496efdc5d1967d08c10297e.html 
    如果你的应用程序仅工作在Windows NT下,那么你可以通过API函数旋转你的位图。 
    你或者使用world transformation和BitBlt()或者使用PlgBlt()旋转位图。一个 
    使用第一种方法的函数显示在下面。 
    如果你的目标是多平台的,那么你的任务变得非常困难。你只能通过旋转源位图中 
    每个象素或者直接操作DIB字节得到旋转位图。第一种方法通过每个点的处理是非 
    常慢的,第二种方法是很复杂的,但它有足够快的速度。注:下面的所有函数旋转 
    后产生新的位图,如果你需要直接绘制位图,请自已修改函数。 其中函数1仅工作 
    在NT环境下,它是最简单也是最快的,可惜它不支持Windows95。 
    所有的函数所接受的角度单位是弧度,如果是角度单位是度请用下面的公式转换。 
    radian = (2*pi *degree)/360 
    旋转步骤: 
    创建一对与设备兼容的显示设备。一个用于源位图,一个用于旋转后的目标位图。 
    预计算正弦和余弦函数值,这样可以避免重复计算。 
    用下面的公式计算旋转图像后的矩形 
    newx = x.cos(angle) + y.sin(angle) 
    newy = y.cos(angle) - x.sin(angle) 
    旋转后的位图将不能占用整个新位图,我们将用背景色填充它。 
    点阵转换公式 
    newx = x * eM11 + y * eM21 + eDx 
    newy = x * eM12 + y * eM22 + eDy 
    其中eM11和eM22是角度的余弦值,eM21是角度的正弦,eM12是eM21的负值。 eDx & eDy 
    目的是旋转后的位图在新的位图不被剪切。 
    函数一:适用于NT

    // GetRotatedBitmapNT - Create a new bitmap with rotated image
    // Returns  - Returns new bitmap with rotated image
    // hBitmap  - Bitmap to rotate
    // radians  - Angle of rotation in radians
    // clrBack  - Color of pixels in the resulting bitmap that do
    //     not get covered by source pixels
    HBITMAP GetRotatedBitmapNT( HBITMAP hBitmap, float radians, COLORREF clrBack )
    {
     // Create a memory DC compatible with the display
     CDC sourceDC, destDC;
     sourceDC.CreateCompatibleDC( NULL );
     destDC.CreateCompatibleDC( NULL );
     // Get logical coordinates
     BITMAP bm;
     ::GetObject( hBitmap, sizeof( bm ), &bm );
     float cosine = (float)cos(radians);
     float sine = (float)sin(radians);
     // Compute dimensions of the resulting bitmap
     // First get the coordinates of the 3 corners other than origin
     int x1 = (int)(bm.bmHeight * sine);
     int y1 = (int)(bm.bmHeight * cosine);
     int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);
     int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);
     int x3 = (int)(bm.bmWidth * cosine);
     int y3 = (int)(-bm.bmWidth * sine);
     int minx = min(0,min(x1, min(x2,x3)));
     int miny = min(0,min(y1, min(y2,y3)));
     int maxx = max(0,max(x1, max(x2,x3)));
     int maxy = max(0,max(y1, max(y2,y3)));
     int w = maxx - minx;
     int h = maxy - miny;
     // Create a bitmap to hold the result
     HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);
     HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
     HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
     // Draw the background color before we change mapping mode
     HBRUSH hbrBack = CreateSolidBrush( clrBack );
     HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
     destDC.PatBlt( 0, 0, w, h, PATCOPY );
     ::DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );
     // We will use world transform to rotate the bitmap
     SetGraphicsMode(destDC.m_hDC, GM_ADVANCED);
     XFORM xform;
     xform.eM11 = cosine;
     xform.eM12 = -sine;
     xform.eM21 = sine;
     xform.eM22 = cosine;
     xform.eDx = (float)-minx;
     xform.eDy = (float)-miny;
     SetWorldTransform( destDC.m_hDC, &xform );
     // Now do the actual rotating - a pixel at a time
     destDC.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );
     // Restore DCs
     ::SelectObject( sourceDC.m_hDC, hbmOldSource );
     ::SelectObject( destDC.m_hDC, hbmOldDest );
     return hbmResult;
    }
    


    函数二: GetRotatedBitmap()使用 GetPixel & SetPixel

    // GetRotatedBitmap - Create a new bitmap with rotated image
    // Returns  - Returns new bitmap with rotated image
    // hBitmap  - Bitmap to rotate
    // radians  - Angle of rotation in radians
    // clrBack  - Color of pixels in the resulting bitmap that do
    //     not get covered by source pixels
    // Note   - If the bitmap uses colors not in the system palette
    //     then the result is unexpected. You can fix this by
    //     adding an argument for the logical palette.
    HBITMAP GetRotatedBitmap( HBITMAP hBitmap, float radians, COLORREF clrBack )
    {
     // Create a memory DC compatible with the display
     CDC sourceDC, destDC;
     sourceDC.CreateCompatibleDC( NULL );
     destDC.CreateCompatibleDC( NULL );
     // Get logical coordinates
     BITMAP bm;
     ::GetObject( hBitmap, sizeof( bm ), &bm );
     float cosine = (float)cos(radians);
     float sine = (float)sin(radians);
     // Compute dimensions of the resulting bitmap
     // First get the coordinates of the 3 corners other than origin
     int x1 = (int)(-bm.bmHeight * sine);
     int y1 = (int)(bm.bmHeight * cosine);
     int x2 = (int)(bm.bmWidth * cosine - bm.bmHeight * sine);
     int y2 = (int)(bm.bmHeight * cosine + bm.bmWidth * sine);
     int x3 = (int)(bm.bmWidth * cosine);
     int y3 = (int)(bm.bmWidth * sine);
     int minx = min(0,min(x1, min(x2,x3)));
     int miny = min(0,min(y1, min(y2,y3)));
     int maxx = max(x1, max(x2,x3));
     int maxy = max(y1, max(y2,y3));
     int w = maxx - minx;
     int h = maxy - miny;
     // Create a bitmap to hold the result
     HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);
     HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
     HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
     // Draw the background color before we change mapping mode
     HBRUSH hbrBack = CreateSolidBrush( clrBack );
     HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
     destDC.PatBlt( 0, 0, w, h, PATCOPY );
     ::DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );
     // Set mapping mode so that +ve y axis is upwords
     sourceDC.SetMapMode(MM_ISOTROPIC);
     sourceDC.SetWindowExt(1,1);
     sourceDC.SetViewportExt(1,-1);
     sourceDC.SetViewportOrg(0, bm.bmHeight-1);
     destDC.SetMapMode(MM_ISOTROPIC);
     destDC.SetWindowExt(1,1);
     destDC.SetViewportExt(1,-1);
     destDC.SetWindowOrg(minx, maxy);
     // Now do the actual rotating - a pixel at a time
     // Computing the destination point for each source point
     // will leave a few pixels that do not get covered
     // So we use a reverse transform - e.i. compute the source point
     // for each destination point
     for( int y = miny; y < maxy; y++ )
     {
      for( int x = minx; x < maxx; x++ )
      {
       int sourcex = (int)(x*cosine + y*sine);
       int sourcey = (int)(y*cosine - x*sine);
       if( sourcex >= 0 && sourcex < bm.bmWidth && sourcey >= 0
         && sourcey < bm.bmHeight )
        destDC.SetPixel(x,y,sourceDC.GetPixel(sourcex,sourcey));
      }
     }
     // Restore DCs
     ::SelectObject( sourceDC.m_hDC, hbmOldSource );
     ::SelectObject( destDC.m_hDC, hbmOldDest );
     return hbmResult;
    }


    函数三: GetRotatedBitmap()使用DIB

              // GetRotatedBitmap - Create a new bitmap with rotated image
              // Returns - Returns new bitmap with rotated image
              // hDIB - Device-independent bitmap to rotate
              // radians - Angle of rotation in radians
              // clrBack - Color of pixels in the resulting bitmap that do
              //   not get covered by source pixels
              HANDLE GetRotatedBitmap( HANDLE hDIB, float radians, COLORREF clrBack)
              {
              // Get source bitmap info
              BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
              int bpp = bmInfo.bmiHeader.biBitCount; // Bits per pixel
              int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed
              :
              1 << bpp;
              int nWidth = bmInfo.bmiHeader.biWidth;
              int nHeight = bmInfo.bmiHeader.biHeight;
              int nRowBytes = ((((nWidth * bpp) + 31) & ~31) / 8);
              // Make sure height is positive and biCompression is BI_RGB or
              BI_BITFIELDS
              DWORD &compression = bmInfo.bmiHeader.biCompression;
              if( nHeight < 0 || (compression!=BI_RGB &&
              compression!=BI_BITFIELDS))
              return NULL;
              LPVOID lpDIBBits;
              if( bmInfo.bmiHeader.biBitCount > 8 )
              lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors +
              bmInfo.bmiHeader.biClrUsed) +
              ((compression == BI_BITFIELDS) ? 3 : 0));
              else
              lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
                 
              // Compute the cosine and sine only once
              float cosine = (float)cos(radians);
              float sine = (float)sin(radians);
              // Compute dimensions of the resulting bitmap
              // First get the coordinates of the 3 corners other than origin
              int x1 = (int)(-nHeight * sine);
              int y1 = (int)(nHeight * cosine);
              int x2 = (int)(nWidth * cosine - nHeight * sine);
              int y2 = (int)(nHeight * cosine + nWidth * sine);
              int x3 = (int)(nWidth * cosine);
              int y3 = (int)(nWidth * sine);
              int minx = min(0,min(x1, min(x2,x3)));
              int miny = min(0,min(y1, min(y2,y3)));
              int maxx = max(x1, max(x2,x3));
              int maxy = max(y1, max(y2,y3));
              int w = maxx - minx;
              int h = maxy - miny;
              // Create a DIB to hold the result
              int nResultRowBytes = ((((w * bpp) + 31) & ~31) / 8);
              long len = nResultRowBytes * h;
              int nHeaderSize = ((LPBYTE)lpDIBBits-(LPBYTE)hDIB) ;
              HANDLE hDIBResult = GlobalAlloc(GMEM_FIXED,len+nHeaderSize);
              // Initialize the header information
              memcpy( (void*)hDIBResult, (void*)hDIB, nHeaderSize);
              BITMAPINFO &bmInfoResult = *(LPBITMAPINFO)hDIBResult ;
              bmInfoResult.bmiHeader.biWidth = w;
              bmInfoResult.bmiHeader.biHeight = h;
              bmInfoResult.bmiHeader.biSizeImage = len;
              LPVOID lpDIBBitsResult = (LPVOID)((LPBYTE)hDIBResult + nHeaderSize);
              // Get the back color value (index)
              ZeroMemory( lpDIBBitsResult, len );
              DWORD dwBackColor;
              switch(bpp)
              {
              case 1: //Monochrome
              if( clrBack == RGB(255,255,255) )
              memset( lpDIBBitsResult, 0xff, len );
              break;
              case 4:
              case 8: //Search the color table
              int i;
              for(i = 0; i < nColors; i++ )
              {
              if( bmInfo.bmiColors[i].rgbBlue ==  GetBValue(clrBack)
              && bmInfo.bmiColors[i].rgbGreen ==  GetGValue(clrBack)
              && bmInfo.bmiColors[i].rgbRed ==  GetRValue(clrBack) )
              {
              if(bpp==4) i = i | i<<4;
              memset( lpDIBBitsResult, i, len );
              break;
              }
              }
              // If not match found the color remains black
              break;
              case 16:
              // Windows95 supports 5 bits each for all colors or 5 bits for red
              & blue
              // and 6 bits for green - Check the color mask for RGB555 or RGB565
              if( *((DWORD*)bmInfo.bmiColors) == 0x7c00 )
              {
              // Bitmap is RGB555
              dwBackColor = ((GetRValue(clrBack)>>3) << 10) +
              ((GetRValue(clrBack)>>3) << 5) +
              (GetBValue(clrBack)>>3) ;
              }
              else
              {
              // Bitmap is RGB565
              dwBackColor = ((GetRValue(clrBack)>>3) << 11) +
              ((GetRValue(clrBack)>>2) << 5) +
              (GetBValue(clrBack)>>3) ;
              }
              break;
              case 24:
              case 32:
              dwBackColor = (((DWORD)GetRValue(clrBack)) << 16) |
              (((DWORD)GetGValue(clrBack)) << 8) |
              (((DWORD)GetBValue(clrBack)));
              break;
              }
              // Now do the actual rotating - a pixel at a time
              // Computing the destination point for each source point
              // will leave a few pixels that do not get covered
              // So we use a reverse transform - e.i. compute the source point
              // for each destination point
              for( int y = 0; y < h; y++ )
              {
              for( int x = 0; x < w; x++ )
              {
              int sourcex = (int)((x+minx)*cosine + (y+miny)*sine);
              int sourcey = (int)((y+miny)*cosine - (x+minx)*sine);
              if( sourcex >= 0 && sourcex < nWidth && sourcey
              >= 0
              && sourcey < nHeight )
              {
              // Set the destination pixel
              switch(bpp)
              {
              BYTE mask;
              case 1: //Monochrome
              mask = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +
              sourcex/8) & (0x80 >> sourcex%8);
              //Adjust mask for destination bitmap
              mask = mask ? (0x80 >> x%8) : 0;
              *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
              (x/8)) &= ~(0x80 >> x%8);
              *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
              (x/8)) |= mask;
              break;
              case 4:
              mask = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +
              sourcex/2) & ((sourcex&1) ? 0x0f : 0xf0);
              //Adjust mask for destination bitmap
              if( (sourcex&1) != (x&1) )
              mask = (mask&0xf0) ? (mask>>4) : (mask<<4);
              *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
              (x/2)) &= ~((x&1) ? 0x0f : 0xf0);
              *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
              (x/2)) |= mask;
              break;
              case 8:
              BYTE pixel ;
              pixel = *((LPBYTE)lpDIBBits + nRowBytes*sourcey +
              sourcex);
              *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) +
              (x)) = pixel;
              break;
              case 16:
              DWORD dwPixel;
              dwPixel = *((LPWORD)((LPBYTE)lpDIBBits +
              nRowBytes*sourcey + sourcex*2));
              *((LPWORD)((LPBYTE)lpDIBBitsResult +
              nResultRowBytes*y + x*2)) = (WORD)dwPixel;
              break;
              case 24:
              dwPixel = *((LPDWORD)((LPBYTE)lpDIBBits +
              nRowBytes*sourcey + sourcex*3)) & 0xffffff;
              *((LPDWORD)((LPBYTE)lpDIBBitsResult +
              nResultRowBytes*y + x*3)) |= dwPixel;
              break;
              case 32:
              dwPixel = *((LPDWORD)((LPBYTE)lpDIBBits +
              nRowBytes*sourcey + sourcex*4));
              *((LPDWORD)((LPBYTE)lpDIBBitsResult +
              nResultRowBytes*y + x*4)) = dwPixel;
              }
              }
              else
              {
              // Draw the background "color."
              tppabs="http://www.codeguru.com/bitmap/color." The
              background color
              // has already been drawn for 8 bits per pixel and less
              switch(bpp)
              {
              case 16:
              *((LPWORD)((LPBYTE)lpDIBBitsResult +
              nResultRowBytes*y + x*2)) =
              (WORD)dwBackColor;
              break;
              case 24:
              *((LPDWORD)((LPBYTE)lpDIBBitsResult +
              nResultRowBytes*y + x*3)) |= dwBackColor;
              break;
              case 32:
              *((LPDWORD)((LPBYTE)lpDIBBitsResult +
              nResultRowBytes*y + x*4)) = dwBackColor;
              break;
              }
              }
              }
              }
              return hDIBResult;
              }
  • 相关阅读:
    Metricbeat
    Flask安装与基本配置
    web框架
    git
    占位
    算法
    面试
    CMDB
    order by关键字排序优化
    动态主机配置协议-DHCP
  • 原文地址:https://www.cnblogs.com/15157737693zsp/p/6015044.html
Copyright © 2011-2022 走看看