众所周知,我们所有的数据在电脑上都是以“010101”的二进制形式存储的。BMP文件格式是windows中广泛使用的图片文件格式。
如果想要读取BMP格式的图片,首先就要了解bmp文件的数据存储方式。bmp文件按数据排列先后顺序由bmp文件头、位图信息头、调色板、位图数据四部分组成。其中:
bmp文件头:提供文件格式、大小等数据,占用14字节
位图信息头:提供图像尺寸、压缩方式等数据,占用40字节。如图:
调色板:索引与其对应颜色的映射表
位图数据:图像的数据,由图像尺寸决定。
下面我们通过一个具体的24位真彩bmp文件的数据来了解一下它的数据存储方式。
这是我用UltraEdit软件打开的bmp文件。上图是其数据开始部分的截图,数据是16进制(每两个数字代表一个字节)我用黑线将所有的数据分成了三部分,第一部分即前十四位是bmp文件头,其中:
(1-2字节)42 4D是说明文件的类型;
(3-6字节)A6 11 00 00是该位图文件的大小;
(7-10字节)00 00 00 00保留部分,必须设为0;
(11-14字节)36 00 00 00文件开始到位图数据的偏移量;
,第二部分是位图信息头,其中:
(1-4字节)28 00 00 00 位图信息头的长度;
(5-8字节)粉色部分:2F 00 00 00 图像的宽度;
(9-12字节)画蓝色部分:1F 00 00 00 图像的高度;
(13-14)01 00:颜色平面数,其值总被设为1;
(15-16)18 00:说明像素
(17-20)00 00 00 00:图像压缩的类型,因为bmp是无压缩的文件所以本数据为0;
(21-24)70 11 00 00:图像大小;
(25-28)00 00 00 00 ;像素水平分辨率;
(29-32)00 00 00 00 ;像素垂直分辨率;
(33-36)00 00 00 00 :位图使用的颜色数,为0表示使用所有颜色板;
(37-40)00 00 00 00:指定重要的颜色数,为0表示都重要
因为是24位真彩图所以并不存在调色板;
第三部分是位图数据,每个像素占一个字节,取得相应的字节,以此字节索引颜色,在显示器中显示出来就好了!
了解了bmp的数据存储方式之后,我们可以发现其实bmp文件的读取非常简单,只要能够获得图像的尺寸,然后进行遍历就可以得到颜色数据,再通过打点的形式就可以读取一张bmp图片啦!此外,应注意的是
1.bmp文件有一个对齐规则,即每行的数据都是4的倍数如果不够就用bit(0)填充。
2.bmp文件是从左下角向右上角读取的。
public class IOpic {
private JFrame jf;
private Graphics g;
private int wight,height;//画板的宽与高
Border b2;
File filename;//文件名
public IOpic(Graphics g) {
this.g=g;
}
/**
* 将byte数组转换成int数组
* b: 要转换的字节数组,start 字符截止的位置:
*/
public int changeint(byte[] b,int start){
int ch1= b[start]&0xff;
int ch2= b[start+1]&0xff;
int ch3= b[start+2]&0xff;
int ch4= b[start+3]&0xff;
int ch=ch1|ch2|ch3|ch4;
return (ch);
}
/**
* 读取BMP图片的方法
* 输入流
* @throws Exception
*/
public void readpic(File filename) throws Exception{
System.out.println(filename);
FileInputStream fis =new FileInputStream(filename);
DataInputStream dis=new DataInputStream(fis);
//创建字节数组,并将字节存储在此数组中
byte[] array1=new byte[14];
byte[] array=new byte[40];
dis.read(array1, 0, 14);
dis.read(array, 0, 40);
wight=changeint(array, 4);
height=changeint(array, 8);
System.out.println("图形的宽度是:"+wight+",图形的高度是:"+height);
//画出图片
//装颜色数据的数组
if (wight*3/4!=0) {
int wid = 4 - (wight * 3) % 4;
int[][] R=new int[height][wight];
int[][] B=new int[height][wight];
int[][] G=new int[height][wight];
for (int i = height-1; i >=0; i--) {
for (int j = 0; j < wight; j++) {
int blue=dis.read();
int green=dis.read();
int red=dis.read();
R[i][j]=red;
B[i][j]=blue;
G[i][j]=green;
}
dis.skipBytes(wid);
}
//循环加入数据,用点打出来
for(int i=0;i<height;i++){
for (int j = 0; j < wight; j++) {
System.out.println(R[i][j]+" "+B[i][j]+" "+G[i][j]);
g.setColor(new Color(R[i][j],G[i][j],B[i][j]));
g.drawLine(i+100,j+100,i+100,j+100);
}
}
}
总结:
1、通过对bmp图片文件的读取,我对io更加的了解,也更加明白了作为流的特性,io利用java实现对文件的输入与输出。如果要读取一段数据流中间的数据必须要读出该数据前面的数据。
2、所谓文件的协议就是文件之间之间的对接及了解,已达到互相转换的目的。