flex实现手写在线签名

企业信息系统中,有时候需要用到手写签名的功能。在这里用flex 实现一个。功能实现了,效果还在改善中。
     在线手写签名分两部份。第一部分是画图功能的实现,第二部份是上传图片的功能(上传到服务器或保存到本地)。
     画图:画图比较简单,只要用到了graphics对像的几个方法。当鼠标按下时,调用graphics的beginFill和moveTo方法。同时,还要把调用了lineTo的方法加入到鼠标的MOUSE_MOVE事件中。代码如下:

Actionscript代码
  1. package com.humanmonth.home.component.page.signature  
  2. {  
  3.     import flash.display.CapsStyle;  
  4.     import flash.display.JointStyle;  
  5.     import flash.display.LineScaleMode;  
  6.     import flash.events.MouseEvent;  
  7.       
  8.     import mx.containers.Canvas;  
  9.     import mx.core.UIComponent;  
  10.       
  11.     /**  
  12.      * 实现手写签名的白板  
  13.      * @author presses  
  14.      *   
  15.      */  
  16.     public class WriteArea extends Canvas  
  17.     {  
  18.         /**  
  19.          *笔   
  20.          */  
  21.         public var signature:UIComponent=new UIComponent();  
  22.         /**  
  23.          *颜色   
  24.          */  
  25.         public var myColor:uint=0x000000 ;  
  26.         /**  
  27.          *线条粗细   
  28.          */  
  29.         public var lineSize:int=1 ;  
  30.         /**  
  31.          *模式   
  32.          */  
  33.         public var pattern:String="圆珠笔";  
  34.         /**  
  35.          *当前的x座标   
  36.          */  
  37.         private var cX:Number;  
  38.         /**  
  39.          *当前的y座标   
  40.          */  
  41.         private var cY:Number;  
  42.           
  43.         public function WriteArea()  
  44.         {  
  45.             this.addChild(signature);  
  46.             this.addEventListener(MouseEvent.MOUSE_DOWN,beginDraw);  
  47.             this.addEventListener(MouseEvent.MOUSE_UP,endDraw);  
  48.         }  
  49.           
  50.         /**  
  51.          *鼠标压下时,开始画图,并添加移动鼠标画线的监听器   
  52.          */  
  53.         private function beginDraw(event:MouseEvent):void{  
  54.             this.signature.graphics.lineStyle(lineSize,myColor,1 ,true,LineScaleMode.NONE,CapsStyle.ROUND,JointStyle.ROUND, 99 );  
  55.             this.signature.graphics.beginFill(myColor);  
  56.             this.cX=event.localX;  
  57.             this.cY=event.localY;  
  58.             this.signature.graphics.moveTo(this.cX,this.cY);  
  59.             this.addEventListener(MouseEvent.MOUSE_MOVE,drawIng);  
  60.         }  
  61.           
  62.         /**  
  63.          * 鼠标移动时,画线   
  64.          */  
  65.         private function drawIng(event:MouseEvent):void{  
  66.             if(this.pattern=="圆珠笔"){  
  67.                 this.signature.graphics.moveTo(this.cX,this.cY);  
  68.             }  
  69.             this.signature.graphics.lineTo(event.localX,event.localY);  
  70.             this.cX=event.localX;  
  71.             this.cY=event.localY;  
  72.         }  
  73.           
  74.         /**  
  75.          * 结束画图   
  76.          */  
  77.         private function endDraw(event:MouseEvent):void{  
  78.             this.removeEventListener(MouseEvent.MOUSE_MOVE,drawIng);  
  79.         }  
  80.           
  81.     }  
  82. }  


            上传签名图片(上传到服务器或保存到本地):fp10(flash player)可以不经服务器,直接把图片保存到本地。但为了兼容fp9,这里的实现是先把图片上传到服务器,再调用下载功能。实现的思路是先把画图的组 件转化为BitmapData,然后再编码成jpeg格式,并上传到服务器。最后调用客户端下载。这里要注意的一点是,fp10对下载的api作了限制, 下载动作只能由用户触发。代码如下:

