首页 > 其他 > 详细

BMP图片——打开和保存

时间:2014-12-18 02:06:26      阅读:429      评论:0      收藏:0      [点我收藏+]

BMP的背后操作—以打开和保存为例

在使用windows的过程中,我们经常能见到bmp格式的图片,但是不知道系统是如何使用BMP图片的。
BMP图片的详细信息包括三个部分:
??????? 信息头(14个字节)
??????? 位图信息(40个字节)
??????? 调色板(当位图=1,4,8 时,分别有 2,16,256 个表项;当为24位图时,没有颜色表项)
??????? 位图数据(记录顺序是在扫描行内是从左到右, 扫描行之间是从下到上)(详细的BMP文档 见附件)
如何打开一张为BMP格式的图片呢?(24位图为例)

在这里我们会发现位运算的重要性,会发现int类型和字节之间的转换非常频繁,int 不仅可以表示数字,还可以表示颜色,还能拆分成字节

我们需要知道:一个int类型是32位,可以拆分成四个字节表示

???????????????????????? 24位图,一个像素占三个字节

???????????????????????? 在windows系统中的输出顺序是倒序,与java中输出顺序相反
?????????????????????????windows中int的保存方式是:低位在前 ,高位在后
??????????????????????? Java 中int的保存方式是:高位在前 低位在后
那我们就简单的来读取一下bmp图片

打开一张bmp图片

先写几个需要用到的方法

//读出int类型数据的方法
 public int myReadInt(InputStream ips) throws Exception {
//先读到的是低位
  int a = ips.read() & 0xff;
  int b = ips.read() & 0xff;
  int c = ips.read() & 0xff;
  int d = ips.read() & 0xff;
//拼接成一个int
  int t = (d << 24) + (c << 16) + (b << 8) + a;
 return t;
 }
//读取颜色的方法
 public int myReadColor(InputStream ips) throws Exception {
//倒序接收
  int b = ips.read() & 0xff;
  int g = ips.read() & 0xff;
  int r = ips.read() & 0xff;
//组成一个颜色,
  int t = (r << 16) + (g << 8) + b;
  return t;
 }

?
为了简洁操作,只读出重要的数据

?

//得到一个输入流
FileInputStream fis = new FileInputStream(path2);
  // 跳过18个字节,直接读取位图的宽和高
  fis.skip
//调用读int类型数据的方法,返回一个int类型的数
  int width = myReadInt(fis);
  int height = myReadInt(fis);
  // 跳到位图数据
  fis.skip(28);
  //计算行末尾需要补0的个数
  int num = width * 3 % 4;
  if (num > 0) {
   num = 4 - num;
  } 
  // 定义一个数组,来存放颜色数据,这里是用已经定义好了的数组
  DrawListener.arr = new int[height][width];
  // 循环取出数据,存放到数组
  for (int i = height - 1; i >= 0; i--) {
   for (int j = 0; j < width; j++) {
//调用将字节变成int类型的颜色的方法
    DrawListener.arr[i][j] = myReadColor(fis);
   }
   // 一行完了,跳过补得num个0;
   fis.skip(num);
  }
  // 重新设置屏幕大小
  panel.setPreferredSize(new Dimension(width, height));
  // 刷新面板
  SwingUtilities.updateComponentTreeUI(panel);

?

保存BMP图片(详细看附件)

???? 我们需要一个文件输出流用来将图片信息输出(字节的形式输出)
???? 按 照bmp输出的要求,将规定的数据输出,有几个点需要注意
????在输出信息头时时,注意我们需要输出图片的大小,在这里是将图片上的所有点的颜色当作一个二维数组,方便操作

 int height = DrawListener.arr.length;
 int width = DrawListener.arr[0].length;

?
由于,Windows规定一个扫描行所占的字节数必须是4 的倍数 ( 即以 long 为单位 ), 不足的以 0 填充,
在计算文件大小时,需要计算补0的个数(4 - width * 3 % 4)
24位位图文件大小=文件头+信息头+位图数据+补0=14+40+宽*3*高+(4-+宽*3%4)*高

int size = 14 + 40 + (width * 3 * height) + (4 - width * 3 % 4)* height;

在输出位图信息时,需要注意

//int类型的输出方法
public void myWriteInt(OutputStream ops, int t) throws Exception {
	// 将int类型转为四个字节
	int a = (t >> 24) & 0xff;
	int b = (t >> 16) & 0xff;
	int c = (t >> 8) & 0xff;
	int d = t & 0xff;
	// windows系统中是倒序传输的
	ops.write(d);ops.write(c);
	ops.write(b);ops.write(a);
}
//输出颜色的方法
public void myWriteColor(OutputStream ops, int t) throws Exception {
		int r = (t >> 16) & 0xFF;
		int g = (t >> 8) & 0xFF;
		int b = t & 0xFF;

		ops.write(b);
		ops.write(g);
		ops.write(r);
}

?

在输出位图数据文件时,需要注意行是否需要补0

//用两个for循环,遍历数组,得到每个点的颜色,  从下到上,从左到右
	for(int i=height-1;i>=0;i--){
		for(int j=0;j<width;j++){
		//调用将颜色输出的方法
		myWriteColor(ops, DrawListener.arr[i][j]);
	}
	//一行完了,在后面补0
	for(int k=0;k<num;k++){
		//补的是字节0
		ops.write(0);
	}
}

?

BMP图片——打开和保存

原文:http://2240550808.iteye.com/blog/2167185

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!