随笔-57  评论-202  文章-17  trackbacks-0
      要将BufferedImage实例保存为BMP文件,就需要知道BMP文件的格式,可以参考我转载的文章:《BMP文件格式》
      下面是我的将BufferedImage实例保存为24位色BMP文件的实现。
      首先是BMP文件相关的两个头结构:BMPFileHeader和BMPInfoHeader。

/*
 * Created on 2005-6-21
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 
*/

package org.lotus.image.codec.bmp;

/**
 * <p> Title: BMP文件的头结构</p>
 * 
 * <p> Description: BMP文件的头结构固定是14个字节,其定义如下:</p>
 * <p>
 * byte[2] bfType;                    指定文件类型,必须是0x424D,即字符串“BM”,也就是说所有.bmp文件的头两个字节都是“BM“
 * byte[4] bfSize;                    指定文件大小,包括这14个字节
 * byte[2] bfReserved1;            保留字
 * byte[2] bfReserved2;            保留字
 * byte[4] bfOffBits;                为从文件头到实际的位图数据的偏移字节数
 * </p>
 * 
 * <p> Copyright: Copyright (c) 2005</p>
 * 
 * <p> Company: 21Lotus</p>
 * 
 * @author George Hill
 * @version 1.0
 
*/


class BMPFileHeader {

    
// Header data
    private byte[] data = new byte[14];

    
public byte[] getData() {
        
return this.data;
    }

    
    
// BMP file size
    private int size;
    
    
public int getSize() {
        
return this.size;
    }

    
    
private int offset;
    
    
public int getOffset() {
        
return this.offset;
    }

    
    BMPFileHeader(
int size, int offset) {
        
this.size = size;
        
this.offset = offset;
        
        data[
0= 'B';
        data[
1= 'M';

        
int value = size;
        data[
2= (byte) value;
        value 
= value >>> 8;
        data[
3= (byte) value;
        value 
= value >>> 8;
        data[
4= (byte) value;
        value 
= value >>> 8;
        data[
5= (byte) value;

        value 
= offset;
        data[
10= (byte) value;
        value 
= value >>> 8;
        data[
11= (byte) value;
        value 
= value >>> 8;
        data[
12= (byte) value;
        value 
= value >>> 8;
        data[
13= (byte) value;
    }

    
}


/*
 * Created on 2005-6-21
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 
*/

package org.lotus.image.codec.bmp;

/**
 * <p>Title: BMP文件内容的头结构</p>
 *
 * <p>Description: BMP文件内容的头结构固定是40个字节,其定义如下:</p>
 * <p>
 * byte[4] biSize;                            指定这个结构的长度,为40
 * byte[4] biWidth;                            指定图象的宽度,单位是象素
 * byte[4] biHeight;                        指定图象的高度,单位是象素
 * byte[2] biPlanes;                        必须是1,不用考虑
 * byte[2] biBitCount;                    指定表示颜色时要用到的位数,常用的值为1(黑白二色图), 4(16色图), 8(256色), 24(真彩色图)
 * byte[4] biCompression;                指定位图是否压缩
 * byte[4] biSizeImage;                    指定实际的位图数据占用的字节数
 * byte[4] biXPelsPerMeter;            指定目标设备的水平分辨率,单位是每米的象素个数
 * byte[4] biYPelsPerMeter;            指定目标设备的垂直分辨率,单位是每米的象素个数
 * byte[4] biClrUsed;                        指定本图象实际用到的颜色数,如果该值为零,则用到的颜色数为2biBitCount
 * byte[4] biClrImportant;            指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的
 * </p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: 21Lotus</p>
 *
 * @author George Hill
 * @version 1.0
 
*/


class BMPInfoHeader {

    
private byte[] data = new byte[40];
    
    
public byte[] getData() {
        
return this.data;
    }

    
    
private int width;
    
    
public int getWidth() {
        
return this.width;
    }

    
    
private int height;
    
    
public int getHeight() {
        
return this.height;
    }

    
    
public int bitCount;
    
    
public int getBitCount() {
        
return this.bitCount;
    }

    
    
public BMPInfoHeader(int width, int height, int bitCount) {
        
this.width = width;
        
this.height = height;
        
this.bitCount = bitCount;
        
        data[
0= 40;

        
int value = width;
        data[
4= (byte) value;
        value 
= value >>> 8;
        data[
5= (byte) value;
        value 
= value >>> 8;
        data[
6= (byte) value;
        value 
= value >>> 8;
        data[
7= (byte) value;

        value 
= height;
        data[
8= (byte) value;
        value 
= value >>> 8;
        data[
9= (byte) value;
        value 
= value >>> 8;
        data[
10= (byte) value;
        value 
= value >>> 8;
        data[
11= (byte) value;

        data[
12= 1;

        data[
14= (byte) bitCount;

        value 
= width * height * 3;
        
if (width % 4 != 0)
          value 
+= (width % 4* height;
        data[
20= (byte) value;
        value 
= value >>> 8;
        data[
21= (byte) value;
        value 
= value >>> 8;
        data[
22= (byte) value;
        value 
= value >>> 8;
        data[
23= (byte) value;
    }

    
}


      仿照com.sun.image.codec.jpeg.JPEGImageEncoder写的接口类BMPEncoder。

/*
 * Created on 2005-6-21
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 
*/

package org.lotus.image.codec.bmp;

import java.awt.image.
*;
import java.io.IOException;

/**
 * <p>Title: </p>
 *
 * <p>Description: </p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: 21Lotus</p>
 *
 * @author George Hill
 * @version 1.0
 
*/


public interface BMPEncoder {

      
public void encode(BufferedImage bi) throws IOException;
      
      
public static final int BIT_COUNT_BLACKWHITE = 1;
      
public static final int BIT_COUNT_16COLORS = 4;
      
public static final int BIT_COUNT_256COLORS = 8;
      
public static final int BIT_COUNT_TRUECOLORS = 24;
      
}


      BMPEncoder接口的实现BMPEncoderImpl。

/*
 * Created on 2005-6-21
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 
*/

package org.lotus.image.codec.bmp;

import java.awt.image.
*;
import java.io.
*;

/**
 * <p>Title: </p>
 *
 * <p>Description: </p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: 21Lotus</p>
 *
 * @author George Hill
 * @version 1.0
 
*/


class BMPEncoderImpl implements BMPEncoder {
    
    
private OutputStream out;
    
    
public BMPEncoderImpl(OutputStream out{
        
this.out = out;
    }

    
      
public void encode(BufferedImage bi) throws IOException {
          
int width = bi.getWidth();
          
int height = bi.getHeight();
          
          boolean needBlank 
= (width % 4 != 0);
          
          
int size = width * height * 3;
          
if (needBlank) {
              size 
+= (width % 4* height;
          }

          
          BMPFileHeader fileHeader 
= new BMPFileHeader(size, 54);
          BMPInfoHeader infoHeader 
= new BMPInfoHeader(width, height, BIT_COUNT_TRUECOLORS);

          
byte[] rgbs = new byte[3];
          
byte[] blank = new byte[width % 4];
          
          
out.write(fileHeader.getData());
          
out.write(infoHeader.getData());

          
int index = 0;
          
for (int y = height - 1; y >= 0; y--{
              
for (int x = 0; x < width; x++{
                  index 
+= 3;

                  
int rgb = bi.getRGB(x, y);
                  rgbs[
0= (byte) rgb;
                  rgb 
= rgb >>> 8;
                  rgbs[
1= (byte) rgb;
                  rgb 
= rgb >>> 8;
                  rgbs[
2= (byte) rgb;

                  
out.write(rgbs);

                  
if (needBlank && (index % (width * 3== 0)) {
                      
out.write(blank);
                  }

              }

          }

      }


}


      一个工厂类BMPCodec。

/*
 * Created on 2005-6-21
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 
*/

package org.lotus.image.codec.bmp;

import java.io.OutputStream;

/**
 * <p>Title: </p>
 *
 * <p>Description: </p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: 21Lotus</p>
 *
 * @author George Hill
 * @version 1.0
 
*/


public class BMPCodec {

    
public static BMPEncoder createBMPEncoder(OutputStream dest) {
        
return new BMPEncoderImpl(dest);
    }

    
}


      下面是我的测试用例:

/*
 * Created on 2005-6-22
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 
*/

package org.lotus.test;

import java.awt.
*;
import java.awt.image.
*;
import java.io.
*;

import junit.framework.TestCase;

import org.lotus.image.codec.bmp.
*;

/**
 * <p>Title: </p>
 *
 * <p>Description: </p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: 21Lotus</p>
 *
 * @author George Hill
 * @version 1.0
 
*/

public class BMPCodecTest extends TestCase {

    
/*
     * @see TestCase#setUp()
     
*/

    
protected void setUp() throws Exception {
        super.setUp();
    }


    
/*
     * @see TestCase#tearDown()
     
*/

    
protected void tearDown() throws Exception {
        super.tearDown();
    }


    
public void testCreateBMPEncoder() throws Exception {
        
int width = 104;
        
int height = 100;
        
int size = width * height * 3;
        
if (width % 4 != 0)
          size 
+= (width % 4* height;
        size 
+= 54;
        BufferedImage image 
= new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g 
= image.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(
00, width, height);

        g.setColor(Color.BLUE);
        g.setFont(
new Font("宋体", Font.ITALIC, 20));
        g.drawString(
"Hello"3030);
        
        BMPCodec.createBMPEncoder(
new FileOutputStream("C:\\house\\test.bmp")).encode(image);
    }


}


      保存的BMP文件如图:

test.JPG
posted on 2005-07-04 17:33 小米 阅读(3395) 评论(6)  编辑  收藏 所属分类: Java

评论:
# re: 如何将BufferedImage实例保存为BMP文件 2005-07-05 21:24 | jek
怎么才能使生成的bmp文件看上去更乱一些呢,例如验证码  回复  更多评论
  
# re: 如何将BufferedImage实例保存为BMP文件 2005-07-06 09:37 | 小米
这个可以看我的另外一篇随笔《我的网页附加码实现》http://www.blogjava.net/georgehill/archive/2005/05/12/4228.html  回复  更多评论
  
# re: 如何将BufferedImage实例保存为BMP文件 2007-11-27 16:29 | wangle

if (needBlank && (index % (width * 3) == 0)) {
out.write(blank);
}

我只看到 blank new了,但没有附值.这一点不里解.请指教.谢谢!

我的mail: wanglework@163.com  回复  更多评论
  
# re: 如何将BufferedImage实例保存为BMP文件 2007-11-27 16:37 | wangle
还对着几句不理解:

byte[width % 4];

if (width % 4 != 0)
size += (width % 4) * height;


if (needBlank && (index % (width * 3) == 0))

望赐教.谢谢!

我的mail: wanglework@163.com  回复  更多评论
  
# re: 如何将BufferedImage实例保存为BMP文件 2007-11-27 16:41 | wangle
这里回复也可以! 我以后回常来拜访的!!  回复  更多评论
  
# re: 如何将BufferedImage实例保存为BMP文件 2007-12-09 17:19 | wangle
呵呵,因为项目里有一个关于解析BMP的问题。在网上找到你这。
自己敲过代码后明白些了。谢谢!!  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: