@pixldocs/canvas-renderer 0.5.68 → 0.5.71
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.cjs +1474 -1458
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1474 -1458
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12123,865 +12123,12 @@ function paintRepeatableSections(config, repeatableSections) {
|
|
|
12123
12123
|
}
|
|
12124
12124
|
}
|
|
12125
12125
|
}
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
500: "Medium",
|
|
12130
|
-
600: "SemiBold",
|
|
12131
|
-
700: "Bold"
|
|
12132
|
-
};
|
|
12133
|
-
function resolveFontWeight(weight) {
|
|
12134
|
-
if (weight <= 350) return 300;
|
|
12135
|
-
if (weight <= 450) return 400;
|
|
12136
|
-
if (weight <= 550) return 500;
|
|
12137
|
-
if (weight <= 650) return 600;
|
|
12138
|
-
return 700;
|
|
12139
|
-
}
|
|
12140
|
-
const FONT_FALLBACK_SYMBOLS = "Noto Sans";
|
|
12141
|
-
const FONT_FALLBACK_DEVANAGARI = "Hind";
|
|
12142
|
-
const FONT_FILES = {
|
|
12143
|
-
"Playfair Display": {
|
|
12144
|
-
regular: "PlayfairDisplay-Regular.ttf",
|
|
12145
|
-
bold: "PlayfairDisplay-Bold.ttf",
|
|
12146
|
-
italic: "PlayfairDisplay-Italic.ttf",
|
|
12147
|
-
boldItalic: "PlayfairDisplay-BoldItalic.ttf"
|
|
12148
|
-
},
|
|
12149
|
-
"Merriweather": {
|
|
12150
|
-
regular: "Merriweather-Regular.ttf",
|
|
12151
|
-
bold: "Merriweather-Bold.ttf",
|
|
12152
|
-
light: "Merriweather-Light.ttf",
|
|
12153
|
-
italic: "Merriweather-Italic.ttf",
|
|
12154
|
-
boldItalic: "Merriweather-BoldItalic.ttf",
|
|
12155
|
-
lightItalic: "Merriweather-LightItalic.ttf"
|
|
12156
|
-
},
|
|
12157
|
-
"Lora": {
|
|
12158
|
-
regular: "Lora-Regular.ttf",
|
|
12159
|
-
bold: "Lora-Bold.ttf",
|
|
12160
|
-
italic: "Lora-Italic.ttf",
|
|
12161
|
-
boldItalic: "Lora-BoldItalic.ttf"
|
|
12162
|
-
},
|
|
12163
|
-
"Montserrat": {
|
|
12164
|
-
regular: "Montserrat-Regular.ttf",
|
|
12165
|
-
bold: "Montserrat-Bold.ttf",
|
|
12166
|
-
light: "Montserrat-Light.ttf",
|
|
12167
|
-
medium: "Montserrat-Medium.ttf",
|
|
12168
|
-
semibold: "Montserrat-SemiBold.ttf",
|
|
12169
|
-
italic: "Montserrat-Italic.ttf",
|
|
12170
|
-
boldItalic: "Montserrat-BoldItalic.ttf",
|
|
12171
|
-
lightItalic: "Montserrat-LightItalic.ttf",
|
|
12172
|
-
mediumItalic: "Montserrat-MediumItalic.ttf",
|
|
12173
|
-
semiboldItalic: "Montserrat-SemiBoldItalic.ttf"
|
|
12174
|
-
},
|
|
12175
|
-
"Open Sans": {
|
|
12176
|
-
regular: "OpenSans-Regular.ttf",
|
|
12177
|
-
bold: "OpenSans-Bold.ttf",
|
|
12178
|
-
light: "OpenSans-Light.ttf",
|
|
12179
|
-
semibold: "OpenSans-SemiBold.ttf",
|
|
12180
|
-
italic: "OpenSans-Italic.ttf",
|
|
12181
|
-
boldItalic: "OpenSans-BoldItalic.ttf",
|
|
12182
|
-
lightItalic: "OpenSans-LightItalic.ttf",
|
|
12183
|
-
semiboldItalic: "OpenSans-SemiBoldItalic.ttf"
|
|
12184
|
-
},
|
|
12185
|
-
"Roboto": {
|
|
12186
|
-
regular: "Roboto-Regular.ttf",
|
|
12187
|
-
bold: "Roboto-Bold.ttf",
|
|
12188
|
-
light: "Roboto-Light.ttf",
|
|
12189
|
-
medium: "Roboto-Medium.ttf",
|
|
12190
|
-
italic: "Roboto-Italic.ttf",
|
|
12191
|
-
boldItalic: "Roboto-BoldItalic.ttf",
|
|
12192
|
-
lightItalic: "Roboto-LightItalic.ttf",
|
|
12193
|
-
mediumItalic: "Roboto-MediumItalic.ttf"
|
|
12194
|
-
},
|
|
12195
|
-
"Lato": {
|
|
12196
|
-
regular: "Lato-Regular.ttf",
|
|
12197
|
-
bold: "Lato-Bold.ttf",
|
|
12198
|
-
light: "Lato-Light.ttf",
|
|
12199
|
-
italic: "Lato-Italic.ttf",
|
|
12200
|
-
boldItalic: "Lato-BoldItalic.ttf",
|
|
12201
|
-
lightItalic: "Lato-LightItalic.ttf"
|
|
12202
|
-
},
|
|
12203
|
-
"Raleway": {
|
|
12204
|
-
regular: "Raleway-Regular.ttf",
|
|
12205
|
-
bold: "Raleway-Bold.ttf",
|
|
12206
|
-
light: "Raleway-Light.ttf",
|
|
12207
|
-
medium: "Raleway-Medium.ttf",
|
|
12208
|
-
semibold: "Raleway-SemiBold.ttf",
|
|
12209
|
-
italic: "Raleway-Italic.ttf",
|
|
12210
|
-
boldItalic: "Raleway-BoldItalic.ttf",
|
|
12211
|
-
lightItalic: "Raleway-LightItalic.ttf"
|
|
12212
|
-
},
|
|
12213
|
-
"Poppins": {
|
|
12214
|
-
regular: "Poppins-Regular.ttf",
|
|
12215
|
-
bold: "Poppins-Bold.ttf",
|
|
12216
|
-
light: "Poppins-Light.ttf",
|
|
12217
|
-
medium: "Poppins-Medium.ttf",
|
|
12218
|
-
semibold: "Poppins-SemiBold.ttf",
|
|
12219
|
-
italic: "Poppins-Italic.ttf",
|
|
12220
|
-
boldItalic: "Poppins-BoldItalic.ttf",
|
|
12221
|
-
lightItalic: "Poppins-LightItalic.ttf",
|
|
12222
|
-
mediumItalic: "Poppins-MediumItalic.ttf",
|
|
12223
|
-
semiboldItalic: "Poppins-SemiBoldItalic.ttf"
|
|
12224
|
-
},
|
|
12225
|
-
"Inter": {
|
|
12226
|
-
regular: "Inter-Regular.ttf",
|
|
12227
|
-
bold: "Inter-Bold.ttf",
|
|
12228
|
-
italic: "Inter-Italic.ttf",
|
|
12229
|
-
boldItalic: "Inter-BoldItalic.ttf"
|
|
12230
|
-
},
|
|
12231
|
-
"Nunito": {
|
|
12232
|
-
regular: "Nunito-Regular.ttf",
|
|
12233
|
-
bold: "Nunito-Bold.ttf",
|
|
12234
|
-
light: "Nunito-Light.ttf",
|
|
12235
|
-
medium: "Nunito-Medium.ttf",
|
|
12236
|
-
semibold: "Nunito-SemiBold.ttf",
|
|
12237
|
-
italic: "Nunito-Italic.ttf",
|
|
12238
|
-
boldItalic: "Nunito-BoldItalic.ttf"
|
|
12239
|
-
},
|
|
12240
|
-
"Source Sans Pro": {
|
|
12241
|
-
regular: "SourceSansPro-Regular.ttf",
|
|
12242
|
-
bold: "SourceSansPro-Bold.ttf",
|
|
12243
|
-
light: "SourceSansPro-Light.ttf",
|
|
12244
|
-
italic: "SourceSansPro-Italic.ttf",
|
|
12245
|
-
boldItalic: "SourceSansPro-BoldItalic.ttf"
|
|
12246
|
-
},
|
|
12247
|
-
"Work Sans": {
|
|
12248
|
-
regular: "WorkSans-Regular.ttf",
|
|
12249
|
-
bold: "WorkSans-Bold.ttf",
|
|
12250
|
-
italic: "WorkSans-Italic.ttf",
|
|
12251
|
-
boldItalic: "WorkSans-BoldItalic.ttf"
|
|
12252
|
-
},
|
|
12253
|
-
"Oswald": { regular: "Oswald-Regular.ttf", bold: "Oswald-Bold.ttf" },
|
|
12254
|
-
"Bebas Neue": { regular: "BebasNeue-Regular.ttf" },
|
|
12255
|
-
"Abril Fatface": { regular: "AbrilFatface-Regular.ttf" },
|
|
12256
|
-
"Dancing Script": { regular: "DancingScript-Regular.ttf", bold: "DancingScript-Bold.ttf" },
|
|
12257
|
-
"Pacifico": { regular: "Pacifico-Regular.ttf" },
|
|
12258
|
-
"Great Vibes": { regular: "GreatVibes-Regular.ttf" },
|
|
12259
|
-
"DM Sans": {
|
|
12260
|
-
regular: "DMSans-Regular.ttf",
|
|
12261
|
-
bold: "DMSans-Bold.ttf",
|
|
12262
|
-
light: "DMSans-Light.ttf",
|
|
12263
|
-
medium: "DMSans-Medium.ttf",
|
|
12264
|
-
semibold: "DMSans-SemiBold.ttf",
|
|
12265
|
-
italic: "DMSans-RegularItalic.ttf",
|
|
12266
|
-
boldItalic: "DMSans-BoldItalic.ttf",
|
|
12267
|
-
lightItalic: "DMSans-LightItalic.ttf",
|
|
12268
|
-
mediumItalic: "DMSans-MediumItalic.ttf",
|
|
12269
|
-
semiboldItalic: "DMSans-SemiBoldItalic.ttf"
|
|
12270
|
-
},
|
|
12271
|
-
"Outfit": {
|
|
12272
|
-
regular: "Outfit-Regular.ttf",
|
|
12273
|
-
bold: "Outfit-Bold.ttf",
|
|
12274
|
-
light: "Outfit-Light.ttf",
|
|
12275
|
-
medium: "Outfit-Medium.ttf",
|
|
12276
|
-
semibold: "Outfit-SemiBold.ttf"
|
|
12277
|
-
},
|
|
12278
|
-
"Figtree": {
|
|
12279
|
-
regular: "Figtree-Regular.ttf",
|
|
12280
|
-
bold: "Figtree-Bold.ttf",
|
|
12281
|
-
light: "Figtree-Light.ttf",
|
|
12282
|
-
medium: "Figtree-Medium.ttf",
|
|
12283
|
-
semibold: "Figtree-SemiBold.ttf",
|
|
12284
|
-
italic: "Figtree-RegularItalic.ttf",
|
|
12285
|
-
boldItalic: "Figtree-BoldItalic.ttf",
|
|
12286
|
-
lightItalic: "Figtree-LightItalic.ttf",
|
|
12287
|
-
mediumItalic: "Figtree-MediumItalic.ttf",
|
|
12288
|
-
semiboldItalic: "Figtree-SemiBoldItalic.ttf"
|
|
12289
|
-
},
|
|
12290
|
-
"Manrope": {
|
|
12291
|
-
regular: "Manrope-Regular.ttf",
|
|
12292
|
-
bold: "Manrope-Bold.ttf",
|
|
12293
|
-
light: "Manrope-Light.ttf",
|
|
12294
|
-
medium: "Manrope-Medium.ttf",
|
|
12295
|
-
semibold: "Manrope-SemiBold.ttf"
|
|
12296
|
-
},
|
|
12297
|
-
"Space Grotesk": {
|
|
12298
|
-
regular: "SpaceGrotesk-Regular.ttf",
|
|
12299
|
-
bold: "SpaceGrotesk-Bold.ttf",
|
|
12300
|
-
light: "SpaceGrotesk-Light.ttf",
|
|
12301
|
-
medium: "SpaceGrotesk-Medium.ttf",
|
|
12302
|
-
semibold: "SpaceGrotesk-SemiBold.ttf"
|
|
12303
|
-
},
|
|
12304
|
-
"League Spartan": {
|
|
12305
|
-
regular: "LeagueSpartan-Regular.ttf",
|
|
12306
|
-
bold: "LeagueSpartan-Bold.ttf",
|
|
12307
|
-
light: "LeagueSpartan-Light.ttf",
|
|
12308
|
-
medium: "LeagueSpartan-Medium.ttf",
|
|
12309
|
-
semibold: "LeagueSpartan-SemiBold.ttf"
|
|
12310
|
-
},
|
|
12311
|
-
"EB Garamond": {
|
|
12312
|
-
regular: "EBGaramond-Regular.ttf",
|
|
12313
|
-
bold: "EBGaramond-Bold.ttf",
|
|
12314
|
-
medium: "EBGaramond-Medium.ttf",
|
|
12315
|
-
semibold: "EBGaramond-SemiBold.ttf",
|
|
12316
|
-
italic: "EBGaramond-RegularItalic.ttf",
|
|
12317
|
-
boldItalic: "EBGaramond-BoldItalic.ttf",
|
|
12318
|
-
mediumItalic: "EBGaramond-MediumItalic.ttf",
|
|
12319
|
-
semiboldItalic: "EBGaramond-SemiBoldItalic.ttf"
|
|
12320
|
-
},
|
|
12321
|
-
"Libre Baskerville": {
|
|
12322
|
-
regular: "LibreBaskerville-Regular.ttf",
|
|
12323
|
-
bold: "LibreBaskerville-Bold.ttf",
|
|
12324
|
-
italic: "LibreBaskerville-RegularItalic.ttf",
|
|
12325
|
-
boldItalic: "LibreBaskerville-BoldItalic.ttf"
|
|
12326
|
-
},
|
|
12327
|
-
"Crimson Text": {
|
|
12328
|
-
regular: "CrimsonText-Regular.ttf",
|
|
12329
|
-
bold: "CrimsonText-Bold.ttf",
|
|
12330
|
-
italic: "CrimsonText-Italic.ttf",
|
|
12331
|
-
boldItalic: "CrimsonText-BoldItalic.ttf"
|
|
12332
|
-
},
|
|
12333
|
-
"DM Serif Display": {
|
|
12334
|
-
regular: "DMSerifDisplay-Regular.ttf",
|
|
12335
|
-
italic: "DMSerifDisplay-Italic.ttf"
|
|
12336
|
-
},
|
|
12337
|
-
"Libre Franklin": {
|
|
12338
|
-
regular: "LibreFranklin-Regular.ttf",
|
|
12339
|
-
bold: "LibreFranklin-Bold.ttf",
|
|
12340
|
-
light: "LibreFranklin-Light.ttf",
|
|
12341
|
-
medium: "LibreFranklin-Medium.ttf",
|
|
12342
|
-
semibold: "LibreFranklin-SemiBold.ttf",
|
|
12343
|
-
italic: "LibreFranklin-RegularItalic.ttf",
|
|
12344
|
-
boldItalic: "LibreFranklin-BoldItalic.ttf",
|
|
12345
|
-
lightItalic: "LibreFranklin-LightItalic.ttf",
|
|
12346
|
-
mediumItalic: "LibreFranklin-MediumItalic.ttf",
|
|
12347
|
-
semiboldItalic: "LibreFranklin-SemiBoldItalic.ttf"
|
|
12348
|
-
},
|
|
12349
|
-
"Mulish": {
|
|
12350
|
-
regular: "Mulish-Regular.ttf",
|
|
12351
|
-
bold: "Mulish-Bold.ttf",
|
|
12352
|
-
light: "Mulish-Light.ttf",
|
|
12353
|
-
medium: "Mulish-Medium.ttf",
|
|
12354
|
-
semibold: "Mulish-SemiBold.ttf",
|
|
12355
|
-
italic: "Mulish-RegularItalic.ttf",
|
|
12356
|
-
boldItalic: "Mulish-BoldItalic.ttf",
|
|
12357
|
-
lightItalic: "Mulish-LightItalic.ttf",
|
|
12358
|
-
mediumItalic: "Mulish-MediumItalic.ttf",
|
|
12359
|
-
semiboldItalic: "Mulish-SemiBoldItalic.ttf"
|
|
12360
|
-
},
|
|
12361
|
-
"Quicksand": {
|
|
12362
|
-
regular: "Quicksand-Regular.ttf",
|
|
12363
|
-
bold: "Quicksand-Bold.ttf",
|
|
12364
|
-
light: "Quicksand-Light.ttf",
|
|
12365
|
-
medium: "Quicksand-Medium.ttf",
|
|
12366
|
-
semibold: "Quicksand-SemiBold.ttf"
|
|
12367
|
-
},
|
|
12368
|
-
"Rubik": {
|
|
12369
|
-
regular: "Rubik-Regular.ttf",
|
|
12370
|
-
bold: "Rubik-Bold.ttf",
|
|
12371
|
-
light: "Rubik-Light.ttf",
|
|
12372
|
-
medium: "Rubik-Medium.ttf",
|
|
12373
|
-
semibold: "Rubik-SemiBold.ttf",
|
|
12374
|
-
italic: "Rubik-RegularItalic.ttf",
|
|
12375
|
-
boldItalic: "Rubik-BoldItalic.ttf",
|
|
12376
|
-
lightItalic: "Rubik-LightItalic.ttf",
|
|
12377
|
-
mediumItalic: "Rubik-MediumItalic.ttf",
|
|
12378
|
-
semiboldItalic: "Rubik-SemiBoldItalic.ttf"
|
|
12379
|
-
},
|
|
12380
|
-
"Karla": {
|
|
12381
|
-
regular: "Karla-Regular.ttf",
|
|
12382
|
-
bold: "Karla-Bold.ttf",
|
|
12383
|
-
light: "Karla-Light.ttf",
|
|
12384
|
-
medium: "Karla-Medium.ttf",
|
|
12385
|
-
semibold: "Karla-SemiBold.ttf",
|
|
12386
|
-
italic: "Karla-RegularItalic.ttf",
|
|
12387
|
-
boldItalic: "Karla-BoldItalic.ttf",
|
|
12388
|
-
lightItalic: "Karla-LightItalic.ttf",
|
|
12389
|
-
mediumItalic: "Karla-MediumItalic.ttf",
|
|
12390
|
-
semiboldItalic: "Karla-SemiBoldItalic.ttf"
|
|
12391
|
-
},
|
|
12392
|
-
"Plus Jakarta Sans": {
|
|
12393
|
-
regular: "PlusJakartaSans-Regular.ttf",
|
|
12394
|
-
bold: "PlusJakartaSans-Bold.ttf",
|
|
12395
|
-
light: "PlusJakartaSans-Light.ttf",
|
|
12396
|
-
medium: "PlusJakartaSans-Medium.ttf",
|
|
12397
|
-
semibold: "PlusJakartaSans-SemiBold.ttf",
|
|
12398
|
-
italic: "PlusJakartaSans-RegularItalic.ttf",
|
|
12399
|
-
boldItalic: "PlusJakartaSans-BoldItalic.ttf",
|
|
12400
|
-
lightItalic: "PlusJakartaSans-LightItalic.ttf",
|
|
12401
|
-
mediumItalic: "PlusJakartaSans-MediumItalic.ttf",
|
|
12402
|
-
semiboldItalic: "PlusJakartaSans-SemiBoldItalic.ttf"
|
|
12403
|
-
},
|
|
12404
|
-
"Sora": {
|
|
12405
|
-
regular: "Sora-Regular.ttf",
|
|
12406
|
-
bold: "Sora-Bold.ttf",
|
|
12407
|
-
light: "Sora-Light.ttf",
|
|
12408
|
-
medium: "Sora-Medium.ttf",
|
|
12409
|
-
semibold: "Sora-SemiBold.ttf"
|
|
12410
|
-
},
|
|
12411
|
-
"Urbanist": {
|
|
12412
|
-
regular: "Urbanist-Regular.ttf",
|
|
12413
|
-
bold: "Urbanist-Bold.ttf",
|
|
12414
|
-
light: "Urbanist-Light.ttf",
|
|
12415
|
-
medium: "Urbanist-Medium.ttf",
|
|
12416
|
-
semibold: "Urbanist-SemiBold.ttf",
|
|
12417
|
-
italic: "Urbanist-RegularItalic.ttf",
|
|
12418
|
-
boldItalic: "Urbanist-BoldItalic.ttf",
|
|
12419
|
-
lightItalic: "Urbanist-LightItalic.ttf",
|
|
12420
|
-
mediumItalic: "Urbanist-MediumItalic.ttf",
|
|
12421
|
-
semiboldItalic: "Urbanist-SemiBoldItalic.ttf"
|
|
12422
|
-
},
|
|
12423
|
-
"Lexend": {
|
|
12424
|
-
regular: "Lexend-Regular.ttf",
|
|
12425
|
-
bold: "Lexend-Bold.ttf",
|
|
12426
|
-
light: "Lexend-Light.ttf",
|
|
12427
|
-
medium: "Lexend-Medium.ttf",
|
|
12428
|
-
semibold: "Lexend-SemiBold.ttf"
|
|
12429
|
-
},
|
|
12430
|
-
"Albert Sans": {
|
|
12431
|
-
regular: "AlbertSans-Regular.ttf",
|
|
12432
|
-
bold: "AlbertSans-Bold.ttf",
|
|
12433
|
-
light: "AlbertSans-Light.ttf",
|
|
12434
|
-
medium: "AlbertSans-Medium.ttf",
|
|
12435
|
-
semibold: "AlbertSans-SemiBold.ttf",
|
|
12436
|
-
italic: "AlbertSans-RegularItalic.ttf",
|
|
12437
|
-
boldItalic: "AlbertSans-BoldItalic.ttf",
|
|
12438
|
-
lightItalic: "AlbertSans-LightItalic.ttf",
|
|
12439
|
-
mediumItalic: "AlbertSans-MediumItalic.ttf",
|
|
12440
|
-
semiboldItalic: "AlbertSans-SemiBoldItalic.ttf"
|
|
12441
|
-
},
|
|
12442
|
-
"Noto Sans": {
|
|
12443
|
-
regular: "NotoSans-Regular.ttf",
|
|
12444
|
-
bold: "NotoSans-Bold.ttf",
|
|
12445
|
-
light: "NotoSans-Light.ttf",
|
|
12446
|
-
medium: "NotoSans-Medium.ttf",
|
|
12447
|
-
semibold: "NotoSans-SemiBold.ttf",
|
|
12448
|
-
italic: "NotoSans-RegularItalic.ttf",
|
|
12449
|
-
boldItalic: "NotoSans-BoldItalic.ttf",
|
|
12450
|
-
lightItalic: "NotoSans-LightItalic.ttf",
|
|
12451
|
-
mediumItalic: "NotoSans-MediumItalic.ttf",
|
|
12452
|
-
semiboldItalic: "NotoSans-SemiBoldItalic.ttf"
|
|
12453
|
-
},
|
|
12454
|
-
"Cabin": {
|
|
12455
|
-
regular: "Cabin-Regular.ttf",
|
|
12456
|
-
bold: "Cabin-Bold.ttf",
|
|
12457
|
-
medium: "Cabin-Medium.ttf",
|
|
12458
|
-
semibold: "Cabin-SemiBold.ttf",
|
|
12459
|
-
italic: "Cabin-RegularItalic.ttf",
|
|
12460
|
-
boldItalic: "Cabin-BoldItalic.ttf",
|
|
12461
|
-
mediumItalic: "Cabin-MediumItalic.ttf",
|
|
12462
|
-
semiboldItalic: "Cabin-SemiBoldItalic.ttf"
|
|
12463
|
-
},
|
|
12464
|
-
"Barlow": {
|
|
12465
|
-
regular: "Barlow-Regular.ttf",
|
|
12466
|
-
bold: "Barlow-Bold.ttf",
|
|
12467
|
-
light: "Barlow-Light.ttf",
|
|
12468
|
-
medium: "Barlow-Medium.ttf",
|
|
12469
|
-
semibold: "Barlow-SemiBold.ttf",
|
|
12470
|
-
italic: "Barlow-Italic.ttf",
|
|
12471
|
-
boldItalic: "Barlow-BoldItalic.ttf"
|
|
12472
|
-
},
|
|
12473
|
-
"Josefin Sans": {
|
|
12474
|
-
regular: "JosefinSans-Regular.ttf",
|
|
12475
|
-
bold: "JosefinSans-Bold.ttf",
|
|
12476
|
-
light: "JosefinSans-Light.ttf",
|
|
12477
|
-
medium: "JosefinSans-Medium.ttf",
|
|
12478
|
-
semibold: "JosefinSans-SemiBold.ttf",
|
|
12479
|
-
italic: "JosefinSans-RegularItalic.ttf",
|
|
12480
|
-
boldItalic: "JosefinSans-BoldItalic.ttf",
|
|
12481
|
-
lightItalic: "JosefinSans-LightItalic.ttf",
|
|
12482
|
-
mediumItalic: "JosefinSans-MediumItalic.ttf",
|
|
12483
|
-
semiboldItalic: "JosefinSans-SemiBoldItalic.ttf"
|
|
12484
|
-
},
|
|
12485
|
-
"Archivo": {
|
|
12486
|
-
regular: "Archivo-Regular.ttf",
|
|
12487
|
-
bold: "Archivo-Bold.ttf",
|
|
12488
|
-
light: "Archivo-Light.ttf",
|
|
12489
|
-
medium: "Archivo-Medium.ttf",
|
|
12490
|
-
semibold: "Archivo-SemiBold.ttf",
|
|
12491
|
-
italic: "Archivo-RegularItalic.ttf",
|
|
12492
|
-
boldItalic: "Archivo-BoldItalic.ttf",
|
|
12493
|
-
lightItalic: "Archivo-LightItalic.ttf",
|
|
12494
|
-
mediumItalic: "Archivo-MediumItalic.ttf",
|
|
12495
|
-
semiboldItalic: "Archivo-SemiBoldItalic.ttf"
|
|
12496
|
-
},
|
|
12497
|
-
"Overpass": {
|
|
12498
|
-
regular: "Overpass-Regular.ttf",
|
|
12499
|
-
bold: "Overpass-Bold.ttf",
|
|
12500
|
-
light: "Overpass-Light.ttf",
|
|
12501
|
-
medium: "Overpass-Medium.ttf",
|
|
12502
|
-
semibold: "Overpass-SemiBold.ttf",
|
|
12503
|
-
italic: "Overpass-RegularItalic.ttf",
|
|
12504
|
-
boldItalic: "Overpass-BoldItalic.ttf",
|
|
12505
|
-
lightItalic: "Overpass-LightItalic.ttf",
|
|
12506
|
-
mediumItalic: "Overpass-MediumItalic.ttf",
|
|
12507
|
-
semiboldItalic: "Overpass-SemiBoldItalic.ttf"
|
|
12508
|
-
},
|
|
12509
|
-
"Exo 2": {
|
|
12510
|
-
regular: "Exo2-Regular.ttf",
|
|
12511
|
-
bold: "Exo2-Bold.ttf",
|
|
12512
|
-
light: "Exo2-Light.ttf",
|
|
12513
|
-
medium: "Exo2-Medium.ttf",
|
|
12514
|
-
semibold: "Exo2-SemiBold.ttf",
|
|
12515
|
-
italic: "Exo2-RegularItalic.ttf",
|
|
12516
|
-
boldItalic: "Exo2-BoldItalic.ttf",
|
|
12517
|
-
lightItalic: "Exo2-LightItalic.ttf",
|
|
12518
|
-
mediumItalic: "Exo2-MediumItalic.ttf",
|
|
12519
|
-
semiboldItalic: "Exo2-SemiBoldItalic.ttf"
|
|
12520
|
-
},
|
|
12521
|
-
"Roboto Mono": {
|
|
12522
|
-
regular: "RobotoMono-Regular.ttf",
|
|
12523
|
-
bold: "RobotoMono-Bold.ttf",
|
|
12524
|
-
light: "RobotoMono-Light.ttf",
|
|
12525
|
-
medium: "RobotoMono-Medium.ttf",
|
|
12526
|
-
semibold: "RobotoMono-SemiBold.ttf",
|
|
12527
|
-
italic: "RobotoMono-RegularItalic.ttf",
|
|
12528
|
-
boldItalic: "RobotoMono-BoldItalic.ttf",
|
|
12529
|
-
lightItalic: "RobotoMono-LightItalic.ttf",
|
|
12530
|
-
mediumItalic: "RobotoMono-MediumItalic.ttf",
|
|
12531
|
-
semiboldItalic: "RobotoMono-SemiBoldItalic.ttf"
|
|
12532
|
-
},
|
|
12533
|
-
"Fira Code": {
|
|
12534
|
-
regular: "FiraCode-Regular.ttf",
|
|
12535
|
-
bold: "FiraCode-Bold.ttf",
|
|
12536
|
-
light: "FiraCode-Light.ttf",
|
|
12537
|
-
medium: "FiraCode-Medium.ttf",
|
|
12538
|
-
semibold: "FiraCode-SemiBold.ttf"
|
|
12539
|
-
},
|
|
12540
|
-
"JetBrains Mono": {
|
|
12541
|
-
regular: "JetBrainsMono-Regular.ttf",
|
|
12542
|
-
bold: "JetBrainsMono-Bold.ttf",
|
|
12543
|
-
light: "JetBrainsMono-Light.ttf",
|
|
12544
|
-
medium: "JetBrainsMono-Medium.ttf",
|
|
12545
|
-
semibold: "JetBrainsMono-SemiBold.ttf",
|
|
12546
|
-
italic: "JetBrainsMono-RegularItalic.ttf",
|
|
12547
|
-
boldItalic: "JetBrainsMono-BoldItalic.ttf",
|
|
12548
|
-
lightItalic: "JetBrainsMono-LightItalic.ttf",
|
|
12549
|
-
mediumItalic: "JetBrainsMono-MediumItalic.ttf",
|
|
12550
|
-
semiboldItalic: "JetBrainsMono-SemiBoldItalic.ttf"
|
|
12551
|
-
},
|
|
12552
|
-
"Source Code Pro": {
|
|
12553
|
-
regular: "SourceCodePro-Regular.ttf",
|
|
12554
|
-
bold: "SourceCodePro-Bold.ttf",
|
|
12555
|
-
light: "SourceCodePro-Light.ttf",
|
|
12556
|
-
medium: "SourceCodePro-Medium.ttf",
|
|
12557
|
-
semibold: "SourceCodePro-SemiBold.ttf",
|
|
12558
|
-
italic: "SourceCodePro-RegularItalic.ttf",
|
|
12559
|
-
boldItalic: "SourceCodePro-BoldItalic.ttf",
|
|
12560
|
-
lightItalic: "SourceCodePro-LightItalic.ttf",
|
|
12561
|
-
mediumItalic: "SourceCodePro-MediumItalic.ttf",
|
|
12562
|
-
semiboldItalic: "SourceCodePro-SemiBoldItalic.ttf"
|
|
12563
|
-
},
|
|
12564
|
-
"IBM Plex Mono": {
|
|
12565
|
-
regular: "IBMPlexMono-Regular.ttf",
|
|
12566
|
-
bold: "IBMPlexMono-Bold.ttf"
|
|
12567
|
-
},
|
|
12568
|
-
"Space Mono": {
|
|
12569
|
-
regular: "SpaceMono-Regular.ttf",
|
|
12570
|
-
bold: "SpaceMono-Bold.ttf",
|
|
12571
|
-
italic: "SpaceMono-Italic.ttf",
|
|
12572
|
-
boldItalic: "SpaceMono-BoldItalic.ttf"
|
|
12573
|
-
},
|
|
12574
|
-
"Sacramento": { regular: "Sacramento-Regular.ttf" },
|
|
12575
|
-
"Alex Brush": { regular: "AlexBrush-Regular.ttf" },
|
|
12576
|
-
"Allura": { regular: "Allura-Regular.ttf" },
|
|
12577
|
-
"Caveat": {
|
|
12578
|
-
regular: "Caveat-Regular.ttf",
|
|
12579
|
-
bold: "Caveat-Bold.ttf",
|
|
12580
|
-
medium: "Caveat-Medium.ttf",
|
|
12581
|
-
semibold: "Caveat-SemiBold.ttf"
|
|
12582
|
-
},
|
|
12583
|
-
"Lobster": { regular: "Lobster-Regular.ttf" },
|
|
12584
|
-
"Comfortaa": {
|
|
12585
|
-
regular: "Comfortaa-Regular.ttf",
|
|
12586
|
-
bold: "Comfortaa-Bold.ttf",
|
|
12587
|
-
light: "Comfortaa-Light.ttf",
|
|
12588
|
-
medium: "Comfortaa-Medium.ttf",
|
|
12589
|
-
semibold: "Comfortaa-SemiBold.ttf"
|
|
12590
|
-
},
|
|
12591
|
-
"Anton": { regular: "Anton-Regular.ttf" },
|
|
12592
|
-
"Teko": {
|
|
12593
|
-
regular: "Teko-Regular.ttf",
|
|
12594
|
-
bold: "Teko-Bold.ttf",
|
|
12595
|
-
light: "Teko-Light.ttf",
|
|
12596
|
-
medium: "Teko-Medium.ttf",
|
|
12597
|
-
semibold: "Teko-SemiBold.ttf"
|
|
12598
|
-
},
|
|
12599
|
-
"Noto Sans Devanagari": {
|
|
12600
|
-
regular: "NotoSansDevanagari-Regular.ttf",
|
|
12601
|
-
bold: "NotoSansDevanagari-Bold.ttf",
|
|
12602
|
-
light: "NotoSansDevanagari-Light.ttf",
|
|
12603
|
-
medium: "NotoSansDevanagari-Medium.ttf",
|
|
12604
|
-
semibold: "NotoSansDevanagari-SemiBold.ttf"
|
|
12605
|
-
},
|
|
12606
|
-
"Hind": {
|
|
12607
|
-
regular: "Hind-Regular.ttf",
|
|
12608
|
-
bold: "Hind-Bold.ttf",
|
|
12609
|
-
light: "Hind-Light.ttf",
|
|
12610
|
-
medium: "Hind-Medium.ttf",
|
|
12611
|
-
semibold: "Hind-SemiBold.ttf"
|
|
12612
|
-
},
|
|
12613
|
-
"Cinzel": { regular: "Cinzel-Regular.ttf", bold: "Cinzel-Bold.ttf" },
|
|
12614
|
-
"Cormorant Garamond": {
|
|
12615
|
-
regular: "CormorantGaramond-Regular.ttf",
|
|
12616
|
-
bold: "CormorantGaramond-Bold.ttf",
|
|
12617
|
-
light: "CormorantGaramond-Light.ttf",
|
|
12618
|
-
medium: "CormorantGaramond-Medium.ttf",
|
|
12619
|
-
semibold: "CormorantGaramond-SemiBold.ttf",
|
|
12620
|
-
italic: "CormorantGaramond-Italic.ttf",
|
|
12621
|
-
boldItalic: "CormorantGaramond-BoldItalic.ttf"
|
|
12622
|
-
}
|
|
12623
|
-
};
|
|
12624
|
-
const WEIGHT_TO_KEYS = {
|
|
12625
|
-
300: ["light", "regular"],
|
|
12626
|
-
400: ["regular"],
|
|
12627
|
-
500: ["medium", "regular"],
|
|
12628
|
-
600: ["semibold", "bold", "regular"],
|
|
12629
|
-
700: ["bold", "regular"]
|
|
12630
|
-
};
|
|
12631
|
-
const WEIGHT_TO_ITALIC_KEYS = {
|
|
12632
|
-
300: ["lightItalic", "italic", "light", "regular"],
|
|
12633
|
-
400: ["italic", "regular"],
|
|
12634
|
-
500: ["mediumItalic", "italic", "medium", "regular"],
|
|
12635
|
-
600: ["semiboldItalic", "boldItalic", "italic", "semibold", "bold", "regular"],
|
|
12636
|
-
700: ["boldItalic", "italic", "bold", "regular"]
|
|
12637
|
-
};
|
|
12638
|
-
function getFontPathForWeight(files, weight, isItalic = false) {
|
|
12639
|
-
const keys = isItalic ? WEIGHT_TO_ITALIC_KEYS[weight] : WEIGHT_TO_KEYS[weight];
|
|
12640
|
-
if (!keys) return files.regular;
|
|
12641
|
-
for (const k of keys) {
|
|
12642
|
-
const path = files[k];
|
|
12643
|
-
if (path) return path;
|
|
12644
|
-
}
|
|
12645
|
-
return files.regular;
|
|
12646
|
-
}
|
|
12647
|
-
function isItalicPath(files, path) {
|
|
12648
|
-
return path === files.italic || path === files.boldItalic || path === files.lightItalic || path === files.mediumItalic || path === files.semiboldItalic;
|
|
12649
|
-
}
|
|
12650
|
-
function getJsPDFFontName(fontName) {
|
|
12651
|
-
return fontName.replace(/\s+/g, "");
|
|
12652
|
-
}
|
|
12653
|
-
function getEmbeddedJsPDFFontName(fontName, weight, isItalic = false) {
|
|
12654
|
-
const resolved = resolveFontWeight(weight);
|
|
12655
|
-
const label = FONT_WEIGHT_LABELS[resolved];
|
|
12656
|
-
const italicSuffix = isItalic ? "Italic" : "";
|
|
12657
|
-
return `${getJsPDFFontName(fontName)}-${label}${italicSuffix}`;
|
|
12658
|
-
}
|
|
12659
|
-
function isFontAvailable(fontName) {
|
|
12660
|
-
return fontName in FONT_FILES;
|
|
12661
|
-
}
|
|
12662
|
-
const ttfCache = /* @__PURE__ */ new Map();
|
|
12663
|
-
async function fetchTTFAsBase64(url) {
|
|
12664
|
-
const cached = ttfCache.get(url);
|
|
12665
|
-
if (cached) return cached;
|
|
12666
|
-
try {
|
|
12667
|
-
const res = await fetch(url);
|
|
12668
|
-
if (!res.ok) return null;
|
|
12669
|
-
const buf = await res.arrayBuffer();
|
|
12670
|
-
const bytes = new Uint8Array(buf);
|
|
12671
|
-
let binary = "";
|
|
12672
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
12673
|
-
binary += String.fromCharCode(bytes[i]);
|
|
12674
|
-
}
|
|
12675
|
-
const b64 = btoa(binary);
|
|
12676
|
-
ttfCache.set(url, b64);
|
|
12677
|
-
return b64;
|
|
12678
|
-
} catch {
|
|
12679
|
-
return null;
|
|
12680
|
-
}
|
|
12681
|
-
}
|
|
12682
|
-
async function embedFont(pdf, fontName, weight, fontBaseUrl, isItalic = false) {
|
|
12683
|
-
const fontFiles = FONT_FILES[fontName];
|
|
12684
|
-
if (!fontFiles) return false;
|
|
12685
|
-
const baseUrl = fontBaseUrl.endsWith("/") ? fontBaseUrl : fontBaseUrl + "/";
|
|
12686
|
-
const resolvedWeight = resolveFontWeight(weight);
|
|
12687
|
-
const fontPath = getFontPathForWeight(fontFiles, resolvedWeight, isItalic);
|
|
12688
|
-
if (!fontPath) return false;
|
|
12689
|
-
const hasItalicFile = isItalic && isItalicPath(fontFiles, fontPath);
|
|
12690
|
-
const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, weight, hasItalicFile);
|
|
12691
|
-
const label = FONT_WEIGHT_LABELS[resolvedWeight];
|
|
12692
|
-
const italicSuffix = hasItalicFile ? "Italic" : "";
|
|
12693
|
-
const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;
|
|
12694
|
-
const url = baseUrl + fontPath;
|
|
12695
|
-
try {
|
|
12696
|
-
const b64 = await fetchTTFAsBase64(url);
|
|
12697
|
-
if (!b64) return false;
|
|
12698
|
-
pdf.addFileToVFS(fileName, b64);
|
|
12699
|
-
pdf.addFont(fileName, jsPdfFontName, "normal");
|
|
12700
|
-
if (fontName !== jsPdfFontName) {
|
|
12701
|
-
try {
|
|
12702
|
-
pdf.addFont(fileName, fontName, "normal");
|
|
12703
|
-
} catch {
|
|
12704
|
-
}
|
|
12705
|
-
}
|
|
12706
|
-
return true;
|
|
12707
|
-
} catch (e) {
|
|
12708
|
-
console.warn(`[pdf-fonts] Failed to embed ${fontName} w${weight}:`, e);
|
|
12709
|
-
return false;
|
|
12710
|
-
}
|
|
12711
|
-
}
|
|
12712
|
-
async function embedFontsForConfig(pdf, config, fontBaseUrl) {
|
|
12713
|
-
const fontKeys = /* @__PURE__ */ new Set();
|
|
12714
|
-
const SEP = "";
|
|
12715
|
-
const walkElements = (elements) => {
|
|
12716
|
-
for (const el of elements) {
|
|
12717
|
-
if (el.fontFamily) {
|
|
12718
|
-
const w = resolveFontWeight(el.fontWeight ?? 400);
|
|
12719
|
-
fontKeys.add(`${el.fontFamily}${SEP}${w}`);
|
|
12720
|
-
}
|
|
12721
|
-
if (el.styles && typeof el.styles === "object") {
|
|
12722
|
-
for (const lineKey of Object.keys(el.styles)) {
|
|
12723
|
-
const lineStyles = el.styles[lineKey];
|
|
12724
|
-
if (lineStyles && typeof lineStyles === "object") {
|
|
12725
|
-
for (const charKey of Object.keys(lineStyles)) {
|
|
12726
|
-
const s = lineStyles[charKey];
|
|
12727
|
-
if (s == null ? void 0 : s.fontFamily) {
|
|
12728
|
-
const w = resolveFontWeight(s.fontWeight ?? 400);
|
|
12729
|
-
fontKeys.add(`${s.fontFamily}${SEP}${w}`);
|
|
12730
|
-
}
|
|
12731
|
-
}
|
|
12732
|
-
}
|
|
12733
|
-
}
|
|
12734
|
-
}
|
|
12735
|
-
if (el.children) walkElements(el.children);
|
|
12736
|
-
if (el.objects) walkElements(el.objects);
|
|
12737
|
-
}
|
|
12738
|
-
};
|
|
12739
|
-
for (const page of (config == null ? void 0 : config.pages) || []) {
|
|
12740
|
-
if (page.children) walkElements(page.children);
|
|
12741
|
-
if (page.elements) walkElements(page.elements);
|
|
12742
|
-
}
|
|
12743
|
-
fontKeys.add(`${FONT_FALLBACK_SYMBOLS}${SEP}400`);
|
|
12744
|
-
for (const w of [300, 400, 500, 600, 700]) {
|
|
12745
|
-
fontKeys.add(`${FONT_FALLBACK_DEVANAGARI}${SEP}${w}`);
|
|
12746
|
-
}
|
|
12747
|
-
const embedded = /* @__PURE__ */ new Set();
|
|
12748
|
-
const tasks = [];
|
|
12749
|
-
for (const key of fontKeys) {
|
|
12750
|
-
const sep = key.indexOf(SEP);
|
|
12751
|
-
const fontName = key.slice(0, sep);
|
|
12752
|
-
const weight = parseInt(key.slice(sep + 1), 10);
|
|
12753
|
-
if (!isFontAvailable(fontName)) continue;
|
|
12754
|
-
tasks.push(
|
|
12755
|
-
embedFont(pdf, fontName, weight, fontBaseUrl).then((ok) => {
|
|
12756
|
-
if (ok) embedded.add(key);
|
|
12757
|
-
})
|
|
12758
|
-
);
|
|
12759
|
-
}
|
|
12760
|
-
await Promise.all(tasks);
|
|
12761
|
-
console.log(`[pdf-fonts] Embedded ${embedded.size} font variants from config`);
|
|
12762
|
-
return embedded;
|
|
12763
|
-
}
|
|
12764
|
-
function isDevanagari(char) {
|
|
12765
|
-
const c = char.codePointAt(0) ?? 0;
|
|
12766
|
-
return c >= 2304 && c <= 2431 || c >= 43232 && c <= 43263 || c >= 7376 && c <= 7423;
|
|
12767
|
-
}
|
|
12768
|
-
function containsDevanagari(text) {
|
|
12769
|
-
if (!text) return false;
|
|
12770
|
-
for (const char of text) {
|
|
12771
|
-
if (isDevanagari(char)) return true;
|
|
12772
|
-
}
|
|
12773
|
-
return false;
|
|
12774
|
-
}
|
|
12775
|
-
function isBasicLatinOrLatin1(char) {
|
|
12776
|
-
const c = char.codePointAt(0) ?? 0;
|
|
12777
|
-
return c <= 591;
|
|
12778
|
-
}
|
|
12779
|
-
function classifyChar(char) {
|
|
12780
|
-
if (isBasicLatinOrLatin1(char)) return "main";
|
|
12781
|
-
if (isDevanagari(char)) return "devanagari";
|
|
12782
|
-
return "symbol";
|
|
12783
|
-
}
|
|
12784
|
-
function splitIntoRuns(text) {
|
|
12785
|
-
if (!text) return [];
|
|
12786
|
-
const runs = [];
|
|
12787
|
-
let currentType = null;
|
|
12788
|
-
let currentText = "";
|
|
12789
|
-
for (const char of text) {
|
|
12790
|
-
const type = classifyChar(char);
|
|
12791
|
-
if (type !== currentType && currentText) {
|
|
12792
|
-
runs.push({ text: currentText, runType: currentType });
|
|
12793
|
-
currentText = "";
|
|
12794
|
-
}
|
|
12795
|
-
currentType = type;
|
|
12796
|
-
currentText += char;
|
|
12797
|
-
}
|
|
12798
|
-
if (currentText && currentType) {
|
|
12799
|
-
runs.push({ text: currentText, runType: currentType });
|
|
12800
|
-
}
|
|
12801
|
-
return runs;
|
|
12802
|
-
}
|
|
12803
|
-
function rewriteSvgFontsForJsPDF(svgStr) {
|
|
12804
|
-
var _a, _b;
|
|
12805
|
-
const parser = new DOMParser();
|
|
12806
|
-
const doc = parser.parseFromString(svgStr, "image/svg+xml");
|
|
12807
|
-
const textEls = doc.querySelectorAll("text, tspan, textPath");
|
|
12808
|
-
const readStyleToken = (style, prop) => {
|
|
12809
|
-
var _a2;
|
|
12810
|
-
const match = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
|
|
12811
|
-
return ((_a2 = match == null ? void 0 : match[1]) == null ? void 0 : _a2.trim()) || null;
|
|
12812
|
-
};
|
|
12813
|
-
const resolveInheritedValue = (el, attr, styleProp = attr) => {
|
|
12814
|
-
var _a2;
|
|
12815
|
-
let current = el;
|
|
12816
|
-
while (current) {
|
|
12817
|
-
const attrVal = (_a2 = current.getAttribute(attr)) == null ? void 0 : _a2.trim();
|
|
12818
|
-
if (attrVal) return attrVal;
|
|
12819
|
-
const styleVal = readStyleToken(current.getAttribute("style") || "", styleProp);
|
|
12820
|
-
if (styleVal) return styleVal;
|
|
12821
|
-
current = current.parentElement;
|
|
12822
|
-
}
|
|
12823
|
-
return null;
|
|
12824
|
-
};
|
|
12825
|
-
const resolveWeightNum = (weightRaw) => {
|
|
12826
|
-
const parsedWeight = Number.parseInt(weightRaw, 10);
|
|
12827
|
-
return Number.isFinite(parsedWeight) ? parsedWeight : /bold/i.test(weightRaw) ? 700 : /medium/i.test(weightRaw) ? 500 : /semi/i.test(weightRaw) ? 600 : /light/i.test(weightRaw) ? 300 : 400;
|
|
12828
|
-
};
|
|
12829
|
-
const buildStyleString = (existingStyle, fontName) => {
|
|
12830
|
-
const stylePairs = existingStyle.split(";").map((part) => part.trim()).filter(Boolean).filter((part) => !/^font-family\s*:/i.test(part) && !/^font-weight\s*:/i.test(part) && !/^font-style\s*:/i.test(part));
|
|
12831
|
-
stylePairs.push(`font-family: ${fontName}`);
|
|
12832
|
-
stylePairs.push(`font-weight: normal`);
|
|
12833
|
-
stylePairs.push(`font-style: normal`);
|
|
12834
|
-
return stylePairs.join("; ");
|
|
12835
|
-
};
|
|
12836
|
-
for (const el of textEls) {
|
|
12837
|
-
const inlineStyle = el.getAttribute("style") || "";
|
|
12838
|
-
const rawFf = resolveInheritedValue(el, "font-family");
|
|
12839
|
-
if (!rawFf) continue;
|
|
12840
|
-
const clean = (_a = rawFf.split(",")[0]) == null ? void 0 : _a.replace(/['"]/g, "").trim();
|
|
12841
|
-
if (!isFontAvailable(clean)) continue;
|
|
12842
|
-
const weightRaw = resolveInheritedValue(el, "font-weight") || "400";
|
|
12843
|
-
const styleRaw = resolveInheritedValue(el, "font-style") || "normal";
|
|
12844
|
-
const weight = resolveWeightNum(weightRaw);
|
|
12845
|
-
const resolved = resolveFontWeight(weight);
|
|
12846
|
-
const isItalic = /italic|oblique/i.test(styleRaw);
|
|
12847
|
-
const jsPdfName = getEmbeddedJsPDFFontName(clean, resolved, isItalic);
|
|
12848
|
-
el.setAttribute("data-source-font-family", clean);
|
|
12849
|
-
el.setAttribute("data-source-font-weight", String(resolved));
|
|
12850
|
-
el.setAttribute("data-source-font-style", isItalic ? "italic" : "normal");
|
|
12851
|
-
const directText = Array.from(el.childNodes).filter((n) => n.nodeType === 3).map((n) => n.textContent || "").join("");
|
|
12852
|
-
const hasDevanagari = containsDevanagari(directText);
|
|
12853
|
-
if (hasDevanagari && directText.length > 0) {
|
|
12854
|
-
const devanagariWeight = resolveFontWeight(weight);
|
|
12855
|
-
const devanagariJsPdfName = getEmbeddedJsPDFFontName(FONT_FALLBACK_DEVANAGARI, devanagariWeight);
|
|
12856
|
-
const symbolJsPdfName = isFontAvailable(FONT_FALLBACK_SYMBOLS) ? getEmbeddedJsPDFFontName(FONT_FALLBACK_SYMBOLS, 400) : jsPdfName;
|
|
12857
|
-
const childNodes = Array.from(el.childNodes);
|
|
12858
|
-
for (const node of childNodes) {
|
|
12859
|
-
if (node.nodeType !== 3 || !node.textContent) continue;
|
|
12860
|
-
const runs = splitIntoRuns(node.textContent);
|
|
12861
|
-
if (runs.length <= 1 && ((_b = runs[0]) == null ? void 0 : _b.runType) !== "devanagari") continue;
|
|
12862
|
-
const fragment = doc.createDocumentFragment();
|
|
12863
|
-
for (const run of runs) {
|
|
12864
|
-
const tspan = doc.createElementNS("http://www.w3.org/2000/svg", "tspan");
|
|
12865
|
-
let runFont;
|
|
12866
|
-
if (run.runType === "devanagari") {
|
|
12867
|
-
runFont = devanagariJsPdfName;
|
|
12868
|
-
} else if (run.runType === "symbol") {
|
|
12869
|
-
runFont = symbolJsPdfName;
|
|
12870
|
-
} else {
|
|
12871
|
-
runFont = jsPdfName;
|
|
12872
|
-
}
|
|
12873
|
-
tspan.setAttribute("font-family", runFont);
|
|
12874
|
-
tspan.setAttribute("font-weight", "normal");
|
|
12875
|
-
tspan.setAttribute("font-style", "normal");
|
|
12876
|
-
tspan.textContent = run.text;
|
|
12877
|
-
fragment.appendChild(tspan);
|
|
12878
|
-
}
|
|
12879
|
-
el.replaceChild(fragment, node);
|
|
12880
|
-
}
|
|
12881
|
-
el.setAttribute("font-family", jsPdfName);
|
|
12882
|
-
el.setAttribute("font-weight", "normal");
|
|
12883
|
-
el.setAttribute("font-style", "normal");
|
|
12884
|
-
el.setAttribute("style", buildStyleString(inlineStyle, jsPdfName));
|
|
12885
|
-
} else {
|
|
12886
|
-
el.setAttribute("font-family", jsPdfName);
|
|
12887
|
-
el.setAttribute("font-weight", "normal");
|
|
12888
|
-
el.setAttribute("font-style", "normal");
|
|
12889
|
-
el.setAttribute("style", buildStyleString(inlineStyle, jsPdfName));
|
|
12890
|
-
}
|
|
12891
|
-
}
|
|
12892
|
-
return new XMLSerializer().serializeToString(doc.documentElement);
|
|
12893
|
-
}
|
|
12894
|
-
function extractFontFamiliesFromSvgs(svgs) {
|
|
12895
|
-
const families = /* @__PURE__ */ new Set();
|
|
12896
|
-
const regex = /font-family[=:]\s*["']?([^"';},]+)/gi;
|
|
12897
|
-
for (const svg of svgs) {
|
|
12898
|
-
let m;
|
|
12899
|
-
while ((m = regex.exec(svg)) !== null) {
|
|
12900
|
-
const raw = m[1].trim().split(",")[0].trim().replace(/^['"]|['"]$/g, "");
|
|
12901
|
-
if (raw && raw !== "serif" && raw !== "sans-serif" && raw !== "monospace") {
|
|
12902
|
-
families.add(raw);
|
|
12903
|
-
}
|
|
12904
|
-
}
|
|
12905
|
-
}
|
|
12906
|
-
return families;
|
|
12907
|
-
}
|
|
12908
|
-
async function embedFontsInPdf(pdf, fontFamilies, fontBaseUrl) {
|
|
12909
|
-
const embedded = /* @__PURE__ */ new Set();
|
|
12910
|
-
const weights = [300, 400, 500, 600, 700];
|
|
12911
|
-
const tasks = [];
|
|
12912
|
-
for (const family of fontFamilies) {
|
|
12913
|
-
if (!isFontAvailable(family)) {
|
|
12914
|
-
console.warn(`[pdf-fonts] No TTF mapping for "${family}" — will use Helvetica fallback`);
|
|
12915
|
-
continue;
|
|
12916
|
-
}
|
|
12917
|
-
for (const w of weights) {
|
|
12918
|
-
tasks.push(
|
|
12919
|
-
embedFont(pdf, family, w, fontBaseUrl).then((ok) => {
|
|
12920
|
-
if (ok) embedded.add(`${family}${w}`);
|
|
12921
|
-
})
|
|
12922
|
-
);
|
|
12923
|
-
}
|
|
12924
|
-
}
|
|
12925
|
-
await Promise.all(tasks);
|
|
12926
|
-
console.log(`[pdf-fonts] Embedded ${embedded.size} font variants for ${fontFamilies.size} families`);
|
|
12927
|
-
return embedded;
|
|
12928
|
-
}
|
|
12929
|
-
const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
12930
|
-
__proto__: null,
|
|
12931
|
-
FONT_FALLBACK_DEVANAGARI,
|
|
12932
|
-
FONT_FALLBACK_SYMBOLS,
|
|
12933
|
-
FONT_FILES,
|
|
12934
|
-
FONT_WEIGHT_LABELS,
|
|
12935
|
-
embedFont,
|
|
12936
|
-
embedFontsForConfig,
|
|
12937
|
-
embedFontsInPdf,
|
|
12938
|
-
extractFontFamiliesFromSvgs,
|
|
12939
|
-
getEmbeddedJsPDFFontName,
|
|
12940
|
-
getFontPathForWeight,
|
|
12941
|
-
isFontAvailable,
|
|
12942
|
-
resolveFontWeight,
|
|
12943
|
-
rewriteSvgFontsForJsPDF
|
|
12944
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
12945
|
-
function normalizeFontFamily(fontStack) {
|
|
12946
|
-
const first = fontStack.split(",")[0].trim();
|
|
12947
|
-
return first.replace(/^['"]|['"]$/g, "");
|
|
12126
|
+
function normalizeFontFamily(fontStack) {
|
|
12127
|
+
const first = fontStack.split(",")[0].trim();
|
|
12128
|
+
return first.replace(/^['"]|['"]$/g, "");
|
|
12948
12129
|
}
|
|
12949
12130
|
const loadedFonts = /* @__PURE__ */ new Set();
|
|
12950
12131
|
const loadingPromises = /* @__PURE__ */ new Map();
|
|
12951
|
-
function getFontBaseUrl() {
|
|
12952
|
-
if (typeof window === "undefined") return "/fonts/";
|
|
12953
|
-
return `${window.location.origin}/fonts/`;
|
|
12954
|
-
}
|
|
12955
|
-
function injectLocalFontFaces(rawFontFamily) {
|
|
12956
|
-
if (typeof document === "undefined") return false;
|
|
12957
|
-
const fontFamily = normalizeFontFamily(rawFontFamily);
|
|
12958
|
-
const files = FONT_FILES[fontFamily];
|
|
12959
|
-
if (!files) return false;
|
|
12960
|
-
const id = `pixldocs-local-font-${fontFamily.replace(/[^a-z0-9_-]+/gi, "-")}`;
|
|
12961
|
-
if (document.getElementById(id)) return true;
|
|
12962
|
-
const baseUrl = getFontBaseUrl();
|
|
12963
|
-
const rules = [];
|
|
12964
|
-
const seen = /* @__PURE__ */ new Set();
|
|
12965
|
-
for (const weight of [300, 400, 500, 600, 700]) {
|
|
12966
|
-
for (const italic of [false, true]) {
|
|
12967
|
-
const resolvedWeight = resolveFontWeight(weight);
|
|
12968
|
-
const file = getFontPathForWeight(files, resolvedWeight, italic);
|
|
12969
|
-
if (!file) continue;
|
|
12970
|
-
const key = `${file}|${weight}|${italic ? "italic" : "normal"}`;
|
|
12971
|
-
if (seen.has(key)) continue;
|
|
12972
|
-
seen.add(key);
|
|
12973
|
-
rules.push(
|
|
12974
|
-
`@font-face{font-family:${JSON.stringify(fontFamily)};src:url(${JSON.stringify(baseUrl + file)}) format("truetype");font-weight:${weight};font-style:${italic ? "italic" : "normal"};font-display:block;}`
|
|
12975
|
-
);
|
|
12976
|
-
}
|
|
12977
|
-
}
|
|
12978
|
-
if (rules.length === 0) return false;
|
|
12979
|
-
const style = document.createElement("style");
|
|
12980
|
-
style.id = id;
|
|
12981
|
-
style.textContent = rules.join("\n");
|
|
12982
|
-
document.head.appendChild(style);
|
|
12983
|
-
return true;
|
|
12984
|
-
}
|
|
12985
12132
|
function withTimeout(promise, timeoutMs = 4e3) {
|
|
12986
12133
|
let timeoutId;
|
|
12987
12134
|
return Promise.race([
|
|
@@ -13002,10 +12149,6 @@ async function loadGoogleFontCSS(rawFontFamily) {
|
|
|
13002
12149
|
if (existing) return existing;
|
|
13003
12150
|
const promise = (async () => {
|
|
13004
12151
|
try {
|
|
13005
|
-
if (injectLocalFontFaces(fontFamily)) {
|
|
13006
|
-
loadedFonts.add(fontFamily);
|
|
13007
|
-
return;
|
|
13008
|
-
}
|
|
13009
12152
|
const encoded = encodeURIComponent(fontFamily);
|
|
13010
12153
|
const url = `https://fonts.googleapis.com/css?family=${encoded}:300,400,500,600,700&display=swap`;
|
|
13011
12154
|
const link = document.createElement("link");
|
|
@@ -13128,7 +12271,7 @@ async function ensureFontsForResolvedConfig(config) {
|
|
|
13128
12271
|
if (typeof document === "undefined") return;
|
|
13129
12272
|
const descriptors = collectFontDescriptorsFromConfig(config);
|
|
13130
12273
|
const families = new Set(descriptors.map((d) => d.family));
|
|
13131
|
-
|
|
12274
|
+
await withTimeout(Promise.all([...families].map((f) => loadGoogleFontCSS(f))), 3500);
|
|
13132
12275
|
if (document.fonts) {
|
|
13133
12276
|
descriptors.forEach((d) => {
|
|
13134
12277
|
const stylePrefix = d.style === "italic" ? "italic " : "";
|
|
@@ -13157,7 +12300,7 @@ function configHasAutoShrinkText$1(config) {
|
|
|
13157
12300
|
}
|
|
13158
12301
|
async function awaitFontsForConfig(config, maxWaitMs) {
|
|
13159
12302
|
if (typeof document === "undefined" || !document.fonts) return;
|
|
13160
|
-
|
|
12303
|
+
await ensureFontsForResolvedConfig(config);
|
|
13161
12304
|
const descriptors = collectFontDescriptorsFromConfig(config);
|
|
13162
12305
|
if (descriptors.length === 0) return;
|
|
13163
12306
|
const loads = Promise.all(
|
|
@@ -13399,7 +12542,7 @@ function PixldocsPreview(props) {
|
|
|
13399
12542
|
!canvasSettled && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
|
|
13400
12543
|
] });
|
|
13401
12544
|
}
|
|
13402
|
-
const PACKAGE_VERSION = "0.5.
|
|
12545
|
+
const PACKAGE_VERSION = "0.5.71";
|
|
13403
12546
|
let __underlineFixInstalled = false;
|
|
13404
12547
|
function installUnderlineFix(fab) {
|
|
13405
12548
|
var _a;
|
|
@@ -13711,638 +12854,1482 @@ class PixldocsRenderer {
|
|
|
13711
12854
|
});
|
|
13712
12855
|
return this.renderAllPages(resolved.config, options);
|
|
13713
12856
|
}
|
|
13714
|
-
// ─── Internal: render a page using the full PreviewCanvas engine ───
|
|
13715
|
-
getExpectedImageCount(config, pageIndex) {
|
|
13716
|
-
const page = config.pages[pageIndex];
|
|
13717
|
-
if (!(page == null ? void 0 : page.children)) return 0;
|
|
13718
|
-
let count = 0;
|
|
13719
|
-
const walk = (nodes) => {
|
|
13720
|
-
for (const node of nodes) {
|
|
13721
|
-
if (!node || node.visible === false) continue;
|
|
13722
|
-
const src = typeof node.src === "string" ? node.src.trim() : "";
|
|
13723
|
-
const imageUrl = typeof node.imageUrl === "string" ? node.imageUrl.trim() : "";
|
|
13724
|
-
if (node.type === "image" && (src || imageUrl)) count += 1;
|
|
13725
|
-
if (Array.isArray(node.children) && node.children.length > 0) {
|
|
13726
|
-
walk(node.children);
|
|
13727
|
-
}
|
|
12857
|
+
// ─── Internal: render a page using the full PreviewCanvas engine ───
|
|
12858
|
+
getExpectedImageCount(config, pageIndex) {
|
|
12859
|
+
const page = config.pages[pageIndex];
|
|
12860
|
+
if (!(page == null ? void 0 : page.children)) return 0;
|
|
12861
|
+
let count = 0;
|
|
12862
|
+
const walk = (nodes) => {
|
|
12863
|
+
for (const node of nodes) {
|
|
12864
|
+
if (!node || node.visible === false) continue;
|
|
12865
|
+
const src = typeof node.src === "string" ? node.src.trim() : "";
|
|
12866
|
+
const imageUrl = typeof node.imageUrl === "string" ? node.imageUrl.trim() : "";
|
|
12867
|
+
if (node.type === "image" && (src || imageUrl)) count += 1;
|
|
12868
|
+
if (Array.isArray(node.children) && node.children.length > 0) {
|
|
12869
|
+
walk(node.children);
|
|
12870
|
+
}
|
|
12871
|
+
}
|
|
12872
|
+
};
|
|
12873
|
+
walk(page.children);
|
|
12874
|
+
return count;
|
|
12875
|
+
}
|
|
12876
|
+
waitForCanvasImages(container, expectedImageCount, maxWaitMs = 15e3, pollMs = 120) {
|
|
12877
|
+
return new Promise((resolve) => {
|
|
12878
|
+
const start = Date.now();
|
|
12879
|
+
let stableFrames = 0;
|
|
12880
|
+
let lastSummary = "";
|
|
12881
|
+
const isRenderableImage = (value) => value instanceof HTMLImageElement && value.complete && value.naturalWidth > 0 && value.naturalHeight > 0;
|
|
12882
|
+
const collectRenderableImages = (obj, seen) => {
|
|
12883
|
+
if (!obj || typeof obj !== "object") return;
|
|
12884
|
+
const candidates = [obj._element, obj._originalElement, obj._filteredEl, obj._cacheCanvasEl];
|
|
12885
|
+
for (const candidate of candidates) {
|
|
12886
|
+
if (isRenderableImage(candidate)) {
|
|
12887
|
+
seen.add(candidate);
|
|
12888
|
+
} else if (candidate instanceof HTMLImageElement) {
|
|
12889
|
+
return false;
|
|
12890
|
+
}
|
|
12891
|
+
}
|
|
12892
|
+
const nested = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
|
|
12893
|
+
for (const child of nested) {
|
|
12894
|
+
if (collectRenderableImages(child, seen) === false) return false;
|
|
12895
|
+
}
|
|
12896
|
+
return true;
|
|
12897
|
+
};
|
|
12898
|
+
const getFabricCanvas = () => {
|
|
12899
|
+
const registry2 = window.__fabricCanvasRegistry;
|
|
12900
|
+
if (registry2 instanceof Map) {
|
|
12901
|
+
for (const entry of registry2.values()) {
|
|
12902
|
+
const canvas = entry == null ? void 0 : entry.canvas;
|
|
12903
|
+
const el = (canvas == null ? void 0 : canvas.lowerCanvasEl) || (canvas == null ? void 0 : canvas.upperCanvasEl);
|
|
12904
|
+
if (el && container.contains(el)) return canvas;
|
|
12905
|
+
}
|
|
12906
|
+
}
|
|
12907
|
+
return null;
|
|
12908
|
+
};
|
|
12909
|
+
const settle = () => requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
12910
|
+
const getImageDebugInfo = (obj, bucket) => {
|
|
12911
|
+
if (!obj || typeof obj !== "object") return;
|
|
12912
|
+
const candidates = [obj._element, obj._originalElement, obj._filteredEl, obj._cacheCanvasEl];
|
|
12913
|
+
for (const candidate of candidates) {
|
|
12914
|
+
if (candidate instanceof HTMLImageElement) {
|
|
12915
|
+
bucket.push({
|
|
12916
|
+
id: obj.__docuforgeId || obj.id || "unknown",
|
|
12917
|
+
src: (candidate.currentSrc || candidate.src || "").slice(0, 240),
|
|
12918
|
+
complete: candidate.complete,
|
|
12919
|
+
naturalWidth: candidate.naturalWidth,
|
|
12920
|
+
naturalHeight: candidate.naturalHeight
|
|
12921
|
+
});
|
|
12922
|
+
}
|
|
12923
|
+
}
|
|
12924
|
+
const nested = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
|
|
12925
|
+
for (const child of nested) {
|
|
12926
|
+
getImageDebugInfo(child, bucket);
|
|
12927
|
+
}
|
|
12928
|
+
};
|
|
12929
|
+
const check = () => {
|
|
12930
|
+
const elapsed = Date.now() - start;
|
|
12931
|
+
const domImages = Array.from(container.querySelectorAll("img"));
|
|
12932
|
+
const allDomLoaded = domImages.every((img) => img.complete && img.naturalWidth > 0 && img.naturalHeight > 0);
|
|
12933
|
+
const fabricCanvas = getFabricCanvas();
|
|
12934
|
+
const fabricObjects = fabricCanvas && typeof fabricCanvas.getObjects === "function" ? fabricCanvas.getObjects() : [];
|
|
12935
|
+
const renderableImages = /* @__PURE__ */ new Set();
|
|
12936
|
+
const fabricReady = fabricObjects.every((obj) => collectRenderableImages(obj, renderableImages) !== false);
|
|
12937
|
+
const actualImageCount = Math.max(domImages.length, renderableImages.size);
|
|
12938
|
+
const canvasReady = !!fabricCanvas && !!(fabricCanvas.lowerCanvasEl || fabricCanvas.upperCanvasEl);
|
|
12939
|
+
const hasExpectedAssets = expectedImageCount === 0 ? true : actualImageCount >= expectedImageCount;
|
|
12940
|
+
const ready = allDomLoaded && fabricReady && hasExpectedAssets;
|
|
12941
|
+
const summary = `expected=${expectedImageCount} actual=${actualImageCount} dom=${domImages.length} fabricReady=${fabricReady} domReady=${allDomLoaded} canvasReady=${canvasReady}`;
|
|
12942
|
+
if (summary !== lastSummary) {
|
|
12943
|
+
lastSummary = summary;
|
|
12944
|
+
console.log(`[canvas-renderer][asset-wait] ${summary}`);
|
|
12945
|
+
}
|
|
12946
|
+
if (ready) {
|
|
12947
|
+
stableFrames += 1;
|
|
12948
|
+
if (stableFrames >= 2) {
|
|
12949
|
+
console.log(`[canvas-renderer][asset-wait] ready after ${elapsed}ms (${summary})`);
|
|
12950
|
+
settle();
|
|
12951
|
+
return;
|
|
12952
|
+
}
|
|
12953
|
+
} else {
|
|
12954
|
+
stableFrames = 0;
|
|
12955
|
+
}
|
|
12956
|
+
if (elapsed >= maxWaitMs) {
|
|
12957
|
+
const fabricImageDebug = [];
|
|
12958
|
+
for (const obj of fabricObjects) {
|
|
12959
|
+
getImageDebugInfo(obj, fabricImageDebug);
|
|
12960
|
+
}
|
|
12961
|
+
const domImageDebug = domImages.map((img, index) => ({
|
|
12962
|
+
index,
|
|
12963
|
+
src: (img.currentSrc || img.src || "").slice(0, 240),
|
|
12964
|
+
complete: img.complete,
|
|
12965
|
+
naturalWidth: img.naturalWidth,
|
|
12966
|
+
naturalHeight: img.naturalHeight
|
|
12967
|
+
}));
|
|
12968
|
+
console.warn(`[canvas-renderer][asset-wait-timeout] elapsed=${elapsed}ms ${summary}`);
|
|
12969
|
+
console.warn("[canvas-renderer][asset-wait-timeout][dom-images]", domImageDebug);
|
|
12970
|
+
console.warn("[canvas-renderer][asset-wait-timeout][fabric-images]", fabricImageDebug);
|
|
12971
|
+
settle();
|
|
12972
|
+
return;
|
|
12973
|
+
}
|
|
12974
|
+
setTimeout(check, pollMs);
|
|
12975
|
+
};
|
|
12976
|
+
setTimeout(check, 0);
|
|
12977
|
+
});
|
|
12978
|
+
}
|
|
12979
|
+
waitForCanvasScene(container, config, pageIndex, maxWaitMs = 8e3, pollMs = 50) {
|
|
12980
|
+
return new Promise((resolve) => {
|
|
12981
|
+
var _a, _b;
|
|
12982
|
+
const start = Date.now();
|
|
12983
|
+
const pageHasContent = (((_b = (_a = config.pages[pageIndex]) == null ? void 0 : _a.children) == null ? void 0 : _b.length) ?? 0) > 0;
|
|
12984
|
+
const settle = () => requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
12985
|
+
const check = () => {
|
|
12986
|
+
const fabricCanvas = this.getFabricCanvasFromContainer(container);
|
|
12987
|
+
const lowerCanvas = (fabricCanvas == null ? void 0 : fabricCanvas.lowerCanvasEl) || container.querySelector("canvas.lower-canvas, canvas");
|
|
12988
|
+
const objectCount = typeof (fabricCanvas == null ? void 0 : fabricCanvas.getObjects) === "function" ? fabricCanvas.getObjects().length : 0;
|
|
12989
|
+
const ready = !!lowerCanvas && (!pageHasContent || objectCount > 0);
|
|
12990
|
+
if (ready) {
|
|
12991
|
+
console.log(`[canvas-renderer][scene-wait] ready after ${Date.now() - start}ms (objects=${objectCount})`);
|
|
12992
|
+
settle();
|
|
12993
|
+
return;
|
|
12994
|
+
}
|
|
12995
|
+
if (Date.now() - start >= maxWaitMs) {
|
|
12996
|
+
console.warn(`[canvas-renderer][scene-wait-timeout] elapsed=${Date.now() - start}ms objects=${objectCount} pageHasContent=${pageHasContent}`);
|
|
12997
|
+
settle();
|
|
12998
|
+
return;
|
|
12999
|
+
}
|
|
13000
|
+
setTimeout(check, pollMs);
|
|
13001
|
+
};
|
|
13002
|
+
setTimeout(check, 0);
|
|
13003
|
+
});
|
|
13004
|
+
}
|
|
13005
|
+
async waitForRelevantFonts(config, maxWaitMs = 1800) {
|
|
13006
|
+
if (typeof document === "undefined" || !document.fonts) return;
|
|
13007
|
+
const descriptors = collectFontDescriptorsFromConfig(config);
|
|
13008
|
+
if (descriptors.length === 0) return;
|
|
13009
|
+
const loads = Promise.all(
|
|
13010
|
+
descriptors.map((descriptor) => {
|
|
13011
|
+
const stylePrefix = descriptor.style === "italic" ? "italic " : "";
|
|
13012
|
+
const spec = `${stylePrefix}${descriptor.weight} 16px "${descriptor.family}"`;
|
|
13013
|
+
return document.fonts.load(spec).catch(() => []);
|
|
13014
|
+
})
|
|
13015
|
+
).then(() => void 0);
|
|
13016
|
+
await Promise.race([
|
|
13017
|
+
loads,
|
|
13018
|
+
new Promise((resolve) => setTimeout(resolve, maxWaitMs))
|
|
13019
|
+
]);
|
|
13020
|
+
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
|
|
13021
|
+
}
|
|
13022
|
+
/**
|
|
13023
|
+
* Block until the webfonts referenced by `config` have actually loaded
|
|
13024
|
+
* (or `maxWaitMs` elapses). Used by the headless capture path BEFORE
|
|
13025
|
+
* mounting `PreviewCanvas`, so the synchronous `createText` auto-shrink
|
|
13026
|
+
* loop measures against final font metrics instead of fallback ones.
|
|
13027
|
+
*
|
|
13028
|
+
* Stronger than `ensureFontsForResolvedConfig` (which is fire-and-forget)
|
|
13029
|
+
* — this awaits each `document.fonts.load(spec)` AND `document.fonts.ready`,
|
|
13030
|
+
* racing the whole thing against `maxWaitMs` so a slow CDN can't hang the
|
|
13031
|
+
* renderer.
|
|
13032
|
+
*/
|
|
13033
|
+
async awaitFontsForConfig(config, maxWaitMs) {
|
|
13034
|
+
if (typeof document === "undefined" || !document.fonts) return;
|
|
13035
|
+
await ensureFontsForResolvedConfig(config);
|
|
13036
|
+
await this.waitForRelevantFonts(config, maxWaitMs);
|
|
13037
|
+
await Promise.race([
|
|
13038
|
+
document.fonts.ready.catch(() => void 0).then(() => void 0),
|
|
13039
|
+
new Promise((r) => setTimeout(r, Math.min(500, maxWaitMs)))
|
|
13040
|
+
]);
|
|
13041
|
+
}
|
|
13042
|
+
getNormalizedGradientStops(gradient) {
|
|
13043
|
+
const stops = Array.isArray(gradient == null ? void 0 : gradient.stops) ? gradient.stops.map((stop) => ({
|
|
13044
|
+
offset: Math.max(0, Math.min(1, Number((stop == null ? void 0 : stop.offset) ?? 0))),
|
|
13045
|
+
color: String((stop == null ? void 0 : stop.color) ?? "#ffffff")
|
|
13046
|
+
})).filter((stop) => Number.isFinite(stop.offset)).sort((a, b) => a.offset - b.offset) : [];
|
|
13047
|
+
if (stops.length === 0) return [];
|
|
13048
|
+
const normalized = [...stops];
|
|
13049
|
+
if (normalized[0].offset > 0) {
|
|
13050
|
+
normalized.unshift({ offset: 0, color: normalized[0].color });
|
|
13051
|
+
}
|
|
13052
|
+
if (normalized[normalized.length - 1].offset < 1) {
|
|
13053
|
+
normalized.push({ offset: 1, color: normalized[normalized.length - 1].color });
|
|
13054
|
+
}
|
|
13055
|
+
return normalized;
|
|
13056
|
+
}
|
|
13057
|
+
paintPageBackground(ctx, page, width, height) {
|
|
13058
|
+
var _a, _b;
|
|
13059
|
+
const backgroundColor = ((_a = page == null ? void 0 : page.settings) == null ? void 0 : _a.backgroundColor) || "#ffffff";
|
|
13060
|
+
const gradient = (_b = page == null ? void 0 : page.settings) == null ? void 0 : _b.backgroundGradient;
|
|
13061
|
+
ctx.clearRect(0, 0, width, height);
|
|
13062
|
+
ctx.fillStyle = backgroundColor;
|
|
13063
|
+
ctx.fillRect(0, 0, width, height);
|
|
13064
|
+
const stops = this.getNormalizedGradientStops(gradient);
|
|
13065
|
+
if (stops.length < 2) return;
|
|
13066
|
+
try {
|
|
13067
|
+
let canvasGradient = null;
|
|
13068
|
+
if ((gradient == null ? void 0 : gradient.type) === "radial") {
|
|
13069
|
+
const cx = Number.isFinite(gradient == null ? void 0 : gradient.cx) ? gradient.cx : 0.5;
|
|
13070
|
+
const cy = Number.isFinite(gradient == null ? void 0 : gradient.cy) ? gradient.cy : 0.5;
|
|
13071
|
+
const centerX = width * cx;
|
|
13072
|
+
const centerY = height * cy;
|
|
13073
|
+
const radius = Math.max(
|
|
13074
|
+
Math.hypot(centerX, centerY),
|
|
13075
|
+
Math.hypot(width - centerX, centerY),
|
|
13076
|
+
Math.hypot(centerX, height - centerY),
|
|
13077
|
+
Math.hypot(width - centerX, height - centerY)
|
|
13078
|
+
);
|
|
13079
|
+
canvasGradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, radius);
|
|
13080
|
+
} else if ((gradient == null ? void 0 : gradient.type) === "conic" && typeof ctx.createConicGradient === "function") {
|
|
13081
|
+
const cx = Number.isFinite(gradient == null ? void 0 : gradient.cx) ? gradient.cx : 0.5;
|
|
13082
|
+
const cy = Number.isFinite(gradient == null ? void 0 : gradient.cy) ? gradient.cy : 0.5;
|
|
13083
|
+
const startAngle = (((gradient == null ? void 0 : gradient.angle) ?? 0) - 90) * Math.PI / 180;
|
|
13084
|
+
canvasGradient = ctx.createConicGradient(startAngle, width * cx, height * cy);
|
|
13085
|
+
} else {
|
|
13086
|
+
const angleDeg = (gradient == null ? void 0 : gradient.angle) ?? 90;
|
|
13087
|
+
const angleRad = angleDeg * Math.PI / 180;
|
|
13088
|
+
const sinA = Math.sin(angleRad);
|
|
13089
|
+
const cosA = Math.cos(angleRad);
|
|
13090
|
+
const midX = width / 2;
|
|
13091
|
+
const midY = height / 2;
|
|
13092
|
+
const corners = [
|
|
13093
|
+
[0, 0],
|
|
13094
|
+
[width, 0],
|
|
13095
|
+
[width, height],
|
|
13096
|
+
[0, height]
|
|
13097
|
+
];
|
|
13098
|
+
const projections = corners.map(([x, y]) => x * sinA - y * cosA);
|
|
13099
|
+
const minProjection = Math.min(...projections);
|
|
13100
|
+
const maxProjection = Math.max(...projections);
|
|
13101
|
+
canvasGradient = ctx.createLinearGradient(
|
|
13102
|
+
midX + minProjection * sinA,
|
|
13103
|
+
midY - minProjection * cosA,
|
|
13104
|
+
midX + maxProjection * sinA,
|
|
13105
|
+
midY - maxProjection * cosA
|
|
13106
|
+
);
|
|
13728
13107
|
}
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
|
|
13108
|
+
if (!canvasGradient) return;
|
|
13109
|
+
stops.forEach((stop) => canvasGradient.addColorStop(stop.offset, stop.color));
|
|
13110
|
+
ctx.fillStyle = canvasGradient;
|
|
13111
|
+
ctx.fillRect(0, 0, width, height);
|
|
13112
|
+
} catch {
|
|
13113
|
+
}
|
|
13732
13114
|
}
|
|
13733
|
-
|
|
13734
|
-
|
|
13735
|
-
|
|
13736
|
-
|
|
13737
|
-
|
|
13738
|
-
|
|
13739
|
-
|
|
13740
|
-
|
|
13741
|
-
|
|
13742
|
-
|
|
13743
|
-
|
|
13744
|
-
|
|
13745
|
-
|
|
13746
|
-
|
|
13747
|
-
|
|
13748
|
-
|
|
13749
|
-
|
|
13750
|
-
|
|
13751
|
-
|
|
13115
|
+
async renderPageViaPreviewCanvas(config, pageIndex, pixelRatio, format, quality, options = {}) {
|
|
13116
|
+
const { PreviewCanvas: PreviewCanvas2 } = await Promise.resolve().then(() => PreviewCanvas$1);
|
|
13117
|
+
const canvasWidth = config.canvas.width;
|
|
13118
|
+
const canvasHeight = config.canvas.height;
|
|
13119
|
+
const hasAutoShrink = configHasAutoShrinkText(config);
|
|
13120
|
+
let firstMountSettled = false;
|
|
13121
|
+
let lateFontSettleDetected = false;
|
|
13122
|
+
if (typeof document !== "undefined" && document.fonts && hasAutoShrink) {
|
|
13123
|
+
document.fonts.ready.then(() => {
|
|
13124
|
+
if (firstMountSettled) lateFontSettleDetected = true;
|
|
13125
|
+
}).catch(() => {
|
|
13126
|
+
});
|
|
13127
|
+
}
|
|
13128
|
+
return new Promise((resolve, reject) => {
|
|
13129
|
+
const container = document.createElement("div");
|
|
13130
|
+
container.style.cssText = `
|
|
13131
|
+
position: fixed; left: -99999px; top: -99999px;
|
|
13132
|
+
width: ${canvasWidth}px; height: ${canvasHeight}px;
|
|
13133
|
+
overflow: hidden; pointer-events: none; opacity: 0;
|
|
13134
|
+
`;
|
|
13135
|
+
document.body.appendChild(container);
|
|
13136
|
+
const timeout = setTimeout(() => {
|
|
13137
|
+
cleanup();
|
|
13138
|
+
reject(new Error("Render timeout (30s)"));
|
|
13139
|
+
}, 3e4);
|
|
13140
|
+
let root;
|
|
13141
|
+
let mountKey = 0;
|
|
13142
|
+
const cleanup = () => {
|
|
13143
|
+
clearTimeout(timeout);
|
|
13144
|
+
try {
|
|
13145
|
+
root.unmount();
|
|
13146
|
+
} catch {
|
|
13752
13147
|
}
|
|
13753
|
-
|
|
13148
|
+
container.remove();
|
|
13754
13149
|
};
|
|
13755
|
-
const
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13759
|
-
|
|
13760
|
-
const el = (canvas == null ? void 0 : canvas.lowerCanvasEl) || (canvas == null ? void 0 : canvas.upperCanvasEl);
|
|
13761
|
-
if (el && container.contains(el)) return canvas;
|
|
13762
|
-
}
|
|
13150
|
+
const remountWithFreshKey = async () => {
|
|
13151
|
+
mountKey += 1;
|
|
13152
|
+
try {
|
|
13153
|
+
clearMeasurementCache();
|
|
13154
|
+
} catch {
|
|
13763
13155
|
}
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
const getImageDebugInfo = (obj, bucket) => {
|
|
13768
|
-
if (!obj || typeof obj !== "object") return;
|
|
13769
|
-
const candidates = [obj._element, obj._originalElement, obj._filteredEl, obj._cacheCanvasEl];
|
|
13770
|
-
for (const candidate of candidates) {
|
|
13771
|
-
if (candidate instanceof HTMLImageElement) {
|
|
13772
|
-
bucket.push({
|
|
13773
|
-
id: obj.__docuforgeId || obj.id || "unknown",
|
|
13774
|
-
src: (candidate.currentSrc || candidate.src || "").slice(0, 240),
|
|
13775
|
-
complete: candidate.complete,
|
|
13776
|
-
naturalWidth: candidate.naturalWidth,
|
|
13777
|
-
naturalHeight: candidate.naturalHeight
|
|
13778
|
-
});
|
|
13779
|
-
}
|
|
13156
|
+
try {
|
|
13157
|
+
clearFabricCharCache();
|
|
13158
|
+
} catch {
|
|
13780
13159
|
}
|
|
13781
|
-
|
|
13782
|
-
|
|
13783
|
-
|
|
13160
|
+
try {
|
|
13161
|
+
root.unmount();
|
|
13162
|
+
} catch {
|
|
13784
13163
|
}
|
|
13164
|
+
root = createRoot(container);
|
|
13165
|
+
await new Promise((settle) => {
|
|
13166
|
+
const onReadyOnce = () => {
|
|
13167
|
+
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
13168
|
+
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
13169
|
+
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
13170
|
+
await this.waitForCanvasImages(container, expectedImageCount);
|
|
13171
|
+
await this.waitForStableTextMetrics(container, config);
|
|
13172
|
+
await this.waitForCanvasScene(container, config, pageIndex);
|
|
13173
|
+
if (!fabricInstance) return settle();
|
|
13174
|
+
settle();
|
|
13175
|
+
}).catch(() => settle());
|
|
13176
|
+
};
|
|
13177
|
+
root.render(
|
|
13178
|
+
createElement(PreviewCanvas2, {
|
|
13179
|
+
key: `remount-${mountKey}`,
|
|
13180
|
+
config,
|
|
13181
|
+
pageIndex,
|
|
13182
|
+
zoom: pixelRatio,
|
|
13183
|
+
absoluteZoom: true,
|
|
13184
|
+
skipFontReadyWait: false,
|
|
13185
|
+
onReady: onReadyOnce
|
|
13186
|
+
})
|
|
13187
|
+
);
|
|
13188
|
+
});
|
|
13785
13189
|
};
|
|
13786
|
-
const
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
|
|
13792
|
-
|
|
13793
|
-
|
|
13794
|
-
|
|
13795
|
-
|
|
13796
|
-
|
|
13797
|
-
|
|
13798
|
-
|
|
13799
|
-
|
|
13800
|
-
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
13804
|
-
|
|
13805
|
-
|
|
13806
|
-
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13815
|
-
|
|
13816
|
-
|
|
13190
|
+
const onReady = () => {
|
|
13191
|
+
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
13192
|
+
try {
|
|
13193
|
+
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
13194
|
+
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
13195
|
+
await this.waitForCanvasImages(container, expectedImageCount);
|
|
13196
|
+
await this.waitForStableTextMetrics(container, config);
|
|
13197
|
+
await this.waitForCanvasScene(container, config, pageIndex);
|
|
13198
|
+
firstMountSettled = true;
|
|
13199
|
+
if (hasAutoShrink && lateFontSettleDetected) {
|
|
13200
|
+
console.log("[canvas-renderer][parity] late font-settle detected — remounting for auto-shrink reflow");
|
|
13201
|
+
await remountWithFreshKey();
|
|
13202
|
+
}
|
|
13203
|
+
const fabricCanvas = container.querySelector("canvas.upper-canvas, canvas");
|
|
13204
|
+
const sourceCanvas = (fabricInstance == null ? void 0 : fabricInstance.lowerCanvasEl) || container.querySelector("canvas.lower-canvas") || fabricCanvas;
|
|
13205
|
+
const fabricInstanceAfter = this.getFabricCanvasFromContainer(container) || fabricInstance;
|
|
13206
|
+
const sourceCanvasAfter = (fabricInstanceAfter == null ? void 0 : fabricInstanceAfter.lowerCanvasEl) || container.querySelector("canvas.lower-canvas") || sourceCanvas;
|
|
13207
|
+
if (!sourceCanvas) {
|
|
13208
|
+
cleanup();
|
|
13209
|
+
reject(new Error("No canvas element found after render"));
|
|
13210
|
+
return;
|
|
13211
|
+
}
|
|
13212
|
+
const exportCanvas = document.createElement("canvas");
|
|
13213
|
+
exportCanvas.width = sourceCanvasAfter.width;
|
|
13214
|
+
exportCanvas.height = sourceCanvasAfter.height;
|
|
13215
|
+
const exportCtx = exportCanvas.getContext("2d");
|
|
13216
|
+
if (!exportCtx) {
|
|
13217
|
+
cleanup();
|
|
13218
|
+
reject(new Error("Failed to create export canvas"));
|
|
13219
|
+
return;
|
|
13220
|
+
}
|
|
13221
|
+
exportCtx.save();
|
|
13222
|
+
exportCtx.scale(sourceCanvasAfter.width / canvasWidth, sourceCanvasAfter.height / canvasHeight);
|
|
13223
|
+
this.paintPageBackground(exportCtx, config.pages[pageIndex], canvasWidth, canvasHeight);
|
|
13224
|
+
exportCtx.restore();
|
|
13225
|
+
exportCtx.drawImage(sourceCanvasAfter, 0, 0);
|
|
13226
|
+
const mimeType = format === "jpeg" ? "image/jpeg" : format === "webp" ? "image/webp" : "image/png";
|
|
13227
|
+
const dataUrl = exportCanvas.toDataURL(mimeType, quality);
|
|
13228
|
+
cleanup();
|
|
13229
|
+
resolve(dataUrl);
|
|
13230
|
+
} catch (err) {
|
|
13231
|
+
cleanup();
|
|
13232
|
+
reject(err);
|
|
13817
13233
|
}
|
|
13818
|
-
|
|
13819
|
-
index,
|
|
13820
|
-
src: (img.currentSrc || img.src || "").slice(0, 240),
|
|
13821
|
-
complete: img.complete,
|
|
13822
|
-
naturalWidth: img.naturalWidth,
|
|
13823
|
-
naturalHeight: img.naturalHeight
|
|
13824
|
-
}));
|
|
13825
|
-
console.warn(`[canvas-renderer][asset-wait-timeout] elapsed=${elapsed}ms ${summary}`);
|
|
13826
|
-
console.warn("[canvas-renderer][asset-wait-timeout][dom-images]", domImageDebug);
|
|
13827
|
-
console.warn("[canvas-renderer][asset-wait-timeout][fabric-images]", fabricImageDebug);
|
|
13828
|
-
settle();
|
|
13829
|
-
return;
|
|
13830
|
-
}
|
|
13831
|
-
setTimeout(check, pollMs);
|
|
13234
|
+
});
|
|
13832
13235
|
};
|
|
13833
|
-
|
|
13236
|
+
root = createRoot(container);
|
|
13237
|
+
root.render(
|
|
13238
|
+
createElement(PreviewCanvas2, {
|
|
13239
|
+
config,
|
|
13240
|
+
pageIndex,
|
|
13241
|
+
zoom: pixelRatio,
|
|
13242
|
+
absoluteZoom: true,
|
|
13243
|
+
skipFontReadyWait: false,
|
|
13244
|
+
onReady
|
|
13245
|
+
})
|
|
13246
|
+
);
|
|
13834
13247
|
});
|
|
13835
13248
|
}
|
|
13836
|
-
|
|
13837
|
-
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
}
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
13249
|
+
// ─── Internal: capture SVG from a rendered Fabric canvas ───
|
|
13250
|
+
//
|
|
13251
|
+
// APPROACH: Use the SAME PreviewCanvas that renders perfect PNGs, then call
|
|
13252
|
+
// Fabric's toSVG() on that canvas. This guarantees 100% layout parity —
|
|
13253
|
+
// the SVG is a vector snapshot of exactly what's on screen.
|
|
13254
|
+
//
|
|
13255
|
+
// The trick: before calling toSVG(), we temporarily neutralize the viewport
|
|
13256
|
+
// transform and retina scaling so Fabric emits coordinates in logical
|
|
13257
|
+
// document space (e.g. 612x792) instead of inflated pixel space.
|
|
13258
|
+
captureSvgViaPreviewCanvas(config, pageIndex, canvasWidth, canvasHeight) {
|
|
13259
|
+
return new Promise(async (resolve, reject) => {
|
|
13260
|
+
const { PreviewCanvas: PreviewCanvas2 } = await Promise.resolve().then(() => PreviewCanvas$1);
|
|
13261
|
+
const container = document.createElement("div");
|
|
13262
|
+
container.style.cssText = `
|
|
13263
|
+
position: fixed; left: -99999px; top: -99999px;
|
|
13264
|
+
width: ${canvasWidth}px; height: ${canvasHeight}px;
|
|
13265
|
+
overflow: hidden; pointer-events: none; opacity: 0;
|
|
13266
|
+
`;
|
|
13267
|
+
document.body.appendChild(container);
|
|
13268
|
+
const timeout = setTimeout(() => {
|
|
13269
|
+
cleanup();
|
|
13270
|
+
reject(new Error("SVG render timeout (30s)"));
|
|
13271
|
+
}, 3e4);
|
|
13272
|
+
let root = null;
|
|
13273
|
+
const mountKey = 0;
|
|
13274
|
+
const cleanup = () => {
|
|
13275
|
+
clearTimeout(timeout);
|
|
13276
|
+
try {
|
|
13277
|
+
root == null ? void 0 : root.unmount();
|
|
13278
|
+
} catch {
|
|
13856
13279
|
}
|
|
13857
|
-
|
|
13280
|
+
container.remove();
|
|
13858
13281
|
};
|
|
13859
|
-
|
|
13282
|
+
const mountPreview = (readyHandler) => {
|
|
13283
|
+
root = createRoot(container);
|
|
13284
|
+
root.render(
|
|
13285
|
+
createElement(PreviewCanvas2, {
|
|
13286
|
+
key: `svg-capture-${mountKey}`,
|
|
13287
|
+
config,
|
|
13288
|
+
pageIndex,
|
|
13289
|
+
zoom: 1,
|
|
13290
|
+
absoluteZoom: true,
|
|
13291
|
+
skipFontReadyWait: false,
|
|
13292
|
+
onReady: readyHandler
|
|
13293
|
+
})
|
|
13294
|
+
);
|
|
13295
|
+
};
|
|
13296
|
+
const onReady = () => {
|
|
13297
|
+
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
13298
|
+
var _a, _b;
|
|
13299
|
+
try {
|
|
13300
|
+
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
13301
|
+
await this.waitForCanvasImages(container, expectedImageCount);
|
|
13302
|
+
await this.waitForStableTextMetrics(container, config);
|
|
13303
|
+
await this.waitForCanvasScene(container, config, pageIndex);
|
|
13304
|
+
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
13305
|
+
if (!fabricInstance) {
|
|
13306
|
+
cleanup();
|
|
13307
|
+
reject(new Error("No Fabric canvas instance found for SVG capture"));
|
|
13308
|
+
return;
|
|
13309
|
+
}
|
|
13310
|
+
const prevVPT = fabricInstance.viewportTransform ? [...fabricInstance.viewportTransform] : void 0;
|
|
13311
|
+
const prevSvgVPT = fabricInstance.svgViewportTransformation;
|
|
13312
|
+
const prevRetina = fabricInstance.enableRetinaScaling;
|
|
13313
|
+
const prevWidth = fabricInstance.width;
|
|
13314
|
+
const prevHeight = fabricInstance.height;
|
|
13315
|
+
fabricInstance.viewportTransform = [1, 0, 0, 1, 0, 0];
|
|
13316
|
+
fabricInstance.svgViewportTransformation = false;
|
|
13317
|
+
fabricInstance.enableRetinaScaling = false;
|
|
13318
|
+
fabricInstance.setDimensions(
|
|
13319
|
+
{ width: canvasWidth, height: canvasHeight },
|
|
13320
|
+
{ cssOnly: false, backstoreOnly: false }
|
|
13321
|
+
);
|
|
13322
|
+
const rawSvgString = fabricInstance.toSVG();
|
|
13323
|
+
const svgString = this.normalizeSvgDimensions(
|
|
13324
|
+
rawSvgString,
|
|
13325
|
+
canvasWidth,
|
|
13326
|
+
canvasHeight
|
|
13327
|
+
);
|
|
13328
|
+
fabricInstance.enableRetinaScaling = prevRetina;
|
|
13329
|
+
fabricInstance.setDimensions(
|
|
13330
|
+
{ width: prevWidth, height: prevHeight },
|
|
13331
|
+
{ cssOnly: false, backstoreOnly: false }
|
|
13332
|
+
);
|
|
13333
|
+
if (prevVPT) fabricInstance.viewportTransform = prevVPT;
|
|
13334
|
+
fabricInstance.svgViewportTransformation = prevSvgVPT;
|
|
13335
|
+
const page = config.pages[pageIndex];
|
|
13336
|
+
const backgroundColor = ((_a = page == null ? void 0 : page.settings) == null ? void 0 : _a.backgroundColor) || "#ffffff";
|
|
13337
|
+
const backgroundGradient = (_b = page == null ? void 0 : page.settings) == null ? void 0 : _b.backgroundGradient;
|
|
13338
|
+
cleanup();
|
|
13339
|
+
resolve({
|
|
13340
|
+
svg: svgString,
|
|
13341
|
+
width: canvasWidth,
|
|
13342
|
+
height: canvasHeight,
|
|
13343
|
+
backgroundColor,
|
|
13344
|
+
backgroundGradient
|
|
13345
|
+
});
|
|
13346
|
+
} catch (err) {
|
|
13347
|
+
cleanup();
|
|
13348
|
+
reject(err);
|
|
13349
|
+
}
|
|
13350
|
+
});
|
|
13351
|
+
};
|
|
13352
|
+
mountPreview(onReady);
|
|
13860
13353
|
});
|
|
13861
13354
|
}
|
|
13862
|
-
async waitForRelevantFonts(config, maxWaitMs = 1800) {
|
|
13863
|
-
if (typeof document === "undefined" || !document.fonts) return;
|
|
13864
|
-
const descriptors = collectFontDescriptorsFromConfig(config);
|
|
13865
|
-
if (descriptors.length === 0) return;
|
|
13866
|
-
const loads = Promise.all(
|
|
13867
|
-
descriptors.map((descriptor) => {
|
|
13868
|
-
const stylePrefix = descriptor.style === "italic" ? "italic " : "";
|
|
13869
|
-
const spec = `${stylePrefix}${descriptor.weight} 16px "${descriptor.family}"`;
|
|
13870
|
-
return document.fonts.load(spec).catch(() => []);
|
|
13871
|
-
})
|
|
13872
|
-
).then(() => void 0);
|
|
13873
|
-
await Promise.race([
|
|
13874
|
-
loads,
|
|
13875
|
-
new Promise((resolve) => setTimeout(resolve, maxWaitMs))
|
|
13876
|
-
]);
|
|
13877
|
-
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
|
|
13878
|
-
}
|
|
13879
13355
|
/**
|
|
13880
|
-
*
|
|
13881
|
-
* (
|
|
13882
|
-
*
|
|
13883
|
-
*
|
|
13884
|
-
*
|
|
13885
|
-
* Stronger than `ensureFontsForResolvedConfig` (which is fire-and-forget)
|
|
13886
|
-
* — this awaits each `document.fonts.load(spec)` AND `document.fonts.ready`,
|
|
13887
|
-
* racing the whole thing against `maxWaitMs` so a slow CDN can't hang the
|
|
13888
|
-
* renderer.
|
|
13356
|
+
* Normalize the SVG's width/height/viewBox to match the logical page dimensions.
|
|
13357
|
+
* Fabric's toSVG() may output dimensions scaled by the canvas element's actual
|
|
13358
|
+
* pixel size (e.g., 2x due to devicePixelRatio), causing svg2pdf to render
|
|
13359
|
+
* content at the wrong scale. This rewrites the root <svg> attributes to ensure
|
|
13360
|
+
* the SVG coordinate system matches the intended page size exactly.
|
|
13889
13361
|
*/
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13362
|
+
normalizeSvgDimensions(svg, targetWidth, targetHeight) {
|
|
13363
|
+
const widthMatch = svg.match(/<svg[^>]*\bwidth="([^"]+)"/i);
|
|
13364
|
+
const heightMatch = svg.match(/<svg[^>]*\bheight="([^"]+)"/i);
|
|
13365
|
+
const svgWidth = widthMatch ? parseFloat(widthMatch[1]) : targetWidth;
|
|
13366
|
+
const svgHeight = heightMatch ? parseFloat(heightMatch[1]) : targetHeight;
|
|
13367
|
+
console.log(
|
|
13368
|
+
`[canvas-renderer][svg-normalize] root ${svgWidth}x${svgHeight} → page ${targetWidth}x${targetHeight}`
|
|
13369
|
+
);
|
|
13370
|
+
let normalized = svg;
|
|
13371
|
+
if (/\bwidth="[^"]*"/i.test(normalized)) {
|
|
13372
|
+
normalized = normalized.replace(/(<svg[^>]*\b)width="[^"]*"/i, `$1width="${targetWidth}"`);
|
|
13373
|
+
} else {
|
|
13374
|
+
normalized = normalized.replace(/<svg\b/i, `<svg width="${targetWidth}"`);
|
|
13375
|
+
}
|
|
13376
|
+
if (/\bheight="[^"]*"/i.test(normalized)) {
|
|
13377
|
+
normalized = normalized.replace(/(<svg[^>]*\b)height="[^"]*"/i, `$1height="${targetHeight}"`);
|
|
13378
|
+
} else {
|
|
13379
|
+
normalized = normalized.replace(/<svg\b/i, `<svg height="${targetHeight}"`);
|
|
13380
|
+
}
|
|
13381
|
+
const viewBox = `0 0 ${targetWidth} ${targetHeight}`;
|
|
13382
|
+
if (/\bviewBox="[^"]*"/i.test(normalized)) {
|
|
13383
|
+
normalized = normalized.replace(/viewBox="[^"]*"/i, `viewBox="${viewBox}"`);
|
|
13384
|
+
} else {
|
|
13385
|
+
normalized = normalized.replace(/<svg\b/i, `<svg viewBox="${viewBox}"`);
|
|
13386
|
+
}
|
|
13387
|
+
normalized = normalized.replace(/="undefined"/g, '="0"');
|
|
13388
|
+
normalized = normalized.replace(/="NaN"/g, '="0"');
|
|
13389
|
+
if (/\bx="[^"]*"/i.test(normalized)) {
|
|
13390
|
+
normalized = normalized.replace(/(<svg[^>]*\b)x="[^"]*"/i, '$1x="0"');
|
|
13391
|
+
} else {
|
|
13392
|
+
normalized = normalized.replace(/<svg\b/i, '<svg x="0"');
|
|
13393
|
+
}
|
|
13394
|
+
if (/\by="[^"]*"/i.test(normalized)) {
|
|
13395
|
+
normalized = normalized.replace(/(<svg[^>]*\b)y="[^"]*"/i, '$1y="0"');
|
|
13396
|
+
} else {
|
|
13397
|
+
normalized = normalized.replace(/<svg\b/i, '<svg y="0"');
|
|
13398
|
+
}
|
|
13399
|
+
normalized = normalized.replace(/\bpreserveAspectRatio="[^"]*"/i, 'preserveAspectRatio="none"');
|
|
13400
|
+
if (!/\bpreserveAspectRatio="[^"]*"/i.test(normalized)) {
|
|
13401
|
+
normalized = normalized.replace(/<svg\b/i, '<svg preserveAspectRatio="none"');
|
|
13402
|
+
}
|
|
13403
|
+
return normalized;
|
|
13898
13404
|
}
|
|
13899
|
-
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13405
|
+
/**
|
|
13406
|
+
* Find the Fabric.Canvas instance that belongs to a given container element,
|
|
13407
|
+
* using the global __fabricCanvasRegistry (set by PageCanvas).
|
|
13408
|
+
*/
|
|
13409
|
+
getFabricCanvasFromContainer(container) {
|
|
13410
|
+
const registry2 = window.__fabricCanvasRegistry;
|
|
13411
|
+
if (registry2 instanceof Map) {
|
|
13412
|
+
for (const entry of registry2.values()) {
|
|
13413
|
+
const canvas = (entry == null ? void 0 : entry.canvas) || entry;
|
|
13414
|
+
if (!canvas || typeof canvas.toSVG !== "function") continue;
|
|
13415
|
+
const el = canvas.lowerCanvasEl || canvas.upperCanvasEl;
|
|
13416
|
+
if (el && container.contains(el)) return canvas;
|
|
13417
|
+
}
|
|
13908
13418
|
}
|
|
13909
|
-
|
|
13910
|
-
|
|
13419
|
+
return null;
|
|
13420
|
+
}
|
|
13421
|
+
async waitForStableTextMetrics(container, config) {
|
|
13422
|
+
var _a, _b, _c;
|
|
13423
|
+
if (typeof document !== "undefined") {
|
|
13424
|
+
void ensureFontsForResolvedConfig(config);
|
|
13425
|
+
await this.waitForRelevantFonts(config);
|
|
13911
13426
|
}
|
|
13912
|
-
|
|
13427
|
+
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
13428
|
+
if (!(fabricInstance == null ? void 0 : fabricInstance.getObjects)) return;
|
|
13429
|
+
const waitForPaint = () => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(() => r())));
|
|
13430
|
+
const primeCharBounds = (obj) => {
|
|
13431
|
+
if (obj instanceof fabric.Textbox) {
|
|
13432
|
+
const lines = obj._textLines;
|
|
13433
|
+
if (Array.isArray(lines)) {
|
|
13434
|
+
for (let i = 0; i < lines.length; i++) {
|
|
13435
|
+
try {
|
|
13436
|
+
obj.getLineWidth(i);
|
|
13437
|
+
} catch {
|
|
13438
|
+
}
|
|
13439
|
+
}
|
|
13440
|
+
}
|
|
13441
|
+
obj.dirty = true;
|
|
13442
|
+
return;
|
|
13443
|
+
}
|
|
13444
|
+
if (obj instanceof fabric.Group) {
|
|
13445
|
+
obj.getObjects().forEach(primeCharBounds);
|
|
13446
|
+
obj.dirty = true;
|
|
13447
|
+
}
|
|
13448
|
+
};
|
|
13449
|
+
fabricInstance.getObjects().forEach(primeCharBounds);
|
|
13450
|
+
(_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
|
|
13451
|
+
(_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
|
|
13452
|
+
await waitForPaint();
|
|
13453
|
+
(_c = fabricInstance.renderAll) == null ? void 0 : _c.call(fabricInstance);
|
|
13454
|
+
await waitForPaint();
|
|
13455
|
+
}
|
|
13456
|
+
}
|
|
13457
|
+
const FONT_WEIGHT_LABELS = {
|
|
13458
|
+
300: "Light",
|
|
13459
|
+
400: "Regular",
|
|
13460
|
+
500: "Medium",
|
|
13461
|
+
600: "SemiBold",
|
|
13462
|
+
700: "Bold"
|
|
13463
|
+
};
|
|
13464
|
+
function resolveFontWeight(weight) {
|
|
13465
|
+
if (weight <= 350) return 300;
|
|
13466
|
+
if (weight <= 450) return 400;
|
|
13467
|
+
if (weight <= 550) return 500;
|
|
13468
|
+
if (weight <= 650) return 600;
|
|
13469
|
+
return 700;
|
|
13470
|
+
}
|
|
13471
|
+
const FONT_FALLBACK_SYMBOLS = "Noto Sans";
|
|
13472
|
+
const FONT_FALLBACK_DEVANAGARI = "Hind";
|
|
13473
|
+
const FONT_FILES = {
|
|
13474
|
+
"Playfair Display": {
|
|
13475
|
+
regular: "PlayfairDisplay-Regular.ttf",
|
|
13476
|
+
bold: "PlayfairDisplay-Bold.ttf",
|
|
13477
|
+
italic: "PlayfairDisplay-Italic.ttf",
|
|
13478
|
+
boldItalic: "PlayfairDisplay-BoldItalic.ttf"
|
|
13479
|
+
},
|
|
13480
|
+
"Merriweather": {
|
|
13481
|
+
regular: "Merriweather-Regular.ttf",
|
|
13482
|
+
bold: "Merriweather-Bold.ttf",
|
|
13483
|
+
light: "Merriweather-Light.ttf",
|
|
13484
|
+
italic: "Merriweather-Italic.ttf",
|
|
13485
|
+
boldItalic: "Merriweather-BoldItalic.ttf",
|
|
13486
|
+
lightItalic: "Merriweather-LightItalic.ttf"
|
|
13487
|
+
},
|
|
13488
|
+
"Lora": {
|
|
13489
|
+
regular: "Lora-Regular.ttf",
|
|
13490
|
+
bold: "Lora-Bold.ttf",
|
|
13491
|
+
italic: "Lora-Italic.ttf",
|
|
13492
|
+
boldItalic: "Lora-BoldItalic.ttf"
|
|
13493
|
+
},
|
|
13494
|
+
"Montserrat": {
|
|
13495
|
+
regular: "Montserrat-Regular.ttf",
|
|
13496
|
+
bold: "Montserrat-Bold.ttf",
|
|
13497
|
+
light: "Montserrat-Light.ttf",
|
|
13498
|
+
medium: "Montserrat-Medium.ttf",
|
|
13499
|
+
semibold: "Montserrat-SemiBold.ttf",
|
|
13500
|
+
italic: "Montserrat-Italic.ttf",
|
|
13501
|
+
boldItalic: "Montserrat-BoldItalic.ttf",
|
|
13502
|
+
lightItalic: "Montserrat-LightItalic.ttf",
|
|
13503
|
+
mediumItalic: "Montserrat-MediumItalic.ttf",
|
|
13504
|
+
semiboldItalic: "Montserrat-SemiBoldItalic.ttf"
|
|
13505
|
+
},
|
|
13506
|
+
"Open Sans": {
|
|
13507
|
+
regular: "OpenSans-Regular.ttf",
|
|
13508
|
+
bold: "OpenSans-Bold.ttf",
|
|
13509
|
+
light: "OpenSans-Light.ttf",
|
|
13510
|
+
semibold: "OpenSans-SemiBold.ttf",
|
|
13511
|
+
italic: "OpenSans-Italic.ttf",
|
|
13512
|
+
boldItalic: "OpenSans-BoldItalic.ttf",
|
|
13513
|
+
lightItalic: "OpenSans-LightItalic.ttf",
|
|
13514
|
+
semiboldItalic: "OpenSans-SemiBoldItalic.ttf"
|
|
13515
|
+
},
|
|
13516
|
+
"Roboto": {
|
|
13517
|
+
regular: "Roboto-Regular.ttf",
|
|
13518
|
+
bold: "Roboto-Bold.ttf",
|
|
13519
|
+
light: "Roboto-Light.ttf",
|
|
13520
|
+
medium: "Roboto-Medium.ttf",
|
|
13521
|
+
italic: "Roboto-Italic.ttf",
|
|
13522
|
+
boldItalic: "Roboto-BoldItalic.ttf",
|
|
13523
|
+
lightItalic: "Roboto-LightItalic.ttf",
|
|
13524
|
+
mediumItalic: "Roboto-MediumItalic.ttf"
|
|
13525
|
+
},
|
|
13526
|
+
"Lato": {
|
|
13527
|
+
regular: "Lato-Regular.ttf",
|
|
13528
|
+
bold: "Lato-Bold.ttf",
|
|
13529
|
+
light: "Lato-Light.ttf",
|
|
13530
|
+
italic: "Lato-Italic.ttf",
|
|
13531
|
+
boldItalic: "Lato-BoldItalic.ttf",
|
|
13532
|
+
lightItalic: "Lato-LightItalic.ttf"
|
|
13533
|
+
},
|
|
13534
|
+
"Raleway": {
|
|
13535
|
+
regular: "Raleway-Regular.ttf",
|
|
13536
|
+
bold: "Raleway-Bold.ttf",
|
|
13537
|
+
light: "Raleway-Light.ttf",
|
|
13538
|
+
medium: "Raleway-Medium.ttf",
|
|
13539
|
+
semibold: "Raleway-SemiBold.ttf",
|
|
13540
|
+
italic: "Raleway-Italic.ttf",
|
|
13541
|
+
boldItalic: "Raleway-BoldItalic.ttf",
|
|
13542
|
+
lightItalic: "Raleway-LightItalic.ttf"
|
|
13543
|
+
},
|
|
13544
|
+
"Poppins": {
|
|
13545
|
+
regular: "Poppins-Regular.ttf",
|
|
13546
|
+
bold: "Poppins-Bold.ttf",
|
|
13547
|
+
light: "Poppins-Light.ttf",
|
|
13548
|
+
medium: "Poppins-Medium.ttf",
|
|
13549
|
+
semibold: "Poppins-SemiBold.ttf",
|
|
13550
|
+
italic: "Poppins-Italic.ttf",
|
|
13551
|
+
boldItalic: "Poppins-BoldItalic.ttf",
|
|
13552
|
+
lightItalic: "Poppins-LightItalic.ttf",
|
|
13553
|
+
mediumItalic: "Poppins-MediumItalic.ttf",
|
|
13554
|
+
semiboldItalic: "Poppins-SemiBoldItalic.ttf"
|
|
13555
|
+
},
|
|
13556
|
+
"Inter": {
|
|
13557
|
+
regular: "Inter-Regular.ttf",
|
|
13558
|
+
bold: "Inter-Bold.ttf",
|
|
13559
|
+
italic: "Inter-Italic.ttf",
|
|
13560
|
+
boldItalic: "Inter-BoldItalic.ttf"
|
|
13561
|
+
},
|
|
13562
|
+
"Nunito": {
|
|
13563
|
+
regular: "Nunito-Regular.ttf",
|
|
13564
|
+
bold: "Nunito-Bold.ttf",
|
|
13565
|
+
light: "Nunito-Light.ttf",
|
|
13566
|
+
medium: "Nunito-Medium.ttf",
|
|
13567
|
+
semibold: "Nunito-SemiBold.ttf",
|
|
13568
|
+
italic: "Nunito-Italic.ttf",
|
|
13569
|
+
boldItalic: "Nunito-BoldItalic.ttf"
|
|
13570
|
+
},
|
|
13571
|
+
"Source Sans Pro": {
|
|
13572
|
+
regular: "SourceSansPro-Regular.ttf",
|
|
13573
|
+
bold: "SourceSansPro-Bold.ttf",
|
|
13574
|
+
light: "SourceSansPro-Light.ttf",
|
|
13575
|
+
italic: "SourceSansPro-Italic.ttf",
|
|
13576
|
+
boldItalic: "SourceSansPro-BoldItalic.ttf"
|
|
13577
|
+
},
|
|
13578
|
+
"Work Sans": {
|
|
13579
|
+
regular: "WorkSans-Regular.ttf",
|
|
13580
|
+
bold: "WorkSans-Bold.ttf",
|
|
13581
|
+
italic: "WorkSans-Italic.ttf",
|
|
13582
|
+
boldItalic: "WorkSans-BoldItalic.ttf"
|
|
13583
|
+
},
|
|
13584
|
+
"Oswald": { regular: "Oswald-Regular.ttf", bold: "Oswald-Bold.ttf" },
|
|
13585
|
+
"Bebas Neue": { regular: "BebasNeue-Regular.ttf" },
|
|
13586
|
+
"Abril Fatface": { regular: "AbrilFatface-Regular.ttf" },
|
|
13587
|
+
"Dancing Script": { regular: "DancingScript-Regular.ttf", bold: "DancingScript-Bold.ttf" },
|
|
13588
|
+
"Pacifico": { regular: "Pacifico-Regular.ttf" },
|
|
13589
|
+
"Great Vibes": { regular: "GreatVibes-Regular.ttf" },
|
|
13590
|
+
"DM Sans": {
|
|
13591
|
+
regular: "DMSans-Regular.ttf",
|
|
13592
|
+
bold: "DMSans-Bold.ttf",
|
|
13593
|
+
light: "DMSans-Light.ttf",
|
|
13594
|
+
medium: "DMSans-Medium.ttf",
|
|
13595
|
+
semibold: "DMSans-SemiBold.ttf",
|
|
13596
|
+
italic: "DMSans-RegularItalic.ttf",
|
|
13597
|
+
boldItalic: "DMSans-BoldItalic.ttf",
|
|
13598
|
+
lightItalic: "DMSans-LightItalic.ttf",
|
|
13599
|
+
mediumItalic: "DMSans-MediumItalic.ttf",
|
|
13600
|
+
semiboldItalic: "DMSans-SemiBoldItalic.ttf"
|
|
13601
|
+
},
|
|
13602
|
+
"Outfit": {
|
|
13603
|
+
regular: "Outfit-Regular.ttf",
|
|
13604
|
+
bold: "Outfit-Bold.ttf",
|
|
13605
|
+
light: "Outfit-Light.ttf",
|
|
13606
|
+
medium: "Outfit-Medium.ttf",
|
|
13607
|
+
semibold: "Outfit-SemiBold.ttf"
|
|
13608
|
+
},
|
|
13609
|
+
"Figtree": {
|
|
13610
|
+
regular: "Figtree-Regular.ttf",
|
|
13611
|
+
bold: "Figtree-Bold.ttf",
|
|
13612
|
+
light: "Figtree-Light.ttf",
|
|
13613
|
+
medium: "Figtree-Medium.ttf",
|
|
13614
|
+
semibold: "Figtree-SemiBold.ttf",
|
|
13615
|
+
italic: "Figtree-RegularItalic.ttf",
|
|
13616
|
+
boldItalic: "Figtree-BoldItalic.ttf",
|
|
13617
|
+
lightItalic: "Figtree-LightItalic.ttf",
|
|
13618
|
+
mediumItalic: "Figtree-MediumItalic.ttf",
|
|
13619
|
+
semiboldItalic: "Figtree-SemiBoldItalic.ttf"
|
|
13620
|
+
},
|
|
13621
|
+
"Manrope": {
|
|
13622
|
+
regular: "Manrope-Regular.ttf",
|
|
13623
|
+
bold: "Manrope-Bold.ttf",
|
|
13624
|
+
light: "Manrope-Light.ttf",
|
|
13625
|
+
medium: "Manrope-Medium.ttf",
|
|
13626
|
+
semibold: "Manrope-SemiBold.ttf"
|
|
13627
|
+
},
|
|
13628
|
+
"Space Grotesk": {
|
|
13629
|
+
regular: "SpaceGrotesk-Regular.ttf",
|
|
13630
|
+
bold: "SpaceGrotesk-Bold.ttf",
|
|
13631
|
+
light: "SpaceGrotesk-Light.ttf",
|
|
13632
|
+
medium: "SpaceGrotesk-Medium.ttf",
|
|
13633
|
+
semibold: "SpaceGrotesk-SemiBold.ttf"
|
|
13634
|
+
},
|
|
13635
|
+
"League Spartan": {
|
|
13636
|
+
regular: "LeagueSpartan-Regular.ttf",
|
|
13637
|
+
bold: "LeagueSpartan-Bold.ttf",
|
|
13638
|
+
light: "LeagueSpartan-Light.ttf",
|
|
13639
|
+
medium: "LeagueSpartan-Medium.ttf",
|
|
13640
|
+
semibold: "LeagueSpartan-SemiBold.ttf"
|
|
13641
|
+
},
|
|
13642
|
+
"EB Garamond": {
|
|
13643
|
+
regular: "EBGaramond-Regular.ttf",
|
|
13644
|
+
bold: "EBGaramond-Bold.ttf",
|
|
13645
|
+
medium: "EBGaramond-Medium.ttf",
|
|
13646
|
+
semibold: "EBGaramond-SemiBold.ttf",
|
|
13647
|
+
italic: "EBGaramond-RegularItalic.ttf",
|
|
13648
|
+
boldItalic: "EBGaramond-BoldItalic.ttf",
|
|
13649
|
+
mediumItalic: "EBGaramond-MediumItalic.ttf",
|
|
13650
|
+
semiboldItalic: "EBGaramond-SemiBoldItalic.ttf"
|
|
13651
|
+
},
|
|
13652
|
+
"Libre Baskerville": {
|
|
13653
|
+
regular: "LibreBaskerville-Regular.ttf",
|
|
13654
|
+
bold: "LibreBaskerville-Bold.ttf",
|
|
13655
|
+
italic: "LibreBaskerville-RegularItalic.ttf",
|
|
13656
|
+
boldItalic: "LibreBaskerville-BoldItalic.ttf"
|
|
13657
|
+
},
|
|
13658
|
+
"Crimson Text": {
|
|
13659
|
+
regular: "CrimsonText-Regular.ttf",
|
|
13660
|
+
bold: "CrimsonText-Bold.ttf",
|
|
13661
|
+
italic: "CrimsonText-Italic.ttf",
|
|
13662
|
+
boldItalic: "CrimsonText-BoldItalic.ttf"
|
|
13663
|
+
},
|
|
13664
|
+
"DM Serif Display": {
|
|
13665
|
+
regular: "DMSerifDisplay-Regular.ttf",
|
|
13666
|
+
italic: "DMSerifDisplay-Italic.ttf"
|
|
13667
|
+
},
|
|
13668
|
+
"Libre Franklin": {
|
|
13669
|
+
regular: "LibreFranklin-Regular.ttf",
|
|
13670
|
+
bold: "LibreFranklin-Bold.ttf",
|
|
13671
|
+
light: "LibreFranklin-Light.ttf",
|
|
13672
|
+
medium: "LibreFranklin-Medium.ttf",
|
|
13673
|
+
semibold: "LibreFranklin-SemiBold.ttf",
|
|
13674
|
+
italic: "LibreFranklin-RegularItalic.ttf",
|
|
13675
|
+
boldItalic: "LibreFranklin-BoldItalic.ttf",
|
|
13676
|
+
lightItalic: "LibreFranklin-LightItalic.ttf",
|
|
13677
|
+
mediumItalic: "LibreFranklin-MediumItalic.ttf",
|
|
13678
|
+
semiboldItalic: "LibreFranklin-SemiBoldItalic.ttf"
|
|
13679
|
+
},
|
|
13680
|
+
"Mulish": {
|
|
13681
|
+
regular: "Mulish-Regular.ttf",
|
|
13682
|
+
bold: "Mulish-Bold.ttf",
|
|
13683
|
+
light: "Mulish-Light.ttf",
|
|
13684
|
+
medium: "Mulish-Medium.ttf",
|
|
13685
|
+
semibold: "Mulish-SemiBold.ttf",
|
|
13686
|
+
italic: "Mulish-RegularItalic.ttf",
|
|
13687
|
+
boldItalic: "Mulish-BoldItalic.ttf",
|
|
13688
|
+
lightItalic: "Mulish-LightItalic.ttf",
|
|
13689
|
+
mediumItalic: "Mulish-MediumItalic.ttf",
|
|
13690
|
+
semiboldItalic: "Mulish-SemiBoldItalic.ttf"
|
|
13691
|
+
},
|
|
13692
|
+
"Quicksand": {
|
|
13693
|
+
regular: "Quicksand-Regular.ttf",
|
|
13694
|
+
bold: "Quicksand-Bold.ttf",
|
|
13695
|
+
light: "Quicksand-Light.ttf",
|
|
13696
|
+
medium: "Quicksand-Medium.ttf",
|
|
13697
|
+
semibold: "Quicksand-SemiBold.ttf"
|
|
13698
|
+
},
|
|
13699
|
+
"Rubik": {
|
|
13700
|
+
regular: "Rubik-Regular.ttf",
|
|
13701
|
+
bold: "Rubik-Bold.ttf",
|
|
13702
|
+
light: "Rubik-Light.ttf",
|
|
13703
|
+
medium: "Rubik-Medium.ttf",
|
|
13704
|
+
semibold: "Rubik-SemiBold.ttf",
|
|
13705
|
+
italic: "Rubik-RegularItalic.ttf",
|
|
13706
|
+
boldItalic: "Rubik-BoldItalic.ttf",
|
|
13707
|
+
lightItalic: "Rubik-LightItalic.ttf",
|
|
13708
|
+
mediumItalic: "Rubik-MediumItalic.ttf",
|
|
13709
|
+
semiboldItalic: "Rubik-SemiBoldItalic.ttf"
|
|
13710
|
+
},
|
|
13711
|
+
"Karla": {
|
|
13712
|
+
regular: "Karla-Regular.ttf",
|
|
13713
|
+
bold: "Karla-Bold.ttf",
|
|
13714
|
+
light: "Karla-Light.ttf",
|
|
13715
|
+
medium: "Karla-Medium.ttf",
|
|
13716
|
+
semibold: "Karla-SemiBold.ttf",
|
|
13717
|
+
italic: "Karla-RegularItalic.ttf",
|
|
13718
|
+
boldItalic: "Karla-BoldItalic.ttf",
|
|
13719
|
+
lightItalic: "Karla-LightItalic.ttf",
|
|
13720
|
+
mediumItalic: "Karla-MediumItalic.ttf",
|
|
13721
|
+
semiboldItalic: "Karla-SemiBoldItalic.ttf"
|
|
13722
|
+
},
|
|
13723
|
+
"Plus Jakarta Sans": {
|
|
13724
|
+
regular: "PlusJakartaSans-Regular.ttf",
|
|
13725
|
+
bold: "PlusJakartaSans-Bold.ttf",
|
|
13726
|
+
light: "PlusJakartaSans-Light.ttf",
|
|
13727
|
+
medium: "PlusJakartaSans-Medium.ttf",
|
|
13728
|
+
semibold: "PlusJakartaSans-SemiBold.ttf",
|
|
13729
|
+
italic: "PlusJakartaSans-RegularItalic.ttf",
|
|
13730
|
+
boldItalic: "PlusJakartaSans-BoldItalic.ttf",
|
|
13731
|
+
lightItalic: "PlusJakartaSans-LightItalic.ttf",
|
|
13732
|
+
mediumItalic: "PlusJakartaSans-MediumItalic.ttf",
|
|
13733
|
+
semiboldItalic: "PlusJakartaSans-SemiBoldItalic.ttf"
|
|
13734
|
+
},
|
|
13735
|
+
"Sora": {
|
|
13736
|
+
regular: "Sora-Regular.ttf",
|
|
13737
|
+
bold: "Sora-Bold.ttf",
|
|
13738
|
+
light: "Sora-Light.ttf",
|
|
13739
|
+
medium: "Sora-Medium.ttf",
|
|
13740
|
+
semibold: "Sora-SemiBold.ttf"
|
|
13741
|
+
},
|
|
13742
|
+
"Urbanist": {
|
|
13743
|
+
regular: "Urbanist-Regular.ttf",
|
|
13744
|
+
bold: "Urbanist-Bold.ttf",
|
|
13745
|
+
light: "Urbanist-Light.ttf",
|
|
13746
|
+
medium: "Urbanist-Medium.ttf",
|
|
13747
|
+
semibold: "Urbanist-SemiBold.ttf",
|
|
13748
|
+
italic: "Urbanist-RegularItalic.ttf",
|
|
13749
|
+
boldItalic: "Urbanist-BoldItalic.ttf",
|
|
13750
|
+
lightItalic: "Urbanist-LightItalic.ttf",
|
|
13751
|
+
mediumItalic: "Urbanist-MediumItalic.ttf",
|
|
13752
|
+
semiboldItalic: "Urbanist-SemiBoldItalic.ttf"
|
|
13753
|
+
},
|
|
13754
|
+
"Lexend": {
|
|
13755
|
+
regular: "Lexend-Regular.ttf",
|
|
13756
|
+
bold: "Lexend-Bold.ttf",
|
|
13757
|
+
light: "Lexend-Light.ttf",
|
|
13758
|
+
medium: "Lexend-Medium.ttf",
|
|
13759
|
+
semibold: "Lexend-SemiBold.ttf"
|
|
13760
|
+
},
|
|
13761
|
+
"Albert Sans": {
|
|
13762
|
+
regular: "AlbertSans-Regular.ttf",
|
|
13763
|
+
bold: "AlbertSans-Bold.ttf",
|
|
13764
|
+
light: "AlbertSans-Light.ttf",
|
|
13765
|
+
medium: "AlbertSans-Medium.ttf",
|
|
13766
|
+
semibold: "AlbertSans-SemiBold.ttf",
|
|
13767
|
+
italic: "AlbertSans-RegularItalic.ttf",
|
|
13768
|
+
boldItalic: "AlbertSans-BoldItalic.ttf",
|
|
13769
|
+
lightItalic: "AlbertSans-LightItalic.ttf",
|
|
13770
|
+
mediumItalic: "AlbertSans-MediumItalic.ttf",
|
|
13771
|
+
semiboldItalic: "AlbertSans-SemiBoldItalic.ttf"
|
|
13772
|
+
},
|
|
13773
|
+
"Noto Sans": {
|
|
13774
|
+
regular: "NotoSans-Regular.ttf",
|
|
13775
|
+
bold: "NotoSans-Bold.ttf",
|
|
13776
|
+
light: "NotoSans-Light.ttf",
|
|
13777
|
+
medium: "NotoSans-Medium.ttf",
|
|
13778
|
+
semibold: "NotoSans-SemiBold.ttf",
|
|
13779
|
+
italic: "NotoSans-RegularItalic.ttf",
|
|
13780
|
+
boldItalic: "NotoSans-BoldItalic.ttf",
|
|
13781
|
+
lightItalic: "NotoSans-LightItalic.ttf",
|
|
13782
|
+
mediumItalic: "NotoSans-MediumItalic.ttf",
|
|
13783
|
+
semiboldItalic: "NotoSans-SemiBoldItalic.ttf"
|
|
13784
|
+
},
|
|
13785
|
+
"Cabin": {
|
|
13786
|
+
regular: "Cabin-Regular.ttf",
|
|
13787
|
+
bold: "Cabin-Bold.ttf",
|
|
13788
|
+
medium: "Cabin-Medium.ttf",
|
|
13789
|
+
semibold: "Cabin-SemiBold.ttf",
|
|
13790
|
+
italic: "Cabin-RegularItalic.ttf",
|
|
13791
|
+
boldItalic: "Cabin-BoldItalic.ttf",
|
|
13792
|
+
mediumItalic: "Cabin-MediumItalic.ttf",
|
|
13793
|
+
semiboldItalic: "Cabin-SemiBoldItalic.ttf"
|
|
13794
|
+
},
|
|
13795
|
+
"Barlow": {
|
|
13796
|
+
regular: "Barlow-Regular.ttf",
|
|
13797
|
+
bold: "Barlow-Bold.ttf",
|
|
13798
|
+
light: "Barlow-Light.ttf",
|
|
13799
|
+
medium: "Barlow-Medium.ttf",
|
|
13800
|
+
semibold: "Barlow-SemiBold.ttf",
|
|
13801
|
+
italic: "Barlow-Italic.ttf",
|
|
13802
|
+
boldItalic: "Barlow-BoldItalic.ttf"
|
|
13803
|
+
},
|
|
13804
|
+
"Josefin Sans": {
|
|
13805
|
+
regular: "JosefinSans-Regular.ttf",
|
|
13806
|
+
bold: "JosefinSans-Bold.ttf",
|
|
13807
|
+
light: "JosefinSans-Light.ttf",
|
|
13808
|
+
medium: "JosefinSans-Medium.ttf",
|
|
13809
|
+
semibold: "JosefinSans-SemiBold.ttf",
|
|
13810
|
+
italic: "JosefinSans-RegularItalic.ttf",
|
|
13811
|
+
boldItalic: "JosefinSans-BoldItalic.ttf",
|
|
13812
|
+
lightItalic: "JosefinSans-LightItalic.ttf",
|
|
13813
|
+
mediumItalic: "JosefinSans-MediumItalic.ttf",
|
|
13814
|
+
semiboldItalic: "JosefinSans-SemiBoldItalic.ttf"
|
|
13815
|
+
},
|
|
13816
|
+
"Archivo": {
|
|
13817
|
+
regular: "Archivo-Regular.ttf",
|
|
13818
|
+
bold: "Archivo-Bold.ttf",
|
|
13819
|
+
light: "Archivo-Light.ttf",
|
|
13820
|
+
medium: "Archivo-Medium.ttf",
|
|
13821
|
+
semibold: "Archivo-SemiBold.ttf",
|
|
13822
|
+
italic: "Archivo-RegularItalic.ttf",
|
|
13823
|
+
boldItalic: "Archivo-BoldItalic.ttf",
|
|
13824
|
+
lightItalic: "Archivo-LightItalic.ttf",
|
|
13825
|
+
mediumItalic: "Archivo-MediumItalic.ttf",
|
|
13826
|
+
semiboldItalic: "Archivo-SemiBoldItalic.ttf"
|
|
13827
|
+
},
|
|
13828
|
+
"Overpass": {
|
|
13829
|
+
regular: "Overpass-Regular.ttf",
|
|
13830
|
+
bold: "Overpass-Bold.ttf",
|
|
13831
|
+
light: "Overpass-Light.ttf",
|
|
13832
|
+
medium: "Overpass-Medium.ttf",
|
|
13833
|
+
semibold: "Overpass-SemiBold.ttf",
|
|
13834
|
+
italic: "Overpass-RegularItalic.ttf",
|
|
13835
|
+
boldItalic: "Overpass-BoldItalic.ttf",
|
|
13836
|
+
lightItalic: "Overpass-LightItalic.ttf",
|
|
13837
|
+
mediumItalic: "Overpass-MediumItalic.ttf",
|
|
13838
|
+
semiboldItalic: "Overpass-SemiBoldItalic.ttf"
|
|
13839
|
+
},
|
|
13840
|
+
"Exo 2": {
|
|
13841
|
+
regular: "Exo2-Regular.ttf",
|
|
13842
|
+
bold: "Exo2-Bold.ttf",
|
|
13843
|
+
light: "Exo2-Light.ttf",
|
|
13844
|
+
medium: "Exo2-Medium.ttf",
|
|
13845
|
+
semibold: "Exo2-SemiBold.ttf",
|
|
13846
|
+
italic: "Exo2-RegularItalic.ttf",
|
|
13847
|
+
boldItalic: "Exo2-BoldItalic.ttf",
|
|
13848
|
+
lightItalic: "Exo2-LightItalic.ttf",
|
|
13849
|
+
mediumItalic: "Exo2-MediumItalic.ttf",
|
|
13850
|
+
semiboldItalic: "Exo2-SemiBoldItalic.ttf"
|
|
13851
|
+
},
|
|
13852
|
+
"Roboto Mono": {
|
|
13853
|
+
regular: "RobotoMono-Regular.ttf",
|
|
13854
|
+
bold: "RobotoMono-Bold.ttf",
|
|
13855
|
+
light: "RobotoMono-Light.ttf",
|
|
13856
|
+
medium: "RobotoMono-Medium.ttf",
|
|
13857
|
+
semibold: "RobotoMono-SemiBold.ttf",
|
|
13858
|
+
italic: "RobotoMono-RegularItalic.ttf",
|
|
13859
|
+
boldItalic: "RobotoMono-BoldItalic.ttf",
|
|
13860
|
+
lightItalic: "RobotoMono-LightItalic.ttf",
|
|
13861
|
+
mediumItalic: "RobotoMono-MediumItalic.ttf",
|
|
13862
|
+
semiboldItalic: "RobotoMono-SemiBoldItalic.ttf"
|
|
13863
|
+
},
|
|
13864
|
+
"Fira Code": {
|
|
13865
|
+
regular: "FiraCode-Regular.ttf",
|
|
13866
|
+
bold: "FiraCode-Bold.ttf",
|
|
13867
|
+
light: "FiraCode-Light.ttf",
|
|
13868
|
+
medium: "FiraCode-Medium.ttf",
|
|
13869
|
+
semibold: "FiraCode-SemiBold.ttf"
|
|
13870
|
+
},
|
|
13871
|
+
"JetBrains Mono": {
|
|
13872
|
+
regular: "JetBrainsMono-Regular.ttf",
|
|
13873
|
+
bold: "JetBrainsMono-Bold.ttf",
|
|
13874
|
+
light: "JetBrainsMono-Light.ttf",
|
|
13875
|
+
medium: "JetBrainsMono-Medium.ttf",
|
|
13876
|
+
semibold: "JetBrainsMono-SemiBold.ttf",
|
|
13877
|
+
italic: "JetBrainsMono-RegularItalic.ttf",
|
|
13878
|
+
boldItalic: "JetBrainsMono-BoldItalic.ttf",
|
|
13879
|
+
lightItalic: "JetBrainsMono-LightItalic.ttf",
|
|
13880
|
+
mediumItalic: "JetBrainsMono-MediumItalic.ttf",
|
|
13881
|
+
semiboldItalic: "JetBrainsMono-SemiBoldItalic.ttf"
|
|
13882
|
+
},
|
|
13883
|
+
"Source Code Pro": {
|
|
13884
|
+
regular: "SourceCodePro-Regular.ttf",
|
|
13885
|
+
bold: "SourceCodePro-Bold.ttf",
|
|
13886
|
+
light: "SourceCodePro-Light.ttf",
|
|
13887
|
+
medium: "SourceCodePro-Medium.ttf",
|
|
13888
|
+
semibold: "SourceCodePro-SemiBold.ttf",
|
|
13889
|
+
italic: "SourceCodePro-RegularItalic.ttf",
|
|
13890
|
+
boldItalic: "SourceCodePro-BoldItalic.ttf",
|
|
13891
|
+
lightItalic: "SourceCodePro-LightItalic.ttf",
|
|
13892
|
+
mediumItalic: "SourceCodePro-MediumItalic.ttf",
|
|
13893
|
+
semiboldItalic: "SourceCodePro-SemiBoldItalic.ttf"
|
|
13894
|
+
},
|
|
13895
|
+
"IBM Plex Mono": {
|
|
13896
|
+
regular: "IBMPlexMono-Regular.ttf",
|
|
13897
|
+
bold: "IBMPlexMono-Bold.ttf"
|
|
13898
|
+
},
|
|
13899
|
+
"Space Mono": {
|
|
13900
|
+
regular: "SpaceMono-Regular.ttf",
|
|
13901
|
+
bold: "SpaceMono-Bold.ttf",
|
|
13902
|
+
italic: "SpaceMono-Italic.ttf",
|
|
13903
|
+
boldItalic: "SpaceMono-BoldItalic.ttf"
|
|
13904
|
+
},
|
|
13905
|
+
"Sacramento": { regular: "Sacramento-Regular.ttf" },
|
|
13906
|
+
"Alex Brush": { regular: "AlexBrush-Regular.ttf" },
|
|
13907
|
+
"Allura": { regular: "Allura-Regular.ttf" },
|
|
13908
|
+
"Caveat": {
|
|
13909
|
+
regular: "Caveat-Regular.ttf",
|
|
13910
|
+
bold: "Caveat-Bold.ttf",
|
|
13911
|
+
medium: "Caveat-Medium.ttf",
|
|
13912
|
+
semibold: "Caveat-SemiBold.ttf"
|
|
13913
|
+
},
|
|
13914
|
+
"Lobster": { regular: "Lobster-Regular.ttf" },
|
|
13915
|
+
"Comfortaa": {
|
|
13916
|
+
regular: "Comfortaa-Regular.ttf",
|
|
13917
|
+
bold: "Comfortaa-Bold.ttf",
|
|
13918
|
+
light: "Comfortaa-Light.ttf",
|
|
13919
|
+
medium: "Comfortaa-Medium.ttf",
|
|
13920
|
+
semibold: "Comfortaa-SemiBold.ttf"
|
|
13921
|
+
},
|
|
13922
|
+
"Anton": { regular: "Anton-Regular.ttf" },
|
|
13923
|
+
"Teko": {
|
|
13924
|
+
regular: "Teko-Regular.ttf",
|
|
13925
|
+
bold: "Teko-Bold.ttf",
|
|
13926
|
+
light: "Teko-Light.ttf",
|
|
13927
|
+
medium: "Teko-Medium.ttf",
|
|
13928
|
+
semibold: "Teko-SemiBold.ttf"
|
|
13929
|
+
},
|
|
13930
|
+
"Noto Sans Devanagari": {
|
|
13931
|
+
regular: "NotoSansDevanagari-Regular.ttf",
|
|
13932
|
+
bold: "NotoSansDevanagari-Bold.ttf",
|
|
13933
|
+
light: "NotoSansDevanagari-Light.ttf",
|
|
13934
|
+
medium: "NotoSansDevanagari-Medium.ttf",
|
|
13935
|
+
semibold: "NotoSansDevanagari-SemiBold.ttf"
|
|
13936
|
+
},
|
|
13937
|
+
"Hind": {
|
|
13938
|
+
regular: "Hind-Regular.ttf",
|
|
13939
|
+
bold: "Hind-Bold.ttf",
|
|
13940
|
+
light: "Hind-Light.ttf",
|
|
13941
|
+
medium: "Hind-Medium.ttf",
|
|
13942
|
+
semibold: "Hind-SemiBold.ttf"
|
|
13943
|
+
},
|
|
13944
|
+
"Cinzel": { regular: "Cinzel-Regular.ttf", bold: "Cinzel-Bold.ttf" },
|
|
13945
|
+
"Cormorant Garamond": {
|
|
13946
|
+
regular: "CormorantGaramond-Regular.ttf",
|
|
13947
|
+
bold: "CormorantGaramond-Bold.ttf",
|
|
13948
|
+
light: "CormorantGaramond-Light.ttf",
|
|
13949
|
+
medium: "CormorantGaramond-Medium.ttf",
|
|
13950
|
+
semibold: "CormorantGaramond-SemiBold.ttf",
|
|
13951
|
+
italic: "CormorantGaramond-Italic.ttf",
|
|
13952
|
+
boldItalic: "CormorantGaramond-BoldItalic.ttf"
|
|
13913
13953
|
}
|
|
13914
|
-
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
);
|
|
13936
|
-
canvasGradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, radius);
|
|
13937
|
-
} else if ((gradient == null ? void 0 : gradient.type) === "conic" && typeof ctx.createConicGradient === "function") {
|
|
13938
|
-
const cx = Number.isFinite(gradient == null ? void 0 : gradient.cx) ? gradient.cx : 0.5;
|
|
13939
|
-
const cy = Number.isFinite(gradient == null ? void 0 : gradient.cy) ? gradient.cy : 0.5;
|
|
13940
|
-
const startAngle = (((gradient == null ? void 0 : gradient.angle) ?? 0) - 90) * Math.PI / 180;
|
|
13941
|
-
canvasGradient = ctx.createConicGradient(startAngle, width * cx, height * cy);
|
|
13942
|
-
} else {
|
|
13943
|
-
const angleDeg = (gradient == null ? void 0 : gradient.angle) ?? 90;
|
|
13944
|
-
const angleRad = angleDeg * Math.PI / 180;
|
|
13945
|
-
const sinA = Math.sin(angleRad);
|
|
13946
|
-
const cosA = Math.cos(angleRad);
|
|
13947
|
-
const midX = width / 2;
|
|
13948
|
-
const midY = height / 2;
|
|
13949
|
-
const corners = [
|
|
13950
|
-
[0, 0],
|
|
13951
|
-
[width, 0],
|
|
13952
|
-
[width, height],
|
|
13953
|
-
[0, height]
|
|
13954
|
-
];
|
|
13955
|
-
const projections = corners.map(([x, y]) => x * sinA - y * cosA);
|
|
13956
|
-
const minProjection = Math.min(...projections);
|
|
13957
|
-
const maxProjection = Math.max(...projections);
|
|
13958
|
-
canvasGradient = ctx.createLinearGradient(
|
|
13959
|
-
midX + minProjection * sinA,
|
|
13960
|
-
midY - minProjection * cosA,
|
|
13961
|
-
midX + maxProjection * sinA,
|
|
13962
|
-
midY - maxProjection * cosA
|
|
13963
|
-
);
|
|
13964
|
-
}
|
|
13965
|
-
if (!canvasGradient) return;
|
|
13966
|
-
stops.forEach((stop) => canvasGradient.addColorStop(stop.offset, stop.color));
|
|
13967
|
-
ctx.fillStyle = canvasGradient;
|
|
13968
|
-
ctx.fillRect(0, 0, width, height);
|
|
13969
|
-
} catch {
|
|
13970
|
-
}
|
|
13954
|
+
};
|
|
13955
|
+
const WEIGHT_TO_KEYS = {
|
|
13956
|
+
300: ["light", "regular"],
|
|
13957
|
+
400: ["regular"],
|
|
13958
|
+
500: ["medium", "regular"],
|
|
13959
|
+
600: ["semibold", "bold", "regular"],
|
|
13960
|
+
700: ["bold", "regular"]
|
|
13961
|
+
};
|
|
13962
|
+
const WEIGHT_TO_ITALIC_KEYS = {
|
|
13963
|
+
300: ["lightItalic", "italic", "light", "regular"],
|
|
13964
|
+
400: ["italic", "regular"],
|
|
13965
|
+
500: ["mediumItalic", "italic", "medium", "regular"],
|
|
13966
|
+
600: ["semiboldItalic", "boldItalic", "italic", "semibold", "bold", "regular"],
|
|
13967
|
+
700: ["boldItalic", "italic", "bold", "regular"]
|
|
13968
|
+
};
|
|
13969
|
+
function getFontPathForWeight(files, weight, isItalic = false) {
|
|
13970
|
+
const keys = isItalic ? WEIGHT_TO_ITALIC_KEYS[weight] : WEIGHT_TO_KEYS[weight];
|
|
13971
|
+
if (!keys) return files.regular;
|
|
13972
|
+
for (const k of keys) {
|
|
13973
|
+
const path = files[k];
|
|
13974
|
+
if (path) return path;
|
|
13971
13975
|
}
|
|
13972
|
-
|
|
13973
|
-
|
|
13974
|
-
|
|
13975
|
-
|
|
13976
|
-
|
|
13977
|
-
|
|
13978
|
-
|
|
13979
|
-
|
|
13980
|
-
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
13984
|
-
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
|
|
13994
|
-
|
|
13995
|
-
|
|
13996
|
-
|
|
13997
|
-
|
|
13998
|
-
|
|
13999
|
-
|
|
14000
|
-
|
|
14001
|
-
|
|
14002
|
-
|
|
14003
|
-
|
|
14004
|
-
|
|
14005
|
-
|
|
14006
|
-
|
|
14007
|
-
const remountWithFreshKey = async () => {
|
|
14008
|
-
mountKey += 1;
|
|
14009
|
-
try {
|
|
14010
|
-
clearMeasurementCache();
|
|
14011
|
-
} catch {
|
|
14012
|
-
}
|
|
14013
|
-
try {
|
|
14014
|
-
clearFabricCharCache();
|
|
14015
|
-
} catch {
|
|
14016
|
-
}
|
|
14017
|
-
try {
|
|
14018
|
-
root.unmount();
|
|
14019
|
-
} catch {
|
|
14020
|
-
}
|
|
14021
|
-
root = createRoot(container);
|
|
14022
|
-
await new Promise((settle) => {
|
|
14023
|
-
const onReadyOnce = () => {
|
|
14024
|
-
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
14025
|
-
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
14026
|
-
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
14027
|
-
await this.waitForCanvasImages(container, expectedImageCount);
|
|
14028
|
-
await this.waitForStableTextMetrics(container, config);
|
|
14029
|
-
await this.waitForCanvasScene(container, config, pageIndex);
|
|
14030
|
-
if (!fabricInstance) return settle();
|
|
14031
|
-
settle();
|
|
14032
|
-
}).catch(() => settle());
|
|
14033
|
-
};
|
|
14034
|
-
root.render(
|
|
14035
|
-
createElement(PreviewCanvas2, {
|
|
14036
|
-
key: `remount-${mountKey}`,
|
|
14037
|
-
config,
|
|
14038
|
-
pageIndex,
|
|
14039
|
-
zoom: pixelRatio,
|
|
14040
|
-
absoluteZoom: true,
|
|
14041
|
-
skipFontReadyWait: false,
|
|
14042
|
-
onReady: onReadyOnce
|
|
14043
|
-
})
|
|
14044
|
-
);
|
|
14045
|
-
});
|
|
14046
|
-
};
|
|
14047
|
-
const onReady = () => {
|
|
14048
|
-
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
14049
|
-
try {
|
|
14050
|
-
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
14051
|
-
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
14052
|
-
await this.waitForCanvasImages(container, expectedImageCount);
|
|
14053
|
-
await this.waitForStableTextMetrics(container, config);
|
|
14054
|
-
await this.waitForCanvasScene(container, config, pageIndex);
|
|
14055
|
-
firstMountSettled = true;
|
|
14056
|
-
if (hasAutoShrink && lateFontSettleDetected) {
|
|
14057
|
-
console.log("[canvas-renderer][parity] late font-settle detected — remounting for auto-shrink reflow");
|
|
14058
|
-
await remountWithFreshKey();
|
|
14059
|
-
}
|
|
14060
|
-
const fabricCanvas = container.querySelector("canvas.upper-canvas, canvas");
|
|
14061
|
-
const sourceCanvas = (fabricInstance == null ? void 0 : fabricInstance.lowerCanvasEl) || container.querySelector("canvas.lower-canvas") || fabricCanvas;
|
|
14062
|
-
const fabricInstanceAfter = this.getFabricCanvasFromContainer(container) || fabricInstance;
|
|
14063
|
-
const sourceCanvasAfter = (fabricInstanceAfter == null ? void 0 : fabricInstanceAfter.lowerCanvasEl) || container.querySelector("canvas.lower-canvas") || sourceCanvas;
|
|
14064
|
-
if (!sourceCanvas) {
|
|
14065
|
-
cleanup();
|
|
14066
|
-
reject(new Error("No canvas element found after render"));
|
|
14067
|
-
return;
|
|
14068
|
-
}
|
|
14069
|
-
const exportCanvas = document.createElement("canvas");
|
|
14070
|
-
exportCanvas.width = sourceCanvasAfter.width;
|
|
14071
|
-
exportCanvas.height = sourceCanvasAfter.height;
|
|
14072
|
-
const exportCtx = exportCanvas.getContext("2d");
|
|
14073
|
-
if (!exportCtx) {
|
|
14074
|
-
cleanup();
|
|
14075
|
-
reject(new Error("Failed to create export canvas"));
|
|
14076
|
-
return;
|
|
14077
|
-
}
|
|
14078
|
-
exportCtx.save();
|
|
14079
|
-
exportCtx.scale(sourceCanvasAfter.width / canvasWidth, sourceCanvasAfter.height / canvasHeight);
|
|
14080
|
-
this.paintPageBackground(exportCtx, config.pages[pageIndex], canvasWidth, canvasHeight);
|
|
14081
|
-
exportCtx.restore();
|
|
14082
|
-
exportCtx.drawImage(sourceCanvasAfter, 0, 0);
|
|
14083
|
-
const mimeType = format === "jpeg" ? "image/jpeg" : format === "webp" ? "image/webp" : "image/png";
|
|
14084
|
-
const dataUrl = exportCanvas.toDataURL(mimeType, quality);
|
|
14085
|
-
cleanup();
|
|
14086
|
-
resolve(dataUrl);
|
|
14087
|
-
} catch (err) {
|
|
14088
|
-
cleanup();
|
|
14089
|
-
reject(err);
|
|
14090
|
-
}
|
|
14091
|
-
});
|
|
14092
|
-
};
|
|
14093
|
-
root = createRoot(container);
|
|
14094
|
-
root.render(
|
|
14095
|
-
createElement(PreviewCanvas2, {
|
|
14096
|
-
config,
|
|
14097
|
-
pageIndex,
|
|
14098
|
-
zoom: pixelRatio,
|
|
14099
|
-
absoluteZoom: true,
|
|
14100
|
-
skipFontReadyWait: false,
|
|
14101
|
-
onReady
|
|
14102
|
-
})
|
|
14103
|
-
);
|
|
14104
|
-
});
|
|
13976
|
+
return files.regular;
|
|
13977
|
+
}
|
|
13978
|
+
function isItalicPath(files, path) {
|
|
13979
|
+
return path === files.italic || path === files.boldItalic || path === files.lightItalic || path === files.mediumItalic || path === files.semiboldItalic;
|
|
13980
|
+
}
|
|
13981
|
+
function getJsPDFFontName(fontName) {
|
|
13982
|
+
return fontName.replace(/\s+/g, "");
|
|
13983
|
+
}
|
|
13984
|
+
function getEmbeddedJsPDFFontName(fontName, weight, isItalic = false) {
|
|
13985
|
+
const resolved = resolveFontWeight(weight);
|
|
13986
|
+
const label = FONT_WEIGHT_LABELS[resolved];
|
|
13987
|
+
const italicSuffix = isItalic ? "Italic" : "";
|
|
13988
|
+
return `${getJsPDFFontName(fontName)}-${label}${italicSuffix}`;
|
|
13989
|
+
}
|
|
13990
|
+
function isFontAvailable(fontName) {
|
|
13991
|
+
return fontName in FONT_FILES;
|
|
13992
|
+
}
|
|
13993
|
+
const ttfCache = /* @__PURE__ */ new Map();
|
|
13994
|
+
async function fetchTTFAsBase64(url) {
|
|
13995
|
+
const cached = ttfCache.get(url);
|
|
13996
|
+
if (cached) return cached;
|
|
13997
|
+
try {
|
|
13998
|
+
const res = await fetch(url);
|
|
13999
|
+
if (!res.ok) return null;
|
|
14000
|
+
const buf = await res.arrayBuffer();
|
|
14001
|
+
const bytes = new Uint8Array(buf);
|
|
14002
|
+
let binary = "";
|
|
14003
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
14004
|
+
binary += String.fromCharCode(bytes[i]);
|
|
14005
|
+
}
|
|
14006
|
+
const b64 = btoa(binary);
|
|
14007
|
+
ttfCache.set(url, b64);
|
|
14008
|
+
return b64;
|
|
14009
|
+
} catch {
|
|
14010
|
+
return null;
|
|
14105
14011
|
}
|
|
14106
|
-
|
|
14107
|
-
|
|
14108
|
-
|
|
14109
|
-
|
|
14110
|
-
|
|
14111
|
-
|
|
14112
|
-
|
|
14113
|
-
|
|
14114
|
-
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
|
|
14118
|
-
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
|
|
14126
|
-
|
|
14127
|
-
|
|
14128
|
-
|
|
14129
|
-
}
|
|
14130
|
-
|
|
14131
|
-
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14135
|
-
|
|
14136
|
-
|
|
14137
|
-
|
|
14138
|
-
|
|
14139
|
-
|
|
14140
|
-
|
|
14141
|
-
|
|
14142
|
-
|
|
14143
|
-
|
|
14144
|
-
|
|
14145
|
-
|
|
14146
|
-
|
|
14147
|
-
|
|
14148
|
-
|
|
14149
|
-
|
|
14150
|
-
|
|
14151
|
-
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
if (didPreviewParityRemount) return;
|
|
14157
|
-
didPreviewParityRemount = true;
|
|
14158
|
-
mountKey += 1;
|
|
14159
|
-
try {
|
|
14160
|
-
clearMeasurementCache();
|
|
14161
|
-
} catch {
|
|
14162
|
-
}
|
|
14163
|
-
try {
|
|
14164
|
-
clearFabricCharCache();
|
|
14165
|
-
} catch {
|
|
14166
|
-
}
|
|
14167
|
-
try {
|
|
14168
|
-
root == null ? void 0 : root.unmount();
|
|
14169
|
-
} catch {
|
|
14170
|
-
}
|
|
14171
|
-
await new Promise((settle) => {
|
|
14172
|
-
mountPreview(() => {
|
|
14173
|
-
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
14174
|
-
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
14175
|
-
await this.waitForCanvasImages(container, expectedImageCount);
|
|
14176
|
-
await this.waitForStableTextMetrics(container, config);
|
|
14177
|
-
await this.waitForCanvasScene(container, config, pageIndex);
|
|
14178
|
-
settle();
|
|
14179
|
-
}).catch(() => settle());
|
|
14180
|
-
});
|
|
14181
|
-
});
|
|
14182
|
-
};
|
|
14183
|
-
const onReady = () => {
|
|
14184
|
-
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
14185
|
-
var _a, _b;
|
|
14186
|
-
try {
|
|
14187
|
-
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
14188
|
-
await this.waitForCanvasImages(container, expectedImageCount);
|
|
14189
|
-
await this.waitForStableTextMetrics(container, config);
|
|
14190
|
-
await this.waitForCanvasScene(container, config, pageIndex);
|
|
14191
|
-
if (hasAutoShrink && !didPreviewParityRemount) {
|
|
14192
|
-
console.log("[canvas-renderer][svg-parity] remounting once to match PixldocsPreview auto-shrink stabilization");
|
|
14193
|
-
await remountForPreviewParity();
|
|
14194
|
-
}
|
|
14195
|
-
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
14196
|
-
if (!fabricInstance) {
|
|
14197
|
-
cleanup();
|
|
14198
|
-
reject(new Error("No Fabric canvas instance found for SVG capture"));
|
|
14199
|
-
return;
|
|
14012
|
+
}
|
|
14013
|
+
async function embedFont(pdf, fontName, weight, fontBaseUrl, isItalic = false) {
|
|
14014
|
+
const fontFiles = FONT_FILES[fontName];
|
|
14015
|
+
if (!fontFiles) return false;
|
|
14016
|
+
const baseUrl = fontBaseUrl.endsWith("/") ? fontBaseUrl : fontBaseUrl + "/";
|
|
14017
|
+
const resolvedWeight = resolveFontWeight(weight);
|
|
14018
|
+
const fontPath = getFontPathForWeight(fontFiles, resolvedWeight, isItalic);
|
|
14019
|
+
if (!fontPath) return false;
|
|
14020
|
+
const hasItalicFile = isItalic && isItalicPath(fontFiles, fontPath);
|
|
14021
|
+
const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, weight, hasItalicFile);
|
|
14022
|
+
const label = FONT_WEIGHT_LABELS[resolvedWeight];
|
|
14023
|
+
const italicSuffix = hasItalicFile ? "Italic" : "";
|
|
14024
|
+
const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;
|
|
14025
|
+
const url = baseUrl + fontPath;
|
|
14026
|
+
try {
|
|
14027
|
+
const b64 = await fetchTTFAsBase64(url);
|
|
14028
|
+
if (!b64) return false;
|
|
14029
|
+
pdf.addFileToVFS(fileName, b64);
|
|
14030
|
+
pdf.addFont(fileName, jsPdfFontName, "normal");
|
|
14031
|
+
if (fontName !== jsPdfFontName) {
|
|
14032
|
+
try {
|
|
14033
|
+
pdf.addFont(fileName, fontName, "normal");
|
|
14034
|
+
} catch {
|
|
14035
|
+
}
|
|
14036
|
+
}
|
|
14037
|
+
return true;
|
|
14038
|
+
} catch (e) {
|
|
14039
|
+
console.warn(`[pdf-fonts] Failed to embed ${fontName} w${weight}:`, e);
|
|
14040
|
+
return false;
|
|
14041
|
+
}
|
|
14042
|
+
}
|
|
14043
|
+
async function embedFontsForConfig(pdf, config, fontBaseUrl) {
|
|
14044
|
+
const fontKeys = /* @__PURE__ */ new Set();
|
|
14045
|
+
const SEP = "";
|
|
14046
|
+
const walkElements = (elements) => {
|
|
14047
|
+
for (const el of elements) {
|
|
14048
|
+
if (el.fontFamily) {
|
|
14049
|
+
const w = resolveFontWeight(el.fontWeight ?? 400);
|
|
14050
|
+
fontKeys.add(`${el.fontFamily}${SEP}${w}`);
|
|
14051
|
+
}
|
|
14052
|
+
if (el.styles && typeof el.styles === "object") {
|
|
14053
|
+
for (const lineKey of Object.keys(el.styles)) {
|
|
14054
|
+
const lineStyles = el.styles[lineKey];
|
|
14055
|
+
if (lineStyles && typeof lineStyles === "object") {
|
|
14056
|
+
for (const charKey of Object.keys(lineStyles)) {
|
|
14057
|
+
const s = lineStyles[charKey];
|
|
14058
|
+
if (s == null ? void 0 : s.fontFamily) {
|
|
14059
|
+
const w = resolveFontWeight(s.fontWeight ?? 400);
|
|
14060
|
+
fontKeys.add(`${s.fontFamily}${SEP}${w}`);
|
|
14061
|
+
}
|
|
14200
14062
|
}
|
|
14201
|
-
const prevVPT = fabricInstance.viewportTransform ? [...fabricInstance.viewportTransform] : void 0;
|
|
14202
|
-
const prevSvgVPT = fabricInstance.svgViewportTransformation;
|
|
14203
|
-
const prevRetina = fabricInstance.enableRetinaScaling;
|
|
14204
|
-
const prevWidth = fabricInstance.width;
|
|
14205
|
-
const prevHeight = fabricInstance.height;
|
|
14206
|
-
fabricInstance.viewportTransform = [1, 0, 0, 1, 0, 0];
|
|
14207
|
-
fabricInstance.svgViewportTransformation = false;
|
|
14208
|
-
fabricInstance.enableRetinaScaling = false;
|
|
14209
|
-
fabricInstance.setDimensions(
|
|
14210
|
-
{ width: canvasWidth, height: canvasHeight },
|
|
14211
|
-
{ cssOnly: false, backstoreOnly: false }
|
|
14212
|
-
);
|
|
14213
|
-
const rawSvgString = fabricInstance.toSVG();
|
|
14214
|
-
const svgString = this.normalizeSvgDimensions(
|
|
14215
|
-
rawSvgString,
|
|
14216
|
-
canvasWidth,
|
|
14217
|
-
canvasHeight
|
|
14218
|
-
);
|
|
14219
|
-
fabricInstance.enableRetinaScaling = prevRetina;
|
|
14220
|
-
fabricInstance.setDimensions(
|
|
14221
|
-
{ width: prevWidth, height: prevHeight },
|
|
14222
|
-
{ cssOnly: false, backstoreOnly: false }
|
|
14223
|
-
);
|
|
14224
|
-
if (prevVPT) fabricInstance.viewportTransform = prevVPT;
|
|
14225
|
-
fabricInstance.svgViewportTransformation = prevSvgVPT;
|
|
14226
|
-
const page = config.pages[pageIndex];
|
|
14227
|
-
const backgroundColor = ((_a = page == null ? void 0 : page.settings) == null ? void 0 : _a.backgroundColor) || "#ffffff";
|
|
14228
|
-
const backgroundGradient = (_b = page == null ? void 0 : page.settings) == null ? void 0 : _b.backgroundGradient;
|
|
14229
|
-
cleanup();
|
|
14230
|
-
resolve({
|
|
14231
|
-
svg: svgString,
|
|
14232
|
-
width: canvasWidth,
|
|
14233
|
-
height: canvasHeight,
|
|
14234
|
-
backgroundColor,
|
|
14235
|
-
backgroundGradient
|
|
14236
|
-
});
|
|
14237
|
-
} catch (err) {
|
|
14238
|
-
cleanup();
|
|
14239
|
-
reject(err);
|
|
14240
14063
|
}
|
|
14241
|
-
}
|
|
14242
|
-
}
|
|
14243
|
-
|
|
14244
|
-
|
|
14064
|
+
}
|
|
14065
|
+
}
|
|
14066
|
+
if (el.children) walkElements(el.children);
|
|
14067
|
+
if (el.objects) walkElements(el.objects);
|
|
14068
|
+
}
|
|
14069
|
+
};
|
|
14070
|
+
for (const page of (config == null ? void 0 : config.pages) || []) {
|
|
14071
|
+
if (page.children) walkElements(page.children);
|
|
14072
|
+
if (page.elements) walkElements(page.elements);
|
|
14245
14073
|
}
|
|
14246
|
-
|
|
14247
|
-
|
|
14248
|
-
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
|
|
14254
|
-
const
|
|
14255
|
-
const
|
|
14256
|
-
|
|
14257
|
-
|
|
14258
|
-
|
|
14259
|
-
|
|
14074
|
+
fontKeys.add(`${FONT_FALLBACK_SYMBOLS}${SEP}400`);
|
|
14075
|
+
for (const w of [300, 400, 500, 600, 700]) {
|
|
14076
|
+
fontKeys.add(`${FONT_FALLBACK_DEVANAGARI}${SEP}${w}`);
|
|
14077
|
+
}
|
|
14078
|
+
const embedded = /* @__PURE__ */ new Set();
|
|
14079
|
+
const tasks = [];
|
|
14080
|
+
for (const key of fontKeys) {
|
|
14081
|
+
const sep = key.indexOf(SEP);
|
|
14082
|
+
const fontName = key.slice(0, sep);
|
|
14083
|
+
const weight = parseInt(key.slice(sep + 1), 10);
|
|
14084
|
+
if (!isFontAvailable(fontName)) continue;
|
|
14085
|
+
tasks.push(
|
|
14086
|
+
embedFont(pdf, fontName, weight, fontBaseUrl).then((ok) => {
|
|
14087
|
+
if (ok) embedded.add(key);
|
|
14088
|
+
})
|
|
14260
14089
|
);
|
|
14261
|
-
|
|
14262
|
-
|
|
14263
|
-
|
|
14264
|
-
|
|
14265
|
-
|
|
14266
|
-
|
|
14267
|
-
|
|
14268
|
-
|
|
14269
|
-
|
|
14270
|
-
|
|
14271
|
-
|
|
14272
|
-
|
|
14273
|
-
if (
|
|
14274
|
-
|
|
14275
|
-
|
|
14276
|
-
|
|
14090
|
+
}
|
|
14091
|
+
await Promise.all(tasks);
|
|
14092
|
+
console.log(`[pdf-fonts] Embedded ${embedded.size} font variants from config`);
|
|
14093
|
+
return embedded;
|
|
14094
|
+
}
|
|
14095
|
+
function isDevanagari(char) {
|
|
14096
|
+
const c = char.codePointAt(0) ?? 0;
|
|
14097
|
+
return c >= 2304 && c <= 2431 || c >= 43232 && c <= 43263 || c >= 7376 && c <= 7423;
|
|
14098
|
+
}
|
|
14099
|
+
function containsDevanagari(text) {
|
|
14100
|
+
if (!text) return false;
|
|
14101
|
+
for (const char of text) {
|
|
14102
|
+
if (isDevanagari(char)) return true;
|
|
14103
|
+
}
|
|
14104
|
+
return false;
|
|
14105
|
+
}
|
|
14106
|
+
function isBasicLatinOrLatin1(char) {
|
|
14107
|
+
const c = char.codePointAt(0) ?? 0;
|
|
14108
|
+
return c <= 591;
|
|
14109
|
+
}
|
|
14110
|
+
function classifyChar(char) {
|
|
14111
|
+
if (isBasicLatinOrLatin1(char)) return "main";
|
|
14112
|
+
if (isDevanagari(char)) return "devanagari";
|
|
14113
|
+
return "symbol";
|
|
14114
|
+
}
|
|
14115
|
+
function splitIntoRuns(text) {
|
|
14116
|
+
if (!text) return [];
|
|
14117
|
+
const runs = [];
|
|
14118
|
+
let currentType = null;
|
|
14119
|
+
let currentText = "";
|
|
14120
|
+
for (const char of text) {
|
|
14121
|
+
const type = classifyChar(char);
|
|
14122
|
+
if (type !== currentType && currentText) {
|
|
14123
|
+
runs.push({ text: currentText, runType: currentType });
|
|
14124
|
+
currentText = "";
|
|
14277
14125
|
}
|
|
14278
|
-
|
|
14279
|
-
|
|
14280
|
-
|
|
14281
|
-
|
|
14282
|
-
|
|
14283
|
-
|
|
14126
|
+
currentType = type;
|
|
14127
|
+
currentText += char;
|
|
14128
|
+
}
|
|
14129
|
+
if (currentText && currentType) {
|
|
14130
|
+
runs.push({ text: currentText, runType: currentType });
|
|
14131
|
+
}
|
|
14132
|
+
return runs;
|
|
14133
|
+
}
|
|
14134
|
+
function rewriteSvgFontsForJsPDF(svgStr) {
|
|
14135
|
+
var _a, _b;
|
|
14136
|
+
const parser = new DOMParser();
|
|
14137
|
+
const doc = parser.parseFromString(svgStr, "image/svg+xml");
|
|
14138
|
+
const textEls = doc.querySelectorAll("text, tspan, textPath");
|
|
14139
|
+
const readStyleToken = (style, prop) => {
|
|
14140
|
+
var _a2;
|
|
14141
|
+
const match = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
|
|
14142
|
+
return ((_a2 = match == null ? void 0 : match[1]) == null ? void 0 : _a2.trim()) || null;
|
|
14143
|
+
};
|
|
14144
|
+
const resolveInheritedValue = (el, attr, styleProp = attr) => {
|
|
14145
|
+
var _a2;
|
|
14146
|
+
let current = el;
|
|
14147
|
+
while (current) {
|
|
14148
|
+
const attrVal = (_a2 = current.getAttribute(attr)) == null ? void 0 : _a2.trim();
|
|
14149
|
+
if (attrVal) return attrVal;
|
|
14150
|
+
const styleVal = readStyleToken(current.getAttribute("style") || "", styleProp);
|
|
14151
|
+
if (styleVal) return styleVal;
|
|
14152
|
+
current = current.parentElement;
|
|
14284
14153
|
}
|
|
14285
|
-
|
|
14286
|
-
|
|
14154
|
+
return null;
|
|
14155
|
+
};
|
|
14156
|
+
const resolveWeightNum = (weightRaw) => {
|
|
14157
|
+
const parsedWeight = Number.parseInt(weightRaw, 10);
|
|
14158
|
+
return Number.isFinite(parsedWeight) ? parsedWeight : /bold/i.test(weightRaw) ? 700 : /medium/i.test(weightRaw) ? 500 : /semi/i.test(weightRaw) ? 600 : /light/i.test(weightRaw) ? 300 : 400;
|
|
14159
|
+
};
|
|
14160
|
+
const buildStyleString = (existingStyle, fontName) => {
|
|
14161
|
+
const stylePairs = existingStyle.split(";").map((part) => part.trim()).filter(Boolean).filter((part) => !/^font-family\s*:/i.test(part) && !/^font-weight\s*:/i.test(part) && !/^font-style\s*:/i.test(part));
|
|
14162
|
+
stylePairs.push(`font-family: ${fontName}`);
|
|
14163
|
+
stylePairs.push(`font-weight: normal`);
|
|
14164
|
+
stylePairs.push(`font-style: normal`);
|
|
14165
|
+
return stylePairs.join("; ");
|
|
14166
|
+
};
|
|
14167
|
+
for (const el of textEls) {
|
|
14168
|
+
const inlineStyle = el.getAttribute("style") || "";
|
|
14169
|
+
const rawFf = resolveInheritedValue(el, "font-family");
|
|
14170
|
+
if (!rawFf) continue;
|
|
14171
|
+
const clean = (_a = rawFf.split(",")[0]) == null ? void 0 : _a.replace(/['"]/g, "").trim();
|
|
14172
|
+
if (!isFontAvailable(clean)) continue;
|
|
14173
|
+
const weightRaw = resolveInheritedValue(el, "font-weight") || "400";
|
|
14174
|
+
const styleRaw = resolveInheritedValue(el, "font-style") || "normal";
|
|
14175
|
+
const weight = resolveWeightNum(weightRaw);
|
|
14176
|
+
const resolved = resolveFontWeight(weight);
|
|
14177
|
+
const isItalic = /italic|oblique/i.test(styleRaw);
|
|
14178
|
+
const jsPdfName = getEmbeddedJsPDFFontName(clean, resolved, isItalic);
|
|
14179
|
+
el.setAttribute("data-source-font-family", clean);
|
|
14180
|
+
el.setAttribute("data-source-font-weight", String(resolved));
|
|
14181
|
+
el.setAttribute("data-source-font-style", isItalic ? "italic" : "normal");
|
|
14182
|
+
const directText = Array.from(el.childNodes).filter((n) => n.nodeType === 3).map((n) => n.textContent || "").join("");
|
|
14183
|
+
const hasDevanagari = containsDevanagari(directText);
|
|
14184
|
+
if (hasDevanagari && directText.length > 0) {
|
|
14185
|
+
const devanagariWeight = resolveFontWeight(weight);
|
|
14186
|
+
const devanagariJsPdfName = getEmbeddedJsPDFFontName(FONT_FALLBACK_DEVANAGARI, devanagariWeight);
|
|
14187
|
+
const symbolJsPdfName = isFontAvailable(FONT_FALLBACK_SYMBOLS) ? getEmbeddedJsPDFFontName(FONT_FALLBACK_SYMBOLS, 400) : jsPdfName;
|
|
14188
|
+
const childNodes = Array.from(el.childNodes);
|
|
14189
|
+
for (const node of childNodes) {
|
|
14190
|
+
if (node.nodeType !== 3 || !node.textContent) continue;
|
|
14191
|
+
const runs = splitIntoRuns(node.textContent);
|
|
14192
|
+
if (runs.length <= 1 && ((_b = runs[0]) == null ? void 0 : _b.runType) !== "devanagari") continue;
|
|
14193
|
+
const fragment = doc.createDocumentFragment();
|
|
14194
|
+
for (const run of runs) {
|
|
14195
|
+
const tspan = doc.createElementNS("http://www.w3.org/2000/svg", "tspan");
|
|
14196
|
+
let runFont;
|
|
14197
|
+
if (run.runType === "devanagari") {
|
|
14198
|
+
runFont = devanagariJsPdfName;
|
|
14199
|
+
} else if (run.runType === "symbol") {
|
|
14200
|
+
runFont = symbolJsPdfName;
|
|
14201
|
+
} else {
|
|
14202
|
+
runFont = jsPdfName;
|
|
14203
|
+
}
|
|
14204
|
+
tspan.setAttribute("font-family", runFont);
|
|
14205
|
+
tspan.setAttribute("font-weight", "normal");
|
|
14206
|
+
tspan.setAttribute("font-style", "normal");
|
|
14207
|
+
tspan.textContent = run.text;
|
|
14208
|
+
fragment.appendChild(tspan);
|
|
14209
|
+
}
|
|
14210
|
+
el.replaceChild(fragment, node);
|
|
14211
|
+
}
|
|
14212
|
+
el.setAttribute("font-family", jsPdfName);
|
|
14213
|
+
el.setAttribute("font-weight", "normal");
|
|
14214
|
+
el.setAttribute("font-style", "normal");
|
|
14215
|
+
el.setAttribute("style", buildStyleString(inlineStyle, jsPdfName));
|
|
14287
14216
|
} else {
|
|
14288
|
-
|
|
14289
|
-
|
|
14290
|
-
|
|
14291
|
-
|
|
14292
|
-
normalized = normalized.replace(/<svg\b/i, '<svg preserveAspectRatio="none"');
|
|
14217
|
+
el.setAttribute("font-family", jsPdfName);
|
|
14218
|
+
el.setAttribute("font-weight", "normal");
|
|
14219
|
+
el.setAttribute("font-style", "normal");
|
|
14220
|
+
el.setAttribute("style", buildStyleString(inlineStyle, jsPdfName));
|
|
14293
14221
|
}
|
|
14294
|
-
return normalized;
|
|
14295
14222
|
}
|
|
14296
|
-
|
|
14297
|
-
|
|
14298
|
-
|
|
14299
|
-
|
|
14300
|
-
|
|
14301
|
-
|
|
14302
|
-
|
|
14303
|
-
|
|
14304
|
-
|
|
14305
|
-
|
|
14306
|
-
|
|
14307
|
-
if (el && container.contains(el)) return canvas;
|
|
14223
|
+
return new XMLSerializer().serializeToString(doc.documentElement);
|
|
14224
|
+
}
|
|
14225
|
+
function extractFontFamiliesFromSvgs(svgs) {
|
|
14226
|
+
const families = /* @__PURE__ */ new Set();
|
|
14227
|
+
const regex = /font-family[=:]\s*["']?([^"';},]+)/gi;
|
|
14228
|
+
for (const svg of svgs) {
|
|
14229
|
+
let m;
|
|
14230
|
+
while ((m = regex.exec(svg)) !== null) {
|
|
14231
|
+
const raw = m[1].trim().split(",")[0].trim().replace(/^['"]|['"]$/g, "");
|
|
14232
|
+
if (raw && raw !== "serif" && raw !== "sans-serif" && raw !== "monospace") {
|
|
14233
|
+
families.add(raw);
|
|
14308
14234
|
}
|
|
14309
14235
|
}
|
|
14310
|
-
return null;
|
|
14311
14236
|
}
|
|
14312
|
-
|
|
14313
|
-
|
|
14314
|
-
|
|
14315
|
-
|
|
14316
|
-
|
|
14237
|
+
return families;
|
|
14238
|
+
}
|
|
14239
|
+
async function embedFontsInPdf(pdf, fontFamilies, fontBaseUrl) {
|
|
14240
|
+
const embedded = /* @__PURE__ */ new Set();
|
|
14241
|
+
const weights = [300, 400, 500, 600, 700];
|
|
14242
|
+
const tasks = [];
|
|
14243
|
+
for (const family of fontFamilies) {
|
|
14244
|
+
if (!isFontAvailable(family)) {
|
|
14245
|
+
console.warn(`[pdf-fonts] No TTF mapping for "${family}" — will use Helvetica fallback`);
|
|
14246
|
+
continue;
|
|
14317
14247
|
}
|
|
14318
|
-
const
|
|
14319
|
-
|
|
14320
|
-
|
|
14321
|
-
|
|
14322
|
-
|
|
14323
|
-
|
|
14324
|
-
|
|
14325
|
-
|
|
14326
|
-
|
|
14327
|
-
|
|
14328
|
-
|
|
14329
|
-
|
|
14330
|
-
|
|
14331
|
-
|
|
14332
|
-
|
|
14333
|
-
|
|
14334
|
-
|
|
14335
|
-
|
|
14336
|
-
|
|
14337
|
-
|
|
14338
|
-
|
|
14248
|
+
for (const w of weights) {
|
|
14249
|
+
tasks.push(
|
|
14250
|
+
embedFont(pdf, family, w, fontBaseUrl).then((ok) => {
|
|
14251
|
+
if (ok) embedded.add(`${family}${w}`);
|
|
14252
|
+
})
|
|
14253
|
+
);
|
|
14254
|
+
}
|
|
14255
|
+
}
|
|
14256
|
+
await Promise.all(tasks);
|
|
14257
|
+
console.log(`[pdf-fonts] Embedded ${embedded.size} font variants for ${fontFamilies.size} families`);
|
|
14258
|
+
return embedded;
|
|
14259
|
+
}
|
|
14260
|
+
const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
14261
|
+
__proto__: null,
|
|
14262
|
+
FONT_FALLBACK_DEVANAGARI,
|
|
14263
|
+
FONT_FALLBACK_SYMBOLS,
|
|
14264
|
+
FONT_FILES,
|
|
14265
|
+
FONT_WEIGHT_LABELS,
|
|
14266
|
+
embedFont,
|
|
14267
|
+
embedFontsForConfig,
|
|
14268
|
+
embedFontsInPdf,
|
|
14269
|
+
extractFontFamiliesFromSvgs,
|
|
14270
|
+
getEmbeddedJsPDFFontName,
|
|
14271
|
+
getFontPathForWeight,
|
|
14272
|
+
isFontAvailable,
|
|
14273
|
+
resolveFontWeight,
|
|
14274
|
+
rewriteSvgFontsForJsPDF
|
|
14275
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
14276
|
+
function dumpSvgTextDiagnostics(svgStr, pageIndex, tag, stage, maxItems = 30) {
|
|
14277
|
+
try {
|
|
14278
|
+
if (typeof DOMParser === "undefined") return;
|
|
14279
|
+
const doc = new DOMParser().parseFromString(svgStr, "image/svg+xml");
|
|
14280
|
+
if (doc.querySelector("parsererror")) {
|
|
14281
|
+
console.warn(`${tag} page=${pageIndex} stage=${stage} parse-error`);
|
|
14282
|
+
return;
|
|
14283
|
+
}
|
|
14284
|
+
const root = doc.documentElement;
|
|
14285
|
+
const svgWidth = root == null ? void 0 : root.getAttribute("width");
|
|
14286
|
+
const svgHeight = root == null ? void 0 : root.getAttribute("height");
|
|
14287
|
+
const svgViewBox = root == null ? void 0 : root.getAttribute("viewBox");
|
|
14288
|
+
const texts = Array.from(doc.querySelectorAll("text"));
|
|
14289
|
+
const summary = {
|
|
14290
|
+
page: pageIndex,
|
|
14291
|
+
stage,
|
|
14292
|
+
svgLen: svgStr.length,
|
|
14293
|
+
svgWidth,
|
|
14294
|
+
svgHeight,
|
|
14295
|
+
svgViewBox,
|
|
14296
|
+
textCount: texts.length
|
|
14339
14297
|
};
|
|
14340
|
-
|
|
14341
|
-
|
|
14342
|
-
|
|
14343
|
-
|
|
14344
|
-
|
|
14345
|
-
|
|
14298
|
+
console.log(`${tag} ${stage} page=${pageIndex} summary`, summary);
|
|
14299
|
+
const sample = texts.slice(0, maxItems).map((t, idx) => {
|
|
14300
|
+
var _a, _b;
|
|
14301
|
+
const tspans = Array.from(t.querySelectorAll("tspan"));
|
|
14302
|
+
const tspanInfo = tspans.slice(0, 4).map((s) => ({
|
|
14303
|
+
x: s.getAttribute("x"),
|
|
14304
|
+
y: s.getAttribute("y"),
|
|
14305
|
+
text: (s.textContent || "").slice(0, 40)
|
|
14306
|
+
}));
|
|
14307
|
+
let containerWidth = null;
|
|
14308
|
+
let cursor = t.parentElement;
|
|
14309
|
+
while (cursor && !containerWidth) {
|
|
14310
|
+
containerWidth = (_a = cursor.getAttribute) == null ? void 0 : _a.call(cursor, "width");
|
|
14311
|
+
cursor = cursor.parentElement;
|
|
14312
|
+
if (cursor && ((_b = cursor.tagName) == null ? void 0 : _b.toLowerCase()) === "svg") break;
|
|
14313
|
+
}
|
|
14314
|
+
return {
|
|
14315
|
+
idx,
|
|
14316
|
+
x: t.getAttribute("x"),
|
|
14317
|
+
y: t.getAttribute("y"),
|
|
14318
|
+
fontSize: t.getAttribute("font-size"),
|
|
14319
|
+
fontFamily: t.getAttribute("font-family"),
|
|
14320
|
+
fontWeight: t.getAttribute("font-weight"),
|
|
14321
|
+
textAnchor: t.getAttribute("text-anchor"),
|
|
14322
|
+
transform: t.getAttribute("transform"),
|
|
14323
|
+
style: (t.getAttribute("style") || "").slice(0, 120),
|
|
14324
|
+
ancestorWidth: containerWidth,
|
|
14325
|
+
textContent: (t.textContent || "").slice(0, 60),
|
|
14326
|
+
tspanCount: tspans.length,
|
|
14327
|
+
tspanSample: tspanInfo
|
|
14328
|
+
};
|
|
14329
|
+
});
|
|
14330
|
+
console.log(`${tag} ${stage} page=${pageIndex} text-sample (first ${sample.length}/${texts.length})`, sample);
|
|
14331
|
+
} catch (err) {
|
|
14332
|
+
console.warn(`${tag} ${stage} page=${pageIndex} dump threw`, err);
|
|
14346
14333
|
}
|
|
14347
14334
|
}
|
|
14348
14335
|
const SVG_DRAWABLE_TAGS = /* @__PURE__ */ new Set([
|
|
@@ -15640,6 +15627,15 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
15640
15627
|
const { title, stripPageBackground } = options;
|
|
15641
15628
|
const firstPage = svgResults[0];
|
|
15642
15629
|
const orientation = firstPage.width > firstPage.height ? "landscape" : "portrait";
|
|
15630
|
+
const PARITY_TAG = "[canvas-renderer][parity-diag][pkg-pdf]";
|
|
15631
|
+
console.log(`${PARITY_TAG} pkg-version=0.5.71 pages=${svgResults.length}`);
|
|
15632
|
+
try {
|
|
15633
|
+
for (let pi = 0; pi < svgResults.length; pi++) {
|
|
15634
|
+
dumpSvgTextDiagnostics(svgResults[pi].svg, pi, PARITY_TAG, "STAGE-1-raw-toSVG");
|
|
15635
|
+
}
|
|
15636
|
+
} catch (e) {
|
|
15637
|
+
console.warn(`${PARITY_TAG} dump failed`, e);
|
|
15638
|
+
}
|
|
15643
15639
|
const pdf = new jsPDF({
|
|
15644
15640
|
orientation,
|
|
15645
15641
|
unit: "px",
|
|
@@ -15669,6 +15665,15 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
15669
15665
|
stripPageBackground: shouldStripBg
|
|
15670
15666
|
});
|
|
15671
15667
|
if (processedSvg) {
|
|
15668
|
+
try {
|
|
15669
|
+
dumpSvgTextDiagnostics(
|
|
15670
|
+
new XMLSerializer().serializeToString(processedSvg),
|
|
15671
|
+
i,
|
|
15672
|
+
PARITY_TAG,
|
|
15673
|
+
"STAGE-2-after-prepareLiveCanvasSvgForPdf"
|
|
15674
|
+
);
|
|
15675
|
+
} catch {
|
|
15676
|
+
}
|
|
15672
15677
|
await convertTextDecorationsToLines(processedSvg);
|
|
15673
15678
|
if (shouldOutlineText) {
|
|
15674
15679
|
try {
|
|
@@ -15690,6 +15695,15 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
15690
15695
|
const reParser = new DOMParser();
|
|
15691
15696
|
const reDoc = reParser.parseFromString(rewrittenSvg, "image/svg+xml");
|
|
15692
15697
|
processedSvg = reDoc.documentElement;
|
|
15698
|
+
try {
|
|
15699
|
+
dumpSvgTextDiagnostics(
|
|
15700
|
+
rewrittenSvg,
|
|
15701
|
+
i,
|
|
15702
|
+
PARITY_TAG,
|
|
15703
|
+
"STAGE-3-after-rewriteSvgFontsForJsPDF"
|
|
15704
|
+
);
|
|
15705
|
+
} catch {
|
|
15706
|
+
}
|
|
15693
15707
|
}
|
|
15694
15708
|
if (processedSvg) {
|
|
15695
15709
|
pdf.setFillColor(0, 0, 0);
|
|
@@ -15713,7 +15727,8 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
15713
15727
|
}
|
|
15714
15728
|
const pdfExport = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
15715
15729
|
__proto__: null,
|
|
15716
|
-
assemblePdfFromSvgs
|
|
15730
|
+
assemblePdfFromSvgs,
|
|
15731
|
+
dumpSvgTextDiagnostics
|
|
15717
15732
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
15718
15733
|
function collectImageUrls(config) {
|
|
15719
15734
|
const urls = [];
|
|
@@ -15817,6 +15832,7 @@ export {
|
|
|
15817
15832
|
collectFontsFromConfig,
|
|
15818
15833
|
collectImageUrls,
|
|
15819
15834
|
configHasAutoShrinkText$1 as configHasAutoShrinkText,
|
|
15835
|
+
dumpSvgTextDiagnostics,
|
|
15820
15836
|
embedFont,
|
|
15821
15837
|
embedFontsForConfig,
|
|
15822
15838
|
embedFontsInPdf,
|