@liquid-js/qr-code-styling 1.6.0-rc.4 → 1.6.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.
@@ -1,1287 +1,1279 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var fileType = require('file-type');
6
4
  var jsdom = require('jsdom');
7
5
  var fetch = require('node-fetch');
8
6
  var sharp = require('sharp');
9
7
  var qrcode = require('qrcode-generator');
10
8
 
11
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
-
13
- var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
14
- var sharp__default = /*#__PURE__*/_interopDefaultLegacy(sharp);
15
- var qrcode__default = /*#__PURE__*/_interopDefaultLegacy(qrcode);
16
-
17
- exports.DotType = void 0;
18
- (function (DotType) {
19
- DotType["dots"] = "dots";
20
- DotType["rounded"] = "rounded";
21
- DotType["classy"] = "classy";
22
- DotType["classyRounded"] = "classy-rounded";
23
- DotType["square"] = "square";
24
- DotType["extraRounded"] = "extra-rounded";
25
- })(exports.DotType || (exports.DotType = {}));
26
- exports.CornerDotType = void 0;
27
- (function (CornerDotType) {
28
- CornerDotType["dot"] = "dot";
29
- CornerDotType["square"] = "square";
30
- })(exports.CornerDotType || (exports.CornerDotType = {}));
31
- exports.CornerSquareType = void 0;
32
- (function (CornerSquareType) {
33
- CornerSquareType["dot"] = "dot";
34
- CornerSquareType["square"] = "square";
35
- CornerSquareType["extraRounded"] = "extra-rounded";
36
- })(exports.CornerSquareType || (exports.CornerSquareType = {}));
37
- exports.GradientType = void 0;
38
- (function (GradientType) {
39
- GradientType["radial"] = "radial";
40
- GradientType["linear"] = "linear";
41
- })(exports.GradientType || (exports.GradientType = {}));
42
- exports.ShapeType = void 0;
43
- (function (ShapeType) {
44
- ShapeType["square"] = "square";
45
- ShapeType["circle"] = "circle";
46
- })(exports.ShapeType || (exports.ShapeType = {}));
47
- const TypeNumber = Array(41)
48
- .fill(0)
49
- .map((_, i) => i);
50
- exports.ErrorCorrectionLevel = void 0;
51
- (function (ErrorCorrectionLevel) {
52
- ErrorCorrectionLevel["L"] = "L";
53
- ErrorCorrectionLevel["M"] = "M";
54
- ErrorCorrectionLevel["Q"] = "Q";
55
- ErrorCorrectionLevel["H"] = "H";
56
- })(exports.ErrorCorrectionLevel || (exports.ErrorCorrectionLevel = {}));
57
- exports.Mode = void 0;
58
- (function (Mode) {
59
- Mode["numeric"] = "Numeric";
60
- Mode["alphanumeric"] = "Alphanumeric";
61
- Mode["byte"] = "Byte";
62
- Mode["kanji"] = "Kanji";
63
- })(exports.Mode || (exports.Mode = {}));
64
- exports.FileExtension = void 0;
65
- (function (FileExtension) {
66
- FileExtension["svg"] = "svg";
67
- FileExtension["png"] = "png";
68
- FileExtension["jpeg"] = "jpeg";
69
- FileExtension["webp"] = "webp";
9
+ exports.DotType = void 0;
10
+ (function (DotType) {
11
+ DotType["dots"] = "dots";
12
+ DotType["rounded"] = "rounded";
13
+ DotType["classy"] = "classy";
14
+ DotType["classyRounded"] = "classy-rounded";
15
+ DotType["square"] = "square";
16
+ DotType["extraRounded"] = "extra-rounded";
17
+ })(exports.DotType || (exports.DotType = {}));
18
+ exports.CornerDotType = void 0;
19
+ (function (CornerDotType) {
20
+ CornerDotType["dot"] = "dot";
21
+ CornerDotType["square"] = "square";
22
+ })(exports.CornerDotType || (exports.CornerDotType = {}));
23
+ exports.CornerSquareType = void 0;
24
+ (function (CornerSquareType) {
25
+ CornerSquareType["dot"] = "dot";
26
+ CornerSquareType["square"] = "square";
27
+ CornerSquareType["extraRounded"] = "extra-rounded";
28
+ })(exports.CornerSquareType || (exports.CornerSquareType = {}));
29
+ exports.GradientType = void 0;
30
+ (function (GradientType) {
31
+ GradientType["radial"] = "radial";
32
+ GradientType["linear"] = "linear";
33
+ })(exports.GradientType || (exports.GradientType = {}));
34
+ exports.ShapeType = void 0;
35
+ (function (ShapeType) {
36
+ ShapeType["square"] = "square";
37
+ ShapeType["circle"] = "circle";
38
+ })(exports.ShapeType || (exports.ShapeType = {}));
39
+ const TypeNumber = Array(41)
40
+ .fill(0)
41
+ .map((_, i) => i);
42
+ exports.ErrorCorrectionLevel = void 0;
43
+ (function (ErrorCorrectionLevel) {
44
+ ErrorCorrectionLevel["L"] = "L";
45
+ ErrorCorrectionLevel["M"] = "M";
46
+ ErrorCorrectionLevel["Q"] = "Q";
47
+ ErrorCorrectionLevel["H"] = "H";
48
+ })(exports.ErrorCorrectionLevel || (exports.ErrorCorrectionLevel = {}));
49
+ exports.Mode = void 0;
50
+ (function (Mode) {
51
+ Mode["numeric"] = "Numeric";
52
+ Mode["alphanumeric"] = "Alphanumeric";
53
+ Mode["byte"] = "Byte";
54
+ Mode["kanji"] = "Kanji";
55
+ })(exports.Mode || (exports.Mode = {}));
56
+ exports.FileExtension = void 0;
57
+ (function (FileExtension) {
58
+ FileExtension["svg"] = "svg";
59
+ FileExtension["png"] = "png";
60
+ FileExtension["jpeg"] = "jpeg";
61
+ FileExtension["webp"] = "webp";
70
62
  })(exports.FileExtension || (exports.FileExtension = {}));
71
63
 
72
- const ErrorCorrectionPercents = {
73
- [exports.ErrorCorrectionLevel.L]: 0.07,
74
- [exports.ErrorCorrectionLevel.M]: 0.15,
75
- [exports.ErrorCorrectionLevel.Q]: 0.25,
76
- [exports.ErrorCorrectionLevel.H]: 0.3
64
+ const ErrorCorrectionPercents = {
65
+ [exports.ErrorCorrectionLevel.L]: 0.07,
66
+ [exports.ErrorCorrectionLevel.M]: 0.15,
67
+ [exports.ErrorCorrectionLevel.Q]: 0.25,
68
+ [exports.ErrorCorrectionLevel.H]: 0.3
77
69
  };
78
70
 
79
- function getMode(data) {
80
- switch (true) {
81
- case /^[0-9]*$/.test(data):
82
- return exports.Mode.numeric;
83
- case /^[0-9A-Z $%*+\-./:]*$/.test(data):
84
- return exports.Mode.alphanumeric;
85
- default:
86
- return exports.Mode.byte;
87
- }
71
+ function getMode(data) {
72
+ switch (true) {
73
+ case /^[0-9]*$/.test(data):
74
+ return exports.Mode.numeric;
75
+ case /^[0-9A-Z $%*+\-./:]*$/.test(data):
76
+ return exports.Mode.alphanumeric;
77
+ default:
78
+ return exports.Mode.byte;
79
+ }
88
80
  }
89
81
 
90
- const isObject = (obj) => !!obj && typeof obj === "object" && !Array.isArray(obj);
91
- function mergeDeep(target, ...sources) {
92
- if (!sources.length)
93
- return target;
94
- const source = sources.shift();
95
- if (source === undefined || !isObject(target) || !isObject(source))
96
- return target;
97
- target = { ...target };
98
- Object.keys(source).forEach((key) => {
99
- const targetValue = target[key];
100
- const sourceValue = source[key];
101
- if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
102
- target[key] = sourceValue;
103
- }
104
- else if (isObject(targetValue) && isObject(sourceValue)) {
105
- target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue);
106
- }
107
- else {
108
- target[key] = sourceValue;
109
- }
110
- });
111
- return mergeDeep(target, ...sources);
82
+ const isObject = (obj) => !!obj && typeof obj === "object" && !Array.isArray(obj);
83
+ function mergeDeep(target, ...sources) {
84
+ if (!sources.length)
85
+ return target;
86
+ const source = sources.shift();
87
+ if (source === undefined || !isObject(target) || !isObject(source))
88
+ return target;
89
+ target = { ...target };
90
+ Object.keys(source).forEach((key) => {
91
+ const targetValue = target[key];
92
+ const sourceValue = source[key];
93
+ if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
94
+ target[key] = sourceValue;
95
+ }
96
+ else if (isObject(targetValue) && isObject(sourceValue)) {
97
+ target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue);
98
+ }
99
+ else {
100
+ target[key] = sourceValue;
101
+ }
102
+ });
103
+ return mergeDeep(target, ...sources);
112
104
  }
113
105
 
114
- function sanitizeGradient(gradient) {
115
- const newGradient = { ...gradient };
116
- if (!newGradient.colorStops || !newGradient.colorStops.length) {
117
- throw "Field 'colorStops' is required in gradient";
118
- }
119
- if (newGradient.rotation) {
120
- newGradient.rotation = Number(newGradient.rotation);
121
- }
122
- else {
123
- newGradient.rotation = 0;
124
- }
125
- newGradient.colorStops = newGradient.colorStops.map((colorStop) => ({
126
- ...colorStop,
127
- offset: Number(colorStop.offset)
128
- }));
129
- return newGradient;
130
- }
131
- function sanitizeOptions(options) {
132
- const newOptions = { ...options };
133
- newOptions.imageOptions = {
134
- ...newOptions.imageOptions,
135
- hideBackgroundDots: Boolean(newOptions.imageOptions.hideBackgroundDots),
136
- imageSize: Math.min(1, Number(newOptions.imageOptions.imageSize)) || 1,
137
- margin: Number(newOptions.imageOptions.margin)
138
- };
139
- newOptions.dotsOptions = {
140
- ...newOptions.dotsOptions
141
- };
142
- if (newOptions.dotsOptions.gradient) {
143
- newOptions.dotsOptions.gradient = sanitizeGradient(newOptions.dotsOptions.gradient);
144
- }
145
- if (newOptions.cornersSquareOptions) {
146
- newOptions.cornersSquareOptions = {
147
- ...newOptions.cornersSquareOptions
148
- };
149
- if (newOptions.cornersSquareOptions.gradient) {
150
- newOptions.cornersSquareOptions.gradient = sanitizeGradient(newOptions.cornersSquareOptions.gradient);
151
- }
152
- }
153
- if (newOptions.cornersDotOptions) {
154
- newOptions.cornersDotOptions = {
155
- ...newOptions.cornersDotOptions
156
- };
157
- if (newOptions.cornersDotOptions.gradient) {
158
- newOptions.cornersDotOptions.gradient = sanitizeGradient(newOptions.cornersDotOptions.gradient);
159
- }
160
- }
161
- if (newOptions.backgroundOptions) {
162
- newOptions.backgroundOptions = {
163
- ...newOptions.backgroundOptions
164
- };
165
- if (newOptions.backgroundOptions.gradient) {
166
- newOptions.backgroundOptions.gradient = sanitizeGradient(newOptions.backgroundOptions.gradient);
167
- }
168
- }
169
- if (!newOptions.document)
170
- newOptions.document = document;
171
- return newOptions;
106
+ function sanitizeGradient(gradient) {
107
+ const newGradient = { ...gradient };
108
+ if (!newGradient.colorStops || !newGradient.colorStops.length) {
109
+ throw "Field 'colorStops' is required in gradient";
110
+ }
111
+ if (newGradient.rotation) {
112
+ newGradient.rotation = Number(newGradient.rotation);
113
+ }
114
+ else {
115
+ newGradient.rotation = 0;
116
+ }
117
+ newGradient.colorStops = newGradient.colorStops.map((colorStop) => ({
118
+ ...colorStop,
119
+ offset: Number(colorStop.offset)
120
+ }));
121
+ return newGradient;
122
+ }
123
+ function sanitizeOptions(options) {
124
+ const newOptions = { ...options };
125
+ newOptions.imageOptions = {
126
+ ...newOptions.imageOptions,
127
+ hideBackgroundDots: Boolean(newOptions.imageOptions.hideBackgroundDots),
128
+ imageSize: Math.min(1, Number(newOptions.imageOptions.imageSize)) || 1,
129
+ margin: Number(newOptions.imageOptions.margin)
130
+ };
131
+ newOptions.dotsOptions = {
132
+ ...newOptions.dotsOptions
133
+ };
134
+ if (newOptions.dotsOptions.gradient) {
135
+ newOptions.dotsOptions.gradient = sanitizeGradient(newOptions.dotsOptions.gradient);
136
+ }
137
+ if (newOptions.cornersSquareOptions) {
138
+ newOptions.cornersSquareOptions = {
139
+ ...newOptions.cornersSquareOptions
140
+ };
141
+ if (newOptions.cornersSquareOptions.gradient) {
142
+ newOptions.cornersSquareOptions.gradient = sanitizeGradient(newOptions.cornersSquareOptions.gradient);
143
+ }
144
+ }
145
+ if (newOptions.cornersDotOptions) {
146
+ newOptions.cornersDotOptions = {
147
+ ...newOptions.cornersDotOptions
148
+ };
149
+ if (newOptions.cornersDotOptions.gradient) {
150
+ newOptions.cornersDotOptions.gradient = sanitizeGradient(newOptions.cornersDotOptions.gradient);
151
+ }
152
+ }
153
+ if (newOptions.backgroundOptions) {
154
+ newOptions.backgroundOptions = {
155
+ ...newOptions.backgroundOptions
156
+ };
157
+ if (newOptions.backgroundOptions.gradient) {
158
+ newOptions.backgroundOptions.gradient = sanitizeGradient(newOptions.backgroundOptions.gradient);
159
+ }
160
+ }
161
+ if (!newOptions.document)
162
+ newOptions.document = document;
163
+ return newOptions;
172
164
  }
173
165
 
174
- const defaultOptions = {
175
- document: undefined,
176
- shape: exports.ShapeType.square,
177
- width: undefined,
178
- height: undefined,
179
- data: "",
180
- qrOptions: {
181
- typeNumber: TypeNumber[0],
182
- mode: undefined,
183
- errorCorrectionLevel: exports.ErrorCorrectionLevel.Q
184
- },
185
- imageOptions: {
186
- hideBackgroundDots: true,
187
- imageSize: 0.4,
188
- crossOrigin: undefined,
189
- margin: 0
190
- },
191
- dotsOptions: {
192
- type: exports.DotType.square,
193
- color: "#000"
194
- }
166
+ const defaultOptions = {
167
+ document: undefined,
168
+ shape: exports.ShapeType.square,
169
+ width: undefined,
170
+ height: undefined,
171
+ data: "",
172
+ qrOptions: {
173
+ typeNumber: TypeNumber[0],
174
+ mode: undefined,
175
+ errorCorrectionLevel: exports.ErrorCorrectionLevel.Q
176
+ },
177
+ imageOptions: {
178
+ hideBackgroundDots: true,
179
+ imageSize: 0.4,
180
+ crossOrigin: undefined,
181
+ margin: 0
182
+ },
183
+ dotsOptions: {
184
+ type: exports.DotType.square,
185
+ color: "#000"
186
+ }
195
187
  };
196
188
 
197
- class QRCornerDot {
198
- constructor({ svg, type, document }) {
199
- this._svg = svg;
200
- this._type = type;
201
- this._document = document;
202
- }
203
- draw(x, y, size, rotation) {
204
- const type = this._type;
205
- let drawFunction;
206
- switch (type) {
207
- case exports.CornerDotType.square:
208
- drawFunction = this._drawSquare;
209
- break;
210
- case exports.CornerDotType.dot:
211
- default:
212
- drawFunction = this._drawDot;
213
- }
214
- drawFunction.call(this, { x, y, size, rotation });
215
- }
216
- _rotateFigure({ x, y, size, rotation = 0, draw }) {
217
- const cx = x + size / 2;
218
- const cy = y + size / 2;
219
- draw();
220
- this._element?.setAttribute("transform", `rotate(${(180 * rotation) / Math.PI},${cx},${cy})`);
221
- }
222
- _basicDot(args) {
223
- const { size, x, y } = args;
224
- this._rotateFigure({
225
- ...args,
226
- draw: () => {
227
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "circle");
228
- this._element.setAttribute("cx", String(x + size / 2));
229
- this._element.setAttribute("cy", String(y + size / 2));
230
- this._element.setAttribute("r", String(size / 2));
231
- }
232
- });
233
- }
234
- _basicSquare(args) {
235
- const { size, x, y } = args;
236
- this._rotateFigure({
237
- ...args,
238
- draw: () => {
239
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "rect");
240
- this._element.setAttribute("x", String(x));
241
- this._element.setAttribute("y", String(y));
242
- this._element.setAttribute("width", String(size));
243
- this._element.setAttribute("height", String(size));
244
- }
245
- });
246
- }
247
- _drawDot({ x, y, size, rotation }) {
248
- this._basicDot({ x, y, size, rotation });
249
- }
250
- _drawSquare({ x, y, size, rotation }) {
251
- this._basicSquare({ x, y, size, rotation });
252
- }
189
+ class QRCornerDot {
190
+ constructor({ svg, type, document }) {
191
+ this._svg = svg;
192
+ this._type = type;
193
+ this._document = document;
194
+ }
195
+ draw(x, y, size, rotation) {
196
+ const type = this._type;
197
+ let drawFunction;
198
+ switch (type) {
199
+ case exports.CornerDotType.square:
200
+ drawFunction = this._drawSquare;
201
+ break;
202
+ case exports.CornerDotType.dot:
203
+ default:
204
+ drawFunction = this._drawDot;
205
+ }
206
+ drawFunction.call(this, { x, y, size, rotation });
207
+ }
208
+ _rotateFigure({ x, y, size, rotation = 0, draw }) {
209
+ const cx = x + size / 2;
210
+ const cy = y + size / 2;
211
+ draw();
212
+ this._element?.setAttribute("transform", `rotate(${(180 * rotation) / Math.PI},${cx},${cy})`);
213
+ }
214
+ _basicDot(args) {
215
+ const { size, x, y } = args;
216
+ this._rotateFigure({
217
+ ...args,
218
+ draw: () => {
219
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "circle");
220
+ this._element.setAttribute("cx", String(x + size / 2));
221
+ this._element.setAttribute("cy", String(y + size / 2));
222
+ this._element.setAttribute("r", String(size / 2));
223
+ }
224
+ });
225
+ }
226
+ _basicSquare(args) {
227
+ const { size, x, y } = args;
228
+ this._rotateFigure({
229
+ ...args,
230
+ draw: () => {
231
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "rect");
232
+ this._element.setAttribute("x", String(x));
233
+ this._element.setAttribute("y", String(y));
234
+ this._element.setAttribute("width", String(size));
235
+ this._element.setAttribute("height", String(size));
236
+ }
237
+ });
238
+ }
239
+ _drawDot({ x, y, size, rotation }) {
240
+ this._basicDot({ x, y, size, rotation });
241
+ }
242
+ _drawSquare({ x, y, size, rotation }) {
243
+ this._basicSquare({ x, y, size, rotation });
244
+ }
253
245
  }
