@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 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
  })
@@ -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":"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"}
@@ -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"}
@@ -33,7 +33,11 @@ export interface BorderPluginOptions {
33
33
  content: string;
34
34
  };
35
35
  };
36
- /** A string of embedded CSS @font-face rules */
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
- [this.backgroundMask, this.backgroundMaskGroup] = this.createMask("mask-background-color"),
803
- this.defs.appendChild(this.backgroundMask), element.setAttribute("x", numToAttr(0)),
804
- element.setAttribute("y", numToAttr(0)), element.setAttribute("width", numToAttr(options.size)),
805
- element.setAttribute("height", numToAttr(options.size)), element.setAttribute("rx", numToAttr(options.size / 2 * (options.backgroundOptions.round || 0))),
806
- this.backgroundMaskGroup.appendChild(element);
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 && (options.size -= 2 * dotSize * (options.imageOptions.margin || 0));
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
- [this.dotsMask, this.dotsMaskGroup] = this.createMask("mask-dot-color"), this.defs.appendChild(this.dotsMask),
817
- options.imageOptions.mode == ImageMode.background && ([this.lightDotsMask, this.lightDotsMaskGroup] = this.createMask("mask-light-dot-color"),
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((options.size / dotSize - count - 2 * margin) / 2),
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.dotsMaskGroup && this.dotsMaskGroup.appendChild(draw({
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.lightDotsMaskGroup && this.lightDotsMaskGroup.appendChild(draw({
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, cornersSquareMaskGroup = this.dotsMaskGroup, cornersDotMask = this.dotsMask, cornersDotMaskGroup = this.dotsMaskGroup;
888
- (options.cornersSquareOptions?.gradient || options.cornersSquareOptions?.color) && ([cornersSquareMask, cornersSquareMaskGroup] = this.createMask(`mask-corners-square-color-${column}-${row}`),
889
- this.defs.appendChild(cornersSquareMask), cornersDotMask = cornersSquareMask, cornersDotMaskGroup = cornersSquareMaskGroup,
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
- cornersSquareMaskGroup && cornersSquareMaskGroup.appendChild(cornerElement), this.lightDotsMaskGroup && this.lightDotsMaskGroup.appendChild(cornerFill);
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
- cornersSquareMaskGroup && cornersSquareMaskGroup.appendChild(cornerElement), this.lightDotsMaskGroup && this.lightDotsMaskGroup.appendChild(cornerFill);
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] ? cornersSquareMaskGroup && cornersSquareMaskGroup.appendChild(draw({
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.lightDotsMaskGroup && this.lightDotsMaskGroup.appendChild(draw({
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.lightDotsMaskGroup && this.lightDotsMaskGroup.appendChild(draw({
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) && ([cornersDotMask, cornersDotMaskGroup] = this.createMask(`mask-corners-dot-color-${column}-${row}`),
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) cornersDotMaskGroup && cornersDotMaskGroup.appendChild(pluinCornerDot); else if (function(val) {
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
- cornersDotMaskGroup && cornersDotMaskGroup.appendChild(draw(dotArgs));
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] && cornersDotMaskGroup && cornersDotMaskGroup.appendChild(draw({
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("style", `mask:url(#mask-${name})`), options) {
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 options = this.options, mask = this.document.createElementNS("http://www.w3.org/2000/svg", "mask");
1050
- mask.setAttribute("id", id), mask.setAttribute("maskUnits", "userSpaceOnUse"), mask.setAttribute("x", "0"),
1051
- mask.setAttribute("y", "0"), mask.setAttribute("width", numToAttr(options.size)),
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(FileExtension) {
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 = {}));