收藏本站腾讯微博新浪微博

经典论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

蓝色理想 最新研发动态 网站开通淘帖功能 - 蓝色理想插件 论坛内容导读一页看论坛 - 给官方提建议

论坛活动及任务 地图和邮件任务 请多用悬赏提问 热夏来袭,选一款蓝色理想的个性T恤吧!

手机上论坛,使用APP获得更好体验 急需前端攻城狮,获得内部推荐机会 论坛开通淘帖功能,收藏终于可以分类了!

搜索
查看: 11402|回复: 28

[分享] flash手写输入

[复制链接]
发表于 2010-4-15 00:52:33 | 显示全部楼层 |阅读模式
之前见有一些网友提到过此类问题,也有人讨论过了,大致原理就是坐标数据,然后根据点坐标去判断笔画,然后生成字符。最近无聊就尝试去试试,因为手写输入,难点就是根据数据生成笔画这,可惜我是前端的,后台数据不是太了解,所以就打算研究下现在网站上比较通用的flash手写输入。[大家不要问我,为什么不拿flash来做数据生成笔画,如果是让flash来做这个,光从效率上 笔画拆解 笔画匹对 字体筛选就决定了,尤其是第三点flash是不适合的]。

好了,言归正传,现在我就拿比较常见的http://hw.baidu.com/这个地址的手写输入来做参谋了
1.jpg
因为大家比较常见,所以我也不对这个多做介绍  
p.s 大家可以看见汉王 大大的Logo,对这个我比较有感情,以前做动画的时候,还是学生时代,买不起影拓,所以攒钱买了汉王的绘图板

因为我之前就分析了,flash是做表现层的,底层的肯定不是由flash来弄的,所以注定了它是有数据读写的,所以在好奇之心的驱动下,我开启了我浏览器中的HttpWatch,然后就试着随便写写,发现了swf真的post了数据给一个地址http://hw.baidu.com/ ,大家可以打开这个链接看看,网页里就是 {"s":"","t":3}这几个内容,貌似和我们的手写数据没有任何关联,其实不是这样的,因为我们单独打开是没有传入任何参数进去的,所以给人错觉了
所以现在我们根据httpWatch来分析下
2.jpg
大家注意红色圈内的内容,很显然有数据post到了之前那个地址,post的值为type =1,wd=一长串字符
好奇之下,接着写点东西,结果如下图
3.jpg
都一样,只是wd的内容更多了,前后两次对比后,发现这次的内容是上次内容的递加,这就说明了,这些数据,就是和我们输入笔画有关联的。

那这些到底和输入内容有何关系呢?
我们接着分析数据,因为是和笔画有关系的,而我之前是随便乱写的,不好分析数据,所以这次我们尝试有规律的写写,很简单,横竖就是我们所要做的
横的效果
4.jpg
发现wd=5a6a8a6a11a6a14a6a17a6a20a6a23a6a24a6貌似有点规律,很显然根据坐标(x,y)来分析下(5,6);(8,6);(11,6);(14,6)......后面依次类推了
发现这个规律和我们的一横的笔画很贴切,Y值不变,X值递加,而且递加的也很有规律间隔为3
为了验证我们的规律
再看看竖的效果
5.jpg
wd=15a14a15a17a16a19a16a22a16a25a16a28a17a30a17a33a17a36a17a39a17a42a19a45a18a48a18a51a19a53a20a55a20a57继续套用(x,y)   ->(15,14);(15,17);(16,19);(16,22)...
发现这个规律大致也成立,之余那个16和15的差别,大家可以看看我的线条,不是笔直的,所以可以将它们近似认为是直线吧,我们只是根据特殊情况来找规律,间隔也近似看作3

从上面两种情况我们可以理解为wd就是我们操作后的坐标数据,每个数据都是用a来隔开,为什么用a?我想是除了数值一外,a是比较通用的符号,毕竟在字母序列表里排第一 间隔为3,又是为什么?因为大家都知道两点构成一线,如果再多一个点,就可以判断出这3个点构成的线的走势是直线还是折线,也就是我们所理解的笔画了,这个是极限情况下特殊情况,你也可以理解在flash操作里,mouseDown mouseMove mouseUp这3个情况下的,所输出的极限数据,即最少的数据。

