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格式,出现java.lang.outOfmemorryError错误,还有当我画图时,用的是g.fillOval(w,h,w,h)方法时,出现的图形刚开始怪模怪样,到最后才呈现出源图的效果。还有就是那个不是4的倍数时,为什么是if(!(image_width*3%4==0))而不是if(!image_width%4==0),