图象旋转的问题?

时间:2021-06-04 15:52:45
请问如何实现图象的旋转呢?为什么我的方法会出错:
主程序:
#define PI 3.1415926535
#define RADIAN(angle) ((angle)*PI/180.0) //convert angle to radian

CBitmap                m_bmp;
HBITMAP                hbit;
hbit = m_voimg.Copy();     //该句得到一个hbitmap句柄
m_bmp.Attach(hbit);

         ......

 HBITMAP tempbit;

tempbit = GetRotatedBitmap(hbit,RADIAN(90), RGB(255,255,0));
m_bmp .DeleteObject();
m_bmp.Attach(tempbit);

旋转函数:
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(this), 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 ) );



// 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 )
{
COLORREF col = sourceDC.GetPixel(sourcex,sourcey);
destDC.SetPixel(x,y,col);
}
}
}

// Restore DCs
::SelectObject( sourceDC.m_hDC, hbmOldSource );
::SelectObject( destDC.m_hDC, hbmOldDest );

return hbmResult;

}

结果我再次把m_bmp显示到屏幕上时,出来没有图象,只有单一的一片颜色,这个颜色为我调用GetRotatedBitmap(hbit,RADIAN(90), RGB(255,255,0)) 时,的最后一个参数的RGB颜色,为什么呢?难道是GetPixel()没有取到东西???请高手指点呀!

11 个解决方案

#1


例子:
http://www.vckbase.com/document/viewdoc.asp?id=451

#2


请用GDI+,里面旋转已经封装了,用matiax实现

#3


你传进来的是HBITMAP,那为什么又要转换成CDC呢?这不是绕了个弯吗?

#4


我是在CE下实现,CE下好象不支持这些吧?他的哪个EVC++,功能没有VC++强大。

#5


请问 jszj: 那我怎么直接用HBITMAP进行转换呢?

#6


help 呀...........

#7


/**
 * 快速旋转指定的Dib对象
 * @param pDib 待旋转的Dib对象
 * @param nAngle 旋转角度(角度制)
 */
void DIB_RotateFast(CDib *pDib, int nAngle) {
    int i, j;
    CDib *pTmp;
    nAngle %= 360;
    BYTE **scanLines = new BYTE*[pDib->m_nHeight];
    BYTE *pScanLine = pDib->m_pBits;
    for (i = 0; i < pDib->m_nHeight; i++) {
        *(scanLines+i) = pScanLine;
        pScanLine += pDib->m_nPitch;
    }
    switch (nAngle) {
    case 0:
        delete scanLines;
        return;
    case 90:
        pTmp = new CDib(pDib->m_nHeight, pDib->m_nWidth, COLOR_BLACK);
        DIB_Filter(pTmp, dib_Rotate90Filter, scanLines);
        *pDib = *pTmp;
        delete scanLines;
        delete pTmp;
        return;
    case 180:
        DIB_Flip(pDib, FLIP_HORIZONTAL | FLIP_VERTICAL);
        return;
    case 270:
        pTmp = new CDib(pDib->m_nHeight, pDib->m_nWidth, COLOR_BLACK);
        DIB_Filter(pTmp, dib_Rotate270Filter, scanLines);
        *pDib = *pTmp;
        delete scanLines;
        delete pTmp;
        return;
    default:
        break;
    }
    double dAngle = nAngle/180.0 * PI;
    int nSin = (int)(sin(dAngle)*65536.0+0.5);
    int nCos = (int)(cos(dAngle)*65536.0+0.5);
    POINT vertex[] = {
        {0, 0}, 
        {(pDib->m_nWidth*nCos) >> 16, (pDib->m_nWidth*nSin) >> 16}, 
        {(pDib->m_nWidth*nCos + pDib->m_nHeight*nSin) >> 16, (pDib->m_nWidth*nSin - pDib->m_nHeight*nCos) >> 16}, 
        {(pDib->m_nHeight*nSin) >> 16, (-pDib->m_nHeight*nCos) >> 16}
    };
    POINT newVertex[4];
    if (nAngle > 0 && nAngle < 90) {
        newVertex[0] = vertex[0];
        newVertex[1] = vertex[1];
        newVertex[2] = vertex[2];
        newVertex[3] = vertex[3];
    } else if (nAngle > 90 && nAngle < 180) {
        newVertex[0] = vertex[1];
        newVertex[1] = vertex[2];
        newVertex[2] = vertex[3];
        newVertex[3] = vertex[0];
    } else if (nAngle > 180 && nAngle < 270) {
        newVertex[0] = vertex[2];
        newVertex[1] = vertex[3];
        newVertex[2] = vertex[0];
        newVertex[3] = vertex[1];
    } else {
        newVertex[0] = vertex[3];
        newVertex[1] = vertex[0];
        newVertex[2] = vertex[1];
        newVertex[3] = vertex[2];
    }
    SIZE newSize;
    int edgeSlope[4];
    int edgeConst[4];
    int deltaX = nCos*newVertex[0].x+nSin*newVertex[1].y;
    int deltaY = nCos*newVertex[1].y-nSin*newVertex[0].x;
    dib_GetEdgeFormulas(newVertex, &newSize, edgeSlope, edgeConst);
    pTmp = new CDib(newSize.cx, newSize.cy, g_colorKey);
    int ox, oy;
    int boundLeft, boundRight;
    BYTE *pVInc = pTmp->m_pBits;  // 初始化为第一个扫描行的首地址(也就是整个图像数据的首址)
    // 水平方向的增量指针。每操作完一个像素,它就被指向下一个像素
    BYTE *pHInc = NULL;     // 它将在每次对一个扫描行开始处理之前被赋值
    int actualY = -pTmp->m_nHeight;
    for (i = 0; i > actualY; i--) {
        if (i > newVertex[0].y) {
            boundLeft = (edgeSlope[0]*i + edgeConst[0]) >> 16;
        } else {
            boundLeft = (edgeSlope[1]*i + edgeConst[1]) >> 16;
        } 
        if (i > newVertex[2].y) {
            boundRight = (edgeSlope[2]*i + edgeConst[2]) >> 16;
        } else {
            boundRight = (edgeSlope[3]*i + edgeConst[3]) >> 16;
        }
        pHInc = pVInc+boundLeft+boundLeft+boundLeft;      // 把水平增量指针初始化为当前扫描行的首址
        for (j = boundLeft; j < boundRight; j++) {
            ox = (nCos*j+nSin*i+deltaX) >> 16;
            oy = -((nCos*i-nSin*j+deltaY) >> 16);
            ox = ox < 0 ? 0 : ox;
            ox = ox >= pDib->m_nWidth ? pDib->m_nWidth-1 : ox;
            oy = oy < 0 ? 0 : oy;
            oy = oy >= pDib->m_nHeight ? pDib->m_nHeight-1 : oy;
            dib_SetColor(pHInc, dib_GetColor(*(scanLines+oy)+ox+ox+ox));
            pHInc += PIXELSIZE;     // 一个像素数据过滤完成,指针指向下一个
        }
        pVInc += pTmp->m_nPitch;          // 一个扫描行处理完,指针指向下一行
    }
    *pDib = *pTmp;
    delete scanLines;
    delete pTmp;
}

