somdigi-qr-generator 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +2 -2
- package/package.json +1 -1
- package/src/core.js +33 -36
- package/src/svg-helper.js +31 -32
package/index.js
CHANGED
package/package.json
CHANGED
package/src/core.js
CHANGED
|
@@ -4,54 +4,53 @@ const fs = require("fs/promises");
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
|
|
6
6
|
const {
|
|
7
|
+
extractPaths,
|
|
7
8
|
buildGradient,
|
|
8
|
-
|
|
9
|
+
pathsToDots,
|
|
9
10
|
insertLogo
|
|
10
11
|
} = require("./svg-helper");
|
|
11
12
|
|
|
12
|
-
class
|
|
13
|
+
class generateQr {
|
|
13
14
|
static async toSVG(text, options = {}) {
|
|
14
|
-
if (!text) throw new Error("text required");
|
|
15
|
-
|
|
16
15
|
const rawSVG = await QRCode.toString(text, {
|
|
17
16
|
type: "svg",
|
|
18
17
|
errorCorrectionLevel: "H",
|
|
19
18
|
margin: options.margin ?? 1
|
|
20
19
|
});
|
|
21
20
|
|
|
21
|
+
const sizeMatch = rawSVG.match(/viewBox="([^"]+)"/);
|
|
22
|
+
const viewBox = sizeMatch ? sizeMatch[1] : "0 0 100 100";
|
|
23
|
+
|
|
24
|
+
const paths = extractPaths(rawSVG);
|
|
25
|
+
|
|
22
26
|
const gradientId = "qrGradient";
|
|
23
|
-
const gradient
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
const useGradient = options.gradient?.length > 1;
|
|
28
|
+
|
|
29
|
+
const fill = useGradient
|
|
30
|
+
? `url(#${gradientId})`
|
|
31
|
+
: options.color ?? "#000";
|
|
32
|
+
|
|
33
|
+
const defs = useGradient
|
|
34
|
+
? buildGradient(gradientId, options.gradient)
|
|
35
|
+
: "";
|
|
36
|
+
|
|
37
|
+
const dots = pathsToDots(
|
|
38
|
+
paths,
|
|
35
39
|
options.radius ?? 1.4,
|
|
36
40
|
fill
|
|
37
41
|
);
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
options.logo,
|
|
43
|
-
options.logoSize ?? 0.25
|
|
44
|
-
);
|
|
45
|
-
}
|
|
43
|
+
const logo = options.logo
|
|
44
|
+
? insertLogo(options.logo, options.logoSize ?? 0.25)
|
|
45
|
+
: "";
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.replace("</svg>", `${content}</svg>`);
|
|
47
|
+
// 🔒 SVG FINAL — VALID 100%
|
|
48
|
+
return `
|
|
49
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}">
|
|
50
|
+
${defs}
|
|
51
|
+
${dots}
|
|
52
|
+
${logo}
|
|
53
|
+
</svg>`;
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
static async toPNG(text, options = {}) {
|
|
@@ -66,15 +65,13 @@ class FastDotQR {
|
|
|
66
65
|
const fullPath = path.join(dir, filename);
|
|
67
66
|
|
|
68
67
|
if (filename.endsWith(".svg")) {
|
|
69
|
-
|
|
70
|
-
await fs.writeFile(fullPath, svg);
|
|
68
|
+
await fs.writeFile(fullPath, await this.toSVG(text, options));
|
|
71
69
|
} else {
|
|
72
|
-
|
|
73
|
-
await fs.writeFile(fullPath, buffer);
|
|
70
|
+
await fs.writeFile(fullPath, await this.toPNG(text, options));
|
|
74
71
|
}
|
|
75
72
|
|
|
76
73
|
return fullPath;
|
|
77
74
|
}
|
|
78
75
|
}
|
|
79
76
|
|
|
80
|
-
module.exports =
|
|
77
|
+
module.exports = generateQr;
|
package/src/svg-helper.js
CHANGED
|
@@ -1,50 +1,49 @@
|
|
|
1
|
+
function extractPaths(svg) {
|
|
2
|
+
return svg.match(/<path[^>]*>/g) || [];
|
|
3
|
+
}
|
|
4
|
+
|
|
1
5
|
function buildGradient(id, colors) {
|
|
2
6
|
return `
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
`;
|
|
7
|
+
<defs>
|
|
8
|
+
<linearGradient id="${id}" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
9
|
+
${colors
|
|
10
|
+
.map(
|
|
11
|
+
(c, i) =>
|
|
12
|
+
`<stop offset="${(i / (colors.length - 1)) * 100}%" stop-color="${c}" />`
|
|
13
|
+
)
|
|
14
|
+
.join("")}
|
|
15
|
+
</linearGradient>
|
|
16
|
+
</defs>`;
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
function
|
|
17
|
-
return
|
|
18
|
-
.
|
|
19
|
-
const m =
|
|
19
|
+
function pathsToDots(paths, radius, fill) {
|
|
20
|
+
return paths
|
|
21
|
+
.map(p => {
|
|
22
|
+
const m = p.match(/M(\d+) (\d+)/);
|
|
20
23
|
if (!m) return "";
|
|
21
24
|
const x = Number(m[1]) + radius;
|
|
22
25
|
const y = Number(m[2]) + radius;
|
|
23
26
|
return `<circle cx="${x}" cy="${y}" r="${radius}" fill="${fill}" />`;
|
|
24
27
|
})
|
|
25
|
-
.
|
|
26
|
-
.replace(/<\/svg>/, "");
|
|
28
|
+
.join("");
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
function insertLogo(
|
|
30
|
-
const
|
|
31
|
-
|
|
31
|
+
function insertLogo(logo, size = 0.25) {
|
|
32
|
+
const percent = size * 100;
|
|
32
33
|
return `
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
preserveAspectRatio="xMidYMid meet"
|
|
42
|
-
/>
|
|
43
|
-
`;
|
|
34
|
+
<image
|
|
35
|
+
href="${logo}"
|
|
36
|
+
x="${50 - percent / 2}%"
|
|
37
|
+
y="${50 - percent / 2}%"
|
|
38
|
+
width="${percent}%"
|
|
39
|
+
height="${percent}%"
|
|
40
|
+
preserveAspectRatio="xMidYMid meet"
|
|
41
|
+
/>`;
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
module.exports = {
|
|
45
|
+
extractPaths,
|
|
47
46
|
buildGradient,
|
|
48
|
-
|
|
47
|
+
pathsToDots,
|
|
49
48
|
insertLogo
|
|
50
49
|
};
|