效果,可以去我们公司官网(http://www.souche.com),里面涉及的大部分js代码暂时换成一个圣诞树,打开各个js代码看看效果。事实上,这并不奇怪。我们使用了自己编写的nodejs库。想要达到这样的效果,只需要按照下面***部分的方法即可。当然也可以在线压缩代码:http://f2e.souche.com/cheniu/js2image.html下面分两章讲解js2image库的使用方法和js2image库的原理。github地址:https://github.com/xinyu198736/js2imageps:求星在线转换地址:http://f2e.souche.com/cheniu/js2image.htmljs2image使用github地址:https://github.com/xinyu198736/js2image欢迎送star或关注。js2image主要有两个特点:将任意js源代码压缩成最终代码,用代码堆起来形成一个图。如圣诞树、圣诞老人、代码和图片都可以定制。压缩后的js代码格式虽然被破坏了,但是还是可以运行的。这是关键点!压缩后的例子可以查看这些js(均来自搜车官网):http://assets.souche.com/assets/js/souche.jssouche主脚本http://assets.souche.com/assets/js/lib/jquery-1.7.1.min.jsjquery1.7.1http://assets.souche.com/assets/js/lib/mustache.jsmustache使用非常简单:npminstalljs2image-g;然后在js所在文件夹执行:js2image-s./resource/jquery.js或者执行一个目录下的所有js(慎用),会深度遍历该目录下所有js文件,并将结果文件用.xmas压缩.js后缀。js2image-s./resource/可以生成对应的**.xmas.js文件。如果想把js2image集成到gulp或者其他nodes项目中,可以使用modules的形式:varJs2Image=require("js2image");//code获取结果Js2Image.getCode("./resource/jquery.js","./resource/tree.png",{}).then(function(code){console.log(code);})更多信息请参考github上的文档。如果你只是想用这个效果,看这里就可以了。先解释一下这个库的原理,有些地方可能会比较混乱。js2image的实现原理js2image的实现从宏观上看一般只有三个关键点。从图片生成人物画,这个有现成的库。把js代码分成小块,尽量小,然后逐行填充,替换成上一步生成的人物画。js代码中有很多语法是不能分开的,分块的时候要将这些语法放在一个块中。这是这个库的难点,也是代码最多的地方。稍微有点概念的同学看到这里大概已经明白是怎么回事了。下面就这三点一一解释。①从图片生成2值人物画这里使用了一个现成的npm包:image-to-ascii。该库的目的是恢复具有指定字符的图像。而我们利用这个库生成了一个字符画,其中?个字符和空格分别代表黑白,然后将字符画的每一行分解成数组的一个元素,供第二步使用。这是我们中间生成的一个struct,代码见utils/image-to-struct.js②把js源码尽量分成小块。这是非常重要的一步。js代码可以分解成多小?看下面这段代码:!function(e,t){("objec"+"t")==typeofmodule&&("objec"+"t")==typeofmodule.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)thrownewError(("jQuer"+"yreq"+"uires"+"awi"+"ndow"+"with"+"adoc"+"ument"));return(e)}:t(e)}(("undef"+"ined")!=typeofwindow?window:this,function(e,t){var这是一段jQuery开头的代码,可以看出大部分操作符都允许中间插入任意数量的空格或者换行符,我们利用这个特性将js代码拆解,然后拼接成任意形状的图片。核心代码其实就是一个规律,我们用这个有规律的把js源码分解成一个数组,然后根据每一行需要的字符数不断的从这个数组中取片段进行拼接。//将代码分离出来,拆分成一个以可分割为单位的数组。varlines=hold_code.replace(/([^a-zA-Z_0-9=!|&$])/g,"/n$1/n").split("/n");//有了这行之后数组,后者很简单。根据第一步生成的struct,提取行中的代码填充到struct中生成最终代码:while(lines.length>0){//循环往struct中填充代码struct.forEach(function(s){varchars_arr=s.replace(/+/g,"");//一行有多组分隔*****varr=s;chars_arr.split(/+/).forEach(function(chars){if(chars.length==0){return;}varchar_count=chars.length;//从行中取出char_count的代码进行填充,不一定准确,确保换行正确varl=pickFromLines(lines,char_count);r=r.replace(chars,function(){returnl;})})result+=r+"/n"})}③保持不可分割的语法注意:此时,还是很早的时候,你分解的代码无法运行。很多不能换行和空格的代码被你隔开,自然会报错。如何处理这些情况?在这一步中,我们做的是:在进行代码拆分之前,将代码中所有不可分割的文法提取出来,保存在一个对象中,并在源代码中用占位符替换这些文法,然后让占位符参与到上一步的分离,由于占位符是一个完整的带连字符的变量,所以不会被拆分。划分完成后,我们可以将这些占位符替换回来。但是,在js中必须将哪些语法连在一起才能正常工作呢?这里总结一下:字符串是不可分割的,包括双引号和单引号里面的内容。正则表达式是绝对不可分割的正则表达式中的转义很难处理,这是这个算法的难点。运算符包括2个字符和3个字符,比如下面两种vardouble_operator=["==",">=","<=","+=","-=","*=","/=","%=","++","--","&&","||",">>","<<"]varthree_operator=['===','!==']一些固定的语法可以用正则表达式表示,如下:varreg_operator=[{start:"return",reg:/^return[^a-zA-Z_0-1"'][a-zA-Z_0-1.]+///return0.1或returnfunction或returnaabb},{start:"return/"",reg:/^return".*?"///return"d"或return""},{start:"return/'",reg:/^return'.*?'///return'd'orreturn''},{start:"throw",reg:/^throw[a-zA-Z_0-1]+?///throwneworthrowobj}]小数点语法,比如0.01因为我们之前用点来分隔代码,但是这里的点不能作为分隔符,需要前后数字和点在一行其他的语法,比如value++之类的语法,变量和运算符是分不开的。那么我们如何从源码中解析出这些语法,然后进行处理呢?核心代码都在utils/keep-line.js中。核心算法其实是通过遍历一个字符串来完成的,然后在遍历每一个字符的时候,会判断是否进入某个逻辑来跳过处理。例如判断当前字符串在双引号内,则进入字符串提取逻辑,继续正常遍历,直到字符串结束。其他运算符和正则表达式的算法也类似,但是有很多细节需要处理,比如转义字符之类的。对于一些比较特殊的,比如小数点语法的提取,在判断当前字符是一个点之后,需要向前和向后查找数字,然后找出整个语法。这里就不细说了,keep-line.js文件中还有一大堆代码来做这件事。④字符串解构实现到这一步的时候,效果其实很好,代码也能保证运行,但是代码中有些字符串很长,会一直保持在一行,这样会导致其他问题。会影响一些图案边缘的准确性(分码的原则是越细越好,就是出于这个考虑)。我们如何处理,即解构字符串,将字符串分成以5为单位的小块。这里有两个重要的问题需要处理;如何处理字符串中的转义字符,以及一些特殊字符,比如0×01,这些字符不能被分割成不同的字符串,所以分割出来的总是保留这些字符串的完整性。将字符串分割成小串,然后用+号拼接在一起,但是要注意运算符的优先级,所以所有分割出来的字符串都要用括号括起来,这样+号的优先级永远是***。具体算法参见keep-line.js中的splitDoubleQuot(分隔双引号字符串)。结论至此,整个应用程序就完成了,可以顺利完成从任意js和图片生成图形代码。再说一下项目的开源地址:https://github.com/xinyu198736/js2image欢迎star,顺便关注楼主更开心。