Actionscript代码
  1. package com.humanmonth.home.component.page.signature.remote  
  2. {  
  3.     import com.humanmonth.global.Config;  
  4.       
  5.     import flash.display.BitmapData;  
  6.     import flash.events.Event;  
  7.     import flash.net.FileReference;  
  8.     import flash.net.URLLoader;  
  9.     import flash.net.URLRequest;  
  10.     import flash.net.URLRequestMethod;  
  11.       
  12.     import mx.controls.Alert;  
  13.     import mx.graphics.codec.JPEGEncoder;  
  14.     import mx.managers.CursorManager;  
  15.       
  16.     /**  
  17.      * 图片的上传及下载  
  18.      * @author presses  
  19.      *   
  20.      */  
  21.     public class Connector  
  22.     {  
  23.         private var file:FileReference;  
  24.         private var myId:String;  
  25.         public function Connector()  
  26.         {  
  27.         }  
  28.           
  29.         /**  
  30.          * 保存图片  
  31.          */  
  32.         public function savePic(myData:BitmapData,fun:Function):void{  
  33.             CursorManager.setBusyCursor();  
  34.             var url:String=Config.picLink+"rea/pic.do?action=savePic&timestamp="+new Date().getTime();  
  35.             var request:URLRequest = new URLRequest(url);             
  36.             request.method=URLRequestMethod.POST;  
  37.             request.contentType = "application/octet-stream";   
  38.             request.data=new JPEGEncoder(80 ).encode(myData);  
  39.             var loader:URLLoader = new URLLoader();                    
  40.             loader.load(request) ;          
  41.             loader.addEventListener(Event.COMPLETE, fun) ;    
  42.             loader.addEventListener(Event.COMPLETE,initMyId);  
  43.             Alert.show("正在上传图片,等待数秒后,即可下载图片");          
  44.         }  
  45.           
  46.         private function initMyId(event:Event):void{  
  47.             CursorManager.removeBusyCursor();  
  48.             var loader:URLLoader=URLLoader(event.target);  
  49.             this.myId=loader.data;  
  50.             Alert.show("上传图片成功,现在可以点击‘下载图片’按钮,保存图片到本地。");  
  51.               
  52.         }  
  53.           
  54.         /**  
  55.          * 下载图片   
  56.          */  
  57.         public function downloadFile(event:Event):void{  
  58.             var url2:String=Config.picLink+"rea/pic.do?action=queryPicById&pid="+myId+"&timestamp="+new Date().getTime();  
  59.             var req:URLRequest=new URLRequest(url2);  
  60.             file=new FileReference();  
  61.             file.download(req,"humanmonth.jpg");  
  62.         }  
  63.     }  
  64. }  


Actionscript代码
  1. package com.humanmonth.home.component.page.signature  
  2. {  
  3.     import com.humanmonth.home.component.page.signature.remote.Connector;  
  4.       
  5.     import flash.display.BitmapData;  
  6.     import flash.events.Event;  
  7.     import flash.events.MouseEvent;  
  8.       
  9.     import mx.core.Application;  
  10.     import mx.events.ColorPickerEvent;  
  11.     import mx.events.FlexEvent;  
  12.     import mx.events.ListEvent;  
  13.     import mx.events.NumericStepperEvent;  
  14.       
  15.     /**  
  16.      * 控制面版  
  17.      * @author presses  
  18.      *   
  19.      */  
  20.     public class MyControlBarAs extends MyControlBar  
  21.     {  
  22.         public var writearea:WriteArea;  
  23.         private var connector:Connector=new Connector();  
  24.         public function MyControlBarAs()  
  25.         {  
  26.             super();  
  27.             this.addEventListener(FlexEvent.CREATION_COMPLETE,myInit);  
  28.         }  
  29.           
  30.         private function myInit(event:Event):void{  
  31.             this.writearea=Application.application.signature.writearea;  
  32.             this.reset.addEventListener(MouseEvent.CLICK,cleanArea);  
  33.             this.size.addEventListener(NumericStepperEvent.CHANGE,setLineSize);  
  34.             this.color.addEventListener(ColorPickerEvent.CHANGE,setColor);  
  35.             this.pattern.addEventListener(ListEvent.CHANGE,setPattern);  
  36.             this.savePic.addEventListener(MouseEvent.CLICK,savePicture);  
  37.             this.downloadPic.addEventListener(MouseEvent.CLICK,connector.downloadFile)  
  38.         }  
  39.         /**  
  40.          * 保存图片   
  41.          */  
  42.         private function savePicture(event:Event):void{  
  43.             var myData:BitmapData=new BitmapData(this.writearea.width,this.writearea.height);  
  44.             myData.draw(this.writearea);  
  45.             connector.savePic(myData,enableDownload);   
  46.         }  
  47.           
  48.         private function enableDownload(event:Event):void{  
  49.             this.downloadPic.enabled=true;  
  50.         }  
  51.         /**  
  52.          * 设置模式   
  53.          */  
  54.         private function setPattern(event:Event):void{  
  55.             this.writearea.pattern=String(this.pattern.value);  
  56.         }  
  57.         /**  
  58.          * 清空写字区   
  59.          */  
  60.         private function cleanArea(event:Event):void{  
  61.             this.writearea.signature.graphics.clear();  
  62.         }  
  63.           
  64.         /**  
  65.          * 设置线条粗细   
  66.          */  
  67.         public function setLineSize(event:Event):void{  
  68.             this.writearea.lineSize=this.size.value;  
  69.         }  
  70.           
  71.         /**  
  72.          * 设置颜色  
  73.          */  
  74.         public function setColor(event:Event):void{  
  75.             this.writearea.myColor=uint(this.color.value);  
  76.         }  
  77.           
  78.           
  79.     }  
  80. }  


          到这里为止,功能已经实现了。但效果不太好。主要是签名时,笔画不圆滑,在flex 的api中,好像找不到在flash中设置圆滑的功能。

           效果图:http://rea.humanmonth.com/