#8


void DIB_RotateFast(CDib *pDib, int nAngle)
这里的CDib是哪里来的呢,没有这个类呀。

#9


/**********************************************************
    dibcore.h WannaPlayDIB实用图形库 类、接口和核心API声明
    版权所有(C) 2001 WannaPlay 
    WannaPlay实用图形函数库完全*发放。
    任何人都可以没有限制的使用、修改和再发布本代码。
    同时作者也没有义务为代码可能对你的应用和系统造
    成的任何损害承担责任。
    发现任何Bug,缺陷,或有任何意见和建议,请联系作者。
    谢谢。
    Home Page:  http://wannaplay.51.net
    eMail:      rocks_lee@263.net
    OICQ:       17219193
***********************************************************/

#ifndef __WANNAPLAY_DIBCORE_H__
#define __WANNAPLAY_DIBCORE_H__

#include "dibstruct.h"

class CDib;
class IAbstractFilter;
class IImageWrapper;

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库自定义类型
//////////////////////////////////////////////////////////////////////

// 颜色数据。CDib每像素由3 bytes组成,在内存中的排列顺序是bbggrr,
// 这是与GDI的24位DIB完全相同的。
// 用这个类型可以一次得到全部三个分量,最高字节置零。
// 而Windows的COLORREF则是最低字节置零,所以必要时要做转换。
typedef DWORD               DIB_COLOR;

// 滤波器回调函数类型。可以与DIB_Filter()函数配合使用,以实现多种滤波算法。
// DIB_Filter()函数对每个像素回调该函数。
typedef void (CALLBACK* DIB_FILTERPROC)(CDib *pDib,         // 用这个参数配合下面的x 和 y,
                                        int x,              // 可以访问和本像素相关的其它像素。
                                        int y,              // 其实如果你愿意,是可以访问任何一个像素数据的。
                                        BYTE *pixel,        // 这是个快捷方式,如果你只对当前像素感兴趣。
                                        void *filterParam); // 回调函数自定义参数,从DIB_Filter()简单传递而来。

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库常量定义,包括常用颜色和每像素长度
//////////////////////////////////////////////////////////////////////

// 常用的几种颜色
#define COLOR_BLACK         ((DIB_COLOR)0x00000000)
#define COLOR_WHITE         ((DIB_COLOR)0x00ffffff)
#define COLOR_BLUE          ((DIB_COLOR)0x000000ff)
#define COLOR_GREEN         ((DIB_COLOR)0x0000ff00)
#define COLOR_RED           ((DIB_COLOR)0x00ff0000)

// 每像素的字节数
#define PIXELSIZE           3

