bmp图像压缩算法详细解析Word格式.docx

上传人:b****1 文档编号:5052748 上传时间:2023-05-04 格式:DOCX 页数:17 大小:20.54KB
下载 相关 举报
bmp图像压缩算法详细解析Word格式.docx_第1页
第1页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第2页
第2页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第3页
第3页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第4页
第4页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第5页
第5页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第6页
第6页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第7页
第7页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第8页
第8页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第9页
第9页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第10页
第10页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第11页
第11页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第12页
第12页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第13页
第13页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第14页
第14页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第15页
第15页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第16页
第16页 / 共17页
bmp图像压缩算法详细解析Word格式.docx_第17页
第17页 / 共17页
亲,该文档总共17页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

bmp图像压缩算法详细解析Word格式.docx

《bmp图像压缩算法详细解析Word格式.docx》由会员分享,可在线阅读,更多相关《bmp图像压缩算法详细解析Word格式.docx(17页珍藏版)》请在冰点文库上搜索。

bmp图像压缩算法详细解析Word格式.docx

位图压缩类型,有效的值为BI_RGB(未经压缩)、BI_RLE8、BI_RLE4、BI_BITFILEDS(均为Windows定义常量)。

这里只讨论未经压缩的情况,即biCompression=BI_RGB。

DWORDbiSizeImage;

实际的位图数据占用的字节数

LONGbiXPelsPerMeter;

指定目标设备的水平分辨率,单位是像素/米。

LONGbiYPelsPerMeter;

指定目标设备的垂直分辨率,单位是像素/米。

DWORDbiClrUsed;

位图实际用到的颜色数,如果该值为零则用到的颜色数为2的biBitCount次幂。

DWORDbiClrImportant;

位图显示过程中重要的颜色数,如果该值为零则认为所有的颜色都是重要的

}BITMAPINFOHEADER,FAR*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER;

·

第3部分为颜色表。

颜色表实际上是一个RGBQUAD结构的数组,数组的长度由biClrUsed指定(如果该值为零,则由biBitCount指定,即2的biBitCount次幂个元素)。

RGBQUAD结构是一个结构体类型,占4个字节,其定义如下:

typedefstructtagRGBQUAD

BYTErgbBlue;

该颜色的蓝色分量;

BYTErgbGreen;

该颜色的绿色分量;

BYTErgbRed;

该颜色的红色分量;

BYTErgbReserved;

保留字节,暂不用。

}RGBQUAD;

有些位图需要颜色表;

有些位图(如真彩色图)则不需要颜色表,颜色表的长度由BITMAPINFOHEADER结构中biBitCount分量决定。

对于biBitCount值为1的二值图像,每像素占1bit,图像中只有两种(如黑白)颜色,颜色表也就有2^1=2个表项,整个颜色表的大小为8个字节;

对于biBitCount值为8的灰度图像,每像素占8bit,图像中有2^8=256种颜色,颜色表也就有256个表项,且每个表项的R、G、B分量相等,整个颜色表的大小为1024个字节;

而对于biBitCount=24的真彩色图像,由于每像素3个字节中分别代表了R、G、B三分量的值,此时不需要颜色表,因此真彩色图的BITMAPINFOHEADER结构后面直接就是位图数据。

第4部分是位图数据,即图像数据,其紧跟在位图文件头、位图信息头和颜色表(如果有颜色表的话)之后,记录了图像的每一个像素值。

对于有颜色表的位图,位图数据就是该像素颜色在调色板中的索引值;

对于真彩色图,位图数据就是实际的R、G、B值(三个分量的存储顺序是B、G、R)。

下面分别就2色、16色、256色和真彩色位图的位图数据进行说明:

—对于2色位图,用1位就可以表示该像素的颜色,所以1个字节能存储8个像素的颜色值。

—对于16色位图,用4位可以表示一个像素的颜色。

所以一个字节可以存储2个像素的颜色值。

—对于256色位图,1个字节刚好存储1个像素的颜色值。

—对于真彩色位图,3个字节才能表示1个像素的颜色值。

需要注意两点:

第一,Windows规定一个扫描行所占的字节数必须是4的倍数,不足4的倍数则要对其进行扩充。

假设图像的宽为biWidth个像素、每像素biBitCount个比特,其一个扫描行所占的真实字节数的计算公式如下:

DataSizePerLine=(biWidth*biBitCount/8+3)/4*4

那么,不压缩情况下位图数据的大小(BITMAPINFOHEADER结构中的biSizeImage成员)计算如下:

biSizeImage=DataSizePerLine*biHeight

第二,一般来说,BMP文件的数据是从图像的左下角开始逐行扫描图像的,即从下到上、从左到右,将图像的像素值一一记录下来,因此图像坐标零点在图像左下角。