评论

3 楼 presses 2009-06-14   引用

java端主要有两个方法。一个是接收客户端保存图片时的流,另一个是根据客户端的ID返回流。当前例子是运行在google app engine上的。以下是核心代码:
servlet:

Java代码
  1. /**  
  2.  *   
  3.  */   
  4. package  com.humanmonth.rea.pic;  
  5.   
  6. import  java.io.IOException;  
  7. import  java.util.logging.Logger;  
  8.   
  9. import  javax.servlet.http.HttpServletRequest;  
  10. import  javax.servlet.http.HttpServletResponse;  
  11.   
  12. import  org.apache.commons.io.IOUtils;  
  13.   
  14. import  com.google.appengine.api.datastore.Blob;  
  15. import  com.humanmonth.framework.web.servlet.Action;  
  16. import  com.humanmonth.framework.web.servlet.AutoMapperServlet;  
  17. import  com.humanmonth.framework.web.servlet.ServletUtil;  
  18.   
  19. /**  
  20.  * @author presses  
  21.  *   
  22.  */   
  23. @SuppressWarnings ( "serial" )  
  24. public   class  PictureServlet  extends  AutoMapperServlet {  
  25. private  Logger log=Logger.getLogger( this .getClass().getName());  
  26.     /**  
  27.      * 测试  
  28.      */   
  29.     @Action ( "sayHi" )  
  30.     public   void  sayHi(HttpServletRequest req, HttpServletResponse res)  throws  IOException {  
  31.         ServletUtil.outTips(res, "hi"null );  
  32.     }  
  33.   
  34.     /**  
  35.      * 保存图片  
  36.      */   
  37.     @Action ( "savePic" )  
  38.     public   void  savePic(HttpServletRequest req, HttpServletResponse res)  throws  IOException {  
  39. String name= ServletUtil  
  40. .getStringParameterWithTrim(req, "name" );  
  41. if (name== null ){  
  42.     name="签名.jpg" ;  
  43. }  
  44.         Picture pic = new  Picture(ServletUtil.getStringParameterWithTrim(req,  "module" ),name,  new  Blob(IOUtils.toByteArray(req.getInputStream())));  
  45.         new  PictureService().savePic(pic);  
  46.         log.info("保存的文件大小:" +pic.getContent().getBytes().length);  
  47.         ServletUtil.outView(res, pic.getId());  
  48.     }  
  49.   
  50.     /**  
  51.      * 查找所有图片  
  52.      */   
  53.     @Action ( "queryAllPic" )  
  54.     public   void  queryAllPic(HttpServletRequest req, HttpServletResponse res)  throws  IOException {  
  55.         String result = "" ;  
  56.         for  (Picture pic :  new  PictureService().queryAllPicture()) {  
  57.             if  (pic.getContent() ==  null ) {  
  58.                 continue ;  
  59.             }  
  60.             result += new  String(pic.getContent().getBytes(),  "utf-8" ) +  ":" ;  
  61.         }  
  62.         ServletUtil.outView(res, result);  
  63.     }  
  64.   
  65.     /**  
  66.      * 以ID获取图片  
  67.      */   
  68.     @Action ( "queryPicById" )  
  69.     public   void  queryPicById(HttpServletRequest req, HttpServletResponse res)  throws  IOException {  
  70.         String id = ServletUtil.getStringParameterWithTrim(req, "pid" );  
  71.         log.info("开始下载文件,ID为:" +id);  
  72.         Picture pic = new  PictureService().queryPicById(Long.valueOf(id));  
  73.         log.info("下载的文件大小:" +pic.getContent().getBytes().length);  
  74.         ServletUtil.downloadToClient(res, pic.getContent().getBytes(), pic.getName());  
  75.     }  
  76. }  
