somdigi-qr-generator 1.0.2 → 1.0.4

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 CHANGED
@@ -1,5 +1,5 @@
1
- const generateQR = require("./src/core");
1
+ const QRGenerator = require("./src/core");
2
2
 
3
3
  module.exports = {
4
- generateQR
4
+ QRGenerator
5
5
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "somdigi-qr-generator",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
package/src/core.js CHANGED
@@ -1,77 +1,95 @@
1
1
  const QRCode = require("qrcode");
2
2
  const sharp = require("sharp");
3
- const fs = require("fs/promises");
4
- const path = require("path");
5
3
 
6
- const {
7
- extractPaths,
8
- buildGradient,
9
- pathsToDots,
10
- insertLogo
11
- } = require("./svg-helper");
12
-
13
- class FastDotQR {
14
- static async toSVG(text, options = {}) {
15
- const rawSVG = await QRCode.toString(text, {
16
- type: "svg",
17
- errorCorrectionLevel: "H",
18
- margin: options.margin ?? 1
19
- });
4
+ class QRGenerator {
5
+ /**
6
+ * Generate QR Buffer
7
+ * @param {Object} options
8
+ * @param {string} options.data (required)
9
+ * @param {"default"|"rounded"} options.type
10
+ * @param {number} options.size
11
+ * @param {string[]} options.gradient
12
+ * @param {string} options.logo (url / base64)
13
+ */
14
+ static async generate(options) {
15
+ if (!options || !options.data) {
16
+ throw new Error("data is required");
17
+ }
20
18
 
21
- const sizeMatch = rawSVG.match(/viewBox="([^"]+)"/);
22
- const viewBox = sizeMatch ? sizeMatch[1] : "0 0 100 100";
19
+ // 🔵 DEFAULT QR (FASTEST)
20
+ if (!options.type || options.type === "default") {
21
+ return QRCode.toBuffer(options.data, {
22
+ width: options.size ?? 512,
23
+ margin: 2
24
+ });
25
+ }
23
26
 
24
- const paths = extractPaths(rawSVG);
27
+ // 🔵 ROUNDED QR
28
+ if (options.type === "rounded") {
29
+ return this._rounded(options);
30
+ }
25
31
 
26
- const gradientId = "qrGradient";
27
- const useGradient = options.gradient?.length > 1;
32
+ throw new Error("invalid type");
33
+ }
28
34
 
29
- const fill = useGradient
30
- ? `url(#${gradientId})`
31
- : options.color ?? "#000";
35
+ static async _rounded(options) {
36
+ const rawSVG = await QRCode.toString(options.data, {
37
+ type: "svg",
38
+ errorCorrectionLevel: "H",
39
+ margin: 1
40
+ });
32
41
 
33
- const defs = useGradient
34
- ? buildGradient(gradientId, options.gradient)
42
+ const viewBox = rawSVG.match(/viewBox="([^"]+)"/)[1];
43
+ const paths = rawSVG.match(/<path[^>]*>/g) || [];
44
+
45
+ const fill = options.gradient?.length
46
+ ? "url(#g)"
47
+ : "#000";
48
+
49
+ const defs = options.gradient?.length
50
+ ? `
51
+ <defs>
52
+ <linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%">
53
+ ${options.gradient
54
+ .map(
55
+ (c, i) =>
56
+ `<stop offset="${(i / (options.gradient.length - 1)) * 100}%" stop-color="${c}" />`
57
+ )
58
+ .join("")}
59
+ </linearGradient>
60
+ </defs>`
35
61
  : "";
36
62
 
37
- const dots = pathsToDots(
38
- paths,
39
- options.radius ?? 1.4,
40
- fill
41
- );
63
+ const dots = paths
64
+ .map(p => {
65
+ const m = p.match(/M(\d+) (\d+)/);
66
+ if (!m) return "";
67
+ return `<circle cx="${+m[1] + 0.5}" cy="${+m[2] + 0.5}" r="0.45" fill="${fill}" />`;
68
+ })
69
+ .join("");
42
70
 
43
71
  const logo = options.logo
44
- ? insertLogo(options.logo, options.logoSize ?? 0.25)
72
+ ? `
73
+ <image
74
+ href="${options.logo}"
75
+ x="35%" y="35%"
76
+ width="30%" height="30%"
77
+ preserveAspectRatio="xMidYMid meet"
78
+ />`
45
79
  : "";
46
80
 
47
- // 🔒 SVG FINAL — VALID 100%
48
- return `
49
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}">
81
+ const svg = `
82
+ <svg xmlns="http://www.w3.org/2000/svg"
83
+ width="${options.size ?? 512}"
84
+ height="${options.size ?? 512}"
85
+ viewBox="${viewBox}">
50
86
  ${defs}
51
87
  ${dots}
52
88
  ${logo}
53
89
  </svg>`;
54
- }
55
90
 
56
- static async toPNG(text, options = {}) {
57
- const svg = await this.toSVG(text, options);
58
91
  return sharp(Buffer.from(svg)).png().toBuffer();
59
92
  }
60
-
61
- static async toFile(text, filename, options = {}) {
62
- const dir = path.join(process.cwd(), "storage/qr-codes");
63
- await fs.mkdir(dir, { recursive: true });
64
-
65
- const fullPath = path.join(dir, filename);
66
-
67
- if (filename.endsWith(".svg")) {
68
- await fs.writeFile(fullPath, await this.toSVG(text, options));
69
- } else {
70
- await fs.writeFile(fullPath, await this.toPNG(text, options));
71
- }
72
-
73
- return fullPath;
74
- }
75
93
  }
76
94
 
77
- module.exports = FastDotQR;
95
+ module.exports = QRGenerator;
package/src/svg-helper.js DELETED
@@ -1,49 +0,0 @@
1
- function extractPaths(svg) {
2
- return svg.match(/<path[^>]*>/g) || [];
3
- }
4
-
5
- function buildGradient(id, colors) {
6
- return `
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>`;
17
- }
18
-
19
- function pathsToDots(paths, radius, fill) {
20
- return paths
21
- .map(p => {
22
- const m = p.match(/M(\d+) (\d+)/);
23
- if (!m) return "";
24
- const x = Number(m[1]) + radius;
25
- const y = Number(m[2]) + radius;
26
- return `<circle cx="${x}" cy="${y}" r="${radius}" fill="${fill}" />`;
27
- })
28
- .join("");
29
- }
30
-
31
- function insertLogo(logo, size = 0.25) {
32
- const percent = size * 100;
33
- return `
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
- />`;
42
- }
43
-
44
- module.exports = {
45
- extractPaths,
46
- buildGradient,
47
- pathsToDots,
48
- insertLogo
49
- };