需求:

公司为了使得和客户领导签字的时候记录下来,签字过程,可以以后动态回放演示,最好是gif图片,在网页上也容易展示,文件也小。

解决过程

始我们去寻找各种app,最终也没有找到合适的,后来我在flash8上看到有个在线的手绘板,很适合我们的需求,但是我尝试了很多次

绘画完成后,导出的是swf文件,我想从这个swf文件中抽出图片,最终发现这个导出的swf里面根本不存在我绘画的记录过程。

网上确实有手绘板的代码,但是没有动态回放的功能及到处gif图片的功能,还是不满足我们需求,

索性自己写了一个flash小程序实现手绘画板及动态回放功能。我把具体的思路及详细代码都贴出来,

希望能给有用到的人带来方便。

整体思路:

  1. 编写一个flash程序,实现基本手绘板功能
  2. 在基础上实现回放功能(这里是难点)
  3. 创建一个asp.ne站点,写个一般处理程序GetSignImg.ashx,用于存储flash发布时候动态创建的jpg图片
  4. 当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图片的更多相关文章

  1. C#做的在线升级小程序

    转自原文C#做的在线升级小程序 日前收到一个小任务,要做一个通用的在线升级程序.更新的内容包括一些dll或exe或.配置文件.升级的大致流程是这样的,从服务器获取一个更新的配置文件,经过核对后如有新的 ...

  2. 解决微信小程序安卓手机访问不到图片,无法显示图片

    关于微信小程序不显示图片 通病可能有以下几个可能性: 非本地图片:确定图片资源存在,copy 图片url再浏览器打开,确定图片资源存在且能正常访问 本地图片:确定相对路径或者绝对路径正确 微信小程序图 ...

  3. 微信小程序换皮肤,动态切换菜单栏和导航栏的样式,动态修改TabBar和NavigationBar

    在做微信小程序换皮肤的时候,需要动态修改菜单栏(TabBar)和导航栏(NavigationBar) 但是在小程序中它们的样式是写在app.json里面,而且app.json是静态编译,运行时哪怕你修 ...

  4. 微信小程序web-view之动态加载html页面

    官方推出的web-view方便了很多开发人员. 我们在做的时候,经常会想到写一个小程序的page然后通过动态加载web-view的形式来完成其他功能页面的开发. 之前研究web-view的时候发现网上 ...

  5. 微信小程序之一:动态添加view(view包含picker,input)

    <view wx:for="{{array}}" wx:key="this" class="borderContainer"> ...

  6. 微信小程序request请求动态获取数据

    微信小程序开发文档链接 1 后台代码: clickButton:function(){ var that = this; wx.request({ url: 'http://localhost:909 ...

  7. Java 获取微信小程序二维码(可以指定小程序页面 与 动态参数)

    一.准备工作 微信公众平台接口调试工具 小程序的唯一标识(appid) 小程序的密钥(secret) 二.获取access_token 打开微信公众平台接口调试工具,在参数列表中输入小程序的appid ...

  8. 微信小程序利用canvas生成海报分享图片

    一 . 效果 这是借用女神照生成的分享的海报,图片来自网络. 新增了poster组件和更新图片自适应 二 . 准备 准备两张图片连接,最好是自己开发账号验证的https图片链接. 三 . 实现思路 其 ...

  9. 关于微信小程序使用canvas生成图片,内容图片跨域的问题

    最近有个项目是保存为名片(图片),让用户发送给朋友或朋友圈,找了很多方案都不适用,绞尽脑汁之后还是选了使用canvas,但是用这玩意儿生成图片最大的缺点就是,如果你的内容中有图片,并且这个图片是通过外 ...

随机推荐

  1. Rem是什么,牛逼的Vue,Epub竟然可以实现阅读器功能。太牛了。

    rem 相当于根元素font-size值的倍数. 1rem=根元素font-size 2rem=根元素font-size * 2 // 1rem = fontSize px // 1px = (1/f ...

  2. NovaException: Unexpected vif_type=binding_failed

    nova/virt/libvirt/vif.py: _("Unexpected vif_type=%s") % vif_type) NovaException: Unexpecte ...

  3. DataWarehouse- 从面试定位自己的水平

    1.讲一下什么是维度表和事实表.用户资料表算是什么类型表. 2. 维度建模属于第几范式,让你对维度建模改进,有什么思路吗. 3. 了解数据血缘分析吗,让你实现的话有什么技术方案,感觉难点在哪. 4. ...

  4. 搜索5--noi1700:八皇后问题

    搜索5--noi1700:八皇后问题 一.心得 二.题目 1700:八皇后问题 查看 提交 统计 提问 总时间限制:  10000ms 内存限制:  65536kB 描述 在国际象棋棋盘上放置八个皇后 ...

  5. wpf数据绑定的论述

    (1)绑定模式: <Lable x:Name=lab Content={binding UserName} /> <!--binding相当于SetBinding--> Con ...

  6. 完全分布式安装hadoop集群

    0.安装jdk 1.配置hosts文件 2.建立hadoop运行账号 3.配置ssh免密码登录 4.在namenode上配置hadoop 4.1.修改hadoop-env.sh文件 4.2.修改yar ...

  7. Chrome Adobe flash player已过期怎么办

    越来越多的朋友感受到了来自谷歌chrome新版浏览器的压力,因为有不少朋友在使用新版chrome浏览器看视频时,却出现了这样的提示:Adobe flash player已过期!怎么办啊? 有网友抱怨: ...

  8. C# 高效过滤DataTable 中重复数据方法

    使用DataView,然后设置ToTable,设置几个字段和一个布尔值,表示这些字段作为一个整体,在这个表内不允许重复,示例代码: namespace A { class Program { stat ...

  9. wordpress 插件 汉化

    http://blog.wpjam.com/article/localizing-a-wordpress-plugin-using-poedit/ 翻译或者说本地化 WordPress 插件和主题可以 ...

  10. poj2010

    大学招n(n为奇数)个牛 招第i个牛需要ai块钱 第i个牛高考si分 输入招的牛数n 总的牛数c 总的钱数f 以及ai si 问用这些钱招的n个牛高考分数的中位数最大是多少 如果钱不够输出-1 这题结 ...