在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
最近得闲,学习一下Lua。 Lua下有个gd图形库,通过简单的Lua语句就能控制、生成图片。 之前在某个项目中要用到验证码,当时对这方面不太了解,就采用最不专业的做法:预先准备好若干验证码图片,把对应的值存入到数据库;使用时随机取出一对“图片-验证码值”供用户验证。这样做的好处是减少编码复杂度和服务器负担,但是问题也显而易见:预先准备的验证码图片数量有限,要是有人恶意攻击的话,这种验证码恐怕只是个摆设。要是专业人士见到我的这种实现,只怕会笑掉大牙。 当时也考虑过动态生成图片,随机生成几个数字、字母组成的验证码,然后将此验证码生成图片,最后对验证码图片进行模糊处理(倾斜、模糊、加干扰等)。验证码的生成到不难,有比较成熟的随机函数可以做到;但是将验证码生成图片并做模糊处理,当时就没有什么好的办法了。考虑过Java下应该有图形库可以做到这一点,但是觉得代码量肯定不小,运行效率恐怕也难以保证,所以就没深究。 直到最近接触到Lua的gd库,才重新想起这事。关于该gd库的细节,请参看官方文档:http://lua-gd.luaforge.net/manual.html
不说废话,直接上代码:
1 require("gd")
2 3 --定义词典 4 5 dict={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','1','2','3','4','5','6','7','8','9','0'} 6 7 --随机种子 8 9 math.randomseed(os.time()) 10 11 im2 = gd.createTrueColor(100, 40) 12 13 white = im2:colorAllocate(255, 255, 255) 14 15 stringmark="" 16 17 for i=1,6 do 18 19 stringmark=stringmark..dict[math.random(62)] 20 21 end 22 23 im2:string(gd.FONT_GIANT, 18, 10, stringmark, white) 24 25 im2:png("./output/验证码.png",100) 26 27
这样总共用不到20行代码就实现了一个简单的验证码,效果如下: 虽然基本实现了验证码图片的生成,但还不太理想;要实现真正可用的验证码,大概还需要做如下处理:设置不同字体、字符要随机倾斜、要随机模糊字符、要增加干扰等。
因此在此基础上略作了改进:设置不同字体、字符随机倾斜;至于随机模糊字符、增加干扰暂时还没想好怎么处理。最后代码如下:
1 require("gd")
2 3 require("lfs") 4 5 --定义词典 6 7 dict={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','1','2','3','4','5','6','7','8','9','0'} 8 9 --随机种子 10 11 math.randomseed(os.time()) 12 13 im2 = gd.createTrueColor(100, 40) 14 15 white = im2:colorAllocate(255, 255, 255) 16 17 stringmark="" 18 19 fonts={} 20 21 --查找字体 22 23 function searchFont() 24 25 local i=1 26 27 for file in lfs.dir("./复件 output/") do 28 29 if file~="." and file~=".." then 30 31 fonts[i]=string.sub(file,1,string.find(file,"ttf")).."tf" 32 33 print(fonts[i]) 34 35 i=i+1 36 37 end 38 39 end 40 41 end 42 43 --测试不同字体的效果 44 45 function testFont() 46 47 searchFont() 48 49 if table.getn(fonts)==0 then --没有指定字体路径,就搜索系统字体 50 51 for file in lfs.dir("C:/WINDOWS/Fonts/") do 52 53 if string.find(file,".ttf")and not string.find(file,"esri") then 54 55 makeStringWithRotate(file) 56 57 end 58 59 end 60 61 else--否则就使用指定字体 62 63 for i=1,table.getn(fonts) do 64 65 makeStringWithRotate(fonts[i]) 66 67 end 68 69 end 70 71 end 72 73 --生成带角度字符串 74 75 function makeStringWithRotate(font) 76 77 for i=1,6 do 78 79 local s=dict[math.random(62)] 80 81 im2:stringFT(white,"C:/WINDOWS/Fonts/"..font,18,math.random()/math.pi,5+(i-1)*15, 25, s) 82 83 stringmark=stringmark..s 84 85 end 86 87 im2:png("./output/"..font..".png",100) 88 89 -- 清理工作,准备下次使用 90 91 stringmark="" 92 93 im2 = gd.createTrueColor(100, 40) 94 95 end 96 97 --生成普通字符串 98 99 function makeString() 100 101 im2 = gd.createTrueColor(100, 40) 102 103 white = im2:colorAllocate(255, 255, 255) 104 105 for i=1,6 do 106 107 stringmark=stringmark..dict[math.random(62)] 108 109 end 110 111 im2:string(gd.FONT_GIANT, 18, 10, stringmark, white) 112 113 stringmark="" 114 115 im2:png("./output/验证码.png",100) 116 117 end 118 119 testFont() 120 121 --makeString() 122 123
说明如下: 由于不同字体的显示效果不一样,在有些字体中0、o、O不分;i、I、1、l、L不分;有些字体无法显示;这样导致验证码无法识别,因此必须去掉不适合用来生成验证码的字体。但是由于系统字体太多,如果逐一由手工验证,将是一件繁复而无意义的工作,因此在这里我采用“循环验证”的方式来处理: 1.使用系统中每一种字体都生成一张验证码图片放到指定目录A中("./output/"),图片名即字体名 2.依次对这些验证码图片进行验证,剔除不适合做验证码的字体 3.将剔除后合格的验证码图片拷到指定目录B下(C:/luaaio_2.0_windows/test/test_gd/复件 output/),删除原目录A("./output/")中的内容 4.重新运行本程序,将读取目录B中合格字体,然后使用这些字体创建验证码图片到目录A中 5.重复步骤2,继续剔除不合格的字体,直到得到所有合格的字体。 最后,在我自己系统上经过多次运行,最后从几百个字体中得到比较容易分辨、适合作验证码的字体如下: courbd.ttf courbi.ttf DejaVuMonoSans.ttf DejaVuMonoSansBold.ttf DejaVuMonoSansBoldOblique.ttf DejaVuMonoSansOblique.ttf lucon.ttf monosbi.ttf nina.ttf simhei.ttf simkai.ttf swissci.ttf tahomabd.ttf timesbd.ttf timesbi.ttf timesi.ttf trebuc.ttf trebucit.ttf 效果如下: 说明:上面代码中为了访问文件系统,使用了lua扩展“LuaFileSystem”,具体些请参看文档:http://keplerproject.github.com/luafilesystem/index.html。
现在找出合适的字体了,做进一步改进:每次生成使用随机字体。 加上背景颜色,代码如下:
1 require("gd") 2 3 require("lfs") 4 5 --定义词典 6 7 dict={'a','b','c','d','e |
请发表评论