好了,有了以上的知识后,可以开始压缩程序啦~恩,现在问题是怎么读取那两个结构体,大家都知道c语言的文件读取有两种方式,一个是按字节读取,一个是按位读取,那么用哪个呢只好又XX了................好了,XX好了:

二进制方式很简单,读文件时,会原封不动的读出文件的全部內容,写的時候,也是把內存缓冲区的內容原封不动的写到文件中。

而文本方式就不一样了,在读文件时,会将换行符号CRLF(0x0D0x0A)全部转换成单个的0x0A,并且当遇到结束符CTRLZ(0x1A)时,就认为文件已经结束。

相应的,写文件时,会将所有的0x0A换成0x0D0x0A。

所以,若使用文本方式打开二进制文件时,就很容易出现文件读不完整,或內容不对的错误。

即使是用文本方式打开文本文件,也要谨慎使用,比如复制文件,就不应该使用文本方式。

(更多类容请自己XX)

;

这里我们选择二进制的读入方式

fread(&

h,sizeof(BITMAPFILEHEADER),1,fp);

以上以读取头部为例,其它的类似(注意要按顺序读取,不要弄反了)

好了,到此第一步已经完成了我们把灰度信息读取到了一个数组里,那开始压缩了,这个按书上那个程序就好,压完得到一个l[],b[],分别记录每一段的长度和那一段每个像素需要的位数,特别提醒,书上的程序有一个bug!

原文output函数里有一段是这样的:

for(intj=1;

j<

=m;

j++){l[j]=l[s[j]];

b[j]=b[s[j]];

}

应该是

