各位大虾:
   如何用VC++实现图象的任意角度旋转,最好图象还能透明。
   用处:我计划做一个数字仪表的控件,表盘的数字刻度由一幅图片来实现,
         而仪表的指针也用一幅图片来实现,请问当指针旋转时如何选择图片。

解决方案 »

  1.   

    图像rotate,看这个。
    http://www.codeproject.com/bitmap/rotatebyshear.asp
      

  2.   

    bitmap旋转效率很低,而且效果我想也不会很好。最好把需要旋转的部分和不需要旋转部分分开,不需要旋转部分用bitmap,可以做的漂亮一些,旋转部分用矢量格式,比如metafile。
      

  3.   

    DDB直接旋转比较慢,DIB旋转只要你不要频繁刷新,感觉速度还可以。
    DDB的像素windows保存在2GB+的核心内存区,需要切换读取,所以慢一些。DIB的数据被复制到2GB-的用户区,所以会快一点,而且算法上也可以做进一步的优化。代码如下:
    -------------------------// 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 CPicture::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. 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;
    }