BMP是一种与硬件无关的图像文件格式,使用非常广泛。
它采用位映射存储格式,除了图像深度可选外,不采用其他任何压缩。因此,BMP文件所占的空间很大。
BMP文件的图像深度可选1 bit、4bit、8bit及 24bit。
BMP的文件存储时,图像的扫描方式是按从左到右、从上到下的顺序。
BMP图像文件由4部分组成:
1、位图文件 头数据结构 它包含BMP图像文件的类型、显示内容等信息;
2、位图信息数据结构 它包含BMP图像的宽、高、压缩方法,以及定义颜色等信息;
3、调色板 这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;
4、位图数据 这部分的内容根据BMP位图使用是位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。
int image_width;// 位图的宽度,以像素为单位(19-22字节) int image_height;// 位图的高度,以像素为单位(23-26字节) int biBitCount;// 每个像素所需的位数,必须是1(双色)、4(16色)、8(256色)、24(真彩色)之一,(29-30字节) int sizeImage;// 位图的大小,以字节为单位(35-38字节) // 跳过补0项 int skip_width; // 用于存储RGB颜色数据的数组 int[][] imageR, imageB, imageG;
读取BMP图像文件数据:
try{ //创建文件输入流 FileInputStream fis=new FileInputStream(path); //把文件输入流包装成输入缓冲流 BufferedInputStream bu=new BufferedInputStream(fis); //读入BMP头文件的基本信息 int bflen=14;//头文件的长度 byte[] bf=new byte[bflen];//定义一个存入头文件事件数据的数组 //读取14字节的BMP文件头 bu.read(bf,0,bflen); int bilen=40; //读入位图信息头 byte[] bi=new byte[bilen]; //读取40字节的BMP位图信息头 bu.read(bi,0,bilen); //获取:位图文件的宽度、高度、每个像素点所需的位数(即图像的深度)、源图的大小(测试时值为0) image_width = changeInt(bi,7);//源文件宽度 image_height=changeInt(bi,11);//源文件的高度 //每个像素点所需的位数,必须是1(双色)、4(16色)、8(256色)、24(真彩色)之一,(29-30字节) biBitCount=(((int)bi[15]&0xff)<<8)|((int)bi[14]&0xff); sizeImage=changeInt(bi,23);//位图的大小,以字节为单位(35-38字节),测试结果为sizeImage=0; //调用读取位图数据的方法,将数据存入imageR.imageG,imageB三个二维数组中 readRGB(bu); bu.close();//关闭缓冲流 fis.close();//关闭输入流 showi(path); } catch(Exception e){ e.printStackTrace(); }
读取BMP图像文件时,要读取位图数据:
public void readRGB(BufferedInputStream bis){ if(!(image_width*3%4==0)){//图片的宽度不为0 skip_width=4-image_width*3%4; }//判断是否后面有补0 的情况 //装载RGB颜色的数据数组 imageR=new int[image_height][image_width]; imageG=new int[image_height][image_width]; imageB=new int[image_height][image_width]; //按行读取,如果H,W为正,则倒着来 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; }catch(IOException ef){ ef.printStackTrace(); } if(w==0){ //跳过补0项 try{ bis.skip(skip_width); }catch(IOException e){ e.printStackTrace(); } } } } }
存在数组中是是字节,要将它转化成int类型。因为的出来的顺序是倒序,所以第i个位置要左移24位才能到高8位,要得到int值,只需将他们每8个字节先进行逻辑与,再左移,在进行逻辑或运算,即可。
public int changeInt(byte[] bu,int i){ return ((((int) bu[i] & 0xff) << 24) | (((int) bu[i - 1] & 0xff) << 16) | (((int) bu[i - 2] & 0xff) << 8) | (((int) bu[i - 3] & 0xff))); }显示界面,将读取的数据显示出来。
public void showi(String path){ this.setTitle(path); this.setSize(image_width, image_height); this.setDefaultCloseOperation(3); this.setVisible(true); Graphics g=this.getGraphics();//得到画布 repaint();//调用重绘方法 this.validate(); }
显示界面时要调用paint()方法,才能够显示BMP图像
public void paint(Graphics g){ super.paint(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);//画点 } } }
结果如下图所示:
注意: 保存类型应为24位位图