正文:
  为了便于讨论,这里只处理32bit的ARGB颜色;
  代码使用C++;涉及到汇编优化的时候假定为x86平台;使用的编译器为vc2005;
  为了代码的可读性,没有加入异常处理代码;
   测试使用的CPU为AMD64x2 4200+(2.37G),测试时使用的单线程执行;
  (一些基础代码和插值原理的详细说明参见作者的《图形图像处理-之-高质量的快速的图像缩放》系列文章
   旋转原理和基础参考《图形图像处理-之-任意角度的高质量的快速的图像旋转 上篇 纯软件的任意角度的快速旋转》)


速度测试说明:
  只测试内存数据到内存数据的缩放
  测试图片都是800*600旋转到1004*1004,测试成绩取各个旋转角度的平均速度值; fps表示每秒钟的帧数,值越大表示函数越快


A:一些颜色和图片的数据定义:

#define asm __asm

typedef unsigned char TUInt8; // [0..255]
struct TARGB32      //32 bit color
{
    TUInt8  b,g,r,a;          //a is alpha
};

struct TPicRegion  //一块颜色数据区的描述,便于参数传递
{
    TARGB32*    pdata;         //颜色数据首地址
    long        byte_width;    //一行数据的物理宽度(字节宽度);
                //abs(byte_width)有可能大于等于width*sizeof(TARGB32);
    long        width;         //像素宽度
    long        height;        //像素高度
};

  inline TARGB32& Pixels(TARGB32* pcolor,const long byte_width,const long x,const long y)
  {
    return ( (TARGB32*)((TUInt8*)pcolor+byte_width*y) )[x];
  }

//那么访问一个点的函数可以写为:
inline TARGB32& Pixels(const TPicRegion& pic,const long x,const long y)
{
    return Pixels(pic.pdata,pic.byte_width,x,y);
}
//判断一个点是否在图片中
inline bool PixelsIsInPic(const TPicRegion& pic,const long x,const long y)
{
    return ( (x>=0)&&(x<pic.width) && (y>=0)&&(y<pic.height) );
}

//访问一个点的函数,(x,y)坐标可能超出图片边界; //边界处理模式:边界饱和
inline TARGB32& Pixels_Bound(const TPicRegion& pic,long x,long y)
{
    //assert((pic.width>0)&&(pic.height>0));
    if (x<0) x=0; else if (x>=pic.width ) x=pic.width -1;
    if (y<0) y=0; else if (y>=pic.height) y=pic.height-1;
    return Pixels(pic,x,y);
}

inline TARGB32& Pixels_Bound(const TPicRegion& pic,long x,long y,bool& IsInPic)
{
    //assert((pic.width>0)&&(pic.height>0));
    IsInPic=true;
    if (x<0) {x=0; IsInPic=false; } else if (x>=pic.width ) {x=pic.width -1; IsInPic=false; }
    if (y<0) {y=0; IsInPic=false; } else if (y>=pic.height) {y=pic.height-1; IsInPic=false; }
    return Pixels(pic,x,y);
}

B:实现二次线性插值的旋转

(插值原理参见我的blog文章《图形图像处理-之-高质量的快速的图像缩放 中篇 二次线性插值和三次卷积插值》)

   a.首先改写用于边界扫描的类TRotaryClipData;在图片边缘插值的时候,插值的颜色数据可能
部分在图片外,部分颜色数据在图片内,所以TRotaryClipData需要同时找出“插值边界以外”、
“插值边界”、“插值边界以内”
    扫描线图示:       外    | 边界 |      内     | 边界 |    外  

struct TRotaryClipData{
public:
    long src_width;
    long src_height;
    long dst_width;
    long dst_height;
    long Ax_16; 
    long Ay_16; 
    long Bx_16; 
    long By_16; 
    long Cx_16;
    long Cy_16; 
    long border_width;//插值边界宽度
private:
    long cur_dst_up_x0;
    long cur_dst_up_x1;
    long cur_dst_down_x0;
    long cur_dst_down_x1;
    inline bool is_border_src(long src_x_16,long src_y_16)
    {
         return ( ( (src_x_16>=(-(border_width<<16)))&&((src_x_16>>16)<(src_width +border_width)) )
               && ( (src_y_16>=(-(border_width<<16)))&&((src_y_16>>16)<(src_height+border_width)) ) );
    }
    inline bool is_in_src(long src_x_16,long src_y_16)
    {
         return ( ( (src_x_16>=(border_width<<16))&&((src_x_16>>16)<(src_width-border_width) ) )
               && ( (src_y_16>=(border_width<<16))&&((src_y_16>>16)<(src_height-border_width)) ) );
    }
    void find_begin_in(long dst_y,long& out_dst_x,long& src_x_16,long& src_y_16)
    {
        src_x_16-=Ax_16;
        src_y_16-=Ay_16;
        while (is_border_src(src_x_16,src_y_16))
        {
            --out_dst_x;
            src_x_16-=Ax_16;
            src_y_16-=Ay_16;
        }
        src_x_16+=Ax_16;
        src_y_16+=Ay_16;
    }
    bool find_begin(long dst_y,long& out_dst_x0,long dst_x1)
    {
        long test_dst_x0=out_dst_x0-1;
        long src_x_16=Ax_16*test_dst_x0 + Bx_16*dst_y + Cx_16;
        long src_y_16=Ay_16*test_dst_x0 + By_16*dst_y + Cy_16;
        for (long i=test_dst_x0;i<=dst_x1;++i)
        {
            if (is_border_src(src_x_16,src_y_16))
            {
                out_dst_x0=i;
                if (i==test_dst_x0)
                    find_begin_in(dst_y,out_dst_x0,src_x_16,src_y_16);
                if (out_dst_x0<0)
                {
                    src_x_16-=(Ax_16*out_dst_x0);
                    src_y_16-=(Ay_16*out_dst_x0);
                }
                out_src_x0_16=src_x_16;
                out_src_y0_16=src_y_16;
                return true;
            }
            else
            {
                src_x_16+=Ax_16;
                src_y_16+=Ay_16;
            }
        }
        return false;
    }
    void find_end(long dst_y,long dst_x0,long& out_dst_x1)
    {
        long test_dst_x1=out_dst_x1;
        if (test_dst_x1<dst_x0) test_dst_x1=dst_x0;

        long src_x_16=Ax_16*test_dst_x1 + Bx_16*dst_y + Cx_16;
        long src_y_16=Ay_16*test_dst_x1 + By_16*dst_y + Cy_16;
        if (is_border_src(src_x_16,src_y_16))
        {
            ++test_dst_x1;
            src_x_16+=Ax_16;
            src_y_16+=Ay_16;
            while (is_border_src(src_x_16,src_y_16))
            {
                ++test_dst_x1;
                src_x_16+=Ax_16;
                src_y_16+=Ay_16;
            }
            out_dst_x1=test_dst_x1;
        }
        else
        {
            src_x_16-=Ax_16;
            src_y_16-=Ay_16;
            while (!is_border_src(src_x_16,src_y_16))
            {
                --test_dst_x1;
                src_x_16-=Ax_16;
                src_y_16-=Ay_16;
            }
            out_dst_x1=test_dst_x1;
        }
    }

