@pixldocs/canvas-renderer 0.5.117 → 0.5.119
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/dist/index-81pAjQOk.cjs +18489 -0
- package/dist/index-81pAjQOk.cjs.map +1 -0
- package/dist/index-CuTWdeXZ.js +18474 -0
- package/dist/index-CuTWdeXZ.js.map +1 -0
- package/dist/index.cjs +36 -18109
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +36 -18092
- package/dist/index.js.map +1 -1
- package/dist/pdfFonts-CB5z77qO.js +1014 -0
- package/dist/pdfFonts-CB5z77qO.js.map +1 -0
- package/dist/{svgTextToPath-CQ2Tp03U.js → pdfFonts-CHHpRsRK.cjs} +304 -645
- package/dist/pdfFonts-CHHpRsRK.cjs.map +1 -0
- package/dist/pdfWatermark-CewmS9qQ.js +36 -0
- package/dist/pdfWatermark-CewmS9qQ.js.map +1 -0
- package/dist/pdfWatermark-DdBUt6s5.cjs +36 -0
- package/dist/pdfWatermark-DdBUt6s5.cjs.map +1 -0
- package/dist/{svgColorUtils-BkKZ8cyd.js → svgColorUtils-CIehRL4U.js} +262 -1
- package/dist/{svgColorUtils-BkKZ8cyd.js.map → svgColorUtils-CIehRL4U.js.map} +1 -1
- package/dist/{svgColorUtils-DQN6fbIM.cjs → svgColorUtils-DKcCq1sO.cjs} +262 -1
- package/dist/{svgColorUtils-DQN6fbIM.cjs.map → svgColorUtils-DKcCq1sO.cjs.map} +1 -1
- package/dist/svgTextToPath-B6FmPvcr.js +626 -0
- package/dist/svgTextToPath-B6FmPvcr.js.map +1 -0
- package/dist/svgTextToPath-B77kYzHp.cjs +665 -0
- package/dist/svgTextToPath-B77kYzHp.cjs.map +1 -0
- package/dist/vectorPdfExport-BrHHt_7L.js +4749 -0
- package/dist/vectorPdfExport-BrHHt_7L.js.map +1 -0
- package/dist/vectorPdfExport-CyJXH2cR.cjs +4766 -0
- package/dist/vectorPdfExport-CyJXH2cR.cjs.map +1 -0
- package/package.json +1 -1
- package/dist/svgTextToPath-4Y_THSBg.cjs +0 -1393
- package/dist/svgTextToPath-4Y_THSBg.cjs.map +0 -1
- package/dist/svgTextToPath-CQ2Tp03U.js.map +0 -1
|
@@ -1,15 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
const __vite_import_meta_env__ = {};
|
|
3
|
-
const fontCache
|
|
4
|
-
const fontBytesCache
|
|
1
|
+
"use strict";
|
|
2
|
+
const __vite_import_meta_env__ = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false };
|
|
3
|
+
const fontCache = /* @__PURE__ */ new Map();
|
|
4
|
+
const fontBytesCache = /* @__PURE__ */ new Map();
|
|
5
5
|
const googleFontUrlCache = /* @__PURE__ */ new Map();
|
|
6
6
|
const googleFontNotFound = /* @__PURE__ */ new Set();
|
|
7
|
+
const registeredFamilies = /* @__PURE__ */ new Set();
|
|
8
|
+
const registeredVariantCoverage = /* @__PURE__ */ new Map();
|
|
9
|
+
const isFamilyEmbedded = (family) => registeredFamilies.has(family);
|
|
10
|
+
const registeredVariants = /* @__PURE__ */ new Set();
|
|
11
|
+
const variantKey = (family, weight, italic) => `${family}|${weight}|${italic ? "i" : "n"}`;
|
|
7
12
|
const remoteVariantKey = (family, weight, italic) => `${family}|${resolveFontWeight(weight)}|${italic ? "i" : "n"}`;
|
|
8
|
-
const
|
|
13
|
+
const doesVariantSupportChar = (family, weight, italic, char) => {
|
|
14
|
+
var _a;
|
|
15
|
+
const cp = char.codePointAt(0);
|
|
16
|
+
if (cp == null) return false;
|
|
17
|
+
return ((_a = registeredVariantCoverage.get(variantKey(family, resolveFontWeight(weight), italic))) == null ? void 0 : _a.has(cp)) === true;
|
|
18
|
+
};
|
|
19
|
+
const resolveBestRegisteredVariant = (family, weight, italic) => {
|
|
20
|
+
const want = resolveFontWeight(weight);
|
|
21
|
+
const weights = [300, 400, 500, 600, 700];
|
|
22
|
+
if (registeredVariants.has(variantKey(family, want, italic))) {
|
|
23
|
+
return { weight: want, italic };
|
|
24
|
+
}
|
|
25
|
+
const sortedByDistance = [...weights].sort((a, b) => {
|
|
26
|
+
const da = Math.abs(a - want);
|
|
27
|
+
const db = Math.abs(b - want);
|
|
28
|
+
if (da !== db) return da - db;
|
|
29
|
+
return want >= 500 ? b - a : a - b;
|
|
30
|
+
});
|
|
31
|
+
for (const w of sortedByDistance) {
|
|
32
|
+
if (registeredVariants.has(variantKey(family, w, italic))) {
|
|
33
|
+
return { weight: w, italic };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for (const w of sortedByDistance) {
|
|
37
|
+
if (registeredVariants.has(variantKey(family, w, !italic))) {
|
|
38
|
+
return { weight: w, italic: !italic };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
};
|
|
43
|
+
function resolveFontProxyUrl() {
|
|
44
|
+
const fromEnv = (() => {
|
|
45
|
+
try {
|
|
46
|
+
return (__vite_import_meta_env__ == null ? void 0 : __vite_import_meta_env__.VITE_SUPABASE_URL) ?? "";
|
|
47
|
+
} catch {
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
50
|
+
})();
|
|
51
|
+
const fromWindow = (() => {
|
|
52
|
+
try {
|
|
53
|
+
return typeof window !== "undefined" && window.__PIXLDOCS_SUPABASE_URL || "";
|
|
54
|
+
} catch {
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
})();
|
|
58
|
+
const base = fromEnv || fromWindow || "";
|
|
59
|
+
return base ? `${base}/functions/v1/font-proxy` : "";
|
|
60
|
+
}
|
|
9
61
|
async function fetchTtfViaProxy(family, weight, isItalic, source) {
|
|
10
|
-
|
|
62
|
+
const proxyUrl = resolveFontProxyUrl();
|
|
63
|
+
if (!proxyUrl) return null;
|
|
11
64
|
try {
|
|
12
|
-
const url = `${
|
|
65
|
+
const url = `${proxyUrl}?family=${encodeURIComponent(family)}&weight=${weight}&italic=${isItalic ? 1 : 0}&source=${source}`;
|
|
13
66
|
const res = await fetch(url);
|
|
14
67
|
if (!res.ok) return null;
|
|
15
68
|
const buf = await res.arrayBuffer();
|
|
@@ -18,6 +71,13 @@ async function fetchTtfViaProxy(family, weight, isItalic, source) {
|
|
|
18
71
|
return null;
|
|
19
72
|
}
|
|
20
73
|
}
|
|
74
|
+
const FONT_WEIGHT_LABELS = {
|
|
75
|
+
300: "Light",
|
|
76
|
+
400: "Regular",
|
|
77
|
+
500: "Medium",
|
|
78
|
+
600: "SemiBold",
|
|
79
|
+
700: "Bold"
|
|
80
|
+
};
|
|
21
81
|
function resolveFontWeight(weight) {
|
|
22
82
|
if (weight <= 350) return 300;
|
|
23
83
|
if (weight <= 450) return 400;
|
|
@@ -537,18 +597,180 @@ function isJsPdfEmbeddableTrueType(bytes) {
|
|
|
537
597
|
}
|
|
538
598
|
return false;
|
|
539
599
|
}
|
|
600
|
+
function extractSupportedCodePointsFromTtf(bytes) {
|
|
601
|
+
const supported = /* @__PURE__ */ new Set();
|
|
602
|
+
if (bytes.length < 12) return supported;
|
|
603
|
+
const u16 = (offset) => bytes[offset] << 8 | bytes[offset + 1];
|
|
604
|
+
const i16 = (offset) => {
|
|
605
|
+
const value = u16(offset);
|
|
606
|
+
return value & 32768 ? value - 65536 : value;
|
|
607
|
+
};
|
|
608
|
+
const u32 = (offset) => (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
|
|
609
|
+
const tableCount = u16(4);
|
|
610
|
+
let cmapOffset = 0;
|
|
611
|
+
for (let i = 0; i < tableCount; i++) {
|
|
612
|
+
const recordOffset = 12 + i * 16;
|
|
613
|
+
if (recordOffset + 16 > bytes.length) return supported;
|
|
614
|
+
if (String.fromCharCode(bytes[recordOffset], bytes[recordOffset + 1], bytes[recordOffset + 2], bytes[recordOffset + 3]) === "cmap") {
|
|
615
|
+
cmapOffset = u32(recordOffset + 8);
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if (!cmapOffset || cmapOffset + 4 > bytes.length) return supported;
|
|
620
|
+
const subtables = u16(cmapOffset + 2);
|
|
621
|
+
const candidates = [];
|
|
622
|
+
for (let j = 0; j < subtables; j++) {
|
|
623
|
+
const encOffset = cmapOffset + 4 + j * 8;
|
|
624
|
+
if (encOffset + 8 > bytes.length) continue;
|
|
625
|
+
const platform = u16(encOffset);
|
|
626
|
+
const encoding = u16(encOffset + 2);
|
|
627
|
+
const subOffset = cmapOffset + u32(encOffset + 4);
|
|
628
|
+
if (subOffset + 2 > bytes.length) continue;
|
|
629
|
+
const format = u16(subOffset);
|
|
630
|
+
const score = format === 12 ? 40 : format === 4 ? 30 : 0;
|
|
631
|
+
if (score) candidates.push({ format, offset: subOffset, score: score + (platform === 3 && encoding === 10 ? 2 : platform === 0 ? 1 : 0) });
|
|
632
|
+
}
|
|
633
|
+
candidates.sort((a, b) => b.score - a.score);
|
|
634
|
+
const best = candidates[0];
|
|
635
|
+
if (!best) return supported;
|
|
636
|
+
if (best.format === 12 && best.offset + 16 <= bytes.length) {
|
|
637
|
+
const nGroups = u32(best.offset + 12);
|
|
638
|
+
for (let i = 0; i < nGroups; i++) {
|
|
639
|
+
const off = best.offset + 16 + i * 12;
|
|
640
|
+
if (off + 12 > bytes.length) break;
|
|
641
|
+
const start = u32(off);
|
|
642
|
+
const end = u32(off + 4);
|
|
643
|
+
for (let cp = start; cp <= end && cp <= 1114111; cp++) supported.add(cp);
|
|
644
|
+
}
|
|
645
|
+
} else if (best.format === 4 && best.offset + 14 <= bytes.length) {
|
|
646
|
+
const segCount = u16(best.offset + 6) / 2;
|
|
647
|
+
const endCodes = best.offset + 14;
|
|
648
|
+
const startCodes = endCodes + segCount * 2 + 2;
|
|
649
|
+
const idDeltas = startCodes + segCount * 2;
|
|
650
|
+
const idRangeOffsets = idDeltas + segCount * 2;
|
|
651
|
+
for (let i = 0; i < segCount; i++) {
|
|
652
|
+
const start = u16(startCodes + i * 2);
|
|
653
|
+
const end = u16(endCodes + i * 2);
|
|
654
|
+
const delta = i16(idDeltas + i * 2);
|
|
655
|
+
const rangeOffset = u16(idRangeOffsets + i * 2);
|
|
656
|
+
for (let cp = start; cp <= end && cp !== 65535; cp++) {
|
|
657
|
+
if (rangeOffset === 0) {
|
|
658
|
+
if ((cp + delta & 65535) !== 0) supported.add(cp);
|
|
659
|
+
} else {
|
|
660
|
+
const glyphOffset = idRangeOffsets + i * 2 + rangeOffset + (cp - start) * 2;
|
|
661
|
+
if (glyphOffset + 2 <= bytes.length && u16(glyphOffset) !== 0) supported.add(cp);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return supported;
|
|
667
|
+
}
|
|
668
|
+
function base64ToBytes(base64) {
|
|
669
|
+
const binary = atob(base64);
|
|
670
|
+
const bytes = new Uint8Array(binary.length);
|
|
671
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
672
|
+
return bytes;
|
|
673
|
+
}
|
|
674
|
+
const getJsPDFFontName = (fontName) => {
|
|
675
|
+
return fontName.replace(/\s+/g, "");
|
|
676
|
+
};
|
|
677
|
+
const WEIGHT_TO_KEYS = {
|
|
678
|
+
300: ["light", "regular"],
|
|
679
|
+
400: ["regular"],
|
|
680
|
+
500: ["medium", "regular"],
|
|
681
|
+
600: ["semibold", "bold", "regular"],
|
|
682
|
+
700: ["bold", "regular"]
|
|
683
|
+
};
|
|
684
|
+
const WEIGHT_TO_ITALIC_KEYS = {
|
|
685
|
+
300: ["lightItalic", "italic", "light", "regular"],
|
|
686
|
+
400: ["italic", "regular"],
|
|
687
|
+
500: ["mediumItalic", "italic", "medium", "regular"],
|
|
688
|
+
600: ["semiboldItalic", "boldItalic", "italic", "semibold", "bold", "regular"],
|
|
689
|
+
700: ["boldItalic", "italic", "bold", "regular"]
|
|
690
|
+
};
|
|
691
|
+
function getFontPathForWeight(fontFiles, resolvedWeight, isItalic = false) {
|
|
692
|
+
const keys = isItalic ? WEIGHT_TO_ITALIC_KEYS[resolvedWeight] : WEIGHT_TO_KEYS[resolvedWeight];
|
|
693
|
+
if (!keys) return fontFiles.regular;
|
|
694
|
+
for (const k of keys) {
|
|
695
|
+
const path = fontFiles[k];
|
|
696
|
+
if (path) return path;
|
|
697
|
+
}
|
|
698
|
+
return fontFiles.regular;
|
|
699
|
+
}
|
|
700
|
+
function isExactWeightItalicMatch(fontFiles, resolvedWeight, isItalic, resolvedPath) {
|
|
701
|
+
const exactKey = isItalic ? resolvedWeight === 300 ? "lightItalic" : resolvedWeight === 500 ? "mediumItalic" : resolvedWeight === 600 ? "semiboldItalic" : resolvedWeight === 700 ? "boldItalic" : "italic" : resolvedWeight === 300 ? "light" : resolvedWeight === 500 ? "medium" : resolvedWeight === 600 ? "semibold" : resolvedWeight === 700 ? "bold" : "regular";
|
|
702
|
+
return fontFiles[exactKey] === resolvedPath;
|
|
703
|
+
}
|
|
704
|
+
const getEmbeddedJsPDFFontName = (fontName, weight, isItalic = false) => {
|
|
705
|
+
const resolved = resolveFontWeight(weight);
|
|
706
|
+
const label = FONT_WEIGHT_LABELS[resolved];
|
|
707
|
+
const italicSuffix = isItalic ? "Italic" : "";
|
|
708
|
+
return `${getJsPDFFontName(fontName)}-${label}${italicSuffix}`;
|
|
709
|
+
};
|
|
710
|
+
const embedFont = async (pdf, fontName, weight = 400, isItalic = false) => {
|
|
711
|
+
const fontFiles = FONT_FILES[fontName];
|
|
712
|
+
if (!fontFiles) {
|
|
713
|
+
console.warn(`Font ${fontName} not found in local fonts`);
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
const resolvedWeight = resolveFontWeight(weight);
|
|
717
|
+
const fontPath = getFontPathForWeight(fontFiles, resolvedWeight, isItalic);
|
|
718
|
+
if (!fontPath) return false;
|
|
719
|
+
if (!isExactWeightItalicMatch(fontFiles, resolvedWeight, isItalic, fontPath)) {
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
const label = FONT_WEIGHT_LABELS[resolvedWeight];
|
|
723
|
+
const italicSuffix = isItalic ? "Italic" : "";
|
|
724
|
+
const cacheKey = `${fontName}-${resolvedWeight}${isItalic ? "-italic" : ""}`;
|
|
725
|
+
const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, weight, isItalic);
|
|
726
|
+
try {
|
|
727
|
+
let base64Font = fontCache.get(cacheKey);
|
|
728
|
+
if (!base64Font) {
|
|
729
|
+
const response = await fetch(fontPath);
|
|
730
|
+
if (!response.ok) throw new Error(`Failed to fetch font: ${response.statusText}`);
|
|
731
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
732
|
+
const bytes = new Uint8Array(arrayBuffer);
|
|
733
|
+
if (!isJsPdfEmbeddableTrueType(bytes)) throw new Error(`Font is not a jsPDF-compatible TrueType file: ${fontPath}`);
|
|
734
|
+
registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(bytes));
|
|
735
|
+
let binary = "";
|
|
736
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
737
|
+
base64Font = btoa(binary);
|
|
738
|
+
fontCache.set(cacheKey, base64Font);
|
|
739
|
+
} else if (!registeredVariantCoverage.has(variantKey(fontName, resolvedWeight, isItalic))) {
|
|
740
|
+
registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(base64ToBytes(base64Font)));
|
|
741
|
+
}
|
|
742
|
+
const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;
|
|
743
|
+
pdf.addFileToVFS(fileName, base64Font);
|
|
744
|
+
pdf.addFont(fileName, jsPdfFontName, "normal");
|
|
745
|
+
if (fontName !== jsPdfFontName) {
|
|
746
|
+
try {
|
|
747
|
+
pdf.addFont(fileName, fontName, "normal");
|
|
748
|
+
} catch {
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
registeredFamilies.add(fontName);
|
|
752
|
+
registeredVariants.add(variantKey(fontName, resolvedWeight, isItalic));
|
|
753
|
+
return true;
|
|
754
|
+
} catch (error) {
|
|
755
|
+
console.error(`Failed to embed font ${fontName} (weight ${weight}, italic=${isItalic}):`, error);
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
const isFontAvailable = (fontName) => {
|
|
760
|
+
return fontName in FONT_FILES;
|
|
761
|
+
};
|
|
540
762
|
async function fetchGoogleFontTTF(fontFamily, weight = 400, isItalic = false) {
|
|
541
763
|
const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
|
|
542
|
-
if (fontCache
|
|
764
|
+
if (fontCache.has(cacheKey)) return fontCache.get(cacheKey);
|
|
543
765
|
const notFoundKey = remoteVariantKey(fontFamily, weight, isItalic);
|
|
544
766
|
if (googleFontNotFound.has(notFoundKey)) return null;
|
|
545
767
|
const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, "google");
|
|
546
768
|
if (proxyBytes && isJsPdfEmbeddableTrueType(proxyBytes)) {
|
|
547
|
-
fontBytesCache
|
|
769
|
+
fontBytesCache.set(cacheKey, proxyBytes);
|
|
548
770
|
let binary = "";
|
|
549
771
|
for (let i = 0; i < proxyBytes.length; i++) binary += String.fromCharCode(proxyBytes[i]);
|
|
550
772
|
const b64 = btoa(binary);
|
|
551
|
-
fontCache
|
|
773
|
+
fontCache.set(cacheKey, b64);
|
|
552
774
|
return b64;
|
|
553
775
|
}
|
|
554
776
|
try {
|
|
@@ -578,11 +800,11 @@ async function fetchGoogleFontTTF(fontFamily, weight = 400, isItalic = false) {
|
|
|
578
800
|
console.warn(`[pdfFonts] Google Fonts returned a non-TTF font for ${fontFamily} (${weight}); skipping jsPDF embed`);
|
|
579
801
|
return null;
|
|
580
802
|
}
|
|
581
|
-
fontBytesCache
|
|
803
|
+
fontBytesCache.set(cacheKey, bytes);
|
|
582
804
|
let binary = "";
|
|
583
805
|
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
584
806
|
const b64 = btoa(binary);
|
|
585
|
-
fontCache
|
|
807
|
+
fontCache.set(cacheKey, b64);
|
|
586
808
|
return b64;
|
|
587
809
|
} catch (err) {
|
|
588
810
|
console.warn(`[pdfFonts] fetchGoogleFontTTF failed for ${fontFamily} (${weight}):`, err);
|
|
@@ -591,9 +813,9 @@ async function fetchGoogleFontTTF(fontFamily, weight = 400, isItalic = false) {
|
|
|
591
813
|
}
|
|
592
814
|
async function getGoogleFontBytes(fontFamily, weight = 400, isItalic = false) {
|
|
593
815
|
const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
|
|
594
|
-
if (fontBytesCache
|
|
816
|
+
if (fontBytesCache.has(cacheKey)) return fontBytesCache.get(cacheKey);
|
|
595
817
|
await fetchGoogleFontTTF(fontFamily, weight, isItalic);
|
|
596
|
-
return fontBytesCache
|
|
818
|
+
return fontBytesCache.get(cacheKey) || null;
|
|
597
819
|
}
|
|
598
820
|
const fontshareNotFound = /* @__PURE__ */ new Set();
|
|
599
821
|
function toFontshareSlug(family) {
|
|
@@ -601,15 +823,15 @@ function toFontshareSlug(family) {
|
|
|
601
823
|
}
|
|
602
824
|
async function fetchFontshareTTF(fontFamily, weight = 400, isItalic = false, slug) {
|
|
603
825
|
const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
|
|
604
|
-
if (fontCache
|
|
826
|
+
if (fontCache.has(cacheKey)) return fontCache.get(cacheKey);
|
|
605
827
|
if (fontshareNotFound.has(fontFamily)) return null;
|
|
606
828
|
const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, "fontshare");
|
|
607
829
|
if (proxyBytes && isJsPdfEmbeddableTrueType(proxyBytes)) {
|
|
608
|
-
fontBytesCache
|
|
830
|
+
fontBytesCache.set(cacheKey, proxyBytes);
|
|
609
831
|
let binary = "";
|
|
610
832
|
for (let i = 0; i < proxyBytes.length; i++) binary += String.fromCharCode(proxyBytes[i]);
|
|
611
833
|
const b64 = btoa(binary);
|
|
612
|
-
fontCache
|
|
834
|
+
fontCache.set(cacheKey, b64);
|
|
613
835
|
return b64;
|
|
614
836
|
}
|
|
615
837
|
const finalSlug = toFontshareSlug(fontFamily);
|
|
@@ -637,11 +859,11 @@ async function fetchFontshareTTF(fontFamily, weight = 400, isItalic = false, slu
|
|
|
637
859
|
console.warn(`[pdfFonts] Fontshare returned a non-TTF font for ${fontFamily} (${weight}); skipping jsPDF embed`);
|
|
638
860
|
return null;
|
|
639
861
|
}
|
|
640
|
-
fontBytesCache
|
|
862
|
+
fontBytesCache.set(cacheKey, bytes);
|
|
641
863
|
let binary = "";
|
|
642
864
|
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
643
865
|
const b64 = btoa(binary);
|
|
644
|
-
fontCache
|
|
866
|
+
fontCache.set(cacheKey, b64);
|
|
645
867
|
return b64;
|
|
646
868
|
} catch (err) {
|
|
647
869
|
console.warn(`[pdfFonts] fetchFontshareTTF failed for ${fontFamily} (${weight}):`, err);
|
|
@@ -650,9 +872,55 @@ async function fetchFontshareTTF(fontFamily, weight = 400, isItalic = false, slu
|
|
|
650
872
|
}
|
|
651
873
|
async function getFontshareFontBytes(fontFamily, weight = 400, isItalic = false, slug) {
|
|
652
874
|
const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
|
|
653
|
-
if (fontBytesCache
|
|
875
|
+
if (fontBytesCache.has(cacheKey)) return fontBytesCache.get(cacheKey);
|
|
654
876
|
await fetchFontshareTTF(fontFamily, weight, isItalic);
|
|
655
|
-
return fontBytesCache
|
|
877
|
+
return fontBytesCache.get(cacheKey) || null;
|
|
878
|
+
}
|
|
879
|
+
const embedFontWithGoogleFallback = async (pdf, fontName, weight = 400, isItalic = false) => {
|
|
880
|
+
if (FONT_FILES[fontName]) {
|
|
881
|
+
const ok = await embedFont(pdf, fontName, weight, isItalic);
|
|
882
|
+
if (ok) return true;
|
|
883
|
+
}
|
|
884
|
+
const resolvedFs = resolveFontWeight(weight);
|
|
885
|
+
const fsB64 = await fetchFontshareTTF(fontName, resolvedFs, isItalic);
|
|
886
|
+
if (fsB64) {
|
|
887
|
+
return registerJsPdfFont(pdf, fontName, resolvedFs, isItalic, fsB64);
|
|
888
|
+
}
|
|
889
|
+
const resolved = resolveFontWeight(weight);
|
|
890
|
+
const b64 = await fetchGoogleFontTTF(fontName, resolved, isItalic);
|
|
891
|
+
if (!b64) {
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
return registerJsPdfFont(pdf, fontName, resolved, isItalic, b64);
|
|
895
|
+
};
|
|
896
|
+
function registerJsPdfFont(pdf, fontName, resolvedWeight, isItalic, base64) {
|
|
897
|
+
const label = FONT_WEIGHT_LABELS[resolvedWeight];
|
|
898
|
+
const italicSuffix = isItalic ? "Italic" : "";
|
|
899
|
+
const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, resolvedWeight, isItalic);
|
|
900
|
+
const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;
|
|
901
|
+
try {
|
|
902
|
+
try {
|
|
903
|
+
const binary = atob(base64);
|
|
904
|
+
const bytes = new Uint8Array(binary.length);
|
|
905
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
906
|
+
registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(bytes));
|
|
907
|
+
} catch {
|
|
908
|
+
}
|
|
909
|
+
pdf.addFileToVFS(fileName, base64);
|
|
910
|
+
pdf.addFont(fileName, jsPdfFontName, "normal");
|
|
911
|
+
if (fontName !== jsPdfFontName) {
|
|
912
|
+
try {
|
|
913
|
+
pdf.addFont(fileName, fontName, "normal");
|
|
914
|
+
} catch {
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
registeredFamilies.add(fontName);
|
|
918
|
+
registeredVariants.add(variantKey(fontName, resolvedWeight, isItalic));
|
|
919
|
+
return true;
|
|
920
|
+
} catch (err) {
|
|
921
|
+
console.warn(`[pdfFonts] registerJsPdfFont failed for ${fontName}:`, err);
|
|
922
|
+
return false;
|
|
923
|
+
}
|
|
656
924
|
}
|
|
657
925
|
const LATIN_TO_DEVANAGARI = {
|
|
658
926
|
// Direct Devanagari subsets — same family carries both scripts
|
|
@@ -728,627 +996,18 @@ function resolveDevanagariSibling(latinFont) {
|
|
|
728
996
|
if (!latinFont) return FONT_FALLBACK_DEVANAGARI;
|
|
729
997
|
return LATIN_TO_DEVANAGARI[latinFont] || FONT_FALLBACK_DEVANAGARI;
|
|
730
998
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
return hbjs(moduleInstance);
|
|
747
|
-
})();
|
|
748
|
-
return hbInstancePromise;
|
|
749
|
-
}
|
|
750
|
-
const hbFontCache = /* @__PURE__ */ new Map();
|
|
751
|
-
async function getHBFont(cacheKey, fontDataLoader) {
|
|
752
|
-
const cached = hbFontCache.get(cacheKey);
|
|
753
|
-
if (cached) return { font: cached.font, upem: cached.upem };
|
|
754
|
-
const hb = await getHB();
|
|
755
|
-
const fontData = await fontDataLoader();
|
|
756
|
-
const blob = hb.createBlob(fontData);
|
|
757
|
-
const face = hb.createFace(blob, 0);
|
|
758
|
-
const font = hb.createFont(face);
|
|
759
|
-
const upem = (face.getUpem ? face.getUpem() : face.upem ?? 1e3) || 1e3;
|
|
760
|
-
font.setScale(upem, upem);
|
|
761
|
-
blob.destroy();
|
|
762
|
-
hbFontCache.set(cacheKey, { face, font, upem });
|
|
763
|
-
return { font, upem };
|
|
764
|
-
}
|
|
765
|
-
async function shapeRunToSvgPath(fontData, cacheKey, text, x, y, fontSize, opts) {
|
|
766
|
-
const hb = await getHB();
|
|
767
|
-
const loader = typeof fontData === "function" ? fontData : async () => fontData;
|
|
768
|
-
const { font, upem } = await getHBFont(cacheKey, loader);
|
|
769
|
-
const buffer = hb.createBuffer();
|
|
770
|
-
buffer.addText(text);
|
|
771
|
-
if (opts == null ? void 0 : opts.direction) buffer.setDirection(opts.direction);
|
|
772
|
-
if (opts == null ? void 0 : opts.script) buffer.setScript(opts.script);
|
|
773
|
-
if (opts == null ? void 0 : opts.language) buffer.setLanguage(opts.language);
|
|
774
|
-
buffer.guessSegmentProperties();
|
|
775
|
-
hb.shape(font, buffer);
|
|
776
|
-
const glyphs = buffer.json();
|
|
777
|
-
const scale = fontSize / upem;
|
|
778
|
-
let penX = 0;
|
|
779
|
-
let penY = 0;
|
|
780
|
-
const pieces = [];
|
|
781
|
-
for (const g of glyphs) {
|
|
782
|
-
const rawPath = font.glyphToPath(g.g);
|
|
783
|
-
if (rawPath) {
|
|
784
|
-
const ox = (penX + g.dx) * scale + x;
|
|
785
|
-
const oy = (penY + g.dy) * -scale + y;
|
|
786
|
-
pieces.push(transformPathData(rawPath, scale, -scale, ox, oy));
|
|
787
|
-
}
|
|
788
|
-
penX += g.ax;
|
|
789
|
-
penY += g.ay;
|
|
790
|
-
}
|
|
791
|
-
buffer.destroy();
|
|
792
|
-
return {
|
|
793
|
-
pathData: pieces.join(""),
|
|
794
|
-
width: penX * scale
|
|
795
|
-
};
|
|
796
|
-
}
|
|
797
|
-
function transformPathData(d, sx, sy, tx, ty) {
|
|
798
|
-
let out = "";
|
|
799
|
-
let i = 0;
|
|
800
|
-
const n = d.length;
|
|
801
|
-
while (i < n) {
|
|
802
|
-
const c = d[i];
|
|
803
|
-
if (c === "M" || c === "L" || c === "C" || c === "Q") {
|
|
804
|
-
out += c;
|
|
805
|
-
i++;
|
|
806
|
-
let pairsBuf = "";
|
|
807
|
-
while (i < n && d[i] !== "M" && d[i] !== "L" && d[i] !== "C" && d[i] !== "Q" && d[i] !== "Z") {
|
|
808
|
-
pairsBuf += d[i];
|
|
809
|
-
i++;
|
|
810
|
-
}
|
|
811
|
-
const nums = pairsBuf.trim().split(/[ ,]+/).filter(Boolean).map(Number);
|
|
812
|
-
for (let k = 0; k < nums.length; k += 2) {
|
|
813
|
-
const px = nums[k] * sx + tx;
|
|
814
|
-
const py = nums[k + 1] * sy + ty;
|
|
815
|
-
if (k > 0) out += " ";
|
|
816
|
-
out += `${round(px)},${round(py)}`;
|
|
817
|
-
}
|
|
818
|
-
} else if (c === "Z") {
|
|
819
|
-
out += "Z";
|
|
820
|
-
i++;
|
|
821
|
-
} else {
|
|
822
|
-
i++;
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
return out;
|
|
826
|
-
}
|
|
827
|
-
function round(n) {
|
|
828
|
-
return (Math.round(n * 100) / 100).toString();
|
|
829
|
-
}
|
|
830
|
-
const fontCache = /* @__PURE__ */ new Map();
|
|
831
|
-
const fontBytesCache = /* @__PURE__ */ new Map();
|
|
832
|
-
function isDevanagari(char) {
|
|
833
|
-
const c = char.codePointAt(0) ?? 0;
|
|
834
|
-
return c >= 2304 && c <= 2431 || c >= 43232 && c <= 43263 || c >= 7376 && c <= 7423;
|
|
835
|
-
}
|
|
836
|
-
function containsDevanagari(text) {
|
|
837
|
-
if (!text) return false;
|
|
838
|
-
for (const char of text) {
|
|
839
|
-
if (isDevanagari(char)) return true;
|
|
840
|
-
}
|
|
841
|
-
return false;
|
|
842
|
-
}
|
|
843
|
-
function isBasicLatinOrLatinExtended(char) {
|
|
844
|
-
const c = char.codePointAt(0) ?? 0;
|
|
845
|
-
return c <= 591;
|
|
846
|
-
}
|
|
847
|
-
function isMathOperatorChar(char) {
|
|
848
|
-
const c = char.codePointAt(0) ?? 0;
|
|
849
|
-
if (c >= 8592 && c <= 8703) return true;
|
|
850
|
-
if (c >= 8704 && c <= 8959) return true;
|
|
851
|
-
if (c >= 8960 && c <= 9215) return true;
|
|
852
|
-
if (c >= 10176 && c <= 10223) return true;
|
|
853
|
-
if (c >= 10624 && c <= 10751) return true;
|
|
854
|
-
if (c >= 10752 && c <= 11007) return true;
|
|
855
|
-
if (c >= 11008 && c <= 11097) return true;
|
|
856
|
-
return false;
|
|
857
|
-
}
|
|
858
|
-
function classifyCharForFontRun(char) {
|
|
859
|
-
if (isBasicLatinOrLatinExtended(char)) return "main";
|
|
860
|
-
if (isDevanagari(char)) return "devanagari";
|
|
861
|
-
if (isMathOperatorChar(char)) return "math";
|
|
862
|
-
return "symbol";
|
|
863
|
-
}
|
|
864
|
-
function isIgnorableForCoverage(char) {
|
|
865
|
-
return /\s/.test(char) || /[\u0964\u0965\u200c\u200d]/u.test(char);
|
|
866
|
-
}
|
|
867
|
-
function fontSupportsRun(font, text, runType) {
|
|
868
|
-
if (!font) return false;
|
|
869
|
-
for (const char of text) {
|
|
870
|
-
if (isIgnorableForCoverage(char)) continue;
|
|
871
|
-
if (runType === "devanagari" && !isDevanagari(char)) continue;
|
|
872
|
-
if (runType === "symbol" && classifyCharForFontRun(char) !== "symbol") continue;
|
|
873
|
-
if (runType === "math" && classifyCharForFontRun(char) !== "math") continue;
|
|
874
|
-
const glyph = font.charToGlyph(char);
|
|
875
|
-
if (!glyph || glyph.index === 0) return false;
|
|
876
|
-
}
|
|
877
|
-
return true;
|
|
878
|
-
}
|
|
879
|
-
const browserMeasureCanvas = typeof document !== "undefined" ? document.createElement("canvas") : null;
|
|
880
|
-
function measureBrowserWidth(fontFamily, weight, fontSize, text) {
|
|
881
|
-
const ctx = browserMeasureCanvas == null ? void 0 : browserMeasureCanvas.getContext("2d");
|
|
882
|
-
if (!ctx) return null;
|
|
883
|
-
ctx.font = `normal normal ${weight} ${fontSize}px "${fontFamily}"`;
|
|
884
|
-
return ctx.measureText(text).width;
|
|
885
|
-
}
|
|
886
|
-
function uniqueFamilies(families) {
|
|
887
|
-
const seen = /* @__PURE__ */ new Set();
|
|
888
|
-
const out = [];
|
|
889
|
-
for (const family of families) {
|
|
890
|
-
const clean = family == null ? void 0 : family.trim();
|
|
891
|
-
if (!clean || seen.has(clean)) continue;
|
|
892
|
-
seen.add(clean);
|
|
893
|
-
out.push(clean);
|
|
894
|
-
}
|
|
895
|
-
return out;
|
|
896
|
-
}
|
|
897
|
-
function fontLooksItalic(font) {
|
|
898
|
-
var _a, _b, _c, _d;
|
|
899
|
-
if (!font) return false;
|
|
900
|
-
const names = font.names;
|
|
901
|
-
const candidates = [
|
|
902
|
-
(_a = names.fontSubfamily) == null ? void 0 : _a.en,
|
|
903
|
-
(_b = names.typographicSubfamily) == null ? void 0 : _b.en,
|
|
904
|
-
(_c = names.fullName) == null ? void 0 : _c.en,
|
|
905
|
-
(_d = names.postScriptName) == null ? void 0 : _d.en
|
|
906
|
-
].filter(Boolean).join(" ");
|
|
907
|
-
return /italic|oblique/i.test(candidates);
|
|
908
|
-
}
|
|
909
|
-
function syntheticItalicTransform(anchorX, baselineY) {
|
|
910
|
-
return `translate(${anchorX} ${baselineY}) skewX(-12) translate(${-anchorX} ${-baselineY})`;
|
|
911
|
-
}
|
|
912
|
-
function getFontPath(fontFiles, weight, isItalic = false) {
|
|
913
|
-
const resolved = resolveFontWeight(weight);
|
|
914
|
-
const uprightMap = {
|
|
915
|
-
300: ["light", "regular"],
|
|
916
|
-
400: ["regular"],
|
|
917
|
-
500: ["medium", "regular"],
|
|
918
|
-
600: ["semibold", "bold"],
|
|
919
|
-
700: ["bold", "semibold", "regular"]
|
|
920
|
-
};
|
|
921
|
-
const italicMap = {
|
|
922
|
-
300: ["lightItalic", "italic", "light", "regular"],
|
|
923
|
-
400: ["italic", "regular"],
|
|
924
|
-
500: ["mediumItalic", "italic", "medium", "regular"],
|
|
925
|
-
600: ["semiboldItalic", "boldItalic", "italic", "semibold", "bold", "regular"],
|
|
926
|
-
700: ["boldItalic", "semiboldItalic", "italic", "bold", "semibold", "regular"]
|
|
927
|
-
};
|
|
928
|
-
const map = isItalic ? italicMap : uprightMap;
|
|
929
|
-
for (const key of map[resolved] || ["regular"]) {
|
|
930
|
-
if (fontFiles[key]) return fontFiles[key];
|
|
931
|
-
}
|
|
932
|
-
return fontFiles.regular || null;
|
|
933
|
-
}
|
|
934
|
-
function resolveFontUrl(fileName, fontBaseUrl) {
|
|
935
|
-
if (/^https?:\/\//i.test(fileName) || fileName.startsWith("data:")) return fileName;
|
|
936
|
-
if (fileName.startsWith("/")) {
|
|
937
|
-
return typeof window !== "undefined" ? new URL(fileName, window.location.origin).toString() : fileName;
|
|
938
|
-
}
|
|
939
|
-
const baseUrl = fontBaseUrl.endsWith("/") ? fontBaseUrl : fontBaseUrl + "/";
|
|
940
|
-
return new URL(fileName, baseUrl).toString();
|
|
941
|
-
}
|
|
942
|
-
async function loadFont(fontFamily, weight, fontBaseUrl, isItalic = false) {
|
|
943
|
-
const cacheKey = `${fontFamily}__${weight}__${isItalic ? "i" : "n"}`;
|
|
944
|
-
if (fontCache.has(cacheKey)) return fontCache.get(cacheKey);
|
|
945
|
-
const fontFiles = FONT_FILES[fontFamily];
|
|
946
|
-
if (fontFiles) {
|
|
947
|
-
const fileName = getFontPath(fontFiles, weight, isItalic);
|
|
948
|
-
if (!fileName) return null;
|
|
949
|
-
const url = resolveFontUrl(fileName, fontBaseUrl);
|
|
950
|
-
try {
|
|
951
|
-
const response = await fetch(url);
|
|
952
|
-
if (!response.ok) {
|
|
953
|
-
console.warn(`[text-to-path] Failed to fetch font ${url}: ${response.status}`);
|
|
954
|
-
return null;
|
|
955
|
-
}
|
|
956
|
-
const buffer = await response.arrayBuffer();
|
|
957
|
-
const bytes = new Uint8Array(buffer);
|
|
958
|
-
fontBytesCache.set(cacheKey, bytes);
|
|
959
|
-
const font = opentype.parse(buffer);
|
|
960
|
-
fontCache.set(cacheKey, font);
|
|
961
|
-
return font;
|
|
962
|
-
} catch (err) {
|
|
963
|
-
console.warn(`[text-to-path] Failed to load local font ${fontFamily}:`, err);
|
|
964
|
-
return null;
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
try {
|
|
968
|
-
const resolvedWeight = resolveFontWeight(weight);
|
|
969
|
-
let bytes = await getGoogleFontBytes(fontFamily, resolvedWeight, isItalic);
|
|
970
|
-
if (!bytes) {
|
|
971
|
-
bytes = await getFontshareFontBytes(fontFamily, resolvedWeight, isItalic);
|
|
972
|
-
}
|
|
973
|
-
if (!bytes && isItalic) {
|
|
974
|
-
bytes = await getGoogleFontBytes(fontFamily, resolvedWeight, false);
|
|
975
|
-
if (!bytes) bytes = await getFontshareFontBytes(fontFamily, resolvedWeight, false);
|
|
976
|
-
}
|
|
977
|
-
if (!bytes) {
|
|
978
|
-
console.warn(`[text-to-path] No TTF available for ${fontFamily} (${weight}) on Google Fonts or Fontshare`);
|
|
979
|
-
return null;
|
|
980
|
-
}
|
|
981
|
-
fontBytesCache.set(cacheKey, bytes);
|
|
982
|
-
const ab = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
983
|
-
const font = opentype.parse(ab);
|
|
984
|
-
fontCache.set(cacheKey, font);
|
|
985
|
-
return font;
|
|
986
|
-
} catch (err) {
|
|
987
|
-
console.warn(`[text-to-path] Failed to load Google font ${fontFamily}:`, err);
|
|
988
|
-
return null;
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
async function getFontBytes(fontFamily, weight, fontBaseUrl, isItalic = false) {
|
|
992
|
-
const cacheKey = `${fontFamily}__${weight}__${isItalic ? "i" : "n"}`;
|
|
993
|
-
if (!fontBytesCache.has(cacheKey)) {
|
|
994
|
-
await loadFont(fontFamily, weight, fontBaseUrl, isItalic);
|
|
995
|
-
}
|
|
996
|
-
const bytes = fontBytesCache.get(cacheKey);
|
|
997
|
-
return bytes ? { bytes, cacheKey } : null;
|
|
998
|
-
}
|
|
999
|
-
function measureRunWidth(font, text, fontSize) {
|
|
1000
|
-
try {
|
|
1001
|
-
return font.getAdvanceWidth(text, fontSize, { kerning: true });
|
|
1002
|
-
} catch {
|
|
1003
|
-
try {
|
|
1004
|
-
return font.getAdvanceWidth(text, fontSize);
|
|
1005
|
-
} catch {
|
|
1006
|
-
return text.length * fontSize * 0.5;
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
function splitByFontRun(text) {
|
|
1011
|
-
if (!text) return [];
|
|
1012
|
-
const runs = [];
|
|
1013
|
-
let buf = "";
|
|
1014
|
-
let bufType = classifyCharForFontRun(text[0]);
|
|
1015
|
-
for (const ch of text) {
|
|
1016
|
-
const chType = classifyCharForFontRun(ch);
|
|
1017
|
-
const isNeutral = /\s/.test(ch);
|
|
1018
|
-
if (chType === bufType || isNeutral) {
|
|
1019
|
-
buf += ch;
|
|
1020
|
-
} else {
|
|
1021
|
-
if (buf) runs.push({ text: buf, runType: bufType });
|
|
1022
|
-
buf = ch;
|
|
1023
|
-
bufType = chType;
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
if (buf) runs.push({ text: buf, runType: bufType });
|
|
1027
|
-
return runs;
|
|
1028
|
-
}
|
|
1029
|
-
async function shapeRunToPath(run, isDeva, primaryFont, primaryBytes, devaFont, devaBytes, x, y, fontSize) {
|
|
1030
|
-
if (isDeva && devaBytes && devaFont) {
|
|
1031
|
-
try {
|
|
1032
|
-
const shaped = await shapeRunToSvgPath(
|
|
1033
|
-
devaBytes.bytes,
|
|
1034
|
-
devaBytes.cacheKey,
|
|
1035
|
-
run,
|
|
1036
|
-
x,
|
|
1037
|
-
y,
|
|
1038
|
-
fontSize,
|
|
1039
|
-
{ script: "deva", language: "hin", direction: "ltr" }
|
|
1040
|
-
);
|
|
1041
|
-
if (shaped.pathData) {
|
|
1042
|
-
const advance = measureRunWidth(devaFont, run, fontSize);
|
|
1043
|
-
return { pathData: shaped.pathData, advance };
|
|
1044
|
-
}
|
|
1045
|
-
} catch (err) {
|
|
1046
|
-
console.warn(`[text-to-path] HarfBuzz failed for "${run}":`, err);
|
|
1047
|
-
}
|
|
1048
|
-
try {
|
|
1049
|
-
const path = devaFont.getPath(run, x, y, fontSize);
|
|
1050
|
-
const d = path.toPathData(2);
|
|
1051
|
-
if (d && d !== "M0 0") return { pathData: d, advance: measureRunWidth(devaFont, run, fontSize) };
|
|
1052
|
-
} catch {
|
|
1053
|
-
}
|
|
1054
|
-
return null;
|
|
1055
|
-
}
|
|
1056
|
-
try {
|
|
1057
|
-
const path = primaryFont.getPath(run, x, y, fontSize, { kerning: true });
|
|
1058
|
-
const d = path.toPathData(2);
|
|
1059
|
-
if (d && d !== "M0 0") return { pathData: d, advance: measureRunWidth(primaryFont, run, fontSize) };
|
|
1060
|
-
return { pathData: "", advance: measureRunWidth(primaryFont, run, fontSize) };
|
|
1061
|
-
} catch (err) {
|
|
1062
|
-
console.warn(`[text-to-path] opentype getPath failed for "${run}":`, err);
|
|
1063
|
-
return null;
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
function parseTranslate(transform) {
|
|
1067
|
-
if (!transform) return { tx: 0, ty: 0 };
|
|
1068
|
-
const m = transform.match(/translate\(\s*([-\d.]+)[ \s,]+([-\d.]+)\s*\)/);
|
|
1069
|
-
if (m) return { tx: parseFloat(m[1]), ty: parseFloat(m[2]) };
|
|
1070
|
-
const mm = transform.match(/matrix\(\s*([-\d.]+)[ \s,]+([-\d.]+)[ \s,]+([-\d.]+)[ \s,]+([-\d.]+)[ \s,]+([-\d.]+)[ \s,]+([-\d.]+)\s*\)/);
|
|
1071
|
-
if (mm) return { tx: parseFloat(mm[5]), ty: parseFloat(mm[6]) };
|
|
1072
|
-
return { tx: 0, ty: 0 };
|
|
1073
|
-
}
|
|
1074
|
-
function needsComplexShaping(text) {
|
|
1075
|
-
if (!text) return false;
|
|
1076
|
-
for (const ch of text) {
|
|
1077
|
-
const c = ch.codePointAt(0) ?? 0;
|
|
1078
|
-
if (c >= 2304 && c <= 2431 || c >= 43232 && c <= 43263 || c >= 7376 && c <= 7423) return true;
|
|
1079
|
-
if (c >= 2432 && c <= 3583) return true;
|
|
1080
|
-
if (c >= 3584 && c <= 4095) return true;
|
|
1081
|
-
if (c >= 4096 && c <= 4255) return true;
|
|
1082
|
-
if (c >= 6016 && c <= 6143) return true;
|
|
1083
|
-
if (c >= 1424 && c <= 1791) return true;
|
|
1084
|
-
if (c >= 1792 && c <= 1871) return true;
|
|
1085
|
-
if (c >= 12288 && c <= 40959) return true;
|
|
1086
|
-
if (c >= 44032 && c <= 55215) return true;
|
|
1087
|
-
if (c >= 126976) return true;
|
|
1088
|
-
if (c >= 8592 && c <= 8703) return true;
|
|
1089
|
-
if (c >= 8704 && c <= 8959) return true;
|
|
1090
|
-
if (c >= 8960 && c <= 9215) return true;
|
|
1091
|
-
if (c >= 10176 && c <= 10223) return true;
|
|
1092
|
-
if (c >= 10624 && c <= 10751) return true;
|
|
1093
|
-
if (c >= 10752 && c <= 11007) return true;
|
|
1094
|
-
if (c >= 11008 && c <= 11097) return true;
|
|
1095
|
-
}
|
|
1096
|
-
return false;
|
|
1097
|
-
}
|
|
1098
|
-
async function convertDevanagariTextToPath(svgStr, fontBaseUrl, options = {}) {
|
|
1099
|
-
var _a, _b, _c;
|
|
1100
|
-
const baseUrl = fontBaseUrl ?? (typeof window !== "undefined" ? window.location.origin + "/fonts/" : "/fonts/");
|
|
1101
|
-
const mode = options.mode ?? "all";
|
|
1102
|
-
const parser = new DOMParser();
|
|
1103
|
-
const doc = parser.parseFromString(svgStr, "image/svg+xml");
|
|
1104
|
-
const textEls = doc.querySelectorAll("text");
|
|
1105
|
-
let convertedCount = 0;
|
|
1106
|
-
let skippedCount = 0;
|
|
1107
|
-
for (const textEl of textEls) {
|
|
1108
|
-
const fullText = textEl.textContent || "";
|
|
1109
|
-
if (!fullText.trim()) continue;
|
|
1110
|
-
const hasMixedStyleTspans = () => {
|
|
1111
|
-
const tspansAll = textEl.querySelectorAll("tspan");
|
|
1112
|
-
const readProp = (el, prop) => {
|
|
1113
|
-
const attr = (el.getAttribute(prop) || "").trim();
|
|
1114
|
-
if (attr) return attr;
|
|
1115
|
-
const style = el.getAttribute("style") || "";
|
|
1116
|
-
const m = style.match(new RegExp(`(?:^|;)\\s*${prop}\\s*:\\s*([^;]+)`, "i"));
|
|
1117
|
-
return m ? m[1].trim() : "";
|
|
1118
|
-
};
|
|
1119
|
-
const baseWeight = readProp(textEl, "font-weight");
|
|
1120
|
-
const baseStyle = readProp(textEl, "font-style");
|
|
1121
|
-
const baseFill = readProp(textEl, "fill");
|
|
1122
|
-
const baseDeco = readProp(textEl, "text-decoration");
|
|
1123
|
-
for (const ts of tspansAll) {
|
|
1124
|
-
const tw = readProp(ts, "font-weight");
|
|
1125
|
-
const tst = readProp(ts, "font-style");
|
|
1126
|
-
const tFill = readProp(ts, "fill");
|
|
1127
|
-
const tDeco = readProp(ts, "text-decoration");
|
|
1128
|
-
const tBg = (ts.getAttribute("style") || "").match(/background|text-background/i);
|
|
1129
|
-
if (tw && tw !== baseWeight || tst && tst !== baseStyle || tFill && tFill !== baseFill || tDeco && tDeco !== baseDeco || tBg) {
|
|
1130
|
-
return true;
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
return false;
|
|
1134
|
-
};
|
|
1135
|
-
if (mode === "complex-only" && !needsComplexShaping(fullText) && !hasMixedStyleTspans()) {
|
|
1136
|
-
skippedCount++;
|
|
1137
|
-
continue;
|
|
1138
|
-
}
|
|
1139
|
-
if (mode === "mixed-style-only" && !hasMixedStyleTspans()) {
|
|
1140
|
-
skippedCount++;
|
|
1141
|
-
continue;
|
|
1142
|
-
}
|
|
1143
|
-
const readStyleToken = (style, prop) => {
|
|
1144
|
-
var _a2;
|
|
1145
|
-
const m = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
|
|
1146
|
-
return ((_a2 = m == null ? void 0 : m[1]) == null ? void 0 : _a2.trim()) || null;
|
|
1147
|
-
};
|
|
1148
|
-
const getAttrOrStyle = (el, attr) => {
|
|
1149
|
-
var _a2;
|
|
1150
|
-
let current = el;
|
|
1151
|
-
while (current) {
|
|
1152
|
-
const attrVal = (_a2 = current.getAttribute(attr)) == null ? void 0 : _a2.trim();
|
|
1153
|
-
if (attrVal) return attrVal;
|
|
1154
|
-
const styleVal = readStyleToken(current.getAttribute("style") || "", attr);
|
|
1155
|
-
if (styleVal) return styleVal;
|
|
1156
|
-
current = current.parentElement;
|
|
1157
|
-
}
|
|
1158
|
-
return null;
|
|
1159
|
-
};
|
|
1160
|
-
const fontFamily = (_b = (_a = getAttrOrStyle(textEl, "font-family")) == null ? void 0 : _a.split(",")[0]) == null ? void 0 : _b.replace(/['"]/g, "").trim();
|
|
1161
|
-
const fontSizeStr = getAttrOrStyle(textEl, "font-size") || "16";
|
|
1162
|
-
const fontSize = parseFloat(fontSizeStr);
|
|
1163
|
-
const fontWeightStr = getAttrOrStyle(textEl, "font-weight") || "400";
|
|
1164
|
-
const fontWeight = Number.parseInt(fontWeightStr, 10) || 400;
|
|
1165
|
-
const fillColor = getAttrOrStyle(textEl, "fill") || "#000000";
|
|
1166
|
-
const fillOpacity = getAttrOrStyle(textEl, "fill-opacity") || "1";
|
|
1167
|
-
if (!fontFamily) {
|
|
1168
|
-
skippedCount++;
|
|
1169
|
-
continue;
|
|
1170
|
-
}
|
|
1171
|
-
const primaryFont = await loadFont(fontFamily, fontWeight, baseUrl);
|
|
1172
|
-
const primaryBytes = await getFontBytes(fontFamily, fontWeight, baseUrl);
|
|
1173
|
-
const hasDeva = containsDevanagari(fullText);
|
|
1174
|
-
const hasSymbol = [...fullText].some((char) => classifyCharForFontRun(char) === "symbol");
|
|
1175
|
-
const hasMath = [...fullText].some((char) => classifyCharForFontRun(char) === "math");
|
|
1176
|
-
const devaCandidateFamilies = hasDeva ? uniqueFamilies([fontFamily, FONT_FALLBACK_DEVANAGARI, resolveDevanagariSibling(fontFamily)]) : [];
|
|
1177
|
-
const devaRunFontCache = /* @__PURE__ */ new Map();
|
|
1178
|
-
const resolveDevaFontForRun = (runText, runFontSize) => {
|
|
1179
|
-
const cacheKey = `${runText}__${runFontSize}`;
|
|
1180
|
-
const cached = devaRunFontCache.get(cacheKey);
|
|
1181
|
-
if (cached) return cached;
|
|
1182
|
-
const promise = (async () => {
|
|
1183
|
-
const browserWidth = measureBrowserWidth(fontFamily, fontWeight, runFontSize, runText);
|
|
1184
|
-
let best = null;
|
|
1185
|
-
for (const family of devaCandidateFamilies) {
|
|
1186
|
-
const font = family === fontFamily ? primaryFont : await loadFont(family, fontWeight, baseUrl);
|
|
1187
|
-
const bytes = family === fontFamily ? primaryBytes : await getFontBytes(family, fontWeight, baseUrl);
|
|
1188
|
-
if (!font || !bytes || !fontSupportsRun(font, runText, "devanagari")) continue;
|
|
1189
|
-
const width = measureRunWidth(font, runText, runFontSize);
|
|
1190
|
-
const diff = browserWidth == null ? 0 : Math.abs(width - browserWidth);
|
|
1191
|
-
if (!best || diff < best.diff) best = { family, font, bytes, diff };
|
|
1192
|
-
if (browserWidth != null && diff <= 0.25) break;
|
|
1193
|
-
}
|
|
1194
|
-
if (best) {
|
|
1195
|
-
console.log("[text-to-path] Devanagari font resolved", {
|
|
1196
|
-
requestedFamily: fontFamily,
|
|
1197
|
-
resolvedFamily: best.family,
|
|
1198
|
-
browserWidth,
|
|
1199
|
-
diff: Math.round(best.diff * 100) / 100
|
|
1200
|
-
});
|
|
1201
|
-
}
|
|
1202
|
-
return best;
|
|
1203
|
-
})();
|
|
1204
|
-
devaRunFontCache.set(cacheKey, promise);
|
|
1205
|
-
return promise;
|
|
1206
|
-
};
|
|
1207
|
-
const symbolRunFontPromise = hasSymbol ? (async () => {
|
|
1208
|
-
const symbolFont = await loadFont(FONT_FALLBACK_SYMBOLS, 400, baseUrl);
|
|
1209
|
-
const symbolBytes = await getFontBytes(FONT_FALLBACK_SYMBOLS, 400, baseUrl);
|
|
1210
|
-
return symbolFont && symbolBytes ? { family: FONT_FALLBACK_SYMBOLS, font: symbolFont, bytes: symbolBytes } : null;
|
|
1211
|
-
})() : null;
|
|
1212
|
-
const mathRunFontPromise = hasMath ? (async () => {
|
|
1213
|
-
const mathFont = await loadFont(FONT_FALLBACK_MATH, 400, baseUrl);
|
|
1214
|
-
const mathBytes = await getFontBytes(FONT_FALLBACK_MATH, 400, baseUrl);
|
|
1215
|
-
return mathFont && mathBytes ? { family: FONT_FALLBACK_MATH, font: mathFont, bytes: mathBytes } : null;
|
|
1216
|
-
})() : null;
|
|
1217
|
-
if (!primaryFont && !hasDeva && !hasSymbol && !hasMath) {
|
|
1218
|
-
console.warn(`[text-to-path] No font available for "${fontFamily}", leaving as <text>`);
|
|
1219
|
-
skippedCount++;
|
|
1220
|
-
continue;
|
|
1221
|
-
}
|
|
1222
|
-
const textAnchorRaw = (getAttrOrStyle(textEl, "text-anchor") || "start").toLowerCase();
|
|
1223
|
-
const textAnchor = textAnchorRaw === "middle" ? "middle" : textAnchorRaw === "end" ? "end" : "start";
|
|
1224
|
-
const tspans = textEl.querySelectorAll("tspan");
|
|
1225
|
-
const elementsToProcess = tspans.length > 0 ? Array.from(tspans) : [textEl];
|
|
1226
|
-
const group = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
1227
|
-
const textTransform = textEl.getAttribute("transform");
|
|
1228
|
-
if (textTransform) group.setAttribute("transform", textTransform);
|
|
1229
|
-
const baseX = parseFloat(textEl.getAttribute("x") || "0");
|
|
1230
|
-
const baseY = parseFloat(textEl.getAttribute("y") || "0");
|
|
1231
|
-
for (const elem of elementsToProcess) {
|
|
1232
|
-
const text = elem.textContent || "";
|
|
1233
|
-
if (!text.trim()) continue;
|
|
1234
|
-
const elemX = parseFloat(elem.getAttribute("x") || String(baseX));
|
|
1235
|
-
const elemY = parseFloat(elem.getAttribute("y") || String(baseY));
|
|
1236
|
-
const elemTransform = elem !== textEl ? parseTranslate(elem.getAttribute("transform")) : { tx: 0, ty: 0 };
|
|
1237
|
-
let x = elemX + elemTransform.tx;
|
|
1238
|
-
const y = elemY + elemTransform.ty;
|
|
1239
|
-
const elemFill = getAttrOrStyle(elem, "fill") || fillColor;
|
|
1240
|
-
const elemFillOpacity = getAttrOrStyle(elem, "fill-opacity") || fillOpacity;
|
|
1241
|
-
const elemFontSizeStr = getAttrOrStyle(elem, "font-size") || String(fontSize);
|
|
1242
|
-
const elemFontSize = parseFloat(elemFontSizeStr);
|
|
1243
|
-
const elemWeightStr = getAttrOrStyle(elem, "font-weight") || String(fontWeight);
|
|
1244
|
-
const elemWeight = Number.parseInt(elemWeightStr, 10) || (/bold/i.test(elemWeightStr) ? 700 : fontWeight);
|
|
1245
|
-
const elemStyleRaw = (getAttrOrStyle(elem, "font-style") || "normal").toLowerCase();
|
|
1246
|
-
const elemItalic = /italic|oblique/i.test(elemStyleRaw);
|
|
1247
|
-
const sameAsPrimary = elemWeight === fontWeight && !elemItalic;
|
|
1248
|
-
const elemFont = sameAsPrimary ? primaryFont : await loadFont(fontFamily, elemWeight, baseUrl, elemItalic);
|
|
1249
|
-
const elemBytes = sameAsPrimary ? primaryBytes : await getFontBytes(fontFamily, elemWeight, baseUrl, elemItalic);
|
|
1250
|
-
const fontForElem = elemFont || primaryFont;
|
|
1251
|
-
const bytesForElem = elemBytes || primaryBytes;
|
|
1252
|
-
const runs = splitByFontRun(text);
|
|
1253
|
-
let totalAdvance = 0;
|
|
1254
|
-
let canMeasureAll = true;
|
|
1255
|
-
for (const r of runs) {
|
|
1256
|
-
if (r.runType === "devanagari") {
|
|
1257
|
-
const resolved = await resolveDevaFontForRun(r.text, elemFontSize);
|
|
1258
|
-
if (resolved) totalAdvance += measureRunWidth(resolved.font, r.text, elemFontSize);
|
|
1259
|
-
else canMeasureAll = false;
|
|
1260
|
-
} else if (r.runType === "symbol") {
|
|
1261
|
-
const resolved = await symbolRunFontPromise;
|
|
1262
|
-
if (resolved && fontSupportsRun(resolved.font, r.text, "symbol")) totalAdvance += measureRunWidth(resolved.font, r.text, elemFontSize);
|
|
1263
|
-
else canMeasureAll = false;
|
|
1264
|
-
} else if (r.runType === "math") {
|
|
1265
|
-
const resolved = await mathRunFontPromise;
|
|
1266
|
-
if (resolved && fontSupportsRun(resolved.font, r.text, "math")) totalAdvance += measureRunWidth(resolved.font, r.text, elemFontSize);
|
|
1267
|
-
else canMeasureAll = false;
|
|
1268
|
-
} else {
|
|
1269
|
-
if (fontForElem) totalAdvance += measureRunWidth(fontForElem, r.text, elemFontSize);
|
|
1270
|
-
else canMeasureAll = false;
|
|
1271
|
-
}
|
|
1272
|
-
}
|
|
1273
|
-
if (canMeasureAll) {
|
|
1274
|
-
if (textAnchor === "middle") x -= totalAdvance / 2;
|
|
1275
|
-
else if (textAnchor === "end") x -= totalAdvance;
|
|
1276
|
-
}
|
|
1277
|
-
let cursor = x;
|
|
1278
|
-
let elemConverted = false;
|
|
1279
|
-
for (const r of runs) {
|
|
1280
|
-
const resolvedDeva = r.runType === "devanagari" ? await resolveDevaFontForRun(r.text, elemFontSize) : null;
|
|
1281
|
-
const resolvedSymbol = r.runType === "symbol" ? await symbolRunFontPromise : null;
|
|
1282
|
-
const resolvedMath = r.runType === "math" ? await mathRunFontPromise : null;
|
|
1283
|
-
const useDeva = !!resolvedDeva;
|
|
1284
|
-
const fontForRun = (resolvedDeva == null ? void 0 : resolvedDeva.font) ?? (resolvedSymbol == null ? void 0 : resolvedSymbol.font) ?? (resolvedMath == null ? void 0 : resolvedMath.font) ?? fontForElem;
|
|
1285
|
-
const bytesForRun = (resolvedDeva == null ? void 0 : resolvedDeva.bytes) ?? (resolvedSymbol == null ? void 0 : resolvedSymbol.bytes) ?? (resolvedMath == null ? void 0 : resolvedMath.bytes) ?? bytesForElem;
|
|
1286
|
-
if (!fontForRun) continue;
|
|
1287
|
-
const result = await shapeRunToPath(
|
|
1288
|
-
r.text,
|
|
1289
|
-
!!useDeva,
|
|
1290
|
-
fontForRun,
|
|
1291
|
-
bytesForRun,
|
|
1292
|
-
(resolvedDeva == null ? void 0 : resolvedDeva.font) ?? null,
|
|
1293
|
-
(resolvedDeva == null ? void 0 : resolvedDeva.bytes) ?? null,
|
|
1294
|
-
cursor,
|
|
1295
|
-
y,
|
|
1296
|
-
elemFontSize
|
|
1297
|
-
);
|
|
1298
|
-
if (result && result.pathData) {
|
|
1299
|
-
const pathEl = doc.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
1300
|
-
pathEl.setAttribute("d", result.pathData);
|
|
1301
|
-
pathEl.setAttribute("fill", elemFill);
|
|
1302
|
-
if (elemItalic && !fontLooksItalic(fontForRun)) {
|
|
1303
|
-
pathEl.setAttribute("transform", syntheticItalicTransform(cursor, y));
|
|
1304
|
-
}
|
|
1305
|
-
if (elemFillOpacity !== "1") {
|
|
1306
|
-
pathEl.setAttribute("fill-opacity", elemFillOpacity);
|
|
1307
|
-
}
|
|
1308
|
-
group.appendChild(pathEl);
|
|
1309
|
-
elemConverted = true;
|
|
1310
|
-
}
|
|
1311
|
-
if (result) cursor += result.advance;
|
|
1312
|
-
}
|
|
1313
|
-
if (elemConverted) {
|
|
1314
|
-
convertedCount++;
|
|
1315
|
-
} else {
|
|
1316
|
-
if (elem === textEl) {
|
|
1317
|
-
const clone = elem.cloneNode(true);
|
|
1318
|
-
if (textTransform) clone.removeAttribute("transform");
|
|
1319
|
-
group.appendChild(clone);
|
|
1320
|
-
} else {
|
|
1321
|
-
const newText = doc.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
1322
|
-
newText.setAttribute("x", String(elemX));
|
|
1323
|
-
newText.setAttribute("y", String(elemY));
|
|
1324
|
-
if (elem.getAttribute("style")) newText.setAttribute("style", elem.getAttribute("style"));
|
|
1325
|
-
if (elem.getAttribute("font-family")) newText.setAttribute("font-family", elem.getAttribute("font-family"));
|
|
1326
|
-
if (elem.getAttribute("font-size")) newText.setAttribute("font-size", elem.getAttribute("font-size"));
|
|
1327
|
-
if (elem.getAttribute("font-weight")) newText.setAttribute("font-weight", elem.getAttribute("font-weight"));
|
|
1328
|
-
newText.textContent = text;
|
|
1329
|
-
group.appendChild(newText);
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
if (group.childNodes.length > 0) {
|
|
1334
|
-
(_c = textEl.parentNode) == null ? void 0 : _c.replaceChild(group, textEl);
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
console.log(
|
|
1338
|
-
`[text-to-path] Universal outline complete: converted=${convertedCount} skipped=${skippedCount}`
|
|
1339
|
-
);
|
|
1340
|
-
return new XMLSerializer().serializeToString(doc.documentElement);
|
|
1341
|
-
}
|
|
1342
|
-
const convertAllTextToPath = convertDevanagariTextToPath;
|
|
1343
|
-
async function preloadDevanagariFont(fontBaseUrl) {
|
|
1344
|
-
const baseUrl = fontBaseUrl ?? (typeof window !== "undefined" ? window.location.origin + "/fonts/" : "/fonts/");
|
|
1345
|
-
for (const weight of [300, 400, 500, 600, 700]) {
|
|
1346
|
-
await loadFont(FONT_FALLBACK_DEVANAGARI, weight, baseUrl);
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
export {
|
|
1350
|
-
convertAllTextToPath,
|
|
1351
|
-
convertDevanagariTextToPath,
|
|
1352
|
-
preloadDevanagariFont
|
|
1353
|
-
};
|
|
1354
|
-
//# sourceMappingURL=svgTextToPath-CQ2Tp03U.js.map
|
|
999
|
+
exports.FONT_FALLBACK_DEVANAGARI = FONT_FALLBACK_DEVANAGARI;
|
|
1000
|
+
exports.FONT_FALLBACK_MATH = FONT_FALLBACK_MATH;
|
|
1001
|
+
exports.FONT_FALLBACK_SYMBOLS = FONT_FALLBACK_SYMBOLS;
|
|
1002
|
+
exports.FONT_FILES = FONT_FILES;
|
|
1003
|
+
exports.doesVariantSupportChar = doesVariantSupportChar;
|
|
1004
|
+
exports.embedFontWithGoogleFallback = embedFontWithGoogleFallback;
|
|
1005
|
+
exports.getEmbeddedJsPDFFontName = getEmbeddedJsPDFFontName;
|
|
1006
|
+
exports.getFontshareFontBytes = getFontshareFontBytes;
|
|
1007
|
+
exports.getGoogleFontBytes = getGoogleFontBytes;
|
|
1008
|
+
exports.isFamilyEmbedded = isFamilyEmbedded;
|
|
1009
|
+
exports.isFontAvailable = isFontAvailable;
|
|
1010
|
+
exports.resolveBestRegisteredVariant = resolveBestRegisteredVariant;
|
|
1011
|
+
exports.resolveDevanagariSibling = resolveDevanagariSibling;
|
|
1012
|
+
exports.resolveFontWeight = resolveFontWeight;
|
|
1013
|
+
//# sourceMappingURL=pdfFonts-CHHpRsRK.cjs.map
|