用canvas畫驗證碼
2019香港居屋抽籤完滿結束,人生依舊殘念。沒事幹的唯有回望一下今年網上居屋申請表格,看看用canvas重新實現表格上的驗證碼,然後試著用tensorflow.js去辨識字母。
這篇重點是重現驗證碼圙案,如果你是想了解如何使用tensorflow.js辨識字母,請到下一篇文章
這裡純學術研究,內容上如有任何冒犯請見諒。
因為活動已完結所以網頁也關了,下面附上截圖先譲各位了解一下:
可以看出圖案由3部分組成:
- 由左邊淺灰色往右漸變成白色的背景;
- 8條黑色線: 4條由上到下,另外4條由左到右,角度隨機場;
- 黑色數字或英文字母,字體大小各異,多款字型,可以是粗體,大約左右置中有少許隨機位移,坐落於一條baseline之上。
下面寫一個function來繪製類似圖䅁,為了之後辨識字母簡單點,只畫單一字母那款(ML我不懂哦就別挑高難度的 🙈)
先定義圖案寛高度各50px:
1 2
const CANVAS_WIDTH = 50; const CANVAS_HEIGHT = 50;
function需要傳入一個數字或字母用以繪製:
3
function generateCharImage(char) {
創建一個canvas元素,呼叫
.getContent("2d")
取得畫布:4 5 6 7 8 9 10
//create canvas const canvasId = `canvas-${char}`; const canvas = document.createElement("canvas"); canvas.setAttribute("id", canvasId); canvas.width = CANVAS_WIDTH; canvas.height = CANVAS_HEIGHT; const ctx = canvas.getContext("2d");
繪製背景(漸變方向原來應該是左至右,這裡加點小改變由左上角至右下角):
11 12 13 14 15 16
//draw background const gradient = ctx.createLinearGradient(0, 0, CANVAS_HEIGHT, CANVAS_HEIGHT); gradient.addColorStop(0, "lightgray"); gradient.addColorStop(1, "white"); ctx.fillStyle = gradient; ctx.fillRect(0, 0, CANVAS_HEIGHT, CANVAS_HEIGHT);
上至下畫一條線,左至右畫再一條,重複4次,位置隨機:
17 18 19 20 21 22 23 24 25 26 27 28
//draw lines ctx.strokeStyle = "black"; for (let i = 0; i < 4; i++) { ctx.beginPath(); ctx.moveTo(Math.round(Math.random() * CANVAS_HEIGHT), 0); ctx.lineTo(Math.round(Math.random() * CANVAS_HEIGHT), CANVAS_HEIGHT); ctx.stroke(); ctx.beginPath(); ctx.moveTo(0, Math.round(Math.random() * CANVAS_HEIGHT)); ctx.lineTo(CANVAS_HEIGHT, Math.round(Math.random() * CANVAS_HEIGHT)); ctx.stroke(); }
畫字,字體大小隨機,不知道原本是甚麼字型所以隨意選兩個相似的,位置簡單點置中好了:
29 30 31 32 33 34 35 36 37
//draw char ctx.fillStyle = "black"; const fontSIze = `${Math.floor(Math.random() * 10) + 30}px`; const fontFamily = ["Courier", "Palatino"][Math.floor(Math.random() * 2)]; const fontBold = Math.random() < 0.5 ? "bold" : ""; ctx.font = `${fontBold} ${fontSIze} ${fontFamily}`; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText(char, CANVAS_HEIGHT / 2, CANVAS_HEIGHT / 2, CANVAS_HEIGHT);
最後把canvas放入
<body>
:38 39
document.body.appendChild(canvas); }
寫好function後,試著0~9、a~z、A~Z都繪製一次:
40 41 42
for (let char of "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") { generateCharImage(char); };
程式碼就先寫到這裡,直接看看效果: https://codepen.io/doggor/pen/YzKxYVg/