/**
 * 
 */
package com.humanmonth.rea.pic;

import java.io.IOException;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

import com.google.appengine.api.datastore.Blob;
import com.humanmonth.framework.web.servlet.Action;
import com.humanmonth.framework.web.servlet.AutoMapperServlet;
import com.humanmonth.framework.web.servlet.ServletUtil;

/**
 * @author presses
 * 
 */
@SuppressWarnings("serial")
public class PictureServlet extends AutoMapperServlet {
private Logger log=Logger.getLogger(this.getClass().getName());
	/**
	 * 测试
	 */
	@Action("sayHi")
	public void sayHi(HttpServletRequest req, HttpServletResponse res) throws IOException {
		ServletUtil.outTips(res, "hi", null);
	}

	/**
	 * 保存图片
	 */
	@Action("savePic")
	public void savePic(HttpServletRequest req, HttpServletResponse res) throws IOException {
String name= ServletUtil
.getStringParameterWithTrim(req, "name");
if(name==null){
	name="签名.jpg";
}
		Picture pic = new Picture(ServletUtil.getStringParameterWithTrim(req, "module"),name, new Blob(IOUtils.toByteArray(req.getInputStream())));
		new PictureService().savePic(pic);
		log.info("保存的文件大小:"+pic.getContent().getBytes().length);
		ServletUtil.outView(res, pic.getId());
	}

	/**
	 * 查找所有图片
	 */
	@Action("queryAllPic")
	public void queryAllPic(HttpServletRequest req, HttpServletResponse res) throws IOException {
		String result = "";
		for (Picture pic : new PictureService().queryAllPicture()) {
			if (pic.getContent() == null) {
				continue;
			}
			result += new String(pic.getContent().getBytes(), "utf-8") + ":";
		}
		ServletUtil.outView(res, result);
	}

	/**
	 * 以ID获取图片
	 */
	@Action("queryPicById")
	public void queryPicById(HttpServletRequest req, HttpServletResponse res) throws IOException {
		String id = ServletUtil.getStringParameterWithTrim(req, "pid");
		log.info("开始下载文件,ID为:"+id);
		Picture pic = new PictureService().queryPicById(Long.valueOf(id));
		log.info("下载的文件大小:"+pic.getContent().getBytes().length);
		ServletUtil.downloadToClient(res, pic.getContent().getBytes(), pic.getName());
	}
}



业务类:

Java代码
  1. /**  
  2.  *   
  3.  */   
  4. package  com.humanmonth.rea.pic;  
  5.   
  6. import  java.util.List;  
  7. import  java.util.logging.Logger;  
  8.   
  9. import  javax.jdo.PersistenceManager;  
  10.   
  11. import  com.humanmonth.framework.dao.JDOTemplate;  
  12.   
  13. /**  
  14.  * @author presses  
  15.  *   
  16.  */   
  17. public   class  PictureService {  
  18.     @SuppressWarnings ( "unused" )  
  19.     private   final  Logger log=Logger.getLogger( this .getClass().getName());  
  20.     /**  
  21.      * 保存图片  
  22.      */   
  23.     public   void  savePic( final  Picture pic) {  
  24.         new  JDOTemplate<Picture>() {  
  25.             @Override   
  26.             public   void  deal(PersistenceManager pm, List<Picture> result) {  
  27.                 pm.makePersistent(pic);  
  28.                 pm.flush();  
  29.             }  
  30.         }.execute();  
  31.     }  
  32.   
  33.     /**  
  34.      * 以ID和条件获取图片  
  35.      */   
  36.     public  Picture queryPicById( final  Long id) {  
  37.         return   new  JDOTemplate<Picture>() {  
  38.             @Override   
  39.             public   void  deal(PersistenceManager pm, List<Picture> result) {  
  40.                 result.add((Picture) pm.getObjectById(Picture.class ,id));  
  41.             }  
  42.         }.execute().get(0 );  
  43.     }  
  44.   
  45.     /**  
  46.      * 查找所有的图片  
  47.      */   
  48.     public  List<Picture> queryAllPicture() {  
  49.         return   new  JDOTemplate<Picture>() {  
  50.             @SuppressWarnings ( "unchecked" )  
  51.             @Override   
  52.             public   void  deal(PersistenceManager pm, List<Picture> result) {  
  53.                 Object obj = pm.newQuery("select from "  + Picture. class .getName()).execute();  
  54.                 result.addAll((List<Picture>) obj);  
  55.             }  
  56.         }.execute();  
  57.     }  
  58. }  
