BMP文件格式的解析和保存

 

  BMP是英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式,能够被多种Windows应用程序所支持。因为几乎不进行压缩,所以BMP格式是最简单的通用格式之一。

  本篇文章主要介绍BMP文件的格式规范,解析及其保存。

 

 

   BMP文件结构(本段代码由小组成员卿雯童鞋呈现)

  位图文件可看成由4个部分组成:位图文件头(bitmap-file header)、位图信息头(bitmap-information header)、彩色表(color table)和定义位图的字节(位图数据,即图像数据,Data Bits 或Data Body)阵列,它具有如下所示的形式。

 

位图文件头 (bitmap-file header) BITMAPFILEHEADER bmfh
/**
	 * bitmap-file header(14 byte)
	 * 
	 */
	class BITMAPFILEHEADER {
		short bfType;// the type of BMP file,value of 'B' or 'M' only.(1-2 byte)
		int bfSize;// the size of BMP file.(3-6 byte)
		short bfReserved1;// reserved word of bmp file,value of 0 only.(7-8 byte)
		short bfReserved2;// reserved word of bmp file,value of 0 only.(9-10byte)
		int bfOffBits;// the offset of file header(11-14 byte)
	}

 

 

 

位图信息头 (bitmap-information header) BITMAPINFOHEADER bmih
/**
	 * bitmap-information header(40 byte)
	 * 
	 */
	class BITMAPINFOHEADER {
		int biSize;// the size of this part.(15-18 byte)
		int biWidth;// the width of bmp file.(19-22 byte)
		int biHeight;// the height of bmp file.(23-26 byte)
		byte biPlanes;// the rank of target device.value of q only(27-28 byte)
		byte biBitCount;// the bit of per pixel,value of 1,4 8 or 24 only.(29-30byte)
		int biCompression;// the type of compression,value of 0(BI_RGB)(non-compression),1(BI_RLE8) or 2(BI_RLE4) only.(31-34 byte)
		int biSizeImage;// the size of image.(35-38 byte)
		int biXPelsPerMeter;// horizontal resolution, Pixels per meter.(39-42 byte)
		int biYPelsPerMeter;// vertical resolution,Pixels per meter.(43-46 byte)
		int biClrUsed;// the number of all used color.(47-50 byte)
		int biClrImportant;// the number of key color.(51-54 byte)
	}
彩色表  (color table) RGBQUAD aColors[]
	/**
	 * color table
	 * 
	 */
	class RGBQUAD {
		byte rgbRed;// the red channel
		byte rgbGreen;// the Green channel
		byte rgbBlue;// the blue channel
		byte rgbReserved;// reserved,value of 0 only
	}
 
图象数据阵列字节 BYTE aBitmapBits[]
/**
	 * Data Bits
	 * 
	 */
	class BITMAPINFO {
		BITMAPINFOHEADER bmiHeader;
		RGBQUAD bmiColors;

	}
 
BMP文件解析(本段代码由小组成员阳超群童鞋呈现)
要点:先读取位图文件头的信息(14 byte)
然后读取位图信息头为的信息(40 byte)
注意:此段要获取信息头的2个重要的参数,位图的宽度和高度
最后读取位图的图像信息。
其中要注意数据类型的匹配。
 
读取位图文件头和信息头
	/**
	 * read the image from the bitmap file
	 * 
	 * @param path
	 *            the path of bitmap file
	 * @throws IOException
	 */
	public void readBMP(String path) throws IOException {
		// creat a FileInputStream object;
		fis = new java.io.FileInputStream(path);
		// creat a DataInputStream object;
		dins = new java.io.DataInputStream(fis);

		// read the bitmap loader of bitmap file
		int bmploaderLen = 14;
		byte[] bmploader = new byte[bmploaderLen];
		dins.read(bmploader, 0, bmploaderLen);

		// read the info header of bitmap file
		int bmpheaderLen = 40;
		byte[] bmpheader = new byte[bmpheaderLen];
		dins.read(bmpheader, 0, bmpheaderLen);

		biWidth = convert2Int(bmpheader, 7);
		biHeight = convert2Int(bmpheader, 11);

	}