// DIB_LoadImage的options
#define LOAD_FROMFILE       0x01
#define LOAD_FROMRES        0x02

// DIB_Flip的options
#define FLIP_HORIZONTAL     0x01
#define FLIP_VERTICAL       0x02

// DIB_Blt和DIB_BltFast的options
#define BLT_COLORKEY        0x01

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库常用宏定义
//////////////////////////////////////////////////////////////////////

// 从扫描行的像素数得到字节数。DIB的扫描行是双字(DWORD)对齐的
#define DIB_WIDTH2PITCH(w)       (((w)+(w)+(w)+3) & 0xfffffffc)

// 得到颜色的RED分量
#define DIB_RVALUE(color)       ((BYTE)(((DIB_COLOR)(color) & COLOR_RED)>>16))

// 得到颜色的GREEN分量
#define DIB_GVALUE(color)       ((BYTE)(((DIB_COLOR)(color) & COLOR_GREEN)>>8))

// 得到颜色的BLUE分量
#define DIB_BVALUE(color)       ((BYTE)((DIB_COLOR)(color) & COLOR_BLUE))

// 把三个BYTE分量重新组合成一个DIB_COLOR
#define DIB_RGB(r, g, b)        (0 | (((r)<<16)&COLOR_RED) | (((g)<<8)&COLOR_GREEN) | ((b)&COLOR_BLUE))

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库常用辅助函数
//////////////////////////////////////////////////////////////////////

// 用一个DIB_COLOR(4 Bytes)型参数快速给一个像素(3 Bytes)赋值
inline void dib_SetColor(BYTE *pPixel, DIB_COLOR color) {
    *((DIB_COLOR*)pPixel) &= 0xff000000;    // 把本像素清0,而下一个像素的首字节要保护起来
    *((DIB_COLOR*)pPixel) |= color;         // 这时像素的三个字节都为0,用or操作就可以了
}

// 把一个像素快速转换为DIB_COLOR类型
inline DIB_COLOR dib_GetColor(BYTE *pPixel) {
    DIB_COLOR ret = *((DIB_COLOR*)pPixel);  // 这样得到的值包含下一个像素的首字节
    return ret & 0x00ffffff;                // 把那个多余的字节屏蔽掉
}

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库的基本数据类型CDib的类定义和部分inline实现,
// 以及两个抽象的接口类,以便于灵活的扩展本库所支持的算法
// 和图形格式
//////////////////////////////////////////////////////////////////////

/**
 * CDib类对设备无关位图(DIB)进行了简单的封装,比起GDI API中定义的DIB,
 * 它更加简单而实用。
 * CDib类以24位(3 bytes)表示一个像素,与GDI中的24位DIB格式兼容。即:
 * 自底向上存储扫描行,每一扫描行长度DWORD对齐;
 * 每像素3字节,存储顺序为bbggrr。
 * WannaPlayDIB实用图形库所提供的所有算法都以CDib类作为操作对象和存储结构。
 */
class CDib {
public:
    /** 
     * 缺省的构造函数
     */
    CDib() : m_nWidth(0), m_nHeight(0), m_nPitch(0), m_pBits(NULL) {}

    /** 
     * 根据给定的大小和颜色构造一个CDib对象
     */
    CDib(int w, int h, DIB_COLOR colorInit);

    /**
     * 根据给定的大小和像素数据构造一个CDib对象
     */
    CDib(int w, int h, BYTE *pBits) : 
        m_nWidth(w), 
        m_nHeight(h), 
        m_nPitch(DIB_WIDTH2PITCH(w)),
        m_pBits(pBits) {}

    /** 
     * 根据另一个CDib对象构造一个新的CDib对象
     */
    CDib(CDib &refDib);

    virtual ~CDib();

    CDib operator =(CDib &refDib);

public:
    DIB_COLOR GetPixel(int x, int y) {
        return dib_GetColor(m_pBits+m_nPitch*y+x+x+x);
    }

    DIB_COLOR SetPixel(int x, int y, DIB_COLOR c) {
        dib_SetColor((BYTE*)(m_pBits+m_nPitch*y+x+x+x), c);
    }

public:
    int m_nWidth;

    int m_nHeight;

    int m_nPitch;

    BYTE *m_pBits;

};

/**
 * 实现这个接口,与DIB_Filter()函数配合使用,
 * 以支持更复杂的滤波算法(比如当像素间的互相关性较大时)
 */
class IAbstractFilter {
public:
    virtual void Filter(CDib *pDib, int x, int y, BYTE *pixel) = 0;
};

/**
 * 实现这个接口以支持更多的图形文件格式。
 * 可以在子类中保存图形的更多信息,以便定制载入和保存操作
 */
class IImageWrapper {
public:
    virtual CDib* LoadDib() = 0;

    virtual void SaveDib(CDib *pDib) = 0;
};

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库API定义
//////////////////////////////////////////////////////////////////////

CDib* DIB_LoadImage(IImageWrapper *loader);

void DIB_SaveImage(CDib *pDib, IImageWrapper *writer);

