都说用Nodejs来生成验证码效率很低下,但有时候你仍然想用node来生成验证码
点开百度搜索结果的第一条,找到三个模块: 1.node-canvas 2.node-gyp 3.ccap 看描述,这些无一例外需要安装其它支持库(C或C++编写,平台兼容性极差) 我个人认为一切需要安装额外支持库的模块都是耍流氓!搜索结果比较多的是CCAP, 而ccap的介绍: https://cnodejs.org/topic/50f90d8edf9e9fcc58a5ee0b在提到性能时,是这样写的: 在2cpu的linux 64位服务器上生成验证码速度可以达到1200次/秒,测试生成的图片是BMP的,jpeg的图片验证码生成速度大约在600次/秒。 也仅仅达到1200次/秒
为什么需要完全用js来实现图形模块?在node本身没有提供图形库的情况下,只有完全用js编写的图形库能做到在任何平台上运行的效果一致,实测,我的模块可以在openwrt路由器上完美运行!我测试了另外一款全js实现的验证码生成模块(图形操作很有限,没有画点、线等一些基本功能,甚至颜色设置也很差) captchapng 在我的电脑上测试:(node版本4.4.4,32位CPU双核2.0G主频) 按照所给的demo,生成的是80x30的验证码,900张/秒 而我的生成的是100x40的验证码,可以达到2400张/秒 在openwrt路由器上测试:(只有完全用js编写的模块可以在路由器上运行!ccap之类的是绝对无法运行的) 同样的代码 captchapng是7张/秒 我的模块也是7张/秒 路由器的型号是TP-WR841N V10,硬改内存64M,CPU超频到850M,node版本4.4.5 之所以说ccap之类的是绝对无法运行,因为路由器的node运行环境非常极端!内存极少,CPU指令与电脑是完全不同的 所以依赖C/C++支持的模块是无法运行的!甚至代码量过大的js程序也无法运行,例如使用npm安装express,由于express需要依赖太多其它模块,导致npm的运行没有足够的内存
以下是我对captchapng的测试代码 png.js
var http = require('http');
var captchapng = require('captchapng');
//captchapng版本 0.0.1
function getImg(){
var p = new captchapng(80,30,parseInt(Math.random()*9000+1000)); // width,height,numeric captcha
p.color(0, 0, 0, 0); // First color: background (red, green, blue, alpha)
p.color(80, 80, 80, 255); // Second color: paint (red, green, blue, alpha)
var img = p.getBase64();
var imgbase64 = new Buffer(img,'base64');
return imgbase64;
}
var start = new Date().getTime();
var i = 0;
while((new Date().getTime() - start) < 1000){
var img = getImg();
i++;
}
console.log("1秒钟生成:" + i);
http.createServer(function (request, response) {
response.writeHead(200, {
'Content-Type': 'image/png'
});
var img = getImg();
response.end(img);
}).listen(8080);
console.log('Web server started.');
好了,现在来介绍一下我花了两天时间编写的“图形库”
字符图形测试: 验证码: 匆忙做出来的,样子很难看,图片大小和百度云网盘登录的验证码是一样的,都是100x40 其实我编写的是一个只能操作24位bmp图片的“图形库”,大家都知道bmp图片是没有压缩的, 所以文件大小必定会比jpg,gif,png之类的大,但是,对于验证码仅仅100x40的图片来说仅仅11.7K,微不足道! 况且,用Js来编写操作这些格式的程序太过复杂。 实测在我的电脑上可以达到2400张/秒的优秀成绩(我的电脑是32位 CPU双核2G主频) 假如去除上面验证码中的正弦曲线,可以达到6500张/秒! 假如同时去除字符和正弦曲线只保留画圆、画线、画空心矩形和实心矩形,可以达到12000张/秒!
安装
npm install zengming 我个人的测试模块,呵呵,有时间再把这个"图形库"拆分出来
测试代码 bmp.js
var http = require('http');
var fs = require('fs');
var z = require('zengming');
var BMP24 = z.BMP24;
var font = z.Font;
/*
用PCtoLCD2002取字模
行列式扫描,正向取模(高位在前)
*/
var cnfonts = {//自定义字模
w : 16,
h : 16,
fonts: "中国",
data : [
[0x01,0x01,0x01,0x01,0x3F,0x21,0x21,0x21,0x21,0x21,0x3F,0x21,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0xF8,0x08,0x08,0x08,0x08,0x08,0xF8,0x08,0x00,0x00,0x00,0x00],/*"中",0*/
[0x00,0x7F,0x40,0x40,0x5F,0x41,0x41,0x4F,0x41,0x41,0x41,0x5F,0x40,0x40,0x7F,0x40,0x00,0xFC,0x04,0x04,0xF4,0x04,0x04,0xE4,0x04,0x44,0x24,0xF4,0x04,0x04,0xFC,0x04],/*"国",1*/
]
};
function makeImg2() {
var img = new BMP24(300,140);
img.drawString('helloworld', 20,10, font.font8x16, 0xff0000);
img.drawString('helloworld', 20,25, font.font12x24, 0x00ff00);
img.drawString('helloworld', 20,50, font.font16x32, 0x0000ff);
img.drawString('中国', 20,85, cnfonts, 0xffffff);
return img;
}
function makeCapcha() {
var img = new BMP24(100, 40);
img.drawCircle(11, 11, 10, z.rand(0, 0xffffff));
img.drawRect(0, 0, img.w-1, img.h-1, z.rand(0, 0xffffff));
img.fillRect(53, 15, 88, 35, z.rand(0, 0xffffff));
img.drawLine(50, 6, 3, 60, z.rand(0, 0xffffff));
//return img;
//画曲线
var w=img.w/2;
var h=img.h;
var color = z.rand(0, 0xffffff);
var y1=z.rand(-5,5); //Y轴位置调整
var w2=z.rand(10,15); //数值越小频率越高
var h3=z.rand(4,6); //数值越小幅度越大
var bl = z.rand(1,5);
for(var i=-w; i<w; i+=0.1) {
var y = Math.floor(h/h3*Math.sin(i/w2)+h/2+y1);
var x = Math.floor(i+w);
for(var j=0; j<bl; j++){
img.drawPoint(x, y+j, color);
}
}
var p = "ABCDEFGHIJKLMNOPQRSTUVWXYZ3456789";
var str = '';
for(var i=0; i<5; i++){
str += p.charAt(Math.random() * p.length |0);
}
var fonts = [font.font8x16, font.font12x24, font.font16x32];
var x = 15, y=8;
for(var i=0; i<str.length; i++){
var f = fonts[Math.random() * fonts.length |0];
y = 8 + z.rand(-10, 10);
img.drawChar(str[i], x, y, f, z.rand(0, 0xffffff));
x += f.w + z.rand(2, 8);
}
return img;
}
var start = new Date().getTime();
var i = 0;
while((new Date().getTime() - start) < 1000){
//var img = makeCapcha();
var img = makeImg2();
i++;
}
console.log("1秒钟生成:" + i);
var src = "C:/Users/Administrator/Desktop/Camera/1121.bmp";
var dst = "C:/Users/Administrator/Desktop/Camera/test.bmp";
http.createServer(function (req,res) {
console.time("bmp24");
var img = makeCapcha();
console.timeEnd("bmp24");
res.setHeader('Content-Type', 'image/bmp');
res.end(img.getFileData());
}).listen(8080);
以上的代码集成了此模块的所有功能,特别说明一下,字符的显示借鉴了单片机的字符显示程序 所以字符是完全可以自定义的,你可以用取字模的软件自己生成字库, 我用的是PCtoLCD2002取字模, 行列式扫描,正向取模(高位在前) 程序已经内置了三种规格的字体,仅包含大小写字母和数字
API,非常简洁、强大、优雅、风骚、时尚、前无古人后无来者
//获得对象的两种方式: //构造函数,创建指定宽高的图片对象(初始化为一张全黑的图片) new BMP24(w, h)
从文件加载bmp 注意!必需确保文件是24位bmp 参数:文件路径 , cb(err, BMP24) BMP24.loadFromFile(filename, cb)
//获取BMP整个文件数据 obj.getFileData()
//画点, RGB颜色值(例如红色0xff0000) obj.drawPoint(x, y, rgb)
//画线 obj.drawLine(x1, y1, x2, y2, rgb)
//画矩形&实心矩形 obj.drawRect(x1, y1, x2, y2, rgb) obj.fillRect(x1, y1, x2, y2, rgb)
//画圆 obj.drawCircle(x, y, r, rgb)
//画字符&字符串,font参数为字库,color为RGB颜色值(例如红色0xff0000) obj.drawChar(ch, x, y, font, color) obj.drawString(str, x, y, font, color)