    inline void update_out_dst_x_in()
    {
        if ((0==border_width)||(out_dst_x0_boder>=out_dst_x1_boder) )
        {
            out_dst_x0_in=out_dst_x0_boder;
            out_dst_x1_in=out_dst_x1_boder;
        }
        else
        {
            long src_x_16=out_src_x0_16;
            long src_y_16=out_src_y0_16;
            long i=out_dst_x0_boder;
            while (i<out_dst_x1_boder)
            {
                if (is_in_src(src_x_16,src_y_16)) break;
                src_x_16+=Ax_16;
                src_y_16+=Ay_16;
                ++i;
            }
            out_dst_x0_in=i;

            src_x_16=out_src_x0_16+(out_dst_x1_boder-out_dst_x0_boder)*Ax_16;
            src_y_16=out_src_y0_16+(out_dst_x1_boder-out_dst_x0_boder)*Ay_16;
            i=out_dst_x1_boder;
            while (i>out_dst_x0_in)
            {
                src_x_16-=Ax_16;
                src_y_16-=Ay_16;
                if (is_in_src(src_x_16,src_y_16)) break;
                --i;
            }
            out_dst_x1_in=i;
        }
    }
    inline void update_out_dst_up_x()
    {
        if (cur_dst_up_x0<0)
            out_dst_x0_boder=0;
        else
            out_dst_x0_boder=cur_dst_up_x0;
        if (cur_dst_up_x1>=dst_width)
            out_dst_x1_boder=dst_width;
        else
            out_dst_x1_boder=cur_dst_up_x1;
        update_out_dst_x_in();
    }
    inline void update_out_dst_down_x()
    {
        if (cur_dst_down_x0<0)
            out_dst_x0_boder=0;
        else
            out_dst_x0_boder=cur_dst_down_x0;
        if (cur_dst_down_x1>=dst_width)
            out_dst_x1_boder=dst_width;
        else
            out_dst_x1_boder=cur_dst_down_x1;
        update_out_dst_x_in();
    }

public:
    long out_src_x0_16;
    long out_src_y0_16;

    long out_dst_up_y;
    long out_dst_down_y;

    long out_dst_x0_boder;
    long out_dst_x0_in;
    long out_dst_x1_in;
    long out_dst_x1_boder;

public:
    bool inti_clip(double move_x,double move_y,unsigned long aborder_width)
    {
        border_width=aborder_width;

        //计算src中心点映射到dst后的坐标
        out_dst_down_y=(long)(src_height*0.5+move_y);
        cur_dst_down_x0=(long)(src_width*0.5+move_x);
        cur_dst_down_x1=cur_dst_down_x0;
        //得到初始扫描线
        if (find_begin(out_dst_down_y,cur_dst_down_x0,cur_dst_down_x1))
            find_end(out_dst_down_y,cur_dst_down_x0,cur_dst_down_x1);
        out_dst_up_y=out_dst_down_y;
        cur_dst_up_x0=cur_dst_down_x0;
        cur_dst_up_x1=cur_dst_down_x1;
        update_out_dst_up_x();
        return (cur_dst_down_x0<cur_dst_down_x1);
    }
    bool next_clip_line_down()
    {
        ++out_dst_down_y;
        if (!find_begin(out_dst_down_y,cur_dst_down_x0,cur_dst_down_x1)) return false;
        find_end(out_dst_down_y,cur_dst_down_x0,cur_dst_down_x1);
        update_out_dst_down_x();
        return (cur_dst_down_x0<cur_dst_down_x1);
    }
    bool next_clip_line_up()
    {
        --out_dst_up_y;
        if (!find_begin(out_dst_up_y,cur_dst_up_x0,cur_dst_up_x1)) return false;
        find_end(out_dst_up_y,cur_dst_up_x0,cur_dst_up_x1);
        update_out_dst_up_x();
        return (cur_dst_up_x0<cur_dst_up_x1);
    }
};

 b. 边界插值的特殊处理
      对于“插值边界以外”很简单,不用处理直接跳过插值;
      对于“插值边界以内”,也比较容易处理,直接调用快速的差值算法就可以了,不用担心内存访问问题;
        插值实现:
 (从《图形图像处理-之-高质量的快速的图像缩放 中篇 二次线性插值和三次卷积插值》文章来的,后面不再说明)

 inline void BilInear_Fast(const TPicRegion& pic,const long x_16,const long y_16,TARGB32* result)
    {
        TARGB32* PColor0=&Pixels(pic,x_16>>16,y_16>>16);
        TARGB32* PColor1=(TARGB32*)((TUInt8*)PColor0+pic.byte_width); 
        unsigned long u_8=(unsigned char)(x_16>>8);
        unsigned long v_8=(unsigned char)(y_16>>8);
        unsigned long pm3_8=(u_8*v_8)>>8;
        unsigned long pm2_8=u_8-pm3_8;
        unsigned long pm1_8=v_8-pm3_8;
        unsigned long pm0_8=256-pm1_8-pm2_8-pm3_8;

        unsigned long Color=*(unsigned long*)(PColor0);
        unsigned long BR=(Color & 0x00FF00FF)*pm0_8;
        unsigned long GA=((Color & 0xFF00FF00)>>8)*pm0_8;
                      Color=((unsigned long*)(PColor0))[1];
                      GA+=((Color & 0xFF00FF00)>>8)*pm2_8;
                      BR+=(Color & 0x00FF00FF)*pm2_8;
                      Color=*(unsigned long*)(PColor1);
                      GA+=((Color & 0xFF00FF00)>>8)*pm1_8;
                      BR+=(Color & 0x00FF00FF)*pm1_8;
                      Color=((unsigned long*)(PColor1))[1];
                      GA+=((Color & 0xFF00FF00)>>8)*pm3_8;
                      BR+=(Color & 0x00FF00FF)*pm3_8;

        *(unsigned long*)result=(GA & 0xFF00FF00)|((BR & 0xFF00FF00)>>8);
    }
      对于“插值边界”,就需要特殊处理了,很多插值旋转的实现可能都在这里打了折扣;要想完美的解决
   这块区域,可以引入AlphaBlend(带Alpha通道的颜色混合) ;
     
      其实AlphaBlend的原理也很简单,就是按不同的比例混合两种颜色:
         new_color=dst_color*(1-alpha)+src_color*alpha;
      对于ARGB32bit颜色,需要用该公式分别处理4个颜色通道,并假设Alpha为[0..255]的整数,那么完整的实现函数为:
  inline TARGB32 AlphaBlend(TARGB32 dst,TARGB32 src)
    {
        //AlphaBlend颜色混合公式(对其中的每个颜色分量分别处理):
        // new_color=(dst_color*(255-src_color.alpha)+src_color*src_color.alpha)/255

        //提示:除法指令是很慢的操作,但vc2005可以把x/255编译为完全等价的"(x*M)>>N"类似的快速计算代码;
        unsigned long a=src.a;
        //if (a==0) return dst;
        //else if (a==255) return src;
        unsigned long ra=255-a;
        unsigned long result_b=(dst.b*ra+src.b*a)/255;
        unsigned long result_g=(dst.g*ra+src.g*a)/255;
        unsigned long result_r=(dst.r*ra+src.r*a)/255;
        unsigned long result_a=(dst.a*ra+a*a)/255;
        unsigned long result=(result_b) | (result_g<<8) | (result_r<<16) | (result_a<<24);
        return *(TARGB32*)&result;
    }

 优化AlphaBlend,颜色处理中,也可以这样近似计算: x/255  =>  x>>8 ,所以有:

 inline TARGB32 AlphaBlend(TARGB32 dst,TARGB32 src)
    {
        unsigned long a=src.a;
        unsigned long ra=255-a;
        unsigned long result_b=(dst.b*ra+src.b*a)>>8;
        unsigned long result_g=(dst.g*ra+src.g*a)>>8;
        unsigned long result_r=(dst.r*ra+src.r*a)>>8;
        unsigned long result_a=(dst.a*ra+a*a)>>8;
        unsigned long result=(result_b) | (result_g<<8) | (result_r<<16) | (result_a<<24);
        return *(TARGB32*)&result;
    }
  (dst*(255-alpha)+src*alpha)>>8 可以近似为:(dst*(256-alpha)+src*alpha)>>8 
         即 (dst<<8+(src-dst)*alpha)>>8  从而用一个移位代替一个乘法 (*256会被优化为移位)
    inline TARGB32 AlphaBlend(TARGB32 dst,TARGB32 src)
    {
        long a=src.a;
        unsigned long result_b=((unsigned long)(((long)dst.b)*256+((long)src.b-(long)dst.b)*a))>>8;
        unsigned long result_g=((unsigned long)(((long)dst.g)*256+((long)src.g-(long)dst.g)*a))>>8;
        unsigned long result_r=((unsigned long)(((long)dst.r)*256+((long)src.r-(long)dst.r)*a))>>8;
        unsigned long result_a=((unsigned long)(((long)dst.a)*256+((long)a-(long)dst.a)*a))>>8;
        unsigned long result=(result_b) | (result_g<<8) | (result_r<<16) | (result_a<<24);
        return *(TARGB32*)&result;
    }

 继续优化,同时运算两路颜色分量的AlphaBlend实现:

  inline TARGB32 AlphaBlend(TARGB32 dst,TARGB32 src)
    {
        unsigned long Src_ARGB=*(unsigned long*)&src;
        unsigned long Dst_ARGB=*(unsigned long*)&dst;
        unsigned long a=Src_ARGB>>24;
        unsigned long ra=255-a;
        unsigned long result_RB=((Dst_ARGB & 0x00FF00FF)*ra + (Src_ARGB & 0x00FF00FF)*a);
        unsigned long result_AG=(((Dst_ARGB & 0xFF00FF00)>>8)*ra + ((Src_ARGB & 0xFF00FF00)>>8)*a);
        unsigned long result=((result_RB & 0xFF00FF00)>>8) | (result_AG & 0xFF00FF00);
        return *(TARGB32*)&result;
    }

    回到我们的主线:完美解决“旋转插值边界”
    怎么利用AlphaBlend呢?  我们可以在处理边界的时候,对于颜色数据在图片内的颜色,把Alpha通道分量设置为255,
