- 浏览: 13943 次
- 性别:
最新评论
简单的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 1349线程的同步通信与线程范围内的数据共享问题一、线程的同步通信 什 ... -
多线程初谈——线程的创建与互斥问题
2013-10-01 18:13 1441多线程初谈——线程的创建与互斥 对于线程起初也很是不 ... -
网络通信见解之谈
2013-07-17 13:38 658一、网络通信的基本原理 现如今,出现了各式各样的聊天平 ... -
分形浅谈——科赫曲线和L-System
2013-06-24 22:47 1261分形浅谈开始接触到分行图时,感觉很难,无法下手,只能做出第一层 ... -
对关键字final、static的理解
2013-05-10 23:36 574一、final关键字 fin ... -
对关键字的理解——访问权限
2013-05-10 16:17 627关键字public、pr ... -
队列的定义及运用
2013-03-23 14:58 728队列简称队,是限制在表的一端进行插入操作,而在表的另一端进行删 ... -
重绘方法的重写利用
2013-03-22 21:44 649重绘是为了在画布上保留原始痕迹的一种方法,他的目的是用来保存你 ... -
数组的定义及递归的运用
2013-03-22 21:43 1056一、数组有一维数组、 ... -
监听器与变量的作用域
2013-03-22 21:41 737监听器是用来实现一些可控操作的工具,如你在打开一个QQ界面的时 ... -
java中的继承
2013-03-08 00:31 589Java中的接口 什么是接口?不是以class定义的类而是以i ... -
Java中类的继承、重写、自动转型以及多态
2013-03-06 01:13 748Java中类的继承、重写、自动转型以及多态 1) 类的继承 在 ... -
java的构造器方法、方法重载和引用传递
2013-03-04 23:55 766Java的构造器方法、方法重载与引用传递 一、 构造器方法 构 ... -
JAVA语言中的类与对象
2013-03-04 00:08 763Java语 ...
相关推荐
- 打开文件:使用C语言的`fopen`函数打开BMP文件,通常以二进制模式("rb")进行读取。 - 读取文件头:提取文件类型的标识(如'BM'),确保文件是BMP格式。然后读取文件大小和其他字段,确认文件完整。 - 读取...
首先,你需要打开文件并读取文件头以确认它是BMP文件,然后读取信息头以获取图像的尺寸和颜色深度。数据区的读取则根据颜色深度(8位灰度、24位RGB等)进行相应的解码。 4. **BMP保存** 保存BMP文件时,你需要创建...
读取BMP文件,我们需要打开文件,然后按照BMP文件的结构逐个读取这些部分。C++中可以使用`ifstream`类来实现文件的读取。例如: ```cpp ifstream file("image.bmp", ios::binary); ``` 接着,我们定义结构体来表示...
保存修改后的BMP文件则与读取过程相反: 1. 创建新的位图信息头:根据修改后的图像尺寸和颜色深度生成新的位图信息头。 2. 写文件头:将新的文件头写入输出文件。 3. 写位图信息头:接着写入修改后的位图信息头。 4...
在VC++编程环境中,将图像保存为BMP文件是一个常见的任务,这通常涉及到Windows图形设备接口(GDI)和GDI+的使用。BMP是一种位图文件格式,它存储了像素数据和图像的元信息,如宽度、高度、颜色深度等。下面,我们将...
总的来说,自制画板打开和保存BMP格式文件涉及到的知识点包括:BMP文件格式的理解与解析,二进制文件操作,图像处理基础,GUI编程,以及事件驱动编程。这个项目既能够加深对图像文件格式的理解,也能锻炼实际编程...
在深入学习BMP文件的读取与保存时,我们需要了解以下几个关键知识点: 1. BMP文件结构:BMP文件分为文件头和图像数据两部分。文件头包括BITMAPFILEHEADER和BITMAPINFOHEADER,它们分别存储了文件的基本信息和图像的...
接着,使用`ifstream`类打开BMP文件进行读取,通过`read`函数读取文件头和位图信息头的数据,解析出图像的尺寸和颜色深度。然后,读取像素数据到二维数组或自定义的图像类中。 读取BMP文件的代码示例: ```cpp ...
这行代码会尝试打开指定路径的BMP文件,如果成功,图像数据将存储在`image`对象中。 4. **读取BMP图像数据** 读取BMP图像的数据包括获取图像的尺寸、颜色深度、以及访问像素值。可以通过`GetWidth()`和`GetHeight...
要将预览的图像保存为BMP文件,我们需要理解BMP文件格式,它是一个未经压缩的位图格式,包含图像的宽度、高度、色彩深度和像素数据。可以使用GDI+或者Windows API函数来创建BMP文件。首先,截取屏幕或MDI子窗口的...
- **保存文件**:同样地,程序可以将修改后的图像保存为新的BMP文件,这可能使用了`CreateObject`或`SavePicture`函数来完成文件写入。 4. **图形绘制**:VB6.0提供了Graphics对象,通过它可以实现对图像的绘制。...
首先,我们需要打开BMP文件并读取其头部信息,以获取图像的尺寸和色彩深度。然后,我们可以逐行读取像素数据,根据色彩深度转换成相应的颜色值。如果是灰度图转换,只需将红、绿、蓝三个分量取平均即可。 保存BMP...
总之,实现BMP文件的打开与预览功能,需要对图像文件格式有深入理解,熟悉至少一种编程语言的图像处理库,并且掌握基本的图形界面开发技巧。这样的功能对于图像处理软件、设计工具或是文件管理应用都是必不可少的,...
在本文中,我们将深入探讨如何使用C++编程语言来实现BMP图像的打开、保存以及24位到8位色彩深度的自动转换。 BMP(Bitmap)是微软开发的一种位图图形文件格式,常用于Windows操作系统。C++是编程中常用的高级语言,...
标题"打开和保存bmp图片的小程序"暗示我们要实现的功能是读取BMP文件的内容并将其显示出来,同时还能将用户编辑的图像保存为BMP格式。DIB句柄在此过程中起着至关重要的作用,因为它提供了与硬件无关的方式来表示图像...
8. **显示或保存图像**:读取并处理完BMP文件后,我们可以选择在控制台输出相关信息,或者将像素数据写入新的BMP文件,甚至可以利用图形库如OpenGL或SDL显示图像。 9. **异常处理**:在读取和处理文件时,应考虑到...
根据提供的文件信息,本文将详细解释BMP格式图像的读取与保存的相关知识点,包括BMP文件的基本结构、如何读取BMP文件以及如何保存BMP文件等内容。 ### BMP文件基本结构 BMP(Bitmap Image File Format)是一种常见...
本篇介绍了一个简单的C++函数,用于将内存中的RGB图像数据保存为BMP文件。该函数首先构建了BMP文件头和位图信息头,然后将这些数据写入新创建的文件中,最后关闭文件完成保存过程。理解BMP文件格式和掌握如何使用C/...
5. 保存修改后的BMP文件:最后,将修改后的BMP文件保存,这样一个看似普通的图片文件就包含了隐藏的ExE文件。 标签中的“黑客”表明这种技术可能与网络安全相关,可能是为了隐藏恶意软件或者进行隐私保护。而"bmp...
在VC++环境下,开发人员经常需要处理BMP文件的读取和写入操作,以便在应用程序中显示或保存图像。以下是一些关于如何在VC++中进行这些操作的关键知识点: 1. **BMP文件结构**: - BMP文件由一个文件头(File ...