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