在图片外的颜色数据(使用Pixels_Bound会返回最接近的一个内部颜色)的Alpha通道分量设置为0;
    这个任务就交给边界插值函数了:

inline void BilInear_Border(const TPicRegion& pic,const long x_16,const long y_16,TARGB32* result)
    {
        unsigned long x0=(x_16>>16);
        unsigned long y0=(y_16>>16);

        TARGB32 pixel[4];
        bool IsInPic;
        pixel[0]=Pixels_Bound(pic,x0,y0,IsInPic);
        if (!IsInPic) pixel[0].a=0; else pixel[0].a=255;
        pixel[2]=Pixels_Bound(pic,x0,y0+1,IsInPic);
        if (!IsInPic) pixel[2].a=0; else pixel[2].a=255;
        pixel[1]=Pixels_Bound(pic,x0+1,y0,IsInPic);
        if (!IsInPic) pixel[1].a=0; else pixel[1].a=255;
        pixel[3]=Pixels_Bound(pic,x0+1,y0+1,IsInPic);
        if (!IsInPic) pixel[3].a=0; else pixel[3].a=255;
        
        TPicRegion npic;
        npic.pdata     =&pixel[0];
        npic.byte_width=2*sizeof(TARGB32);
        //npic.width     =2;
        //npic.height    =2;
        BilInear_Fast(npic,(unsigned short)x_16,(unsigned short)y_16,result);
    }

 返回的颜色中的Alpha的值就代表了颜色的有效强度(一般介于0..255之间);
    那么,对边界上的插值就可以用类似这样的代码处理好了:
        TARGB32 tmp_color;
        BilInear_Border(SrcPic,srcx0_16,srcy0_16,&tmp_color);
        pDstLine[x]=AlphaBlend(pDstLine[x],tmp_color);

  c. OK,给出完整的函数:

