因行動裝置的流行而跟著帶動起來的QR Code,是眾多條碼類型的其中一種,它讓我們的生活更便利,傳遞資訊的速度更快,省下許多使用鍵盤打字的時間。如果要產生出QR Code,已經有許多相關的現成工具能夠使用,甚至還能直接在網頁上產生。可是如果要我們自己用來做的話,究竟要如何才能產生QR Code呢?



magic-qr-code

magic-qr-code是一個使用Node.js 8之後才支援的N-API所開發的模組,引用了這個函式庫「QR Code generator library」(Rust語言)來編碼出QR Code的資料。

GitHub:

https://github.com/magiclen/node-qr-code

npm:

https://www.npmjs.com/package/magic-qr-code

安裝

直接使用npm指令進行安裝:

npm install magic-qr-code

用法

初始化
const QRCode = require("magic-qr-code");
將字串編碼成QR Code

使用模組提供的「encode」函數可以將任意字串編碼成QR Code資料,用法如下:

QRCode.encode("任意文字");

如果想要控制QR Code的容錯率,可以再加上第二個參數,用法如下:

QRCode.encode("任意文字", QRCode.ErrorCorrection.High);

以上的QRCode.ErrorCorrection.High表示30%的容錯率。另外還有25%的QRCode.ErrorCorrection.Quartile、15%的QRCode.ErrorCorrection.Medium和7%的QRCode.ErrorCorrection.Low。相同的任意文字,使用愈高的容錯率編碼出來的QR Code的「版本」(version)愈高,換句話說,QR Code的資料量會愈大,呈現出來的點數會愈多。當然,增加容錯率,並不一定會提升QR Code的版本,資料量還是得要超過該QR Code版本的上限,版本才會再往上提升。

這個模組會自動以該QR Code版本能夠容許的最大容錯率來選擇容錯率。舉例來說,如果相同的任意文字使用QRCode.ErrorCorrection.QuartileQRCode.ErrorCorrection.High所編碼出來的QR Code都是同一個版本,就算我們傳給encode函數的第二個參數是QRCode.ErrorCorrection.Quartile,這個模組會自動使用QRCode.ErrorCorrection.High來進行編碼。

QR Code有區分不同的字元集,如果要被編碼的字串都是數字,就會使用數值(Numeric)模式來進行編碼;如果要被編碼的字串都是數字、大寫英文字母和部份有涵蓋的標點符號,就會使用數值(Alphanumeric)模式來進行編碼。QR Code編碼的模式還會影響到每個版本所能容許的字串長度,好像很複雜對吧?但是別緊張,使用這個模組來編碼QR Code,會自動選擇合適的模式來進行編碼,保證最後編碼出來的QR Code是版本最小、容錯率最高的!

encode函數將字串編碼成QR Code的資料後,會以Buffer陣列(Buffer[])的形式回傳。如下:

const result = QRCode.encode("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中的值只會有010表示為白點;1表示為黑點。利用這筆資料,我們就可以產生出QR Code的圖形了!

Node.js有一個強大的畫圖模組──canvas,可以直接使用npm指令進行安裝:

npm install canvas

這個canvas模組是用C++語言來實作的,效能極佳。

canvas模組和magic-qr-code模組搭配使用的程式碼如下:

const QRCode = require("magic-qr-code");
const Canvas = require("canvas");

const result = QRCode.encode("https://magiclen.org".toUpperCase());

function draw(data, size = 1024) {
    const marginSize = 1;
    const dataLength = data.length;
    const dataLengthWithMargin = dataLength + (2 * marginSize);
    const canvas = 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 fs = require("fs");
const pngBuffer = canvas.toBuffer();
fs.writeFileSync("./out.png", pngBuffer);

以上程式會成功輸出底下張PNG格式的QR Code:

node-qrcode