通过分析bmp图片的格式,可以完成BMP图片的打开和保存
一、bmp格式:
典型的BMP 图像文件由四部分组成:
1 .位图文件头数据结构,它包含BMP 图像文件的类型、显示内容等信息;
2 .位图信息数据结构,它包含有BMP 图像的宽、高、压缩方法,以及定义颜色等信息;
3.调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24 位的 BMP )就不需要调色板;
4.位图数据,这部分的内容根据BMP 位图使用的位数不同而不同,在 24 位图中直接使用 RGB ,而其他的小于 24 位的使用调色板中颜色索引值。
① BMP文件头 (14 字节 )
BMP文件头数据结构含有 BMP 文件的类型、文件大小和位图起始位置等信息。其结构定义如下:
intbfType; // 位图文件的类型,必须为 ' B '' M '两个字母 (0-1字节 ) intbfSize; // 位图文件的大小,以字节为单位 (2-5 字节 ) intbfReserved1; // 位图文件保留字,必须为 0(6-7 字节 ) intbfReserved2; // 位图文件保留字,必须为 0(8-9 字节 ) intbfOffBits; // 位图数据的起始位置,以相对于位图 (10-13 字节 ) |
② 位图信息头(40 字节 )
BMP 位图信息头数据用于说明位图的尺寸等信息。
intSize; // 本结构所占用字节数 (14-17 字节 ) intimage_width; // 位图的宽度,以像素为单位 (18-21 字节 ) intimage_heigh; // 位图的高度,以像素为单位 (22-25 字节 ) intPlanes; // 目标设备的级别,必须为 1(26-27 字节 ) intbiBitCount;// 每个像素所需的位数,必须是或1,4,8 24(// 真彩色 ) 之一 (28-29 字节) intbiCompression; // 位图压缩类型,必须是 0( 不压缩 ), 1(BI_RLE8 压缩类型 ) 或// 2(BI_RLE4 压缩类型 ) 之一 (30-33 字节 ) intSizeImage; // 位图数据的大小,以字节为单位 (34-37 字节 ) intbiXPelsPerMeter; // 位图水平分辨率,每米像素数 (38-41 字节 ) intbiYPelsPerMeter; // 位图垂直分辨率,每米像素数 (42-45 字节 ) intbiClrUsed;// 位图实际使用的颜色表中的颜色数 (46-49 字节 ) intbiClrImportant;// 位图显示过程中重要的颜色数 (50-53 字节 ) |
③ 颜色表
颜色表中的个数有 biBitCount 来确定。当biBitCount=1,4,8 时,分别有 2,16,256 个颜色 ; 当biBitCount=24 时,没有颜色表项。
在windows中每个颜色是 b g r a 四个字节保存,a代表透明度,如果是1位位图,那么颜色表一共站八个字节,如果是4位位图,颜色表站84个字节,如果是8位位图,需要表示256中颜色,每种颜色站四个字节,所以颜色表一共站1024个字节。
256色的时候,windows中,位图数据的大小就是0-255,代表着调色板中的数据,每次读八个为就是一个像素信息,其他位图类似。
④ 位图数据
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右, 扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1 时, 8 个像素占 1 个字节 ;
当biBitCount=4 时, 2 个像素占 1 个字节 ;
当biBitCount=8 时, 1 个像素占 1 个字节 ;
当biBitCount=24 时, 1 个像素占 3 个字节 ;
Windows规定一个扫描行所占的字节数必须是4 的倍数 ( 即以 long 为单位 ), 不足的以 0 填充,具体数据举例:
也就是说,写入图片一行的像素信息的时候,每一行的字节数都必须是4的倍数,不足的在后面补0,然后才又开始写入下一行的像素信息。
位图数据,其实就是在描述图片上每一个点的颜色,在windos中,是先写入该图片的最有一排像素点,从下往上,从左往右,没写完一排,如果写入的字节数不是4的倍数,就会补0,比如写入了3个字节,就不要再补一个字节的0,然后开始写下一排的数据。
对于单色位图,只需要一个位就可以表示其所有的颜色可能,黑白,对于16色位图,也就是有16中颜色的可能,那么需要四个位就可以表示16中可能,对于256色位图,那么需要8个位才能表示256中情况,对于真彩色,也就是表示所有的颜色,那么需要三个字节才可以表示所有情况(透明度不算),对于单色,16色,256色位图来说,位图数据读到的是调色板上的索引,通过这个索引在调试版中找到对应的颜色,然后显示在屏幕上。所以对于单色位图,他的调色板只有黑白两种颜色,16色位图,他的调色板有16种颜色,256色的调色板有256中颜色,如果是24位位图,他的位图信息,就是保存的真实颜色,每读三个字节就表示了一个像素点的颜色,不需要再进行调色板查找对应的颜色。
前言:windows中存入基本数据,是先存入了低位,再存入高位。
******************************************************************************************
首先完成打开一张bmp24位位图图片:
1、利用系统画图板画一张图片,保存的时候选择24位位图,由于24为位图没有调试板,位图数据区保存的是每个像素点的颜色,不需要我们进行调试板的转换,所有有利于初学者对于bmp格式的理解,完成了24位的再来看其他位图的。
2、利用swing写一个图形界面,中间留一个panel区域用于显示图片。将图片的每一个颜色保存到二维数组中,然后画在面板上,就打开了一张图片。
3、读取到图片的主要信息:
- File file = new File("d:\\8bit.bmp");
- FileInputStream fis = new FileInputStream(file);
- // 首先得到宽度和高度
- fis.skip(18);
- int width = myReadInt(fis);
- int height = myReadInt(fis);
- //由于24位位图没有调试板数据,所以现在已经已经读取了26个字节,再跳过28个字节就到了位图
- //数据区
- fis.skip(28);
- //再开始读取就是位图数据了,现在是24位位图,每读取三个字节就代表一个像素点的颜色,注意
- //windows在保存的时候是先保存的最后一排的数据,从下往上从左往右保存的,所以我们取出数
- //据只有需要保存的数组正确的位置。每次读取三个字节我们就转成颜色保存起来
- // 现在读取位图数据
- // 判断是否补零
- Color[][] colors = new Color[height][width];
- int sk = 0;
- if (width % 4 > 0) {
- sk = 4 - width % 4;
- }
- for (int h = image_heigh - 1; h >= 0; h--) {
- for (int w = 0; w < image_width; w++) {
- // dis.skipBytes(bfOffBits-60);
- // 读入三原色
- int blue = dis.read();
- int green = dis.read();
- int red = dis.read();
- Color color = new Color(red,green,blue);
- colors[h][w]=color;
- }
- // 跳过补0项,每次读取第一行就判断需要跳过的字节
- dis.skipBytes(sk);
- }
File file = new File("d:\\8bit.bmp"); FileInputStream fis = new FileInputStream(file); // 首先得到宽度和高度 fis.skip(18); int width = myReadInt(fis); int height = myReadInt(fis); //由于24位位图没有调试板数据,所以现在已经已经读取了26个字节,再跳过28个字节就到了位图 //数据区 fis.skip(28); //再开始读取就是位图数据了,现在是24位位图,每读取三个字节就代表一个像素点的颜色,注意 //windows在保存的时候是先保存的最后一排的数据,从下往上从左往右保存的,所以我们取出数 //据只有需要保存的数组正确的位置。每次读取三个字节我们就转成颜色保存起来 // 现在读取位图数据 // 判断是否补零 Color[][] colors = new Color[height][width]; int sk = 0; if (width % 4 > 0) { sk = 4 - width % 4; } for (int h = image_heigh - 1; h >= 0; h--) { for (int w = 0; w < image_width; w++) { // dis.skipBytes(bfOffBits-60); // 读入三原色 int blue = dis.read(); int green = dis.read(); int red = dis.read(); Color color = new Color(red,green,blue); colors[h][w]=color; } // 跳过补0项,每次读取第一行就判断需要跳过的字节 dis.skipBytes(sk); }
保存下来所有像素的颜色,就可以画在面板上了,面板的大小应该是图片的大小。
如果理解了文件格式含义,那么就可以尝试完成256色位图的打开和保存。
保存的时候,我们需要严格按照格式规定,写入正确的字节,如果是256色,需要进行颜色的转换:
下面是256色位图的打开:
说明:我先根据系统画图板的图片,保存一张256色图片,读取出了调调色板的数据,放在一个文件中
便于我在进行打开256色图片的时候,把位图数据读到的信息转成调色板对应的颜色,所以要完成下面的操作,请先自己
读取256色的调色板数据。把由于系统画图板,位图信息是0,代表的是第一个颜色,如果是255代表最后一个颜色,所以
我们可以把调色板数据放在一维数组中,利用下标来进行查找。
- // 打开256色,也就是8位表示一个像素点的颜色
- File file = new File("d:\\8bit.bmp");
- FileInputStream fis = new FileInputStream(file);
- // 首先得到宽度和高度
- fis.skip(18);
- int width = myReadInt(fis);
- int height = myReadInt(fis);
- // 现在流的位置,26
- // 再跳过12个字节,到达需要测试的数据区
- fis.skip(12);
- int biXPelsPerMeter = myReadInt(fis); // 位图水平分辨率,每米像素数 (38-41 字节
- // )
- int biYPelsPerMeter = myReadInt(fis); // 位图垂直分辨率,每米像素数 (42-45 字节
- // )
- int biClrUsed = myReadInt(fis);// 位图实际使用的颜色表中的颜色数 (46-49 字节 )
- int biClrImportant = myReadInt(fis);// 位图显示过程中重要的颜色数 (50-53 字节 )
- System.out.println("" + biXPelsPerMeter + " " + biYPelsPerMeter
- + " " + biClrUsed + " " + biClrImportant);
- // 由于是256色,所以颜色表是[256][4]大小的数组,每个分量占1个字节
- // 定义一个256的数组,保存下颜色表的数据
- Color[] colors256 = new Color[256];
- for (int i = 0; i < 256; i++) {
- colors256[i] = myReadColor(fis);
- System.out.println("颜色表" + colors256[i]);
- }
- // 现在读取位图数据
- // 判断是否补零
- int sk = 0;
- if (width % 4 > 0) {
- sk = 4 - width % 4;
- }
- DrawUI.array = newint[height][width];
- System.out.println("宽度" + width + "高度" + height);
- for (int i = height - 1; i >= 0; i--) {
- for (int j = 0; j < width; j++) {
- int index = fis.read();
- DrawUI.array[i][j] = colors256[index].getRGB();
- System.out.println("保存的值"+DrawUI.array[i][j]);
- }
- fis.skip(sk);
- }
- // 设置画布大小
- panel.setPreferredSize(new Dimension(width, height));
- // 重新绘制panel,如果是repaint,只会重新绘制原来panel中的内容,不会将panel更新大小
- SwingUtilities.updateComponentTreeUI(panel);
// 打开256色,也就是8位表示一个像素点的颜色 File file = new File("d:\\8bit.bmp"); FileInputStream fis = new FileInputStream(file); // 首先得到宽度和高度 fis.skip(18); int width = myReadInt(fis); int height = myReadInt(fis); // 现在流的位置,26 // 再跳过12个字节,到达需要测试的数据区 fis.skip(12); int biXPelsPerMeter = myReadInt(fis); // 位图水平分辨率,每米像素数 (38-41 字节 // ) int biYPelsPerMeter = myReadInt(fis); // 位图垂直分辨率,每米像素数 (42-45 字节 // ) int biClrUsed = myReadInt(fis);// 位图实际使用的颜色表中的颜色数 (46-49 字节 ) int biClrImportant = myReadInt(fis);// 位图显示过程中重要的颜色数 (50-53 字节 ) System.out.println("" + biXPelsPerMeter + " " + biYPelsPerMeter + " " + biClrUsed + " " + biClrImportant); // 由于是256色,所以颜色表是[256][4]大小的数组,每个分量占1个字节 // 定义一个256的数组,保存下颜色表的数据 Color[] colors256 = new Color[256]; for (int i = 0; i < 256; i++) { colors256[i] = myReadColor(fis); System.out.println("颜色表" + colors256[i]); } // 现在读取位图数据 // 判断是否补零 int sk = 0; if (width % 4 > 0) { sk = 4 - width % 4; } DrawUI.array = new int[height][width]; System.out.println("宽度" + width + "高度" + height); for (int i = height - 1; i >= 0; i--) { for (int j = 0; j < width; j++) { int index = fis.read(); DrawUI.array[i][j] = colors256[index].getRGB(); System.out.println("保存的值"+DrawUI.array[i][j]); } fis.skip(sk); } // 设置画布大小 panel.setPreferredSize(new Dimension(width, height)); // 重新绘制panel,如果是repaint,只会重新绘制原来panel中的内容,不会将panel更新大小 SwingUtilities.updateComponentTreeUI(panel);
下面的代码,保存256色位图的bmp图片,注意需要自己写入调色板,调色板的信息是按照b g r a的顺序写入,调色板字节
先要准备好。
- // 将图片保存为bmp格式
- File mysave256 = new File("d:\\mysave256bmp.bmp");
- FileOutputStream fos = new FileOutputStream(mysave256);
- // 先写bm
- fos.write('B');
- fos.write('M');
- int width = DrawUI.array[0].length;
- int height = DrawUI.array.length;
- int bu0 = 0;
- if (width * bit % 4 > 0) {
- bu0 = 4 - width * bit % 4;
- }
- int size = 14 + 40 + width * height * bit + bu0 * height;
- // 写入文图文件大小
- myWriteInt(fos, size);
- // 写入文件保留字
- myWriteShort(fos, (short) 0);
- myWriteShort(fos, (short) 0);
- // 位图数据起始位置,54 + 颜色表
- int beginweitu = 54 + 256 * 4;
- myWriteInt(fos, beginweitu);
- // 位图信息头
- // 写入写入信息大小
- myWriteInt(fos, 40);
- // 写入宽度和高度
- myWriteInt(fos, width);
- myWriteInt(fos, height);
- // 写入级别
- myWriteShort(fos, (short) 1);
- // 每个像素所需的位数
- myWriteShort(fos, (short) 8);
- // 位图压缩类型
- myWriteInt(fos, 0);
- // 位图数据的大小
- int wsize = width * height + bu0 * height;
- myWriteInt(fos, wsize);
- // 保留的字节
- myWriteInt(fos, 0);
- myWriteInt(fos, 0);
- myWriteInt(fos, 0);
- myWriteInt(fos, 0);
- // 开始写入调色板
- FileInputStream fiscolor = new FileInputStream(fcolor256);
- // 得到调试板数组,用于转换
- HashMap hm = new HashMap();
- for (int i = 0; i < 256; i++) {
- int b = fiscolor.read() & 0xff;
- int g = fiscolor.read() & 0xff;
- int r = fiscolor.read() & 0xff;
- int a = fiscolor.read() & 0xff;
- Color colora =new Color(r,g,b) ;
- hm.put(colora.getRGB(),i );
- fos.write(b);
- fos.write(g);
- fos.write(r);
- fos.write(a);
- }
- fiscolor.close();
- // 开始写入位图数据,从最后一行从下往上输入
- int b0 = 0;
- if (width % 4 > 0) {
- b0 = 4 - width % 4;
- }
- int yuan = 0;
- int zhuan = 0;
- for (int i = height - 1; i >= 0; i--) {
- for (int j = 0; j < width; j++) {
- if(DrawUI.array[i][j]!=-1){
- System.out.print(DrawUI.array[i][j]+" ");
- }
- yuan = DrawUI.array[i][j];
- try{
- zhuan =(Integer) hm.get(yuan);
- }catch (Exception e2){
- zhuan=0;
- }
- fos.write(zhuan);
- }
- System.out.println();
- for (int k = 0; k < b0; k++) {
- fos.write(0);
- }
- }
- fos.flush();
- fos.close();
- publicvoid myWriteInt(OutputStream os, int num) throws IOException {
- int a = num & 0xff;
- int b = (num >> 8) & 0xff;
- int c = (num >> 16) & 0xff;
- int d = (num >> 24) & 0xff;
- os.write(a);
- os.write(b);
- os.write(c);
- os.write(d);
- os.flush();
- }
- publicvoid myWriteShort(OutputStream os, short num) throws IOException {
- int a = num & 0xff;
- int b = (num >> 8) & 0xff;
- os.write(a);
- os.write(b);
- os.flush();
- }
相关推荐
BMP图片格式解析 BMP图片格式是当前计算机图形系统中最为常用的图像文件格式之一。它是由微软公司开发的,用于存储位图图像的文件格式。该格式的文件通常以“.bmp”结尾。 BITMAPFILEHEADER结构体是BMP图片文件的...
### BMP 图片格式解析知识点 #### 一、BMP 文件格式简介 BMP(Bitmap Image File Format)是一种用于存储位图图像的文件格式,由Microsoft公司设计,主要用于Windows操作系统。BMP格式支持单色和彩色图像,并且...
"BMP 图像格式详解" BMP 图像格式是与硬件设备无关的图像文件格式,使用非常广泛。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP 文件所占用的空间很大。BMP 文件的图像深度可选 ...
首先,BMP是一种常见的位图图像格式,全称为Bitmap,广泛应用于Windows操作系统中。它以未经压缩的原始像素数据存储图像,因此文件体积相对较大,但易于处理。在实现OSD叠加时,BMP图片作为静态资源,可以用来展示...
BMP图片解析软件是一款专注于处理8位、16位和24位BMP图像格式的应用程序。BMP,全称为Bitmap,是一种无损的位图文件格式,广泛用于Windows和Microsoft Office等系统中。该软件目前的功能限制在于仅能解析这三种位...
本主题涉及的是一个名为“灰度256X256_BMP图片”的资源,这是一张256x256像素大小的灰度图像,采用BMP(Bitmap)格式存储。下面我们将深入探讨相关的知识点。 1. **灰度图像**:灰度图像,又称单色图像或强度图像,...
本项目" BMP图片解析C程序 "是一个C语言编写的程序,专门设计来读取BMP文件,并将其内容显示在LCD(Liquid Crystal Display)屏幕上。此外,该程序还具有生成缩略图的功能,这对于资源有限的设备或者需要高效处理...
在计算机图形处理中,将BMP图片解析为RGB(Red, Green, Blue)三原色模式是基础且重要的步骤,因为RGB是数字图像处理中广泛使用的颜色模型。本文将深入探讨BMP文件的结构以及如何将其解析为RGB模式。 首先,理解BMP...
总之,"PNG图片转换成BMP图片格式"是一个常见的图像处理需求,这个工具简化了这个过程,使得用户可以轻松地在两种格式之间切换,适应不同的应用场景。在日常工作中,理解这两种格式的特点和转换原理,有助于我们更好...
// 存为bmp格式图片 ``` 使用`imwrite`函数将内存中的图像矩阵保存为BMP格式的文件。 #### 7. 清理资源 ```cpp fclose(fp); return 0; ``` 最后关闭文件指针并返回0表示程序正常结束。 ### 总结 通过上述代码...
在图像处理领域,RAW 和 BMP 是两种常见的图片格式。RAW 格式通常由数码相机直接生成,包含了未经处理的原始像素数据,而 BMP(Bitmap)是 Windows 操作系统下的标准位图格式,易于读写和显示。本篇将详细介绍如何...
在C语言中,图片格式转换通常需要解析图片文件的头部信息,然后读取像素数据并重新编码。PNG和JPEG都是压缩格式,而BMP是未压缩的,因此在转换过程中需要解压前两者,并将解压后的像素数据保存到BMP文件中。 3. **...
使用这个工具类,你可以方便地读取各种颜色深度的BMP图片,将其转换为Java可以操作的图像对象。在实际应用中,你可能还需要考虑图像的旋转、缩放、裁剪等几何处理,以及颜色空间转换、滤波等图像处理操作。这些都是`...
### 图片格式解析:JPEG, BMP, PNG, GIF #### JPEG 文件结构 JPEG(Joint Photographic Experts Group)是一种广泛使用的图像文件格式,特别是在处理需要压缩的高质量照片时。JPEG 文件结构由八个主要部分组成,每...
本教程将专注于一个特定的转换过程:将10位的CCD纯数据格式RAW文件转化为8位的BMP格式文件。首先,我们需要理解这两种格式的基础知识。 **RAW格式**: RAW图像格式是一种未经处理的数据格式,它直接记录了相机...
要实现“将DICOM格式转换为BMP格式图片”,你需要理解以下几个关键知识点: 1. DICOM文件解析:首先,你需要理解DICOM文件的结构,包括其头文件(Header)和像素数据(Pixel Data)。DICOM头文件包含了元数据,如...
一、BMP文件分析 1. 什么是BMP(位图)? 常见的图像文件格式有:BMP、JPG...BMP格式的图片,没有使用任何压缩算法,这种方式在以前使用的比较多,现在用的就比较少了,不过为了学习图像处理算法,所以先以该种格式的文
标题中的“DEM输出为BMP格式图片”是指将数字高程模型(Digital Elevation Model,简称DEM)数据转换成位图图像(Bitmap,通常表示为BMP)的过程。这一过程通常涉及地理信息系统(Geographic Information System,...