数据分析完毕了,剩下的工作就是我们在flash中去构建我们的逻辑,去实现了
因为时间比较晚了。。写教程真的耗时间
所以我就先放源文件和效果,因为代码比较简单,也没有去优化了
代码是为了凑成合格的数据而弄的,所以有点点乱,因为时间关系。。没有去细化,有问题明天再继续

  1. var pointTotalArr :Array   = [];
  2. var pointArr      :Array;
  3. var sp       :Sprite       = new Sprite();
  4. var lineSp:Sprite;
  5. addChild(sp);


  6. function onLoaded(event:Event):void {
  7.         var str:String = event.target.data;
  8.         var tempStr:String = str.slice(6,str.length-8);
  9.         var arr:Array  = tempStr.split("\\u");
  10.         txt.text         ="";
  11.         for (var i:uint = 1; i<arr.length; i++) {
  12.                 //trace(String.fromCharCode(Number("0x"+arr[i])));
  13.                 txt.appendText(String.fromCharCode(Number("0x"+arr[i]))+" ")
  14.         }
  15. }

  16. writeHotArea.addEventListener(MouseEvent.MOUSE_DOWN,onStageMouseDown);


  17. function onStageMouseDown(event:MouseEvent):void {
  18.         lineSp = new Sprite();
  19.         lineSp.graphics.clear();
  20.         lineSp.graphics.lineStyle(2);
  21.         lineSp.graphics.moveTo(mouseX,mouseY);
  22.         writeHotArea.addEventListener(MouseEvent.MOUSE_MOVE,onStageMouseMove);
  23.         pointArr = [];
  24.         pointArr.push(new Point(mouseX,mouseY));
  25.         pointTotalArr.push(pointArr);
  26.         sp.addChild(lineSp);
  27.         stage.addEventListener(MouseEvent.MOUSE_UP,onStageMouseUP);
  28. }

  29. function onStageMouseUP(event:MouseEvent):void {
  30.         writeHotArea.removeEventListener(MouseEvent.MOUSE_MOVE,onStageMouseMove);
  31.         stage.removeEventListener(MouseEvent.MOUSE_UP,onStageMouseUP);
  32.         var sendStr:String = "";
  33.         for (var j:uint = 0; j<pointTotalArr.length; j++) {
  34.                 if (j!=0) {
  35.                         sendStr+="a";
  36.                 }
  37.                 for (var i:uint = 0; i<pointTotalArr[j].length; i+=3) {
  38.                         sendStr+=pointTotalArr[j][i].x +"a"+pointTotalArr[j][i].y;
  39.                         if(i<(pointTotalArr[j].length-3))sendStr+="a"
  40.                 }
  41.         }
  42.         var urlLoader:URLLoader    = new URLLoader();
  43.         urlLoader.dataFormat       = URLLoaderDataFormat.TEXT;
  44.         var request:URLRequest     = new URLRequest("http://hw.baidu.com/");
  45.         request.method             = "post";
  46.         var urlLV    :URLVariables = new URLVariables();
  47.         urlLV.wd                   = sendStr;
  48.         urlLV.type                 = 1;
  49.         request.data = urlLV;
  50.         urlLoader.load(request);
  51.         urlLoader.addEventListener(Event.COMPLETE,onLoaded);
  52. }
  53. function onStageMouseMove(event:MouseEvent):void {
  54.         lineSp.graphics.lineTo(mouseX,mouseY);
  55.         pointArr.push(new Point(mouseX,mouseY));
  56.         event.updateAfterEvent();
  57. }

  58. reWriteBtn.addEventListener(MouseEvent.CLICK,onClick);

  59. function onClick(event:MouseEvent):void{
  60.         pointTotalArr = [];
  61.         txt.text         ="";
  62.         while(sp.numChildren>0) sp.removeChildAt(0);
  63. }
复制代码

手写.fla (671 KB, 下载次数: 1097)
 楼主| 发表于 2010-4-15 00:57:05 | 显示全部楼层
占位,可能需要补充

图片看不清楚,点击查看大图
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-4-15 12:00:18 | 显示全部楼层
有个细节昨晚忘记提示了
就是用户的每一个笔画输入时,数据都会加一个"a",用户分隔每一笔的数据
这也是为什么代码里
if (j!=0) {
   sendStr+="a";
}
除了第一个笔画不用加这个,其他的笔画都是需要在开始添加的
回复 支持 反对

使用道具 举报

发表于 2010-4-16 13:13:07 | 显示全部楼层
支持原创!!!!!
回复 支持 反对

使用道具 举报

发表于 2010-5-4 10:50:49 | 显示全部楼层
感谢楼主的大公无私,顶---
回复 支持 反对

使用道具 举报

发表于 2010-5-6 23:14:31 | 显示全部楼层
libins 怎么将手写输入加入自己的网站呢?谢谢了!
回复 支持 反对

使用道具 举报

发表于 2010-5-6 23:46:14 | 显示全部楼层
楼主好牛。我只有看看的份
回复 支持 反对

使用道具 举报

