@vkontakte/vk-qr 3.0.0 → 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/README.md +21 -2
- 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 +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +848 -672
- package/dist/index.js.map +1 -1
- package/dist/qr.d.ts +62 -70
- package/dist/qr.d.ts.map +1 -1
- package/dist/svg-path.d.ts +8 -0
- package/dist/svg-path.d.ts.map +1 -0
- package/dist/svg.d.ts +5 -9
- package/dist/svg.d.ts.map +1 -1
- package/dist/types.d.ts +13 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/constants.ts +9 -0
- package/src/figures.ts +106 -0
- package/src/index.ts +16 -10
- package/src/qr.ts +707 -871
- package/src/svg-path.ts +254 -0
- package/src/svg.ts +129 -270
- package/src/types.ts +15 -1
package/src/svg.ts
CHANGED
|
@@ -1,82 +1,25 @@
|
|
|
1
1
|
import type { QrCode } from './qr.ts';
|
|
2
2
|
import type { RequiredQrOptions } from './types.ts';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (x >= size - QR_BORDER && y < QR_BORDER) {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (x < QR_BORDER && y >= size - QR_BORDER) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (isLogoShowed) {
|
|
35
|
-
let imageTiles = QR_BORDER + 2;
|
|
36
|
-
if (size <= SMALL_QR_SIZE) {
|
|
37
|
-
imageTiles--;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
let paddingTiles = (size - QR_BORDER * 2 - imageTiles) / 2 - 1;
|
|
41
|
-
if (size <= SMALL_QR_SIZE) {
|
|
42
|
-
paddingTiles++;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
x > QR_BORDER + paddingTiles &&
|
|
47
|
-
x < size - QR_BORDER - paddingTiles - 1 &&
|
|
48
|
-
y > QR_BORDER + paddingTiles &&
|
|
49
|
-
y < size - QR_BORDER - paddingTiles - 1
|
|
50
|
-
) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return 0 <= x && x < size && 0 <= y && y < size && modules[y][x];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return modules[y]?.[x];
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const getNeighbors = (
|
|
61
|
-
x: number,
|
|
62
|
-
y: number,
|
|
63
|
-
size: number,
|
|
64
|
-
modules: boolean[][],
|
|
65
|
-
isLogoShowed = true,
|
|
66
|
-
) => ({
|
|
67
|
-
l: getPixel(x - 1, y, size, modules, isLogoShowed),
|
|
68
|
-
r: getPixel(x + 1, y, size, modules, isLogoShowed),
|
|
69
|
-
t: getPixel(x, y - 1, size, modules, isLogoShowed),
|
|
70
|
-
b: getPixel(x, y + 1, size, modules, isLogoShowed),
|
|
71
|
-
current: getPixel(x, y, size, modules, isLogoShowed),
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Converts QrCode instance to SVG code
|
|
76
|
-
* @param qrCode QrCode instance
|
|
77
|
-
* @param options Convertation options
|
|
78
|
-
*/
|
|
79
|
-
export const convertSegmentsToSvgString = (qrCode: QrCode, options: RequiredQrOptions): string => {
|
|
3
|
+
import { extractFigures, isFinderPattern } from './figures.ts';
|
|
4
|
+
import { figureToSvgPath } from './svg-path.ts';
|
|
5
|
+
import {
|
|
6
|
+
FINDER_PATTERN_SIZE,
|
|
7
|
+
TILE_SIZE,
|
|
8
|
+
SMALL_QR_SIZE,
|
|
9
|
+
FINDER_CORNER_RADIUS,
|
|
10
|
+
} from './constants.ts';
|
|
11
|
+
|
|
12
|
+
export const INC_TILE_SIZE = TILE_SIZE;
|
|
13
|
+
|
|
14
|
+
interface BackgroundLayout {
|
|
15
|
+
size: number;
|
|
16
|
+
padding: number;
|
|
17
|
+
radius: number;
|
|
18
|
+
hideQr: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Converts a QR module matrix to SVG. */
|
|
22
|
+
export function convertSegmentsToSvgString(qrCode: QrCode, options: RequiredQrOptions): string {
|
|
80
23
|
if (typeof options.qrSize !== 'number') {
|
|
81
24
|
throw new Error('Size should be a number');
|
|
82
25
|
}
|
|
@@ -85,223 +28,146 @@ export const convertSegmentsToSvgString = (qrCode: QrCode, options: RequiredQrOp
|
|
|
85
28
|
throw new Error('Classname should be a string');
|
|
86
29
|
}
|
|
87
30
|
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
const _14_7 = 14.7 * MULTI;
|
|
92
|
-
const _14_8 = 14.8 * MULTI;
|
|
93
|
-
const _15_9 = 15.9 * MULTI;
|
|
94
|
-
const _28_6 = 28.6 * MULTI;
|
|
95
|
-
const _30_5 = 30.5 * MULTI;
|
|
96
|
-
const _84_7 = 84.7776815 * MULTI;
|
|
97
|
-
const _87_3 = 87.3 * MULTI;
|
|
98
|
-
const _71_4 = 71.4 * MULTI;
|
|
99
|
-
const _42_9 = 42.9 * MULTI;
|
|
100
|
-
const _87_2 = 87.2 * MULTI;
|
|
101
|
-
const _85_2 = 85.2 * MULTI;
|
|
102
|
-
const _85_3 = 85.3 * MULTI;
|
|
103
|
-
const _69_5 = 69.5 * MULTI;
|
|
104
|
-
const _98 = 98 * MULTI;
|
|
105
|
-
const _100 = 100 * MULTI;
|
|
31
|
+
const background = getBackgroundLayout(qrCode.size, options);
|
|
32
|
+
const parts = renderFinderPatterns(qrCode.size, options);
|
|
33
|
+
if (options.isShowLogo) parts.push(renderLogo(qrCode.size, options));
|
|
106
34
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
yCoord = y + topPadding;
|
|
35
|
+
return `
|
|
36
|
+
<svg
|
|
37
|
+
version="1.1"
|
|
38
|
+
viewBox="${-background.padding} ${-background.padding} ${background.size} ${background.size}"
|
|
39
|
+
width="${options.qrSize}px"
|
|
40
|
+
height="${options.qrSize}px"
|
|
41
|
+
style="display: block"
|
|
42
|
+
${options.className ? `class="${options.className}"` : ''}
|
|
43
|
+
xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
44
|
+
>
|
|
45
|
+
${renderDefinitions(options)}
|
|
119
46
|
|
|
120
|
-
|
|
47
|
+
${renderBackground(background, options)}
|
|
121
48
|
|
|
122
|
-
|
|
123
|
-
|
|
49
|
+
<g${background.hideQr ? ' display="none"' : ''}>
|
|
50
|
+
${renderModules(qrCode, options)}
|
|
51
|
+
${parts.join('\n')}
|
|
52
|
+
</g>
|
|
124
53
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
neighbors.b &&
|
|
149
|
-
getPixel(x - 1, y + 1, qrCode.size, qrCode.modules, options.isShowLogo)
|
|
150
|
-
? 'n_lb'
|
|
151
|
-
: '';
|
|
152
|
-
selector =
|
|
153
|
-
!selector &&
|
|
154
|
-
neighbors.r &&
|
|
155
|
-
neighbors.t &&
|
|
156
|
-
getPixel(x + 1, y - 1, qrCode.size, qrCode.modules, options.isShowLogo)
|
|
157
|
-
? 'n_rt'
|
|
158
|
-
: '';
|
|
159
|
-
selector =
|
|
160
|
-
!selector &&
|
|
161
|
-
neighbors.r &&
|
|
162
|
-
neighbors.b &&
|
|
163
|
-
getPixel(x + 1, y + 1, qrCode.size, qrCode.modules, options.isShowLogo)
|
|
164
|
-
? 'n_rb'
|
|
165
|
-
: '';
|
|
166
|
-
}
|
|
54
|
+
</svg>`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getVisibleModules(qrCode: QrCode, isShowLogo: boolean): boolean[][] {
|
|
58
|
+
if (!isShowLogo) return qrCode.modules;
|
|
59
|
+
|
|
60
|
+
// Clear the logo area before tracing contours so transparent logos retain
|
|
61
|
+
// their quiet zone and neighboring modules do not connect through it.
|
|
62
|
+
const logoAreaSize = qrCode.size <= SMALL_QR_SIZE ? FINDER_PATTERN_SIZE : FINDER_PATTERN_SIZE + 2;
|
|
63
|
+
const logoAreaStart = (qrCode.size - logoAreaSize) / 2;
|
|
64
|
+
return qrCode.modules.map((row, y) =>
|
|
65
|
+
row.map(
|
|
66
|
+
(pixel, x) =>
|
|
67
|
+
pixel &&
|
|
68
|
+
!(
|
|
69
|
+
x >= logoAreaStart &&
|
|
70
|
+
x < logoAreaStart + logoAreaSize &&
|
|
71
|
+
y >= logoAreaStart &&
|
|
72
|
+
y < logoAreaStart + logoAreaSize
|
|
73
|
+
),
|
|
74
|
+
),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
167
77
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
78
|
+
function renderModules(qrCode: QrCode, options: RequiredQrOptions): string {
|
|
79
|
+
return extractFigures(getVisibleModules(qrCode, options.isShowLogo))
|
|
80
|
+
.filter((figure) => !isFinderPattern(figure, qrCode.size))
|
|
81
|
+
.map(
|
|
82
|
+
(figure) => `
|
|
83
|
+
<path
|
|
84
|
+
d="${figureToSvgPath(figure)}"
|
|
85
|
+
fill="${options.foregroundColor}"
|
|
86
|
+
fill-rule="evenodd"
|
|
87
|
+
/>`,
|
|
88
|
+
)
|
|
89
|
+
.join('');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function renderFinderPatterns(size: number, options: RequiredQrOptions): string[] {
|
|
93
|
+
const pointPosition = (size - FINDER_PATTERN_SIZE) * TILE_SIZE;
|
|
94
|
+
return [
|
|
95
|
+
`<use fill-rule="evenodd" transform="translate(0,0)" xlink:href="#point-${options.suffix}"/>`,
|
|
96
|
+
`<use fill-rule="evenodd" transform="translate(${pointPosition},0)" xlink:href="#point-${options.suffix}"/>`,
|
|
97
|
+
`<use fill-rule="evenodd" transform="translate(0,${pointPosition})" xlink:href="#point-${options.suffix}"/>`,
|
|
98
|
+
];
|
|
99
|
+
}
|
|
176
100
|
|
|
101
|
+
function renderLogo(size: number, options: RequiredQrOptions): string {
|
|
177
102
|
let scale = '';
|
|
178
|
-
let position =
|
|
179
|
-
|
|
103
|
+
let position =
|
|
104
|
+
((size - FINDER_PATTERN_SIZE * 3) / 2) * TILE_SIZE + TILE_SIZE * FINDER_PATTERN_SIZE - 10;
|
|
105
|
+
if (size <= SMALL_QR_SIZE) {
|
|
180
106
|
scale = 'scale(0.85)';
|
|
181
107
|
position += 50;
|
|
182
108
|
}
|
|
183
109
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
`<use fill-rule="evenodd" transform="translate(0,0)" xlink:href="#point-${options.suffix}"/>`,
|
|
187
|
-
);
|
|
188
|
-
parts.push(
|
|
189
|
-
`<use fill-rule="evenodd" transform="translate(${pointPosition},0)" xlink:href="#point-${options.suffix}"/>`,
|
|
190
|
-
);
|
|
191
|
-
parts.push(
|
|
192
|
-
`<use fill-rule="evenodd" transform="translate(0,${pointPosition})" xlink:href="#point-${options.suffix}"/>`,
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
if (options.isShowLogo) {
|
|
196
|
-
if (!options.logoData) {
|
|
197
|
-
parts.push(`
|
|
110
|
+
if (!options.logoData) {
|
|
111
|
+
return `
|
|
198
112
|
<use style="width: 750px; height: 750px;" width="750" height="750"
|
|
199
113
|
fill="none"
|
|
200
114
|
fill-rule="evenodd"
|
|
201
115
|
transform="translate(${position},${position}) ${scale}" xlink:href="#vk_logo-${options.suffix}"
|
|
202
116
|
/>
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return `
|
|
206
121
|
<image
|
|
207
122
|
preserveAspectRatio="xMidYMid slice" clip-path="url(#logo-mask-${options.suffix})"
|
|
208
123
|
style="width: 750px; height: 750px;" width="750" height="750"
|
|
209
124
|
transform="translate(${position},${position}) ${scale}"
|
|
210
125
|
xlink:href="${options.logoData}"
|
|
211
126
|
/>
|
|
212
|
-
|
|
213
|
-
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function getBackgroundLayout(size: number, options: RequiredQrOptions): BackgroundLayout {
|
|
131
|
+
const contentSize = TILE_SIZE * size;
|
|
132
|
+
if (!options.isShowBackground) {
|
|
133
|
+
return { size: contentSize, padding: 0, radius: 0, hideQr: false };
|
|
214
134
|
}
|
|
215
135
|
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
136
|
+
const frameWidth = Math.min(options.backgroundPadding, options.qrSize / 2);
|
|
137
|
+
const contentWidth = options.qrSize - frameWidth * 2;
|
|
138
|
+
const hideQr = contentWidth <= 0;
|
|
139
|
+
const backgroundSize = hideQr ? contentSize : (contentSize * options.qrSize) / contentWidth;
|
|
140
|
+
const padding = (backgroundSize - contentSize) / 2;
|
|
141
|
+
const radius =
|
|
142
|
+
(Math.min(options.backgroundRadius, options.qrSize / 2) / options.qrSize) * backgroundSize;
|
|
143
|
+
|
|
144
|
+
return { size: backgroundSize, padding, radius, hideQr };
|
|
145
|
+
}
|
|
219
146
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const padding = (backgroundSize / options.qrSize) * 21;
|
|
223
|
-
const radius = Math.ceil(backgroundSize / (options.qrSize / 36)); // 7.11111111 = 256px/36px radius
|
|
147
|
+
function renderBackground(layout: BackgroundLayout, options: RequiredQrOptions): string {
|
|
148
|
+
if (!options.isShowBackground) return '';
|
|
224
149
|
|
|
225
|
-
|
|
150
|
+
const { size, padding, radius } = layout;
|
|
151
|
+
return `
|
|
226
152
|
<rect
|
|
227
|
-
x="
|
|
228
|
-
|
|
229
|
-
|
|
153
|
+
x="${-padding}"
|
|
154
|
+
y="${-padding}"
|
|
155
|
+
width="${size}"
|
|
156
|
+
height="${size}"
|
|
230
157
|
rx="${radius}"
|
|
231
158
|
fill="${options.backgroundColor}"
|
|
232
159
|
/>`;
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// eslint-disable-next-line
|
|
237
|
-
const oneSide = `M0,0 L66,0 C${_84_7},-3.44940413e-15 ${_100},15.2223185 ${_100},34 L${_100},66 C${_100},${_84_7} \
|
|
238
|
-
${_84_7},${_100} 66,${_100} L0,${_100} L0,0 Z`;
|
|
239
|
-
const twoSides = `M0,0 L${_100},0 L${_100},66 C${_100},${_84_7} ${_84_7},${_100} 66,${_100} L0,${_100} L0,0 Z`;
|
|
160
|
+
}
|
|
240
161
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
viewBox="0 0 ${backgroundSize} ${backgroundSize}"
|
|
245
|
-
width="${options.qrSize}px"
|
|
246
|
-
height="${options.qrSize}px"
|
|
247
|
-
${options.className ? `class="${options.className}"` : ''}
|
|
248
|
-
xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
249
|
-
>
|
|
250
|
-
<defs>
|
|
251
|
-
<rect id="rect-${options.suffix}" width="100" height="100" fill="${options.foregroundColor}"/>
|
|
252
|
-
<path
|
|
253
|
-
id="empty-${options.suffix}"
|
|
254
|
-
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},\
|
|
255
|
-
${_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"
|
|
256
|
-
fill="${options.foregroundColor}"
|
|
257
|
-
/>
|
|
258
|
-
<path id="b-${options.suffix}" d="${oneSide}" transform="rotate(-90 50 50)" fill="${options.foregroundColor}"/>
|
|
259
|
-
<path id="r-${options.suffix}" d="${oneSide}" transform="rotate(-180 50 50)" fill="${options.foregroundColor}"/>
|
|
260
|
-
<path id="l-${options.suffix}" d="${oneSide}" fill="${options.foregroundColor}"/>
|
|
261
|
-
<path id="t-${options.suffix}" d="${oneSide}" transform="rotate(90 50 50)" fill="${options.foregroundColor}"/>
|
|
262
|
-
<path id="l-${options.suffix}" d="${twoSides}" transform="rotate(-90 50 50)" fill="${options.foregroundColor}"/>
|
|
263
|
-
<path id="lt-${options.suffix}" d="${twoSides}" fill="${options.foregroundColor}"/>
|
|
264
|
-
<path id="lb-${options.suffix}" d="${twoSides}" transform="rotate(-90 50 50)" fill="${options.foregroundColor}"/>
|
|
265
|
-
<path id="rb-${options.suffix}" d="${twoSides}" transform="rotate(-180 50 50)" fill="${options.foregroundColor}"/>
|
|
266
|
-
<path id="rt-${options.suffix}" d="${twoSides}" transform="rotate(90 50 50)" fill="${options.foregroundColor}"/>
|
|
267
|
-
<path
|
|
268
|
-
id="n_lt-${options.suffix}"
|
|
269
|
-
d="M${_30_5},${_2}V0H0v${_30_5}h${_2}C${_2},${_14_7},${_14_8},${_2},${_30_5},${_2}z"
|
|
270
|
-
fill="${options.foregroundColor}"
|
|
271
|
-
/>
|
|
272
|
-
<path
|
|
273
|
-
id="n_lb-${options.suffix}"
|
|
274
|
-
d="M${_2},${_69_5}H0V${_100}h${_30_5}v-${_2}C${_14_7},${_98},${_2},${_85_2},${_2},${_69_5}z"
|
|
275
|
-
fill="${options.foregroundColor}"
|
|
276
|
-
/>
|
|
277
|
-
<path
|
|
278
|
-
id="n_rt-${options.suffix}"
|
|
279
|
-
d="M${_98},${_30_5}h${_2}V0H${_69_5}v${_2}C${_85_3},${_2},${_98},${_14_8},${_98},${_30_5}z"
|
|
280
|
-
fill="${options.foregroundColor}"
|
|
281
|
-
/>
|
|
282
|
-
<path id="n_rb-${options.suffix}"
|
|
283
|
-
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"
|
|
284
|
-
fill="${options.foregroundColor}"
|
|
285
|
-
/>
|
|
286
|
-
<path
|
|
162
|
+
function renderDefinitions(options: RequiredQrOptions): string {
|
|
163
|
+
return `<defs>
|
|
164
|
+
<g
|
|
287
165
|
id="point-${options.suffix}"
|
|
288
166
|
fill="${options.foregroundColor}"
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
C99.9982143,552.627632 112.972983,575.877216 118.547883,581.464617 C124.122784,587.027017 \
|
|
294
|
-
147.372368,600.001786 242.670667,600.001786 L457.329333,600.001786 C552.627632,600.001786 \
|
|
295
|
-
575.877216,587.027017 581.464617,581.464617 C587.039517,575.877216 600.001786,552.627632 \
|
|
296
|
-
600.001786,457.329333 Z M457.329333,0 C653.338333,0 700,46.6616668 700,242.658167 C700,438.667167 \
|
|
297
|
-
700,261.332833 700,457.329333 C700,653.338333 653.338333,700 457.329333,700 C261.332833,700 438.667167,700 \
|
|
298
|
-
242.670667,700 C46.6616668,700 0,653.338333 0,457.329333 C0,261.332833 0,352.118712 0,242.658167 \
|
|
299
|
-
C0,46.6616668 46.6616668,0 242.670667,0 C438.667167,0 261.332833,0 457.329333,0 Z M395.996667,200 \
|
|
300
|
-
C480.004166,200 500,220.008332 500,303.990835 C500,387.998334 500,312.001666 500,395.996667 \
|
|
301
|
-
C500,479.991668 480.004166,500 395.996667,500 C312.001666,500 387.998334,500 304.003333,500 C220.008332,500 \
|
|
302
|
-
200,479.991668 200,395.996667 C200,312.001666 200,350.906061 200,303.990835 C200,220.008332 220.008332,200 \
|
|
303
|
-
304.003333,200 C387.998334,200 312.001666,200 395.996667,200 Z"
|
|
304
|
-
/>
|
|
167
|
+
>
|
|
168
|
+
<rect width="300" height="300" x="200" y="200" rx="${FINDER_CORNER_RADIUS}" />
|
|
169
|
+
<rect width="600" height="600" x="50" y="50" rx="${FINDER_CORNER_RADIUS * 2}" stroke-width="100" fill="none" stroke="${options.foregroundColor}" />
|
|
170
|
+
</g>
|
|
305
171
|
<g id="vk_logo-${options.suffix}">
|
|
306
172
|
<path
|
|
307
173
|
fill="${options.logoColor}"
|
|
@@ -322,12 +188,5 @@ C500,479.991668 480.004166,500 395.996667,500 C312.001666,500 387.998334,500 304
|
|
|
322
188
|
<clipPath id="logo-mask-${options.suffix}">
|
|
323
189
|
<rect x="0" y="0" width="750" height="750" />
|
|
324
190
|
</clipPath>
|
|
325
|
-
</defs
|
|
326
|
-
|
|
327
|
-
${qrBackground}
|
|
328
|
-
|
|
329
|
-
<g transform="${qrTransform}">
|
|
330
|
-
${parts.join('\n')}
|
|
331
|
-
</g>
|
|
332
|
-
</svg>`;
|
|
333
|
-
};
|
|
191
|
+
</defs>`;
|
|
192
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -28,6 +28,20 @@ export type QrOptions = {
|
|
|
28
28
|
*/
|
|
29
29
|
backgroundColor?: string | undefined;
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Background frame thickness in output pixels. Works if `isShowBackground` is enabled.
|
|
33
|
+
* Must be finite and non-negative. Clamped to half of `qrSize`.
|
|
34
|
+
* @default 20
|
|
35
|
+
*/
|
|
36
|
+
backgroundPadding?: number | undefined;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Background corner radius in output pixels. Works if `isShowBackground` is enabled.
|
|
40
|
+
* Must be finite and non-negative. Clamped to half of `qrSize`.
|
|
41
|
+
* @default 36
|
|
42
|
+
*/
|
|
43
|
+
backgroundRadius?: number | undefined;
|
|
44
|
+
|
|
31
45
|
/**
|
|
32
46
|
* QR code HEX color
|
|
33
47
|
*/
|
|
@@ -55,7 +69,7 @@ export type QrOptions = {
|
|
|
55
69
|
ecc?: number | undefined;
|
|
56
70
|
|
|
57
71
|
/**
|
|
58
|
-
*
|
|
72
|
+
* @deprecated Ignored. QR module size is fixed internally.
|
|
59
73
|
*/
|
|
60
74
|
incTileSize?: number | undefined;
|
|
61
75
|
};
|