void DIB_Filter(CDib *pDib, DIB_FILTERPROC filterProc, void *filterParam);

void DIB_Filter(CDib *pDib, IAbstractFilter *filter);

void DIB_FilterRect(CDib *pDib, DIB_FILTERPROC filterProc, void *filterParam, LPRECT pRect);

void DIB_SetColorKey(int rr, int gg, int bb);

void DIB_SetColorKey(DIB_COLOR colorKey);

DIB_COLOR DIB_GetColorKey();

void DIB_RotateFast(CDib *pDib, int nAngle);

void DIB_Rotate(CDib *pDib, double dAngle);

void DIB_StretchFast(CDib *pDib, int newWidth, int newHeight);

void DIB_Stretch(CDib *pDib, int newWidth, int newHeight);

void DIB_Flip(CDib *pDib, UINT uOption);

void DIB_BltFast(CDib *pDibDest, 
                 int nXDest, 
                 int nYDest, 
                 CDib *pDibSrc, 
                 LPRECT pRectSrc,
                 UINT uOptions);

void DIB_AlphaBlend(CDib *pDibDest, 
                    int nXDest,
                    int nYDest,
                    CDib *pDibSrc,
                    LPRECT pRectSrc,
                    CDib *pDibAlpha,
                    int nXAlpha,
                    int nYAlpha);

void DIB_ClearColorRange(CDib *pDib, 
                         DIB_COLOR colorLow, 
                         DIB_COLOR colorHigh);

void DIB_Line(CDib *pDib, int x0, int y0, int x1, int y1);

#endif//__WANNAPLAY_DIBCORE_H__

#10


//////////////////////////////////////////////////////////////////////
// CDib类的成员函数实现
//////////////////////////////////////////////////////////////////////

/** 
 * 创建指定大小的单色图像。
 * @param w 宽度
 * @param h 高度
 * @param colorInit 初始化颜色
 * 注意,如果你只是想创建一块用来绘图的数据缓冲,
 * 那么请用黑色作为参数,效率将更高。
 */
CDib::CDib(int w, int h, DIB_COLOR colorInit) {
    m_nWidth = w;
    m_nHeight = h;
    m_nPitch = DIB_WIDTH2PITCH(w);
    int size = h*m_nPitch;
    m_pBits = new BYTE[size];   // 分配图像数据内存 
    memset(m_pBits, 0, size);   // 把这块得到的内存清0
    if (colorInit == COLOR_BLACK) {
        return;     // 因为黑色实际就是全0,所以这里就可以快速返回了
    }
    // 下面将用一个二重循环访问每一个像素,并用指定的颜色赋值
    int i = 0, j = 0;       // 循环计数器
    // 垂直方向的增量指针。每操作完一行数据,它就被指向下一个扫描行
    BYTE *pVInc = m_pBits;  // 初始化为第一个扫描行的首地址(也就是整个图像数据的首址)
    // 水平方向的增量指针。每操作完一个像素,它就被指向下一个像素
    BYTE *pHInc = NULL;     // 它将在每次对一个扫描行开始处理之前被赋值
    for (i = 0; i < h; i++) {
        pHInc = pVInc;      // 把水平增量指针初始化为当前扫描行的首址
        for (j = 0; j < w; j++) {
            dib_SetColor(pHInc, colorInit);
            pHInc += PIXELSIZE;     // 一个像素数据赋值完成,指针指向下一个
        }
        pVInc += m_nPitch;          // 一个扫描行处理完,指针指向下一行
    }
}

/** 
 * 把给定的CDib对象“克隆”一份,包括图像数据。
 * @param refDib 被clone对象的引用
 */
CDib::CDib(CDib &refDib) {
    m_nWidth = refDib.m_nWidth;
    m_nHeight = refDib.m_nHeight;
    m_nPitch = DIB_WIDTH2PITCH(m_nWidth);
    int size = m_nHeight * m_nPitch;
    m_pBits = new BYTE[size];
    memcpy(m_pBits, refDib.m_pBits, size);
}

/** 
 * 析构函数。
 * 把为这个CDib对象的图像数据分配的内存释放掉。
 */
CDib::~CDib() {
    if (m_pBits != NULL) {
        delete[] m_pBits;
    }
}

/** 
 * 重载等号运算符。
 * 这样你可以像对一个一般变量一样直接对一个CDib赋值。
 * 和上面的第二个构造函数一样,
 * 把给定的CDib对象“克隆”一份,包括图像数据。
 * @param refDib 被clone对象的引用
 */
CDib CDib::operator =(CDib &refDib) {
    if (this == &refDib) {
        return *this;
    }
    if (m_pBits != NULL) {
        delete[] m_pBits;
    }
    m_nWidth = refDib.m_nWidth;
    m_nHeight = refDib.m_nHeight;
    m_nPitch = DIB_WIDTH2PITCH(m_nWidth);
    int size = m_nHeight * m_nPitch;
    m_pBits = new BYTE[size];
    memcpy(m_pBits, refDib.m_pBits, size);
    return *this;
}

