BMP文件格式小总结

时间:2024-03-19 12:35:36

 1.BMP是一种与硬件无关的图像文件格式,它所占用的空间很大,不采用其他任何压缩,它的深度可选1个字节,4个字节,8个字节,24个字节,我们通常所说的真彩色就是24个字节,BMP图像的扫描方式是从下往上,从左到右,当文件的宽度不是4的倍数是,要通过补0来使文件是4的倍数,但是由于BMP图像文件占得内存太大,我们平常都不用这种格式。

 

 

2.BMP文件结构

   位图文件 头数据结构,它包含BMP图像文件的内容,显示内容等信喜,大小是14个字节。

   位图信息数据结构,它包含了图像的宽和高,通常我们要显示一张图片时,必须要把这两个数据从图像中读出来。

   调色板 像我们说的24位真彩色图的BMP不需要调色板

   位图数据  这一项比较重要,当要显示一张图片时,一定要遍历整个图片,从下往上,从左往右依次得到三种不同的颜色。

3.BMP文件解析实现

要将既定位置的图片显示出来,必须要用到输入流,因为输入流是将硬盘中的数据读到内存中来,不能只用输入流,还必须配合使用dataInputStream 或者是BufferedInputStream,

FileInputStream fis=new FileInputStream(path);//创建文件输入流
BufferedInputStream bis=new BufferedInputStream(fis);//将文件流打包

 

 其实不用缓冲流而用dataInputStream也行,效果是一样的,当创建好输入流之后,就应该读取既定位置图像的头文件,以及图像的宽度和高度。

                                               int Btop=14;//头部的长度
			byte []b=new byte[Btop];//定义一个存入图像头部的数组
			bis.read(b,0,Btop);//将图像头部的14个字节读到数组b中
			int blien=40;//读入位图信息头
			byte [] bc=new byte[blien];//定义一个存入位图信息头的数组
			bis.read(bc,0,blien);//将位图信息头的40个字节读到数组bc中
			image_width=changInt(bc,7);//获取图形的宽度
			image_height=changInt(bc,11);//获取图形的高度
                               public static int changInt(byte []bi,int i){
		return(((int)bi[i]&0xFF)<<24)|(((int)bi[i-1]&0xFF)<<16)|(((int)bi[i-2]&0xFF)<<8)|((int)bi[i-3]&0xFF);
	}

 

 因为图像的宽和高是存在第7个和第11个位置,所以传的索引值为7和11,存在数组中的是字节,所以要将byte转化成int型,又因为它读出来的位置是倒序的,所以第i个位置需左移24位才能到高8位,依次类推,要得到int值,只需将它们每8个字节先与0xff进行逻辑与,在将它们逻辑或,就可得到想要的值。

现在要做的就是读取位图数据:

 public void readRGB(BufferedInputStream bis){
				if(!(image_width*3%4==0)){
				 skip_width = 4-image_width*3%4;
			}
				//装载RGB颜色的数据数组
			imageR=new int[image_height][image_width];
			imageG=new int[image_height][image_width];
			imageB=new int[image_height][image_width];
			//读取位图数据,按行读取,从下到上,从左到右
			for(int h=image_height-1;h>=0;h--){
				for(int w=0;w<image_width;w++){
					//读入三原色
					try{
					int blue=bis.read();
					int green=bis.read();
					int red=bis.read();
					imageR[h][w]=red;
					imageG[h][w]=green;
					imageB[h][w]=blue;
//					if(w==0){//跳过补0项
//						System.out.println(dis.skipBytes(skip_width));
//					}
				}catch(IOException e){
					e.printStackTrace();
				}
				if(w==0){
					try{
						bis.skip(skip_width);
					}  catch (IOException e) {
						e.printStackTrace();
					}
				}
				}
			}
	

 

 当我们读取了位图数据之后,需要将图像显示出来,要显示图片肯定要需要窗体,所以我们再需要写一个方法,该方法是用来显示窗体的。

public void showUI(String path){
			 
			this.setTitle(path);
			this.setLocationRelativeTo(null);
			this.setSize(image_width,image_height);//弹出一个图片大的大小的窗体
			this.setResizable(false);
			this.setDefaultCloseOperation(3);
			this.setVisible(true);//窗体可见
			graphics=this.getGraphics();//得到画布
			 repaint();
			 }

 

 

 我们将图像的信息读取出来之后,就要将它显示出来,故要写一个paint方法:

/**
	 * 把的到得数据显示出来
	 */
	public void paint(Graphics g){
		for(int h=0;h<image_height;h++){
			for(int w=0;w<image_width;w++){
				g.setColor(new java.awt.Color(imageR[h][w],imageG[h][w],imageB[h][w]));
				g.drawLine(w, h, w, h);
				
			}
		}
	}

 

 整个BMP文件格式解析就已经实现了,实验的结果是:
BMP文件格式小总结
 操作中遇到的问题:虽然BMP文件解析的思路比较明确,但是在实际操作中经常遇到问题:比如我所有程序写好之后,我图片没有改为BMP格式,出现java.lang.outOfmemorryError错误,还有当我画图时,用的是g.fillOval(w,h,w,h)方法时,出现的图形刚开始怪模怪样,到最后才呈现出源图的效果。还有就是那个不是4的倍数时,为什么是if(!(image_width*3%4==0))而不是if(!image_width%4==0),