@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,1393 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
for (let key of __getOwnPropNames(from))
|
|
11
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
-
}
|
|
14
|
-
return to;
|
|
15
|
-
};
|
|
16
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
-
mod
|
|
23
|
-
));
|
|
24
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
25
|
-
const opentype = require("opentype.js");
|
|
26
|
-
function _interopNamespaceDefault(e) {
|
|
27
|
-
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
28
|
-
if (e) {
|
|
29
|
-
for (const k in e) {
|
|
30
|
-
if (k !== "default") {
|
|
31
|
-
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
32
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
33
|
-
enumerable: true,
|
|
34
|
-
get: () => e[k]
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
n.default = e;
|
|
40
|
-
return Object.freeze(n);
|
|
41
|
-
}
|
|
42
|
-
const opentype__namespace = /* @__PURE__ */ _interopNamespaceDefault(opentype);
|
|
43
|
-
const __vite_import_meta_env__ = {};
|
|
44
|
-
const fontCache$1 = /* @__PURE__ */ new Map();
|
|
45
|
-
const fontBytesCache$1 = /* @__PURE__ */ new Map();
|
|
46
|
-
const googleFontUrlCache = /* @__PURE__ */ new Map();
|
|
47
|
-
const googleFontNotFound = /* @__PURE__ */ new Set();
|
|
48
|
-
const remoteVariantKey = (family, weight, italic) => `${family}|${resolveFontWeight(weight)}|${italic ? "i" : "n"}`;
|
|
49
|
-
const FONT_PROXY_URL = `${(__vite_import_meta_env__ == null ? void 0 : __vite_import_meta_env__.VITE_SUPABASE_URL) ?? ""}/functions/v1/font-proxy`;
|
|
50
|
-
async function fetchTtfViaProxy(family, weight, isItalic, source) {
|
|
51
|
-
if (!FONT_PROXY_URL || FONT_PROXY_URL.startsWith("/functions")) return null;
|
|
52
|
-
try {
|
|
53
|
-
const url = `${FONT_PROXY_URL}?family=${encodeURIComponent(family)}&weight=${weight}&italic=${isItalic ? 1 : 0}&source=${source}`;
|
|
54
|
-
const res = await fetch(url);
|
|
55
|
-
if (!res.ok) return null;
|
|
56
|
-
const buf = await res.arrayBuffer();
|
|
57
|
-
return new Uint8Array(buf);
|
|
58
|
-
} catch {
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function resolveFontWeight(weight) {
|
|
63
|
-
if (weight <= 350) return 300;
|
|
64
|
-
if (weight <= 450) return 400;
|
|
65
|
-
if (weight <= 550) return 500;
|
|
66
|
-
if (weight <= 650) return 600;
|
|
67
|
-
return 700;
|
|
68
|
-
}
|
|
69
|
-
const FONT_FALLBACK_SYMBOLS = "Noto Sans";
|
|
70
|
-
const FONT_FALLBACK_MATH = "Noto Sans Math";
|
|
71
|
-
const FONT_FALLBACK_DEVANAGARI = "Hind";
|
|
72
|
-
const FONT_FILES = {
|
|
73
|
-
"Playfair Display": {
|
|
74
|
-
regular: "/fonts/PlayfairDisplay-Regular.ttf",
|
|
75
|
-
bold: "/fonts/PlayfairDisplay-Bold.ttf",
|
|
76
|
-
italic: "/fonts/PlayfairDisplay-Italic.ttf",
|
|
77
|
-
boldItalic: "/fonts/PlayfairDisplay-BoldItalic.ttf"
|
|
78
|
-
},
|
|
79
|
-
"Merriweather": {
|
|
80
|
-
regular: "/fonts/Merriweather-Regular.ttf",
|
|
81
|
-
bold: "/fonts/Merriweather-Bold.ttf",
|
|
82
|
-
light: "/fonts/Merriweather-Light.ttf",
|
|
83
|
-
italic: "/fonts/Merriweather-Italic.ttf",
|
|
84
|
-
boldItalic: "/fonts/Merriweather-BoldItalic.ttf",
|
|
85
|
-
lightItalic: "/fonts/Merriweather-LightItalic.ttf"
|
|
86
|
-
},
|
|
87
|
-
"Lora": {
|
|
88
|
-
regular: "/fonts/Lora-Regular.ttf",
|
|
89
|
-
bold: "/fonts/Lora-Bold.ttf",
|
|
90
|
-
italic: "/fonts/Lora-Italic.ttf",
|
|
91
|
-
boldItalic: "/fonts/Lora-BoldItalic.ttf"
|
|
92
|
-
},
|
|
93
|
-
"Montserrat": {
|
|
94
|
-
regular: "/fonts/Montserrat-Regular.ttf",
|
|
95
|
-
bold: "/fonts/Montserrat-Bold.ttf",
|
|
96
|
-
light: "/fonts/Montserrat-Light.ttf",
|
|
97
|
-
medium: "/fonts/Montserrat-Medium.ttf",
|
|
98
|
-
semibold: "/fonts/Montserrat-SemiBold.ttf",
|
|
99
|
-
italic: "/fonts/Montserrat-Italic.ttf",
|
|
100
|
-
boldItalic: "/fonts/Montserrat-BoldItalic.ttf",
|
|
101
|
-
lightItalic: "/fonts/Montserrat-LightItalic.ttf",
|
|
102
|
-
mediumItalic: "/fonts/Montserrat-MediumItalic.ttf",
|
|
103
|
-
semiboldItalic: "/fonts/Montserrat-SemiBoldItalic.ttf"
|
|
104
|
-
},
|
|
105
|
-
"Open Sans": {
|
|
106
|
-
regular: "/fonts/OpenSans-Regular.ttf",
|
|
107
|
-
bold: "/fonts/OpenSans-Bold.ttf",
|
|
108
|
-
light: "/fonts/OpenSans-Light.ttf",
|
|
109
|
-
semibold: "/fonts/OpenSans-SemiBold.ttf",
|
|
110
|
-
italic: "/fonts/OpenSans-Italic.ttf",
|
|
111
|
-
boldItalic: "/fonts/OpenSans-BoldItalic.ttf",
|
|
112
|
-
lightItalic: "/fonts/OpenSans-LightItalic.ttf",
|
|
113
|
-
semiboldItalic: "/fonts/OpenSans-SemiBoldItalic.ttf"
|
|
114
|
-
},
|
|
115
|
-
"Roboto": {
|
|
116
|
-
regular: "/fonts/Roboto-Regular.ttf",
|
|
117
|
-
bold: "/fonts/Roboto-Bold.ttf",
|
|
118
|
-
light: "/fonts/Roboto-Light.ttf",
|
|
119
|
-
medium: "/fonts/Roboto-Medium.ttf",
|
|
120
|
-
italic: "/fonts/Roboto-Italic.ttf",
|
|
121
|
-
boldItalic: "/fonts/Roboto-BoldItalic.ttf",
|
|
122
|
-
lightItalic: "/fonts/Roboto-LightItalic.ttf",
|
|
123
|
-
mediumItalic: "/fonts/Roboto-MediumItalic.ttf"
|
|
124
|
-
},
|
|
125
|
-
"Lato": {
|
|
126
|
-
regular: "/fonts/Lato-Regular.ttf",
|
|
127
|
-
bold: "/fonts/Lato-Bold.ttf",
|
|
128
|
-
light: "/fonts/Lato-Light.ttf",
|
|
129
|
-
italic: "/fonts/Lato-Italic.ttf",
|
|
130
|
-
boldItalic: "/fonts/Lato-BoldItalic.ttf",
|
|
131
|
-
lightItalic: "/fonts/Lato-LightItalic.ttf"
|
|
132
|
-
},
|
|
133
|
-
"Raleway": {
|
|
134
|
-
regular: "/fonts/Raleway-Regular.ttf",
|
|
135
|
-
bold: "/fonts/Raleway-Bold.ttf",
|
|
136
|
-
light: "/fonts/Raleway-Light.ttf",
|
|
137
|
-
medium: "/fonts/Raleway-Medium.ttf",
|
|
138
|
-
semibold: "/fonts/Raleway-SemiBold.ttf",
|
|
139
|
-
italic: "/fonts/Raleway-Italic.ttf",
|
|
140
|
-
boldItalic: "/fonts/Raleway-BoldItalic.ttf",
|
|
141
|
-
lightItalic: "/fonts/Raleway-LightItalic.ttf"
|
|
142
|
-
},
|
|
143
|
-
"Poppins": {
|
|
144
|
-
regular: "/fonts/Poppins-Regular.ttf",
|
|
145
|
-
bold: "/fonts/Poppins-Bold.ttf",
|
|
146
|
-
light: "/fonts/Poppins-Light.ttf",
|
|
147
|
-
medium: "/fonts/Poppins-Medium.ttf",
|
|
148
|
-
semibold: "/fonts/Poppins-SemiBold.ttf",
|
|
149
|
-
italic: "/fonts/Poppins-Italic.ttf",
|
|
150
|
-
boldItalic: "/fonts/Poppins-BoldItalic.ttf",
|
|
151
|
-
lightItalic: "/fonts/Poppins-LightItalic.ttf",
|
|
152
|
-
mediumItalic: "/fonts/Poppins-MediumItalic.ttf",
|
|
153
|
-
semiboldItalic: "/fonts/Poppins-SemiBoldItalic.ttf"
|
|
154
|
-
},
|
|
155
|
-
"Inter": {
|
|
156
|
-
regular: "/fonts/Inter-Regular.ttf",
|
|
157
|
-
bold: "/fonts/Inter-Bold.ttf",
|
|
158
|
-
italic: "/fonts/Inter-Italic.ttf",
|
|
159
|
-
boldItalic: "/fonts/Inter-BoldItalic.ttf"
|
|
160
|
-
},
|
|
161
|
-
"Nunito": {
|
|
162
|
-
regular: "/fonts/Nunito-Regular.ttf",
|
|
163
|
-
bold: "/fonts/Nunito-Bold.ttf",
|
|
164
|
-
light: "/fonts/Nunito-Light.ttf",
|
|
165
|
-
medium: "/fonts/Nunito-Medium.ttf",
|
|
166
|
-
semibold: "/fonts/Nunito-SemiBold.ttf",
|
|
167
|
-
italic: "/fonts/Nunito-Italic.ttf",
|
|
168
|
-
boldItalic: "/fonts/Nunito-BoldItalic.ttf"
|
|
169
|
-
},
|
|
170
|
-
"Source Sans Pro": {
|
|
171
|
-
regular: "/fonts/SourceSansPro-Regular.ttf",
|
|
172
|
-
bold: "/fonts/SourceSansPro-Bold.ttf",
|
|
173
|
-
light: "/fonts/SourceSansPro-Light.ttf",
|
|
174
|
-
italic: "/fonts/SourceSansPro-Italic.ttf",
|
|
175
|
-
boldItalic: "/fonts/SourceSansPro-BoldItalic.ttf"
|
|
176
|
-
},
|
|
177
|
-
"Work Sans": {
|
|
178
|
-
regular: "/fonts/WorkSans-Regular.ttf",
|
|
179
|
-
bold: "/fonts/WorkSans-Bold.ttf",
|
|
180
|
-
italic: "/fonts/WorkSans-Italic.ttf",
|
|
181
|
-
boldItalic: "/fonts/WorkSans-BoldItalic.ttf"
|
|
182
|
-
},
|
|
183
|
-
"Oswald": { regular: "/fonts/Oswald-Regular.ttf", bold: "/fonts/Oswald-Bold.ttf" },
|
|
184
|
-
"Bebas Neue": { regular: "/fonts/BebasNeue-Regular.ttf" },
|
|
185
|
-
"Abril Fatface": { regular: "/fonts/AbrilFatface-Regular.ttf" },
|
|
186
|
-
"Dancing Script": { regular: "/fonts/DancingScript-Regular.ttf", bold: "/fonts/DancingScript-Bold.ttf" },
|
|
187
|
-
"Pacifico": { regular: "/fonts/Pacifico-Regular.ttf" },
|
|
188
|
-
"Great Vibes": { regular: "/fonts/GreatVibes-Regular.ttf" },
|
|
189
|
-
// ── Previously variable-only fonts — now with static per-weight TTFs for PDF export ──
|
|
190
|
-
"DM Sans": {
|
|
191
|
-
regular: "/fonts/DMSans-Regular.ttf",
|
|
192
|
-
bold: "/fonts/DMSans-Bold.ttf",
|
|
193
|
-
light: "/fonts/DMSans-Light.ttf",
|
|
194
|
-
medium: "/fonts/DMSans-Medium.ttf",
|
|
195
|
-
semibold: "/fonts/DMSans-SemiBold.ttf",
|
|
196
|
-
italic: "/fonts/DMSans-RegularItalic.ttf",
|
|
197
|
-
boldItalic: "/fonts/DMSans-BoldItalic.ttf",
|
|
198
|
-
lightItalic: "/fonts/DMSans-LightItalic.ttf",
|
|
199
|
-
mediumItalic: "/fonts/DMSans-MediumItalic.ttf",
|
|
200
|
-
semiboldItalic: "/fonts/DMSans-SemiBoldItalic.ttf"
|
|
201
|
-
},
|
|
202
|
-
"Outfit": {
|
|
203
|
-
regular: "/fonts/Outfit-Regular.ttf",
|
|
204
|
-
bold: "/fonts/Outfit-Bold.ttf",
|
|
205
|
-
light: "/fonts/Outfit-Light.ttf",
|
|
206
|
-
medium: "/fonts/Outfit-Medium.ttf",
|
|
207
|
-
semibold: "/fonts/Outfit-SemiBold.ttf"
|
|
208
|
-
},
|
|
209
|
-
"Figtree": {
|
|
210
|
-
regular: "/fonts/Figtree-Regular.ttf",
|
|
211
|
-
bold: "/fonts/Figtree-Bold.ttf",
|
|
212
|
-
light: "/fonts/Figtree-Light.ttf",
|
|
213
|
-
medium: "/fonts/Figtree-Medium.ttf",
|
|
214
|
-
semibold: "/fonts/Figtree-SemiBold.ttf",
|
|
215
|
-
italic: "/fonts/Figtree-RegularItalic.ttf",
|
|
216
|
-
boldItalic: "/fonts/Figtree-BoldItalic.ttf",
|
|
217
|
-
lightItalic: "/fonts/Figtree-LightItalic.ttf",
|
|
218
|
-
mediumItalic: "/fonts/Figtree-MediumItalic.ttf",
|
|
219
|
-
semiboldItalic: "/fonts/Figtree-SemiBoldItalic.ttf"
|
|
220
|
-
},
|
|
221
|
-
"Manrope": {
|
|
222
|
-
regular: "/fonts/Manrope-Regular.ttf",
|
|
223
|
-
bold: "/fonts/Manrope-Bold.ttf",
|
|
224
|
-
light: "/fonts/Manrope-Light.ttf",
|
|
225
|
-
medium: "/fonts/Manrope-Medium.ttf",
|
|
226
|
-
semibold: "/fonts/Manrope-SemiBold.ttf"
|
|
227
|
-
},
|
|
228
|
-
"Space Grotesk": {
|
|
229
|
-
regular: "/fonts/SpaceGrotesk-Regular.ttf",
|
|
230
|
-
bold: "/fonts/SpaceGrotesk-Bold.ttf",
|
|
231
|
-
light: "/fonts/SpaceGrotesk-Light.ttf",
|
|
232
|
-
medium: "/fonts/SpaceGrotesk-Medium.ttf",
|
|
233
|
-
semibold: "/fonts/SpaceGrotesk-SemiBold.ttf"
|
|
234
|
-
},
|
|
235
|
-
"League Spartan": {
|
|
236
|
-
regular: "/fonts/LeagueSpartan-Regular.ttf",
|
|
237
|
-
bold: "/fonts/LeagueSpartan-Bold.ttf",
|
|
238
|
-
light: "/fonts/LeagueSpartan-Light.ttf",
|
|
239
|
-
medium: "/fonts/LeagueSpartan-Medium.ttf",
|
|
240
|
-
semibold: "/fonts/LeagueSpartan-SemiBold.ttf"
|
|
241
|
-
},
|
|
242
|
-
"EB Garamond": {
|
|
243
|
-
regular: "/fonts/EBGaramond-Regular.ttf",
|
|
244
|
-
bold: "/fonts/EBGaramond-Bold.ttf",
|
|
245
|
-
medium: "/fonts/EBGaramond-Medium.ttf",
|
|
246
|
-
semibold: "/fonts/EBGaramond-SemiBold.ttf",
|
|
247
|
-
italic: "/fonts/EBGaramond-RegularItalic.ttf",
|
|
248
|
-
boldItalic: "/fonts/EBGaramond-BoldItalic.ttf",
|
|
249
|
-
mediumItalic: "/fonts/EBGaramond-MediumItalic.ttf",
|
|
250
|
-
semiboldItalic: "/fonts/EBGaramond-SemiBoldItalic.ttf"
|
|
251
|
-
},
|
|
252
|
-
"Libre Baskerville": {
|
|
253
|
-
regular: "/fonts/LibreBaskerville-Regular.ttf",
|
|
254
|
-
bold: "/fonts/LibreBaskerville-Bold.ttf",
|
|
255
|
-
italic: "/fonts/LibreBaskerville-RegularItalic.ttf",
|
|
256
|
-
boldItalic: "/fonts/LibreBaskerville-BoldItalic.ttf"
|
|
257
|
-
},
|
|
258
|
-
"Crimson Text": {
|
|
259
|
-
regular: "/fonts/CrimsonText-Regular.ttf",
|
|
260
|
-
bold: "/fonts/CrimsonText-Bold.ttf",
|
|
261
|
-
italic: "/fonts/CrimsonText-Italic.ttf",
|
|
262
|
-
boldItalic: "/fonts/CrimsonText-BoldItalic.ttf"
|
|
263
|
-
},
|
|
264
|
-
"DM Serif Display": {
|
|
265
|
-
regular: "/fonts/DMSerifDisplay-Regular.ttf",
|
|
266
|
-
italic: "/fonts/DMSerifDisplay-Italic.ttf"
|
|
267
|
-
},
|
|
268
|
-
"Libre Franklin": {
|
|
269
|
-
regular: "/fonts/LibreFranklin-Regular.ttf",
|
|
270
|
-
bold: "/fonts/LibreFranklin-Bold.ttf",
|
|
271
|
-
light: "/fonts/LibreFranklin-Light.ttf",
|
|
272
|
-
medium: "/fonts/LibreFranklin-Medium.ttf",
|
|
273
|
-
semibold: "/fonts/LibreFranklin-SemiBold.ttf",
|
|
274
|
-
italic: "/fonts/LibreFranklin-RegularItalic.ttf",
|
|
275
|
-
boldItalic: "/fonts/LibreFranklin-BoldItalic.ttf",
|
|
276
|
-
lightItalic: "/fonts/LibreFranklin-LightItalic.ttf",
|
|
277
|
-
mediumItalic: "/fonts/LibreFranklin-MediumItalic.ttf",
|
|
278
|
-
semiboldItalic: "/fonts/LibreFranklin-SemiBoldItalic.ttf"
|
|
279
|
-
},
|
|
280
|
-
"Mulish": {
|
|
281
|
-
regular: "/fonts/Mulish-Regular.ttf",
|
|
282
|
-
bold: "/fonts/Mulish-Bold.ttf",
|
|
283
|
-
light: "/fonts/Mulish-Light.ttf",
|
|
284
|
-
medium: "/fonts/Mulish-Medium.ttf",
|
|
285
|
-
semibold: "/fonts/Mulish-SemiBold.ttf",
|
|
286
|
-
italic: "/fonts/Mulish-RegularItalic.ttf",
|
|
287
|
-
boldItalic: "/fonts/Mulish-BoldItalic.ttf",
|
|
288
|
-
lightItalic: "/fonts/Mulish-LightItalic.ttf",
|
|
289
|
-
mediumItalic: "/fonts/Mulish-MediumItalic.ttf",
|
|
290
|
-
semiboldItalic: "/fonts/Mulish-SemiBoldItalic.ttf"
|
|
291
|
-
},
|
|
292
|
-
"Quicksand": {
|
|
293
|
-
regular: "/fonts/Quicksand-Regular.ttf",
|
|
294
|
-
bold: "/fonts/Quicksand-Bold.ttf",
|
|
295
|
-
light: "/fonts/Quicksand-Light.ttf",
|
|
296
|
-
medium: "/fonts/Quicksand-Medium.ttf",
|
|
297
|
-
semibold: "/fonts/Quicksand-SemiBold.ttf"
|
|
298
|
-
},
|
|
299
|
-
"Rubik": {
|
|
300
|
-
regular: "/fonts/Rubik-Regular.ttf",
|
|
301
|
-
bold: "/fonts/Rubik-Bold.ttf",
|
|
302
|
-
light: "/fonts/Rubik-Light.ttf",
|
|
303
|
-
medium: "/fonts/Rubik-Medium.ttf",
|
|
304
|
-
semibold: "/fonts/Rubik-SemiBold.ttf",
|
|
305
|
-
italic: "/fonts/Rubik-RegularItalic.ttf",
|
|
306
|
-
boldItalic: "/fonts/Rubik-BoldItalic.ttf",
|
|
307
|
-
lightItalic: "/fonts/Rubik-LightItalic.ttf",
|
|
308
|
-
mediumItalic: "/fonts/Rubik-MediumItalic.ttf",
|
|
309
|
-
semiboldItalic: "/fonts/Rubik-SemiBoldItalic.ttf"
|
|
310
|
-
},
|
|
311
|
-
"Karla": {
|
|
312
|
-
regular: "/fonts/Karla-Regular.ttf",
|
|
313
|
-
bold: "/fonts/Karla-Bold.ttf",
|
|
314
|
-
light: "/fonts/Karla-Light.ttf",
|
|
315
|
-
medium: "/fonts/Karla-Medium.ttf",
|
|
316
|
-
semibold: "/fonts/Karla-SemiBold.ttf",
|
|
317
|
-
italic: "/fonts/Karla-RegularItalic.ttf",
|
|
318
|
-
boldItalic: "/fonts/Karla-BoldItalic.ttf",
|
|
319
|
-
lightItalic: "/fonts/Karla-LightItalic.ttf",
|
|
320
|
-
mediumItalic: "/fonts/Karla-MediumItalic.ttf",
|
|
321
|
-
semiboldItalic: "/fonts/Karla-SemiBoldItalic.ttf"
|
|
322
|
-
},
|
|
323
|
-
"Plus Jakarta Sans": {
|
|
324
|
-
regular: "/fonts/PlusJakartaSans-Regular.ttf",
|
|
325
|
-
bold: "/fonts/PlusJakartaSans-Bold.ttf",
|
|
326
|
-
light: "/fonts/PlusJakartaSans-Light.ttf",
|
|
327
|
-
medium: "/fonts/PlusJakartaSans-Medium.ttf",
|
|
328
|
-
semibold: "/fonts/PlusJakartaSans-SemiBold.ttf",
|
|
329
|
-
italic: "/fonts/PlusJakartaSans-RegularItalic.ttf",
|
|
330
|
-
boldItalic: "/fonts/PlusJakartaSans-BoldItalic.ttf",
|
|
331
|
-
lightItalic: "/fonts/PlusJakartaSans-LightItalic.ttf",
|
|
332
|
-
mediumItalic: "/fonts/PlusJakartaSans-MediumItalic.ttf",
|
|
333
|
-
semiboldItalic: "/fonts/PlusJakartaSans-SemiBoldItalic.ttf"
|
|
334
|
-
},
|
|
335
|
-
"Sora": {
|
|
336
|
-
regular: "/fonts/Sora-Regular.ttf",
|
|
337
|
-
bold: "/fonts/Sora-Bold.ttf",
|
|
338
|
-
light: "/fonts/Sora-Light.ttf",
|
|
339
|
-
medium: "/fonts/Sora-Medium.ttf",
|
|
340
|
-
semibold: "/fonts/Sora-SemiBold.ttf"
|
|
341
|
-
},
|
|
342
|
-
"Urbanist": {
|
|
343
|
-
regular: "/fonts/Urbanist-Regular.ttf",
|
|
344
|
-
bold: "/fonts/Urbanist-Bold.ttf",
|
|
345
|
-
light: "/fonts/Urbanist-Light.ttf",
|
|
346
|
-
medium: "/fonts/Urbanist-Medium.ttf",
|
|
347
|
-
semibold: "/fonts/Urbanist-SemiBold.ttf",
|
|
348
|
-
italic: "/fonts/Urbanist-RegularItalic.ttf",
|
|
349
|
-
boldItalic: "/fonts/Urbanist-BoldItalic.ttf",
|
|
350
|
-
lightItalic: "/fonts/Urbanist-LightItalic.ttf",
|
|
351
|
-
mediumItalic: "/fonts/Urbanist-MediumItalic.ttf",
|
|
352
|
-
semiboldItalic: "/fonts/Urbanist-SemiBoldItalic.ttf"
|
|
353
|
-
},
|
|
354
|
-
"Lexend": {
|
|
355
|
-
regular: "/fonts/Lexend-Regular.ttf",
|
|
356
|
-
bold: "/fonts/Lexend-Bold.ttf",
|
|
357
|
-
light: "/fonts/Lexend-Light.ttf",
|
|
358
|
-
medium: "/fonts/Lexend-Medium.ttf",
|
|
359
|
-
semibold: "/fonts/Lexend-SemiBold.ttf"
|
|
360
|
-
},
|
|
361
|
-
"Albert Sans": {
|
|
362
|
-
regular: "/fonts/AlbertSans-Regular.ttf",
|
|
363
|
-
bold: "/fonts/AlbertSans-Bold.ttf",
|
|
364
|
-
light: "/fonts/AlbertSans-Light.ttf",
|
|
365
|
-
medium: "/fonts/AlbertSans-Medium.ttf",
|
|
366
|
-
semibold: "/fonts/AlbertSans-SemiBold.ttf",
|
|
367
|
-
italic: "/fonts/AlbertSans-RegularItalic.ttf",
|
|
368
|
-
boldItalic: "/fonts/AlbertSans-BoldItalic.ttf",
|
|
369
|
-
lightItalic: "/fonts/AlbertSans-LightItalic.ttf",
|
|
370
|
-
mediumItalic: "/fonts/AlbertSans-MediumItalic.ttf",
|
|
371
|
-
semiboldItalic: "/fonts/AlbertSans-SemiBoldItalic.ttf"
|
|
372
|
-
},
|
|
373
|
-
"Noto Sans": {
|
|
374
|
-
regular: "/fonts/NotoSans-Regular.ttf",
|
|
375
|
-
bold: "/fonts/NotoSans-Bold.ttf",
|
|
376
|
-
light: "/fonts/NotoSans-Light.ttf",
|
|
377
|
-
medium: "/fonts/NotoSans-Medium.ttf",
|
|
378
|
-
semibold: "/fonts/NotoSans-SemiBold.ttf",
|
|
379
|
-
italic: "/fonts/NotoSans-RegularItalic.ttf",
|
|
380
|
-
boldItalic: "/fonts/NotoSans-BoldItalic.ttf",
|
|
381
|
-
lightItalic: "/fonts/NotoSans-LightItalic.ttf",
|
|
382
|
-
mediumItalic: "/fonts/NotoSans-MediumItalic.ttf",
|
|
383
|
-
semiboldItalic: "/fonts/NotoSans-SemiBoldItalic.ttf"
|
|
384
|
-
},
|
|
385
|
-
"Cabin": {
|
|
386
|
-
regular: "/fonts/Cabin-Regular.ttf",
|
|
387
|
-
bold: "/fonts/Cabin-Bold.ttf",
|
|
388
|
-
medium: "/fonts/Cabin-Medium.ttf",
|
|
389
|
-
semibold: "/fonts/Cabin-SemiBold.ttf",
|
|
390
|
-
italic: "/fonts/Cabin-RegularItalic.ttf",
|
|
391
|
-
boldItalic: "/fonts/Cabin-BoldItalic.ttf",
|
|
392
|
-
mediumItalic: "/fonts/Cabin-MediumItalic.ttf",
|
|
393
|
-
semiboldItalic: "/fonts/Cabin-SemiBoldItalic.ttf"
|
|
394
|
-
},
|
|
395
|
-
"Barlow": {
|
|
396
|
-
regular: "/fonts/Barlow-Regular.ttf",
|
|
397
|
-
bold: "/fonts/Barlow-Bold.ttf",
|
|
398
|
-
light: "/fonts/Barlow-Light.ttf",
|
|
399
|
-
medium: "/fonts/Barlow-Medium.ttf",
|
|
400
|
-
semibold: "/fonts/Barlow-SemiBold.ttf",
|
|
401
|
-
italic: "/fonts/Barlow-Italic.ttf",
|
|
402
|
-
boldItalic: "/fonts/Barlow-BoldItalic.ttf"
|
|
403
|
-
},
|
|
404
|
-
"Josefin Sans": {
|
|
405
|
-
regular: "/fonts/JosefinSans-Regular.ttf",
|
|
406
|
-
bold: "/fonts/JosefinSans-Bold.ttf",
|
|
407
|
-
light: "/fonts/JosefinSans-Light.ttf",
|
|
408
|
-
medium: "/fonts/JosefinSans-Medium.ttf",
|
|
409
|
-
semibold: "/fonts/JosefinSans-SemiBold.ttf",
|
|
410
|
-
italic: "/fonts/JosefinSans-RegularItalic.ttf",
|
|
411
|
-
boldItalic: "/fonts/JosefinSans-BoldItalic.ttf",
|
|
412
|
-
lightItalic: "/fonts/JosefinSans-LightItalic.ttf",
|
|
413
|
-
mediumItalic: "/fonts/JosefinSans-MediumItalic.ttf",
|
|
414
|
-
semiboldItalic: "/fonts/JosefinSans-SemiBoldItalic.ttf"
|
|
415
|
-
},
|
|
416
|
-
"Archivo": {
|
|
417
|
-
regular: "/fonts/Archivo-Regular.ttf",
|
|
418
|
-
bold: "/fonts/Archivo-Bold.ttf",
|
|
419
|
-
light: "/fonts/Archivo-Light.ttf",
|
|
420
|
-
medium: "/fonts/Archivo-Medium.ttf",
|
|
421
|
-
semibold: "/fonts/Archivo-SemiBold.ttf",
|
|
422
|
-
italic: "/fonts/Archivo-RegularItalic.ttf",
|
|
423
|
-
boldItalic: "/fonts/Archivo-BoldItalic.ttf",
|
|
424
|
-
lightItalic: "/fonts/Archivo-LightItalic.ttf",
|
|
425
|
-
mediumItalic: "/fonts/Archivo-MediumItalic.ttf",
|
|
426
|
-
semiboldItalic: "/fonts/Archivo-SemiBoldItalic.ttf"
|
|
427
|
-
},
|
|
428
|
-
"Overpass": {
|
|
429
|
-
regular: "/fonts/Overpass-Regular.ttf",
|
|
430
|
-
bold: "/fonts/Overpass-Bold.ttf",
|
|
431
|
-
light: "/fonts/Overpass-Light.ttf",
|
|
432
|
-
medium: "/fonts/Overpass-Medium.ttf",
|
|
433
|
-
semibold: "/fonts/Overpass-SemiBold.ttf",
|
|
434
|
-
italic: "/fonts/Overpass-RegularItalic.ttf",
|
|
435
|
-
boldItalic: "/fonts/Overpass-BoldItalic.ttf",
|
|
436
|
-
lightItalic: "/fonts/Overpass-LightItalic.ttf",
|
|
437
|
-
mediumItalic: "/fonts/Overpass-MediumItalic.ttf",
|
|
438
|
-
semiboldItalic: "/fonts/Overpass-SemiBoldItalic.ttf"
|
|
439
|
-
},
|
|
440
|
-
"Exo 2": {
|
|
441
|
-
regular: "/fonts/Exo2-Regular.ttf",
|
|
442
|
-
bold: "/fonts/Exo2-Bold.ttf",
|
|
443
|
-
light: "/fonts/Exo2-Light.ttf",
|
|
444
|
-
medium: "/fonts/Exo2-Medium.ttf",
|
|
445
|
-
semibold: "/fonts/Exo2-SemiBold.ttf",
|
|
446
|
-
italic: "/fonts/Exo2-RegularItalic.ttf",
|
|
447
|
-
boldItalic: "/fonts/Exo2-BoldItalic.ttf",
|
|
448
|
-
lightItalic: "/fonts/Exo2-LightItalic.ttf",
|
|
449
|
-
mediumItalic: "/fonts/Exo2-MediumItalic.ttf",
|
|
450
|
-
semiboldItalic: "/fonts/Exo2-SemiBoldItalic.ttf"
|
|
451
|
-
},
|
|
452
|
-
"Roboto Mono": {
|
|
453
|
-
regular: "/fonts/RobotoMono-Regular.ttf",
|
|
454
|
-
bold: "/fonts/RobotoMono-Bold.ttf",
|
|
455
|
-
light: "/fonts/RobotoMono-Light.ttf",
|
|
456
|
-
medium: "/fonts/RobotoMono-Medium.ttf",
|
|
457
|
-
semibold: "/fonts/RobotoMono-SemiBold.ttf",
|
|
458
|
-
italic: "/fonts/RobotoMono-RegularItalic.ttf",
|
|
459
|
-
boldItalic: "/fonts/RobotoMono-BoldItalic.ttf",
|
|
460
|
-
lightItalic: "/fonts/RobotoMono-LightItalic.ttf",
|
|
461
|
-
mediumItalic: "/fonts/RobotoMono-MediumItalic.ttf",
|
|
462
|
-
semiboldItalic: "/fonts/RobotoMono-SemiBoldItalic.ttf"
|
|
463
|
-
},
|
|
464
|
-
"Fira Code": {
|
|
465
|
-
regular: "/fonts/FiraCode-Regular.ttf",
|
|
466
|
-
bold: "/fonts/FiraCode-Bold.ttf",
|
|
467
|
-
light: "/fonts/FiraCode-Light.ttf",
|
|
468
|
-
medium: "/fonts/FiraCode-Medium.ttf",
|
|
469
|
-
semibold: "/fonts/FiraCode-SemiBold.ttf"
|
|
470
|
-
},
|
|
471
|
-
"JetBrains Mono": {
|
|
472
|
-
regular: "/fonts/JetBrainsMono-Regular.ttf",
|
|
473
|
-
bold: "/fonts/JetBrainsMono-Bold.ttf",
|
|
474
|
-
light: "/fonts/JetBrainsMono-Light.ttf",
|
|
475
|
-
medium: "/fonts/JetBrainsMono-Medium.ttf",
|
|
476
|
-
semibold: "/fonts/JetBrainsMono-SemiBold.ttf",
|
|
477
|
-
italic: "/fonts/JetBrainsMono-RegularItalic.ttf",
|
|
478
|
-
boldItalic: "/fonts/JetBrainsMono-BoldItalic.ttf",
|
|
479
|
-
lightItalic: "/fonts/JetBrainsMono-LightItalic.ttf",
|
|
480
|
-
mediumItalic: "/fonts/JetBrainsMono-MediumItalic.ttf",
|
|
481
|
-
semiboldItalic: "/fonts/JetBrainsMono-SemiBoldItalic.ttf"
|
|
482
|
-
},
|
|
483
|
-
"Source Code Pro": {
|
|
484
|
-
regular: "/fonts/SourceCodePro-Regular.ttf",
|
|
485
|
-
bold: "/fonts/SourceCodePro-Bold.ttf",
|
|
486
|
-
light: "/fonts/SourceCodePro-Light.ttf",
|
|
487
|
-
medium: "/fonts/SourceCodePro-Medium.ttf",
|
|
488
|
-
semibold: "/fonts/SourceCodePro-SemiBold.ttf",
|
|
489
|
-
italic: "/fonts/SourceCodePro-RegularItalic.ttf",
|
|
490
|
-
boldItalic: "/fonts/SourceCodePro-BoldItalic.ttf",
|
|
491
|
-
lightItalic: "/fonts/SourceCodePro-LightItalic.ttf",
|
|
492
|
-
mediumItalic: "/fonts/SourceCodePro-MediumItalic.ttf",
|
|
493
|
-
semiboldItalic: "/fonts/SourceCodePro-SemiBoldItalic.ttf"
|
|
494
|
-
},
|
|
495
|
-
"IBM Plex Mono": {
|
|
496
|
-
regular: "/fonts/IBMPlexMono-Regular.ttf",
|
|
497
|
-
bold: "/fonts/IBMPlexMono-Bold.ttf"
|
|
498
|
-
},
|
|
499
|
-
"Space Mono": {
|
|
500
|
-
regular: "/fonts/SpaceMono-Regular.ttf",
|
|
501
|
-
bold: "/fonts/SpaceMono-Bold.ttf",
|
|
502
|
-
italic: "/fonts/SpaceMono-Italic.ttf",
|
|
503
|
-
boldItalic: "/fonts/SpaceMono-BoldItalic.ttf"
|
|
504
|
-
},
|
|
505
|
-
"Sacramento": { regular: "/fonts/Sacramento-Regular.ttf" },
|
|
506
|
-
"Alex Brush": { regular: "/fonts/AlexBrush-Regular.ttf" },
|
|
507
|
-
"Allura": { regular: "/fonts/Allura-Regular.ttf" },
|
|
508
|
-
"Caveat": {
|
|
509
|
-
regular: "/fonts/Caveat-Regular.ttf",
|
|
510
|
-
bold: "/fonts/Caveat-Bold.ttf",
|
|
511
|
-
medium: "/fonts/Caveat-Medium.ttf",
|
|
512
|
-
semibold: "/fonts/Caveat-SemiBold.ttf"
|
|
513
|
-
},
|
|
514
|
-
"Lobster": { regular: "/fonts/Lobster-Regular.ttf" },
|
|
515
|
-
"Comfortaa": {
|
|
516
|
-
regular: "/fonts/Comfortaa-Regular.ttf",
|
|
517
|
-
bold: "/fonts/Comfortaa-Bold.ttf",
|
|
518
|
-
light: "/fonts/Comfortaa-Light.ttf",
|
|
519
|
-
medium: "/fonts/Comfortaa-Medium.ttf",
|
|
520
|
-
semibold: "/fonts/Comfortaa-SemiBold.ttf"
|
|
521
|
-
},
|
|
522
|
-
"Anton": { regular: "/fonts/Anton-Regular.ttf" },
|
|
523
|
-
"Teko": {
|
|
524
|
-
regular: "/fonts/Teko-Regular.ttf",
|
|
525
|
-
bold: "/fonts/Teko-Bold.ttf",
|
|
526
|
-
light: "/fonts/Teko-Light.ttf",
|
|
527
|
-
medium: "/fonts/Teko-Medium.ttf",
|
|
528
|
-
semibold: "/fonts/Teko-SemiBold.ttf"
|
|
529
|
-
},
|
|
530
|
-
// ── Indic Script Fallback Fonts ──
|
|
531
|
-
"Noto Sans Devanagari": {
|
|
532
|
-
regular: "/fonts/NotoSansDevanagari-Regular.ttf",
|
|
533
|
-
bold: "/fonts/NotoSansDevanagari-Bold.ttf",
|
|
534
|
-
light: "/fonts/NotoSansDevanagari-Light.ttf",
|
|
535
|
-
medium: "/fonts/NotoSansDevanagari-Medium.ttf",
|
|
536
|
-
semibold: "/fonts/NotoSansDevanagari-SemiBold.ttf"
|
|
537
|
-
},
|
|
538
|
-
"Hind": {
|
|
539
|
-
regular: "/fonts/Hind-Regular.ttf",
|
|
540
|
-
bold: "/fonts/Hind-Bold.ttf",
|
|
541
|
-
light: "/fonts/Hind-Light.ttf",
|
|
542
|
-
medium: "/fonts/Hind-Medium.ttf",
|
|
543
|
-
semibold: "/fonts/Hind-SemiBold.ttf"
|
|
544
|
-
},
|
|
545
|
-
// ── Math / Operator Symbol Fallback ──
|
|
546
|
-
// Carries glyphs that NotoSans-Regular's Latin subset is missing
|
|
547
|
-
// (≠ ≤ ≥ ≈ ∞ → ← × ÷ ∑ √ ∈ ∀ ∃ etc.). Used as a tertiary fallback
|
|
548
|
-
// ONLY for chars classified as 'math' that the main font + Noto Sans
|
|
549
|
-
// both lack.
|
|
550
|
-
"Noto Sans Math": {
|
|
551
|
-
regular: "/fonts/NotoSansMath-Regular.ttf"
|
|
552
|
-
}
|
|
553
|
-
};
|
|
554
|
-
function isJsPdfEmbeddableTrueType(bytes) {
|
|
555
|
-
if (bytes.length < 12) return false;
|
|
556
|
-
const signature = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);
|
|
557
|
-
if (signature !== "\0\0\0" && signature !== "true") return false;
|
|
558
|
-
const u16 = (offset) => bytes[offset] << 8 | bytes[offset + 1];
|
|
559
|
-
const u32 = (offset) => (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
|
|
560
|
-
const tableCount = u16(4);
|
|
561
|
-
for (let i = 0; i < tableCount; i++) {
|
|
562
|
-
const recordOffset = 12 + i * 16;
|
|
563
|
-
if (recordOffset + 16 > bytes.length) return false;
|
|
564
|
-
const tag = String.fromCharCode(bytes[recordOffset], bytes[recordOffset + 1], bytes[recordOffset + 2], bytes[recordOffset + 3]);
|
|
565
|
-
if (tag !== "cmap") continue;
|
|
566
|
-
const cmapOffset = u32(recordOffset + 8);
|
|
567
|
-
const cmapLength = u32(recordOffset + 12);
|
|
568
|
-
if (cmapOffset + Math.min(cmapLength, 4) > bytes.length) return false;
|
|
569
|
-
const subtables = u16(cmapOffset + 2);
|
|
570
|
-
for (let j = 0; j < subtables; j++) {
|
|
571
|
-
const encOffset = cmapOffset + 4 + j * 8;
|
|
572
|
-
if (encOffset + 8 > bytes.length) return false;
|
|
573
|
-
const platform = u16(encOffset);
|
|
574
|
-
const encoding = u16(encOffset + 2);
|
|
575
|
-
if (platform === 0 || platform === 3 && (encoding === 1 || encoding === 10)) return true;
|
|
576
|
-
}
|
|
577
|
-
return false;
|
|
578
|
-
}
|
|
579
|
-
return false;
|
|
580
|
-
}
|
|
581
|
-
async function fetchGoogleFontTTF(fontFamily, weight = 400, isItalic = false) {
|
|
582
|
-
const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
|
|
583
|
-
if (fontCache$1.has(cacheKey)) return fontCache$1.get(cacheKey);
|
|
584
|
-
const notFoundKey = remoteVariantKey(fontFamily, weight, isItalic);
|
|
585
|
-
if (googleFontNotFound.has(notFoundKey)) return null;
|
|
586
|
-
const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, "google");
|
|
587
|
-
if (proxyBytes && isJsPdfEmbeddableTrueType(proxyBytes)) {
|
|
588
|
-
fontBytesCache$1.set(cacheKey, proxyBytes);
|
|
589
|
-
let binary = "";
|
|
590
|
-
for (let i = 0; i < proxyBytes.length; i++) binary += String.fromCharCode(proxyBytes[i]);
|
|
591
|
-
const b64 = btoa(binary);
|
|
592
|
-
fontCache$1.set(cacheKey, b64);
|
|
593
|
-
return b64;
|
|
594
|
-
}
|
|
595
|
-
try {
|
|
596
|
-
const ital = isItalic ? "1" : "0";
|
|
597
|
-
const cssUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(
|
|
598
|
-
fontFamily
|
|
599
|
-
)}:ital,wght@${ital},${weight}&display=swap`;
|
|
600
|
-
const cssRes = await fetch(cssUrl, {
|
|
601
|
-
headers: {
|
|
602
|
-
"User-Agent": "Mozilla/5.0 (Linux; U; Android 2.2; en-us) AppleWebKit/533.1 (KHTML, like Gecko)"
|
|
603
|
-
}
|
|
604
|
-
});
|
|
605
|
-
if (!cssRes.ok) {
|
|
606
|
-
if (cssRes.status === 400 || cssRes.status === 404) googleFontNotFound.add(notFoundKey);
|
|
607
|
-
return null;
|
|
608
|
-
}
|
|
609
|
-
const css = await cssRes.text();
|
|
610
|
-
const urlMatch = css.match(/url\(([^)]+)\)\s+format\(['"]?truetype['"]?\)/i) || css.match(/url\(([^)]+)\)/);
|
|
611
|
-
if (!urlMatch) return null;
|
|
612
|
-
const ttfUrl = urlMatch[1].replace(/['"]/g, "");
|
|
613
|
-
googleFontUrlCache.set(cacheKey, ttfUrl);
|
|
614
|
-
const ttfRes = await fetch(ttfUrl);
|
|
615
|
-
if (!ttfRes.ok) return null;
|
|
616
|
-
const buf = await ttfRes.arrayBuffer();
|
|
617
|
-
const bytes = new Uint8Array(buf);
|
|
618
|
-
if (!isJsPdfEmbeddableTrueType(bytes)) {
|
|
619
|
-
console.warn(`[pdfFonts] Google Fonts returned a non-TTF font for ${fontFamily} (${weight}); skipping jsPDF embed`);
|
|
620
|
-
return null;
|
|
621
|
-
}
|
|
622
|
-
fontBytesCache$1.set(cacheKey, bytes);
|
|
623
|
-
let binary = "";
|
|
624
|
-
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
625
|
-
const b64 = btoa(binary);
|
|
626
|
-
fontCache$1.set(cacheKey, b64);
|
|
627
|
-
return b64;
|
|
628
|
-
} catch (err) {
|
|
629
|
-
console.warn(`[pdfFonts] fetchGoogleFontTTF failed for ${fontFamily} (${weight}):`, err);
|
|
630
|
-
return null;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
async function getGoogleFontBytes(fontFamily, weight = 400, isItalic = false) {
|
|
634
|
-
const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
|
|
635
|
-
if (fontBytesCache$1.has(cacheKey)) return fontBytesCache$1.get(cacheKey);
|
|
636
|
-
await fetchGoogleFontTTF(fontFamily, weight, isItalic);
|
|
637
|
-
return fontBytesCache$1.get(cacheKey) || null;
|
|
638
|
-
}
|
|
639
|
-
const fontshareNotFound = /* @__PURE__ */ new Set();
|
|
640
|
-
function toFontshareSlug(family) {
|
|
641
|
-
return family.trim().toLowerCase().replace(/\s+/g, "-");
|
|
642
|
-
}
|
|
643
|
-
async function fetchFontshareTTF(fontFamily, weight = 400, isItalic = false, slug) {
|
|
644
|
-
const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
|
|
645
|
-
if (fontCache$1.has(cacheKey)) return fontCache$1.get(cacheKey);
|
|
646
|
-
if (fontshareNotFound.has(fontFamily)) return null;
|
|
647
|
-
const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, "fontshare");
|
|
648
|
-
if (proxyBytes && isJsPdfEmbeddableTrueType(proxyBytes)) {
|
|
649
|
-
fontBytesCache$1.set(cacheKey, proxyBytes);
|
|
650
|
-
let binary = "";
|
|
651
|
-
for (let i = 0; i < proxyBytes.length; i++) binary += String.fromCharCode(proxyBytes[i]);
|
|
652
|
-
const b64 = btoa(binary);
|
|
653
|
-
fontCache$1.set(cacheKey, b64);
|
|
654
|
-
return b64;
|
|
655
|
-
}
|
|
656
|
-
const finalSlug = toFontshareSlug(fontFamily);
|
|
657
|
-
try {
|
|
658
|
-
const styleSuffix = isItalic ? "i" : "";
|
|
659
|
-
const cssUrl = `https://api.fontshare.com/v2/css?f[]=${finalSlug}@${weight}${styleSuffix}&display=swap`;
|
|
660
|
-
const cssRes = await fetch(cssUrl);
|
|
661
|
-
if (!cssRes.ok) {
|
|
662
|
-
if (cssRes.status === 400 || cssRes.status === 404) fontshareNotFound.add(fontFamily);
|
|
663
|
-
return null;
|
|
664
|
-
}
|
|
665
|
-
const css = await cssRes.text();
|
|
666
|
-
const ttMatch = css.match(/url\(([^)]+)\)\s+format\(['"]?truetype['"]?\)/i);
|
|
667
|
-
if (!ttMatch) {
|
|
668
|
-
fontshareNotFound.add(fontFamily);
|
|
669
|
-
return null;
|
|
670
|
-
}
|
|
671
|
-
let ttfUrl = ttMatch[1].replace(/['"]/g, "").trim();
|
|
672
|
-
if (ttfUrl.startsWith("//")) ttfUrl = `https:${ttfUrl}`;
|
|
673
|
-
const ttfRes = await fetch(ttfUrl);
|
|
674
|
-
if (!ttfRes.ok) return null;
|
|
675
|
-
const buf = await ttfRes.arrayBuffer();
|
|
676
|
-
const bytes = new Uint8Array(buf);
|
|
677
|
-
if (!isJsPdfEmbeddableTrueType(bytes)) {
|
|
678
|
-
console.warn(`[pdfFonts] Fontshare returned a non-TTF font for ${fontFamily} (${weight}); skipping jsPDF embed`);
|
|
679
|
-
return null;
|
|
680
|
-
}
|
|
681
|
-
fontBytesCache$1.set(cacheKey, bytes);
|
|
682
|
-
let binary = "";
|
|
683
|
-
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
684
|
-
const b64 = btoa(binary);
|
|
685
|
-
fontCache$1.set(cacheKey, b64);
|
|
686
|
-
return b64;
|
|
687
|
-
} catch (err) {
|
|
688
|
-
console.warn(`[pdfFonts] fetchFontshareTTF failed for ${fontFamily} (${weight}):`, err);
|
|
689
|
-
return null;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
async function getFontshareFontBytes(fontFamily, weight = 400, isItalic = false, slug) {
|
|
693
|
-
const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
|
|
694
|
-
if (fontBytesCache$1.has(cacheKey)) return fontBytesCache$1.get(cacheKey);
|
|
695
|
-
await fetchFontshareTTF(fontFamily, weight, isItalic);
|
|
696
|
-
return fontBytesCache$1.get(cacheKey) || null;
|
|
697
|
-
}
|
|
698
|
-
const LATIN_TO_DEVANAGARI = {
|
|
699
|
-
// Direct Devanagari subsets — same family carries both scripts
|
|
700
|
-
"Poppins": "Poppins",
|
|
701
|
-
"Noto Sans": "Noto Sans Devanagari",
|
|
702
|
-
"Noto Serif": "Noto Serif Devanagari",
|
|
703
|
-
"Hind": "Hind",
|
|
704
|
-
"Mukta": "Mukta",
|
|
705
|
-
// Curated visual matches (Google's own recommendations)
|
|
706
|
-
"Montserrat": "Mukta",
|
|
707
|
-
"Open Sans": "Mukta",
|
|
708
|
-
"Lato": "Mukta",
|
|
709
|
-
"Roboto": "Mukta",
|
|
710
|
-
"Inter": "Mukta",
|
|
711
|
-
"Nunito": "Mukta",
|
|
712
|
-
"Source Sans Pro": "Mukta",
|
|
713
|
-
"Work Sans": "Mukta",
|
|
714
|
-
"DM Sans": "Mukta",
|
|
715
|
-
"Outfit": "Mukta",
|
|
716
|
-
"Figtree": "Mukta",
|
|
717
|
-
"Manrope": "Mukta",
|
|
718
|
-
"Plus Jakarta Sans": "Mukta",
|
|
719
|
-
"Sora": "Mukta",
|
|
720
|
-
"Urbanist": "Mukta",
|
|
721
|
-
"Lexend": "Mukta",
|
|
722
|
-
"Albert Sans": "Mukta",
|
|
723
|
-
"Cabin": "Mukta",
|
|
724
|
-
"Karla": "Mukta",
|
|
725
|
-
"Mulish": "Mukta",
|
|
726
|
-
"Rubik": "Mukta",
|
|
727
|
-
"Quicksand": "Mukta",
|
|
728
|
-
"Libre Franklin": "Mukta",
|
|
729
|
-
"Barlow": "Mukta",
|
|
730
|
-
"Archivo": "Mukta",
|
|
731
|
-
"Overpass": "Mukta",
|
|
732
|
-
"Josefin Sans": "Mukta",
|
|
733
|
-
"Exo 2": "Mukta",
|
|
734
|
-
"Space Grotesk": "Mukta",
|
|
735
|
-
// Display / heavy
|
|
736
|
-
"Oswald": "Teko",
|
|
737
|
-
"Bebas Neue": "Teko",
|
|
738
|
-
"Anton": "Teko",
|
|
739
|
-
"Teko": "Teko",
|
|
740
|
-
"League Spartan": "Teko",
|
|
741
|
-
// Serifs → Tiro Devanagari Hindi (a refined Devanagari serif)
|
|
742
|
-
"Playfair Display": "Tiro Devanagari Hindi",
|
|
743
|
-
"Merriweather": "Tiro Devanagari Hindi",
|
|
744
|
-
"Lora": "Tiro Devanagari Hindi",
|
|
745
|
-
"EB Garamond": "Tiro Devanagari Hindi",
|
|
746
|
-
"Libre Baskerville": "Tiro Devanagari Hindi",
|
|
747
|
-
"Crimson Text": "Tiro Devanagari Hindi",
|
|
748
|
-
"DM Serif Display": "Tiro Devanagari Sanskrit",
|
|
749
|
-
"Abril Fatface": "Tiro Devanagari Sanskrit",
|
|
750
|
-
// Handwriting → Kalam (the only serious Devanagari handwriting family on GF)
|
|
751
|
-
"Dancing Script": "Kalam",
|
|
752
|
-
"Pacifico": "Kalam",
|
|
753
|
-
"Great Vibes": "Kalam",
|
|
754
|
-
"Sacramento": "Kalam",
|
|
755
|
-
"Alex Brush": "Kalam",
|
|
756
|
-
"Allura": "Kalam",
|
|
757
|
-
"Caveat": "Kalam",
|
|
758
|
-
"Lobster": "Kalam",
|
|
759
|
-
"Comfortaa": "Mukta",
|
|
760
|
-
// Monospace → there's no proper Devanagari mono; fall back to Mukta
|
|
761
|
-
"Roboto Mono": "Mukta",
|
|
762
|
-
"Fira Code": "Mukta",
|
|
763
|
-
"JetBrains Mono": "Mukta",
|
|
764
|
-
"Source Code Pro": "Mukta",
|
|
765
|
-
"IBM Plex Mono": "Mukta",
|
|
766
|
-
"Space Mono": "Mukta"
|
|
767
|
-
};
|
|
768
|
-
function resolveDevanagariSibling(latinFont) {
|
|
769
|
-
if (!latinFont) return FONT_FALLBACK_DEVANAGARI;
|
|
770
|
-
return LATIN_TO_DEVANAGARI[latinFont] || FONT_FALLBACK_DEVANAGARI;
|
|
771
|
-
}
|
|
772
|
-
const HB_WASM_URL = "/wasm/hb.wasm";
|
|
773
|
-
let hbInstancePromise = null;
|
|
774
|
-
async function getHB() {
|
|
775
|
-
if (hbInstancePromise) return hbInstancePromise;
|
|
776
|
-
hbInstancePromise = (async () => {
|
|
777
|
-
const [{ default: createHarfBuzz }, { default: hbjs }] = await Promise.all([
|
|
778
|
-
import("harfbuzzjs/hb.js"),
|
|
779
|
-
import("harfbuzzjs/hbjs.js")
|
|
780
|
-
]);
|
|
781
|
-
const moduleInstance = await createHarfBuzz({
|
|
782
|
-
locateFile: (path) => {
|
|
783
|
-
if (path.endsWith(".wasm")) return HB_WASM_URL;
|
|
784
|
-
return path;
|
|
785
|
-
}
|
|
786
|
-
});
|
|
787
|
-
return hbjs(moduleInstance);
|
|
788
|
-
})();
|
|
789
|
-
return hbInstancePromise;
|
|
790
|
-
}
|
|
791
|
-
const hbFontCache = /* @__PURE__ */ new Map();
|
|
792
|
-
async function getHBFont(cacheKey, fontDataLoader) {
|
|
793
|
-
const cached = hbFontCache.get(cacheKey);
|
|
794
|
-
if (cached) return { font: cached.font, upem: cached.upem };
|
|
795
|
-
const hb = await getHB();
|
|
796
|
-
const fontData = await fontDataLoader();
|
|
797
|
-
const blob = hb.createBlob(fontData);
|
|
798
|
-
const face = hb.createFace(blob, 0);
|
|
799
|
-
const font = hb.createFont(face);
|
|
800
|
-
const upem = (face.getUpem ? face.getUpem() : face.upem ?? 1e3) || 1e3;
|
|
801
|
-
font.setScale(upem, upem);
|
|
802
|
-
blob.destroy();
|
|
803
|
-
hbFontCache.set(cacheKey, { face, font, upem });
|
|
804
|
-
return { font, upem };
|
|
805
|
-
}
|
|
806
|
-
async function shapeRunToSvgPath(fontData, cacheKey, text, x, y, fontSize, opts) {
|
|
807
|
-
const hb = await getHB();
|
|
808
|
-
const loader = typeof fontData === "function" ? fontData : async () => fontData;
|
|
809
|
-
const { font, upem } = await getHBFont(cacheKey, loader);
|
|
810
|
-
const buffer = hb.createBuffer();
|
|
811
|
-
buffer.addText(text);
|
|
812
|
-
if (opts == null ? void 0 : opts.direction) buffer.setDirection(opts.direction);
|
|
813
|
-
if (opts == null ? void 0 : opts.script) buffer.setScript(opts.script);
|
|
814
|
-
if (opts == null ? void 0 : opts.language) buffer.setLanguage(opts.language);
|
|
815
|
-
buffer.guessSegmentProperties();
|
|
816
|
-
hb.shape(font, buffer);
|
|
817
|
-
const glyphs = buffer.json();
|
|
818
|
-
const scale = fontSize / upem;
|
|
819
|
-
let penX = 0;
|
|
820
|
-
let penY = 0;
|
|
821
|
-
const pieces = [];
|
|
822
|
-
for (const g of glyphs) {
|
|
823
|
-
const rawPath = font.glyphToPath(g.g);
|
|
824
|
-
if (rawPath) {
|
|
825
|
-
const ox = (penX + g.dx) * scale + x;
|
|
826
|
-
const oy = (penY + g.dy) * -scale + y;
|
|
827
|
-
pieces.push(transformPathData(rawPath, scale, -scale, ox, oy));
|
|
828
|
-
}
|
|
829
|
-
penX += g.ax;
|
|
830
|
-
penY += g.ay;
|
|
831
|
-
}
|
|
832
|
-
buffer.destroy();
|
|
833
|
-
return {
|
|
834
|
-
pathData: pieces.join(""),
|
|
835
|
-
width: penX * scale
|
|
836
|
-
};
|
|
837
|
-
}
|
|
838
|
-
function transformPathData(d, sx, sy, tx, ty) {
|
|
839
|
-
let out = "";
|
|
840
|
-
let i = 0;
|
|
841
|
-
const n = d.length;
|
|
842
|
-
while (i < n) {
|
|
843
|
-
const c = d[i];
|
|
844
|
-
if (c === "M" || c === "L" || c === "C" || c === "Q") {
|
|
845
|
-
out += c;
|
|
846
|
-
i++;
|
|
847
|
-
let pairsBuf = "";
|
|
848
|
-
while (i < n && d[i] !== "M" && d[i] !== "L" && d[i] !== "C" && d[i] !== "Q" && d[i] !== "Z") {
|
|
849
|
-
pairsBuf += d[i];
|
|
850
|
-
i++;
|
|
851
|
-
}
|
|
852
|
-
const nums = pairsBuf.trim().split(/[ ,]+/).filter(Boolean).map(Number);
|
|
853
|
-
for (let k = 0; k < nums.length; k += 2) {
|
|
854
|
-
const px = nums[k] * sx + tx;
|
|
855
|
-
const py = nums[k + 1] * sy + ty;
|
|
856
|
-
if (k > 0) out += " ";
|
|
857
|
-
out += `${round(px)},${round(py)}`;
|
|
858
|
-
}
|
|
859
|
-
} else if (c === "Z") {
|
|
860
|
-
out += "Z";
|
|
861
|
-
i++;
|
|
862
|
-
} else {
|
|
863
|
-
i++;
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
return out;
|
|
867
|
-
}
|
|
868
|
-
function round(n) {
|
|
869
|
-
return (Math.round(n * 100) / 100).toString();
|
|
870
|
-
}
|
|
871
|
-
const fontCache = /* @__PURE__ */ new Map();
|
|
872
|
-
const fontBytesCache = /* @__PURE__ */ new Map();
|
|
873
|
-
function isDevanagari(char) {
|
|
874
|
-
const c = char.codePointAt(0) ?? 0;
|
|
875
|
-
return c >= 2304 && c <= 2431 || c >= 43232 && c <= 43263 || c >= 7376 && c <= 7423;
|
|
876
|
-
}
|
|
877
|
-
function containsDevanagari(text) {
|
|
878
|
-
if (!text) return false;
|
|
879
|
-
for (const char of text) {
|
|
880
|
-
if (isDevanagari(char)) return true;
|
|
881
|
-
}
|
|
882
|
-
return false;
|
|
883
|
-
}
|
|
884
|
-
function isBasicLatinOrLatinExtended(char) {
|
|
885
|
-
const c = char.codePointAt(0) ?? 0;
|
|
886
|
-
return c <= 591;
|
|
887
|
-
}
|
|
888
|
-
function isMathOperatorChar(char) {
|
|
889
|
-
const c = char.codePointAt(0) ?? 0;
|
|
890
|
-
if (c >= 8592 && c <= 8703) return true;
|
|
891
|
-
if (c >= 8704 && c <= 8959) return true;
|
|
892
|
-
if (c >= 8960 && c <= 9215) return true;
|
|
893
|
-
if (c >= 10176 && c <= 10223) return true;
|
|
894
|
-
if (c >= 10624 && c <= 10751) return true;
|
|
895
|
-
if (c >= 10752 && c <= 11007) return true;
|
|
896
|
-
if (c >= 11008 && c <= 11097) return true;
|
|
897
|
-
return false;
|
|
898
|
-
}
|
|
899
|
-
function classifyCharForFontRun(char) {
|
|
900
|
-
if (isBasicLatinOrLatinExtended(char)) return "main";
|
|
901
|
-
if (isDevanagari(char)) return "devanagari";
|
|
902
|
-
if (isMathOperatorChar(char)) return "math";
|
|
903
|
-
return "symbol";
|
|
904
|
-
}
|
|
905
|
-
function isIgnorableForCoverage(char) {
|
|
906
|
-
return /\s/.test(char) || /[\u0964\u0965\u200c\u200d]/u.test(char);
|
|
907
|
-
}
|
|
908
|
-
function fontSupportsRun(font, text, runType) {
|
|
909
|
-
if (!font) return false;
|
|
910
|
-
for (const char of text) {
|
|
911
|
-
if (isIgnorableForCoverage(char)) continue;
|
|
912
|
-
if (runType === "devanagari" && !isDevanagari(char)) continue;
|
|
913
|
-
if (runType === "symbol" && classifyCharForFontRun(char) !== "symbol") continue;
|
|
914
|
-
if (runType === "math" && classifyCharForFontRun(char) !== "math") continue;
|
|
915
|
-
const glyph = font.charToGlyph(char);
|
|
916
|
-
if (!glyph || glyph.index === 0) return false;
|
|
917
|
-
}
|
|
918
|
-
return true;
|
|
919
|
-
}
|
|
920
|
-
const browserMeasureCanvas = typeof document !== "undefined" ? document.createElement("canvas") : null;
|
|
921
|
-
function measureBrowserWidth(fontFamily, weight, fontSize, text) {
|
|
922
|
-
const ctx = browserMeasureCanvas == null ? void 0 : browserMeasureCanvas.getContext("2d");
|
|
923
|
-
if (!ctx) return null;
|
|
924
|
-
ctx.font = `normal normal ${weight} ${fontSize}px "${fontFamily}"`;
|
|
925
|
-
return ctx.measureText(text).width;
|
|
926
|
-
}
|
|
927
|
-
function uniqueFamilies(families) {
|
|
928
|
-
const seen = /* @__PURE__ */ new Set();
|
|
929
|
-
const out = [];
|
|
930
|
-
for (const family of families) {
|
|
931
|
-
const clean = family == null ? void 0 : family.trim();
|
|
932
|
-
if (!clean || seen.has(clean)) continue;
|
|
933
|
-
seen.add(clean);
|
|
934
|
-
out.push(clean);
|
|
935
|
-
}
|
|
936
|
-
return out;
|
|
937
|
-
}
|
|
938
|
-
function fontLooksItalic(font) {
|
|
939
|
-
var _a, _b, _c, _d;
|
|
940
|
-
if (!font) return false;
|
|
941
|
-
const names = font.names;
|
|
942
|
-
const candidates = [
|
|
943
|
-
(_a = names.fontSubfamily) == null ? void 0 : _a.en,
|
|
944
|
-
(_b = names.typographicSubfamily) == null ? void 0 : _b.en,
|
|
945
|
-
(_c = names.fullName) == null ? void 0 : _c.en,
|
|
946
|
-
(_d = names.postScriptName) == null ? void 0 : _d.en
|
|
947
|
-
].filter(Boolean).join(" ");
|
|
948
|
-
return /italic|oblique/i.test(candidates);
|
|
949
|
-
}
|
|
950
|
-
function syntheticItalicTransform(anchorX, baselineY) {
|
|
951
|
-
return `translate(${anchorX} ${baselineY}) skewX(-12) translate(${-anchorX} ${-baselineY})`;
|
|
952
|
-
}
|
|
953
|
-
function getFontPath(fontFiles, weight, isItalic = false) {
|
|
954
|
-
const resolved = resolveFontWeight(weight);
|
|
955
|
-
const uprightMap = {
|
|
956
|
-
300: ["light", "regular"],
|
|
957
|
-
400: ["regular"],
|
|
958
|
-
500: ["medium", "regular"],
|
|
959
|
-
600: ["semibold", "bold"],
|
|
960
|
-
700: ["bold", "semibold", "regular"]
|
|
961
|
-
};
|
|
962
|
-
const italicMap = {
|
|
963
|
-
300: ["lightItalic", "italic", "light", "regular"],
|
|
964
|
-
400: ["italic", "regular"],
|
|
965
|
-
500: ["mediumItalic", "italic", "medium", "regular"],
|
|
966
|
-
600: ["semiboldItalic", "boldItalic", "italic", "semibold", "bold", "regular"],
|
|
967
|
-
700: ["boldItalic", "semiboldItalic", "italic", "bold", "semibold", "regular"]
|
|
968
|
-
};
|
|
969
|
-
const map = isItalic ? italicMap : uprightMap;
|
|
970
|
-
for (const key of map[resolved] || ["regular"]) {
|
|
971
|
-
if (fontFiles[key]) return fontFiles[key];
|
|
972
|
-
}
|
|
973
|
-
return fontFiles.regular || null;
|
|
974
|
-
}
|
|
975
|
-
function resolveFontUrl(fileName, fontBaseUrl) {
|
|
976
|
-
if (/^https?:\/\//i.test(fileName) || fileName.startsWith("data:")) return fileName;
|
|
977
|
-
if (fileName.startsWith("/")) {
|
|
978
|
-
return typeof window !== "undefined" ? new URL(fileName, window.location.origin).toString() : fileName;
|
|
979
|
-
}
|
|
980
|
-
const baseUrl = fontBaseUrl.endsWith("/") ? fontBaseUrl : fontBaseUrl + "/";
|
|
981
|
-
return new URL(fileName, baseUrl).toString();
|
|
982
|
-
}
|
|
983
|
-
async function loadFont(fontFamily, weight, fontBaseUrl, isItalic = false) {
|
|
984
|
-
const cacheKey = `${fontFamily}__${weight}__${isItalic ? "i" : "n"}`;
|
|
985
|
-
if (fontCache.has(cacheKey)) return fontCache.get(cacheKey);
|
|
986
|
-
const fontFiles = FONT_FILES[fontFamily];
|
|
987
|
-
if (fontFiles) {
|
|
988
|
-
const fileName = getFontPath(fontFiles, weight, isItalic);
|
|
989
|
-
if (!fileName) return null;
|
|
990
|
-
const url = resolveFontUrl(fileName, fontBaseUrl);
|
|
991
|
-
try {
|
|
992
|
-
const response = await fetch(url);
|
|
993
|
-
if (!response.ok) {
|
|
994
|
-
console.warn(`[text-to-path] Failed to fetch font ${url}: ${response.status}`);
|
|
995
|
-
return null;
|
|
996
|
-
}
|
|
997
|
-
const buffer = await response.arrayBuffer();
|
|
998
|
-
const bytes = new Uint8Array(buffer);
|
|
999
|
-
fontBytesCache.set(cacheKey, bytes);
|
|
1000
|
-
const font = opentype__namespace.parse(buffer);
|
|
1001
|
-
fontCache.set(cacheKey, font);
|
|
1002
|
-
return font;
|
|
1003
|
-
} catch (err) {
|
|
1004
|
-
console.warn(`[text-to-path] Failed to load local font ${fontFamily}:`, err);
|
|
1005
|
-
return null;
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
try {
|
|
1009
|
-
const resolvedWeight = resolveFontWeight(weight);
|
|
1010
|
-
let bytes = await getGoogleFontBytes(fontFamily, resolvedWeight, isItalic);
|
|
1011
|
-
if (!bytes) {
|
|
1012
|
-
bytes = await getFontshareFontBytes(fontFamily, resolvedWeight, isItalic);
|
|
1013
|
-
}
|
|
1014
|
-
if (!bytes && isItalic) {
|
|
1015
|
-
bytes = await getGoogleFontBytes(fontFamily, resolvedWeight, false);
|
|
1016
|
-
if (!bytes) bytes = await getFontshareFontBytes(fontFamily, resolvedWeight, false);
|
|
1017
|
-
}
|
|
1018
|
-
if (!bytes) {
|
|
1019
|
-
console.warn(`[text-to-path] No TTF available for ${fontFamily} (${weight}) on Google Fonts or Fontshare`);
|
|
1020
|
-
return null;
|
|
1021
|
-
}
|
|
1022
|
-
fontBytesCache.set(cacheKey, bytes);
|
|
1023
|
-
const ab = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
1024
|
-
const font = opentype__namespace.parse(ab);
|
|
1025
|
-
fontCache.set(cacheKey, font);
|
|
1026
|
-
return font;
|
|
1027
|
-
} catch (err) {
|
|
1028
|
-
console.warn(`[text-to-path] Failed to load Google font ${fontFamily}:`, err);
|
|
1029
|
-
return null;
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
async function getFontBytes(fontFamily, weight, fontBaseUrl, isItalic = false) {
|
|
1033
|
-
const cacheKey = `${fontFamily}__${weight}__${isItalic ? "i" : "n"}`;
|
|
1034
|
-
if (!fontBytesCache.has(cacheKey)) {
|
|
1035
|
-
await loadFont(fontFamily, weight, fontBaseUrl, isItalic);
|
|
1036
|
-
}
|
|
1037
|
-
const bytes = fontBytesCache.get(cacheKey);
|
|
1038
|
-
return bytes ? { bytes, cacheKey } : null;
|
|
1039
|
-
}
|
|
1040
|
-
function measureRunWidth(font, text, fontSize) {
|
|
1041
|
-
try {
|
|
1042
|
-
return font.getAdvanceWidth(text, fontSize, { kerning: true });
|
|
1043
|
-
} catch {
|
|
1044
|
-
try {
|
|
1045
|
-
return font.getAdvanceWidth(text, fontSize);
|
|
1046
|
-
} catch {
|
|
1047
|
-
return text.length * fontSize * 0.5;
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
function splitByFontRun(text) {
|
|
1052
|
-
if (!text) return [];
|
|
1053
|
-
const runs = [];
|
|
1054
|
-
let buf = "";
|
|
1055
|
-
let bufType = classifyCharForFontRun(text[0]);
|
|
1056
|
-
for (const ch of text) {
|
|
1057
|
-
const chType = classifyCharForFontRun(ch);
|
|
1058
|
-
const isNeutral = /\s/.test(ch);
|
|
1059
|
-
if (chType === bufType || isNeutral) {
|
|
1060
|
-
buf += ch;
|
|
1061
|
-
} else {
|
|
1062
|
-
if (buf) runs.push({ text: buf, runType: bufType });
|
|
1063
|
-
buf = ch;
|
|
1064
|
-
bufType = chType;
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
if (buf) runs.push({ text: buf, runType: bufType });
|
|
1068
|
-
return runs;
|
|
1069
|
-
}
|
|
1070
|
-
async function shapeRunToPath(run, isDeva, primaryFont, primaryBytes, devaFont, devaBytes, x, y, fontSize) {
|
|
1071
|
-
if (isDeva && devaBytes && devaFont) {
|
|
1072
|
-
try {
|
|
1073
|
-
const shaped = await shapeRunToSvgPath(
|
|
1074
|
-
devaBytes.bytes,
|
|
1075
|
-
devaBytes.cacheKey,
|
|
1076
|
-
run,
|
|
1077
|
-
x,
|
|
1078
|
-
y,
|
|
1079
|
-
fontSize,
|
|
1080
|
-
{ script: "deva", language: "hin", direction: "ltr" }
|
|
1081
|
-
);
|
|
1082
|
-
if (shaped.pathData) {
|
|
1083
|
-
const advance = measureRunWidth(devaFont, run, fontSize);
|
|
1084
|
-
return { pathData: shaped.pathData, advance };
|
|
1085
|
-
}
|
|
1086
|
-
} catch (err) {
|
|
1087
|
-
console.warn(`[text-to-path] HarfBuzz failed for "${run}":`, err);
|
|
1088
|
-
}
|
|
1089
|
-
try {
|
|
1090
|
-
const path = devaFont.getPath(run, x, y, fontSize);
|
|
1091
|
-
const d = path.toPathData(2);
|
|
1092
|
-
if (d && d !== "M0 0") return { pathData: d, advance: measureRunWidth(devaFont, run, fontSize) };
|
|
1093
|
-
} catch {
|
|
1094
|
-
}
|
|
1095
|
-
return null;
|
|
1096
|
-
}
|
|
1097
|
-
try {
|
|
1098
|
-
const path = primaryFont.getPath(run, x, y, fontSize, { kerning: true });
|
|
1099
|
-
const d = path.toPathData(2);
|
|
1100
|
-
if (d && d !== "M0 0") return { pathData: d, advance: measureRunWidth(primaryFont, run, fontSize) };
|
|
1101
|
-
return { pathData: "", advance: measureRunWidth(primaryFont, run, fontSize) };
|
|
1102
|
-
} catch (err) {
|
|
1103
|
-
console.warn(`[text-to-path] opentype getPath failed for "${run}":`, err);
|
|
1104
|
-
return null;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
function parseTranslate(transform) {
|
|
1108
|
-
if (!transform) return { tx: 0, ty: 0 };
|
|
1109
|
-
const m = transform.match(/translate\(\s*([-\d.]+)[ \s,]+([-\d.]+)\s*\)/);
|
|
1110
|
-
if (m) return { tx: parseFloat(m[1]), ty: parseFloat(m[2]) };
|
|
1111
|
-
const mm = transform.match(/matrix\(\s*([-\d.]+)[ \s,]+([-\d.]+)[ \s,]+([-\d.]+)[ \s,]+([-\d.]+)[ \s,]+([-\d.]+)[ \s,]+([-\d.]+)\s*\)/);
|
|
1112
|
-
if (mm) return { tx: parseFloat(mm[5]), ty: parseFloat(mm[6]) };
|
|
1113
|
-
return { tx: 0, ty: 0 };
|
|
1114
|
-
}
|
|
1115
|
-
function needsComplexShaping(text) {
|
|
1116
|
-
if (!text) return false;
|
|
1117
|
-
for (const ch of text) {
|
|
1118
|
-
const c = ch.codePointAt(0) ?? 0;
|
|
1119
|
-
if (c >= 2304 && c <= 2431 || c >= 43232 && c <= 43263 || c >= 7376 && c <= 7423) return true;
|
|
1120
|
-
if (c >= 2432 && c <= 3583) return true;
|
|
1121
|
-
if (c >= 3584 && c <= 4095) return true;
|
|
1122
|
-
if (c >= 4096 && c <= 4255) return true;
|
|
1123
|
-
if (c >= 6016 && c <= 6143) return true;
|
|
1124
|
-
if (c >= 1424 && c <= 1791) return true;
|
|
1125
|
-
if (c >= 1792 && c <= 1871) return true;
|
|
1126
|
-
if (c >= 12288 && c <= 40959) return true;
|
|
1127
|
-
if (c >= 44032 && c <= 55215) return true;
|
|
1128
|
-
if (c >= 126976) return true;
|
|
1129
|
-
if (c >= 8592 && c <= 8703) return true;
|
|
1130
|
-
if (c >= 8704 && c <= 8959) return true;
|
|
1131
|
-
if (c >= 8960 && c <= 9215) return true;
|
|
1132
|
-
if (c >= 10176 && c <= 10223) return true;
|
|
1133
|
-
if (c >= 10624 && c <= 10751) return true;
|
|
1134
|
-
if (c >= 10752 && c <= 11007) return true;
|
|
1135
|
-
if (c >= 11008 && c <= 11097) return true;
|
|
1136
|
-
}
|
|
1137
|
-
return false;
|
|
1138
|
-
}
|
|
1139
|
-
async function convertDevanagariTextToPath(svgStr, fontBaseUrl, options = {}) {
|
|
1140
|
-
var _a, _b, _c;
|
|
1141
|
-
const baseUrl = fontBaseUrl ?? (typeof window !== "undefined" ? window.location.origin + "/fonts/" : "/fonts/");
|
|
1142
|
-
const mode = options.mode ?? "all";
|
|
1143
|
-
const parser = new DOMParser();
|
|
1144
|
-
const doc = parser.parseFromString(svgStr, "image/svg+xml");
|
|
1145
|
-
const textEls = doc.querySelectorAll("text");
|
|
1146
|
-
let convertedCount = 0;
|
|
1147
|
-
let skippedCount = 0;
|
|
1148
|
-
for (const textEl of textEls) {
|
|
1149
|
-
const fullText = textEl.textContent || "";
|
|
1150
|
-
if (!fullText.trim()) continue;
|
|
1151
|
-
const hasMixedStyleTspans = () => {
|
|
1152
|
-
const tspansAll = textEl.querySelectorAll("tspan");
|
|
1153
|
-
const readProp = (el, prop) => {
|
|
1154
|
-
const attr = (el.getAttribute(prop) || "").trim();
|
|
1155
|
-
if (attr) return attr;
|
|
1156
|
-
const style = el.getAttribute("style") || "";
|
|
1157
|
-
const m = style.match(new RegExp(`(?:^|;)\\s*${prop}\\s*:\\s*([^;]+)`, "i"));
|
|
1158
|
-
return m ? m[1].trim() : "";
|
|
1159
|
-
};
|
|
1160
|
-
const baseWeight = readProp(textEl, "font-weight");
|
|
1161
|
-
const baseStyle = readProp(textEl, "font-style");
|
|
1162
|
-
const baseFill = readProp(textEl, "fill");
|
|
1163
|
-
const baseDeco = readProp(textEl, "text-decoration");
|
|
1164
|
-
for (const ts of tspansAll) {
|
|
1165
|
-
const tw = readProp(ts, "font-weight");
|
|
1166
|
-
const tst = readProp(ts, "font-style");
|
|
1167
|
-
const tFill = readProp(ts, "fill");
|
|
1168
|
-
const tDeco = readProp(ts, "text-decoration");
|
|
1169
|
-
const tBg = (ts.getAttribute("style") || "").match(/background|text-background/i);
|
|
1170
|
-
if (tw && tw !== baseWeight || tst && tst !== baseStyle || tFill && tFill !== baseFill || tDeco && tDeco !== baseDeco || tBg) {
|
|
1171
|
-
return true;
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
|
-
return false;
|
|
1175
|
-
};
|
|
1176
|
-
if (mode === "complex-only" && !needsComplexShaping(fullText) && !hasMixedStyleTspans()) {
|
|
1177
|
-
skippedCount++;
|
|
1178
|
-
continue;
|
|
1179
|
-
}
|
|
1180
|
-
if (mode === "mixed-style-only" && !hasMixedStyleTspans()) {
|
|
1181
|
-
skippedCount++;
|
|
1182
|
-
continue;
|
|
1183
|
-
}
|
|
1184
|
-
const readStyleToken = (style, prop) => {
|
|
1185
|
-
var _a2;
|
|
1186
|
-
const m = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
|
|
1187
|
-
return ((_a2 = m == null ? void 0 : m[1]) == null ? void 0 : _a2.trim()) || null;
|
|
1188
|
-
};
|
|
1189
|
-
const getAttrOrStyle = (el, attr) => {
|
|
1190
|
-
var _a2;
|
|
1191
|
-
let current = el;
|
|
1192
|
-
while (current) {
|
|
1193
|
-
const attrVal = (_a2 = current.getAttribute(attr)) == null ? void 0 : _a2.trim();
|
|
1194
|
-
if (attrVal) return attrVal;
|
|
1195
|
-
const styleVal = readStyleToken(current.getAttribute("style") || "", attr);
|
|
1196
|
-
if (styleVal) return styleVal;
|
|
1197
|
-
current = current.parentElement;
|
|
1198
|
-
}
|
|
1199
|
-
return null;
|
|
1200
|
-
};
|
|
1201
|
-
const fontFamily = (_b = (_a = getAttrOrStyle(textEl, "font-family")) == null ? void 0 : _a.split(",")[0]) == null ? void 0 : _b.replace(/['"]/g, "").trim();
|
|
1202
|
-
const fontSizeStr = getAttrOrStyle(textEl, "font-size") || "16";
|
|
1203
|
-
const fontSize = parseFloat(fontSizeStr);
|
|
1204
|
-
const fontWeightStr = getAttrOrStyle(textEl, "font-weight") || "400";
|
|
1205
|
-
const fontWeight = Number.parseInt(fontWeightStr, 10) || 400;
|
|
1206
|
-
const fillColor = getAttrOrStyle(textEl, "fill") || "#000000";
|
|
1207
|
-
const fillOpacity = getAttrOrStyle(textEl, "fill-opacity") || "1";
|
|
1208
|
-
if (!fontFamily) {
|
|
1209
|
-
skippedCount++;
|
|
1210
|
-
continue;
|
|
1211
|
-
}
|
|
1212
|
-
const primaryFont = await loadFont(fontFamily, fontWeight, baseUrl);
|
|
1213
|
-
const primaryBytes = await getFontBytes(fontFamily, fontWeight, baseUrl);
|
|
1214
|
-
const hasDeva = containsDevanagari(fullText);
|
|
1215
|
-
const hasSymbol = [...fullText].some((char) => classifyCharForFontRun(char) === "symbol");
|
|
1216
|
-
const hasMath = [...fullText].some((char) => classifyCharForFontRun(char) === "math");
|
|
1217
|
-
const devaCandidateFamilies = hasDeva ? uniqueFamilies([fontFamily, FONT_FALLBACK_DEVANAGARI, resolveDevanagariSibling(fontFamily)]) : [];
|
|
1218
|
-
const devaRunFontCache = /* @__PURE__ */ new Map();
|
|
1219
|
-
const resolveDevaFontForRun = (runText, runFontSize) => {
|
|
1220
|
-
const cacheKey = `${runText}__${runFontSize}`;
|
|
1221
|
-
const cached = devaRunFontCache.get(cacheKey);
|
|
1222
|
-
if (cached) return cached;
|
|
1223
|
-
const promise = (async () => {
|
|
1224
|
-
const browserWidth = measureBrowserWidth(fontFamily, fontWeight, runFontSize, runText);
|
|
1225
|
-
let best = null;
|
|
1226
|
-
for (const family of devaCandidateFamilies) {
|
|
1227
|
-
const font = family === fontFamily ? primaryFont : await loadFont(family, fontWeight, baseUrl);
|
|
1228
|
-
const bytes = family === fontFamily ? primaryBytes : await getFontBytes(family, fontWeight, baseUrl);
|
|
1229
|
-
if (!font || !bytes || !fontSupportsRun(font, runText, "devanagari")) continue;
|
|
1230
|
-
const width = measureRunWidth(font, runText, runFontSize);
|
|
1231
|
-
const diff = browserWidth == null ? 0 : Math.abs(width - browserWidth);
|
|
1232
|
-
if (!best || diff < best.diff) best = { family, font, bytes, diff };
|
|
1233
|
-
if (browserWidth != null && diff <= 0.25) break;
|
|
1234
|
-
}
|
|
1235
|
-
if (best) {
|
|
1236
|
-
console.log("[text-to-path] Devanagari font resolved", {
|
|
1237
|
-
requestedFamily: fontFamily,
|
|
1238
|
-
resolvedFamily: best.family,
|
|
1239
|
-
browserWidth,
|
|
1240
|
-
diff: Math.round(best.diff * 100) / 100
|
|
1241
|
-
});
|
|
1242
|
-
}
|
|
1243
|
-
return best;
|
|
1244
|
-
})();
|
|
1245
|
-
devaRunFontCache.set(cacheKey, promise);
|
|
1246
|
-
return promise;
|
|
1247
|
-
};
|
|
1248
|
-
const symbolRunFontPromise = hasSymbol ? (async () => {
|
|
1249
|
-
const symbolFont = await loadFont(FONT_FALLBACK_SYMBOLS, 400, baseUrl);
|
|
1250
|
-
const symbolBytes = await getFontBytes(FONT_FALLBACK_SYMBOLS, 400, baseUrl);
|
|
1251
|
-
return symbolFont && symbolBytes ? { family: FONT_FALLBACK_SYMBOLS, font: symbolFont, bytes: symbolBytes } : null;
|
|
1252
|
-
})() : null;
|
|
1253
|
-
const mathRunFontPromise = hasMath ? (async () => {
|
|
1254
|
-
const mathFont = await loadFont(FONT_FALLBACK_MATH, 400, baseUrl);
|
|
1255
|
-
const mathBytes = await getFontBytes(FONT_FALLBACK_MATH, 400, baseUrl);
|
|
1256
|
-
return mathFont && mathBytes ? { family: FONT_FALLBACK_MATH, font: mathFont, bytes: mathBytes } : null;
|
|
1257
|
-
})() : null;
|
|
1258
|
-
if (!primaryFont && !hasDeva && !hasSymbol && !hasMath) {
|
|
1259
|
-
console.warn(`[text-to-path] No font available for "${fontFamily}", leaving as <text>`);
|
|
1260
|
-
skippedCount++;
|
|
1261
|
-
continue;
|
|
1262
|
-
}
|
|
1263
|
-
const textAnchorRaw = (getAttrOrStyle(textEl, "text-anchor") || "start").toLowerCase();
|
|
1264
|
-
const textAnchor = textAnchorRaw === "middle" ? "middle" : textAnchorRaw === "end" ? "end" : "start";
|
|
1265
|
-
const tspans = textEl.querySelectorAll("tspan");
|
|
1266
|
-
const elementsToProcess = tspans.length > 0 ? Array.from(tspans) : [textEl];
|
|
1267
|
-
const group = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
1268
|
-
const textTransform = textEl.getAttribute("transform");
|
|
1269
|
-
if (textTransform) group.setAttribute("transform", textTransform);
|
|
1270
|
-
const baseX = parseFloat(textEl.getAttribute("x") || "0");
|
|
1271
|
-
const baseY = parseFloat(textEl.getAttribute("y") || "0");
|
|
1272
|
-
for (const elem of elementsToProcess) {
|
|
1273
|
-
const text = elem.textContent || "";
|
|
1274
|
-
if (!text.trim()) continue;
|
|
1275
|
-
const elemX = parseFloat(elem.getAttribute("x") || String(baseX));
|
|
1276
|
-
const elemY = parseFloat(elem.getAttribute("y") || String(baseY));
|
|
1277
|
-
const elemTransform = elem !== textEl ? parseTranslate(elem.getAttribute("transform")) : { tx: 0, ty: 0 };
|
|
1278
|
-
let x = elemX + elemTransform.tx;
|
|
1279
|
-
const y = elemY + elemTransform.ty;
|
|
1280
|
-
const elemFill = getAttrOrStyle(elem, "fill") || fillColor;
|
|
1281
|
-
const elemFillOpacity = getAttrOrStyle(elem, "fill-opacity") || fillOpacity;
|
|
1282
|
-
const elemFontSizeStr = getAttrOrStyle(elem, "font-size") || String(fontSize);
|
|
1283
|
-
const elemFontSize = parseFloat(elemFontSizeStr);
|
|
1284
|
-
const elemWeightStr = getAttrOrStyle(elem, "font-weight") || String(fontWeight);
|
|
1285
|
-
const elemWeight = Number.parseInt(elemWeightStr, 10) || (/bold/i.test(elemWeightStr) ? 700 : fontWeight);
|
|
1286
|
-
const elemStyleRaw = (getAttrOrStyle(elem, "font-style") || "normal").toLowerCase();
|
|
1287
|
-
const elemItalic = /italic|oblique/i.test(elemStyleRaw);
|
|
1288
|
-
const sameAsPrimary = elemWeight === fontWeight && !elemItalic;
|
|
1289
|
-
const elemFont = sameAsPrimary ? primaryFont : await loadFont(fontFamily, elemWeight, baseUrl, elemItalic);
|
|
1290
|
-
const elemBytes = sameAsPrimary ? primaryBytes : await getFontBytes(fontFamily, elemWeight, baseUrl, elemItalic);
|
|
1291
|
-
const fontForElem = elemFont || primaryFont;
|
|
1292
|
-
const bytesForElem = elemBytes || primaryBytes;
|
|
1293
|
-
const runs = splitByFontRun(text);
|
|
1294
|
-
let totalAdvance = 0;
|
|
1295
|
-
let canMeasureAll = true;
|
|
1296
|
-
for (const r of runs) {
|
|
1297
|
-
if (r.runType === "devanagari") {
|
|
1298
|
-
const resolved = await resolveDevaFontForRun(r.text, elemFontSize);
|
|
1299
|
-
if (resolved) totalAdvance += measureRunWidth(resolved.font, r.text, elemFontSize);
|
|
1300
|
-
else canMeasureAll = false;
|
|
1301
|
-
} else if (r.runType === "symbol") {
|
|
1302
|
-
const resolved = await symbolRunFontPromise;
|
|
1303
|
-
if (resolved && fontSupportsRun(resolved.font, r.text, "symbol")) totalAdvance += measureRunWidth(resolved.font, r.text, elemFontSize);
|
|
1304
|
-
else canMeasureAll = false;
|
|
1305
|
-
} else if (r.runType === "math") {
|
|
1306
|
-
const resolved = await mathRunFontPromise;
|
|
1307
|
-
if (resolved && fontSupportsRun(resolved.font, r.text, "math")) totalAdvance += measureRunWidth(resolved.font, r.text, elemFontSize);
|
|
1308
|
-
else canMeasureAll = false;
|
|
1309
|
-
} else {
|
|
1310
|
-
if (fontForElem) totalAdvance += measureRunWidth(fontForElem, r.text, elemFontSize);
|
|
1311
|
-
else canMeasureAll = false;
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
if (canMeasureAll) {
|
|
1315
|
-
if (textAnchor === "middle") x -= totalAdvance / 2;
|
|
1316
|
-
else if (textAnchor === "end") x -= totalAdvance;
|
|
1317
|
-
}
|
|
1318
|
-
let cursor = x;
|
|
1319
|
-
let elemConverted = false;
|
|
1320
|
-
for (const r of runs) {
|
|
1321
|
-
const resolvedDeva = r.runType === "devanagari" ? await resolveDevaFontForRun(r.text, elemFontSize) : null;
|
|
1322
|
-
const resolvedSymbol = r.runType === "symbol" ? await symbolRunFontPromise : null;
|
|
1323
|
-
const resolvedMath = r.runType === "math" ? await mathRunFontPromise : null;
|
|
1324
|
-
const useDeva = !!resolvedDeva;
|
|
1325
|
-
const fontForRun = (resolvedDeva == null ? void 0 : resolvedDeva.font) ?? (resolvedSymbol == null ? void 0 : resolvedSymbol.font) ?? (resolvedMath == null ? void 0 : resolvedMath.font) ?? fontForElem;
|
|
1326
|
-
const bytesForRun = (resolvedDeva == null ? void 0 : resolvedDeva.bytes) ?? (resolvedSymbol == null ? void 0 : resolvedSymbol.bytes) ?? (resolvedMath == null ? void 0 : resolvedMath.bytes) ?? bytesForElem;
|
|
1327
|
-
if (!fontForRun) continue;
|
|
1328
|
-
const result = await shapeRunToPath(
|
|
1329
|
-
r.text,
|
|
1330
|
-
!!useDeva,
|
|
1331
|
-
fontForRun,
|
|
1332
|
-
bytesForRun,
|
|
1333
|
-
(resolvedDeva == null ? void 0 : resolvedDeva.font) ?? null,
|
|
1334
|
-
(resolvedDeva == null ? void 0 : resolvedDeva.bytes) ?? null,
|
|
1335
|
-
cursor,
|
|
1336
|
-
y,
|
|
1337
|
-
elemFontSize
|
|
1338
|
-
);
|
|
1339
|
-
if (result && result.pathData) {
|
|
1340
|
-
const pathEl = doc.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
1341
|
-
pathEl.setAttribute("d", result.pathData);
|
|
1342
|
-
pathEl.setAttribute("fill", elemFill);
|
|
1343
|
-
if (elemItalic && !fontLooksItalic(fontForRun)) {
|
|
1344
|
-
pathEl.setAttribute("transform", syntheticItalicTransform(cursor, y));
|
|
1345
|
-
}
|
|
1346
|
-
if (elemFillOpacity !== "1") {
|
|
1347
|
-
pathEl.setAttribute("fill-opacity", elemFillOpacity);
|
|
1348
|
-
}
|
|
1349
|
-
group.appendChild(pathEl);
|
|
1350
|
-
elemConverted = true;
|
|
1351
|
-
}
|
|
1352
|
-
if (result) cursor += result.advance;
|
|
1353
|
-
}
|
|
1354
|
-
if (elemConverted) {
|
|
1355
|
-
convertedCount++;
|
|
1356
|
-
} else {
|
|
1357
|
-
if (elem === textEl) {
|
|
1358
|
-
const clone = elem.cloneNode(true);
|
|
1359
|
-
if (textTransform) clone.removeAttribute("transform");
|
|
1360
|
-
group.appendChild(clone);
|
|
1361
|
-
} else {
|
|
1362
|
-
const newText = doc.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
1363
|
-
newText.setAttribute("x", String(elemX));
|
|
1364
|
-
newText.setAttribute("y", String(elemY));
|
|
1365
|
-
if (elem.getAttribute("style")) newText.setAttribute("style", elem.getAttribute("style"));
|
|
1366
|
-
if (elem.getAttribute("font-family")) newText.setAttribute("font-family", elem.getAttribute("font-family"));
|
|
1367
|
-
if (elem.getAttribute("font-size")) newText.setAttribute("font-size", elem.getAttribute("font-size"));
|
|
1368
|
-
if (elem.getAttribute("font-weight")) newText.setAttribute("font-weight", elem.getAttribute("font-weight"));
|
|
1369
|
-
newText.textContent = text;
|
|
1370
|
-
group.appendChild(newText);
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
if (group.childNodes.length > 0) {
|
|
1375
|
-
(_c = textEl.parentNode) == null ? void 0 : _c.replaceChild(group, textEl);
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
console.log(
|
|
1379
|
-
`[text-to-path] Universal outline complete: converted=${convertedCount} skipped=${skippedCount}`
|
|
1380
|
-
);
|
|
1381
|
-
return new XMLSerializer().serializeToString(doc.documentElement);
|
|
1382
|
-
}
|
|
1383
|
-
const convertAllTextToPath = convertDevanagariTextToPath;
|
|
1384
|
-
async function preloadDevanagariFont(fontBaseUrl) {
|
|
1385
|
-
const baseUrl = fontBaseUrl ?? (typeof window !== "undefined" ? window.location.origin + "/fonts/" : "/fonts/");
|
|
1386
|
-
for (const weight of [300, 400, 500, 600, 700]) {
|
|
1387
|
-
await loadFont(FONT_FALLBACK_DEVANAGARI, weight, baseUrl);
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
exports.convertAllTextToPath = convertAllTextToPath;
|
|
1391
|
-
exports.convertDevanagariTextToPath = convertDevanagariTextToPath;
|
|
1392
|
-
exports.preloadDevanagariFont = preloadDevanagariFont;
|
|
1393
|
-
//# sourceMappingURL=svgTextToPath-4Y_THSBg.cjs.map
|