@vkontakte/vk-qr 2.0.13 → 3.0.0
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/LICENSE +1 -1
- package/README.md +3 -3
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1135 -0
- package/dist/index.js.map +1 -0
- package/dist/{types/qr.d.ts → qr.d.ts} +79 -87
- package/dist/qr.d.ts.map +1 -0
- package/dist/svg.d.ts +10 -0
- package/dist/svg.d.ts.map +1 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +55 -77
- package/src/index.ts +39 -26
- package/src/qr.ts +217 -179
- package/src/svg.ts +30 -14
- package/src/types.ts +19 -10
- package/dist/cjs/index.js +0 -1184
- package/dist/es/index.js +0 -1182
- package/dist/types/index.d.ts +0 -20
- package/dist/types/svg.d.ts +0 -8
- package/dist/types/types.d.ts +0 -47
- package/dist/umd/qrCodeGenerator.js +0 -1190
- package/dist/umd/qrCodeGenerator.min.js +0 -1
package/dist/index.js
ADDED
|
@@ -0,0 +1,1135 @@
|
|
|
1
|
+
import { _ as _define_property__ } from "@swc/helpers/_/_define_property";
|
|
2
|
+
const MULTI = 1;
|
|
3
|
+
const QR_BORDER = 7;
|
|
4
|
+
const TILE_SIZE = 96 * MULTI;
|
|
5
|
+
const SMALL_QR_SIZE = 25;
|
|
6
|
+
const getPixel = (x, y, size, modules, isLogoShowed)=>{
|
|
7
|
+
if (x < QR_BORDER && y < QR_BORDER) return false;
|
|
8
|
+
if (x >= size - QR_BORDER && y < QR_BORDER) return false;
|
|
9
|
+
if (x < QR_BORDER && y >= size - QR_BORDER) return false;
|
|
10
|
+
if (isLogoShowed) {
|
|
11
|
+
let imageTiles = QR_BORDER + 2;
|
|
12
|
+
if (size <= SMALL_QR_SIZE) imageTiles--;
|
|
13
|
+
let paddingTiles = (size - 2 * QR_BORDER - imageTiles) / 2 - 1;
|
|
14
|
+
if (size <= SMALL_QR_SIZE) paddingTiles++;
|
|
15
|
+
if (x > QR_BORDER + paddingTiles && x < size - QR_BORDER - paddingTiles - 1 && y > QR_BORDER + paddingTiles && y < size - QR_BORDER - paddingTiles - 1) return false;
|
|
16
|
+
return 0 <= x && x < size && 0 <= y && y < size && modules[y][x];
|
|
17
|
+
}
|
|
18
|
+
return modules[y]?.[x];
|
|
19
|
+
};
|
|
20
|
+
const getNeighbors = (x, y, size, modules, isLogoShowed = true)=>({
|
|
21
|
+
l: getPixel(x - 1, y, size, modules, isLogoShowed),
|
|
22
|
+
r: getPixel(x + 1, y, size, modules, isLogoShowed),
|
|
23
|
+
t: getPixel(x, y - 1, size, modules, isLogoShowed),
|
|
24
|
+
b: getPixel(x, y + 1, size, modules, isLogoShowed),
|
|
25
|
+
current: getPixel(x, y, size, modules, isLogoShowed)
|
|
26
|
+
});
|
|
27
|
+
const convertSegmentsToSvgString = (qrCode, options)=>{
|
|
28
|
+
if ('number' != typeof options.qrSize) throw new Error('Size should be a number');
|
|
29
|
+
if ('string' != typeof options.className) throw new Error('Classname should be a string');
|
|
30
|
+
const _2 = 2 * MULTI;
|
|
31
|
+
const _12_7 = 12.7 * MULTI;
|
|
32
|
+
const _12_8 = 12.8 * MULTI;
|
|
33
|
+
const _14_7 = 14.7 * MULTI;
|
|
34
|
+
const _14_8 = 14.8 * MULTI;
|
|
35
|
+
const _15_9 = 15.9 * MULTI;
|
|
36
|
+
const _28_6 = 28.6 * MULTI;
|
|
37
|
+
const _30_5 = 30.5 * MULTI;
|
|
38
|
+
const _84_7 = 84.7776815 * MULTI;
|
|
39
|
+
const _87_3 = 87.3 * MULTI;
|
|
40
|
+
const _71_4 = 71.4 * MULTI;
|
|
41
|
+
const _42_9 = 42.9 * MULTI;
|
|
42
|
+
const _87_2 = 87.2 * MULTI;
|
|
43
|
+
const _85_2 = 85.2 * MULTI;
|
|
44
|
+
const _85_3 = 85.3 * MULTI;
|
|
45
|
+
const _69_5 = 69.5 * MULTI;
|
|
46
|
+
const _98 = 98 * MULTI;
|
|
47
|
+
const _100 = 100 * MULTI;
|
|
48
|
+
const parts = [];
|
|
49
|
+
let leftPadding = 0;
|
|
50
|
+
let topPadding = 0;
|
|
51
|
+
let xCoord = 0;
|
|
52
|
+
let yCoord = 0;
|
|
53
|
+
for(let y = 0; y < qrCode.size; y++){
|
|
54
|
+
leftPadding = 0;
|
|
55
|
+
for(let x = 0; x < qrCode.size; x++){
|
|
56
|
+
xCoord = x + leftPadding;
|
|
57
|
+
leftPadding += TILE_SIZE;
|
|
58
|
+
yCoord = y + topPadding;
|
|
59
|
+
const neighbors = getNeighbors(x, y, qrCode.size, qrCode.modules, options.isShowLogo);
|
|
60
|
+
let path = '';
|
|
61
|
+
let selector = '';
|
|
62
|
+
if (neighbors.current) {
|
|
63
|
+
selector = selector || neighbors.l || neighbors.r || neighbors.t || neighbors.b ? '' : 'empty';
|
|
64
|
+
selector = !selector && neighbors.l && neighbors.r || neighbors.t && neighbors.b ? 'rect' : '';
|
|
65
|
+
if (!selector) {
|
|
66
|
+
selector += neighbors.l ? 'l' : neighbors.r ? 'r' : '';
|
|
67
|
+
selector += neighbors.t ? 't' : neighbors.b ? 'b' : '';
|
|
68
|
+
if (!selector) selector = 'empty';
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
selector = !selector && neighbors.l && neighbors.t && getPixel(x - 1, y - 1, qrCode.size, qrCode.modules, options.isShowLogo) ? 'n_lt' : '';
|
|
72
|
+
selector = !selector && neighbors.l && neighbors.b && getPixel(x - 1, y + 1, qrCode.size, qrCode.modules, options.isShowLogo) ? 'n_lb' : '';
|
|
73
|
+
selector = !selector && neighbors.r && neighbors.t && getPixel(x + 1, y - 1, qrCode.size, qrCode.modules, options.isShowLogo) ? 'n_rt' : '';
|
|
74
|
+
selector = !selector && neighbors.r && neighbors.b && getPixel(x + 1, y + 1, qrCode.size, qrCode.modules, options.isShowLogo) ? 'n_rb' : '';
|
|
75
|
+
}
|
|
76
|
+
if (selector) {
|
|
77
|
+
path = `<use xlink:href="#${selector}-${options.suffix}"/>`;
|
|
78
|
+
parts.push(`<g transform="translate(${xCoord},${yCoord})">${path}</g>`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
topPadding += TILE_SIZE;
|
|
82
|
+
}
|
|
83
|
+
let scale = '';
|
|
84
|
+
let position = (qrCode.size - 3 * QR_BORDER) / 2 * TILE_SIZE + TILE_SIZE * QR_BORDER - 10;
|
|
85
|
+
if (qrCode.size <= SMALL_QR_SIZE) {
|
|
86
|
+
scale = 'scale(0.85)';
|
|
87
|
+
position += 50;
|
|
88
|
+
}
|
|
89
|
+
const pointPosition = (qrCode.size - QR_BORDER) * options.incTileSize;
|
|
90
|
+
parts.push(`<use fill-rule="evenodd" transform="translate(0,0)" xlink:href="#point-${options.suffix}"/>`);
|
|
91
|
+
parts.push(`<use fill-rule="evenodd" transform="translate(${pointPosition},0)" xlink:href="#point-${options.suffix}"/>`);
|
|
92
|
+
parts.push(`<use fill-rule="evenodd" transform="translate(0,${pointPosition})" xlink:href="#point-${options.suffix}"/>`);
|
|
93
|
+
if (options.isShowLogo) if (options.logoData) parts.push(`
|
|
94
|
+
<image
|
|
95
|
+
preserveAspectRatio="xMidYMid slice" clip-path="url(#logo-mask-${options.suffix})"
|
|
96
|
+
style="width: 750px; height: 750px;" width="750" height="750"
|
|
97
|
+
transform="translate(${position},${position}) ${scale}"
|
|
98
|
+
xlink:href="${options.logoData}"
|
|
99
|
+
/>
|
|
100
|
+
`);
|
|
101
|
+
else parts.push(`
|
|
102
|
+
<use style="width: 750px; height: 750px;" width="750" height="750"
|
|
103
|
+
fill="none"
|
|
104
|
+
fill-rule="evenodd"
|
|
105
|
+
transform="translate(${position},${position}) ${scale}" xlink:href="#vk_logo-${options.suffix}"
|
|
106
|
+
/>
|
|
107
|
+
`);
|
|
108
|
+
const backgroundSize = 99 * qrCode.size;
|
|
109
|
+
let qrBackground = '';
|
|
110
|
+
let qrTransform = 'translate(0,0)';
|
|
111
|
+
if (options.isShowBackground) {
|
|
112
|
+
const qrScale = (options.qrSize - 40) / options.qrSize;
|
|
113
|
+
const padding = backgroundSize / options.qrSize * 21;
|
|
114
|
+
const radius = Math.ceil(backgroundSize / (options.qrSize / 36));
|
|
115
|
+
qrBackground = `
|
|
116
|
+
<rect
|
|
117
|
+
x="0"
|
|
118
|
+
width="${backgroundSize}"
|
|
119
|
+
height="${backgroundSize}"
|
|
120
|
+
rx="${radius}"
|
|
121
|
+
fill="${options.backgroundColor}"
|
|
122
|
+
/>`;
|
|
123
|
+
qrTransform = `translate(${padding}, ${padding}) scale(${qrScale})`;
|
|
124
|
+
}
|
|
125
|
+
const oneSide = `M0,0 L66,0 C${_84_7},-3.44940413e-15 ${_100},15.2223185 ${_100},34 L${_100},66 C${_100},${_84_7} \
|
|
126
|
+
${_84_7},${_100} 66,${_100} L0,${_100} L0,0 Z`;
|
|
127
|
+
const twoSides = `M0,0 L${_100},0 L${_100},66 C${_100},${_84_7} ${_84_7},${_100} 66,${_100} L0,${_100} L0,0 Z`;
|
|
128
|
+
return `
|
|
129
|
+
<svg
|
|
130
|
+
version="1.1"
|
|
131
|
+
viewBox="0 0 ${backgroundSize} ${backgroundSize}"
|
|
132
|
+
width="${options.qrSize}px"
|
|
133
|
+
height="${options.qrSize}px"
|
|
134
|
+
${options.className ? `class="${options.className}"` : ''}
|
|
135
|
+
xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
136
|
+
>
|
|
137
|
+
<defs>
|
|
138
|
+
<rect id="rect-${options.suffix}" width="100" height="100" fill="${options.foregroundColor}"/>
|
|
139
|
+
<path
|
|
140
|
+
id="empty-${options.suffix}"
|
|
141
|
+
d="M0,${_28_6}v${_42_9}C0,${_87_3},${_12_8},${_100},${_28_6},${_100}h${_42_9}c${_15_9},0,${_28_6}-${_12_8},\
|
|
142
|
+
${_28_6}-${_28_6}V${_28_6}C${_100},${_12_7},${_87_2},0,${_71_4},0H${_28_6} C${_12_8},0,0,${_12_8},0,${_28_6}z"
|
|
143
|
+
fill="${options.foregroundColor}"
|
|
144
|
+
/>
|
|
145
|
+
<path id="b-${options.suffix}" d="${oneSide}" transform="rotate(-90 50 50)" fill="${options.foregroundColor}"/>
|
|
146
|
+
<path id="r-${options.suffix}" d="${oneSide}" transform="rotate(-180 50 50)" fill="${options.foregroundColor}"/>
|
|
147
|
+
<path id="l-${options.suffix}" d="${oneSide}" fill="${options.foregroundColor}"/>
|
|
148
|
+
<path id="t-${options.suffix}" d="${oneSide}" transform="rotate(90 50 50)" fill="${options.foregroundColor}"/>
|
|
149
|
+
<path id="l-${options.suffix}" d="${twoSides}" transform="rotate(-90 50 50)" fill="${options.foregroundColor}"/>
|
|
150
|
+
<path id="lt-${options.suffix}" d="${twoSides}" fill="${options.foregroundColor}"/>
|
|
151
|
+
<path id="lb-${options.suffix}" d="${twoSides}" transform="rotate(-90 50 50)" fill="${options.foregroundColor}"/>
|
|
152
|
+
<path id="rb-${options.suffix}" d="${twoSides}" transform="rotate(-180 50 50)" fill="${options.foregroundColor}"/>
|
|
153
|
+
<path id="rt-${options.suffix}" d="${twoSides}" transform="rotate(90 50 50)" fill="${options.foregroundColor}"/>
|
|
154
|
+
<path
|
|
155
|
+
id="n_lt-${options.suffix}"
|
|
156
|
+
d="M${_30_5},${_2}V0H0v${_30_5}h${_2}C${_2},${_14_7},${_14_8},${_2},${_30_5},${_2}z"
|
|
157
|
+
fill="${options.foregroundColor}"
|
|
158
|
+
/>
|
|
159
|
+
<path
|
|
160
|
+
id="n_lb-${options.suffix}"
|
|
161
|
+
d="M${_2},${_69_5}H0V${_100}h${_30_5}v-${_2}C${_14_7},${_98},${_2},${_85_2},${_2},${_69_5}z"
|
|
162
|
+
fill="${options.foregroundColor}"
|
|
163
|
+
/>
|
|
164
|
+
<path
|
|
165
|
+
id="n_rt-${options.suffix}"
|
|
166
|
+
d="M${_98},${_30_5}h${_2}V0H${_69_5}v${_2}C${_85_3},${_2},${_98},${_14_8},${_98},${_30_5}z"
|
|
167
|
+
fill="${options.foregroundColor}"
|
|
168
|
+
/>
|
|
169
|
+
<path id="n_rb-${options.suffix}"
|
|
170
|
+
d="M${_69_5},${_98}v${_2}H${_100}V${_69_5}h-${_2}C${_98},${_85_3},${_85_2},${_98},${_69_5},${_98}z"
|
|
171
|
+
fill="${options.foregroundColor}"
|
|
172
|
+
/>
|
|
173
|
+
<path
|
|
174
|
+
id="point-${options.suffix}"
|
|
175
|
+
fill="${options.foregroundColor}"
|
|
176
|
+
d="M600.001786,457.329333 L600.001786,242.658167 C600.001786,147.372368 587.039517,124.122784 \
|
|
177
|
+
581.464617,118.535383 C575.877216,112.960483 552.627632,99.9982143 457.329333,99.9982143 \
|
|
178
|
+
L242.670667,99.9982143 C147.372368,99.9982143 124.122784,112.960483 118.547883,118.535383 \
|
|
179
|
+
C112.972983,124.122784 99.9982143,147.372368 99.9982143,242.658167 L99.9982143,457.329333 \
|
|
180
|
+
C99.9982143,552.627632 112.972983,575.877216 118.547883,581.464617 C124.122784,587.027017 \
|
|
181
|
+
147.372368,600.001786 242.670667,600.001786 L457.329333,600.001786 C552.627632,600.001786 \
|
|
182
|
+
575.877216,587.027017 581.464617,581.464617 C587.039517,575.877216 600.001786,552.627632 \
|
|
183
|
+
600.001786,457.329333 Z M457.329333,0 C653.338333,0 700,46.6616668 700,242.658167 C700,438.667167 \
|
|
184
|
+
700,261.332833 700,457.329333 C700,653.338333 653.338333,700 457.329333,700 C261.332833,700 438.667167,700 \
|
|
185
|
+
242.670667,700 C46.6616668,700 0,653.338333 0,457.329333 C0,261.332833 0,352.118712 0,242.658167 \
|
|
186
|
+
C0,46.6616668 46.6616668,0 242.670667,0 C438.667167,0 261.332833,0 457.329333,0 Z M395.996667,200 \
|
|
187
|
+
C480.004166,200 500,220.008332 500,303.990835 C500,387.998334 500,312.001666 500,395.996667 \
|
|
188
|
+
C500,479.991668 480.004166,500 395.996667,500 C312.001666,500 387.998334,500 304.003333,500 C220.008332,500 \
|
|
189
|
+
200,479.991668 200,395.996667 C200,312.001666 200,350.906061 200,303.990835 C200,220.008332 220.008332,200 \
|
|
190
|
+
304.003333,200 C387.998334,200 312.001666,200 395.996667,200 Z"
|
|
191
|
+
/>
|
|
192
|
+
<g id="vk_logo-${options.suffix}">
|
|
193
|
+
<path
|
|
194
|
+
fill="${options.logoColor}"
|
|
195
|
+
d="M83.3334 363.333C83.3334 231.34 83.3334 165.343 124.338 124.338C165.343 83.3333 231.34 \
|
|
196
|
+
83.3333 363.333 83.3333H386.667C518.66 83.3333 584.657 83.3333 625.662 124.338C666.667 165.343 \
|
|
197
|
+
666.667 231.34 666.667 363.333V386.667C666.667 518.66 666.667 584.657 625.662 625.662C584.657 \
|
|
198
|
+
666.667 518.66 666.667 386.667 666.667H363.333C231.34 666.667 165.343 666.667 124.338 625.662C83.3334 \
|
|
199
|
+
584.657 83.3334 518.66 83.3334 386.667V363.333Z"
|
|
200
|
+
/>
|
|
201
|
+
<path
|
|
202
|
+
fill="#FFF"
|
|
203
|
+
d="M394.907 508.681C263.293 508.681 183.442 417.365 180.313 265.625H246.972C249.05 377.09 \
|
|
204
|
+
299.763 424.323 338.638 434.036V265.625H402.519V361.82C440.016 357.664 479.264 313.909 \
|
|
205
|
+
492.456 265.625H555.333C545.27 325 502.543 368.754 472.353 386.803C502.566 401.395 551.177 \
|
|
206
|
+
439.593 569.926 508.681H500.815C486.222 462.498 450.476 426.728 402.542 421.872V508.681H394.907Z"
|
|
207
|
+
/>
|
|
208
|
+
</g>
|
|
209
|
+
<clipPath id="logo-mask-${options.suffix}">
|
|
210
|
+
<rect x="0" y="0" width="750" height="750" />
|
|
211
|
+
</clipPath>
|
|
212
|
+
</defs>
|
|
213
|
+
|
|
214
|
+
${qrBackground}
|
|
215
|
+
|
|
216
|
+
<g transform="${qrTransform}">
|
|
217
|
+
${parts.join('\n')}
|
|
218
|
+
</g>
|
|
219
|
+
</svg>`;
|
|
220
|
+
};
|
|
221
|
+
class QrCode {
|
|
222
|
+
static encodeText(text, ecl) {
|
|
223
|
+
const segs = QrSegment.makeSegments(text);
|
|
224
|
+
return QrCode.encodeSegments(segs, ecl);
|
|
225
|
+
}
|
|
226
|
+
static encodeBinary(data, ecl) {
|
|
227
|
+
const seg = QrSegment.makeBytes(data);
|
|
228
|
+
return QrCode.encodeSegments([
|
|
229
|
+
seg
|
|
230
|
+
], ecl);
|
|
231
|
+
}
|
|
232
|
+
static encodeSegments(segs, ecl, minVersion = 1, maxVersion = 40, mask = -1, boostEcl = true) {
|
|
233
|
+
if (!(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION) || mask < -1 || mask > 7) throw 'Invalid value';
|
|
234
|
+
let version;
|
|
235
|
+
let dataUsedBits;
|
|
236
|
+
for(version = minVersion;; version++){
|
|
237
|
+
const dataCapacityBits = 8 * QrCode.getNumDataCodewords(version, ecl);
|
|
238
|
+
const usedBits = QrSegment.getTotalBits(segs, version);
|
|
239
|
+
if (usedBits <= dataCapacityBits) {
|
|
240
|
+
dataUsedBits = usedBits;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
if (version >= maxVersion) throw 'Data too long';
|
|
244
|
+
}
|
|
245
|
+
for (const newEcl of [
|
|
246
|
+
QrCodeEcc.MEDIUM,
|
|
247
|
+
QrCodeEcc.QUARTILE,
|
|
248
|
+
QrCodeEcc.HIGH
|
|
249
|
+
])if (boostEcl && dataUsedBits <= 8 * QrCode.getNumDataCodewords(version, newEcl)) ecl = newEcl;
|
|
250
|
+
const bb = new BitBuffer();
|
|
251
|
+
for (const seg of segs){
|
|
252
|
+
bb.appendBits(seg.mode.modeBits, 4);
|
|
253
|
+
bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
|
|
254
|
+
for (const b of seg.getData())bb.array.push(b);
|
|
255
|
+
}
|
|
256
|
+
if (bb.array.length !== dataUsedBits) throw 'Assertion error';
|
|
257
|
+
const dataCapacityBits = 8 * QrCode.getNumDataCodewords(version, ecl);
|
|
258
|
+
if (bb.array.length > dataCapacityBits) throw 'Assertion error';
|
|
259
|
+
bb.appendBits(0, Math.min(4, dataCapacityBits - bb.array.length));
|
|
260
|
+
bb.appendBits(0, (8 - bb.array.length % 8) % 8);
|
|
261
|
+
if (bb.array.length % 8 !== 0) throw 'Assertion error';
|
|
262
|
+
for(let padByte = 0xec; bb.array.length < dataCapacityBits; padByte ^= 253)bb.appendBits(padByte, 8);
|
|
263
|
+
const dataCodewords = [];
|
|
264
|
+
while(8 * dataCodewords.length < bb.array.length)dataCodewords.push(0);
|
|
265
|
+
bb.array.forEach((b, i)=>{
|
|
266
|
+
dataCodewords[i >>> 3] |= b << 7 - (7 & i);
|
|
267
|
+
});
|
|
268
|
+
return new QrCode(version, ecl, dataCodewords, mask);
|
|
269
|
+
}
|
|
270
|
+
getModule(x, y) {
|
|
271
|
+
return 0 <= x && x < this.size && 0 <= y && y < this.size && this.modules[y][x];
|
|
272
|
+
}
|
|
273
|
+
toSvgString(border) {
|
|
274
|
+
if (border < 0) throw 'Border must be non-negative';
|
|
275
|
+
const parts = [];
|
|
276
|
+
for(let y = 0; y < this.size; y++)for(let x = 0; x < this.size; x++)if (this.getModule(x, y)) parts.push(`M${x + border},${y + border}h1v1h-1z`);
|
|
277
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
278
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
279
|
+
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 ${this.size + 2 * border} ${this.size + 2 * border}" stroke="none">
|
|
280
|
+
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
|
281
|
+
<path d="${parts.join(' ')}" fill="#000000"/>
|
|
282
|
+
</svg>
|
|
283
|
+
`;
|
|
284
|
+
}
|
|
285
|
+
drawFunctionPatterns() {
|
|
286
|
+
for(let i = 0; i < this.size; i++){
|
|
287
|
+
this.setFunctionModule(6, i, i % 2 === 0);
|
|
288
|
+
this.setFunctionModule(i, 6, i % 2 === 0);
|
|
289
|
+
}
|
|
290
|
+
this.drawFinderPattern(3, 3);
|
|
291
|
+
this.drawFinderPattern(this.size - 4, 3);
|
|
292
|
+
this.drawFinderPattern(3, this.size - 4);
|
|
293
|
+
const alignPatPos = this.getAlignmentPatternPositions();
|
|
294
|
+
const numAlign = alignPatPos.length;
|
|
295
|
+
for(let i = 0; i < numAlign; i++)for(let j = 0; j < numAlign; j++)if (!(0 === i && 0 === j || 0 === i && j === numAlign - 1 || i === numAlign - 1 && 0 === j)) this.drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
|
|
296
|
+
this.drawFormatBits(0);
|
|
297
|
+
this.drawVersion();
|
|
298
|
+
}
|
|
299
|
+
drawFormatBits(mask) {
|
|
300
|
+
const data = this.errorCorrectionLevel.formatBits << 3 | mask;
|
|
301
|
+
let rem = data;
|
|
302
|
+
for(let i = 0; i < 10; i++)rem = rem << 1 ^ (rem >>> 9) * 0x537;
|
|
303
|
+
const bits = (data << 10 | rem) ^ 0x5412;
|
|
304
|
+
if (bits >>> 15 !== 0) throw 'Assertion error';
|
|
305
|
+
for(let i = 0; i <= 5; i++)this.setFunctionModule(8, i, getBit(bits, i));
|
|
306
|
+
this.setFunctionModule(8, 7, getBit(bits, 6));
|
|
307
|
+
this.setFunctionModule(8, 8, getBit(bits, 7));
|
|
308
|
+
this.setFunctionModule(7, 8, getBit(bits, 8));
|
|
309
|
+
for(let i = 9; i < 15; i++)this.setFunctionModule(14 - i, 8, getBit(bits, i));
|
|
310
|
+
for(let i = 0; i < 8; i++)this.setFunctionModule(this.size - 1 - i, 8, getBit(bits, i));
|
|
311
|
+
for(let i = 8; i < 15; i++)this.setFunctionModule(8, this.size - 15 + i, getBit(bits, i));
|
|
312
|
+
this.setFunctionModule(8, this.size - 8, true);
|
|
313
|
+
}
|
|
314
|
+
drawVersion() {
|
|
315
|
+
if (this.version < 7) return;
|
|
316
|
+
let rem = this.version;
|
|
317
|
+
for(let i = 0; i < 12; i++)rem = rem << 1 ^ (rem >>> 11) * 0x1f25;
|
|
318
|
+
const bits = this.version << 12 | rem;
|
|
319
|
+
if (bits >>> 18 !== 0) throw 'Assertion error';
|
|
320
|
+
for(let i = 0; i < 18; i++){
|
|
321
|
+
const color = getBit(bits, i);
|
|
322
|
+
const a = this.size - 11 + i % 3;
|
|
323
|
+
const b = Math.floor(i / 3);
|
|
324
|
+
this.setFunctionModule(a, b, color);
|
|
325
|
+
this.setFunctionModule(b, a, color);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
drawFinderPattern(x, y) {
|
|
329
|
+
for(let dy = -4; dy <= 4; dy++)for(let dx = -4; dx <= 4; dx++){
|
|
330
|
+
const dist = Math.max(Math.abs(dx), Math.abs(dy));
|
|
331
|
+
const xx = x + dx;
|
|
332
|
+
const yy = y + dy;
|
|
333
|
+
if (0 <= xx && xx < this.size && 0 <= yy && yy < this.size) this.setFunctionModule(xx, yy, 2 !== dist && 4 !== dist);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
drawAlignmentPattern(x, y) {
|
|
337
|
+
for(let dy = -2; dy <= 2; dy++)for(let dx = -2; dx <= 2; dx++)this.setFunctionModule(x + dx, y + dy, 1 !== Math.max(Math.abs(dx), Math.abs(dy)));
|
|
338
|
+
}
|
|
339
|
+
setFunctionModule(x, y, isBlack) {
|
|
340
|
+
this.modules[y][x] = isBlack;
|
|
341
|
+
this.isFunction[y][x] = true;
|
|
342
|
+
}
|
|
343
|
+
addEccAndInterleave(data) {
|
|
344
|
+
const ver = this.version;
|
|
345
|
+
const ecl = this.errorCorrectionLevel;
|
|
346
|
+
if (data.length !== QrCode.getNumDataCodewords(ver, ecl)) throw 'Invalid argument';
|
|
347
|
+
const numBlocks = QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
|
|
348
|
+
const blockEccLen = QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver];
|
|
349
|
+
const rawCodewords = Math.floor(QrCode.getNumRawDataModules(ver) / 8);
|
|
350
|
+
const numShortBlocks = numBlocks - rawCodewords % numBlocks;
|
|
351
|
+
const shortBlockLen = Math.floor(rawCodewords / numBlocks);
|
|
352
|
+
const blocks = [];
|
|
353
|
+
const rs = new ReedSolomonGenerator(blockEccLen);
|
|
354
|
+
for(let i = 0, k = 0; i < numBlocks; i++){
|
|
355
|
+
const dat = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
|
|
356
|
+
k += dat.length;
|
|
357
|
+
const ecc = rs.getRemainder(dat);
|
|
358
|
+
if (i < numShortBlocks) dat.push(0);
|
|
359
|
+
blocks.push(dat.concat(ecc));
|
|
360
|
+
}
|
|
361
|
+
const result = [];
|
|
362
|
+
for(let i = 0; i < blocks[0].length; i++)for(let j = 0; j < blocks.length; j++)if (i !== shortBlockLen - blockEccLen || j >= numShortBlocks) result.push(blocks[j][i]);
|
|
363
|
+
if (result.length !== rawCodewords) throw 'Assertion error';
|
|
364
|
+
return result;
|
|
365
|
+
}
|
|
366
|
+
drawCodewords(data) {
|
|
367
|
+
if (data.length !== Math.floor(QrCode.getNumRawDataModules(this.version) / 8)) throw 'Invalid argument';
|
|
368
|
+
let i = 0;
|
|
369
|
+
for(let right = this.size - 1; right >= 1; right -= 2){
|
|
370
|
+
if (6 === right) right = 5;
|
|
371
|
+
for(let vert = 0; vert < this.size; vert++)for(let j = 0; j < 2; j++){
|
|
372
|
+
const x = right - j;
|
|
373
|
+
const upward = (right + 1 & 2) === 0;
|
|
374
|
+
const y = upward ? this.size - 1 - vert : vert;
|
|
375
|
+
if (!this.isFunction[y][x] && i < 8 * data.length) {
|
|
376
|
+
this.modules[y][x] = getBit(data[i >>> 3], 7 - (7 & i));
|
|
377
|
+
i++;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (i !== 8 * data.length) throw 'Assertion error';
|
|
382
|
+
}
|
|
383
|
+
applyMask(mask) {
|
|
384
|
+
if (mask < 0 || mask > 7) throw 'Mask value out of range';
|
|
385
|
+
for(let y = 0; y < this.size; y++)for(let x = 0; x < this.size; x++){
|
|
386
|
+
let invert;
|
|
387
|
+
switch(mask){
|
|
388
|
+
case 0:
|
|
389
|
+
invert = (x + y) % 2 === 0;
|
|
390
|
+
break;
|
|
391
|
+
case 1:
|
|
392
|
+
invert = y % 2 === 0;
|
|
393
|
+
break;
|
|
394
|
+
case 2:
|
|
395
|
+
invert = x % 3 === 0;
|
|
396
|
+
break;
|
|
397
|
+
case 3:
|
|
398
|
+
invert = (x + y) % 3 === 0;
|
|
399
|
+
break;
|
|
400
|
+
case 4:
|
|
401
|
+
invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0;
|
|
402
|
+
break;
|
|
403
|
+
case 5:
|
|
404
|
+
invert = x * y % 2 + x * y % 3 === 0;
|
|
405
|
+
break;
|
|
406
|
+
case 6:
|
|
407
|
+
invert = (x * y % 2 + x * y % 3) % 2 === 0;
|
|
408
|
+
break;
|
|
409
|
+
case 7:
|
|
410
|
+
invert = ((x + y) % 2 + x * y % 3) % 2 === 0;
|
|
411
|
+
break;
|
|
412
|
+
default:
|
|
413
|
+
throw 'Assertion error';
|
|
414
|
+
}
|
|
415
|
+
if (!this.isFunction[y][x] && invert) this.modules[y][x] = !this.modules[y][x];
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
getPenaltyScore() {
|
|
419
|
+
let result = 0;
|
|
420
|
+
for(let y = 0; y < this.size; y++){
|
|
421
|
+
const runHistory = [
|
|
422
|
+
0,
|
|
423
|
+
0,
|
|
424
|
+
0,
|
|
425
|
+
0,
|
|
426
|
+
0,
|
|
427
|
+
0,
|
|
428
|
+
0
|
|
429
|
+
];
|
|
430
|
+
let color = false;
|
|
431
|
+
let runX = 0;
|
|
432
|
+
for(let x = 0; x < this.size; x++)if (this.modules[y][x] === color) {
|
|
433
|
+
runX++;
|
|
434
|
+
if (5 === runX) result += QrCode.PENALTY_N1;
|
|
435
|
+
else if (runX > 5) result++;
|
|
436
|
+
} else {
|
|
437
|
+
QrCode.addRunToHistory(runX, runHistory);
|
|
438
|
+
if (!color && QrCode.hasFinderLikePattern(runHistory)) result += QrCode.PENALTY_N3;
|
|
439
|
+
color = this.modules[y][x];
|
|
440
|
+
runX = 1;
|
|
441
|
+
}
|
|
442
|
+
QrCode.addRunToHistory(runX, runHistory);
|
|
443
|
+
if (color) QrCode.addRunToHistory(0, runHistory);
|
|
444
|
+
if (QrCode.hasFinderLikePattern(runHistory)) result += QrCode.PENALTY_N3;
|
|
445
|
+
}
|
|
446
|
+
for(let x = 0; x < this.size; x++){
|
|
447
|
+
const runHistory = [
|
|
448
|
+
0,
|
|
449
|
+
0,
|
|
450
|
+
0,
|
|
451
|
+
0,
|
|
452
|
+
0,
|
|
453
|
+
0,
|
|
454
|
+
0
|
|
455
|
+
];
|
|
456
|
+
let color = false;
|
|
457
|
+
let runY = 0;
|
|
458
|
+
for(let y = 0; y < this.size; y++)if (this.modules[y][x] === color) {
|
|
459
|
+
runY++;
|
|
460
|
+
if (5 === runY) result += QrCode.PENALTY_N1;
|
|
461
|
+
else if (runY > 5) result++;
|
|
462
|
+
} else {
|
|
463
|
+
QrCode.addRunToHistory(runY, runHistory);
|
|
464
|
+
if (!color && QrCode.hasFinderLikePattern(runHistory)) result += QrCode.PENALTY_N3;
|
|
465
|
+
color = this.modules[y][x];
|
|
466
|
+
runY = 1;
|
|
467
|
+
}
|
|
468
|
+
QrCode.addRunToHistory(runY, runHistory);
|
|
469
|
+
if (color) QrCode.addRunToHistory(0, runHistory);
|
|
470
|
+
if (QrCode.hasFinderLikePattern(runHistory)) result += QrCode.PENALTY_N3;
|
|
471
|
+
}
|
|
472
|
+
for(let y = 0; y < this.size - 1; y++)for(let x = 0; x < this.size - 1; x++){
|
|
473
|
+
const color = this.modules[y][x];
|
|
474
|
+
if (color === this.modules[y][x + 1] && color === this.modules[y + 1][x] && color === this.modules[y + 1][x + 1]) result += QrCode.PENALTY_N2;
|
|
475
|
+
}
|
|
476
|
+
let black = 0;
|
|
477
|
+
for (const row of this.modules)for (const color of row)if (color) black++;
|
|
478
|
+
const total = this.size * this.size;
|
|
479
|
+
const k = Math.ceil(Math.abs(20 * black - 10 * total) / total) - 1;
|
|
480
|
+
result += k * QrCode.PENALTY_N4;
|
|
481
|
+
return result;
|
|
482
|
+
}
|
|
483
|
+
getAlignmentPatternPositions() {
|
|
484
|
+
if (1 === this.version) return [];
|
|
485
|
+
{
|
|
486
|
+
const numAlign = Math.floor(this.version / 7) + 2;
|
|
487
|
+
const step = 32 === this.version ? 26 : 2 * Math.ceil((this.size - 13) / (2 * numAlign - 2));
|
|
488
|
+
const result = [
|
|
489
|
+
6
|
|
490
|
+
];
|
|
491
|
+
for(let pos = this.size - 7; result.length < numAlign; pos -= step)result.splice(1, 0, pos);
|
|
492
|
+
return result;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
static getNumRawDataModules(ver) {
|
|
496
|
+
if (ver < QrCode.MIN_VERSION || ver > QrCode.MAX_VERSION) throw 'Version number out of range';
|
|
497
|
+
let result = (16 * ver + 128) * ver + 64;
|
|
498
|
+
if (ver >= 2) {
|
|
499
|
+
const numAlign = Math.floor(ver / 7) + 2;
|
|
500
|
+
result -= (25 * numAlign - 10) * numAlign - 55;
|
|
501
|
+
if (ver >= 7) result -= 36;
|
|
502
|
+
}
|
|
503
|
+
return result;
|
|
504
|
+
}
|
|
505
|
+
static getNumDataCodewords(ver, ecl) {
|
|
506
|
+
return Math.floor(QrCode.getNumRawDataModules(ver) / 8) - QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] * QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
|
|
507
|
+
}
|
|
508
|
+
static addRunToHistory(run, history) {
|
|
509
|
+
history.pop();
|
|
510
|
+
history.unshift(run);
|
|
511
|
+
}
|
|
512
|
+
static hasFinderLikePattern(runHistory) {
|
|
513
|
+
const n = runHistory[1];
|
|
514
|
+
return n > 0 && runHistory[2] === n && runHistory[4] === n && runHistory[5] === n && runHistory[3] === 3 * n && Math.max(runHistory[0], runHistory[6]) >= 4 * n;
|
|
515
|
+
}
|
|
516
|
+
constructor(version, errorCorrectionLevel, dataCodewords, mask){
|
|
517
|
+
_define_property__(this, "size", void 0);
|
|
518
|
+
_define_property__(this, "modules", []);
|
|
519
|
+
_define_property__(this, "isFunction", []);
|
|
520
|
+
_define_property__(this, "version", void 0);
|
|
521
|
+
_define_property__(this, "errorCorrectionLevel", void 0);
|
|
522
|
+
_define_property__(this, "mask", void 0);
|
|
523
|
+
if (version < QrCode.MIN_VERSION || version > QrCode.MAX_VERSION) throw 'Version value out of range';
|
|
524
|
+
if (mask < -1 || mask > 7) throw 'Mask value out of range';
|
|
525
|
+
this.version = version;
|
|
526
|
+
this.errorCorrectionLevel = errorCorrectionLevel;
|
|
527
|
+
this.size = 4 * version + 17;
|
|
528
|
+
const row = [];
|
|
529
|
+
for(let i = 0; i < this.size; i++)row.push(false);
|
|
530
|
+
for(let i = 0; i < this.size; i++){
|
|
531
|
+
this.modules.push(row.slice());
|
|
532
|
+
this.isFunction.push(row.slice());
|
|
533
|
+
}
|
|
534
|
+
this.drawFunctionPatterns();
|
|
535
|
+
const allCodewords = this.addEccAndInterleave(dataCodewords);
|
|
536
|
+
this.drawCodewords(allCodewords);
|
|
537
|
+
if (-1 === mask) {
|
|
538
|
+
let minPenalty = 1000000000;
|
|
539
|
+
for(let i = 0; i < 8; i++){
|
|
540
|
+
this.applyMask(i);
|
|
541
|
+
this.drawFormatBits(i);
|
|
542
|
+
const penalty = this.getPenaltyScore();
|
|
543
|
+
if (penalty < minPenalty) {
|
|
544
|
+
mask = i;
|
|
545
|
+
minPenalty = penalty;
|
|
546
|
+
}
|
|
547
|
+
this.applyMask(i);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (mask < 0 || mask > 7) throw 'Assertion error';
|
|
551
|
+
this.mask = mask;
|
|
552
|
+
this.applyMask(mask);
|
|
553
|
+
this.drawFormatBits(mask);
|
|
554
|
+
this.isFunction = [];
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
_define_property__(QrCode, "MIN_VERSION", 1);
|
|
558
|
+
_define_property__(QrCode, "MAX_VERSION", 40);
|
|
559
|
+
_define_property__(QrCode, "PENALTY_N1", 3);
|
|
560
|
+
_define_property__(QrCode, "PENALTY_N2", 3);
|
|
561
|
+
_define_property__(QrCode, "PENALTY_N3", 40);
|
|
562
|
+
_define_property__(QrCode, "PENALTY_N4", 10);
|
|
563
|
+
_define_property__(QrCode, "ECC_CODEWORDS_PER_BLOCK", [
|
|
564
|
+
[
|
|
565
|
+
-1,
|
|
566
|
+
7,
|
|
567
|
+
10,
|
|
568
|
+
15,
|
|
569
|
+
20,
|
|
570
|
+
26,
|
|
571
|
+
18,
|
|
572
|
+
20,
|
|
573
|
+
24,
|
|
574
|
+
30,
|
|
575
|
+
18,
|
|
576
|
+
20,
|
|
577
|
+
24,
|
|
578
|
+
26,
|
|
579
|
+
30,
|
|
580
|
+
22,
|
|
581
|
+
24,
|
|
582
|
+
28,
|
|
583
|
+
30,
|
|
584
|
+
28,
|
|
585
|
+
28,
|
|
586
|
+
28,
|
|
587
|
+
28,
|
|
588
|
+
30,
|
|
589
|
+
30,
|
|
590
|
+
26,
|
|
591
|
+
28,
|
|
592
|
+
30,
|
|
593
|
+
30,
|
|
594
|
+
30,
|
|
595
|
+
30,
|
|
596
|
+
30,
|
|
597
|
+
30,
|
|
598
|
+
30,
|
|
599
|
+
30,
|
|
600
|
+
30,
|
|
601
|
+
30,
|
|
602
|
+
30,
|
|
603
|
+
30,
|
|
604
|
+
30,
|
|
605
|
+
30
|
|
606
|
+
],
|
|
607
|
+
[
|
|
608
|
+
-1,
|
|
609
|
+
10,
|
|
610
|
+
16,
|
|
611
|
+
26,
|
|
612
|
+
18,
|
|
613
|
+
24,
|
|
614
|
+
16,
|
|
615
|
+
18,
|
|
616
|
+
22,
|
|
617
|
+
22,
|
|
618
|
+
26,
|
|
619
|
+
30,
|
|
620
|
+
22,
|
|
621
|
+
22,
|
|
622
|
+
24,
|
|
623
|
+
24,
|
|
624
|
+
28,
|
|
625
|
+
28,
|
|
626
|
+
26,
|
|
627
|
+
26,
|
|
628
|
+
26,
|
|
629
|
+
26,
|
|
630
|
+
28,
|
|
631
|
+
28,
|
|
632
|
+
28,
|
|
633
|
+
28,
|
|
634
|
+
28,
|
|
635
|
+
28,
|
|
636
|
+
28,
|
|
637
|
+
28,
|
|
638
|
+
28,
|
|
639
|
+
28,
|
|
640
|
+
28,
|
|
641
|
+
28,
|
|
642
|
+
28,
|
|
643
|
+
28,
|
|
644
|
+
28,
|
|
645
|
+
28,
|
|
646
|
+
28,
|
|
647
|
+
28,
|
|
648
|
+
28
|
|
649
|
+
],
|
|
650
|
+
[
|
|
651
|
+
-1,
|
|
652
|
+
13,
|
|
653
|
+
22,
|
|
654
|
+
18,
|
|
655
|
+
26,
|
|
656
|
+
18,
|
|
657
|
+
24,
|
|
658
|
+
18,
|
|
659
|
+
22,
|
|
660
|
+
20,
|
|
661
|
+
24,
|
|
662
|
+
28,
|
|
663
|
+
26,
|
|
664
|
+
24,
|
|
665
|
+
20,
|
|
666
|
+
30,
|
|
667
|
+
24,
|
|
668
|
+
28,
|
|
669
|
+
28,
|
|
670
|
+
26,
|
|
671
|
+
30,
|
|
672
|
+
28,
|
|
673
|
+
30,
|
|
674
|
+
30,
|
|
675
|
+
30,
|
|
676
|
+
30,
|
|
677
|
+
28,
|
|
678
|
+
30,
|
|
679
|
+
30,
|
|
680
|
+
30,
|
|
681
|
+
30,
|
|
682
|
+
30,
|
|
683
|
+
30,
|
|
684
|
+
30,
|
|
685
|
+
30,
|
|
686
|
+
30,
|
|
687
|
+
30,
|
|
688
|
+
30,
|
|
689
|
+
30,
|
|
690
|
+
30,
|
|
691
|
+
30
|
|
692
|
+
],
|
|
693
|
+
[
|
|
694
|
+
-1,
|
|
695
|
+
17,
|
|
696
|
+
28,
|
|
697
|
+
22,
|
|
698
|
+
16,
|
|
699
|
+
22,
|
|
700
|
+
28,
|
|
701
|
+
26,
|
|
702
|
+
26,
|
|
703
|
+
24,
|
|
704
|
+
28,
|
|
705
|
+
24,
|
|
706
|
+
28,
|
|
707
|
+
22,
|
|
708
|
+
24,
|
|
709
|
+
24,
|
|
710
|
+
30,
|
|
711
|
+
28,
|
|
712
|
+
28,
|
|
713
|
+
26,
|
|
714
|
+
28,
|
|
715
|
+
30,
|
|
716
|
+
24,
|
|
717
|
+
30,
|
|
718
|
+
30,
|
|
719
|
+
30,
|
|
720
|
+
30,
|
|
721
|
+
30,
|
|
722
|
+
30,
|
|
723
|
+
30,
|
|
724
|
+
30,
|
|
725
|
+
30,
|
|
726
|
+
30,
|
|
727
|
+
30,
|
|
728
|
+
30,
|
|
729
|
+
30,
|
|
730
|
+
30,
|
|
731
|
+
30,
|
|
732
|
+
30,
|
|
733
|
+
30,
|
|
734
|
+
30
|
|
735
|
+
]
|
|
736
|
+
]);
|
|
737
|
+
_define_property__(QrCode, "NUM_ERROR_CORRECTION_BLOCKS", [
|
|
738
|
+
[
|
|
739
|
+
-1,
|
|
740
|
+
1,
|
|
741
|
+
1,
|
|
742
|
+
1,
|
|
743
|
+
1,
|
|
744
|
+
1,
|
|
745
|
+
2,
|
|
746
|
+
2,
|
|
747
|
+
2,
|
|
748
|
+
2,
|
|
749
|
+
4,
|
|
750
|
+
4,
|
|
751
|
+
4,
|
|
752
|
+
4,
|
|
753
|
+
4,
|
|
754
|
+
6,
|
|
755
|
+
6,
|
|
756
|
+
6,
|
|
757
|
+
6,
|
|
758
|
+
7,
|
|
759
|
+
8,
|
|
760
|
+
8,
|
|
761
|
+
9,
|
|
762
|
+
9,
|
|
763
|
+
10,
|
|
764
|
+
12,
|
|
765
|
+
12,
|
|
766
|
+
12,
|
|
767
|
+
13,
|
|
768
|
+
14,
|
|
769
|
+
15,
|
|
770
|
+
16,
|
|
771
|
+
17,
|
|
772
|
+
18,
|
|
773
|
+
19,
|
|
774
|
+
19,
|
|
775
|
+
20,
|
|
776
|
+
21,
|
|
777
|
+
22,
|
|
778
|
+
24,
|
|
779
|
+
25
|
|
780
|
+
],
|
|
781
|
+
[
|
|
782
|
+
-1,
|
|
783
|
+
1,
|
|
784
|
+
1,
|
|
785
|
+
1,
|
|
786
|
+
2,
|
|
787
|
+
2,
|
|
788
|
+
4,
|
|
789
|
+
4,
|
|
790
|
+
4,
|
|
791
|
+
5,
|
|
792
|
+
5,
|
|
793
|
+
5,
|
|
794
|
+
8,
|
|
795
|
+
9,
|
|
796
|
+
9,
|
|
797
|
+
10,
|
|
798
|
+
10,
|
|
799
|
+
11,
|
|
800
|
+
13,
|
|
801
|
+
14,
|
|
802
|
+
16,
|
|
803
|
+
17,
|
|
804
|
+
17,
|
|
805
|
+
18,
|
|
806
|
+
20,
|
|
807
|
+
21,
|
|
808
|
+
23,
|
|
809
|
+
25,
|
|
810
|
+
26,
|
|
811
|
+
28,
|
|
812
|
+
29,
|
|
813
|
+
31,
|
|
814
|
+
33,
|
|
815
|
+
35,
|
|
816
|
+
37,
|
|
817
|
+
38,
|
|
818
|
+
40,
|
|
819
|
+
43,
|
|
820
|
+
45,
|
|
821
|
+
47,
|
|
822
|
+
49
|
|
823
|
+
],
|
|
824
|
+
[
|
|
825
|
+
-1,
|
|
826
|
+
1,
|
|
827
|
+
1,
|
|
828
|
+
2,
|
|
829
|
+
2,
|
|
830
|
+
4,
|
|
831
|
+
4,
|
|
832
|
+
6,
|
|
833
|
+
6,
|
|
834
|
+
8,
|
|
835
|
+
8,
|
|
836
|
+
8,
|
|
837
|
+
10,
|
|
838
|
+
12,
|
|
839
|
+
16,
|
|
840
|
+
12,
|
|
841
|
+
17,
|
|
842
|
+
16,
|
|
843
|
+
18,
|
|
844
|
+
21,
|
|
845
|
+
20,
|
|
846
|
+
23,
|
|
847
|
+
23,
|
|
848
|
+
25,
|
|
849
|
+
27,
|
|
850
|
+
29,
|
|
851
|
+
34,
|
|
852
|
+
34,
|
|
853
|
+
35,
|
|
854
|
+
38,
|
|
855
|
+
40,
|
|
856
|
+
43,
|
|
857
|
+
45,
|
|
858
|
+
48,
|
|
859
|
+
51,
|
|
860
|
+
53,
|
|
861
|
+
56,
|
|
862
|
+
59,
|
|
863
|
+
62,
|
|
864
|
+
65,
|
|
865
|
+
68
|
|
866
|
+
],
|
|
867
|
+
[
|
|
868
|
+
-1,
|
|
869
|
+
1,
|
|
870
|
+
1,
|
|
871
|
+
2,
|
|
872
|
+
4,
|
|
873
|
+
4,
|
|
874
|
+
4,
|
|
875
|
+
5,
|
|
876
|
+
6,
|
|
877
|
+
8,
|
|
878
|
+
8,
|
|
879
|
+
11,
|
|
880
|
+
11,
|
|
881
|
+
16,
|
|
882
|
+
16,
|
|
883
|
+
18,
|
|
884
|
+
16,
|
|
885
|
+
19,
|
|
886
|
+
21,
|
|
887
|
+
25,
|
|
888
|
+
25,
|
|
889
|
+
25,
|
|
890
|
+
34,
|
|
891
|
+
30,
|
|
892
|
+
32,
|
|
893
|
+
35,
|
|
894
|
+
37,
|
|
895
|
+
40,
|
|
896
|
+
42,
|
|
897
|
+
45,
|
|
898
|
+
48,
|
|
899
|
+
51,
|
|
900
|
+
54,
|
|
901
|
+
57,
|
|
902
|
+
60,
|
|
903
|
+
63,
|
|
904
|
+
66,
|
|
905
|
+
70,
|
|
906
|
+
74,
|
|
907
|
+
77,
|
|
908
|
+
81
|
|
909
|
+
]
|
|
910
|
+
]);
|
|
911
|
+
function getBit(x, i) {
|
|
912
|
+
return (x >>> i & 1) !== 0;
|
|
913
|
+
}
|
|
914
|
+
class QrSegment {
|
|
915
|
+
static makeBytes(data) {
|
|
916
|
+
const bb = new BitBuffer();
|
|
917
|
+
for (const b of data)bb.appendBits(b, 8);
|
|
918
|
+
return new QrSegment(QrSegmentMode.BYTE, data.length, bb.array);
|
|
919
|
+
}
|
|
920
|
+
static makeNumeric(digits) {
|
|
921
|
+
if (!QrSegment.NUMERIC_REGEX.test(digits)) throw 'String contains non-numeric characters';
|
|
922
|
+
const bb = new BitBuffer();
|
|
923
|
+
for(let i = 0; i < digits.length;){
|
|
924
|
+
const n = Math.min(digits.length - i, 3);
|
|
925
|
+
bb.appendBits(parseInt(digits.substr(i, n), 10), 3 * n + 1);
|
|
926
|
+
i += n;
|
|
927
|
+
}
|
|
928
|
+
return new QrSegment(QrSegmentMode.NUMERIC, digits.length, bb.array);
|
|
929
|
+
}
|
|
930
|
+
static makeAlphanumeric(text) {
|
|
931
|
+
if (!QrSegment.ALPHANUMERIC_REGEX.test(text)) throw 'String contains unencodable characters in alphanumeric mode';
|
|
932
|
+
const bb = new BitBuffer();
|
|
933
|
+
let i;
|
|
934
|
+
for(i = 0; i + 2 <= text.length; i += 2){
|
|
935
|
+
let temp = 45 * QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i));
|
|
936
|
+
temp += QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));
|
|
937
|
+
bb.appendBits(temp, 11);
|
|
938
|
+
}
|
|
939
|
+
if (i < text.length) bb.appendBits(QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6);
|
|
940
|
+
return new QrSegment(QrSegmentMode.ALPHANUMERIC, text.length, bb.array);
|
|
941
|
+
}
|
|
942
|
+
static makeSegments(text) {
|
|
943
|
+
if ('' === text) return [];
|
|
944
|
+
if (QrSegment.NUMERIC_REGEX.test(text)) return [
|
|
945
|
+
QrSegment.makeNumeric(text)
|
|
946
|
+
];
|
|
947
|
+
if (QrSegment.ALPHANUMERIC_REGEX.test(text)) return [
|
|
948
|
+
QrSegment.makeAlphanumeric(text)
|
|
949
|
+
];
|
|
950
|
+
return [
|
|
951
|
+
QrSegment.makeBytes(QrSegment.toUtf8ByteArray(text))
|
|
952
|
+
];
|
|
953
|
+
}
|
|
954
|
+
static makeEci(assignVal) {
|
|
955
|
+
const bb = new BitBuffer();
|
|
956
|
+
if (assignVal < 0) throw 'ECI assignment value out of range';
|
|
957
|
+
if (assignVal < 128) bb.appendBits(assignVal, 8);
|
|
958
|
+
else if (assignVal < 16384) {
|
|
959
|
+
bb.appendBits(2, 2);
|
|
960
|
+
bb.appendBits(assignVal, 14);
|
|
961
|
+
} else if (assignVal < 1000000) {
|
|
962
|
+
bb.appendBits(6, 3);
|
|
963
|
+
bb.appendBits(assignVal, 21);
|
|
964
|
+
} else throw 'ECI assignment value out of range';
|
|
965
|
+
return new QrSegment(QrSegmentMode.ECI, 0, bb.array);
|
|
966
|
+
}
|
|
967
|
+
getData() {
|
|
968
|
+
return this.bitData.slice();
|
|
969
|
+
}
|
|
970
|
+
static getTotalBits(segs, version) {
|
|
971
|
+
let result = 0;
|
|
972
|
+
for (const seg of segs){
|
|
973
|
+
const ccbits = seg.mode.numCharCountBits(version);
|
|
974
|
+
if (seg.numChars >= 1 << ccbits) return 1 / 0;
|
|
975
|
+
result += 4 + ccbits + seg.bitData.length;
|
|
976
|
+
}
|
|
977
|
+
return result;
|
|
978
|
+
}
|
|
979
|
+
static toUtf8ByteArray(str) {
|
|
980
|
+
str = encodeURI(str);
|
|
981
|
+
const result = [];
|
|
982
|
+
for(let i = 0; i < str.length; i++)if ('%' !== str.charAt(i)) result.push(str.charCodeAt(i));
|
|
983
|
+
else {
|
|
984
|
+
result.push(parseInt(str.substr(i + 1, 2), 16));
|
|
985
|
+
i += 2;
|
|
986
|
+
}
|
|
987
|
+
return result;
|
|
988
|
+
}
|
|
989
|
+
constructor(mode, numChars, bitData){
|
|
990
|
+
_define_property__(this, "mode", void 0);
|
|
991
|
+
_define_property__(this, "numChars", void 0);
|
|
992
|
+
_define_property__(this, "bitData", void 0);
|
|
993
|
+
if (numChars < 0) throw 'Invalid argument';
|
|
994
|
+
this.mode = mode;
|
|
995
|
+
this.numChars = numChars;
|
|
996
|
+
this.bitData = bitData.slice();
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
_define_property__(QrSegment, "NUMERIC_REGEX", /^[0-9]*$/);
|
|
1000
|
+
_define_property__(QrSegment, "ALPHANUMERIC_REGEX", /^[A-Z0-9 $%*+./:-]*$/);
|
|
1001
|
+
_define_property__(QrSegment, "ALPHANUMERIC_CHARSET", '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:');
|
|
1002
|
+
class ReedSolomonGenerator {
|
|
1003
|
+
getRemainder(data) {
|
|
1004
|
+
const result = this.coefficients.map((_)=>0);
|
|
1005
|
+
for (const b of data){
|
|
1006
|
+
const factor = b ^ result.shift();
|
|
1007
|
+
result.push(0);
|
|
1008
|
+
this.coefficients.forEach((coef, i)=>{
|
|
1009
|
+
result[i] ^= ReedSolomonGenerator.multiply(coef, factor);
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
return result;
|
|
1013
|
+
}
|
|
1014
|
+
static multiply(x, y) {
|
|
1015
|
+
if (x >>> 8 !== 0 || y >>> 8 !== 0) throw 'Byte out of range';
|
|
1016
|
+
let z = 0;
|
|
1017
|
+
for(let i = 7; i >= 0; i--){
|
|
1018
|
+
z = z << 1 ^ (z >>> 7) * 0x11d;
|
|
1019
|
+
z ^= (y >>> i & 1) * x;
|
|
1020
|
+
}
|
|
1021
|
+
if (z >>> 8 !== 0) throw 'Assertion error';
|
|
1022
|
+
return z;
|
|
1023
|
+
}
|
|
1024
|
+
constructor(degree){
|
|
1025
|
+
_define_property__(this, "coefficients", []);
|
|
1026
|
+
if (degree < 1 || degree > 255) throw 'Degree out of range';
|
|
1027
|
+
const coefs = this.coefficients;
|
|
1028
|
+
for(let i = 0; i < degree - 1; i++)coefs.push(0);
|
|
1029
|
+
coefs.push(1);
|
|
1030
|
+
let root = 1;
|
|
1031
|
+
for(let i = 0; i < degree; i++){
|
|
1032
|
+
for(let j = 0; j < coefs.length; j++){
|
|
1033
|
+
coefs[j] = ReedSolomonGenerator.multiply(coefs[j], root);
|
|
1034
|
+
if (j + 1 < coefs.length) coefs[j] ^= coefs[j + 1];
|
|
1035
|
+
}
|
|
1036
|
+
root = ReedSolomonGenerator.multiply(root, 0x02);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
class BitBuffer {
|
|
1041
|
+
appendBits(val, len) {
|
|
1042
|
+
if (len < 0 || len > 31 || val >>> len !== 0) throw 'Value out of range';
|
|
1043
|
+
for(let i = len - 1; i >= 0; i--)this.array.push(val >>> i & 1);
|
|
1044
|
+
}
|
|
1045
|
+
constructor(){
|
|
1046
|
+
_define_property__(this, "array", []);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
class QrCodeEcc {
|
|
1050
|
+
constructor(ordinal, formatBits){
|
|
1051
|
+
_define_property__(this, "ordinal", void 0);
|
|
1052
|
+
_define_property__(this, "formatBits", void 0);
|
|
1053
|
+
this.ordinal = ordinal;
|
|
1054
|
+
this.formatBits = formatBits;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
_define_property__(QrCodeEcc, "LOW", new QrCodeEcc(0, 1));
|
|
1058
|
+
_define_property__(QrCodeEcc, "MEDIUM", new QrCodeEcc(1, 0));
|
|
1059
|
+
_define_property__(QrCodeEcc, "QUARTILE", new QrCodeEcc(2, 3));
|
|
1060
|
+
_define_property__(QrCodeEcc, "HIGH", new QrCodeEcc(3, 2));
|
|
1061
|
+
class QrSegmentMode {
|
|
1062
|
+
numCharCountBits(ver) {
|
|
1063
|
+
return this.numBitsCharCount[Math.floor((ver + 7) / 17)];
|
|
1064
|
+
}
|
|
1065
|
+
constructor(modeBits, numBitsCharCount){
|
|
1066
|
+
_define_property__(this, "modeBits", void 0);
|
|
1067
|
+
_define_property__(this, "numBitsCharCount", void 0);
|
|
1068
|
+
this.modeBits = modeBits;
|
|
1069
|
+
this.numBitsCharCount = numBitsCharCount;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
_define_property__(QrSegmentMode, "NUMERIC", new QrSegmentMode(0x1, [
|
|
1073
|
+
10,
|
|
1074
|
+
12,
|
|
1075
|
+
14
|
|
1076
|
+
]));
|
|
1077
|
+
_define_property__(QrSegmentMode, "ALPHANUMERIC", new QrSegmentMode(0x2, [
|
|
1078
|
+
9,
|
|
1079
|
+
11,
|
|
1080
|
+
13
|
|
1081
|
+
]));
|
|
1082
|
+
_define_property__(QrSegmentMode, "BYTE", new QrSegmentMode(0x4, [
|
|
1083
|
+
8,
|
|
1084
|
+
16,
|
|
1085
|
+
16
|
|
1086
|
+
]));
|
|
1087
|
+
_define_property__(QrSegmentMode, "KANJI", new QrSegmentMode(0x8, [
|
|
1088
|
+
8,
|
|
1089
|
+
10,
|
|
1090
|
+
12
|
|
1091
|
+
]));
|
|
1092
|
+
_define_property__(QrSegmentMode, "ECI", new QrSegmentMode(0x7, [
|
|
1093
|
+
0,
|
|
1094
|
+
0,
|
|
1095
|
+
0
|
|
1096
|
+
]));
|
|
1097
|
+
const DEFAULT_SIZE = 128;
|
|
1098
|
+
const BACKGROUND_COLOR_DEFAULT = '#ffffff';
|
|
1099
|
+
const FOREGROUND_COLOR_DEFAULT = '#000000';
|
|
1100
|
+
const LOGO_COLOR_DEFAULT = '#07f';
|
|
1101
|
+
function createQR(text, qrSizeOrOptions, classNameLegacy, legacyOptions) {
|
|
1102
|
+
if ('string' != typeof text) throw new TypeError('Enter text for encoding');
|
|
1103
|
+
const options = {
|
|
1104
|
+
...'object' == typeof qrSizeOrOptions && null !== qrSizeOrOptions ? qrSizeOrOptions : {},
|
|
1105
|
+
...'object' == typeof legacyOptions && null !== legacyOptions ? legacyOptions : {},
|
|
1106
|
+
qrSize: 'object' == typeof qrSizeOrOptions && null !== qrSizeOrOptions && 'number' == typeof qrSizeOrOptions.qrSize ? qrSizeOrOptions.qrSize : qrSizeOrOptions,
|
|
1107
|
+
className: 'object' == typeof qrSizeOrOptions && null !== qrSizeOrOptions && 'string' == typeof qrSizeOrOptions.className ? qrSizeOrOptions.className : classNameLegacy
|
|
1108
|
+
};
|
|
1109
|
+
const eccLevels = [
|
|
1110
|
+
QrCodeEcc.LOW,
|
|
1111
|
+
QrCodeEcc.MEDIUM,
|
|
1112
|
+
QrCodeEcc.QUARTILE,
|
|
1113
|
+
QrCodeEcc.HIGH
|
|
1114
|
+
];
|
|
1115
|
+
const fallbackOptions = {
|
|
1116
|
+
qrSize: 'number' == typeof options.qrSize ? options.qrSize : DEFAULT_SIZE,
|
|
1117
|
+
className: 'string' == typeof options.className ? options.className : classNameLegacy || '',
|
|
1118
|
+
isShowLogo: !!options.isShowLogo || false,
|
|
1119
|
+
isShowBackground: !!options.isShowBackground || false,
|
|
1120
|
+
foregroundColor: 'string' == typeof options.foregroundColor ? options.foregroundColor : FOREGROUND_COLOR_DEFAULT,
|
|
1121
|
+
backgroundColor: 'string' == typeof options.backgroundColor ? options.backgroundColor : BACKGROUND_COLOR_DEFAULT,
|
|
1122
|
+
logoColor: 'string' == typeof options.logoColor ? options.logoColor : LOGO_COLOR_DEFAULT,
|
|
1123
|
+
suffix: options.suffix ? options.suffix.toString() : '0',
|
|
1124
|
+
logoData: 'string' == typeof options.logoData ? options.logoData : null,
|
|
1125
|
+
ecc: 'number' == typeof options.ecc && eccLevels[options.ecc] ? options.ecc : 3,
|
|
1126
|
+
incTileSize: 'number' == typeof options.incTileSize ? options.incTileSize : 96
|
|
1127
|
+
};
|
|
1128
|
+
const segments = QrSegment.makeSegments(text);
|
|
1129
|
+
const qrCode = QrCode.encodeSegments(segments, eccLevels[fallbackOptions.ecc], 1, 40, -1, true);
|
|
1130
|
+
const svgCode = convertSegmentsToSvgString(qrCode, fallbackOptions);
|
|
1131
|
+
return svgCode;
|
|
1132
|
+
}
|
|
1133
|
+
export { createQR };
|
|
1134
|
+
|
|
1135
|
+
//# sourceMappingURL=index.js.map
|