254
246
 
255
- class QRCornerSquare {
256
- constructor({ svg, type, document }) {
257
- this._svg = svg;
258
- this._type = type;
259
- this._document = document;
260
- }
261
- draw(x, y, size, rotation) {
262
- const type = this._type;
263
- let drawFunction;
264
- switch (type) {
265
- case exports.CornerSquareType.square:
266
- drawFunction = this._drawSquare;
267
- break;
268
- case exports.CornerSquareType.extraRounded:
269
- drawFunction = this._drawExtraRounded;
270
- break;
271
- case exports.CornerSquareType.dot:
272
- default:
273
- drawFunction = this._drawDot;
274
- }
275
- drawFunction.call(this, { x, y, size, rotation });
276
- }
277
- _rotateFigure({ x, y, size, rotation = 0, draw }) {
278
- const cx = x + size / 2;
279
- const cy = y + size / 2;
280
- draw();
281
- this._element?.setAttribute("transform", `rotate(${(180 * rotation) / Math.PI},${cx},${cy})`);
282
- }
283
- _basicDot(args) {
284
- const { size, x, y } = args;
285
- const dotSize = size / 7;
286
- this._rotateFigure({
287
- ...args,
288
- draw: () => {
289
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
290
- this._element.setAttribute("clip-rule", "evenodd");
291
- this._element.setAttribute("d", `M ${x + size / 2} ${y}` + // M cx, y // Move to top of ring
292
- `a ${size / 2} ${size / 2} 0 1 0 0.1 0` + // a outerRadius, outerRadius, 0, 1, 0, 1, 0 // Draw outer arc, but don't close it
293
- `z` + // Z // Close the outer shape
294
- `m 0 ${dotSize}` + // m -1 outerRadius-innerRadius // Move to top point of inner radius
295
- `a ${size / 2 - dotSize} ${size / 2 - dotSize} 0 1 1 -0.1 0` + // a innerRadius, innerRadius, 0, 1, 1, -1, 0 // Draw inner arc, but don't close it
296
- `Z` // Z // Close the inner ring. Actually will still work without, but inner ring will have one unit missing in stroke
297
- );
298
- }
299
- });
300
- }
301
- _basicSquare(args) {
302
- const { size, x, y } = args;
303
- const dotSize = size / 7;
304
- this._rotateFigure({
305
- ...args,
306
- draw: () => {
307
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
308
- this._element.setAttribute("clip-rule", "evenodd");
309
- this._element.setAttribute("d", `M ${x} ${y}` +
310
- `v ${size}` +
311
- `h ${size}` +
312
- `v ${-size}` +
313
- `z` +
314
- `M ${x + dotSize} ${y + dotSize}` +
315
- `h ${size - 2 * dotSize}` +
316
- `v ${size - 2 * dotSize}` +
317
- `h ${-size + 2 * dotSize}` +
318
- `z`);
319
- }
320
- });
321
- }
322
- _basicExtraRounded(args) {
323
- const { size, x, y } = args;
324
- const dotSize = size / 7;
325
- this._rotateFigure({
326
- ...args,
327
- draw: () => {
328
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
329
- this._element.setAttribute("clip-rule", "evenodd");
330
- this._element.setAttribute("d", `M ${x} ${y + 2.5 * dotSize}` +
331
- `v ${2 * dotSize}` +
332
- `a ${2.5 * dotSize} ${2.5 * dotSize}, 0, 0, 0, ${dotSize * 2.5} ${dotSize * 2.5}` +
333
- `h ${2 * dotSize}` +
334
- `a ${2.5 * dotSize} ${2.5 * dotSize}, 0, 0, 0, ${dotSize * 2.5} ${-dotSize * 2.5}` +
335
- `v ${-2 * dotSize}` +
336
- `a ${2.5 * dotSize} ${2.5 * dotSize}, 0, 0, 0, ${-dotSize * 2.5} ${-dotSize * 2.5}` +
337
- `h ${-2 * dotSize}` +
338
- `a ${2.5 * dotSize} ${2.5 * dotSize}, 0, 0, 0, ${-dotSize * 2.5} ${dotSize * 2.5}` +
339
- `M ${x + 2.5 * dotSize} ${y + dotSize}` +
340
- `h ${2 * dotSize}` +
341
- `a ${1.5 * dotSize} ${1.5 * dotSize}, 0, 0, 1, ${dotSize * 1.5} ${dotSize * 1.5}` +
342
- `v ${2 * dotSize}` +
343
- `a ${1.5 * dotSize} ${1.5 * dotSize}, 0, 0, 1, ${-dotSize * 1.5} ${dotSize * 1.5}` +
344
- `h ${-2 * dotSize}` +
345
- `a ${1.5 * dotSize} ${1.5 * dotSize}, 0, 0, 1, ${-dotSize * 1.5} ${-dotSize * 1.5}` +
346
- `v ${-2 * dotSize}` +
347
- `a ${1.5 * dotSize} ${1.5 * dotSize}, 0, 0, 1, ${dotSize * 1.5} ${-dotSize * 1.5}`);
348
- }
349
- });
350
- }
351
- _drawDot({ x, y, size, rotation }) {
352
- this._basicDot({ x, y, size, rotation });
353
- }
354
- _drawSquare({ x, y, size, rotation }) {
355
- this._basicSquare({ x, y, size, rotation });
356
- }
357
- _drawExtraRounded({ x, y, size, rotation }) {
358
- this._basicExtraRounded({ x, y, size, rotation });
359
- }
247
+ class QRCornerSquare {
248
+ constructor({ svg, type, document }) {
249
+ this._svg = svg;
250
+ this._type = type;
251
+ this._document = document;
252
+ }
253
+ draw(x, y, size, rotation) {
254
+ const type = this._type;
255
+ let drawFunction;
256
+ switch (type) {
257
+ case exports.CornerSquareType.square:
258
+ drawFunction = this._drawSquare;
259
+ break;
260
+ case exports.CornerSquareType.extraRounded:
261
+ drawFunction = this._drawExtraRounded;
262
+ break;
263
+ case exports.CornerSquareType.dot:
264
+ default:
265
+ drawFunction = this._drawDot;
266
+ }
267
+ drawFunction.call(this, { x, y, size, rotation });
268
+ }
269
+ _rotateFigure({ x, y, size, rotation = 0, draw }) {
270
+ const cx = x + size / 2;
271
+ const cy = y + size / 2;
272
+ draw();
273
+ this._element?.setAttribute("transform", `rotate(${(180 * rotation) / Math.PI},${cx},${cy})`);
274
+ }
275
+ _basicDot(args) {
276
+ const { size, x, y } = args;
277
+ const dotSize = size / 7;
278
+ this._rotateFigure({
279
+ ...args,
280
+ draw: () => {
281
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
282
+ this._element.setAttribute("clip-rule", "evenodd");
283
+ this._element.setAttribute("d", `M ${x + size / 2} ${y}` + // M cx, y // Move to top of ring
284
+ `a ${size / 2} ${size / 2} 0 1 0 0.1 0` + // a outerRadius, outerRadius, 0, 1, 0, 1, 0 // Draw outer arc, but don't close it
285
+ `z` + // Z // Close the outer shape
286
+ `m 0 ${dotSize}` + // m -1 outerRadius-innerRadius // Move to top point of inner radius
287
+ `a ${size / 2 - dotSize} ${size / 2 - dotSize} 0 1 1 -0.1 0` + // a innerRadius, innerRadius, 0, 1, 1, -1, 0 // Draw inner arc, but don't close it
288
+ `Z` // Z // Close the inner ring. Actually will still work without, but inner ring will have one unit missing in stroke
289
+ );
290
+ }
291
+ });
292
+ }
293
+ _basicSquare(args) {
294
+ const { size, x, y } = args;
295
+ const dotSize = size / 7;
296
+ this._rotateFigure({
297
+ ...args,
298
+ draw: () => {
299
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
300
+ this._element.setAttribute("clip-rule", "evenodd");
301
+ this._element.setAttribute("d", `M ${x} ${y}` +
302
+ `v ${size}` +
303
+ `h ${size}` +
304
+ `v ${-size}` +
305
+ `z` +
306
+ `M ${x + dotSize} ${y + dotSize}` +
307
+ `h ${size - 2 * dotSize}` +
308
+ `v ${size - 2 * dotSize}` +
309
+ `h ${-size + 2 * dotSize}` +
310
+ `z`);
311
+ }
312
+ });
313
+ }
314
+ _basicExtraRounded(args) {
315
+ const { size, x, y } = args;
316
+ const dotSize = size / 7;
317
+ this._rotateFigure({
318
+ ...args,
319
+ draw: () => {
320
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
321
+ this._element.setAttribute("clip-rule", "evenodd");
322
+ this._element.setAttribute("d", `M ${x} ${y + 2.5 * dotSize}` +
323
+ `v ${2 * dotSize}` +
324
+ `a ${2.5 * dotSize} ${2.5 * dotSize}, 0, 0, 0, ${dotSize * 2.5} ${dotSize * 2.5}` +
325
+ `h ${2 * dotSize}` +
326
+ `a ${2.5 * dotSize} ${2.5 * dotSize}, 0, 0, 0, ${dotSize * 2.5} ${-dotSize * 2.5}` +
327
+ `v ${-2 * dotSize}` +
328
+ `a ${2.5 * dotSize} ${2.5 * dotSize}, 0, 0, 0, ${-dotSize * 2.5} ${-dotSize * 2.5}` +
329
+ `h ${-2 * dotSize}` +
330
+ `a ${2.5 * dotSize} ${2.5 * dotSize}, 0, 0, 0, ${-dotSize * 2.5} ${dotSize * 2.5}` +
331
+ `M ${x + 2.5 * dotSize} ${y + dotSize}` +
332
+ `h ${2 * dotSize}` +
333
+ `a ${1.5 * dotSize} ${1.5 * dotSize}, 0, 0, 1, ${dotSize * 1.5} ${dotSize * 1.5}` +
334
+ `v ${2 * dotSize}` +
335
+ `a ${1.5 * dotSize} ${1.5 * dotSize}, 0, 0, 1, ${-dotSize * 1.5} ${dotSize * 1.5}` +
336
+ `h ${-2 * dotSize}` +
337
+ `a ${1.5 * dotSize} ${1.5 * dotSize}, 0, 0, 1, ${-dotSize * 1.5} ${-dotSize * 1.5}` +
338
+ `v ${-2 * dotSize}` +
339
+ `a ${1.5 * dotSize} ${1.5 * dotSize}, 0, 0, 1, ${dotSize * 1.5} ${-dotSize * 1.5}`);
340
+ }
341
+ });
342
+ }
343
+ _drawDot({ x, y, size, rotation }) {
344
+ this._basicDot({ x, y, size, rotation });
345
+ }
346
+ _drawSquare({ x, y, size, rotation }) {
347
+ this._basicSquare({ x, y, size, rotation });
348
+ }
349
+ _drawExtraRounded({ x, y, size, rotation }) {
350
+ this._basicExtraRounded({ x, y, size, rotation });
351
+ }
360
352
  }
361
353
 
362
- class QRDot {
363
- constructor({ svg, type, document }) {
364
- this._svg = svg;
365
- this._type = type;
366
- this._document = document;
367
- }
368
- draw(x, y, size, getNeighbor) {
369
- const type = this._type;
370
- let drawFunction;
371
- switch (type) {
372
- case exports.DotType.dots:
373
- drawFunction = this._drawDot;
374
- break;
375
- case exports.DotType.classy:
376
- drawFunction = this._drawClassy;
377
- break;
378
- case exports.DotType.classyRounded:
379
- drawFunction = this._drawClassyRounded;
380
- break;
381
- case exports.DotType.rounded:
382
- drawFunction = this._drawRounded;
383
- break;
384
- case exports.DotType.extraRounded:
385
- drawFunction = this._drawExtraRounded;
386
- break;
387
- case exports.DotType.square:
388
- default:
389
- drawFunction = this._drawSquare;
390
- }
391
- drawFunction.call(this, { x, y, size, getNeighbor });
392
- }
393
- _rotateFigure({ x, y, size, rotation = 0, draw }) {
394
- const cx = x + size / 2;
395
- const cy = y + size / 2;
396
- draw();
397
- this._element?.setAttribute("transform", `rotate(${(180 * rotation) / Math.PI},${cx},${cy})`);
398
- }
399
- _basicDot(args) {
400
- const { size, x, y } = args;
401
- this._rotateFigure({
402
- ...args,
403
- draw: () => {
404
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "circle");
405
- this._element.setAttribute("cx", String(x + size / 2));
406
- this._element.setAttribute("cy", String(y + size / 2));
407
- this._element.setAttribute("r", String(size / 2));
408
- }
409
- });
410
- }
411
- _basicSquare(args) {
412
- const { size, x, y } = args;
413
- this._rotateFigure({
414
- ...args,
415
- draw: () => {
416
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "rect");
417
- this._element.setAttribute("x", String(x));
418
- this._element.setAttribute("y", String(y));
419
- this._element.setAttribute("width", String(size));
420
- this._element.setAttribute("height", String(size));
421
- }
422
- });
423
- }
424
- //if rotation === 0 - right side is rounded
425
- _basicSideRounded(args) {
426
- const { size, x, y } = args;
427
- this._rotateFigure({
428
- ...args,
429
- draw: () => {
430
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
431
- this._element.setAttribute("d", `M ${x} ${y}` + //go to top left position
432
- `v ${size}` + //draw line to left bottom corner
433
- `h ${size / 2}` + //draw line to left bottom corner + half of size right
434
- `a ${size / 2} ${size / 2}, 0, 0, 0, 0 ${-size}` // draw rounded corner
435
- );
436
- }
437
- });
438
- }
439
- //if rotation === 0 - top right corner is rounded
440
- _basicCornerRounded(args) {
441
- const { size, x, y } = args;
442
- this._rotateFigure({
443
- ...args,
444
- draw: () => {
445
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
446
- this._element.setAttribute("d", `M ${x} ${y}` + //go to top left position
447
- `v ${size}` + //draw line to left bottom corner
448
- `h ${size}` + //draw line to right bottom corner
449
- `v ${-size / 2}` + //draw line to right bottom corner + half of size top
450
- `a ${size / 2} ${size / 2}, 0, 0, 0, ${-size / 2} ${-size / 2}` // draw rounded corner
451
- );
452
- }
453
- });
454
- }
455
- //if rotation === 0 - top right corner is rounded
456
- _basicCornerExtraRounded(args) {
457
- const { size, x, y } = args;
458
- this._rotateFigure({
459
- ...args,
460
- draw: () => {
461
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
462
- this._element.setAttribute("d", `M ${x} ${y}` + //go to top left position
463
- `v ${size}` + //draw line to left bottom corner
464
- `h ${size}` + //draw line to right bottom corner
465
- `a ${size} ${size}, 0, 0, 0, ${-size} ${-size}` // draw rounded top right corner
466
- );
467
- }
468
- });
469
- }
470
- //if rotation === 0 - left bottom and right top corners are rounded
471
- _basicCornersRounded(args) {
472
- const { size, x, y } = args;
473
- this._rotateFigure({
474
- ...args,
475
- draw: () => {
476
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
477
- this._element.setAttribute("d", `M ${x} ${y}` + //go to left top position
478
- `v ${size / 2}` + //draw line to left top corner + half of size bottom
479
- `a ${size / 2} ${size / 2}, 0, 0, 0, ${size / 2} ${size / 2}` + // draw rounded left bottom corner
480
- `h ${size / 2}` + //draw line to right bottom corner
481
- `v ${-size / 2}` + //draw line to right bottom corner + half of size top
482
- `a ${size / 2} ${size / 2}, 0, 0, 0, ${-size / 2} ${-size / 2}` // draw rounded right top corner
483
- );
484
- }
485
- });
486
- }
487
- _drawDot({ x, y, size }) {
488
- this._basicDot({ x, y, size, rotation: 0 });
489
- }
490
- _drawSquare({ x, y, size }) {
491
- this._basicSquare({ x, y, size, rotation: 0 });
492
- }
493
- _drawRounded({ x, y, size, getNeighbor }) {
494
- const leftNeighbor = getNeighbor ? +getNeighbor(-1, 0) : 0;
495
- const rightNeighbor = getNeighbor ? +getNeighbor(1, 0) : 0;
496
- const topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0;
497
- const bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0;
498
- const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor;
499
- if (neighborsCount === 0) {
500
- this._basicDot({ x, y, size, rotation: 0 });
501
- return;
502
- }
503
- if (neighborsCount > 2 || (leftNeighbor && rightNeighbor) || (topNeighbor && bottomNeighbor)) {
504
- this._basicSquare({ x, y, size, rotation: 0 });
505
- return;
506
- }
507
- if (neighborsCount === 2) {
508
- let rotation = 0;
509
- if (leftNeighbor && topNeighbor) {
510
- rotation = Math.PI / 2;
511
- }
512
- else if (topNeighbor && rightNeighbor) {
513
- rotation = Math.PI;
514
- }
515
- else if (rightNeighbor && bottomNeighbor) {
516
- rotation = -Math.PI / 2;
517
- }
518
- this._basicCornerRounded({ x, y, size, rotation });
519
- return;
520
- }
521
- if (neighborsCount === 1) {
522
- let rotation = 0;
523
- if (topNeighbor) {
524
- rotation = Math.PI / 2;
525
- }
526
- else if (rightNeighbor) {
527
- rotation = Math.PI;
528
- }
529
- else if (bottomNeighbor) {
530
- rotation = -Math.PI / 2;
531
- }
532
- this._basicSideRounded({ x, y, size, rotation });
533
- return;
534
- }
535
- }
536
- _drawExtraRounded({ x, y, size, getNeighbor }) {
537
- const leftNeighbor = getNeighbor ? +getNeighbor(-1, 0) : 0;
538
- const rightNeighbor = getNeighbor ? +getNeighbor(1, 0) : 0;
539
- const topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0;
540
- const bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0;
541
- const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor;
542
- if (neighborsCount === 0) {
543
- this._basicDot({ x, y, size, rotation: 0 });
544
- return;
545
- }
546
- if (neighborsCount > 2 || (leftNeighbor && rightNeighbor) || (topNeighbor && bottomNeighbor)) {
547
- this._basicSquare({ x, y, size, rotation: 0 });
548
- return;
549
- }
550
- if (neighborsCount === 2) {
551
- let rotation = 0;
552
- if (leftNeighbor && topNeighbor) {
553
- rotation = Math.PI / 2;
554
- }
555
- else if (topNeighbor && rightNeighbor) {
556
- rotation = Math.PI;
557
- }
558
- else if (rightNeighbor && bottomNeighbor) {
559
- rotation = -Math.PI / 2;
560
- }
561
- this._basicCornerExtraRounded({ x, y, size, rotation });
562
- return;
563
- }
564
- if (neighborsCount === 1) {
565
- let rotation = 0;
566
- if (topNeighbor) {
567
- rotation = Math.PI / 2;
568
- }
569
- else if (rightNeighbor) {
570
- rotation = Math.PI;
571
- }
572
- else if (bottomNeighbor) {
573
- rotation = -Math.PI / 2;
574
- }
575
- this._basicSideRounded({ x, y, size, rotation });
576
- return;
577
- }
578
- }
579
- _drawClassy({ x, y, size, getNeighbor }) {
580
- const leftNeighbor = getNeighbor ? +getNeighbor(-1, 0) : 0;
581
- const rightNeighbor = getNeighbor ? +getNeighbor(1, 0) : 0;
582
- const topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0;
583
- const bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0;
584
- const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor;
585
- if (neighborsCount === 0) {
586
- this._basicCornersRounded({ x, y, size, rotation: Math.PI / 2 });
587
- return;
588
- }
589
- if (!leftNeighbor && !topNeighbor) {
590
- this._basicCornerRounded({ x, y, size, rotation: -Math.PI / 2 });
591
- return;
592
- }
593
- if (!rightNeighbor && !bottomNeighbor) {
594
- this._basicCornerRounded({ x, y, size, rotation: Math.PI / 2 });
595
- return;
596
- }
597
- this._basicSquare({ x, y, size, rotation: 0 });
598
- }
599
- _drawClassyRounded({ x, y, size, getNeighbor }) {
600
- const leftNeighbor = getNeighbor ? +getNeighbor(-1, 0) : 0;
601
- const rightNeighbor = getNeighbor ? +getNeighbor(1, 0) : 0;
602
- const topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0;
603
- const bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0;
604
- const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor;
605
- if (neighborsCount === 0) {
606
- this._basicCornersRounded({ x, y, size, rotation: Math.PI / 2 });
607
- return;
608
- }
609
- if (!leftNeighbor && !topNeighbor) {
610
- this._basicCornerExtraRounded({ x, y, size, rotation: -Math.PI / 2 });
611
- return;
612
- }
613
- if (!rightNeighbor && !bottomNeighbor) {
614
- this._basicCornerExtraRounded({ x, y, size, rotation: Math.PI / 2 });
615
- return;
616
- }
617
- this._basicSquare({ x, y, size, rotation: 0 });
618
- }
354
+ class QRDot {
355
+ constructor({ svg, type, document }) {
356
+ this._svg = svg;
357
+ this._type = type;
358
+ this._document = document;
359
+ }
360
+ draw(x, y, size, getNeighbor) {
361
+ const type = this._type;
362
+ let drawFunction;
363
+ switch (type) {
364
+ case exports.DotType.dots:
365
+ drawFunction = this._drawDot;
366
+ break;
367
+ case exports.DotType.classy:
368
+ drawFunction = this._drawClassy;
369
+ break;
370
+ case exports.DotType.classyRounded:
371
+ drawFunction = this._drawClassyRounded;
372
+ break;
373
+ case exports.DotType.rounded:
374
+ drawFunction = this._drawRounded;
375
+ break;
376
+ case exports.DotType.extraRounded:
377
+ drawFunction = this._drawExtraRounded;
378
+ break;
379
+ case exports.DotType.square:
380
+ default:
381
+ drawFunction = this._drawSquare;
382
+ }
383
+ drawFunction.call(this, { x, y, size, getNeighbor });
384
+ }
385
+ _rotateFigure({ x, y, size, rotation = 0, draw }) {
386
+ const cx = x + size / 2;
387
+ const cy = y + size / 2;
388
+ draw();
389
+ this._element?.setAttribute("transform", `rotate(${(180 * rotation) / Math.PI},${cx},${cy})`);
390
+ }
391
+ _basicDot(args) {
392
+ const { size, x, y } = args;
393
+ this._rotateFigure({
394
+ ...args,
395
+ draw: () => {
396
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "circle");
397
+ this._element.setAttribute("cx", String(x + size / 2));
398
+ this._element.setAttribute("cy", String(y + size / 2));
399
+ this._element.setAttribute("r", String(size / 2));
400
+ }
401
+ });
402
+ }
403
+ _basicSquare(args) {
404
+ const { size, x, y } = args;
405
+ this._rotateFigure({
406
+ ...args,
407
+ draw: () => {
408
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "rect");
409
+ this._element.setAttribute("x", String(x));
410
+ this._element.setAttribute("y", String(y));
411
+ this._element.setAttribute("width", String(size));
412
+ this._element.setAttribute("height", String(size));
413
+ }
414
+ });
415
+ }
416
+ //if rotation === 0 - right side is rounded
417
+ _basicSideRounded(args) {
418
+ const { size, x, y } = args;
419
+ this._rotateFigure({
420
+ ...args,
421
+ draw: () => {
422
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
423
+ this._element.setAttribute("d", `M ${x} ${y}` + //go to top left position
424
+ `v ${size}` + //draw line to left bottom corner
425
+ `h ${size / 2}` + //draw line to left bottom corner + half of size right
426
+ `a ${size / 2} ${size / 2}, 0, 0, 0, 0 ${-size}` // draw rounded corner
427
+ );
428
+ }
429
+ });
430
+ }
431
+ //if rotation === 0 - top right corner is rounded
432
+ _basicCornerRounded(args) {
433
+ const { size, x, y } = args;
434
+ this._rotateFigure({
435
+ ...args,
436
+ draw: () => {
437
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
438
+ this._element.setAttribute("d", `M ${x} ${y}` + //go to top left position
439
+ `v ${size}` + //draw line to left bottom corner
440
+ `h ${size}` + //draw line to right bottom corner
441
+ `v ${-size / 2}` + //draw line to right bottom corner + half of size top
442
+ `a ${size / 2} ${size / 2}, 0, 0, 0, ${-size / 2} ${-size / 2}` // draw rounded corner
443
+ );
444
+ }
445
+ });
446
+ }
447
+ //if rotation === 0 - top right corner is rounded
448
+ _basicCornerExtraRounded(args) {
449
+ const { size, x, y } = args;
450
+ this._rotateFigure({
451
+ ...args,
452
+ draw: () => {
453
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
454
+ this._element.setAttribute("d", `M ${x} ${y}` + //go to top left position
455
+ `v ${size}` + //draw line to left bottom corner
456
+ `h ${size}` + //draw line to right bottom corner
457
+ `a ${size} ${size}, 0, 0, 0, ${-size} ${-size}` // draw rounded top right corner
458
+ );
459
+ }
460
+ });
461
+ }
462
+ //if rotation === 0 - left bottom and right top corners are rounded
463
+ _basicCornersRounded(args) {
464
+ const { size, x, y } = args;
465
+ this._rotateFigure({
466
+ ...args,
467
+ draw: () => {
468
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "path");
469
+ this._element.setAttribute("d", `M ${x} ${y}` + //go to left top position
470
+ `v ${size / 2}` + //draw line to left top corner + half of size bottom
471
+ `a ${size / 2} ${size / 2}, 0, 0, 0, ${size / 2} ${size / 2}` + // draw rounded left bottom corner
472
+ `h ${size / 2}` + //draw line to right bottom corner
473
+ `v ${-size / 2}` + //draw line to right bottom corner + half of size top
474
+ `a ${size / 2} ${size / 2}, 0, 0, 0, ${-size / 2} ${-size / 2}` // draw rounded right top corner
475
+ );
476
+ }
477
+ });
478
+ }
479
+ _drawDot({ x, y, size }) {
480
+ this._basicDot({ x, y, size, rotation: 0 });
481
+ }
482
+ _drawSquare({ x, y, size }) {
483
+ this._basicSquare({ x, y, size, rotation: 0 });
484
+ }
485
+ _drawRounded({ x, y, size, getNeighbor }) {
486
+ const leftNeighbor = getNeighbor ? +getNeighbor(-1, 0) : 0;
487
+ const rightNeighbor = getNeighbor ? +getNeighbor(1, 0) : 0;
488
+ const topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0;
489
+ const bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0;
490
+ const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor;
491
+ if (neighborsCount === 0) {
492
+ this._basicDot({ x, y, size, rotation: 0 });
493
+ return;
494
+ }
495
+ if (neighborsCount > 2 || (leftNeighbor && rightNeighbor) || (topNeighbor && bottomNeighbor)) {
496
+ this._basicSquare({ x, y, size, rotation: 0 });
497
+ return;
498
+ }
499
+ if (neighborsCount === 2) {
500
+ let rotation = 0;
501
+ if (leftNeighbor && topNeighbor) {
502
+ rotation = Math.PI / 2;
503
+ }
504
+ else if (topNeighbor && rightNeighbor) {
505
+ rotation = Math.PI;
506
+ }
507
+ else if (rightNeighbor && bottomNeighbor) {
508
+ rotation = -Math.PI / 2;
509
+ }
510
+ this._basicCornerRounded({ x, y, size, rotation });
511
+ return;
512
+ }
513
+ if (neighborsCount === 1) {
514
+ let rotation = 0;
515
+ if (topNeighbor) {
516
+ rotation = Math.PI / 2;
517
+ }
518
+ else if (rightNeighbor) {
519
+ rotation = Math.PI;
520
+ }
521
+ else if (bottomNeighbor) {
522
+ rotation = -Math.PI / 2;
523
+ }
524
+ this._basicSideRounded({ x, y, size, rotation });
525
+ return;
526
+ }
527
+ }
528
+ _drawExtraRounded({ x, y, size, getNeighbor }) {
529
+ const leftNeighbor = getNeighbor ? +getNeighbor(-1, 0) : 0;
530
+ const rightNeighbor = getNeighbor ? +getNeighbor(1, 0) : 0;
531
+ const topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0;
532
+ const bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0;
533
+ const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor;
534
+ if (neighborsCount === 0) {
535
+ this._basicDot({ x, y, size, rotation: 0 });
536
+ return;
537
+ }
538
+ if (neighborsCount > 2 || (leftNeighbor && rightNeighbor) || (topNeighbor && bottomNeighbor)) {
539
+ this._basicSquare({ x, y, size, rotation: 0 });
540
+ return;
541
+ }
542
+ if (neighborsCount === 2) {
543
+ let rotation = 0;
544
+ if (leftNeighbor && topNeighbor) {
545
+ rotation = Math.PI / 2;
546
+ }
547
+ else if (topNeighbor && rightNeighbor) {
548
+ rotation = Math.PI;
549
+ }
550
+ else if (rightNeighbor && bottomNeighbor) {
551
+ rotation = -Math.PI / 2;
552
+ }
553
+ this._basicCornerExtraRounded({ x, y, size, rotation });
554
+ return;
555
+ }
556
+ if (neighborsCount === 1) {
557
+ let rotation = 0;
558
+ if (topNeighbor) {
559
+ rotation = Math.PI / 2;
560
+ }
561
+ else if (rightNeighbor) {
562
+ rotation = Math.PI;
563
+ }
564
+ else if (bottomNeighbor) {
565
+ rotation = -Math.PI / 2;
566
+ }
567
+ this._basicSideRounded({ x, y, size, rotation });
568
+ return;
569
+ }
570
+ }
571
+ _drawClassy({ x, y, size, getNeighbor }) {
572
+ const leftNeighbor = getNeighbor ? +getNeighbor(-1, 0) : 0;
573
+ const rightNeighbor = getNeighbor ? +getNeighbor(1, 0) : 0;
574
+ const topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0;
575
+ const bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0;
576
+ const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor;
577
+ if (neighborsCount === 0) {
578
+ this._basicCornersRounded({ x, y, size, rotation: Math.PI / 2 });
579
+ return;
580
+ }
581
+ if (!leftNeighbor && !topNeighbor) {
582
+ this._basicCornerRounded({ x, y, size, rotation: -Math.PI / 2 });
583
+ return;
584
+ }
585
+ if (!rightNeighbor && !bottomNeighbor) {
586
+ this._basicCornerRounded({ x, y, size, rotation: Math.PI / 2 });
587
+ return;
588
+ }
589
+ this._basicSquare({ x, y, size, rotation: 0 });
590
+ }
591
+ _drawClassyRounded({ x, y, size, getNeighbor }) {
592
+ const leftNeighbor = getNeighbor ? +getNeighbor(-1, 0) : 0;
593
+ const rightNeighbor = getNeighbor ? +getNeighbor(1, 0) : 0;
594
+ const topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0;
595
+ const bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0;
596
+ const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor;
597
+ if (neighborsCount === 0) {
598
+ this._basicCornersRounded({ x, y, size, rotation: Math.PI / 2 });
599
+ return;
600
+ }
601
+ if (!leftNeighbor && !topNeighbor) {
602
+ this._basicCornerExtraRounded({ x, y, size, rotation: -Math.PI / 2 });
603
+ return;
604
+ }
605
+ if (!rightNeighbor && !bottomNeighbor) {
606
+ this._basicCornerExtraRounded({ x, y, size, rotation: Math.PI / 2 });
607
+ return;
608
+ }
609
+ this._basicSquare({ x, y, size, rotation: 0 });
610
+ }
619
611
  }
