181 lines
5.1 KiB
JavaScript
181 lines
5.1 KiB
JavaScript
"use strict";
|
|
|
|
var encode = require('./encode');
|
|
var calculateEC = require('./errorcode');
|
|
var matrix = require('./matrix');
|
|
|
|
function _deepCopy(obj) {
|
|
return JSON.parse(JSON.stringify(obj));
|
|
}
|
|
|
|
var EC_LEVELS = ['L', 'M', 'Q', 'H'];
|
|
|
|
// {{{1 Versions
|
|
var versions = [
|
|
[], // there is no version 0
|
|
// total number of codewords, (number of ec codewords, number of blocks) * ( L, M, Q, H )
|
|
[26, 7, 1, 10, 1, 13, 1, 17, 1],
|
|
[44, 10, 1, 16, 1, 22, 1, 28, 1],
|
|
[70, 15, 1, 26, 1, 36, 2, 44, 2],
|
|
[100, 20, 1, 36, 2, 52, 2, 64, 4],
|
|
[134, 26, 1, 48, 2, 72, 4, 88, 4], // 5
|
|
[172, 36, 2, 64, 4, 96, 4, 112, 4],
|
|
[196, 40, 2, 72, 4, 108, 6, 130, 5],
|
|
[242, 48, 2, 88, 4, 132, 6, 156, 6],
|
|
[292, 60, 2, 110, 5, 160, 8, 192, 8],
|
|
[346, 72, 4, 130, 5, 192, 8, 224, 8], // 10
|
|
[404, 80, 4, 150, 5, 224, 8, 264, 11],
|
|
[466, 96, 4, 176, 8, 260, 10, 308, 11],
|
|
[532, 104, 4, 198, 9, 288, 12, 352, 16],
|
|
[581, 120, 4, 216, 9, 320, 16, 384, 16],
|
|
[655, 132, 6, 240, 10, 360, 12, 432, 18], // 15
|
|
[733, 144, 6, 280, 10, 408, 17, 480, 16],
|
|
[815, 168, 6, 308, 11, 448, 16, 532, 19],
|
|
[901, 180, 6, 338, 13, 504, 18, 588, 21],
|
|
[991, 196, 7, 364, 14, 546, 21, 650, 25],
|
|
[1085, 224, 8, 416, 16, 600, 20, 700, 25], // 20
|
|
[1156, 224, 8, 442, 17, 644, 23, 750, 25],
|
|
[1258, 252, 9, 476, 17, 690, 23, 816, 34],
|
|
[1364, 270, 9, 504, 18, 750, 25, 900, 30],
|
|
[1474, 300, 10, 560, 20, 810, 27, 960, 32],
|
|
[1588, 312, 12, 588, 21, 870, 29, 1050, 35], // 25
|
|
[1706, 336, 12, 644, 23, 952, 34, 1110, 37],
|
|
[1828, 360, 12, 700, 25, 1020, 34, 1200, 40],
|
|
[1921, 390, 13, 728, 26, 1050, 35, 1260, 42],
|
|
[2051, 420, 14, 784, 28, 1140, 38, 1350, 45],
|
|
[2185, 450, 15, 812, 29, 1200, 40, 1440, 48], // 30
|
|
[2323, 480, 16, 868, 31, 1290, 43, 1530, 51],
|
|
[2465, 510, 17, 924, 33, 1350, 45, 1620, 54],
|
|
[2611, 540, 18, 980, 35, 1440, 48, 1710, 57],
|
|
[2761, 570, 19, 1036, 37, 1530, 51, 1800, 60],
|
|
[2876, 570, 19, 1064, 38, 1590, 53, 1890, 63], // 35
|
|
[3034, 600, 20, 1120, 40, 1680, 56, 1980, 66],
|
|
[3196, 630, 21, 1204, 43, 1770, 59, 2100, 70],
|
|
[3362, 660, 22, 1260, 45, 1860, 62, 2220, 74],
|
|
[3532, 720, 24, 1316, 47, 1950, 65, 2310, 77],
|
|
[3706, 750, 25, 1372, 49, 2040, 68, 2430, 81] // 40
|
|
];
|
|
|
|
versions = versions.map(function(v, index) {
|
|
if (!index) return {};
|
|
|
|
var res = {
|
|
}
|
|
for (var i = 1; i < 8; i += 2) {
|
|
var length = v[0] - v[i];
|
|
var num_template = v[i+1];
|
|
var ec_level = EC_LEVELS[(i/2)|0];
|
|
var level = {
|
|
version: index,
|
|
ec_level: ec_level,
|
|
data_len: length,
|
|
ec_len: v[i] / num_template,
|
|
blocks: [],
|
|
ec: []
|
|
}
|
|
|
|
for (var k = num_template, n = length; k > 0; k--) {
|
|
var block = (n / k)|0;
|
|
level.blocks.push(block);
|
|
n -= block;
|
|
|
|
}
|
|
res[ec_level] = level;
|
|
}
|
|
return res;
|
|
});
|
|
|
|
// {{{1 Get version template
|
|
function getTemplate(message, ec_level) {
|
|
var i = 1;
|
|
var len;
|
|
|
|
if (message.data1) {
|
|
len = Math.ceil(message.data1.length / 8);
|
|
} else {
|
|
i = 10;
|
|
}
|
|
for (/* i */; i < 10; i++) {
|
|
var version = versions[i][ec_level];
|
|
if (version.data_len >= len) {
|
|
return _deepCopy(version);
|
|
}
|
|
}
|
|
|
|
if (message.data10) {
|
|
len = Math.ceil(message.data10.length / 8);
|
|
} else {
|
|
i = 27;
|
|
}
|
|
for (/* i */; i < 27; i++) {
|
|
var version = versions[i][ec_level];
|
|
if (version.data_len >= len) {
|
|
return _deepCopy(version);
|
|
}
|
|
}
|
|
|
|
len = Math.ceil(message.data27.length / 8);
|
|
for (/* i */; i < 41; i++) {
|
|
var version = versions[i][ec_level];
|
|
if (version.data_len >= len) {
|
|
return _deepCopy(version);
|
|
}
|
|
}
|
|
throw new Error("Too much data");
|
|
}
|
|
|
|
// {{{1 Fill template
|
|
function fillTemplate(message, template) {
|
|
var blocks = new Buffer(template.data_len);
|
|
blocks.fill(0);
|
|
|
|
if (template.version < 10) {
|
|
message = message.data1;
|
|
} else if (template.version < 27) {
|
|
message = message.data10;
|
|
} else {
|
|
message = message.data27;
|
|
}
|
|
|
|
var len = message.length;
|
|
|
|
for (var i = 0; i < len; i += 8) {
|
|
var b = 0;
|
|
for (var j = 0; j < 8; j++) {
|
|
b = (b << 1) | (message[i + j] ? 1 : 0);
|
|
}
|
|
blocks[i / 8] = b;
|
|
}
|
|
|
|
var pad = 236;
|
|
for (var i = Math.ceil((len + 4) / 8); i < blocks.length; i++) {
|
|
blocks[i] = pad;
|
|
pad = (pad == 236) ? 17 : 236;
|
|
}
|
|
|
|
var offset = 0;
|
|
template.blocks = template.blocks.map(function(n) {
|
|
var b = blocks.slice(offset, offset + n);
|
|
offset += n;
|
|
template.ec.push(calculateEC(b, template.ec_len));
|
|
return b;
|
|
});
|
|
|
|
return template;
|
|
}
|
|
|
|
// {{{1 All-in-one
|
|
function QR(text, ec_level, parse_url) {
|
|
ec_level = EC_LEVELS.indexOf(ec_level) > -1 ? ec_level : 'M';
|
|
var message = encode(text, parse_url);
|
|
var data = fillTemplate(message, getTemplate(message, ec_level));
|
|
return matrix.getMatrix(data);
|
|
}
|
|
|
|
// {{{1 export functions
|
|
module.exports = {
|
|
QR: QR,
|
|
getTemplate: getTemplate,
|
|
fillTemplate: fillTemplate,
|
|
}
|