sard-uniapp 1.2.2 → 1.4.0-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +13 -0
- package/components/alert/alert.d.ts +35 -0
- package/components/alert/alert.vue +74 -0
- package/components/alert/common.d.ts +26 -0
- package/components/alert/common.js +8 -0
- package/components/alert/index.d.ts +1 -0
- package/components/alert/index.js +1 -0
- package/components/alert/index.scss +59 -0
- package/components/alert/variables.scss +14 -0
- package/components/button/button.d.ts +1 -1
- package/components/calendar-input/calendar-input.vue +8 -7
- package/components/cascader-input/cascader-input.vue +8 -7
- package/components/checkbox/common.d.ts +13 -0
- package/components/checkbox/common.js +4 -0
- package/components/checkbox-group/checkbox-group.vue +27 -7
- package/components/checkbox-input/checkbox-input.d.ts +35 -0
- package/components/checkbox-input/checkbox-input.vue +185 -0
- package/components/checkbox-input/common.d.ts +15 -0
- package/components/checkbox-input/common.js +5 -0
- package/components/checkbox-input/index.d.ts +1 -0
- package/components/checkbox-input/index.js +1 -0
- package/components/checkbox-input/index.scss +7 -0
- package/components/checkbox-input/variables.scss +5 -0
- package/components/config/index.d.ts +40 -0
- package/components/config/index.js +20 -0
- package/components/datetime-picker-input/datetime-picker-input.vue +2 -1
- package/components/form/variables.scss +2 -2
- package/components/input/common.d.ts +1 -0
- package/components/input/index.scss +21 -0
- package/components/input/input.vue +22 -4
- package/components/input/variables.scss +1 -0
- package/components/list/index.scss +6 -0
- package/components/list/list.vue +1 -0
- package/components/list-item/index.scss +1 -0
- package/components/notify/notify.d.ts +1 -1
- package/components/notify-agent/notify-agent.d.ts +1 -1
- package/components/picker-input/picker-input.vue +2 -1
- package/components/popout-input/common.d.ts +1 -0
- package/components/popout-input/popout-input.vue +6 -2
- package/components/qrcode/common.d.ts +23 -0
- package/components/qrcode/common.js +2 -0
- package/components/qrcode/index.d.ts +1 -0
- package/components/qrcode/index.js +1 -0
- package/components/qrcode/index.scss +17 -0
- package/components/qrcode/qrcode.d.ts +47 -0
- package/components/qrcode/qrcode.vue +107 -0
- package/components/qrcode/variables.scss +4 -0
- package/components/radio/common.d.ts +13 -0
- package/components/radio/common.js +4 -0
- package/components/radio-group/radio-group.vue +27 -7
- package/components/radio-input/common.d.ts +16 -0
- package/components/radio-input/common.js +5 -0
- package/components/radio-input/index.d.ts +1 -0
- package/components/radio-input/index.js +1 -0
- package/components/radio-input/index.scss +7 -0
- package/components/radio-input/radio-input.d.ts +38 -0
- package/components/radio-input/radio-input.vue +181 -0
- package/components/radio-input/variables.scss +5 -0
- package/components/result/result.d.ts +1 -1
- package/components/result/result.vue +1 -1
- package/components/tag/tag.d.ts +1 -1
- package/global.d.ts +9 -1
- package/index.d.ts +4 -0
- package/index.js +4 -0
- package/index.scss +4 -0
- package/package.json +2 -1
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/is.d.ts +6 -0
- package/utils/is.js +8 -0
- package/utils/qrcode.d.ts +8 -0
- package/utils/qrcode.js +616 -0
package/utils/qrcode.js
ADDED
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|-------------------------------------------------------------------------------
|
|
3
|
+
| Error Correction Coding
|
|
4
|
+
|-------------------------------------------------------------------------------
|
|
5
|
+
| https://dev.to/maxart2501/let-s-develop-a-qr-code-generator-part-iii-error-correction-1kbm
|
|
6
|
+
|
|
|
7
|
+
*/
|
|
8
|
+
const LOG = new Uint8Array(256);
|
|
9
|
+
const EXP = new Uint8Array(256);
|
|
10
|
+
(() => {
|
|
11
|
+
for (let exponent = 1, value = 1; exponent < 256; exponent++) {
|
|
12
|
+
value = value > 127 ? (value << 1) ^ 285 : value << 1;
|
|
13
|
+
LOG[value] = exponent % 255;
|
|
14
|
+
EXP[exponent % 255] = value;
|
|
15
|
+
}
|
|
16
|
+
})();
|
|
17
|
+
function mul(a, b) {
|
|
18
|
+
return a && b ? EXP[(LOG[a] + LOG[b]) % 255] : 0;
|
|
19
|
+
}
|
|
20
|
+
function div(a, b) {
|
|
21
|
+
return EXP[(LOG[a] + LOG[b] * 254) % 255];
|
|
22
|
+
}
|
|
23
|
+
function polyMul(poly1, poly2) {
|
|
24
|
+
const coeffs = new Uint8Array(poly1.length + poly2.length - 1);
|
|
25
|
+
for (let index = 0; index < coeffs.length; index++) {
|
|
26
|
+
let coeff = 0;
|
|
27
|
+
for (let p1index = 0; p1index <= index; p1index++) {
|
|
28
|
+
const p2index = index - p1index;
|
|
29
|
+
coeff ^= mul(poly1[p1index], poly2[p2index]);
|
|
30
|
+
}
|
|
31
|
+
coeffs[index] = coeff;
|
|
32
|
+
}
|
|
33
|
+
return coeffs;
|
|
34
|
+
}
|
|
35
|
+
function polyRest(dividend, divisor) {
|
|
36
|
+
const quotientLength = dividend.length - divisor.length + 1;
|
|
37
|
+
let rest = new Uint8Array(dividend);
|
|
38
|
+
for (let count = 0; count < quotientLength; count++) {
|
|
39
|
+
if (rest[0]) {
|
|
40
|
+
const factor = div(rest[0], divisor[0]);
|
|
41
|
+
const subtr = new Uint8Array(rest.length);
|
|
42
|
+
subtr.set(polyMul(divisor, new Uint8Array([factor])), 0);
|
|
43
|
+
rest = rest.map((value, index) => value ^ subtr[index]).slice(1);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
rest = rest.slice(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return rest;
|
|
50
|
+
}
|
|
51
|
+
const cacheGeneratorPoly = {};
|
|
52
|
+
function getGeneratorPoly(degree) {
|
|
53
|
+
if (cacheGeneratorPoly[degree]) {
|
|
54
|
+
return cacheGeneratorPoly[degree];
|
|
55
|
+
}
|
|
56
|
+
let lastPoly = new Uint8Array([1]);
|
|
57
|
+
for (let index = 0; index < degree; index++) {
|
|
58
|
+
lastPoly = polyMul(lastPoly, new Uint8Array([1, EXP[index]]));
|
|
59
|
+
}
|
|
60
|
+
return (cacheGeneratorPoly[degree] = lastPoly);
|
|
61
|
+
}
|
|
62
|
+
function getECC(data, degree) {
|
|
63
|
+
const messagePoly = new Uint8Array(data.length + degree);
|
|
64
|
+
messagePoly.set(data, 0);
|
|
65
|
+
return polyRest(messagePoly, getGeneratorPoly(degree));
|
|
66
|
+
}
|
|
67
|
+
/*
|
|
68
|
+
|-------------------------------------------------------------------------------
|
|
69
|
+
| QR Code Generator
|
|
70
|
+
|-------------------------------------------------------------------------------
|
|
71
|
+
| https://www.thonky.com/qr-code-tutorial/
|
|
72
|
+
|
|
|
73
|
+
*/
|
|
74
|
+
const ECCodewordsPerBlock = [
|
|
75
|
+
[
|
|
76
|
+
7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28,
|
|
77
|
+
28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
|
78
|
+
30, 30,
|
|
79
|
+
],
|
|
80
|
+
[
|
|
81
|
+
10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26,
|
|
82
|
+
26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
|
83
|
+
28, 28,
|
|
84
|
+
],
|
|
85
|
+
[
|
|
86
|
+
13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26,
|
|
87
|
+
30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
|
88
|
+
30, 30,
|
|
89
|
+
],
|
|
90
|
+
[
|
|
91
|
+
17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26,
|
|
92
|
+
28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
|
93
|
+
30, 30,
|
|
94
|
+
],
|
|
95
|
+
];
|
|
96
|
+
const ECBlocks = [
|
|
97
|
+
[
|
|
98
|
+
1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12,
|
|
99
|
+
12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25,
|
|
100
|
+
],
|
|
101
|
+
[
|
|
102
|
+
1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17,
|
|
103
|
+
18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49,
|
|
104
|
+
],
|
|
105
|
+
[
|
|
106
|
+
1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23,
|
|
107
|
+
25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68,
|
|
108
|
+
],
|
|
109
|
+
[
|
|
110
|
+
1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25,
|
|
111
|
+
34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81,
|
|
112
|
+
],
|
|
113
|
+
];
|
|
114
|
+
function appendBits(num, length, bits) {
|
|
115
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
116
|
+
bits.push((num >>> i) & 1);
|
|
117
|
+
}
|
|
118
|
+
return bits;
|
|
119
|
+
}
|
|
120
|
+
var Mode;
|
|
121
|
+
(function (Mode) {
|
|
122
|
+
Mode[Mode["Numeric"] = 0] = "Numeric";
|
|
123
|
+
Mode[Mode["Alphanumeric"] = 1] = "Alphanumeric";
|
|
124
|
+
Mode[Mode["Byte"] = 2] = "Byte";
|
|
125
|
+
})(Mode || (Mode = {}));
|
|
126
|
+
function getMode(text) {
|
|
127
|
+
if (/^[0-9]*$/.test(text)) {
|
|
128
|
+
return Mode.Numeric;
|
|
129
|
+
}
|
|
130
|
+
if (/^[0-9A-Z $%*+-./:]*$/.test(text)) {
|
|
131
|
+
return Mode.Alphanumeric;
|
|
132
|
+
}
|
|
133
|
+
return Mode.Byte;
|
|
134
|
+
}
|
|
135
|
+
function getModeIndicator(mode) {
|
|
136
|
+
switch (mode) {
|
|
137
|
+
case Mode.Numeric:
|
|
138
|
+
return 0b0001;
|
|
139
|
+
case Mode.Alphanumeric:
|
|
140
|
+
return 0b0010;
|
|
141
|
+
default:
|
|
142
|
+
return 0b0100;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function encodeNumeric(text) {
|
|
146
|
+
const bits = [];
|
|
147
|
+
(text.match(/.{1,3}/g) || []).forEach((item) => {
|
|
148
|
+
appendBits(+item, (item.length - 1) * 3 + 4, bits);
|
|
149
|
+
});
|
|
150
|
+
return bits;
|
|
151
|
+
}
|
|
152
|
+
export const ALPHANUMERIC_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';
|
|
153
|
+
function encodeAlphaNumeric(text) {
|
|
154
|
+
const bits = [];
|
|
155
|
+
(text.match(/.{1,2}/g) || []).forEach((item) => {
|
|
156
|
+
const i1 = ALPHANUMERIC_CHARS.indexOf(item[0]);
|
|
157
|
+
const i2 = ALPHANUMERIC_CHARS.indexOf(item[1]);
|
|
158
|
+
if (i2 === -1) {
|
|
159
|
+
appendBits(i1, 6, bits);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
appendBits(i1 * 45 + i2, 11, bits);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
return bits;
|
|
166
|
+
}
|
|
167
|
+
function toUtf8ByteArray(text) {
|
|
168
|
+
text = encodeURI(text);
|
|
169
|
+
const bytes = [];
|
|
170
|
+
for (let i = 0; i < text.length; i++) {
|
|
171
|
+
if (text.charAt(i) !== '%') {
|
|
172
|
+
bytes.push(text.charCodeAt(i));
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
bytes.push(parseInt(text.slice(i + 1, i + 3), 16));
|
|
176
|
+
i += 2;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return bytes;
|
|
180
|
+
}
|
|
181
|
+
function encodeByte(text) {
|
|
182
|
+
const bits = [];
|
|
183
|
+
toUtf8ByteArray(text).forEach((item) => {
|
|
184
|
+
appendBits(item, 8, bits);
|
|
185
|
+
});
|
|
186
|
+
return bits;
|
|
187
|
+
}
|
|
188
|
+
function encodeData(mode, text) {
|
|
189
|
+
switch (mode) {
|
|
190
|
+
case Mode.Numeric:
|
|
191
|
+
return encodeNumeric(text);
|
|
192
|
+
case Mode.Alphanumeric:
|
|
193
|
+
return encodeAlphaNumeric(text);
|
|
194
|
+
default:
|
|
195
|
+
return encodeByte(text);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function getFunctionModules(version) {
|
|
199
|
+
let count = 225 + 8 * version;
|
|
200
|
+
if (version > 6) {
|
|
201
|
+
count += 36;
|
|
202
|
+
}
|
|
203
|
+
if (version > 1) {
|
|
204
|
+
const alignCount = ~~(version / 7) + 2;
|
|
205
|
+
count += (25 * alignCount - 10) * alignCount - 55;
|
|
206
|
+
}
|
|
207
|
+
return count;
|
|
208
|
+
}
|
|
209
|
+
function getSize(version) {
|
|
210
|
+
return version * 4 + 17;
|
|
211
|
+
}
|
|
212
|
+
function getTotalDataModules(version) {
|
|
213
|
+
return Math.pow(getSize(version), 2) - getFunctionModules(version);
|
|
214
|
+
}
|
|
215
|
+
function getECCodewords(eclIndex, version) {
|
|
216
|
+
const codewords = ECCodewordsPerBlock[eclIndex][version - 1];
|
|
217
|
+
const blocks = ECBlocks[eclIndex][version - 1];
|
|
218
|
+
return codewords * blocks;
|
|
219
|
+
}
|
|
220
|
+
function getRawDataCodewords(eclIndex, version) {
|
|
221
|
+
return getTotalDataModules(version) / 8 - getECCodewords(eclIndex, version);
|
|
222
|
+
}
|
|
223
|
+
const charCountIndicatorTable = {
|
|
224
|
+
[Mode.Numeric]: [10, 12, 14],
|
|
225
|
+
[Mode.Alphanumeric]: [9, 11, 13],
|
|
226
|
+
[Mode.Byte]: [8, 16, 16],
|
|
227
|
+
};
|
|
228
|
+
function getCharCountIndicator(mode, version) {
|
|
229
|
+
return charCountIndicatorTable[mode][~~((version + 7) / 17)];
|
|
230
|
+
}
|
|
231
|
+
function getVersion(mode, eclIndex, codewords) {
|
|
232
|
+
for (let version = 1; version <= 40; version++) {
|
|
233
|
+
const rawDataCodewords = getRawDataCodewords(eclIndex, version);
|
|
234
|
+
if (rawDataCodewords >=
|
|
235
|
+
codewords + (4 + getCharCountIndicator(mode, version)) / 8) {
|
|
236
|
+
return version;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return 40;
|
|
240
|
+
}
|
|
241
|
+
function addFinderPatterns(map, size) {
|
|
242
|
+
for (let i = 0; i < 3; i++) {
|
|
243
|
+
const originX = i === 1 ? size - 7 : 0;
|
|
244
|
+
const originY = i === 2 ? size - 7 : 0;
|
|
245
|
+
for (let y = 0; y < 7; y++) {
|
|
246
|
+
for (let x = 0; x < 7; x++) {
|
|
247
|
+
const bit = x === 0 ||
|
|
248
|
+
x === 6 ||
|
|
249
|
+
y === 0 ||
|
|
250
|
+
y === 6 ||
|
|
251
|
+
(x > 1 && x < 5 && y > 1 && y < 5)
|
|
252
|
+
? 1
|
|
253
|
+
: 0;
|
|
254
|
+
map[originY + y][originX + x] = bit;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function addSeparatorPatterns(map, size) {
|
|
260
|
+
for (let i = 0; i < 8; i++) {
|
|
261
|
+
map[i][7] = 0;
|
|
262
|
+
map[i][size - 8] = 0;
|
|
263
|
+
map[size - 8 + i][7] = 0;
|
|
264
|
+
map[7][i] = 0;
|
|
265
|
+
map[7][size - 8 + i] = 0;
|
|
266
|
+
map[size - 8][i] = 0;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function getAlignmentPatternLocations(version) {
|
|
270
|
+
if (version == 1) {
|
|
271
|
+
return [];
|
|
272
|
+
}
|
|
273
|
+
const alignCount = ~~(version / 7) + 2;
|
|
274
|
+
const step = version === 32
|
|
275
|
+
? 26
|
|
276
|
+
: Math.ceil((version * 4 + 4) / (alignCount * 2 - 2)) * 2;
|
|
277
|
+
const locations = [6];
|
|
278
|
+
for (let location = getSize(version) - 7; locations.length < alignCount; location -= step) {
|
|
279
|
+
locations.splice(1, 0, location);
|
|
280
|
+
}
|
|
281
|
+
return locations;
|
|
282
|
+
}
|
|
283
|
+
function addAlignmentPatterns(map, version) {
|
|
284
|
+
const locations = getAlignmentPatternLocations(version);
|
|
285
|
+
for (const locY of locations) {
|
|
286
|
+
for (const locX of locations) {
|
|
287
|
+
if (map[locY][locX] !== null) {
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
for (let y = 0; y < 5; y++) {
|
|
291
|
+
for (let x = 0; x < 5; x++) {
|
|
292
|
+
map[locY - 2 + y][locX - 2 + x] =
|
|
293
|
+
x === 0 || x === 4 || y === 0 || y === 4 || (x === 2 && y === 2)
|
|
294
|
+
? 1
|
|
295
|
+
: 0;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function addTimingPatterns(map, size) {
|
|
302
|
+
const length = size - 16;
|
|
303
|
+
for (let i = 0; i < length; i++) {
|
|
304
|
+
const n = i % 2 === 0 ? 1 : 0;
|
|
305
|
+
map[6][8 + i] = n;
|
|
306
|
+
map[8 + i][6] = n;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function addDarkPattern(map, size) {
|
|
310
|
+
map[size - 8][8] = 1;
|
|
311
|
+
}
|
|
312
|
+
function addFormatInformationPatterns(map, size, fillBit) {
|
|
313
|
+
for (let i = 0; i < 15; i++) {
|
|
314
|
+
const bit = fillBit(15 - 1 - i);
|
|
315
|
+
// 横条
|
|
316
|
+
map[8][i < 6 ? i : i < 7 ? i + 1 : size - 15 + i] = bit;
|
|
317
|
+
// 竖条
|
|
318
|
+
map[size - 1 - (i < 7 ? i : i < 9 ? size - 16 + i : size - 15 + i)][8] = bit;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function addVersionInformationPatterns(map, size, fillBit) {
|
|
322
|
+
for (let i = 0; i < 18; i++) {
|
|
323
|
+
// 左下
|
|
324
|
+
map[size - 11 + (i % 3)][~~(i / 3)] = fillBit(i);
|
|
325
|
+
// 右上
|
|
326
|
+
map[~~(i / 3)][size - 11 + ~~(i % 3)] = fillBit(i);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function placeDataBits(map, size, dataBits) {
|
|
330
|
+
const length = size * size;
|
|
331
|
+
let b = 0;
|
|
332
|
+
for (let i = 0; i < length; i++) {
|
|
333
|
+
const rest = ~~(i / 2) % size;
|
|
334
|
+
const quo = ~~(i / (size * 2));
|
|
335
|
+
const y = quo % 2 === 0 ? size - 1 - rest : rest;
|
|
336
|
+
let x = size - 2 - (quo * 2 - (i % 2 === 0 ? 1 : 0));
|
|
337
|
+
if (x < 7) {
|
|
338
|
+
x--;
|
|
339
|
+
}
|
|
340
|
+
if (map[y][x] === null) {
|
|
341
|
+
map[y][x] = dataBits[b++] + 2;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const maskModes = [
|
|
346
|
+
(row, col) => (row + col) % 2 === 0,
|
|
347
|
+
(row) => row % 2 === 0,
|
|
348
|
+
(_, col) => col % 3 === 0,
|
|
349
|
+
(row, col) => (row + col) % 3 === 0,
|
|
350
|
+
(row, col) => (~~(row / 2) + ~~(col / 3)) % 2 === 0,
|
|
351
|
+
(row, col) => ((row * col) % 2) + ((row * col) % 3) === 0,
|
|
352
|
+
(row, col) => (((row * col) % 2) + ((row * col) % 3)) % 2 === 0,
|
|
353
|
+
(row, col) => (((row + col) % 2) + ((row * col) % 3)) % 2 === 0,
|
|
354
|
+
];
|
|
355
|
+
function getLeastFiveSameColoredPenalty(getEach, size) {
|
|
356
|
+
let score = 0;
|
|
357
|
+
for (let i = 0; i < size; i++) {
|
|
358
|
+
let sum = 0;
|
|
359
|
+
let last = -1;
|
|
360
|
+
for (let j = 0; j < size; j++) {
|
|
361
|
+
const bit = getEach(i, j);
|
|
362
|
+
if (sum === 0 || last === bit) {
|
|
363
|
+
sum++;
|
|
364
|
+
last = bit;
|
|
365
|
+
}
|
|
366
|
+
if (last !== bit || j === size - 1) {
|
|
367
|
+
if (sum >= 5) {
|
|
368
|
+
score += sum - 2;
|
|
369
|
+
}
|
|
370
|
+
sum = 1;
|
|
371
|
+
last = bit;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return score;
|
|
376
|
+
}
|
|
377
|
+
function getTwoByTwoSameColoredPenalty(map, size) {
|
|
378
|
+
let score = 0;
|
|
379
|
+
for (let y = 0; y < size - 2; y++) {
|
|
380
|
+
for (let x = 0; x < size - 2; x++) {
|
|
381
|
+
if ((map[y][x] + map[y][x + 1] + map[y + 1][x] + map[y + 1][x + 1]) % 4 ===
|
|
382
|
+
0) {
|
|
383
|
+
score += 3;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return score;
|
|
388
|
+
}
|
|
389
|
+
function getFinderLikePenalty(map, size) {
|
|
390
|
+
let score = 0;
|
|
391
|
+
for (let i = 0; i < size - 11; i++) {
|
|
392
|
+
for (let j = 0; j < size - 11; j++) {
|
|
393
|
+
let rowBits = 0;
|
|
394
|
+
let colBits = 0;
|
|
395
|
+
for (let k = 0; k < 11; k++) {
|
|
396
|
+
rowBits = (rowBits << 1) + map[i][j + k];
|
|
397
|
+
colBits = (colBits << 1) + map[j + k][i];
|
|
398
|
+
}
|
|
399
|
+
if (rowBits === 0b10111010000 || rowBits === 0b00001011101) {
|
|
400
|
+
score += 40;
|
|
401
|
+
}
|
|
402
|
+
if (colBits === 0b10111010000 || colBits === 0b00001011101) {
|
|
403
|
+
score += 40;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return score;
|
|
408
|
+
}
|
|
409
|
+
function getBalancePenalty(map) {
|
|
410
|
+
const darkModules = map.reduce((sum, row) => sum + row.reduce((sum, bit) => sum + bit, 0), 0);
|
|
411
|
+
const percent = (darkModules / (map.length * map.length)) * 100;
|
|
412
|
+
const score = Math.min(Math.abs(Math.floor(percent / 5) * 5 - 50) / 5, Math.abs(Math.ceil(percent / 5) * 5 - 50) / 5) * 10;
|
|
413
|
+
return score;
|
|
414
|
+
}
|
|
415
|
+
const errorCorrectionBit = [0b01, 0b00, 0b11, 0b10];
|
|
416
|
+
function getFormatInformationBits(eclIndex, maskNum) {
|
|
417
|
+
const ecMaskBits = (errorCorrectionBit[eclIndex] << 3) | maskNum;
|
|
418
|
+
let rest = ecMaskBits;
|
|
419
|
+
for (let i = 0; i < 10; i++) {
|
|
420
|
+
rest = (rest << 1) ^ ((rest >>> 9) * 0b10100110111);
|
|
421
|
+
}
|
|
422
|
+
return ((ecMaskBits << 10) | rest) ^ 0b101010000010010;
|
|
423
|
+
}
|
|
424
|
+
function getVersionInformationBits(version) {
|
|
425
|
+
let rest = version;
|
|
426
|
+
for (let i = 0; i < 12; i++) {
|
|
427
|
+
rest = (rest << 1) ^ ((rest >>> 11) * 0b1111100100101);
|
|
428
|
+
}
|
|
429
|
+
return (version << 12) | rest;
|
|
430
|
+
}
|
|
431
|
+
export const ECLList = ['L', 'M', 'Q', 'H'];
|
|
432
|
+
export function qrcode(text, options = {}) {
|
|
433
|
+
const { ecl = 'M' } = options;
|
|
434
|
+
let eclIndex = ECLList.indexOf(ecl);
|
|
435
|
+
if (eclIndex < 0) {
|
|
436
|
+
eclIndex = 1;
|
|
437
|
+
}
|
|
438
|
+
const mode = getMode(text);
|
|
439
|
+
const modeIndicator = getModeIndicator(mode);
|
|
440
|
+
let version = 0;
|
|
441
|
+
let size = 0;
|
|
442
|
+
let dataBits = [];
|
|
443
|
+
const groups = [];
|
|
444
|
+
let map = [];
|
|
445
|
+
let maskNum = 0;
|
|
446
|
+
let maskMap = [];
|
|
447
|
+
// 数据编码
|
|
448
|
+
{
|
|
449
|
+
// 使用选定模式进行编码
|
|
450
|
+
dataBits = encodeData(mode, text);
|
|
451
|
+
const codewords = dataBits.length / 8;
|
|
452
|
+
const charLength = mode === Mode.Byte ? codewords : text.length;
|
|
453
|
+
// 确定数据的最小版本
|
|
454
|
+
version = getVersion(mode, eclIndex, codewords);
|
|
455
|
+
size = getSize(version);
|
|
456
|
+
// 添加模式指示器、字符计数指示器
|
|
457
|
+
dataBits = [
|
|
458
|
+
...appendBits(modeIndicator, 4, []),
|
|
459
|
+
...appendBits(charLength, getCharCountIndicator(mode, version), []),
|
|
460
|
+
...dataBits,
|
|
461
|
+
];
|
|
462
|
+
// 确定此QR码所需的数据位数
|
|
463
|
+
const rawDataBits = getRawDataCodewords(eclIndex, version) * 8;
|
|
464
|
+
// 如有必要,添加0结束符
|
|
465
|
+
appendBits(0, Math.min(rawDataBits - dataBits.length, 4), dataBits);
|
|
466
|
+
// 添加更多的0使长度成为8的倍数
|
|
467
|
+
appendBits(0, (8 - (dataBits.length % 8)) % 8, dataBits);
|
|
468
|
+
// 如果字符串仍然太短,添加填充字节
|
|
469
|
+
for (let padByte = 0b11101100; dataBits.length < rawDataBits; padByte ^= 0b11101100 ^ 0b00010001) {
|
|
470
|
+
appendBits(padByte, 8, dataBits);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
// 纠错编码
|
|
474
|
+
{
|
|
475
|
+
const codewords = [];
|
|
476
|
+
dataBits.forEach((bit, i) => {
|
|
477
|
+
codewords[i >> 3] |= bit << (7 - (i & 7));
|
|
478
|
+
});
|
|
479
|
+
const blocks = ECBlocks[eclIndex][version - 1];
|
|
480
|
+
const g2Blocks = ~~(getTotalDataModules(version) / 8) % blocks;
|
|
481
|
+
const g1Blocks = blocks - g2Blocks;
|
|
482
|
+
const totalDC = getRawDataCodewords(eclIndex, version);
|
|
483
|
+
const g1DCPerBlock = ~~(totalDC / blocks);
|
|
484
|
+
const g2DCPerBlock = g2Blocks === 0 ? 0 : (totalDC - g1DCPerBlock * g1Blocks) / g2Blocks;
|
|
485
|
+
const eccNum = ECCodewordsPerBlock[eclIndex][version - 1];
|
|
486
|
+
let currentIndex = 0;
|
|
487
|
+
for (const [blocks, DCPerBlock] of [
|
|
488
|
+
[g1Blocks, g1DCPerBlock],
|
|
489
|
+
[g2Blocks, g2DCPerBlock],
|
|
490
|
+
]) {
|
|
491
|
+
for (let b = 0; b < blocks; b++) {
|
|
492
|
+
const dataCodewords = new Uint8Array(codewords.slice(currentIndex, currentIndex + DCPerBlock));
|
|
493
|
+
groups.push({
|
|
494
|
+
data: dataCodewords,
|
|
495
|
+
ecc: getECC(dataCodewords, eccNum),
|
|
496
|
+
});
|
|
497
|
+
currentIndex += DCPerBlock;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
// 构造最后信息
|
|
502
|
+
{
|
|
503
|
+
// 将块进行交叉
|
|
504
|
+
const dataCodewords = [];
|
|
505
|
+
const ecCodewords = [];
|
|
506
|
+
let i = 0;
|
|
507
|
+
while (true) {
|
|
508
|
+
const result = groups.map((block) => {
|
|
509
|
+
const dataCodeWord = block.data[i];
|
|
510
|
+
if (dataCodeWord !== undefined) {
|
|
511
|
+
dataCodewords.push(dataCodeWord);
|
|
512
|
+
}
|
|
513
|
+
const ecCodeWord = block.ecc[i];
|
|
514
|
+
if (ecCodeWord !== undefined) {
|
|
515
|
+
ecCodewords.push(ecCodeWord);
|
|
516
|
+
}
|
|
517
|
+
return dataCodeWord === undefined && ecCodeWord === undefined;
|
|
518
|
+
});
|
|
519
|
+
if (result.every((done) => done)) {
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
i++;
|
|
523
|
+
}
|
|
524
|
+
// 将交错纠错码字放在交错数据码字之后
|
|
525
|
+
const interleavedCodewords = dataCodewords.concat(ecCodewords);
|
|
526
|
+
dataBits = [];
|
|
527
|
+
interleavedCodewords.forEach((codewords) => {
|
|
528
|
+
appendBits(codewords, 8, dataBits);
|
|
529
|
+
});
|
|
530
|
+
// 如果有必要,添加剩余位
|
|
531
|
+
appendBits(0, getTotalDataModules(version) - dataBits.length, dataBits);
|
|
532
|
+
}
|
|
533
|
+
// 模块在矩阵中的放置
|
|
534
|
+
{
|
|
535
|
+
map = Array(size)
|
|
536
|
+
.fill(null)
|
|
537
|
+
.map(() => Array(size).fill(null));
|
|
538
|
+
// 添加查找器图案
|
|
539
|
+
addFinderPatterns(map, size);
|
|
540
|
+
// 添加分隔符
|
|
541
|
+
addSeparatorPatterns(map, size);
|
|
542
|
+
// 添加对齐图案
|
|
543
|
+
addAlignmentPatterns(map, version);
|
|
544
|
+
// 添加时序图案
|
|
545
|
+
addTimingPatterns(map, size);
|
|
546
|
+
// 添加黑暗图案
|
|
547
|
+
addDarkPattern(map, size);
|
|
548
|
+
// 添加格式信息占位图案
|
|
549
|
+
addFormatInformationPatterns(map, size, () => 0);
|
|
550
|
+
// 添加版本信息占位图案
|
|
551
|
+
if (version >= 7) {
|
|
552
|
+
addVersionInformationPatterns(map, size, () => 0);
|
|
553
|
+
}
|
|
554
|
+
// 放置数据位
|
|
555
|
+
placeDataBits(map, size, dataBits);
|
|
556
|
+
}
|
|
557
|
+
// 数据掩码
|
|
558
|
+
{
|
|
559
|
+
let lowerScore = Infinity;
|
|
560
|
+
for (let i = 0; i < 8; i++) {
|
|
561
|
+
const maskMode = maskModes[i];
|
|
562
|
+
// 生成掩码图案
|
|
563
|
+
const seedMap = map.map((row, rowIndex) => row.map((col, colIndex) => {
|
|
564
|
+
if (col < 2) {
|
|
565
|
+
return col;
|
|
566
|
+
}
|
|
567
|
+
col = col - 2;
|
|
568
|
+
return maskMode(rowIndex, colIndex) ? col ^ 1 : col;
|
|
569
|
+
}));
|
|
570
|
+
// 计算罚分
|
|
571
|
+
let score = 0;
|
|
572
|
+
// 评估条件1
|
|
573
|
+
// 行
|
|
574
|
+
score += getLeastFiveSameColoredPenalty((i, j) => seedMap[i][j], size);
|
|
575
|
+
// 列
|
|
576
|
+
score += getLeastFiveSameColoredPenalty((i, j) => seedMap[j][i], size);
|
|
577
|
+
// 评估条件2
|
|
578
|
+
score += getTwoByTwoSameColoredPenalty(seedMap, size);
|
|
579
|
+
// 评估条件3
|
|
580
|
+
score += getFinderLikePenalty(seedMap, size);
|
|
581
|
+
// 评估条件4
|
|
582
|
+
score += getBalancePenalty(seedMap);
|
|
583
|
+
// 选择八种掩码图案的最低罚分
|
|
584
|
+
if (score < lowerScore) {
|
|
585
|
+
lowerScore = score;
|
|
586
|
+
maskNum = i;
|
|
587
|
+
maskMap = seedMap;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
// 格式和版本信息
|
|
592
|
+
{
|
|
593
|
+
// 添加格式信息图案
|
|
594
|
+
const formatBits = getFormatInformationBits(eclIndex, maskNum);
|
|
595
|
+
addFormatInformationPatterns(map, size, (i) => (formatBits >> i) & 1);
|
|
596
|
+
{
|
|
597
|
+
// 添加版本信息图案
|
|
598
|
+
if (version > 6) {
|
|
599
|
+
const versionBits = getVersionInformationBits(version);
|
|
600
|
+
addVersionInformationPatterns(map, size, (i) => (versionBits >> i) & 1);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
// 输出最终矩阵
|
|
605
|
+
{
|
|
606
|
+
maskMap.forEach((row, y) => {
|
|
607
|
+
row.forEach((col, x) => {
|
|
608
|
+
const mapCol = map[y][x];
|
|
609
|
+
if (mapCol !== 0 && mapCol !== 1) {
|
|
610
|
+
map[y][x] = col;
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
return map;
|
|
615
|
+
}
|
|
616
|
+
}
|