#11


用GDI+解决:
REAL PosX,PosY; //图像的初始位置
REAL centerX,centerY; //旋转中心
REAL Rangle; //旋转角度
PointF CenterPoint(centerX,centerY);
Graphics graphics(hdc);
Image newImage(L("filename")); //要旋转的图像
Matrix RotateMatrix; //旋转矩阵
graphics.DrawImage (newImage,PosX,PosY);
rotateMatrix.RotateAt(Rangle,CenterPoint,MatrixOrderPrepend)
graphics.SetTransform(RotateMatrix);

#1


例子:
http://www.vckbase.com/document/viewdoc.asp?id=451

#2


请用GDI+,里面旋转已经封装了,用matiax实现

#3


你传进来的是HBITMAP,那为什么又要转换成CDC呢?这不是绕了个弯吗?

#4


我是在CE下实现,CE下好象不支持这些吧?他的哪个EVC++,功能没有VC++强大。

#5


请问 jszj: 那我怎么直接用HBITMAP进行转换呢?

#6


help 呀...........

#7


/**
 * 快速旋转指定的Dib对象
 * @param pDib 待旋转的Dib对象
 * @param nAngle 旋转角度(角度制)
 */
void DIB_RotateFast(CDib *pDib, int nAngle) {
    int i, j;
    CDib *pTmp;
    nAngle %= 360;
    BYTE **scanLines = new BYTE*[pDib->m_nHeight];
    BYTE *pScanLine = pDib->m_pBits;
    for (i = 0; i < pDib->m_nHeight; i++) {
        *(scanLines+i) = pScanLine;
        pScanLine += pDib->m_nPitch;
    }
    switch (nAngle) {
    case 0:
        delete scanLines;
        return;
    case 90:
        pTmp = new CDib(pDib->m_nHeight, pDib->m_nWidth, COLOR_BLACK);
        DIB_Filter(pTmp, dib_Rotate90Filter, scanLines);
        *pDib = *pTmp;
        delete scanLines;
        delete pTmp;
        return;
    case 180:
        DIB_Flip(pDib, FLIP_HORIZONTAL | FLIP_VERTICAL);
        return;
    case 270:
        pTmp = new CDib(pDib->m_nHeight, pDib->m_nWidth, COLOR_BLACK);
        DIB_Filter(pTmp, dib_Rotate270Filter, scanLines);
        *pDib = *pTmp;
        delete scanLines;
        delete pTmp;
        return;
    default:
        break;
    }
    double dAngle = nAngle/180.0 * PI;
    int nSin = (int)(sin(dAngle)*65536.0+0.5);
    int nCos = (int)(cos(dAngle)*65536.0+0.5);
    POINT vertex[] = {
        {0, 0}, 
        {(pDib->m_nWidth*nCos) >> 16, (pDib->m_nWidth*nSin) >> 16}, 
        {(pDib->m_nWidth*nCos + pDib->m_nHeight*nSin) >> 16, (pDib->m_nWidth*nSin - pDib->m_nHeight*nCos) >> 16}, 
        {(pDib->m_nHeight*nSin) >> 16, (-pDib->m_nHeight*nCos) >> 16}
    };
    POINT newVertex[4];
    if (nAngle > 0 && nAngle < 90) {
        newVertex[0] = vertex[0];
        newVertex[1] = vertex[1];
        newVertex[2] = vertex[2];
        newVertex[3] = vertex[3];
    } else if (nAngle > 90 && nAngle < 180) {
        newVertex[0] = vertex[1];
        newVertex[1] = vertex[2];
        newVertex[2] = vertex[3];
        newVertex[3] = vertex[0];
    } else if (nAngle > 180 && nAngle < 270) {
        newVertex[0] = vertex[2];
        newVertex[1] = vertex[3];
        newVertex[2] = vertex[0];
        newVertex[3] = vertex[1];
    } else {
        newVertex[0] = vertex[3];
        newVertex[1] = vertex[0];
        newVertex[2] = vertex[1];
        newVertex[3] = vertex[2];
    }
    SIZE newSize;
    int edgeSlope[4];
    int edgeConst[4];
    int deltaX = nCos*newVertex[0].x+nSin*newVertex[1].y;
    int deltaY = nCos*newVertex[1].y-nSin*newVertex[0].x;
    dib_GetEdgeFormulas(newVertex, &newSize, edgeSlope, edgeConst);
    pTmp = new CDib(newSize.cx, newSize.cy, g_colorKey);
    int ox, oy;
    int boundLeft, boundRight;
    BYTE *pVInc = pTmp->m_pBits;  // 初始化为第一个扫描行的首地址(也就是整个图像数据的首址)
    // 水平方向的增量指针。每操作完一个像素,它就被指向下一个像素
    BYTE *pHInc = NULL;     // 它将在每次对一个扫描行开始处理之前被赋值
    int actualY = -pTmp->m_nHeight;
    for (i = 0; i > actualY; i--) {
        if (i > newVertex[0].y) {
            boundLeft = (edgeSlope[0]*i + edgeConst[0]) >> 16;
        } else {
            boundLeft = (edgeSlope[1]*i + edgeConst[1]) >> 16;
        } 
        if (i > newVertex[2].y) {
            boundRight = (edgeSlope[2]*i + edgeConst[2]) >> 16;
        } else {
            boundRight = (edgeSlope[3]*i + edgeConst[3]) >> 16;
        }
        pHInc = pVInc+boundLeft+boundLeft+boundLeft;      // 把水平增量指针初始化为当前扫描行的首址
        for (j = boundLeft; j < boundRight; j++) {
            ox = (nCos*j+nSin*i+deltaX) >> 16;
            oy = -((nCos*i-nSin*j+deltaY) >> 16);
            ox = ox < 0 ? 0 : ox;
            ox = ox >= pDib->m_nWidth ? pDib->m_nWidth-1 : ox;
            oy = oy < 0 ? 0 : oy;
            oy = oy >= pDib->m_nHeight ? pDib->m_nHeight-1 : oy;
            dib_SetColor(pHInc, dib_GetColor(*(scanLines+oy)+ox+ox+ox));
            pHInc += PIXELSIZE;     // 一个像素数据过滤完成,指针指向下一个
        }
        pVInc += pTmp->m_nPitch;          // 一个扫描行处理完,指针指向下一行
    }
    *pDib = *pTmp;
    delete scanLines;
    delete pTmp;
}

