要將BufferedImage實例保存為BMP文件,就需要知道BMP文件的格式,可以參考我轉(zhuǎn)載的文章:
《BMP文件格式》。
下面是我的將BufferedImage實例保存為24位色BMP文件的實現(xiàn)。
首先是BMP文件相關(guān)的兩個頭結(jié)構(gòu):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文件的頭結(jié)構(gòu)</p>
*
* <p> Description: BMP文件的頭結(jié)構(gòu)固定是14個字節(jié),其定義如下:</p>
* <p>
* byte[2] bfType; 指定文件類型,必須是0x424D,即字符串“BM”,也就是說所有.bmp文件的頭兩個字節(jié)都是“BM“
* byte[4] bfSize; 指定文件大小,包括這14個字節(jié)
* byte[2] bfReserved1; 保留字
* byte[2] bfReserved2; 保留字
* byte[4] bfOffBits; 為從文件頭到實際的位圖數(shù)據(jù)的偏移字節(jié)數(shù)
* </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文件內(nèi)容的頭結(jié)構(gòu)</p>
*
* <p>Description: BMP文件內(nèi)容的頭結(jié)構(gòu)固定是40個字節(jié),其定義如下:</p>
* <p>
* byte[4] biSize; 指定這個結(jié)構(gòu)的長度,為40
* byte[4] biWidth; 指定圖象的寬度,單位是象素
* byte[4] biHeight; 指定圖象的高度,單位是象素
* byte[2] biPlanes; 必須是1,不用考慮
* byte[2] biBitCount; 指定表示顏色時要用到的位數(shù),常用的值為1(黑白二色圖), 4(16色圖), 8(256色), 24(真彩色圖)
* byte[4] biCompression; 指定位圖是否壓縮
* byte[4] biSizeImage; 指定實際的位圖數(shù)據(jù)占用的字節(jié)數(shù)
* byte[4] biXPelsPerMeter; 指定目標(biāo)設(shè)備的水平分辨率,單位是每米的象素個數(shù)
* byte[4] biYPelsPerMeter; 指定目標(biāo)設(shè)備的垂直分辨率,單位是每米的象素個數(shù)
* byte[4] biClrUsed; 指定本圖象實際用到的顏色數(shù),如果該值為零,則用到的顏色數(shù)為2biBitCount
* byte[4] biClrImportant; 指定本圖象中重要的顏色數(shù),如果該值為零,則認(rèn)為所有的顏色都是重要的
* </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接口的實現(xiàn)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(0, 0, width, height);

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

}

保存的BMP文件如圖:
posted on 2005-07-04 17:33
小米 閱讀(3432)
評論(6) 編輯 收藏 所屬分類:
Java