@liquid-js/qr-code-styling
Version:
Generate styled QR codes on web or in Node
912 lines (881 loc) • 67 kB
JavaScript
import { QRUtil } from "@liquid-js/qrcode-generator/lib/qrcode/QRUtil.js";
import { stringToBytes_UTF8 } from "@liquid-js/qrcode-generator/lib/text/stringToBytes_UTF8.js";
import { ErrorCorrectionLevel, TypeNumber, Mode, QRCodeMinimal } from "@liquid-js/qrcode-generator/lib/qrcode/QRCodeMinimal.js";
import sharp from "sharp";
import { fileTypeFromBuffer } from "file-type";
import { DOMImplementation, XMLSerializer as XMLSerializer$1, DOMParser as DOMParser$1 } from "@xmldom/xmldom";
export { ErrorCorrectionLevel, Mode, TypeNumber } from "@liquid-js/qrcode-generator/lib/qrcode/QRCodeMinimal.js";
let isObject = obj => !!obj && "object" == typeof obj && !Array.isArray(obj);
function mergeDeep(target, ...sources) {
if (!sources.length) return target;
let source = sources.shift();
return void 0 !== source && isObject(target) && isObject(source) ? (target = {
...target
}, Object.keys(source).forEach(key => {
let targetValue = target[key], sourceValue = source[key];
Array.isArray(targetValue) && Array.isArray(sourceValue) ? target[key] = sourceValue : isObject(targetValue) && isObject(sourceValue) ? target[key] = mergeDeep({
...targetValue
}, sourceValue) : target[key] = sourceValue;
}), mergeDeep(target, ...sources)) : target;
}
var GradientType, DotType, CornerDotType, CornerSquareType, ShapeType, ImageMode;
function sanitizeGradient(gradient) {
let newGradient = {
...gradient
};
if (!newGradient.colorStops || !newGradient.colorStops.length) throw new Error("Field 'colorStops' is required in gradient");
return newGradient.rotation ? newGradient.rotation = Number(newGradient.rotation) : newGradient.rotation = 0,
newGradient.colorStops = newGradient.colorStops.map(colorStop => ({
...colorStop,
offset: Number(colorStop.offset)
})), newGradient;
}
!function(GradientType) {
GradientType.radial = "radial", GradientType.linear = "linear";
}(GradientType || (GradientType = {})), function(DotType) {
DotType.dot = "dot", DotType.randomDot = "random-dot", DotType.rounded = "rounded",
DotType.extraRounded = "extra-rounded", DotType.verticalLine = "vertical-line",
DotType.horizontalLine = "horizontal-line", DotType.classy = "classy", DotType.classyRounded = "classy-rounded",
DotType.square = "square", DotType.smallSquare = "small-square", DotType.tinySquare = "tiny-square",
DotType.diamond = "diamond", DotType.wave = "wave", DotType.heart = "heart", DotType.star = "star",
DotType.weave = "weave", DotType.pentagon = "pentagon", DotType.hexagon = "hexagon",
DotType.zebraHorizontal = "zebra-horizontal", DotType.zebraVertical = "zebra-vertical",
DotType.blocksHorizontal = "blocks-horizontal", DotType.blocksVertical = "blocks-vertical";
}(DotType || (DotType = {})), function(CornerDotType) {
CornerDotType.dot = "dot", CornerDotType.square = "square", CornerDotType.heart = "heart",
CornerDotType.extraRounded = "extra-rounded", CornerDotType.classy = "classy", CornerDotType.inpoint = "inpoint",
CornerDotType.outpoint = "outpoint", CornerDotType.star = "star", CornerDotType.pentagon = "pentagon",
CornerDotType.hexagon = "hexagon", CornerDotType.diamond = "diamond";
}(CornerDotType || (CornerDotType = {})), function(CornerSquareType) {
CornerSquareType.dot = "dot", CornerSquareType.square = "square", CornerSquareType.extraRounded = "extra-rounded",
CornerSquareType.classy = "classy", CornerSquareType.inpoint = "inpoint", CornerSquareType.outpoint = "outpoint",
CornerSquareType.centerCircle = "center-circle";
}(CornerSquareType || (CornerSquareType = {})), function(ShapeType) {
ShapeType.square = "square", ShapeType.circle = "circle";
}(ShapeType || (ShapeType = {})), function(ImageMode) {
ImageMode.center = "center", ImageMode.overlay = "overlay", ImageMode.background = "background";
}(ImageMode || (ImageMode = {}));
let defaultOptions = {
document: void 0,
shape: ShapeType.square,
width: void 0,
height: void 0,
data: "",
qrOptions: {
typeNumber: TypeNumber[0],
mode: void 0,
errorCorrectionLevel: ErrorCorrectionLevel.Q
},
imageOptions: {
mode: ImageMode.center,
imageSize: .4,
crossOrigin: void 0,
margin: 0,
fill: {
color: "rgba(255,255,255,1)"
}
},
dotsOptions: {
type: DotType.square,
color: "#000",
size: 10
}
};
function sanitizeOptions(options) {
let newOptions = {
...options
};
return newOptions.imageOptions = {
...newOptions.imageOptions,
imageSize: Math.min(1, Number(newOptions.imageOptions.imageSize)) || 1,
margin: Number(newOptions.imageOptions.margin),
fill: {
...newOptions.imageOptions.fill
}
}, newOptions.imageOptions.mode == ImageMode.overlay && (newOptions.imageOptions.margin = 0),
newOptions.imageOptions.fill.gradient && (newOptions.imageOptions.fill.gradient = sanitizeGradient(newOptions.imageOptions.fill.gradient)),
newOptions.dotsOptions = {
...newOptions.dotsOptions
}, newOptions.dotsOptions.gradient && (newOptions.dotsOptions.gradient = sanitizeGradient(newOptions.dotsOptions.gradient)),
newOptions.dotsOptions.size = Math.round(Math.max(0, newOptions.dotsOptions.size) || 10),
newOptions.cornersSquareOptions && (newOptions.cornersSquareOptions = {
...newOptions.cornersSquareOptions
}, newOptions.cornersSquareOptions.gradient && (newOptions.cornersSquareOptions.gradient = sanitizeGradient(newOptions.cornersSquareOptions.gradient))),
newOptions.cornersDotOptions && (newOptions.cornersDotOptions = {
...newOptions.cornersDotOptions
}, newOptions.cornersDotOptions.gradient && (newOptions.cornersDotOptions.gradient = sanitizeGradient(newOptions.cornersDotOptions.gradient))),
newOptions.backgroundOptions && (newOptions.backgroundOptions = {
...newOptions.backgroundOptions
}, newOptions.backgroundOptions.gradient && (newOptions.backgroundOptions.gradient = sanitizeGradient(newOptions.backgroundOptions.gradient))),
newOptions.document || (newOptions.document = document), newOptions;
}
let ErrorCorrectionPercents = {
[ErrorCorrectionLevel.L]: .07,
[ErrorCorrectionLevel.M]: .15,
[ErrorCorrectionLevel.Q]: .25,
[ErrorCorrectionLevel.H]: .3
};
let rx = /\.?0+$/;
function numToAttr(value) {
return "string" == typeof value ? value : value.toFixed(7).replace(rx, "");
}
function svgPath(strings, ...values) {
return strings.reduce((t, v, i) => {
let p = "";
return i && (p = values[i - 1]), "number" == typeof p && (p = numToAttr(p)), `${t}${p}${v}`;
}, "").trim().replace(/[\s\n\r]+/gim, " ");
}
function rotateFigure({draw, ...args}) {
let {x, y, size, rotation = 0} = args, cx = x + size / 2, cy = y + size / 2, element = draw(args);
return rotation && (Array.isArray(element) ? element : [ element ]).forEach(el => el.setAttribute("transform", `rotate(${numToAttr(180 * rotation / Math.PI)},${cx},${cy})`)),
element;
}
let DotElements = {
dot: args => {
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "circle");
return element.setAttribute("cx", numToAttr(x + size / 2)), element.setAttribute("cy", numToAttr(y + size / 2)),
element.setAttribute("r", numToAttr(size / 2)), element;
},
square: (args, {width = args.size, height = args.size} = {}) => {
const {x, y, size, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "rect");
return element.setAttribute("x", numToAttr(x + (size - width) / 2)), element.setAttribute("y", numToAttr(y + (size - height) / 2)),
element.setAttribute("width", numToAttr(width)), element.setAttribute("height", numToAttr(height)),
element;
},
sideRounded: (args, {height = args.size} = {}) => {
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
return element.setAttribute("d", svgPath`M ${x} ${y + (size - height) / 2} v ${height} h ${size / 2} a ${height / 2} ${height / 2} 0 0 0 0 ${-height} z`),
element;
},
cornerRounded: args => {
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
return element.setAttribute("d", svgPath`M ${x} ${y} v ${size} h ${size} v ${-size / 2} a ${size / 2} ${size / 2} 0 0 0 ${-size / 2} ${-size / 2} z`),
element;
},
cornerExtraRounded: args => {
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
return element.setAttribute("d", svgPath`M ${x} ${y} v ${size} h ${size} a ${size} ${size} 0 0 0 ${-size} ${-size} z`),
element;
},
classyDot: args => {
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
return element.setAttribute("d", svgPath`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`),
element;
},
wave: args => {
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");
return element.setAttribute("d", svgPath`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`),
element;
},
heart: args => {
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
return element.setAttribute("d", function(path, {x, y, size}) {
let move = !1, i = 0;
return path.map(v => "string" == typeof v ? (i = 0, move = v.toUpperCase() == v,
v) : (i++, v *= size, move && (v += i % 2 == 1 ? x : y), numToAttr(v))).join(" ");
}([ "M", 1, .31629, "c", -86e-5, .15702, -.10534, .26323, -.21876, .38123, "c", -.06736, .06834, -.18938, .17948, -.28124, .26126, "c", -.09188, -.08178, -.2139, -.19292, -.28124, -.26126, "c", -.11344, -.118, -.2179, -.22422, -.21876, -.38123, "c", -96e-5, -.27136, .33154, -.36842, .5, -.17, "c", .16844, -.19842, .50094, -.10136, .5, .17, "z" ], {
x,
y,
size
})), element;
},
rounded: args => {
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "rect");
return element.setAttribute("x", numToAttr(x)), element.setAttribute("y", numToAttr(y)),
element.setAttribute("width", numToAttr(size)), element.setAttribute("height", numToAttr(size)),
element.setAttribute("rx", numToAttr(size / 4)), element.setAttribute("ry", numToAttr(size / 4)),
element;
},
classy: args => {
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
return element.setAttribute("d", svgPath`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`),
element;
},
inpoint: args => {
const {size, x, y, document} = args, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
return element.setAttribute("d", svgPath`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`),
element;
},
star: (args, {spikes = 5, outerRadius = args.size / 2, innerRadius = args.size / 4} = {}) => {
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");
return element.setAttribute("d", Array(2 * spikes).fill(0).map((_, i) => {
const radius = i % 2 == 0 ? outerRadius : innerRadius;
return svgPath`${0 === i ? "M" : "L"} ${cx + radius * Math.sin(i * angle)} ${cy - radius * Math.cos(i * angle)}`;
}).join(" ")), element;
},
weave: args => {
const {size, x, y, document} = args, thickness = .6 * size, notch = (size - thickness) / 2, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
return element.setAttribute("d", svgPath`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`),
element;
}
}, qrCornerDotFigures = {
[CornerDotType.dot]: args => rotateFigure({
...args,
draw: DotElements.dot
}),
[CornerDotType.square]: args => rotateFigure({
...args,
draw: DotElements.square
}),
[CornerDotType.heart]: args => DotElements.heart(args),
[CornerDotType.extraRounded]: args => rotateFigure({
...args,
draw: DotElements.rounded
}),
[CornerDotType.classy]: args => rotateFigure({
...args,
draw: DotElements.classy
}),
[CornerDotType.inpoint]: args => rotateFigure({
...args,
draw: DotElements.inpoint
}),
[CornerDotType.outpoint]: args => rotateFigure({
...args,
rotation: (args.rotation || 0) + Math.PI,
draw: DotElements.inpoint
}),
[CornerDotType.star]: args => DotElements.star(args),
[CornerDotType.pentagon]: args => DotElements.star(args, {
spikes: 2.5,
outerRadius: args.size / 2,
innerRadius: args.size / 2
}),
[CornerDotType.hexagon]: args => DotElements.star(args, {
spikes: 3,
outerRadius: args.size / 2,
innerRadius: args.size / 2
}),
[CornerDotType.diamond]: args => rotateFigure({
...args,
rotation: Math.PI / 4,
draw: args2 => DotElements.square(args2, {
width: .85 * args2.size,
height: .85 * args2.size
})
})
};
let SquareElements = {
dot: args => {
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgPath`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`);
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgPath`M ${x + size / 2} ${y - dotSize} a ${size / 2 + dotSize} ${size / 2 + dotSize} 0 1 0 0.1 0 z`),
[ element, fill ];
},
square: args => {
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgPath`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`);
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgPath`M ${x - dotSize} ${y - dotSize} h ${size + 2 * dotSize} v ${size + 2 * dotSize} h ${-size - 2 * dotSize} z`),
[ element, fill ];
},
extraRounded: args => {
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgPath`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`);
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgPath`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`),
[ element, fill ];
},
classy: args => {
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgPath`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`);
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgPath`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`),
[ element, fill ];
},
inpoint: args => {
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgPath`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`);
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgPath`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`),
[ element, fill ];
},
centerCircle: args => {
const {x, y, size} = 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");
element.setAttribute("clip-rule", "evenodd"), element.setAttribute("d", svgPath`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`);
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
return fill.setAttribute("clip-rule", "evenodd"), fill.setAttribute("d", svgPath`M ${x - dotSize} ${y - dotSize} h ${size + 2 * dotSize} v ${size + 2 * dotSize} h ${-size - 2 * dotSize} z`),
[ element, fill ];
}
}, qrCornerSquareFigures = {
[CornerSquareType.dot]: args => SquareElements.dot(args),
[CornerSquareType.square]: args => SquareElements.square(args),
[CornerSquareType.extraRounded]: args => SquareElements.extraRounded(args),
[CornerSquareType.classy]: args => rotateFigure({
...args,
draw: SquareElements.classy
}),
[CornerSquareType.inpoint]: args => rotateFigure({
...args,
draw: SquareElements.inpoint
}),
[CornerSquareType.outpoint]: ({rotation, ...args}) => rotateFigure({
...args,
rotation: (rotation || 0) + Math.PI,
draw: SquareElements.inpoint
}),
[CornerSquareType.centerCircle]: args => SquareElements.centerCircle(args)
};
function roundedCorners({x, y, size, document, getNeighbor}, {corner = DotElements.cornerRounded, end = DotElements.sideRounded} = {}) {
let leftNeighbor = getNeighbor ? +getNeighbor(-1, 0) : 0, rightNeighbor = getNeighbor ? +getNeighbor(1, 0) : 0, topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0, bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0, neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor;
if (0 === neighborsCount) return DotElements.dot({
x,
y,
size,
document
});
if (neighborsCount > 2 || leftNeighbor && rightNeighbor || topNeighbor && bottomNeighbor) return DotElements.square({
x,
y,
size,
document
});
if (2 === neighborsCount) {
let rotation = 0;
return leftNeighbor && topNeighbor ? rotation = Math.PI / 2 : topNeighbor && rightNeighbor ? rotation = Math.PI : rightNeighbor && bottomNeighbor && (rotation = -Math.PI / 2),
rotateFigure({
x,
y,
size,
rotation,
document,
draw: corner
});
}
{
let rotation = 0;
return topNeighbor ? rotation = Math.PI / 2 : rightNeighbor ? rotation = Math.PI : bottomNeighbor && (rotation = -Math.PI / 2),
rotateFigure({
x,
y,
size,
rotation,
document,
draw: end
});
}
}
function classy({x, y, size, document, getNeighbor}, {corner = DotElements.cornerRounded} = {}) {
let leftNeighbor = getNeighbor ? +getNeighbor(-1, 0) : 0, rightNeighbor = getNeighbor ? +getNeighbor(1, 0) : 0, topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0, bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0;
return 0 === leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor ? rotateFigure({
x,
y,
size,
rotation: Math.PI / 2,
document,
draw: DotElements.classyDot
}) : leftNeighbor || topNeighbor ? rightNeighbor || bottomNeighbor ? DotElements.square({
x,
y,
size,
document
}) : rotateFigure({
x,
y,
size,
rotation: Math.PI / 2,
document,
draw: corner
}) : rotateFigure({
x,
y,
size,
rotation: -Math.PI / 2,
document,
draw: corner
});
}
function stripes({x, y, size, document, getNeighbor}, {stripe = size, rotation = 0, endpoint = DotElements.sideRounded, dot = DotElements.dot} = {}) {
let topNeighbor = getNeighbor ? +getNeighbor(0, -1) : 0, bottomNeighbor = getNeighbor ? +getNeighbor(0, 1) : 0;
return topNeighbor && bottomNeighbor ? rotateFigure({
x,
y,
size,
rotation,
document,
draw: _ => DotElements.square({
x,
y,
size,
document
}, {
width: stripe
})
}) : topNeighbor && !bottomNeighbor ? (rotation += Math.PI / 2, rotateFigure({
x,
y,
size,
rotation,
document,
draw: args => endpoint(args, {
height: stripe
})
})) : bottomNeighbor && !topNeighbor ? (rotation -= Math.PI / 2, rotateFigure({
x,
y,
size,
rotation,
document,
draw: args => endpoint(args, {
height: stripe
})
})) : rotateFigure({
x,
y,
size,
rotation,
document,
draw: _ => dot({
x: x + (size - stripe) / 2,
y: y + (size - stripe) / 2,
size: stripe,
document
})
});
}
let qrDotFigures = {
[DotType.dot]: args => DotElements.dot(args),
[DotType.randomDot]: ({size, x, y, getPRandom, ...args}) => {
const rnd = getPRandom || Math.random, randomFactor = .25 * rnd() + .75;
return DotElements.dot({
...args,
size: size * randomFactor,
x: x + size * rnd() * (1 - randomFactor),
y: y + size * rnd() * (1 - randomFactor)
});
},
[DotType.rounded]: args => roundedCorners(args),
[DotType.extraRounded]: args => roundedCorners(args, {
corner: DotElements.cornerExtraRounded
}),
[DotType.verticalLine]: args => stripes(args),
[DotType.horizontalLine]: ({getNeighbor, ...args}) => stripes({
...args,
getNeighbor: getNeighbor ? (x, y) => getNeighbor(y, x) : void 0
}, {
rotation: -Math.PI / 2
}),
[DotType.classy]: args => classy(args),
[DotType.classyRounded]: args => classy(args, {
corner: DotElements.cornerExtraRounded
}),
[DotType.square]: args => DotElements.square(args),
[DotType.smallSquare]: ({x, y, size, document}) => DotElements.square({
x: x += .15 * size,
y: y += .15 * size,
size: size = .7 * size,
document
}),
[DotType.tinySquare]: ({x, y, size, document}) => DotElements.square({
x: x += .35 * size,
y: y += .35 * size,
size: size = .3 * size,
document
}),
[DotType.diamond]: args => rotateFigure({
...args,
rotation: Math.PI / 4,
draw: args2 => DotElements.square(args2, {
width: .85 * args2.size,
height: .85 * args2.size
})
}),
[DotType.wave]: args => roundedCorners(args, {
corner: DotElements.cornerExtraRounded,
end: DotElements.wave
}),
[DotType.heart]: args => DotElements.heart(args),
[DotType.star]: args => DotElements.star(args),
[DotType.weave]: args => DotElements.weave(args),
[DotType.pentagon]: args => DotElements.star(args, {
spikes: 2.5,
outerRadius: args.size / 2,
innerRadius: args.size / 2
}),
[DotType.hexagon]: args => DotElements.star(args, {
spikes: 3,
outerRadius: args.size / 2,
innerRadius: args.size / 2
}),
[DotType.zebraVertical]: args => stripes(args, {
stripe: .8 * args.size
}),
[DotType.zebraHorizontal]: ({getNeighbor, ...args}) => stripes({
...args,
getNeighbor: getNeighbor ? (x, y) => getNeighbor(y, x) : void 0
}, {
stripe: .8 * args.size,
rotation: -Math.PI / 2
}),
[DotType.blocksVertical]: args => stripes(args, {
stripe: .8 * args.size,
endpoint: (_args, _params) => {
const rnd = args.getPRandom || Math.random, width = args.size * (1 - .25 * rnd()), x = args.x - (args.size - width) / 2;
return DotElements.square({
..._args,
x
}, {
..._params,
width
});
},
dot: _args => {
const rnd = args.getPRandom || Math.random, height = args.size * (1 - .25 * rnd()), y = args.y + (args.size - height) * rnd();
return DotElements.square({
..._args,
y
}, {
height
});
}
}),
[DotType.blocksHorizontal]: ({getNeighbor, ...args}) => stripes({
...args,
getNeighbor: getNeighbor ? (x, y) => getNeighbor(y, x) : void 0
}, {
stripe: .8 * args.size,
rotation: -Math.PI / 2,
endpoint: (_args, _params) => {
const rnd = args.getPRandom || Math.random, width = args.size * (1 - .25 * rnd()), x = args.x - (args.size - width) / 2;
return DotElements.square({
..._args,
x
}, {
..._params,
width
});
},
dot: _args => {
const rnd = args.getPRandom || Math.random, height = args.size * (1 - .25 * rnd()), y = args.y + (args.size - height) * rnd();
return DotElements.square({
..._args,
y
}, {
height
});
}
})
};
function getQrDotFigure(type, plugins) {
let defaultDraw = qrDotFigures[type] || qrDotFigures[DotType.square];
if (!plugins?.length) return defaultDraw;
let drawPlugin = function(plugins) {
return args => {
for (let plugin of plugins) {
let el = plugin.drawDot?.(args);
if (el) return el;
}
};
}(plugins);
return args => drawPlugin(args) || defaultDraw(args);
}
let browserImageTools = {
toDataURL: url => "string" == typeof url && url.startsWith("data:") ? Promise.resolve(url) : new Promise((resolve, reject) => {
if ("string" == typeof url) {
const xhr = new XMLHttpRequest;
xhr.onload = () => {
const reader = new FileReader;
reader.onloadend = () => {
resolve(reader.result);
}, reader.readAsDataURL(xhr.response);
}, xhr.onerror = xhr.onabort = xhr.ontimeout = reject, xhr.open("GET", url, !0),
xhr.responseType = "blob", xhr.send();
} else {
const reader = new FileReader;
reader.onloadend = () => {
resolve(reader.result);
}, reader.readAsDataURL(url);
}
}),
getSize: (src, crossOrigin) => new Promise((resolve, reject) => {
const image = new Image;
"string" === crossOrigin && (image.crossOrigin = crossOrigin), image.onload = () => {
resolve({
width: image.width,
height: image.height
});
}, image.onerror = image.onabort = reject, "string" == typeof src ? image.src = src : browserImageTools.toDataURL(src).then(url => image.src = url).catch(reject);
})
};
function parseColor(cstr) {
let m, parts = [], alpha = 1;
if ("#" === (cstr = cstr.toLowerCase())[0]) {
let base = cstr.slice(1), size = base.length;
size <= 4 ? (parts = [ parseInt(base[0] + base[0], 16), parseInt(base[1] + base[1], 16), parseInt(base[2] + base[2], 16) ],
4 === size && (alpha = parseInt(base[3] + base[3], 16) / 255)) : (parts = [ parseInt(base[0] + base[1], 16), parseInt(base[2] + base[3], 16), parseInt(base[4] + base[5], 16) ],
8 === size && (alpha = parseInt(base[6] + base[7], 16) / 255)), parts[0] || (parts[0] = 0),
parts[1] || (parts[1] = 0), parts[2] || (parts[2] = 0);
} else {
if (!(m = /^((?:rgba?))\s*\(([^)]*)\)/.exec(cstr))) return {
value: cstr,
alpha
};
{
let dims = 3;
parts = m[2].trim().split(/\s*[,/]\s*|\s+/), parts = parts.map((x, i) => {
if ("%" === x[x.length - 1]) {
let v = parseFloat(x) / 100;
return 3 === i ? v : 255 * v;
}
return "none" === x ? 0 : parseFloat(x);
}), alpha = parts.length > dims ? parts.pop() : 1;
}
}
return {
value: "#" + parts.map(v => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join(""),
alpha: Math.max(0, Math.min(1, alpha))
};
}
function getRng(matrix, i, j, match = !0) {
let seed;
return () => {
if (null == seed) {
seed = 0;
let ix = 0;
for (let xOffset = -3; xOffset < 4; xOffset++) for (let yOffset = -3; yOffset < 4; yOffset++) ix++,
seed |= Number(matrix[(i + xOffset + matrix.length << yOffset) % matrix.length]?.[(j + yOffset + matrix.length << xOffset) % matrix.length] === match) << ix;
}
let t = seed += 1831565813;
return t = Math.imul(t ^ t >>> 15, 1 | t), t ^= t + Math.imul(t ^ t >>> 7, 61 | t),
((t ^ t >>> 14) >>> 0) / 4294967296;
};
}
let squareMask = [ [ 1, 1, 1, 1, 1, 1, 1 ], [ 1, 0, 0, 0, 0, 0, 1 ], [ 1, 0, 0, 0, 0, 0, 1 ], [ 1, 0, 0, 0, 0, 0, 1 ], [ 1, 0, 0, 0, 0, 0, 1 ], [ 1, 0, 0, 0, 0, 0, 1 ], [ 1, 1, 1, 1, 1, 1, 1 ] ], cornerSquareTypes = new Set(Object.values(CornerSquareType));
let dotMask = [ [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 1, 1, 0, 0 ], [ 0, 0, 1, 1, 1, 0, 0 ], [ 0, 0, 1, 1, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ] ], cornerDotTypes = new Set(Object.values(CornerDotType));
class QRSVG {
options;
_element;
_fakeMatrix;
get element() {
return this._element;
}
defs;
backgroundMask;
backgroundMaskGroup;
dotsMask;
dotsMaskGroup;
lightDotsMask;
lightDotsMaskGroup;
qr;
document;
imageTools;
constructor(options) {
this.options = options, this.document = options.document, this._element = this.document.createElementNS("http://www.w3.org/2000/svg", "svg");
let width = numToAttr(options.width), height = numToAttr(options.height);
this._element.setAttribute("width", width), this._element.setAttribute("height", height),
this._element.setAttribute("viewBox", `0 0 ${width} ${height}`), this.defs = this.document.createElementNS("http://www.w3.org/2000/svg", "defs"),
this._element.appendChild(this.defs), this.imageTools = options.imageTools || browserImageTools;
}
get width() {
return this.options.width;
}
get height() {
return this.options.height;
}
async drawQR(qr) {
let count = qr.getModuleCount(), typeNumber = parseInt(((count - 17) / 4).toFixed(0), 10), dotSize = this.options.dotsOptions.size, drawImageSize = {
hideXDots: 0,
hideYDots: 0,
width: 0,
height: 0
};
if (this.qr = qr, this.options.image) {
let size = await this.imageTools.getSize(this.options.image, this.options.imageOptions.crossOrigin), {imageOptions, errorCorrectionPercent} = this.options;
if (imageOptions.mode == ImageMode.background) {
let margin = this.options.backgroundOptions && this.options.backgroundOptions.margin || 0, maxWidth = (this.options.width - 2 * margin * dotSize) * imageOptions.imageSize, maxHeight = (this.options.height - 2 * margin * dotSize) * imageOptions.imageSize, {width, height} = size;
height = height / width * maxWidth, width = maxWidth, height > maxHeight && (width = width / height * maxHeight,
height = maxHeight), drawImageSize = {
hideXDots: 0,
hideYDots: 0,
width,
height
};
} else {
let coverLevel = imageOptions.imageSize * errorCorrectionPercent, alignment = QRUtil.getPatternPosition(typeNumber), maxHiddenDots = Math.floor(coverLevel * (count * count - 192 - 2 * (count - 16) - alignment.length ** 2 * 25));
drawImageSize = function({originalHeight, originalWidth, maxHiddenDots, maxHiddenAxisDots, dotSize, margin}) {
let hideDots = {
x: 0,
y: 0
}, imageSize = {
x: 0,
y: 0
};
if (originalHeight <= 0 || originalWidth <= 0 || maxHiddenDots <= 0 || dotSize <= 0 || 4 * margin ** 2 > maxHiddenDots) return {
height: 0,
width: 0,
hideYDots: 0,
hideXDots: 0
};
maxHiddenAxisDots && maxHiddenAxisDots % 2 == 0 && (maxHiddenAxisDots = Math.max(1, maxHiddenAxisDots - 1));
let dimMax = Math.max(originalWidth, originalHeight), dimMin = Math.min(originalWidth, originalHeight), lower = 0, upper = (maxHiddenAxisDots || maxHiddenDots) - 2 * margin;
do {
let newSize = lower + (upper - lower) / 2, dotsMax = Math.max(1, Math.ceil(newSize + 2 * margin));
dotsMax % 2 == 0 && dotsMax++;
let dotsMin = Math.max(1, Math.ceil(newSize * dimMin / dimMax + 2 * margin));
dotsMin % 2 == 0 && dotsMin++, dotsMax * dotsMin > maxHiddenDots ? upper = newSize : lower = newSize;
} while (Math.abs(lower - upper) > .001);
let size = lower, hideMax = Math.max(1, Math.ceil(size + 2 * margin));
hideMax % 2 == 0 && hideMax++;
let hideMin = Math.max(1, Math.ceil(size * dimMin / dimMax + 2 * margin));
hideMin % 2 == 0 && hideMin++, originalWidth > originalHeight ? (hideDots.x = hideMax,
hideDots.y = hideMin) : (hideDots.x = hideMin, hideDots.y = hideMax);
let maxW = (hideDots.x - 2 * margin) * dotSize, maxH = (hideDots.y - 2 * margin) * dotSize;
return imageSize.x = maxW, imageSize.y = maxW * originalHeight / originalWidth,
imageSize.y > maxH && (imageSize.y = maxH, imageSize.x = maxH * originalWidth / originalHeight),
{
height: Math.round(imageSize.y + 2 * margin * dotSize),
width: Math.round(imageSize.x + 2 * margin * dotSize),
hideYDots: hideDots.y,
hideXDots: hideDots.x
};
}({
originalWidth: size.width,
originalHeight: size.height,
maxHiddenDots,
maxHiddenAxisDots: count - 14,
dotSize,
margin: imageOptions.margin
});
}
}
this.drawBackground(), this.options.imageOptions.mode != ImageMode.overlay && this.options.image && drawImageSize.width > 0 && drawImageSize.height > 0 && await this.drawImage({
width: drawImageSize.width,
height: drawImageSize.height,
count,
dotSize
}), this.drawDots((i, j) => !(this.options.imageOptions.mode == ImageMode.center && i >= (count - drawImageSize.hideXDots) / 2 && i < (count + drawImageSize.hideXDots) / 2 && j >= (count - drawImageSize.hideYDots) / 2 && j < (count + drawImageSize.hideYDots) / 2) && !(i < 8 && j < 8 || i >= count - 8 && j < 8 || j >= count - 8 && i < 8)),
this.options.imageOptions.mode == ImageMode.overlay && this.options.image && drawImageSize.width > 0 && drawImageSize.height > 0 && await this.drawImage({
width: drawImageSize.width,
height: drawImageSize.height,
count,
dotSize
}), this.drawCorners();
}
drawBackground() {
let options = this.options;
if (this._element && options.backgroundOptions) {
let gradientOptions = options.backgroundOptions.gradient, color = options.backgroundOptions.color;
this.createColor({
options: gradientOptions,
color,
additionalRotation: 0,
x: 0,
y: 0,
height: options.height,
width: options.width,
name: "background-color"
});
let size = Math.min(options.width, options.height), element = this.document.createElementNS("http://www.w3.org/2000/svg", "rect");
[this.backgroundMask, this.backgroundMaskGroup] = this.createMask("mask-background-color"),
this.defs.appendChild(this.backgroundMask), element.setAttribute("x", numToAttr((options.width - size) / 2)),
element.setAttribute("y", numToAttr((options.height - size) / 2)), element.setAttribute("width", numToAttr(size)),
element.setAttribute("height", numToAttr(size)), element.setAttribute("rx", numToAttr(size / 2 * (options.backgroundOptions.round || 0))),
this.backgroundMaskGroup.appendChild(element);
}
}
drawDots(filter) {
if (!this.qr) throw new Error("QR code is not defined");
let options = this.options, count = this.qr.getModuleCount();
if (count > options.width || count > options.height) throw new Error("The canvas is too small");
let dotSize = this.options.dotsOptions.size, minSize = Math.min(options.width, options.height);
options.imageOptions.mode == ImageMode.background && (minSize -= 2 * dotSize * (options.imageOptions.margin || 0));
let xBeginning = Math.floor((options.width - count * dotSize) / 2), yBeginning = Math.floor((options.height - count * dotSize) / 2), draw = getQrDotFigure(options.dotsOptions.type, options.plugins);
[this.dotsMask, this.dotsMaskGroup] = this.createMask("mask-dot-color"), this.defs.appendChild(this.dotsMask),
options.imageOptions.mode == ImageMode.background && ([this.lightDotsMask, this.lightDotsMaskGroup] = this.createMask("mask-light-dot-color"),
this.defs.appendChild(this.lightDotsMask));
let margin = 0, additionalDots = 0, fakeCount = count;
options.shape === ShapeType.circle ? (margin = this.options.backgroundOptions && this.options.backgroundOptions.margin || 0,
additionalDots = Math.floor((minSize / dotSize - count - 2 * margin) / 2), fakeCount = count + 2 * additionalDots) : options.imageOptions.mode == ImageMode.background && (additionalDots = 1,
fakeCount = count + 2 * additionalDots);
let xFakeBeginning = xBeginning - additionalDots * dotSize, yFakeBeginning = yBeginning - additionalDots * dotSize, colorX = xFakeBeginning, colorY = yFakeBeginning, colorCount = count + 2 * additionalDots;
this._fakeMatrix = new Array(fakeCount);
let center = Math.floor(fakeCount / 2);
for (let i = 0; i < fakeCount; i++) {
this._fakeMatrix[i] = new Array(fakeCount);
for (let j = 0; j < fakeCount; j++) {
if (i > additionalDots - 1 && i < fakeCount - additionalDots && j > additionalDots - 1 && j < fakeCount - additionalDots) {
let ii = i - additionalDots, jj = j - additionalDots;
filter && !filter(ii, jj) ? this._fakeMatrix[i][j] = void 0 : this._fakeMatrix[i][j] = !!this.qr.isDark(jj, ii);
continue;
}
options.shape === ShapeType.circle && Math.sqrt((i - center) * (i - center) + (j - center) * (j - center)) > center ? this._fakeMatrix[i][j] = void 0 : this._fakeMatrix[i][j] = i != additionalDots - 1 && i != fakeCount - additionalDots && j != additionalDots - 1 && j != fakeCount - additionalDots ? 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) : (j == additionalDots - 1 && (i < additionalDots + 8 || i > fakeCount - additionalDots - 9) || j == fakeCount - additionalDots && i < additionalDots + 8 || i == additionalDots - 1 && (j < additionalDots + 8 || j > fakeCount - additionalDots - 9) || i == fakeCount - additionalDots && j < additionalDots + 8) && void 0;
}
}
let typeNr = (count - 17) / 4, alignment = QRUtil.getPatternPosition(typeNr);
for (let i = 0; i < fakeCount; i++) {
let iAlign = alignment.find(v => i - additionalDots > v - 3 && i - additionalDots < v + 3);
for (let j = 0; j < fakeCount; j++) {
let jAlign = alignment.find(v => j - additionalDots > v - 3 && j - additionalDots < v + 3);
null != this._fakeMatrix[i][j] && (this.lightDotsMask && (draw = iAlign && jAlign && (iAlign != alignment[0] && jAlign != alignment[0] || jAlign != alignment[0] && jAlign != alignment[alignment.length - 1] || iAlign != alignment[0] && iAlign != alignment[alignment.length - 1]) ? getQrDotFigure(DotType.square) : getQrDotFigure(DotType.tinySquare)),
this._fakeMatrix[i][j] ? this.dotsMaskGroup && this.dotsMaskGroup.appendChild(draw({
x: xFakeBeginning + i * dotSize,
y: yFakeBeginning + j * dotSize,
size: dotSize,
document: this.options.document,
getNeighbor: (xOffset, yOffset) => !0 === this._fakeMatrix[i + xOffset]?.[j + yOffset],
getPRandom: getRng(this._fakeMatrix, i, j)
})) : this.lightDotsMask && this.lightDotsMaskGroup && this.lightDotsMaskGroup.appendChild(draw({
x: xFakeBeginning + i * dotSize,
y: yFakeBeginning + j * dotSize,
size: dotSize,
document: this.options.document,
getNeighbor: (xOffset, yOffset) => !1 === this._fakeMatrix[i + xOffset]?.[j + yOffset],
getPRandom: getRng(this._fakeMatrix, i, j, !1)
})));
}
}
this.lightDotsMask && this.createColor({
options: options.imageOptions.fill.gradient,
color: options.imageOptions.fill.color,
additionalRotation: 0,
x: colorX,
y: colorY,
height: colorCount * dotSize,
width: colorCount * dotSize,
name: "light-dot-color"
}), this.createColor({
options: options.dotsOptions?.gradient,
color: options.dotsOptions.color,
additionalRotation: 0,
x: colorX,
y: colorY,
height: colorCount * dotSize,
width: colorCount * dotSize,
name: "dot-color"
});
}
drawCorners() {
if (!this.qr) throw new Error("QR code is not defined");
let element = this._element, options = this.options;
if (!element) throw new Error("Element code is not defined");
let count = this.qr.getModuleCount(), dotSize = this.options.dotsOptions.size, cornersSquareSize = 7 * dotSize, cornersDotSize = 3 * dotSize, xBeginning = Math.floor((options.width - count * dotSize) / 2), yBeginning = Math.floor((options.height - count * dotSize) / 2);
[ [ 0, 0, 0 ], [ 1, 0, Math.PI / 2 ], [ 0, 1, -Math.PI / 2 ] ].forEach(([column, row, rotation]) => {
let x = xBeginning + column * dotSize * (count - 7), y = yBeginning + row * dotSize * (count - 7), cornersSquareMask = this.dotsMask, cornersSquareMaskGroup = this.dotsMaskGroup, cornersDotMask = this.dotsMask, cornersDotMaskGroup = this.dotsMaskGroup;
(options.cornersSquareOptions?.gradient || options.cornersSquareOptions?.color) && ([cornersSquareMask, cornersSquareMaskGroup] = this.createMask(`mask-corners-square-color-${column}-${row}`),
this.defs.appendChild(cornersSquareMask), cornersDotMask = cornersSquareMask, cornersDotMaskGroup = cornersSquareMaskGroup,
this.createColor({
options: options.cornersSquareOptions?.gradient,
color: options.cornersSquareOptions?.color,
additionalRotation: rotation,
x,
y,
height: cornersSquareSize,
width: cornersSquareSize,
name: `corners-square-color-${column}-${row}`
}));
let squareArgs = {
x,
y,
size: cornersSquareSize,
document: this.options.document,
rotation
}, pluinCornerSquare = options.plugins?.length ? (plugins = options.plugins, args => {
for (let plugin of plugins) {
let el = plugin.drawCornerSquare?.(args);
if (el) return el;
}
})(squareArgs) : void 0;
var plugins, type, val;
if (pluinCornerSquare) {
let [cornerElement, cornerFill] = pluinCornerSquare;