日期:2014-05-20  浏览次数:20570 次

读取bmp文件时的位操作问题
Java code

            FileInputStream stream = new FileInputStream(filePath);
            
            byte bh[] = new byte[bfhead];
            byte bi[] = new byte[bfinfo];
            stream.read(bh, 0, bfhead);
            stream.read(bi, 0, bfinfo);
            
            // 因为数据是以小端方式存储的,所以高地址存放的是高位数据
            width = ( ( (int) bi[7] & 0xff) << 24) //width of source file
            | ( ( (int) bi[6] & 0xff) << 16)
            | ( ( (int) bi[5] & 0xff) << 8)
            | (int) bi[4] & 0xff;
            height = ( ( (int) bi[11] & 0xff) << 24) //heigth of source file
            | ( ( (int) bi[10] & 0xff) << 16)
            | ( ( (int) bi[9] & 0xff) << 8)
            | (int) bi[8] & 0xff;


以上代码中width, height在之前已经定义为int类型。数组bi中存放的是位图信息头40个字节的数据。
为什么在取bi中4个字节的位图宽度和高度时每个字节都要进行“& 0xff”操作?求解释


------解决方案--------------------
主要原因是java的byte类型是有符号的,不进行&0xff操作的话,就会得到不正确的数。

假设位图高为1000,其16进制表示为3e8. 存放到4个字节里是 bi[7]=0x00;bi[6]=0x00;bi[5]=0x03;bi[4]=0xe8(232). 把他们组合起来,能够得到1000。
java 里还原这个整数,实际上是把这4个字节的数,组合起来,形成一个int型整数。
对于bi[7],bi[6],bi[5],因为他们的范围小于127,都是正整数(符号位为0)。即使不进行&0xff操作,也正常。
但对于bi[4],不处理就有问题了!java 读这个字节时,java把它认为是个负数,是-24! (实际上是232)看看变成int型的情况,(int)bi[4]:
变成int型,占4个子节,实际上还是-24,其二进制表示是:
1111 1111 1111 1111 1111 1111 1110 1000,显然这个数不是我们要的232,那怎么办呢,用位与运算最好解决了。把它和0xff(二进制是0000 0000 0000 0000 0000 0000 1111 1111)进行与运算,最后就得到了,
0000 0000 0000 0000 0000 0000 1110 1000,即10进制的232。把代表负号的高位都去掉了,得到了0000 0000 0000 0000 0000 0000 1110 1000。

我说的不一定清楚,楼主参考一下。