BMP图像解析
BMP是一种与硬件设备无关的图像文件格式,使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此, BMP 文件所占用的空间很大。 BMP 文件的图像深度可选 lbit 、 4bit 、 8bit 及 24bit 。 BMP 文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。 由于 BMP 文件格式是 Windows 环境中交换与图有关的数据的一种标准,因此在 Windows 环境中运行的图形图像软件都支持 BMP 图像格式。
要解析文件,就必须知道他的文件结构:
6.3.1 BMP文件结构
典型的BMP 图像文件由四部分组成:
1 . 位图文件 头数据结构 ,它包含BMP 图像文件的类型、显示内容等信息;
2 .位图信息数据结构 ,它包含有BMP 图像的宽、高、压缩方法,以及定义颜色等信息;
3. 调色板 ,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24 位的 BMP )就不需要调色板;
4. 位图数据 ,这部分的内容根据BMP 位图使用的位数不同而不同,在 24 位图中直接使用 RGB ,而其他的小于 24 位的使用调色板中颜色索引值。
6.3.2对应的数据结构
① BMP文件头 (14 字节 )
BMP文件头数据结构含有 BMP 文件的类型、文件大小和位图起始位置等信息。其结构定义如下:
int bfType; // 位图文件的类型,必须为 ' B '' M '两个字母 (0-1字节 ) int bfSize; // 位图文件的大小,以字节为单位 (2-5 字节 ) int bfReserved1; // 位图文件保留字,必须为 0(6-7 字节 ) int bfReserved2; // 位图文件保留字,必须为 0(8-9 字节 ) int bfOffBits; // 位图数据的起始位置,以相对于位图 (10-13 字节 ) |
② 位图信息头(40 字节 )
BMP 位图信息头数据用于说明位图的尺寸等信息。
int Size; // 本结构所占用字节数 (14-17 字节 ) int image_width; // 位图的宽度,以像素为单位 (18-21 字节 ) int image_heigh; // 位图的高度,以像素为单位 (22-25 字节 ) int Planes; // 目标设备的级别,必须为 1(26-27 字节 ) int biBitCount;// 每个像素所需的位数,必须是 1(双色),(28-29 字节) 4(16 色 ) , 8(256 色 ) 或 24(// 真彩色 ) 之一 int biCompression; // 位图压缩类型,必须是 0( 不压缩 ),(30-33 字节 ) 1(BI_RLE8 压缩类型 ) 或// 2(BI_RLE4 压缩类型 ) 之一 int SizeImage; // 位图的大小,以字节为单位 (34-37 字节 ) int biXPelsPerMeter; // 位图水平分辨率,每米像素数 (38-41 字节 ) int biYPelsPerMeter; // 位图垂直分辨率,每米像素数 (42-45 字节 ) int biClrUsed;// 位图实际使用的颜色表中的颜色数 (46-49 字节 ) int biClrImportant;// 位图显示过程中重要的颜色数 (50-53 字节 ) |
③ 颜色表
颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD 类型的结构,定义一种颜色。
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 时,没有颜色表项。
位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下 :
class BITMAPINFO { BITMAPINFOHEADER bmiHeader; // 位图信息头 RGBQUAD bmiColors[1]; // 颜色表 } |
④ 位图数据
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右, 扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1 时, 8 个像素占 1 个字节 ;
当biBitCount=4 时, 2 个像素占 1 个字节 ;
当biBitCount=8 时, 1 个像素占 1 个字节 ;
当biBitCount=24 时 ,1 个像素占 3 个字节 ;
Windows规定一个扫描行所占的字节数必须是4 的倍数 ( 即以 long 为单位 ), 不足的以 0 填充,具体数据举例:如某BMP 文件开头: 424D 4690 0000 0000 0000 4600 0000 2800 0000 8000 0000 9000 0000 0100*1000 0300 0000
0090 0000 A00F 0000 A00F 0000 0000 0000 0000 0000*00F8 E007 1F00 0000*02F1 84F1
04F1 84F1 84F1 06F2 84F1 06F2 04F2 86F2 06F2 86F2 86F2 .... ....
BMP 文件可分为四个部分:位图文件头、位图信息头、彩色板、图像数据阵列,在上图中已用 * 分隔。 比方说,我们就可以做一个BMP图片的查看器 (暂时只做24位BMP图像解析器,大多数BMP图像也是2位):
package data0605_bmp; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.UIManager; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.filechooser.FileNameExtensionFilter; /* * bmp文件读取保存 */ public class Projiect extends JFrame{ int map[][];//保存像素颜色的数组 MyPanel center;//绘图面板 File selectFile;//读取的文件 int width;//图像宽度 int height;//图像高度 byte temp1[];//读取BMP文件的前18个字节信息 byte temp2[];//读取BMP文件的后28个字节信息 JScrollPane scrollpane;//滚动面板 public Projiect() { //观感必须为main方法的第一个操作,否则可能不起作用 try { UIManager .setLookAndFeel(new com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel()); } catch (Exception e) { e.printStackTrace(); } this.setLayout(new BorderLayout());//最好先设置布局再添加组件 //初始化画图面板 center=new MyPanel(); center.setBackground(Color.WHITE); center.setPreferredSize(new Dimension(400,200)); scrollpane=new JScrollPane(center);//用center初始化滚动面板 scrollpane.setPreferredSize(new Dimension(500,300)); MyListener lis=new MyListener(); //初始化菜单栏 JMenuBar menuBar=new JMenuBar(); JMenu fileMenu=new JMenu("file"); JMenuItem open=new JMenuItem("open"); JMenuItem save=new JMenuItem("save"); open.addActionListener(lis); save.addActionListener(lis); fileMenu.add(open); fileMenu.add(save); menuBar.add(fileMenu); // JPanel left=new JPanel(); left.setBackground(Color.DARK_GRAY); left.setPreferredSize(new Dimension(50,0)); this.add(left,BorderLayout.WEST); this.setJMenuBar(menuBar); this.add(scrollpane,BorderLayout.CENTER);//加入的是滚动面板 this.setTitle("bmp"); this.setLocation(300, 150); this.setSize(800, 500); this.setDefaultCloseOperation(3); this.setVisible(true); } /** * 读取bmp文件 */ public void readBMP() { try { FileInputStream fis=new FileInputStream(selectFile); BufferedInputStream bis=new BufferedInputStream(fis); byte[] wb=new byte[4];//读取宽度的字节数组 byte[] hb=new byte[4];//读取高度的字节数组 temp1=new byte[18]; bis.read(temp1);//bis.skip(18);//跳过前18个byte bis.read(wb);//读取宽度 bis.read(hb);//读取高度 width=byteToint(wb); height=byteToint(hb); System.out.println(width+"<>"+height); map=new int[height][width]; int skip=4-width*3%4;//得到每行要跳过的数字(与windows 系统机制有关) temp2=new byte[28]; bis.read(temp2);//bis.skip(28); for(int i=0;i<height;i++) { for(int j=0;j<width;j++) { int blue=bis.read(); int green=bis.read(); int red=bis.read(); Color c=new Color(red,green,blue); map[i][j]=c.getRGB(); } if(skip!=4) bis.skip(skip); } bis.close(); center.setPreferredSize(new Dimension(width,height)); javax.swing.SwingUtilities.updateComponentTreeUI(center);//这里必须要用updateComponentTreeUI(center)函数 //不能用repaint()函数 } catch (Exception e) { e.printStackTrace(); } } public void writeBMP() { try { FileOutputStream fos=new FileOutputStream(selectFile); BufferedOutputStream bos=new BufferedOutputStream(fos); bos.write(temp1);// bos.write(intTobyte(width,4));//写入宽度 bos.write(intTobyte(height,4));//写入高度 bos.write(temp2); int skip=0; if(width*3/4!=0) { skip=4-width*3%4; } for(int i=0;i<height;i++) { for(int j=0;j<width;j++) { Color c=new Color(map[i][j]); int blue=c.getBlue(); int green=c.getGreen(); int red=c.getRed(); bos.write(blue); bos.write(green); bos.write(red); } if(skip!=0) bos.write(new byte[skip]); } bos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } //字节转int public static int byteToint(byte b[]) { int t1=(b[3]&0xff)<<24; int t2=(b[2]&0xff)<<16; int t3=(b[1]&0xff)<<8; int t4=b[0]&0xff; //System.out.println(b[1]&0xff);//输出的是一个整形数据 //在java中,设计int和比int位数来的小的类型b,如byte,char等,都是先把小类型扩展成int再来运算, //return( t1<<24)+(t2<<16)+(t3<<8)+t4;//必须加括号 return t1+t2+t3+t4; } //int 转byte public static byte[] intTobyte(int a,int len) { byte []t=new byte[len]; t[0]=(byte) ((a&0xff)); if(len>1) t[1]=(byte)((a&0xff00)>>8); if(len>2) t[2]=(byte)((a&0xff0000)>>16); if(len>3) t[3]=(byte)((a&0xff000000)>>24); return t; } /** * 绘图面板 * @author ZhangZunC * */ class MyPanel extends JPanel{ public void paint(Graphics g) { super.paint(g); if(map!=null) { for(int i=0;i<map.length;i++) { for(int j=0;j<map[i].length;j++) { g.setColor(new Color(map[i][j])); g.drawLine(j, height-i, j,height- i); } } } } } class MyListener implements ActionListener{ JFileChooser fileChosser; MyListener() { FileNameExtensionFilter filter=new FileNameExtensionFilter("24位位图(*.bmp)", "bmp"); fileChosser=new JFileChooser(); fileChosser.setFileFilter(filter); fileChosser.setCurrentDirectory(new File("\\")); } public void actionPerformed(ActionEvent e) { if(e.getActionCommand().equals("open"))//选择的是打开 { int choose=fileChosser.showOpenDialog(null); if(choose==JFileChooser.APPROVE_OPTION)//点击的是确定按钮 { selectFile=fileChosser.getSelectedFile(); readBMP(); } } if(e.getActionCommand().equals("save"))//选择的是打开 { int choose=fileChosser.showSaveDialog(null); if(choose==JFileChooser.APPROVE_OPTION) { selectFile=fileChosser.getSelectedFile(); writeBMP(); System.out.println("save "); } } } } public static void main(String[] args) { new Projiect(); // byte[] b=new byte[4]; // b[0]=0; // b[1]=(byte) 0xaf; // b[2]=0; // b[3]=0; // System.out.println(byteToint(b)); // byte b1[]=intTobyte(byteToint(b),4); // System.out.println(b1[0]+"<>"+b1[1]+"<>"+b1[2]+"<>"+b1[3]); } }
相关推荐
### Java语言读取BMP文件的关键知识点 #### 1. BMP文件格式理解 BMP(Bitmap)是一种位图文件格式,主要用于Windows操作系统中存储图像数据。它由文件头、信息头、颜色表以及实际的像素数据四部分组成。在处理BMP...
通过读取bmp格式文件的数据格式,用数组合理的读取后,重新画出该图片
1. **文件读取**:使用Java的`java.io`包中的`FileInputStream`或`BufferedInputStream`读取BMP文件的二进制流。 2. **解析文件头**:根据BMP文件格式定义,解析文件头以获取文件的整体信息。 3. **解析信息头**:...
本文将详细讨论如何从BMP文件读取数据并将其转换为TXT文本文件,以及如何将TXT文件的数据重新写入为BMP文件。这两个过程涉及到二进制与文本之间的转换,这对于理解计算机数据处理和文件格式至关重要。 首先,我们来...
读取BMP文件通常涉及以下步骤: 1. **打开文件**:使用编程语言(如C++、Python或Java)的文件操作函数打开BMP文件。 2. **读取文件头**:BMP文件头包含两个部分:BITMAPFILEHEADER(BFH)和BITMAPINFOHEADER(BIH...
本话题将深入探讨如何读取BMP格式的图片,并从中提取RGB(Red, Green, Blue)颜色信息,然后将这些信息输出到TXT文件中。 RGB色彩模型是计算机图形学中广泛使用的颜色模型,它通过红、绿、蓝三种基本颜色的不同强度...
这个压缩包“BMP文件采样读取缩略图.rar”显然包含了与BMP文件处理相关的代码或教程,特别是关于如何采样读取BMP文件以生成缩略图的内容。以下是对这个主题的详细讲解: 首先,BMP文件结构主要包括以下几个部分: ...
3. **读取BMP文件** 使用编程语言(例如C++、Python或Java)打开文件,读取文件头数据以获取图像的基本信息。然后跳过可能存在的色彩表,直接定位到图像数据部分。 4. **处理色彩信息** BMP文件通常支持24位色彩...
在本篇博文中,我们将探讨如何使用Java编程语言来实现一个简单的画图板应用程序,并学习如何保存和读取BMP(Bitmap)格式的图片。BMP是一种无损图像格式,通常用于存储像素数据,便于程序处理。以下是实现这一功能所...
下面将详细介绍如何读取BMP图像以及相关知识点。 1. BMP文件结构: BMP文件由两部分组成:位图头信息和位图数据。位图头信息包含了图像的宽度、高度、颜色深度等元数据,而位图数据则存储实际的像素颜色值。常见的...
1. **读取BMP文件**:使用Java的`java.awt.image.BufferedImage`类来读取BMP文件。BMP文件的图像数据是按行存放的,每行数据可能需要填充以保持字节对齐。 ```java FileInputStream fis = new FileInputStream(...
实现这个过程,我们可以创建一个Java类,包含解析和显示BMP文件的方法。首先,使用`java.io.RandomAccessFile`来读取文件的各个部分。然后,将读取到的数据转化为图像的像素数组。最后,可以利用Java的`java.awt....
转换过程中,我们首先读取BMP文件的头部信息,获取图像的宽度和高度,然后逐行读取像素数据。对于24位BMP(每像素有8位红、绿、蓝分量),我们可以直接将RGB值存入RAW文件。由于RAW格式通常不包含元数据,所以我们...
读取BMP文件时,首先需要解析文件头以确定数据的布局,然后根据位图信息头解析图像尺寸和颜色信息,最后读取像素数据。这个过程通常涉及文件I/O操作,如打开、读取和关闭文件。 写入BMP文件则需要逆向进行,先创建...
这个主题主要涉及如何读取BMP文件以及理解BMP文件的内部结构,特别是颜色通道——红色、绿色和蓝色(RGB)之间的转换,尤其是BGR(Blue-Green-Red)顺序的处理。 首先,我们需要理解BMP文件的基本结构。BMP文件通常...
C++中可以利用文件流操作直接读取BMP文件,Python则可以借助PIL(Pillow)库轻松处理图像,Java则有Java AWT和Swing库提供支持。编写代码时,需要注意内存管理和数据类型的选择,确保正确地处理不同平台和字节序的...
Java编程语言在处理各种文件类型,如Flash(SWF)、JPEG(JPG)、GIF和BMP等图像格式时,提供了强大的支持。本压缩包文件包含的源码着重于如何在Java环境中准确地读取这些文件,从而实现对它们内容的解析、显示或...
Java提取压缩包中的文件,文件操作的范畴,操作对象为ZIP格式的压缩文件,将从ZIP中提取出BMP图像文件,要将从压缩包中提取文件,必须先解压压缩包,然后将指定文件拷贝出来,代码中先实现了对zip文件的解压,然后...
`ImageIO`类是这个API的核心,提供了`read()`方法来读取图像文件。 2. **使用ImageIO.read()**: 要读取图片,首先需要导入`javax.imageio.ImageIO`和`java.awt.image.BufferedImage`。然后,你可以使用`ImageIO....
这些库提供了读取和操作DCM文件,以及创建和写入BMP文件的功能。 7. **错误处理与兼容性**:转换过程中可能会遇到各种问题,如文件格式不正确、元数据错误等,需要有适当的错误处理机制。此外,考虑不同版本的DCM...