/**
 * 
 */
package com.humanmonth.rea.pic;

import java.util.List;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;

import com.humanmonth.framework.dao.JDOTemplate;

/**
 * @author presses
 * 
 */
public class PictureService {
	@SuppressWarnings("unused")
	private final Logger log=Logger.getLogger(this.getClass().getName());
	/**
	 * 保存图片
	 */
	public void savePic(final Picture pic) {
		new JDOTemplate<Picture>() {
			@Override
			public void deal(PersistenceManager pm, List<Picture> result) {
				pm.makePersistent(pic);
				pm.flush();
			}
		}.execute();
	}

	/**
	 * 以ID和条件获取图片
	 */
	public Picture queryPicById(final Long id) {
		return new JDOTemplate<Picture>() {
			@Override
			public void deal(PersistenceManager pm, List<Picture> result) {
				result.add((Picture) pm.getObjectById(Picture.class,id));
			}
		}.execute().get(0);
	}

	/**
	 * 查找所有的图片
	 */
	public List<Picture> queryAllPicture() {
		return new JDOTemplate<Picture>() {
			@SuppressWarnings("unchecked")
			@Override
			public void deal(PersistenceManager pm, List<Picture> result) {
				Object obj = pm.newQuery("select from " + Picture.class.getName()).execute();
				result.addAll((List<Picture>) obj);
			}
		}.execute();
	}
}



域对像:

Java代码
  1. package  com.humanmonth.rea.pic;  
  2.   
  3. import  java.sql.Date;  
  4.   
  5. import  javax.jdo.annotations.IdGeneratorStrategy;  
  6. import  javax.jdo.annotations.IdentityType;  
  7. import  javax.jdo.annotations.PersistenceCapable;  
  8. import  javax.jdo.annotations.Persistent;  
  9. import  javax.jdo.annotations.PrimaryKey;  
  10.   
  11. import  com.google.appengine.api.datastore.Blob;  
  12.   
  13. /**  
  14.  * 图片  
  15.  *   
  16.  * @author presses  
  17.  *   
  18.  */   
  19. @PersistenceCapable (identityType = IdentityType.APPLICATION)  
  20. public   class  Picture {  
  21.     /**  
  22.      * 主键  
  23.      */   
  24.     @PrimaryKey   
  25.     @Persistent (valueStrategy = IdGeneratorStrategy.IDENTITY)  
  26.     private  Long id;  
  27.     /**  
  28.      * 模块  
  29.      */   
  30.     @Persistent   
  31.     private  String module;  
  32.     /**  
  33.      * 文件名  
  34.      */   
  35.     @Persistent   
  36.     private  String name;  
  37.     /**  
  38.      * 内容  
  39.      */   
  40.     @Persistent   
  41.     private  Blob content;  
  42.     /**  
  43.      * 保存时间  
  44.      */   
  45.     @Persistent   
  46.     private  Date date;  
  47.   
  48.     public  Picture(String module, String name,Blob content) {  
  49.         this .module = module;  
  50.         this .name=name;  
  51.         this .content = content;  
  52.   
  53.     }  
  54.   
  55.     public  Long getId() {  
  56.         return  id;  
  57.     }  
  58.   
  59.     public   void  setId(Long id) {  
  60.         this .id = id;  
  61.     }  
  62.   
  63.     public  String getModule() {  
  64.         return  module;  
  65.     }  
  66.   
  67.     public   void  setModule(String module) {  
  68.         this .module = module;  
  69.     }  
  70.   
  71.     public  Date getDate() {  
  72.         return  date;  
  73.     }  
  74.   
  75.     public   void  setDate(Date date) {  
  76.         this .date = date;  
  77.     }  
  78.   
  79.     public  Blob getContent() {  
  80.         return  content;  
  81.     }  
  82.   
  83.     public   void  setContent(Blob content) {  
  84.         this .content = content;  
  85.     }  
  86.   
  87.     public  String getName() {  
  88.         return  name;  
  89.     }  
  90.   
  91.     public   void  setName(String name) {  
  92.         this .name = name;  
  93.     }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值