#8


void DIB_RotateFast(CDib *pDib, int nAngle)
这里的CDib是哪里来的呢,没有这个类呀。

#9


/**********************************************************
    dibcore.h WannaPlayDIB实用图形库 类、接口和核心API声明
    版权所有(C) 2001 WannaPlay 
    WannaPlay实用图形函数库完全*发放。
    任何人都可以没有限制的使用、修改和再发布本代码。
    同时作者也没有义务为代码可能对你的应用和系统造
    成的任何损害承担责任。
    发现任何Bug,缺陷,或有任何意见和建议,请联系作者。
    谢谢。
    Home Page:  http://wannaplay.51.net
    eMail:      rocks_lee@263.net
    OICQ:       17219193
***********************************************************/

#ifndef __WANNAPLAY_DIBCORE_H__
#define __WANNAPLAY_DIBCORE_H__

#include "dibstruct.h"

class CDib;
class IAbstractFilter;
class IImageWrapper;

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库自定义类型
//////////////////////////////////////////////////////////////////////

// 颜色数据。CDib每像素由3 bytes组成,在内存中的排列顺序是bbggrr,
// 这是与GDI的24位DIB完全相同的。
// 用这个类型可以一次得到全部三个分量,最高字节置零。
// 而Windows的COLORREF则是最低字节置零,所以必要时要做转换。
typedef DWORD               DIB_COLOR;

// 滤波器回调函数类型。可以与DIB_Filter()函数配合使用,以实现多种滤波算法。
// DIB_Filter()函数对每个像素回调该函数。
typedef void (CALLBACK* DIB_FILTERPROC)(CDib *pDib,         // 用这个参数配合下面的x 和 y,
                                        int x,              // 可以访问和本像素相关的其它像素。
                                        int y,              // 其实如果你愿意,是可以访问任何一个像素数据的。
                                        BYTE *pixel,        // 这是个快捷方式,如果你只对当前像素感兴趣。
                                        void *filterParam); // 回调函数自定义参数,从DIB_Filter()简单传递而来。

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库常量定义,包括常用颜色和每像素长度
//////////////////////////////////////////////////////////////////////

// 常用的几种颜色
#define COLOR_BLACK         ((DIB_COLOR)0x00000000)
#define COLOR_WHITE         ((DIB_COLOR)0x00ffffff)
#define COLOR_BLUE          ((DIB_COLOR)0x000000ff)
#define COLOR_GREEN         ((DIB_COLOR)0x0000ff00)
#define COLOR_RED           ((DIB_COLOR)0x00ff0000)

// 每像素的字节数
#define PIXELSIZE           3

// DIB_LoadImage的options
#define LOAD_FROMFILE       0x01
#define LOAD_FROMRES        0x02

// DIB_Flip的options
#define FLIP_HORIZONTAL     0x01
#define FLIP_VERTICAL       0x02

// DIB_Blt和DIB_BltFast的options
#define BLT_COLORKEY        0x01

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库常用宏定义
//////////////////////////////////////////////////////////////////////

// 从扫描行的像素数得到字节数。DIB的扫描行是双字(DWORD)对齐的
#define DIB_WIDTH2PITCH(w)       (((w)+(w)+(w)+3) & 0xfffffffc)

// 得到颜色的RED分量
#define DIB_RVALUE(color)       ((BYTE)(((DIB_COLOR)(color) & COLOR_RED)>>16))

