import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import javax.swing.JFrame;
/**
* 打开BMP格式图片的程序
*
* @author XiongMinghua
*
* 主函数
*/
public class OpenBMP extends JFrame {
public static void main(String[] args) {
OpenBMP obmp = new OpenBMP();
String path = "D:\\My Documents\\StudySample\\src\\images\\Sunset.bmp";
obmp.openFile(path);
}
private void openFile(String path) {
try {
// 创建文件输入流
FileInputStream fis = new FileInputStream(path);
// 把文件输入流包装成输入缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
// 读入BMP头文件的基本信息
int bflen = 14;
byte[] bf = new byte[bflen];
bis.read(bf, 0, bflen);// 读取14字节的BMP文件头
// 读入位图信息头
int bilen = 40;
byte[] bi = new byte[bilen];
bis.read(bi, 0, bilen);// 读取40字节的BMP位图信息头
/**
* 获取一些重要信息: 位图的宽度、高度、每个像素点所需的位数(即图像的深度)、源图大小(测试时值为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, imageB, imageG三个二维数组中
readRGB(bis);
// 关闭流
bis.close();
fis.close();
showUI(path);
} catch (Exception e) {
e.printStackTrace();
}
}
// 读取位图数据的方法
public void readRGB(BufferedInputStream bis) {
if (!(image_width * 3 % 4 == 0)) {
skip_width = 4 - image_width * 3 % 4;
}
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++) {
int blue;
try {
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 e) {
e.printStackTrace();
}
if (w == 0) {
// 跳过补0项
try {
bis.skip(skip_width);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
// 显示窗体的方法
void showUI(String path) {
this.setTitle(path);
this.setSize(image_width, image_height);
this.setDefaultCloseOperation(3);
this.setVisible(true);
this.getGraphics();
repaint();// 调用重绘方法
}
// 重绘方法
public void paint(java.awt.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);
}
}
}
private int changeInt(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));
}
/**
* 1.BMP文件头(占14个字节)
*/
int bfType;// 位图文件类型,占两个字节,第一个字节为字母'B',第二个字节为字母'M'(1-2字节)
int bfSize;// 位图文件的大小,以字节为单位(3-6字节)
// 第7-10字节为位图的保留字,其Int值为0
// 位图数据的起始位置,以相对与位图(11-14字节)
int bfOffBits;
/**
* 2.位图信息头(占40字节)
*/
int size;// 位图信息头所占用字节数,为40个字节(15-18字节)
int image_width;// 位图的宽度,以像素为单位(19-22字节)
int image_height;// 位图的高度,以像素为单位(23-26字节)
int planes;// 目标设备的级别,必须为1(27-28字节)
int biBitCount;// 每个像素所需的位数,必须是1(双色)、4(16色)、8(256色)、24(真彩色)之一,(29-30字节)
int biCompression;// 位图压缩类型,必须是0(不压缩)、1(BI_RLE8压缩类型)、2(BI_RLE4压缩类型)之一。(31-34字节)
int sizeImage;// 位图的大小,以字节为单位(35-38字节)
int biXPelsPerMeter;// 位图水平分辨率,每米像素数(39-42字节)
int biYPelsPerMeter;// 位图垂直分辨率,每米像素数(43-46字节)
int biClrUsed;// 位图实际使用的颜色表中的颜色数(47-50字节)
int biClrImportant;// 位图显示过程中重要的颜色数(51-54字节)
// 跳过补0项
int skip_width;
/**
* 颜色表
* 颜色表中的RGBQUAD结构数据的个数由biBitCount来确定。当biBitCount分别取1,4,8时,分别有2,16,256个表项;
* 当biBitCount=24时,没有颜色表项
*/
class RGBQUAD {
byte rgbBlue;// 蓝色的深度(值范围为0-255)
byte rgbGreen;// 绿色的深度(值范围为0-255)
byte rgbRed;// 红色的深度(值范围为0-255)
byte rgbReserved;// 保留,必须为0
}
// 用于存储RGB颜色数据的数组
int[][] imageR, imageB, imageG;
}