From c378af9be10b4e964ad665f0203eeb4aac5dfdb8 Mon Sep 17 00:00:00 2001 From: BokkyPooBah Date: Fri, 10 May 2024 10:55:16 +1000 Subject: [PATCH] qrcode generator wip --- docs/js/qrcode.vue.js | 1131 +++++++++++++++++++++++++++++++++++++ docs/js/qrcode.vue.min.js | 7 + docs/notes.md | 7 + docs/offline.html | 3 +- docs/online.html | 1 + 5 files changed, 1148 insertions(+), 1 deletion(-) create mode 100644 docs/js/qrcode.vue.js create mode 100644 docs/js/qrcode.vue.min.js create mode 100644 docs/notes.md diff --git a/docs/js/qrcode.vue.js b/docs/js/qrcode.vue.js new file mode 100644 index 0000000..0983e47 --- /dev/null +++ b/docs/js/qrcode.vue.js @@ -0,0 +1,1131 @@ +/*! + * qrcode.vue v1.7.0 + * A Vue component to generate QRCode. + * © 2017-2019 @scopewu(https://github.com/scopewu) + * MIT License. + */ +(function (global, factory) { +typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : +typeof define === 'function' && define.amd ? define(factory) : +(global = global || self, global.QrcodeVue = factory()); +}(this, function () { 'use strict'; + +var mode = { + MODE_NUMBER: 1 << 0, + MODE_ALPHA_NUM: 1 << 1, + MODE_8BIT_BYTE: 1 << 2, + MODE_KANJI: 1 << 3 +}; + +function QR8bitByte(data) { + this.mode = mode.MODE_8BIT_BYTE; + this.data = data; +} + +QR8bitByte.prototype = { + getLength: function (buffer) { + return this.data.length; + }, + write: function (buffer) { + for (var i = 0; i < this.data.length; i++) { + // not JIS ... + buffer.put(this.data.charCodeAt(i), 8); + } + } +}; +var _8BitByte = QR8bitByte; + +var ErrorCorrectLevel = { + L: 1, + M: 0, + Q: 3, + H: 2 +}; + +function QRRSBlock(totalCount, dataCount) { + this.totalCount = totalCount; + this.dataCount = dataCount; +} + +QRRSBlock.RS_BLOCK_TABLE = [// L +// M +// Q +// H +// 1 +[1, 26, 19], [1, 26, 16], [1, 26, 13], [1, 26, 9], // 2 +[1, 44, 34], [1, 44, 28], [1, 44, 22], [1, 44, 16], // 3 +[1, 70, 55], [1, 70, 44], [2, 35, 17], [2, 35, 13], // 4 +[1, 100, 80], [2, 50, 32], [2, 50, 24], [4, 25, 9], // 5 +[1, 134, 108], [2, 67, 43], [2, 33, 15, 2, 34, 16], [2, 33, 11, 2, 34, 12], // 6 +[2, 86, 68], [4, 43, 27], [4, 43, 19], [4, 43, 15], // 7 +[2, 98, 78], [4, 49, 31], [2, 32, 14, 4, 33, 15], [4, 39, 13, 1, 40, 14], // 8 +[2, 121, 97], [2, 60, 38, 2, 61, 39], [4, 40, 18, 2, 41, 19], [4, 40, 14, 2, 41, 15], // 9 +[2, 146, 116], [3, 58, 36, 2, 59, 37], [4, 36, 16, 4, 37, 17], [4, 36, 12, 4, 37, 13], // 10 +[2, 86, 68, 2, 87, 69], [4, 69, 43, 1, 70, 44], [6, 43, 19, 2, 44, 20], [6, 43, 15, 2, 44, 16], // 11 +[4, 101, 81], [1, 80, 50, 4, 81, 51], [4, 50, 22, 4, 51, 23], [3, 36, 12, 8, 37, 13], // 12 +[2, 116, 92, 2, 117, 93], [6, 58, 36, 2, 59, 37], [4, 46, 20, 6, 47, 21], [7, 42, 14, 4, 43, 15], // 13 +[4, 133, 107], [8, 59, 37, 1, 60, 38], [8, 44, 20, 4, 45, 21], [12, 33, 11, 4, 34, 12], // 14 +[3, 145, 115, 1, 146, 116], [4, 64, 40, 5, 65, 41], [11, 36, 16, 5, 37, 17], [11, 36, 12, 5, 37, 13], // 15 +[5, 109, 87, 1, 110, 88], [5, 65, 41, 5, 66, 42], [5, 54, 24, 7, 55, 25], [11, 36, 12], // 16 +[5, 122, 98, 1, 123, 99], [7, 73, 45, 3, 74, 46], [15, 43, 19, 2, 44, 20], [3, 45, 15, 13, 46, 16], // 17 +[1, 135, 107, 5, 136, 108], [10, 74, 46, 1, 75, 47], [1, 50, 22, 15, 51, 23], [2, 42, 14, 17, 43, 15], // 18 +[5, 150, 120, 1, 151, 121], [9, 69, 43, 4, 70, 44], [17, 50, 22, 1, 51, 23], [2, 42, 14, 19, 43, 15], // 19 +[3, 141, 113, 4, 142, 114], [3, 70, 44, 11, 71, 45], [17, 47, 21, 4, 48, 22], [9, 39, 13, 16, 40, 14], // 20 +[3, 135, 107, 5, 136, 108], [3, 67, 41, 13, 68, 42], [15, 54, 24, 5, 55, 25], [15, 43, 15, 10, 44, 16], // 21 +[4, 144, 116, 4, 145, 117], [17, 68, 42], [17, 50, 22, 6, 51, 23], [19, 46, 16, 6, 47, 17], // 22 +[2, 139, 111, 7, 140, 112], [17, 74, 46], [7, 54, 24, 16, 55, 25], [34, 37, 13], // 23 +[4, 151, 121, 5, 152, 122], [4, 75, 47, 14, 76, 48], [11, 54, 24, 14, 55, 25], [16, 45, 15, 14, 46, 16], // 24 +[6, 147, 117, 4, 148, 118], [6, 73, 45, 14, 74, 46], [11, 54, 24, 16, 55, 25], [30, 46, 16, 2, 47, 17], // 25 +[8, 132, 106, 4, 133, 107], [8, 75, 47, 13, 76, 48], [7, 54, 24, 22, 55, 25], [22, 45, 15, 13, 46, 16], // 26 +[10, 142, 114, 2, 143, 115], [19, 74, 46, 4, 75, 47], [28, 50, 22, 6, 51, 23], [33, 46, 16, 4, 47, 17], // 27 +[8, 152, 122, 4, 153, 123], [22, 73, 45, 3, 74, 46], [8, 53, 23, 26, 54, 24], [12, 45, 15, 28, 46, 16], // 28 +[3, 147, 117, 10, 148, 118], [3, 73, 45, 23, 74, 46], [4, 54, 24, 31, 55, 25], [11, 45, 15, 31, 46, 16], // 29 +[7, 146, 116, 7, 147, 117], [21, 73, 45, 7, 74, 46], [1, 53, 23, 37, 54, 24], [19, 45, 15, 26, 46, 16], // 30 +[5, 145, 115, 10, 146, 116], [19, 75, 47, 10, 76, 48], [15, 54, 24, 25, 55, 25], [23, 45, 15, 25, 46, 16], // 31 +[13, 145, 115, 3, 146, 116], [2, 74, 46, 29, 75, 47], [42, 54, 24, 1, 55, 25], [23, 45, 15, 28, 46, 16], // 32 +[17, 145, 115], [10, 74, 46, 23, 75, 47], [10, 54, 24, 35, 55, 25], [19, 45, 15, 35, 46, 16], // 33 +[17, 145, 115, 1, 146, 116], [14, 74, 46, 21, 75, 47], [29, 54, 24, 19, 55, 25], [11, 45, 15, 46, 46, 16], // 34 +[13, 145, 115, 6, 146, 116], [14, 74, 46, 23, 75, 47], [44, 54, 24, 7, 55, 25], [59, 46, 16, 1, 47, 17], // 35 +[12, 151, 121, 7, 152, 122], [12, 75, 47, 26, 76, 48], [39, 54, 24, 14, 55, 25], [22, 45, 15, 41, 46, 16], // 36 +[6, 151, 121, 14, 152, 122], [6, 75, 47, 34, 76, 48], [46, 54, 24, 10, 55, 25], [2, 45, 15, 64, 46, 16], // 37 +[17, 152, 122, 4, 153, 123], [29, 74, 46, 14, 75, 47], [49, 54, 24, 10, 55, 25], [24, 45, 15, 46, 46, 16], // 38 +[4, 152, 122, 18, 153, 123], [13, 74, 46, 32, 75, 47], [48, 54, 24, 14, 55, 25], [42, 45, 15, 32, 46, 16], // 39 +[20, 147, 117, 4, 148, 118], [40, 75, 47, 7, 76, 48], [43, 54, 24, 22, 55, 25], [10, 45, 15, 67, 46, 16], // 40 +[19, 148, 118, 6, 149, 119], [18, 75, 47, 31, 76, 48], [34, 54, 24, 34, 55, 25], [20, 45, 15, 61, 46, 16]]; + +QRRSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) { + var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel); + + if (rsBlock == undefined) { + throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel); + } + + var length = rsBlock.length / 3; + var list = new Array(); + + for (var i = 0; i < length; i++) { + var count = rsBlock[i * 3 + 0]; + var totalCount = rsBlock[i * 3 + 1]; + var dataCount = rsBlock[i * 3 + 2]; + + for (var j = 0; j < count; j++) { + list.push(new QRRSBlock(totalCount, dataCount)); + } + } + + return list; +}; + +QRRSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) { + switch (errorCorrectLevel) { + case ErrorCorrectLevel.L: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; + + case ErrorCorrectLevel.M: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; + + case ErrorCorrectLevel.Q: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; + + case ErrorCorrectLevel.H: + return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; + + default: + return undefined; + } +}; + +var RSBlock = QRRSBlock; + +function QRBitBuffer() { + this.buffer = new Array(); + this.length = 0; +} + +QRBitBuffer.prototype = { + get: function (index) { + var bufIndex = Math.floor(index / 8); + return (this.buffer[bufIndex] >>> 7 - index % 8 & 1) == 1; + }, + put: function (num, length) { + for (var i = 0; i < length; i++) { + this.putBit((num >>> length - i - 1 & 1) == 1); + } + }, + getLengthInBits: function () { + return this.length; + }, + putBit: function (bit) { + var bufIndex = Math.floor(this.length / 8); + + if (this.buffer.length <= bufIndex) { + this.buffer.push(0); + } + + if (bit) { + this.buffer[bufIndex] |= 0x80 >>> this.length % 8; + } + + this.length++; + } +}; +var BitBuffer = QRBitBuffer; + +var QRMath = { + glog: function (n) { + if (n < 1) { + throw new Error("glog(" + n + ")"); + } + + return QRMath.LOG_TABLE[n]; + }, + gexp: function (n) { + while (n < 0) { + n += 255; + } + + while (n >= 256) { + n -= 255; + } + + return QRMath.EXP_TABLE[n]; + }, + EXP_TABLE: new Array(256), + LOG_TABLE: new Array(256) +}; + +for (var i = 0; i < 8; i++) { + QRMath.EXP_TABLE[i] = 1 << i; +} + +for (var i = 8; i < 256; i++) { + QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8]; +} + +for (var i = 0; i < 255; i++) { + QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i; +} + +var math = QRMath; + +function QRPolynomial(num, shift) { + if (num.length == undefined) { + throw new Error(num.length + "/" + shift); + } + + var offset = 0; + + while (offset < num.length && num[offset] == 0) { + offset++; + } + + this.num = new Array(num.length - offset + shift); + + for (var i = 0; i < num.length - offset; i++) { + this.num[i] = num[i + offset]; + } +} + +QRPolynomial.prototype = { + get: function (index) { + return this.num[index]; + }, + getLength: function () { + return this.num.length; + }, + multiply: function (e) { + var num = new Array(this.getLength() + e.getLength() - 1); + + for (var i = 0; i < this.getLength(); i++) { + for (var j = 0; j < e.getLength(); j++) { + num[i + j] ^= math.gexp(math.glog(this.get(i)) + math.glog(e.get(j))); + } + } + + return new QRPolynomial(num, 0); + }, + mod: function (e) { + if (this.getLength() - e.getLength() < 0) { + return this; + } + + var ratio = math.glog(this.get(0)) - math.glog(e.get(0)); + var num = new Array(this.getLength()); + + for (var i = 0; i < this.getLength(); i++) { + num[i] = this.get(i); + } + + for (var i = 0; i < e.getLength(); i++) { + num[i] ^= math.gexp(math.glog(e.get(i)) + ratio); + } // recursive call + + + return new QRPolynomial(num, 0).mod(e); + } +}; +var Polynomial = QRPolynomial; + +var QRMaskPattern = { + PATTERN000: 0, + PATTERN001: 1, + PATTERN010: 2, + PATTERN011: 3, + PATTERN100: 4, + PATTERN101: 5, + PATTERN110: 6, + PATTERN111: 7 +}; +var QRUtil = { + PATTERN_POSITION_TABLE: [[], [6, 18], [6, 22], [6, 26], [6, 30], [6, 34], [6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50], [6, 30, 54], [6, 32, 58], [6, 34, 62], [6, 26, 46, 66], [6, 26, 48, 70], [6, 26, 50, 74], [6, 30, 54, 78], [6, 30, 56, 82], [6, 30, 58, 86], [6, 34, 62, 90], [6, 28, 50, 72, 94], [6, 26, 50, 74, 98], [6, 30, 54, 78, 102], [6, 28, 54, 80, 106], [6, 32, 58, 84, 110], [6, 30, 58, 86, 114], [6, 34, 62, 90, 118], [6, 26, 50, 74, 98, 122], [6, 30, 54, 78, 102, 126], [6, 26, 52, 78, 104, 130], [6, 30, 56, 82, 108, 134], [6, 34, 60, 86, 112, 138], [6, 30, 58, 86, 114, 142], [6, 34, 62, 90, 118, 146], [6, 30, 54, 78, 102, 126, 150], [6, 24, 50, 76, 102, 128, 154], [6, 28, 54, 80, 106, 132, 158], [6, 32, 58, 84, 110, 136, 162], [6, 26, 54, 82, 110, 138, 166], [6, 30, 58, 86, 114, 142, 170]], + G15: 1 << 10 | 1 << 8 | 1 << 5 | 1 << 4 | 1 << 2 | 1 << 1 | 1 << 0, + G18: 1 << 12 | 1 << 11 | 1 << 10 | 1 << 9 | 1 << 8 | 1 << 5 | 1 << 2 | 1 << 0, + G15_MASK: 1 << 14 | 1 << 12 | 1 << 10 | 1 << 4 | 1 << 1, + getBCHTypeInfo: function (data) { + var d = data << 10; + + while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) { + d ^= QRUtil.G15 << QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15); + } + + return (data << 10 | d) ^ QRUtil.G15_MASK; + }, + getBCHTypeNumber: function (data) { + var d = data << 12; + + while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) { + d ^= QRUtil.G18 << QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18); + } + + return data << 12 | d; + }, + getBCHDigit: function (data) { + var digit = 0; + + while (data != 0) { + digit++; + data >>>= 1; + } + + return digit; + }, + getPatternPosition: function (typeNumber) { + return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]; + }, + getMask: function (maskPattern, i, j) { + switch (maskPattern) { + case QRMaskPattern.PATTERN000: + return (i + j) % 2 == 0; + + case QRMaskPattern.PATTERN001: + return i % 2 == 0; + + case QRMaskPattern.PATTERN010: + return j % 3 == 0; + + case QRMaskPattern.PATTERN011: + return (i + j) % 3 == 0; + + case QRMaskPattern.PATTERN100: + return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0; + + case QRMaskPattern.PATTERN101: + return i * j % 2 + i * j % 3 == 0; + + case QRMaskPattern.PATTERN110: + return (i * j % 2 + i * j % 3) % 2 == 0; + + case QRMaskPattern.PATTERN111: + return (i * j % 3 + (i + j) % 2) % 2 == 0; + + default: + throw new Error("bad maskPattern:" + maskPattern); + } + }, + getErrorCorrectPolynomial: function (errorCorrectLength) { + var a = new Polynomial([1], 0); + + for (var i = 0; i < errorCorrectLength; i++) { + a = a.multiply(new Polynomial([1, math.gexp(i)], 0)); + } + + return a; + }, + getLengthInBits: function (mode$1, type) { + if (1 <= type && type < 10) { + // 1 - 9 + switch (mode$1) { + case mode.MODE_NUMBER: + return 10; + + case mode.MODE_ALPHA_NUM: + return 9; + + case mode.MODE_8BIT_BYTE: + return 8; + + case mode.MODE_KANJI: + return 8; + + default: + throw new Error("mode:" + mode$1); + } + } else if (type < 27) { + // 10 - 26 + switch (mode$1) { + case mode.MODE_NUMBER: + return 12; + + case mode.MODE_ALPHA_NUM: + return 11; + + case mode.MODE_8BIT_BYTE: + return 16; + + case mode.MODE_KANJI: + return 10; + + default: + throw new Error("mode:" + mode$1); + } + } else if (type < 41) { + // 27 - 40 + switch (mode$1) { + case mode.MODE_NUMBER: + return 14; + + case mode.MODE_ALPHA_NUM: + return 13; + + case mode.MODE_8BIT_BYTE: + return 16; + + case mode.MODE_KANJI: + return 12; + + default: + throw new Error("mode:" + mode$1); + } + } else { + throw new Error("type:" + type); + } + }, + getLostPoint: function (qrCode) { + var moduleCount = qrCode.getModuleCount(); + var lostPoint = 0; // LEVEL1 + + for (var row = 0; row < moduleCount; row++) { + for (var col = 0; col < moduleCount; col++) { + var sameCount = 0; + var dark = qrCode.isDark(row, col); + + for (var r = -1; r <= 1; r++) { + if (row + r < 0 || moduleCount <= row + r) { + continue; + } + + for (var c = -1; c <= 1; c++) { + if (col + c < 0 || moduleCount <= col + c) { + continue; + } + + if (r == 0 && c == 0) { + continue; + } + + if (dark == qrCode.isDark(row + r, col + c)) { + sameCount++; + } + } + } + + if (sameCount > 5) { + lostPoint += 3 + sameCount - 5; + } + } + } // LEVEL2 + + + for (var row = 0; row < moduleCount - 1; row++) { + for (var col = 0; col < moduleCount - 1; col++) { + var count = 0; + if (qrCode.isDark(row, col)) count++; + if (qrCode.isDark(row + 1, col)) count++; + if (qrCode.isDark(row, col + 1)) count++; + if (qrCode.isDark(row + 1, col + 1)) count++; + + if (count == 0 || count == 4) { + lostPoint += 3; + } + } + } // LEVEL3 + + + for (var row = 0; row < moduleCount; row++) { + for (var col = 0; col < moduleCount - 6; col++) { + if (qrCode.isDark(row, col) && !qrCode.isDark(row, col + 1) && qrCode.isDark(row, col + 2) && qrCode.isDark(row, col + 3) && qrCode.isDark(row, col + 4) && !qrCode.isDark(row, col + 5) && qrCode.isDark(row, col + 6)) { + lostPoint += 40; + } + } + } + + for (var col = 0; col < moduleCount; col++) { + for (var row = 0; row < moduleCount - 6; row++) { + if (qrCode.isDark(row, col) && !qrCode.isDark(row + 1, col) && qrCode.isDark(row + 2, col) && qrCode.isDark(row + 3, col) && qrCode.isDark(row + 4, col) && !qrCode.isDark(row + 5, col) && qrCode.isDark(row + 6, col)) { + lostPoint += 40; + } + } + } // LEVEL4 + + + var darkCount = 0; + + for (var col = 0; col < moduleCount; col++) { + for (var row = 0; row < moduleCount; row++) { + if (qrCode.isDark(row, col)) { + darkCount++; + } + } + } + + var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; + lostPoint += ratio * 10; + return lostPoint; + } +}; +var util = QRUtil; + +function QRCode(typeNumber, errorCorrectLevel) { + this.typeNumber = typeNumber; + this.errorCorrectLevel = errorCorrectLevel; + this.modules = null; + this.moduleCount = 0; + this.dataCache = null; + this.dataList = []; +} // for client side minification + + +var proto = QRCode.prototype; + +proto.addData = function (data) { + var newData = new _8BitByte(data); + this.dataList.push(newData); + this.dataCache = null; +}; + +proto.isDark = function (row, col) { + if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) { + throw new Error(row + "," + col); + } + + return this.modules[row][col]; +}; + +proto.getModuleCount = function () { + return this.moduleCount; +}; + +proto.make = function () { + // Calculate automatically typeNumber if provided is < 1 + if (this.typeNumber < 1) { + var typeNumber = 1; + + for (typeNumber = 1; typeNumber < 40; typeNumber++) { + var rsBlocks = RSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel); + var buffer = new BitBuffer(); + var totalDataCount = 0; + + for (var i = 0; i < rsBlocks.length; i++) { + totalDataCount += rsBlocks[i].dataCount; + } + + for (var i = 0; i < this.dataList.length; i++) { + var data = this.dataList[i]; + buffer.put(data.mode, 4); + buffer.put(data.getLength(), util.getLengthInBits(data.mode, typeNumber)); + data.write(buffer); + } + + if (buffer.getLengthInBits() <= totalDataCount * 8) break; + } + + this.typeNumber = typeNumber; + } + + this.makeImpl(false, this.getBestMaskPattern()); +}; + +proto.makeImpl = function (test, maskPattern) { + this.moduleCount = this.typeNumber * 4 + 17; + this.modules = new Array(this.moduleCount); + + for (var row = 0; row < this.moduleCount; row++) { + this.modules[row] = new Array(this.moduleCount); + + for (var col = 0; col < this.moduleCount; col++) { + this.modules[row][col] = null; //(col + row) % 3; + } + } + + this.setupPositionProbePattern(0, 0); + this.setupPositionProbePattern(this.moduleCount - 7, 0); + this.setupPositionProbePattern(0, this.moduleCount - 7); + this.setupPositionAdjustPattern(); + this.setupTimingPattern(); + this.setupTypeInfo(test, maskPattern); + + if (this.typeNumber >= 7) { + this.setupTypeNumber(test); + } + + if (this.dataCache == null) { + this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList); + } + + this.mapData(this.dataCache, maskPattern); +}; + +proto.setupPositionProbePattern = function (row, col) { + for (var r = -1; r <= 7; r++) { + if (row + r <= -1 || this.moduleCount <= row + r) continue; + + for (var c = -1; c <= 7; c++) { + if (col + c <= -1 || this.moduleCount <= col + c) continue; + + if (0 <= r && r <= 6 && (c == 0 || c == 6) || 0 <= c && c <= 6 && (r == 0 || r == 6) || 2 <= r && r <= 4 && 2 <= c && c <= 4) { + this.modules[row + r][col + c] = true; + } else { + this.modules[row + r][col + c] = false; + } + } + } +}; + +proto.getBestMaskPattern = function () { + var minLostPoint = 0; + var pattern = 0; + + for (var i = 0; i < 8; i++) { + this.makeImpl(true, i); + var lostPoint = util.getLostPoint(this); + + if (i == 0 || minLostPoint > lostPoint) { + minLostPoint = lostPoint; + pattern = i; + } + } + + return pattern; +}; + +proto.createMovieClip = function (target_mc, instance_name, depth) { + var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth); + var cs = 1; + this.make(); + + for (var row = 0; row < this.modules.length; row++) { + var y = row * cs; + + for (var col = 0; col < this.modules[row].length; col++) { + var x = col * cs; + var dark = this.modules[row][col]; + + if (dark) { + qr_mc.beginFill(0, 100); + qr_mc.moveTo(x, y); + qr_mc.lineTo(x + cs, y); + qr_mc.lineTo(x + cs, y + cs); + qr_mc.lineTo(x, y + cs); + qr_mc.endFill(); + } + } + } + + return qr_mc; +}; + +proto.setupTimingPattern = function () { + for (var r = 8; r < this.moduleCount - 8; r++) { + if (this.modules[r][6] != null) { + continue; + } + + this.modules[r][6] = r % 2 == 0; + } + + for (var c = 8; c < this.moduleCount - 8; c++) { + if (this.modules[6][c] != null) { + continue; + } + + this.modules[6][c] = c % 2 == 0; + } +}; + +proto.setupPositionAdjustPattern = function () { + var pos = util.getPatternPosition(this.typeNumber); + + for (var i = 0; i < pos.length; i++) { + for (var j = 0; j < pos.length; j++) { + var row = pos[i]; + var col = pos[j]; + + if (this.modules[row][col] != null) { + continue; + } + + for (var r = -2; r <= 2; r++) { + for (var c = -2; c <= 2; c++) { + if (r == -2 || r == 2 || c == -2 || c == 2 || r == 0 && c == 0) { + this.modules[row + r][col + c] = true; + } else { + this.modules[row + r][col + c] = false; + } + } + } + } + } +}; + +proto.setupTypeNumber = function (test) { + var bits = util.getBCHTypeNumber(this.typeNumber); + + for (var i = 0; i < 18; i++) { + var mod = !test && (bits >> i & 1) == 1; + this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod; + } + + for (var i = 0; i < 18; i++) { + var mod = !test && (bits >> i & 1) == 1; + this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod; + } +}; + +proto.setupTypeInfo = function (test, maskPattern) { + var data = this.errorCorrectLevel << 3 | maskPattern; + var bits = util.getBCHTypeInfo(data); // vertical + + for (var i = 0; i < 15; i++) { + var mod = !test && (bits >> i & 1) == 1; + + if (i < 6) { + this.modules[i][8] = mod; + } else if (i < 8) { + this.modules[i + 1][8] = mod; + } else { + this.modules[this.moduleCount - 15 + i][8] = mod; + } + } // horizontal + + + for (var i = 0; i < 15; i++) { + var mod = !test && (bits >> i & 1) == 1; + + if (i < 8) { + this.modules[8][this.moduleCount - i - 1] = mod; + } else if (i < 9) { + this.modules[8][15 - i - 1 + 1] = mod; + } else { + this.modules[8][15 - i - 1] = mod; + } + } // fixed module + + + this.modules[this.moduleCount - 8][8] = !test; +}; + +proto.mapData = function (data, maskPattern) { + var inc = -1; + var row = this.moduleCount - 1; + var bitIndex = 7; + var byteIndex = 0; + + for (var col = this.moduleCount - 1; col > 0; col -= 2) { + if (col == 6) col--; + + while (true) { + for (var c = 0; c < 2; c++) { + if (this.modules[row][col - c] == null) { + var dark = false; + + if (byteIndex < data.length) { + dark = (data[byteIndex] >>> bitIndex & 1) == 1; + } + + var mask = util.getMask(maskPattern, row, col - c); + + if (mask) { + dark = !dark; + } + + this.modules[row][col - c] = dark; + bitIndex--; + + if (bitIndex == -1) { + byteIndex++; + bitIndex = 7; + } + } + } + + row += inc; + + if (row < 0 || this.moduleCount <= row) { + row -= inc; + inc = -inc; + break; + } + } + } +}; + +QRCode.PAD0 = 0xEC; +QRCode.PAD1 = 0x11; + +QRCode.createData = function (typeNumber, errorCorrectLevel, dataList) { + var rsBlocks = RSBlock.getRSBlocks(typeNumber, errorCorrectLevel); + var buffer = new BitBuffer(); + + for (var i = 0; i < dataList.length; i++) { + var data = dataList[i]; + buffer.put(data.mode, 4); + buffer.put(data.getLength(), util.getLengthInBits(data.mode, typeNumber)); + data.write(buffer); + } // calc num max data. + + + var totalDataCount = 0; + + for (var i = 0; i < rsBlocks.length; i++) { + totalDataCount += rsBlocks[i].dataCount; + } + + if (buffer.getLengthInBits() > totalDataCount * 8) { + throw new Error("code length overflow. (" + buffer.getLengthInBits() + ">" + totalDataCount * 8 + ")"); + } // end code + + + if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { + buffer.put(0, 4); + } // padding + + + while (buffer.getLengthInBits() % 8 != 0) { + buffer.putBit(false); + } // padding + + + while (true) { + if (buffer.getLengthInBits() >= totalDataCount * 8) { + break; + } + + buffer.put(QRCode.PAD0, 8); + + if (buffer.getLengthInBits() >= totalDataCount * 8) { + break; + } + + buffer.put(QRCode.PAD1, 8); + } + + return QRCode.createBytes(buffer, rsBlocks); +}; + +QRCode.createBytes = function (buffer, rsBlocks) { + var offset = 0; + var maxDcCount = 0; + var maxEcCount = 0; + var dcdata = new Array(rsBlocks.length); + var ecdata = new Array(rsBlocks.length); + + for (var r = 0; r < rsBlocks.length; r++) { + var dcCount = rsBlocks[r].dataCount; + var ecCount = rsBlocks[r].totalCount - dcCount; + maxDcCount = Math.max(maxDcCount, dcCount); + maxEcCount = Math.max(maxEcCount, ecCount); + dcdata[r] = new Array(dcCount); + + for (var i = 0; i < dcdata[r].length; i++) { + dcdata[r][i] = 0xff & buffer.buffer[i + offset]; + } + + offset += dcCount; + var rsPoly = util.getErrorCorrectPolynomial(ecCount); + var rawPoly = new Polynomial(dcdata[r], rsPoly.getLength() - 1); + var modPoly = rawPoly.mod(rsPoly); + ecdata[r] = new Array(rsPoly.getLength() - 1); + + for (var i = 0; i < ecdata[r].length; i++) { + var modIndex = i + modPoly.getLength() - ecdata[r].length; + ecdata[r][i] = modIndex >= 0 ? modPoly.get(modIndex) : 0; + } + } + + var totalCodeCount = 0; + + for (var i = 0; i < rsBlocks.length; i++) { + totalCodeCount += rsBlocks[i].totalCount; + } + + var data = new Array(totalCodeCount); + var index = 0; + + for (var i = 0; i < maxDcCount; i++) { + for (var r = 0; r < rsBlocks.length; r++) { + if (i < dcdata[r].length) { + data[index++] = dcdata[r][i]; + } + } + } + + for (var i = 0; i < maxEcCount; i++) { + for (var r = 0; r < rsBlocks.length; r++) { + if (i < ecdata[r].length) { + data[index++] = ecdata[r][i]; + } + } + } + + return data; +}; + +var QRCode_1 = QRCode; + +/** + * Encode UTF16 to UTF8. + * See: http://jonisalonen.com/2012/from-utf-16-to-utf-8-in-javascript/ + * @param str {string} + * @returns {string} + */ + +function toUTF8String(str) { + var utf8Str = ''; + + for (var i = 0; i < str.length; i++) { + var charCode = str.charCodeAt(i); + + if (charCode < 0x0080) { + utf8Str += String.fromCharCode(charCode); + } else if (charCode < 0x0800) { + utf8Str += String.fromCharCode(0xc0 | charCode >> 6); + utf8Str += String.fromCharCode(0x80 | charCode & 0x3f); + } else if (charCode < 0xd800 || charCode >= 0xe000) { + utf8Str += String.fromCharCode(0xe0 | charCode >> 12); + utf8Str += String.fromCharCode(0x80 | charCode >> 6 & 0x3f); + utf8Str += String.fromCharCode(0x80 | charCode & 0x3f); + } else { + // surrogate pair + i++; // UTF-16 encodes 0x10000-0x10FFFF by + // subtracting 0x10000 and splitting the + // 20 bits of 0x0-0xFFFFF into two halves + + charCode = 0x10000 + ((charCode & 0x3ff) << 10 | str.charCodeAt(i) & 0x3ff); + utf8Str += String.fromCharCode(0xf0 | charCode >> 18); + utf8Str += String.fromCharCode(0x80 | charCode >> 12 & 0x3f); + utf8Str += String.fromCharCode(0x80 | charCode >> 6 & 0x3f); + utf8Str += String.fromCharCode(0x80 | charCode & 0x3f); + } + } + + return utf8Str; +} + +function generatePath(modules) { + var margin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var ops = []; + modules.forEach(function (row, y) { + var start = null; + row.forEach(function (cell, x) { + if (!cell && start !== null) { + // M0 0h7v1H0z injects the space with the move and drops the comma, + // saving a char per operation + ops.push("M".concat(start + margin, " ").concat(y + margin, "h").concat(x - start, "v1H").concat(start + margin, "z")); + start = null; + return; + } // end of row, clean up or skip + + + if (x === row.length - 1) { + if (!cell) { + // We would have closed the op above already so this can only mean + // 2+ light modules in a row. + return; + } + + if (start === null) { + // Just a single dark module. + ops.push("M".concat(x + margin, ",").concat(y + margin, " h1v1H").concat(x + margin, "z")); + } else { + // Otherwise finish the current line. + ops.push("M".concat(start + margin, ",").concat(y + margin, " h").concat(x + 1 - start, "v1H").concat(start + margin, "z")); + } + + return; + } + + if (cell && start === null) { + start = x; + } + }); + }); + return ops.join(''); +} // @vue/component + + +var QrcodeVue = { + props: { + value: { + type: String, + required: true, + default: '' + }, + className: { + type: String, + default: '' + }, + size: { + type: [Number, String], + default: 100, + validator: function validator(s) { + return isNaN(Number(s)) !== true; + } + }, + level: { + type: String, + default: 'L', + validator: function validator(l) { + return ['L', 'Q', 'M', 'H'].indexOf(l) > -1; + } + }, + background: { + type: String, + default: '#fff' + }, + foreground: { + type: String, + default: '#000' + }, + renderAs: { + type: String, + required: false, + default: 'canvas', + validator: function validator(as) { + return ['canvas', 'svg'].indexOf(as) > -1; + } + } + }, + data: function data() { + return { + numCells: 0, + fgPath: '' + }; + }, + updated: function updated() { + this.render(); + }, + mounted: function mounted() { + this.render(); + }, + methods: { + render: function render() { + var value = this.value, + size = this.size, + level = this.level, + background = this.background, + foreground = this.foreground, + renderAs = this.renderAs; + + var _size = size >>> 0; // size to number + // We'll use type===-1 to force QRCode to automatically pick the best type + + + var qrCode = new QRCode_1(-1, ErrorCorrectLevel[level]); + qrCode.addData(toUTF8String(value)); + qrCode.make(); + var cells = qrCode.modules; + var tileW = _size / cells.length; + var tileH = _size / cells.length; + var scale = window.devicePixelRatio || 1; + + if (renderAs === 'svg') { + this.numCells = cells.length; // Drawing strategy: instead of a rect per module, we're going to create a + // single path for the dark modules and layer that on top of a light rect, + // for a total of 2 DOM nodes. We pay a bit more in string concat but that's + // way faster than DOM ops. + // For level 1, 441 nodes -> 2 + // For level 40, 31329 -> 2 + + this.fgPath = generatePath(cells); + } else { + var canvas = this.$refs['qrcode-vue']; + var ctx = canvas.getContext('2d'); + canvas.height = canvas.width = _size * scale; + ctx.scale(scale, scale); + cells.forEach(function (row, rdx) { + row.forEach(function (cell, cdx) { + ctx.fillStyle = cell ? foreground : background; + var w = Math.ceil((cdx + 1) * tileW) - Math.floor(cdx * tileW); + var h = Math.ceil((rdx + 1) * tileH) - Math.floor(rdx * tileH); + ctx.fillRect(Math.round(cdx * tileW), Math.round(rdx * tileH), w, h); + }); + }); + } + } + }, + render: function render(createElement) { + var className = this.className, + value = this.value, + level = this.level, + background = this.background, + foreground = this.foreground, + size = this.size, + renderAs = this.renderAs, + numCells = this.numCells, + fgPath = this.fgPath; + return createElement('div', { + class: this.class || className, + attrs: { + value: value, + level: level, + background: background, + foreground: foreground + } + }, [renderAs === 'svg' ? createElement('svg', { + attrs: { + height: size, + width: size, + shapeRendering: 'crispEdges', + viewBox: "0 0 ".concat(numCells, " ").concat(numCells) + }, + style: { + width: size + 'px', + height: size + 'px' + } + }, [createElement('path', { + attrs: { + fill: background, + d: "M0,0 h".concat(numCells, "v").concat(numCells, "H0z") + } + }), createElement('path', { + attrs: { + fill: foreground, + d: fgPath + } + })]) : createElement('canvas', { + attrs: { + height: size, + width: size + }, + style: { + width: size + 'px', + height: size + 'px' + }, + ref: 'qrcode-vue' + }, [])]); + } +}; + +return QrcodeVue; + +})); diff --git a/docs/js/qrcode.vue.min.js b/docs/js/qrcode.vue.min.js new file mode 100644 index 0000000..7db225e --- /dev/null +++ b/docs/js/qrcode.vue.min.js @@ -0,0 +1,7 @@ +/*! + * qrcode.vue v1.7.0 + * A Vue component to generate QRCode. + * © 2017-2019 @scopewu(https://github.com/scopewu) + * MIT License. + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).QrcodeVue=e()}(this,function(){"use strict";var r=1,n=2,o=4,i=8;function t(t){this.mode=o,this.data=t}t.prototype={getLength:function(t){return this.data.length},write:function(t){for(var e=0;e>>7-t%8&1)},put:function(t,e){for(var r=0;r>>e-r-1&1))},getLengthInBits:function(){return this.length},putBit:function(t){var e=Math.floor(this.length/8);e>>this.length%8),this.length++}};for(var h=e,s={glog:function(t){if(t<1)throw Error("glog("+t+")");return s.LOG_TABLE[t]},gexp:function(t){for(;t<0;)t+=255;for(;256<=t;)t-=255;return s.EXP_TABLE[t]},EXP_TABLE:Array(256),LOG_TABLE:Array(256)},f=0;f<8;f++)s.EXP_TABLE[f]=1<>>=1;return e},getPatternPosition:function(t){return A.PATTERN_POSITION_TABLE[t-1]},getMask:function(t,e,r){switch(t){case m:return(e+r)%2==0;case v:return e%2==0;case C:return r%3==0;case L:return(e+r)%3==0;case B:return(Math.floor(e/2)+Math.floor(r/3))%2==0;case y:return e*r%2+e*r%3==0;case P:return(e*r%2+e*r%3)%2==0;case E:return(e*r%3+(e+r)%2)%2==0;default:throw Error("bad maskPattern:"+t)}},getErrorCorrectPolynomial:function(t){for(var e=new p([1],0),r=0;r>r&1);this.modules[Math.floor(r/3)][r%3+this.moduleCount-8-3]=n}for(r=0;r<18;r++){n=!t&&1==(e>>r&1);this.modules[r%3+this.moduleCount-8-3][Math.floor(r/3)]=n}},T.setupTypeInfo=function(t,e){for(var r=k.getBCHTypeInfo(this.errorCorrectLevel<<3|e),n=0;n<15;n++){var o=!t&&1==(r>>n&1);n<6?this.modules[n][8]=o:n<8?this.modules[n+1][8]=o:this.modules[this.moduleCount-15+n][8]=o}for(n=0;n<15;n++){o=!t&&1==(r>>n&1);n<8?this.modules[8][this.moduleCount-n-1]=o:n<9?this.modules[8][15-n-1+1]=o:this.modules[8][15-n-1]=o}this.modules[this.moduleCount-8][8]=!t},T.mapData=function(t,e){for(var r=-1,n=this.moduleCount-1,o=7,i=0,a=this.moduleCount-1;0>>o&1)),k.getMask(e,n,a-s)&&(u=!u),this.modules[n][a-s]=u,-1==--o&&(i++,o=7)}if((n+=r)<0||this.moduleCount<=n){n-=r,r=-r;break}}},D.PAD0=236,D.PAD1=17,D.createData=function(t,e,r){for(var n=u.getRSBlocks(t,e),o=new h,i=0;i8*s)throw Error("code length overflow. ("+o.getLengthInBits()+">"+8*s+")");for(o.getLengthInBits()+4>8*s||o.put(0,4);o.getLengthInBits()%8!=0;)o.putBit(!1);for(;o.getLengthInBits()<8*s&&(o.put(D.PAD0,8),o.getLengthInBits()<8*s);)o.put(D.PAD1,8);return D.createBytes(o,n)},D.createBytes=function(t,e){for(var r=0,n=0,o=0,i=Array(e.length),a=Array(e.length),s=0;s>>0,n=new b(-1,g[this.level]);n.addData(function(t){for(var e="",r=0;r>6):(n<55296||57344<=n?e+=String.fromCharCode(224|n>>12):(n=65536+((1023&n)<<10|1023&t.charCodeAt(++r)),e+=String.fromCharCode(240|n>>18),e+=String.fromCharCode(128|n>>12&63)),e+=String.fromCharCode(128|n>>6&63)),e+=String.fromCharCode(128|63&n))}return e}(t)),n.make();var o=n.modules,s=r/o.length,u=r/o.length,h=window.devicePixelRatio||1;if("svg"===e)this.numCells=o.length,this.fgPath=function(t,e){var i=1 https://scanapp.org/html5-qrcode-docs/docs/intro +--> https://unpkg.com/html5-qrcode + +https://github.com/scopewu/qrcode.vue/releases?page=2 v1.7.0 +npm install --save qrcode.vue@1.7.0 +copy qrcode.vue.js and qrcode.vue.min.js diff --git a/docs/offline.html b/docs/offline.html index 16b962c..1cb9364 100644 --- a/docs/offline.html +++ b/docs/offline.html @@ -19,6 +19,7 @@ + @@ -1366,7 +1367,7 @@ function onScanFailure(error) { // handle scan failure, usually better to ignore and keep scanning. // for example: - console.warn(`Code scan error = ${error}`); + // console.warn(`Code scan error = ${error}`); } let html5QrcodeScanner = new Html5QrcodeScanner( diff --git a/docs/online.html b/docs/online.html index 7f99cc4..6de5a48 100644 --- a/docs/online.html +++ b/docs/online.html @@ -19,6 +19,7 @@ +