void PicRotary_BilInear_CopyLine(TARGB32* pDstLine,long dst_border_x0,long dst_in_x0,long dst_in_x1,long dst_border_x1,
                        const TPicRegion& SrcPic,long srcx0_16,long srcy0_16,long Ax_16,long Ay_16)
{
    long x;
    for (x=dst_border_x0;x<dst_in_x0;++x)
    {
        TARGB32 src_color;
        BilInear_Border(SrcPic,srcx0_16,srcy0_16,&src_color);
        pDstLine[x]=AlphaBlend(pDstLine[x],src_color);
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
    for (x=dst_in_x0;x<dst_in_x1;++x)
    {
        BilInear_Fast(SrcPic,srcx0_16,srcy0_16,&pDstLine[x]);
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
    for (x=dst_in_x1;x<dst_border_x1;++x)
    {
        TARGB32 src_color;
        BilInear_Border(SrcPic,srcx0_16,srcy0_16,&src_color);
        pDstLine[x]=AlphaBlend(pDstLine[x],src_color);
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
}

void PicRotaryBilInear(const TPicRegion& Dst,const TPicRegion& Src,double RotaryAngle,double ZoomX,double ZoomY,double move_x,double move_y)
{
    if ( (fabs(ZoomX*Src.width)<1.0e-4) || (fabs(ZoomY*Src.height)<1.0e-4) ) return; //太小的缩放比例认为已经不可见
    double tmprZoomXY=1.0/(ZoomX*ZoomY);  
    double rZoomX=tmprZoomXY*ZoomY;
    double rZoomY=tmprZoomXY*ZoomX;
    double sinA,cosA;
    SinCos(RotaryAngle,sinA,cosA);
    long Ax_16=(long)(rZoomX*cosA*(1<<16)); 
    long Ay_16=(long)(rZoomX*sinA*(1<<16)); 
    long Bx_16=(long)(-rZoomY*sinA*(1<<16)); 
    long By_16=(long)(rZoomY*cosA*(1<<16)); 
    double rx0=Src.width*0.5;  //(rx0,ry0)为旋转中心 
    double ry0=Src.height*0.5; 
    long Cx_16=(long)((-(rx0+move_x)*rZoomX*cosA+(ry0+move_y)*rZoomY*sinA+rx0)*(1<<16));
    long Cy_16=(long)((-(rx0+move_x)*rZoomX*sinA-(ry0+move_y)*rZoomY*cosA+ry0)*(1<<16)); 

    TRotaryClipData rcData;
    rcData.Ax_16=Ax_16;
    rcData.Bx_16=Bx_16;
    rcData.Cx_16=Cx_16;
    rcData.Ay_16=Ay_16;
    rcData.By_16=By_16;
    rcData.Cy_16=Cy_16;
    rcData.dst_width=Dst.width;
    rcData.dst_height=Dst.height;
    rcData.src_width=Src.width;
    rcData.src_height=Src.height;
    if (!rcData.inti_clip(move_x,move_y,1)) return;

    TARGB32* pDstLine=Dst.pdata;
    ((TUInt8*&)pDstLine)+=(Dst.byte_width*rcData.out_dst_down_y);
    while (true) //to down
    {
        long y=rcData.out_dst_down_y;
        if (y>=Dst.height) break;
        if (y>=0)
        {
            PicRotary_BilInear_CopyLine(pDstLine,rcData.out_dst_x0_boder,rcData.out_dst_x0_in,
                rcData.out_dst_x1_in,rcData.out_dst_x1_boder,Src,rcData.out_src_x0_16,rcData.out_src_y0_16,Ax_16,Ay_16);
        }
        if (!rcData.next_clip_line_down()) break;
        ((TUInt8*&)pDstLine)+=Dst.byte_width;
    }
   
    pDstLine=Dst.pdata;
    ((TUInt8*&)pDstLine)+=(Dst.byte_width*rcData.out_dst_up_y);
    while (rcData.next_clip_line_up()) //to up 
    {
        long y=rcData.out_dst_up_y;
        if (y<0) break;
        ((TUInt8*&)pDstLine)-=Dst.byte_width;
        if (y<Dst.height)
        {
            PicRotary_BilInear_CopyLine(pDstLine,rcData.out_dst_x0_boder,rcData.out_dst_x0_in,
                rcData.out_dst_x1_in,rcData.out_dst_x1_boder,Src,rcData.out_src_x0_16,rcData.out_src_y0_16,Ax_16,Ay_16);
        }
    }
}

//注:测试图片都是800*600的图片旋转到1004*1004的图片中心 测试成绩取各个旋转角度的平均速度值
////////////////////////////////////////////////////////////////////////////////
//速度测试:                  
//==============================================================================
// PicRotaryBilInear         68.9 fps
//////////////////////////////////////////////////////////////////////////////// 


二次线性插值旋转结果图示:

   
                  30度                         60度                        90度

   
                 120度                        150度                       180度

  
                 210度                        240度                       270度

    
                 300度                        330度                       360度

 

C:用MMX指令来改进二次线性插值的旋转

 inline TARGB32 AlphaBlend_MMX(TARGB32 dst,TARGB32 src)
    {
        unsigned long result;
        asm
        {
            PXOR      MM7,MM7
            MOVD      MM0,src
            MOVD      MM2,dst
            PUNPCKLBW MM0,MM7
            PUNPCKLBW MM2,MM7
            MOVQ      MM1,MM0
            PUNPCKHWD MM1,MM1
            PSUBW     MM0,MM2
            PUNPCKHDQ MM1,MM1
            PSLLW     MM2,8
            PMULLW    MM0,MM1
            PADDW     MM2,MM0
            PSRLW     MM2,8
            PACKUSWB  MM2,MM7
            MOVD      result,MM2
        }
        return *(TARGB32*)&result;
    }

    void __declspec(naked) __stdcall BilInear_Fast_MMX(const TPicRegion& pic,const long x_16,const long y_16,TARGB32* result)
    {
        asm
        {    
              mov       edx,[esp+12] //y_16
              mov       eax,[esp+8]  //x_16
              PXOR      mm7,mm7
              shl       edx,16
              shl       eax,16
              shr       edx,24 //edx=v_8
              shr       eax,24 //eax=u_8
              MOVD      MM6,edx
              MOVD      MM5,eax
              mov       ecx,[esp+4]//pic
              mov       edx,[esp+12]//y_16
              mov       eax,[ecx]TPicRegion.byte_width
              sar       edx,16
              imul      edx,eax
              add       edx,[ecx]TPicRegion.pdata
              add       eax,edx

              mov       ecx,[esp+8] //x_16
              sar       ecx,16     //srcx_16>>16

              MOVD         MM2,dword ptr [eax+ecx*4]  //MM2=Color1
              MOVD         MM0,dword ptr [eax+ecx*4+4]//MM0=Color3
              PUNPCKLWD    MM5,MM5
              PUNPCKLWD    MM6,MM6
              MOVD         MM3,dword ptr [edx+ecx*4]  //MM3=Color0
              MOVD         MM1,dword ptr [edx+ecx*4+4]//MM1=Color2
              PUNPCKLDQ    MM5,MM5 //mm5=u_8
              PUNPCKLBW    MM0,MM7
              PUNPCKLBW    MM1,MM7
              PUNPCKLBW    MM2,MM7
              PUNPCKLBW    MM3,MM7
              PSUBw        MM0,MM2
              PSUBw        MM1,MM3
              PSLLw        MM2,8
              PSLLw        MM3,8
              PMULlw       MM0,MM5
              PMULlw       MM1,MM5
              PUNPCKLDQ    MM6,MM6 //mm6=v_8
              PADDw        MM0,MM2
              PADDw        MM1,MM3

              PSRLw        MM0,8
              PSRLw        MM1,8
              PSUBw        MM0,MM1
              PSLLw        MM1,8
              PMULlw       MM0,MM6
              mov       eax,[esp+16]//result
              PADDw        MM0,MM1

              PSRLw        MM0,8
              PACKUSwb     MM0,MM7
              movd      [eax],MM0 

              //emms
              ret 16
        }
    }

    void BilInear_Border_MMX(const TPicRegion& pic,const long x_16,const long y_16,TARGB32* result)
    {
        unsigned long x0=(x_16>>16);
        unsigned long y0=(y_16>>16);

        TARGB32 pixel[4];
        bool IsInPic;
        pixel[0]=Pixels_Bound(pic,x0,y0,IsInPic);
        if (!IsInPic) pixel[0].a=0; else pixel[0].a=255;
        pixel[2]=Pixels_Bound(pic,x0,y0+1,IsInPic);
        if (!IsInPic) pixel[2].a=0; else pixel[2].a=255;
        pixel[1]=Pixels_Bound(pic,x0+1,y0,IsInPic);
        if (!IsInPic) pixel[1].a=0; else pixel[1].a=255;
        pixel[3]=Pixels_Bound(pic,x0+1,y0+1,IsInPic);
        if (!IsInPic) pixel[3].a=0; else pixel[3].a=255;
        
        TPicRegion npic;
        npic.pdata     =&pixel[0];
        npic.byte_width=2*sizeof(TARGB32);
        //npic.width     =2;
        //npic.height    =2;
        BilInear_Fast_MMX(npic,(unsigned short)x_16,(unsigned short)y_16,result);
    }

void PicRotary_BilInear_CopyLine_MMX(TARGB32* pDstLine,long dst_border_x0,long dst_in_x0,long dst_in_x1,long dst_border_x1,
                        const TPicRegion& SrcPic,long srcx0_16,long srcy0_16,long Ax_16,long Ay_16)
{
    long x;
    for (x=dst_border_x0;x<dst_in_x0;++x)
    {
        TARGB32 src_color;
        BilInear_Border_MMX(SrcPic,srcx0_16,srcy0_16,&src_color);
        pDstLine[x]=AlphaBlend_MMX(pDstLine[x],src_color);        
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
    for (x=dst_in_x0;x<dst_in_x1;++x)
    {
        BilInear_Fast_MMX(SrcPic,srcx0_16,srcy0_16,&pDstLine[x]);
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
    for (x=dst_in_x1;x<dst_border_x1;++x)
    {
        TARGB32 src_color;
        BilInear_Border_MMX(SrcPic,srcx0_16,srcy0_16,&src_color);
        pDstLine[x]=AlphaBlend_MMX(pDstLine[x],src_color);        
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
    asm  emms
}

void PicRotaryBilInear_MMX(const TPicRegion& Dst,const TPicRegion& Src,double RotaryAngle,double ZoomX,double ZoomY,double move_x,double move_y)
{
    if ( (fabs(ZoomX*Src.width)<1.0e-4) || (fabs(ZoomY*Src.height)<1.0e-4) ) return; //太小的缩放比例认为已经不可见
    double tmprZoomXY=1.0/(ZoomX*ZoomY);  
    double rZoomX=tmprZoomXY*ZoomY;
    double rZoomY=tmprZoomXY*ZoomX;
    double sinA,cosA;
    SinCos(RotaryAngle,sinA,cosA);
    long Ax_16=(long)(rZoomX*cosA*(1<<16)); 
    long Ay_16=(long)(rZoomX*sinA*(1<<16)); 
    long Bx_16=(long)(-rZoomY*sinA*(1<<16)); 
    long By_16=(long)(rZoomY*cosA*(1<<16)); 
    double rx0=Src.width*0.5;  //(rx0,ry0)为旋转中心 
    double ry0=Src.height*0.5; 
    long Cx_16=(long)((-(rx0+move_x)*rZoomX*cosA+(ry0+move_y)*rZoomY*sinA+rx0)*(1<<16));
    long Cy_16=(long)((-(rx0+move_x)*rZoomX*sinA-(ry0+move_y)*rZoomY*cosA+ry0)*(1<<16)); 

    TRotaryClipData rcData;
    rcData.Ax_16=Ax_16;
    rcData.Bx_16=Bx_16;
    rcData.Cx_16=Cx_16;
    rcData.Ay_16=Ay_16;
    rcData.By_16=By_16;
    rcData.Cy_16=Cy_16;
    rcData.dst_width=Dst.width;
    rcData.dst_height=Dst.height;
    rcData.src_width=Src.width;
    rcData.src_height=Src.height;
    if (!rcData.inti_clip(move_x,move_y,1)) return;

    TARGB32* pDstLine=Dst.pdata;
    ((TUInt8*&)pDstLine)+=(Dst.byte_width*rcData.out_dst_down_y);
    while (true) //to down
    {
        long y=rcData.out_dst_down_y;
        if (y>=Dst.height) break;
        if (y>=0)
        {
            PicRotary_BilInear_CopyLine_MMX(pDstLine,rcData.out_dst_x0_boder,rcData.out_dst_x0_in,
                rcData.out_dst_x1_in,rcData.out_dst_x1_boder,Src,rcData.out_src_x0_16,rcData.out_src_y0_16,Ax_16,Ay_16);
        }
        if (!rcData.next_clip_line_down()) break;
        ((TUInt8*&)pDstLine)+=Dst.byte_width;
    }
   
    pDstLine=Dst.pdata;
    ((TUInt8*&)pDstLine)+=(Dst.byte_width*rcData.out_dst_up_y);
    while (rcData.next_clip_line_up()) //to up 
    {
        long y=rcData.out_dst_up_y;
        if (y<0) break;
        ((TUInt8*&)pDstLine)-=Dst.byte_width;
        if (y<Dst.height)
        {
            PicRotary_BilInear_CopyLine_MMX(pDstLine,rcData.out_dst_x0_boder,rcData.out_dst_x0_in,
                rcData.out_dst_x1_in,rcData.out_dst_x1_boder,Src,rcData.out_src_x0_16,rcData.out_src_y0_16,Ax_16,Ay_16);
        }
    }
}

//注:测试图片都是800*600的图片旋转到1004*1004的图片中心 测试成绩取各个旋转角度的平均速度值
////////////////////////////////////////////////////////////////////////////////
//速度测试:                  
//==============================================================================
// PicRotaryBilInear_MMX    100.2 fps
//////////////////////////////////////////////////////////////////////////////// 


D:三次卷积插值的旋转
   (实现就比较简单了,几乎就是拷贝代码,然后稍微改写几个单词:)
  (很多代码从《图形图像处理-之-高质量的快速的图像缩放 中篇 二次线性插值和三次卷积插值》文章来的)

 inline double SinXDivX(double x) 
        {
            //该函数计算插值曲线sin(x*PI)/(x*PI)的值 //PI=3.1415926535897932385; 
            //下面是它的近似拟合表达式
            const float a = -1; //a还可以取 a=-2,-1,-0.75,-0.5等等,起到调节锐化或模糊程度的作用

            if (x<0) x=-x; //x=abs(x);
            double x2=x*x;
            double x3=x2*x;
            if (x<=1)
              return (a+2)*x3 - (a+3)*x2 + 1;
            else if (x<=2) 
              return a*x3 - (5*a)*x2 + (8*a)*x - (4*a);
            else
              return 0;
        } 
        inline TUInt8 ColorBound(long Color)
        {
            if (Color<=0)
                return 0;
            else if (Color>=255)
                return 255;
            else
                return Color;
        }

    static long SinXDivX_Table_8[(2<<8)+1];
    class _CAutoInti_SinXDivX_Table {
    private: 
        void _Inti_SinXDivX_Table()
        {
            for (long i=0;i<=(2<<8);++i)
                SinXDivX_Table_8[i]=long(0.5+256*SinXDivX(i*(1.0/(256))));
        };
    public:
        _CAutoInti_SinXDivX_Table() { _Inti_SinXDivX_Table(); }
    };
    static _CAutoInti_SinXDivX_Table __tmp_CAutoInti_SinXDivX_Table;



    void ThreeOrder_Fast(const TPicRegion& pic,const long x_16,const long y_16,TARGB32* result)
    {
        long u_8=(unsigned char)((x_16)>>8);
        long v_8=(unsigned char)((y_16)>>8);
        const TARGB32* pixel=&Pixels(pic,(x_16>>16)-1,(y_16>>16)-1);
        long pic_byte_width=pic.byte_width;

        long au_8[4],av_8[4];
        //
        au_8[0]=SinXDivX_Table_8[(1<<8)+u_8];
        au_8[1]=SinXDivX_Table_8[u_8];
        au_8[2]=SinXDivX_Table_8[(1<<8)-u_8];
        au_8[3]=SinXDivX_Table_8[(2<<8)-u_8];
        av_8[0]=SinXDivX_Table_8[(1<<8)+v_8];
        av_8[1]=SinXDivX_Table_8[v_8];
        av_8[2]=SinXDivX_Table_8[(1<<8)-v_8];
        av_8[3]=SinXDivX_Table_8[(2<<8)-v_8];

        long sR=0,sG=0,sB=0,sA=0;
        for (long i=0;i<4;++i)
        {
            long aA=au_8[0]*pixel[0].a + au_8[1]*pixel[1].a + au_8[2]*pixel[2].a + au_8[3]*pixel[3].a;
            long aR=au_8[0]*pixel[0].r + au_8[1]*pixel[1].r + au_8[2]*pixel[2].r + au_8[3]*pixel[3].r;
            long aG=au_8[0]*pixel[0].g + au_8[1]*pixel[1].g + au_8[2]*pixel[2].g + au_8[3]*pixel[3].g;
            long aB=au_8[0]*pixel[0].b + au_8[1]*pixel[1].b + au_8[2]*pixel[2].b + au_8[3]*pixel[3].b;
            sA+=aA*av_8[i];
            sR+=aR*av_8[i];
            sG+=aG*av_8[i];
            sB+=aB*av_8[i];
            ((TUInt8*&)pixel)+=pic_byte_width;
        }

        *(unsigned long*)result=ColorBound(sB>>16) | (ColorBound(sG>>16)<<8) | (ColorBound(sR>>16)<<16)| (ColorBound(sA>>16)<<24);
    }

    void ThreeOrder_Border(const TPicRegion& pic,const long x_16,const long y_16,TARGB32* result)
    {
        unsigned long x0_sub1=(x_16>>16)-1;
        unsigned long y0_sub1=(y_16>>16)-1;
        long u_16_add1=((unsigned short)(x_16))+(1<<16);
        long v_16_add1=((unsigned short)(y_16))+(1<<16);

        TARGB32 pixel[16];
        long i,j;

        for (i=0;i<4;++i)
        {
            long y=y0_sub1+i;
            for (j=0;j<4;++j)
            {
                long x=x0_sub1+j;
                bool IsInPic;
                pixel[i*4+j]=Pixels_Bound(pic,x,y,IsInPic);
                if (!IsInPic) pixel[i*4+j].a=0; else pixel[i*4+j].a=255;
            }
        }
        
        TPicRegion npic;
        npic.pdata     =&pixel[0];
        npic.byte_width=4*sizeof(TARGB32);
        //npic.width     =4;
        //npic.height    =4;
        ThreeOrder_Fast(npic,u_16_add1,v_16_add1,result);
    }

void PicRotary_ThreeOrder_CopyLine(TARGB32* pDstLine,long dst_border_x0,long dst_in_x0,long dst_in_x1,long dst_border_x1,
                        const TPicRegion& SrcPic,long srcx0_16,long srcy0_16,long Ax_16,long Ay_16)
{
    long x;
    for (x=dst_border_x0;x<dst_in_x0;++x)
    {

        TARGB32 src_color;
        ThreeOrder_Border(SrcPic,srcx0_16,srcy0_16,&src_color);
        pDstLine[x]=AlphaBlend(pDstLine[x],src_color);
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
    for (x=dst_in_x0;x<dst_in_x1;++x)
    {
        ThreeOrder_Fast(SrcPic,srcx0_16,srcy0_16,&pDstLine[x]);
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
    for (x=dst_in_x1;x<dst_border_x1;++x)
    {
        TARGB32 src_color;
        ThreeOrder_Border(SrcPic,srcx0_16,srcy0_16,&src_color);
        pDstLine[x]=AlphaBlend(pDstLine[x],src_color);
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
}

void PicRotaryThreeOrder(const TPicRegion& Dst,const TPicRegion& Src,double RotaryAngle,double ZoomX,double ZoomY,double move_x,double move_y)
{
    if ( (fabs(ZoomX*Src.width)<1.0e-4) || (fabs(ZoomY*Src.height)<1.0e-4) ) return; //太小的缩放比例认为已经不可见
    double tmprZoomXY=1.0/(ZoomX*ZoomY);  
    double rZoomX=tmprZoomXY*ZoomY;
    double rZoomY=tmprZoomXY*ZoomX;
    double sinA,cosA;
    SinCos(RotaryAngle,sinA,cosA);
    long Ax_16=(long)(rZoomX*cosA*(1<<16)); 
    long Ay_16=(long)(rZoomX*sinA*(1<<16)); 
    long Bx_16=(long)(-rZoomY*sinA*(1<<16)); 
    long By_16=(long)(rZoomY*cosA*(1<<16)); 
    double rx0=Src.width*0.5;  //(rx0,ry0)为旋转中心 
    double ry0=Src.height*0.5; 
    long Cx_16=(long)((-(rx0+move_x)*rZoomX*cosA+(ry0+move_y)*rZoomY*sinA+rx0)*(1<<16));
    long Cy_16=(long)((-(rx0+move_x)*rZoomX*sinA-(ry0+move_y)*rZoomY*cosA+ry0)*(1<<16)); 

    TRotaryClipData rcData;
    rcData.Ax_16=Ax_16;
    rcData.Bx_16=Bx_16;
    rcData.Cx_16=Cx_16;
    rcData.Ay_16=Ay_16;
    rcData.By_16=By_16;
    rcData.Cy_16=Cy_16;
    rcData.dst_width=Dst.width;
    rcData.dst_height=Dst.height;
    rcData.src_width=Src.width;
    rcData.src_height=Src.height;
    if (!rcData.inti_clip(move_x,move_y,2)) return;

    TARGB32* pDstLine=Dst.pdata;
    ((TUInt8*&)pDstLine)+=(Dst.byte_width*rcData.out_dst_down_y);
    while (true) //to down
    {
        long y=rcData.out_dst_down_y;
        if (y>=Dst.height) break;
        if (y>=0)
        {
            PicRotary_ThreeOrder_CopyLine(pDstLine,rcData.out_dst_x0_boder,rcData.out_dst_x0_in,
                rcData.out_dst_x1_in,rcData.out_dst_x1_boder,Src,rcData.out_src_x0_16,rcData.out_src_y0_16,Ax_16,Ay_16);
        }
        if (!rcData.next_clip_line_down()) break;
        ((TUInt8*&)pDstLine)+=Dst.byte_width;
    }
   
    pDstLine=Dst.pdata;
    ((TUInt8*&)pDstLine)+=(Dst.byte_width*rcData.out_dst_up_y);
    while (rcData.next_clip_line_up()) //to up 
    {
        long y=rcData.out_dst_up_y;
        if (y<0) break;
        ((TUInt8*&)pDstLine)-=Dst.byte_width;
        if (y<Dst.height)
        {
            PicRotary_ThreeOrder_CopyLine(pDstLine,rcData.out_dst_x0_boder,rcData.out_dst_x0_in,
                rcData.out_dst_x1_in,rcData.out_dst_x1_boder,Src,rcData.out_src_x0_16,rcData.out_src_y0_16,Ax_16,Ay_16);
        }
    }
}

//注:测试图片都是800*600的图片旋转到1004*1004的图片中心 测试成绩取各个旋转角度的平均速度值
////////////////////////////////////////////////////////////////////////////////
//速度测试:                  
//==============================================================================
// PicRotaryThreeOrder       22.8 fps
////////////////////////////////////////////////////////////////////////////////   


三次卷积插值旋转结果图示:

 

   
                  30度                         60度                        90度

   
                 120度                        150度                       180度

  
                 210度                        240度                       270度

    
                 300度                        330度                       360度

 

E:用MMX优化三次卷积插值的旋转

//注:测试图片都是800*600的图片旋转到1004*1004的图片中心 测试成绩取各个旋转角度的平均速度值
////////////////////////////////////////////////////////////////////////////////
//速度测试:                  
//==============================================================================
// PicRotaryThreeOrder_MMX   44.2 fps
////////////////////////////////////////////////////////////////////////////////   

 typedef   unsigned long TMMXData32;
    static TMMXData32 SinXDivX_Table_MMX[(2<<8)+1];
    class _CAutoInti_SinXDivX_Table_MMX {
    private: 
        void _Inti_SinXDivX_Table_MMX()
        {
            for (long i=0;i<=(2<<8);++i)
            {
                unsigned short t=long(0.5+(1<<14)*SinXDivX(i*(1.0/(256))));
                unsigned long tl=t | (((unsigned long)t)<<16);
                SinXDivX_Table_MMX[i]=tl;
            }
        };
    public:
        _CAutoInti_SinXDivX_Table_MMX() { _Inti_SinXDivX_Table_MMX(); }
    };
    static _CAutoInti_SinXDivX_Table_MMX __tmp_CAutoInti_SinXDivX_Table_MMX;


    void __declspec(naked) _private_ThreeOrder_Fast_MMX()
    {
        asm
        {
            movd        mm1,dword ptr [edx]
            movd        mm2,dword ptr [edx+4]
            movd        mm3,dword ptr [edx+8]
            movd        mm4,dword ptr [edx+12]
            movd        mm5,dword ptr [(offset SinXDivX_Table_MMX)+256*4+eax*4]
            movd        mm6,dword ptr [(offset SinXDivX_Table_MMX)+eax*4]
            punpcklbw   mm1,mm7
            punpcklbw   mm2,mm7
            punpcklwd   mm5,mm5
            punpcklwd   mm6,mm6
            psllw       mm1,7
            psllw       mm2,7
            pmulhw      mm1,mm5
            pmulhw      mm2,mm6
            punpcklbw   mm3,mm7
            punpcklbw   mm4,mm7
            movd        mm5,dword ptr [(offset SinXDivX_Table_MMX)+256*4+ecx*4]
            movd        mm6,dword ptr [(offset SinXDivX_Table_MMX)+512*4+ecx*4]
            punpcklwd   mm5,mm5
            punpcklwd   mm6,mm6
            psllw       mm3,7
            psllw       mm4,7
            pmulhw      mm3,mm5
            pmulhw      mm4,mm6
            paddsw      mm1,mm2
            paddsw      mm3,mm4
            movd        mm6,dword ptr [ebx] //v
            paddsw      mm1,mm3
            punpcklwd   mm6,mm6

            pmulhw      mm1,mm6
            add     edx,esi  //+pic.byte_width
            paddsw      mm0,mm1

            ret
        }
    }

    inline void ThreeOrder_Fast_MMX(const TPicRegion& pic,const long x_16,const long y_16,TARGB32* result)
    {
        asm
        {
            mov     ecx,pic
            mov     eax,y_16
            mov     ebx,x_16
            movzx   edi,ah //v_8
            mov     edx,[ecx+TPicRegion.pdata]
            shr     eax,16
            mov     esi,[ecx+TPicRegion.byte_width]
            dec     eax
            movzx   ecx,bh //u_8
            shr     ebx,16
            imul    eax,esi
            lea     edx,[edx+ebx*4-4]
            add     edx,eax //pixel

            mov     eax,ecx
            neg     ecx

            pxor    mm7,mm7  //0
            //mov     edx,pixel
            pxor    mm0,mm0  //result=0
            //lea     eax,auv_7

            lea    ebx,[(offset SinXDivX_Table_MMX)+256*4+edi*4]
            call  _private_ThreeOrder_Fast_MMX
            lea    ebx,[(offset SinXDivX_Table_MMX)+edi*4]
            call  _private_ThreeOrder_Fast_MMX
            neg    edi
            lea    ebx,[(offset SinXDivX_Table_MMX)+256*4+edi*4]
            call  _private_ThreeOrder_Fast_MMX
            lea    ebx,[(offset SinXDivX_Table_MMX)+512*4+edi*4]
            call  _private_ThreeOrder_Fast_MMX

            psraw     mm0,3
            mov       eax,result
            packuswb  mm0,mm7
            movd      [eax],mm0

            emms
        }
    }

    void ThreeOrder_Border_MMX(const TPicRegion& pic,const long x_16,const long y_16,TARGB32* result)
    {
        unsigned long x0_sub1=(x_16>>16)-1;
        unsigned long y0_sub1=(y_16>>16)-1;
        long u_16_add1=((unsigned short)(x_16))+(1<<16);
        long v_16_add1=((unsigned short)(y_16))+(1<<16);

        TARGB32 pixel[16];
        long i,j;

        for (i=0;i<4;++i)
        {
            long y=y0_sub1+i;
            for (j=0;j<4;++j)
            {
                long x=x0_sub1+j;
                bool IsInPic;
                pixel[i*4+j]=Pixels_Bound(pic,x,y,IsInPic);
                if (!IsInPic) pixel[i*4+j].a=0; else pixel[i*4+j].a=255;
            }
        }
        
        TPicRegion npic;
        npic.pdata     =&pixel[0];
        npic.byte_width=4*sizeof(TARGB32);
        //npic.width     =4;
        //npic.height    =4;
        ThreeOrder_Fast_MMX(npic,u_16_add1,v_16_add1,result);
    }

void PicRotary_ThreeOrder_CopyLine_MMX(TARGB32* pDstLine,long dst_border_x0,long dst_in_x0,long dst_in_x1,long dst_border_x1,
                        const TPicRegion& SrcPic,long srcx0_16,long srcy0_16,long Ax_16,long Ay_16)
{
    long x;
    for (x=dst_border_x0;x<dst_in_x0;++x)
    {
        TARGB32 src_color;
        ThreeOrder_Border_MMX(SrcPic,srcx0_16,srcy0_16,&src_color);
        pDstLine[x]=AlphaBlend_MMX(pDstLine[x],src_color);
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
    for (x=dst_in_x0;x<dst_in_x1;++x)
    {
        ThreeOrder_Fast_MMX(SrcPic,srcx0_16,srcy0_16,&pDstLine[x]);
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
    for (x=dst_in_x1;x<dst_border_x1;++x)
    {
        TARGB32 src_color;
        ThreeOrder_Border_MMX(SrcPic,srcx0_16,srcy0_16,&src_color);
        pDstLine[x]=AlphaBlend_MMX(pDstLine[x],src_color);
        srcx0_16+=Ax_16;
        srcy0_16+=Ay_16;
    }
    asm  emms
}

void PicRotaryThreeOrder_MMX(const TPicRegion& Dst,const TPicRegion& Src,double RotaryAngle,double ZoomX,double ZoomY,double move_x,double move_y)
{
    if ( (fabs(ZoomX*Src.width)<1.0e-4) || (fabs(ZoomY*Src.height)<1.0e-4) ) return; //太小的缩放比例认为已经不可见
    double tmprZoomXY=1.0/(ZoomX*ZoomY);  
    double rZoomX=tmprZoomXY*ZoomY;
    double rZoomY=tmprZoomXY*ZoomX;
    double sinA,cosA;
    SinCos(RotaryAngle,sinA,cosA);
    long Ax_16=(long)(rZoomX*cosA*(1<<16)); 
    long Ay_16=(long)(rZoomX*sinA*(1<<16)); 
    long Bx_16=(long)(-rZoomY*sinA*(1<<16)); 
    long By_16=(long)(rZoomY*cosA*(1<<16)); 
    double rx0=Src.width*0.5;  //(rx0,ry0)为旋转中心 
    double ry0=Src.height*0.5; 
    long Cx_16=(long)((-(rx0+move_x)*rZoomX*cosA+(ry0+move_y)*rZoomY*sinA+rx0)*(1<<16));
    long Cy_16=(long)((-(rx0+move_x)*rZoomX*sinA-(ry0+move_y)*rZoomY*cosA+ry0)*(1<<16)); 

    TRotaryClipData rcData;
    rcData.Ax_16=Ax_16;
    rcData.Bx_16=Bx_16;
    rcData.Cx_16=Cx_16;
    rcData.Ay_16=Ay_16;
    rcData.By_16=By_16;
    rcData.Cy_16=Cy_16;
    rcData.dst_width=Dst.width;
    rcData.dst_height=Dst.height;
    rcData.src_width=Src.width;
    rcData.src_height=Src.height;
    if (!rcData.inti_clip(move_x,move_y,2)) return;

    TARGB32* pDstLine=Dst.pdata;
    ((TUInt8*&)pDstLine)+=(Dst.byte_width*rcData.out_dst_down_y);
    while (true) //to down
    {
        long y=rcData.out_dst_down_y;
        if (y>=Dst.height) break;
        if (y>=0)
        {
            PicRotary_ThreeOrder_CopyLine_MMX(pDstLine,rcData.out_dst_x0_boder,rcData.out_dst_x0_in,
                rcData.out_dst_x1_in,rcData.out_dst_x1_boder,Src,rcData.out_src_x0_16,rcData.out_src_y0_16,Ax_16,Ay_16);
        }
        if (!rcData.next_clip_line_down()) break;
        ((TUInt8*&)pDstLine)+=Dst.byte_width;
    }
   
    pDstLine=Dst.pdata;
    ((TUInt8*&)pDstLine)+=(Dst.byte_width*rcData.out_dst_up_y);
    while (rcData.next_clip_line_up()) //to up 
    {
        long y=rcData.out_dst_up_y;
        if (y<0) break;
        ((TUInt8*&)pDstLine)-=Dst.byte_width;
        if (y<Dst.height)
        {
            PicRotary_ThreeOrder_CopyLine_MMX(pDstLine,rcData.out_dst_x0_boder,rcData.out_dst_x0_in,
                rcData.out_dst_x1_in,rcData.out_dst_x1_boder,Src,rcData.out_src_x0_16,rcData.out_src_y0_16,Ax_16,Ay_16);
        }
    }
}
 

F 效果图:
 //程序使用的调用参数:
    const long testcount=2000;
    long dst_wh=1004;
    for (int i=0;i<testcount;++i)
    {
        double zoom=rand()*(1.0/RAND_MAX)+0.5;
        PicRotary_XXX(ppicDst,ppicSrc,rand()*(PI*2/RAND_MAX),zoom,zoom,((dst_wh+ppicSrc.width)*rand()*(1.0/RAND_MAX)-ppicSrc.width),(dst_wh+ppicSrc.height)*rand()*(1.0/RAND_MAX)-ppicSrc.height);
    }

   近邻取样插值旋转效果图:

   二次线性插值旋转效果图:

   三次卷积插值旋转效果图:

G:旋转测试的结果放到一起:

//注:测试图片都是800*600的图片旋转到1004*1004的图片中心,测试成绩取各个旋转角度的平均速度值  
////////////////////////////////////////////////////////////////////////////////
//速度测试:  (测试CPU为AMD64x2 4200+(2.37G),单线程)
//==============================================================================
// PicRotary3               280.9 fps
// PicRotarySEE             306.3 fps
// PicRotarySEE2            304.2 fps
//
// PicRotaryBilInear         68.9 fps
// PicRotaryBilInear_MMX    100.2 fps
// PicRotaryThreeOrder       22.8 fps
// PicRotaryThreeOrder_MMX   44.2 fps
////////////////////////////////////////////////////////////////////////////////

补充Intel Core2 4400上的测试成绩:

////////////////////////////////////////////////////////////////////////////////
//速度测试:  (测试CPU为Intel Core2 4400(2.00G)单线程)
//==============================================================================
// PicRotary3               334.9 fps
// PicRotarySEE             463.1 fps
// PicRotarySEE2            449.3 fps
//
// PicRotaryBilInear         68.9 fps
// PicRotaryBilInear_MMX    109.5 fps
// PicRotaryThreeOrder       24.0 fps
// PicRotaryThreeOrder_MMX   45.9 fps
////////////////////////////////////////////////////////////////////////////////

(针对大图片的预读缓冲区优化的旋转请参见《下篇 补充话题》中的优化版本)

(对于旋转的MipMap处理和三次线性插值,可以参考《图形图像处理-之-高质量的快速的图像缩放 下篇 三次线性插值和MipMap链》文章)

(这里为了函数的独立性和容易理解,都是拷贝代码然后稍作修改;实际的程序中,建议把他们合并到同一个函数中,
减少代码量,提高可维护性;  对于MMX、SSE、SSE2等的使用建议用CPUID指令测试看CPU是否支持这些指令,
动态决定调用不同的实现)

(欢迎指出文章中的错误、我没有做到的优化、改进意见 等)

 

转自:http://blog.csdn.net/housisong/article/details/1666962

posted on 2013-08-19 10:14  裴银祥的博客园  阅读(1047)  评论(0编辑  收藏  举报