因行動裝置的流行而跟著帶動起來的QR Code,是眾多條碼類型的其中一種,它讓我們的生活更便利,傳遞資訊的速度更快,省下許多使用鍵盤打字的時間。如果要產生出QR Code,已經有許多相關的現成工具能夠使用,甚至還能直接在網頁上產生。可是如果要我們自己用來做的話,究竟要如何才能產生QR Code呢?
magic-qr-code
magic-qr-code
是一個使用Node.js 8之後才支援的N-API所開發的模組,引用了這個函式庫「QR Code generator library」(Rust語言)來編碼出QR Code的資料。
npmjs.com
npm 安裝指令
使用方法
將字串編碼成QR Code
使用模組提供的encodeString
函數可以將任意字串編碼成QR Code資料;encodeBuffer
函數則可以將任意Buffer
編碼成QR Code資料。用法如下:
import { encodeString } from "magic-qr-code";
encodeString("任意文字");
如果想要控制QR Code的容錯率,可以再加上第二個參數,用法如下:
import { encodeString, ErrorCorrection } from "magic-qr-code";
encodeString("任意文字", ErrorCorrection.High);
以上的ErrorCorrection.High
表示30%的容錯率。另外還有25%的ErrorCorrection.Quartile
、15%的ErrorCorrection.Medium
和7%的ErrorCorrection.Low
。相同的任意文字,使用愈高的容錯率編碼出來的QR Code的「版本」(version)愈高,換句話說,QR Code的資料量會愈大,呈現出來的點數會愈多。當然,增加容錯率,並不一定會提升QR Code的版本,資料量還是得要超過該QR Code版本的上限,版本才會再往上提升。
這個模組會自動以該QR Code版本能夠容許的最大容錯率來選擇容錯率。舉例來說,如果相同的任意文字使用ErrorCorrection.Quartile
和ErrorCorrection.High
所編碼出來的QR Code都是同一個版本,就算我們傳給encodeString
或encodeBuffer
函數的第二個參數是ErrorCorrection.Quartile
,這個模組會自動使用ErrorCorrection.High
來進行編碼。
QR Code有區分不同的字元集,如果要被編碼的字串都是數字,就會使用數值(Numeric)模式來進行編碼;如果要被編碼的字串都是數字、大寫英文字母和部份有涵蓋的標點符號,就會使用數值(Alphanumeric)模式來進行編碼。QR Code編碼的模式還會影響到每個版本所能容許的字串長度,好像很複雜對吧?但是別緊張,使用這個模組來編碼QR Code,會自動選擇合適的模式來進行編碼,保證最後編碼出來的QR Code是版本最小、容錯率最高的!
encodeString
函數將字串編碼成QR Code的資料後,會以Buffer陣列(Buffer[]
)的形式回傳。如下:
import { encodeString } from "magic-qr-code";
const result = encodeString("https://magiclen.org".toUpperCase());
/*
[
<Buffer 01 01 01 01 01 01 01 00 01 01 00 00 01 00 01 01 01 01 01 01 01>,
<Buffer 01 00 00 00 00 00 01 00 01 01 01 00 00 00 01 00 00 00 00 00 01>,
<Buffer 01 00 01 01 01 00 01 00 01 01 01 00 00 00 01 00 01 01 01 00 01>,
<Buffer 01 00 01 01 01 00 01 00 00 01 01 01 00 00 01 00 01 01 01 00 01>,
<Buffer 01 00 01 01 01 00 01 00 01 00 00 01 01 00 01 00 01 01 01 00 01>,
<Buffer 01 00 00 00 00 00 01 00 00 01 00 01 01 00 01 00 00 00 00 00 01>,
<Buffer 01 01 01 01 01 01 01 00 01 00 01 00 01 00 01 01 01 01 01 01 01>,
<Buffer 00 00 00 00 00 00 00 00 00 01 01 00 00 00 00 00 00 00 00 00 00>,
<Buffer 01 00 00 01 01 01 01 01 01 00 00 01 00 01 00 00 01 00 01 01 01>,
<Buffer 01 00 01 00 01 01 00 01 01 01 01 01 01 01 00 01 01 00 00 00 00>,
<Buffer 00 00 01 00 01 00 01 00 01 01 01 01 00 00 01 00 00 01 00 00 00>,
<Buffer 00 01 01 01 01 00 00 01 01 01 01 00 01 01 00 00 01 00 01 01 00>,
<Buffer 00 01 00 01 00 01 01 00 01 01 01 01 00 01 01 01 00 01 00 01 01>,
<Buffer 00 00 00 00 00 00 00 00 01 01 00 00 00 01 00 00 01 01 01 00 00>,
<Buffer 01 01 01 01 01 01 01 00 01 00 01 00 00 01 00 00 00 01 01 01 00>,
<Buffer 01 00 00 00 00 00 01 00 01 00 01 01 00 01 00 01 00 01 01 00 00>,
<Buffer 01 00 01 01 01 00 01 00 01 01 01 00 01 00 01 01 00 01 01 00 00>,
<Buffer 01 00 01 01 01 00 01 00 01 00 00 00 00 01 00 01 01 00 01 00 00>,
<Buffer 01 00 01 01 01 00 01 00 00 01 00 00 00 00 01 00 00 01 00 01 01>,
<Buffer 01 00 00 00 00 00 01 00 00 00 00 00 00 00 01 01 00 00 01 01 00>,
<Buffer 01 01 01 01 01 01 01 00 01 01 00 01 01 01 00 00 00 01 00 01 00>
]
*/
將QR Code資料畫成圖
encode
函數會回傳Buffer陣列,每個Buffer
均表示一排QR Code圖形的橫向資料,Buffer
中的值只會有0
或1
。0
表示為白點;1
表示為黑點。利用這筆資料,我們就可以產生出QR Code的圖形了!
Node.js有一個強大的畫圖模組──canvas
。這個canvas
模組是用C++語言來實作的,效能極佳。
將canvas
模組和magic-qr-code
模組搭配使用的程式碼如下:
import { writeFileSync } from "node:fs";
import { encodeString } from "magic-qr-code";
import { createCanvas } from "canvas";
const result = encodeString("https://magiclen.org".toUpperCase());
function draw(data: Buffer[], size = 1024) {
const marginSize = 1;
const dataLength = data.length;
const dataLengthWithMargin = dataLength + (2 * marginSize);
const canvas = createCanvas(size, size);
const ctx = canvas.getContext("2d");
const pointSize = Math.floor(size / dataLengthWithMargin);
if (pointSize === 0) {
throw new Error("cannot draw this QR Code");
}
const margin = Math.floor((size - (pointSize * dataLength)) / 2);
ctx.fillStyle = "white";
ctx.fillRect(0, 0, size, size);
ctx.fillStyle = "black";
for (let i = 0;i < dataLength;++i) {
for (let j = 0;j < dataLength;++j) {
if (data[i][j]) {
const x = (j * pointSize) + margin;
const y = (i * pointSize) + margin;
ctx.fillRect(x, y, pointSize, pointSize);
}
}
}
return canvas;
}
const canvas = draw(result);
// Output
const pngBuffer = canvas.toBuffer();
writeFileSync("./out.png", pngBuffer);
以上程式會成功輸出底下張PNG格式的QR Code: