JAVA BMP解码 超详细解释

  • 格式:doc
  • 大小:218.50 KB
  • 文档页数:9

首先,对于BMP格式的图片大家都不感觉到陌生吧。

简单的说明下:BMP是一种与硬件设备无关的图像文件格式,使用非常广。

它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。

BMP文件的图像深度可选lbit、4bit、8bit及24bit。

BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。

由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。

要解析文件,就必须知道他的文件结构文件结构组成典型的BMP图像文件由四部分组成:1:位图文件头数据结构,它包含BMP图像文件的类型、显示内容等信息;2:位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;3:调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;4:位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。

对应的数据结构1.BMP文件头(14字节)BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

其结构定义如下:Int bfType; // 位图文件的类型,必须为'B''M'两个字母(0-1字节)Int bfSize; // 位图文件的大小,以字节为单位(2-5字节)usignedshort bfReserved1; // 位图文件保留字,必须为0(6-7字节)usignedshort bfReserved2; // 位图文件保留字,必须为0(8-9字节)Int bfOffBits; // 位图数据的起始位置,以相对于位图(10-13字节)Int bfOffBits; // 文件头的偏移量表示,以字节为单位2:位图信息头(40字节)BMP位图信息头数据用于说明位图的尺寸等信息。

Int Size; // 本结构所占用字节数(14-17字节)Int image_width; // 位图的宽度,以像素为单位(18-21字节)int image_heigh; // 位图的高度,以像素为单位(22-25字节)Int Planes; // 目标设备的级别,必须为1(26-27字节)int n biBitCount;// 每个像素所需的位数,必须是1(双色),(28-29字节)// 4(16色),8(256色)或24(真彩色)之一Int biCompression; // 位图压缩类型,必须是 0(不压缩),(30-33字节)// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一Int n SizeImage; // 位图的大小,以字节为单位(34-37字节)Int biXPelsPerMeter; // 位图水平分辨率,每米像素数(38-41字节)Int biYPelsPerMeter; // 位图垂直分辨率,每米像素数(42-45字节)Int biClrUsed;// 位图实际使用的颜色表中的颜色数(46-49字节)Int biClrImportant;// 位图显示过程中重要的颜色数(50-53字节)3:颜色表颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。

class RGBQUAD{byte rgbBlue;// 蓝色的亮度(值范围为0-255)byte rgbGreen; // 绿色的亮度(值范围为0-255)byte rgbRed; // 红色的亮度(值范围为0-255)byte rgbReserved;// 保留,必须为0}颜色表中RGBQUAD结构数据的个数有biBitCount来确定:当biBitCount=1,4,8时,分别有2,16,256个表项;当biBitCount=24时,没有颜色表项。

位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:class BITMAPINFO{BITMAPINFOHEADER bmiHeader; // 位图信息头RGBQUAD bmiColors[1]; // 颜色表}4:位图数据位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。

位图的一个像素值所占的字节数:当biBitCount=1时,8个像素占1个字节;当biBitCount=4时,2个像素占1个字节;当biBitCount=8时,1个像素占1个字节;当biBitCount=24时,1个像素占3个字节;Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,具体数据举例:如某BMP文件开头:424D 4690 0000 0000 0000 4600 0000 2800 0000 8000 0000 9000 0000 0100*1000 0300 0000 0090 0000 A00F 0000 A00F 0000 0000 0000 0000 0000*00F8 E007 1F00 0000*02F1 84F104F1 84F1 84F1 06F2 84F1 06F2 04F2 86F2 06F2 86F2 86F2 .... ....BMP文件可分为四个部分:位图文件头、位图信息头、彩色板、图像数据阵列,在上图中已用*分隔。

-----------------------------------猥琐分割线-------------------------------------------------------------比方说,我们就可以做一个BMP图片的查看器1、打开BMP文件时,我们这里选择使用dataInputstream 读取一个最常见的24位真彩色BMP图片Java代码1.// 创建文件输入流2.java.io.FileInputStream fis = new java.io.FileInputStream(path);3.// 将文件流包装成一个可以写基本数据类型的输出流4.java.io.DataInputStream dis = new java.io.DataInputStream(fis);2、读入BMP头文件的基本信息Java代码1.int bflen=14;2.byte bf[]=new byte[bflen];3.dis.read(bf,0,bflen); //读取14字节BMP文件头因为看到了BMP头文件中没有说明显示图片重要的信息,我只是开一个BF的数组,把头文件信息读取了出来,不做任何的处理。

3、读入位图信息头Java代码1.int bilen=40;2.byte bi[]=new byte[bilen];3.dis.read(bi,0,bilen);//读取40字节BMP信息头4.5.// 获取一些重要数据6.image_width=ChangeInt(bi,7);//源图宽度7.8.System.out.println("宽:"+image_width);9.10. image_heigh=ChangeInt(bi,11);//源图高度11. System.out.println("高:"+image_heigh);12.//位数13. int nbitcount=(((int)bi[15]&0xff)<<8) | (int)bi[14]&0xff;14. System.out.println("位数:"+nbitcount);15.//源图大小16. int nsizeimage=ChangeInt(bi,23);17. System.out.println("源图大小:"+nsizeimage);由位图信息头中我们也可以看出来,要显示图片,重要的信息也就只有几个,其他都是一些不重要的,我们直接忽略掉。

因为我是直接读取40位的信息头所以要将一些byte转为int 即ChangeInt即 4个byte -------> 一个intJava代码1.//转成int2.public int ChangeInt(byte[] bi,int start){3.return (((int)bi[start]&0xff)<<24)4.| (((int)bi[start-1]&0xff)<<16)5.| (((int)bi[start-2]&0xff)<<8)6.| (int)bi[start-3]&0xff;7.}因为24为的没有颜色表,所以我们直接读位图数据最后,最关键的就是,读取位图数据Java代码1.public void showRGB24(DataInputStream dis) throws IOException{2.this.setTitle(path);3.//弹出一个图片的窗口一个大小4.this.setSize(image_width, image_heigh);5.this.setResizable(false);6.this.setVisible(true);7.g=this.getGraphics();8.9.10.if(!(image_width*3% 4==0)){//图片的宽度不为011.skip_width =4-image_width*3%4;12.}//判断是否后面有补0 的情况13.//装载RGB颜色的数据数组14.imageR = new int[image_heigh][image_width];15.imageG = new int[image_heigh][image_width];16.imageB = new int[image_heigh][image_width];17.18.19. //按行读取如果H,W为正则倒着来20. for (int h=image_heigh-1;h>=0;h--){21. for (int w=0;w<image_width;w++){22./ 读入三原色23. int blue = dis.read();24. int green = dis.read();25. int red = dis.read();26. imageB[h][w]=blue;27. imageG[h][w]=green;28. imageR[h][w]=red;29. if(w==0){//跳过补0项30. System.out.println(dis.skipBytes(skip_width));31.32. }33. }34. }35. repaint();36.}关键就是在于位图是否有补0有则要跳过,没有就直接读,不然显示出来的BMP图像会倾斜。