`
JAVA小韦
  • 浏览: 6882 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

读懂BMP,用BMP来表达

    博客分类:
  • java
阅读更多

       如果有个伪文青问你:“你能读懂这个世界吗?”作为技术男的你就要很淡定的说:“只要把它的协议给我,就有办法读懂它。”读,就是对信息的分析解释理解。世界是复杂的,可对于信息的有效传递,我认为,可以简单的概括为“理解——表达”的模式,而连接理解和表达的逻辑桥梁就是规则、协议。虽然是技术男,但你是不是也经常因为不理解心爱的人的心思而犯愁,她/他想要苹果,你却认为她/他想要的是香蕉,唉,没办法,网上没有这样的协议可供下载,或许有用的就是心理学规律了。而现在要讲的就是bmp的读取,我们要用电脑去理解bmp文件描述的画面,从某个角度来说,这要比用心理解那个ta要简单,因为计算机表达的都是确定的信息,是用一个个01串,一个一个字节去沟通的。

       首先从bmp文件的协议入手,这是我在网上搜到的bmp解析文档:http://wenku.baidu.com/view/e9ed3ae39b89680203d8257d.html,我就不多说了,总而言之,bmp的协议主要由四个部分组成:1.文件头信息块。2.图像描述信息块。3.颜色表。4.图像数据区。我们先从简单的24位bmp图开始,而24位图是不用颜色表的。为了比较好的理解协议,一开始我是用UltraEdit十六进制的显示方式打开一张小图片,一个一个去对照理解的,如果有带有标记的红绿蓝三种颜色每种都有256色的笔,我们也可以参照协议画出那幅图,哈哈,当然只是假设。既然我的目标是用我编的程序显示bmp文件,那么我就抓住关键点得就行了——文件协议所对应的的有用信息:1.图片的长和宽。2.图片每个像素点的颜色值。3.基本规律:图像的扫描方式是自下而上,自左而右的;为了方便扫描,文件的行字节数是4的倍数,不够的用0补齐。代码实现如下:

因为在读取图片的长和宽时,字节需要逆置再读入一个整型

/**
	 * 将读入的四个字节,按第一个字节为最低位,最后一个字节为最高位转为整数型
	 * @param dis 输入流
	 * @return 所需整数
	 */
	public int changeInt(DataInputStream dis){
        int ch1=0,ch2=0,ch3=0,ch4=0;
		try {
			    ch1 = dis.read();
			    ch2 = dis.read();
		        ch3 = dis.read();
		        ch4 = dis.read();
		        if ((ch1 | ch2 | ch3 | ch4) < 0)
		            throw new EOFException();
		} catch (Exception e) {
			e.printStackTrace();
		}
		 return ((ch1 << 0) + (ch2 << 8) + (ch3 << 16) + (ch4 << 24));
    }

 解决了这个问题,我们就可以依次读取我们需要的数据了

/**
	 * 读取文件
	 * @param f文件路径
	 */
	public void readFile(File f){
		try {
			fis = new FileInputStream(f);
			dis = new DataInputStream(fis);
			//读取文件头信息块,共14个字节
			int firstLen = 14;
			byte[] bs1 = new byte[firstLen];
			dis.read(bs1);
			//读取图像描述信息块,获得图片长宽,共40个字节
			dis.readInt();
			Wide = this.changeInt(dis);
			Height = this.changeInt(dis);
			int secondLen = 28;
			byte[] bs2 = new byte[secondLen];
			dis.read(bs2);
			//读取图像数据区,将获取值存入二维坐标颜色数组
			R = new int[Height][Wide];
			G = new int[Height][Wide];
			B = new int[Height][Wide];
			if(!(Wide*3%4==0)){
				skipWide= 4-Wide*3%4;
			}//记得哦,一次扫描四个字节,不够四个字节用0补齐,那么我们就要跳过读了
			for(int h=Height-1;h>=0;h--){
				for(int w=0;w<Wide;w++){
					int blue=dis.read();
					int green=dis.read();
					int red=dis.read();
					R[h][w]=red;
					G[h][w]=green;
					B[h][w]=blue;
					
					if(w==Wide-1){
						dis.skipBytes(skipWide);
					}
				}
			}		
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

 这样就可以显示图片了

	/**
	 * 将图片显示
	 */
	public void displayIma(){
		Graphics g = jf.getGraphics();
		for(int h=0;h<Height;h++){
			for(int w=0;w<Wide;w++){
			g.setColor(new Color(R[h][w],G[h][w],B[h][w]));
			g.drawLine(w+(BmpViewer.wide-Wide)/2, h+(BmpViewer.hight-Height)/2, w+(BmpViewer.wide-Wide)/2, h+(BmpViewer.hight-Height)/2);
			}
		}
	}

 



  终于可以读懂bmp了!如果要用bmp的格式去表达一张图片呢?就是把图片保存下来。答案很简单:依照协议去表达。非图像数据区的写入具体代码就不show了。不过可以增加一个好玩的小功能,给图片上的美女化化妆再保存下来。下边是写入像素点颜色数据和在图片上画画并保存下来的方法的代码:

/**
	 * 将图片和所画的图放入缓存图片中
	 */
	public void changetoBuffer(){
		bfi = new BufferedImage(BmpViewer.wide,BmpViewer.hight,BufferedImage.TYPE_3BYTE_BGR);
		Graphics g2 = bfi.getGraphics();
		g2.setColor(jf.getBackground());
		g2.fillRect(0, 0, BmpViewer.wide, BmpViewer.hight);
		for(int h=0;h<Height;h++){
			for(int w=0;w<Wide;w++){
			g2.setColor(new Color(R[h][w],G[h][w],B[h][w]));
			g2.drawLine(w+(BmpViewer.wide-Wide)/2, h+(BmpViewer.hight-Height)/2, w+(BmpViewer.wide-Wide)/2, h+(BmpViewer.hight-Height)/2);
			}
		}
		for(int i=0;i<DrawListener.list.size();i++){
			int x = DrawListener.list.get(i).x;
			int y = DrawListener.list.get(i).y;
			g2.setColor(Color.red);
			g2.fillOval(x, y, 8, 8);
		}
	}
	
	/**
	 * 获得每个点RGB值
	 */
	public void getImageRgb(){
		for(int h=jf.getHeight()-1;h>=0;h--){
			for(int w=0;w<jf.getWidth();w++){
				int rgb = bfi.getRGB(w, h);
				this.changRgb(rgb,h,w);//因为BufferedImage的getRGB方法只能获得改点的TYPE_INT_ARGB型值,所以要转换成我们想要的TYPE_3BYTE_BGR
			}
		}
	}
	
	/**
	 * 将相应像素点的颜色值变为我们所需的TYPE_3BYTE_BGR值,并存储的坐标颜色数组中
	 * @param rgb TYPE_INT_ARGB型值
	 * @param h	纵坐标值
	 * @param w	横坐标值
	 */
	public void changRgb(int rgb,int h,int w){
		R1[h][w] =(int) ((rgb & 0xff0000 ) >> 16) ;
		G1[h][w]= (int) ((rgb & 0xff00   ) >> 8) ;
		B1[h][w]= (int) ( rgb & 0xff     );
		System.out.println(">>>>>>>>>>>>>>>>>>");
	}

 给美女涂上口红,保存下来,可以在Windows自带的图片查看器里显示了!



 现在是不是漂亮多了!!!呵呵

       程序做的很粗糙,望多多指教!不过这样我们就已经实现了bmp协议下的基于计算机的“理解——表达”,那么只要有物理介质,并且有在介质中传递的协议,是不是我们就能够通信了呢?未完待续~~

  • 大小: 289.1 KB
  • 大小: 156.6 KB
6
4
分享到:
评论
1 楼 lsjinpeng 2013-07-18  
         
理解和被理解是伟大的

相关推荐

Global site tag (gtag.js) - Google Analytics