`
不打伞的蘑菇
  • 浏览: 14899 次
社区版块
存档分类
最新评论

自定义画图板实现与系统bmp图片的打开保存

阅读更多
 
 
 
 

 

 

    在这个项目中,我们利用的是swing开发做出的一个画图板的界面。在界面上实现了画图和保存的功能。但是由于自定义的保存方式导致只能用自定义的打开方式来打开,也就是说,我们用自定义画图板创建的图片别人根本打不开。-_-||

    所以为了与国际接轨,与系统接轨,我们必须要使用系统的打开和保存方式来处理一张图片。以下用bmp格式为例。

    因为bmp图片的保存格式是开源的,我们能简单的知道系统画图板是怎么保存一个bmp格式的图片的。这个网上百度可以搜到。

典型的BMP 图像文件由四部分组成:   

 ① 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(双色), 4(16 色 ) , 8(256 色 ) 或 24(// 真彩色 ) 之一  (28-29 字节)
int biCompression; // 位图压缩类型,必须是 0( 不压缩 ), 1(BI_RLE8 压缩类型 ) 或// 2(BI_RLE4 压缩类型 ) 之一  (30-33 字节 )
int SizeImage; // 位图数据的大小,以字节为单位 (34-37 字节 )   
int biXPelsPerMeter; // 位图水平分辨率,每米像素数 (38-41 字节 )   
int biYPelsPerMeter; // 位图垂直分辨率,每米像素数 (42-45 字节 )   
int biClrUsed;// 位图实际使用的颜色表中的颜色数 (46-49 字节 )   
int biClrImportant;// 位图显示过程中重要的颜色数 (50-53 字节 )

 

  3、调色板 ,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24 位的 BMP )就不需要调色板。所以,想当然,我选的是不需要调色板的24位的。所以下面做保存的时候直接跳过啦。  

 

class  BITMAPINFO {   
BITMAPINFOHEADER bmiHeader; // 位图信息头   
RGBQUAD bmiColors[1]; // 颜色表   
} 

 

      4、位图数据 ,这部分的内容根据BMP 位图使用的位数不同而不同,在 24 位图中直接使用 RGB ,而其他的小于 24 位的使用调色板中颜色索引值。

 

准备完成,下面是写代码阶段。

 

首先得swing界面中添加画布和菜单栏,对画布实现鼠标监听器,对菜单项实现事件监听器。然后在画布监听器中,实现鼠标按下,拖动,释放的方法,写的简陋,就只实现了这三个方法。在这个监听器中,我们把鼠标对画布的操作保存在缓存中,使用int数组保存一张图片中所有的像素点,在监听器的构造方法中初始化这个画图为白色。

public static int array[][]; //定义数组保存图片的像素点
   public DrawListener(JPanel panel){
      This.panel=panel;
      Dimension dim=panel.getPreferredSize();
      array=new int[dim.height][dim.width];
      for(int i=0;i<array.length;i++){
          for(int j=0;j<array[i].length;j++){
          //画布初始化,设置画布为白色
          array[i][j]=Color.WHITE.getRGB();
          }
      }
}

 

在鼠标监听器里面,鼠标按下拖动的方法里面可以画连续的线段,可是,当你把画图板最小化在重新打开时你会发现你先前画的线条都没有了。这个怎么解决呢?办法是把这张图片的像素已经保存在电脑缓存中,在释放的方法里面把画布中的像素点保存在int数组当中,然后在每一次重新调用这个面板的时候(比如最小化后再打开就是一次重新调用)重绘这个画布中的像素点。如下面的代码所示:

public void mouseReleased(MouseEvent e) {
		//当鼠标释放的时候保存
		Point p=panel.getLocationOnScreen();
		Dimension dim=panel.getPreferredSize();
		Rectangle rect=new Rectangle(p,dim);
		BufferedImage img=robot.createScreenCapture(rect);
		array=new int[img.getHeight()][img.getWidth()];
		for(int i=0;i<array.length;i++){
				for(int j=0;j<array[i].length;j++){
                              //遍历图片的宽高,把图片的像素点保存在int数组中,图片的宽高和数组的下表是相反的。
				array[i][j]=img.getRGB(j, i);
			}
		}
	}

 

 

 

public void paint(Graphics g) {
			super.paint(g);
			for(int i=0;i<DrawListener.array.length;i++){
				for(int j=0;j<DrawListener.array[i].length;j++){
					g.setColor(new Color(DrawListener.array[i][j]));
                                      //重新绘制保存好的int数组中的像素。
				        g.drawLine(j, i, j, i);
			}
		}
	}

 

此时,自定义的画图板实现了简陋的绘画的功能了,接下来就遇到一开始说的问题了,画完之后的如何保存到硬盘中,并且让系统的画图软件也能打开我们保存的图片呢?实际上,我们在电脑上看到的图片真的是一张图片吗?不是的,它只是一组数据的集合。只是画图软件能知道怎么把这组数据还还原成一张图片显示在画图板中而已。

接下来,以bmp24位保存格式为例。

首先是如何打开一个bmp格式的图片,这个先在自己系统的画图板中画好,并以bmp24位的格式保存。而从前面我们已经能够知道它是怎么个保存方法了。只要读取到我们所需要的图片的高度和宽度还有每一个点的像素点就能在自定义的画图板中把图片显示出来了。

 

 

FileInputStream  fis=new FileInputStream(file1);
			fis.skip(18);
			int width=changeInt(fis);//跳过不需要的,读取宽度和高度
			int height=changeInt(fis);
			fis.skip(28);
                       //跳过,直接读取位图数据。
			DrawListener.array=new int[height][width];
			int t=0;
			if(width*3%4>0){
				t=4-width*3%4;
			}
			for(int i=height-1;i>=0;i--){
				for(int j=0;j<width;j++){
                               //调用自定义方法,得到图片的像素点并保存到int数组中
					int c=readColor(fis);
					DrawListener.array[i][j]=c;
				}
				fis.skip(t);
			}
			fis.close();
                       //刷新,重绘面板,打开系统保存的图片。
			panel.setPreferredSize(new Dimension(width, height));
			SwingUtilities.updateComponentTreeUI(panel);

 

       //由于读取的是字节,把读取到的4个byte转化成1个int
       public int changeInt(FileInputStream ips) throws IOException{
		int t1=ips.read() & 0xff;
		int t2=ips.read() & 0xff;
		int t3=ips.read() & 0xff;
		int t4=ips.read() & 0xff;
		int num=(t4<<24)+(t3<<16)+(t2<<8)+t1;
		System.out.println(num);
		return num;
	}
       //24位的图片是1个像素3个字节。
	public int readColor(FileInputStream ips) throws IOException{
		int b=ips.read() & 0xff;
		int g=ips.read() & 0xff;
		int r=ips.read() & 0xff;
		int c=(r<<16)+(g<<8)+b;
		return c;
	}

 

     以上就完成打开的操作了,保存图片比打开图片复杂一点,不过也只要你依据正确的存储方式把数据存储起来系统的画图板就能识别你保存的数据打开你的图片了。部分代码如下。

              if("savebmp".equals(commend)){
			FileOutputStream fos=new FileOutputStream(file2);
			savebmpTop(fos);
			savebmpInfo(fos);
			savebmpDate(fos);
			fos.flush();
			fos.close();
		}

 

          public void savebmpTop(OutputStream ops) throws Exception{
		ops.write('B');
		ops.write('M');
		int height=DrawListener.array.length;
		int width=DrawListener.array[0].length;
		int size=14+40+height*width*3+(4-width*3%4)*height;
		//位图文件的大小				
                size=14+40+hight*width*3+(4-width*3%4)*255
		writeInt(ops,size);
		writeShort(ops,(short) 0);
		writeShort(ops,(short) 0);
		writeInt(ops,54);
	}

 

       public void savebmpInfo(OutputStream ops) throws Exception{
		int height=DrawListener.array.length;
		int width=DrawListener.array[0].length;
		writeInt(ops,40);
		writeInt(ops,width);
		writeInt(ops,height);
		writeShort(ops, (short) 1);
		writeShort(ops, (short) 24);
		writeInt(ops,0);
		writeInt(ops,height*width*3+(4-width*3%4)*height);
		writeInt(ops,0);
		writeInt(ops,0);
		writeInt(ops,0);
		writeInt(ops,0);
	}

 

      public void savebmpDate(OutputStream ops) throws Exception{
		int height=DrawListener.array.length;
		int width=DrawListener.array[0].length;
		int m=0;
		if(width*3%4>0){
			m=4-width*3%4;
		}
		for(int i=height-1;i>=0;i--){
			for(int j=0;j<width;j++){
				int t=DrawListener.array[i][j];
				writeColor(ops,t);
			}
			for(int k=0;k<m;k++){
			ops.write(0);
		        }
		}
	}

 

        public void writeInt(OutputStream ops,int t) throws Exception{
		int a=(t>>24)&0xff;
		int b=(t>>16)&0xff;
		int c=(t>>8)&0xff;
		int d=t&0xff;
		ops.write(d);
		ops.write(c);
		ops.write(b);
		ops.write(a);
	}
	public void writeColor(OutputStream ops,int t) throws Exception{
		int b=(t>>16)&0xff;
		int c=(t>>8)&0xff;
		int d=t&0xff;
		ops.write(d);
		ops.write(c);
		ops.write(b);
	}
	public void writeShort(OutputStream ops,short t) throws Exception{
		int c=(t>>8)&0xff;
		int d=t&0xff;
		ops.write(d);
		ops.write(c);
	}

 

至此,整个保存bmp24位格式的代码就写完了,虽然只是部分代码,但还是感觉很多啊╮(╯▽╰)╭。每次我都是写完之后才感觉整个项目的难度系数不大。本项目就是系统是C语言的存储的字节使用Java处理起来有点小复杂而已。掌握了整个bmp格式的数据结构其实很容易实现。

1
1
分享到:
评论

相关推荐

    C++Builder精彩编程实例集锦的源代码后3部分.rar

    实例047 如何在程序中自定义系统菜单 实例048 如何在执行程序间进行数据通信 实例049 如何使用OLE技术启动画图 实例050 如何在程序中添加Word文档表格 实例051 如何在程序中设置Word文档的字体风格 实例052 ...

    看图王2013 V2.6正式版

    相比简陋的画图板和复杂的Photoshop。2345看图王的内置功能都简单易学,方便性使用性兼备。 【看图王最新版更新日志】 2013看图王V2.7 正式版 1. 新增图库,DIY的多图浏览更惬意! 2. 新增一键收藏图片功能,方便、...

    EXCEL集成工具箱V6.0

    【系统常用工具】 系统常用工具的快捷调用,例如:计算器、记事本、WORD、画图板。 【隐藏选项卡】 可以隐藏Excel2007及2010功能区的各选项卡(如:开始、插入、开发工具等)。 图 片 工 具 【选择本表图片】 将...

    Visual C++程序开发范例宝典(光盘) 第四部分

    实例085 浏览大幅BMP图片 实例086 放大和缩小图片 实例087 可随鼠标移动的图形 实例088 随图像大小变换的图像浏览器 3.3 图片效果 实例089 图片马赛克效果 实例090 图片百叶窗效果 实例091 电影胶片特效 ...

    Visual C++程序开发范例宝典(光盘) 第八部分

    实例085 浏览大幅BMP图片 实例086 放大和缩小图片 实例087 可随鼠标移动的图形 实例088 随图像大小变换的图像浏览器 3.3 图片效果 实例089 图片马赛克效果 实例090 图片百叶窗效果 实例091 电影胶片特效 ...

    EXCEL集成工具箱V8.0完整增强版(精简)

    【系统常用工具】 系统常用工具的快捷调用,例如:计算器、记事本、WORD、画图板。 【隐藏选项卡】 可以隐藏Excel2007及2010功能区的各选项卡(如:开始、插入、开发工具等)。 图 片 工 具 【选择本表图片】 将...

    Visual C++ 程序开发范例宝典 源码 光盘 part2

    cc实例178 内存使用状态 cc实例179 监视剪贴板内容 cc实例180 利用钩子技术实现键盘监控 6.6 程序相关设置 cc实例181 用列表显示系统正在运行的程序 cc实例182 为程序添加快捷方式 cc实例183 设置其他...

    Visual C++程序开发范例宝典(PDF扫描版).part2

     cc实例085 浏览大幅BMP图片   cc实例086 放大和缩小图片   cc实例087 可随鼠标移动的图形   cc实例088 随图像大小变换的图像浏览器   3.3 图片效果   cc实例089 图片马赛克效果   cc实例090 ...

    Visual C++程序开发范例宝典(PDF扫描版).part3

     cc实例085 浏览大幅BMP图片   cc实例086 放大和缩小图片   cc实例087 可随鼠标移动的图形   cc实例088 随图像大小变换的图像浏览器   3.3 图片效果   cc实例089 图片马赛克效果   cc实例090 ...

    C#程序开发范例宝典(第2版).part13

    实例106 使用EventLog组件保存Windows系统日志 153 实例107 使用EventLog组件向本机现有日志中添加条目 155 3.4 FileSystemWatcher组件 156 实例108 使用FileSystemWatcher组件监视系统日志文件是否被更改 157 ...

    GetScreen v1.0

    命令:这是为了方便对所截的图进行编辑而设置的,默认为用Windows画图板进行编辑,当然你也可以自定义编辑命令。 关于截图: 截图界面下,“关闭”结束程序,“取消”取消截图,“设置”进入设置,“编辑”编辑所选...

    C#程序开发范例宝典(第2版).part02

    实例106 使用EventLog组件保存Windows系统日志 153 实例107 使用EventLog组件向本机现有日志中添加条目 155 3.4 FileSystemWatcher组件 156 实例108 使用FileSystemWatcher组件监视系统日志文件是否被更改 157 ...

    C#程序开发范例宝典(第2版).part08

    实例106 使用EventLog组件保存Windows系统日志 153 实例107 使用EventLog组件向本机现有日志中添加条目 155 3.4 FileSystemWatcher组件 156 实例108 使用FileSystemWatcher组件监视系统日志文件是否被更改 157 ...

    C#程序开发范例宝典(第2版).part12

    实例106 使用EventLog组件保存Windows系统日志 153 实例107 使用EventLog组件向本机现有日志中添加条目 155 3.4 FileSystemWatcher组件 156 实例108 使用FileSystemWatcher组件监视系统日志文件是否被更改 157 ...

Global site tag (gtag.js) - Google Analytics