一:协议之感想
学了协议以后我就感觉这个东西有种很美妙的感觉,让我更进一步认识到计算机和计算机之间的交流原来是通过协议进行的。一旦双方不遵守这个协议那么这个交流就变得没有意义了 就像是用两种不同的语言进行交流一样,那么这种结果就只能是你看着我,然后我看着你,谁也不懂谁的。忽然想到那句话“世界上最遥远的距离不是生与死的距离,而是两个人之间明明说着话,却不知道对方的意思” 由此看来,协议是那么的重要。以前我总是认为很多大牛们,他们之所有成为大牛,是因为他们往往都不去遵循这个世界的规矩,总是表现得和平凡的人不一样,结果就成了大牛。学了协议以后 我慢慢的改变了这个看法,他们是在大规矩下的不拘泥小节。无规矩则不成方圆,我们必须在遵循这个大规矩前提下尽可能的发挥我们的想象力。协议是通信之枢纽。那么下面我将用解析bmp格式这个协议来谈谈我对他的理解吧。
二:bmp格式的定义
BMP格式由四部分组成:
1:文件头信息块
0000-0001 :文件标识,字母为ASCII码"BM".
0002-0005: 文件大小。
0006-0009: 保留,每字节以"00",填写。
000A-000D: 记录图像数据区的起始的位置。各字节的信息含义依次为: 文件头信息块大小 ,图像描述信息块的大小 , 图像颜色表的大小,保留为(01)
2:图像描述信息块:
000E-0011: 图像描述信息块的大小,常为28H。
0012-0015:图像宽度。
0016-0019:图像的高度。
001A-001B:图像的plane总数(横为1)
001C-001D:记录像素的位数,很重要的数值,图像的颜色数由该值决定。
001E-0021:数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩)
0022-0025:图像区数据的大小。
0026-0029:水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002A-002D:垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002E-0031:此图像所用的颜色数,如值为0,表示所有颜色一样重要
3.颜色表
颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B (蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号1的颜色,接下来表示颜色号2的颜色,依此类推。
4.图像数据区:
这里是图片最重要的地方,要是想了解去百度。我也没太搞懂,先将其弄过来
颜色表接下来位为位图文件的图像数据区,在此部分记录着每点像素对应的颜色号,其记录方式也随颜色模式而定,既2色图像每点占1位(8位为1字节);16色图像每点占4位(半字节);256色图像每点占8位(1字节);真彩色图像每点占24位(3 字节)。所以,整个数据区的大小也会随之变化。究其规律而言,可的出如下计算公式:图像数据信息大小=(图像宽度*图像高度*记录像素的位数)/8。
然而,未压缩的图像信息区的大小。除了真彩色模式外,其余的均大于或等 于数据信息的大小。这是为什么呢?原因有两个:
1.BMP文件记录一行图像是以字节为单位的。因此,就不存在一个字节中的数据位信息表示的点在不同的两行中。也就是说,设显示模式位16色,在每个字节分配两个点信息时,如果图像的宽度位奇数,那么最后一个像素点的信息将独占一个字节,这个字节的后4位将没有意义。接下来的一个字节将开始记录下一行的信息。
2.为了显示的方便,除了真彩色外,其他的每中颜色模式的行字节数要用数据“00”补齐为4的整数倍。如果显示模式为16色,当图像宽为19时,存储时每行则要补充4-(19/2+1)%4=2个字节(加1是因为里面有一个像素点要独占了一字节)。如果显示模式为256色,当图像宽为 19时,每行也要补充4-19%4=1个字节。
这些定义不用去记。到用的时候去查就行了。现在就举例一个bmp文件格式的解析吧,上代码
三:举例说明bmp文件格式的解析(这里用比较简单的24为真彩 ,因为要考虑的比较少)
首先实现一个窗体类 :用来读取和保存bmp格式图片
运行该界面类,结果如图所示:
[img]
[/img]
然后实现bmp格式的读取和写操作,都放入到监听器类
定义bmp的头文件结构类(保存bmp格式的时候用到) 代码如下
文件头结构内容代码 (主要是用于保存图片为bmp格式的时候)
最后实现一个鼠标监听器类,用鼠标点击事件去画图 然后将画好的图片保存;
紧接着上面的运行 首先完成读取操作 选择要打开的文件如图
[img]
[/img]
点击之后读取bmp图像就会显示到我自己上的画图板上了。看看是什么图片吧
[img]
[/img]
在之后就是自己先到画图板上随便画一个 然后用图片编辑器打开,结果如下
[img]
[/img]
[img]
[/img]
代码实现总结:到这里bmp格式的读取和保存就实现了。但是在写代码的时候花的时间还是比较久,首先得到找资料查看bmp格式的协议 ,知道了协议以后就是然后才能进行读写操作,这里就花了不少的时间。在写代码的时候自己又遇见了很多很多的技术上的问题,其中我觉得最难理解的也最重要的就是将字节型和整形进行相互转化,我写到这里的时候卡了好久。测试的时候要不就是不出来,要不就不是自己想要的。后面经过和同学的讨论 又问了老师,才把这个问题彻底解决了。这种基础性的问题以后还是要多看点书吧。还有就是讨论真的很重要。有时候自己想了很久的问题在别人稍微指导一下就能轻松的懂了。所以在以后的学习过程中 ,又有机会讨论的时候尽量去讨论。自己写代码的时间随时都会有。在写的时候还有一个难点就是在补0那一块不太了解,我在没有补零的时候,图片虽然是出来了,但是却是斜的。问了同学,查资料都是说这是规定要记。好吧,那我就把记下,知道有这么回事,会用就行了。就这样慢慢的问题就都解决了。在做完这个作品以后我个人感想吧就是问题总是会解决的,所以不要害怕出现问题。以后的路还很长.任重而道远......
学了协议以后我就感觉这个东西有种很美妙的感觉,让我更进一步认识到计算机和计算机之间的交流原来是通过协议进行的。一旦双方不遵守这个协议那么这个交流就变得没有意义了 就像是用两种不同的语言进行交流一样,那么这种结果就只能是你看着我,然后我看着你,谁也不懂谁的。忽然想到那句话“世界上最遥远的距离不是生与死的距离,而是两个人之间明明说着话,却不知道对方的意思” 由此看来,协议是那么的重要。以前我总是认为很多大牛们,他们之所有成为大牛,是因为他们往往都不去遵循这个世界的规矩,总是表现得和平凡的人不一样,结果就成了大牛。学了协议以后 我慢慢的改变了这个看法,他们是在大规矩下的不拘泥小节。无规矩则不成方圆,我们必须在遵循这个大规矩前提下尽可能的发挥我们的想象力。协议是通信之枢纽。那么下面我将用解析bmp格式这个协议来谈谈我对他的理解吧。
二:bmp格式的定义
BMP格式由四部分组成:
1:文件头信息块
0000-0001 :文件标识,字母为ASCII码"BM".
0002-0005: 文件大小。
0006-0009: 保留,每字节以"00",填写。
000A-000D: 记录图像数据区的起始的位置。各字节的信息含义依次为: 文件头信息块大小 ,图像描述信息块的大小 , 图像颜色表的大小,保留为(01)
2:图像描述信息块:
000E-0011: 图像描述信息块的大小,常为28H。
0012-0015:图像宽度。
0016-0019:图像的高度。
001A-001B:图像的plane总数(横为1)
001C-001D:记录像素的位数,很重要的数值,图像的颜色数由该值决定。
001E-0021:数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩)
0022-0025:图像区数据的大小。
0026-0029:水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002A-002D:垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。
002E-0031:此图像所用的颜色数,如值为0,表示所有颜色一样重要
3.颜色表
颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B (蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号1的颜色,接下来表示颜色号2的颜色,依此类推。
4.图像数据区:
这里是图片最重要的地方,要是想了解去百度。我也没太搞懂,先将其弄过来
颜色表接下来位为位图文件的图像数据区,在此部分记录着每点像素对应的颜色号,其记录方式也随颜色模式而定,既2色图像每点占1位(8位为1字节);16色图像每点占4位(半字节);256色图像每点占8位(1字节);真彩色图像每点占24位(3 字节)。所以,整个数据区的大小也会随之变化。究其规律而言,可的出如下计算公式:图像数据信息大小=(图像宽度*图像高度*记录像素的位数)/8。
然而,未压缩的图像信息区的大小。除了真彩色模式外,其余的均大于或等 于数据信息的大小。这是为什么呢?原因有两个:
1.BMP文件记录一行图像是以字节为单位的。因此,就不存在一个字节中的数据位信息表示的点在不同的两行中。也就是说,设显示模式位16色,在每个字节分配两个点信息时,如果图像的宽度位奇数,那么最后一个像素点的信息将独占一个字节,这个字节的后4位将没有意义。接下来的一个字节将开始记录下一行的信息。
2.为了显示的方便,除了真彩色外,其他的每中颜色模式的行字节数要用数据“00”补齐为4的整数倍。如果显示模式为16色,当图像宽为19时,存储时每行则要补充4-(19/2+1)%4=2个字节(加1是因为里面有一个像素点要独占了一字节)。如果显示模式为256色,当图像宽为 19时,每行也要补充4-19%4=1个字节。
这些定义不用去记。到用的时候去查就行了。现在就举例一个bmp文件格式的解析吧,上代码
三:举例说明bmp文件格式的解析(这里用比较简单的24为真彩 ,因为要考虑的比较少)
首先实现一个窗体类 :用来读取和保存bmp格式图片
/** * 实现bmp文件的解析类,继承窗体。将其读入到自己的画板中 * */ public class AnalysisBmp extends JFrame{ /** * 显示窗体的方法 */ public void intitUi(){ this.setTitle("bmp图形解析器"); this.setSize(600,500); this.setResizable(false); //设置关闭的时候退出 this.setDefaultCloseOperation(3); //给窗体设置面板布局方式 this.setLayout(new BorderLayout()); //实例化一个菜单栏对象,并把该对象添加到窗体上 JMenuBar menuBar=new JMenuBar(); this.setJMenuBar(menuBar); //实例化菜单项对象 JMenu jmenu1=new JMenu("文件(F)"); JMenu jmenu2=new JMenu("编辑(E)"); menuBar.add(jmenu1); menuBar.add(jmenu2); JMenuItem menuitem=new JMenuItem("打开"); JMenuItem menuitem2=new JMenuItem("保存"); JMenuItem menuitem3=new JMenuItem("退出"); JMenuItem menuitem4=new JMenuItem("撤销"); JMenuItem menuitem5=new JMenuItem("复制"); JMenuItem menuitem6=new JMenuItem("粘贴"); //在“文件”菜单项中添加 “打开”,“保存”,“退出”, jmenu1.add(menuitem); jmenu1.add(menuitem2); jmenu1.add(menuitem3); //在“编辑”菜单项中添加“撤销”,“复制”,“粘贴” jmenu2.add(menuitem4); jmenu2.add(menuitem5); jmenu2.add(menuitem6); //显示窗体,放在最后面 this.setVisible(true); //注意在实例化对象的时候就是产生一个新的对象,很容易产生空指针异常 // //实例化一个PanelMouseListener对象 并将窗体传递给改对象 PanelMouseListener pm=new PanelMouseListener(this); //实例化一个MenuActionListener对象 其实就是面板 并将pm传递给listener; MenuActionListener listener=new MenuActionListener(pm,this); //将面板listener添加到窗体上面 this.add(listener, BorderLayout.CENTER); //然后给画板添加鼠标监听器 listener.addMouseListener(pm); //给菜单项上事件添加监听器 menuitem.addActionListener(listener); menuitem2.addActionListener(listener); menuitem3.addActionListener(listener); menuitem4.addActionListener(listener); menuitem5.addActionListener(listener); menuitem6.addActionListener(listener); } //主函数,程序的入口 public static void main(String[] args) { //实例化一个对象用来调用显示窗体的方法 AnalysisBmp asp=new AnalysisBmp(); //调用显示窗体的方法 asp.intitUi(); } }
运行该界面类,结果如图所示:
[img]

[/img]
然后实现bmp格式的读取和写操作,都放入到监听器类
/** * 菜单项上实现监听器 * @author Administrator * */ public class MenuActionListener extends JPanel implements ActionListener { // private Graphics g; //声明画布变量,用来保存传过来的画布 private JFileChooser fileChooser; private int width; //声明整型变量,保存图片的宽度(在位信息的14~17位) private int heigh; //声明整型变量,保存图片的高度(在位信息的18~21位) private int skip_width; private int[][] ColorR; //保存像素中的红色变量 private int[][] ColorG; //保存像素中的绿色变量 private int[][] ColorB; //保存像素中的蓝色变量 private int bflen=14; //头文件的14个字节的整形变量 private int bilen=40; //40位的信息头变量 private int size=0; //bmp信息头大小 14~17 固定值为28H; java.io.FileInputStream fis; java.io.DataInputStream dis; File file; //打开选择的文件 File file1; //保存选择的文件 javax.swing.JFrame jf; PanelMouseListener pm; //保存PanelMouseListener对象的属性 /** * 构造器对象 ,用来接收PanelMouseListener的对象和窗体对象 * @param pm PanelMouseListener的对象 */ public MenuActionListener(PanelMouseListener pm,JFrame jf){ this.pm=pm; this.jf=jf; } //监听器中的抽象方法 public void actionPerformed(ActionEvent e) { if("打开".equals(e.getActionCommand())){ //点击打开菜单项时,弹出选择文件对话框 // System.out.println("执行啦"); fileChooser=new JFileChooser(); //调设置只能选择目录,默认是选择文件 (收索目录的时候用到,或则就不要用到) // fileChooser.setFileSelectionMode(); //然后将显示出来。null是显示在窗体中中央 fileChooser.showOpenDialog(null); //接收读取得到的文件 file = fileChooser.getSelectedFile(); if(file!=null){ //当选择有文件的时候 进行读取 readBmp(file); System.out.println("读取得到的文件"+file); } } if("退出".equals(e.getActionCommand())){ //退出 System.exit(0); } if("保存".equals(e.getActionCommand())){ //点击保存事件的时候就 把所画的图形保存出来 fileChooser=new JFileChooser(); //实例化一个文件选择器 //宣示保存文件 fileChooser.showSaveDialog(null); file1=fileChooser.getSelectedFile(); //将取得的BufferedImage对象赋值给bm writeBMP(pm.bi); System.out.println(pm.bi); } } /** * 读取所选中的bmp文件方法 * @param fileName 所选择的文件 */ public void readBmp(File fileName){ try { //实例化输入流对象 fis=new java.io.FileInputStream(fileName); dis=new java.io.DataInputStream(fis); //1:读取Bmp头文件 长度14位 byte []bf=new byte[bflen]; int d=dis.read(bf,0,bflen); System.out.println("头文件所占的字节:"+d); //2:读取为信息图 40位 byte[] bi=new byte[bilen]; int t=dis.read(bi,0,bilen); System.out.println("位信息所占的字节:"+t); //在位图信息中 获取重要的信息,主要是图片的高度和宽度 size=changeInt(bi,3); //信息头在14~17位 width=changeInt(bi,7); //宽度在18~21位 heigh=changeInt(bi,11); //高度在22~25位 //打印图片相关信息 System.out.println("bmp信息头大小:"+size); System.out.println("bmp源图的宽度:"+width); System.out.println("bmp源图的高度:"+heigh); //判断图片宽度字节数能否被4整除,不能整除要补0 if(width*3%4!=0){ skip_width=4-width*3%4; //检验无效的长度,方便后面直接跳过该位数 System.out.println("要补的0长度为:"+skip_width); } //调用读取像素颜色的具体值方法 dispalyRGB(); } catch (Exception e) { e.printStackTrace(); System.out.println("出错误啦。。。。。"); } } /** * 读取颜色的方法 并调用paint()方法 * @throws IOException */ public void dispalyRGB() throws IOException{ //声明二维数组用来保存点的 坐标 ColorR= new int[heigh][width]; ColorG= new int[heigh][width]; ColorB= new int[heigh][width]; //读取每个点的具体颜色值 //用两个for循环 读取像素的颜色值 每一个点都是由 R,G,B组成 for(int h=heigh-1;h>=0;h--){ for(int w=0;w<width;w++){ //因为下标是从0开始的,所以不能取到宽度 // System.out.println("h="+h+",w="+w); ColorB[h][w]=dis.read(); ColorG[h][w]=dis.read(); ColorR[h][w]=dis.read(); if(w==width-1){ //当宽度读到最后的时候,就跳过后面补零的位 dis.skipBytes(skip_width); } //打印颜色的值 // System.out.println("像素的绿色:"+ColorG[h][w] // +",像素的红色:"+ColorR[h][w] // +",像素的蓝色:"+ColorB[h][w]); } } //重写绘画方法 ,保证重绘的时候是读取的画过的图片 this.repaint(); } /** * 将字节转化为整形的方法 * @param bi要进行变化的字节数组 * @param start 字节开始的位数 * @return 转化好的整形 */ public int changeInt(byte []bi,int start){ return (((int)bi[start]&0xff)<<24)| (((int)bi[start-1]&0xff)<<16)| (((int)bi[start-2]&0xff)<<8)| (int)bi[start-3]&0xff; } /** * 重写面板的方法 * 用什么画就重绘什么 */ public void paint(Graphics g){ //调用父类的窗体方法 super.paint(g); //重绘鼠标所画的图片 this.pm.draw(); System.out.println("重绘!! "+"高度"+heigh+"宽度"+width); //重绘所打开图片画的RGB图形 this.drawRGB(g); System.out.println("重绘结束!!"); } /** * 将像素的颜色画出来 */ public void drawRGB(Graphics g){ for(int h=heigh-1;h>=0;h--){ for(int w=0;w<width;w++){ //设置颜色为 原图读取的像素颜色值 g.setColor(new Color(ColorR[h][w],ColorG[h][w],ColorB[h][w])); //将各个像素画出来 // g.fillOval(w, h, 1, 1); //用这种方法画的时候就不出现题目, 我还不懂!!!!!! int w1=w+(jf.getWidth()-width)/2; //将水平方向平移,图片显示在窗体的最中间 g.drawLine(w1, h, w1, h); // System.out.println("w==="+w+"h==="+h); // System.out.println("像素的绿色:"+ColorG[h][w] // +",像素的红色:"+ColorR[h][w] // +",像素的蓝色:"+ColorB[h][w]); if(w==width-1){ //当宽度读到最后的时候,就跳过后面补零的位 try { dis.skipBytes(skip_width); } catch (IOException e) { e.printStackTrace(); System.out.println("我出错误啦啦啦..."); } } } } } /** * 将所画图片转化成bmp格式文件 * @param bi */ public void writeBMP(BufferedImage bi){ try { if(file1!=null){ //实例化一个输出对象 java.io.FileOutputStream out=new java.io.FileOutputStream(file1); java.io.DataOutputStream dout=new java.io.DataOutputStream(out); int w=bi.getWidth(); //取得图片的宽度 int h=bi.getHeight(); //取得图片的高度 int size =w*h*3; //所以像素的字节 System.out.println("w="+w+",h="+h+",size="+size); if(w%4!=0){ size+=(w%4)*h; } //实例化一个bmp头文件头对象 BmpFileHeader bfi=new BmpFileHeader(size,56); //实例化一个bmp头文件内容对象 BmpInfoHeader bis=new BmpInfoHeader(w,h,24); //定义一个长度为三的数组,保存颜色 byte[]rgbs=new byte[3]; byte[]blank=new byte[w%4]; //将数据写入 dout.write(bfi.getData()); dout.write(bis.getData()); //定义一个标记 int index=0; //取得默认的颜色R,G,B的值 ,对用下面注销掉的颜色写入 ColorModel cm = ColorModel.getRGBdefault(); for(int y=h-1;y>=0;y--){ //循还里面的要注意啊。不要把变量写错啊。。。。出了好多次错误 for(int x=0;x<w;x++){ index+=3; // System.out.println("x="+x+",y="+y); //取得颜色 int rgb=bi.getRGB(x, y); // System.out.println("rgb="+rgb); //将颜色写入到文件中 // rgbs[2] = (byte)cm.getGreen(rgb); // rgbs[1] = (byte)cm.getBlue(rgb); // rgbs[0] = (byte)cm.getRed(rgb); /**颜色写的时候要让BGR的顺序读取 在存的时候是按顺序rgbs[0]=r,rgbs[1]=g,rgbs[2]=b; 所以要按反方向写入 */ rgbs[2]=(byte)rgb; rgb=rgb>>>8; rgbs[1]=(byte)rgb; rgb=rgb>>>8; rgbs[0]=(byte)rgb; // System.out.println("颜色是:"+rgbs[0]+" "+rgbs[1]+" "+rgbs[2]); dout.write(rgbs); if((w%4!=0)&&(index%(w*3)==0)){ dout.write(blank); //写入多余的部分 } } } //刷新输出流中的数据,完成之后并关闭输出流 dout.flush(); dout.close(); } } catch (Exception e) { e.printStackTrace(); } } }
定义bmp的头文件结构类(保存bmp格式的时候用到) 代码如下
/** * bmp的头文件结构类 用于保存文件时候做 * Title :bmp头文件结构 * * byte[2] bfTyte 文件结构类型 必须是0x424D 即字符串"BM"; * byte[4] bfSize 指定文件大小,包括这14个字节 * byte[2] bfReserved1; 保留字 * byte[2] bfReserved2; 保留字 * byte[4] bfOffBits ; 文件头到实际位图数据的偏移字节数 */ public class BmpFileHeader { //声明一个14长度字节的字节数组 private byte[] data=new byte[14]; private int size; //文件的大小 2~5字节 private int offset; //偏移量 11~14字节 /** * 用构造方法介绍文件的大小和偏移量 * 并且写入 * @param size 大小 * @param offsert 偏移量 */ public BmpFileHeader(int size,int offsert){ this.size=size; //文件的大小 2~5字节 this.offset=offsert; //偏移量 11~14字节; data[0]='B'; data[1]='M'; // System.out.println("头文件data[0]="+Integer.toHexString((int)data[0])+ // ",头文件data[1]="+Integer.toHexString((int)data[1])); //将文件大小赋值给一个value 并将文件大小转化为字节 因为要写入 所以要转化为字节 int value=size; data[2]=(byte)value; value=value>>>8; data[3]=(byte)value; value=value>>>8; data[4]=(byte)value; value=value>>>8; data[5]=(byte)value; value=value>>>8; //检验文件大小 按位输出, // System.out.println("头文件第三位是:"+Integer.toHexString((int)data[2])+ // ",头文件第四位是:"+Integer.toHexString((int)data[3])+ // ",头文件第五位是:"+Integer.toHexString((int)data[4])+ // ",头文件第六位是:"+Integer.toHexString((int)data[5])); //将offsert 转化为字节型; 用中间变量 来做 value=offsert; //先将强制转化为字节型; 运用强制转化和位的右移运算 data[10]=(byte)value; value=value>>>8; data[11]=(byte)value; value=value>>>8; data[12]=(byte)value; value=value>>>8; data[13]=(byte)value; //打印验证 // System.out.println("头文件第十一位是:"+Integer.toHexString((int)data[10])+ // ",头文件第十二位是:"+Integer.toHexString((int)data[11])+ // ",头文件第十三位是:"+Integer.toHexString((int)data[12])+ // ",头文件第十四位是:"+Integer.toHexString((int)data[13])); } /** * 取得文件结构的数组数据; * @return 数组数据 */ public byte[] getData() { return data; } /** * 取得头文件的大小 * @return */ public int getSize() { return size; } /** * 取得文件偏移量 * @return */ public int getOffset() { return offset; } }
文件头结构内容代码 (主要是用于保存图片为bmp格式的时候)
/** * bmp文件头内容的结构 * 文件内容的头结构固定是40个字节, * * byte[4] biSize:这个结构的长度 为40; (15位) * byte[4] biWidth;指定图形的宽度,单位为像素;() (19~12) * byte[4] biHeigh;指定图形的高度,单位为像素 ()(23~26) * byte[2] biPlanes 必须是1,不用考虑 (27~28) * byte[2] biBitCount;指定颜色时要用到的位数, () (29~30) * 常用值为1(黑白) 4(16色) 8(256色),24(真彩彩色图) * byte[4] biCompression ;指定是否压缩 (31~34) * byte[4] biSizeImage 指定实际的位图数据占用的字节数 (35~38) * byte[4] biXPelsPerMeter 指定目标水平的分辨率 单位是每米像素的个数 (39~42) * byte[4] biXPelsPerMeter 指定目标垂直的分辨率 单位是每米像素的个数 (43~46) * byte[4] biClrUsed 指定本图像实际用到的颜色数 如果为0,则用2biBitCount;(47~50) * byte[4] biClrImportant; 指定本图像中的重要颜色数,如果该值为零,则都是重要的(41~54) * * */ public class BmpInfoHeader { private int width; //图片的宽度变量 private int heigh; //图片的高度变量 private int biBitCount; //图片的颜色的位数变量 private int biLen=40; private byte []data; //声明一个字节数组,保存文件内容 /** * 构造函数 用来接收 所要保存图片的高度 宽度 和 指定颜色的位数属性 */ public BmpInfoHeader(int width,int heigh,int biBitCount){ this.width=width; this.heigh=heigh; this.biBitCount=biBitCount; //创建40字节的的字节数组 data=new byte[biLen]; data[0]=40; //文件内容大小为40; // System.out.println("信息内容大小:"+(int)data[0]); //2到4位默认值为0; int value=width; //将图片宽度转化为字节型 data[4]=(byte)value; value=value>>>8; data[5]=(byte)value; value=value>>>8; data[6]=(byte)value; value=value>>>8; data[7]=(byte)value; // System.out.println("文件内容第5位是:"+Integer.toHexString((int)data[4])+ // ",文件内容第6位是:"+Integer.toHexString((int)data[5])+ // ",文件内容第7位是:"+Integer.toHexString((int)data[6])+ // ",文件内容第8位是:"+Integer.toHexString((int)data[7])); //将图片的高度转化为字节型 value =heigh; data[8]=(byte)value; value=value>>>8; data[9]=(byte)value; value=value>>>8; data[10]=(byte)value; value=value>>>8; data[11]=(byte)value; // System.out.println("文件内容第9位:"+Integer.toHexString((int)data[8])+ // ",文件内容第10位是:"+Integer.toHexString((int)data[9])+ // ",文件内容第11位是:"+Integer.toHexString((int)data[10])+ // ",文件内容第12位是:"+Integer.toHexString((int)data[11])); data[12]=1; data[14]=(byte)biBitCount; //颜色位数 //所有像素所占的字节 赋值给value 在(35~38字节,包括文件头14) value=width*heigh*3; if(width%4!=0){ //不能被4整除 value+=(width%4)*heigh; //加上所补的零 } data[20]=(byte)value; value=value>>>8; data[21]=(byte)value; value=value>>>8; data[22]=(byte)value; value=value>>>8; data[23]=(byte)value; // System.out.println("文件内容第35位是:"+Integer.toHexString((int)data[20])+ // ",文件内容第36位是:"+Integer.toHexString((int)data[21])+ // ",文件内容第37位是:"+Integer.toHexString((int)data[22])+ // ",文件内容第38位是:"+Integer.toHexString((int)data[23])); } /** * 取得图片的宽度 * @return */ public int getWidth() { return width; } /** * 取得图片的高度 * @return */ public int getHeigh() { return heigh; } /** * 取得颜色的位数 * @return */ public int getBiBiCount() { return biBitCount; } /** * 取得文件内容的数据 * @return */ public byte[] getData() { return data; } }
最后实现一个鼠标监听器类,用鼠标点击事件去画图 然后将画好的图片保存;
public class PanelMouseListener implements MouseListener{ JFrame jf; //窗体的变量 int x1,y1,x2,y2; //定义保存鼠标按下和释放时候的坐标 BufferedImage bi;//保存缓冲对象的变量 JPanel jp; /** * 构造方法,用来接收传递过来的窗体 * @param jf */ public PanelMouseListener(JFrame jf){ this.jf=jf; } public void mousePressed(MouseEvent e) { x1=e.getX(); y1=e.getY(); // System.out.println("x1="+x1+",y1="+y1); } public void mouseReleased(MouseEvent e) { x2=e.getX(); y2=e.getY(); jp = (JPanel)e.getSource(); draw(); // System.out.println("x1="+x1+",y1="+y1); } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } Graphics gg; /** * 定义画线的方法 并且将画好的图保存下来 */ public void draw(){ if(jp!=null){ int w=jp.getWidth(); int h=jp.getHeight(); Graphics g=jp.getGraphics(); // System.out.println("w="+w+",h="+h); //将图片画到缓冲流中 if(bi == null){ bi=new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB); gg=bi.getGraphics(); } //取得BufferedImage的画布对象 // Graphics gg=bi.getGraphics(); gg.setColor(Color.BLUE); gg.drawLine(x1, y1, x2, y2); //将缓冲流中的图片画到画布上 gg.setColor(Color.WHITE); g.drawImage(bi, 0, 0, null); } } }
紧接着上面的运行 首先完成读取操作 选择要打开的文件如图
[img]

[/img]
点击之后读取bmp图像就会显示到我自己上的画图板上了。看看是什么图片吧
[img]

[/img]
在之后就是自己先到画图板上随便画一个 然后用图片编辑器打开,结果如下
[img]

[/img]
[img]

[/img]
代码实现总结:到这里bmp格式的读取和保存就实现了。但是在写代码的时候花的时间还是比较久,首先得到找资料查看bmp格式的协议 ,知道了协议以后就是然后才能进行读写操作,这里就花了不少的时间。在写代码的时候自己又遇见了很多很多的技术上的问题,其中我觉得最难理解的也最重要的就是将字节型和整形进行相互转化,我写到这里的时候卡了好久。测试的时候要不就是不出来,要不就不是自己想要的。后面经过和同学的讨论 又问了老师,才把这个问题彻底解决了。这种基础性的问题以后还是要多看点书吧。还有就是讨论真的很重要。有时候自己想了很久的问题在别人稍微指导一下就能轻松的懂了。所以在以后的学习过程中 ,又有机会讨论的时候尽量去讨论。自己写代码的时间随时都会有。在写的时候还有一个难点就是在补0那一块不太了解,我在没有补零的时候,图片虽然是出来了,但是却是斜的。问了同学,查资料都是说这是规定要记。好吧,那我就把记下,知道有这么回事,会用就行了。就这样慢慢的问题就都解决了。在做完这个作品以后我个人感想吧就是问题总是会解决的,所以不要害怕出现问题。以后的路还很长.任重而道远......
相关推荐
BMP(Bitmap)文件格式是计算机图形领域中最基础的位图图像存储格式之一,它广泛应用于Windows操作系统和许多其他软件中。BMP文件格式的详细理解对于任何对图像处理和编程感兴趣的人来说都是非常重要的,尤其是初学...
本示例主要涉及的是C++编程语言,以及两种常见的位图格式——BMP(Bitmap)和JPG(Joint Photographic Experts Group)。BMP是一种无损的、未压缩的图像格式,而JPG则是一种有损压缩格式,广泛用于网络和存储效率...
其中,最简单的BMP文件通常包含两个主要部分:文件头和位图数据。文件头包括两个子部分——DOS头和Windows头,它们提供了文件的基本信息。位图数据则按照像素顺序存储,从左到右,从下到上排列。 在BMP Util项目中...
本文将深入探讨如何将三种不同类型的图像格式——ICO、BMP和内存中的图片——转换为PNG格式,这是一种广泛支持且高效的网络图像格式。我们还将讨论涉及的编程代码和相关技术。 首先,ICO是一种用于Windows操作系统...
本教程将详细阐述如何利用Visual Studio 2010(VS2010)创建一个简单的单文档应用程序(Single Document Interface, SDI),该程序能够加载并显示BMP格式的图像。这个项目对于初学者来说是很好的实践案例,有助于...
此外,为了增加安全性,通常会结合其他加密技术,如哈希函数或密钥交换协议,来保护嵌入的信息不被轻易解析。 总的来说,LSB技术是信息隐藏领域的一种基础且实用的方法,尤其在BMP图像中,能够有效地实现信息的隐藏...
在处理图像时,经常需要识别一张图片的具体格式,比如 JPEG、PNG 或 BMP 等。这不仅是为了更好地进行图片展示,也是为了能够根据不同的格式采取相应的优化措施。在 Java 开发中,可以通过 Java 的标准库 `java.awt` ...
《64位系统下的格式转换工具——Product x64 v20210508.1.1详解》 在数字化的世界里,文件格式的兼容性问题常常困扰着我们。无论是视频、音频还是图像,不同的设备和软件可能对文件格式有着不同的要求。因此,拥有...
BMP格式虽然占用较多存储空间,但编写和解析相对简单,对于嵌入式设备来说是一个可行的选择。在实时显示方面,同样需要软件层面的支持,确保图像数据能够及时准确地在TFT LCD上显示,保证画面的流畅性。 最后,文章...
本项目利用VC++(Microsoft Visual C++)作为开发环境,结合MITK库,实现了对五种常见图片格式——JPEG、DICOM、BMP、TIFF和RAW的读取功能。接下来,我们将深入探讨这些知识点。 1. **VC++**:VC++是微软推出的一种...
通过分析以上内容,我们可以看到,即使是最简单的2D游戏,也需要综合运用到图形处理、事件驱动编程、逻辑控制等多个方面的知识。理解并实践这样的项目,对于初学者来说,是提升编程技能和游戏开发能力的有效途径。...
《截图小工具——简易截屏程序的解析与探讨》 在信息技术日新月异的今天,截图工具已经成为了我们日常工作中不可或缺的一部分。无论是为了记录屏幕信息、分享视觉内容,还是进行远程协作,都需要借助这样的软件。...
《电脑端高效截屏工具——FSCapture深度解析》 在日常的工作与学习中,截屏功能已经成为我们不可或缺的一部分,无论是记录重要信息、分享屏幕内容还是进行教程制作,一款优秀的截屏工具都能大大提高效率。FSCapture...
《字符及图片取模软件——PcToLCD2002深度解析》 在IT行业中,数据可视化和信息处理是一项重要的任务,特别是在嵌入式系统和电子显示屏的设计中。这时,字符与图片的取模软件就显得尤为重要。PcToLCD2002是一款专门...
常见的位图格式有BMP、PNG等,但STemWin通常处理的是BMP格式,因为这种格式的解析相对简单。确保位图的颜色深度与你的LCD兼容,例如16位色或24位色。 2. **加载位图数据**:在程序中,你需要读取位图文件并将其加载...
在读取文件时,我们需要按照BMP文件格式解析这些数据,将其加载到内存中。接着,利用WIN32 API中的GDI(Graphics Device Interface)函数,如CreateDIBSection和CreateCompatibleDC,创建设备上下文和位图对象,将...
《全面解析:ACDSee——你的理想看图之选》 在数字图像日益普及的今天,拥有一款高效、易用的看图软件是每个电脑用户必不可少的需求。今天我们要介绍的主角,就是被誉为“最新最好”的看图软件——ACDSee。这款软件...
SimpleAviPlayer是一款基于DirectShow(简称Dshow)技术实现的AVI文件播放器,它不仅能够流畅地播放AVI格式的视频文件,还具备一项独特的功能——用户可以指定帧的位置,抓取帧数据并将其保存为BMP图片。这一特性...
本项目是利用C++2008编程语言和Microsoft Foundation Classes(MFC)库,构建一个简单但实用的图像处理软件,特别关注对BMP格式图像的反色和线性变换操作。本文将深入探讨这一项目的实现原理和技术细节。 首先,...
JPG格式以较高的压缩率著称,适合存储大量图片,而BMP则是一种无损格式,能保留原始图像的所有细节,适用于对图像质量有较高要求的场合。通过选择合适的格式,用户可以在质量和容量之间找到最佳平衡。 WebShot v...