发表于 2010-5-21 15:38:52 | 显示全部楼层
期待下文。。楼主啥时候把整个反馈识别文字的过程给剖析出来啊,做个实例
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-5-21 17:54:34 | 显示全部楼层
@778cn 你把我那个swf插入在你的页面里就可以了
@qlan  你是指根据数据反馈笔画?这个不是我这里所分析的效果,是由汉王那个API接口实现的,AS里处理这个,我在文章开头就说了,效率和实用性上不太现实。
回复 支持 反对

使用道具 举报

发表于 2010-7-30 11:28:59 | 显示全部楼层
感谢分享 学习!
回复 支持 反对

使用道具 举报

发表于 2010-8-3 09:28:19 | 显示全部楼层
不错!
回复 支持 反对

使用道具 举报

发表于 2010-8-3 11:41:59 | 显示全部楼层
我顶下。
回复 支持 反对

使用道具 举报

发表于 2010-8-3 14:47:07 | 显示全部楼层
分析得很详细,谢谢分享
回复 支持 反对

使用道具 举报

发表于 2010-8-5 13:42:24 | 显示全部楼层
Good
不过今天试了一下 hw.baidu.com ioError了
回复 支持 反对

使用道具 举报

发表于 2010-10-14 19:06:03 | 显示全部楼层
不错,不错,很强大
回复 支持 反对

使用道具 举报

发表于 2010-11-5 10:31:02 | 显示全部楼层
  牛人啊~
回复 支持 反对

使用道具 举报

发表于 2011-1-2 21:31:22 | 显示全部楼层
牛,牛,真牛
回复 支持 反对

使用道具 举报

发表于 2011-3-31 23:09:46 | 显示全部楼层
不支持跨域啊!如果是放到网页里,就不行了!直接在flash播放器里就可以!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-4-1 09:14:57 | 显示全部楼层
原帖由 [i]nacco 于 2011-3-31 23:09 发表
不支持跨域啊!如果是放到网页里,就不行了!直接在flash播放器里就可以!

你设置只允许网络访问就可以了
回复 支持 反对

使用道具 举报

发表于 2012-5-29 19:20:52 | 显示全部楼层
libins , 运行源码确实可行,如何实现点击列表的字体后赋值到自己新建的textarea 里面呢?望libins 抽空解说一下。
回复 支持 反对

使用道具 举报

发表于 2012-6-4 01:41:27 | 显示全部楼层


这图片中下面的是什么工具?可以查看到网络数据和进程?
回复 支持 反对

使用道具 举报

发表于 2012-6-18 17:37:42 | 显示全部楼层
楼主NB,汉王好像没有说,这个是对外的接口,如果用于项目中,万一接口关了就蛋痛!
回复 支持 反对

使用道具 举报

发表于 2012-6-27 09:20:16 | 显示全部楼层
为什么可以获得网络数据?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-6-27 15:43:09 | 显示全部楼层
drupalnet 发表于 2012-5-29 19:20
libins , 运行源码确实可行,如何实现点击列表的字体后赋值到自己新建的textarea 里面呢?望libins 抽空解说 ...

for (var i:uint = 1; i<arr.length; i++) {
                //trace(String.fromCharCode(Number("0x"+arr[i])));
                txt.appendText(String.fromCharCode(Number("0x"+arr[i]))+" ")
}

这个是为了简单展示做的效果,你如果需要点击添加文字的效果,可以没一个文字展示都存在一个Textfield里去,点击这个tf后,获取这个文字信息,再赋值到你个textArea里去?!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-6-27 15:44:23 | 显示全部楼层
hglgsxy 发表于 2012-6-4 01:41
这图片中下面的是什么工具?可以查看到网络数据和进程?

HttpWatch 挺方便的一个软件
现在的好多浏览器都有自带可以装网络抓包信息的插件
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-6-27 15:46:06 | 显示全部楼层
thisword 发表于 2012-6-18 17:37
楼主NB,汉王好像没有说,这个是对外的接口,如果用于项目中,万一接口关了就蛋痛!

实在不行,项目有需要,自己做字库 笔画分析了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-6-27 15:47:05 | 显示全部楼层
demonangle 发表于 2012-6-27 09:20
为什么可以获得网络数据?

沙箱分本地域和网络域,如果发布设为网络域就可以获得网络数据了
回复 支持 反对

使用道具 举报

发表于 2012-6-28 16:29:05 | 显示全部楼层
这个真不错,很nb的功能
回复 支持 反对

使用道具 举报

发表于 2012-7-2 10:37:04 | 显示全部楼层
libins 发表于 2012-6-27 15:46
实在不行,项目有需要,自己做字库 笔画分析了

非常感谢啊
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|小黑屋|Archiver|手机版|blueidea.com ( ICP05002321 )  

GMT+8, 2019-7-22 11:53 , Processed in 0.111048 second(s), 10 queries , Gzip On, Memcache On.

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表