使用GDI+保存图片为GIF效果很差??缺了抖动算法??? 使用GDI进行图形转换很方便,但是存为GIF,效果很差且尺寸很大,怎么回事??缺了抖动算法???ACDSEE的CONVERT为GIF,几乎不失真,太棒了,可惜,我怎样才能做到??? 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 256色是调色版格式无法直接进行色彩空间映射所以有三种方法处理:一、最近颜色匹配。Windows就是用这种方法,与系统调色版匹配二、有序抖动、误差分散等抖动算法三、色彩量化处理。效果是最好的,但算法极其复杂,一般人是看不懂的我写的 有序抖动 的例子:http://zyl910vb.51.net/vb/map/ddsfdq.htmhttp://zyl910vb.51.net/vb/map/ddsfDIB.htm右击连接,目标另存为注意把下载后的*.zip.jpg改名成*.zip保存gif:http://expert.csdn.net/Expert/topic/679/679628.xml?temp=.3175775 有一点要说明,我们原来介绍的程序都是先开一个char类型的缓冲区,用来存储新图数据,但在这个算法中,因为e有可能是负数,为了防止得到的值超出char能表示的范围,我们使用了一个int类型的缓冲区存储新值。另外,当按从左到右,从上到下的顺序处理像素时,处理过的像素以后不会再用到了,所以用这个int类型的缓冲区存储新值是可行的。全部像素处理完后,再将这些值拷贝到char类型的缓冲区去。BOOL Steinberg(HWND hWnd){DWORD OffBits,BufSize,IntBufSize;LPBITMAPINFOHEADER lpImgData;HLOCAL hTempImgData;LPBITMAPINFOHEADER lpTempImgData;LPSTR lpPtr;LPSTR lpTempPtr;HDC hDc;HFILE hf;LONG x,y;unsigned char num;float e,f;HLOCAL hIntBuf;int *lpIntBuf,*lpIntPtr;int tempnum;//OffBits为BITMAPINFOHEADER结构长度加调色板的大小OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);BufSize=bf.bfSize-sizeof(BITMAPFILEHEADER); //要开的缓冲区的大小if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL) //char 类型的缓冲区{MessageBox(hWnd,"Error alloc memory!","Error Message",MB_OK|MB_ICONEXCLAMATION);return FALSE;}IntBufSize=(DWORD)bi.biHeight*LineBytes*sizeof(int); //int类型缓冲区的大小if((hIntBuf=LocalAlloc(LHND,IntBufSize))==NULL) //int 类型的缓冲区{MessageBox(hWnd,"Error alloc memory!","Error Message",MB_OK|MB_ICONEXCLAMATION);LocalFree(hTempImgData);return FALSE;}lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData); lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);lpIntBuf=(int *)LocalLock(hIntBuf);//拷贝头信息memcpy(lpTempImgData,lpImgData,OffBits);//将图象数据拷贝到int类型的缓冲区中for(y=0;y<bi.biHeight;y++){lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes);lpIntPtr=(int *)lpIntBuf+(bi.biHeight-1-y)*LineBytes;for(x=0;x<bi.biWidth;x++) *(lpIntPtr++)=(unsigned char)*(lpPtr++);}for(y=0;y<bi.biHeight;y++){for(x=0;x<bi.biWidth;x++){lpIntPtr=(int *)lpIntBuf+(bi.biHeight-1-y)*LineBytes+x; num=(unsigned char)*lpIntPtr; if ( num > 128 ){ //128是中值 *lpIntPtr=255; //打白点 e=(float)(num-255.0); //计算误差 } else{ *lpIntPtr=0; //打黑点 e=(float)num; //计算误差 } if(x<bi.biWidth-1){ //注意判断边界 f=(float)*(lpIntPtr+1); f+=(float)( (3.0/8.0) * e); *(lpIntPtr+1)=(int)f; //向左传播} if(y<bi.biHeight-1){ //注意判断边界 f=(float)*(lpIntPtr-LineBytes); f+=(float)( (3.0/8.0) * e); *(lpIntPtr-LineBytes)=(int)f; //向下传播 f=(float)*(lpIntPtr-LineBytes+1); f+=(float)( (1.0/4.0) * e); *(lpIntPtr-LineBytes+1)=(int)f; //向右下传播 } }}//从int类型的缓冲区拷贝到char类型的缓冲区for(y=0;y<bi.biHeight;y++){lpTempPtr=(char *)lpTempImgData+(BufSize-LineBytes-y*LineBytes);lpIntPtr=(int *)lpIntBuf+(bi.biHeight-1-y)*LineBytes;for(x=0;x<bi.biWidth;x++){ tempnum=*(lpIntPtr++); if(tempnum>255) tempnum=255; else if (tempnum<0) tempnum=0; *(lpTempPtr++)=(unsigned char)tempnum; }}if(hBitmap!=NULL)DeleteObject(hBitmap);hDc=GetDC(hWnd);//产生新的位图 hBitmap=CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lpTempImgData, (LONG)CBM_INIT,(LPSTR)lpTempImgData+sizeof(BITMAPINFOHEADER) +NumColors*sizeof(RGBQUAD), (LPBITMAPINFO)lpTempImgData, DIB_RGB_COLORS);hf=_lcreat("c:\\steinberg.bmp",0);_lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER)); _lwrite(hf,(LPSTR)lpTempImgData,BufSize);_lclose(hf);//释放内存和资源ReleaseDC(hWnd,hDc);GlobalUnlock(hImgData);LocalUnlock(hTempImgData);LocalFree(hTempImgData);LocalUnlock(hIntBuf);LocalFree(hIntBuf);return TRUE;}要注意的是,误差传播有时会引起流水效应,即误差不断向下,向右累加传播。解决的办法是:奇数行从左到右传播,偶数行从右到左传播。 vector可以支持类添加吗? 像杀毒软件一样在windows启动前添加自己的图标? VC8 下 如何将CString 转换成 int 谁知道如何获得mp3中的id3信息? 【开源】一个自己封装的xml类 请问如何枚举并切换当前使用的摄像头?要求不用DirectX,只能用API. 那里有com本质论(中文版的,潘或者侯捷的都可以)下载么? 进程管理 一个多视单文档的问题 两个软件之间的通讯 怎样控制别人程序中的CheckBox???(在线等待) 工具栏的问题,一定有人知道。如果不是那么简单可再加分。
无法直接进行色彩空间映射
所以有三种方法处理:
一、最近颜色匹配。Windows就是用这种方法,与系统调色版匹配
二、有序抖动、误差分散等抖动算法
三、色彩量化处理。效果是最好的,但算法极其复杂,一般人是看不懂的
我写的 有序抖动 的例子:
http://zyl910vb.51.net/vb/map/ddsfdq.htm
http://zyl910vb.51.net/vb/map/ddsfDIB.htm右击连接,目标另存为
注意把下载后的*.zip.jpg改名成*.zip
保存gif:
http://expert.csdn.net/Expert/topic/679/679628.xml?temp=.3175775
所以用这个int类型的缓冲区存储新值是可行的。全部像素处理完后,再将这些值拷贝到char类型的缓冲区去。
BOOL Steinberg(HWND hWnd)
{
DWORD OffBits,BufSize,IntBufSize;
LPBITMAPINFOHEADER lpImgData;
HLOCAL hTempImgData;
LPBITMAPINFOHEADER lpTempImgData;
LPSTR lpPtr;
LPSTR lpTempPtr;
HDC hDc;
HFILE hf;
LONG x,y;
unsigned char num;
float e,f;
HLOCAL hIntBuf;
int *lpIntBuf,*lpIntPtr;
int tempnum;//OffBits为BITMAPINFOHEADER结构长度加调色板的大小
OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);
BufSize=bf.bfSize-sizeof(BITMAPFILEHEADER); //要开的缓冲区的大小
if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL) //char 类型的缓冲区
{
MessageBox(hWnd,"Error alloc memory!","Error
Message",MB_OK|
MB_ICONEXCLAMATION);
return FALSE;
}
IntBufSize=(DWORD)bi.biHeight*LineBytes*sizeof(int); //int类型缓冲区的大小
if((hIntBuf=LocalAlloc(LHND,IntBufSize))==NULL) //int 类型的缓冲区
{
MessageBox(hWnd,"Error alloc memory!","Error
Message",MB_OK|
MB_ICONEXCLAMATION);
LocalFree(hTempImgData);
return FALSE;
}
lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);
lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImg
Data);
lpIntBuf=(int *)LocalLock(hIntBuf);//拷贝头信息
memcpy(lpTempImgData,lpImgData,OffBits);
//将图象数据拷贝到int类型的缓冲区中
for(y=0;y<bi.biHeight;y++){
lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes);
lpIntPtr=(int *)lpIntBuf+(bi.biHeight-1-y)*LineBytes;
for(x=0;x<bi.biWidth;x++)
*(lpIntPtr++)=(unsigned char)*(lpPtr++);
}for(y=0;y<bi.biHeight;y++){
for(x=0;x<bi.biWidth;x++){
lpIntPtr=(int *)lpIntBuf+(bi.biHeight-1-y)*LineBytes+x;
num=(unsigned char)*lpIntPtr;
if ( num > 128 ){ //128是中值
*lpIntPtr=255; //打白点
e=(float)(num-255.0); //计算误差
}
else{
*lpIntPtr=0; //打黑点
e=(float)num; //计算误差
}
if(x<bi.biWidth-1){ //注意判断边界
f=(float)*(lpIntPtr+1);
f+=(float)( (3.0/8.0) * e);
*(lpIntPtr+1)=(int)f; //向左传播
}
if(y<bi.biHeight-1){ //注意判断边界
f=(float)*(lpIntPtr-LineBytes);
f+=(float)( (3.0/8.0) * e);
*(lpIntPtr-LineBytes)=(int)f; //向下传播
f=(float)*(lpIntPtr-LineBytes+1);
f+=(float)( (1.0/4.0) * e);
*(lpIntPtr-LineBytes+1)=(int)f; //向右下传播
}
}
}
//从int类型的缓冲区拷贝到char类型的缓冲区
for(y=0;y<bi.biHeight;y++){
lpTempPtr=(char *)lpTempImgData+(BufSize-LineBytes-
y*LineBytes);
lpIntPtr=(int *)lpIntBuf+(bi.biHeight-1-y)*LineBytes;
for(x=0;x<bi.biWidth;x++){
tempnum=*(lpIntPtr++);
if(tempnum>255) tempnum=255;
else if (tempnum<0) tempnum=0;
*(lpTempPtr++)=(unsigned char)tempnum;
}
}
if(hBitmap!=NULL)
DeleteObject(hBitmap);
hDc=GetDC(hWnd);
//产生新的位图
hBitmap=CreateDIBitmap(hDc,
(LPBITMAPINFOHEADER)lpTempImgData,
(LONG)CBM_INIT,
(LPSTR)lpTempImgData+sizeof(BITMAPI
NFOHEADER)
+NumColors*sizeof(RGBQUAD),
(LPBITMAPINFO)lpTempImgData,
DIB_RGB_COLORS);
hf=_lcreat("c:\\steinberg.bmp",0);
_lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));
_lwrite(hf,(LPSTR)lpTempImgData,BufSize);
_lclose(hf);
//释放内存和资源
ReleaseDC(hWnd,hDc);
GlobalUnlock(hImgData);
LocalUnlock(hTempImgData);
LocalFree(hTempImgData);
LocalUnlock(hIntBuf);
LocalFree(hIntBuf);
return TRUE;
}
要注意的是,误差传播有时会引起流水效应,即误差不断向下,向右累加传播。解决的办法是:奇数行从左到右传播,偶数行从右到左传播。