Jpeg压缩的二进制流代码解析

  Jpeg压缩,由于需要进行Huffman编码,所以出现了很多二进制码流。而实际在计算机处理中,都是按照一个字节的来进行存储和处理的。这样就出现了一个很现实的问题-如何

读取和写入二进制码流?
  看一段实际的代码(摘自网上)
static Uint8 bytenew=0; // The byte that will be written in the JPG file
static Int8 bytepos=7; //bit position in the byte we write (bytenew)
//should be<=7 and >=0
static Uint16 mask[16]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};

这三个全局变量基本上就是在字节中处理二进制码流的基础。
在这段代码中的存储函数


 //********************************************************************
 // 方法名称:savebytes
 // 方法说明:保存数据流
 // 参数说明:
 // savestream:欲保存的数据流
 // filestream:保存位置
 // savelength:该次保存的数据长度
 // filelength:文件总长度(用于单增)
 //********************************************************************
void savebytes(char *savestream, char *filestream, int savelength, Uint32 *filelength)
{
    int i;
 int tempfilelength=*filelength;
 for(i=0;i<savelength;i++)
 {
  *(filestream+i+tempfilelength)=*(savestream+i);
  (*filelength)++;
 }
}
从这个函数中可以看到是 将savestream中的字节拷贝savelength个字节到filestream中去,然后对应更改文件长度

 


 //********************************************************************
 // 方法名称:WriteBits
 //
 // 方法说明:写入二进制流
 //
 // 参数说明:
 // value:AC/DC信号的振幅
 //********************************************************************
 void WriteBits(HUFFCODE huffCode)
 { 
  WriteBitsStream(huffCode.code,huffCode.length);
 }
 
 void WriteBitsSYM2(SYM2 sym)
 {
  WriteBitsStream(sym.amplitude,sym.codeLen);
 }
 
 //********************************************************************
 // 方法名称:WriteBitsStream
 // 方法说明:写入二进制流
 // 参数说明:
 // value:需要写入的值
 // codeLen:二进制长度
 //********************************************************************
 void WriteBitsStream(Uint16 value,Int8 codeLen)
 {
  int posval;//bit position in the bitstring we read, should be<=15 and >=0
  posval=codeLen-1;
  while (posval>=0)
  {
   if (value & mask[posval])
   {
    bytenew|=mask[bytepos];
   }
   posval--;bytepos--; //bytepos is the position in a byte.
   if (bytepos<0)
   {
    if (bytenew==0xFF)
    {
     static Uint8 tempbytenew=0;
     savebytes((char*)&bytenew,jpegstream,sizeof(bytenew),&length);
     savebytes((char*)&tempbytenew,jpegstream,1,&length);
    }
    else
    {
     savebytes((char*)&bytenew,jpegstream,sizeof(bytenew),&length);
    }
    bytepos=7;bytenew=0;   // if bytepos get a zero,Set it to 7.
   }
  }
 }
注意:WriteBitsStream中的length是全局变量,代表文件中当前已写入了多少个字节长度。
bytepos指示这个bit在当前这个字节中位置,所以范围是0~7.
   而由于Huffman编码的长度不止8bit,也可能会超过8bit,所以由codeLen来表示长度,并且根据codeLen的长度来控制循环。至于为什么要等到bytepos<0,才调用savebytes来存储,当然是因为计算机的存储时以字节为单位的,所以我们不得已只能让bytepos<0来作为完成8个bit的存储的标志。由于程序的这种设计,我们可以看到,如果不到8bit(即一个字节)时,即使调WriteBitsStream,也不会存储二进制数,只是更改相应的bytenew的值,为下次写入bit做准备,直到又一次调用WriteBitsStream时,bytepos终于小于0了累积到了8bit时才写入一个字节,写完后重新置bytepos=7;bytenew=0,重头开始。
  函数实际的运行过程:从value中的低bit往高bit位置开始数codeLen个bit,然后从高bit的位置开始取bit,若如果该位数据为1,则将其对应的bytenew这个字节中的权值(相与)的值置1(添加到bytenew中去),bytenew的权值的相关变量bytepos会减一;若该位数据位0,则bytenew的权值的相关变量bytepos仍然会减一,bytenew中该权值对应的位即为0,这样下次则考虑下一位的权值。
例如:
在开始运行时,
第一次调用WriteBitsStream。
如果value值等于0x7e ,codeLen等于0x07。
那么在WriteBitsStream运行完后,bytenew等于0xfc,bytepos等于0x00。而且这两个个值会被保留到下一次WriteBitsStream调用

第二次调用WriteBitsStream。
如果value值等于0xe3,codeLen等于0x08。
那么在WriteBitsStream运行过程中,bytepos在运行在判决bytepos<0时,已经小于0了,这样直接执行
savebytes((char*)&bytenew,jpegstream,sizeof(bytenew),&length);将0xFC存储值jpegstream中。posval也减少了一位。
接着重新开始由bytepos=7;bytenew=0;来进行。

 

从低到高数到7bit,然后开始从这个高bit的位置往低bit的方向取7bit为0xfc。同理0x000000e3也是从低到高数出9bit,然后从这个高bit的位置往低bit的方向取1bit为0。所以最

终形成一个字节得到0xfc。


注:intel中都是实际存储都是低bit在前,高bit在后的。所谓的big-endian,数据的MSB是最有意义的数据位,存放在低地址位置。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值