在之前,我们要先了解BMP存储的格式,专业点也就是协议。
(1)BMP文件头(14个字节):
int bfType;//位图文件的类型,为'B'、'M'两个字母, (0-1字节)
int bfSize;//位图文件大小, (2-5字节)
int usignedshort bfReserved1;//位图文件保留字,必须为0 ,(6-7字节)
int usignedshort bfReserved2;//位图文件保留字,必须为0 ,(8-9字节)
int bfOffBits;//文件头的偏移量 ,(10-13字节)
(2)位图信息头(40个字节):
int Size;//本结构所占用的字节数 ,(14-17字节)
int image_width;//位图的宽度,单位为像素,(18-21字节)
int image_height;//位图的高度,单位为像素 ,(22-25字节)
int Planes;//目标设备的级别,为1 ,(26-27字节)
int biBitCount;//每个像素所需的位数,必须为1、4、8、24其中一个,分别代表双色、16色,256色和真彩色 ,(28-29字节)
int biCompression;//位图压缩类型,为0 ,(30-33字节)
int SizeImage;//位图大小 ,(34-37字节)
int biXPelsPerMeter;//位图水平分辨率 ,(38-41字节)
int biYPelsPerMeter;//位图垂直分辨率 ,(42-45字节)
int biClrUsed;//位图实际使用的颜色表中的颜色数 ,(46-49字节)
int biClrImportant;//位图显示过程中重要的颜色数 ,(50-53字节)
(3)颜色表:
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时,没有颜色表。
(4)位图数据:
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内从左到右,扫描行之间是从下到上,位图的一个像素值所占用的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=8时,2个像素占1个字节;
当biBitCount=16时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0补充,补在每行尾部。
知道协议后,就容易了,只不过用输入流把每个数据都读出来,然后按照协议可以得到各个数据,知道各个数据的意义后,就可以画出图片。我所做的24位BMP读取只需要图片的长度,宽度和各个点RGB即可。代码如下:
/**
* 读取方法
* @param file:文件
* @throws Exception:异常
*/
public void readBMP(File file) throws Exception{
Graphics g=frame.getGraphics();
FileInputStream ins=new FileInputStream(file);//输入流
dins = new DataInputStream(ins);//包装为数据输入流
/**BMP文件头*/
int bf1len=14;
byte bf1[]=new byte[bf1len];
dins.read(bf1);
/**位图信息头*/
int bf2len=40;
byte bf2[]=new byte[bf2len];
dins.read(bf2);
int image_width=changeInt(bf2,7);//位图的宽度
int image_heith=changeInt(bf2,11);//位图的高度
/**得到补0长度*/
if(!(image_width*3%4==0)){
skip_width=4-image_width*3%4;
}
/**读入RGB*/
//分别用三个二维数组存储RGB
int [][]imageB=new int[image_heith][image_width];
int [][]imageG=new int[image_heith][image_width];
int [][]imageR=new int[image_heith][image_width];
for(int h=image_heith-1;h>=0;h--){
for(int w=0;w<image_width;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;
/**补0跳过*/
if(w==image_width-1){
byte bf3[]=new byte[skip_width];
dins.read(bf3);//读出0项字节,不使用
}
}
}
/**画出图片*/
for(int h=0;h<image_heith;h++){
for(int w=0;w<image_width;w++){
g.setColor(new Color(imageR[h][w],imageG[h][w],imageB[h][w]));
g.fillRect(w+(frame.getWidth()-image_width)/2, h+(frame.getHeight()-image_heith)/2, 1, 1);
}
}
}
/**
* 位运算方法
* @param bi:数组
* @param start:开始位置
* @return:整形数据
*/
public int changeInt(byte[] bi,int start){
return(((int)bi[start]&0xff<<24)|(((int)bi[start-1]&0xff)<<16)|(((int)bi[start-2]&0xff)<<8)|((int)bi[start-3]&0xff));
}
这里想说的是由于输入流只能一个一个字节的读入,也就是就算数据你并不需要,也要把它读出来才能接着往下读。另外这里做的是24位的读取,无法读取其他位的BMP图片。
至于保存,只要按照协议一个字节一个字节的写入,按照电脑的协议写入,电脑才看的懂,读的出来。代码如下:
/**
* 保存BMP方法
* @param file:保存目标文件
* @throws Exception:异常
*/
public void saveBMP(File file) throws Exception{
FileOutputStream ous=new FileOutputStream(file);//输出流
dous = new DataOutputStream(ous);//包装为数据输出流
/**写入BMP文件头*/
byte []bfType={'B','M'};//位图文件类型,0-1字节
dous.write(bfType);
byte []bfSize=changeByte(580*490*3+54);//位图文件大小,2-5字节
dous.write(bfSize);
byte[]bfReserved1={0,0};//位图文件保留字,必须为0,6-7字节
dous.write(bfReserved1);
byte[]bfReserved2={0,0};//位图文件保留字,必须为0,8-9字节
dous.write(bfReserved2);
byte [] bfOffBits={54,0,0,0};//位图数据起始位置,以相对于位图,10-13字节
dous.write(bfOffBits);
/**写入位图信息头*/
byte []size={40,0,0,0};//本结构所占字节数,14-17字节
dous.write(size);
byte[]image_width=changeByte(580);//位图的宽度,以像素为单位,18-21字节
dous.write(image_width);
byte[]image_heigh=changeByte(490);//位图的高度,以像素为单位,22-25字节
dous.write(image_heigh);
byte []planes={1,0};//目标设备的级别,必须为1,26-27字节
dous.write(planes);
byte[]biBitCount={24,0};//每个像素所需的位数,必须是1(真彩色)或4(16色)或8(256色)或24(真彩色),28-29字节
dous.write(biBitCount);
int biCompressin=0;//位图压缩类型,必须是0(不压缩)或1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型),30-34字节
dous.writeInt(biCompressin);
byte[] sizeImage=changeByte(580*490*3);//位图的大小,以字节为单位,34-37字节
dous.write(sizeImage);
int biXPelsPerMeter=0;//位图水平分辨率,每米像素数,38-41字节
dous.writeInt(biXPelsPerMeter);
int biYPelsPerMeter=0;//位图垂直分辨率,每米像素数,42-45字节
dous.writeInt(biYPelsPerMeter);
int biClrUsed=0;//位图实际使用的颜色表的颜色数,46-49字节
dous.writeInt(biClrUsed);
int biClrImportant=0;//位图显示过程中重要的颜色表,50-53字节
dous.writeInt(biClrImportant);
/**颜色表*/
//用BufferedImage对象可以得到每个点的RGB,截取屏幕固定大小矩形,在窗体内部截取,这里的x,y为窗体此刻的坐标,其中580,490为截取的矩形大小,取宽度580完全是我的懒惰,定长不用去考虑补0
BufferedImage image=new Robot().createScreenCapture(new Rectangle(x+10,y+100,580,490));
for(int h=image.getHeight()-1;h>=0;h--){
for(int w=0;w<image.getWidth();w++){
//分别得到截取的矩形内的每个点的RGB,按照协议顺序存储
int rgb=image.getRGB(w, h);
byte rgbs[]=new byte[3];
rgbs[0]=(byte)rgb;
rgb=rgb>>8;
rgbs[1]=(byte)rgb;
rgb=rgb>>8;
rgbs[2]=(byte)rgb;
dous.write(rgbs);
}
}
}
/**
* 将int转化为byte数组的方法、
* @param int:将转化的整数
* @return byte[]:返回得到的数组
*/
public byte[] changeByte(int num){
byte[]b=new byte[4];
b[0]=(byte)num;
num=num>>8;
b[1]=(byte)num;
num=num>>8;
b[2]=(byte)num;
num=num>>8;
b[3]=(byte)num;
return b;
}
BMP只是各种协议中的比较简单的一种,文件之所以能被各种软件打开,只不过是它们的协议符合,各种文件格式只不过是表象,只是按照各自的协议将byte组合而已。而各种软件也按照它们的协议读出数据,知道各个数据的意义,就能打开各种文件,就会出现各种图片,文字,视频等。
分享到:
相关推荐
bmp位图文件的读取与保存 bmp位图文件的读取与保存
C++读取保存BMP图像,包括8位,24位的读取和保存,灰度图的转换,不使用任何已有读取、转换、保存等库函数。跨平台使用,理论上Linux与Windows上均可使用,Windows上测试成功。
C++进行bmp图片的读取与保存 在bmp读取过程中需要注意内存对齐,是否有调色板等问题
基于vs2005,实现BMP图像文件读取和保存。适合初学者入门。
bmp位图文件的读取与保存
c的bmp图像读取保存放大缩小程序.txt c的bmp图像读取保存放大缩小程序.txt
一个图像的读出与保存的程序,希望对初学者有所帮助!
BMP格式图片信息读取及保存:宽、高、每像素所占位数、灰度图像的颜色表、位图RGB数据等
c++源代码 实现bmp位图文件的读取与保存 二进制方法读取bmp的像素信息
BMP图片读取并保存成文本C程序,加了保存到文本的功能
读取,保存,打开bmp图片。并且可以详细读取bmp表头的各种数据。
实现了BMP图像的读取、保存、创建、修改某一像素的代码。跨平台。
程序代码 博文链接:https://479001499.iteye.com/blog/2078110
一个用c++编写的读取BMP文件的小程序
使用C++读取TM遥感数据,并写成8位的BMP位图
bmp位图文件的读取与保存 bmp位图文件的读取与保存,可以借此熟悉bmp的文件结构
C source code,包含两个函数ReadBmp和SaveBmp
本文件中有三份C++程序的代码,均可以读取.bmp文件的图像。其中包括彩色的.bmp文件和黑白的.bmp文件的代码。并且可以实现对文件图像的任意角度的旋转,以及旋转后的图像保存,为广大朋友提供诸多便利。并且也可以在...
1、可以读取1位、8位、24位、32位的bmp文件; 2、将不同位的bmp图像转为24位bmp图像; 3、可以保存为黑白、256、真彩色图像。
vc++6.0环境下,读取bmp图像文件,并能保存成bmp文件格式。