// 得到颜色的GREEN分量
#define DIB_GVALUE(color)       ((BYTE)(((DIB_COLOR)(color) & COLOR_GREEN)>>8))

// 得到颜色的BLUE分量
#define DIB_BVALUE(color)       ((BYTE)((DIB_COLOR)(color) & COLOR_BLUE))

// 把三个BYTE分量重新组合成一个DIB_COLOR
#define DIB_RGB(r, g, b)        (0 | (((r)<<16)&COLOR_RED) | (((g)<<8)&COLOR_GREEN) | ((b)&COLOR_BLUE))

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库常用辅助函数
//////////////////////////////////////////////////////////////////////

// 用一个DIB_COLOR(4 Bytes)型参数快速给一个像素(3 Bytes)赋值
inline void dib_SetColor(BYTE *pPixel, DIB_COLOR color) {
    *((DIB_COLOR*)pPixel) &= 0xff000000;    // 把本像素清0,而下一个像素的首字节要保护起来
    *((DIB_COLOR*)pPixel) |= color;         // 这时像素的三个字节都为0,用or操作就可以了
}

// 把一个像素快速转换为DIB_COLOR类型
inline DIB_COLOR dib_GetColor(BYTE *pPixel) {
    DIB_COLOR ret = *((DIB_COLOR*)pPixel);  // 这样得到的值包含下一个像素的首字节
    return ret & 0x00ffffff;                // 把那个多余的字节屏蔽掉
}

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库的基本数据类型CDib的类定义和部分inline实现,
// 以及两个抽象的接口类,以便于灵活的扩展本库所支持的算法
// 和图形格式
//////////////////////////////////////////////////////////////////////

/**
 * CDib类对设备无关位图(DIB)进行了简单的封装,比起GDI API中定义的DIB,
 * 它更加简单而实用。
 * CDib类以24位(3 bytes)表示一个像素,与GDI中的24位DIB格式兼容。即:
 * 自底向上存储扫描行,每一扫描行长度DWORD对齐;
 * 每像素3字节,存储顺序为bbggrr。
 * WannaPlayDIB实用图形库所提供的所有算法都以CDib类作为操作对象和存储结构。
 */
class CDib {
public:
    /** 
     * 缺省的构造函数
     */
    CDib() : m_nWidth(0), m_nHeight(0), m_nPitch(0), m_pBits(NULL) {}

    /** 
     * 根据给定的大小和颜色构造一个CDib对象
     */
    CDib(int w, int h, DIB_COLOR colorInit);

    /**
     * 根据给定的大小和像素数据构造一个CDib对象
     */
    CDib(int w, int h, BYTE *pBits) : 
        m_nWidth(w), 
        m_nHeight(h), 
        m_nPitch(DIB_WIDTH2PITCH(w)),
        m_pBits(pBits) {}

    /** 
     * 根据另一个CDib对象构造一个新的CDib对象
     */
    CDib(CDib &refDib);

    virtual ~CDib();

    CDib operator =(CDib &refDib);

public:
    DIB_COLOR GetPixel(int x, int y) {
        return dib_GetColor(m_pBits+m_nPitch*y+x+x+x);
    }

    DIB_COLOR SetPixel(int x, int y, DIB_COLOR c) {
        dib_SetColor((BYTE*)(m_pBits+m_nPitch*y+x+x+x), c);
    }

public:
    int m_nWidth;

    int m_nHeight;

    int m_nPitch;

    BYTE *m_pBits;

};

/**
 * 实现这个接口,与DIB_Filter()函数配合使用,
 * 以支持更复杂的滤波算法(比如当像素间的互相关性较大时)
 */
class IAbstractFilter {
public:
    virtual void Filter(CDib *pDib, int x, int y, BYTE *pixel) = 0;
};

/**
 * 实现这个接口以支持更多的图形文件格式。
 * 可以在子类中保存图形的更多信息,以便定制载入和保存操作
 */
class IImageWrapper {
public:
    virtual CDib* LoadDib() = 0;

    virtual void SaveDib(CDib *pDib) = 0;
};

//////////////////////////////////////////////////////////////////////
// WannaPlayDIB实用图形库API定义
//////////////////////////////////////////////////////////////////////

CDib* DIB_LoadImage(IImageWrapper *loader);

void DIB_SaveImage(CDib *pDib, IImageWrapper *writer);

void DIB_Filter(CDib *pDib, DIB_FILTERPROC filterProc, void *filterParam);

void DIB_Filter(CDib *pDib, IAbstractFilter *filter);

void DIB_FilterRect(CDib *pDib, DIB_FILTERPROC filterProc, void *filterParam, LPRECT pRect);

void DIB_SetColorKey(int rr, int gg, int bb);

void DIB_SetColorKey(DIB_COLOR colorKey);

DIB_COLOR DIB_GetColorKey();

void DIB_RotateFast(CDib *pDib, int nAngle);

void DIB_Rotate(CDib *pDib, double dAngle);

