qr-core 1.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 +21 -0
- package/README.md +126 -0
- package/dist/bench/bench.d.ts +1 -0
- package/dist/bench/bench.js +38 -0
- package/dist/src/api/index.d.ts +9 -0
- package/dist/src/api/index.js +224 -0
- package/dist/src/core/bit-buffer.d.ts +11 -0
- package/dist/src/core/bit-buffer.js +53 -0
- package/dist/src/core/error.d.ts +8 -0
- package/dist/src/core/error.js +16 -0
- package/dist/src/core/gf.d.ts +4 -0
- package/dist/src/core/gf.js +52 -0
- package/dist/src/core/rs.d.ts +1 -0
- package/dist/src/core/rs.js +60 -0
- package/dist/src/encoding/bitstream.d.ts +7 -0
- package/dist/src/encoding/bitstream.js +68 -0
- package/dist/src/encoding/encoders.d.ts +13 -0
- package/dist/src/encoding/encoders.js +54 -0
- package/dist/src/encoding/interleave.d.ts +5 -0
- package/dist/src/encoding/interleave.js +49 -0
- package/dist/src/encoding/segmentation.d.ts +12 -0
- package/dist/src/encoding/segmentation.js +43 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +3 -0
- package/dist/src/layout/patterns.d.ts +12 -0
- package/dist/src/layout/patterns.js +120 -0
- package/dist/src/mapping/zigzag.d.ts +5 -0
- package/dist/src/mapping/zigzag.js +28 -0
- package/dist/src/mask/patterns.d.ts +6 -0
- package/dist/src/mask/patterns.js +13 -0
- package/dist/src/mask/penalty.d.ts +5 -0
- package/dist/src/mask/penalty.js +173 -0
- package/dist/src/mask/selection.d.ts +12 -0
- package/dist/src/mask/selection.js +178 -0
- package/dist/src/matrix/bit-matrix.d.ts +46 -0
- package/dist/src/matrix/bit-matrix.js +139 -0
- package/dist/src/spec/bch.d.ts +11 -0
- package/dist/src/spec/bch.js +30 -0
- package/dist/src/spec/constants.d.ts +40 -0
- package/dist/src/spec/constants.js +37 -0
- package/dist/src/spec/tables.d.ts +20 -0
- package/dist/src/spec/tables.js +1099 -0
- package/dist/src/strategies/index.d.ts +3 -0
- package/dist/src/strategies/index.js +3 -0
- package/dist/src/strategies/mask.d.ts +16 -0
- package/dist/src/strategies/mask.js +9 -0
- package/dist/src/strategies/segmentation.d.ts +12 -0
- package/dist/src/strategies/segmentation.js +41 -0
- package/dist/src/strategies/version.d.ts +12 -0
- package/dist/src/strategies/version.js +22 -0
- package/dist/src/types/index.d.ts +51 -0
- package/dist/src/types/index.js +1 -0
- package/dist/tests/golden/golden.test.d.ts +1 -0
- package/dist/tests/golden/golden.test.js +26 -0
- package/dist/tests/unit/api.test.d.ts +1 -0
- package/dist/tests/unit/api.test.js +35 -0
- package/dist/tests/unit/bit-matrix.test.d.ts +1 -0
- package/dist/tests/unit/bit-matrix.test.js +46 -0
- package/dist/tests/unit/core.test.d.ts +1 -0
- package/dist/tests/unit/core.test.js +88 -0
- package/dist/tests/unit/encoding.test.d.ts +1 -0
- package/dist/tests/unit/encoding.test.js +63 -0
- package/dist/tests/unit/layout.test.d.ts +1 -0
- package/dist/tests/unit/layout.test.js +62 -0
- package/dist/tests/unit/masking.test.d.ts +1 -0
- package/dist/tests/unit/masking.test.js +31 -0
- package/package.json +45 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { Matrix } from "../matrix/bit-matrix.js";
|
|
2
|
+
import { getFormatInfo } from "../spec/bch.js";
|
|
3
|
+
import { calculatePenalty } from "./penalty.js";
|
|
4
|
+
/**
|
|
5
|
+
* Evaluates all 8 masks and applies the one with the lowest penalty.
|
|
6
|
+
* Implements the deterministic tie-break (lowest ID).
|
|
7
|
+
*/
|
|
8
|
+
export function selectAndApplyBestMask(matrix, ecc) {
|
|
9
|
+
let minPenalty = Infinity;
|
|
10
|
+
let bestMask = 0;
|
|
11
|
+
const penalties = [];
|
|
12
|
+
// Pre-allocate work matrix to avoid garbage
|
|
13
|
+
const workMatrix = new Matrix(matrix.size);
|
|
14
|
+
for (let id = 0; id < 8; id++) {
|
|
15
|
+
const maskId = id;
|
|
16
|
+
// Reset work matrix
|
|
17
|
+
workMatrix._data.set(matrix._data);
|
|
18
|
+
const currentPenalty = evaluateMask(workMatrix, ecc, maskId);
|
|
19
|
+
penalties.push(currentPenalty);
|
|
20
|
+
if (currentPenalty < minPenalty) {
|
|
21
|
+
minPenalty = currentPenalty;
|
|
22
|
+
bestMask = maskId;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Final apply of the winner
|
|
26
|
+
applyMask(matrix, bestMask);
|
|
27
|
+
writeFormatInformation(matrix, ecc, bestMask);
|
|
28
|
+
return { mask: bestMask, penalties };
|
|
29
|
+
}
|
|
30
|
+
function evaluateMask(workMatrix, ecc, maskId) {
|
|
31
|
+
// workMatrix is already a copy/reset
|
|
32
|
+
applyMask(workMatrix, maskId);
|
|
33
|
+
writeFormatInformation(workMatrix, ecc, maskId);
|
|
34
|
+
return calculatePenalty(workMatrix);
|
|
35
|
+
}
|
|
36
|
+
export function applyMask(matrix, maskId) {
|
|
37
|
+
const size = matrix.size;
|
|
38
|
+
const data = matrix._data; // Direct access
|
|
39
|
+
switch (maskId) {
|
|
40
|
+
case 0:
|
|
41
|
+
for (let y = 0; y < size; y++) {
|
|
42
|
+
for (let x = 0; x < size; x++) {
|
|
43
|
+
const idx = y * size + x;
|
|
44
|
+
const val = data[idx] ?? 0;
|
|
45
|
+
if (!(val & 2)) {
|
|
46
|
+
if (((x + y) & 1) === 0)
|
|
47
|
+
data[idx] = val ^ 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case 1:
|
|
53
|
+
for (let y = 0; y < size; y++) {
|
|
54
|
+
for (let x = 0; x < size; x++) {
|
|
55
|
+
const idx = y * size + x;
|
|
56
|
+
const val = data[idx] ?? 0;
|
|
57
|
+
if (!(val & 2)) {
|
|
58
|
+
if ((y & 1) === 0)
|
|
59
|
+
data[idx] = val ^ 1;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
case 2:
|
|
65
|
+
for (let y = 0; y < size; y++) {
|
|
66
|
+
for (let x = 0; x < size; x++) {
|
|
67
|
+
const idx = y * size + x;
|
|
68
|
+
const val = data[idx] ?? 0;
|
|
69
|
+
if (!(val & 2)) {
|
|
70
|
+
if (x % 3 === 0)
|
|
71
|
+
data[idx] = val ^ 1;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
case 3:
|
|
77
|
+
for (let y = 0; y < size; y++) {
|
|
78
|
+
for (let x = 0; x < size; x++) {
|
|
79
|
+
const idx = y * size + x;
|
|
80
|
+
const val = data[idx] ?? 0;
|
|
81
|
+
if (!(val & 2)) {
|
|
82
|
+
if ((x + y) % 3 === 0)
|
|
83
|
+
data[idx] = val ^ 1;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
break;
|
|
88
|
+
case 4:
|
|
89
|
+
for (let y = 0; y < size; y++) {
|
|
90
|
+
for (let x = 0; x < size; x++) {
|
|
91
|
+
const idx = y * size + x;
|
|
92
|
+
const val = data[idx] ?? 0;
|
|
93
|
+
if (!(val & 2)) {
|
|
94
|
+
if ((((y >>> 1) + ((x / 3) | 0)) & 1) === 0)
|
|
95
|
+
data[idx] = val ^ 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
case 5:
|
|
101
|
+
for (let y = 0; y < size; y++) {
|
|
102
|
+
for (let x = 0; x < size; x++) {
|
|
103
|
+
const idx = y * size + x;
|
|
104
|
+
const val = data[idx] ?? 0;
|
|
105
|
+
if (!(val & 2)) {
|
|
106
|
+
const temp = x * y;
|
|
107
|
+
if ((temp & 1) + (temp % 3) === 0)
|
|
108
|
+
data[idx] = val ^ 1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
break;
|
|
113
|
+
case 6:
|
|
114
|
+
for (let y = 0; y < size; y++) {
|
|
115
|
+
for (let x = 0; x < size; x++) {
|
|
116
|
+
const idx = y * size + x;
|
|
117
|
+
const val = data[idx] ?? 0;
|
|
118
|
+
if (!(val & 2)) {
|
|
119
|
+
const temp = x * y;
|
|
120
|
+
if ((((temp & 1) + (temp % 3)) & 1) === 0)
|
|
121
|
+
data[idx] = val ^ 1;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
case 7:
|
|
127
|
+
for (let y = 0; y < size; y++) {
|
|
128
|
+
for (let x = 0; x < size; x++) {
|
|
129
|
+
const idx = y * size + x;
|
|
130
|
+
const val = data[idx] ?? 0;
|
|
131
|
+
if (!(val & 2)) {
|
|
132
|
+
if (((((x + y) & 1) + ((x * y) % 3)) & 1) === 0)
|
|
133
|
+
data[idx] = val ^ 1;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export function writeFormatInformation(matrix, ecc, maskId) {
|
|
141
|
+
const formatBits = getFormatInfo(ecc, maskId);
|
|
142
|
+
const size = matrix.size;
|
|
143
|
+
for (let i = 0; i < 15; i++) {
|
|
144
|
+
const bit = (formatBits >>> i) & 1;
|
|
145
|
+
// Top-left
|
|
146
|
+
let x;
|
|
147
|
+
let y;
|
|
148
|
+
if (i < 6) {
|
|
149
|
+
x = i;
|
|
150
|
+
y = 8;
|
|
151
|
+
}
|
|
152
|
+
else if (i < 8) {
|
|
153
|
+
x = i + 1;
|
|
154
|
+
y = 8;
|
|
155
|
+
}
|
|
156
|
+
else if (i === 8) {
|
|
157
|
+
x = 8;
|
|
158
|
+
y = 7;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
x = 8;
|
|
162
|
+
y = 14 - i;
|
|
163
|
+
}
|
|
164
|
+
matrix.setReserved(x, y, bit === 1);
|
|
165
|
+
// Split area
|
|
166
|
+
let x2;
|
|
167
|
+
let y2;
|
|
168
|
+
if (i < 8) {
|
|
169
|
+
x2 = 8;
|
|
170
|
+
y2 = size - 1 - i;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
x2 = size - 15 + i;
|
|
174
|
+
y2 = 8;
|
|
175
|
+
}
|
|
176
|
+
matrix.setReserved(x2, y2, bit === 1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QR Matris Yönetimi
|
|
3
|
+
*/
|
|
4
|
+
import type { BitMatrix } from "../types/index.js";
|
|
5
|
+
export declare class Matrix implements BitMatrix {
|
|
6
|
+
readonly size: number;
|
|
7
|
+
private data;
|
|
8
|
+
constructor(size: number);
|
|
9
|
+
/**
|
|
10
|
+
* Internal access to raw data for performance-critical operations (e.g. penalty calculation).
|
|
11
|
+
*/
|
|
12
|
+
get _data(): Uint8Array;
|
|
13
|
+
/**
|
|
14
|
+
* Hücrenin değerini döndürür (Sadece 0 veya 1)
|
|
15
|
+
*/
|
|
16
|
+
get(x: number, y: number): 0 | 1;
|
|
17
|
+
/**
|
|
18
|
+
* Hücrenin "Reserved" (ayrılmış) olup olmadığını kontrol eder
|
|
19
|
+
*/
|
|
20
|
+
isReserved(x: number, y: number): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Hücreyi ayarlar ve rezerve eder (Fonksiyonel desenler için)
|
|
23
|
+
*/
|
|
24
|
+
setReserved(x: number, y: number, isDark: boolean): void;
|
|
25
|
+
/**
|
|
26
|
+
* Sadece veri modülleri için (Ayrılmamış alanlara yazar)
|
|
27
|
+
*/
|
|
28
|
+
set(x: number, y: number, isDark: boolean): void;
|
|
29
|
+
/**
|
|
30
|
+
* RFC 5.2: Matrisi satırlar halinde döndürür
|
|
31
|
+
*/
|
|
32
|
+
toRows(): ReadonlyArray<Uint8Array>;
|
|
33
|
+
/**
|
|
34
|
+
* RFC 5.2: Matrisi paketlenmiş (MSB-first) bayt dizisi olarak döndürür
|
|
35
|
+
*/
|
|
36
|
+
toPacked(): Uint8Array;
|
|
37
|
+
clone(): Matrix;
|
|
38
|
+
}
|
|
39
|
+
export declare class ReadOnlyMatrix implements BitMatrix {
|
|
40
|
+
readonly size: number;
|
|
41
|
+
private readonly inner;
|
|
42
|
+
constructor(matrix: Matrix);
|
|
43
|
+
get(x: number, y: number): 0 | 1;
|
|
44
|
+
toRows(): ReadonlyArray<Uint8Array>;
|
|
45
|
+
toPacked(): Uint8Array;
|
|
46
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QR Matris Yönetimi
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Matris hücre durumları (Dahili kullanım)
|
|
6
|
+
*/
|
|
7
|
+
const STATUS = {
|
|
8
|
+
LIGHT: 0,
|
|
9
|
+
DARK: 1,
|
|
10
|
+
RESERVED_LIGHT: 2,
|
|
11
|
+
RESERVED_DARK: 3,
|
|
12
|
+
};
|
|
13
|
+
export class Matrix {
|
|
14
|
+
size;
|
|
15
|
+
data;
|
|
16
|
+
constructor(size) {
|
|
17
|
+
this.size = size;
|
|
18
|
+
// Varsayılan olarak tüm hücreler "light" (0)
|
|
19
|
+
this.data = new Uint8Array(size * size);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Internal access to raw data for performance-critical operations (e.g. penalty calculation).
|
|
23
|
+
*/
|
|
24
|
+
get _data() {
|
|
25
|
+
return this.data;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Hücrenin değerini döndürür (Sadece 0 veya 1)
|
|
29
|
+
*/
|
|
30
|
+
get(x, y) {
|
|
31
|
+
if (x < 0 || x >= this.size || y < 0 || y >= this.size) {
|
|
32
|
+
throw new Error(`Matrix access out of bounds: (${x},${y})`);
|
|
33
|
+
}
|
|
34
|
+
const idx = y * this.size + x;
|
|
35
|
+
const val = this.data[idx];
|
|
36
|
+
if (val === undefined) {
|
|
37
|
+
// Should be bounds checked or checked at call site, but defensive coding here:
|
|
38
|
+
throw new Error(`Matrix access out of bounds: (${x},${y})`);
|
|
39
|
+
}
|
|
40
|
+
return (val & 1);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Hücrenin "Reserved" (ayrılmış) olup olmadığını kontrol eder
|
|
44
|
+
*/
|
|
45
|
+
isReserved(x, y) {
|
|
46
|
+
if (x < 0 || x >= this.size || y < 0 || y >= this.size) {
|
|
47
|
+
throw new Error(`Matrix access out of bounds: (${x},${y})`);
|
|
48
|
+
}
|
|
49
|
+
const idx = y * this.size + x;
|
|
50
|
+
const val = this.data[idx];
|
|
51
|
+
if (val === undefined) {
|
|
52
|
+
throw new Error(`Matrix access out of bounds: (${x},${y})`);
|
|
53
|
+
}
|
|
54
|
+
return (val & 2) !== 0;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Hücreyi ayarlar ve rezerve eder (Fonksiyonel desenler için)
|
|
58
|
+
*/
|
|
59
|
+
setReserved(x, y, isDark) {
|
|
60
|
+
if (x < 0 || x >= this.size || y < 0 || y >= this.size) {
|
|
61
|
+
throw new Error(`Matrix access out of bounds: (${x},${y})`);
|
|
62
|
+
}
|
|
63
|
+
const idx = y * this.size + x;
|
|
64
|
+
if (idx < 0 || idx >= this.data.length) {
|
|
65
|
+
throw new Error(`Matrix access out of bounds: (${x},${y})`);
|
|
66
|
+
}
|
|
67
|
+
this.data[idx] = isDark ? STATUS.RESERVED_DARK : STATUS.RESERVED_LIGHT;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Sadece veri modülleri için (Ayrılmamış alanlara yazar)
|
|
71
|
+
*/
|
|
72
|
+
set(x, y, isDark) {
|
|
73
|
+
if (x < 0 || x >= this.size || y < 0 || y >= this.size) {
|
|
74
|
+
throw new Error(`Matrix access out of bounds: (${x},${y})`);
|
|
75
|
+
}
|
|
76
|
+
if (this.isReserved(x, y))
|
|
77
|
+
return;
|
|
78
|
+
const idx = y * this.size + x;
|
|
79
|
+
if (idx < 0 || idx >= this.data.length) {
|
|
80
|
+
// Double safety
|
|
81
|
+
throw new Error(`Matrix access out of bounds: (${x},${y})`);
|
|
82
|
+
}
|
|
83
|
+
this.data[idx] = isDark ? STATUS.DARK : STATUS.LIGHT;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* RFC 5.2: Matrisi satırlar halinde döndürür
|
|
87
|
+
*/
|
|
88
|
+
toRows() {
|
|
89
|
+
const rows = [];
|
|
90
|
+
for (let y = 0; y < this.size; y++) {
|
|
91
|
+
rows.push(this.data
|
|
92
|
+
.slice(y * this.size, (y + 1) * this.size)
|
|
93
|
+
.map((v) => (v & 1)));
|
|
94
|
+
}
|
|
95
|
+
return rows;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* RFC 5.2: Matrisi paketlenmiş (MSB-first) bayt dizisi olarak döndürür
|
|
99
|
+
*/
|
|
100
|
+
toPacked() {
|
|
101
|
+
const rowBytes = Math.ceil(this.size / 8);
|
|
102
|
+
const packed = new Uint8Array(rowBytes * this.size);
|
|
103
|
+
for (let y = 0; y < this.size; y++) {
|
|
104
|
+
for (let x = 0; x < this.size; x++) {
|
|
105
|
+
if (this.get(x, y)) {
|
|
106
|
+
const idx = y * rowBytes + (x >>> 3);
|
|
107
|
+
const current = packed[idx];
|
|
108
|
+
// safe access or initialized 0
|
|
109
|
+
if (current !== undefined) {
|
|
110
|
+
packed[idx] = current | (0x80 >>> (x & 7));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return packed;
|
|
116
|
+
}
|
|
117
|
+
clone() {
|
|
118
|
+
const copy = new Matrix(this.size);
|
|
119
|
+
copy.data.set(this.data);
|
|
120
|
+
return copy;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export class ReadOnlyMatrix {
|
|
124
|
+
size;
|
|
125
|
+
inner;
|
|
126
|
+
constructor(matrix) {
|
|
127
|
+
this.inner = matrix;
|
|
128
|
+
this.size = matrix.size;
|
|
129
|
+
}
|
|
130
|
+
get(x, y) {
|
|
131
|
+
return this.inner.get(x, y);
|
|
132
|
+
}
|
|
133
|
+
toRows() {
|
|
134
|
+
return this.inner.toRows();
|
|
135
|
+
}
|
|
136
|
+
toPacked() {
|
|
137
|
+
return this.inner.toPacked();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BCH (Bose-Chaudhuri-Hocquenghem) Error Correction for QR Metadata
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format Info BCH (15, 5)
|
|
6
|
+
*/
|
|
7
|
+
export declare function getFormatInfo(eccLevel: "L" | "M" | "Q" | "H", mask: number): number;
|
|
8
|
+
/**
|
|
9
|
+
* Version Info BCH (18, 6)
|
|
10
|
+
*/
|
|
11
|
+
export declare function getVersionInfo(version: number): number;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BCH (Bose-Chaudhuri-Hocquenghem) Error Correction for QR Metadata
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format Info BCH (15, 5)
|
|
6
|
+
*/
|
|
7
|
+
export function getFormatInfo(eccLevel, mask) {
|
|
8
|
+
const eccBits = { L: 1, M: 0, Q: 3, H: 2 };
|
|
9
|
+
const bits = eccBits[eccLevel];
|
|
10
|
+
if (bits === undefined)
|
|
11
|
+
throw new Error(`Invalid ecc level: ${eccLevel}`);
|
|
12
|
+
const data = (bits << 3) | mask;
|
|
13
|
+
let rem = data;
|
|
14
|
+
for (let i = 0; i < 10; i++) {
|
|
15
|
+
rem = (rem << 1) ^ (rem >>> 9 ? 0x537 : 0);
|
|
16
|
+
}
|
|
17
|
+
return ((data << 10) | rem) ^ 0x5412;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Version Info BCH (18, 6)
|
|
21
|
+
*/
|
|
22
|
+
export function getVersionInfo(version) {
|
|
23
|
+
if (version < 7)
|
|
24
|
+
return 0;
|
|
25
|
+
let rem = version;
|
|
26
|
+
for (let i = 0; i < 12; i++) {
|
|
27
|
+
rem = (rem << 1) ^ (rem >>> 11 ? 0x1f25 : 0);
|
|
28
|
+
}
|
|
29
|
+
return (version << 12) | rem;
|
|
30
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { QrMode } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* QR Code constants and lookup tables
|
|
4
|
+
*/
|
|
5
|
+
export declare const MIN_VERSION = 1;
|
|
6
|
+
export declare const MAX_VERSION = 40;
|
|
7
|
+
/**
|
|
8
|
+
* Mode indicators (4-bit values)
|
|
9
|
+
*/
|
|
10
|
+
export declare const MODE_INDICATOR: Record<Exclude<QrMode, "auto">, number>;
|
|
11
|
+
/**
|
|
12
|
+
* Bit lengths for Character Count Indicator based on version groups
|
|
13
|
+
* Groups: 1-9, 10-26, 27-40
|
|
14
|
+
*/
|
|
15
|
+
export declare const CHAR_COUNT_INDICATOR_BITS: Record<Exclude<QrMode, "auto">, [
|
|
16
|
+
number,
|
|
17
|
+
number,
|
|
18
|
+
number
|
|
19
|
+
]>;
|
|
20
|
+
/**
|
|
21
|
+
* Version group index for Character Count Indicator
|
|
22
|
+
*/
|
|
23
|
+
export declare function getVersionGroupIndex(version: number): 0 | 1 | 2;
|
|
24
|
+
/**
|
|
25
|
+
* Alphanumeric character set mapping
|
|
26
|
+
*/
|
|
27
|
+
export declare const ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
|
|
28
|
+
/**
|
|
29
|
+
* ECC Codeword tables, Alignment pattern positions, etc. will go here or in sub-files.
|
|
30
|
+
* For now, defining the structure for capacity lookup.
|
|
31
|
+
*/
|
|
32
|
+
export interface EccBlockConfig {
|
|
33
|
+
totalCodewords: number;
|
|
34
|
+
dataCodewords: number;
|
|
35
|
+
eccCodewordsPerBlock: number;
|
|
36
|
+
blocksGroup1: number;
|
|
37
|
+
dataPerBlockGroup1: number;
|
|
38
|
+
blocksGroup2: number;
|
|
39
|
+
dataPerBlockGroup2: number;
|
|
40
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QR Code constants and lookup tables
|
|
3
|
+
*/
|
|
4
|
+
export const MIN_VERSION = 1;
|
|
5
|
+
export const MAX_VERSION = 40;
|
|
6
|
+
/**
|
|
7
|
+
* Mode indicators (4-bit values)
|
|
8
|
+
*/
|
|
9
|
+
export const MODE_INDICATOR = {
|
|
10
|
+
numeric: 0b0001,
|
|
11
|
+
alphanumeric: 0b0010,
|
|
12
|
+
byte: 0b0100,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Bit lengths for Character Count Indicator based on version groups
|
|
16
|
+
* Groups: 1-9, 10-26, 27-40
|
|
17
|
+
*/
|
|
18
|
+
export const CHAR_COUNT_INDICATOR_BITS = {
|
|
19
|
+
numeric: [10, 12, 14],
|
|
20
|
+
alphanumeric: [9, 11, 13],
|
|
21
|
+
byte: [8, 16, 16],
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Version group index for Character Count Indicator
|
|
25
|
+
*/
|
|
26
|
+
export function getVersionGroupIndex(version) {
|
|
27
|
+
if (version <= 9)
|
|
28
|
+
return 0;
|
|
29
|
+
if (version <= 26)
|
|
30
|
+
return 1;
|
|
31
|
+
return 2;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Alphanumeric character set mapping
|
|
35
|
+
*/
|
|
36
|
+
export const ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
|
|
37
|
+
// These tables are large and will be populated in src/spec/tables.ts
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EccLevel } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Alignment pattern center coordinates for each version (1-40)
|
|
4
|
+
*/
|
|
5
|
+
export declare const ALIGNMENT_PATTERN_POSITIONS: number[][];
|
|
6
|
+
export interface EccBlockInfo {
|
|
7
|
+
numBlocks: number;
|
|
8
|
+
dataCodewords: number;
|
|
9
|
+
}
|
|
10
|
+
export interface VersionInfo {
|
|
11
|
+
totalCodewords: number;
|
|
12
|
+
eccPerBlock: number;
|
|
13
|
+
group1: EccBlockInfo;
|
|
14
|
+
group2: EccBlockInfo;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* ECC capacity table for V1 and V2.
|
|
18
|
+
*/
|
|
19
|
+
export declare const ECC_TABLE: Record<number, Record<EccLevel, VersionInfo>>;
|
|
20
|
+
export declare function getDataCapacity(version: number, ecc: EccLevel): number;
|