- 浏览: 13355 次
- 性别:
最新评论
简单的bmp文件打开与保存
- 博客分类:
- java语言
简单的bmp文件打开与保存
在谈bmp文件的打开、保存之前,我先说说在制作这一软件时的感受。在初次听到用输入输出流制作bmp格式文件的打开和保存时,有点不知所措,不知什么是bmp文件,他的格式是怎样的,我该如何制作一个程序去打开、保存这一文件。于是,就在网上找bmp文件格式的定义,让我感受特别深的是:你要用自己写的软件打开某一东西,必须知道他的协议是什么。你想要别人认同你制作的软件,你也必须定义一个完整规范的协议。协议是作为计算机之间,网络之间或者是软件、文件之间互通的一条通道规则。你不认同遵守协议你就寸步难行,你不制定规范协议,你自己制作的东西也无法得到认同。
下面就谈谈bmp格式的协议:
bmp文件有一个规范的格式:
他由四部分构成:
1、位图文件头(占14个字节):它包含BMP图像的文件类型,位图文件大小,文件头偏移量(偏移量是指从文件当前位置跳到指定位置的大小值)等。
2、位图信息头(占40个字节):包含位图宽高,位图大小,目标设备级别(必须为1),每个像素所需位数(下面用到的是24位),压缩类型等。
3、调色板:这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP文件)就不需要调色板。
4、位图数据:位图数据记录了位图的每个像素值,记录顺序的在扫描行内从左到右,从下到上。当位图像素所需位数为24位时,一个像素占三个字节,即R、G、B三个颜色值(0-255)。
对应的数据结构:
【BMP文件头(14个字节)】:
int bfType;//(0-1字节)位图文件的类型,为'B'、'M'两个字母
int bfSize;//(2-5字节)位图文件大小
int usignedshort bfReserved1;//(6-7字节)位图文件保留字,必须为0
int usignedshort bfReserved2;//(8-9字节)位图文件保留字,必须为0
int bfOffBits;//(10-13字节)文件头的偏移量
【位图信息头(40个字节)】:
int Size;//(14-17字节)本结构所占用的字节数
int image_width;//(18-21字节)位图的宽度,单位为像素
int image_height;//(22-25字节)位图的高度,单位为像素
int Planes;//(26-27字节)目标设备的级别,为1
int biBitCount;//(28-29字节)每个像素所需的位数,必须为1、4、8、24其中一个,分别代表双色、16色,256色和真彩色
int biCompression;//(30-33字节)位图压缩类型,为0
int SizeImage;//(34-37字节)位图大小
int biXPelsPerMeter;//(38-41字节)位图水平分辨率
int biYPelsPerMeter;//(42-45字节)位图垂直分辨率
int biClrUsed;//(46-49字节)位图实际使用的颜色表中的颜色数
int biClrImportant;//(50-53字节)位图显示过程中重要的颜色数
由于我们选择的是24位的BMP图片,所以今天不讨论颜色表的问题。
【位图数据】:
位图数据记录了位图的每一个像素值,记录顺序的在扫描行内从左到右,从下到上。位图的一个像素值所占用的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=8时,2个像素占1个字节;
当biBitCount=16时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
【BMP文件读取步骤】:
1.利用DataInputStream流将文件中的信息按一定次序读入
2.获取文件中的重要信息
3.根据信息绘制图像
按一定次序:因为我们在文件中读入的是一个一个的字节,而实际操作需要的最少也是一个int(即四个字节),因此我们需要将byte数组转化成int型。
重要信息:BMP文件有很多信息,但是我们打开、保存该文件所需要的信息也就是那几个关键的数据。比如文件的宽高,文件的颜色数值。
【BMP文件读取的关键代码如下】:
//输入流InputStream、DataInputStream的实例化 InputStream in=new FileInputStream(f); dis=new DataInputStream(in); //读入文件头信息 int len=14; byte[] b=new byte[len]; dis.read(b); //读入位图信息头 int len1=40; byte[] b1=new byte[len1]; dis.read(b1); //读取重要的数据宽高,调用位转换方法changeInt() w=changeInt(b1,7); h=changeInt(b1,11); //参数的直接传递 bmp.w=w; bmp.h=h; //创建数组用于保存rgb值 imageR=new int[h][w]; imageG=new int[h][w]; imageB=new int[h][w]; int skip_width=0; //计算补零的字节数 int m=w%4; if(m!=0){ skip_width=4-m; } /* * 读取颜色数值的方法 */ for(int i=h-1;i>=0;i--){ for(int j=0;j<w;j++){ Bmp bp=new Bmp(); int blue=dis.read(); int green=dis.read(); int red=dis.read(); imageB[i][j]=blue; imageG[i][j]=green; imageR[i][j]=red; //跳过补0字节 if(j==w-1){ byte bf3[]=new byte[skip_width]; dis.read(bf3); } } }
其中调用的changeInt()方法定义如下:
/* * 将字节转换为整形的方法 */ private int changeInt(byte[] b1, int i) { return (((int)b1[i]&0xff)<<24) |(((int)b1[i-1]&0xff)<<16) |(((int)b1[i-2]&0xff)<<8) |(int)b1[i-3]&0xff; }
在解释之前,先给大家补一点关于Java的位运算符的知识
【Java位运算符】
按位与 & 两位同时为1,结果才为1,否则为0
0000 1111 & 1111 0000 = 0000 0000
按位或 | 两位中至少一位为1,结果为1,否则为0
0000 1111 | 1111 0000 =1111 1111
左移运算符 << 将一个二进制运算单位的各二进制位全部左移若干位(左边二进制位丢弃,右边补0)
1111 0000 << 2 = 1100 0000
右移运算符 >> 将一个二进制运算单位的各二进制位全部右移若干位(右边二进制位丢弃,左边补0)
0000 1111 >> 2 = 0000 0011【疑问】:
w=changeInt(b1,7);
这句代码的意思是,将b1[7],b16],b1[5],b1[4]四个字节组合成一个Int型数。(((int)b1[i]&0xff)<<24):假如b1[7]中存的是【0000 1111】,现先将b1[7]与0xff进行与运算,然后强制转换为int形,再往前移24位。最后把b1[7],b16],b1[5],b1[4]进行或运算(如9|5=13),即为得到的宽。
int m=w%4; if(m!=0){ skip_width=4-m; }
因系统在保存BMP格式文件时,为了效率,规定图片每行的字节数必须是4的倍数。也就是说,若不为四字节的整数倍时,我们要补上0。所以skip_width为4减去每行的字节数对4的余数。
--------------------------------------------------------------------
【BMP文件的保存关键代码】:
//得到当前窗体的左上顶点在电脑屏幕中的坐标值 int x=bmp.getLocation().x; int y=bmp.getLocation().y; //System.out.println("x:"+x+"y:"+y); JFileChooser jfc=new JFileChooser(); jfc.showSaveDialog(null); File f=jfc.getSelectedFile(); //File f1=new File(f.getPath()); try { //实例化输出流 FileOutputStream out=new FileOutputStream(f); DataOutputStream dos=new DataOutputStream(out); //用于截取当前画板上的图画,并返回一张相应的位图 BufferedImage bf_image=new Robot().createScreenCapture(new Rectangle(x+10,y+100,bmp.getWidth()-20,bmp.getHeight()-110)); //得到图片的高度,宽度 int image_w=bf_image.getWidth(); int image_h=bf_image.getHeight(); //文件的大小 int image_size=image_w*image_h*3; //判断文件的保存是否需要补0 if(image_w%4!=0){ image_size+=(image_w%4)*image_h*3; } //创建数组用于保存颜色RGB值 byte[] rgbs=new byte[3]; //创建数组用于补0 byte[] b0=new byte[image_w%4]; //实例化一个bmp文件头信息的写入类 FileHead fh=new FileHead(image_size,54); //实例化一个bmp文件位图信息的写入类 FileMid fm=new FileMid(image_w,image_h); //写入以上字节码 dos.write(fh.data()); dos.write(fm.getData()); //获取当前像素的rgb值,并写入 for(int h=image_h-1;h>=0;h--){ for(int w=0;w<image_w;w++){ int rgb=bf_image.getRGB(w, h); //将整形数据转换成字节保存,一个像素点为三个字节 rgbs[0]=(byte)rgb; rgb=rgb>>8; rgbs[1]=(byte)rgb; rgb=rgb>>8; rgbs[2]=(byte)rgb; //写入rgb字节码 dos.write(rgbs); //判断补零的方法 if((image_w%4!=0)){ dos.write(b0); } } } //清空并关闭输出流 dos.flush(); dos.close(); } catch (Exception e1) { e1.printStackTrace(); }
【疑问】:
rgbs[0]=(byte)rgb; rgb=rgb>>8; rgbs[1]=(byte)rgb; rgb=rgb>>8; rgbs[2]=(byte)rgb;
首先把rgb值强制转化为byte(强制转换后rgb值不变),赋给rgbs[0],然后将rgb右移8个位(将右八位抛弃,左边补0),强制转化为byte赋给rgbs[1],如此循环,就把rgb(int型)的值反序存在了rgb[0]、rgb[1]、rgb[2]三个字节中了。
【FileHead和FileMid类】:
public class FileHead { //存储头文件信息的数组,头文件大小为14个字节 private byte[] hf=new byte[14]; //文件的大小 private int fsize; //头文件偏移量 private int move; public FileHead(int fsize, int move){ this.fsize=fsize; this.move=move; //头两个字节必写入BM,作为bmp文件的标识 hf[0]='B'; hf[1]='M'; //文件大小的写入 int value=fsize; hf[2]=(byte)value; value=value>>8; hf[3]=(byte)value; value=value>>8; hf[4]=(byte)value; value=value>>8; hf[5]=(byte)value; //头文件偏移量的写入 value=move; hf[10]=(byte)value; value=value>>8; hf[11]=(byte)value; value=value>>8; hf[12]=(byte)value; value=value>>8; hf[13]=(byte)value; } //返回数组hf[] public byte[] data(){ return hf; } }
public class FileMid { //本结构所占用字节数 int size=40; //目标设备的级别,必须为1 private int level=1; //位图的宽度 private int image_w; //位图的高度 private int image_h; //每个像素所需的位数 private int count=24; //位图压缩类型,这里不压缩为0 private int compression=0; //位图的大小 private int sizeimage; //创建数组 private byte[] fm=new byte[40]; public FileMid(int image_w, int image_h) { this.image_w=image_w; this.image_h=image_h; //保存字节占用数 fm[0]=(byte)size; size=size>>8; fm[1]=(byte)size; size=size>>8; fm[2]=(byte)size; size=size>>8; fm[3]=(byte)size; //写入位图的宽 int value=image_w; fm[4]=(byte)value; value=value>>8; fm[5]=(byte)value; value=value>>8; fm[6]=(byte)value; value=value>>8; fm[7]=(byte)value; //写入位图的高 value=image_h; fm[8]=(byte)value; value=value>>8; fm[9]=(byte)value; value=value>>8; fm[10]=(byte)value; value=value>>8; fm[11]=(byte)value; //写入目标设备的级别 fm[12]=(byte)level; level=level>>8; fm[13]=(byte)level; //写入每个像素所需的位数,24位 fm[14]=(byte)count; count=count>>8; fm[15]=(byte)count; //写入压缩类型,这里为0 fm[16]=(byte)compression; compression=compression>>8; fm[17]=(byte)compression; compression=compression>>8; fm[18]=(byte)compression; compression=compression>>8; fm[19]=(byte)compression; //得到位图大小,并写入 sizeimage=image_w*image_h*3-54; if(image_w%4!=0){ sizeimage+=(image_w%4)*image_h*3; } fm[20]=(byte)sizeimage; sizeimage=sizeimage>>8; fm[21]=(byte)sizeimage; sizeimage=sizeimage>>8; fm[22]=(byte)sizeimage; sizeimage=sizeimage>>8; fm[23]=(byte)sizeimage; } //返回数组fm[] public byte[] getData(){ return fm; } }
发表评论
-
线程的同步通信与线程范围内的数据共享问题
2013-10-02 22:05 1324线程的同步通信与线程范围内的数据共享问题一、线程的同步通信 什 ... -
多线程初谈——线程的创建与互斥问题
2013-10-01 18:13 1400多线程初谈——线程的创建与互斥 对于线程起初也很是不 ... -
网络通信见解之谈
2013-07-17 13:38 616一、网络通信的基本原理 现如今,出现了各式各样的聊天平 ... -
分形浅谈——科赫曲线和L-System
2013-06-24 22:47 1232分形浅谈开始接触到分行图时,感觉很难,无法下手,只能做出第一层 ... -
对关键字final、static的理解
2013-05-10 23:36 534一、final关键字 fin ... -
对关键字的理解——访问权限
2013-05-10 16:17 598关键字public、pr ... -
队列的定义及运用
2013-03-23 14:58 640队列简称队,是限制在表的一端进行插入操作,而在表的另一端进行删 ... -
重绘方法的重写利用
2013-03-22 21:44 616重绘是为了在画布上保留原始痕迹的一种方法,他的目的是用来保存你 ... -
数组的定义及递归的运用
2013-03-22 21:43 1020一、数组有一维数组、 ... -
监听器与变量的作用域
2013-03-22 21:41 703监听器是用来实现一些可控操作的工具,如你在打开一个QQ界面的时 ... -
java中的继承
2013-03-08 00:31 566Java中的接口 什么是接口?不是以class定义的类而是以i ... -
Java中类的继承、重写、自动转型以及多态
2013-03-06 01:13 716Java中类的继承、重写、自动转型以及多态 1) 类的继承 在 ... -
java的构造器方法、方法重载和引用传递
2013-03-04 23:55 728Java的构造器方法、方法重载与引用传递 一、 构造器方法 构 ... -
JAVA语言中的类与对象
2013-03-04 00:08 731Java语 ...
相关推荐
将客户区的图像保存到bmp文件,通过截取屏幕实现
用自制画板打开和保存BMP格式文件。画板代码如下
勾月画图程序(VB6.0源代码编写)可以打开一个*.bmp文件,也可以保存为另一个*.bmp文件,可以画出不同颜色和线条.
使用C++将BMP文件从硬盘读入到内存、然后修改其数据,最后将修改的文件保存到硬盘
利用强大的CImage类打开和保存jpeg、bmp、gif和png格式图片,有VC下的Demo。
能够实现bmp文件的打开和保存,主要用的是DIB句柄,其中的DIB类是MFC里没有的
[bmp.rar] - 打开bmp文件源代码,VC实现,相当好用,用于毕业设计及课程设计 [bmp位图文件程序.rar] - 手把手教你了解bmp图形文件结构,C语言文件读写函数应用,一般数据处理方法,如果看不懂,说明我写的还不够具体,以后...
本程序是基于vc++开发环境的,实现bmp文件的打开与保存功能的一个程序
VB采用高密嵌入算法将文件隐藏到BMP文件中,打开BMP图片与信息文件,取得信息文件长度,从bmp中读取位图开始处,向BMP图片中写入信息长度,有无使用密码,保存位图开始处读写指针,写入信息时会用,跳到位图开始处,...
打开、保存位图文件,获取指定坐标的颜色值,目前支持 8位、24位位图
win32实现的画图,可对整个屏幕进行截图,有工具栏和调色板的子窗口,可进行一系列相关设置 可保存为bmp格式,并且可以打开 有橡皮功能
VS2005下的wince下打开和保存bmp文件,保存bmp文件为整个屏幕,打开bmp文件采用picture control,至于选择区域保存还未实现
VS2010 C++学习(2):BMP图像文件的结构分析、反色处理、平滑处理代码
打开一个bmp文件,在中心画一个圆,在保存如文件
能对图像文件(bmp、 jpg、 tiff、 gif等)进行打开、保存、另存、打印、退出等功能操作; 图像格式转换 缩放(有能力增加) 统计图像大小等 图像变换 二维离散傅里叶变换 二维离散余弦变换 图像增强 图像直方图 点...
使用vs2010,创建单文档,使用CImage可对bmp jpg 格式的文件进行打开 保存 放大 缩小操作!
vc对BMP文件的打开,显示,保存等操作。
BMP图的绘制和保存,EXCEL报表的导出,保存界面显示曲线图和保存功能,并有打开EXE文件的功能!
本代码用C++编写,能够读写位图文件(256色,24位)并提取RGB分量大小。没有利用MFC中的接口函数,对于理解BMP文件结构非常有用。
压缩文件提供: 1. bmp位图文件详细格式分析; 2. bmp位图文件打开,读取功能; 3. bmp位图文件写入,保存功能; 4. bmp位图文件显示到指定控件(如,picture控件上);