散分,BMP缩放的问题 //函数说明:将源文件中的bmp图像读出缩放后,保存在目标文件里//输入参数:srcFile源文件名// destFile目录文件名// nNewWidth缩放后图片宽// nNewHeight缩放后图片高//输出参数:无//返回值:如果缩放成功返回1,否则返回0//其它说明:图片是32位真彩色,若能用24位保存最好BOOL BMPZoom(char * srcFile,char *destFile,int nNewWidth,int nNewHeight) 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 需要查一下bmp文件的存储格式了 我没有完全合适的函数,我以前写的函数是针对位图内存操作缩放的。做位图高效率的缩放必须用到汇编语言,要做到平滑缩放,则要求位图具有alpha通道/*转换主函数pSrc 源数据 要求32位widthSrc 源宽heightSrc 源高pDst 转换后数据 32位,要求先创建widthDst 要求目标宽heightDst 要求目标高*/void Image::BltStretch(void * pSrc,int widthSrc,int heightSrc,void *pDst,int widthDst,int heightDst);/*图片从24位转换为32位*/void Image::_convert_24_32(void * src,void * dst,int src_len);/*将位图数据保持为完整BMP数据*/bool Image::_build_bitmap(int width,int height,int bits,char * src,int srclen,std::auto_ptr<char> & dst,int & dstlen) // Alpha表尺寸#define _IRWE_THUM_APLHATAB_SIZE 129// 四字类型对定义typedef __int64 QWORD;static QWORD s_AlphaTable[_IRWE_THUM_APLHATAB_SIZE];static BOOL s_bAlphaTableInit=FALSE;// 初始化Alpha表(此函数应该在主程序初始化时就调用)static void InitAlphaTable(){ QWORD temp; for(int i=0;i<_IRWE_THUM_APLHATAB_SIZE;i++) { temp = (QWORD)i; s_AlphaTable[i] = temp<<48 | temp<<32 | temp<<16 | temp; }}// 行缩放函数(内部函数)static void DrawScanLine(DWORD* DestAddr, DWORD* SrcAddr, int Width, DWORD dU){ __asm{ mov esi, SrcAddr; mov edi, DestAddr; mov ecx, Width; xor edx, edx; //edx = U1 mov ebx, dU; pxor mm7, mm7; LoopX: mov eax, edx; and eax, 0xffff; shr eax, 9; movq mm6, [s_AlphaTable + eax * 8]; //mm6 = a2 neg eax; add eax, 128; movq mm5, [s_AlphaTable + eax * 8]; //mm5 = a1 mov eax, edx; shr eax, 16; movq mm0, [esi + eax * 4]; movq mm1, mm0; PUNPCKLBW mm0, mm7; //mm0 = 0a10r10g10b1 PUNPCKHBW mm1, mm7; //mm1 = 0a20r20g20b2 pmullw mm0, mm5; pmullw mm1, mm6; paddw mm0, mm1; psrlw mm0, 7; packuswb mm0, mm0; movd eax, mm0; add edx, ebx; stosd; dec ecx; jnz LoopX; emms; }}static void DrawScanLineAlpha(DWORD* DestAddr, DWORD* SrcAddr, int Width, DWORD dU, DWORD Alpha){ if(!Alpha) return; __asm{ mov esi, SrcAddr; mov edi, DestAddr; mov ecx, Width; xor edx, edx; //edx = U1 mov ebx, dU; mov eax, Alpha; pxor mm7, mm7; movq mm4, [s_AlphaTable + eax * 8]; //mm4 = alpha LoopX: mov eax, edx; and eax, 0xffff; shr eax, 9; movq mm6, [s_AlphaTable + eax * 8]; //mm6 = a2 neg eax; add eax, 128; movq mm5, [s_AlphaTable + eax * 8]; //mm5 = a1 mov eax, edx; shr eax, 16; movq mm0, [esi + eax * 4]; movq mm1, mm0; PUNPCKLBW mm0, mm7; //mm0 = 0a10r10g10b1 movd mm2, [edi]; PUNPCKHBW mm1, mm7; //mm1 = 0a20r20g20b2 pmullw mm0, mm5; punpcklbw mm2, mm7; pmullw mm1, mm6; paddw mm0, mm1; psrlw mm0, 7; psubw mm0, mm2; pmullw mm0, mm4; psraw mm0, 7; paddw mm0, mm2; packuswb mm0, mm0; movd eax, mm0; add edx, ebx; stosd; dec ecx; jnz LoopX; emms; }}int _get_image_line(int iWidth){ return iWidth*4;}void * _get_address_of_pixel(void * data,int width,int height,int x,int y){ int iLine= _get_image_line(width); return (char*)data + y * iLine + x * sizeof(RGBTRIPLE);}void * _get_address_of_line(void * data,int width,int height,int line){ return _get_address_of_pixel(data,width,height,0,line);}int _byte_per_line(int width){ return _get_image_line(width);}using namespace OpenCam::Media;void Image::_width_adjuest(int & width){ int idle = width%4; int a = width/4; width = a*4; if(idle>0) width+=4;}void Image::BltStretch(void * pSrc,int widthSrc,int heightSrc,void *pDst,int widthDst,int heightDst){ if (!s_bAlphaTableInit) InitAlphaTable(); DWORD dU = (widthSrc<< 16) / widthDst; DWORD dV = (heightSrc<< 16) / heightDst; DWORD V1 = 0; DWORD *ps,*pd; pd=(DWORD *)_get_address_of_pixel(pDst,widthDst,heightDst,widthDst-1,0); int i = 0; for(i = 0; i < heightDst-1; i++) { DrawScanLine((DWORD*)(_get_address_of_line(pDst,widthDst,heightDst,i)) ,(DWORD *)(_get_address_of_line(pSrc,widthSrc,heightSrc,V1>>16)) ,widthDst, dU); DrawScanLineAlpha((DWORD*)(_get_address_of_line(pDst,widthDst,heightDst,i)), (DWORD *)(_get_address_of_line(pSrc,widthSrc,heightSrc,(V1>>16)+1)) ,widthDst ,dU ,(V1>>9)&0x7f); ps=(DWORD *)_get_address_of_pixel(pSrc,widthSrc,heightSrc,widthSrc-1,(V1>>16)); *pd=*ps; pd+=_byte_per_line(widthDst)/4; V1 += dV; } DrawScanLine((DWORD*)(_get_address_of_line(pDst,widthDst,heightDst,i)), (DWORD *)(_get_address_of_line(pSrc,widthSrc,heightSrc,V1>>16)) ,widthDst, dU); DrawScanLineAlpha((DWORD*)(_get_address_of_line(pDst,widthDst,heightDst,i)), (DWORD *)(_get_address_of_line(pSrc,widthSrc,heightSrc,heightSrc-1)) ,widthDst ,dU ,0x7f); ps=(DWORD *)_get_address_of_pixel(pSrc,widthSrc,heightSrc,widthSrc-1,heightSrc-1); *pd=*ps;}void Image::_convert_24_32(void * src,void * dst,int src_len){ int dst_len = (src_len*4)/3; char * pTemp,*ptr; pTemp = (char*)src; ptr = (char*)dst; for(int index=0;index<src_len/3;index++) { unsigned char r = *(pTemp++); unsigned char g = *(pTemp++); unsigned char b = *(pTemp++); *(ptr++) = r; *(ptr++) = g; *(ptr++) = b; ptr++; }}bool Image::_build_bitmap(int width,int height,int bits,char * src,int srclen,std::auto_ptr<char> & dst,int & dstlen){ try { int HEADER_SIZE = 0x36; int DESC_SIZE = 0x28; if(width==0 || height==0 || (bits!=24&&bits!=32)) throw std::string("do not support"); dstlen = HEADER_SIZE+srclen; dst.reset(new char[dstlen]); char * pdst = dst.get(); //header *pdst = 0x42; pdst++; *pdst = 0x4D; pdst++; *((int*)pdst) = dstlen; pdst+=4; *((int*)pdst) = 0; pdst+=4; *((int*)pdst) = HEADER_SIZE; pdst+=4; //desc *((int*)pdst) = DESC_SIZE; pdst+=4; *((int*)pdst) = width; pdst+=4; *((int*)pdst) = height; pdst+=4; *pdst = 0x01; pdst++; *pdst = 0x00; pdst++; *pdst = bits; pdst++; *pdst = 0x00; pdst++; *((int*)pdst) = 0; pdst+=4; *((int*)pdst) = srclen; pdst+=4; *((int*)pdst) = 0; pdst+=4; *((int*)pdst) = 0; pdst+=4; *((int*)pdst) = 0; pdst+=4; //reserve *((int*)pdst) = 0; pdst+=4; //data memcpy(pdst,src,srclen); return true; } catch(std::string) { return false; }} bmp里面就是从下往上把每个点的RGB列出来,放缩就是取相应的比例值 晕 这么长的代码,给你个简单的#include<atlimage.h>CImage* pImage;pImage=new CImage;pImage->Load(你的路劲);pImage->draw(任何你要缩放的尺寸) 这要看了,如果是处理1张2张图片用简单CImage可以,但是对于性能要求比较高的程序,还是要使用到复杂甚至汇编基本才行。这就是为什么ffmpeg,xvid等SDK源码中处处可见汇编的缘故。像xImage类库也能实现简单的处理,例如CxImage a;a.Load(...);a.Scale(...);但是看了源码就知道,其实性能很差的,缩放处理也不平滑。 这种说法也有问题,简单的比例缩放当然不行,不会出现平滑效果从1024*768缩放到200×200,明显可以看到图像变形了,真正的缩放,是需要通过alpha通道,应用相应的图形算法计算像素才行。 我是楼主Email:[email protected]谢谢各位 多文档中能否使两个窗口的下拉条同步 如何区分 WDM驱动 和NT驱动?? 如何对编辑框实时更新? FINDWINDOWEX的问题 很丢脸的问一个在函数名前加::是什么意思? 在VC6.0中如何读取二进制文件 如何传递CArray对象呢?请高手指教 在项目在查找指定的字符串 谁知道怎么在UltraEdit里编译Java程序:) 平面坐标和逻辑坐标,设备坐标 鼠标点击消息WM_LBUTTONUP不能响应? 结构体中 运算符能重载吗?
做位图高效率的缩放必须用到汇编语言,要做到平滑缩放,则要求位图具有alpha通道/*
转换主函数
pSrc 源数据 要求32位
widthSrc 源宽
heightSrc 源高
pDst 转换后数据 32位,要求先创建
widthDst 要求目标宽
heightDst 要求目标高
*/
void Image::BltStretch(void * pSrc,int widthSrc,int heightSrc,void *pDst,int widthDst,int heightDst);
/*
图片从24位转换为32位
*/
void Image::_convert_24_32(void * src,void * dst,int src_len);
/*
将位图数据保持为完整BMP数据
*/
bool Image::_build_bitmap(int width,int height,int bits,char * src,int srclen,std::auto_ptr<char> & dst,int & dstlen)
// Alpha表尺寸
#define _IRWE_THUM_APLHATAB_SIZE 129
// 四字类型对定义
typedef __int64 QWORD;
static QWORD s_AlphaTable[_IRWE_THUM_APLHATAB_SIZE];
static BOOL s_bAlphaTableInit=FALSE;
// 初始化Alpha表(此函数应该在主程序初始化时就调用)
static void InitAlphaTable()
{
QWORD temp;
for(int i=0;i<_IRWE_THUM_APLHATAB_SIZE;i++)
{
temp = (QWORD)i;
s_AlphaTable[i] = temp<<48 | temp<<32 | temp<<16 | temp;
}
}
// 行缩放函数(内部函数)
static void DrawScanLine(DWORD* DestAddr, DWORD* SrcAddr, int Width, DWORD dU)
{
__asm{
mov esi, SrcAddr;
mov edi, DestAddr;
mov ecx, Width;
xor edx, edx; //edx = U1
mov ebx, dU;
pxor mm7, mm7; LoopX:
mov eax, edx;
and eax, 0xffff;
shr eax, 9;
movq mm6, [s_AlphaTable + eax * 8]; //mm6 = a2
neg eax;
add eax, 128;
movq mm5, [s_AlphaTable + eax * 8]; //mm5 = a1 mov eax, edx;
shr eax, 16;
movq mm0, [esi + eax * 4];
movq mm1, mm0;
PUNPCKLBW mm0, mm7; //mm0 = 0a10r10g10b1
PUNPCKHBW mm1, mm7; //mm1 = 0a20r20g20b2 pmullw mm0, mm5;
pmullw mm1, mm6;
paddw mm0, mm1;
psrlw mm0, 7;
packuswb mm0, mm0;
movd eax, mm0;
add edx, ebx;
stosd; dec ecx;
jnz LoopX;
emms;
}
}static void DrawScanLineAlpha(DWORD* DestAddr, DWORD* SrcAddr, int Width, DWORD dU, DWORD Alpha)
{
if(!Alpha)
return; __asm{
mov esi, SrcAddr;
mov edi, DestAddr;
mov ecx, Width;
xor edx, edx; //edx = U1
mov ebx, dU;
mov eax, Alpha;
pxor mm7, mm7;
movq mm4, [s_AlphaTable + eax * 8]; //mm4 = alpha LoopX:
mov eax, edx;
and eax, 0xffff;
shr eax, 9;
movq mm6, [s_AlphaTable + eax * 8]; //mm6 = a2
neg eax;
add eax, 128;
movq mm5, [s_AlphaTable + eax * 8]; //mm5 = a1 mov eax, edx;
shr eax, 16;
movq mm0, [esi + eax * 4];
movq mm1, mm0;
PUNPCKLBW mm0, mm7; //mm0 = 0a10r10g10b1
movd mm2, [edi];
PUNPCKHBW mm1, mm7; //mm1 = 0a20r20g20b2 pmullw mm0, mm5;
punpcklbw mm2, mm7;
pmullw mm1, mm6;
paddw mm0, mm1;
psrlw mm0, 7; psubw mm0, mm2;
pmullw mm0, mm4;
psraw mm0, 7;
paddw mm0, mm2; packuswb mm0, mm0;
movd eax, mm0;
add edx, ebx;
stosd; dec ecx;
jnz LoopX;
emms;
}
}int _get_image_line(int iWidth)
{
return iWidth*4;
}
void * _get_address_of_pixel(void * data,int width,int height,int x,int y)
{
int iLine= _get_image_line(width);
return (char*)data + y * iLine + x * sizeof(RGBTRIPLE);
}
void * _get_address_of_line(void * data,int width,int height,int line)
{
return _get_address_of_pixel(data,width,height,0,line);
}
int _byte_per_line(int width)
{
return _get_image_line(width);
}using namespace OpenCam::Media;
void Image::_width_adjuest(int & width)
{
int idle = width%4;
int a = width/4;
width = a*4;
if(idle>0)
width+=4;
}
void Image::BltStretch(void * pSrc,int widthSrc,int heightSrc,void *pDst,int widthDst,int heightDst)
{
if (!s_bAlphaTableInit) InitAlphaTable();
DWORD dU = (widthSrc<< 16) / widthDst;
DWORD dV = (heightSrc<< 16) / heightDst;
DWORD V1 = 0; DWORD *ps,*pd;
pd=(DWORD *)_get_address_of_pixel(pDst,widthDst,heightDst,widthDst-1,0);
int i = 0;
for(i = 0; i < heightDst-1; i++)
{
DrawScanLine((DWORD*)(_get_address_of_line(pDst,widthDst,heightDst,i))
,(DWORD *)(_get_address_of_line(pSrc,widthSrc,heightSrc,V1>>16))
,widthDst, dU);
DrawScanLineAlpha((DWORD*)(_get_address_of_line(pDst,widthDst,heightDst,i)),
(DWORD *)(_get_address_of_line(pSrc,widthSrc,heightSrc,(V1>>16)+1))
,widthDst
,dU
,(V1>>9)&0x7f);
ps=(DWORD *)_get_address_of_pixel(pSrc,widthSrc,heightSrc,widthSrc-1,(V1>>16));
*pd=*ps;
pd+=_byte_per_line(widthDst)/4;
V1 += dV;
}
DrawScanLine((DWORD*)(_get_address_of_line(pDst,widthDst,heightDst,i)),
(DWORD *)(_get_address_of_line(pSrc,widthSrc,heightSrc,V1>>16))
,widthDst, dU);
DrawScanLineAlpha((DWORD*)(_get_address_of_line(pDst,widthDst,heightDst,i)),
(DWORD *)(_get_address_of_line(pSrc,widthSrc,heightSrc,heightSrc-1))
,widthDst
,dU
,0x7f);
ps=(DWORD *)_get_address_of_pixel(pSrc,widthSrc,heightSrc,widthSrc-1,heightSrc-1);
*pd=*ps;
}
void Image::_convert_24_32(void * src,void * dst,int src_len)
{
int dst_len = (src_len*4)/3;
char * pTemp,*ptr;
pTemp = (char*)src;
ptr = (char*)dst;
for(int index=0;index<src_len/3;index++)
{
unsigned char r = *(pTemp++);
unsigned char g = *(pTemp++);
unsigned char b = *(pTemp++);
*(ptr++) = r;
*(ptr++) = g;
*(ptr++) = b;
ptr++;
}
}bool Image::_build_bitmap(int width,int height,int bits,char * src,int srclen,std::auto_ptr<char> & dst,int & dstlen)
{
try
{
int HEADER_SIZE = 0x36;
int DESC_SIZE = 0x28;
if(width==0 || height==0 || (bits!=24&&bits!=32))
throw std::string("do not support");
dstlen = HEADER_SIZE+srclen;
dst.reset(new char[dstlen]);
char * pdst = dst.get();
//header
*pdst = 0x42; pdst++;
*pdst = 0x4D; pdst++;
*((int*)pdst) = dstlen; pdst+=4;
*((int*)pdst) = 0; pdst+=4;
*((int*)pdst) = HEADER_SIZE; pdst+=4;
//desc
*((int*)pdst) = DESC_SIZE; pdst+=4;
*((int*)pdst) = width; pdst+=4;
*((int*)pdst) = height; pdst+=4;
*pdst = 0x01; pdst++;
*pdst = 0x00; pdst++;
*pdst = bits; pdst++;
*pdst = 0x00; pdst++;
*((int*)pdst) = 0; pdst+=4;
*((int*)pdst) = srclen; pdst+=4;
*((int*)pdst) = 0; pdst+=4;
*((int*)pdst) = 0; pdst+=4;
*((int*)pdst) = 0; pdst+=4;
//reserve
*((int*)pdst) = 0; pdst+=4;
//data
memcpy(pdst,src,srclen);
return true;
}
catch(std::string)
{
return false;
}
}
#include<atlimage.h>
CImage* pImage;
pImage=new CImage;
pImage->Load(你的路劲);
pImage->draw(任何你要缩放的尺寸)
这就是为什么ffmpeg,xvid等SDK源码中处处可见汇编的缘故。
像xImage类库也能实现简单的处理,例如
CxImage a;
a.Load(...);
a.Scale(...);
但是看了源码就知道,其实性能很差的,缩放处理也不平滑。
从1024*768缩放到200×200,明显可以看到图像变形了,
真正的缩放,是需要通过alpha通道,应用相应的图形算法计算像素才行。
Email:[email protected]
谢谢各位