X-Git-Url: https://git.josue.xyz/?a=blobdiff_plain;f=lib%2Fqr.js;h=9469b47efadeaf02ffdc935e6bc68cc5c968971a;hb=5dbccedf943f0f768d80a9da1bffff061a5cef3e;hp=059ba550588bdfafe5adfd07690f387fcc91e7d8;hpb=ce14ba4beb779a4a026bbe0e1c869583ca5e572a;p=crowdnode.js%2F.git diff --git a/lib/qr.js b/lib/qr.js index 059ba55..9469b47 100644 --- a/lib/qr.js +++ b/lib/qr.js @@ -6,6 +6,22 @@ let Fs = require("fs").promises; let QrCode = require("qrcode-svg"); +/** + * @typedef QrOpts + * @property {String} [background] + * @property {String} [color] + * @property {String} [ecl] + * @property {Number} [height] + * @property {Number} [indent] + * @property {Number} [padding] + * @property {"mini" | "micro"} [size] + * @property {Number} [width] + */ + +/** + * @param {String} data + * @param {QrOpts} opts + */ Qr._create = function (data, opts) { return new QrCode({ content: data, @@ -18,12 +34,111 @@ Qr._create = function (data, opts) { }); }; +/** + * @typedef {Object.} BlockMap + */ + +/** + * Encoded as top-left, top-right, bottom-left, bottom-right + * @type {Object.<"mini" | "micro", BlockMap>} + */ +let charMaps = { + micro: { + 0b0000: " ", + 0b0001: "▗", + 0b0010: "▖", + 0b0011: "▄", + 0b0100: "▝", + 0b0101: "▐", + 0b0110: "▞", + 0b0111: "▟", + 0b1000: "▘", + 0b1001: "▚", + 0b1010: "▌", + 0b1011: "▙", + 0b1100: "▀", + 0b1101: "▜", + 0b1110: "▛", + 0b1111: "█", + }, + mini: { + 0b0000: " ", + 0b0001: " ▄", + 0b0010: "▄ ", + 0b0011: "▄▄", + 0b0100: " ▀", + 0b0101: " █", + 0b0110: "▄▀", + 0b0111: "▄█", + 0b1000: "▀ ", + 0b1001: "▀▄", + 0b1010: "█ ", + 0b1011: "█▄", + 0b1100: "▀▀", + 0b1101: "▀█", + 0b1110: "█▀", + 0b1111: "██", + }, +}; + +/** + * @param {String} data + * @param {QrOpts} opts + */ +Qr.quadAscii = function (data, opts) { + let charMap = charMaps[opts.size || "mini"]; + let qrcode = Qr._create(data, opts); + let indent = opts?.indent ?? 4; + let modules = qrcode.qrcode.modules; + + let ascii = ``.padStart(indent - 1, " "); + let length = modules.length; + for (let y = 0; y < length; y += 2) { + for (let x = 0; x < length; x += 2) { + let count = 0; + // qr codes can be odd numbers + if (x >= length) { + ascii += charMap[count]; + continue; + } + if (modules[x][y]) { + count += 8; + } + if (modules[x][y + 1]) { + count += 2; + } + + if (x + 1 >= length) { + ascii += charMap[count]; + continue; + } + if (modules[x + 1][y]) { + count += 4; + } + if (modules[x + 1][y + 1]) { + count += 1; + } + ascii += charMap[count]; + } + ascii += `\n`.padEnd(indent, " "); + } + return ascii.replace(/\s+$/, ""); +}; + +/** + * @param {String} data + * @param {QrOpts} opts + */ Qr.ascii = function (data, opts) { + if (opts.size) { + return Qr.quadAscii(data, opts); + } + let qrcode = Qr._create(data, opts); let indent = opts?.indent ?? 4; - var modules = qrcode.qrcode.modules; + let modules = qrcode.qrcode.modules; - let ascii = ``.padStart(indent - 1, ' '); + let ascii = ``.padStart(indent - 1, " "); let length = modules.length; for (let y = 0; y < length; y += 1) { for (let x = 0; x < length; x += 1) { @@ -33,16 +148,25 @@ Qr.ascii = function (data, opts) { } ascii += block; } - ascii += `\n`.padEnd(indent, ' '); + ascii += `\n`.padEnd(indent, " "); } return ascii; }; +/** + * @param {String} data + * @param {QrOpts} opts + */ Qr.svg = function (data, opts) { let qrcode = Qr._create(data, opts); return qrcode.svg(); }; +/** + * @param {String} filepath + * @param {String} data + * @param {QrOpts} opts + */ Qr.save = async function (filepath, data, opts) { let qrcode = Qr.svg(data, opts); await Fs.writeFile(filepath, qrcode, "utf8");