将byte数组转换为int类型的数据
/**
	 * 4 byte convert to 1 int
	 * @param bytes the source byte array
	 * @return the converted int
	 */
	private int convert2Int(byte[] bytes, int index) {
		return (((int) bytes[index] & 0xff) << 24)
				| (((int) bytes[index - 1] & 0xff) << 16)
				| (((int) bytes[index - 2] & 0xff) << 8)
				| ((int) bytes[index - 3] & 0xff);
	}
计算补零的长度
// calculate the length of zero-padding
		if (!(biHeight * 3 % 4 == 0)) {
			skip_width = 4 - biWidth * 3 % 4;
		}
 
读取RGB信息
for (int h = biHeight - 1; h >= 0; h--) {
			for (int w = 0; w < biWidth; w++) {
				// 分别按照协议顺序读出字节
				int blue = dins.read();
				int green = dins.read();
				int red = dins.read();
				// 由于颜色值范围超出byte正值范围,可能存储为负值,进行位运算
				int blue_temp = (blue & 0xff);
				int green_temp = (green & 0xff);
				int red_temp = (red & 0xff);
				imageB[h][w] = blue_temp;
				imageG[h][w] = green_temp;
				imageR[h][w] = red_temp;

				// zero-padding
				if (w == 0) {
					byte bytes[] = new byte[skip_width];
					dins.read(bytes);
				}
			}
		}
		dins.close();
		fis.close();

	}
 
绘出位图图像
    /**
	 * paint the image on the frame
	 */
	public void paint(Graphics g) {
		super.paint(g);
		// g = this.getGraphics();
		for (int h = 0; h < biHeight; h++) {
			for (int w = 0; w < biWidth; w++) {
				g.setColor(new Color(imageR[h][w], imageG[h][w], imageB[h][w]));
				g.fillRect(w, h, 1, 1);
			}
		}
	}
 
