@liquid-js/qr-code-styling 5.6.1 → 5.7.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -231
- package/lib/border-plugin.js +1 -1
- package/lib/border-plugin.js.map +1 -1
- package/lib/color-dpqpq3zE.js +2 -0
- package/lib/color-dpqpq3zE.js.map +1 -0
- package/lib/core/qr-svg.d.ts +14 -1
- package/lib/event-plugin.js +1 -1
- package/lib/event-plugin.js.map +1 -1
- package/lib/image-BdYCSwfG.js +2 -0
- package/lib/image-BdYCSwfG.js.map +1 -0
- package/lib/image-mask-plugin.js +2 -0
- package/lib/image-mask-plugin.js.map +1 -0
- package/lib/index.d.ts +1 -1
- package/lib/node.d.ts +1 -1
- package/lib/plugin-utils.js +1 -1
- package/lib/plugin-utils.js.map +1 -1
- package/lib/plugins/image-mask/index.d.ts +63 -0
- package/lib/plugins/image-mask/raster.d.ts +58 -0
- package/lib/qr-code-styling-node.js +317 -112
- package/lib/qr-code-styling-node.js.map +1 -1
- package/lib/qr-code-styling.js +1 -1
- package/lib/qr-code-styling.js.map +1 -1
- package/lib/utils/image.d.ts +9 -0
- package/lib/utils/options.d.ts +48 -1
- package/lib/utils/svg.d.ts +32 -2
- package/package.json +6 -5
- package/lib/color-dXYWdVDW.js +0 -2
- package/lib/color-dXYWdVDW.js.map +0 -1
|
@@ -135,10 +135,12 @@ let ErrorCorrectionPercents = {
|
|
|
135
135
|
let rx = /\.?0+$/;
|
|
136
136
|
|
|
137
137
|
function numToAttr(value) {
|
|
138
|
-
|
|
138
|
+
if ("string" == typeof value) return value;
|
|
139
|
+
let str = value.toFixed(7).replace(rx, "");
|
|
140
|
+
return "-0" == str ? "0" : str;
|
|
139
141
|
}
|
|
140
142
|
|
|
141
|
-
function
|
|
143
|
+
function svgAttr(strings, ...values) {
|
|
142
144
|
return strings.reduce((t, v, i) => {
|
|
143
145
|
let p = "";
|
|
144
146
|
return i && (p = values[i - 1]), "number" == typeof p && (p = numToAttr(p)), `${t}${p}${v}`;
|
|
@@ -147,10 +149,125 @@ function svgPath(strings, ...values) {
|
|
|
147
149
|
|
|
148
150
|
function rotateFigure({draw, ...args}) {
|
|
149
151
|
let {x, y, size, rotation = 0} = args, cx = x + size / 2, cy = y + size / 2, element = draw(args);
|
|
150
|
-
return rotation && (Array.isArray(element) ? element : [ element ]).forEach(el => el.setAttribute("transform", `rotate(${
|
|
152
|
+
return rotation && (Array.isArray(element) ? element : [ element ]).forEach(el => el.setAttribute("transform", svgAttr`rotate(${180 * rotation / Math.PI},${cx},${cy})`)),
|
|
151
153
|
element;
|
|
152
154
|
}
|
|
153
155
|
|
|
156
|
+
let paramCount = {
|
|
157
|
+
m: 2,
|
|
158
|
+
l: 2,
|
|
159
|
+
h: 1,
|
|
160
|
+
v: 1,
|
|
161
|
+
c: 6,
|
|
162
|
+
s: 4,
|
|
163
|
+
q: 4,
|
|
164
|
+
t: 2,
|
|
165
|
+
a: 7,
|
|
166
|
+
z: 0
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
function rotatePath(d, angle = 0, cx = 0, cy = 0) {
|
|
170
|
+
let segments = function(d) {
|
|
171
|
+
let segments = [], skipRx = /[\s,]*/y, cmdRx = /[MmLlHhVvCcSsQqTtAaZz]/y, numRx = /[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/y, flagRx = /[01]/y, pos = 0, match = re => {
|
|
172
|
+
skipRx.lastIndex = pos, skipRx.exec(d), pos = re.lastIndex = skipRx.lastIndex;
|
|
173
|
+
const m = re.exec(d);
|
|
174
|
+
return m && (pos = re.lastIndex), m?.[0];
|
|
175
|
+
}, cmd = "";
|
|
176
|
+
for (;;) {
|
|
177
|
+
let c = match(cmdRx);
|
|
178
|
+
if (c) cmd = c; else {
|
|
179
|
+
if (pos >= d.length) break;
|
|
180
|
+
if (!cmd || "z" == cmd || "Z" == cmd) return;
|
|
181
|
+
"M" == cmd && (cmd = "L"), "m" == cmd && (cmd = "l");
|
|
182
|
+
}
|
|
183
|
+
let isArc = "a" == cmd || "A" == cmd, args = [];
|
|
184
|
+
for (let i = 0; i < paramCount[cmd.toLowerCase()]; i++) {
|
|
185
|
+
let v = match(!isArc || 3 != i && 4 != i ? numRx : flagRx);
|
|
186
|
+
if (void 0 === v) return;
|
|
187
|
+
args.push(parseFloat(v));
|
|
188
|
+
}
|
|
189
|
+
segments.push([ cmd, args ]);
|
|
190
|
+
}
|
|
191
|
+
return segments;
|
|
192
|
+
}(d);
|
|
193
|
+
if (!segments) return;
|
|
194
|
+
let rad = angle * Math.PI / 180, cos = Math.cos(rad), sin = Math.sin(rad), vector = (dx, dy) => svgAttr`${dx * cos - dy * sin} ${dx * sin + dy * cos}`, point = (px, py) => svgAttr`${cx + (px - cx) * cos - (py - cy) * sin} ${cy + (px - cx) * sin + (py - cy) * cos}`, x = 0, y = 0, startX = 0, startY = 0;
|
|
195
|
+
return segments.map(([cmd, args], i) => {
|
|
196
|
+
0 == i && "m" == cmd && (cmd = "M");
|
|
197
|
+
let rel = cmd != cmd.toUpperCase(), map = rel ? vector : point, ox = rel ? x : 0, oy = rel ? y : 0;
|
|
198
|
+
switch (cmd.toUpperCase()) {
|
|
199
|
+
case "Z":
|
|
200
|
+
return x = startX, y = startY, cmd;
|
|
201
|
+
|
|
202
|
+
case "H":
|
|
203
|
+
case "V":
|
|
204
|
+
{
|
|
205
|
+
let isH = "H" == cmd.toUpperCase(), dx = isH ? args[0] - (rel ? 0 : x) : 0, dy = isH ? 0 : args[0] - (rel ? 0 : y);
|
|
206
|
+
return x += dx, y += dy, angle ? svgAttr`l ${vector(dx, dy)}` : svgAttr`${cmd} ${args[0]}`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
case "A":
|
|
210
|
+
return x = ox + args[5], y = oy + args[6], svgAttr`${cmd} ${args[0]} ${args[1]} ${args[2] + angle} ${args[3]} ${args[4]} ${map(args[5], args[6])}`;
|
|
211
|
+
|
|
212
|
+
default:
|
|
213
|
+
{
|
|
214
|
+
let points = [];
|
|
215
|
+
for (let j = 0; j < args.length; j += 2) points.push(map(args[j], args[j + 1]));
|
|
216
|
+
return x = ox + args[args.length - 2], y = oy + args[args.length - 1], "M" != cmd && "m" != cmd || (startX = x,
|
|
217
|
+
startY = y), svgAttr`${cmd} ${points.join(" ")}`;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}).join(" ");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function shapeToPath(el) {
|
|
224
|
+
let num = name => parseFloat(el.getAttribute(name) || "0") || 0;
|
|
225
|
+
switch (el.tagName) {
|
|
226
|
+
case "path":
|
|
227
|
+
return el.getAttribute("d") || "";
|
|
228
|
+
|
|
229
|
+
case "rect":
|
|
230
|
+
{
|
|
231
|
+
let x = num("x"), y = num("y"), w = num("width"), h = num("height"), rX = el.hasAttribute("rx") ? num("rx") : num("ry"), rY = el.hasAttribute("ry") ? num("ry") : rX;
|
|
232
|
+
return rX = Math.min(Math.max(rX, 0), w / 2), rY = Math.min(Math.max(rY, 0), h / 2),
|
|
233
|
+
w <= 0 || h <= 0 ? "" : rX && rY ? svgAttr`M ${x} ${y + rY} v ${h - 2 * rY} a ${rX} ${rY} 0 0 0 ${rX} ${rY} h ${w - 2 * rX} a ${rX} ${rY} 0 0 0 ${rX} ${-rY} v ${2 * rY - h} a ${rX} ${rY} 0 0 0 ${-rX} ${-rY} h ${2 * rX - w} a ${rX} ${rY} 0 0 0 ${-rX} ${rY} z` : svgAttr`M ${x} ${y} v ${h} h ${w} v ${-h} z`;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
case "circle":
|
|
237
|
+
case "ellipse":
|
|
238
|
+
{
|
|
239
|
+
let cx = num("cx"), cy = num("cy"), rX = "circle" == el.tagName ? num("r") : num("rx"), rY = "circle" == el.tagName ? rX : num("ry");
|
|
240
|
+
return rX <= 0 || rY <= 0 ? "" : svgAttr`M ${cx - rX} ${cy} a ${rX} ${rY} 0 1 0 ${2 * rX} 0 a ${rX} ${rY} 0 1 0 ${-2 * rX} 0 z`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
case "polygon":
|
|
244
|
+
return `M ${el.getAttribute("points") || ""} z`;
|
|
245
|
+
|
|
246
|
+
default:
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function mergeShapes(elements) {
|
|
252
|
+
let rotateRx = /^\s*rotate\(\s*([-+.\deE]+)(?:[\s,]+([-+.\deE]+)[\s,]+([-+.\deE]+))?\s*\)\s*$/, paths = {};
|
|
253
|
+
for (let el of elements) {
|
|
254
|
+
if (el.hasAttribute("clip-path")) return;
|
|
255
|
+
let d = shapeToPath(el);
|
|
256
|
+
if (void 0 === d) return;
|
|
257
|
+
if (!d) continue;
|
|
258
|
+
let transform = el.getAttribute("transform"), m = transform ? rotateRx.exec(transform) : void 0;
|
|
259
|
+
if (null === m) return;
|
|
260
|
+
let rotated = m ? rotatePath(d, parseFloat(m[1]), parseFloat(m[2] || "0"), parseFloat(m[3] || "0")) : rotatePath(d);
|
|
261
|
+
if (void 0 === rotated) return;
|
|
262
|
+
let rule = "evenodd" == el.getAttribute("clip-rule") ? "evenodd" : "nonzero";
|
|
263
|
+
paths[rule] || (paths[rule] = []), paths[rule].push(rotated);
|
|
264
|
+
}
|
|
265
|
+
return Object.entries(paths).map(([rule, d]) => ({
|
|
266
|
+
rule,
|
|
267
|
+
d: d.join(" ")
|
|
268
|
+
}));
|
|
269
|
+
}
|
|
270
|
+
|
|
154
271
|
let DotElements = {
|
|
155
272
|
dot: args => {
|
|
156
273
|
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
@@ -165,27 +282,27 @@ let DotElements = {
|
|
|
165
282
|
},
|
|
166
283
|
sideRounded: (args, {height = args.size} = {}) => {
|
|
167
284
|
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
168
|
-
return element.setAttribute("d",
|
|
285
|
+
return element.setAttribute("d", svgAttr`M ${x} ${y + (size - height) / 2} v ${height} h ${size / 2} a ${height / 2} ${height / 2} 0 0 0 0 ${-height} z`),
|
|
169
286
|
element;
|
|
170
287
|
},
|
|
171
288
|
cornerRounded: args => {
|
|
172
289
|
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
173
|
-
return element.setAttribute("d",
|
|
290
|
+
return element.setAttribute("d", svgAttr`M ${x} ${y} v ${size} h ${size} v ${-size / 2} a ${size / 2} ${size / 2} 0 0 0 ${-size / 2} ${-size / 2} z`),
|
|
174
291
|
element;
|
|
175
292
|
},
|
|
176
293
|
cornerExtraRounded: args => {
|
|
177
294
|
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
178
|
-
return element.setAttribute("d",
|
|
295
|
+
return element.setAttribute("d", svgAttr`M ${x} ${y} v ${size} h ${size} a ${size} ${size} 0 0 0 ${-size} ${-size} z`),
|
|
179
296
|
element;
|
|
180
297
|
},
|
|
181
298
|
classyDot: args => {
|
|
182
299
|
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
183
|
-
return element.setAttribute("d",
|
|
300
|
+
return element.setAttribute("d", svgAttr`M ${x} ${y} v ${size / 2} a ${size / 2} ${size / 2} 0 0 0 ${size / 2} ${size / 2} h ${size / 2} v ${-size / 2} a ${size / 2} ${size / 2} 0 0 0 ${-size / 2} ${-size / 2} z`),
|
|
184
301
|
element;
|
|
185
302
|
},
|
|
186
303
|
wave: args => {
|
|
187
304
|
const {size, x, y, document} = args, a1 = 5 * Math.PI / 180, a2 = 65 * Math.PI / 180, c23x = size * (1 - .65 * Math.sin(a1)), c23y = -size * (.95 - .65 * Math.cos(a1)), c31x = -size * Math.sin(a2) / 2, c31y = size * Math.cos(a2) / 2, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
188
|
-
return element.setAttribute("d",
|
|
305
|
+
return element.setAttribute("d", svgAttr`M ${x} ${y + size} c ${.65 * size} 0 ${c23x} ${c23y} ${size} ${.95 * -size} c ${c31x} ${c31y} ${-size / 2} ${size * (.95 - 1)} ${-size} ${size * (.95 - 1)} z`),
|
|
189
306
|
element;
|
|
190
307
|
},
|
|
191
308
|
heart: args => {
|
|
@@ -209,44 +326,44 @@ let DotElements = {
|
|
|
209
326
|
},
|
|
210
327
|
classy: args => {
|
|
211
328
|
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
212
|
-
return element.setAttribute("d",
|
|
329
|
+
return element.setAttribute("d", svgAttr`M ${x} ${y + 2.5 * dotSize} v ${2 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * dotSize} ${2.5 * dotSize} h ${4.5 * dotSize} v ${-4.5 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * -dotSize} ${2.5 * -dotSize} h ${-2 * dotSize} H ${x} z`),
|
|
213
330
|
element;
|
|
214
331
|
},
|
|
215
332
|
inpoint: args => {
|
|
216
333
|
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
217
|
-
return element.setAttribute("d",
|
|
334
|
+
return element.setAttribute("d", svgAttr`M ${x} ${y + size / 2} v ${size / 4} a ${size / 4} ${size / 4} 0 0 0 ${size / 4} ${size / 4} h ${size / 4 * 3} v ${-size / 4 * 3} a ${size / 4} ${size / 4} 0 0 0 ${-size / 4} ${-size / 4} h ${-size / 2} a ${size / 4} ${size / 4} 0 0 0 ${-size / 4} ${size / 4} z`),
|
|
218
335
|
element;
|
|
219
336
|
},
|
|
220
337
|
star: (args, {spikes = 5, outerRadius = args.size / 2, innerRadius = args.size / 4} = {}) => {
|
|
221
338
|
const {size, x, y, document} = args, cx = x + size / 2, cy = y + size / 2, angle = Math.PI / spikes, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
222
339
|
return element.setAttribute("d", Array(2 * spikes).fill(0).map((_, i) => {
|
|
223
340
|
const radius = i % 2 == 0 ? outerRadius : innerRadius;
|
|
224
|
-
return
|
|
341
|
+
return svgAttr`${0 === i ? "M" : "L"} ${cx + radius * Math.sin(i * angle)} ${cy - radius * Math.cos(i * angle)}`;
|
|
225
342
|
}).join(" ")), element;
|
|
226
343
|
},
|
|
227
344
|
weave: args => {
|
|
228
345
|
const {size, x, y, document} = args, thickness = .6 * size, notch = (size - thickness) / 2, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
229
|
-
return element.setAttribute("d",
|
|
346
|
+
return element.setAttribute("d", svgAttr`M ${x + notch} ${y} l ${thickness} 0 l 0 ${notch} l ${notch} 0 l 0 ${thickness} l ${-notch} 0 l 0 ${notch} l ${-thickness} 0 l 0 ${-notch} l ${-notch} 0 l 0 ${-thickness} l ${notch} 0 z`),
|
|
230
347
|
element;
|
|
231
348
|
},
|
|
232
349
|
blob: (args, corners) => {
|
|
233
|
-
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path"), parts = [
|
|
350
|
+
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path"), parts = [ svgAttr`M ${x} ${y + 2.5 * dotSize}` ];
|
|
234
351
|
let l = 2 * dotSize;
|
|
235
|
-
return "round" == corners.bl ? (parts.push(
|
|
236
|
-
l = 2 * dotSize) : "out" == corners.bl ? (parts.push(
|
|
237
|
-
l = 2 * dotSize) : (parts.push(
|
|
238
|
-
"round" == corners.br ? (parts.push(
|
|
239
|
-
l = -2 * dotSize) : "out" == corners.br ? (parts.push(
|
|
240
|
-
l = -2 * dotSize) : (parts.push(
|
|
241
|
-
"round" == corners.tr ? (parts.push(
|
|
242
|
-
l = -2 * dotSize) : "out" == corners.tr ? (parts.push(
|
|
243
|
-
l = -2 * dotSize) : (parts.push(
|
|
244
|
-
"round" == corners.tl ? parts.push(
|
|
352
|
+
return "round" == corners.bl ? (parts.push(svgAttr`v ${l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * dotSize} ${2.5 * dotSize}`),
|
|
353
|
+
l = 2 * dotSize) : "out" == corners.bl ? (parts.push(svgAttr`v ${5 * dotSize + l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 1 ${2.5 * dotSize} ${-2.5 * dotSize}`),
|
|
354
|
+
l = 2 * dotSize) : (parts.push(svgAttr`v ${2.5 * dotSize + l}`), l = 4.5 * dotSize),
|
|
355
|
+
"round" == corners.br ? (parts.push(svgAttr`h ${l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * dotSize} ${-2.5 * dotSize}`),
|
|
356
|
+
l = -2 * dotSize) : "out" == corners.br ? (parts.push(svgAttr`h ${5 * dotSize + l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 1 ${-2.5 * dotSize} ${-2.5 * dotSize}`),
|
|
357
|
+
l = -2 * dotSize) : (parts.push(svgAttr`h ${2.5 * dotSize + l}`), l = -4.5 * dotSize),
|
|
358
|
+
"round" == corners.tr ? (parts.push(svgAttr`v ${l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${-2.5 * dotSize} ${-2.5 * dotSize}`),
|
|
359
|
+
l = -2 * dotSize) : "out" == corners.tr ? (parts.push(svgAttr`v ${-5 * dotSize + l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 1 ${-2.5 * dotSize} ${2.5 * dotSize}`),
|
|
360
|
+
l = -2 * dotSize) : (parts.push(svgAttr`v ${-2.5 * dotSize + l}`), l = -4.5 * dotSize),
|
|
361
|
+
"round" == corners.tl ? parts.push(svgAttr`h ${l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${-2.5 * dotSize} ${2.5 * dotSize}`) : "out" == corners.tl ? parts.push(svgAttr`h ${-5 * dotSize + l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 1 ${2.5 * dotSize} ${2.5 * dotSize}`) : parts.push(svgAttr`h ${-2.5 * dotSize + l}`),
|
|
245
362
|
element.setAttribute("d", parts.join(" ") + " z"), element;
|
|
246
363
|
},
|
|
247
364
|
circuit: (args, left = !1) => {
|
|
248
365
|
const {size, x, y, document} = args, dP = .17 ** .5 * size, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
249
|
-
return element.setAttribute("d",
|
|
366
|
+
return element.setAttribute("d", svgAttr`M ${x + .4 * size} ${y + .5 * size - dP} a ${.4 * size} ${.4 * size} 0 0 0 ${left ? .1 * size - dP : -.3 * size} ${left ? dP - .1 * size : dP} ${left ? svgAttr`h ${-.65 * size} v ${.2 * size} h ${.65 * size} a ${.4 * size} ${.4 * size} 0 0 0 ${dP} ${.3 * size}` : svgAttr`a ${.4 * size} ${.4 * size} 0 0 0 ${.4 * size} ${.4 * size}`} a ${.4 * size} ${.4 * size} 0 0 0 ${.4 * size} ${-.4 * size} a ${.4 * size} ${.4 * size} 0 0 0 ${-.3 * size} ${-dP} v ${-.65 * size} h ${-.2 * size} z`),
|
|
250
367
|
element.setAttribute("fill-rule", "nonzero"), element;
|
|
251
368
|
}
|
|
252
369
|
}, qrCornerDotFigures = {
|
|
@@ -305,44 +422,44 @@ let DotElements = {
|
|
|
305
422
|
let SquareElements = {
|
|
306
423
|
dot: args => {
|
|
307
424
|
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
308
|
-
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d",
|
|
425
|
+
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgAttr`M ${x + size / 2} ${y} a ${size / 2} ${size / 2} 0 1 0 0.1 0 z m 0 ${dotSize} a ${size / 2 - dotSize} ${size / 2 - dotSize} 0 1 1 -0.1 0 Z`);
|
|
309
426
|
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
310
|
-
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d",
|
|
427
|
+
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgAttr`M ${x + size / 2} ${y - dotSize} a ${size / 2 + dotSize} ${size / 2 + dotSize} 0 1 0 0.1 0 z`),
|
|
311
428
|
[ element, fill ];
|
|
312
429
|
},
|
|
313
430
|
square: args => {
|
|
314
431
|
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
315
|
-
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d",
|
|
432
|
+
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgAttr`M ${x} ${y} v ${size} h ${size} v ${-size} z M ${x + dotSize} ${y + dotSize} h ${size - 2 * dotSize} v ${size - 2 * dotSize} h ${2 * dotSize - size} z`);
|
|
316
433
|
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
317
|
-
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d",
|
|
434
|
+
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgAttr`M ${x - dotSize} ${y - dotSize} h ${size + 2 * dotSize} v ${size + 2 * dotSize} h ${-size - 2 * dotSize} z`),
|
|
318
435
|
[ element, fill ];
|
|
319
436
|
},
|
|
320
437
|
extraRounded: args => {
|
|
321
438
|
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
322
|
-
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d",
|
|
439
|
+
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgAttr`M ${x} ${y + 2.5 * dotSize} v ${2 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * dotSize} ${2.5 * dotSize} h ${2 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * dotSize} ${2.5 * -dotSize} v ${-2 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * -dotSize} ${2.5 * -dotSize} h ${-2 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * -dotSize} ${2.5 * dotSize} z M ${x + 2.5 * dotSize} ${y + dotSize} h ${2 * dotSize} a ${1.5 * dotSize} ${1.5 * dotSize} 0 0 1 ${1.5 * dotSize} ${1.5 * dotSize} v ${2 * dotSize} a ${1.5 * dotSize} ${1.5 * dotSize} 0 0 1 ${1.5 * -dotSize} ${1.5 * dotSize} h ${-2 * dotSize} a ${1.5 * dotSize} ${1.5 * dotSize} 0 0 1 ${1.5 * -dotSize} ${1.5 * -dotSize} v ${-2 * dotSize} a ${1.5 * dotSize} ${1.5 * dotSize} 0 0 1 ${1.5 * dotSize} ${1.5 * -dotSize} z`);
|
|
323
440
|
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
324
|
-
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d",
|
|
441
|
+
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgAttr`M ${x - dotSize} ${y + 2.5 * dotSize} v ${2 * dotSize} a ${3.5 * dotSize} ${3.5 * dotSize} 0 0 0 ${3.5 * dotSize} ${3.5 * dotSize} h ${2 * dotSize} a ${3.5 * dotSize} ${3.5 * dotSize} 0 0 0 ${3.5 * dotSize} ${3.5 * -dotSize} v ${-2 * dotSize} a ${3.5 * dotSize} ${3.5 * dotSize} 0 0 0 ${3.5 * -dotSize} ${3.5 * -dotSize} h ${-2 * dotSize} a ${3.5 * dotSize} ${3.5 * dotSize} 0 0 0 ${3.5 * -dotSize} ${3.5 * dotSize} z`),
|
|
325
442
|
[ element, fill ];
|
|
326
443
|
},
|
|
327
444
|
classy: args => {
|
|
328
445
|
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
329
|
-
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d",
|
|
446
|
+
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgAttr`M ${x} ${y + 2.5 * dotSize} v ${2 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * dotSize} ${2.5 * dotSize} h ${4.5 * dotSize} v ${-4.5 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * -dotSize} ${2.5 * -dotSize} h ${-2 * dotSize} H ${x} z M ${x + 2.5 * dotSize} ${y + dotSize} h ${2 * dotSize} a ${1.5 * dotSize} ${1.5 * dotSize} 0 0 1 ${1.5 * dotSize} ${1.5 * dotSize} v ${3.5 * dotSize} h ${-3.5 * dotSize} a ${1.5 * dotSize} ${1.5 * dotSize} 0 0 1 ${1.5 * -dotSize} ${1.5 * -dotSize} v ${-3.5 * dotSize} z`);
|
|
330
447
|
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
331
|
-
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d",
|
|
448
|
+
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgAttr`M ${x + .5 * dotSize} ${y - dotSize} h ${4 * dotSize} a ${3.5 * dotSize} ${3.5 * dotSize} 0 0 1 ${3.5 * dotSize} ${3.5 * dotSize} v ${5.5 * dotSize} h ${-5.5 * dotSize} a ${3.5 * dotSize} ${3.5 * dotSize} 0 0 1 ${3.5 * -dotSize} ${3.5 * -dotSize} v ${-5.5 * dotSize} z`),
|
|
332
449
|
[ element, fill ];
|
|
333
450
|
},
|
|
334
451
|
inpoint: args => {
|
|
335
452
|
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
336
|
-
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d",
|
|
453
|
+
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgAttr`M ${x} ${y + 2.5 * dotSize} v ${2 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * dotSize} ${2.5 * dotSize} h ${4.5 * dotSize} v ${-4.5 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * -dotSize} ${2.5 * -dotSize} h ${-2 * dotSize} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * -dotSize} ${2.5 * dotSize} z M ${x + 2.5 * dotSize} ${y + dotSize} h ${2 * dotSize} a ${1.5 * dotSize} ${1.5 * dotSize} 0 0 1 ${1.5 * dotSize} ${1.5 * dotSize} v ${3.5 * dotSize} h ${-3.5 * dotSize} a ${1.5 * dotSize} ${1.5 * dotSize} 0 0 1 ${1.5 * -dotSize} ${1.5 * -dotSize} v ${-2 * dotSize} a ${1.5 * dotSize} ${1.5 * dotSize} 0 0 1 ${1.5 * dotSize} ${1.5 * -dotSize} z`);
|
|
337
454
|
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
338
|
-
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d",
|
|
455
|
+
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgAttr`M ${x + .5 * dotSize} ${y - dotSize} h ${4 * dotSize} a ${3.5 * dotSize} ${3.5 * dotSize} 0 0 1 ${3.5 * dotSize} ${3.5 * dotSize} v ${5.5 * dotSize} h ${-5.5 * dotSize} a ${3.5 * dotSize} ${3.5 * dotSize} 0 0 1 ${3.5 * -dotSize} ${3.5 * -dotSize} v ${-2 * dotSize} a ${3.5 * dotSize} ${3.5 * dotSize} 0 0 1 ${3.5 * dotSize} ${3.5 * -dotSize} z`),
|
|
339
456
|
[ element, fill ];
|
|
340
457
|
},
|
|
341
458
|
centerCircle: args => {
|
|
342
459
|
const {x, y, size, document} = args, circleRadius = size / 2.5, cx = x + size / 2, cy = y + size / 2, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
343
|
-
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d",
|
|
460
|
+
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgAttr`M ${x} ${y} h ${size} v ${size} h ${-size} z M ${cx - circleRadius} ${cy} a ${circleRadius} ${circleRadius} 0 1 0 ${2 * circleRadius} 0 a ${circleRadius} ${circleRadius} 0 1 0 ${2 * -circleRadius} 0 z`);
|
|
344
461
|
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
345
|
-
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d",
|
|
462
|
+
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgAttr`M ${x - dotSize} ${y - dotSize} h ${size + 2 * dotSize} v ${size + 2 * dotSize} h ${-size - 2 * dotSize} z`),
|
|
346
463
|
[ element, fill ];
|
|
347
464
|
}
|
|
348
465
|
}, qrCornerSquareFigures = {
|
|
@@ -774,6 +891,8 @@ class QRSVG {
|
|
|
774
891
|
backgroundMask;
|
|
775
892
|
dotsMask;
|
|
776
893
|
lightDotsMask;
|
|
894
|
+
colorLayers=[];
|
|
895
|
+
segmentMask;
|
|
777
896
|
qr;
|
|
778
897
|
document;
|
|
779
898
|
imageTools;
|
|
@@ -797,7 +916,7 @@ class QRSVG {
|
|
|
797
916
|
width: 0,
|
|
798
917
|
height: 0
|
|
799
918
|
};
|
|
800
|
-
if (this.qr = qr, this.options.image) {
|
|
919
|
+
if (this.qr = qr, this.segmentMask = this.getSegmentMask(count), this.options.image) {
|
|
801
920
|
let size = await this.imageTools.getSize(this.options.image, this.options.imageOptions.crossOrigin), {imageOptions, errorCorrectionPercent} = this.options;
|
|
802
921
|
if (imageOptions.mode == ImageMode.background) {
|
|
803
922
|
let margin = this.options.backgroundOptions && this.options.backgroundOptions.margin || 0, maxSize = (this.options.size - 2 * margin * dotSize) * imageOptions.imageSize, {width, height} = size;
|
|
@@ -867,7 +986,33 @@ class QRSVG {
|
|
|
867
986
|
height: drawImageSize.height,
|
|
868
987
|
count,
|
|
869
988
|
dotSize
|
|
870
|
-
}), this.drawCorners();
|
|
989
|
+
}), this.drawCorners(), this.flattenColorLayers();
|
|
990
|
+
}
|
|
991
|
+
flattenColorLayers() {
|
|
992
|
+
let masks = new Map;
|
|
993
|
+
Array.from(this.defs.childNodes).forEach(node => {
|
|
994
|
+
let id = node.getAttribute?.("id");
|
|
995
|
+
id && masks.set(id, node);
|
|
996
|
+
});
|
|
997
|
+
for (let {rect, mask: id} of this.colorLayers) {
|
|
998
|
+
let mask = masks.get(id);
|
|
999
|
+
if (!mask) continue;
|
|
1000
|
+
let paths = mergeShapes(Array.from(mask.childNodes).filter(node => 1 == node.nodeType));
|
|
1001
|
+
if (!paths) continue;
|
|
1002
|
+
let elements = paths.map(({rule, d}) => {
|
|
1003
|
+
const path = this.document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
1004
|
+
path.setAttribute("d", d), "nonzero" != rule && path.setAttribute("fill-rule", rule);
|
|
1005
|
+
const fill = rect.getAttribute("fill");
|
|
1006
|
+
fill && path.setAttribute("fill", fill);
|
|
1007
|
+
const opacity = rect.getAttribute("opacity");
|
|
1008
|
+
return opacity && path.setAttribute("fill-opacity", opacity), path;
|
|
1009
|
+
}), layer = elements[0];
|
|
1010
|
+
if (elements.length > 1) {
|
|
1011
|
+
let group = this.document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
1012
|
+
elements.forEach(el => group.appendChild(el)), layer = group;
|
|
1013
|
+
}
|
|
1014
|
+
mask.parentNode.removeChild(mask), layer ? (layer.setAttribute("id", id), rect.parentNode.replaceChild(layer, rect)) : rect.parentNode.removeChild(rect);
|
|
1015
|
+
}
|
|
871
1016
|
}
|
|
872
1017
|
drawBackground() {
|
|
873
1018
|
let options = this.options;
|
|
@@ -895,46 +1040,44 @@ class QRSVG {
|
|
|
895
1040
|
if (!this.qr) throw new Error("QR code is not defined");
|
|
896
1041
|
let options = this.options, count = this.qr.getModuleCount();
|
|
897
1042
|
if (count > options.size) throw new Error("The canvas is too small");
|
|
898
|
-
let dotSize = this.options.dotsOptions.size, size = options.
|
|
899
|
-
options.imageOptions.mode == ImageMode.background && (size -= 2 * dotSize * (options.imageOptions.margin || 0));
|
|
900
|
-
let beginning = Math.floor((options.size - count * dotSize) / 2), draw = getQrDotFigure(options.dotsOptions.type, options.plugins), orgDarw = draw;
|
|
1043
|
+
let dotSize = this.options.dotsOptions.size, beginning = Math.floor((options.size - count * dotSize) / 2), draw = getQrDotFigure(options.dotsOptions.type, options.plugins), orgDarw = draw;
|
|
901
1044
|
this.dotsMask = this.createMask("mask-dot-color"), this.defs.appendChild(this.dotsMask),
|
|
902
1045
|
options.imageOptions.mode == ImageMode.background && (this.lightDotsMask = this.createMask("mask-light-dot-color"),
|
|
903
1046
|
this.defs.appendChild(this.lightDotsMask));
|
|
904
|
-
let
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
this._fakeMatrix = new Array(
|
|
910
|
-
let
|
|
911
|
-
for (let i = 0; i <
|
|
912
|
-
this._fakeMatrix[i] = new Array(
|
|
913
|
-
for (let j = 0; j <
|
|
914
|
-
if (i >
|
|
915
|
-
let ii = i -
|
|
1047
|
+
let mask = this.segmentMask || this.getSegmentMask(count), offsetX = mask.startX, offsetY = mask.startY, fakeCountX = mask.mask.length, fakeCountY = Math.max(0, ...mask.mask.map(col => col.length)), fakeBeginningX = beginning - offsetX * dotSize, fakeBeginningY = beginning - offsetY * dotSize, colorSize = Math.max(fakeCountX, fakeCountY) * dotSize, colorX = fakeBeginningX + (fakeCountX * dotSize - colorSize) / 2, colorY = fakeBeginningY + (fakeCountY * dotSize - colorSize) / 2;
|
|
1048
|
+
if (!mask.fitGradient) {
|
|
1049
|
+
let half = count / 2 + Math.max(offsetX, offsetY, fakeCountX - offsetX - count, fakeCountY - offsetY - count);
|
|
1050
|
+
colorX = colorY = beginning + (count / 2 - half) * dotSize, colorSize = 2 * half * dotSize;
|
|
1051
|
+
}
|
|
1052
|
+
this._fakeMatrix = new Array(fakeCountX);
|
|
1053
|
+
let rng = getRng(this._fakeMatrix, 0, 0, !1);
|
|
1054
|
+
for (let i = 0; i < fakeCountX; i++) {
|
|
1055
|
+
this._fakeMatrix[i] = new Array(fakeCountY);
|
|
1056
|
+
for (let j = 0; j < fakeCountY; j++) if (mask.mask[i][j]) {
|
|
1057
|
+
if (i > offsetX - 1 && i < offsetX + count && j > offsetY - 1 && j < offsetY + count) {
|
|
1058
|
+
let ii = i - offsetX, jj = j - offsetY;
|
|
916
1059
|
filter && !filter(ii, jj) ? this._fakeMatrix[i][j] = void 0 : this._fakeMatrix[i][j] = !!this.qr.isDark(jj, ii);
|
|
917
1060
|
continue;
|
|
918
1061
|
}
|
|
919
|
-
|
|
920
|
-
}
|
|
1062
|
+
this._fakeMatrix[i][j] = !(i >= offsetX - 1 && i <= offsetX + count && j >= offsetY - 1 && j <= offsetY + count) && this.qr.isDark(Math.floor(rng() * count), Math.floor(rng() * count));
|
|
1063
|
+
} else this._fakeMatrix[i][j] = void 0;
|
|
921
1064
|
}
|
|
922
|
-
let typeNr = (count - 17) / 4, alignment = QRUtil.getPatternPosition(typeNr), alignmentMatrix = new Array(
|
|
923
|
-
for (let i = 0; i <
|
|
924
|
-
alignmentMatrix[i] = new Array(
|
|
925
|
-
let iAlign = alignment.find(v => i -
|
|
926
|
-
for (let j = 0; j <
|
|
927
|
-
let jAlign = alignment.find(v => j -
|
|
1065
|
+
let typeNr = (count - 17) / 4, alignment = QRUtil.getPatternPosition(typeNr), alignmentMatrix = new Array(fakeCountX);
|
|
1066
|
+
for (let i = 0; i < fakeCountX; i++) {
|
|
1067
|
+
alignmentMatrix[i] = new Array(fakeCountY);
|
|
1068
|
+
let iAlign = alignment.find(v => i - offsetX > v - 3 && i - offsetX < v + 3);
|
|
1069
|
+
for (let j = 0; j < fakeCountY; j++) {
|
|
1070
|
+
let jAlign = alignment.find(v => j - offsetY > v - 3 && j - offsetY < v + 3);
|
|
928
1071
|
alignmentMatrix[i][j] = void 0, null != this._fakeMatrix[i][j] && (this.lightDotsMask && iAlign && jAlign && (iAlign != alignment[0] && jAlign != alignment[0] || jAlign != alignment[0] && jAlign != alignment[alignment.length - 1] || iAlign != alignment[0] && iAlign != alignment[alignment.length - 1]) && (alignmentMatrix[i][j] = this._fakeMatrix[i][j]));
|
|
929
1072
|
}
|
|
930
1073
|
}
|
|
931
|
-
for (let i = 0; i <
|
|
1074
|
+
for (let i = 0; i < fakeCountX; i++) for (let j = 0; j < fakeCountY; j++) {
|
|
932
1075
|
if (null == this._fakeMatrix[i][j]) continue;
|
|
933
1076
|
this.lightDotsMask && (draw = null != alignmentMatrix[i][j] ? orgDarw : getQrDotFigure(DotType.tinySquare));
|
|
934
1077
|
let alignmentNb = options.imageOptions.mode == ImageMode.background && null != alignmentMatrix[i][j];
|
|
935
1078
|
this._fakeMatrix[i][j] ? this.dotsMask && this.dotsMask.appendChild(draw({
|
|
936
|
-
x:
|
|
937
|
-
y:
|
|
1079
|
+
x: fakeBeginningX + i * dotSize,
|
|
1080
|
+
y: fakeBeginningY + j * dotSize,
|
|
938
1081
|
size: dotSize,
|
|
939
1082
|
document: this.options.document,
|
|
940
1083
|
getNeighbor: (xOffset, yOffset) => {
|
|
@@ -943,8 +1086,8 @@ class QRSVG {
|
|
|
943
1086
|
},
|
|
944
1087
|
getPRandom: getRng(this._fakeMatrix, i, j)
|
|
945
1088
|
})) : this.lightDotsMask && this.lightDotsMask && this.lightDotsMask.appendChild(draw({
|
|
946
|
-
x:
|
|
947
|
-
y:
|
|
1089
|
+
x: fakeBeginningX + i * dotSize,
|
|
1090
|
+
y: fakeBeginningY + j * dotSize,
|
|
948
1091
|
size: dotSize,
|
|
949
1092
|
document: this.options.document,
|
|
950
1093
|
getNeighbor: (xOffset, yOffset) => {
|
|
@@ -958,19 +1101,19 @@ class QRSVG {
|
|
|
958
1101
|
options: options.imageOptions.fill.gradient,
|
|
959
1102
|
color: options.imageOptions.fill.color,
|
|
960
1103
|
additionalRotation: 0,
|
|
961
|
-
x:
|
|
962
|
-
y:
|
|
963
|
-
height:
|
|
964
|
-
width:
|
|
1104
|
+
x: colorX,
|
|
1105
|
+
y: colorY,
|
|
1106
|
+
height: colorSize,
|
|
1107
|
+
width: colorSize,
|
|
965
1108
|
name: "light-dot-color"
|
|
966
1109
|
}), this._dotsColor = this.createColor({
|
|
967
1110
|
options: options.dotsOptions?.gradient,
|
|
968
1111
|
color: options.dotsOptions.color,
|
|
969
1112
|
additionalRotation: 0,
|
|
970
|
-
x:
|
|
971
|
-
y:
|
|
972
|
-
height:
|
|
973
|
-
width:
|
|
1113
|
+
x: colorX,
|
|
1114
|
+
y: colorY,
|
|
1115
|
+
height: colorSize,
|
|
1116
|
+
width: colorSize,
|
|
974
1117
|
name: "dot-color"
|
|
975
1118
|
});
|
|
976
1119
|
}
|
|
@@ -1086,22 +1229,51 @@ class QRSVG {
|
|
|
1086
1229
|
}
|
|
1087
1230
|
});
|
|
1088
1231
|
}
|
|
1232
|
+
getSegmentMask(count) {
|
|
1233
|
+
let options = this.options;
|
|
1234
|
+
if (options.mask) return options.mask;
|
|
1235
|
+
let dotSize = options.dotsOptions.size, offset = 0;
|
|
1236
|
+
if (options.shape === ShapeType.circle) {
|
|
1237
|
+
let size = options.size;
|
|
1238
|
+
options.imageOptions.mode == ImageMode.background && (size -= 2 * dotSize * (options.imageOptions.margin || 0));
|
|
1239
|
+
let margin = options.backgroundOptions && options.backgroundOptions.margin || 0;
|
|
1240
|
+
offset = Math.floor((size / dotSize - count - 2 * margin) / 2);
|
|
1241
|
+
} else options.imageOptions.mode == ImageMode.background && (offset = 1);
|
|
1242
|
+
let fakeCount = count + 2 * offset, center = Math.floor(fakeCount / 2);
|
|
1243
|
+
return {
|
|
1244
|
+
mask: Array.from({
|
|
1245
|
+
length: fakeCount
|
|
1246
|
+
}, (_col, i) => Array.from({
|
|
1247
|
+
length: fakeCount
|
|
1248
|
+
}, (_cell, j) => options.shape !== ShapeType.circle || i >= offset && i < offset + count && j >= offset && j < offset + count || Math.sqrt((i - center) * (i - center) + (j - center) * (j - center)) <= center)),
|
|
1249
|
+
startX: offset,
|
|
1250
|
+
startY: offset
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1089
1253
|
async drawImage({width, height, count, dotSize}) {
|
|
1090
1254
|
let options = this.options, beginning = Math.floor((options.size - count * dotSize) / 2), margin = options.imageOptions.margin * dotSize;
|
|
1091
1255
|
options.imageOptions.mode == ImageMode.background && (margin = 0);
|
|
1092
|
-
let dx = beginning + margin + (count * dotSize - width) / 2, dy = beginning + margin + (count * dotSize - height) / 2, dw = width - 2 * margin, dh = height - 2 * margin, imageUrl = await this.imageTools.toDataURL(options.image || "")
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1256
|
+
let dx = beginning + margin + (count * dotSize - width) / 2, dy = beginning + margin + (count * dotSize - height) / 2, dw = width - 2 * margin, dh = height - 2 * margin, imageUrl = await this.imageTools.toDataURL(options.image || "");
|
|
1257
|
+
this._element.appendChild(function(document, imageUrl, {x, y, width, height}) {
|
|
1258
|
+
let image = document.createElementNS("http://www.w3.org/2000/svg", "image");
|
|
1259
|
+
if (image.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", imageUrl || ""),
|
|
1260
|
+
imageUrl.startsWith("data:image/svg+xml;")) {
|
|
1261
|
+
let data = imageUrl.substring(19), i = data.indexOf(","), encoding = data.substring(0, i);
|
|
1262
|
+
if (data = data.substring(i + 1), data = "base64" === encoding ? "function" == typeof atob ? atob(data) : Buffer.from(data, "base64").toString("utf8") : "",
|
|
1263
|
+
data) {
|
|
1264
|
+
let container = (new DOMParser).parseFromString(data, "text/xml"), rootEl = Array.from(container.getElementsByTagName("svg"));
|
|
1265
|
+
rootEl.length && (image = rootEl[0], image.setAttribute("overflow", "visible"));
|
|
1266
|
+
}
|
|
1100
1267
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
this.
|
|
1268
|
+
return image.setAttribute("x", numToAttr(x)), image.setAttribute("y", numToAttr(y)),
|
|
1269
|
+
image.setAttribute("width", svgAttr`${width}px`), image.setAttribute("height", svgAttr`${height}px`),
|
|
1270
|
+
image;
|
|
1271
|
+
}(this.document, imageUrl, {
|
|
1272
|
+
x: dx,
|
|
1273
|
+
y: dy,
|
|
1274
|
+
width: dw,
|
|
1275
|
+
height: dh
|
|
1276
|
+
}));
|
|
1105
1277
|
}
|
|
1106
1278
|
createColor(cfg) {
|
|
1107
1279
|
let {width, height, x, y} = cfg;
|
|
@@ -1132,7 +1304,7 @@ class QRSVG {
|
|
|
1132
1304
|
}
|
|
1133
1305
|
return options.colorStops.forEach(stopCfg => {
|
|
1134
1306
|
let stop = document.createElementNS("http://www.w3.org/2000/svg", "stop");
|
|
1135
|
-
stop.setAttribute("offset", `${
|
|
1307
|
+
stop.setAttribute("offset", svgAttr`${100 * stopCfg.offset}%`);
|
|
1136
1308
|
let parsed = parseColor(stopCfg.color);
|
|
1137
1309
|
stop.setAttribute("stop-color", parsed.value), parsed.alpha < 1 && stop.setAttribute("stop-opacity", parsed.alpha.toFixed(7)),
|
|
1138
1310
|
gradient.appendChild(stop);
|
|
@@ -1156,7 +1328,10 @@ class QRSVG {
|
|
|
1156
1328
|
});
|
|
1157
1329
|
return value && (rect.setAttribute("fill", value.value), value.gradient && this.defs.appendChild(value.gradient),
|
|
1158
1330
|
value.opacity < 1 && rect.setAttribute("opacity", value.opacity.toFixed(7))), this._element.appendChild(rect),
|
|
1159
|
-
|
|
1331
|
+
this.colorLayers.push({
|
|
1332
|
+
rect,
|
|
1333
|
+
mask: `mask-${cfg.name}`
|
|
1334
|
+
}), value;
|
|
1160
1335
|
}
|
|
1161
1336
|
createMask(id) {
|
|
1162
1337
|
let mask = this.document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
|
|
@@ -1232,34 +1407,64 @@ let QRCodeStyling$1 = class {
|
|
|
1232
1407
|
}
|
|
1233
1408
|
setupSvg() {
|
|
1234
1409
|
if (!this.qr) return;
|
|
1235
|
-
let moduleCount = this.qr.getModuleCount();
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1410
|
+
let mask, size, appliedMask, moduleCount = this.qr.getModuleCount(), isBackground = this.options.imageOptions.mode == ImageMode.background, padding = isBackground ? 1 : 0;
|
|
1411
|
+
for (let plugin of this.options.plugins || []) if (mask = plugin.applyMask?.(moduleCount, padding) || void 0,
|
|
1412
|
+
mask) break;
|
|
1413
|
+
if (mask) {
|
|
1414
|
+
let {startX, startY} = mask, columns = mask.mask.slice(startX, startX + moduleCount);
|
|
1415
|
+
if (startX < padding || startY < padding || startX + moduleCount + padding > mask.mask.length || columns.length < moduleCount || columns.some(col => startY + moduleCount + padding > col.length)) throw new Error(padding ? `The mask must extend ${padding} segment(s) beyond the QR code on each side` : "The QR code must lie inside the mask");
|
|
1416
|
+
if ([ [ 0, 0 ], [ moduleCount - 7, 0 ], [ 0, moduleCount - 7 ] ].some(([x, y]) => columns.slice(x, x + 7).some(col => col.slice(startY + y, startY + y + 7).some(v => !v)))) throw new Error("The QR code corners must not be hidden by the mask");
|
|
1417
|
+
}
|
|
1418
|
+
if (mask) {
|
|
1419
|
+
let dotSize = this.options.dotsOptions.size, margin = isBackground ? 1 + (this.options.imageOptions.margin || 0) : 0;
|
|
1420
|
+
size = Math.ceil(dotSize * (moduleCount + 2 * margin));
|
|
1421
|
+
let beginning = Math.floor((size - moduleCount * dotSize) / 2);
|
|
1422
|
+
appliedMask = {
|
|
1423
|
+
...mask,
|
|
1424
|
+
count: moduleCount,
|
|
1425
|
+
dotSize,
|
|
1426
|
+
x: beginning - mask.startX * dotSize,
|
|
1427
|
+
y: beginning - mask.startY * dotSize
|
|
1428
|
+
};
|
|
1429
|
+
} else {
|
|
1430
|
+
this.options.imageOptions.mode == ImageMode.background && this.options.shape != ShapeType.circle && (moduleCount += 2);
|
|
1431
|
+
let count = Math.ceil((this.options.shape == ShapeType.circle ? Math.sqrt(2) : 1) * moduleCount);
|
|
1432
|
+
count % 2 == 0 && (count -= 1);
|
|
1433
|
+
let margin = this.options.backgroundOptions && this.options.backgroundOptions.margin || 0;
|
|
1434
|
+
this.options.imageOptions.mode == ImageMode.background && (margin += this.options.imageOptions.margin || 0),
|
|
1435
|
+
size = Math.ceil(this.options.dotsOptions.size * (count + 2 * margin));
|
|
1436
|
+
}
|
|
1242
1437
|
this.qrSVG = new QRSVG({
|
|
1243
1438
|
...this.options,
|
|
1439
|
+
...mask && {
|
|
1440
|
+
shape: ShapeType.square,
|
|
1441
|
+
backgroundOptions: void 0
|
|
1442
|
+
},
|
|
1244
1443
|
width: size,
|
|
1245
1444
|
height: size,
|
|
1246
1445
|
size,
|
|
1446
|
+
mask,
|
|
1247
1447
|
errorCorrectionPercent: ErrorCorrectionPercents[this.options.qrOptions.errorCorrectionLevel]
|
|
1248
|
-
}), this.svgDrawingPromise = this.qrSVG.drawQR(this.qr).then(() => {
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1448
|
+
}), this.svgDrawingPromise = this.qrSVG.drawQR(this.qr).then(async () => {
|
|
1449
|
+
if (this.qrSVG?.element) {
|
|
1450
|
+
if (this.options.plugins) for (let plugin of this.options.plugins) await (plugin.postProcess?.(this.qrSVG.element, {
|
|
1451
|
+
...this.options,
|
|
1452
|
+
width: size,
|
|
1453
|
+
height: size,
|
|
1454
|
+
size,
|
|
1455
|
+
mask: appliedMask
|
|
1456
|
+
}, {
|
|
1457
|
+
dots: this.qrSVG?.dotsColor,
|
|
1458
|
+
background: this.qrSVG?.backgroundColor
|
|
1459
|
+
}));
|
|
1460
|
+
this.extension?.(this.qrSVG.element, {
|
|
1461
|
+
...this.options,
|
|
1462
|
+
width: size,
|
|
1463
|
+
height: size,
|
|
1464
|
+
size,
|
|
1465
|
+
mask: appliedMask
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1263
1468
|
});
|
|
1264
1469
|
}
|
|
1265
1470
|
};
|
|
@@ -1299,8 +1504,8 @@ class QRCodeStyling extends QRCodeStyling$1 {
|
|
|
1299
1504
|
imageTools: options.imageTools || {
|
|
1300
1505
|
toDataURL: url => "string" == typeof url && url.startsWith("data:") ? Promise.resolve(url) : loadImage(url).then(({contentType, data}) => `data:${contentType?.replace("application/xml", "image/svg+xml")};base64,${data.toString("base64")}`),
|
|
1301
1506
|
getSize: async src => {
|
|
1302
|
-
let {data} = Buffer.isBuffer(
|
|
1303
|
-
data:
|
|
1507
|
+
let {data} = Buffer.isBuffer(src) ? {
|
|
1508
|
+
data: src
|
|
1304
1509
|
} : await loadImage(src), meta = await sharp(data).metadata();
|
|
1305
1510
|
return {
|
|
1306
1511
|
width: meta.width,
|