UNPKG

@liquid-js/qr-code-styling

Version:

Generate styled QR codes on web or in Node

912 lines (881 loc) 67 kB
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;