BMP文件的保存(本段代码有小组成员曹睿超童鞋呈现)
要点:按BMP文件结构依次写入位图文件头,位图信息图,RGB颜色表,和图象数据阵列字节 
注意:数据类型的匹配。
/**
	 * 写入bmp文件
	 * @param image
	 * @param file
	 */
	public void writeBMP(BufferedImage image, File file) {

		try {
			// 创建输入流
			FileOutputStream fos = new FileOutputStream(file);
			DataOutputStream dos = new DataOutputStream(fos);
			
			
			//位图文件类型,2个字节,必须为'B'和'M'
			dos.writeByte((int)'B');
			dos.writeByte((int)'M');
			
			
			
			//BMP头文件
			biWidth = image.getWidth();
			biHeight = image.getHeight();
			
			//位图文件大小,4个字节
			int skip_width = 0;
			//一个扫描行所占的字节数必须为4的倍数,不足的补上0
			if(skip_width * 3 % 4 != 0)
				skip_width = 4 - skip_width * 3 % 4;
			
			//得到文件的大小
			bfSize = 54 + (biWidth + skip_width) * 3 * biHeight;
			dos.write(changeIntToByte(bfSize, 4) , 0, 4);
			
			//起始位置4个字节
			dos.write(changeIntToByte(bfReserved1, 2), 0, 2);
			dos.write(changeIntToByte(bfReserved2, 2), 0, 2);
			
			//写入位图文件的起始位置
			dos.write(changeIntToByte(bfOffBits, 4), 0, 4);
			
			//位图信息图
			biSize = (biWidth + skip_width) * 3 * biHeight;
			dos.write(changeIntToByte(biSize, 4), 0, 4);
			
			//宽度,高度
			dos.write(changeIntToByte(biWidth, 4), 0, 4);
			dos.write(changeIntToByte(biHeight, 4), 0, 4);
			
			//目标设备
			dos.write(changeIntToByte(biPlanes, 2), 0, 2);
			
			//像素所需位数,24
			biBitCount = 24;
			dos.write(changeIntToByte(biBitCount, 2), 0 ,2);
			
			//压缩类型
			dos.write(changeIntToByte(biCompression, 4), 0 ,4);
			
			//位图大小
			dos.write(changeIntToByte(biSizeImage,  4), 0, 4);
			
			//写入水平,垂直分辨率(150ppm)
			dos.write(changeIntToByte(biXPelsPreMeter, 4), 0, 4);
			dos.write(changeIntToByte(biYPelsPreMeter, 4), 0, 4);
			
			//写入位图中实际使用的颜色表的颜色数
			dos.write(changeIntToByte(biClrUsed, 4), 0, 4);
			
			//写入重要的颜色
			dos.write(changeIntToByte(biClrImportant, 4), 0, 4);
			
			//位图数据
			int color [][] = new int [biWidth][biHeight];
			byte colorR[][] = new byte [biWidth][biHeight];
			byte colorG[][] = new byte [biWidth][biHeight];
			byte colorB[][] = new byte [biWidth][biHeight];
			
			for(int i = 0;i < biHeight;i ++) {
				for(int j = 0;j < biWidth;j ++) {
					int temp = image.getRGB(j, i);
					color[i][j] = temp;
					colorR[i][j] = (byte)(temp >> 16);
					colorG[i][j] = (byte)(temp >> 8);
					colorB[i][j] = (byte)(temp >> 0);
				}
			}
			
			for(int i = biHeight - 1;i >= 0;i ++) {
				for(int j = biWidth - 1;j >= 0;j --){
					dos.write(colorB[i][j]);
					dos.write(colorG[i][j]);
					dos.write(colorR[i][j]);
					
					if(skip_width != 0 && j == 0)
						dos.write(changeIntToByte(0, skip_width), 0, skip_width);
					
				}
			}
			fos.flush();
			fos.close();
			dos.flush();
			dos.close();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
 
将int类型转换为Byte数组
         /**
	 * 将int类型转换为byte数组
	 * @param num int类型的对象
	 * @param size 数组的长度
	 * @return byte类型数组
	 */
	private byte[] changeIntToByte(int num, int size) {
		
		//定义一个byte类型数组
		byte[] count = new byte[size];
		
		//循环进行位运算
		for(int i = 0;i < size;i ++) {
			count[i] = (byte) (num >> (i * 8));
		}
		
		return count;
	}
 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BMP格式是Windows操作系统中最常见的图像文件格式之一,它采用无压缩的位图图像存储方法,可以保存不同颜色、分辨率和位深度的图像。而RGB文件则是指将图像的颜色信息按照红、绿和蓝三种颜色通道进行分离保存文件。 要将BMP格式转换为RGB文件,首先需要了解BMP文件的结构。BMP文件文件头和图像数据组成,文件头包含了文件的基本信息,而图像数据则包含了每个像素点的颜色信息。 要进行转换,可以使用编程语言或图像处理软件来实现。以编程语言为例,可以按照以下步骤进行转换: 1. 读取BMP文件文件头信息,识别出图像的宽度、高度和位深度等参数。 2. 根据位深度信息,确定每个像素点的大小。 3. 读取图像数据,按照每个像素点的大小进行解析,获取每个像素点的颜色信息。 4. 将每个像素点的颜色信息拆分为红、绿、蓝三个通道的颜色值。 5. 将红、绿、蓝三个通道的颜色值保存为RGB文件。 通过以上步骤,就能够将BMP格式的图像转换为RGB文件,其中RGB文件中的数据就是按照每个像素点的颜色信息进行分离的,可以方便地进行进一步的图像处理和分析。 需要注意的是,对于一些特殊的BMP文件,可能存在压缩或者加密的情况,这种情况下需要根据具体的情况来进行相应的处理。另外,为了保证转换的准确性和稳定性,建议使用专业的图像处理软件或者图像处理库进行转换操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值