@liquid-js/qr-code-styling 5.1.0 → 5.3.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 +12 -1
- package/lib/border-plugin.js.map +1 -1
- package/lib/core/qr-svg.d.ts +0 -3
- package/lib/figures/dot-elements.d.ts +1 -0
- package/lib/font-faces-plugin.js +2 -0
- package/lib/font-faces-plugin.js.map +1 -0
- package/lib/plugins/border.d.ts +5 -1
- package/lib/plugins/font-faces.d.ts +19 -0
- package/lib/qr-code-styling-node.js +63 -40
- 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/tools/resize.d.ts +41 -0
- package/lib/utils/options.d.ts +5 -4
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -84,6 +84,7 @@ While the old API only supports a single extension, it is now possible to apply
|
|
|
84
84
|
|
|
85
85
|
```ts
|
|
86
86
|
import BorderPlugin from '@liquid-js/qr-code-styling/border-plugin'
|
|
87
|
+
import FontFacesPlugin from '@liquid-js/qr-code-styling/font-faces-plugin'
|
|
87
88
|
|
|
88
89
|
const qrCode = new QRCodeStyling({
|
|
89
90
|
plugins: [
|
|
@@ -107,7 +108,17 @@ const qrCode = new QRCodeStyling({
|
|
|
107
108
|
content: 'QR code'.toUpperCase()
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
|
-
})
|
|
111
|
+
}),
|
|
112
|
+
/**
|
|
113
|
+
* Embed fonts used with BorderPlugin
|
|
114
|
+
*
|
|
115
|
+
* Not needed when using standard or local fonts, but recommended for portability and consistency; use
|
|
116
|
+
* subsetting if possible to reduce the generated file size.
|
|
117
|
+
*/
|
|
118
|
+
new FontFacesPlugin([{
|
|
119
|
+
font: 'sans-serif',
|
|
120
|
+
src: `url(data:font/otf;base64,d09GMgABAA...)`
|
|
121
|
+
}])
|
|
111
122
|
]
|
|
112
123
|
// ...other options
|
|
113
124
|
})
|
package/lib/border-plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"border-plugin.js","sources":["../src/plugins/border.ts"],"sourcesContent":["import { Options, Plugin } from '../utils/options.js'\r\nimport { extendSVG, numToAttr, svgPath } from './utils.js'\r\n\r\nenum TextPosition {\r\n top = 'top',\r\n bottom = 'bottom',\r\n left = 'left',\r\n right = 'right'\r\n}\r\n\r\nexport interface TextConfig {\r\n font?: string\r\n color?: string\r\n size?: number\r\n fontWeight?: 'normal' | 'bold' | number\r\n fontStyle?: 'normal' | 'italic' | 'oblique'\r\n}\r\n\r\nexport interface BorderPluginOptions {\r\n /** Border roundnes, from 0 (square) to 1 (circle) */\r\n round?: number\r\n size: number\r\n color: string\r\n dasharray?: string\r\n margin?: number\r\n /**\r\n * If true, all dimensions are proportional to the code size,\r\n * i.e. `size: 0.1` means the border thickness is 1/10 of the QR code size\r\n *\r\n * This is useful to keep the border visually consistent regardless of the amount of data\r\n *\r\n * Note: if using dasharray, use percentage values to maintain consistency\r\n */\r\n proportional?: boolean\r\n text?: TextConfig & {\r\n [key in TextPosition]?: TextConfig & {\r\n content: string\r\n }\r\n }\r\n /** A string of embedded CSS @font-face rules */\r\n fontFaces?: string\r\n}\r\n\r\nexport default class BorderPlugin implements Plugin {\r\n\r\n constructor(\r\n private readonly pluginOptions: BorderPluginOptions,\r\n /** @ignore Create unique id for SVG elements to prevent naming collisions; specify your own if neccesary e.g. for testing */\r\n private readonly idSuffix = Math.random().toFixed(10).substring(2)\r\n ) { }\r\n\r\n postProcess(svg: SVGSVGElement, options: Options) {\r\n const { document } = options\r\n const sizeFactor = this.pluginOptions.proportional ? options.size : 1\r\n\r\n const margin = (this.pluginOptions.margin || 0) * sizeFactor\r\n let thickness = (this.pluginOptions.size) * sizeFactor\r\n const drawArea = extendSVG(svg, thickness + margin)\r\n if (!drawArea)\r\n return\r\n\r\n thickness = Math.abs(thickness)\r\n\r\n const cx = (drawArea.left + drawArea.right) / 2\r\n const cy = (drawArea.top + drawArea.bottom) / 2\r\n const lineSize = options.size / 2 * (1 - (this.pluginOptions.round || 0))\r\n const r = (Math.min(drawArea.right - drawArea.left - 2 * thickness, drawArea.bottom - drawArea.top - 2 * thickness) / 2) - lineSize + thickness / 2\r\n\r\n let pathR = this.pluginOptions.round ? r : 0\r\n let pathL = this.pluginOptions.round ? lineSize : lineSize + r\r\n\r\n const borderEl = document.createElementNS('http://www.w3.org/2000/svg', 'rect')\r\n borderEl.setAttribute('width', numToAttr((pathL + pathR) * 2))\r\n borderEl.setAttribute('height', numToAttr((pathL + pathR) * 2))\r\n borderEl.setAttribute('x', numToAttr(cx - pathL - pathR))\r\n borderEl.setAttribute('y', numToAttr(cy - pathL - pathR))\r\n borderEl.setAttribute('rx', numToAttr(pathR))\r\n borderEl.setAttribute('fill', 'none')\r\n borderEl.setAttribute('stroke', this.pluginOptions.color)\r\n borderEl.setAttribute('stroke-width', numToAttr(thickness))\r\n if (this.pluginOptions.dasharray) {\r\n borderEl.setAttribute('stroke-dasharray', this.pluginOptions.dasharray)\r\n }\r\n\r\n svg.appendChild(borderEl);\r\n\r\n [TextPosition.left, TextPosition.top, TextPosition.right, TextPosition.bottom].forEach(postion => {\r\n const textCfg = this.pluginOptions.text\r\n const config = textCfg?.[postion]\r\n if (config) {\r\n let defs = Array.from(svg.childNodes).find(v => (v as HTMLElement).tagName.toUpperCase() == 'DEFS')\r\n if (!defs) {\r\n defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')\r\n svg.appendChild(defs)\r\n }\r\n const element = document.createElementNS('http://www.w3.org/2000/svg', 'path')\r\n const size = (config.size || textCfg.size || 1) * sizeFactor\r\n pathR = this.pluginOptions.round ? r - size / 3 : 0\r\n pathL = this.pluginOptions.round ? lineSize : lineSize + (r - size / 3)\r\n switch (postion) {\r\n case TextPosition.top:\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx} ${cy + pathR + pathL}\r\n h ${-pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${-pathR}\r\n v ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${-pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${pathR}\r\n v ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${pathR}\r\n h ${-pathL}`\r\n )\r\n break\r\n case TextPosition.bottom:\r\n if (this.pluginOptions.round)\r\n pathR += size * 2 / 3\r\n else\r\n pathL += size * 2 / 3\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx} ${cy - pathR - pathL}\r\n h ${-pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${-pathR} ${pathR}\r\n v ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${pathR} ${pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${pathR} ${-pathR}\r\n v ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${-pathR} ${-pathR}\r\n h ${-pathL}`\r\n )\r\n break\r\n case TextPosition.left:\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx + pathR + pathL} ${cy}\r\n v ${pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${pathR}\r\n h ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${-pathR}\r\n v ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${-pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${pathR}\r\n v ${pathL}`\r\n )\r\n break\r\n case TextPosition.right:\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx - pathR - pathL} ${cy}\r\n v ${-pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${-pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${pathR}\r\n v ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${pathR}\r\n h ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${-pathR}\r\n v ${-pathL}`\r\n )\r\n break\r\n }\r\n const id = `border-text-${postion}-${this.idSuffix}`\r\n element.setAttribute('id', id)\r\n element.setAttribute('fill', 'none')\r\n\r\n const span = document.createElementNS('http://www.w3.org/2000/svg', 'tspan')\r\n span.setAttribute('font-family', config.font || textCfg.font || 'sans-serif')\r\n span.setAttribute('fill', config.color || textCfg.color || '#000')\r\n span.setAttribute('font-weight', numToAttr(config.fontWeight || textCfg.fontWeight || 'normal'))\r\n span.setAttribute('font-style', config.fontStyle || textCfg.fontStyle || 'normal')\r\n span.setAttribute('font-size', numToAttr(size))\r\n span.textContent = config.content\r\n\r\n const textPath = document.createElementNS('http://www.w3.org/2000/svg', 'textPath')\r\n textPath.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#' + id)\r\n textPath.setAttribute('startOffset', '50%')\r\n textPath.setAttribute('text-anchor', 'middle')\r\n textPath.appendChild(span)\r\n\r\n const text = document.createElementNS('http://www.w3.org/2000/svg', 'text')\r\n text.appendChild(textPath)\r\n\r\n defs.appendChild(element)\r\n svg.appendChild(text)\r\n }\r\n })\r\n\r\n if (this.pluginOptions.fontFaces) {\r\n let defs = Array.from(svg.childNodes).find(v => (v as HTMLElement).tagName.toUpperCase() == 'DEFS')\r\n if (!defs) {\r\n defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')\r\n svg.appendChild(defs)\r\n }\r\n const style = document.createElementNS('http://www.w3.org/2000/svg', 'style')\r\n style.textContent = this.pluginOptions.fontFaces\r\n defs.appendChild(style)\r\n }\r\n }\r\n}\r\n"],"names":["extendSVG","numToAttr","TextPosition","g","v","top","bottom","left","right","pluginOptions","idSuffix","constructor","Math","random","toFixed","substring","this","postProcess","svg","options","document","sizeFactor","proportional","size","thickness","drawArea","margin","abs","cx","cy","round","min","lineSize","pathR","r","pathL","createElementNS","setAttribute","borderEl","color","dasharray","appendChild","forEach","postion","text","textCfg","config","defs","Array","from","childNodes","find","tagName","toUpperCase","element","svgPath","id","span","font","fontWeight","fontStyle","textContent","content","textPath","setAttributeNS","fontFaces","style"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"border-plugin.js","sources":["../src/plugins/border.ts"],"sourcesContent":["import { Options, Plugin } from '../utils/options.js'\r\nimport { extendSVG, numToAttr, svgPath } from './utils.js'\r\n\r\nenum TextPosition {\r\n top = 'top',\r\n bottom = 'bottom',\r\n left = 'left',\r\n right = 'right'\r\n}\r\n\r\nexport interface TextConfig {\r\n font?: string\r\n color?: string\r\n size?: number\r\n fontWeight?: 'normal' | 'bold' | number\r\n fontStyle?: 'normal' | 'italic' | 'oblique'\r\n}\r\n\r\nexport interface BorderPluginOptions {\r\n /** Border roundnes, from 0 (square) to 1 (circle) */\r\n round?: number\r\n size: number\r\n color: string\r\n dasharray?: string\r\n margin?: number\r\n /**\r\n * If true, all dimensions are proportional to the code size,\r\n * i.e. `size: 0.1` means the border thickness is 1/10 of the QR code size\r\n *\r\n * This is useful to keep the border visually consistent regardless of the amount of data\r\n *\r\n * Note: if using dasharray, use percentage values to maintain consistency\r\n */\r\n proportional?: boolean\r\n text?: TextConfig & {\r\n [key in TextPosition]?: TextConfig & {\r\n content: string\r\n }\r\n }\r\n /**\r\n * A string of embedded CSS @font-face rules\r\n *\r\n * @deprecated Use @liquid-js/qr-code-styling/font-faces-plugin\r\n */\r\n fontFaces?: string\r\n}\r\n\r\nexport default class BorderPlugin implements Plugin {\r\n\r\n constructor(\r\n private readonly pluginOptions: BorderPluginOptions,\r\n /** @ignore Create unique id for SVG elements to prevent naming collisions; specify your own if neccesary e.g. for testing */\r\n private readonly idSuffix = Math.random().toFixed(10).substring(2)\r\n ) { }\r\n\r\n postProcess(svg: SVGSVGElement, options: Options) {\r\n const { document } = options\r\n const sizeFactor = this.pluginOptions.proportional ? options.size : 1\r\n\r\n const margin = (this.pluginOptions.margin || 0) * sizeFactor\r\n let thickness = (this.pluginOptions.size) * sizeFactor\r\n const drawArea = extendSVG(svg, thickness + margin)\r\n if (!drawArea)\r\n return\r\n\r\n thickness = Math.abs(thickness)\r\n\r\n const cx = (drawArea.left + drawArea.right) / 2\r\n const cy = (drawArea.top + drawArea.bottom) / 2\r\n const lineSize = options.size / 2 * (1 - (this.pluginOptions.round || 0))\r\n const r = (Math.min(drawArea.right - drawArea.left - 2 * thickness, drawArea.bottom - drawArea.top - 2 * thickness) / 2) - lineSize + thickness / 2\r\n\r\n let pathR = this.pluginOptions.round ? r : 0\r\n let pathL = this.pluginOptions.round ? lineSize : lineSize + r\r\n\r\n const borderEl = document.createElementNS('http://www.w3.org/2000/svg', 'rect')\r\n borderEl.setAttribute('width', numToAttr((pathL + pathR) * 2))\r\n borderEl.setAttribute('height', numToAttr((pathL + pathR) * 2))\r\n borderEl.setAttribute('x', numToAttr(cx - pathL - pathR))\r\n borderEl.setAttribute('y', numToAttr(cy - pathL - pathR))\r\n borderEl.setAttribute('rx', numToAttr(pathR))\r\n borderEl.setAttribute('fill', 'none')\r\n borderEl.setAttribute('stroke', this.pluginOptions.color)\r\n borderEl.setAttribute('stroke-width', numToAttr(thickness))\r\n if (this.pluginOptions.dasharray) {\r\n borderEl.setAttribute('stroke-dasharray', this.pluginOptions.dasharray)\r\n }\r\n\r\n svg.appendChild(borderEl);\r\n\r\n [TextPosition.left, TextPosition.top, TextPosition.right, TextPosition.bottom].forEach(postion => {\r\n const textCfg = this.pluginOptions.text\r\n const config = textCfg?.[postion]\r\n if (config) {\r\n let defs = Array.from(svg.childNodes).find(v => (v as HTMLElement).tagName.toUpperCase() == 'DEFS')\r\n if (!defs) {\r\n defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')\r\n svg.appendChild(defs)\r\n }\r\n const element = document.createElementNS('http://www.w3.org/2000/svg', 'path')\r\n const size = (config.size || textCfg.size || 1) * sizeFactor\r\n pathR = this.pluginOptions.round ? r - size / 3 : 0\r\n pathL = this.pluginOptions.round ? lineSize : lineSize + (r - size / 3)\r\n switch (postion) {\r\n case TextPosition.top:\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx} ${cy + pathR + pathL}\r\n h ${-pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${-pathR}\r\n v ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${-pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${pathR}\r\n v ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${pathR}\r\n h ${-pathL}`\r\n )\r\n break\r\n case TextPosition.bottom:\r\n if (this.pluginOptions.round)\r\n pathR += size * 2 / 3\r\n else\r\n pathL += size * 2 / 3\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx} ${cy - pathR - pathL}\r\n h ${-pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${-pathR} ${pathR}\r\n v ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${pathR} ${pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${pathR} ${-pathR}\r\n v ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 0 ${-pathR} ${-pathR}\r\n h ${-pathL}`\r\n )\r\n break\r\n case TextPosition.left:\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx + pathR + pathL} ${cy}\r\n v ${pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${pathR}\r\n h ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${-pathR}\r\n v ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${-pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${pathR}\r\n v ${pathL}`\r\n )\r\n break\r\n case TextPosition.right:\r\n element.setAttribute(\r\n 'd',\r\n svgPath`M ${cx - pathR - pathL} ${cy}\r\n v ${-pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${-pathR}\r\n h ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${pathR} ${pathR}\r\n v ${2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${pathR}\r\n h ${-2 * pathL}\r\n a ${pathR} ${pathR} 0 0 1 ${-pathR} ${-pathR}\r\n v ${-pathL}`\r\n )\r\n break\r\n }\r\n const id = `border-text-${postion}-${this.idSuffix}`\r\n element.setAttribute('id', id)\r\n element.setAttribute('fill', 'none')\r\n\r\n const span = document.createElementNS('http://www.w3.org/2000/svg', 'tspan')\r\n span.setAttribute('font-family', config.font || textCfg.font || 'sans-serif')\r\n span.setAttribute('fill', config.color || textCfg.color || '#000')\r\n span.setAttribute('font-weight', numToAttr(config.fontWeight || textCfg.fontWeight || 'normal'))\r\n span.setAttribute('font-style', config.fontStyle || textCfg.fontStyle || 'normal')\r\n span.setAttribute('font-size', numToAttr(size))\r\n span.textContent = config.content\r\n\r\n const textPath = document.createElementNS('http://www.w3.org/2000/svg', 'textPath')\r\n textPath.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#' + id)\r\n textPath.setAttribute('startOffset', '50%')\r\n textPath.setAttribute('text-anchor', 'middle')\r\n textPath.appendChild(span)\r\n\r\n const text = document.createElementNS('http://www.w3.org/2000/svg', 'text')\r\n text.appendChild(textPath)\r\n\r\n defs.appendChild(element)\r\n svg.appendChild(text)\r\n }\r\n })\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n if (this.pluginOptions.fontFaces) {\r\n let defs = Array.from(svg.childNodes).find(v => (v as HTMLElement).tagName.toUpperCase() == 'DEFS')\r\n if (!defs) {\r\n defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')\r\n svg.appendChild(defs)\r\n }\r\n const style = document.createElementNS('http://www.w3.org/2000/svg', 'style')\r\n // eslint-disable-next-line @typescript-eslint/no-deprecated\r\n style.textContent = this.pluginOptions.fontFaces\r\n defs.appendChild(style)\r\n }\r\n }\r\n}\r\n"],"names":["extendSVG","numToAttr","TextPosition","g","v","top","bottom","left","right","pluginOptions","idSuffix","constructor","Math","random","toFixed","substring","this","postProcess","svg","options","document","sizeFactor","proportional","size","thickness","drawArea","margin","abs","cx","cy","round","min","lineSize","pathR","r","pathL","createElementNS","setAttribute","borderEl","color","dasharray","appendChild","forEach","postion","text","textCfg","config","defs","Array","from","childNodes","find","tagName","toUpperCase","element","svgPath","id","span","font","fontWeight","fontStyle","textContent","content","textPath","setAttributeNS","fontFaces","style"],"mappings":"oBAGKA,eACDC,aACAC,MAAA,oBAEAA,IAAAC,EAAAC,EAAAD,IAAA,CAAA,EAwCUC,EAAAC,IAAA,MAAAD,EAAAE,OAAA,SAAAF,EAAAG,KAAA,OAAAH,EAAAI,MAAA,6BAGWC,cAEAC,SAHrBC,WAAAA,CACqBF,EAEAC,EAAWE,KAAKC,SAASC,QAAQ,IAAIC,UAAU,IAF/CC,KAAAP,cAAAA,EAEAO,KAAAN,SAAAA,CAAiD,CAGtEO,WAAAA,CAAYC,EAAoBC,GAC5B,IAAMC,SAAAA,KACNC,EAAgBL,KAAGP,cAAKa,aAA0BH,EAAGI,WAGjDC,EAAaR,KAAKP,cAAcc,KAAQF,EAC5C,IAAAI,EAAczB,EAAGkB,EAAaM,GAFlBR,KAAIP,cAAKiB,QAAoB,GAAKL,GAG9C,GAAKI,EAAL,CAGAD,EAAYZ,KAAKe,IAAIH,GAErB,IAAAI,GAAQH,EAAIlB,KAAakB,EAAGjB,OAAc,EAC1CqB,GAAQJ,EAAIpB,IAAYoB,EAAGnB,QAAe,IAC5Ba,UAAmB,GAAKH,KAAIP,cAAKqB,OAAmB,MAC3DlB,KAAImB,IAAKN,EAAIjB,MAAciB,EAAGlB,KAAa,EAAIiB,EAAYC,EAAEnB,OAAemB,QAAmBD,KAAiBQ,EAAYR,IAE/HS,EAAQjB,KAAKP,cAAcqB,MAAQI,EAAI,EACvCC,EAAQnB,KAAKP,cAAcqB,MAAQE,EAAWA,EAAWE,KAE/Cd,EAAGgB,6CAAqD,SAC7DC,aAAa,QAASpC,EAA4B,GAAjBkC,EAAQF,KAClDK,EAASD,aAAa,SAAUpC,EAA4B,GAAjBkC,EAAQF,KACnDK,EAASD,aAAa,IAAKpC,EAAU2B,EAAKO,EAAQF,IAClDK,EAASD,aAAa,IAAKpC,EAAU4B,EAAKM,EAAQF,IAClDK,EAASD,aAAa,KAAMpC,EAAUgC,IACtCK,EAASD,aAAa,OAAQ,QAC9BC,EAASD,aAAa,SAAUrB,KAAKP,cAAc8B,SAC1CF,aAAa,eAAgBpC,EAAUuB,IAC5CR,KAAKP,cAAc+B,WACnBF,EAASD,aAAa,mBAAoBrB,KAAKP,cAAc+B,WAGjEtB,EAAIuB,YAAYH,GAEhB,CAACpC,EAAaK,KAAML,EAAaG,IAAKH,EAAaM,MAAON,EAAaI,QAAQoC,QAAQC,IACnF,MAAa3B,mBAAQ4B,OACTC,IAAUF,MAClBG,EAAQ,CACR,IAAIC,EAAOC,MAAMC,KAAK/B,EAAIgC,YAAYC,KAAK/C,GAAiD,QAA3CA,EAAkBgD,QAAQC,eACtEN,IACDA,EAAO3B,EAASgB,gBAAgB,6BAA8B,QAC9DlB,EAAIuB,YAAYM,QAEpBO,EAAalC,EAAGgB,6CAAqD,QACrEb,GAAUuB,QAAeD,EAAItB,MAAY,cACjCP,KAAKP,cAAcqB,MAAQI,EAAIX,EAAO,EAAI,IAC1CP,KAAKP,cAAcqB,MAAQE,EAAWA,GAAYE,EAAIX,EAAO,GAC7DoB,GACJ,KAAKzC,EAAaG,IACdiD,EAAQjB,aACJ,IACAkB,CAAA,KAAY3B,KAAMC,EAAKI,EAAQE,QAC5BA,OACDF,KAASA,YAAgBA,MAAUA,QACnC,EAAKE,OACLF,KAASA,WAAeA,MAAUA,OAClC,EAAIE,OACJF,KAASA,WAAeA,KAASA,OACjC,EAAIE,OACJF,KAASA,YAAgBA,KAASA,QACjCE,KAEP,WACCjC,EAAaI,OACVU,KAAKP,cAAcqB,MACnBG,GAAgB,EAAPV,EAAW,EAEpBY,GAAgB,EAAPZ,EAAW,EACxB+B,EAAQjB,aACJ,IACAkB,CAAA,KAAY3B,KAAMC,EAAKI,EAAQE,QAC5BA,OACDF,KAASA,YAAgBA,KAASA,OAClC,EAAIE,OACJF,KAASA,WAAeA,KAASA,OACjC,EAAIE,OACJF,KAASA,WAAeA,MAAUA,QAClC,EAAKE,OACLF,KAASA,YAAgBA,MAAUA,QAClCE,KAEP,WACCjC,EAAaK,KACd+C,EAAQjB,aACJ,IACAkB,CAAA,KAAY3B,EAAKK,EAAQE,KAASN,OAChCM,OACAF,KAASA,YAAgBA,KAASA,QAClC,EAAKE,OACLF,KAASA,YAAgBA,MAAUA,QACnC,EAAKE,OACLF,KAASA,WAAeA,MAAUA,OAClC,EAAIE,OACJF,KAASA,WAAeA,KAASA,OACjCE,KAEN,MACJ,KAAKjC,EAAaM,MACd8C,EAAQjB,aACJ,IACAkB,CAAA,KAAY3B,EAAKK,EAAQE,KAASN,QAC/BM,OACDF,KAASA,WAAeA,MAAUA,OAClC,EAAIE,OACJF,KAASA,WAAeA,KAASA,OACjC,EAAIE,OACJF,KAASA,YAAgBA,KAASA,QAClC,EAAKE,OACLF,KAASA,YAAgBA,MAAUA,QAClCE,KAIfqB,EAAQ,eAAGb,UAA0BjC,aAC7B2B,aAAa,KAAMmB,GAC3BF,EAAQjB,aAAa,OAAQ,QAE7B,IAAAoB,EAAUrC,EAAGgB,6CAAqD,SAClEqB,EAAKpB,aAAa,cAAeS,EAAOY,MAAQb,EAAQa,MAAQ,cAChED,EAAKpB,aAAa,OAAQS,EAAOP,OAASM,EAAQN,OAAS,UACtDF,aAAa,cAAepC,EAAU6C,EAAOa,YAAcd,EAAQc,YAAc,WACtFF,EAAKpB,aAAa,aAAcS,EAAOc,WAAaf,EAAQe,WAAa,YACpEvB,aAAa,YAAapC,EAAUsB,IACzCkC,EAAKI,YAAcf,EAAOgB,SAE1BC,EAAc3C,EAAGgB,6CAAqD,aAC7D4B,eAAe,+BAAgC,aAAc,IAAMR,GAC5EO,EAAS1B,aAAa,cAAe,OACrC0B,EAAS1B,aAAa,cAAe,UACrC0B,EAAStB,YAAYgB,IAErBb,EAAUxB,EAAGgB,6CAAqD,SAC7DK,YAAYsB,KAEZtB,YAAYa,GACjBpC,EAAIuB,YAAYG,EAlGR,IAuGZ5B,KAAKP,cAAcwD,aACflB,EAAOC,MAAMC,KAAK/B,EAAIgC,YAAYC,KAAK/C,GAAiD,QAA3CA,EAAkBgD,QAAQC,kBAEvEN,EAAO3B,EAASgB,gBAAgB,6BAA8B,QAC9DlB,EAAIuB,YAAYM,KAEpBmB,EAAW9C,EAAGgB,6CAAqD,UAE7DyB,YAAc7C,KAAKP,cAAcwD,UACvClB,EAAKN,YAAYyB,GA/IrB,CAP4C"}
|
package/lib/core/qr-svg.d.ts
CHANGED
|
@@ -7,11 +7,8 @@ export declare class QRSVG {
|
|
|
7
7
|
get element(): SVGSVGElement;
|
|
8
8
|
private defs;
|
|
9
9
|
private backgroundMask?;
|
|
10
|
-
private backgroundMaskGroup?;
|
|
11
10
|
private dotsMask?;
|
|
12
|
-
private dotsMaskGroup?;
|
|
13
11
|
private lightDotsMask?;
|
|
14
|
-
private lightDotsMaskGroup?;
|
|
15
12
|
private qr?;
|
|
16
13
|
private document;
|
|
17
14
|
private imageTools;
|
|
@@ -22,4 +22,5 @@ export declare const DotElements: {
|
|
|
22
22
|
innerRadius?: number | undefined;
|
|
23
23
|
}) => SVGElement;
|
|
24
24
|
weave: (args: BasicFigureDrawArgs) => SVGElement;
|
|
25
|
+
blob: (args: BasicFigureDrawArgs, corners: Record<"tl" | "tr" | "bl" | "br", "round" | "out" | "square">) => SVGElement;
|
|
25
26
|
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export default class{fontFaces;constructor(t){this.fontFaces=t.map(t=>"string"==typeof t?t:`@font-face { font-family: ${JSON.stringify(t.font)}; src: ${t.src}; ${t.fontStyle?`font-style: ${t.fontStyle};`:""} ${t.fontWeight?`font-weight: ${t.fontWeight};`:""} }`).join("\n")}postProcess(t,e){let o=e.document;(e=Array.from(t.childNodes).find(t=>"DEFS"==t.tagName.toUpperCase()))||(e=o.createElementNS("http://www.w3.org/2000/svg","defs"),t.appendChild(e)),(t=o.createElementNS("http://www.w3.org/2000/svg","style")).textContent=this.fontFaces,e.appendChild(t)}}
|
|
2
|
+
//# sourceMappingURL=font-faces-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-faces-plugin.js","sources":["../src/plugins/font-faces.ts"],"sourcesContent":["import { Options, Plugin } from '../utils/options.js'\r\nimport { TextConfig } from './border.js'\r\n\r\nexport interface FontFace extends Pick<TextConfig, 'font' | 'fontWeight' | 'fontStyle'> {\r\n /**\r\n * Base64 encoded font, e.g. `url(data:font/otf;base64,...)`\r\n */\r\n src: string\r\n}\r\n\r\n/**\r\n * Embed font faces into the generated SVG\r\n *\r\n * Use as the last plugin when using BorderPlugin({ text: { ... } })\r\n * or other plugins that insert text.\r\n */\r\nexport default class FontFacesPlugin implements Plugin {\r\n private readonly fontFaces: string\r\n constructor(fontFaces: Array<FontFace | string>) {\r\n this.fontFaces = fontFaces.map(v => {\r\n if (typeof v == 'string')\r\n return v\r\n return `@font-face { font-family: ${JSON.stringify(v.font)}; src: ${v.src}; ${v.fontStyle ? `font-style: ${v.fontStyle};` : ''} ${v.fontWeight ? `font-weight: ${v.fontWeight};` : ''} }`\r\n }).join('\\n')\r\n }\r\n\r\n postProcess(svg: SVGSVGElement, options: Options) {\r\n const document = options.document\r\n let defs = Array.from(svg.childNodes).find(v => (v as HTMLElement).tagName.toUpperCase() == 'DEFS')\r\n if (!defs) {\r\n defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')\r\n svg.appendChild(defs)\r\n }\r\n const style = document.createElementNS('http://www.w3.org/2000/svg', 'style')\r\n style.textContent = this.fontFaces\r\n defs.appendChild(style)\r\n }\r\n}\r\n"],"names":["fontFaces","constructor","this","map","v","JSON","stringify","font","src","fontStyle","fontWeight","join","postProcess","svg","options","document","defs","Array","from","childNodes","find","tagName","toUpperCase","createElementNS","appendChild","style","textContent"],"mappings":"eAgBc,MACOA,UACjBC,WAAAA,CAAYD,GACRE,KAAKF,UAAYA,EAAUG,IAAIC,GACX,iBAALA,EACAA,EACJ,6BAA6BC,KAAKC,UAAUF,EAAEG,eAAeH,EAAEI,QAAQJ,EAAEK,UAAY,eAAeL,EAAEK,aAAe,MAAML,EAAEM,WAAa,gBAAgBN,EAAEM,cAAgB,QACpLC,KAAK,KALmC,CAQ/CC,WAAAA,CAAYC,EAAoBC,GAC5B,IAAAC,EAAcD,EAAGC,UACbC,EAAOC,MAAMC,KAAKL,EAAIM,YAAYC,KAAKhB,GAAiD,QAA3CA,EAAkBiB,QAAQC,kBAEvEN,EAAOD,EAASQ,gBAAgB,6BAA8B,QAC9DV,EAAIW,YAAYR,KAEpBS,EAAWV,EAAGQ,6CAAqD,UAC7DG,YAAcxB,KAAKF,UACzBgB,EAAKQ,YAAYC,EAT2B"}
|
package/lib/plugins/border.d.ts
CHANGED
|
@@ -33,7 +33,11 @@ export interface BorderPluginOptions {
|
|
|
33
33
|
content: string;
|
|
34
34
|
};
|
|
35
35
|
};
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* A string of embedded CSS @font-face rules
|
|
38
|
+
*
|
|
39
|
+
* @deprecated Use @liquid-js/qr-code-styling/font-faces-plugin
|
|
40
|
+
*/
|
|
37
41
|
fontFaces?: string;
|
|
38
42
|
}
|
|
39
43
|
export default class BorderPlugin implements Plugin {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Options, Plugin } from '../utils/options.js';
|
|
2
|
+
import { TextConfig } from './border.js';
|
|
3
|
+
export interface FontFace extends Pick<TextConfig, 'font' | 'fontWeight' | 'fontStyle'> {
|
|
4
|
+
/**
|
|
5
|
+
* Base64 encoded font, e.g. `url(data:font/otf;base64,...)`
|
|
6
|
+
*/
|
|
7
|
+
src: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Embed font faces into the generated SVG
|
|
11
|
+
*
|
|
12
|
+
* Use as the last plugin when using BorderPlugin({ text: { ... } })
|
|
13
|
+
* or other plugins that insert text.
|
|
14
|
+
*/
|
|
15
|
+
export default class FontFacesPlugin implements Plugin {
|
|
16
|
+
private readonly fontFaces;
|
|
17
|
+
constructor(fontFaces: Array<FontFace | string>);
|
|
18
|
+
postProcess(svg: SVGSVGElement, options: Options): void;
|
|
19
|
+
}
|
|
@@ -51,7 +51,8 @@ function sanitizeGradient(gradient) {
|
|
|
51
51
|
DotType.diamond = "diamond", DotType.wave = "wave", DotType.heart = "heart", DotType.star = "star",
|
|
52
52
|
DotType.weave = "weave", DotType.pentagon = "pentagon", DotType.hexagon = "hexagon",
|
|
53
53
|
DotType.zebraHorizontal = "zebra-horizontal", DotType.zebraVertical = "zebra-vertical",
|
|
54
|
-
DotType.blocksHorizontal = "blocks-horizontal", DotType.blocksVertical = "blocks-vertical"
|
|
54
|
+
DotType.blocksHorizontal = "blocks-horizontal", DotType.blocksVertical = "blocks-vertical",
|
|
55
|
+
DotType.blobs = "blobs";
|
|
55
56
|
}(DotType || (DotType = {})), function(CornerDotType) {
|
|
56
57
|
CornerDotType.dot = "dot", CornerDotType.square = "square", CornerDotType.heart = "heart",
|
|
57
58
|
CornerDotType.extraRounded = "extra-rounded", CornerDotType.classy = "classy", CornerDotType.inpoint = "inpoint",
|
|
@@ -227,6 +228,21 @@ let DotElements = {
|
|
|
227
228
|
const {size, x, y, document} = args, thickness = .6 * size, notch = (size - thickness) / 2, element = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
228
229
|
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`),
|
|
229
230
|
element;
|
|
231
|
+
},
|
|
232
|
+
blob: (args, corners) => {
|
|
233
|
+
const {size, x, y, document} = args, dotSize = size / 7, element = document.createElementNS("http://www.w3.org/2000/svg", "path"), parts = [ svgPath`M ${x} ${y + 2.5 * dotSize}` ];
|
|
234
|
+
let l = 2 * dotSize;
|
|
235
|
+
return "round" == corners.bl ? (parts.push(svgPath`v ${l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * dotSize} ${2.5 * dotSize}`),
|
|
236
|
+
l = 2 * dotSize) : "out" == corners.bl ? (parts.push(svgPath`v ${5 * dotSize + l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 1 ${2.5 * dotSize} ${-2.5 * dotSize}`),
|
|
237
|
+
l = 2 * dotSize) : (parts.push(svgPath`v ${2.5 * dotSize + l}`), l = 4.5 * dotSize),
|
|
238
|
+
"round" == corners.br ? (parts.push(svgPath`h ${l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${2.5 * dotSize} ${-2.5 * dotSize}`),
|
|
239
|
+
l = -2 * dotSize) : "out" == corners.br ? (parts.push(svgPath`h ${5 * dotSize + l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 1 ${-2.5 * dotSize} ${-2.5 * dotSize}`),
|
|
240
|
+
l = -2 * dotSize) : (parts.push(svgPath`h ${2.5 * dotSize + l}`), l = -4.5 * dotSize),
|
|
241
|
+
"round" == corners.tr ? (parts.push(svgPath`v ${l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${-2.5 * dotSize} ${-2.5 * dotSize}`),
|
|
242
|
+
l = -2 * dotSize) : "out" == corners.tr ? (parts.push(svgPath`v ${-5 * dotSize + l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 1 ${-2.5 * dotSize} ${2.5 * dotSize}`),
|
|
243
|
+
l = -2 * dotSize) : (parts.push(svgPath`v ${-2.5 * dotSize + l}`), l = -4.5 * dotSize),
|
|
244
|
+
"round" == corners.tl ? parts.push(svgPath`h ${l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 0 ${-2.5 * dotSize} ${2.5 * dotSize}`) : "out" == corners.tl ? parts.push(svgPath`h ${-5 * dotSize + l} a ${2.5 * dotSize} ${2.5 * dotSize} 0 0 1 ${2.5 * dotSize} ${2.5 * dotSize}`) : parts.push(svgPath`h ${-2.5 * dotSize + l}`),
|
|
245
|
+
element.setAttribute("d", parts.join(" ") + " z"), element;
|
|
230
246
|
}
|
|
231
247
|
}, qrCornerDotFigures = {
|
|
232
248
|
[CornerDotType.dot]: args => rotateFigure({
|
|
@@ -313,7 +329,7 @@ let SquareElements = {
|
|
|
313
329
|
[ element, fill ];
|
|
314
330
|
},
|
|
315
331
|
centerCircle: args => {
|
|
316
|
-
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");
|
|
332
|
+
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");
|
|
317
333
|
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`);
|
|
318
334
|
const fill = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
319
335
|
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`),
|
|
@@ -580,7 +596,19 @@ let qrDotFigures = {
|
|
|
580
596
|
height
|
|
581
597
|
});
|
|
582
598
|
}
|
|
583
|
-
})
|
|
599
|
+
}),
|
|
600
|
+
[DotType.blobs]: ({getNeighbor, ...args}) => {
|
|
601
|
+
const tl = getNeighbor?.(-1, -1), t = getNeighbor?.(0, -1), tr = getNeighbor?.(1, -1), r = getNeighbor?.(1, 0), br = getNeighbor?.(1, 1), b = getNeighbor?.(0, 1), bl = getNeighbor?.(-1, 1), l = getNeighbor?.(-1, 0), corners = {
|
|
602
|
+
tl: "square",
|
|
603
|
+
tr: "square",
|
|
604
|
+
bl: "square",
|
|
605
|
+
br: "square"
|
|
606
|
+
};
|
|
607
|
+
return !l && tl && (corners.tl = "out"), !t && tr && (corners.tr = "out"), !r && br && (corners.br = "out"),
|
|
608
|
+
!b && bl && (corners.bl = "out"), l || tl || t || (corners.tl = "round"), t || tr || r || (corners.tr = "round"),
|
|
609
|
+
r || br || b || (corners.br = "round"), b || bl || l || (corners.bl = "round"),
|
|
610
|
+
DotElements.blob(args, corners);
|
|
611
|
+
}
|
|
584
612
|
};
|
|
585
613
|
|
|
586
614
|
function getQrDotFigure(type, plugins) {
|
|
@@ -684,11 +712,8 @@ class QRSVG {
|
|
|
684
712
|
}
|
|
685
713
|
defs;
|
|
686
714
|
backgroundMask;
|
|
687
|
-
backgroundMaskGroup;
|
|
688
715
|
dotsMask;
|
|
689
|
-
dotsMaskGroup;
|
|
690
716
|
lightDotsMask;
|
|
691
|
-
lightDotsMaskGroup;
|
|
692
717
|
qr;
|
|
693
718
|
document;
|
|
694
719
|
imageTools;
|
|
@@ -799,27 +824,26 @@ class QRSVG {
|
|
|
799
824
|
name: "background-color"
|
|
800
825
|
});
|
|
801
826
|
let element = this.document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
element.setAttribute("
|
|
805
|
-
element.setAttribute("
|
|
806
|
-
this.
|
|
827
|
+
this.backgroundMask = this.createMask("mask-background-color"), this.defs.appendChild(this.backgroundMask),
|
|
828
|
+
element.setAttribute("x", numToAttr(0)), element.setAttribute("y", numToAttr(0)),
|
|
829
|
+
element.setAttribute("width", numToAttr(options.size)), element.setAttribute("height", numToAttr(options.size)),
|
|
830
|
+
element.setAttribute("rx", numToAttr(options.size / 2 * (options.backgroundOptions.round || 0))),
|
|
831
|
+
this.backgroundMask.appendChild(element);
|
|
807
832
|
}
|
|
808
833
|
}
|
|
809
834
|
drawDots(filter) {
|
|
810
835
|
if (!this.qr) throw new Error("QR code is not defined");
|
|
811
836
|
let options = this.options, count = this.qr.getModuleCount();
|
|
812
837
|
if (count > options.size) throw new Error("The canvas is too small");
|
|
813
|
-
let dotSize = this.options.dotsOptions.size;
|
|
814
|
-
options.imageOptions.mode == ImageMode.background && (
|
|
838
|
+
let dotSize = this.options.dotsOptions.size, size = options.size;
|
|
839
|
+
options.imageOptions.mode == ImageMode.background && (size -= 2 * dotSize * (options.imageOptions.margin || 0));
|
|
815
840
|
let beginning = Math.floor((options.size - count * dotSize) / 2), draw = getQrDotFigure(options.dotsOptions.type, options.plugins);
|
|
816
|
-
|
|
817
|
-
options.imageOptions.mode == ImageMode.background && (
|
|
841
|
+
this.dotsMask = this.createMask("mask-dot-color"), this.defs.appendChild(this.dotsMask),
|
|
842
|
+
options.imageOptions.mode == ImageMode.background && (this.lightDotsMask = this.createMask("mask-light-dot-color"),
|
|
818
843
|
this.defs.appendChild(this.lightDotsMask));
|
|
819
844
|
let margin = 0, additionalDots = 0, fakeCount = count;
|
|
820
845
|
options.shape === ShapeType.circle ? (margin = this.options.backgroundOptions && this.options.backgroundOptions.margin || 0,
|
|
821
|
-
additionalDots = Math.floor((
|
|
822
|
-
fakeCount = count + 2 * additionalDots) : options.imageOptions.mode == ImageMode.background && (additionalDots = 1,
|
|
846
|
+
additionalDots = Math.floor((size / dotSize - count - 2 * margin) / 2), fakeCount = count + 2 * additionalDots) : options.imageOptions.mode == ImageMode.background && (additionalDots = 1,
|
|
823
847
|
fakeCount = count + 2 * additionalDots);
|
|
824
848
|
let fakeBeginning = beginning - additionalDots * dotSize, colorCount = count + 2 * additionalDots;
|
|
825
849
|
this._fakeMatrix = new Array(fakeCount);
|
|
@@ -841,14 +865,14 @@ class QRSVG {
|
|
|
841
865
|
for (let j = 0; j < fakeCount; j++) {
|
|
842
866
|
let jAlign = alignment.find(v => j - additionalDots > v - 3 && j - additionalDots < v + 3);
|
|
843
867
|
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)),
|
|
844
|
-
this._fakeMatrix[i][j] ? this.
|
|
868
|
+
this._fakeMatrix[i][j] ? this.dotsMask && this.dotsMask.appendChild(draw({
|
|
845
869
|
x: fakeBeginning + i * dotSize,
|
|
846
870
|
y: fakeBeginning + j * dotSize,
|
|
847
871
|
size: dotSize,
|
|
848
872
|
document: this.options.document,
|
|
849
873
|
getNeighbor: (xOffset, yOffset) => !0 === this._fakeMatrix[i + xOffset]?.[j + yOffset],
|
|
850
874
|
getPRandom: getRng(this._fakeMatrix, i, j)
|
|
851
|
-
})) : this.lightDotsMask && this.
|
|
875
|
+
})) : this.lightDotsMask && this.lightDotsMask && this.lightDotsMask.appendChild(draw({
|
|
852
876
|
x: fakeBeginning + i * dotSize,
|
|
853
877
|
y: fakeBeginning + j * dotSize,
|
|
854
878
|
size: dotSize,
|
|
@@ -884,9 +908,9 @@ class QRSVG {
|
|
|
884
908
|
if (!element) throw new Error("Element code is not defined");
|
|
885
909
|
let count = this.qr.getModuleCount(), dotSize = this.options.dotsOptions.size, cornersSquareSize = 7 * dotSize, cornersDotSize = 3 * dotSize, beginning = Math.floor((options.size - count * dotSize) / 2);
|
|
886
910
|
[ [ 0, 0, 0 ], [ 1, 0, Math.PI / 2 ], [ 0, 1, -Math.PI / 2 ] ].forEach(([column, row, rotation]) => {
|
|
887
|
-
let x = beginning + column * dotSize * (count - 7), y = beginning + row * dotSize * (count - 7), cornersSquareMask = this.dotsMask,
|
|
888
|
-
(options.cornersSquareOptions?.gradient || options.cornersSquareOptions?.color) && (
|
|
889
|
-
this.defs.appendChild(cornersSquareMask), cornersDotMask = cornersSquareMask,
|
|
911
|
+
let x = beginning + column * dotSize * (count - 7), y = beginning + row * dotSize * (count - 7), cornersSquareMask = this.dotsMask, cornersDotMask = this.dotsMask;
|
|
912
|
+
(options.cornersSquareOptions?.gradient || options.cornersSquareOptions?.color) && (cornersSquareMask = this.createMask(`mask-corners-square-color-${column}-${row}`),
|
|
913
|
+
this.defs.appendChild(cornersSquareMask), cornersDotMask = cornersSquareMask, cornersDotMask = cornersSquareMask,
|
|
890
914
|
this.createColor({
|
|
891
915
|
options: options.cornersSquareOptions?.gradient,
|
|
892
916
|
color: options.cornersSquareOptions?.color,
|
|
@@ -912,20 +936,20 @@ class QRSVG {
|
|
|
912
936
|
var plugins, type, val;
|
|
913
937
|
if (pluinCornerSquare) {
|
|
914
938
|
let [cornerElement, cornerFill] = pluinCornerSquare;
|
|
915
|
-
|
|
939
|
+
cornersSquareMask && cornersSquareMask.appendChild(cornerElement), this.lightDotsMask && this.lightDotsMask.appendChild(cornerFill);
|
|
916
940
|
} else if (val = options.cornersSquareOptions?.type, val && cornerSquareTypes.has(val)) {
|
|
917
941
|
let draw = (type = options.cornersSquareOptions.type, qrCornerSquareFigures[type] || qrCornerSquareFigures[CornerSquareType.square]), [cornerElement, cornerFill] = draw(squareArgs);
|
|
918
|
-
|
|
942
|
+
cornersSquareMask && cornersSquareMask.appendChild(cornerElement), this.lightDotsMask && this.lightDotsMask.appendChild(cornerFill);
|
|
919
943
|
} else {
|
|
920
944
|
let draw = getQrDotFigure(options.cornersSquareOptions?.type || options.dotsOptions.type, options.plugins);
|
|
921
|
-
for (let i = 0; i < squareMask.length; i++) for (let j = 0; j < squareMask[i].length; j++) squareMask[i]?.[j] ?
|
|
945
|
+
for (let i = 0; i < squareMask.length; i++) for (let j = 0; j < squareMask[i].length; j++) squareMask[i]?.[j] ? cornersSquareMask && cornersSquareMask.appendChild(draw({
|
|
922
946
|
x: x + i * dotSize,
|
|
923
947
|
y: y + j * dotSize,
|
|
924
948
|
size: dotSize,
|
|
925
949
|
document: this.options.document,
|
|
926
950
|
getNeighbor: (xOffset, yOffset) => !!squareMask[i + xOffset]?.[j + yOffset],
|
|
927
951
|
getPRandom: getRng(this._fakeMatrix, x / dotSize + i, y / dotSize + j, !1)
|
|
928
|
-
})) : this.lightDotsMask && !dotMask[i]?.[j] && this.
|
|
952
|
+
})) : this.lightDotsMask && !dotMask[i]?.[j] && this.lightDotsMask && this.lightDotsMask.appendChild(draw({
|
|
929
953
|
x: x + i * dotSize,
|
|
930
954
|
y: y + j * dotSize,
|
|
931
955
|
size: dotSize,
|
|
@@ -933,7 +957,7 @@ class QRSVG {
|
|
|
933
957
|
getNeighbor: (xOffset, yOffset) => !squareMask[i + xOffset]?.[j + yOffset] && !dotMask[i + xOffset]?.[j + yOffset],
|
|
934
958
|
getPRandom: getRng(this._fakeMatrix, x / dotSize + i, y / dotSize + j, !1)
|
|
935
959
|
}));
|
|
936
|
-
if (this.lightDotsMask) for (let i = -1; i < 8; i++) for (let j = -1; j < 8; j++) -1 != i && 7 != i && -1 != j && 7 != j || this.
|
|
960
|
+
if (this.lightDotsMask) for (let i = -1; i < 8; i++) for (let j = -1; j < 8; j++) -1 != i && 7 != i && -1 != j && 7 != j || this.lightDotsMask && this.lightDotsMask.appendChild(draw({
|
|
937
961
|
x: x + i * dotSize,
|
|
938
962
|
y: y + j * dotSize,
|
|
939
963
|
size: dotSize,
|
|
@@ -945,7 +969,7 @@ class QRSVG {
|
|
|
945
969
|
getPRandom: getRng(this._fakeMatrix, x / dotSize + i, y / dotSize + j, !1)
|
|
946
970
|
}));
|
|
947
971
|
}
|
|
948
|
-
(options.cornersDotOptions?.gradient || options.cornersDotOptions?.color) && (
|
|
972
|
+
(options.cornersDotOptions?.gradient || options.cornersDotOptions?.color) && (cornersDotMask = this.createMask(`mask-corners-dot-color-${column}-${row}`),
|
|
949
973
|
this.defs.appendChild(cornersDotMask), this.createColor({
|
|
950
974
|
options: options.cornersDotOptions?.gradient,
|
|
951
975
|
color: options.cornersDotOptions?.color,
|
|
@@ -970,16 +994,16 @@ class QRSVG {
|
|
|
970
994
|
}
|
|
971
995
|
};
|
|
972
996
|
}(options.plugins)(dotArgs) : void 0;
|
|
973
|
-
if (pluinCornerDot)
|
|
997
|
+
if (pluinCornerDot) cornersDotMask && cornersDotMask.appendChild(pluinCornerDot); else if (function(val) {
|
|
974
998
|
return !(!val || !cornerDotTypes.has(val));
|
|
975
999
|
}(options.cornersDotOptions?.type)) {
|
|
976
1000
|
let draw = function(type) {
|
|
977
1001
|
return qrCornerDotFigures[type] || qrCornerDotFigures[CornerDotType.square];
|
|
978
1002
|
}(options.cornersDotOptions.type);
|
|
979
|
-
|
|
1003
|
+
cornersDotMask && cornersDotMask.appendChild(draw(dotArgs));
|
|
980
1004
|
} else {
|
|
981
1005
|
let draw = getQrDotFigure(options.cornersDotOptions?.type || options.dotsOptions.type, options.plugins);
|
|
982
|
-
for (let i = 0; i < dotMask.length; i++) for (let j = 0; j < dotMask[i].length; j++) dotMask[i]?.[j] &&
|
|
1006
|
+
for (let i = 0; i < dotMask.length; i++) for (let j = 0; j < dotMask[i].length; j++) dotMask[i]?.[j] && cornersDotMask && cornersDotMask.appendChild(draw({
|
|
983
1007
|
x: x + i * dotSize,
|
|
984
1008
|
y: y + j * dotSize,
|
|
985
1009
|
size: dotSize,
|
|
@@ -1014,7 +1038,7 @@ class QRSVG {
|
|
|
1014
1038
|
let rect = this.document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
1015
1039
|
if (rect.setAttribute("x", numToAttr(x)), rect.setAttribute("y", numToAttr(y)),
|
|
1016
1040
|
rect.setAttribute("height", numToAttr(height)), rect.setAttribute("width", numToAttr(width)),
|
|
1017
|
-
rect.setAttribute("
|
|
1041
|
+
rect.setAttribute("clip-path", `url(#mask-${name})`), options) {
|
|
1018
1042
|
let gradient;
|
|
1019
1043
|
if (options.type === GradientType.radial) gradient = this.document.createElementNS("http://www.w3.org/2000/svg", "radialGradient"),
|
|
1020
1044
|
gradient.setAttribute("id", name), gradient.setAttribute("gradientUnits", "userSpaceOnUse"),
|
|
@@ -1046,12 +1070,9 @@ class QRSVG {
|
|
|
1046
1070
|
this._element.appendChild(rect);
|
|
1047
1071
|
}
|
|
1048
1072
|
createMask(id) {
|
|
1049
|
-
let
|
|
1050
|
-
mask.setAttribute("id", id), mask.setAttribute("
|
|
1051
|
-
mask
|
|
1052
|
-
mask.setAttribute("height", numToAttr(options.size));
|
|
1053
|
-
let group = this.document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
1054
|
-
return group.setAttribute("fill", "#fff"), mask.appendChild(group), [ mask, group ];
|
|
1073
|
+
let mask = this.document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
|
|
1074
|
+
return mask.setAttribute("id", id), mask.setAttribute("clipPathUnits", "userSpaceOnUse"),
|
|
1075
|
+
mask;
|
|
1055
1076
|
}
|
|
1056
1077
|
}
|
|
1057
1078
|
|
|
@@ -1145,11 +1166,13 @@ let QRCodeStyling$1 = class {
|
|
|
1145
1166
|
}
|
|
1146
1167
|
};
|
|
1147
1168
|
|
|
1148
|
-
var FileExtension;
|
|
1169
|
+
var KernelType, FileExtension;
|
|
1149
1170
|
|
|
1150
1171
|
let browserUtils;
|
|
1151
1172
|
|
|
1152
|
-
!function(
|
|
1173
|
+
!function(KernelType) {
|
|
1174
|
+
KernelType.Lanczos = "lanczos", KernelType.Linear = "linear";
|
|
1175
|
+
}(KernelType || (KernelType = {})), KernelType.Lanczos, KernelType.Linear, function(FileExtension) {
|
|
1153
1176
|
FileExtension.svg = "svg", FileExtension.png = "png", FileExtension.jpeg = "jpeg",
|
|
1154
1177
|
FileExtension.webp = "webp";
|
|
1155
1178
|
}(FileExtension || (FileExtension = {}));
|