@vkontakte/vk-qr 2.1.1 → 3.1.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 +22 -3
- package/dist/constants.d.ts +10 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/figures.d.ts +9 -0
- package/dist/figures.d.ts.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1311 -0
- package/dist/index.js.map +1 -0
- package/dist/qr.d.ts +71 -0
- package/dist/qr.d.ts.map +1 -0
- package/dist/svg-path.d.ts +8 -0
- package/dist/svg-path.d.ts.map +1 -0
- package/dist/svg.d.ts +6 -0
- package/dist/svg.d.ts.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +55 -80
- package/src/constants.ts +9 -0
- package/src/figures.ts +106 -0
- package/src/index.ts +45 -27
- package/src/qr.ts +711 -837
- package/src/svg-path.ts +254 -0
- package/src/svg.ts +132 -257
- package/src/types.ts +30 -12
- package/dist/cjs/index.js +0 -1185
- package/dist/es/index.js +0 -1183
- package/dist/types/index.d.ts +0 -20
- package/dist/types/qr.d.ts +0 -87
- package/dist/types/svg.d.ts +0 -9
- package/dist/types/types.d.ts +0 -51
- package/dist/umd/qrCodeGenerator.js +0 -1191
- package/dist/umd/qrCodeGenerator.min.js +0 -1
package/src/figures.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { FINDER_PATTERN_SIZE } from './constants.ts';
|
|
2
|
+
|
|
3
|
+
/** A connected group of modules stored in its smallest bounding box. */
|
|
4
|
+
export interface Figure {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
pixels: boolean[][];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function isFinderPattern(figure: Figure, size: number): boolean {
|
|
11
|
+
const { x, y, pixels } = figure;
|
|
12
|
+
const width = pixels[0]?.length ?? 0;
|
|
13
|
+
const height = pixels.length;
|
|
14
|
+
const right = x + width - 1;
|
|
15
|
+
const bottom = y + height - 1;
|
|
16
|
+
|
|
17
|
+
const finderRegions: Array<[number, number, number, number]> = [
|
|
18
|
+
[0, 0, FINDER_PATTERN_SIZE - 1, FINDER_PATTERN_SIZE - 1],
|
|
19
|
+
[size - FINDER_PATTERN_SIZE, 0, size - 1, FINDER_PATTERN_SIZE - 1],
|
|
20
|
+
[0, size - FINDER_PATTERN_SIZE, FINDER_PATTERN_SIZE - 1, size - 1],
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
for (const [rx1, ry1, rx2, ry2] of finderRegions) {
|
|
24
|
+
if (x >= rx1 && y >= ry1 && right <= rx2 && bottom <= ry2) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function extractFigures(image: boolean[][]): Figure[] {
|
|
33
|
+
const height = image.length;
|
|
34
|
+
const width = image[0]?.length ?? 0;
|
|
35
|
+
|
|
36
|
+
const visited: boolean[][] = Array.from({ length: height }, () => Array(width).fill(false));
|
|
37
|
+
|
|
38
|
+
const figures: Figure[] = [];
|
|
39
|
+
|
|
40
|
+
const directions = [
|
|
41
|
+
[0, -1], // up
|
|
42
|
+
[1, 0], // right
|
|
43
|
+
[0, 1], // down
|
|
44
|
+
[-1, 0], // left
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
function isInside(x: number, y: number): boolean {
|
|
48
|
+
return y >= 0 && y < height && x >= 0 && x < width;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for (let y = 0; y < height; y++) {
|
|
52
|
+
for (let x = 0; x < width; x++) {
|
|
53
|
+
if (visited[y][x]) continue;
|
|
54
|
+
if (!image[y][x]) continue;
|
|
55
|
+
|
|
56
|
+
const cells: Array<[number, number]> = [[x, y]];
|
|
57
|
+
|
|
58
|
+
visited[y][x] = true;
|
|
59
|
+
|
|
60
|
+
let minX = x;
|
|
61
|
+
let maxX = x;
|
|
62
|
+
let minY = y;
|
|
63
|
+
let maxY = y;
|
|
64
|
+
|
|
65
|
+
for (let head = 0; head < cells.length; head++) {
|
|
66
|
+
const [cx, cy] = cells[head];
|
|
67
|
+
|
|
68
|
+
minX = Math.min(minX, cx);
|
|
69
|
+
maxX = Math.max(maxX, cx);
|
|
70
|
+
minY = Math.min(minY, cy);
|
|
71
|
+
maxY = Math.max(maxY, cy);
|
|
72
|
+
|
|
73
|
+
for (const [dx, dy] of directions) {
|
|
74
|
+
const nx = cx + dx;
|
|
75
|
+
const ny = cy + dy;
|
|
76
|
+
|
|
77
|
+
if (!isInside(nx, ny)) continue;
|
|
78
|
+
if (visited[ny][nx]) continue;
|
|
79
|
+
if (!image[ny][nx]) continue;
|
|
80
|
+
|
|
81
|
+
visited[ny][nx] = true;
|
|
82
|
+
cells.push([nx, ny]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const figureWidth = maxX - minX + 1;
|
|
87
|
+
const figureHeight = maxY - minY + 1;
|
|
88
|
+
|
|
89
|
+
const pixels: boolean[][] = Array.from({ length: figureHeight }, () =>
|
|
90
|
+
Array(figureWidth).fill(false),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
for (const [cellX, cellY] of cells) {
|
|
94
|
+
pixels[cellY - minY][cellX - minX] = true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
figures.push({
|
|
98
|
+
x: minX,
|
|
99
|
+
y: minY,
|
|
100
|
+
pixels,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return figures;
|
|
106
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { convertSegmentsToSvgString, INC_TILE_SIZE } from './svg';
|
|
2
|
-
import {
|
|
3
|
-
import { QrOptions } from './types';
|
|
4
|
-
import
|
|
1
|
+
import { convertSegmentsToSvgString, INC_TILE_SIZE } from './svg.ts';
|
|
2
|
+
import { makeSegments, encodeSegments, QrCodeEcc } from './qr.ts';
|
|
3
|
+
import type { QrOptions, RequiredQrOptions } from './types.ts';
|
|
4
|
+
import { BACKGROUND_PADDING, BACKGROUND_RADIUS } from './constants.ts';
|
|
5
5
|
|
|
6
6
|
/** Default width and height of QR code */
|
|
7
7
|
const DEFAULT_SIZE = 128;
|
|
@@ -20,7 +20,7 @@ const LOGO_COLOR_DEFAULT = '#07f';
|
|
|
20
20
|
* @param text String to encode
|
|
21
21
|
* @param options QR code options
|
|
22
22
|
*/
|
|
23
|
-
function createQR(text: string, options?: QrOptions): string;
|
|
23
|
+
export function createQR(text: string, options?: QrOptions): string;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Legacy interface
|
|
@@ -30,16 +30,21 @@ function createQR(text: string, options?: QrOptions): string;
|
|
|
30
30
|
* @param className SVG element class name
|
|
31
31
|
* @param options Options of the QR code
|
|
32
32
|
*/
|
|
33
|
-
function createQR(
|
|
33
|
+
export function createQR(
|
|
34
|
+
text: string,
|
|
35
|
+
qrSize: number,
|
|
36
|
+
className: string,
|
|
37
|
+
options?: QrOptions,
|
|
38
|
+
): string;
|
|
34
39
|
|
|
35
40
|
/**
|
|
36
41
|
* Implementation
|
|
37
42
|
*/
|
|
38
|
-
function createQR(
|
|
43
|
+
export function createQR(
|
|
39
44
|
text: string,
|
|
40
45
|
qrSizeOrOptions?: number | QrOptions,
|
|
41
46
|
classNameLegacy?: string,
|
|
42
|
-
legacyOptions?: QrOptions
|
|
47
|
+
legacyOptions?: QrOptions,
|
|
43
48
|
): string {
|
|
44
49
|
if (typeof text !== 'string') {
|
|
45
50
|
throw new TypeError('Enter text for encoding');
|
|
@@ -50,46 +55,59 @@ function createQR(
|
|
|
50
55
|
...(typeof qrSizeOrOptions === 'object' && qrSizeOrOptions !== null ? qrSizeOrOptions : {}),
|
|
51
56
|
...(typeof legacyOptions === 'object' && legacyOptions !== null ? legacyOptions : {}),
|
|
52
57
|
qrSize:
|
|
53
|
-
typeof qrSizeOrOptions === 'object' &&
|
|
58
|
+
typeof qrSizeOrOptions === 'object' &&
|
|
59
|
+
qrSizeOrOptions !== null &&
|
|
60
|
+
typeof qrSizeOrOptions.qrSize === 'number'
|
|
54
61
|
? qrSizeOrOptions.qrSize
|
|
55
62
|
: (qrSizeOrOptions as number),
|
|
56
63
|
className:
|
|
57
|
-
typeof qrSizeOrOptions === 'object' &&
|
|
64
|
+
typeof qrSizeOrOptions === 'object' &&
|
|
65
|
+
qrSizeOrOptions !== null &&
|
|
66
|
+
typeof qrSizeOrOptions.className === 'string'
|
|
58
67
|
? qrSizeOrOptions.className
|
|
59
|
-
: classNameLegacy
|
|
68
|
+
: classNameLegacy,
|
|
60
69
|
};
|
|
61
70
|
|
|
62
71
|
// ECC levels mapping
|
|
63
|
-
const eccLevels = [
|
|
64
|
-
QrCode.Ecc.LOW,
|
|
65
|
-
QrCode.Ecc.MEDIUM,
|
|
66
|
-
QrCode.Ecc.QUARTILE,
|
|
67
|
-
QrCode.Ecc.HIGH
|
|
68
|
-
];
|
|
72
|
+
const eccLevels = [QrCodeEcc.LOW, QrCodeEcc.MEDIUM, QrCodeEcc.QUARTILE, QrCodeEcc.HIGH];
|
|
69
73
|
|
|
70
74
|
// Fallback undefined options
|
|
71
|
-
const fallbackOptions:
|
|
75
|
+
const fallbackOptions: RequiredQrOptions = {
|
|
72
76
|
qrSize: typeof options.qrSize === 'number' ? options.qrSize : DEFAULT_SIZE,
|
|
73
77
|
className: typeof options.className === 'string' ? options.className : classNameLegacy || '',
|
|
74
78
|
isShowLogo: !!options.isShowLogo || false,
|
|
75
79
|
isShowBackground: !!options.isShowBackground || false,
|
|
76
|
-
foregroundColor:
|
|
77
|
-
|
|
80
|
+
foregroundColor:
|
|
81
|
+
typeof options.foregroundColor === 'string'
|
|
82
|
+
? options.foregroundColor
|
|
83
|
+
: FOREGROUND_COLOR_DEFAULT,
|
|
84
|
+
backgroundColor:
|
|
85
|
+
typeof options.backgroundColor === 'string'
|
|
86
|
+
? options.backgroundColor
|
|
87
|
+
: BACKGROUND_COLOR_DEFAULT,
|
|
88
|
+
backgroundPadding:
|
|
89
|
+
typeof options.backgroundPadding === 'number' &&
|
|
90
|
+
Number.isFinite(options.backgroundPadding) &&
|
|
91
|
+
options.backgroundPadding >= 0
|
|
92
|
+
? options.backgroundPadding
|
|
93
|
+
: BACKGROUND_PADDING,
|
|
94
|
+
backgroundRadius:
|
|
95
|
+
typeof options.backgroundRadius === 'number' &&
|
|
96
|
+
Number.isFinite(options.backgroundRadius) &&
|
|
97
|
+
options.backgroundRadius >= 0
|
|
98
|
+
? options.backgroundRadius
|
|
99
|
+
: BACKGROUND_RADIUS,
|
|
78
100
|
logoColor: typeof options.logoColor === 'string' ? options.logoColor : LOGO_COLOR_DEFAULT,
|
|
79
101
|
suffix: options.suffix ? options.suffix.toString() : '0',
|
|
80
102
|
logoData: typeof options.logoData === 'string' ? options.logoData : null,
|
|
81
|
-
ecc:
|
|
103
|
+
ecc: typeof options.ecc === 'number' && eccLevels[options.ecc] ? options.ecc : 3,
|
|
82
104
|
incTileSize: typeof options.incTileSize === 'number' ? options.incTileSize : INC_TILE_SIZE,
|
|
83
105
|
};
|
|
84
106
|
|
|
85
107
|
// Code generation
|
|
86
|
-
const segments
|
|
87
|
-
const qrCode
|
|
108
|
+
const segments = makeSegments(text);
|
|
109
|
+
const qrCode = encodeSegments(segments, eccLevels[fallbackOptions.ecc], 1, 40, -1, true);
|
|
88
110
|
const svgCode = convertSegmentsToSvgString(qrCode, fallbackOptions);
|
|
89
111
|
|
|
90
112
|
return svgCode;
|
|
91
113
|
}
|
|
92
|
-
|
|
93
|
-
export default {
|
|
94
|
-
createQR
|
|
95
|
-
};
|