BMP文件

BMP图像解析

 

平常我们接触到各种图像格式,但是这些图像格式具体是在计算机中运行的,今天我们来简单探讨一下BMP文件格式,BMP是一种与硬件设备无关的图像文件格式,使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此, BMP 文件所占用的空间很大。 BMP 文件的图像深度可选 lbit 、 4bit 、 8bit 及 24bit 。 BMP 文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。 由于 BMP 文件格式是 Windows 环境中交换与图有关的数据的一种标准,因此在 Windows 环境中运行的图形图像软件都支持 BMP 图像格式。 

 

要解析文件,就必须知道他的文件结构:

 BMP文件结构 

典型的BMP 图像文件由四部分组成:   

 . 位图文件 头数据结构 ,它包含BMP 图像文件的类型、显示内容等信息;  

 .位图信息数据结构 ,它包含有BMP 图像的宽、高、压缩方法,以及定义颜色等信息;   

  3. 调色板 ,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24 位的 BMP )就不需要调色板;  

     4. 位图数据 ,这部分的内容根据BMP 位图使用的位数不同而不同,在 24 位图中直接使用 RGB ,而其他的小于 24 位的使用调色板中颜色索引值。  

 

6.3.2对应的数据结构

① BMP文件头 (14 字节     

   BMP文件头数据结构含有 BMP 文件的类型、文件大小和位图起始位置等信息其结构定义如下

int bfType; // 位图文件的类型,必须为 ' B '' M '两个字母 (0-1字节 )   
int bfSize; // 位图文件的大小,以字节为单位 (2-5 字节 )   
int bfReserved1; // 位图文件保留字,必须为 0(6-7 字节 )    
int  bfReserved2; // 位图文件保留字,必须为 0(8-9 字节 )   
int  bfOffBits; // 位图数据的起始位置,以相对于位图 (10-13 字节 )    
 

 

 

   

 

② 位图信息头(40 字节   

  BMP 位图信息头数据用于说明位图的尺寸等信息。

  int Size; // 本结构所占用字节数 (14-17 字节 )  
	int image_width; // 位图的宽度,以像素为单位 (18-21 字节 )   
	int image_heigh; // 位图的高度,以像素为单位 (22-25 字节 )  
	int Planes; // 目标设备的级别,必须为 1(26-27 字节 )   
	int biBitCount;// 每个像素所需的位数,必须是 1(双色),(28-29 字节) 4(16 色 ) , 8(256 色 ) 或 24(// 真彩色 ) 之一  
	int biCompression; // 位图压缩类型,必须是 0( 不压缩 ),(30-33 字节 ) 1(BI_RLE8 压缩类型 ) 或// 2(BI_RLE4 压缩类型 ) 之一  
	int SizeImage; // 位图的大小,以字节为单位 (34-37 字节 )   
	int biXPelsPerMeter; // 位图水平分辨率,每米像素数 (38-41 字节 )   
	int biYPelsPerMeter; // 位图垂直分辨率,每米像素数 (42-45 字节 )   
	int biClrUsed;// 位图实际使用的颜色表中的颜色数 (46-49 字节 )   
	int biClrImportant;// 位图显示过程中重要的颜色数 (50-53 字节 )

 

 

 

 

③ 颜色表    

颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD 类型的结构定义一种颜色。 

class  RGBQUAD {   
	byte  rgbBlue;// 蓝色的亮度 ( 值范围为 0-255)    
	byte  rgbGreen; // 绿色的亮度 ( 值范围为 0-255)   
	byte  rgbRed; // 红色的亮度 ( 值范围为 0-255)    
	byte  rgbReserved;// 保留,必须为 0    
}

 

颜色表中RGBQUAD 结构数据的个数有 biBitCount 来确定biBitCount=1,4,8 时,分别有 2,16,256 个表项 biBitCount=24 时,没有颜色表项。   

位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下  

class  BITMAPINFO {   
	BITMAPINFOHEADER bmiHeader; // 位图信息头   
	RGBQUAD bmiColors[1]; // 颜色表   
}  

 

 

 

 

④ 位图数据    

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右扫描行之间是从下到上。位图的一个像素值所占的字节数   

biBitCount=1 时, 个像素占 个字节    

biBitCount=4 时, 个像素占 个字节    

biBitCount=8 时, 个像素占 个字节    

biBitCount=24 时 ,1 个像素占 个字节  

今天就简单说明一下24位图像的保存与打开
BMP文件
BMP文件
 
 

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.io.BufferedInputStream;
import java.io.FileInputStream;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

/**
 * 图片查看器窗口
 * 
 * @author 王伟
 * 
 */
public class PicUI extends JFrame {

	public static void main(String args[]) {
		PicUI ui = new PicUI();
		ui.initUI();
	}

	public void initUI() {
		this.setTitle("图片查看器");
		this.setSize(600, 500);

		// 设置布局为流式布局
		FlowLayout layout = new FlowLayout();
		this.setLayout(layout);



		// 用来显示图片的JPanel
		JPanel center = new MyPanel();



		center.setPreferredSize(new Dimension(400, 300));
		center.setBackground(Color.WHITE);

		this.add(center);

		this.setDefaultCloseOperation(3);
		this.setVisible(true);
	}

	/**
	 * 读取BMP文件的方法(暂时考虑24位位图)
	 * 
	 * @param path
	 */
	public int[][] readFile(String path) {
		try {
			// 根据文件路径创建输入流对象
			FileInputStream fis = new FileInputStream(path);
			// 包装成缓冲流,提高效率
			BufferedInputStream bis = new BufferedInputStream(fis);

			// 读取BMP文件流中的18~21个字节,图片的宽度
			// 丢弃掉前18个字节
			bis.skip(18);
			byte[] b = new byte[4];
			bis.read(b);
			// 读取BMP文件流中的22~25个字节,图片的高度
			byte[] b2 = new byte[4];
			bis.read(b2);
			// 得到宽度和高度
			int width = byte2Int(b);
			int height = byte2Int(b2);

			System.out.println(width + "<>" + height);
			// 定义二位数组来存储读取到的位图数据
			int[][] data = new int[height][width];
			// // 定义三个数组用来存储RGB三种颜色
			// int[][] R = new int[height][width];
			// int[][] G = new int[height][width];
			// int[][] B = new int[height][width];

			int skipNum = 0;// 每行补0的个数
			if (width * 3 / 4 != 0) {
				// 计算补0的个数
				skipNum = 4 - width * 3 % 4;
			}

			// 读位图数据
			bis.skip(28);// 丢弃28个字节,来到位置数据处
			for (int i = 0; i < data.length; i++) {
				for (int j = 0; j < data[i].length; j++) {
					// // 每次读取3个字节,表示的是三种颜色
					// B[i][j] = bis.read();
					// G[i][j] = bis.read();
					// R[i][j] = bis.read();

					int blue = bis.read();
					int green = bis.read();
					int red = bis.read();
					// 将三种颜色构造成一种颜色
					Color c = new Color(red, green, blue);
					data[i][j] = c.getRGB();
				}
				// 如果补0的个数不为0,则需要跳过这些补上的0




				if (skipNum != 0) {
					bis.skip(skipNum);
				}
			}
			return data;
		} catch (Exception ef) {
			ef.printStackTrace();
		}
		return null;
	}

	// 将4个byte拼成一个int
	public int byte2Int(byte[] by) {
		int t1 = by[3] & 0xff;
		int t2 = by[2] & 0xff;
		int t3 = by[1] & 0xff;
		int t4 = by[0] & 0xff;
		int num = t1 << 24 | t2 << 16 | t3 << 8 | t4;
		return num;
	}

	class MyPanel extends JPanel {
		public void paint(Graphics g) {
			super.paint(g);
			// 读取数据
			int[][] data = readFile("F:\\image\\abc.bmp");

			if (data != null) {
				this.setPreferredSize(new Dimension(data[0].length, data.length));
				// SwingUtilities.updateComponentTreeUI(this);
				for (int i = 0; i < data.length; i++) {
					for (int j = 0; j < data[i].length; j++) {
						Color c = new Color(data[i][j]);// 得到一个点的颜色
						g.setColor(c);
						// 绘制这个点
						g.drawLine(j, data.length - i, j, data.length - i);
					}
				}
			}
			System.out.println("wanbi");
		}

	}
}

 

 

<!--EndFragment--><!--EndFragment--><!--EndFragment--><!--EndFragment--><!--EndFragment-->

你可能感兴趣的:(文件)