java读取bitmap文件

来源:互联网 发布:2017seo新手教程 编辑:程序博客网 时间:2024/04/28 23:05

读取24位bitmap(bmp)格式图片文件

//读取bmp图片文件
package pcm24;    import java.awt.Color;  import java.awt.Graphics;  import java.io.IOException;    public class BmpRead24 extends javax.swing.JFrame {      /**      *       */      private static final long serialVersionUID = 1L;        /**      * 位图的宽      */      private static int width;        /**      * 位图的高      */      private static int height;        /**      * 位图数据数组,即一个像素的三个分量的数据数组      */      private static int[][] red, green, blue;        Graphics g;        public static void main(String args[]) {          BmpRead24 bmp = new BmpRead24();          bmp.init();      }        public void init() {          try {              // 通过bmp文件地址创建文件输入流对象              java.io.FileInputStream fin = new java.io.FileInputStream(                      "C:\\Documents and Settings\\专属于我\\桌面\\未命名1.bmp");                // 根据文件输入流对象创建原始数据输入对象              // 这里既可以用原始数据输入流来读取数据,也可以用缓冲输入流来读取,后者速度相比较快点。  //          java.io.DataInputStream bis = new java.io.DataInputStream(fin);                java.io.BufferedInputStream bis = new java.io.BufferedInputStream(                      fin);                // 建立两个字节数组来得到文件头和信息头的数据              byte[] array1 = new byte[14];              bis.read(array1, 0, 14);                byte[] array2 = new byte[40];              bis.read(array2, 0, 40);                // 翻译bmp文件的数据,即将字节数据转化为int数据              // 通过翻译得到位图数据的宽和高              width = ChangeInt(array2, 7);              height = ChangeInt(array2, 11);                // 调用可以将整个位图数据读取成byte数组的方法              getInf(bis);                fin.close();              bis.close();                // 创建BMP对象来显示图画              showUI();          } catch (Exception e) {              e.printStackTrace();          }      }        /**      * 实现可将四个字节翻译int数据的方法      *       * @param array2      *            存储字节的字节数组      * @param start      *            起始字节      * @return 返回翻译后的int数据      */      public int ChangeInt(byte[] array2, int start) {          // 因为char,byte,short这些数据类型经过运算符后会自动转为成int数据类,          // 所以array2[start]&0xff的实际意思就是通过&0xff将字符数据转化为正int数据,然后在进行位运算。          // 这里需要注意的是<<的优先级别比&高,所以必须加上括号。            int i = (int) ((array2[start] & 0xff) << 24)                  | ((array2[start - 1] & 0xff) << 16)                  | ((array2[start - 2] & 0xff) << 8)                  | (array2[start - 3] & 0xff);          return i;      }        /**      * 得到位图数据的int数组      *       * @param dis      *            数据输入流对象      */      public void getInf(java.io.BufferedInputStream bis) {          // 给数组开辟空间          red = new int[height][width];          green = new int[height][width];          blue = new int[height][width];            // 通过计算得到每行计算机需要填充的字符数。          // 为什么要填充?这是因为windows系统在扫描数据的时候,每行都是按照4个字节的倍数来读取的。          // 因为图片是由每个像素点组成。而每个像素点都是由3个颜色分量来构成的,而每个分量占据1个字节。          // 因此在内存存储中实际图片数据每行的长度是width*3。          int skip_width = 0;          int m = width * 3 % 4;          if (m != 0) {              skip_width = 4 - m;          }            // 通过遍历给数组填值          // 这里需要注意,因为根据bmp的保存格式。          // 位图数据中height的值如果是正数的话:          // 那么数据就是按从下到上,从左到右的顺序来保存。这个称之为倒向位图。          // 反之就是按从上到下,从左到右的顺序来保存。这个则称之为正向位图。          for (int i = height - 1; i >= 0; i--) {              for (int j = 0; j < width; j++) {                  try {                      // 这里遍历的时候,一定要注意本来像素是有RGB来表示,                      // 但是在存储的时候由于windows是小段存储,所以在内存中是BGR顺序。                      blue[i][j] = bis.read();                      green[i][j] = bis.read();                      red[i][j] = bis.read();                        // 这里一定要知道,其实系统在给位图数据中添加填充0的时候,都是加在每行的最后。                      // 但是我们在使用dis.skipBytes()这个方法的时候,却不一定要在最后一列。                      // 系统在填充数据的时候,在数据上加了标记。                      // 所以dis.skipBytes()这个方法只要调用了,那么系统就会自动不读取填充数据。                      if (j == 0) {                          bis.skip(skip_width);                      }                  } catch (IOException e) {                      e.printStackTrace();                  }              }          }      }        public void showUI() {          // 对窗体的属性进行设置          this.setTitle("BMP解析");//设置标题          this.setSize(width, height);//设置窗体大小          this.setDefaultCloseOperation(3);//点击关闭,程序自动退出。          this.setResizable(false);//设置窗体大小不可以调节          this.setLocationRelativeTo(null);//设置窗体出现在屏幕中间            //创建自己的panel,用其来显示图形。          //因为如果将图片设置到窗体上显示时,因为jframe是一个复合组件,上面的组件有多个paint方法,所以在paint的时候会画两次,          //而panel是只需画一次。          MyPanel panel = new MyPanel();          java.awt.Dimension di = new java.awt.Dimension(width, height);//设置panel大小          panel.setPreferredSize(di);          this.add(panel);//窗体添加panel          this.setVisible(true);//使窗体可见。      }        public class MyPanel extends javax.swing.JPanel {          /**          *           */          private static final long serialVersionUID = 1L;            /**          * 重写paint方法          */          public void paint(Graphics g) {              // 这句话可写可不写,因为这句话是用来画jframe的contentPane的。               // 而这里我们已经在下面定义了contentPane的方法了              super.paint(g);              for (int i = 0; i < height; i++) {                  for (int j = 0; j < width; j++) {                      g.setColor(new Color(red[i][j], green[i][j], blue[i][j]));                      // 如果这里画点的话,是不能使用下面注释掉的方法的,不行的话,亲,自己试试吧                      // 因为系统在画椭圆的时候,是先画出椭圆的外切矩形。而矩形的边框刚好是占据一个像素点。                      // 因此也就出现了,jdk api中说g.drawOval的像素点是width+1,height+1。                      // 如果亲,你有更好的理解,请告诉我们。欢迎交流!!!                      // g.fillOval(j, i, 1, 1);                      g.fillRect(j, i, 1, 1);// 这里可以使用画点的任何方法,除了上面那种特例。                  }              }          }      }  }  

编写bmp
package pcm24;    import java.awt.Color;    /**  *   * 类说明:实现BMP文件格式的保存  *   * @author 彭晨明 E-mail:2294552925@qq.com  *   * @version 创建时间:2012-2-5下午9:06:28  *   */  public class BmpWrite24 {      /**      * 图形数据数组      */      private Color[][] pointArray;        /**      * 图形的宽      */      int width;        /**      * 图形的高      */      int height;        /**      * BMPWrite构造器的重载,传入图形数据数组      *       * @param pointArray      */      public BmpWrite24(Color[][] pointArray) {          this.pointArray = pointArray;          this.width = pointArray.length;          this.height = pointArray[0].length;          this.write();      }        /**      * 将数据传入内存      */      public void write() {          try {              // 创建输出流文件对象              java.io.FileOutputStream fos = new java.io.FileOutputStream(                      "C:\\Documents and Settings\\专属于我\\桌面\\未命名1.bmp");              // 创建原始数据输出流对象              java.io.DataOutputStream dos = new java.io.DataOutputStream(fos);                // 给文件头的变量赋值              int bfType = 0x424d; // 位图文件类型(0—1字节)              int bfSize = 54 + width * height * 3;// bmp文件的大小(2—5字节)              int bfReserved1 = 0;// 位图文件保留字,必须为0(6-7字节)              int bfReserved2 = 0;// 位图文件保留字,必须为0(8-9字节)              int bfOffBits = 54;// 文件头开始到位图实际数据之间的字节的偏移量(10-13字节)                // 输入数据的时候要注意输入的数据在内存中要占几个字节,              // 然后再选择相应的写入方法,而不是它自己本身的数据类型              // 输入文件头数据              dos.writeShort(bfType); // 输入位图文件类型'BM'              dos.write(changeByte(bfSize),0,4); // 输入位图文件大小              dos.write(changeByte(bfReserved1),0,2);// 输入位图文件保留字              dos.write(changeByte(bfReserved2),0,2);// 输入位图文件保留字              dos.write(changeByte(bfOffBits),0,4);// 输入位图文件偏移量                // 给信息头的变量赋值              int biSize = 40;// 信息头所需的字节数(14-17字节)              int biWidth = width;// 位图的宽(18-21字节)              int biHeight = height;// 位图的高(22-25字节)              int biPlanes = 1; // 目标设备的级别,必须是1(26-27字节)              int biBitcount = 24;// 每个像素所需的位数(28-29字节),必须是1位(双色)、4位(16色)、8位(256色)或者24位(真彩色)之一。              int biCompression = 0;// 位图压缩类型,必须是0(不压缩)(30-33字节)、1(BI_RLEB压缩类型)或2(BI_RLE4压缩类型)之一。              int biSizeImage = width * height;// 实际位图图像的大小,即整个实际绘制的图像大小(34-37字节)              int biXPelsPerMeter = 0;// 位图水平分辨率,每米像素数(38-41字节)这个数是系统默认值              int biYPelsPerMeter = 0;// 位图垂直分辨率,每米像素数(42-45字节)这个数是系统默认值              int biClrUsed = 0;// 位图实际使用的颜色表中的颜色数(46-49字节),如果为0的话,说明全部使用了              int biClrImportant = 0;// 位图显示过程中重要的颜色数(50-53字节),如果为0的话,说明全部重要                            // 因为java是大端存储,那么也就是说同样会大端输出。              // 但计算机是按小端读取,如果我们不改变多字节数据的顺序的话,那么机器就不能正常读取。              // 所以首先调用方法将int数据转变为多个byte数据,并且按小端存储的顺序。                            // 输入信息头数据              dos.write(changeByte(biSize),0,4);// 输入信息头数据的总字节数              dos.write(changeByte(biWidth),0,4);// 输入位图的宽              dos.write(changeByte(biHeight),0,4);// 输入位图的高              dos.write(changeByte(biPlanes),0,2);// 输入位图的目标设备级别              dos.write(changeByte(biBitcount),0,2);// 输入每个像素占据的字节数              dos.write(changeByte(biCompression),0,4);// 输入位图的压缩类型              dos.write(changeByte(biSizeImage),0,4);// 输入位图的实际大小              dos.write(changeByte(biXPelsPerMeter),0,4);// 输入位图的水平分辨率              dos.write(changeByte(biYPelsPerMeter),0,4);// 输入位图的垂直分辨率              dos.write(changeByte(biClrUsed),0,4);// 输入位图使用的总颜色数              dos.write(changeByte(biClrImportant),0,4);// 输入位图使用过程中重要的颜色数                // 因为是24位图,所以没有颜色表              // 通过遍历输入位图数据              // 这里遍历的时候注意,在计算机内存中位图数据是从左到右,从下到上来保存的,              // 也就是说实际图像的第一行的点在内存是最后一行              for (int i = height - 1; i >= 0; i--) {                  for (int j = 0; j < width; j++) {                      // 这里还需要注意的是,每个像素是有三个RGB颜色分量组成的,                      // 而数据在windows操作系统下是小端存储,对多字节数据有用。                      int red = pointArray[i][j].getRed();// 得到位图点的红色分量                      int green = pointArray[i][j].getGreen();// 得到位图点的绿色分量                      int blue = pointArray[i][j].getBlue();// 得到位图点的蓝色分量                      byte[] red1 = changeByte(red);                      byte[] green1 = changeByte(green);                      byte[] blue1 = changeByte(blue);                      dos.write(blue1,0,1);                      dos.write(green1,0,1);                      dos.write(red1,0,1);                  }              }              //关闭数据的传输              dos.flush();              dos.close();              fos.close();              System.out.println("success!!!");          } catch (Exception e) {              e.printStackTrace();          }      }            /**      * 将一个int数据转为按小端顺序排列的字节数组      * @param data int数据      * @return  按小端顺序排列的字节数组      */      public byte[] changeByte(int data){          byte b4 = (byte)((data)>>24);          byte b3 = (byte)(((data)<<8)>>24);          byte b2= (byte)(((data)<<16)>>24);          byte b1 = (byte)(((data)<<24)>>24);          byte[] bytes = {b1,b2,b3,b4};          return bytes;      }  }  


原创粉丝点击