void DIB_StretchFast(CDib *pDib, int newWidth, int newHeight);

void DIB_Stretch(CDib *pDib, int newWidth, int newHeight);

void DIB_Flip(CDib *pDib, UINT uOption);

void DIB_BltFast(CDib *pDibDest, 
                 int nXDest, 
                 int nYDest, 
                 CDib *pDibSrc, 
                 LPRECT pRectSrc,
                 UINT uOptions);

void DIB_AlphaBlend(CDib *pDibDest, 
                    int nXDest,
                    int nYDest,
                    CDib *pDibSrc,
                    LPRECT pRectSrc,
                    CDib *pDibAlpha,
                    int nXAlpha,
                    int nYAlpha);

void DIB_ClearColorRange(CDib *pDib, 
                         DIB_COLOR colorLow, 
                         DIB_COLOR colorHigh);

void DIB_Line(CDib *pDib, int x0, int y0, int x1, int y1);

#endif//__WANNAPLAY_DIBCORE_H__

#10


//////////////////////////////////////////////////////////////////////
// CDib类的成员函数实现
//////////////////////////////////////////////////////////////////////

/** 
 * 创建指定大小的单色图像。
 * @param w 宽度
 * @param h 高度
 * @param colorInit 初始化颜色
 * 注意,如果你只是想创建一块用来绘图的数据缓冲,
 * 那么请用黑色作为参数,效率将更高。
 */
CDib::CDib(int w, int h, DIB_COLOR colorInit) {
    m_nWidth = w;
    m_nHeight = h;
    m_nPitch = DIB_WIDTH2PITCH(w);
    int size = h*m_nPitch;
    m_pBits = new BYTE[size];   // 分配图像数据内存 
    memset(m_pBits, 0, size);   // 把这块得到的内存清0
    if (colorInit == COLOR_BLACK) {
        return;     // 因为黑色实际就是全0,所以这里就可以快速返回了
    }
    // 下面将用一个二重循环访问每一个像素,并用指定的颜色赋值
    int i = 0, j = 0;       // 循环计数器
    // 垂直方向的增量指针。每操作完一行数据,它就被指向下一个扫描行
    BYTE *pVInc = m_pBits;  // 初始化为第一个扫描行的首地址(也就是整个图像数据的首址)
    // 水平方向的增量指针。每操作完一个像素,它就被指向下一个像素
    BYTE *pHInc = NULL;     // 它将在每次对一个扫描行开始处理之前被赋值
    for (i = 0; i < h; i++) {
        pHInc = pVInc;      // 把水平增量指针初始化为当前扫描行的首址
        for (j = 0; j < w; j++) {
            dib_SetColor(pHInc, colorInit);
            pHInc += PIXELSIZE;     // 一个像素数据赋值完成,指针指向下一个
        }
        pVInc += m_nPitch;          // 一个扫描行处理完,指针指向下一行
    }
}

/** 
 * 把给定的CDib对象“克隆”一份,包括图像数据。
 * @param refDib 被clone对象的引用
 */
CDib::CDib(CDib &refDib) {
    m_nWidth = refDib.m_nWidth;
    m_nHeight = refDib.m_nHeight;
    m_nPitch = DIB_WIDTH2PITCH(m_nWidth);
    int size = m_nHeight * m_nPitch;
    m_pBits = new BYTE[size];
    memcpy(m_pBits, refDib.m_pBits, size);
}

/** 
 * 析构函数。
 * 把为这个CDib对象的图像数据分配的内存释放掉。
 */
CDib::~CDib() {
    if (m_pBits != NULL) {
        delete[] m_pBits;
    }
}

/** 
 * 重载等号运算符。
 * 这样你可以像对一个一般变量一样直接对一个CDib赋值。
 * 和上面的第二个构造函数一样,
 * 把给定的CDib对象“克隆”一份,包括图像数据。
 * @param refDib 被clone对象的引用
 */
CDib CDib::operator =(CDib &refDib) {
    if (this == &refDib) {
        return *this;
    }
    if (m_pBits != NULL) {
        delete[] m_pBits;
    }
    m_nWidth = refDib.m_nWidth;
    m_nHeight = refDib.m_nHeight;
    m_nPitch = DIB_WIDTH2PITCH(m_nWidth);
    int size = m_nHeight * m_nPitch;
    m_pBits = new BYTE[size];
    memcpy(m_pBits, refDib.m_pBits, size);
    return *this;
}

#11


用GDI+解决:
REAL PosX,PosY; //图像的初始位置
REAL centerX,centerY; //旋转中心
REAL Rangle; //旋转角度
PointF CenterPoint(centerX,centerY);
Graphics graphics(hdc);
Image newImage(L("filename")); //要旋转的图像
Matrix RotateMatrix; //旋转矩阵
graphics.DrawImage (newImage,PosX,PosY);
rotateMatrix.RotateAt(Rangle,CenterPoint,MatrixOrderPrepend)
graphics.SetTransform(RotateMatrix);