`
liguanyi11111
  • 浏览: 62523 次
  • 性别: Icon_minigender_1
  • 来自: 黑龙江
社区版块
存档分类
最新评论

bmp图片的打开与保存(画图板的基础)

 
阅读更多

        花了将近5个小时的努力。才完成了这项对我来说算是蛮艰难的任务。bmp格式图片的打开与保存,首先要先了解格式究竟是什么东西。曾经天真的认为,格式嘛。就是文件后缀而已。确实,很多人都喜欢把文件后缀叫做格式。而经过学习之后,那个后缀充其量只能叫做格式的名字。就像人的名字一样,张三李四,只不过是一个称呼。对本身没有任何限制。你可以叫张三,别人也可以。但是你究竟还是你,不会变成别人。对于文件一样,后缀只不过是让其他软件认识他是谁,好对应其使用相应的解码方式,对文件不会产生影响。例如一个txt的记事本文件,将其后缀改为MP3,他也不可能变成一首歌,他依旧还是那个记事本。只不过,软件以为他是一首歌。就例如你用了别人的名字,那个人的朋友认为你就是他了,来找你玩,结果见了面发现根本不认识你,也就玩不成了。所以说格式是一种内在的东西,一种本质,一种数据的构成方式。就像每个人都有不同的长相啊、身高啊等等等等的一系列不同,但是他仍然是基本的几十个化学元素构成的一个整体而已。文件也是一样的,组成他的“元素”更少,仅仅是0和1,或者说是字节也可以。大量化学元素组成了一个细胞,大量的细胞有组成了组织,组织又组成了……,最后成为一个完整的人体。所以说这种组成不可能是随机的,而都是按照一种方式在组合。而这种组成方式就叫做他的格式。对于文件,格式也就是文件所蕴含的大量字节的组成方式,和所代表的含义。说了这么多,就为了更形象的解释一下格式所谓的含义,下面进入正题。

        既然已经明白了格式既是一种组成的规律与方法,那么下面我们就要了解,bmp这个图片格式中各个字节所代表的含义,和他们是如何组成为一张图片的。首先,bmp图片是由四大部分所组成的,分别为:文件头、信息头、颜色表、图像数据。(下面为基本介绍,详细数据请百度“bmp”)

1、文件头中含有BMP文件的类型、文件大小和位图起始位置等信息。共有14个字节。

2、信息头中含有位图的尺寸等信息。共40个字节。

3、颜色表是用于说明位图中的颜色,简单来说就是指这个bmp图片中会用到的颜色个数。(由于我的程序使用24位bmp图片,就是使用全部RGB颜色,所以没有颜色表这一项)

4、图像数据即用于保存图像中各个点的颜色的数据。

         由此我们现在就可以开始研究bmp的打开与保存了。首先,先研究如何打开一个bmp图片。再此,要先回忆一下画图板上用数组保存和画出一张图片的方法。即使用二维数组将画好的图片上相应坐标的点的颜色RGB用int类型保存起来。然后遍历这个数组,就可以在相应的坐标点处获取到颜色,就可以画出图像了。所以打开一个bmp图片,我们要做的就是将图片转化为我们所知的那个二维int数组。既然要创建一个二维数组,就要知道这个二维数组的高宽长度各是多少。这时,我们回到bmp的信息头数据那里发现,bmp图片里的相应位置已经给我记录好了这二个值。LONG biWidth; // 位图的宽度,以像素为单位(18-21字节) 和LONG biHeight; // 位图的高度,以像素为单位(22-25字节) 。所以我们只要取得这两个值了就可以创建数组了。但是这里又有个问题,这两个数据是以字节的形式记录的,并不是我们要用的int值。虽然java中有相应的方法把读取的4个字节读取成为一个int。但是这个方法是将从高位写起,即将第一个字节作为int中的高八位,然后依次向后排,形成一个int。而在bmp中,int值是从最低位开始储存的,正好与其相反。所以我们要专门写一个转化方法,来用于我们的代码中。我写的如下(其中“by”要传入:用 从文件中读出的一系列字节 所组成的 byte类型的数组,start表示的为从这个数组的下标为start的字节开始读取,截取四个组成一个int值)

// 把byte转换为int的方法
	public int turnInt(byte[] by, int start) throws EOFException {
		int ch1 = by[start] & 0xff;
		int ch2 = by[start + 1] & 0xff;
		int ch3 = by[start + 2] & 0xff;
		int ch4 = by[start + 3] & 0xff;
		return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0));
	}

 这样,我就可以获取到我所想要的图像二维数组的大小,也就是这个图片的高和宽了(以下代码所用的文件流建议为缓冲流,否则读取和存储可能会比较缓慢)。

int width = turnInt(by, 4); // 位图宽度
int height = turnInt(by, 8); // 位图高度

 

下一部,也就是要把我们已经建立好的二维数据添加进相应的颜色数据。在24位bmp图片中,每一个像素点由3个字节组成,分别储存着颜色值中的B、G、R三个数据。所以我们要建立三个刚才的二维数组分别储存这三中颜色。然后把从文件中读取到的值分别传给他们。

if ((width * 3) % 4 != 0) { // 判断是否后面有补0 的情况
	wid = 4 - (width * 3) % 4;
}
// 装载颜色数据二维数组
int[][] R = new int[height][width];
int[][] G = new int[height][width];
int[][] B = new int[height][width];
// 循环加入数据
for (int i = height - 1; i >= 0; i--) {
	for (int j = 0; j < width; j++) {
		int blue = bis.read();
		int green = bis.read();
		int red = bis.read();
		B[i][j] = blue;
		G[i][j] = green;
		R[i][j] = red;					
	}
	bis.skip(wid);
}

 

细心看的人不难发现,我写的这个代码中出现了一个判断语句,一个wid变量和一个skip(wid)方法。下面我就要解释一下这写代码的作用何在。在bmp的保存中,有一项规定(我也不知道为什么有这项规定),就是在图像的横向即宽度大小(以字节为单位)必须要被4所整除,不能被4整除的就要在每一行的末尾添加0来补位,以便使其可以被4整除。例如,这一行一共有150个像素(宽度为150),那么就有150x3=450个字节。450/4=112……2那么就要补充4-2=2个字节。所以就有了上述wid这个int类型的变量,就是计算要补充的字节数。一遍在读取颜色数据时将不充的0也读取进取,轻则图像发生倾斜,重则整个图像的颜色都会发生混乱。最后,有了这些颜色数组,我们就可以轻易画出一个图片来了。

for (int i = 0; i < height; i++) {
	for (int j = 0; j < width; j++) {
	                g.setColor(new Color(R[i][j], G[i][j], B[i][j]));
		g.fillOval(j, i, 1, 1);
	}
}

 

现在bmp图片的打开就基本完成了。下面我要再来说一下把自己画图板上的图片返过来保存成一个bmp格式的图片。其实只不过将打开的方法倒过来,写入进文件中就可以了。但是要注意,打开中有大量的数据并没有使用,但是在保存中我们却仍然要将其全部写入正确的位置。首先是文件头的写入:

// 存入bmp文件头数据(14字节)*******************
oos.write((byte) 66); // B
oos.write((byte) 77); // M
// 位图文件的大小
int size=(4-(w*3)%4)*h+h*w*3+54;
oos.write(turnByte((int) size));// 2-5字节 一个int
// 保留字
oos.write(0);
oos.write(0);
oos.write(0);
oos.write(0); // 6-9 4个字节
// 位图的起始位置(第54字节)
  oos.write(turnByte((int) 54)); // 10-13 4个字节

 

其中size为本文件的大小。即为:(所保存图片的)高度x宽度x3+每一行所补充的0的个数x行数(高度)+54(文件头+信息头)。然后写入信息头。这时,我们有碰到了与刚刚类似的问题,就是将一个int值转换为4个byte的值。就将刚刚的方法到过来就可以了。

// 把int转换为4个byte的方法
public byte[] turnByte(int a) {
                byte[] by = new byte[4];
	for (int i = 0; i < 4; i++) {
		by[i] = (byte) ((a >>> (8 * i)) & 0xFF); // 将int从低8位到高8位加入到byte数组中
	}
	return by;
}

 

然后写入信息头中的相应数据:

// 存入bmp信息头数据(40字节)********************
oos.write(turnByte((int) 40)); // 14-17 4个字节 本结构所占用字节数
oos.write(turnByte(w)); // 18-21 4个字节 图片宽度
oos.write(turnByte(h)); // 22-25 4个字节 图片高度
oos.write((byte) 1);
oos.write((byte) 0); // 26-27 2个字节 必须1
oos.write((byte) 24);
oos.write((byte) 0); // 28-29 2个字节 必须24
oos.write(turnByte((int) 0)); // 30-34 4个字节 必须0	
oos.write(turnByte((int) (size-54))); // 34-37 4个字节 位图的大小,以字节为单位
oos.write(turnByte((int) 4000)); // 38-41 4个字节 位图水平分辨率,每米像素数,默认4000
oos.write(turnByte((int) 4000)); // 42-45 4个字节 位图垂直分辨率,每米像素数
oos.write(turnByte((int) 0)); // 46-49 4个字节 位图实际使用的颜色表中的颜色数(全选)
oos.write(turnByte((int) 0)); // 50-53 4个字节 位图显示过程中重要的颜色数(都重要)

 

然后就是图像信息了(24位位图,不写颜色表),跟上述同理,将颜色值分成B,G,R三个数据一次存入,并在每一行结尾处补0.

int wid=0;
		if ((w * 3) % 4 != 0) { // 判断是否后面有补0 的情况
			wid = 4 - (w * 3) % 4;
		}
		for(int i=h-1;i>=0;i--){
			for(int j=0;j<w;j++){
				Color c=new Color(aa[i][j]);
				oos.write((byte)c.getBlue());
				oos.write((byte)c.getGreen());
				oos.write((byte)c.getRed());				
			}
			for(int j=0;j<wid;j++){
				oos.write((byte)0);
			}
		}
		
		
		//关闭流
		oos.flush();
		oos.close();

 

由于是从内存中保存到硬盘中,所以flush非常重要,否则会缺少很多数据。这时bmp的保存也已经完成了。

         好了,到此为止。24位bmp的保存与打开已经基本完成了。以后我可能还会对其进行相应的完善,但都是后话了。

分享到:
评论

相关推荐

    画图板_Vc_

    “打开保存图片文件”功能,可以使用Windows API中的LoadImage和SaveImage函数来读写BMP或其他图像格式。如果支持更多格式,可能需要引入第三方库,如libpng或FreeImage。 总的来说,这个“画图板”项目涵盖了GUI...

    win32画图程序 可保存bmp 截图

    在本文中,我们将深入探讨如何使用Win32 API在C++环境下实现一个简易的画图程序,该程序具有截图、工具栏、调色板、橡皮擦功能,并能保存图片为BMP格式。首先,我们需要了解Win32 API的基础知识。 Win32 API是微软...

    仿XP画图板

    5. **文件操作**:保存和打开图像文件是画图板的重要功能。JAVA提供了文件I/O流,使得开发者能够读写BMP、PNG等图像文件格式。 6. **颜色选择器**:实现颜色选择器可能需要自定义组件或使用已有的库,允许用户选取...

    VC++实现简单的画图板程序

    在本项目中,"VC++实现简单的画图板程序"是一个基础级别的计算机图形学应用,主要目的是让初学者了解如何使用Microsoft Visual C++ (VC++) 编程环境来创建一个功能丰富的图形用户界面(GUI)应用程序。这个程序允许...

    仿windows画图板

    5. **OpenFileDialog/SaveFileDialog**:提供打开和保存图片的对话框。 6. **TrackBar/ScrollBar**:可能用于调整画笔大小或透明度。 实现这些功能需要掌握以下VB编程概念和技术: 1. **事件驱动编程**:用户与...

    MFC 简易画图板

    考虑到保存和加载绘图的功能,可以实现`OnFileSave`和`OnFileOpen`函数,将当前的绘图序列化存储到文件中(如BMP或SVG格式),并在打开文件时反序列化并重新绘制。 通过以上步骤,我们可以构建一个功能完备的MFC...

    windows画图板程序源码

    《Windows画图板程序源码解析与探讨》 在计算机编程领域,Windows画图板程序是一种常见的学习和实践窗口应用程序设计的案例。本篇文章将深入剖析"windows画图板程序源码",揭示其背后的原理和技术,以帮助读者更好...

    用C#做的一个画图板工具,可以打开图片在其上画圆,矩形,三角形,直线等,实现看鼠标拖拽画图,可任意选择颜色级画刷类型,可保存为BMP格式

    用C#做的一个画图板工具,可以打开图片在其上画圆,矩形,三角形,直线等,实现看鼠标拖拽画图,可任意选择颜色级画刷类型,可保存为BMP格式

    C#画图板程序

    - **保存(Save)**:程序可能提供保存当前画布为图片文件的功能,如BMP、JPEG或PNG格式。这需要用到`Bitmap`类的`Save`方法。 - **打开(Open)**:允许用户加载先前保存的图片继续编辑,这需要读取文件内容并...

    C# Winform画图板

    8. **图片的打开与保存**: - 使用`OpenFileDialog`控件让用户选择要打开的图片文件,然后通过`Image.FromFile`加载图片到`PictureBox`控件。 - `SaveFileDialog`控件用于保存用户的绘图作品,可以将其保存为BMP、...

    VB画图板 用户图形界面设计

    7. **保存和加载**:为了保存用户的画作,开发者可能实现了保存(SaveFileDialog)和加载(OpenFileDialog)功能,将图片以位图(.bmp)或JPEG等格式保存到硬盘,并能重新打开继续编辑。 8. **控件布局**:使用布局...

    GDI+画图板程序

    本项目是一个使用GDI+编写的画图板程序,对于想要学习GDI+基础和实践操作的人来说,这是一个很好的起点。 GDI+的主要功能包括: 1. **图形绘制**:GDI+提供了丰富的绘图工具,如线条、曲线、矩形、椭圆、多边形等...

    画图板C++写的代码

    7. **保存/加载**:实现保存用户绘制的图形为图片文件(如BMP、PNG或JPEG格式),并支持打开已保存的文件。 8. **菜单和对话框**:添加文件菜单,允许用户打开、保存、退出等操作,还可以添加颜色选择、形状选择等...

    C++画图板 画图工具

    在这个"画图板"应用中,MFC的CView类被用来作为画布的基础,它是所有视图类的基类。开发者可能扩展了CView类,创建了一个自定义的派生类,增加了绘制、选择颜色、撤销/重做等特定于画图的功能。CView类处理WM_PAINT...

    仿照win的简易画图板

    7. **保存与打开**:保存功能将用户的绘图数据以图像文件格式(如BMP、JPEG或PNG)存储,而打开功能则能加载已有的图像文件,继续编辑。这涉及到文件I/O操作和图像编码解码技术。 8. **透明效果**:虽然这个简易...

    用EVC4.0开发的画图板

    本篇文章将详细探讨如何使用EVC4.0来开发一个简单的画图板程序,该程序具备打开和保存BMP图像文件的能力。 首先,让我们了解EVC4.0。EVC4.0是针对Microsoft Windows CE和Pocket PC等嵌入式平台的C++编译器和开发...

    仿 XP 系统画图板

    5. **图像处理**:除了基本的绘图操作,可能还涉及到图像的保存和打开功能,这需要对JAVA的I/O流和图像处理类库(如`java.awt.image.BufferedImage`)有深入理解,以便读写图片文件,如BMP、JPEG或PNG格式。...

    基于VC++MFC程序设计——简易画图板

    该画图板的主要功能包括但不限于图形的绘制、线型与颜色的设置、图形文件的重绘及保存等。 #### MFC与VC++简介 1. **VC++6.0:** - VC++6.0是微软发布的一款在Windows平台上的强大C++编译器。 - 它提供了高级的...

    类似画图板的小程序-windows

    功能主要有: 手绘线、简单图形、文字输入、图块拖放、重复撤销、画面缩放、打开保存图片文件,另外为了直接从数据库或者XML中存取图片,另外还提供了从Base64编码存取图片的接口,其他还实现了和画图板同样效果的...

    vc++画图板(计算机图形学)

    在这个项目中,“vc++画图板(计算机图形学)”是一个基于Microsoft Visual C++(简称VC++)编写的简易画图应用程序,旨在帮助用户理解和实践计算机图形学的基本概念和技术。 VC++是一种强大的集成开发环境,它支持...

Global site tag (gtag.js) - Google Analytics