for(j=1;

j<

=m;

j++){

l[j]=l[s[j]];

max=-1;

~

for(i=s[j-1]+1;

i<

=s[j];

i++){)

好了,灰度值我们知道怎么压缩了,下面就开始压缩吧,头部,头部信息,调试板不变,直接写进文件,额不对,我们怎么知道压缩后的灰度值数组有多长还记得这个吗DWORDbiSizeImage;

实际的位图数据占用的字节数,我们把压缩后的灰度值数组大小存进去,到时候解压的时候别忘了恢复哈。

压缩完了,下面开始解压,解压就是压缩的逆过程

同样的,我们用i指示当前要读取的字节,left指示当前字节剩余的可用位数,bit表示要读取的灰度值的位数,将结果存到temp里面

if(left<

=bit){

$

temp+=((a[i++]<

<

(8-left))&

0xff)>

>

(8-bit);

temp+=a[i]>

(8-(bit-left));

left=8-(bit-left);

}else{

temp+=((a[i]>

(left-bit)<

(8-bit))&

0xff)

*

>

left-=bit;

}

对运算符的优先级不了解的话还是老老实实加括号吧(同样的自己在草稿纸上演算一下)

至此,大功告成了。

将bmp四部分的信息按顺序写入文件就好了。

下面贴上可以运行的代码,写得有点乱,有时间重构下...

压缩程序

#include<

#definelmax256//压缩时每一段包含的最大像素数

#defineheader11//每一段需要11位来保存这一段的信息(8位用来表示段长度

//,3位用来表示每一像素占的位数)

intbmpWidth;

//图像的宽

intbmpHeight;

//图像的高

RGBQUAD*pColorTable;

//颜色表指针

intbiBitCount;

//图像类型,每像素位数

unsignedchar*pBmpBuf;

//灰度值数组

intlineByte;

//每一行的字节数

BITMAPFILEHEADERh;

//头部

BITMAPINFOHEADERhead;

//头部信息

inti,j;

//循环要用到的遍历变量

int*s,*l,*b;

//这三个数组的意义和书上是一样的

intm;

//分割的段数

intle(inti)//log(i+1)向上取整

intk=1;

i=i/2;

while(i>

0){

\

k++;

returnk;

voidtraceback(intn,ints[],intl[])//和书上一样不解释了

if(n==0)

return;

traceback(n-l[n],s,l);

s[m++]=n-l[n];

voidcompress(unsignedcharp[],ints[],intl[],intb[])//这个也和书上一样

intn=bmpWidth*bmpHeight;

'

intbmax;

s[0]=0;

for(i=1;

=n;

i++){

b[i]=le(p[i]);

bmax=b[i];

s[i]=s[i-1]+bmax;

l[i]=1;

for(j=2;

=i&

&

=lmax;

if(bmax<

b[i-j+1])

bmax=b[i-j+1];

if(s[i]>

s[i-j]+j*bmax){

s[i]=s[i-j]+j*bmax;

l[i]=j;

s[i]+=header;

voidcollect(unsignedcharp[],ints[],intl[],intb[])

intmax;

traceback(n,s,l);

s[m]=n;

for(j=1;

i++){//特别注意这个地方,书上错了

if(le(p[i])>

max)//b[i]应该取第i段中占用位数最大的那个

max=le(p[i]);

b[j]=max;

voidstore(unsignedchar*a,int*j,int*left,intbit,inttemp)//将temp存到数组里

if(*left<

=bit){

a[(*j)++]+=temp>

(bit-(*left));

a[(*j)]+=(temp<

(8+(*left)-bit))&

0xff;

*left=8-(bit-(*left));

}else{

a[(*j)]+=(temp<

(*left-bit))&

*left-=bit;

[

voidcompressToFile(char*file,unsignedcharp[],intl[],intb[],intm)//压缩存到文件里

FILE*out=fopen(file,"

wb"

);

intn=bmpWidth*bmpHeight,left,k=1,t;

unsignedchar*a=(unsignedchar*)malloc(n);

memset(a,0,n);

left=8;

j=0;

store(a,&

j,&

left,8,l[i]-1);

left,3,b[i]-1);

t=k+l[i];

for(;

k<

t;

k++){

left,b[i],p[k]);

=j+1;

//修改文件大小,这个解压图像中要用到

fwrite(&

h,sizeof(BITMAPFILEHEADER),1,out);

head,sizeof(BITMAPINFOHEADER),1,out);

fwrite(pColorTable,sizeof(RGBQUAD),256,out);

fwrite(a,1,j+1,out);

fclose(out);

unsignedchar*readBmp(char*file)//读取文件

]

unsignedchar*pBmpBuf;

FILE*fp=fopen(file,"

rb"

fread(&

//获取图片头信息

head,sizeof(BITMAPINFOHEADER),1,fp);

//定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中

bmpWidth=;

//获取图像宽、高、每像素所占位数等信息

@

bmpHeight=;

biBitCount=;

lineByte=(bmpWidth*biBitCount/8+3)/4*4;

//定义变量,计算图像每行像素所占的字节数(必须是4的倍数)

if(biBitCount==8){

pColorTable=(RGBQUAD*)malloc(sizeof(RGBQUAD)*256);

//申请颜色表所需要的空间,读颜色表进内存

fread(pColorTable,sizeof(RGBQUAD),256,fp);

//灰度图像有颜色表,且颜色表表项为256

}

pBmpBuf=(unsignedchar*)malloc(sizeof(unsignedchar)*(lineByte//申请位图数据所需要的空间,读位图数据进内存

*bmpHeight+1));

fread(pBmpBuf+1,1,lineByte*bmpHeight,fp);

//为了数组下标从1开始

fclose(fp);

//关闭文件

returnpBmpBuf;

intmain()

^

char*file="

"

pBmpBuf=readBmp(file);

s=(int*)malloc(sizeof(int)*(bmpWidth*bmpHeight+1));

l=(int*)malloc(sizeof(int)*(bmpWidth*bmpHeight+1));

b=(int*)malloc(sizeof(int)*(bmpWidth*bmpHeight+1));

compress(pBmpBuf,s,l,b);

collect(pBmpBuf,s,l,b);

compressToFile("

pBmpBuf,l,b,m);

return0;

解压程序

//要恢复灰度值数组

unsignedchar*a;

//压缩的灰度值数组

voidload(unsignedchar*a,int*i,int*left,intbit,int*temp)//将temp存到数组里

*temp+=((a[(*i)++]<

(8-(*left)))&

*temp+=a[(*i)]>

(8-(bit-(*left)));

*temp+=((a[(*i)]>

((*left)-bit)<

voidcraming()

FILE*ss=fopen("

"

intleft=8,bit,length,k;

inti=0;

//解压前数组index

intj=0;

//解压后数组index

while(i<

{

length=0;

bit=0;

load(a,&

i,&

left,8,&

length);

left,3,&

bit);

length++;

//因为压缩的时候有减1

bit++;

k=j;

k+length;

left,bit,&

pBmpBuf[j]);

=bmpWidth*bmpHeight;

//恢复像素所占的空间

h,sizeof(BITMAPFILEHEADER),1,ss);

head,sizeof(BITMAPINFOHEADER),1,ss);

fwrite(pColorTable,sizeof(RGBQUAD),256,ss);

fwrite(pBmpBuf,1,,ss);

fclose(ss);

unsignedchar*readBmp(char*file)

unsignedchar*a;

if(biBitCount==8){

a=(unsignedchar*)malloc;

fread(a,1,,fp);

returna;

a=readBmp(file);

pBmpBuf=(unsignedchar*)malloc(sizeof(unsignedchar)*lineByte

*bmpHeight);

/

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 总结汇报 > 学习总结

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2