HTML5 canvas画布

26 Aug

HTMl5里新元素很多,但画布<canvas>绝对是大人气,本篇要简介下画布<canvas>,并用画布绘出验证码。

使用画布<canvas>需要先获取2D上下文:getContext(“2d”)

2D上下文最基本的操作就是描边和填充,分别取决于两个属性:strokeStylefillStyle

下面是常用的画布API:

画矩形:fillRect,strokeRect,clearRect

路径:beginPath,closePath,arc(弧度),arcTo,bezierCurveTo(曲线),quadraticCurveTo(二次曲线),moveTo,lineTo,rect。路径完成后可以用fill填充,可以用stroke描边

画文本:fillText,strokeText,textBaseline(文本基线)

画图像:drawImage,getImageData,putImageData

阴影:shadowColor,shadowOffsetX,shadowOffsetY,shadowBlur

渐变:createLinearGradient,createRadialGradient

变换:rotate,scale,translate,transform,setTransform

保存恢复上下文:save,restore

具体API的应用可以参照HTML5 doctor,这里不会一一介绍。现在利用画布<canvas>来画一个验证码输入框来。通常页面点击提交按钮时,都会要求输入类似下图那样的验证码。目的是区别下单的是真人,还是个机器人脚本程序。如果写一个脚本程序攻击网站,每秒下100个单,网络肯定堵塞。但如果每次下单前随机生成个验证码,这样机器人脚本程序就无法提交表单了:

20141231161432734

Step1:HTML端配置<canvas>元素

<p>Verification:</p> 
<p><input type="text" class="topAlign" id="verify" name="verify" value="" required>
   <canvas width="100" height="25" id="verifyCanvas"></canvas></p>

这里建议在HTML端的<canvas>元素里指定画布width,height。你也可以在CSS中重新指定画布的大小,但如果你指定300px宽的画布,在CSS中重新指定为600px宽时,同样像素会扩展为原来的2倍,看起来会矮矮胖胖。因此建议直接在HTML端设置画布的width和height,而不是在CSS中设置这些属性,除非你本来就打算缩放画布。

Step2:JavaScript端生成4位随机码

var nums = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];  
      
var rand1 = nums[Math.floor(Math.random() * nums.length)];  
var rand2 = nums[Math.floor(Math.random() * nums.length)];  
var rand3 = nums[Math.floor(Math.random() * nums.length)];  
var rand4 = nums[Math.floor(Math.random() * nums.length)];  

你也可以加上英语使4位随机码更随机

Step3:填充画布背景色

window.onload = function() {  
    var canvas = document.getElementById("verifyCanvas");  //获取HTML端画布  
    var context = canvas.getContext("2d");                 //获取画布2D上下文  
  
    // Fill the background  
    context.fillStyle = "#FFFFFF";                         //设置填充色  
    context.fillRect(0, 0, canvas.width, canvas.height);   //填充背景色  
} 

20141231162533020

Step4:画布上画出4位随机码

window.onload = function() {  
    ... //代码见上  

    // Draw the pass-phrase string  
    context.fillStyle = "#FF0000";    //设置填充色  
    context.font = "25px Arial";      //设置字体  
    context.fillText(rand1, 10, 20);  //设置第一个随机码显示的位置,并显示。下面同理  
    context.fillText(rand2, 30, 20);  
    context.fillText(rand3, 50, 20);  
    context.fillText(rand4, 70, 20);  
}  

20141231163010857

Step5:画布上随机画几条随机线。目前很多OCR图像文字识别技术比较发达,纯数字容易被识别出来,增加随机线段可以增加识别的难度

window.onload = function() {
    ... //代码见上  
      
    var i = 0;  
    // Draw some random lines  
    for (i = 0; i < 4; i++) {  
        drawline(canvas, context);  //画4条随机线  
    }  
}  
      
function drawline(canvas, context) {  
    //随机线的起点x坐标是画布x坐标0位置,y坐标是画布高度的随机数
    context.moveTo(0, Math.floor(Math.random() * canvas.height));
    //随机线的终点x坐标是画布宽度,y坐标是画布高度的随机数
    context.lineTo(canvas.width, Math.floor(Math.random() * canvas.height));
    context.lineWidth = 0.5;                 //随机线宽  
    context.strokeStyle = 'rgb(50,50,50)';   //随机线描边属性  
    context.stroke();                        //描边,即起点描到终点  
}  

20141231163803953

Step6:为了给图像文字识别技术再增加点难度,可以在画布上随机画几个点

window.onload = function() {  
    ... //代码见上  
  
    // Sprinkle in some random dots  
    for (i = 0; i < 30; i++) {  
        drawDot(canvas, context);  
    }  
}  
function drawDot(canvas, context) {  //所谓画点其实就是画1px像素的线,方法不再赘述  
    var px = Math.floor(Math.random() * canvas.width);  
    var py = Math.floor(Math.random() * canvas.height);  
    context.moveTo(px, py);  
    context.lineTo(px+1, py+1);  
    context.lineWidth = 0.2;  
    context.stroke();  
}  

20141231164032502

大功告成,完整代码如下:

var nums = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];  
  
var rand1 = nums[Math.floor(Math.random() * nums.length)];  
var rand2 = nums[Math.floor(Math.random() * nums.length)];  
var rand3 = nums[Math.floor(Math.random() * nums.length)];  
var rand4 = nums[Math.floor(Math.random() * nums.length)];  
  
window.onload = function() {  
    var canvas = document.getElementById("verifyCanvas");  
    var context = canvas.getContext("2d");  
  
    // Fill the background  
    context.fillStyle = "#FFFFFF";  
    context.fillRect(0, 0, canvas.width, canvas.height);  
  
    var i = 0;  
    // Draw some random lines  
    for (i = 0; i < 4; i++) {  
        drawline(canvas, context);  
    }  
  
    // Sprinkle in some random dots  
    for (i = 0; i < 30; i++) {  
        drawDot(canvas, context);  
    }  
  
    // Draw the pass-phrase string  
    context.fillStyle = "#FF0000";  
    context.font = "25px Arial";  
    context.fillText(rand1, 10, 20);  
    context.fillText(rand2, 30, 20);  
    context.fillText(rand3, 50, 20);  
    context.fillText(rand4, 70, 20);  
}  
  
function drawline(canvas, context) {  
    context.moveTo(0, Math.floor(Math.random() * canvas.height));  
    context.lineTo(canvas.width, Math.floor(Math.random() * canvas.height));  
    context.lineWidth = 0.5;  
    context.strokeStyle = 'rgb(50,50,50)';  
    context.stroke();  
}  
  
function drawDot(canvas, context) {  
    var px = Math.floor(Math.random() * canvas.width);  
    var py = Math.floor(Math.random() * canvas.height);  
    context.moveTo(px, py);  
    context.lineTo(px+1, py+1);  
    context.lineWidth = 0.2;  
    context.stroke();  
}  

你也可以继续充分发挥自己的想象力,将验证码弄的更变态,更难被识别,击败那些机器人脚本 ^_^

Leave a Reply

Your email address will not be published. Required fields are marked *