彻底跨平台,Node.js高效生成验证码,我自己用纯js实现了一个图形模块
发布于 8 年前 作者 zengming00 82171 次浏览 最后一次编辑是 7 年前 来自 分享

都说用Nodejs来生成验证码效率很低下,但有时候你仍然需要用node来生成验证码

注:此技术现在已经拆分成独立模块了

安装方法为npm install gd-bmp,参考gd-bmp模块下的demo

百度搜索.jpg 点开百度搜索结果的第一条,找到三个模块: 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张/秒 captchapng测试.jpg 在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.');

好了,现在来介绍一下我花了两天时间编写的“图形库”

字符图形测试: 字符测试.jpg 验证码: 验证码1.jpg 验证码2.jpg 匆忙做出来的,样子很难看,图片大小和百度云网盘登录的验证码是一样的,都是100x40 其实我编写的是一个只能操作24位bmp图片的“图形库”,大家都知道bmp图片是没有压缩的, 所以文件大小必定会比jpg,gif,png之类的大,但是,对于验证码仅仅100x40的图片来说仅仅11.7K,微不足道! 况且,用Js来编写操作这些格式的程序太过复杂。 实测在我的电脑上可以达到2400张/秒的优秀成绩(我的电脑是32位 CPU双核2G主频) 假如去除上面验证码中的正弦曲线,可以达到6500张/秒! 假如同时去除字符和正弦曲线只保留画圆、画线、画空心矩形和实心矩形,可以达到12000张/秒!

安装

npm install zengming 我个人的测试模块,呵呵,有时间再把这个"图形库"拆分出来

现在已经拆分成独立模块了: npm install gd-bmp github地址: https://github.com/zengming00/node-gd-bmp 使用与zengming模块基本一致,只是将字体和类绑在了一起,细微的差异请参考gd-bmp模块下的demo

测试代码 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);

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)

license

MIT


68 回复

先mark

来自酷炫的 CNodeMD

来看看,学习一下。

收藏。以后,可能会用到。我在server端也是安装的node-canvas模块。node-canvas安装时真心地好麻烦,而且只有node-canvas@1.5.0能够被 安装在CentOS6.6上。 如果在Ubuntu机器上(我的开发box),就只有node-canvas@1.1.6是能够安装成功的。提起来都是泪呀。当初可是折腾死我了。 node自身为什么不带图形库呢?

ccap也好麻烦的说

顶!d=====( ̄▽ ̄*)b

我之前也在这里求助过,然后在centos6.5下使用了ccap,现在看到楼主这个,觉得真心不错,赞一个

因垂死听,想知道是否支持中文、噪点、变形、变色

这才是做实事的,完善node的底层支持,而不是依赖非node生态的库,一个字,赞!

顶一个 自豪地采用 CNodeJS ionic

楼主,实现这个是不是需要计算机图形学的知识,有空要拜读一下源码看如何实现的

这怎么了得 mark

mark,厉害了word哥。

牛逼!!!!

captcha.png

让你们欣赏一下撒了金粉的验证码

厉害了 我的歌

赞👍🏻

支持一个,可以再完善完善,把样式和风格做的多样一些,获取可以进行配置.效率满足需求就够了

赞!膜拜一下

你需要这个 https://github.com/kyriosli/yapd 纯js实现的png编码器。 当然了其中的deflate编码模块可以使用native实现,如果node支持crypto模块,包含了zlib模块的话

用上了。造验证码费点劲。不过是个很易用的库。要是库结构、文档能再规范化一些兴许能火。

@kyriosli 不错 不错 加上这个 一共有三个纯js实现图片验证码的模块了

svg-captcha 使用svg生成也比较简单

我感觉中国node的没几个人能写出这个来,厉害了

@zh-h 也是纯js写出来的?

@yuu2lee4 请问另外两个模块是什么?

简单易用的话还真不错

今天拆分成独立模块gd-bmp

厉害了,这个加精没问题

支持呀。真心厉害

就冲协议说的我也得顶一下啊

这么好的东西,为啥没给精华?

牛逼,这轮子造的有技术

厉害了我的哥

👍👍👍

@Hyurl 点赞!<br/><br/><a class=“form” href=“https://github.com/shinygang/Vue-cnodejs”>I‘m webapp-cnodejs-vue</a>

“创建指定宽高的图片对象(初始化为一张全黑的图片)”

这个怎么构造出其他颜色背景的图片呢

thx

@zh-h 你好,背景色(洒金粉)是怎么处理的呢

一传到linux里,图片就糊了

@Bingchean //修改背景颜色 img.fillRect(0, 0, 100, 40, 0x252632);

image.png

回到顶部