项目需要,要截图屏幕图片,并缩放1/4显示,使用已有的方式,缩小的效果不好,要用二次线性,在网络上找了一个算法加以修改,得到可接受的图像。代码如下:
采用浮点数运算可以得到比较好的效果,
而定点数,得到的效果比较差,用公司内部的定点数方式,得到的效果有所改善,但与浮点数效果还是有差距,感觉是取的定点数不是最合适的,谁有更好的取得定点数的方式可以分享一下。
#if 1 //浮点数的二次线性缩放
void RotateBmpB0(SFNColor* pSrcBuf,SFNColor* pDestBuf,int nSrcWi,int nSrcHe,int nDestWi,int nDestHe);
void Bilinear0(SFNColor* pic,double fx,double fy,int width,SFNColor* result);
#else //定点数的二次线性缩放,但是定点数没有取好,导致图像模糊严重,所以才要浮点数的
void Bilinear0(SFNColor* pic,long fx,long fy,int width,SFNColor* result);
void RotateBmpB0(SFNColor* pSrcBuf,SFNColor* pDestBuf,int nSrcWi,int nSrcHe,int nDestWi,int nDestHe);
#endif
#if 1
void Bilinear0(SFNColor* pic,double fx,double fy,int width,SFNColor* result)
{
long x= (long)fx;
long y=(long)fy;
if (x>fx)
--x;
//x=floor(fx);
if (y>fy)
--y;
//y=floor(fy);
{
SFNColor Color0=pic[y * width + x];
SFNColor Color2=pic[y * width + x+1];
SFNColor Color1=pic[(y+1) * width + x];
SFNColor Color3=pic[(y +1)* width + (x+1)];
double u=fx-x;
double v=fy-y;
double pm3=u*v;
double pm2=u*(1-v);
double pm1=v*(1-u);
double pm0=(1-u)*(1-v);
SFInt8 R=(pm0*(Color0>>11)+pm1*(Color1>>11)+pm2*(Color2>>11)+pm3*(Color3>>11));//(Color0>>11);//
SFInt8 G=(pm0*((Color0&0x07E0)>> 5)+pm1*((Color1&0x07E0)>> 5)+pm2*((Color2&0x07E0)>> 5)+pm3*((Color3&0x07E0)>> 5));//(Color0&0x07E0)>> 5;//
SFInt8 B=(pm0*((Color0&0x001F))+pm1*((Color1&0x001F))+pm2*((Color2&0x001F))+pm3*((Color3&0x001F)));//(Color0&0x001F);//
*result = (R<<11)|(G<<5)|B;
}
}
void RotateBmpB0(SFNColor* pSrcBuf,SFNColor* pDestBuf,int nSrcWi,int nSrcHe,int nDestWi,int nDestHe)
{
SFNColor* pDstLine = pDestBuf;
long y=0;
for ( y=0;y<nDestHe;++y)
{
long x=0;
double srcy=(y+0.4999999)*nSrcHe/nDestHe-0.5;
if(srcy<0)srcy = 0;
for ( x=0;x<nDestWi;++x)
{
double srcx=(x+0.4999999)*nSrcWi/nDestWi-0.5;
if(srcx<0)srcx = 0;
Bilinear0(pSrcBuf,srcx,srcy,nSrcWi,&pDstLine[x]);
}
pDstLine += nDestWi;
}
}
#else
void Bilinear0(SFNColor* pic,long fx,long fy,int width,SFNColor* result)
{
long x=fx >> 16; //if (x>fx) --x; x=floor(fx);
long y=fy >> 16;// if (y>fy) --y; y=floor(fy);
SFUint16 Color0=pic[y * width + x];
SFUint16 Color2=pic[y * width + x+1];
SFUint16 Color1=pic[(y+1) * width + x];
SFUint16 Color3=pic[(y +1)* width + (x+1)];
SFUint32 u_8=(fx & 0xFFFF)>>8;
SFUint32 v_8=(fy & 0xFFFF)>>8;
SFUint32 pm3=(u_8*v_8);
SFUint32 pm2=(u_8*(SFUint32)(256-v_8));
SFUint32 pm1=(v_8*(SFUint32)(256-u_8));
SFUint32 pm0=((256-u_8)*(256-v_8));
SFUint8 R=(pm0*((Color0&0xF800)>>11)+pm1*((Color1&0xF800)>>11)+pm2*((Color2&0xF800)>>11)+pm3*((Color3&0xF800)>>11))>>16;//(Color0>>11);//
SFUint8 G=(pm0*((Color0&0x07E0)>> 5)+pm1*((Color1&0x07E0)>> 5)+pm2*((Color2&0x07E0)>> 5)+pm3*((Color3&0x07E0)>> 5))>>16;//(Color0&0x07E0)>> 5;//
SFUint8 B=(pm0*((Color0&0x001F))+pm1*((Color1&0x001F))+pm2*((Color2&0x001F))+pm3*((Color3&0x001F)))>>16;//(Color0&0x001F);//
*result = (R<<11)|(G<<5)|B;
}
extern const SFUint16 _xs_fast_div_table_i16[513];
SFInt32 fx32divi(SFInt32 a, int b) //定点数除法,用这个方式,显示效果有所改善
{
if(!a)
{
return 0;
}
else if(b>=-512 && b<=512)
{
if(b<0)
{
return (SFInt32)(((SFInt64)a*(-(int)_xs_fast_div_table_i16[-b]))>>16);
}
else
{
return (SFInt32)(((SFInt64)a*((int)_xs_fast_div_table_i16[b]))>>16);
}
}
else
{
return (SFInt32)(a/b);
}
}
void RotateBmpB0(SFNColor* pSrcBuf,SFNColor* pDestBuf,int nSrcWi,int nSrcHe,int nDestWi,int nDestHe)
{
//int nSrcX = 0,nSrcY= 0;
long srcy=0;
long y=0;
SFNColor* pDstLine = pDestBuf;
//SFUint64 nSrcXStep = nSrcWi / (float)nDestWi * (1<<16);
//SFUint64 nSrcYStep = nSrcHe / (float)nDestHe* (1<<16);
//long nSrcXStep = fx32div(nSrcWi<<16,nDestWi<<16);
//long nSrcYStep = fx32div(nSrcHe<<16,nDestHe<<16);
// sf_dbgprintf(L"_______nSrcXStep=%d ; nSrcYStep=%d",nSrcXStep,nSrcYStep);
/*long nSrcXStep = fx32divi(nSrcWi<<16,nDestWi);
long nSrcYStep = fx32divi(nSrcHe<<16,nDestHe);*/
long nSrcXStep = (nSrcWi<<16)/nDestWi;
long nSrcYStep = (nSrcHe<<16)/nDestHe;
//sf_dbgprintf(L"_______nSrcXStep=%d ; nSrcYStep=%d",nSrcXStep,nSrcYStep);
if (nSrcXStep > nSrcYStep)
{
nSrcXStep = nSrcYStep;
}
else
{
nSrcYStep = nSrcXStep;
}
//sf_dbgprintf(L"___222____nSrcXStep=%d ; nSrcYStep=%d",nSrcXStep,nSrcYStep);
for ( y=0;y<nDestHe;++y)
{
long srcx=0;
long x=0;
for ( x=0;x<nDestWi;++x)
{
Bilinear0(pSrcBuf,srcx,srcy,nSrcWi,&pDstLine[x]);
srcx += nSrcXStep;
}
srcy += nSrcYStep;
pDstLine += nDestWi;
}
}
#endif