@liquid-js/qr-code-styling 5.6.1 → 5.7.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/node.d.ts CHANGED
@@ -9,7 +9,7 @@ export { type RecursivePartial } from './types/helper.js';
9
9
  export { type CanvasOptions } from './utils/canvas-options.js';
10
10
  export { type ColorElementValue } from './utils/color.js';
11
11
  export { GradientType, type Gradient } from './utils/gradient.js';
12
- export { CornerDotType, CornerSquareType, DotType, ImageMode, ShapeType, type Options, type Plugin } from './utils/options.js';
12
+ export { CornerDotType, CornerSquareType, DotType, ImageMode, ShapeType, type AppliedMask, type GeneratorMask, type Options, type Plugin } from './utils/options.js';
13
13
  export { ErrorCorrectionPercents } from './utils/qrcode.js';
14
14
  export declare const browserUtils: typeof _browserUtils | undefined;
15
15
  export declare class QRCodeStyling extends _QRCodeStyling {
@@ -1,2 +1,2 @@
1
- var t=/\.?0+$/;function r(r){return"string"==typeof r?r:r.toFixed(7).replace(t,"")}function e(t,e){e=Math.max(e,0),t.setAttribute("width",r(parseFloat(t.getAttribute("width")||"0")+2*e)),t.setAttribute("height",r(parseFloat(t.getAttribute("height")||"0")+2*e));var i=(t.getAttribute("viewBox")||"").split(" ").map((t,r)=>parseFloat(t)+(r<2?-1:2)*e);if(t.setAttribute("viewBox",i.map(r).join(" ")),!(i.length<4))return{left:i[0],right:i[2]+i[0],top:i[1],bottom:i[3]+i[1]}}function i({draw:t,...e}){var{x:i,y:a,size:o,rotation:n=0}=e,u=i+o/2,s=a+o/2;return t=t(e),n&&(Array.isArray(t)?t:[t]).forEach(t=>t.setAttribute("transform",`rotate(${r(180*n/Math.PI)},${u},${s})`)),t}function a(t,{x:e,y:i,size:a}){var o=!1,n=0;return t.map(t=>"string"==typeof t?(n=0,o=t.toUpperCase()==t,t):(n++,t*=a,o&&(t+=n%2==1?e:i),r(t))).join(" ")}function o(t,...e){return t.reduce((t,i,a)=>{var o="";return a&&(o=e[a-1]),"number"==typeof o&&(o=r(o)),`${t}${o}${i}`},"").trim().replace(/[\s\n\r]+/gim," ")}export{e as extendSVG,r as numToAttr,i as rotateFigure,a as scalePath,o as svgPath};
1
+ var t=/\.?0+$/;function e(e){return"string"==typeof e?e:"-0"==(e=e.toFixed(7).replace(t,""))?"0":e}function r(t,...r){return t.reduce((t,a,i)=>{var n="";return i&&(n=r[i-1]),"number"==typeof n&&(n=e(n)),`${t}${n}${a}`},"").trim().replace(/[\s\n\r]+/gim," ")}var a={m:2,l:2,h:1,v:1,c:6,s:4,q:4,t:2,a:7,z:0};function i(t){for(var e=[],r=/[\s,]*/y,i=/[MmLlHhVvCcSsQqTtAaZz]/y,n=/[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/y,o=/[01]/y,s=0,u=e=>{r.lastIndex=s,r.exec(t),s=e.lastIndex=r.lastIndex;var a=e.exec(t);return a&&(s=e.lastIndex),a?.[0]},$="";;){var h=u(i);if(h)$=h;else{if(s>=t.length)break;if(!$||"z"==$||"Z"==$)return;"M"==$&&($="L"),"m"==$&&($="l")}h="a"==$||"A"==$;let r=[];for(let t=0;t<a[$.toLowerCase()];t++){let e=u(!h||3!=t&&4!=t?n:o);if(void 0===e)return;r.push(parseFloat(e))}e.push([$,r])}return e}function n(t,e=0,a=0,n=0){if(t=i(t)){var o=e*Math.PI/180,s=Math.cos(o),u=Math.sin(o),$=(t,e)=>r`${t*s-e*u} ${t*u+e*s}`,h=(t,e)=>r`${a+(t-a)*s-(e-n)*u} ${n+(t-a)*u+(e-n)*s}`,l=0,p=0,c=0,f=0;return t.map(([t,a],i)=>{0==i&&"m"==t&&(t="M");var n=(i=t!=t.toUpperCase())?$:h,o=i?l:0,s=i?p:0;switch(t.toUpperCase()){case"Z":return l=c,p=f,t;case"H":case"V":return n=(o="H"==t.toUpperCase())?a[0]-(i?0:l):0,i=o?0:a[0]-(i?0:p),l+=n,p+=i,e?r`l ${$(n,i)}`:r`${t} ${a[0]}`;case"A":return l=o+a[5],p=s+a[6],r`${t} ${a[0]} ${a[1]} ${a[2]+e} ${a[3]} ${a[4]} ${n(a[5],a[6])}`;default:i=[];for(let t=0;t<a.length;t+=2)i.push(n(a[t],a[t+1]));return l=o+a[a.length-2],p=s+a[a.length-1],"M"!=t&&"m"!=t||(c=l,f=p),r`${t} ${i.join(" ")}`}}).join(" ")}}function o(t){var e=e=>parseFloat(t.getAttribute(e)||"0")||0;switch(t.tagName){case"path":return t.getAttribute("d")||"";case"rect":var a=e("x"),i=e("y"),n=e("width");let o=e("height"),s=t.hasAttribute("rx")?e("rx"):e("ry");return e=t.hasAttribute("ry")?e("ry"):s,s=Math.min(Math.max(s,0),n/2),e=Math.min(Math.max(e,0),o/2),n<=0||o<=0?"":s&&e?r`M ${a} ${i+e} v ${o-2*e} a ${s} ${e} 0 0 0 ${s} ${e} h ${n-2*s} a ${s} ${e} 0 0 0 ${s} ${-e} v ${2*e-o} a ${s} ${e} 0 0 0 ${-s} ${-e} h ${2*s-n} a ${s} ${e} 0 0 0 ${-s} ${e} z`:r`M ${a} ${i} v ${o} h ${n} v ${-o} z`;case"circle":case"ellipse":return a=e("cx"),i=e("cy"),n="circle"==t.tagName?e("r"):e("rx"),e="circle"==t.tagName?n:e("ry"),n<=0||e<=0?"":r`M ${a-n} ${i} a ${n} ${e} 0 1 0 ${2*n} 0 a ${n} ${e} 0 1 0 ${-2*n} 0 z`;case"polygon":return`M ${t.getAttribute("points")||""} z`}}function s(t,r){"number"==typeof r&&(r={left:Math.max(r,0),top:Math.max(r,0),right:Math.max(r,0),bottom:Math.max(r,0)});var{left:a=0,top:i=0,right:n=0,bottom:o=0}=r;if(t.setAttribute("width",e(parseFloat(t.getAttribute("width")||"0")+a+n)),t.setAttribute("height",e(parseFloat(t.getAttribute("height")||"0")+i+o)),(r=(t.getAttribute("viewBox")||"").split(" ").map(parseFloat)).length>=4&&(r[0]-=a,r[1]-=i,r[2]+=a+n,r[3]+=i+o),t.setAttribute("viewBox",r.map(e).join(" ")),!(r.length<4))return{left:r[0],right:r[2]+r[0],top:r[1],bottom:r[3]+r[1]}}function u(t){var e=/^\s*rotate\(\s*([-+.\deE]+)(?:[\s,]+([-+.\deE]+)[\s,]+([-+.\deE]+))?\s*\)\s*$/,r={};for(let i of t){if(i.hasAttribute("clip-path"))return;if(void 0===(t=o(i)))return;if(t){var a=i.getAttribute("transform");if(null===(a=a?e.exec(a):void 0))return;if(void 0===(t=a?n(t,parseFloat(a[1]),parseFloat(a[2]||"0"),parseFloat(a[3]||"0")):n(t)))return;r[a="evenodd"==i.getAttribute("clip-rule")?"evenodd":"nonzero"]||(r[a]=[]),r[a].push(t)}}return Object.entries(r).map(([t,e])=>({rule:t,d:e.join(" ")}))}function $({draw:t,...e}){var{x:a,y:i,size:n,rotation:o=0}=e,s=a+n/2,u=i+n/2;return t=t(e),o&&(Array.isArray(t)?t:[t]).forEach(t=>t.setAttribute("transform",r`rotate(${180*o/Math.PI},${s},${u})`)),t}function h(t,{x:r,y:a,size:i}){var n=!1,o=0;return t.map(t=>"string"==typeof t?(o=0,n=t.toUpperCase()==t,t):(o++,t*=i,n&&(t+=o%2==1?r:a),e(t))).join(" ")}export{s as extendSVG,u as mergeShapes,e as numToAttr,i as parsePath,$ as rotateFigure,h as scalePath,r as svgAttr,r as svgPath};
2
2
  //# sourceMappingURL=plugin-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-utils.js","sources":["../src/utils/svg.ts"],"sourcesContent":["import { RotateFigureArgs } from '../types/helper.js'\n\nconst rx = /\\.?0+$/\n\nexport function numToAttr(value: number | string) {\n if (typeof value == 'string') return value\n return value.toFixed(7).replace(rx, '')\n}\n\nexport function svgPath(strings: TemplateStringsArray, ...values: unknown[]) {\n return strings\n .reduce((t, v, i) => {\n let p: unknown = ''\n if (i) p = values[i - 1]\n if (typeof p == 'number') p = numToAttr(p)\n return `${t}${p}${v}`\n }, '')\n .trim()\n .replace(/[\\s\\n\\r]+/gim, ' ')\n}\n\nexport function rotateFigure<T extends SVGElement | ReadonlyArray<SVGElement>>({ draw, ...args }: RotateFigureArgs<T>) {\n const { x, y, size, rotation = 0 } = args\n const cx = x + size / 2\n const cy = y + size / 2\n\n const element = draw(args)\n if (rotation) (Array.isArray(element) ? element : [element])\n .forEach(el => el.setAttribute('transform', `rotate(${numToAttr((180 * rotation) / Math.PI)},${cx},${cy})`))\n return element\n}\n\nexport function scalePath(path: Array<string | number>, { x, y, size }: {\n x: number\n y: number\n size: number\n}) {\n let move = false\n let i = 0\n return path\n .map((v) => {\n if (typeof v == 'string') {\n i = 0\n move = v.toUpperCase() == v\n return v\n }\n i++\n v = v * size\n if (move) {\n v += i % 2 == 1 ? x : y\n }\n return numToAttr(v)\n })\n .join(' ')\n}\n\nexport function extendSVG(svg: SVGSVGElement, padding: number) {\n padding = Math.max(padding, 0)\n svg.setAttribute('width', numToAttr(parseFloat(svg.getAttribute('width') || '0') + 2 * padding))\n svg.setAttribute('height', numToAttr(parseFloat(svg.getAttribute('height') || '0') + 2 * padding))\n const vb = (svg.getAttribute('viewBox') || '').split(' ').map((v, i) => parseFloat(v) + (i < 2 ? -1 : 2) * padding)\n svg.setAttribute('viewBox', vb.map(numToAttr).join(' '))\n if (vb.length < 4)\n return undefined\n return {\n left: vb[0],\n right: vb[2] + vb[0],\n top: vb[1],\n bottom: vb[3] + vb[1]\n }\n}\n"],"names":["rx","numToAttr","value","toFixed","replace","extendSVG","svg","padding","max","k","parseFloat","c","a","setAttribute","getAttribute","b","split","h","map","i","length","left","right","vb","top","bottom","e","d","f","size","rotation","isArray","draw","args","forEach","Math","PI","cy","element","scalePath","path","y","v","toUpperCase","reduce","trim","rotateFigure","svgPath"],"mappings":"AAEA,IAAAA,WAEMC,SAAUA,EAAUC,GACtB,MAAoB,iBAATA,EAA0BA,EAC9BA,EAAMC,QAAQ,GAAGC,QAAQJ,EAAI,GAFQ,YAoD1CK,EAAAA,GAAAA,EAAoBC,KACtBC,MAAeC,GAAAA,EAAID,qBACFE,EAAAC,WAAmBA,EAAAA,uBAA4B,KAA5B,EAAwCC,IAAlDC,EAAAC,aACtBA,SAAaJ,EAAAC,WAAoBA,EAAAA,aAAeI,WAAa,KAA5B,EAAyCH,IAAnD,IAAAI,GAC3BH,EAAAE,aAAYA,gBAAJE,MAAqCA,KAAAA,KAArCC,EAAgDC,IAAER,WAASA,IAAAA,EAAA,GAAT,EAA2BS,GAAAR,GACzD,GADyDC,EAA3BC,uBACzCE,EAAAG,IAAjBT,GAA+BS,KAAH,QAA5BH,SACOK,GAAAA,MAAP,CAEAC,KAAAN,EACIM,GAAAA,MADGN,EAEHO,GAAAA,EAAOC,GAAAC,IAAWT,EAFf,GAGHS,OACAC,EAAAA,GAAAA,EAAQF,GAAA,qCA/C+DN,OAAAS,WAC3EC,EAAM,GAANhB,EAASiB,EAATb,EAAYW,EAAA,EAAAG,EAAMZ,EAAAS,EAAA,EAMyDI,OANzDlB,EAAAA,EAAAD,GAAlBgB,UAAAI,WAIaC,EAAGC,CAAHrB,IACbsB,QAAqBH,kBAChBG,YAAiBrB,UAAAA,EAAAA,IAAac,EAAAQ,KAAAC,mBAAyDA,CAAAA,CAA5C,SAAyDC,EACzGzB,GAAO0B,EAR0G3B,mBAW/G4B,SAAoBC,OAAmC5B,EAAA6B,IAAGb,oBAKjDA,GAGDc,EAAD,EACDhB,EAAAE,EAAIe,eAAYf,EAAhBA,IAGID,IAAAC,GAAOc,EAAAA,IADEC,GAAAA,EAAAA,GAAAA,EAAAA,EAAF5B,GAGXN,YAEA,IACa,oBAxCF,OACnBG,EAAAgC,OACKA,UAAWF,IAAJf,EAAY,GAGhB,OAFAD,IAAiBC,EACbR,EAAJO,EAAA,IACI,iBAAAC,QAAJA,IACA,GAAAZ,wBAEH8B,QACAzC,eAAQ,IAAA,QAT0DC,eAAAI,eAAAqC,kBAAAP,eAAAQ"}
1
+ {"version":3,"file":"plugin-utils.js","sources":["../src/utils/svg.ts"],"sourcesContent":["import { RotateFigureArgs } from '../types/helper.js'\n\nconst rx = /\\.?0+$/\n\nexport function numToAttr(value: number | string) {\n if (typeof value == 'string') return value\n const str = value.toFixed(7).replace(rx, '')\n // Avoid negative zero for values rounded to 0\n return str == '-0' ? '0' : str\n}\n\n/**\n * Template tag for SVG attribute values (path data, transforms, lengths, ...);\n * formats interpolated numbers with numToAttr and collapses whitespace\n */\nexport function svgAttr(strings: TemplateStringsArray, ...values: unknown[]) {\n return strings\n .reduce((t, v, i) => {\n let p: unknown = ''\n if (i) p = values[i - 1]\n if (typeof p == 'number') p = numToAttr(p)\n return `${t}${p}${v}`\n }, '')\n .trim()\n .replace(/[\\s\\n\\r]+/gim, ' ')\n}\n\n/**\n * @deprecated Use svgAttr\n */\nexport const svgPath = svgAttr\n\nexport function rotateFigure<T extends SVGElement | ReadonlyArray<SVGElement>>({ draw, ...args }: RotateFigureArgs<T>) {\n const { x, y, size, rotation = 0 } = args\n const cx = x + size / 2\n const cy = y + size / 2\n\n const element = draw(args)\n if (rotation) (Array.isArray(element) ? element : [element])\n .forEach(el => el.setAttribute('transform', svgAttr`rotate(${(180 * rotation) / Math.PI},${cx},${cy})`))\n return element\n}\n\nexport function scalePath(path: Array<string | number>, { x, y, size }: {\n x: number\n y: number\n size: number\n}) {\n let move = false\n let i = 0\n return path\n .map((v) => {\n if (typeof v == 'string') {\n i = 0\n move = v.toUpperCase() == v\n return v\n }\n i++\n v = v * size\n if (move) {\n v += i % 2 == 1 ? x : y\n }\n return numToAttr(v)\n })\n .join(' ')\n}\n\nconst paramCount: Record<string, number> = { m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0 }\n\n/**\n * Parse path data into commands with numeric arguments; undefined if invalid\n */\nexport function parsePath(d: string) {\n const segments: Array<[string, number[]]> = []\n const skipRx = /[\\s,]*/y\n const cmdRx = /[MmLlHhVvCcSsQqTtAaZz]/y\n const numRx = /[-+]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][-+]?\\d+)?/y\n const flagRx = /[01]/y\n let pos = 0\n const match = (re: RegExp) => {\n skipRx.lastIndex = pos\n skipRx.exec(d)\n pos = re.lastIndex = skipRx.lastIndex\n const m = re.exec(d)\n if (m) pos = re.lastIndex\n return m?.[0]\n }\n\n let cmd = ''\n while (true) {\n const c = match(cmdRx)\n if (c) {\n cmd = c\n } else {\n if (pos >= d.length) break\n // Implicit command repetition\n if (!cmd || cmd == 'z' || cmd == 'Z') return undefined\n if (cmd == 'M') cmd = 'L'\n if (cmd == 'm') cmd = 'l'\n }\n\n const isArc = cmd == 'a' || cmd == 'A'\n const args: number[] = []\n for (let i = 0; i < paramCount[cmd.toLowerCase()]; i++) {\n const v = match(isArc && (i == 3 || i == 4) ? flagRx : numRx)\n if (v === undefined) return undefined\n args.push(parseFloat(v))\n }\n segments.push([cmd, args])\n }\n return segments\n}\n\n/**\n * Rotate path data around (cx, cy), keeping relative commands relative\n * (converting them to absolute would accumulate rounding errors of the original values)\n */\nfunction rotatePath(d: string, angle = 0, cx = 0, cy = 0) {\n const segments = parsePath(d)\n if (!segments) return undefined\n\n const rad = (angle * Math.PI) / 180\n const cos = Math.cos(rad)\n const sin = Math.sin(rad)\n const vector = (dx: number, dy: number) => svgAttr`${dx * cos - dy * sin} ${dx * sin + dy * cos}`\n const point = (px: number, py: number) => svgAttr`${cx + (px - cx) * cos - (py - cy) * sin} ${cy + (px - cx) * sin + (py - cy) * cos}`\n\n // Track the current point to resolve absolute H / V commands\n let x = 0\n let y = 0\n let startX = 0\n let startY = 0\n return segments.map(([cmd, args], i) => {\n // The first moveto is always absolute\n if (i == 0 && cmd == 'm') cmd = 'M'\n const rel = cmd != cmd.toUpperCase()\n const map = rel ? vector : point\n const ox = rel ? x : 0\n const oy = rel ? y : 0\n switch (cmd.toUpperCase()) {\n case 'Z':\n x = startX\n y = startY\n return cmd\n case 'H':\n case 'V': {\n const isH = cmd.toUpperCase() == 'H'\n const dx = isH ? args[0] - (rel ? 0 : x) : 0\n const dy = isH ? 0 : args[0] - (rel ? 0 : y)\n x += dx\n y += dy\n if (!angle) return svgAttr`${cmd} ${args[0]}`\n return svgAttr`l ${vector(dx, dy)}`\n }\n case 'A':\n x = ox + args[5]\n y = oy + args[6]\n return svgAttr`${cmd} ${args[0]} ${args[1]} ${args[2] + angle} ${args[3]} ${args[4]} ${map(args[5], args[6])}`\n default: {\n const points: string[] = []\n for (let j = 0; j < args.length; j += 2) points.push(map(args[j], args[j + 1]))\n x = ox + args[args.length - 2]\n y = oy + args[args.length - 1]\n if (cmd == 'M' || cmd == 'm') {\n startX = x\n startY = y\n }\n return svgAttr`${cmd} ${points.join(' ')}`\n }\n }\n }).join(' ')\n}\n\nfunction shapeToPath(el: Element) {\n const num = (name: string) => parseFloat(el.getAttribute(name) || '0') || 0\n switch (el.tagName) {\n case 'path':\n return el.getAttribute('d') || ''\n case 'rect': {\n const x = num('x')\n const y = num('y')\n const w = num('width')\n const h = num('height')\n let rX = el.hasAttribute('rx') ? num('rx') : num('ry')\n let rY = el.hasAttribute('ry') ? num('ry') : rX\n rX = Math.min(Math.max(rX, 0), w / 2)\n rY = Math.min(Math.max(rY, 0), h / 2)\n if (w <= 0 || h <= 0) return ''\n if (!rX || !rY) return svgAttr`M ${x} ${y} v ${h} h ${w} v ${-h} z`\n return svgAttr`M ${x} ${y + rY}\n v ${h - 2 * rY}\n a ${rX} ${rY} 0 0 0 ${rX} ${rY}\n h ${w - 2 * rX}\n a ${rX} ${rY} 0 0 0 ${rX} ${-rY}\n v ${-h + 2 * rY}\n a ${rX} ${rY} 0 0 0 ${-rX} ${-rY}\n h ${-w + 2 * rX}\n a ${rX} ${rY} 0 0 0 ${-rX} ${rY}\n z`\n }\n case 'circle':\n case 'ellipse': {\n const cx = num('cx')\n const cy = num('cy')\n const rX = el.tagName == 'circle' ? num('r') : num('rx')\n const rY = el.tagName == 'circle' ? rX : num('ry')\n if (rX <= 0 || rY <= 0) return ''\n return svgAttr`M ${cx - rX} ${cy}\n a ${rX} ${rY} 0 1 0 ${2 * rX} 0\n a ${rX} ${rY} 0 1 0 ${-2 * rX} 0\n z`\n }\n case 'polygon':\n return `M ${el.getAttribute('points') || ''} z`\n default:\n return undefined\n }\n}\n\n/**\n * Merge clip path shapes into a single path per clip rule, so the result can be drawn as a plain filled path\n *\n * @returns Path data grouped by clip rule, or undefined if any of the shapes can't be expressed as a path\n */\nexport function mergeShapes(elements: Element[]) {\n const rotateRx = /^\\s*rotate\\(\\s*([-+.\\deE]+)(?:[\\s,]+([-+.\\deE]+)[\\s,]+([-+.\\deE]+))?\\s*\\)\\s*$/\n const paths: Record<string, string[]> = {}\n\n for (const el of elements) {\n if (el.hasAttribute('clip-path')) return undefined\n\n const d = shapeToPath(el)\n if (d === undefined) return undefined\n if (!d) continue\n\n const transform = el.getAttribute('transform')\n const m = transform ? rotateRx.exec(transform) : undefined\n if (m === null) return undefined\n const rotated = m ? rotatePath(d, parseFloat(m[1]), parseFloat(m[2] || '0'), parseFloat(m[3] || '0')) : rotatePath(d)\n if (rotated === undefined) return undefined\n\n const rule = el.getAttribute('clip-rule') == 'evenodd' ? 'evenodd' : 'nonzero'\n if (!paths[rule]) paths[rule] = []\n paths[rule].push(rotated)\n }\n\n return Object.entries(paths).map(([rule, d]) => ({ rule, d: d.join(' ') }))\n}\n\nexport interface SVGPadding {\n left: number\n top: number\n right: number\n bottom: number\n}\n\n/**\n * Extend the SVG by a uniform (non-negative) padding, or by the given amount on each side\n */\nexport function extendSVG(svg: SVGSVGElement, padding: number | Partial<SVGPadding>) {\n if (typeof padding == 'number') padding = { left: Math.max(padding, 0), top: Math.max(padding, 0), right: Math.max(padding, 0), bottom: Math.max(padding, 0) }\n const { left = 0, top = 0, right = 0, bottom = 0 } = padding\n svg.setAttribute('width', numToAttr(parseFloat(svg.getAttribute('width') || '0') + left + right))\n svg.setAttribute('height', numToAttr(parseFloat(svg.getAttribute('height') || '0') + top + bottom))\n const vb = (svg.getAttribute('viewBox') || '').split(' ').map(parseFloat)\n if (vb.length >= 4) {\n vb[0] -= left\n vb[1] -= top\n vb[2] += left + right\n vb[3] += top + bottom\n }\n svg.setAttribute('viewBox', vb.map(numToAttr).join(' '))\n if (vb.length < 4)\n return undefined\n return {\n left: vb[0],\n right: vb[2] + vb[0],\n top: vb[1],\n bottom: vb[3] + vb[1]\n }\n}\n"],"names":["rx","numToAttr","value","str","toFixed","replace","strings","values","reduce","t","v","i","p","trim","paramCount","m","l","h","c","s","q","a","z","parsePath","d","segments","skipRx","cmdRx","numRx","flagRx","pos","match","re","lastIndex","exec","cmd","length","isArc","args","toLowerCase","push","parseFloat","rotatePath","angle","cx","cy","rad","PI","cos","Math","sin","vector","dx","dy","svgAttr","point","px","py","x","y","startX","startY","map","rel","toUpperCase","isH","ox","oy","points","j","join","shapeToPath","el","name","getAttribute","tagName","num","rX","hasAttribute","rY","min","max","w","extendSVG","left","top","right","bottom","padding","g","e","f","setAttribute","u","b","split","vb","mergeShapes","elements","E","undefined","rotateRx","D","rule","Object","entries","paths","draw","size","isArray","element","forEach","scalePath"],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import type { GeneratorMask, Options, Plugin } from '../../utils/options.js';
2
+ import { FillRule, Square } from './raster.js';
3
+ export interface ImageMaskPluginOptions {
4
+ /** Image drawn behind the QR code */
5
+ image: string | Buffer | Blob;
6
+ /** Path data (in the image coordinate space) outlining the area to fill with QR code segments */
7
+ path: string;
8
+ /**
9
+ * Fill rule of the path
10
+ *
11
+ * @default 'nonzero'
12
+ */
13
+ fillRule?: FillRule;
14
+ /**
15
+ * Prefer squares up to this fraction smaller than the largest one if they touch the edge of the area
16
+ * more, or are closer to its center
17
+ *
18
+ * @default 0.02
19
+ */
20
+ sizeTolerance?: number;
21
+ /**
22
+ * Sampling cells along the longer side of the area
23
+ *
24
+ * @default 2000
25
+ */
26
+ resolution?: number;
27
+ /**
28
+ * Gaps and edge irregularities smaller than this fraction of the area size are ignored
29
+ *
30
+ * @default 0.01
31
+ */
32
+ noise?: number;
33
+ /** See GeneratorMask.fitGradient */
34
+ fitGradient?: boolean;
35
+ /**
36
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLImageElement/crossOrigin)
37
+ */
38
+ crossOrigin?: string;
39
+ }
40
+ /**
41
+ * Fit the QR code into an area of an image outlined by a path, and draw the image behind the code
42
+ */
43
+ export default class ImageMaskPlugin implements Plugin {
44
+ private readonly pluginOptions;
45
+ private readonly fillRule;
46
+ private readonly resolution;
47
+ private readonly sizeTolerance;
48
+ private readonly noise;
49
+ private analysis?;
50
+ constructor(pluginOptions: ImageMaskPluginOptions);
51
+ /**
52
+ * Drop the cached path analyses and images
53
+ */
54
+ static clearCache(): void;
55
+ /**
56
+ * Square (in image coordinates) the QR code is fitted into, before nudging
57
+ */
58
+ getSquare(): Square;
59
+ private getAnalysis;
60
+ applyMask(count: number, padding?: number): GeneratorMask;
61
+ private getImageData;
62
+ postProcess(svg: SVGSVGElement, options: Options): Promise<void>;
63
+ }
@@ -0,0 +1,58 @@
1
+ export type Point = [number, number];
2
+ export type FillRule = 'nonzero' | 'evenodd';
3
+ export interface Square {
4
+ x: number;
5
+ y: number;
6
+ size: number;
7
+ }
8
+ /**
9
+ * Flatten path data into polygons (one per subpath), approximating curves with line segments
10
+ *
11
+ * @param tolerance Maximum deviation of the approximation; a fixed number of segments if not positive
12
+ * @returns Polygons, or undefined if the path data is invalid
13
+ */
14
+ export declare function pathToPolygons(d: string, tolerance?: number): Point[][] | undefined;
15
+ export declare function polygonBounds(polygons: Point[][]): {
16
+ minX: number;
17
+ minY: number;
18
+ maxX: number;
19
+ maxY: number;
20
+ };
21
+ /**
22
+ * Sample the filled area at cell centers, as grid[column][row]
23
+ */
24
+ export declare function rasterizePolygons(polygons: Point[][], rule: FillRule, x0: number, y0: number, cell: number, cols: number, rows: number): boolean[][];
25
+ /**
26
+ * Close gaps smaller than about twice the radius (in cells)
27
+ */
28
+ export declare function closeGrid(grid: boolean[][], radius: number): boolean[][];
29
+ /** Sampled area around the square, for validating nudges */
30
+ export interface AreaWindow {
31
+ x0: number;
32
+ y0: number;
33
+ cell: number;
34
+ cols: number;
35
+ rows: number;
36
+ data: Uint8Array;
37
+ }
38
+ export interface AreaAnalysis {
39
+ square: Square;
40
+ window: AreaWindow;
41
+ }
42
+ /**
43
+ * Whether all window cells centered within the square are inside the area
44
+ */
45
+ export declare function squareFits({ x0, y0, cell, cols, rows, data }: AreaWindow, x: number, y: number, size: number): boolean;
46
+ /**
47
+ * Largest square inside the filled area; among squares within the tolerance of the largest, prefer those
48
+ * touching the edge the most, then the one closest to the center of its connected area
49
+ *
50
+ * @param resolution Sampling cells along the longer side of the area
51
+ * @param noise Gaps and edge irregularities smaller than this fraction of the area size are ignored
52
+ * @returns Square and the sampled area around it, or undefined if the area is empty
53
+ */
54
+ export declare function analyzeArea(polygons: Point[][], rule: FillRule, resolution?: number, tolerance?: number, noise?: number): AreaAnalysis | undefined;
55
+ /**
56
+ * See analyzeArea
57
+ */
58
+ export declare function findSquare(polygons: Point[][], rule: FillRule, resolution?: number, tolerance?: number, noise?: number): Square | undefined;