620
612
 
621
- function calculateImageSize({ originalHeight, originalWidth, maxHiddenDots, maxHiddenAxisDots, dotSize }) {
622
- const hideDots = { x: 0, y: 0 };
623
- const imageSize = { x: 0, y: 0 };
624
- if (originalHeight <= 0 || originalWidth <= 0 || maxHiddenDots <= 0 || dotSize <= 0) {
625
- return {
626
- height: 0,
627
- width: 0,
628
- hideYDots: 0,
629
- hideXDots: 0
630
- };
631
- }
632
- const k = originalHeight / originalWidth;
633
- //Getting the maximum possible axis hidden dots
634
- hideDots.x = Math.floor(Math.sqrt(maxHiddenDots / k));
635
- //The count of hidden dot's can't be less than 1
636
- if (hideDots.x <= 0)
637
- hideDots.x = 1;
638
- //Check the limit of the maximum allowed axis hidden dots
639
- if (maxHiddenAxisDots && maxHiddenAxisDots < hideDots.x)
640
- hideDots.x = maxHiddenAxisDots;
641
- //The count of dots should be odd
642
- if (hideDots.x % 2 === 0)
643
- hideDots.x--;
644
- imageSize.x = hideDots.x * dotSize;
645
- //Calculate opposite axis hidden dots based on axis value.
646
- //The value will be odd.
647
- //We use ceil to prevent dots covering by the image.
648
- hideDots.y = 1 + 2 * Math.ceil((hideDots.x * k - 1) / 2);
649
- imageSize.y = Math.round(imageSize.x * k);
650
- //If the result dots count is bigger than max - then decrease size and calculate again
651
- if (hideDots.y * hideDots.x > maxHiddenDots || (maxHiddenAxisDots && maxHiddenAxisDots < hideDots.y)) {
652
- if (maxHiddenAxisDots && maxHiddenAxisDots < hideDots.y) {
653
- hideDots.y = maxHiddenAxisDots;
654
- if (hideDots.y % 2 === 0)
655
- hideDots.x--;
656
- }
657
- else {
658
- hideDots.y -= 2;
659
- }
660
- imageSize.y = hideDots.y * dotSize;
661
- hideDots.x = 1 + 2 * Math.ceil((hideDots.y / k - 1) / 2);
662
- imageSize.x = Math.round(imageSize.y / k);
663
- }
664
- return {
665
- height: imageSize.y,
666
- width: imageSize.x,
667
- hideYDots: hideDots.y,
668
- hideXDots: hideDots.x
669
- };
613
+ function calculateImageSize({ originalHeight, originalWidth, maxHiddenDots, maxHiddenAxisDots, dotSize }) {
614
+ const hideDots = { x: 0, y: 0 };
615
+ const imageSize = { x: 0, y: 0 };
616
+ if (originalHeight <= 0 || originalWidth <= 0 || maxHiddenDots <= 0 || dotSize <= 0) {
617
+ return {
618
+ height: 0,
619
+ width: 0,
620
+ hideYDots: 0,
621
+ hideXDots: 0
622
+ };
623
+ }
624
+ const k = originalHeight / originalWidth;
625
+ //Getting the maximum possible axis hidden dots
626
+ hideDots.x = Math.floor(Math.sqrt(maxHiddenDots / k));
627
+ //The count of hidden dot's can't be less than 1
628
+ if (hideDots.x <= 0)
629
+ hideDots.x = 1;
630
+ //Check the limit of the maximum allowed axis hidden dots
631
+ if (maxHiddenAxisDots && maxHiddenAxisDots < hideDots.x)
632
+ hideDots.x = maxHiddenAxisDots;
633
+ //The count of dots should be odd
634
+ if (hideDots.x % 2 === 0)
635
+ hideDots.x--;
636
+ imageSize.x = hideDots.x * dotSize;
637
+ //Calculate opposite axis hidden dots based on axis value.
638
+ //The value will be odd.
639
+ //We use ceil to prevent dots covering by the image.
640
+ hideDots.y = 1 + 2 * Math.ceil((hideDots.x * k - 1) / 2);
641
+ imageSize.y = Math.round(imageSize.x * k);
642
+ //If the result dots count is bigger than max - then decrease size and calculate again
643
+ if (hideDots.y * hideDots.x > maxHiddenDots || (maxHiddenAxisDots && maxHiddenAxisDots < hideDots.y)) {
644
+ if (maxHiddenAxisDots && maxHiddenAxisDots < hideDots.y) {
645
+ hideDots.y = maxHiddenAxisDots;
646
+ if (hideDots.y % 2 === 0)
647
+ hideDots.x--;
648
+ }
649
+ else {
650
+ hideDots.y -= 2;
651
+ }
652
+ imageSize.y = hideDots.y * dotSize;
653
+ hideDots.x = 1 + 2 * Math.ceil((hideDots.y / k - 1) / 2);
654
+ imageSize.x = Math.round(imageSize.y / k);
655
+ }
656
+ return {
657
+ height: imageSize.y,
658
+ width: imageSize.x,
659
+ hideYDots: hideDots.y,
660
+ hideXDots: hideDots.x
661
+ };
670
662
  }
671
663
 
672
- const browserImageTools = {
673
- toDataURL(url) {
674
- return new Promise((resolve, reject) => {
675
- if (typeof url == "string") {
676
- const xhr = new XMLHttpRequest();
677
- xhr.onload = function () {
678
- const reader = new FileReader();
679
- reader.onloadend = function () {
680
- resolve(reader.result);
681
- };
682
- reader.readAsDataURL(xhr.response);
683
- };
684
- xhr.onerror = xhr.onabort = xhr.ontimeout = reject;
685
- xhr.open("GET", url);
686
- xhr.responseType = "blob";
687
- xhr.send();
688
- }
689
- else {
690
- const reader = new FileReader();
691
- reader.onloadend = function () {
692
- resolve(reader.result);
693
- };
694
- reader.readAsDataURL(url);
695
- }
696
- });
697
- },
698
- getSize(options) {
699
- return new Promise((resolve, reject) => {
700
- if (!options.image) {
701
- return reject("Image is not defined");
702
- }
703
- const image = new Image();
704
- if (typeof options.imageOptions.crossOrigin === "string") {
705
- image.crossOrigin = options.imageOptions.crossOrigin;
706
- }
707
- image.onload = () => {
708
- resolve({ width: image.width, height: image.height });
709
- };
710
- image.onerror = image.onabort = reject;
711
- if (typeof options.image == "string")
712
- image.src = options.image;
713
- else
714
- browserImageTools
715
- .toDataURL(options.image)
716
- .then((url) => (image.src = url))
717
- .catch(reject);
718
- });
719
- }
664
+ const browserImageTools = {
665
+ toDataURL(url) {
666
+ return new Promise((resolve, reject) => {
667
+ if (typeof url == "string") {
668
+ const xhr = new XMLHttpRequest();
669
+ xhr.onload = function () {
670
+ const reader = new FileReader();
671
+ reader.onloadend = function () {
672
+ resolve(reader.result);
673
+ };
674
+ reader.readAsDataURL(xhr.response);
675
+ };
676
+ xhr.onerror = xhr.onabort = xhr.ontimeout = reject;
677
+ xhr.open("GET", url);
678
+ xhr.responseType = "blob";
679
+ xhr.send();
680
+ }
681
+ else {
682
+ const reader = new FileReader();
683
+ reader.onloadend = function () {
684
+ resolve(reader.result);
685
+ };
686
+ reader.readAsDataURL(url);
687
+ }
688
+ });
689
+ },
690
+ getSize(options) {
691
+ return new Promise((resolve, reject) => {
692
+ if (!options.image) {
693
+ return reject("Image is not defined");
694
+ }
695
+ const image = new Image();
696
+ if (typeof options.imageOptions.crossOrigin === "string") {
697
+ image.crossOrigin = options.imageOptions.crossOrigin;
698
+ }
699
+ image.onload = () => {
700
+ resolve({ width: image.width, height: image.height });
701
+ };
702
+ image.onerror = image.onabort = reject;
703
+ if (typeof options.image == "string")
704
+ image.src = options.image;
705
+ else
706
+ browserImageTools
707
+ .toDataURL(options.image)
708
+ .then((url) => (image.src = url))
709
+ .catch(reject);
710
+ });
711
+ }
720
712
  };
721
713
 
722
- const squareMask = [
723
- [1, 1, 1, 1, 1, 1, 1],
724
- [1, 0, 0, 0, 0, 0, 1],
725
- [1, 0, 0, 0, 0, 0, 1],
726
- [1, 0, 0, 0, 0, 0, 1],
727
- [1, 0, 0, 0, 0, 0, 1],
728
- [1, 0, 0, 0, 0, 0, 1],
729
- [1, 1, 1, 1, 1, 1, 1]
730
- ];
731
- const dotMask = [
732
- [0, 0, 0, 0, 0, 0, 0],
733
- [0, 0, 0, 0, 0, 0, 0],
734
- [0, 0, 1, 1, 1, 0, 0],
735
- [0, 0, 1, 1, 1, 0, 0],
736
- [0, 0, 1, 1, 1, 0, 0],
737
- [0, 0, 0, 0, 0, 0, 0],
738
- [0, 0, 0, 0, 0, 0, 0]
739
- ];
740
- class QRSVG {
741
- //TODO don't pass all options to this class
742
- constructor(options) {
743
- this._document = options.document;
744
- this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "svg");
745
- this._element.setAttribute("width", String(options.width));
746
- this._element.setAttribute("height", String(options.height));
747
- this._element.setAttribute("viewBox", `0 0 ${options.width} ${options.height}`);
748
- this._defs = this._document.createElementNS("http://www.w3.org/2000/svg", "defs");
749
- this._element.appendChild(this._defs);
750
- this._imageTools = options.imageTools || browserImageTools;
751
- this._options = options;
752
- }
753
- get width() {
754
- return this._options.width;
755
- }
756
- get height() {
757
- return this._options.height;
758
- }
759
- getElement() {
760
- return this._element;
761
- }
762
- async drawQR(qr) {
763
- const count = qr.getModuleCount();
764
- const minSize = Math.min(this._options.width, this._options.height);
765
- const realQRSize = this._options.shape === exports.ShapeType.circle ? minSize / Math.sqrt(2) : minSize;
766
- const dotSize = Math.floor(realQRSize / count);
767
- let drawImageSize = {
768
- hideXDots: 0,
769
- hideYDots: 0,
770
- width: 0,
771
- height: 0
772
- };
773
- this._qr = qr;
774
- if (this._options.image) {
775
- //We need it to get image size
776
- const size = await this._imageTools.getSize(this._options);
777
- const { imageOptions, qrOptions } = this._options;
778
- const coverLevel = imageOptions.imageSize * ErrorCorrectionPercents[qrOptions.errorCorrectionLevel];
779
- const maxHiddenDots = Math.floor(coverLevel * count * count);
780
- drawImageSize = calculateImageSize({
781
- originalWidth: size.width,
782
- originalHeight: size.height,
783
- maxHiddenDots,
784
- maxHiddenAxisDots: count - 14,
785
- dotSize
786
- });
787
- }
788
- this.drawBackground();
789
- this.drawDots((i, j) => {
790
- if (this._options.imageOptions.hideBackgroundDots) {
791
- if (i >= (count - drawImageSize.hideXDots) / 2 &&
792
- i < (count + drawImageSize.hideXDots) / 2 &&
793
- j >= (count - drawImageSize.hideYDots) / 2 &&
794
- j < (count + drawImageSize.hideYDots) / 2) {
795
- return false;
796
- }
797
- }
798
- if (squareMask[i]?.[j] || squareMask[i - count + 7]?.[j] || squareMask[i]?.[j - count + 7]) {
799
- return false;
800
- }
801
- if (dotMask[i]?.[j] || dotMask[i - count + 7]?.[j] || dotMask[i]?.[j - count + 7]) {
802
- return false;
803
- }
804
- return true;
805
- });
806
- this.drawCorners();
807
- if (this._options.image) {
808
- await this.drawImage({ width: drawImageSize.width, height: drawImageSize.height, count, dotSize });
809
- }
810
- }
811
- drawBackground() {
812
- const element = this._element;
813
- const options = this._options;
814
- if (element && options.backgroundOptions) {
815
- const gradientOptions = options.backgroundOptions.gradient;
816
- const color = options.backgroundOptions.color;
817
- this._createColor({
818
- options: gradientOptions,
819
- color: color,
820
- additionalRotation: 0,
821
- x: 0,
822
- y: 0,
823
- height: options.height,
824
- width: options.width,
825
- name: "background-color"
826
- });
827
- const size = Math.min(options.width, options.height);
828
- const element = this._document.createElementNS("http://www.w3.org/2000/svg", "rect");
829
- this._backgroundClipPath = this._document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
830
- this._backgroundClipPath.setAttribute("id", "clip-path-background-color");
831
- this._defs.appendChild(this._backgroundClipPath);
832
- element.setAttribute("x", String((options.width - size) / 2));
833
- element.setAttribute("y", String((options.height - size) / 2));
834
- element.setAttribute("width", String(size));
835
- element.setAttribute("height", String(size));
836
- element.setAttribute("rx", String((size / 2) * (options.backgroundOptions.round || 0)));
837
- this._backgroundClipPath.appendChild(element);
838
- }
839
- }
840
- drawDots(filter) {
841
- if (!this._qr) {
842
- throw "QR code is not defined";
843
- }
844
- const options = this._options;
845
- const count = this._qr.getModuleCount();
846
- if (count > options.width || count > options.height) {
847
- throw "The canvas is too small.";
848
- }
849
- const minSize = Math.min(options.width, options.height);
850
- const realQRSize = options.shape === exports.ShapeType.circle ? minSize / Math.sqrt(2) : minSize;
851
- const dotSize = Math.floor(realQRSize / count);
852
- const xBeginning = Math.floor((options.width - count * dotSize) / 2);
853
- const yBeginning = Math.floor((options.height - count * dotSize) / 2);
854
- const dot = new QRDot({ svg: this._element, type: options.dotsOptions.type, document: this._document });
855
- this._dotsClipPath = this._document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
856
- this._dotsClipPath.setAttribute("id", "clip-path-dot-color");
857
- this._defs.appendChild(this._dotsClipPath);
858
- this._createColor({
859
- options: options.dotsOptions?.gradient,
860
- color: options.dotsOptions.color,
861
- additionalRotation: 0,
862
- x: 0,
863
- y: 0,
864
- height: options.height,
865
- width: options.width,
866
- name: "dot-color"
867
- });
868
- for (let i = 0; i < count; i++) {
869
- for (let j = 0; j < count; j++) {
870
- if (filter && !filter(i, j)) {
871
- continue;
872
- }
873
- if (!this._qr?.isDark(i, j)) {
874
- continue;
875
- }
876
- dot.draw(xBeginning + i * dotSize, yBeginning + j * dotSize, dotSize, (xOffset, yOffset) => {
877
- if (i + xOffset < 0 || j + yOffset < 0 || i + xOffset >= count || j + yOffset >= count)
878
- return false;
879
- if (filter && !filter(i + xOffset, j + yOffset))
880
- return false;
881
- return !!this._qr && this._qr.isDark(i + xOffset, j + yOffset);
882
- });
883
- if (dot._element && this._dotsClipPath) {
884
- this._dotsClipPath.appendChild(dot._element);
885
- }
886
- }
887
- }
888
- if (options.shape === exports.ShapeType.circle) {
889
- const additionalDots = Math.floor((minSize / dotSize - count) / 2);
890
- const fakeCount = count + additionalDots * 2;
891
- const xFakeBeginning = xBeginning - additionalDots * dotSize;
892
- const yFakeBeginning = yBeginning - additionalDots * dotSize;
893
- const fakeMatrix = [];
894
- const center = Math.floor(fakeCount / 2);
895
- for (let i = 0; i < fakeCount; i++) {
896
- fakeMatrix[i] = [];
897
- for (let j = 0; j < fakeCount; j++) {
898
- if (i >= additionalDots - 1 &&
899
- i <= fakeCount - additionalDots &&
900
- j >= additionalDots - 1 &&
901
- j <= fakeCount - additionalDots) {
902
- fakeMatrix[i][j] = 0;
903
- continue;
904
- }
905
- if (Math.sqrt((i - center) * (i - center) + (j - center) * (j - center)) > center) {
906
- fakeMatrix[i][j] = 0;
907
- continue;
908
- }
909
- //Get random dots from QR code to show it outside of QR code
910
- fakeMatrix[i][j] = this._qr.isDark(j - 2 * additionalDots < 0 ? j : j >= count ? j - 2 * additionalDots : j - additionalDots, i - 2 * additionalDots < 0 ? i : i >= count ? i - 2 * additionalDots : i - additionalDots)
911
- ? 1
912
- : 0;
913
- }
914
- }
915
- for (let i = 0; i < fakeCount; i++) {
916
- for (let j = 0; j < fakeCount; j++) {
917
- if (!fakeMatrix[i][j])
918
- continue;
919
- dot.draw(xFakeBeginning + i * dotSize, yFakeBeginning + j * dotSize, dotSize, (xOffset, yOffset) => {
920
- return !!fakeMatrix[i + xOffset]?.[j + yOffset];
921
- });
922
- if (dot._element && this._dotsClipPath) {
923
- this._dotsClipPath.appendChild(dot._element);
924
- }
925
- }
926
- }
927
- }
928
- }
929
- drawCorners() {
930
- if (!this._qr) {
931
- throw "QR code is not defined";
932
- }
933
- const element = this._element;
934
- const options = this._options;
935
- if (!element) {
936
- throw "Element code is not defined";
937
- }
938
- const count = this._qr.getModuleCount();
939
- const minSize = Math.min(options.width, options.height);
940
- const realQRSize = options.shape === exports.ShapeType.circle ? minSize / Math.sqrt(2) : minSize;
941
- const dotSize = Math.floor(realQRSize / count);
942
- const cornersSquareSize = dotSize * 7;
943
- const cornersDotSize = dotSize * 3;
944
- const xBeginning = Math.floor((options.width - count * dotSize) / 2);
945
- const yBeginning = Math.floor((options.height - count * dotSize) / 2);
946
- [
947
- [0, 0, 0],
948
- [1, 0, Math.PI / 2],
949
- [0, 1, -Math.PI / 2]
950
- ].forEach(([column, row, rotation]) => {
951
- const x = xBeginning + column * dotSize * (count - 7);
952
- const y = yBeginning + row * dotSize * (count - 7);
953
- let cornersSquareClipPath = this._dotsClipPath;
954
- let cornersDotClipPath = this._dotsClipPath;
955
- if (options.cornersSquareOptions?.gradient || options.cornersSquareOptions?.color) {
956
- cornersSquareClipPath = this._document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
957
- cornersSquareClipPath.setAttribute("id", `clip-path-corners-square-color-${column}-${row}`);
958
- this._defs.appendChild(cornersSquareClipPath);
959
- this._cornersSquareClipPath = this._cornersDotClipPath = cornersDotClipPath = cornersSquareClipPath;
960
- this._createColor({
961
- options: options.cornersSquareOptions?.gradient,
962
- color: options.cornersSquareOptions?.color,
963
- additionalRotation: rotation,
964
- x,
965
- y,
966
- height: cornersSquareSize,
967
- width: cornersSquareSize,
968
- name: `corners-square-color-${column}-${row}`
969
- });
970
- }
971
- if (options.cornersSquareOptions?.type) {
972
- const cornersSquare = new QRCornerSquare({
973
- svg: this._element,
974
- type: options.cornersSquareOptions.type,
975
- document: this._document
976
- });
977
- cornersSquare.draw(x, y, cornersSquareSize, rotation);
978
- if (cornersSquare._element && cornersSquareClipPath) {
979
- cornersSquareClipPath.appendChild(cornersSquare._element);
980
- }
981
- }
982
- else {
983
- const dot = new QRDot({ svg: this._element, type: options.dotsOptions.type, document: this._document });
984
- for (let i = 0; i < squareMask.length; i++) {
985
- for (let j = 0; j < squareMask[i].length; j++) {
986
- if (!squareMask[i]?.[j]) {
987
- continue;
988
- }
989
- dot.draw(x + i * dotSize, y + j * dotSize, dotSize, (xOffset, yOffset) => !!squareMask[i + xOffset]?.[j + yOffset]);
990
- if (dot._element && cornersSquareClipPath) {
991
- cornersSquareClipPath.appendChild(dot._element);
992
- }
993
- }
994
- }
995
- }
996
- if (options.cornersDotOptions?.gradient || options.cornersDotOptions?.color) {
997
- cornersDotClipPath = this._document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
998
- cornersDotClipPath.setAttribute("id", `clip-path-corners-dot-color-${column}-${row}`);
999
- this._defs.appendChild(cornersDotClipPath);
1000
- this._cornersDotClipPath = cornersDotClipPath;
1001
- this._createColor({
1002
- options: options.cornersDotOptions?.gradient,
1003
- color: options.cornersDotOptions?.color,
1004
- additionalRotation: rotation,
1005
- x: x + dotSize * 2,
1006
- y: y + dotSize * 2,
1007
- height: cornersDotSize,
1008
- width: cornersDotSize,
1009
- name: `corners-dot-color-${column}-${row}`
1010
- });
1011
- }
1012
- if (options.cornersDotOptions?.type) {
1013
- const cornersDot = new QRCornerDot({
1014
- svg: this._element,
1015
- type: options.cornersDotOptions.type,
1016
- document: this._document
1017
- });
1018
- cornersDot.draw(x + dotSize * 2, y + dotSize * 2, cornersDotSize, rotation);
1019
- if (cornersDot._element && cornersDotClipPath) {
1020
- cornersDotClipPath.appendChild(cornersDot._element);
1021
- }
1022
- }
1023
- else {
1024
- const dot = new QRDot({ svg: this._element, type: options.dotsOptions.type, document: this._document });
1025
- for (let i = 0; i < dotMask.length; i++) {
1026
- for (let j = 0; j < dotMask[i].length; j++) {
1027
- if (!dotMask[i]?.[j]) {
1028
- continue;
1029
- }
1030
- dot.draw(x + i * dotSize, y + j * dotSize, dotSize, (xOffset, yOffset) => !!dotMask[i + xOffset]?.[j + yOffset]);
1031
- if (dot._element && cornersDotClipPath) {
1032
- cornersDotClipPath.appendChild(dot._element);
1033
- }
1034
- }
1035
- }
1036
- }
1037
- });
1038
- }
1039
- async drawImage({ width, height, count, dotSize }) {
1040
- const options = this._options;
1041
- const xBeginning = Math.floor((options.width - count * dotSize) / 2);
1042
- const yBeginning = Math.floor((options.height - count * dotSize) / 2);
1043
- const margin = options.imageOptions.margin * dotSize;
1044
- const dx = xBeginning + margin + (count * dotSize - width) / 2;
1045
- const dy = yBeginning + margin + (count * dotSize - height) / 2;
1046
- const dw = width - margin * 2;
1047
- const dh = height - margin * 2;
1048
- const imageUrl = await this._imageTools.toDataURL(options.image || "");
1049
- let image = this._document.createElementNS("http://www.w3.org/2000/svg", "image");
1050
- image.setAttribute("href", imageUrl || "");
1051
- if (imageUrl.startsWith("data:image/svg+xml;")) {
1052
- let data = imageUrl.substring(19);
1053
- const i = data.indexOf(",");
1054
- const encoding = data.substring(0, i);
1055
- data = data.substring(i + 1);
1056
- switch (encoding) {
1057
- case "base64":
1058
- data = typeof atob == "function" ? atob(data) : Buffer.from(data, "base64").toString("utf8");
1059
- break;
1060
- default:
1061
- data = "";
1062
- break;
1063
- }
1064
- if (data) {
1065
- const container = this._document.createElement("div");
1066
- container.innerHTML = data;
1067
- const rootEl = container.querySelector("svg");
1068
- if (rootEl)
1069
- image = rootEl;
1070
- }
1071
- }
1072
- image.setAttribute("x", String(dx));
1073
- image.setAttribute("y", String(dy));
1074
- image.setAttribute("width", `${dw}px`);
1075
- image.setAttribute("height", `${dh}px`);
1076
- this._element.appendChild(image);
1077
- }
1078
- _createColor({ options, color, additionalRotation, x, y, height, width, name }) {
1079
- const size = width > height ? width : height;
1080
- const rect = this._document.createElementNS("http://www.w3.org/2000/svg", "rect");
1081
- rect.setAttribute("x", String(x));
1082
- rect.setAttribute("y", String(y));
1083
- rect.setAttribute("height", String(height));
1084
- rect.setAttribute("width", String(width));
1085
- rect.setAttribute("clip-path", `url('#clip-path-${name}')`);
1086
- if (options) {
1087
- let gradient;
1088
- if (options.type === exports.GradientType.radial) {
1089
- gradient = this._document.createElementNS("http://www.w3.org/2000/svg", "radialGradient");
1090
- gradient.setAttribute("id", name);
1091
- gradient.setAttribute("gradientUnits", "userSpaceOnUse");
1092
- gradient.setAttribute("fx", String(x + width / 2));
1093
- gradient.setAttribute("fy", String(y + height / 2));
1094
- gradient.setAttribute("cx", String(x + width / 2));
1095
- gradient.setAttribute("cy", String(y + height / 2));
1096
- gradient.setAttribute("r", String(size / 2));
1097
- }
1098
- else {
1099
- const rotation = ((options.rotation || 0) + additionalRotation) % (2 * Math.PI);
1100
- const positiveRotation = (rotation + 2 * Math.PI) % (2 * Math.PI);
1101
- let x0 = x + width / 2;
1102
- let y0 = y + height / 2;
1103
- let x1 = x + width / 2;
1104
- let y1 = y + height / 2;
1105
- if ((positiveRotation >= 0 && positiveRotation <= 0.25 * Math.PI) ||
1106
- (positiveRotation > 1.75 * Math.PI && positiveRotation <= 2 * Math.PI)) {
1107
- x0 = x0 - width / 2;
1108
- y0 = y0 - (height / 2) * Math.tan(rotation);
1109
- x1 = x1 + width / 2;
1110
- y1 = y1 + (height / 2) * Math.tan(rotation);
1111
- }
1112
- else if (positiveRotation > 0.25 * Math.PI && positiveRotation <= 0.75 * Math.PI) {
1113
- y0 = y0 - height / 2;
1114
- x0 = x0 - width / 2 / Math.tan(rotation);
1115
- y1 = y1 + height / 2;
1116
- x1 = x1 + width / 2 / Math.tan(rotation);
1117
- }
1118
- else if (positiveRotation > 0.75 * Math.PI && positiveRotation <= 1.25 * Math.PI) {
1119
- x0 = x0 + width / 2;
1120
- y0 = y0 + (height / 2) * Math.tan(rotation);
1121
- x1 = x1 - width / 2;
1122
- y1 = y1 - (height / 2) * Math.tan(rotation);
1123
- }
1124
- else if (positiveRotation > 1.25 * Math.PI && positiveRotation <= 1.75 * Math.PI) {
1125
- y0 = y0 + height / 2;
1126
- x0 = x0 + width / 2 / Math.tan(rotation);
1127
- y1 = y1 - height / 2;
1128
- x1 = x1 - width / 2 / Math.tan(rotation);
1129
- }
1130
- gradient = this._document.createElementNS("http://www.w3.org/2000/svg", "linearGradient");
1131
- gradient.setAttribute("id", name);
1132
- gradient.setAttribute("gradientUnits", "userSpaceOnUse");
1133
- gradient.setAttribute("x1", String(Math.round(x0)));
1134
- gradient.setAttribute("y1", String(Math.round(y0)));
1135
- gradient.setAttribute("x2", String(Math.round(x1)));
1136
- gradient.setAttribute("y2", String(Math.round(y1)));
1137
- }
1138
- options.colorStops.forEach(({ offset, color }) => {
1139
- const stop = this._document.createElementNS("http://www.w3.org/2000/svg", "stop");
1140
- stop.setAttribute("offset", `${100 * offset}%`);
1141
- stop.setAttribute("stop-color", color);
1142
- gradient.appendChild(stop);
1143
- });
1144
- rect.setAttribute("fill", `url('#${name}')`);
1145
- this._defs.appendChild(gradient);
1146
- }
1147
- else if (color) {
1148
- rect.setAttribute("fill", color);
1149
- }
1150
- this._element.appendChild(rect);
1151
- }
714
+ const squareMask = [
715
+ [1, 1, 1, 1, 1, 1, 1],
716
+ [1, 0, 0, 0, 0, 0, 1],
717
+ [1, 0, 0, 0, 0, 0, 1],
718
+ [1, 0, 0, 0, 0, 0, 1],
719
+ [1, 0, 0, 0, 0, 0, 1],
720
+ [1, 0, 0, 0, 0, 0, 1],
721
+ [1, 1, 1, 1, 1, 1, 1]
722
+ ];
723
+ const dotMask = [
724
+ [0, 0, 0, 0, 0, 0, 0],
725
+ [0, 0, 0, 0, 0, 0, 0],
726
+ [0, 0, 1, 1, 1, 0, 0],
727
+ [0, 0, 1, 1, 1, 0, 0],
728
+ [0, 0, 1, 1, 1, 0, 0],
729
+ [0, 0, 0, 0, 0, 0, 0],
730
+ [0, 0, 0, 0, 0, 0, 0]
731
+ ];
732
+ class QRSVG {
733
+ //TODO don't pass all options to this class
734
+ constructor(options) {
735
+ this._document = options.document;
736
+ this._element = this._document.createElementNS("http://www.w3.org/2000/svg", "svg");
737
+ this._element.setAttribute("width", String(options.width));
738
+ this._element.setAttribute("height", String(options.height));
739
+ this._element.setAttribute("viewBox", `0 0 ${options.width} ${options.height}`);
740
+ this._defs = this._document.createElementNS("http://www.w3.org/2000/svg", "defs");
741
+ this._element.appendChild(this._defs);
742
+ this._imageTools = options.imageTools || browserImageTools;
743
+ this._options = options;
744
+ }
745
+ get width() {
746
+ return this._options.width;
747
+ }
748
+ get height() {
749
+ return this._options.height;
750
+ }
751
+ getElement() {
752
+ return this._element;
753
+ }
754
+ async drawQR(qr) {
755
+ const count = qr.getModuleCount();
756
+ const minSize = Math.min(this._options.width, this._options.height);
757
+ const realQRSize = this._options.shape === exports.ShapeType.circle ? minSize / Math.sqrt(2) : minSize;
758
+ const dotSize = Math.floor(realQRSize / count);
759
+ let drawImageSize = {
760
+ hideXDots: 0,
761
+ hideYDots: 0,
762
+ width: 0,
763
+ height: 0
764
+ };
765
+ this._qr = qr;
766
+ if (this._options.image) {
767
+ //We need it to get image size
768
+ const size = await this._imageTools.getSize(this._options);
769
+ const { imageOptions, qrOptions } = this._options;
770
+ const coverLevel = imageOptions.imageSize * ErrorCorrectionPercents[qrOptions.errorCorrectionLevel];
771
+ const maxHiddenDots = Math.floor(coverLevel * count * count);
772
+ drawImageSize = calculateImageSize({
773
+ originalWidth: size.width,
774
+ originalHeight: size.height,
775
+ maxHiddenDots,
776
+ maxHiddenAxisDots: count - 14,
777
+ dotSize
778
+ });
779
+ }
780
+ this.drawBackground();
781
+ this.drawDots((i, j) => {
782
+ if (this._options.imageOptions.hideBackgroundDots) {
783
+ if (i >= (count - drawImageSize.hideXDots) / 2 &&
784
+ i < (count + drawImageSize.hideXDots) / 2 &&
785
+ j >= (count - drawImageSize.hideYDots) / 2 &&
786
+ j < (count + drawImageSize.hideYDots) / 2) {
787
+ return false;
788
+ }
789
+ }
790
+ if (squareMask[i]?.[j] || squareMask[i - count + 7]?.[j] || squareMask[i]?.[j - count + 7]) {
791
+ return false;
792
+ }
793
+ if (dotMask[i]?.[j] || dotMask[i - count + 7]?.[j] || dotMask[i]?.[j - count + 7]) {
794
+ return false;
795
+ }
796
+ return true;
797
+ });
798
+ this.drawCorners();
799
+ if (this._options.image) {
800
+ await this.drawImage({ width: drawImageSize.width, height: drawImageSize.height, count, dotSize });
801
+ }
802
+ }
803
+ drawBackground() {
804
+ const element = this._element;
805
+ const options = this._options;
806
+ if (element && options.backgroundOptions) {
807
+ const gradientOptions = options.backgroundOptions.gradient;
808
+ const color = options.backgroundOptions.color;
809
+ this._createColor({
810
+ options: gradientOptions,
811
+ color: color,
812
+ additionalRotation: 0,
813
+ x: 0,
814
+ y: 0,
815
+ height: options.height,
816
+ width: options.width,
817
+ name: "background-color"
818
+ });
819
+ const size = Math.min(options.width, options.height);
820
+ const element = this._document.createElementNS("http://www.w3.org/2000/svg", "rect");
821
+ this._backgroundClipPath = this._document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
822
+ this._backgroundClipPath.setAttribute("id", "clip-path-background-color");
823
+ this._defs.appendChild(this._backgroundClipPath);
824
+ element.setAttribute("x", String((options.width - size) / 2));
825
+ element.setAttribute("y", String((options.height - size) / 2));
826
+ element.setAttribute("width", String(size));
827
+ element.setAttribute("height", String(size));
828
+ element.setAttribute("rx", String((size / 2) * (options.backgroundOptions.round || 0)));
829
+ this._backgroundClipPath.appendChild(element);
830
+ }
831
+ }
832
+ drawDots(filter) {
833
+ if (!this._qr) {
834
+ throw "QR code is not defined";
835
+ }
836
+ const options = this._options;
837
+ const count = this._qr.getModuleCount();
838
+ if (count > options.width || count > options.height) {
839
+ throw "The canvas is too small.";
840
+ }
841
+ const minSize = Math.min(options.width, options.height);
842
+ const realQRSize = options.shape === exports.ShapeType.circle ? minSize / Math.sqrt(2) : minSize;
843
+ const dotSize = Math.floor(realQRSize / count);
844
+ const xBeginning = Math.floor((options.width - count * dotSize) / 2);
845
+ const yBeginning = Math.floor((options.height - count * dotSize) / 2);
846
+ const dot = new QRDot({ svg: this._element, type: options.dotsOptions.type, document: this._document });
847
+ this._dotsClipPath = this._document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
848
+ this._dotsClipPath.setAttribute("id", "clip-path-dot-color");
849
+ this._defs.appendChild(this._dotsClipPath);
850
+ this._createColor({
851
+ options: options.dotsOptions?.gradient,
852
+ color: options.dotsOptions.color,
853
+ additionalRotation: 0,
854
+ x: 0,
855
+ y: 0,
856
+ height: options.height,
857
+ width: options.width,
858
+ name: "dot-color"
859
+ });
860
+ for (let i = 0; i < count; i++) {
861
+ for (let j = 0; j < count; j++) {
862
+ if (filter && !filter(i, j)) {
863
+ continue;
864
+ }
865
+ if (!this._qr?.isDark(i, j)) {
866
+ continue;
867
+ }
868
+ dot.draw(xBeginning + i * dotSize, yBeginning + j * dotSize, dotSize, (xOffset, yOffset) => {
869
+ if (i + xOffset < 0 || j + yOffset < 0 || i + xOffset >= count || j + yOffset >= count)
870
+ return false;
871
+ if (filter && !filter(i + xOffset, j + yOffset))
872
+ return false;
873
+ return !!this._qr && this._qr.isDark(i + xOffset, j + yOffset);
874
+ });
875
+ if (dot._element && this._dotsClipPath) {
876
+ this._dotsClipPath.appendChild(dot._element);
877
+ }
878
+ }
879
+ }
880
+ if (options.shape === exports.ShapeType.circle) {
881
+ const additionalDots = Math.floor((minSize / dotSize - count) / 2);
882
+ const fakeCount = count + additionalDots * 2;
883
+ const xFakeBeginning = xBeginning - additionalDots * dotSize;
884
+ const yFakeBeginning = yBeginning - additionalDots * dotSize;
885
+ const fakeMatrix = [];
886
+ const center = Math.floor(fakeCount / 2);
887
+ for (let i = 0; i < fakeCount; i++) {
888
+ fakeMatrix[i] = [];
889
+ for (let j = 0; j < fakeCount; j++) {
890
+ if (i >= additionalDots - 1 &&
891
+ i <= fakeCount - additionalDots &&
892
+ j >= additionalDots - 1 &&
893
+ j <= fakeCount - additionalDots) {
894
+ fakeMatrix[i][j] = 0;
895
+ continue;
896
+ }
897
+ if (Math.sqrt((i - center) * (i - center) + (j - center) * (j - center)) > center) {
898
+ fakeMatrix[i][j] = 0;
899
+ continue;
900
+ }
901
+ //Get random dots from QR code to show it outside of QR code
902
+ fakeMatrix[i][j] = this._qr.isDark(j - 2 * additionalDots < 0 ? j : j >= count ? j - 2 * additionalDots : j - additionalDots, i - 2 * additionalDots < 0 ? i : i >= count ? i - 2 * additionalDots : i - additionalDots)
903
+ ? 1
904
+ : 0;
905
+ }
906
+ }
907
+ for (let i = 0; i < fakeCount; i++) {
908
+ for (let j = 0; j < fakeCount; j++) {
909
+ if (!fakeMatrix[i][j])
910
+ continue;
911
+ dot.draw(xFakeBeginning + i * dotSize, yFakeBeginning + j * dotSize, dotSize, (xOffset, yOffset) => {
912
+ return !!fakeMatrix[i + xOffset]?.[j + yOffset];
913
+ });
914
+ if (dot._element && this._dotsClipPath) {
915
+ this._dotsClipPath.appendChild(dot._element);
916
+ }
917
+ }
918
+ }
919
+ }
920
+ }
921
+ drawCorners() {
922
+ if (!this._qr) {
923
+ throw "QR code is not defined";
924
+ }
925
+ const element = this._element;
926
+ const options = this._options;
927
+ if (!element) {
928
+ throw "Element code is not defined";
929
+ }
930
+ const count = this._qr.getModuleCount();
931
+ const minSize = Math.min(options.width, options.height);
932
+ const realQRSize = options.shape === exports.ShapeType.circle ? minSize / Math.sqrt(2) : minSize;
933
+ const dotSize = Math.floor(realQRSize / count);
934
+ const cornersSquareSize = dotSize * 7;
935
+ const cornersDotSize = dotSize * 3;
936
+ const xBeginning = Math.floor((options.width - count * dotSize) / 2);
937
+ const yBeginning = Math.floor((options.height - count * dotSize) / 2);
938
+ [
939
+ [0, 0, 0],
940
+ [1, 0, Math.PI / 2],
941
+ [0, 1, -Math.PI / 2]
942
+ ].forEach(([column, row, rotation]) => {
943
+ const x = xBeginning + column * dotSize * (count - 7);
944
+ const y = yBeginning + row * dotSize * (count - 7);
945
+ let cornersSquareClipPath = this._dotsClipPath;
946
+ let cornersDotClipPath = this._dotsClipPath;
947
+ if (options.cornersSquareOptions?.gradient || options.cornersSquareOptions?.color) {
948
+ cornersSquareClipPath = this._document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
949
+ cornersSquareClipPath.setAttribute("id", `clip-path-corners-square-color-${column}-${row}`);
950
+ this._defs.appendChild(cornersSquareClipPath);
951
+ this._cornersSquareClipPath = this._cornersDotClipPath = cornersDotClipPath = cornersSquareClipPath;
952
+ this._createColor({
953
+ options: options.cornersSquareOptions?.gradient,
954
+ color: options.cornersSquareOptions?.color,
955
+ additionalRotation: rotation,
956
+ x,
957
+ y,
958
+ height: cornersSquareSize,
959
+ width: cornersSquareSize,
960
+ name: `corners-square-color-${column}-${row}`
961
+ });
962
+ }
963
+ if (options.cornersSquareOptions?.type) {
964
+ const cornersSquare = new QRCornerSquare({
965
+ svg: this._element,
966
+ type: options.cornersSquareOptions.type,
967
+ document: this._document
968
+ });
969
+ cornersSquare.draw(x, y, cornersSquareSize, rotation);
970
+ if (cornersSquare._element && cornersSquareClipPath) {
971
+ cornersSquareClipPath.appendChild(cornersSquare._element);
972
+ }
973
+ }
974
+ else {
975
+ const dot = new QRDot({ svg: this._element, type: options.dotsOptions.type, document: this._document });
976
+ for (let i = 0; i < squareMask.length; i++) {
977
+ for (let j = 0; j < squareMask[i].length; j++) {
978
+ if (!squareMask[i]?.[j]) {
979
+ continue;
980
+ }
981
+ dot.draw(x + i * dotSize, y + j * dotSize, dotSize, (xOffset, yOffset) => !!squareMask[i + xOffset]?.[j + yOffset]);
982
+ if (dot._element && cornersSquareClipPath) {
983
+ cornersSquareClipPath.appendChild(dot._element);
984
+ }
985
+ }
986
+ }
987
+ }
988
+ if (options.cornersDotOptions?.gradient || options.cornersDotOptions?.color) {
989
+ cornersDotClipPath = this._document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
990
+ cornersDotClipPath.setAttribute("id", `clip-path-corners-dot-color-${column}-${row}`);
991
+ this._defs.appendChild(cornersDotClipPath);
992
+ this._cornersDotClipPath = cornersDotClipPath;
993
+ this._createColor({
994
+ options: options.cornersDotOptions?.gradient,
995
+ color: options.cornersDotOptions?.color,
996
+ additionalRotation: rotation,
997
+ x: x + dotSize * 2,
998
+ y: y + dotSize * 2,
999
+ height: cornersDotSize,
1000
+ width: cornersDotSize,
1001
+ name: `corners-dot-color-${column}-${row}`
1002
+ });
1003
+ }
1004
+ if (options.cornersDotOptions?.type) {
1005
+ const cornersDot = new QRCornerDot({
1006
+ svg: this._element,
1007
+ type: options.cornersDotOptions.type,
1008
+ document: this._document
1009
+ });
1010
+ cornersDot.draw(x + dotSize * 2, y + dotSize * 2, cornersDotSize, rotation);
1011
+ if (cornersDot._element && cornersDotClipPath) {
1012
+ cornersDotClipPath.appendChild(cornersDot._element);
1013
+ }
1014
+ }
1015
+ else {
1016
+ const dot = new QRDot({ svg: this._element, type: options.dotsOptions.type, document: this._document });
1017
+ for (let i = 0; i < dotMask.length; i++) {
1018
+ for (let j = 0; j < dotMask[i].length; j++) {
1019
+ if (!dotMask[i]?.[j]) {
1020
+ continue;
1021
+ }
1022
+ dot.draw(x + i * dotSize, y + j * dotSize, dotSize, (xOffset, yOffset) => !!dotMask[i + xOffset]?.[j + yOffset]);
1023
+ if (dot._element && cornersDotClipPath) {
1024
+ cornersDotClipPath.appendChild(dot._element);
1025
+ }
1026
+ }
1027
+ }
1028
+ }
1029
+ });
1030
+ }
1031
+ async drawImage({ width, height, count, dotSize }) {
1032
+ const options = this._options;
1033
+ const xBeginning = Math.floor((options.width - count * dotSize) / 2);
1034
+ const yBeginning = Math.floor((options.height - count * dotSize) / 2);
1035
+ const margin = options.imageOptions.margin * dotSize;
1036
+ const dx = xBeginning + margin + (count * dotSize - width) / 2;
1037
+ const dy = yBeginning + margin + (count * dotSize - height) / 2;
1038
+ const dw = width - margin * 2;
1039
+ const dh = height - margin * 2;
1040
+ const imageUrl = await this._imageTools.toDataURL(options.image || "");
1041
+ let image = this._document.createElementNS("http://www.w3.org/2000/svg", "image");
1042
+ image.setAttribute("href", imageUrl || "");
1043
+ if (imageUrl.startsWith("data:image/svg+xml;")) {
1044
+ let data = imageUrl.substring(19);
1045
+ const i = data.indexOf(",");
1046
+ const encoding = data.substring(0, i);
1047
+ data = data.substring(i + 1);
1048
+ switch (encoding) {
1049
+ case "base64":
1050
+ data = typeof atob == "function" ? atob(data) : Buffer.from(data, "base64").toString("utf8");
1051
+ break;
1052
+ default:
1053
+ data = "";
1054
+ break;
1055
+ }
1056
+ if (data) {
1057
+ const container = this._document.createElement("div");
1058
+ container.innerHTML = data;
1059
+ const rootEl = container.querySelector("svg");
1060
+ if (rootEl)
1061
+ image = rootEl;
1062
+ }
1063
+ }
1064
+ image.setAttribute("x", String(dx));
1065
+ image.setAttribute("y", String(dy));
1066
+ image.setAttribute("width", `${dw}px`);
1067
+ image.setAttribute("height", `${dh}px`);
1068
+ this._element.appendChild(image);
1069
+ }
1070
+ _createColor({ options, color, additionalRotation, x, y, height, width, name }) {
1071
+ const size = width > height ? width : height;
1072
+ const rect = this._document.createElementNS("http://www.w3.org/2000/svg", "rect");
1073
+ rect.setAttribute("x", String(x));
1074
+ rect.setAttribute("y", String(y));
1075
+ rect.setAttribute("height", String(height));
1076
+ rect.setAttribute("width", String(width));
1077
+ rect.setAttribute("clip-path", `url('#clip-path-${name}')`);
1078
+ if (options) {
1079
+ let gradient;
1080
+ if (options.type === exports.GradientType.radial) {
1081
+ gradient = this._document.createElementNS("http://www.w3.org/2000/svg", "radialGradient");
1082
+ gradient.setAttribute("id", name);
1083
+ gradient.setAttribute("gradientUnits", "userSpaceOnUse");
1084
+ gradient.setAttribute("fx", String(x + width / 2));
1085
+ gradient.setAttribute("fy", String(y + height / 2));
1086
+ gradient.setAttribute("cx", String(x + width / 2));
1087
+ gradient.setAttribute("cy", String(y + height / 2));
1088
+ gradient.setAttribute("r", String(size / 2));
1089
+ }
1090
+ else {
1091
+ const rotation = ((options.rotation || 0) + additionalRotation) % (2 * Math.PI);
1092
+ const positiveRotation = (rotation + 2 * Math.PI) % (2 * Math.PI);
1093
+ let x0 = x + width / 2;
1094
+ let y0 = y + height / 2;
1095
+ let x1 = x + width / 2;
1096
+ let y1 = y + height / 2;
1097
+ if ((positiveRotation >= 0 && positiveRotation <= 0.25 * Math.PI) ||
1098
+ (positiveRotation > 1.75 * Math.PI && positiveRotation <= 2 * Math.PI)) {
1099
+ x0 = x0 - width / 2;
1100
+ y0 = y0 - (height / 2) * Math.tan(rotation);
1101
+ x1 = x1 + width / 2;
1102
+ y1 = y1 + (height / 2) * Math.tan(rotation);
1103
+ }
1104
+ else if (positiveRotation > 0.25 * Math.PI && positiveRotation <= 0.75 * Math.PI) {
1105
+ y0 = y0 - height / 2;
1106
+ x0 = x0 - width / 2 / Math.tan(rotation);
1107
+ y1 = y1 + height / 2;
1108
+ x1 = x1 + width / 2 / Math.tan(rotation);
1109
+ }
1110
+ else if (positiveRotation > 0.75 * Math.PI && positiveRotation <= 1.25 * Math.PI) {
1111
+ x0 = x0 + width / 2;
1112
+ y0 = y0 + (height / 2) * Math.tan(rotation);
1113
+ x1 = x1 - width / 2;
1114
+ y1 = y1 - (height / 2) * Math.tan(rotation);
1115
+ }
1116
+ else if (positiveRotation > 1.25 * Math.PI && positiveRotation <= 1.75 * Math.PI) {
1117
+ y0 = y0 + height / 2;
1118
+ x0 = x0 + width / 2 / Math.tan(rotation);
1119
+ y1 = y1 - height / 2;
1120
+ x1 = x1 - width / 2 / Math.tan(rotation);
1121
+ }
1122
+ gradient = this._document.createElementNS("http://www.w3.org/2000/svg", "linearGradient");
1123
+ gradient.setAttribute("id", name);
1124
+ gradient.setAttribute("gradientUnits", "userSpaceOnUse");
1125
+ gradient.setAttribute("x1", String(Math.round(x0)));
1126
+ gradient.setAttribute("y1", String(Math.round(y0)));
1127
+ gradient.setAttribute("x2", String(Math.round(x1)));
1128
+ gradient.setAttribute("y2", String(Math.round(y1)));
1129
+ }
1130
+ options.colorStops.forEach(({ offset, color }) => {
1131
+ const stop = this._document.createElementNS("http://www.w3.org/2000/svg", "stop");
1132
+ stop.setAttribute("offset", `${100 * offset}%`);
1133
+ stop.setAttribute("stop-color", color);
1134
+ gradient.appendChild(stop);
1135
+ });
1136
+ rect.setAttribute("fill", `url('#${name}')`);
1137
+ this._defs.appendChild(gradient);
1138
+ }
1139
+ else if (color) {
1140
+ rect.setAttribute("fill", color);
1141
+ }
1142
+ this._element.appendChild(rect);
1143
+ }
1152
1144
  }
1153
1145
 
1154
- class QRCodeStyling$1 {
1155
- constructor(options) {
1156
- this._options = options ? sanitizeOptions(mergeDeep(defaultOptions, options)) : defaultOptions;
1157
- this.update();
1158
- }
1159
- static _clearContainer(container) {
1160
- if (container) {
1161
- container.innerHTML = "";
1162
- }
1163
- }
1164
- _setupSvg() {
1165
- if (!this._qr) {
1166
- return;
1167
- }
1168
- this._options.width = this._options.height = 10 * this._qr.getModuleCount();
1169
- const qrSVG = new QRSVG(this._options);
1170
- this._svg = qrSVG.getElement();
1171
- this._svgDrawingPromise = qrSVG.drawQR(this._qr).then(() => {
1172
- if (!this._svg)
1173
- return;
1174
- this._extension?.(qrSVG.getElement(), this._options);
1175
- });
1176
- }
1177
- async _getElement() {
1178
- if (!this._qr)
1179
- throw "QR code is empty";
1180
- if (!this._svg || !this._svgDrawingPromise) {
1181
- this._setupSvg();
1182
- }
1183
- await this._svgDrawingPromise;
1184
- return this._svg;
1185
- }
1186
- update(options) {
1187
- QRCodeStyling$1._clearContainer(this._container);
1188
- this._options = options ? sanitizeOptions(mergeDeep(this._options, options)) : this._options;
1189
- if (!this._options.data) {
1190
- return;
1191
- }
1192
- this._qr = qrcode__default["default"](this._options.qrOptions.typeNumber, this._options.qrOptions.errorCorrectionLevel);
1193
- this._qr.addData(this._options.data, this._options.qrOptions.mode || getMode(this._options.data));
1194
- this._qr.make();
1195
- this._setupSvg();
1196
- this.append(this._container);
1197
- }
1198
- append(container) {
1199
- if (!container) {
1200
- return;
1201
- }
1202
- if (typeof container.appendChild !== "function") {
1203
- throw "Container should be a single DOM node";
1204
- }
1205
- if (this._svg) {
1206
- container.appendChild(this._svg);
1207
- }
1208
- this._container = container;
1209
- }
1210
- applyExtension(extension) {
1211
- if (!extension) {
1212
- throw "Extension function should be defined.";
1213
- }
1214
- this._extension = extension;
1215
- this.update();
1216
- }
1217
- deleteExtension() {
1218
- this._extension = undefined;
1219
- this.update();
1220
- }
1221
- async serialize() {
1222
- if (!this._qr)
1223
- throw "QR code is empty";
1224
- const element = await this._getElement();
1225
- if (!element) {
1226
- return;
1227
- }
1228
- const serializer = new XMLSerializer();
1229
- let source = serializer.serializeToString(element);
1230
- source = '<?xml version="1.0" standalone="no"?>\r\n' + source;
1231
- return source;
1232
- }
1233
- }
1146
+ let QRCodeStyling$1 = class QRCodeStyling {
1147
+ constructor(options) {
1148
+ this._options = options ? sanitizeOptions(mergeDeep(defaultOptions, options)) : defaultOptions;
1149
+ this.update();
1150
+ }
1151
+ static _clearContainer(container) {
1152
+ if (container) {
1153
+ container.innerHTML = "";
1154
+ }
1155
+ }
1156
+ _setupSvg() {
1157
+ if (!this._qr) {
1158
+ return;
1159
+ }
1160
+ this._options.width = this._options.height = 10 * this._qr.getModuleCount();
1161
+ const qrSVG = new QRSVG(this._options);
1162
+ this._svg = qrSVG.getElement();
1163
+ this._svgDrawingPromise = qrSVG.drawQR(this._qr).then(() => {
1164
+ if (!this._svg)
1165
+ return;
1166
+ this._extension?.(qrSVG.getElement(), this._options);
1167
+ });
1168
+ }
1169
+ async _getElement() {
1170
+ if (!this._qr)
1171
+ throw "QR code is empty";
1172
+ if (!this._svg || !this._svgDrawingPromise) {
1173
+ this._setupSvg();
1174
+ }
1175
+ await this._svgDrawingPromise;
1176
+ return this._svg;
1177
+ }
1178
+ update(options) {
1179
+ QRCodeStyling._clearContainer(this._container);
1180
+ this._options = options ? sanitizeOptions(mergeDeep(this._options, options)) : this._options;
1181
+ if (!this._options.data) {
1182
+ return;
1183
+ }
1184
+ this._qr = qrcode(this._options.qrOptions.typeNumber, this._options.qrOptions.errorCorrectionLevel);
1185
+ this._qr.addData(this._options.data, this._options.qrOptions.mode || getMode(this._options.data));
1186
+ this._qr.make();
1187
+ this._setupSvg();
1188
+ this.append(this._container);
1189
+ }
1190
+ append(container) {
1191
+ if (!container) {
1192
+ return;
1193
+ }
1194
+ if (typeof container.appendChild !== "function") {
1195
+ throw "Container should be a single DOM node";
1196
+ }
1197
+ if (this._svg) {
1198
+ container.appendChild(this._svg);
1199
+ }
1200
+ this._container = container;
1201
+ }
1202
+ applyExtension(extension) {
1203
+ if (!extension) {
1204
+ throw "Extension function should be defined.";
1205
+ }
1206
+ this._extension = extension;
1207
+ this.update();
1208
+ }
1209
+ deleteExtension() {
1210
+ this._extension = undefined;
1211
+ this.update();
1212
+ }
1213
+ async serialize() {
1214
+ if (!this._qr)
1215
+ throw "QR code is empty";
1216
+ const element = await this._getElement();
1217
+ if (!element) {
1218
+ return;
1219
+ }
1220
+ const serializer = new XMLSerializer();
1221
+ let source = serializer.serializeToString(element);
1222
+ source = '<?xml version="1.0" standalone="no"?>\r\n' + source;
1223
+ return source;
1224
+ }
1225
+ };
1234
1226
 
1235
- class QRCodeStyling extends QRCodeStyling$1 {
1236
- constructor(options) {
1237
- const dom = new jsdom.JSDOM("<!DOCTYPE html>");
1238
- const imageCache = new Map();
1239
- const loadImage = async (url) => {
1240
- if (typeof url == "string") {
1241
- let pr = imageCache.get(url);
1242
- if (pr)
1243
- return pr;
1244
- pr = fetch__default["default"](url).then((res) => res
1245
- .arrayBuffer()
1246
- .then((buff) => Buffer.from(buff))
1247
- .then(async (data) => ({
1248
- contentType: res.headers.get("Content-Type") || (await fileType.fromBuffer(data).then((r) => r?.mime)),
1249
- data
1250
- })));
1251
- imageCache.set(url, pr);
1252
- return pr;
1253
- }
1254
- else {
1255
- const buff = Buffer.from(url);
1256
- const mime = await fileType.fromBuffer(buff).then((r) => r?.mime);
1257
- return {
1258
- contentType: mime,
1259
- data: buff
1260
- };
1261
- }
1262
- };
1263
- global.XMLSerializer = dom.window.XMLSerializer;
1264
- super({
1265
- ...options,
1266
- document: options.document || dom.window.document,
1267
- imageTools: options.imageTools || {
1268
- toDataURL: (url) => loadImage(url).then(({ contentType, data }) => `data:${contentType?.replace("application/xml", "image/svg+xml")};base64,${data.toString("base64")}`),
1269
- getSize: async (options) => {
1270
- if (!options.image) {
1271
- throw new Error("Image is not defined");
1272
- }
1273
- const { data } = Buffer.isBuffer(options.image) ? { data: options.image } : await loadImage(options.image);
1274
- const meta = await sharp__default["default"](data).metadata();
1275
- return {
1276
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1277
- width: meta.width,
1278
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1279
- height: meta.height
1280
- };
1281
- }
1282
- }
1283
- });
1284
- }
1227
+ class QRCodeStyling extends QRCodeStyling$1 {
1228
+ constructor(options) {
1229
+ const dom = new jsdom.JSDOM("<!DOCTYPE html>");
1230
+ const imageCache = new Map();
1231
+ const loadImage = async (url) => {
1232
+ if (typeof url == "string") {
1233
+ let pr = imageCache.get(url);
1234
+ if (pr)
1235
+ return pr;
1236
+ pr = fetch(url).then((res) => res
1237
+ .arrayBuffer()
1238
+ .then((buff) => Buffer.from(buff))
1239
+ .then(async (data) => ({
1240
+ contentType: res.headers.get("Content-Type") || (await fileType.fromBuffer(data).then((r) => r?.mime)),
1241
+ data
1242
+ })));
1243
+ imageCache.set(url, pr);
1244
+ return pr;
1245
+ }
1246
+ else {
1247
+ const buff = Buffer.from(url);
1248
+ const mime = await fileType.fromBuffer(buff).then((r) => r?.mime);
1249
+ return {
1250
+ contentType: mime,
1251
+ data: buff
1252
+ };
1253
+ }
1254
+ };
1255
+ global.XMLSerializer = dom.window.XMLSerializer;
1256
+ super({
1257
+ ...options,
1258
+ document: options.document || dom.window.document,
1259
+ imageTools: options.imageTools || {
1260
+ toDataURL: (url) => loadImage(url).then(({ contentType, data }) => `data:${contentType?.replace("application/xml", "image/svg+xml")};base64,${data.toString("base64")}`),
1261
+ getSize: async (options) => {
1262
+ if (!options.image) {
1263
+ throw new Error("Image is not defined");
1264
+ }
1265
+ const { data } = Buffer.isBuffer(options.image) ? { data: options.image } : await loadImage(options.image);
1266
+ const meta = await sharp(data).metadata();
1267
+ return {
1268
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1269
+ width: meta.width,
1270
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1271
+ height: meta.height
1272
+ };
1273
+ }
1274
+ }
1275
+ });
1276
+ }
1285
1277
  }
1286
1278
 
1287
1279
  exports.ErrorCorrectionPercents = ErrorCorrectionPercents;