Flash在线签名小程序,可回放,动态导出gif图片
需求:
公司为了使得和客户领导签字的时候记录下来,签字过程,可以以后动态回放演示,最好是gif图片,在网页上也容易展示,文件也小。
解决过程:
始我们去寻找各种app,最终也没有找到合适的,后来我在flash8上看到有个在线的手绘板,很适合我们的需求,但是我尝试了很多次
绘画完成后,导出的是swf文件,我想从这个swf文件中抽出图片,最终发现这个导出的swf里面根本不存在我绘画的记录过程。
网上确实有手绘板的代码,但是没有动态回放的功能及到处gif图片的功能,还是不满足我们需求,
索性自己写了一个flash小程序实现手绘画板及动态回放功能。我把具体的思路及详细代码都贴出来,
希望能给有用到的人带来方便。
整体思路:
- 编写一个flash程序,实现基本手绘板功能
- 在基础上实现回放功能(这里是难点)
- 创建一个asp.ne站点,写个一般处理程序GetSignImg.ashx,用于存储flash发布时候动态创建的jpg图片
- 当swf程序发布后点击下载的时候,后台程序将所有的jpg图片拼成gif图片导出(使用了Gif.Components.dll)。
截图:


具体过程
一、实现手绘板功能,在网上能找到很多代码,这块也简单。
二、在基础上实现回放功能,我重点讲下这里的实现,起初我是这么判断的,当鼠标MOUSE_DOWN时候开始记录画笔当前位置信息存入一个数组中(包含X,Y坐标值),
鼠标MOUSE_UP的时候,这个数组存储结束,开启一个新的数组用于点的信息。当回放的时候,将这些所有数组中的点的信息重新绘制一遍,包括flash8.net的实现都是这么干的
如果一笔绘制很长,当它回放的时候一下子全显示出来,没有一个绘制的过程。后来领导说这样不行,因为领导签字的时候很多都是一笔走完,最后我想了一个解决的办法,
就是在回放的时候设置一个阀值,比如50个点,够50个点就回放一次,这样一来,即使领导签字是一笔,回放的时候效果也会很好。
下面是所有ActinScipt源码
import flash.ui.Mouse;
import flash.display.BitmapData;
import com.adobe.images.JPGEncoder;
import flash.events.MouseEvent; var linesize:uint = 2;//画笔大小
var isDown:Boolean = false;
var oldX:Number;
var oldY:Number;
var arrayBig:Array=new Array();//存放笔画的数组,外层数组
var num:uint = 0;//当前数组个数
var playNum:uint = 0;//当前回放的数字(代表当前回放到第几个数组了)
var intervalDuration:Number = 500;// 回放延时时间间隔
var relaseDuration:Number = 1000;//发布时时间间隔
var intervalId:uint;//回放循环的ID
var relaseId:uint;//发布的ID
var url = "http://www.wispdawn.com/";//暂用我的网站做服务器
var serviceFile = "GetSignImg.ashx";//服务文件 mc_canvas.addEventListener(MouseEvent.MOUSE_DOWN ,onDown);
mc_canvas.addEventListener(MouseEvent.MOUSE_UP ,onUp);
mc_canvas.addEventListener(MouseEvent.MOUSE_MOVE ,onMove);
mc_canvas.addEventListener(MouseEvent.MOUSE_OVER,onMouseOver);
mc_canvas.addEventListener(MouseEvent.MOUSE_OUT,onMouseOut); function onDown(event:MouseEvent):void
{
arrayBig[num]=new Array();//这里设置为数组
isDown = true;
oldX = mouseX;
oldY = mouseY;
}
function onMove(event:MouseEvent):void
{
if (isDown)
{
mc_canvas.graphics.lineStyle(linesize);
mc_canvas.graphics.moveTo(oldX,oldY);
mc_canvas.graphics.lineTo(mouseX,mouseY);
oldX = mouseX;
oldY = mouseY;
arrayBig[num].push([oldX,oldY]);
if (arrayBig[num].length > 80)
{
//isDown = false;
trace(num);
num++;//数组个数+1
arrayBig[num]=new Array();
arrayBig[num].push([oldX,oldY]);
}
}
} function onUp(event:MouseEvent):void
{
isDown = false;
trace(num);
num++;//数组个数+1
} function onMouseOver(event:MouseEvent):void
{
mc_canvas.addEventListener(Event.ENTER_FRAME, onEnter);
} function onMouseOut(event:MouseEvent):void
{
mc_canvas.removeEventListener(Event.ENTER_FRAME, onEnter);
Mouse.show();
mc_pen.visible = false;
} //画布监听事件
function onEnter(event:Event):void
{
Mouse.hide();
mc_pen.visible = true;
mc_pen.x = mouseX + 22;
mc_pen.y = mouseY + 22;
} //清空
btn_clear.addEventListener(MouseEvent.CLICK,onClear);
function onClear(event:MouseEvent):void
{
arrayBig = [];
playNum = 0;
num = 0;
mc_canvas.graphics.clear();
}
//保存;
btn_save.addEventListener(MouseEvent.CLICK,onSave);
function onSave(event:MouseEvent):void
{
var imager:BitmapData = new BitmapData(mc_canvas.width,mc_canvas.height);
imager.draw(mc_canvas);
var jpg:JPGEncoder = new JPGEncoder(100);
var file:FileReference = new FileReference();
file.save(jpg.encode(imager),"sign.jpg"); } //回放按钮
btn_replay.addEventListener(MouseEvent.CLICK,onReplay);
function onReplay(event:MouseEvent):void
{
if (arrayBig.length > 0)
{
mc_canvas.graphics.clear();
//清除画面;
playNum = 0;//初始为0
intervalId = setInterval(onReplayDelay,intervalDuration);
}
} //用于设置循环的回放
function onReplayDelay():void
{
//当前笔画
var arr:Array = arrayBig[playNum];
//当前笔画下面所有的点
for (var i:uint=0; i<arr.length-1; i++)
{
var curPoint = arr[i];
var nexPoint = arr[i + 1];
mc_canvas.graphics.lineStyle(linesize);
mc_canvas.graphics.moveTo(curPoint[0],curPoint[1]);
mc_canvas.graphics.lineTo(nexPoint[0],nexPoint[1]);
} playNum++;
if (playNum==num)
{
clearInterval(intervalId);
}
} //上传图片
function UpImg(seq:uint):void
{
var imager:BitmapData = new BitmapData(mc_canvas.width,mc_canvas.height);
imager.draw(mc_canvas);
var jpg:JPGEncoder = new JPGEncoder(100);
var bytes:ByteArray = jpg.encode(imager); var signName:String = mc_mask.txt_name.text;
var req:URLRequest = new URLRequest(url+serviceFile+"?name="+signName+"&seq="+seq+"&total="+arrayBig.length);
req.data = bytes;
req.method = URLRequestMethod.POST;
req.contentType = "application/octet-stream"; var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.load(req);
}
//loader.addEventListener(Event.COMPLETE, completeHandler); //function completeHandler(evt:Event):void
//{
//trace(evt.target.data);
//} //发布
btn_release.addEventListener(MouseEvent.CLICK,onReleas);
function onReleas(event:MouseEvent):void
{
if (arrayBig.length > 0)
{
mc_mask.x = mc_mask.y = 0;
mc_mask.mc_mask_bg.alpha = 0.8;
mc_mask.btn_complete.visible = false;//隐藏完成
mc_mask.btn_down.visible = false;//隐藏下载
}
}
//真正发布事件执行
function Release():void
{
//当前笔画
var arr:Array = arrayBig[playNum];
//当前笔画下面所有的点
for (var i:uint=0; i<arr.length-1; i++)
{
var curPoint = arr[i];
var nexPoint = arr[i + 1];
mc_canvas.graphics.lineStyle(linesize);
mc_canvas.graphics.moveTo(curPoint[0],curPoint[1]);
mc_canvas.graphics.lineTo(nexPoint[0],nexPoint[1]);
}
//上传图片;;
UpImg(playNum);
playNum++;
if (playNum==num)
{
clearInterval(relaseId);
AfterRelease();
}
}
//取消发布
mc_mask.btn_cancel.addEventListener(MouseEvent.CLICK,onCancel);
function onCancel(event:MouseEvent):void
{
mc_mask.x = 10000;
mc_mask.mc_mask_bg.alpha = 0;
}
//真正发布按钮
mc_mask.btn_release.addEventListener(MouseEvent.CLICK,onTrueRelease);
function onTrueRelease(event:MouseEvent):void
{
var name1 = mc_mask.txt_name.text;
if (name1!="")
{
BeginRelease();
mc_canvas.graphics.clear();
playNum = 0;
relaseId = setInterval(Release,relaseDuration);
}
else
{
mc_mask.txt_state.text = "请输入姓名";
}
}
//发布前设置
function BeginRelease():void
{
mc_mask.btn_release.visible = false;
mc_mask.btn_cancel.visible = false;
mc_mask.txt_name.visible = false;
mc_mask.txt_nameTile.visible = false;
mc_mask.txt_state.text = "正在发布...";
}
//发布后设置
function AfterRelease():void
{
mc_mask.btn_complete.visible = true;
mc_mask.btn_down.visible = true;
mc_mask.btn_complete.addEventListener(MouseEvent.CLICK,onComplete);
mc_mask.txt_state.text = "发布完成"; }
//发布完成
function onComplete(event:MouseEvent):void
{
mc_mask.x = 10000;
mc_mask.mc_mask_bg.alpha = 0;
mc_mask.btn_down.visible = true;
mc_mask.btn_release.visible = true;
mc_mask.btn_cancel.visible = true;
mc_mask.txt_name.visible = true;
mc_mask.txt_nameTile.visible = true;
mc_mask.txt_state.text = "";
mc_mask.txt_name.text = "";
} //下载gif
mc_mask.btn_down.addEventListener(MouseEvent.CLICK,onDownGif);
function onDownGif(event:MouseEvent):void
{
var today:Date =new Date();
var todayStr = getDateFormat(today);//获取当天日期例如 20131130
var signName:String = mc_mask.txt_name.text; var gifUrl:URLRequest = new URLRequest(url+"/Img/"+signName+"_"+todayStr+"/"+signName+".gif");
var fileRef:FileReference=new FileReference();
//fileRef.addEventListener(ProgressEvent.PROGRESS,onProgress);
fileRef.download(gifUrl,"sign.gif");
}
function onProgress(event:ProgressEvent):void
{
var loaded:uint = event.bytesLoaded;
var total:uint = event.bytesTotal;
} //获取当天日期
function getDateFormat( date:Date):String
{
var dYear:String = String(date.getFullYear());
var dMonth:String = String((date.getMonth() + 1 < 10) ? "0" : "") + (date.getMonth() + 1);
var dDate:String = String(date.getDate() < 10 ? "0":"") + date.getDate();
return dYear+dMonth+dDate;
}
三、创建一个asp.ne站点,写个一般处理程序GetSignImg.ashx
这里就是用于的获取flash传递过来的图片,获取后导出jpg图片序列,然后将这些序列图片用程序生成一个gif图片存放在目录下,当flash点击到处gif图片时候,执行下载
源文件如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using Gif.Components; namespace Web
{
/// <summary>
/// GetSignImg1 的摘要说明
/// </summary>
public class GetSignImg1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string name = context.Request["name"];
int seq = Convert.ToInt32(context.Request["seq"]);
int total =Convert.ToInt32(context.Request["total"]);
int length = context.Request.TotalBytes;
byte[] buffer = context.Request.BinaryRead(length);
string newPath=HttpContext.Current.Server.MapPath("Img/" + name + "_"+DateTime.Now.ToString("yyyyMMdd"));
if (!Directory.Exists(newPath))
{
Directory.CreateDirectory(newPath);
};
string path = string.Format("{0}/{1}.jpg", newPath, seq);
FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(buffer);
bw.Close();
fs.Close(); //下载gif
if (seq + == total)
{
//生成gif图片
List<string> fileList = new List<string>();
for (int i = ; i < total; i++)
{
fileList.Add(newPath + "/" + i + ".jpg");
}
string[] imageFilePaths = fileList.ToArray();
string outputFilePath = newPath + "/" + name + ".gif";
AnimatedGifEncoder e = new AnimatedGifEncoder();
e.Start(outputFilePath);
//图片转换时间
e.SetDelay();
//1表示只动一次,0:表示循环,n:表示循环n次
e.SetRepeat();
for (int i = , count = imageFilePaths.Length; i < count; i++)
{
e.AddFrame(System.Drawing.Image.FromFile(imageFilePaths[i]));
}
e.Finish();
}
} public bool IsReusable
{
get
{
return false;
}
}
}
}
GetSignImg.ashx.cs
四、所有程序打包下载 Download
Flash在线签名小程序,可回放,动态导出gif图片的更多相关文章
- C#做的在线升级小程序
转自原文C#做的在线升级小程序 日前收到一个小任务,要做一个通用的在线升级程序.更新的内容包括一些dll或exe或.配置文件.升级的大致流程是这样的,从服务器获取一个更新的配置文件,经过核对后如有新的 ...
- 解决微信小程序安卓手机访问不到图片,无法显示图片
关于微信小程序不显示图片 通病可能有以下几个可能性: 非本地图片:确定图片资源存在,copy 图片url再浏览器打开,确定图片资源存在且能正常访问 本地图片:确定相对路径或者绝对路径正确 微信小程序图 ...
- 微信小程序换皮肤,动态切换菜单栏和导航栏的样式,动态修改TabBar和NavigationBar
在做微信小程序换皮肤的时候,需要动态修改菜单栏(TabBar)和导航栏(NavigationBar) 但是在小程序中它们的样式是写在app.json里面,而且app.json是静态编译,运行时哪怕你修 ...
- 微信小程序web-view之动态加载html页面
官方推出的web-view方便了很多开发人员. 我们在做的时候,经常会想到写一个小程序的page然后通过动态加载web-view的形式来完成其他功能页面的开发. 之前研究web-view的时候发现网上 ...
- 微信小程序之一:动态添加view(view包含picker,input)
<view wx:for="{{array}}" wx:key="this" class="borderContainer"> ...
- 微信小程序request请求动态获取数据
微信小程序开发文档链接 1 后台代码: clickButton:function(){ var that = this; wx.request({ url: 'http://localhost:909 ...
- Java 获取微信小程序二维码(可以指定小程序页面 与 动态参数)
一.准备工作 微信公众平台接口调试工具 小程序的唯一标识(appid) 小程序的密钥(secret) 二.获取access_token 打开微信公众平台接口调试工具,在参数列表中输入小程序的appid ...
- 微信小程序利用canvas生成海报分享图片
一 . 效果 这是借用女神照生成的分享的海报,图片来自网络. 新增了poster组件和更新图片自适应 二 . 准备 准备两张图片连接,最好是自己开发账号验证的https图片链接. 三 . 实现思路 其 ...
- 关于微信小程序使用canvas生成图片,内容图片跨域的问题
最近有个项目是保存为名片(图片),让用户发送给朋友或朋友圈,找了很多方案都不适用,绞尽脑汁之后还是选了使用canvas,但是用这玩意儿生成图片最大的缺点就是,如果你的内容中有图片,并且这个图片是通过外 ...
随机推荐
- java菜鸟笔记(一)
- vue v-on监听事件
在html或jsp页面中我们总能碰到监听DOM事件来触发javaScript代码,下面我们就简单聊聊Vue.js中的监听事件是怎么处理的. 在vue.js中监听事件是通过v-on指令来实现的,先看一下 ...
- UOJ66 新年的巧克力棒
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- keystone cache
http://docs.openstack.org/juno/config-reference/content/section_keystone.conf.html http://docs.opens ...
- review04
在编译源文件时,所用到的其他源文件也会被自动编译.这是因为它会使用到其他源文件产生的字节码文件. javac A.java A指的是源文件的名称 java B B指的是源文件中有main方法的类. 虽 ...
- HTML代码中的空格和空行
HTML 代码中的所有连续的空格或空行(换行)都会被显示为一个空格. 例子1:(文本内容中的连续空格) 代码 <p>这段文本中,输入连续的空格 大概输入了十个.</p> 显示效 ...
- 2018.7.30 Designing a Qi-compliant receiver coil for wireless power systems
1) 找资料: http://www.mouser.cn/datasheet/2/389/stwlc33-1156583.pdf https://training.ti.com/wireless-po ...
- git教程2-删除修改和文件
文件处于三种状态: 1.位于工作区,未修改状态: 2.位于工作区,已经修改状态: 3.位于暂存区,已经暂存但未commit. 4.已经commit. 一.文件删除修改: 1.已经修改,但未add: g ...
- Codeforces Round #276 (Div. 2)A. Factory(数论)
这道题可以暴力的一直按要求的方法去做,做1000000次还不能整除m就认为永远不能整除m了(m不超过100000,循环1000000次比较安全了已经).这种方法可以AC. 下面深入的分析一下到底循环多 ...
- cmake安装MySQL数据库实例
一.编译安装MySQL前的准备工作 首先检查是否有安装其他版本的编译器和数据库,先卸载干净. 安装编译源码所需的工具和库 yum install gcc gcc-c++ ncurses-devel p ...