@atooyu/uxto-ui 1.1.37 → 1.1.39
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/dist/index.js +218 -489
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +218 -489
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +18 -18
- package/package.json +1 -1
- package/src/components/u-qrcode/u-qrcode.vue +286 -547
- package/src/components/u-tabbar/u-tabbar.vue +3 -3
|
@@ -45,60 +45,30 @@ const cellSize = computed(() => {
|
|
|
45
45
|
})
|
|
46
46
|
|
|
47
47
|
//---------------------------------------------------------------------------
|
|
48
|
-
// QR Code Generator -
|
|
48
|
+
// QR Code Generator - Based on qrcode-generator by kazuhikoarase
|
|
49
49
|
// https://github.com/kazuhikoarase/qrcode-generator
|
|
50
50
|
// License: MIT
|
|
51
51
|
//---------------------------------------------------------------------------
|
|
52
52
|
|
|
53
|
-
// Error correction levels
|
|
54
|
-
const QRErrorCorrectionLevel = { L: 1, M: 0, Q: 3, H: 2 }
|
|
53
|
+
// Error correction levels: L=1, M=0, Q=3, H=2
|
|
54
|
+
const QRErrorCorrectionLevel: Record<string, number> = { L: 1, M: 0, Q: 3, H: 2 }
|
|
55
55
|
|
|
56
56
|
// Padding bytes
|
|
57
57
|
const PAD0 = 0xEC
|
|
58
58
|
const PAD1 = 0x11
|
|
59
59
|
|
|
60
|
-
// Pattern position table (alignment patterns)
|
|
60
|
+
// Pattern position table (alignment patterns) - index is typeNumber - 1
|
|
61
61
|
const PATTERN_POSITION_TABLE: number[][] = [
|
|
62
|
-
[],
|
|
63
|
-
[6,
|
|
64
|
-
[6,
|
|
65
|
-
[6,
|
|
66
|
-
[6, 30],
|
|
67
|
-
[6, 34],
|
|
68
|
-
[6,
|
|
69
|
-
[6,
|
|
70
|
-
[6,
|
|
71
|
-
[6,
|
|
72
|
-
[6, 30, 54],
|
|
73
|
-
[6, 32, 58],
|
|
74
|
-
[6, 34, 62],
|
|
75
|
-
[6, 26, 46, 66],
|
|
76
|
-
[6, 26, 48, 70],
|
|
77
|
-
[6, 26, 50, 74],
|
|
78
|
-
[6, 30, 54, 78],
|
|
79
|
-
[6, 30, 56, 82],
|
|
80
|
-
[6, 30, 58, 86],
|
|
81
|
-
[6, 34, 62, 90],
|
|
82
|
-
[6, 28, 50, 72, 94],
|
|
83
|
-
[6, 26, 50, 74, 98],
|
|
84
|
-
[6, 30, 54, 78, 102],
|
|
85
|
-
[6, 28, 54, 80, 106],
|
|
86
|
-
[6, 32, 58, 84, 110],
|
|
87
|
-
[6, 30, 58, 86, 114],
|
|
88
|
-
[6, 34, 62, 90, 118],
|
|
89
|
-
[6, 26, 50, 74, 98, 122],
|
|
90
|
-
[6, 30, 54, 78, 102, 126],
|
|
91
|
-
[6, 26, 52, 78, 104, 130],
|
|
92
|
-
[6, 30, 56, 82, 108, 134],
|
|
93
|
-
[6, 34, 60, 86, 112, 138],
|
|
94
|
-
[6, 30, 58, 86, 114, 142],
|
|
95
|
-
[6, 34, 62, 90, 118, 146],
|
|
96
|
-
[6, 30, 54, 78, 102, 126, 150],
|
|
97
|
-
[6, 24, 50, 76, 102, 128, 154],
|
|
98
|
-
[6, 28, 54, 80, 106, 132, 158],
|
|
99
|
-
[6, 32, 58, 84, 110, 136, 162],
|
|
100
|
-
[6, 26, 54, 82, 110, 138, 166],
|
|
101
|
-
[6, 30, 58, 86, 114, 142, 170]
|
|
62
|
+
[], [6, 18], [6, 22], [6, 26], [6, 30], [6, 34],
|
|
63
|
+
[6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50], [6, 30, 54],
|
|
64
|
+
[6, 32, 58], [6, 34, 62], [6, 26, 46, 66], [6, 26, 48, 70], [6, 26, 50, 74],
|
|
65
|
+
[6, 30, 54, 78], [6, 30, 56, 82], [6, 30, 58, 86], [6, 34, 62, 90],
|
|
66
|
+
[6, 28, 50, 72, 94], [6, 26, 50, 74, 98], [6, 30, 54, 78, 102], [6, 28, 54, 80, 106],
|
|
67
|
+
[6, 32, 58, 84, 110], [6, 30, 58, 86, 114], [6, 34, 62, 90, 118], [6, 26, 50, 74, 98, 122],
|
|
68
|
+
[6, 30, 54, 78, 102, 126], [6, 26, 52, 78, 104, 130], [6, 30, 56, 82, 108, 134],
|
|
69
|
+
[6, 34, 60, 86, 112, 138], [6, 30, 58, 86, 114, 142], [6, 34, 62, 90, 118, 146],
|
|
70
|
+
[6, 30, 54, 78, 102, 126, 150], [6, 24, 50, 76, 102, 128, 154], [6, 28, 54, 80, 106, 132, 158],
|
|
71
|
+
[6, 32, 58, 84, 110, 136, 162], [6, 26, 54, 82, 110, 138, 166], [6, 30, 58, 86, 114, 142, 170]
|
|
102
72
|
]
|
|
103
73
|
|
|
104
74
|
// BCH codes
|
|
@@ -106,7 +76,7 @@ const G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (
|
|
|
106
76
|
const G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0)
|
|
107
77
|
const G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1)
|
|
108
78
|
|
|
109
|
-
// RS Block table
|
|
79
|
+
// RS Block table - each entry is for one typeNumber, 4 error levels
|
|
110
80
|
const RS_BLOCK_TABLE: number[][] = [
|
|
111
81
|
[1, 26, 19], [1, 26, 16], [1, 26, 13], [1, 26, 9],
|
|
112
82
|
[1, 44, 34], [1, 44, 28], [1, 44, 22], [1, 44, 16],
|
|
@@ -127,44 +97,18 @@ const RS_BLOCK_TABLE: number[][] = [
|
|
|
127
97
|
[1, 135, 107, 5, 136, 108], [10, 74, 46, 1, 75, 47], [1, 50, 22, 15, 51, 23], [2, 42, 14, 17, 43, 15],
|
|
128
98
|
[5, 150, 120, 1, 151, 121], [9, 69, 43, 4, 70, 44], [17, 50, 22, 1, 51, 23], [2, 42, 14, 19, 43, 15],
|
|
129
99
|
[3, 141, 113, 4, 142, 114], [3, 70, 44, 11, 71, 45], [17, 47, 21, 4, 48, 22], [9, 39, 13, 16, 40, 14],
|
|
130
|
-
[3, 135, 107, 5, 136, 108], [3, 67, 41, 13, 68, 42], [15, 54, 24, 5, 55, 25], [15, 43, 15, 10, 44, 16]
|
|
131
|
-
[4, 144, 116, 4, 145, 117], [17, 68, 42], [17, 50, 22, 6, 51, 23], [19, 46, 16, 6, 47, 17],
|
|
132
|
-
[2, 139, 111, 7, 140, 112], [17, 74, 46], [7, 54, 24, 16, 55, 25], [34, 37, 13],
|
|
133
|
-
[4, 151, 121, 5, 152, 122], [4, 75, 47, 14, 76, 48], [11, 54, 24, 14, 55, 25], [16, 45, 15, 14, 46, 16],
|
|
134
|
-
[6, 147, 117, 4, 148, 118], [6, 73, 45, 14, 74, 46], [11, 54, 24, 16, 55, 25], [30, 46, 16, 2, 47, 17],
|
|
135
|
-
[8, 132, 106, 4, 133, 107], [8, 75, 47, 13, 76, 48], [7, 54, 24, 22, 55, 25], [22, 45, 15, 13, 46, 16],
|
|
136
|
-
[10, 142, 114, 2, 143, 115], [19, 74, 46, 4, 75, 47], [28, 50, 22, 6, 51, 23], [33, 46, 16, 4, 47, 17],
|
|
137
|
-
[8, 152, 122, 4, 153, 123], [22, 73, 45, 3, 74, 46], [8, 53, 23, 26, 54, 24], [12, 45, 15, 28, 46, 16],
|
|
138
|
-
[3, 147, 117, 10, 148, 118], [3, 73, 45, 23, 74, 46], [4, 54, 24, 31, 55, 25], [11, 45, 15, 31, 46, 16],
|
|
139
|
-
[7, 146, 116, 7, 147, 117], [21, 73, 45, 7, 74, 46], [1, 53, 23, 37, 54, 24], [19, 45, 15, 26, 46, 16],
|
|
140
|
-
[5, 145, 115, 10, 146, 116], [19, 75, 47, 10, 76, 48], [15, 54, 24, 25, 55, 25], [23, 45, 15, 25, 46, 16],
|
|
141
|
-
[13, 145, 115, 3, 146, 116], [2, 74, 46, 29, 75, 47], [42, 54, 24, 1, 55, 25], [23, 45, 15, 28, 46, 16],
|
|
142
|
-
[17, 145, 115], [10, 74, 46, 23, 75, 47], [10, 54, 24, 35, 55, 25], [19, 45, 15, 35, 46, 16],
|
|
143
|
-
[17, 145, 115, 1, 146, 116], [14, 74, 46, 21, 75, 47], [29, 54, 24, 19, 55, 25], [11, 45, 15, 46, 46, 16],
|
|
144
|
-
[13, 145, 115, 6, 146, 116], [14, 74, 46, 23, 75, 47], [44, 54, 24, 7, 55, 25], [59, 46, 16, 1, 47, 17],
|
|
145
|
-
[12, 151, 121, 7, 152, 122], [12, 75, 47, 26, 76, 48], [39, 54, 24, 14, 55, 25], [22, 45, 15, 41, 46, 16],
|
|
146
|
-
[6, 151, 121, 14, 152, 122], [6, 75, 47, 34, 76, 48], [46, 54, 24, 10, 55, 25], [2, 45, 15, 64, 46, 16],
|
|
147
|
-
[17, 152, 122, 4, 153, 123], [29, 74, 46, 14, 75, 47], [49, 54, 24, 10, 55, 25], [24, 45, 15, 46, 46, 16],
|
|
148
|
-
[4, 152, 122, 18, 153, 123], [13, 74, 46, 32, 75, 47], [48, 54, 24, 14, 55, 25], [42, 45, 15, 32, 46, 16],
|
|
149
|
-
[20, 147, 117, 4, 148, 118], [40, 75, 47, 7, 76, 48], [43, 54, 24, 22, 55, 25], [10, 45, 15, 67, 46, 16],
|
|
150
|
-
[19, 148, 118, 6, 149, 119], [18, 75, 47, 31, 76, 48], [34, 54, 24, 34, 55, 25], [20, 45, 15, 61, 46, 16]
|
|
100
|
+
[3, 135, 107, 5, 136, 108], [3, 67, 41, 13, 68, 42], [15, 54, 24, 5, 55, 25], [15, 43, 15, 10, 44, 16]
|
|
151
101
|
]
|
|
152
102
|
|
|
153
|
-
//
|
|
154
|
-
const EXP_TABLE: number[] =
|
|
155
|
-
const LOG_TABLE: number[] =
|
|
103
|
+
// Galois Field tables
|
|
104
|
+
const EXP_TABLE: number[] = []
|
|
105
|
+
const LOG_TABLE: number[] = []
|
|
156
106
|
|
|
157
|
-
// Initialize
|
|
158
|
-
for (let i = 0; i < 8; i++)
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
for (let i =
|
|
162
|
-
EXP_TABLE[i] = EXP_TABLE[i - 4] ^ EXP_TABLE[i - 5] ^ EXP_TABLE[i - 6] ^ EXP_TABLE[i - 8]
|
|
163
|
-
}
|
|
164
|
-
// Initialize LOG_TABLE
|
|
165
|
-
for (let i = 0; i < 255; i++) {
|
|
166
|
-
LOG_TABLE[EXP_TABLE[i]] = i
|
|
167
|
-
}
|
|
107
|
+
// Initialize GF tables
|
|
108
|
+
for (let i = 0; i < 8; i++) EXP_TABLE[i] = 1 << i
|
|
109
|
+
for (let i = 8; i < 256; i++) EXP_TABLE[i] = EXP_TABLE[i - 4] ^ EXP_TABLE[i - 5] ^ EXP_TABLE[i - 6] ^ EXP_TABLE[i - 8]
|
|
110
|
+
for (let i = 0; i < 255; i++) LOG_TABLE[EXP_TABLE[i]] = i
|
|
111
|
+
for (let i = 255; i < 512; i++) EXP_TABLE[i] = EXP_TABLE[i - 255]
|
|
168
112
|
|
|
169
113
|
function glog(n: number): number {
|
|
170
114
|
if (n < 1) throw new Error('glog(' + n + ')')
|
|
@@ -177,80 +121,23 @@ function gexp(n: number): number {
|
|
|
177
121
|
return EXP_TABLE[n]
|
|
178
122
|
}
|
|
179
123
|
|
|
180
|
-
// Polynomial operations
|
|
181
|
-
interface Polynomial {
|
|
182
|
-
getAt(index: number): number
|
|
183
|
-
getLength(): number
|
|
184
|
-
multiply(e: Polynomial): Polynomial
|
|
185
|
-
mod(e: Polynomial): Polynomial
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function createPolynomial(num: number[], shift: number): Polynomial {
|
|
189
|
-
// Remove leading zeros
|
|
190
|
-
let offset = 0
|
|
191
|
-
while (offset < num.length && num[offset] === 0) offset++
|
|
192
|
-
const _num = new Array(num.length - offset + shift).fill(0)
|
|
193
|
-
for (let i = 0; i < num.length - offset; i++) {
|
|
194
|
-
_num[i] = num[i + offset]
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
getAt: (index: number) => _num[index],
|
|
199
|
-
getLength: () => _num.length,
|
|
200
|
-
multiply: (e: Polynomial): Polynomial => {
|
|
201
|
-
const result = new Array(_num.length + e.getLength() - 1).fill(0)
|
|
202
|
-
for (let i = 0; i < _num.length; i++) {
|
|
203
|
-
for (let j = 0; j < e.getLength(); j++) {
|
|
204
|
-
result[i + j] ^= gexp(glog(_num[i]) + glog(e.getAt(j)))
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return createPolynomial(result, 0)
|
|
208
|
-
},
|
|
209
|
-
mod: (e: Polynomial): Polynomial => {
|
|
210
|
-
const lenDiff = _num.length - e.getLength()
|
|
211
|
-
if (lenDiff < 0) return createPolynomial(_num, 0)
|
|
212
|
-
|
|
213
|
-
const ratio = glog(_num[0]) - glog(e.getAt(0))
|
|
214
|
-
const result = [..._num]
|
|
215
|
-
for (let i = 0; i < e.getLength(); i++) {
|
|
216
|
-
result[i] ^= gexp(glog(e.getAt(i)) + ratio)
|
|
217
|
-
}
|
|
218
|
-
return createPolynomial(result, 0).mod(e)
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
124
|
// Get BCH digit count
|
|
224
125
|
function getBCHDigit(data: number): number {
|
|
225
126
|
let digit = 0
|
|
226
|
-
while (data !== 0) {
|
|
227
|
-
digit++
|
|
228
|
-
data >>>= 1
|
|
229
|
-
}
|
|
127
|
+
while (data !== 0) { digit++; data >>>= 1 }
|
|
230
128
|
return digit
|
|
231
129
|
}
|
|
232
130
|
|
|
233
131
|
// Get BCH type info
|
|
234
132
|
function getBCHTypeInfo(data: number): number {
|
|
235
133
|
let d = data << 10
|
|
236
|
-
while (getBCHDigit(d) - getBCHDigit(G15) >= 0)
|
|
237
|
-
d ^= G15 << (getBCHDigit(d) - getBCHDigit(G15))
|
|
238
|
-
}
|
|
134
|
+
while (getBCHDigit(d) - getBCHDigit(G15) >= 0) d ^= G15 << (getBCHDigit(d) - getBCHDigit(G15))
|
|
239
135
|
return ((data << 10) | d) ^ G15_MASK
|
|
240
136
|
}
|
|
241
137
|
|
|
242
|
-
// Get BCH type number
|
|
243
|
-
function getBCHTypeNumber(data: number): number {
|
|
244
|
-
let d = data << 12
|
|
245
|
-
while (getBCHDigit(d) - getBCHDigit(G18) >= 0) {
|
|
246
|
-
d ^= G18 << (getBCHDigit(d) - getBCHDigit(G18))
|
|
247
|
-
}
|
|
248
|
-
return (data << 12) | d
|
|
249
|
-
}
|
|
250
|
-
|
|
251
138
|
// Get pattern position
|
|
252
139
|
function getPatternPosition(typeNumber: number): number[] {
|
|
253
|
-
return PATTERN_POSITION_TABLE[typeNumber - 1]
|
|
140
|
+
return PATTERN_POSITION_TABLE[typeNumber - 1] || []
|
|
254
141
|
}
|
|
255
142
|
|
|
256
143
|
// Get mask function
|
|
@@ -264,507 +151,372 @@ function getMaskFunction(maskPattern: number): (i: number, j: number) => boolean
|
|
|
264
151
|
case 5: return (i, j) => (i * j) % 2 + (i * j) % 3 === 0
|
|
265
152
|
case 6: return (i, j) => ((i * j) % 2 + (i * j) % 3) % 2 === 0
|
|
266
153
|
case 7: return (i, j) => ((i * j) % 3 + (i + j) % 2) % 2 === 0
|
|
267
|
-
default:
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Get error correct polynomial
|
|
272
|
-
function getErrorCorrectPolynomial(errorCorrectLength: number): Polynomial {
|
|
273
|
-
let a = createPolynomial([1], 0)
|
|
274
|
-
for (let i = 0; i < errorCorrectLength; i++) {
|
|
275
|
-
a = a.multiply(createPolynomial([1, gexp(i)], 0))
|
|
276
|
-
}
|
|
277
|
-
return a
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Get length in bits for mode
|
|
281
|
-
function getLengthInBits(mode: number, type: number): number {
|
|
282
|
-
if (1 <= type && type < 10) {
|
|
283
|
-
switch (mode) {
|
|
284
|
-
case 1: return 10 // NUMBER
|
|
285
|
-
case 2: return 9 // ALPHA_NUM
|
|
286
|
-
case 4: return 8 // 8BIT_BYTE
|
|
287
|
-
case 8: return 8 // KANJI
|
|
288
|
-
default: throw new Error('mode:' + mode)
|
|
289
|
-
}
|
|
290
|
-
} else if (type < 27) {
|
|
291
|
-
switch (mode) {
|
|
292
|
-
case 1: return 12
|
|
293
|
-
case 2: return 11
|
|
294
|
-
case 4: return 16
|
|
295
|
-
case 8: return 10
|
|
296
|
-
default: throw new Error('mode:' + mode)
|
|
297
|
-
}
|
|
298
|
-
} else if (type < 41) {
|
|
299
|
-
switch (mode) {
|
|
300
|
-
case 1: return 14
|
|
301
|
-
case 2: return 13
|
|
302
|
-
case 4: return 16
|
|
303
|
-
case 8: return 12
|
|
304
|
-
default: throw new Error('mode:' + mode)
|
|
305
|
-
}
|
|
306
|
-
} else {
|
|
307
|
-
throw new Error('type:' + type)
|
|
154
|
+
default: return () => false
|
|
308
155
|
}
|
|
309
156
|
}
|
|
310
157
|
|
|
311
158
|
// Get RS blocks
|
|
312
159
|
function getRSBlocks(typeNumber: number, errorCorrectionLevel: number): { totalCount: number; dataCount: number }[] {
|
|
313
|
-
const
|
|
314
|
-
|
|
160
|
+
const index = (typeNumber - 1) * 4 + errorCorrectionLevel
|
|
161
|
+
const block = RS_BLOCK_TABLE[index]
|
|
162
|
+
if (!block) throw new Error('bad rs block')
|
|
315
163
|
|
|
316
|
-
const length = rsBlock.length / 3
|
|
317
164
|
const list: { totalCount: number; dataCount: number }[] = []
|
|
165
|
+
const length = Math.floor(block.length / 3)
|
|
318
166
|
|
|
319
167
|
for (let i = 0; i < length; i++) {
|
|
320
|
-
const count =
|
|
321
|
-
const totalCount =
|
|
322
|
-
const dataCount =
|
|
323
|
-
for (let j = 0; j < count; j++) {
|
|
324
|
-
list.push({ totalCount, dataCount })
|
|
325
|
-
}
|
|
168
|
+
const count = block[i * 3]
|
|
169
|
+
const totalCount = block[i * 3 + 1]
|
|
170
|
+
const dataCount = block[i * 3 + 2]
|
|
171
|
+
for (let j = 0; j < count; j++) list.push({ totalCount, dataCount })
|
|
326
172
|
}
|
|
327
173
|
return list
|
|
328
174
|
}
|
|
329
175
|
|
|
330
|
-
// Bit buffer
|
|
176
|
+
// Bit buffer class
|
|
331
177
|
class BitBuffer {
|
|
332
|
-
|
|
333
|
-
|
|
178
|
+
buffer: number[] = []
|
|
179
|
+
length = 0
|
|
334
180
|
|
|
335
|
-
getBuffer()
|
|
336
|
-
getLengthInBits()
|
|
181
|
+
getBuffer() { return this.buffer }
|
|
182
|
+
getLengthInBits() { return this.length }
|
|
337
183
|
|
|
338
184
|
put(num: number, len: number) {
|
|
339
|
-
for (let i = 0; i < len; i++)
|
|
340
|
-
this.putBit(((num >>> (len - i - 1)) & 1) === 1)
|
|
341
|
-
}
|
|
185
|
+
for (let i = 0; i < len; i++) this.putBit(((num >>> (len - i - 1)) & 1) === 1)
|
|
342
186
|
}
|
|
343
187
|
|
|
344
188
|
putBit(bit: boolean) {
|
|
345
189
|
const bufIndex = Math.floor(this.length / 8)
|
|
346
|
-
if (this.buffer.length <= bufIndex)
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
if (bit) {
|
|
350
|
-
this.buffer[bufIndex] |= (0x80 >>> (this.length % 8))
|
|
351
|
-
}
|
|
190
|
+
if (this.buffer.length <= bufIndex) this.buffer.push(0)
|
|
191
|
+
if (bit) this.buffer[bufIndex] |= 0x80 >>> (this.length % 8)
|
|
352
192
|
this.length++
|
|
353
193
|
}
|
|
354
194
|
}
|
|
355
195
|
|
|
356
|
-
// String to bytes
|
|
196
|
+
// String to bytes
|
|
357
197
|
function stringToBytes(s: string): number[] {
|
|
358
198
|
const bytes: number[] = []
|
|
359
|
-
for (let i = 0; i < s.length; i++)
|
|
360
|
-
const c = s.charCodeAt(i)
|
|
361
|
-
bytes.push(c & 0xff)
|
|
362
|
-
}
|
|
199
|
+
for (let i = 0; i < s.length; i++) bytes.push(s.charCodeAt(i) & 0xff)
|
|
363
200
|
return bytes
|
|
364
201
|
}
|
|
365
202
|
|
|
366
|
-
//
|
|
367
|
-
function
|
|
368
|
-
|
|
369
|
-
|
|
203
|
+
// Get length in bits for mode
|
|
204
|
+
function getLengthInBits(mode: number, type: number): number {
|
|
205
|
+
if (type < 10) return mode === 4 ? 8 : 8
|
|
206
|
+
if (type < 27) return mode === 4 ? 16 : 10
|
|
207
|
+
return mode === 4 ? 16 : 12
|
|
208
|
+
}
|
|
370
209
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
for (
|
|
376
|
-
|
|
210
|
+
// Polynomial multiplication
|
|
211
|
+
function multiplyPolynomials(a: number[], b: number[]): number[] {
|
|
212
|
+
const result = new Array(a.length + b.length - 1).fill(0)
|
|
213
|
+
for (let i = 0; i < a.length; i++) {
|
|
214
|
+
for (let j = 0; j < b.length; j++) {
|
|
215
|
+
result[i + j] ^= gexp(glog(a[i]) + glog(b[j]))
|
|
377
216
|
}
|
|
378
217
|
}
|
|
218
|
+
return result
|
|
219
|
+
}
|
|
379
220
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
221
|
+
// Polynomial modulo
|
|
222
|
+
function modPolynomial(a: number[], b: number[]): number[] {
|
|
223
|
+
let result = [...a]
|
|
224
|
+
while (result.length >= b.length) {
|
|
225
|
+
const ratio = glog(result[0]) - glog(b[0])
|
|
226
|
+
for (let i = 0; i < b.length; i++) {
|
|
227
|
+
result[i] ^= gexp(glog(b[i]) + ratio)
|
|
228
|
+
}
|
|
229
|
+
while (result.length > 0 && result[0] === 0) result.shift()
|
|
384
230
|
}
|
|
231
|
+
return result
|
|
232
|
+
}
|
|
385
233
|
|
|
386
|
-
|
|
387
|
-
|
|
234
|
+
// Get error correction codewords
|
|
235
|
+
function getErrorCorrectPolynomial(errorCorrectLength: number): number[] {
|
|
236
|
+
let poly = [1]
|
|
237
|
+
for (let i = 0; i < errorCorrectLength; i++) {
|
|
238
|
+
poly = multiplyPolynomials(poly, [1, gexp(i)])
|
|
388
239
|
}
|
|
240
|
+
return poly
|
|
241
|
+
}
|
|
389
242
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
243
|
+
// Create data bytes with error correction
|
|
244
|
+
function createData(typeNumber: number, errorCorrectionLevel: number, data: string): number[] {
|
|
245
|
+
const rsBlocks = getRSBlocks(typeNumber, errorCorrectionLevel)
|
|
394
246
|
|
|
395
|
-
//
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
247
|
+
// Calculate total data count
|
|
248
|
+
let totalDataCount = 0
|
|
249
|
+
for (const block of rsBlocks) totalDataCount += block.dataCount
|
|
399
250
|
|
|
400
|
-
|
|
401
|
-
while (true) {
|
|
402
|
-
if (buffer.getLengthInBits() >= totalDataCount * 8) break
|
|
403
|
-
buffer.put(PAD0, 8)
|
|
404
|
-
if (buffer.getLengthInBits() >= totalDataCount * 8) break
|
|
405
|
-
buffer.put(PAD1, 8)
|
|
406
|
-
}
|
|
251
|
+
const buffer = new BitBuffer()
|
|
407
252
|
|
|
408
|
-
|
|
409
|
-
|
|
253
|
+
// Mode indicator (4 = byte mode)
|
|
254
|
+
buffer.put(4, 4)
|
|
410
255
|
|
|
411
|
-
//
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
let maxDcCount = 0
|
|
415
|
-
let maxEcCount = 0
|
|
256
|
+
// Character count
|
|
257
|
+
const bytes = stringToBytes(data)
|
|
258
|
+
buffer.put(bytes.length, getLengthInBits(4, typeNumber))
|
|
416
259
|
|
|
417
|
-
|
|
418
|
-
const
|
|
260
|
+
// Data
|
|
261
|
+
for (const byte of bytes) buffer.put(byte, 8)
|
|
419
262
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const ecCount = block.totalCount - dcCount
|
|
263
|
+
// Terminator
|
|
264
|
+
if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) buffer.put(0, 4)
|
|
423
265
|
|
|
424
|
-
|
|
425
|
-
|
|
266
|
+
// Pad to byte boundary
|
|
267
|
+
while (buffer.getLengthInBits() % 8 !== 0) buffer.putBit(false)
|
|
426
268
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
269
|
+
// Padding bytes
|
|
270
|
+
let padIndex = 0
|
|
271
|
+
const padBytes = [PAD0, PAD1]
|
|
272
|
+
while (buffer.getLengthInBits() < totalDataCount * 8) {
|
|
273
|
+
buffer.put(padBytes[padIndex], 8)
|
|
274
|
+
padIndex = (padIndex + 1) % 2
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Create data and EC codewords
|
|
278
|
+
const dataBuffer = buffer.getBuffer()
|
|
279
|
+
let dataIndex = 0
|
|
280
|
+
const dcData: number[][] = []
|
|
281
|
+
const ecData: number[][] = []
|
|
282
|
+
|
|
283
|
+
for (const block of rsBlocks) {
|
|
284
|
+
const dc = dataBuffer.slice(dataIndex, dataIndex + block.dataCount)
|
|
285
|
+
dataIndex += block.dataCount
|
|
286
|
+
dcData.push(dc)
|
|
433
287
|
|
|
434
|
-
|
|
288
|
+
const ecCount = block.totalCount - block.dataCount
|
|
435
289
|
const rsPoly = getErrorCorrectPolynomial(ecCount)
|
|
436
|
-
const rawPoly = createPolynomial(dc, rsPoly.getLength() - 1)
|
|
437
|
-
const modPoly = rawPoly.mod(rsPoly)
|
|
438
290
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
ecdata.push(ec)
|
|
291
|
+
// Pad data polynomial
|
|
292
|
+
const dataPoly = [...dc, ...new Array(ecCount).fill(0)]
|
|
293
|
+
const ec = modPolynomial(dataPoly, rsPoly)
|
|
294
|
+
|
|
295
|
+
ecData.push(ec.slice(-ecCount))
|
|
445
296
|
}
|
|
446
297
|
|
|
447
|
-
// Interleave
|
|
298
|
+
// Interleave data codewords
|
|
448
299
|
const result: number[] = []
|
|
300
|
+
let maxDcCount = 0
|
|
301
|
+
let maxEcCount = 0
|
|
302
|
+
for (const block of rsBlocks) {
|
|
303
|
+
maxDcCount = Math.max(maxDcCount, block.dataCount)
|
|
304
|
+
maxEcCount = Math.max(maxEcCount, block.totalCount - block.dataCount)
|
|
305
|
+
}
|
|
306
|
+
|
|
449
307
|
for (let i = 0; i < maxDcCount; i++) {
|
|
450
|
-
for (
|
|
451
|
-
if (i <
|
|
308
|
+
for (const dc of dcData) {
|
|
309
|
+
if (i < dc.length) result.push(dc[i])
|
|
452
310
|
}
|
|
453
311
|
}
|
|
312
|
+
|
|
454
313
|
for (let i = 0; i < maxEcCount; i++) {
|
|
455
|
-
for (
|
|
456
|
-
if (i <
|
|
314
|
+
for (const ec of ecData) {
|
|
315
|
+
if (i < ec.length) result.push(ec[i])
|
|
457
316
|
}
|
|
458
317
|
}
|
|
459
318
|
|
|
460
319
|
return result
|
|
461
320
|
}
|
|
462
321
|
|
|
463
|
-
// QR Code
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
private errorCorrectionLevel: number
|
|
467
|
-
private modules: (boolean | null)[][] = []
|
|
468
|
-
private moduleCount = 0
|
|
469
|
-
private dataCache: number[] | null = null
|
|
470
|
-
|
|
471
|
-
constructor(typeNumber: number, errorCorrectionLevel: string) {
|
|
472
|
-
this.typeNumber = typeNumber
|
|
473
|
-
this.errorCorrectionLevel = QRErrorCorrectionLevel[errorCorrectionLevel]
|
|
474
|
-
}
|
|
322
|
+
// Main QR Code generator
|
|
323
|
+
function generateQRCode(text: string, errorLevel: string): { modules: boolean[][]; moduleCount: number } {
|
|
324
|
+
const ecl = QRErrorCorrectionLevel[errorLevel] ?? 0
|
|
475
325
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
if (this.typeNumber < 1) {
|
|
483
|
-
// Auto detect type number
|
|
484
|
-
let typeNumber = 1
|
|
485
|
-
for (; typeNumber < 40; typeNumber++) {
|
|
486
|
-
try {
|
|
487
|
-
const testData = createData(typeNumber, this.errorCorrectionLevel, [{ mode: 4, data: 'test' }])
|
|
488
|
-
// Just check if it works
|
|
489
|
-
this.dataCache = createData(typeNumber, this.errorCorrectionLevel, [{ mode: 4, data: '' }])
|
|
490
|
-
break
|
|
491
|
-
} catch {
|
|
492
|
-
continue
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
this.typeNumber = typeNumber
|
|
496
|
-
// Recreate data cache with correct type number
|
|
497
|
-
const dataList = [{ mode: 4, data: '' }]
|
|
498
|
-
// We'll set data again below
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
this.makeImpl(false, this.getBestMaskPattern())
|
|
502
|
-
}
|
|
326
|
+
// Find minimum version
|
|
327
|
+
let typeNumber = 1
|
|
328
|
+
for (; typeNumber <= 40; typeNumber++) {
|
|
329
|
+
const rsBlocks = getRSBlocks(typeNumber, ecl)
|
|
330
|
+
let totalDataCount = 0
|
|
331
|
+
for (const block of rsBlocks) totalDataCount += block.dataCount
|
|
503
332
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
333
|
+
// Byte mode: 4 (mode) + length bits + data bits
|
|
334
|
+
const lengthBits = typeNumber < 10 ? 8 : 16
|
|
335
|
+
const totalBits = 4 + lengthBits + (stringToBytes(text).length * 8)
|
|
507
336
|
|
|
508
|
-
|
|
509
|
-
this.makeImpl(true, i)
|
|
510
|
-
const lostPoint = this.getLostPoint()
|
|
511
|
-
if (i === 0 || minLostPoint > lostPoint) {
|
|
512
|
-
minLostPoint = lostPoint
|
|
513
|
-
pattern = i
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
return pattern
|
|
337
|
+
if (totalBits <= totalDataCount * 8) break
|
|
517
338
|
}
|
|
518
339
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
this.modules = []
|
|
522
|
-
for (let row = 0; row < this.moduleCount; row++) {
|
|
523
|
-
this.modules[row] = new Array(this.moduleCount).fill(null)
|
|
524
|
-
}
|
|
340
|
+
const size = typeNumber * 4 + 17
|
|
341
|
+
const data = createData(typeNumber, ecl, text)
|
|
525
342
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
this.setupPositionAdjustPattern()
|
|
530
|
-
this.setupTimingPattern()
|
|
531
|
-
this.setupTypeInfo(test, maskPattern)
|
|
343
|
+
// Initialize modules
|
|
344
|
+
const mod: (boolean | null)[][] = []
|
|
345
|
+
for (let i = 0; i < size; i++) mod[i] = new Array(size).fill(null)
|
|
532
346
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
if (this.dataCache === null) {
|
|
538
|
-
throw new Error('dataCache is null')
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
this.mapData(this.dataCache, maskPattern)
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
private setupPositionProbePattern(row: number, col: number) {
|
|
347
|
+
// Setup finder patterns
|
|
348
|
+
const setupFinderPattern = (row: number, col: number) => {
|
|
545
349
|
for (let r = -1; r <= 7; r++) {
|
|
546
|
-
if (row + r <= -1 || this.moduleCount <= row + r) continue
|
|
547
350
|
for (let c = -1; c <= 7; c++) {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
this.modules[row + r][col + c] = true
|
|
351
|
+
const nr = row + r, nc = col + c
|
|
352
|
+
if (nr < 0 || nr >= size || nc < 0 || nc >= size) continue
|
|
353
|
+
|
|
354
|
+
if ((r >= 0 && r <= 6 && (c === 0 || c === 6)) ||
|
|
355
|
+
(c >= 0 && c <= 6 && (r === 0 || r === 6)) ||
|
|
356
|
+
(r >= 2 && r <= 4 && c >= 2 && c <= 4)) {
|
|
357
|
+
mod[nr][nc] = true
|
|
556
358
|
} else {
|
|
557
|
-
|
|
359
|
+
mod[nr][nc] = false
|
|
558
360
|
}
|
|
559
361
|
}
|
|
560
362
|
}
|
|
561
363
|
}
|
|
562
364
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
}
|
|
365
|
+
setupFinderPattern(0, 0)
|
|
366
|
+
setupFinderPattern(size - 7, 0)
|
|
367
|
+
setupFinderPattern(0, size - 7)
|
|
368
|
+
|
|
369
|
+
// Setup timing patterns
|
|
370
|
+
for (let i = 8; i < size - 8; i++) {
|
|
371
|
+
if (mod[i][6] === null) mod[i][6] = i % 2 === 0
|
|
372
|
+
if (mod[6][i] === null) mod[6][i] = i % 2 === 0
|
|
572
373
|
}
|
|
573
374
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
for (let r = -2; r <= 2; r++) {
|
|
583
|
-
for (let c = -2; c <= 2; c++) {
|
|
584
|
-
if (r === -2 || r === 2 || c === -2 || c === 2 || (r === 0 && c === 0)) {
|
|
585
|
-
this.modules[row + r][col + c] = true
|
|
586
|
-
} else {
|
|
587
|
-
this.modules[row + r][col + c] = false
|
|
588
|
-
}
|
|
589
|
-
}
|
|
375
|
+
// Setup alignment patterns
|
|
376
|
+
const alignPos = getPatternPosition(typeNumber)
|
|
377
|
+
for (const row of alignPos) {
|
|
378
|
+
for (const col of alignPos) {
|
|
379
|
+
if (mod[row][col] !== null) continue
|
|
380
|
+
for (let r = -2; r <= 2; r++) {
|
|
381
|
+
for (let c = -2; c <= 2; c++) {
|
|
382
|
+
mod[row + r][col + c] = r === -2 || r === 2 || c === -2 || c === 2 || (r === 0 && c === 0)
|
|
590
383
|
}
|
|
591
384
|
}
|
|
592
385
|
}
|
|
593
386
|
}
|
|
594
387
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod
|
|
600
|
-
}
|
|
601
|
-
for (let i = 0; i < 18; i++) {
|
|
602
|
-
const mod = !test && ((bits >> i) & 1) === 1
|
|
603
|
-
this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod
|
|
604
|
-
}
|
|
388
|
+
// Setup format info area (reserved)
|
|
389
|
+
for (let i = 0; i < 9; i++) {
|
|
390
|
+
if (mod[8][i] === null) mod[8][i] = false
|
|
391
|
+
if (mod[i][8] === null) mod[i][8] = false
|
|
605
392
|
}
|
|
393
|
+
for (let i = 0; i < 8; i++) {
|
|
394
|
+
if (mod[8][size - 1 - i] === null) mod[8][size - 1 - i] = false
|
|
395
|
+
if (mod[size - 1 - i][8] === null) mod[size - 1 - i][8] = false
|
|
396
|
+
}
|
|
397
|
+
// Dark module
|
|
398
|
+
mod[size - 8][8] = true
|
|
606
399
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
const bits =
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
if (i < 6) {
|
|
615
|
-
this.modules[i][8] = mod
|
|
616
|
-
} else if (i < 8) {
|
|
617
|
-
this.modules[i + 1][8] = mod
|
|
618
|
-
} else {
|
|
619
|
-
this.modules[this.moduleCount - 15 + i][8] = mod
|
|
400
|
+
// Setup type number (version 7+)
|
|
401
|
+
if (typeNumber >= 7) {
|
|
402
|
+
const bits = typeNumber
|
|
403
|
+
for (let i = 0; i < 6; i++) {
|
|
404
|
+
for (let j = 0; j < 3; j++) {
|
|
405
|
+
mod[i][size - 11 + j] = ((bits >> (i * 3 + j)) & 1) === 1
|
|
406
|
+
mod[size - 11 + j][i] = ((bits >> (i * 3 + j)) & 1) === 1
|
|
620
407
|
}
|
|
621
408
|
}
|
|
409
|
+
}
|
|
622
410
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
if (i < 8) {
|
|
627
|
-
this.modules[8][this.moduleCount - i - 1] = mod
|
|
628
|
-
} else if (i < 9) {
|
|
629
|
-
this.modules[8][15 - i - 1 + 1] = mod
|
|
630
|
-
} else {
|
|
631
|
-
this.modules[8][15 - i - 1] = mod
|
|
632
|
-
}
|
|
633
|
-
}
|
|
411
|
+
// Map data with best mask
|
|
412
|
+
let bestMask = 0
|
|
413
|
+
let bestPenalty = Infinity
|
|
634
414
|
|
|
635
|
-
|
|
636
|
-
|
|
415
|
+
for (let mask = 0; mask < 8; mask++) {
|
|
416
|
+
const testMod = mod.map(row => [...row])
|
|
417
|
+
mapData(testMod, size, data, mask)
|
|
418
|
+
const penalty = calculatePenalty(testMod, size)
|
|
419
|
+
if (penalty < bestPenalty) {
|
|
420
|
+
bestPenalty = penalty
|
|
421
|
+
bestMask = mask
|
|
422
|
+
}
|
|
637
423
|
}
|
|
638
424
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
let row = this.moduleCount - 1
|
|
642
|
-
let bitIndex = 7
|
|
643
|
-
let byteIndex = 0
|
|
644
|
-
const maskFunc = getMaskFunction(maskPattern)
|
|
645
|
-
|
|
646
|
-
for (let col = this.moduleCount - 1; col > 0; col -= 2) {
|
|
647
|
-
if (col === 6) col -= 1
|
|
648
|
-
|
|
649
|
-
while (true) {
|
|
650
|
-
for (let c = 0; c < 2; c++) {
|
|
651
|
-
if (this.modules[row][col - c] === null) {
|
|
652
|
-
let dark = false
|
|
653
|
-
if (byteIndex < data.length) {
|
|
654
|
-
dark = ((data[byteIndex] >>> bitIndex) & 1) === 1
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
const mask = maskFunc(row, col - c)
|
|
658
|
-
if (mask) dark = !dark
|
|
659
|
-
|
|
660
|
-
this.modules[row][col - c] = dark
|
|
661
|
-
bitIndex--
|
|
662
|
-
|
|
663
|
-
if (bitIndex === -1) {
|
|
664
|
-
byteIndex++
|
|
665
|
-
bitIndex = 7
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
}
|
|
425
|
+
// Apply best mask
|
|
426
|
+
mapData(mod, size, data, bestMask)
|
|
669
427
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
428
|
+
// Write format info
|
|
429
|
+
const formatData = (ecl << 3) | bestMask
|
|
430
|
+
const formatBits = getBCHTypeInfo(formatData)
|
|
431
|
+
|
|
432
|
+
// Write format bits
|
|
433
|
+
for (let i = 0; i < 6; i++) mod[8][i] = ((formatBits >> i) & 1) === 1
|
|
434
|
+
mod[8][7] = ((formatBits >> 6) & 1) === 1
|
|
435
|
+
mod[8][8] = ((formatBits >> 7) & 1) === 1
|
|
436
|
+
mod[7][8] = ((formatBits >> 8) & 1) === 1
|
|
437
|
+
for (let i = 9; i < 15; i++) mod[14 - i][8] = ((formatBits >> i) & 1) === 1
|
|
438
|
+
|
|
439
|
+
for (let i = 0; i < 8; i++) mod[8][size - 1 - i] = ((formatBits >> i) & 1) === 1
|
|
440
|
+
for (let i = 8; i < 15; i++) mod[size - 15 + i][8] = ((formatBits >> i) & 1) === 1
|
|
441
|
+
|
|
442
|
+
// Convert to boolean matrix
|
|
443
|
+
const result: boolean[][] = []
|
|
444
|
+
for (let r = 0; r < size; r++) {
|
|
445
|
+
result[r] = []
|
|
446
|
+
for (let c = 0; c < size; c++) {
|
|
447
|
+
result[r][c] = mod[r][c] === true
|
|
677
448
|
}
|
|
678
449
|
}
|
|
679
450
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
451
|
+
return { modules: result, moduleCount: size }
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Map data to modules
|
|
455
|
+
function mapData(mod: (boolean | null)[][], size: number, data: number[], maskPattern: number) {
|
|
456
|
+
const maskFunc = getMaskFunction(maskPattern)
|
|
457
|
+
let bitIndex = 0
|
|
458
|
+
let inc = -1
|
|
459
|
+
let row = size - 1
|
|
460
|
+
|
|
461
|
+
for (let col = size - 1; col > 0; col -= 2) {
|
|
462
|
+
if (col === 6) col = 5
|
|
463
|
+
|
|
464
|
+
while (true) {
|
|
465
|
+
for (let c = 0; c < 2; c++) {
|
|
466
|
+
const tc = col - c
|
|
467
|
+
if (mod[row][tc] === null) {
|
|
468
|
+
let dark = false
|
|
469
|
+
if (bitIndex < data.length * 8) {
|
|
470
|
+
dark = ((data[Math.floor(bitIndex / 8)] >>> (7 - (bitIndex % 8))) & 1) === 1
|
|
695
471
|
}
|
|
472
|
+
if (maskFunc(row, tc)) dark = !dark
|
|
473
|
+
mod[row][tc] = dark
|
|
474
|
+
bitIndex++
|
|
696
475
|
}
|
|
697
|
-
if (sameCount > 5) lostPoint += 3 + sameCount - 5
|
|
698
476
|
}
|
|
699
|
-
}
|
|
700
477
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
if (this.modules[row + 1][col]) count++
|
|
707
|
-
if (this.modules[row][col + 1]) count++
|
|
708
|
-
if (this.modules[row + 1][col + 1]) count++
|
|
709
|
-
if (count === 0 || count === 4) lostPoint += 3
|
|
478
|
+
row += inc
|
|
479
|
+
if (row < 0 || row >= size) {
|
|
480
|
+
row -= inc
|
|
481
|
+
inc = -inc
|
|
482
|
+
break
|
|
710
483
|
}
|
|
711
484
|
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
712
487
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
if (
|
|
717
|
-
this.modules[row][col] &&
|
|
718
|
-
!this.modules[row][col + 1] &&
|
|
719
|
-
this.modules[row][col + 2] &&
|
|
720
|
-
this.modules[row][col + 3] &&
|
|
721
|
-
this.modules[row][col + 4] &&
|
|
722
|
-
!this.modules[row][col + 5] &&
|
|
723
|
-
this.modules[row][col + 6]
|
|
724
|
-
) {
|
|
725
|
-
lostPoint += 40
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
for (let col = 0; col < this.moduleCount; col++) {
|
|
730
|
-
for (let row = 0; row < this.moduleCount - 6; row++) {
|
|
731
|
-
if (
|
|
732
|
-
this.modules[row][col] &&
|
|
733
|
-
!this.modules[row + 1][col] &&
|
|
734
|
-
this.modules[row + 2][col] &&
|
|
735
|
-
this.modules[row + 3][col] &&
|
|
736
|
-
this.modules[row + 4][col] &&
|
|
737
|
-
!this.modules[row + 5][col] &&
|
|
738
|
-
this.modules[row + 6][col]
|
|
739
|
-
) {
|
|
740
|
-
lostPoint += 40
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
}
|
|
488
|
+
// Calculate penalty score
|
|
489
|
+
function calculatePenalty(mod: (boolean | null)[][], size: number): number {
|
|
490
|
+
let penalty = 0
|
|
744
491
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
492
|
+
// Rule 1: Adjacent modules in row/column
|
|
493
|
+
for (let row = 0; row < size; row++) {
|
|
494
|
+
let count = 1
|
|
495
|
+
for (let col = 1; col < size; col++) {
|
|
496
|
+
if (mod[row][col] === mod[row][col - 1]) {
|
|
497
|
+
count++
|
|
498
|
+
} else {
|
|
499
|
+
if (count >= 5) penalty += 3 + (count - 5)
|
|
500
|
+
count = 1
|
|
750
501
|
}
|
|
751
502
|
}
|
|
752
|
-
|
|
753
|
-
lostPoint += ratio * 10
|
|
754
|
-
|
|
755
|
-
return lostPoint
|
|
503
|
+
if (count >= 5) penalty += 3 + (count - 5)
|
|
756
504
|
}
|
|
757
505
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
506
|
+
for (let col = 0; col < size; col++) {
|
|
507
|
+
let count = 1
|
|
508
|
+
for (let row = 1; row < size; row++) {
|
|
509
|
+
if (mod[row][col] === mod[row - 1][col]) {
|
|
510
|
+
count++
|
|
511
|
+
} else {
|
|
512
|
+
if (count >= 5) penalty += 3 + (count - 5)
|
|
513
|
+
count = 1
|
|
514
|
+
}
|
|
765
515
|
}
|
|
766
|
-
|
|
516
|
+
if (count >= 5) penalty += 3 + (count - 5)
|
|
767
517
|
}
|
|
518
|
+
|
|
519
|
+
return penalty
|
|
768
520
|
}
|
|
769
521
|
|
|
770
522
|
// Generate QR code
|
|
@@ -776,22 +528,9 @@ const generate = () => {
|
|
|
776
528
|
}
|
|
777
529
|
|
|
778
530
|
try {
|
|
779
|
-
const qr =
|
|
780
|
-
qr.
|
|
781
|
-
qr.
|
|
782
|
-
|
|
783
|
-
const count = qr.getModuleCount()
|
|
784
|
-
moduleCount.value = count
|
|
785
|
-
|
|
786
|
-
const result: boolean[][] = []
|
|
787
|
-
for (let row = 0; row < count; row++) {
|
|
788
|
-
result[row] = []
|
|
789
|
-
for (let col = 0; col < count; col++) {
|
|
790
|
-
result[row][col] = qr.isDark(row, col)
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
modules.value = result
|
|
531
|
+
const qr = generateQRCode(props.value, props.errorCorrectLevel)
|
|
532
|
+
modules.value = qr.modules
|
|
533
|
+
moduleCount.value = qr.moduleCount
|
|
795
534
|
} catch (e) {
|
|
796
535
|
console.error('QR Code generation failed:', e)
|
|
797
536
|
modules.value = []
|