-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathQRCodeRaw.ts
121 lines (103 loc) · 3.16 KB
/
QRCodeRaw.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { QRCode as QRCodeCore, ErrorCorrectLevel } from '@akamfoad/qr';
export const ERROR_CORRECTION_LEVEL_LOW = 'L'; // Allows recovery of up to 7% data loss
export const ERROR_CORRECTION_LEVEL_MEDIUM = 'M'; // Allows recovery of up to 15% data loss
export const ERROR_CORRECTION_LEVEL_QUARTILE = 'Q'; // Allows recovery of up to 25% data loss
export const ERROR_CORRECTION_LEVEL_HIGH = 'H'; // Allows recovery of up to 30% data loss
export type ErrorCorrectionLevelType =
| typeof ERROR_CORRECTION_LEVEL_LOW
| typeof ERROR_CORRECTION_LEVEL_MEDIUM
| typeof ERROR_CORRECTION_LEVEL_QUARTILE
| typeof ERROR_CORRECTION_LEVEL_HIGH;
export type OptionsType = {
level: ErrorCorrectionLevelType;
typeNumber: number;
padding: number;
invert: boolean;
errorsEnabled: boolean;
};
export type QRCodeDataType = boolean[][];
const DEFAULT_CONSTRUCTOR_PARAMS: OptionsType = {
level: ERROR_CORRECTION_LEVEL_LOW,
padding: 1,
invert: false,
typeNumber: 0,
errorsEnabled: false,
};
export default class QRCodeRaw {
value: string;
level: ErrorCorrectionLevelType;
typeNumber: number;
padding: number;
errorsEnabled: boolean;
invert: boolean;
qrCodeData: QRCodeDataType | null | undefined;
constructor(value: string, options: Partial<OptionsType> = {}) {
const params = { ...DEFAULT_CONSTRUCTOR_PARAMS, ...options };
this.value = value;
this.level = params.level;
this.typeNumber = params.typeNumber;
this.padding = params.padding;
this.invert = params.invert;
this.errorsEnabled = params.errorsEnabled;
}
setValue(value: string): void {
this.value = value;
this._clearCache();
}
getDataSize(): number {
const data = this.getData();
return data ? data.length : 0;
}
_clearCache(): void {
this.qrCodeData = null;
}
_getQrCodeData(modules: QRCodeDataType): QRCodeDataType {
const qrCodeData: QRCodeDataType = [];
const padding = this.padding;
const invert = this.invert;
const rowPadding = Array<boolean>(padding * 2 + modules.length).fill(
invert,
);
const rowsPadding = Array<boolean[]>(padding).fill(rowPadding);
const columnPadding = Array<boolean>(padding).fill(invert);
if (padding) {
qrCodeData.push(...rowsPadding);
}
modules.forEach((row: boolean[]) => {
const qrCodeRow: boolean[] = [];
qrCodeRow.push(
...columnPadding,
...row.map((isBlack) => (invert ? !isBlack : isBlack)),
...columnPadding,
);
qrCodeData.push(qrCodeRow);
});
if (padding) {
qrCodeData.push(...rowsPadding);
}
return qrCodeData;
}
getData(): QRCodeDataType | null {
if (!this.qrCodeData) {
try {
const qrcode = new QRCodeCore(
this.typeNumber,
ErrorCorrectLevel[this.level],
);
qrcode.addData(this.value);
qrcode.make();
if (!qrcode.modules) {
return null;
}
this.qrCodeData = this._getQrCodeData(qrcode.modules as boolean[][]);
Object.freeze(this.qrCodeData);
} catch (error) {
if (this.errorsEnabled) {
throw error;
}
return null;
}
}
return this.qrCodeData;
}
}