Contexte :
lors de l'achat d'un billet de cinéma,
le texte normal du code de collecte de billets généré génère un code à deux dimensions, et la valeur reconnue est également un texte normal, par exemple : code à barres, le contenu du code de collecte de billets de cinéma est tout ordinaire texte;
Différences de plate-forme :
1. jquery.qrcode,js (utilisé par H5)
est une bibliothèque JavaScript permettant de générer des codes QR, principalement en obtenant des balises DOM, puis en les dessinant via HTML5 Canvas, sans dépendre d'aucune bibliothèque.
Les petits programmes n'ont pas le concept de DOM, ils ne peuvent donc pas être utilisés universellement ;
2. weapp-qrcode-canvas-2d
https://developers.weixin.qq.com/community/develop/article/doc/000e88e73a415835ed9b46d7956013
Présentez principalement l'applet pour générer des plug-ins de code QR :
Introduction :
weapp-qrcode-canvas-2d est un package js qui utilise la nouvelle interface canvas-2d pour générer des codes QR (codes QR externes) dans les applets WeChat. L'interface canvas 2d prend en charge le rendu sur la même couche et offre de meilleures performances. Il est recommandé de passer à l'utilisation, ce qui peut grandement améliorer la vitesse ;
adresse de l'entrepôt :
Utilisation :
1. <canvas type="2d" style="width : 127px ; height : 127px;position : fixed;top : -1000px;" id="myQrcode"></canvas>Remarque : ne peut pas être à l'intérieur de v-
if , sinon le nœud ne sera pas trouvé
2. importez drawQrcode depuis '@/common/qrcodeJs/qrcode.js' ;
Remarque : Vous pouvez également installer npm install weapp-qrcode-canvas-2d --save
3. C'est dans le projet Pour une utilisation pratique, sans superposition d'images
/**
* 生成二维码(没有使用叠加图片)
* text - 码值
* */
handleMakeQrcode(text) {
return new Promise((resolve, reject) => {
const query = uni.createSelectorQuery()
query.select('#myQrcode').fields({
node: true,
size: true
}).exec((res) => {
// 获取node节点实例,目前仅微信,快手,京东小程序支持;
// #ifdef MP-WEIXIN || MP-KUAISHOU
let canvas = res[0].node
// #endif
// 调用方法drawQrcode生成二维码
drawQrcode({
// #ifdef MP-WEIXIN || MP-KUAISHOU
canvas: canvas,
// #endif
canvasId: 'myQrcode',
width: 127,
padding: 0,
background: '#ffffff',
foreground: '#000000',
text: text,
})
// 获取临时路径
uni.canvasToTempFilePath({
canvasId: 'myQrcode',
// #ifdef MP-WEIXIN || MP-KUAISHOU
canvas: canvas,
// #endif
x: 0,
y: 0,
width: 127,
height: 127,
destWidth: 127,
destHeight: 127,
success(res) {
resolve(res.tempFilePath); // 临时路径
},
fail(res) {
console.error(res);
reject();
}
})
});
})
}
/*
* 文档中示例 - 有叠加图片的(在二维码中加logo)
*/
const query = wx.createSelectorQuery()
query.select('#myQrcode')
.fields({
node: true,
size: true
})
.exec(async (res) => {
var canvas = res[0].node
var img = canvas.createImage();
img.src = "/image/logo.png"
img.onload = function () {
// img.onload完成后才能调用 drawQrcode方法
var options = {
canvas: canvas,
canvasId: 'myQrcode',
width: 260,
padding: 30,
paddingColor: '#fff',
background: '#fff',
foreground: '#000000',
text: 'https://gitee.com/WeiDoctor/weapp-qrcode-canvas-2d',
image: {
imageResource: img,
width: 80, // 建议不要设置过大,以免影响扫码
height: 80 // 建议不要设置过大,以免影响扫码
round: true // Logo图片是否为圆形
}
}
drawQrcode(options)
// 获取临时路径(得到之后,想干嘛就干嘛了)
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: 260,
height: 260,
destWidth: 600,
destHeight: 600,
canvasId: 'myQrcode',
canvas: canvas,
success(res) {
console.log('二维码临时路径为:', res.tempFilePath)
},
fail(res) {
console.error(res)
}
})
};
})
Remarques :
1. Étant donné que l'API de l'entrepôt ci-dessus est l'API du côté WeChat, je l'ai ensuite modifiée en une API multiplateforme uniapp, qui a été testée pour prendre en charge le côté WeChat et le côté H5 ; 2.
uni.createSelectorQuery () NodesRef est utilisé pour obtenir l'
instance de nœud Get Node de l'objet d'informations de nœud. Prend actuellement en charge l'acquisition de canevas et ne prend en charge que les applets WeChat, Kuaishou et JD ;
ainsi l'instance de canevas n'est pas transmise là où elle n'est pas prise en charge,
// Lorsque l'instance ne peut pas être obtenue, créez un canevas et renvoyez canvasContext
ctx = options ._this ? uni .createCanvasContext && uni.createCanvasContext(options.canvasId, options._this) : uni.createCanvasContext && uni.createCanvasContext(options.canvasId);
Le qrcode nécessaire pour générer le code QR ;
/**
* weapp.qrcode.js v1.1.2 https://developers.weixin.qq.com/community/develop/article/doc/000e88e73a415835ed9b46d7956013
*/
(function(global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.drawQrcode = factory());
}(this, (function() {
'use strict';
var hasOwn = Object.prototype.hasOwnProperty;
var toStr = Object.prototype.toString;
var defineProperty = Object.defineProperty;
var gOPD = Object.getOwnPropertyDescriptor;
var isArray = function isArray(arr) {
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
};
var isPlainObject = function isPlainObject(obj) {
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj
.constructor.prototype, 'isPrototypeOf');
// Not own constructor property must be Object
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for (key in obj) {
/**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
};
// If name is '__proto__', and Object.defineProperty is available, define __proto__ as an own property on target
var setProperty = function setProperty(target, options) {
if (defineProperty && options.name === '__proto__') {
defineProperty(target, options.name, {
enumerable: true,
configurable: true,
value: options.newValue,
writable: true
});
} else {
target[options.name] = options.newValue;
}
};
// Return undefined instead of __proto__ if '__proto__' is not an own property
var getProperty = function getProperty(obj, name) {
if (name === '__proto__') {
if (!hasOwn.call(obj, name)) {
return void 0;
} else if (gOPD) {
// In early versions of node, obj['__proto__'] is buggy when obj has
// __proto__ as an own property. Object.getOwnPropertyDescriptor() works.
return gOPD(obj, name).value;
}
}
return obj[name];
};
var extend = function extend() {
var options, name, src, copy, copyIsArray, clone;
var target = arguments[0];
var i = 1;
var length = arguments.length;
var deep = false;
// Handle a deep copy situation
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
// Only deal with non-null/undefined values
if (options != null) {
// Extend the base object
for (name in options) {
src = getProperty(target, name);
copy = getProperty(options, name);
// Prevent never-ending loop
if (target !== copy) {
// Recurse if we're merging plain objects or arrays
if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && isArray(src) ? src : [];
} else {
clone = src && isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
setProperty(target, {
name: name,
newValue: extend(deep, clone, copy)
});
// Don't bring in undefined values
} else if (typeof copy !== 'undefined') {
setProperty(target, {
name: name,
newValue: copy
});
}
}
}
}
}
// Return the modified object
return target;
};
//---------------------------------------------------------------------
// QRCode for JavaScript
//
// Copyright (c) 2009 Kazuhiko Arase
//
// URL: http://www.d-project.com/
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license.php
//
// The word "QR Code" is registered trademark of
// DENSO WAVE INCORPORATED
// http://www.denso-wave.com/qrcode/faqpatent-e.html
//
//---------------------------------------------------------------------
//---------------------------------------------------------------------
// QR8bitByte
//---------------------------------------------------------------------
function QR8bitByte(data) {
this.mode = QRMode.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);
}
}
};
//---------------------------------------------------------------------
// QRCode
//---------------------------------------------------------------------
function QRCode(typeNumber, errorCorrectLevel) {
this.typeNumber = typeNumber;
this.errorCorrectLevel = errorCorrectLevel;
this.modules = null;
this.moduleCount = 0;
this.dataCache = null;
this.dataList = new Array();
}
QRCode.prototype = {
addData: function(data) {
var newData = new QR8bitByte(data);
this.dataList.push(newData);
this.dataCache = null;
},
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];
},
getModuleCount: function() {
return this.moduleCount;
},
make: function() {
// Calculate automatically typeNumber if provided is < 1
if (this.typeNumber < 1) {
var typeNumber = 1;
for (typeNumber = 1; typeNumber < 40; typeNumber++) {
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
var buffer = new QRBitBuffer();
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(), QRUtil.getLengthInBits(data.mode, typeNumber));
data.write(buffer);
}
if (buffer.getLengthInBits() <= totalDataCount * 8) break;
}
this.typeNumber = typeNumber;
}
this.makeImpl(false, this.getBestMaskPattern());
},
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);
},
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;
}
}
}
},
getBestMaskPattern: function() {
var minLostPoint = 0;
var pattern = 0;
for (var i = 0; i < 8; i++) {
this.makeImpl(true, i);
var lostPoint = QRUtil.getLostPoint(this);
if (i == 0 || minLostPoint > lostPoint) {
minLostPoint = lostPoint;
pattern = i;
}
}
return pattern;
},
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;
},
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;
}
},
setupPositionAdjustPattern: function() {
var pos = QRUtil.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;
}
}
}
}
}
},
setupTypeNumber: function(test) {
var bits = QRUtil.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;
}
},
setupTypeInfo: function(test, maskPattern) {
var data = this.errorCorrectLevel << 3 | maskPattern;
var bits = QRUtil.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;
},
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 = QRUtil.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 = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
var buffer = new QRBitBuffer();
for (var i = 0; i < dataList.length; i++) {
var data = dataList[i];
buffer.put(data.mode, 4);
buffer.put(data.getLength(), QRUtil.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 = QRUtil.getErrorCorrectPolynomial(ecCount);
var rawPoly = new QRPolynomial(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;
};
//---------------------------------------------------------------------
// QRMode
//---------------------------------------------------------------------
var QRMode = {
MODE_NUMBER: 1 << 0,
MODE_ALPHA_NUM: 1 << 1,
MODE_8BIT_BYTE: 1 << 2,
MODE_KANJI: 1 << 3
};
//---------------------------------------------------------------------
// QRErrorCorrectLevel
//---------------------------------------------------------------------
var QRErrorCorrectLevel = {
L: 1,
M: 0,
Q: 3,
H: 2
};
//---------------------------------------------------------------------
// QRMaskPattern
//---------------------------------------------------------------------
var QRMaskPattern = {
PATTERN000: 0,
PATTERN001: 1,
PATTERN010: 2,
PATTERN011: 3,
PATTERN100: 4,
PATTERN101: 5,
PATTERN110: 6,
PATTERN111: 7
};
//---------------------------------------------------------------------
// QRUtil
//---------------------------------------------------------------------
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 QRPolynomial([1], 0);
for (var i = 0; i < errorCorrectLength; i++) {
a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
}
return a;
},
getLengthInBits: function(mode, type) {
if (1 <= type && type < 10) {
// 1 - 9
switch (mode) {
case QRMode.MODE_NUMBER:
return 10;
case QRMode.MODE_ALPHA_NUM:
return 9;
case QRMode.MODE_8BIT_BYTE:
return 8;
case QRMode.MODE_KANJI:
return 8;
default:
throw new Error("mode:" + mode);
}
} else if (type < 27) {
// 10 - 26
switch (mode) {
case QRMode.MODE_NUMBER:
return 12;
case QRMode.MODE_ALPHA_NUM:
return 11;
case QRMode.MODE_8BIT_BYTE:
return 16;
case QRMode.MODE_KANJI:
return 10;
default:
throw new Error("mode:" + mode);
}
} else if (type < 41) {
// 27 - 40
switch (mode) {
case QRMode.MODE_NUMBER:
return 14;
case QRMode.MODE_ALPHA_NUM:
return 13;
case QRMode.MODE_8BIT_BYTE:
return 16;
case QRMode.MODE_KANJI:
return 12;
default:
throw new Error("mode:" + mode);
}
} 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;
}
};
//---------------------------------------------------------------------
// QRMath
//---------------------------------------------------------------------
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;
}
//---------------------------------------------------------------------
// QRPolynomial
//---------------------------------------------------------------------
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] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
}
}
return new QRPolynomial(num, 0);
},
mod: function(e) {
if (this.getLength() - e.getLength() < 0) {
return this;
}
var ratio = QRMath.glog(this.get(0)) - QRMath.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] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
}
// recursive call
return new QRPolynomial(num, 0).mod(e);
}
};
//---------------------------------------------------------------------
// QRRSBlock
//---------------------------------------------------------------------
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 QRErrorCorrectLevel.L:
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
case QRErrorCorrectLevel.M:
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
case QRErrorCorrectLevel.Q:
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
case QRErrorCorrectLevel.H:
return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
default:
return undefined;
}
};
//---------------------------------------------------------------------
// QRBitBuffer
//---------------------------------------------------------------------
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++;
}
};
// support Chinese
function utf16to8(str) {
var out, i, len, c;
out = '';
len = str.length;
for (i = 0; i < len; i++) {
c = str.charCodeAt(i);
if (c >= 0x0001 && c <= 0x007F) {
out += str.charAt(i);
} else if (c > 0x07FF) {
out += String.fromCharCode(0xE0 | c >> 12 & 0x0F);
out += String.fromCharCode(0x80 | c >> 6 & 0x3F);
out += String.fromCharCode(0x80 | c >> 0 & 0x3F);
} else {
out += String.fromCharCode(0xC0 | c >> 6 & 0x1F);
out += String.fromCharCode(0x80 | c >> 0 & 0x3F);
}
}
return out;
}
function drawQrcode(options, debug) {
options = options || {};
options = extend(true, {
canvasId: 'myQrcode',
// canvas: canvas,
text: '爱一个人就要勇敢说出来',
x: 0,
y: 0,
width: 260,
height: 260,
padding: 20,
// paddingColor: '#ffffff', // 默认与background一致
typeNumber: -1,
correctLevel: QRErrorCorrectLevel.H,
background: '#ffffff',
foreground: '#000000',
image: {
imageResource: '',
width: 80,
height: 80,
round: true
}
}, options);
if (!options.canvasId && !options.canvas) {
console.warn('please set canvasId or canvas!');
return;
}
if (!options.paddingColor) options.paddingColor = options.background;
if (debug) {
var qrcode = new QRCode(options.typeNumber, options.correctLevel);
qrcode.addData(utf16to8(options.text));
qrcode.make();
return new Promise(function(resolve, reject) {
resolve(qrcode);
});
} else {
return new Promise(function(resolve, reject) {
return resolve(createCanvas());
});
}
function createCanvas() {
// create the qrcode itself
var qrcode = new QRCode(options.typeNumber, options.correctLevel);
qrcode.addData(utf16to8(options.text));
qrcode.make();
const dpr = uni.getSystemInfoSync().pixelRatio;
// 获取canvas实例 兼容拿不到canvas实例的情况;
var ctx;
var width;
var canvas = options.canvas;
if (canvas) {
ctx = canvas.getContext('2d');
canvas.width = options.width * dpr;
canvas.height = options.width * dpr;
width = options.width * dpr;
// 背景色
ctx.fillStyle = options.paddingColor;
ctx.fillRect(0, 0, width + options.padding * 2, width + options.padding * 2);
var tileW = (width - options.padding * 2) / qrcode.getModuleCount();
var tileH = (width - options.padding * 2) / qrcode.getModuleCount();
// 开始画二维码
for (var row = 0; row < qrcode.getModuleCount(); row++) {
for (var col = 0; col < qrcode.getModuleCount(); col++) {
ctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background;
var w = Math.ceil((col + 1) * tileW) - Math.floor(col * tileW);
var h = Math.ceil((row + 1) * tileW) - Math.floor(row * tileW);
ctx.fillRect(Math.round(col * tileW) + options.padding, Math.round(row * tileH) +
options.padding, w, h);
}
}
if (options.image.imageResource) {
const imgW = options.image.width * dpr;
const imgH = options.image.height * dpr;
const dx = (width - imgW) / 2;
const dy = (width - imgH) / 2;
if (options.image.round) {
// Logo边框
const imgW2 = options.image.width * dpr + 30;
const dx2 = (width - imgW2) / 2;
const r2 = imgW2 / 2;
const cx2 = dx2 + r2;
ctx.beginPath();
ctx.arc(cx2, cx2, r2, 0, 2 * Math.PI);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.restore();
// 画Logo
const r = imgW / 2;
const cx = dx + r;
const cy = dy + r;
ctx.beginPath();
ctx.arc(cx, cy, r, 0, 2 * Math.PI);
ctx.clip();
ctx.drawImage(options.image.imageResource, dx, dy, imgW, imgW);
ctx.restore();
} else {
ctx.drawImage(options.image.imageResource, dx, dy, imgW, imgH);
ctx.restore();
}
}
return ctx;
} else {
// 拿不到实例时,创建canvas,返回canvasContext
ctx = options._this ? uni.createCanvasContext && uni.createCanvasContext(options.canvasId,
options._this) : uni.createCanvasContext && uni.createCanvasContext(options
.canvasId);
width = options.width;
var tileW = (width - options.padding * 2) / qrcode.getModuleCount();
var tileH = (width - options.padding * 2) / qrcode.getModuleCount();
// draw in the canvas
for (var row = 0; row < qrcode.getModuleCount(); row++) {
for (var col = 0; col < qrcode.getModuleCount(); col++) {
ctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background;
var w = Math.ceil((col + 1) * tileW) - Math.floor(col * tileW);
var h = Math.ceil((row + 1) * tileW) - Math.floor(row * tileW);
ctx.fillRect(Math.round(col * tileW) + options.padding, Math.round(row * tileH) +
options.padding, w, h);
}
}
if (options.image.imageResource) {
ctx.drawImage(options.image.imageResource, options.image.dx, options.image.dy, options
.image.dWidth, options.image.dHeight);
}
ctx.draw(false, function(e) {
options.callback && options.callback(e);
});
}
}
}
return drawQrcode;
})));