@pixldocs/canvas-renderer 0.3.28 → 0.4.1
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/README.md +35 -0
- package/dist/index.cjs +1880 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +125 -1
- package/dist/index.js +1880 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -7,6 +7,8 @@ import { flushSync } from "react-dom";
|
|
|
7
7
|
import { create } from "zustand";
|
|
8
8
|
import * as fabric from "fabric";
|
|
9
9
|
import { createRoot } from "react-dom/client";
|
|
10
|
+
import { jsPDF, ShadingPattern } from "jspdf";
|
|
11
|
+
import { svg2pdf } from "svg2pdf.js";
|
|
10
12
|
let API_URL = "";
|
|
11
13
|
function setPackageApiUrl(imageProxyUrl) {
|
|
12
14
|
if (!imageProxyUrl) {
|
|
@@ -10747,8 +10749,38 @@ class PixldocsRenderer {
|
|
|
10747
10749
|
return this.renderAllPageSvgs(configToRender);
|
|
10748
10750
|
}
|
|
10749
10751
|
/**
|
|
10750
|
-
*
|
|
10752
|
+
* Render a pre-resolved template config to a vector PDF.
|
|
10753
|
+
* Returns a Blob and ArrayBuffer.
|
|
10751
10754
|
*/
|
|
10755
|
+
async renderPdf(templateConfig, options) {
|
|
10756
|
+
const svgs = await this.renderAllPageSvgs(templateConfig);
|
|
10757
|
+
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|
|
10758
|
+
return assemblePdfFromSvgs2(svgs, { title: options == null ? void 0 : options.title, fontBaseUrl: options == null ? void 0 : options.fontBaseUrl });
|
|
10759
|
+
}
|
|
10760
|
+
/**
|
|
10761
|
+
* Resolve from V2 sectionState and render a vector PDF.
|
|
10762
|
+
* This is the primary PDF export API — mirrors renderFromForm() but returns a PDF.
|
|
10763
|
+
*/
|
|
10764
|
+
async renderPdfFromForm(options) {
|
|
10765
|
+
const { templateId, formSchemaId, sectionState, themeId, watermark, title, fontBaseUrl } = options;
|
|
10766
|
+
const resolved = await resolveFromForm({
|
|
10767
|
+
templateId,
|
|
10768
|
+
formSchemaId,
|
|
10769
|
+
sectionState,
|
|
10770
|
+
themeId,
|
|
10771
|
+
supabaseUrl: this.config.supabaseUrl,
|
|
10772
|
+
supabaseAnonKey: this.config.supabaseAnonKey
|
|
10773
|
+
});
|
|
10774
|
+
const shouldWatermark = watermark ?? resolved.price > 0;
|
|
10775
|
+
let configToRender = resolved.config;
|
|
10776
|
+
if (shouldWatermark) {
|
|
10777
|
+
const { injectWatermark } = await import("./canvasWatermark-CM85x4k7.js");
|
|
10778
|
+
configToRender = injectWatermark(configToRender);
|
|
10779
|
+
}
|
|
10780
|
+
const svgs = await this.renderAllPageSvgs(configToRender);
|
|
10781
|
+
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|
|
10782
|
+
return assemblePdfFromSvgs2(svgs, { title: title ?? resolved.config.name, fontBaseUrl });
|
|
10783
|
+
}
|
|
10752
10784
|
async renderById(templateId, formData, options) {
|
|
10753
10785
|
const resolved = await resolveTemplateData({
|
|
10754
10786
|
templateId,
|
|
@@ -11201,6 +11233,1841 @@ class PixldocsRenderer {
|
|
|
11201
11233
|
return null;
|
|
11202
11234
|
}
|
|
11203
11235
|
}
|
|
11236
|
+
const FONT_WEIGHT_LABELS = {
|
|
11237
|
+
300: "Light",
|
|
11238
|
+
400: "Regular",
|
|
11239
|
+
500: "Medium",
|
|
11240
|
+
600: "SemiBold",
|
|
11241
|
+
700: "Bold"
|
|
11242
|
+
};
|
|
11243
|
+
function resolveFontWeight(weight) {
|
|
11244
|
+
if (weight <= 350) return 300;
|
|
11245
|
+
if (weight <= 450) return 400;
|
|
11246
|
+
if (weight <= 550) return 500;
|
|
11247
|
+
if (weight <= 650) return 600;
|
|
11248
|
+
return 700;
|
|
11249
|
+
}
|
|
11250
|
+
const FONT_FALLBACK_SYMBOLS = "Noto Sans";
|
|
11251
|
+
const FONT_FALLBACK_DEVANAGARI = "Hind";
|
|
11252
|
+
const FONT_FILES = {
|
|
11253
|
+
"Playfair Display": {
|
|
11254
|
+
regular: "PlayfairDisplay-Regular.ttf",
|
|
11255
|
+
bold: "PlayfairDisplay-Bold.ttf",
|
|
11256
|
+
italic: "PlayfairDisplay-Italic.ttf",
|
|
11257
|
+
boldItalic: "PlayfairDisplay-BoldItalic.ttf"
|
|
11258
|
+
},
|
|
11259
|
+
"Merriweather": {
|
|
11260
|
+
regular: "Merriweather-Regular.ttf",
|
|
11261
|
+
bold: "Merriweather-Bold.ttf",
|
|
11262
|
+
light: "Merriweather-Light.ttf",
|
|
11263
|
+
italic: "Merriweather-Italic.ttf",
|
|
11264
|
+
boldItalic: "Merriweather-BoldItalic.ttf",
|
|
11265
|
+
lightItalic: "Merriweather-LightItalic.ttf"
|
|
11266
|
+
},
|
|
11267
|
+
"Lora": {
|
|
11268
|
+
regular: "Lora-Regular.ttf",
|
|
11269
|
+
bold: "Lora-Bold.ttf",
|
|
11270
|
+
italic: "Lora-Italic.ttf",
|
|
11271
|
+
boldItalic: "Lora-BoldItalic.ttf"
|
|
11272
|
+
},
|
|
11273
|
+
"Montserrat": {
|
|
11274
|
+
regular: "Montserrat-Regular.ttf",
|
|
11275
|
+
bold: "Montserrat-Bold.ttf",
|
|
11276
|
+
light: "Montserrat-Light.ttf",
|
|
11277
|
+
medium: "Montserrat-Medium.ttf",
|
|
11278
|
+
semibold: "Montserrat-SemiBold.ttf",
|
|
11279
|
+
italic: "Montserrat-Italic.ttf",
|
|
11280
|
+
boldItalic: "Montserrat-BoldItalic.ttf",
|
|
11281
|
+
lightItalic: "Montserrat-LightItalic.ttf",
|
|
11282
|
+
mediumItalic: "Montserrat-MediumItalic.ttf",
|
|
11283
|
+
semiboldItalic: "Montserrat-SemiBoldItalic.ttf"
|
|
11284
|
+
},
|
|
11285
|
+
"Open Sans": {
|
|
11286
|
+
regular: "OpenSans-Regular.ttf",
|
|
11287
|
+
bold: "OpenSans-Bold.ttf",
|
|
11288
|
+
light: "OpenSans-Light.ttf",
|
|
11289
|
+
semibold: "OpenSans-SemiBold.ttf",
|
|
11290
|
+
italic: "OpenSans-Italic.ttf",
|
|
11291
|
+
boldItalic: "OpenSans-BoldItalic.ttf",
|
|
11292
|
+
lightItalic: "OpenSans-LightItalic.ttf",
|
|
11293
|
+
semiboldItalic: "OpenSans-SemiBoldItalic.ttf"
|
|
11294
|
+
},
|
|
11295
|
+
"Roboto": {
|
|
11296
|
+
regular: "Roboto-Regular.ttf",
|
|
11297
|
+
bold: "Roboto-Bold.ttf",
|
|
11298
|
+
light: "Roboto-Light.ttf",
|
|
11299
|
+
medium: "Roboto-Medium.ttf",
|
|
11300
|
+
italic: "Roboto-Italic.ttf",
|
|
11301
|
+
boldItalic: "Roboto-BoldItalic.ttf",
|
|
11302
|
+
lightItalic: "Roboto-LightItalic.ttf",
|
|
11303
|
+
mediumItalic: "Roboto-MediumItalic.ttf"
|
|
11304
|
+
},
|
|
11305
|
+
"Lato": {
|
|
11306
|
+
regular: "Lato-Regular.ttf",
|
|
11307
|
+
bold: "Lato-Bold.ttf",
|
|
11308
|
+
light: "Lato-Light.ttf",
|
|
11309
|
+
italic: "Lato-Italic.ttf",
|
|
11310
|
+
boldItalic: "Lato-BoldItalic.ttf",
|
|
11311
|
+
lightItalic: "Lato-LightItalic.ttf"
|
|
11312
|
+
},
|
|
11313
|
+
"Raleway": {
|
|
11314
|
+
regular: "Raleway-Regular.ttf",
|
|
11315
|
+
bold: "Raleway-Bold.ttf",
|
|
11316
|
+
light: "Raleway-Light.ttf",
|
|
11317
|
+
medium: "Raleway-Medium.ttf",
|
|
11318
|
+
semibold: "Raleway-SemiBold.ttf",
|
|
11319
|
+
italic: "Raleway-Italic.ttf",
|
|
11320
|
+
boldItalic: "Raleway-BoldItalic.ttf",
|
|
11321
|
+
lightItalic: "Raleway-LightItalic.ttf"
|
|
11322
|
+
},
|
|
11323
|
+
"Poppins": {
|
|
11324
|
+
regular: "Poppins-Regular.ttf",
|
|
11325
|
+
bold: "Poppins-Bold.ttf",
|
|
11326
|
+
light: "Poppins-Light.ttf",
|
|
11327
|
+
medium: "Poppins-Medium.ttf",
|
|
11328
|
+
semibold: "Poppins-SemiBold.ttf",
|
|
11329
|
+
italic: "Poppins-Italic.ttf",
|
|
11330
|
+
boldItalic: "Poppins-BoldItalic.ttf",
|
|
11331
|
+
lightItalic: "Poppins-LightItalic.ttf",
|
|
11332
|
+
mediumItalic: "Poppins-MediumItalic.ttf",
|
|
11333
|
+
semiboldItalic: "Poppins-SemiBoldItalic.ttf"
|
|
11334
|
+
},
|
|
11335
|
+
"Inter": {
|
|
11336
|
+
regular: "Inter-Regular.ttf",
|
|
11337
|
+
bold: "Inter-Bold.ttf",
|
|
11338
|
+
italic: "Inter-Italic.ttf",
|
|
11339
|
+
boldItalic: "Inter-BoldItalic.ttf"
|
|
11340
|
+
},
|
|
11341
|
+
"Nunito": {
|
|
11342
|
+
regular: "Nunito-Regular.ttf",
|
|
11343
|
+
bold: "Nunito-Bold.ttf",
|
|
11344
|
+
light: "Nunito-Light.ttf",
|
|
11345
|
+
medium: "Nunito-Medium.ttf",
|
|
11346
|
+
semibold: "Nunito-SemiBold.ttf",
|
|
11347
|
+
italic: "Nunito-Italic.ttf",
|
|
11348
|
+
boldItalic: "Nunito-BoldItalic.ttf"
|
|
11349
|
+
},
|
|
11350
|
+
"Source Sans Pro": {
|
|
11351
|
+
regular: "SourceSansPro-Regular.ttf",
|
|
11352
|
+
bold: "SourceSansPro-Bold.ttf",
|
|
11353
|
+
light: "SourceSansPro-Light.ttf",
|
|
11354
|
+
italic: "SourceSansPro-Italic.ttf",
|
|
11355
|
+
boldItalic: "SourceSansPro-BoldItalic.ttf"
|
|
11356
|
+
},
|
|
11357
|
+
"Work Sans": {
|
|
11358
|
+
regular: "WorkSans-Regular.ttf",
|
|
11359
|
+
bold: "WorkSans-Bold.ttf",
|
|
11360
|
+
italic: "WorkSans-Italic.ttf",
|
|
11361
|
+
boldItalic: "WorkSans-BoldItalic.ttf"
|
|
11362
|
+
},
|
|
11363
|
+
"Oswald": { regular: "Oswald-Regular.ttf", bold: "Oswald-Bold.ttf" },
|
|
11364
|
+
"Bebas Neue": { regular: "BebasNeue-Regular.ttf" },
|
|
11365
|
+
"Abril Fatface": { regular: "AbrilFatface-Regular.ttf" },
|
|
11366
|
+
"Dancing Script": { regular: "DancingScript-Regular.ttf", bold: "DancingScript-Bold.ttf" },
|
|
11367
|
+
"Pacifico": { regular: "Pacifico-Regular.ttf" },
|
|
11368
|
+
"Great Vibes": { regular: "GreatVibes-Regular.ttf" },
|
|
11369
|
+
"DM Sans": {
|
|
11370
|
+
regular: "DMSans-Regular.ttf",
|
|
11371
|
+
bold: "DMSans-Bold.ttf",
|
|
11372
|
+
light: "DMSans-Light.ttf",
|
|
11373
|
+
medium: "DMSans-Medium.ttf",
|
|
11374
|
+
semibold: "DMSans-SemiBold.ttf",
|
|
11375
|
+
italic: "DMSans-RegularItalic.ttf",
|
|
11376
|
+
boldItalic: "DMSans-BoldItalic.ttf",
|
|
11377
|
+
lightItalic: "DMSans-LightItalic.ttf",
|
|
11378
|
+
mediumItalic: "DMSans-MediumItalic.ttf",
|
|
11379
|
+
semiboldItalic: "DMSans-SemiBoldItalic.ttf"
|
|
11380
|
+
},
|
|
11381
|
+
"Outfit": {
|
|
11382
|
+
regular: "Outfit-Regular.ttf",
|
|
11383
|
+
bold: "Outfit-Bold.ttf",
|
|
11384
|
+
light: "Outfit-Light.ttf",
|
|
11385
|
+
medium: "Outfit-Medium.ttf",
|
|
11386
|
+
semibold: "Outfit-SemiBold.ttf"
|
|
11387
|
+
},
|
|
11388
|
+
"Figtree": {
|
|
11389
|
+
regular: "Figtree-Regular.ttf",
|
|
11390
|
+
bold: "Figtree-Bold.ttf",
|
|
11391
|
+
light: "Figtree-Light.ttf",
|
|
11392
|
+
medium: "Figtree-Medium.ttf",
|
|
11393
|
+
semibold: "Figtree-SemiBold.ttf",
|
|
11394
|
+
italic: "Figtree-RegularItalic.ttf",
|
|
11395
|
+
boldItalic: "Figtree-BoldItalic.ttf",
|
|
11396
|
+
lightItalic: "Figtree-LightItalic.ttf",
|
|
11397
|
+
mediumItalic: "Figtree-MediumItalic.ttf",
|
|
11398
|
+
semiboldItalic: "Figtree-SemiBoldItalic.ttf"
|
|
11399
|
+
},
|
|
11400
|
+
"Manrope": {
|
|
11401
|
+
regular: "Manrope-Regular.ttf",
|
|
11402
|
+
bold: "Manrope-Bold.ttf",
|
|
11403
|
+
light: "Manrope-Light.ttf",
|
|
11404
|
+
medium: "Manrope-Medium.ttf",
|
|
11405
|
+
semibold: "Manrope-SemiBold.ttf"
|
|
11406
|
+
},
|
|
11407
|
+
"Space Grotesk": {
|
|
11408
|
+
regular: "SpaceGrotesk-Regular.ttf",
|
|
11409
|
+
bold: "SpaceGrotesk-Bold.ttf",
|
|
11410
|
+
light: "SpaceGrotesk-Light.ttf",
|
|
11411
|
+
medium: "SpaceGrotesk-Medium.ttf",
|
|
11412
|
+
semibold: "SpaceGrotesk-SemiBold.ttf"
|
|
11413
|
+
},
|
|
11414
|
+
"League Spartan": {
|
|
11415
|
+
regular: "LeagueSpartan-Regular.ttf",
|
|
11416
|
+
bold: "LeagueSpartan-Bold.ttf",
|
|
11417
|
+
light: "LeagueSpartan-Light.ttf",
|
|
11418
|
+
medium: "LeagueSpartan-Medium.ttf",
|
|
11419
|
+
semibold: "LeagueSpartan-SemiBold.ttf"
|
|
11420
|
+
},
|
|
11421
|
+
"EB Garamond": {
|
|
11422
|
+
regular: "EBGaramond-Regular.ttf",
|
|
11423
|
+
bold: "EBGaramond-Bold.ttf",
|
|
11424
|
+
medium: "EBGaramond-Medium.ttf",
|
|
11425
|
+
semibold: "EBGaramond-SemiBold.ttf",
|
|
11426
|
+
italic: "EBGaramond-RegularItalic.ttf",
|
|
11427
|
+
boldItalic: "EBGaramond-BoldItalic.ttf",
|
|
11428
|
+
mediumItalic: "EBGaramond-MediumItalic.ttf",
|
|
11429
|
+
semiboldItalic: "EBGaramond-SemiBoldItalic.ttf"
|
|
11430
|
+
},
|
|
11431
|
+
"Libre Baskerville": {
|
|
11432
|
+
regular: "LibreBaskerville-Regular.ttf",
|
|
11433
|
+
bold: "LibreBaskerville-Bold.ttf",
|
|
11434
|
+
italic: "LibreBaskerville-RegularItalic.ttf",
|
|
11435
|
+
boldItalic: "LibreBaskerville-BoldItalic.ttf"
|
|
11436
|
+
},
|
|
11437
|
+
"Crimson Text": {
|
|
11438
|
+
regular: "CrimsonText-Regular.ttf",
|
|
11439
|
+
bold: "CrimsonText-Bold.ttf",
|
|
11440
|
+
italic: "CrimsonText-Italic.ttf",
|
|
11441
|
+
boldItalic: "CrimsonText-BoldItalic.ttf"
|
|
11442
|
+
},
|
|
11443
|
+
"DM Serif Display": {
|
|
11444
|
+
regular: "DMSerifDisplay-Regular.ttf",
|
|
11445
|
+
italic: "DMSerifDisplay-Italic.ttf"
|
|
11446
|
+
},
|
|
11447
|
+
"Libre Franklin": {
|
|
11448
|
+
regular: "LibreFranklin-Regular.ttf",
|
|
11449
|
+
bold: "LibreFranklin-Bold.ttf",
|
|
11450
|
+
light: "LibreFranklin-Light.ttf",
|
|
11451
|
+
medium: "LibreFranklin-Medium.ttf",
|
|
11452
|
+
semibold: "LibreFranklin-SemiBold.ttf",
|
|
11453
|
+
italic: "LibreFranklin-RegularItalic.ttf",
|
|
11454
|
+
boldItalic: "LibreFranklin-BoldItalic.ttf",
|
|
11455
|
+
lightItalic: "LibreFranklin-LightItalic.ttf",
|
|
11456
|
+
mediumItalic: "LibreFranklin-MediumItalic.ttf",
|
|
11457
|
+
semiboldItalic: "LibreFranklin-SemiBoldItalic.ttf"
|
|
11458
|
+
},
|
|
11459
|
+
"Mulish": {
|
|
11460
|
+
regular: "Mulish-Regular.ttf",
|
|
11461
|
+
bold: "Mulish-Bold.ttf",
|
|
11462
|
+
light: "Mulish-Light.ttf",
|
|
11463
|
+
medium: "Mulish-Medium.ttf",
|
|
11464
|
+
semibold: "Mulish-SemiBold.ttf",
|
|
11465
|
+
italic: "Mulish-RegularItalic.ttf",
|
|
11466
|
+
boldItalic: "Mulish-BoldItalic.ttf",
|
|
11467
|
+
lightItalic: "Mulish-LightItalic.ttf",
|
|
11468
|
+
mediumItalic: "Mulish-MediumItalic.ttf",
|
|
11469
|
+
semiboldItalic: "Mulish-SemiBoldItalic.ttf"
|
|
11470
|
+
},
|
|
11471
|
+
"Quicksand": {
|
|
11472
|
+
regular: "Quicksand-Regular.ttf",
|
|
11473
|
+
bold: "Quicksand-Bold.ttf",
|
|
11474
|
+
light: "Quicksand-Light.ttf",
|
|
11475
|
+
medium: "Quicksand-Medium.ttf",
|
|
11476
|
+
semibold: "Quicksand-SemiBold.ttf"
|
|
11477
|
+
},
|
|
11478
|
+
"Rubik": {
|
|
11479
|
+
regular: "Rubik-Regular.ttf",
|
|
11480
|
+
bold: "Rubik-Bold.ttf",
|
|
11481
|
+
light: "Rubik-Light.ttf",
|
|
11482
|
+
medium: "Rubik-Medium.ttf",
|
|
11483
|
+
semibold: "Rubik-SemiBold.ttf",
|
|
11484
|
+
italic: "Rubik-RegularItalic.ttf",
|
|
11485
|
+
boldItalic: "Rubik-BoldItalic.ttf",
|
|
11486
|
+
lightItalic: "Rubik-LightItalic.ttf",
|
|
11487
|
+
mediumItalic: "Rubik-MediumItalic.ttf",
|
|
11488
|
+
semiboldItalic: "Rubik-SemiBoldItalic.ttf"
|
|
11489
|
+
},
|
|
11490
|
+
"Karla": {
|
|
11491
|
+
regular: "Karla-Regular.ttf",
|
|
11492
|
+
bold: "Karla-Bold.ttf",
|
|
11493
|
+
light: "Karla-Light.ttf",
|
|
11494
|
+
medium: "Karla-Medium.ttf",
|
|
11495
|
+
semibold: "Karla-SemiBold.ttf",
|
|
11496
|
+
italic: "Karla-RegularItalic.ttf",
|
|
11497
|
+
boldItalic: "Karla-BoldItalic.ttf",
|
|
11498
|
+
lightItalic: "Karla-LightItalic.ttf",
|
|
11499
|
+
mediumItalic: "Karla-MediumItalic.ttf",
|
|
11500
|
+
semiboldItalic: "Karla-SemiBoldItalic.ttf"
|
|
11501
|
+
},
|
|
11502
|
+
"Plus Jakarta Sans": {
|
|
11503
|
+
regular: "PlusJakartaSans-Regular.ttf",
|
|
11504
|
+
bold: "PlusJakartaSans-Bold.ttf",
|
|
11505
|
+
light: "PlusJakartaSans-Light.ttf",
|
|
11506
|
+
medium: "PlusJakartaSans-Medium.ttf",
|
|
11507
|
+
semibold: "PlusJakartaSans-SemiBold.ttf",
|
|
11508
|
+
italic: "PlusJakartaSans-RegularItalic.ttf",
|
|
11509
|
+
boldItalic: "PlusJakartaSans-BoldItalic.ttf",
|
|
11510
|
+
lightItalic: "PlusJakartaSans-LightItalic.ttf",
|
|
11511
|
+
mediumItalic: "PlusJakartaSans-MediumItalic.ttf",
|
|
11512
|
+
semiboldItalic: "PlusJakartaSans-SemiBoldItalic.ttf"
|
|
11513
|
+
},
|
|
11514
|
+
"Sora": {
|
|
11515
|
+
regular: "Sora-Regular.ttf",
|
|
11516
|
+
bold: "Sora-Bold.ttf",
|
|
11517
|
+
light: "Sora-Light.ttf",
|
|
11518
|
+
medium: "Sora-Medium.ttf",
|
|
11519
|
+
semibold: "Sora-SemiBold.ttf"
|
|
11520
|
+
},
|
|
11521
|
+
"Urbanist": {
|
|
11522
|
+
regular: "Urbanist-Regular.ttf",
|
|
11523
|
+
bold: "Urbanist-Bold.ttf",
|
|
11524
|
+
light: "Urbanist-Light.ttf",
|
|
11525
|
+
medium: "Urbanist-Medium.ttf",
|
|
11526
|
+
semibold: "Urbanist-SemiBold.ttf",
|
|
11527
|
+
italic: "Urbanist-RegularItalic.ttf",
|
|
11528
|
+
boldItalic: "Urbanist-BoldItalic.ttf",
|
|
11529
|
+
lightItalic: "Urbanist-LightItalic.ttf",
|
|
11530
|
+
mediumItalic: "Urbanist-MediumItalic.ttf",
|
|
11531
|
+
semiboldItalic: "Urbanist-SemiBoldItalic.ttf"
|
|
11532
|
+
},
|
|
11533
|
+
"Lexend": {
|
|
11534
|
+
regular: "Lexend-Regular.ttf",
|
|
11535
|
+
bold: "Lexend-Bold.ttf",
|
|
11536
|
+
light: "Lexend-Light.ttf",
|
|
11537
|
+
medium: "Lexend-Medium.ttf",
|
|
11538
|
+
semibold: "Lexend-SemiBold.ttf"
|
|
11539
|
+
},
|
|
11540
|
+
"Albert Sans": {
|
|
11541
|
+
regular: "AlbertSans-Regular.ttf",
|
|
11542
|
+
bold: "AlbertSans-Bold.ttf",
|
|
11543
|
+
light: "AlbertSans-Light.ttf",
|
|
11544
|
+
medium: "AlbertSans-Medium.ttf",
|
|
11545
|
+
semibold: "AlbertSans-SemiBold.ttf",
|
|
11546
|
+
italic: "AlbertSans-RegularItalic.ttf",
|
|
11547
|
+
boldItalic: "AlbertSans-BoldItalic.ttf",
|
|
11548
|
+
lightItalic: "AlbertSans-LightItalic.ttf",
|
|
11549
|
+
mediumItalic: "AlbertSans-MediumItalic.ttf",
|
|
11550
|
+
semiboldItalic: "AlbertSans-SemiBoldItalic.ttf"
|
|
11551
|
+
},
|
|
11552
|
+
"Noto Sans": {
|
|
11553
|
+
regular: "NotoSans-Regular.ttf",
|
|
11554
|
+
bold: "NotoSans-Bold.ttf",
|
|
11555
|
+
light: "NotoSans-Light.ttf",
|
|
11556
|
+
medium: "NotoSans-Medium.ttf",
|
|
11557
|
+
semibold: "NotoSans-SemiBold.ttf",
|
|
11558
|
+
italic: "NotoSans-RegularItalic.ttf",
|
|
11559
|
+
boldItalic: "NotoSans-BoldItalic.ttf",
|
|
11560
|
+
lightItalic: "NotoSans-LightItalic.ttf",
|
|
11561
|
+
mediumItalic: "NotoSans-MediumItalic.ttf",
|
|
11562
|
+
semiboldItalic: "NotoSans-SemiBoldItalic.ttf"
|
|
11563
|
+
},
|
|
11564
|
+
"Cabin": {
|
|
11565
|
+
regular: "Cabin-Regular.ttf",
|
|
11566
|
+
bold: "Cabin-Bold.ttf",
|
|
11567
|
+
medium: "Cabin-Medium.ttf",
|
|
11568
|
+
semibold: "Cabin-SemiBold.ttf",
|
|
11569
|
+
italic: "Cabin-RegularItalic.ttf",
|
|
11570
|
+
boldItalic: "Cabin-BoldItalic.ttf",
|
|
11571
|
+
mediumItalic: "Cabin-MediumItalic.ttf",
|
|
11572
|
+
semiboldItalic: "Cabin-SemiBoldItalic.ttf"
|
|
11573
|
+
},
|
|
11574
|
+
"Barlow": {
|
|
11575
|
+
regular: "Barlow-Regular.ttf",
|
|
11576
|
+
bold: "Barlow-Bold.ttf",
|
|
11577
|
+
light: "Barlow-Light.ttf",
|
|
11578
|
+
medium: "Barlow-Medium.ttf",
|
|
11579
|
+
semibold: "Barlow-SemiBold.ttf",
|
|
11580
|
+
italic: "Barlow-Italic.ttf",
|
|
11581
|
+
boldItalic: "Barlow-BoldItalic.ttf"
|
|
11582
|
+
},
|
|
11583
|
+
"Josefin Sans": {
|
|
11584
|
+
regular: "JosefinSans-Regular.ttf",
|
|
11585
|
+
bold: "JosefinSans-Bold.ttf",
|
|
11586
|
+
light: "JosefinSans-Light.ttf",
|
|
11587
|
+
medium: "JosefinSans-Medium.ttf",
|
|
11588
|
+
semibold: "JosefinSans-SemiBold.ttf",
|
|
11589
|
+
italic: "JosefinSans-RegularItalic.ttf",
|
|
11590
|
+
boldItalic: "JosefinSans-BoldItalic.ttf",
|
|
11591
|
+
lightItalic: "JosefinSans-LightItalic.ttf",
|
|
11592
|
+
mediumItalic: "JosefinSans-MediumItalic.ttf",
|
|
11593
|
+
semiboldItalic: "JosefinSans-SemiBoldItalic.ttf"
|
|
11594
|
+
},
|
|
11595
|
+
"Archivo": {
|
|
11596
|
+
regular: "Archivo-Regular.ttf",
|
|
11597
|
+
bold: "Archivo-Bold.ttf",
|
|
11598
|
+
light: "Archivo-Light.ttf",
|
|
11599
|
+
medium: "Archivo-Medium.ttf",
|
|
11600
|
+
semibold: "Archivo-SemiBold.ttf",
|
|
11601
|
+
italic: "Archivo-RegularItalic.ttf",
|
|
11602
|
+
boldItalic: "Archivo-BoldItalic.ttf",
|
|
11603
|
+
lightItalic: "Archivo-LightItalic.ttf",
|
|
11604
|
+
mediumItalic: "Archivo-MediumItalic.ttf",
|
|
11605
|
+
semiboldItalic: "Archivo-SemiBoldItalic.ttf"
|
|
11606
|
+
},
|
|
11607
|
+
"Overpass": {
|
|
11608
|
+
regular: "Overpass-Regular.ttf",
|
|
11609
|
+
bold: "Overpass-Bold.ttf",
|
|
11610
|
+
light: "Overpass-Light.ttf",
|
|
11611
|
+
medium: "Overpass-Medium.ttf",
|
|
11612
|
+
semibold: "Overpass-SemiBold.ttf",
|
|
11613
|
+
italic: "Overpass-RegularItalic.ttf",
|
|
11614
|
+
boldItalic: "Overpass-BoldItalic.ttf",
|
|
11615
|
+
lightItalic: "Overpass-LightItalic.ttf",
|
|
11616
|
+
mediumItalic: "Overpass-MediumItalic.ttf",
|
|
11617
|
+
semiboldItalic: "Overpass-SemiBoldItalic.ttf"
|
|
11618
|
+
},
|
|
11619
|
+
"Exo 2": {
|
|
11620
|
+
regular: "Exo2-Regular.ttf",
|
|
11621
|
+
bold: "Exo2-Bold.ttf",
|
|
11622
|
+
light: "Exo2-Light.ttf",
|
|
11623
|
+
medium: "Exo2-Medium.ttf",
|
|
11624
|
+
semibold: "Exo2-SemiBold.ttf",
|
|
11625
|
+
italic: "Exo2-RegularItalic.ttf",
|
|
11626
|
+
boldItalic: "Exo2-BoldItalic.ttf",
|
|
11627
|
+
lightItalic: "Exo2-LightItalic.ttf",
|
|
11628
|
+
mediumItalic: "Exo2-MediumItalic.ttf",
|
|
11629
|
+
semiboldItalic: "Exo2-SemiBoldItalic.ttf"
|
|
11630
|
+
},
|
|
11631
|
+
"Roboto Mono": {
|
|
11632
|
+
regular: "RobotoMono-Regular.ttf",
|
|
11633
|
+
bold: "RobotoMono-Bold.ttf",
|
|
11634
|
+
light: "RobotoMono-Light.ttf",
|
|
11635
|
+
medium: "RobotoMono-Medium.ttf",
|
|
11636
|
+
semibold: "RobotoMono-SemiBold.ttf",
|
|
11637
|
+
italic: "RobotoMono-RegularItalic.ttf",
|
|
11638
|
+
boldItalic: "RobotoMono-BoldItalic.ttf",
|
|
11639
|
+
lightItalic: "RobotoMono-LightItalic.ttf",
|
|
11640
|
+
mediumItalic: "RobotoMono-MediumItalic.ttf",
|
|
11641
|
+
semiboldItalic: "RobotoMono-SemiBoldItalic.ttf"
|
|
11642
|
+
},
|
|
11643
|
+
"Fira Code": {
|
|
11644
|
+
regular: "FiraCode-Regular.ttf",
|
|
11645
|
+
bold: "FiraCode-Bold.ttf",
|
|
11646
|
+
light: "FiraCode-Light.ttf",
|
|
11647
|
+
medium: "FiraCode-Medium.ttf",
|
|
11648
|
+
semibold: "FiraCode-SemiBold.ttf"
|
|
11649
|
+
},
|
|
11650
|
+
"JetBrains Mono": {
|
|
11651
|
+
regular: "JetBrainsMono-Regular.ttf",
|
|
11652
|
+
bold: "JetBrainsMono-Bold.ttf",
|
|
11653
|
+
light: "JetBrainsMono-Light.ttf",
|
|
11654
|
+
medium: "JetBrainsMono-Medium.ttf",
|
|
11655
|
+
semibold: "JetBrainsMono-SemiBold.ttf",
|
|
11656
|
+
italic: "JetBrainsMono-RegularItalic.ttf",
|
|
11657
|
+
boldItalic: "JetBrainsMono-BoldItalic.ttf",
|
|
11658
|
+
lightItalic: "JetBrainsMono-LightItalic.ttf",
|
|
11659
|
+
mediumItalic: "JetBrainsMono-MediumItalic.ttf",
|
|
11660
|
+
semiboldItalic: "JetBrainsMono-SemiBoldItalic.ttf"
|
|
11661
|
+
},
|
|
11662
|
+
"Source Code Pro": {
|
|
11663
|
+
regular: "SourceCodePro-Regular.ttf",
|
|
11664
|
+
bold: "SourceCodePro-Bold.ttf",
|
|
11665
|
+
light: "SourceCodePro-Light.ttf",
|
|
11666
|
+
medium: "SourceCodePro-Medium.ttf",
|
|
11667
|
+
semibold: "SourceCodePro-SemiBold.ttf",
|
|
11668
|
+
italic: "SourceCodePro-RegularItalic.ttf",
|
|
11669
|
+
boldItalic: "SourceCodePro-BoldItalic.ttf",
|
|
11670
|
+
lightItalic: "SourceCodePro-LightItalic.ttf",
|
|
11671
|
+
mediumItalic: "SourceCodePro-MediumItalic.ttf",
|
|
11672
|
+
semiboldItalic: "SourceCodePro-SemiBoldItalic.ttf"
|
|
11673
|
+
},
|
|
11674
|
+
"IBM Plex Mono": {
|
|
11675
|
+
regular: "IBMPlexMono-Regular.ttf",
|
|
11676
|
+
bold: "IBMPlexMono-Bold.ttf"
|
|
11677
|
+
},
|
|
11678
|
+
"Space Mono": {
|
|
11679
|
+
regular: "SpaceMono-Regular.ttf",
|
|
11680
|
+
bold: "SpaceMono-Bold.ttf",
|
|
11681
|
+
italic: "SpaceMono-Italic.ttf",
|
|
11682
|
+
boldItalic: "SpaceMono-BoldItalic.ttf"
|
|
11683
|
+
},
|
|
11684
|
+
"Sacramento": { regular: "Sacramento-Regular.ttf" },
|
|
11685
|
+
"Alex Brush": { regular: "AlexBrush-Regular.ttf" },
|
|
11686
|
+
"Allura": { regular: "Allura-Regular.ttf" },
|
|
11687
|
+
"Caveat": {
|
|
11688
|
+
regular: "Caveat-Regular.ttf",
|
|
11689
|
+
bold: "Caveat-Bold.ttf",
|
|
11690
|
+
medium: "Caveat-Medium.ttf",
|
|
11691
|
+
semibold: "Caveat-SemiBold.ttf"
|
|
11692
|
+
},
|
|
11693
|
+
"Lobster": { regular: "Lobster-Regular.ttf" },
|
|
11694
|
+
"Comfortaa": {
|
|
11695
|
+
regular: "Comfortaa-Regular.ttf",
|
|
11696
|
+
bold: "Comfortaa-Bold.ttf",
|
|
11697
|
+
light: "Comfortaa-Light.ttf",
|
|
11698
|
+
medium: "Comfortaa-Medium.ttf",
|
|
11699
|
+
semibold: "Comfortaa-SemiBold.ttf"
|
|
11700
|
+
},
|
|
11701
|
+
"Anton": { regular: "Anton-Regular.ttf" },
|
|
11702
|
+
"Teko": {
|
|
11703
|
+
regular: "Teko-Regular.ttf",
|
|
11704
|
+
bold: "Teko-Bold.ttf",
|
|
11705
|
+
light: "Teko-Light.ttf",
|
|
11706
|
+
medium: "Teko-Medium.ttf",
|
|
11707
|
+
semibold: "Teko-SemiBold.ttf"
|
|
11708
|
+
},
|
|
11709
|
+
"Noto Sans Devanagari": {
|
|
11710
|
+
regular: "NotoSansDevanagari-Regular.ttf",
|
|
11711
|
+
bold: "NotoSansDevanagari-Bold.ttf",
|
|
11712
|
+
light: "NotoSansDevanagari-Light.ttf",
|
|
11713
|
+
medium: "NotoSansDevanagari-Medium.ttf",
|
|
11714
|
+
semibold: "NotoSansDevanagari-SemiBold.ttf"
|
|
11715
|
+
},
|
|
11716
|
+
"Hind": {
|
|
11717
|
+
regular: "Hind-Regular.ttf",
|
|
11718
|
+
bold: "Hind-Bold.ttf",
|
|
11719
|
+
light: "Hind-Light.ttf",
|
|
11720
|
+
medium: "Hind-Medium.ttf",
|
|
11721
|
+
semibold: "Hind-SemiBold.ttf"
|
|
11722
|
+
},
|
|
11723
|
+
"Cinzel": { regular: "Cinzel-Regular.ttf", bold: "Cinzel-Bold.ttf" },
|
|
11724
|
+
"Cormorant Garamond": {
|
|
11725
|
+
regular: "CormorantGaramond-Regular.ttf",
|
|
11726
|
+
bold: "CormorantGaramond-Bold.ttf",
|
|
11727
|
+
light: "CormorantGaramond-Light.ttf",
|
|
11728
|
+
medium: "CormorantGaramond-Medium.ttf",
|
|
11729
|
+
semibold: "CormorantGaramond-SemiBold.ttf",
|
|
11730
|
+
italic: "CormorantGaramond-Italic.ttf",
|
|
11731
|
+
boldItalic: "CormorantGaramond-BoldItalic.ttf"
|
|
11732
|
+
}
|
|
11733
|
+
};
|
|
11734
|
+
const WEIGHT_TO_KEYS = {
|
|
11735
|
+
300: ["light", "regular"],
|
|
11736
|
+
400: ["regular"],
|
|
11737
|
+
500: ["medium", "regular"],
|
|
11738
|
+
600: ["semibold", "bold", "regular"],
|
|
11739
|
+
700: ["bold", "regular"]
|
|
11740
|
+
};
|
|
11741
|
+
const WEIGHT_TO_ITALIC_KEYS = {
|
|
11742
|
+
300: ["lightItalic", "italic", "light", "regular"],
|
|
11743
|
+
400: ["italic", "regular"],
|
|
11744
|
+
500: ["mediumItalic", "italic", "medium", "regular"],
|
|
11745
|
+
600: ["semiboldItalic", "boldItalic", "italic", "semibold", "bold", "regular"],
|
|
11746
|
+
700: ["boldItalic", "italic", "bold", "regular"]
|
|
11747
|
+
};
|
|
11748
|
+
function getFontPathForWeight(files, weight, isItalic = false) {
|
|
11749
|
+
const keys = isItalic ? WEIGHT_TO_ITALIC_KEYS[weight] : WEIGHT_TO_KEYS[weight];
|
|
11750
|
+
if (!keys) return files.regular;
|
|
11751
|
+
for (const k of keys) {
|
|
11752
|
+
const path = files[k];
|
|
11753
|
+
if (path) return path;
|
|
11754
|
+
}
|
|
11755
|
+
return files.regular;
|
|
11756
|
+
}
|
|
11757
|
+
function isItalicPath(files, path) {
|
|
11758
|
+
return path === files.italic || path === files.boldItalic || path === files.lightItalic || path === files.mediumItalic || path === files.semiboldItalic;
|
|
11759
|
+
}
|
|
11760
|
+
function getJsPDFFontName(fontName) {
|
|
11761
|
+
return fontName.replace(/\s+/g, "");
|
|
11762
|
+
}
|
|
11763
|
+
function getEmbeddedJsPDFFontName(fontName, weight, isItalic = false) {
|
|
11764
|
+
const resolved = resolveFontWeight(weight);
|
|
11765
|
+
const label = FONT_WEIGHT_LABELS[resolved];
|
|
11766
|
+
const italicSuffix = isItalic ? "Italic" : "";
|
|
11767
|
+
return `${getJsPDFFontName(fontName)}-${label}${italicSuffix}`;
|
|
11768
|
+
}
|
|
11769
|
+
function isFontAvailable(fontName) {
|
|
11770
|
+
return fontName in FONT_FILES;
|
|
11771
|
+
}
|
|
11772
|
+
const ttfCache = /* @__PURE__ */ new Map();
|
|
11773
|
+
async function fetchTTFAsBase64(url) {
|
|
11774
|
+
const cached = ttfCache.get(url);
|
|
11775
|
+
if (cached) return cached;
|
|
11776
|
+
try {
|
|
11777
|
+
const res = await fetch(url);
|
|
11778
|
+
if (!res.ok) return null;
|
|
11779
|
+
const buf = await res.arrayBuffer();
|
|
11780
|
+
const bytes = new Uint8Array(buf);
|
|
11781
|
+
let binary = "";
|
|
11782
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
11783
|
+
binary += String.fromCharCode(bytes[i]);
|
|
11784
|
+
}
|
|
11785
|
+
const b64 = btoa(binary);
|
|
11786
|
+
ttfCache.set(url, b64);
|
|
11787
|
+
return b64;
|
|
11788
|
+
} catch {
|
|
11789
|
+
return null;
|
|
11790
|
+
}
|
|
11791
|
+
}
|
|
11792
|
+
async function embedFont(pdf, fontName, weight, fontBaseUrl, isItalic = false) {
|
|
11793
|
+
const fontFiles = FONT_FILES[fontName];
|
|
11794
|
+
if (!fontFiles) return false;
|
|
11795
|
+
const baseUrl = fontBaseUrl.endsWith("/") ? fontBaseUrl : fontBaseUrl + "/";
|
|
11796
|
+
const resolvedWeight = resolveFontWeight(weight);
|
|
11797
|
+
const fontPath = getFontPathForWeight(fontFiles, resolvedWeight, isItalic);
|
|
11798
|
+
if (!fontPath) return false;
|
|
11799
|
+
const hasItalicFile = isItalic && isItalicPath(fontFiles, fontPath);
|
|
11800
|
+
const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, weight, hasItalicFile);
|
|
11801
|
+
const label = FONT_WEIGHT_LABELS[resolvedWeight];
|
|
11802
|
+
const italicSuffix = hasItalicFile ? "Italic" : "";
|
|
11803
|
+
const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;
|
|
11804
|
+
const url = baseUrl + fontPath;
|
|
11805
|
+
try {
|
|
11806
|
+
const b64 = await fetchTTFAsBase64(url);
|
|
11807
|
+
if (!b64) return false;
|
|
11808
|
+
pdf.addFileToVFS(fileName, b64);
|
|
11809
|
+
pdf.addFont(fileName, jsPdfFontName, "normal");
|
|
11810
|
+
if (fontName !== jsPdfFontName) {
|
|
11811
|
+
try {
|
|
11812
|
+
pdf.addFont(fileName, fontName, "normal");
|
|
11813
|
+
} catch {
|
|
11814
|
+
}
|
|
11815
|
+
}
|
|
11816
|
+
return true;
|
|
11817
|
+
} catch (e) {
|
|
11818
|
+
console.warn(`[pdf-fonts] Failed to embed ${fontName} w${weight}:`, e);
|
|
11819
|
+
return false;
|
|
11820
|
+
}
|
|
11821
|
+
}
|
|
11822
|
+
async function embedFontsForConfig(pdf, config, fontBaseUrl) {
|
|
11823
|
+
const fontKeys = /* @__PURE__ */ new Set();
|
|
11824
|
+
const SEP = "";
|
|
11825
|
+
const walkElements = (elements) => {
|
|
11826
|
+
for (const el of elements) {
|
|
11827
|
+
if (el.fontFamily) {
|
|
11828
|
+
const w = resolveFontWeight(el.fontWeight ?? 400);
|
|
11829
|
+
fontKeys.add(`${el.fontFamily}${SEP}${w}`);
|
|
11830
|
+
}
|
|
11831
|
+
if (el.styles && typeof el.styles === "object") {
|
|
11832
|
+
for (const lineKey of Object.keys(el.styles)) {
|
|
11833
|
+
const lineStyles = el.styles[lineKey];
|
|
11834
|
+
if (lineStyles && typeof lineStyles === "object") {
|
|
11835
|
+
for (const charKey of Object.keys(lineStyles)) {
|
|
11836
|
+
const s = lineStyles[charKey];
|
|
11837
|
+
if (s == null ? void 0 : s.fontFamily) {
|
|
11838
|
+
const w = resolveFontWeight(s.fontWeight ?? 400);
|
|
11839
|
+
fontKeys.add(`${s.fontFamily}${SEP}${w}`);
|
|
11840
|
+
}
|
|
11841
|
+
}
|
|
11842
|
+
}
|
|
11843
|
+
}
|
|
11844
|
+
}
|
|
11845
|
+
if (el.children) walkElements(el.children);
|
|
11846
|
+
if (el.objects) walkElements(el.objects);
|
|
11847
|
+
}
|
|
11848
|
+
};
|
|
11849
|
+
for (const page of (config == null ? void 0 : config.pages) || []) {
|
|
11850
|
+
if (page.children) walkElements(page.children);
|
|
11851
|
+
if (page.elements) walkElements(page.elements);
|
|
11852
|
+
}
|
|
11853
|
+
fontKeys.add(`${FONT_FALLBACK_SYMBOLS}${SEP}400`);
|
|
11854
|
+
for (const w of [300, 400, 500, 600, 700]) {
|
|
11855
|
+
fontKeys.add(`${FONT_FALLBACK_DEVANAGARI}${SEP}${w}`);
|
|
11856
|
+
}
|
|
11857
|
+
const embedded = /* @__PURE__ */ new Set();
|
|
11858
|
+
const tasks = [];
|
|
11859
|
+
for (const key of fontKeys) {
|
|
11860
|
+
const sep = key.indexOf(SEP);
|
|
11861
|
+
const fontName = key.slice(0, sep);
|
|
11862
|
+
const weight = parseInt(key.slice(sep + 1), 10);
|
|
11863
|
+
if (!isFontAvailable(fontName)) continue;
|
|
11864
|
+
tasks.push(
|
|
11865
|
+
embedFont(pdf, fontName, weight, fontBaseUrl).then((ok) => {
|
|
11866
|
+
if (ok) embedded.add(key);
|
|
11867
|
+
})
|
|
11868
|
+
);
|
|
11869
|
+
}
|
|
11870
|
+
await Promise.all(tasks);
|
|
11871
|
+
console.log(`[pdf-fonts] Embedded ${embedded.size} font variants from config`);
|
|
11872
|
+
return embedded;
|
|
11873
|
+
}
|
|
11874
|
+
function rewriteSvgFontsForJsPDF(svgStr) {
|
|
11875
|
+
var _a;
|
|
11876
|
+
const parser = new DOMParser();
|
|
11877
|
+
const doc = parser.parseFromString(svgStr, "image/svg+xml");
|
|
11878
|
+
const textEls = doc.querySelectorAll("text, tspan, textPath");
|
|
11879
|
+
const readStyleToken = (style, prop) => {
|
|
11880
|
+
var _a2;
|
|
11881
|
+
const match = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
|
|
11882
|
+
return ((_a2 = match == null ? void 0 : match[1]) == null ? void 0 : _a2.trim()) || null;
|
|
11883
|
+
};
|
|
11884
|
+
const resolveInheritedValue = (el, attr, styleProp = attr) => {
|
|
11885
|
+
var _a2;
|
|
11886
|
+
let current = el;
|
|
11887
|
+
while (current) {
|
|
11888
|
+
const attrVal = (_a2 = current.getAttribute(attr)) == null ? void 0 : _a2.trim();
|
|
11889
|
+
if (attrVal) return attrVal;
|
|
11890
|
+
const styleVal = readStyleToken(current.getAttribute("style") || "", styleProp);
|
|
11891
|
+
if (styleVal) return styleVal;
|
|
11892
|
+
current = current.parentElement;
|
|
11893
|
+
}
|
|
11894
|
+
return null;
|
|
11895
|
+
};
|
|
11896
|
+
for (const el of textEls) {
|
|
11897
|
+
const inlineStyle = el.getAttribute("style") || "";
|
|
11898
|
+
const rawFf = resolveInheritedValue(el, "font-family");
|
|
11899
|
+
if (!rawFf) continue;
|
|
11900
|
+
const clean = (_a = rawFf.split(",")[0]) == null ? void 0 : _a.replace(/['"]/g, "").trim();
|
|
11901
|
+
if (!isFontAvailable(clean)) continue;
|
|
11902
|
+
const weightRaw = resolveInheritedValue(el, "font-weight") || "400";
|
|
11903
|
+
const styleRaw = resolveInheritedValue(el, "font-style") || "normal";
|
|
11904
|
+
const parsedWeight = Number.parseInt(weightRaw, 10);
|
|
11905
|
+
const weight = 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;
|
|
11906
|
+
const resolved = resolveFontWeight(weight);
|
|
11907
|
+
const isItalic = /italic|oblique/i.test(styleRaw);
|
|
11908
|
+
const jsPdfName = getEmbeddedJsPDFFontName(clean, resolved, isItalic);
|
|
11909
|
+
el.setAttribute("font-family", jsPdfName);
|
|
11910
|
+
el.setAttribute("font-weight", "normal");
|
|
11911
|
+
el.setAttribute("font-style", "normal");
|
|
11912
|
+
const stylePairs = inlineStyle.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));
|
|
11913
|
+
stylePairs.push(`font-family: ${jsPdfName}`);
|
|
11914
|
+
stylePairs.push(`font-weight: normal`);
|
|
11915
|
+
stylePairs.push(`font-style: normal`);
|
|
11916
|
+
el.setAttribute("style", stylePairs.join("; "));
|
|
11917
|
+
}
|
|
11918
|
+
return new XMLSerializer().serializeToString(doc.documentElement);
|
|
11919
|
+
}
|
|
11920
|
+
function extractFontFamiliesFromSvgs(svgs) {
|
|
11921
|
+
const families = /* @__PURE__ */ new Set();
|
|
11922
|
+
const regex = /font-family[=:]\s*["']?([^"';},]+)/gi;
|
|
11923
|
+
for (const svg of svgs) {
|
|
11924
|
+
let m;
|
|
11925
|
+
while ((m = regex.exec(svg)) !== null) {
|
|
11926
|
+
const raw = m[1].trim().split(",")[0].trim().replace(/^['"]|['"]$/g, "");
|
|
11927
|
+
if (raw && raw !== "serif" && raw !== "sans-serif" && raw !== "monospace") {
|
|
11928
|
+
families.add(raw);
|
|
11929
|
+
}
|
|
11930
|
+
}
|
|
11931
|
+
}
|
|
11932
|
+
return families;
|
|
11933
|
+
}
|
|
11934
|
+
async function embedFontsInPdf(pdf, fontFamilies, fontBaseUrl) {
|
|
11935
|
+
const embedded = /* @__PURE__ */ new Set();
|
|
11936
|
+
const weights = [300, 400, 500, 600, 700];
|
|
11937
|
+
const tasks = [];
|
|
11938
|
+
for (const family of fontFamilies) {
|
|
11939
|
+
if (!isFontAvailable(family)) {
|
|
11940
|
+
console.warn(`[pdf-fonts] No TTF mapping for "${family}" — will use Helvetica fallback`);
|
|
11941
|
+
continue;
|
|
11942
|
+
}
|
|
11943
|
+
for (const w of weights) {
|
|
11944
|
+
tasks.push(
|
|
11945
|
+
embedFont(pdf, family, w, fontBaseUrl).then((ok) => {
|
|
11946
|
+
if (ok) embedded.add(`${family}${w}`);
|
|
11947
|
+
})
|
|
11948
|
+
);
|
|
11949
|
+
}
|
|
11950
|
+
}
|
|
11951
|
+
await Promise.all(tasks);
|
|
11952
|
+
console.log(`[pdf-fonts] Embedded ${embedded.size} font variants for ${fontFamilies.size} families`);
|
|
11953
|
+
return embedded;
|
|
11954
|
+
}
|
|
11955
|
+
const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
11956
|
+
__proto__: null,
|
|
11957
|
+
FONT_FALLBACK_DEVANAGARI,
|
|
11958
|
+
FONT_FALLBACK_SYMBOLS,
|
|
11959
|
+
FONT_FILES,
|
|
11960
|
+
FONT_WEIGHT_LABELS,
|
|
11961
|
+
embedFont,
|
|
11962
|
+
embedFontsForConfig,
|
|
11963
|
+
embedFontsInPdf,
|
|
11964
|
+
extractFontFamiliesFromSvgs,
|
|
11965
|
+
getEmbeddedJsPDFFontName,
|
|
11966
|
+
isFontAvailable,
|
|
11967
|
+
resolveFontWeight,
|
|
11968
|
+
rewriteSvgFontsForJsPDF
|
|
11969
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
11970
|
+
const SVG_DRAWABLE_TAGS = /* @__PURE__ */ new Set([
|
|
11971
|
+
"path",
|
|
11972
|
+
"rect",
|
|
11973
|
+
"circle",
|
|
11974
|
+
"ellipse",
|
|
11975
|
+
"polygon",
|
|
11976
|
+
"polyline",
|
|
11977
|
+
"line",
|
|
11978
|
+
"text",
|
|
11979
|
+
"tspan"
|
|
11980
|
+
]);
|
|
11981
|
+
const SVG_DEFINITION_CONTAINER_TAGS = /* @__PURE__ */ new Set([
|
|
11982
|
+
"defs",
|
|
11983
|
+
"clippath",
|
|
11984
|
+
"mask",
|
|
11985
|
+
"pattern",
|
|
11986
|
+
"marker",
|
|
11987
|
+
"symbol",
|
|
11988
|
+
"filter",
|
|
11989
|
+
"lineargradient",
|
|
11990
|
+
"radialgradient"
|
|
11991
|
+
]);
|
|
11992
|
+
const SVG_STYLE_PROPS = /* @__PURE__ */ new Set([
|
|
11993
|
+
"fill",
|
|
11994
|
+
"stroke",
|
|
11995
|
+
"color",
|
|
11996
|
+
"opacity",
|
|
11997
|
+
"fill-opacity",
|
|
11998
|
+
"stroke-opacity",
|
|
11999
|
+
"fill-rule",
|
|
12000
|
+
"stroke-width",
|
|
12001
|
+
"stroke-linecap",
|
|
12002
|
+
"stroke-linejoin",
|
|
12003
|
+
"stroke-miterlimit",
|
|
12004
|
+
"stroke-dasharray",
|
|
12005
|
+
"stroke-dashoffset",
|
|
12006
|
+
"display",
|
|
12007
|
+
"visibility",
|
|
12008
|
+
"stop-color",
|
|
12009
|
+
"stop-opacity",
|
|
12010
|
+
"clip-rule",
|
|
12011
|
+
"clip-path",
|
|
12012
|
+
"mask",
|
|
12013
|
+
"filter"
|
|
12014
|
+
]);
|
|
12015
|
+
const GRADIENT_ATTRS_LINEAR = ["x1", "y1", "x2", "y2", "gradientUnits", "gradientTransform", "spreadMethod"];
|
|
12016
|
+
const GRADIENT_ATTRS_RADIAL = ["cx", "cy", "r", "fx", "fy", "gradientUnits", "gradientTransform", "spreadMethod"];
|
|
12017
|
+
const URL_GRADIENT_RE = /^\s*url\s*\(\s*(['"]?)([^)]+?)\1\s*\)/i;
|
|
12018
|
+
function parseColor(color) {
|
|
12019
|
+
if (!color) return null;
|
|
12020
|
+
const raw = color.trim().toLowerCase();
|
|
12021
|
+
if (!raw || raw === "transparent" || raw === "none") return null;
|
|
12022
|
+
const clamp2 = (value) => Math.max(0, Math.min(255, Math.round(value)));
|
|
12023
|
+
const parseNumeric = (token) => {
|
|
12024
|
+
const value = parseFloat(token);
|
|
12025
|
+
return Number.isFinite(value) ? value : NaN;
|
|
12026
|
+
};
|
|
12027
|
+
const parseRgbComponent = (token) => {
|
|
12028
|
+
const value = parseNumeric(token);
|
|
12029
|
+
if (!Number.isFinite(value)) return NaN;
|
|
12030
|
+
return token.endsWith("%") ? value / 100 * 255 : value;
|
|
12031
|
+
};
|
|
12032
|
+
const parseAlpha = (token) => {
|
|
12033
|
+
if (!token) return 1;
|
|
12034
|
+
const value = parseNumeric(token);
|
|
12035
|
+
if (!Number.isFinite(value)) return 1;
|
|
12036
|
+
return token.endsWith("%") ? value / 100 : value;
|
|
12037
|
+
};
|
|
12038
|
+
const toRgbFromHsl = (h, s, l) => {
|
|
12039
|
+
const hue = (h % 360 + 360) % 360;
|
|
12040
|
+
const sat = Math.max(0, Math.min(1, s));
|
|
12041
|
+
const light = Math.max(0, Math.min(1, l));
|
|
12042
|
+
if (sat === 0) {
|
|
12043
|
+
const gray = clamp2(light * 255);
|
|
12044
|
+
return { r: gray, g: gray, b: gray };
|
|
12045
|
+
}
|
|
12046
|
+
const q = light < 0.5 ? light * (1 + sat) : light + sat - light * sat;
|
|
12047
|
+
const p = 2 * light - q;
|
|
12048
|
+
const hueToRgb = (t) => {
|
|
12049
|
+
let tt = t;
|
|
12050
|
+
if (tt < 0) tt += 1;
|
|
12051
|
+
if (tt > 1) tt -= 1;
|
|
12052
|
+
if (tt < 1 / 6) return p + (q - p) * 6 * tt;
|
|
12053
|
+
if (tt < 1 / 2) return q;
|
|
12054
|
+
if (tt < 2 / 3) return p + (q - p) * (2 / 3 - tt) * 6;
|
|
12055
|
+
return p;
|
|
12056
|
+
};
|
|
12057
|
+
return {
|
|
12058
|
+
r: clamp2(hueToRgb(hue / 360 + 1 / 3) * 255),
|
|
12059
|
+
g: clamp2(hueToRgb(hue / 360) * 255),
|
|
12060
|
+
b: clamp2(hueToRgb(hue / 360 - 1 / 3) * 255)
|
|
12061
|
+
};
|
|
12062
|
+
};
|
|
12063
|
+
if (raw.startsWith("#")) {
|
|
12064
|
+
const hex = raw.slice(1);
|
|
12065
|
+
const expanded = hex.length === 3 || hex.length === 4 ? hex.split("").map((char) => char + char).join("") : hex;
|
|
12066
|
+
if (expanded.length !== 6 && expanded.length !== 8) return null;
|
|
12067
|
+
const intValue = parseInt(expanded.slice(0, 6), 16);
|
|
12068
|
+
if (!Number.isFinite(intValue)) return null;
|
|
12069
|
+
if (expanded.length === 8) {
|
|
12070
|
+
const alphaHex = parseInt(expanded.slice(6, 8), 16);
|
|
12071
|
+
if (Number.isFinite(alphaHex) && alphaHex <= 0) return null;
|
|
12072
|
+
}
|
|
12073
|
+
return { r: intValue >> 16 & 255, g: intValue >> 8 & 255, b: intValue & 255 };
|
|
12074
|
+
}
|
|
12075
|
+
const rgbMatch = raw.match(/^rgba?\((.+)\)$/);
|
|
12076
|
+
if (rgbMatch) {
|
|
12077
|
+
const normalized = rgbMatch[1].replace(/\//g, " ").replace(/,/g, " ");
|
|
12078
|
+
const parts = normalized.split(/\s+/).filter(Boolean);
|
|
12079
|
+
if (parts.length >= 3) {
|
|
12080
|
+
const alpha = parseAlpha(parts[3]);
|
|
12081
|
+
if (alpha <= 0) return null;
|
|
12082
|
+
const r = parseRgbComponent(parts[0]);
|
|
12083
|
+
const g = parseRgbComponent(parts[1]);
|
|
12084
|
+
const b = parseRgbComponent(parts[2]);
|
|
12085
|
+
if (Number.isFinite(r) && Number.isFinite(g) && Number.isFinite(b)) {
|
|
12086
|
+
return { r: clamp2(r), g: clamp2(g), b: clamp2(b) };
|
|
12087
|
+
}
|
|
12088
|
+
}
|
|
12089
|
+
}
|
|
12090
|
+
const hslMatch = raw.match(/^hsla?\((.+)\)$/);
|
|
12091
|
+
if (hslMatch) {
|
|
12092
|
+
const normalized = hslMatch[1].replace(/\//g, " ").replace(/,/g, " ");
|
|
12093
|
+
const parts = normalized.split(/\s+/).filter(Boolean);
|
|
12094
|
+
if (parts.length >= 3) {
|
|
12095
|
+
const alpha = parseAlpha(parts[3]);
|
|
12096
|
+
if (alpha <= 0) return null;
|
|
12097
|
+
const h = parseNumeric(parts[0].replace(/deg$/, ""));
|
|
12098
|
+
const sRaw = parseNumeric(parts[1].replace(/%$/, ""));
|
|
12099
|
+
const lRaw = parseNumeric(parts[2].replace(/%$/, ""));
|
|
12100
|
+
if (Number.isFinite(h) && Number.isFinite(sRaw) && Number.isFinite(lRaw)) {
|
|
12101
|
+
return toRgbFromHsl(h, sRaw / 100, lRaw / 100);
|
|
12102
|
+
}
|
|
12103
|
+
}
|
|
12104
|
+
}
|
|
12105
|
+
return null;
|
|
12106
|
+
}
|
|
12107
|
+
function rgbToHex(r, g, b) {
|
|
12108
|
+
return "#" + [r, g, b].map((x) => Math.max(0, Math.min(255, Math.round(x))).toString(16).padStart(2, "0")).join("");
|
|
12109
|
+
}
|
|
12110
|
+
function cssColorToHex(css) {
|
|
12111
|
+
var _a;
|
|
12112
|
+
const s = css.trim();
|
|
12113
|
+
if (/^#[0-9a-f]{3}$/i.test(s)) {
|
|
12114
|
+
const r = s[1] + s[1], g = s[2] + s[2], b = s[3] + s[3];
|
|
12115
|
+
return "#" + r + g + b;
|
|
12116
|
+
}
|
|
12117
|
+
if (/^#[0-9a-f]{6}$/i.test(s)) return s;
|
|
12118
|
+
if (/^#[0-9a-f]{8}$/i.test(s)) return "#" + s.slice(1, 7);
|
|
12119
|
+
const rgb = s.match(/^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);
|
|
12120
|
+
if (rgb) {
|
|
12121
|
+
const r = Number(rgb[1]).toString(16).padStart(2, "0");
|
|
12122
|
+
const g = Number(rgb[2]).toString(16).padStart(2, "0");
|
|
12123
|
+
const b = Number(rgb[3]).toString(16).padStart(2, "0");
|
|
12124
|
+
return "#" + r + g + b;
|
|
12125
|
+
}
|
|
12126
|
+
if (typeof document === "undefined") return null;
|
|
12127
|
+
const div = document.createElement("div");
|
|
12128
|
+
div.style.color = s;
|
|
12129
|
+
const computed = (_a = document.defaultView) == null ? void 0 : _a.getComputedStyle(div).color;
|
|
12130
|
+
if (!computed || !computed.startsWith("rgb")) return null;
|
|
12131
|
+
const m = computed.match(/\d+/g);
|
|
12132
|
+
if (!m || m.length < 3) return null;
|
|
12133
|
+
return "#" + [m[0], m[1], m[2]].map((v) => Number(v).toString(16).padStart(2, "0")).join("");
|
|
12134
|
+
}
|
|
12135
|
+
function isInSvgDefinitionSubtree(el) {
|
|
12136
|
+
var _a;
|
|
12137
|
+
let current = el;
|
|
12138
|
+
while (current) {
|
|
12139
|
+
if (SVG_DEFINITION_CONTAINER_TAGS.has(((_a = current.tagName) == null ? void 0 : _a.toLowerCase()) ?? "")) return true;
|
|
12140
|
+
current = current.parentElement;
|
|
12141
|
+
}
|
|
12142
|
+
return false;
|
|
12143
|
+
}
|
|
12144
|
+
function parseInlineSvgStyleDeclarations(styleText) {
|
|
12145
|
+
return styleText.split(";").map((part) => part.trim()).filter(Boolean).map((part) => {
|
|
12146
|
+
const idx = part.indexOf(":");
|
|
12147
|
+
if (idx <= 0) return null;
|
|
12148
|
+
return { key: part.slice(0, idx).trim().toLowerCase(), value: part.slice(idx + 1).trim() };
|
|
12149
|
+
}).filter((x) => !!x);
|
|
12150
|
+
}
|
|
12151
|
+
function extractGradientIdFromPaint(value) {
|
|
12152
|
+
if (!value) return null;
|
|
12153
|
+
const match = value.trim().match(URL_GRADIENT_RE);
|
|
12154
|
+
if (!match) return null;
|
|
12155
|
+
const rawRef = (match[2] || "").trim();
|
|
12156
|
+
if (!rawRef) return null;
|
|
12157
|
+
const hashIdx = rawRef.lastIndexOf("#");
|
|
12158
|
+
if (hashIdx < 0 || hashIdx === rawRef.length - 1) return null;
|
|
12159
|
+
const id = rawRef.slice(hashIdx + 1).trim();
|
|
12160
|
+
if (!id) return null;
|
|
12161
|
+
return id.replace(/[\s"')].*$/, "");
|
|
12162
|
+
}
|
|
12163
|
+
function normalizeGradientPaintRef(value) {
|
|
12164
|
+
const id = extractGradientIdFromPaint(value);
|
|
12165
|
+
return id ? `url(#${id})` : value;
|
|
12166
|
+
}
|
|
12167
|
+
function findGradientInTree(svgRoot, gradientId) {
|
|
12168
|
+
for (const el of svgRoot.querySelectorAll("[id]")) {
|
|
12169
|
+
if (el.getAttribute("id") === gradientId) return el;
|
|
12170
|
+
}
|
|
12171
|
+
return null;
|
|
12172
|
+
}
|
|
12173
|
+
function getInlineStyleValue(el, key) {
|
|
12174
|
+
const style = el.getAttribute("style") || "";
|
|
12175
|
+
if (!style) return null;
|
|
12176
|
+
const hit = parseInlineSvgStyleDeclarations(style).find((decl) => decl.key === key);
|
|
12177
|
+
return (hit == null ? void 0 : hit.value) ?? null;
|
|
12178
|
+
}
|
|
12179
|
+
function isTransparentColorToken(value) {
|
|
12180
|
+
if (!value) return false;
|
|
12181
|
+
const s = value.trim().toLowerCase();
|
|
12182
|
+
if (!s || s === "none" || s === "transparent") return true;
|
|
12183
|
+
if (/^#[0-9a-f]{8}$/i.test(s)) {
|
|
12184
|
+
return Number.parseInt(s.slice(7, 9), 16) === 0;
|
|
12185
|
+
}
|
|
12186
|
+
const rgba = s.match(/^rgba\s*\(([^)]+)\)$/i);
|
|
12187
|
+
if (rgba) {
|
|
12188
|
+
const parts = rgba[1].split(",").map((part) => part.trim());
|
|
12189
|
+
if (parts.length >= 4) {
|
|
12190
|
+
const alpha = parseSvgOpacity(parts[3]);
|
|
12191
|
+
return alpha != null && alpha <= 1e-4;
|
|
12192
|
+
}
|
|
12193
|
+
}
|
|
12194
|
+
return false;
|
|
12195
|
+
}
|
|
12196
|
+
function parseSvgOpacity(value) {
|
|
12197
|
+
if (!value) return null;
|
|
12198
|
+
const raw = value.trim();
|
|
12199
|
+
if (!raw) return null;
|
|
12200
|
+
if (raw.endsWith("%")) {
|
|
12201
|
+
const pct = Number.parseFloat(raw.slice(0, -1));
|
|
12202
|
+
if (!Number.isFinite(pct)) return null;
|
|
12203
|
+
return Math.max(0, Math.min(1, pct / 100));
|
|
12204
|
+
}
|
|
12205
|
+
const n = Number.parseFloat(raw);
|
|
12206
|
+
if (!Number.isFinite(n)) return null;
|
|
12207
|
+
return Math.max(0, Math.min(1, n));
|
|
12208
|
+
}
|
|
12209
|
+
function formatSvgOpacity(value) {
|
|
12210
|
+
return Number(Math.max(0, Math.min(1, value)).toFixed(4)).toString();
|
|
12211
|
+
}
|
|
12212
|
+
function multiplySvgOpacityAttr(el, attr, factor) {
|
|
12213
|
+
const existing = parseSvgOpacity(el.getAttribute(attr));
|
|
12214
|
+
el.setAttribute(attr, formatSvgOpacity((existing ?? 1) * factor));
|
|
12215
|
+
}
|
|
12216
|
+
function inlineSvgStyleBlockDeclarations(svg) {
|
|
12217
|
+
const styleNodes = Array.from(svg.querySelectorAll("style"));
|
|
12218
|
+
if (styleNodes.length === 0) return;
|
|
12219
|
+
const cssText = styleNodes.map((node) => node.textContent || "").join("\n").replace(/\/\*[\s\S]*?\*\//g, " ");
|
|
12220
|
+
if (!cssText.trim()) return;
|
|
12221
|
+
const allElements = [svg, ...Array.from(svg.querySelectorAll("*"))];
|
|
12222
|
+
const classIndex = /* @__PURE__ */ new Map();
|
|
12223
|
+
allElements.forEach((el) => {
|
|
12224
|
+
(el.getAttribute("class") || "").split(/\s+/).map((t) => t.trim()).filter(Boolean).forEach((token) => {
|
|
12225
|
+
const list = classIndex.get(token) ?? [];
|
|
12226
|
+
list.push(el);
|
|
12227
|
+
classIndex.set(token, list);
|
|
12228
|
+
});
|
|
12229
|
+
});
|
|
12230
|
+
const normalizePresentationValue = (key, value) => {
|
|
12231
|
+
if (["fill", "stroke", "clip-path", "mask", "filter"].includes(key)) return normalizeGradientPaintRef(value);
|
|
12232
|
+
return value;
|
|
12233
|
+
};
|
|
12234
|
+
const applyDeclarations = (elements, declarations) => {
|
|
12235
|
+
for (const el of elements) {
|
|
12236
|
+
const inlineDeclMap = new Map(
|
|
12237
|
+
parseInlineSvgStyleDeclarations(el.getAttribute("style") || "").map(({ key, value }) => [key, value])
|
|
12238
|
+
);
|
|
12239
|
+
for (const { key, value } of declarations) {
|
|
12240
|
+
if (!value || inlineDeclMap.has(key)) continue;
|
|
12241
|
+
el.setAttribute(key, normalizePresentationValue(key, value));
|
|
12242
|
+
}
|
|
12243
|
+
}
|
|
12244
|
+
};
|
|
12245
|
+
const ruleRegex = /([^{}]+)\{([^}]*)\}/g;
|
|
12246
|
+
let ruleMatch;
|
|
12247
|
+
while (ruleMatch = ruleRegex.exec(cssText)) {
|
|
12248
|
+
const selectors = ruleMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
12249
|
+
const declarations = parseInlineSvgStyleDeclarations(ruleMatch[2]).filter((d) => SVG_STYLE_PROPS.has(d.key));
|
|
12250
|
+
if (selectors.length === 0 || declarations.length === 0) continue;
|
|
12251
|
+
for (const selector of selectors) {
|
|
12252
|
+
if (!selector || selector.startsWith("@")) continue;
|
|
12253
|
+
const classOnlyMatch = selector.match(/^\.([A-Za-z_][\w-]*)$/);
|
|
12254
|
+
if (classOnlyMatch) {
|
|
12255
|
+
applyDeclarations(classIndex.get(classOnlyMatch[1]) ?? [], declarations);
|
|
12256
|
+
continue;
|
|
12257
|
+
}
|
|
12258
|
+
try {
|
|
12259
|
+
applyDeclarations(svg.querySelectorAll(selector), declarations);
|
|
12260
|
+
} catch {
|
|
12261
|
+
const classMatch = selector.match(/\.([A-Za-z0-9_-]+)/);
|
|
12262
|
+
if (classMatch) applyDeclarations(classIndex.get(classMatch[1]) ?? [], declarations);
|
|
12263
|
+
}
|
|
12264
|
+
}
|
|
12265
|
+
}
|
|
12266
|
+
for (const el of allElements) {
|
|
12267
|
+
const style = el.getAttribute("style");
|
|
12268
|
+
if (!style) continue;
|
|
12269
|
+
const keptDecls = [];
|
|
12270
|
+
let changed = false;
|
|
12271
|
+
for (const { key, value } of parseInlineSvgStyleDeclarations(style)) {
|
|
12272
|
+
if (SVG_STYLE_PROPS.has(key)) {
|
|
12273
|
+
el.setAttribute(key, normalizePresentationValue(key, value));
|
|
12274
|
+
changed = true;
|
|
12275
|
+
} else {
|
|
12276
|
+
keptDecls.push(`${key}: ${value}`);
|
|
12277
|
+
}
|
|
12278
|
+
}
|
|
12279
|
+
if (changed) {
|
|
12280
|
+
if (keptDecls.length > 0) el.setAttribute("style", keptDecls.join("; "));
|
|
12281
|
+
else el.removeAttribute("style");
|
|
12282
|
+
}
|
|
12283
|
+
}
|
|
12284
|
+
for (const styleNode of styleNodes) {
|
|
12285
|
+
const css = styleNode.textContent || "";
|
|
12286
|
+
let cleaned = css;
|
|
12287
|
+
for (const prop of SVG_STYLE_PROPS) {
|
|
12288
|
+
const regex = new RegExp(`${prop.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&")}\\s*:\\s*[^;}{]+;?`, "gi");
|
|
12289
|
+
cleaned = cleaned.replace(regex, "");
|
|
12290
|
+
}
|
|
12291
|
+
styleNode.textContent = cleaned.replace(/;\s*;/g, ";").replace(/\{\s*;/g, "{").replace(/;\s*}/g, "}").replace(/\{\s*}/g, "{}");
|
|
12292
|
+
}
|
|
12293
|
+
}
|
|
12294
|
+
function normalizeSvgExplicitColors(svg) {
|
|
12295
|
+
const clone = svg.cloneNode(true);
|
|
12296
|
+
inlineSvgStyleBlockDeclarations(clone);
|
|
12297
|
+
const getAttr = (el, attr) => {
|
|
12298
|
+
var _a;
|
|
12299
|
+
const v = el.getAttribute(attr) ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue(attr));
|
|
12300
|
+
if (!v) return null;
|
|
12301
|
+
const s = v.trim().toLowerCase();
|
|
12302
|
+
if (!s || s === "none" || s === "transparent" || s === "currentcolor") return null;
|
|
12303
|
+
return normalizeGradientPaintRef(v);
|
|
12304
|
+
};
|
|
12305
|
+
const hasExplicitNonePaint = (el, attr) => {
|
|
12306
|
+
var _a, _b;
|
|
12307
|
+
const raw = (el.getAttribute(attr) ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue(attr)) ?? "").trim().toLowerCase();
|
|
12308
|
+
if (raw === "none" || raw === "transparent") return true;
|
|
12309
|
+
const rawOpacity = (el.getAttribute(`${attr}-opacity`) ?? ((_b = el.style) == null ? void 0 : _b.getPropertyValue(`${attr}-opacity`)) ?? "").trim().toLowerCase();
|
|
12310
|
+
return rawOpacity === "0" || rawOpacity === "0%" || rawOpacity === "0.0";
|
|
12311
|
+
};
|
|
12312
|
+
function walk(el, parentFill, parentStroke, parentColor) {
|
|
12313
|
+
var _a;
|
|
12314
|
+
if (isInSvgDefinitionSubtree(el)) {
|
|
12315
|
+
for (let i = 0; i < el.children.length; i++) walk(el.children[i], null, null, null);
|
|
12316
|
+
return;
|
|
12317
|
+
}
|
|
12318
|
+
const tag = ((_a = el.tagName) == null ? void 0 : _a.toLowerCase()) ?? "";
|
|
12319
|
+
const isDrawable = SVG_DRAWABLE_TAGS.has(tag);
|
|
12320
|
+
let fill = getAttr(el, "fill");
|
|
12321
|
+
let stroke = getAttr(el, "stroke");
|
|
12322
|
+
const color = getAttr(el, "color") ?? parentColor;
|
|
12323
|
+
const fillNone = hasExplicitNonePaint(el, "fill");
|
|
12324
|
+
const strokeNone = hasExplicitNonePaint(el, "stroke");
|
|
12325
|
+
const inheritedFill = parentFill === "none" ? null : parentFill;
|
|
12326
|
+
const inheritedStroke = parentStroke === "none" ? null : parentStroke;
|
|
12327
|
+
if (isDrawable) {
|
|
12328
|
+
if (fillNone) {
|
|
12329
|
+
el.setAttribute("fill", "none");
|
|
12330
|
+
fill = null;
|
|
12331
|
+
} else {
|
|
12332
|
+
const resolved = fill ?? color ?? inheritedFill;
|
|
12333
|
+
if (resolved) {
|
|
12334
|
+
el.setAttribute("fill", resolved);
|
|
12335
|
+
fill = resolved;
|
|
12336
|
+
} else if (tag !== "text" && tag !== "tspan") {
|
|
12337
|
+
el.setAttribute("fill", "none");
|
|
12338
|
+
fill = null;
|
|
12339
|
+
}
|
|
12340
|
+
}
|
|
12341
|
+
}
|
|
12342
|
+
if (isDrawable) {
|
|
12343
|
+
if (strokeNone) {
|
|
12344
|
+
el.setAttribute("stroke", "none");
|
|
12345
|
+
stroke = null;
|
|
12346
|
+
} else if (stroke != null || color != null || inheritedStroke != null) {
|
|
12347
|
+
const resolved = stroke ?? color ?? inheritedStroke;
|
|
12348
|
+
if (resolved) {
|
|
12349
|
+
el.setAttribute("stroke", resolved);
|
|
12350
|
+
stroke = resolved;
|
|
12351
|
+
}
|
|
12352
|
+
}
|
|
12353
|
+
}
|
|
12354
|
+
const nextColor = color ?? parentColor;
|
|
12355
|
+
const nextFill = fillNone ? "none" : fill ?? inheritedFill;
|
|
12356
|
+
const nextStroke = strokeNone ? "none" : stroke ?? inheritedStroke;
|
|
12357
|
+
for (let i = 0; i < el.children.length; i++) walk(el.children[i], nextFill, nextStroke, nextColor);
|
|
12358
|
+
}
|
|
12359
|
+
const rootColor = getAttr(clone, "color") ?? (clone.getAttribute("color") || null);
|
|
12360
|
+
const rootFill = getAttr(clone, "fill") ?? rootColor;
|
|
12361
|
+
const rootStroke = getAttr(clone, "stroke") ?? rootColor;
|
|
12362
|
+
const rootFillNone = hasExplicitNonePaint(clone, "fill");
|
|
12363
|
+
const rootStrokeNone = hasExplicitNonePaint(clone, "stroke");
|
|
12364
|
+
if (rootFillNone) clone.setAttribute("fill", "none");
|
|
12365
|
+
else if (rootFill) clone.setAttribute("fill", rootFill);
|
|
12366
|
+
if (rootStrokeNone) clone.setAttribute("stroke", "none");
|
|
12367
|
+
else if (rootStroke) clone.setAttribute("stroke", rootStroke);
|
|
12368
|
+
for (let i = 0; i < clone.children.length; i++) {
|
|
12369
|
+
walk(clone.children[i], rootFillNone ? "none" : rootFill ?? null, rootStrokeNone ? "none" : rootStroke ?? null, rootColor);
|
|
12370
|
+
}
|
|
12371
|
+
return clone;
|
|
12372
|
+
}
|
|
12373
|
+
function bakeGroupOpacityIntoChildren(svg) {
|
|
12374
|
+
const DRAWABLE = /* @__PURE__ */ new Set(["path", "rect", "circle", "ellipse", "polygon", "polyline", "line", "text", "tspan"]);
|
|
12375
|
+
function walkAndBake(el, inheritedOpacity) {
|
|
12376
|
+
var _a, _b, _c;
|
|
12377
|
+
if (isInSvgDefinitionSubtree(el)) {
|
|
12378
|
+
for (let i = 0; i < el.children.length; i++) walkAndBake(el.children[i], 1);
|
|
12379
|
+
return;
|
|
12380
|
+
}
|
|
12381
|
+
const tag = ((_a = el.tagName) == null ? void 0 : _a.toLowerCase()) ?? "";
|
|
12382
|
+
const opacityAttr = parseSvgOpacity(el.getAttribute("opacity"));
|
|
12383
|
+
const styleOpacity = parseSvgOpacity(((_b = el.style) == null ? void 0 : _b.getPropertyValue("opacity")) || null);
|
|
12384
|
+
const ownOpacity = opacityAttr ?? styleOpacity ?? 1;
|
|
12385
|
+
const combinedOpacity = inheritedOpacity * ownOpacity;
|
|
12386
|
+
if (ownOpacity < 0.999) {
|
|
12387
|
+
el.removeAttribute("opacity");
|
|
12388
|
+
if ((_c = el.style) == null ? void 0 : _c.opacity) el.style.removeProperty("opacity");
|
|
12389
|
+
}
|
|
12390
|
+
if (DRAWABLE.has(tag) && combinedOpacity < 0.999) {
|
|
12391
|
+
multiplySvgOpacityAttr(el, "fill-opacity", combinedOpacity);
|
|
12392
|
+
multiplySvgOpacityAttr(el, "stroke-opacity", combinedOpacity);
|
|
12393
|
+
}
|
|
12394
|
+
if (tag === "stop" && ownOpacity < 0.999) {
|
|
12395
|
+
multiplySvgOpacityAttr(el, "stop-opacity", ownOpacity);
|
|
12396
|
+
}
|
|
12397
|
+
for (let i = 0; i < el.children.length; i++) walkAndBake(el.children[i], combinedOpacity);
|
|
12398
|
+
}
|
|
12399
|
+
walkAndBake(svg, 1);
|
|
12400
|
+
}
|
|
12401
|
+
function hasInvalidSvgNumericToken(value) {
|
|
12402
|
+
return typeof value === "string" && /\b(?:NaN|-?Infinity)\b/.test(value);
|
|
12403
|
+
}
|
|
12404
|
+
function sanitizeSvgNumericTokens(value) {
|
|
12405
|
+
return value.replace(/\bNaN\b/g, "0").replace(/\b-?Infinity\b/g, "0");
|
|
12406
|
+
}
|
|
12407
|
+
function sanitizeSvgTreeForPdf(svg) {
|
|
12408
|
+
const attrsToSanitize = [
|
|
12409
|
+
"d",
|
|
12410
|
+
"points",
|
|
12411
|
+
"transform",
|
|
12412
|
+
"gradientTransform",
|
|
12413
|
+
"patternTransform",
|
|
12414
|
+
"viewBox",
|
|
12415
|
+
"x",
|
|
12416
|
+
"y",
|
|
12417
|
+
"x1",
|
|
12418
|
+
"y1",
|
|
12419
|
+
"x2",
|
|
12420
|
+
"y2",
|
|
12421
|
+
"cx",
|
|
12422
|
+
"cy",
|
|
12423
|
+
"r",
|
|
12424
|
+
"rx",
|
|
12425
|
+
"ry",
|
|
12426
|
+
"width",
|
|
12427
|
+
"height",
|
|
12428
|
+
"dx",
|
|
12429
|
+
"dy",
|
|
12430
|
+
"opacity",
|
|
12431
|
+
"fill-opacity",
|
|
12432
|
+
"stroke-opacity",
|
|
12433
|
+
"stroke-width",
|
|
12434
|
+
"stroke-dashoffset",
|
|
12435
|
+
"font-size",
|
|
12436
|
+
"letter-spacing",
|
|
12437
|
+
"word-spacing"
|
|
12438
|
+
];
|
|
12439
|
+
const nodes = [svg, ...Array.from(svg.querySelectorAll("*"))];
|
|
12440
|
+
for (const node of nodes) {
|
|
12441
|
+
for (const attr of attrsToSanitize) {
|
|
12442
|
+
const value = node.getAttribute(attr);
|
|
12443
|
+
if (!hasInvalidSvgNumericToken(value)) continue;
|
|
12444
|
+
node.setAttribute(attr, sanitizeSvgNumericTokens(value));
|
|
12445
|
+
}
|
|
12446
|
+
}
|
|
12447
|
+
}
|
|
12448
|
+
function normalizeSvgGradientStopOffsets(svg) {
|
|
12449
|
+
for (const stop of svg.querySelectorAll("linearGradient stop, radialGradient stop")) {
|
|
12450
|
+
const offset = stop.getAttribute("offset");
|
|
12451
|
+
if (!offset) continue;
|
|
12452
|
+
const trimmed = offset.trim();
|
|
12453
|
+
if (trimmed.endsWith("%")) {
|
|
12454
|
+
const num = parseFloat(trimmed.slice(0, -1)) / 100;
|
|
12455
|
+
if (Number.isFinite(num)) stop.setAttribute("offset", String(Math.max(0, Math.min(1, num))));
|
|
12456
|
+
}
|
|
12457
|
+
}
|
|
12458
|
+
}
|
|
12459
|
+
function copyGradientAttrsFromRef(gradient, ref) {
|
|
12460
|
+
var _a;
|
|
12461
|
+
const tag = (_a = gradient.tagName) == null ? void 0 : _a.toLowerCase();
|
|
12462
|
+
const attrs = tag === "radialgradient" ? GRADIENT_ATTRS_RADIAL : GRADIENT_ATTRS_LINEAR;
|
|
12463
|
+
for (const name of attrs) {
|
|
12464
|
+
if (!gradient.hasAttribute(name) && ref.hasAttribute(name)) {
|
|
12465
|
+
gradient.setAttribute(name, ref.getAttribute(name));
|
|
12466
|
+
}
|
|
12467
|
+
}
|
|
12468
|
+
}
|
|
12469
|
+
function expandSvgGradientHrefs(svg) {
|
|
12470
|
+
const visited = /* @__PURE__ */ new Set();
|
|
12471
|
+
function expand(gradient) {
|
|
12472
|
+
const id = gradient.getAttribute("id");
|
|
12473
|
+
if (!id || visited.has(id)) return;
|
|
12474
|
+
visited.add(id);
|
|
12475
|
+
if (gradient.querySelectorAll("stop").length > 0) return;
|
|
12476
|
+
const href = (gradient.getAttribute("href") || gradient.getAttribute("xlink:href") || "").trim();
|
|
12477
|
+
if (!href.startsWith("#")) return;
|
|
12478
|
+
const ref = findGradientInTree(svg, href.slice(1));
|
|
12479
|
+
if (!ref) return;
|
|
12480
|
+
expand(ref);
|
|
12481
|
+
copyGradientAttrsFromRef(gradient, ref);
|
|
12482
|
+
for (const stop of ref.querySelectorAll("stop")) gradient.appendChild(stop.cloneNode(true));
|
|
12483
|
+
gradient.removeAttribute("href");
|
|
12484
|
+
gradient.removeAttribute("xlink:href");
|
|
12485
|
+
}
|
|
12486
|
+
for (const g of svg.querySelectorAll("linearGradient, radialGradient")) expand(g);
|
|
12487
|
+
}
|
|
12488
|
+
function expandSvgUseElements(svg) {
|
|
12489
|
+
var _a;
|
|
12490
|
+
const doc = svg.ownerDocument;
|
|
12491
|
+
for (const use of Array.from(svg.querySelectorAll("use"))) {
|
|
12492
|
+
const ref = (use.getAttribute("href") || use.getAttribute("xlink:href") || "").trim();
|
|
12493
|
+
if (!ref.startsWith("#")) continue;
|
|
12494
|
+
const target = doc.getElementById(ref.slice(1));
|
|
12495
|
+
if (!target) continue;
|
|
12496
|
+
const x = parseFloat(use.getAttribute("x") || "0") || 0;
|
|
12497
|
+
const y = parseFloat(use.getAttribute("y") || "0") || 0;
|
|
12498
|
+
const w = parseFloat(use.getAttribute("width") || "0") || 0;
|
|
12499
|
+
const h = parseFloat(use.getAttribute("height") || "0") || 0;
|
|
12500
|
+
const g = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
12501
|
+
if (((_a = target.tagName) == null ? void 0 : _a.toLowerCase()) === "symbol") {
|
|
12502
|
+
const viewBox = target.getAttribute("viewBox");
|
|
12503
|
+
for (let i = 0; i < target.children.length; i++) g.appendChild(target.children[i].cloneNode(true));
|
|
12504
|
+
if (viewBox && w && h) {
|
|
12505
|
+
const parts = viewBox.split(/\s+/).map(Number);
|
|
12506
|
+
const vbW = parts[2];
|
|
12507
|
+
const vbH = parts[3];
|
|
12508
|
+
if (vbW && vbH) g.setAttribute("transform", `translate(${x},${y}) scale(${w / vbW},${h / vbH})`);
|
|
12509
|
+
else g.setAttribute("transform", `translate(${x},${y})`);
|
|
12510
|
+
} else if (x || y) g.setAttribute("transform", `translate(${x},${y})`);
|
|
12511
|
+
} else {
|
|
12512
|
+
const clone = target.cloneNode(true);
|
|
12513
|
+
if (x || y) g.setAttribute("transform", `translate(${x},${y})`);
|
|
12514
|
+
g.appendChild(clone);
|
|
12515
|
+
}
|
|
12516
|
+
if (use.parentNode) use.parentNode.replaceChild(g, use);
|
|
12517
|
+
}
|
|
12518
|
+
}
|
|
12519
|
+
function normalizeSvgViewBoxOrigin(svg) {
|
|
12520
|
+
const viewBox = svg.getAttribute("viewBox");
|
|
12521
|
+
if (!viewBox) return;
|
|
12522
|
+
const parts = viewBox.split(/[\s,]+/).map(Number.parseFloat).filter(Number.isFinite);
|
|
12523
|
+
if (parts.length !== 4) return;
|
|
12524
|
+
const [vx, vy, vw, vh] = parts;
|
|
12525
|
+
if (vw <= 0 || vh <= 0) return;
|
|
12526
|
+
if (Math.abs(vx) < 1e-3 && Math.abs(vy) < 1e-3) return;
|
|
12527
|
+
const doc = svg.ownerDocument;
|
|
12528
|
+
if (!doc) return;
|
|
12529
|
+
const keepAtRoot = /* @__PURE__ */ new Set(["defs", "style", "title", "desc", "metadata"]);
|
|
12530
|
+
const translatableChildren = Array.from(svg.children).filter((c) => !keepAtRoot.has(c.tagName.toLowerCase()));
|
|
12531
|
+
if (translatableChildren.length === 0) {
|
|
12532
|
+
svg.setAttribute("viewBox", `0 0 ${vw} ${vh}`);
|
|
12533
|
+
return;
|
|
12534
|
+
}
|
|
12535
|
+
const wrapper = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
12536
|
+
wrapper.setAttribute("transform", `translate(${-vx} ${-vy})`);
|
|
12537
|
+
for (const child of translatableChildren) wrapper.appendChild(child);
|
|
12538
|
+
svg.appendChild(wrapper);
|
|
12539
|
+
svg.setAttribute("viewBox", `0 0 ${vw} ${vh}`);
|
|
12540
|
+
}
|
|
12541
|
+
function stripRootPageBackgroundFromSvg(svg) {
|
|
12542
|
+
for (const child of Array.from(svg.children)) {
|
|
12543
|
+
const tag = child.tagName.toLowerCase();
|
|
12544
|
+
if (tag !== "rect" && tag !== "path") continue;
|
|
12545
|
+
const x = Number.parseFloat(child.getAttribute("x") || "0");
|
|
12546
|
+
const y = Number.parseFloat(child.getAttribute("y") || "0");
|
|
12547
|
+
const width = Number.parseFloat(child.getAttribute("width") || "0");
|
|
12548
|
+
const height = Number.parseFloat(child.getAttribute("height") || "0");
|
|
12549
|
+
const fill = child.getAttribute("fill") || getInlineStyleValue(child, "fill");
|
|
12550
|
+
const stroke = child.getAttribute("stroke") || getInlineStyleValue(child, "stroke");
|
|
12551
|
+
const opacity = parseSvgOpacity(child.getAttribute("opacity")) ?? 1;
|
|
12552
|
+
const isFullPageRect = tag === "rect" && Math.abs(x) < 0.01 && Math.abs(y) < 0.01 && Math.abs(width - Number.parseFloat(svg.getAttribute("width") || "0")) < 0.5 && Math.abs(height - Number.parseFloat(svg.getAttribute("height") || "0")) < 0.5;
|
|
12553
|
+
const isVisiblePaint = opacity > 1e-4 && !isTransparentColorToken(fill) && (!stroke || isTransparentColorToken(stroke));
|
|
12554
|
+
if (isFullPageRect && isVisiblePaint) {
|
|
12555
|
+
child.remove();
|
|
12556
|
+
return;
|
|
12557
|
+
}
|
|
12558
|
+
}
|
|
12559
|
+
}
|
|
12560
|
+
function stripSuspiciousFullPageOverlayNodes(svg) {
|
|
12561
|
+
const pageWidth = Number.parseFloat(svg.getAttribute("width") || "0");
|
|
12562
|
+
const pageHeight = Number.parseFloat(svg.getAttribute("height") || "0");
|
|
12563
|
+
if (!(pageWidth > 0 && pageHeight > 0)) return;
|
|
12564
|
+
const isNear = (a, b, tolerance = 0.75) => Math.abs(a - b) <= tolerance;
|
|
12565
|
+
const isDarkPaint = (value) => {
|
|
12566
|
+
const rgb = value ? parseColor(value) : null;
|
|
12567
|
+
return rgb ? rgb.r <= 32 && rgb.g <= 32 && rgb.b <= 32 : false;
|
|
12568
|
+
};
|
|
12569
|
+
const removeIfSuspicious = (el) => {
|
|
12570
|
+
const opacity = parseSvgOpacity(el.getAttribute("opacity")) ?? parseSvgOpacity(getInlineStyleValue(el, "opacity")) ?? 1;
|
|
12571
|
+
if (opacity <= 1e-3) return;
|
|
12572
|
+
const fill = el.getAttribute("fill") || getInlineStyleValue(el, "fill");
|
|
12573
|
+
const stroke = el.getAttribute("stroke") || getInlineStyleValue(el, "stroke");
|
|
12574
|
+
if (!isDarkPaint(fill) && !isDarkPaint(stroke)) return;
|
|
12575
|
+
const w = Number.parseFloat(el.getAttribute("width") || "0");
|
|
12576
|
+
const h = Number.parseFloat(el.getAttribute("height") || "0");
|
|
12577
|
+
const x = Number.parseFloat(el.getAttribute("x") || "0");
|
|
12578
|
+
const y = Number.parseFloat(el.getAttribute("y") || "0");
|
|
12579
|
+
const isRectLike = el.tagName.toLowerCase() === "rect" && isNear(x, 0) && isNear(y, 0) && isNear(w, pageWidth, 1.5) && isNear(h, pageHeight, 1.5);
|
|
12580
|
+
if (isRectLike) el.remove();
|
|
12581
|
+
};
|
|
12582
|
+
for (const child of Array.from(svg.children)) {
|
|
12583
|
+
const tag = child.tagName.toLowerCase();
|
|
12584
|
+
if (["defs", "style", "title", "desc", "metadata"].includes(tag)) continue;
|
|
12585
|
+
if (tag === "g") {
|
|
12586
|
+
for (const gc of Array.from(child.children)) removeIfSuspicious(gc);
|
|
12587
|
+
}
|
|
12588
|
+
removeIfSuspicious(child);
|
|
12589
|
+
}
|
|
12590
|
+
}
|
|
12591
|
+
function decodeSvgDataUri(href) {
|
|
12592
|
+
if (!href.startsWith("data:image/svg+xml")) return null;
|
|
12593
|
+
const commaIdx = href.indexOf(",");
|
|
12594
|
+
if (commaIdx < 0) return null;
|
|
12595
|
+
const meta = href.slice(0, commaIdx).toLowerCase();
|
|
12596
|
+
const payload = href.slice(commaIdx + 1);
|
|
12597
|
+
try {
|
|
12598
|
+
if (meta.includes(";base64")) {
|
|
12599
|
+
const binary = atob(payload);
|
|
12600
|
+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
12601
|
+
return new TextDecoder("utf-8").decode(bytes);
|
|
12602
|
+
}
|
|
12603
|
+
return decodeURIComponent(payload);
|
|
12604
|
+
} catch {
|
|
12605
|
+
try {
|
|
12606
|
+
return atob(payload);
|
|
12607
|
+
} catch {
|
|
12608
|
+
return null;
|
|
12609
|
+
}
|
|
12610
|
+
}
|
|
12611
|
+
}
|
|
12612
|
+
function inlineNestedSvgImageDataUris(svgString, domParser = new DOMParser()) {
|
|
12613
|
+
var _a;
|
|
12614
|
+
try {
|
|
12615
|
+
const doc = domParser.parseFromString(svgString, "image/svg+xml");
|
|
12616
|
+
if (doc.querySelector("parsererror")) return svgString;
|
|
12617
|
+
const root = doc.documentElement;
|
|
12618
|
+
if (!root || root.tagName.toLowerCase() !== "svg") return svgString;
|
|
12619
|
+
let changed = false;
|
|
12620
|
+
for (const img of Array.from(doc.querySelectorAll("image"))) {
|
|
12621
|
+
const href = img.getAttribute("href") || img.getAttributeNS("http://www.w3.org/1999/xlink", "href");
|
|
12622
|
+
if (!href || !href.startsWith("data:image/svg+xml")) continue;
|
|
12623
|
+
try {
|
|
12624
|
+
const svgContent = decodeSvgDataUri(href);
|
|
12625
|
+
if (!svgContent || !/<svg[\s>]/i.test(svgContent)) continue;
|
|
12626
|
+
const innerDoc = domParser.parseFromString(svgContent, "image/svg+xml");
|
|
12627
|
+
if (innerDoc.querySelector("parsererror")) continue;
|
|
12628
|
+
const innerSvg = innerDoc.documentElement;
|
|
12629
|
+
if (!innerSvg || innerSvg.tagName.toLowerCase() !== "svg") continue;
|
|
12630
|
+
const ix = parseFloat(img.getAttribute("x") || "0") || 0;
|
|
12631
|
+
const iy = parseFloat(img.getAttribute("y") || "0") || 0;
|
|
12632
|
+
const iw = parseFloat(img.getAttribute("width") || "0");
|
|
12633
|
+
const ih = parseFloat(img.getAttribute("height") || "0");
|
|
12634
|
+
if (!(iw > 0 && ih > 0)) continue;
|
|
12635
|
+
const nestedSvg = doc.importNode(innerSvg, true);
|
|
12636
|
+
if (!nestedSvg.getAttribute("viewBox")) nestedSvg.setAttribute("viewBox", `0 0 ${iw} ${ih}`);
|
|
12637
|
+
nestedSvg.setAttribute("x", "0");
|
|
12638
|
+
nestedSvg.setAttribute("y", "0");
|
|
12639
|
+
nestedSvg.setAttribute("width", String(iw));
|
|
12640
|
+
nestedSvg.setAttribute("height", String(ih));
|
|
12641
|
+
nestedSvg.setAttribute("preserveAspectRatio", img.getAttribute("preserveAspectRatio") || nestedSvg.getAttribute("preserveAspectRatio") || "xMidYMid meet");
|
|
12642
|
+
const g = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
12643
|
+
const existingTransform = img.getAttribute("transform") || "";
|
|
12644
|
+
g.setAttribute("transform", `${existingTransform}${existingTransform ? " " : ""}translate(${ix},${iy})`);
|
|
12645
|
+
for (const attr of Array.from(img.attributes)) {
|
|
12646
|
+
if (["id", "class", "style", "opacity", "display", "visibility", "clip-path", "mask", "filter", "pointer-events"].includes(attr.name)) {
|
|
12647
|
+
g.setAttribute(attr.name, attr.value);
|
|
12648
|
+
}
|
|
12649
|
+
}
|
|
12650
|
+
g.appendChild(nestedSvg);
|
|
12651
|
+
(_a = img.parentNode) == null ? void 0 : _a.replaceChild(g, img);
|
|
12652
|
+
changed = true;
|
|
12653
|
+
} catch {
|
|
12654
|
+
}
|
|
12655
|
+
}
|
|
12656
|
+
return changed ? new XMLSerializer().serializeToString(doc.documentElement) : svgString;
|
|
12657
|
+
} catch {
|
|
12658
|
+
return svgString;
|
|
12659
|
+
}
|
|
12660
|
+
}
|
|
12661
|
+
function inlineComputedStyles(svg) {
|
|
12662
|
+
if (typeof document === "undefined") return;
|
|
12663
|
+
const wrap = document.createElement("div");
|
|
12664
|
+
wrap.style.cssText = "position:fixed;left:-9999px;top:0;width:400px;height:400px;overflow:hidden;pointer-events:none";
|
|
12665
|
+
const root = svg;
|
|
12666
|
+
if (!root.hasAttribute("width")) root.setAttribute("width", "400");
|
|
12667
|
+
if (!root.hasAttribute("height")) root.setAttribute("height", "400");
|
|
12668
|
+
wrap.appendChild(root);
|
|
12669
|
+
document.body.appendChild(wrap);
|
|
12670
|
+
try {
|
|
12671
|
+
let walk = function(el) {
|
|
12672
|
+
var _a;
|
|
12673
|
+
const tag = (_a = el.tagName) == null ? void 0 : _a.toLowerCase();
|
|
12674
|
+
if (drawableTags.includes(tag)) {
|
|
12675
|
+
const cs = window.getComputedStyle(el);
|
|
12676
|
+
const fill = cs.fill;
|
|
12677
|
+
const stroke = cs.stroke;
|
|
12678
|
+
if (fill && fill !== "none" && fill !== "rgba(0, 0, 0, 0)") {
|
|
12679
|
+
const parsed = parseColor(fill);
|
|
12680
|
+
if (parsed) el.setAttribute("fill", rgbToHex(parsed.r, parsed.g, parsed.b));
|
|
12681
|
+
} else if (fill === "rgba(0, 0, 0, 0)" || fill === "transparent") {
|
|
12682
|
+
el.setAttribute("fill", "none");
|
|
12683
|
+
}
|
|
12684
|
+
if (stroke && stroke !== "none" && stroke !== "rgba(0, 0, 0, 0)") {
|
|
12685
|
+
const parsed = parseColor(stroke);
|
|
12686
|
+
if (parsed) el.setAttribute("stroke", rgbToHex(parsed.r, parsed.g, parsed.b));
|
|
12687
|
+
}
|
|
12688
|
+
}
|
|
12689
|
+
for (let i = 0; i < el.children.length; i++) walk(el.children[i]);
|
|
12690
|
+
};
|
|
12691
|
+
const drawableTags = ["path", "rect", "circle", "ellipse", "polygon", "polyline", "line", "text", "tspan"];
|
|
12692
|
+
walk(root);
|
|
12693
|
+
root.remove();
|
|
12694
|
+
} finally {
|
|
12695
|
+
if (wrap.parentNode) document.body.removeChild(wrap);
|
|
12696
|
+
}
|
|
12697
|
+
}
|
|
12698
|
+
function prefixSvgIds(svg, prefix) {
|
|
12699
|
+
const safePrefix = String(prefix).replace(/[^a-zA-Z0-9-]/g, "_");
|
|
12700
|
+
const idMap = /* @__PURE__ */ new Map();
|
|
12701
|
+
svg.querySelectorAll("[id]").forEach((el) => {
|
|
12702
|
+
const id = el.getAttribute("id");
|
|
12703
|
+
if (id) idMap.set(id, `${safePrefix}_${id}`);
|
|
12704
|
+
});
|
|
12705
|
+
if (idMap.size === 0) return;
|
|
12706
|
+
idMap.forEach((newId, oldId) => {
|
|
12707
|
+
svg.querySelectorAll(`[id="${oldId}"]`).forEach((el) => el.setAttribute("id", newId));
|
|
12708
|
+
});
|
|
12709
|
+
const replaceUrlRefs = (value) => {
|
|
12710
|
+
return value.replace(/url\(\s*(['"]?)([^)]+?)\1\s*\)/gi, (full, quoteRaw, refRaw) => {
|
|
12711
|
+
const ref = String(refRaw || "").trim();
|
|
12712
|
+
const hashIdx = ref.lastIndexOf("#");
|
|
12713
|
+
if (hashIdx < 0 || hashIdx === ref.length - 1) return full;
|
|
12714
|
+
const base = ref.slice(0, hashIdx + 1);
|
|
12715
|
+
const oldId = ref.slice(hashIdx + 1).trim().replace(/[\s"')].*$/, "");
|
|
12716
|
+
const mapped = idMap.get(oldId);
|
|
12717
|
+
if (!mapped) return full;
|
|
12718
|
+
const quote = String(quoteRaw || "");
|
|
12719
|
+
return `url(${quote}${base}${mapped}${quote})`;
|
|
12720
|
+
});
|
|
12721
|
+
};
|
|
12722
|
+
const replaceHrefRef = (value) => {
|
|
12723
|
+
const trimmed = value.trim();
|
|
12724
|
+
if (trimmed.startsWith("#")) {
|
|
12725
|
+
const mapped = idMap.get(trimmed.slice(1));
|
|
12726
|
+
return mapped ? `#${mapped}` : value;
|
|
12727
|
+
}
|
|
12728
|
+
return replaceUrlRefs(value);
|
|
12729
|
+
};
|
|
12730
|
+
const refAttrs = ["fill", "stroke", "clip-path", "mask", "filter", "href", "xlink:href", "marker-start", "marker-mid", "marker-end"];
|
|
12731
|
+
svg.querySelectorAll("*").forEach((el) => {
|
|
12732
|
+
refAttrs.forEach((attr) => {
|
|
12733
|
+
const val = el.getAttribute(attr);
|
|
12734
|
+
if (!val) return;
|
|
12735
|
+
const next = attr === "href" || attr === "xlink:href" ? replaceHrefRef(val) : replaceUrlRefs(val);
|
|
12736
|
+
if (next !== val) el.setAttribute(attr, next);
|
|
12737
|
+
});
|
|
12738
|
+
const style = el.getAttribute("style");
|
|
12739
|
+
if (style) {
|
|
12740
|
+
const nextStyle = replaceUrlRefs(style);
|
|
12741
|
+
if (nextStyle !== style) el.setAttribute("style", nextStyle);
|
|
12742
|
+
}
|
|
12743
|
+
});
|
|
12744
|
+
svg.querySelectorAll("style").forEach((styleNode) => {
|
|
12745
|
+
const text = styleNode.textContent || "";
|
|
12746
|
+
const next = replaceUrlRefs(text);
|
|
12747
|
+
if (next !== text) styleNode.textContent = next;
|
|
12748
|
+
});
|
|
12749
|
+
}
|
|
12750
|
+
function getFirstExplicitColorFromSvg(svg) {
|
|
12751
|
+
let fill = null;
|
|
12752
|
+
let stroke = null;
|
|
12753
|
+
const isRealColor = (v) => {
|
|
12754
|
+
if (!v || v === "none") return false;
|
|
12755
|
+
const s = v.trim().toLowerCase();
|
|
12756
|
+
return s !== "currentcolor" && s !== "inherit" && (s.startsWith("#") || s.startsWith("rgb"));
|
|
12757
|
+
};
|
|
12758
|
+
const resolveUrl = (v) => {
|
|
12759
|
+
if (!v || v === "none") return null;
|
|
12760
|
+
const gradientId = extractGradientIdFromPaint(v);
|
|
12761
|
+
if (!gradientId) return null;
|
|
12762
|
+
return getGradientStopColorAsHex(svg, gradientId);
|
|
12763
|
+
};
|
|
12764
|
+
function walk(el) {
|
|
12765
|
+
var _a, _b;
|
|
12766
|
+
if (fill && stroke) return;
|
|
12767
|
+
const f = el.getAttribute("fill") ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue("fill"));
|
|
12768
|
+
const s = el.getAttribute("stroke") ?? ((_b = el.style) == null ? void 0 : _b.getPropertyValue("stroke"));
|
|
12769
|
+
if (!fill) {
|
|
12770
|
+
if (isRealColor(f)) fill = f;
|
|
12771
|
+
else if (f) {
|
|
12772
|
+
const resolved = resolveUrl(f);
|
|
12773
|
+
if (resolved) fill = resolved;
|
|
12774
|
+
}
|
|
12775
|
+
}
|
|
12776
|
+
if (!stroke) {
|
|
12777
|
+
if (isRealColor(s)) stroke = s;
|
|
12778
|
+
else if (s) {
|
|
12779
|
+
const resolved = resolveUrl(s);
|
|
12780
|
+
if (resolved) stroke = resolved;
|
|
12781
|
+
}
|
|
12782
|
+
}
|
|
12783
|
+
for (let i = 0; i < el.children.length; i++) walk(el.children[i]);
|
|
12784
|
+
}
|
|
12785
|
+
walk(svg);
|
|
12786
|
+
return { fill, stroke };
|
|
12787
|
+
}
|
|
12788
|
+
function isNearWhite(hex) {
|
|
12789
|
+
if (!/^#[0-9a-f]{6}$/i.test(hex)) return false;
|
|
12790
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
12791
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
12792
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
12793
|
+
return r >= 250 && g >= 250 && b >= 250;
|
|
12794
|
+
}
|
|
12795
|
+
function getStopColorRaw(stop) {
|
|
12796
|
+
var _a, _b;
|
|
12797
|
+
return stop.getAttribute("stop-color") ?? ((_b = (_a = stop.style) == null ? void 0 : _a.getPropertyValue("stop-color")) == null ? void 0 : _b.trim()) ?? getInlineStyleValue(stop, "stop-color");
|
|
12798
|
+
}
|
|
12799
|
+
function getGradientStopColorAsHex(svgRoot, gradientId, visited = /* @__PURE__ */ new Set()) {
|
|
12800
|
+
var _a;
|
|
12801
|
+
if (visited.has(gradientId)) return null;
|
|
12802
|
+
visited.add(gradientId);
|
|
12803
|
+
const gradient = findGradientInTree(svgRoot, gradientId);
|
|
12804
|
+
if (!gradient) return null;
|
|
12805
|
+
const tag = (_a = gradient.tagName) == null ? void 0 : _a.toLowerCase();
|
|
12806
|
+
if (tag !== "lineargradient" && tag !== "radialgradient") return null;
|
|
12807
|
+
const stops = Array.from(gradient.querySelectorAll("stop"));
|
|
12808
|
+
if (stops.length > 0) {
|
|
12809
|
+
const first = getStopColorRaw(stops[0]);
|
|
12810
|
+
const last = getStopColorRaw(stops[stops.length - 1]);
|
|
12811
|
+
const firstHex = first ? cssColorToHex(first) : null;
|
|
12812
|
+
const lastHex = last ? cssColorToHex(last) : null;
|
|
12813
|
+
if (firstHex && !isNearWhite(firstHex)) return firstHex;
|
|
12814
|
+
if (lastHex && !isNearWhite(lastHex)) return lastHex;
|
|
12815
|
+
return firstHex ?? lastHex;
|
|
12816
|
+
}
|
|
12817
|
+
const href = (gradient.getAttribute("href") || gradient.getAttribute("xlink:href") || "").trim();
|
|
12818
|
+
if (href.startsWith("#")) return getGradientStopColorAsHex(svgRoot, href.slice(1), visited);
|
|
12819
|
+
return null;
|
|
12820
|
+
}
|
|
12821
|
+
function setPdfColorFromSvg(pdf, svg, _elementId) {
|
|
12822
|
+
const { fill, stroke } = getFirstExplicitColorFromSvg(svg);
|
|
12823
|
+
const setColor = (hex, setter) => {
|
|
12824
|
+
if (!hex) return;
|
|
12825
|
+
const c = parseColor(hex);
|
|
12826
|
+
if (c) pdf[setter](c.r, c.g, c.b);
|
|
12827
|
+
};
|
|
12828
|
+
setColor(fill, "setFillColor");
|
|
12829
|
+
setColor(stroke ?? fill, "setDrawColor");
|
|
12830
|
+
}
|
|
12831
|
+
function svg2pdfOpts(x, y, width, height) {
|
|
12832
|
+
const sanitize = (value, fallback) => Number.isFinite(value) ? Number(value.toFixed(3)) : fallback;
|
|
12833
|
+
const w = Math.max(1e-3, sanitize(width, 1));
|
|
12834
|
+
const h = Math.max(1e-3, sanitize(height, 1));
|
|
12835
|
+
return { x: sanitize(x, 0), y: sanitize(y, 0), width: w, height: h };
|
|
12836
|
+
}
|
|
12837
|
+
async function svg2pdfWithDomMount(svg, pdf, opts) {
|
|
12838
|
+
const wrap = document.createElement("div");
|
|
12839
|
+
wrap.style.cssText = "position:fixed;left:-9999px;top:0;width:0;height:0;overflow:hidden;pointer-events:none;opacity:0";
|
|
12840
|
+
wrap.appendChild(svg);
|
|
12841
|
+
document.body.appendChild(wrap);
|
|
12842
|
+
try {
|
|
12843
|
+
await svg2pdf(svg, pdf, opts);
|
|
12844
|
+
} finally {
|
|
12845
|
+
svg.remove();
|
|
12846
|
+
if (wrap.parentNode) document.body.removeChild(wrap);
|
|
12847
|
+
}
|
|
12848
|
+
}
|
|
12849
|
+
function convertTextDecorationsToLines(svg) {
|
|
12850
|
+
const doc = svg.ownerDocument;
|
|
12851
|
+
if (!doc) return;
|
|
12852
|
+
let measureCanvas = null;
|
|
12853
|
+
let ctx = null;
|
|
12854
|
+
try {
|
|
12855
|
+
measureCanvas = doc.createElement("canvas");
|
|
12856
|
+
ctx = measureCanvas.getContext("2d");
|
|
12857
|
+
} catch {
|
|
12858
|
+
}
|
|
12859
|
+
const textEls = Array.from(svg.querySelectorAll("text"));
|
|
12860
|
+
for (const textEl of textEls) {
|
|
12861
|
+
const tspans = Array.from(textEl.querySelectorAll("tspan"));
|
|
12862
|
+
if (tspans.length === 0) continue;
|
|
12863
|
+
const textDecOnText = (textEl.getAttribute("text-decoration") || "").toLowerCase();
|
|
12864
|
+
const textStyleDec = (getInlineStyleValue(textEl, "text-decoration") || "").toLowerCase();
|
|
12865
|
+
const textHasUnderline = textDecOnText.includes("underline") || textStyleDec.includes("underline");
|
|
12866
|
+
for (const tspan of tspans) {
|
|
12867
|
+
const tspanDec = (tspan.getAttribute("text-decoration") || "").toLowerCase();
|
|
12868
|
+
const tspanStyleDec = (getInlineStyleValue(tspan, "text-decoration") || "").toLowerCase();
|
|
12869
|
+
const hasUnderline = tspanDec.includes("underline") || tspanStyleDec.includes("underline") || textHasUnderline;
|
|
12870
|
+
if (!hasUnderline) continue;
|
|
12871
|
+
const content = tspan.textContent || "";
|
|
12872
|
+
if (!content.trim()) continue;
|
|
12873
|
+
const xAttr = tspan.getAttribute("x") ?? textEl.getAttribute("x") ?? "0";
|
|
12874
|
+
const yAttr = tspan.getAttribute("y") ?? textEl.getAttribute("y") ?? "0";
|
|
12875
|
+
const x = parseFloat(xAttr) || 0;
|
|
12876
|
+
const y = parseFloat(yAttr) || 0;
|
|
12877
|
+
const fontSize = parseFloat(
|
|
12878
|
+
tspan.getAttribute("font-size") || textEl.getAttribute("font-size") || "16"
|
|
12879
|
+
);
|
|
12880
|
+
const fontFamily = tspan.getAttribute("font-family") || textEl.getAttribute("font-family") || "sans-serif";
|
|
12881
|
+
const fontWeight = tspan.getAttribute("font-weight") || textEl.getAttribute("font-weight") || "normal";
|
|
12882
|
+
const fill = tspan.getAttribute("fill") || textEl.getAttribute("fill") || "#000000";
|
|
12883
|
+
let textWidth;
|
|
12884
|
+
if (ctx) {
|
|
12885
|
+
ctx.font = `${fontWeight} ${fontSize}px ${fontFamily.replace(/'/g, "")}`;
|
|
12886
|
+
textWidth = ctx.measureText(content).width;
|
|
12887
|
+
} else {
|
|
12888
|
+
textWidth = content.length * fontSize * 0.6;
|
|
12889
|
+
}
|
|
12890
|
+
const underlineY = y + fontSize * 0.15;
|
|
12891
|
+
const thickness = Math.max(0.5, fontSize * 0.066667);
|
|
12892
|
+
const line = doc.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
12893
|
+
line.setAttribute("x1", String(x));
|
|
12894
|
+
line.setAttribute("y1", String(underlineY));
|
|
12895
|
+
line.setAttribute("x2", String(x + textWidth));
|
|
12896
|
+
line.setAttribute("y2", String(underlineY));
|
|
12897
|
+
line.setAttribute("stroke", fill.startsWith("url(") ? "#000000" : fill);
|
|
12898
|
+
line.setAttribute("stroke-width", String(thickness));
|
|
12899
|
+
line.setAttribute("fill", "none");
|
|
12900
|
+
if (textEl.parentElement) {
|
|
12901
|
+
textEl.parentElement.insertBefore(line, textEl.nextSibling);
|
|
12902
|
+
}
|
|
12903
|
+
}
|
|
12904
|
+
}
|
|
12905
|
+
}
|
|
12906
|
+
function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey, options) {
|
|
12907
|
+
try {
|
|
12908
|
+
const parser = new DOMParser();
|
|
12909
|
+
const processedSvg = inlineNestedSvgImageDataUris(rawSvg, parser);
|
|
12910
|
+
const doc = parser.parseFromString(processedSvg, "image/svg+xml");
|
|
12911
|
+
if (doc.querySelector("parsererror")) return null;
|
|
12912
|
+
const svg = doc.documentElement;
|
|
12913
|
+
if (!svg || svg.tagName.toLowerCase() !== "svg") return null;
|
|
12914
|
+
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
12915
|
+
if (/xlink:href/i.test(processedSvg) && !svg.getAttribute("xmlns:xlink")) {
|
|
12916
|
+
svg.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
|
|
12917
|
+
}
|
|
12918
|
+
svg.setAttribute("width", String(pageWidth));
|
|
12919
|
+
svg.setAttribute("height", String(pageHeight));
|
|
12920
|
+
svg.setAttribute("viewBox", `0 0 ${pageWidth} ${pageHeight}`);
|
|
12921
|
+
sanitizeSvgTreeForPdf(svg);
|
|
12922
|
+
normalizeSvgViewBoxOrigin(svg);
|
|
12923
|
+
expandSvgUseElements(svg);
|
|
12924
|
+
const svgToDraw = normalizeSvgExplicitColors(svg);
|
|
12925
|
+
inlineComputedStyles(svgToDraw);
|
|
12926
|
+
sanitizeSvgTreeForPdf(svgToDraw);
|
|
12927
|
+
normalizeSvgGradientStopOffsets(svgToDraw);
|
|
12928
|
+
expandSvgGradientHrefs(svgToDraw);
|
|
12929
|
+
prefixSvgIds(svgToDraw, pageKey);
|
|
12930
|
+
bakeGroupOpacityIntoChildren(svgToDraw);
|
|
12931
|
+
stripSuspiciousFullPageOverlayNodes(svgToDraw);
|
|
12932
|
+
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
12933
|
+
sanitizeSvgTreeForPdf(svgToDraw);
|
|
12934
|
+
convertTextDecorationsToLines(svgToDraw);
|
|
12935
|
+
return svgToDraw;
|
|
12936
|
+
} catch {
|
|
12937
|
+
return null;
|
|
12938
|
+
}
|
|
12939
|
+
}
|
|
12940
|
+
function drawPageBackground(pdf, pageIndex, pageWidth, pageHeight, backgroundColor, backgroundGradient) {
|
|
12941
|
+
var _a, _b;
|
|
12942
|
+
if (backgroundGradient && ((_a = backgroundGradient.stops) == null ? void 0 : _a.length) >= 2) {
|
|
12943
|
+
const grad = backgroundGradient;
|
|
12944
|
+
const colorStops = grad.stops.map((s) => {
|
|
12945
|
+
const c = parseColor(s.color);
|
|
12946
|
+
return {
|
|
12947
|
+
offset: Math.max(0, Math.min(1, Number(s.offset))),
|
|
12948
|
+
color: c ? [c.r, c.g, c.b] : [0, 0, 0]
|
|
12949
|
+
};
|
|
12950
|
+
}).filter((s) => Number.isFinite(s.offset)).sort((a, b) => a.offset - b.offset);
|
|
12951
|
+
const normalizedStops = [...colorStops];
|
|
12952
|
+
if (normalizedStops.length > 0) {
|
|
12953
|
+
if (normalizedStops[0].offset > 0) normalizedStops.unshift({ offset: 0, color: normalizedStops[0].color });
|
|
12954
|
+
if (normalizedStops[normalizedStops.length - 1].offset < 1) normalizedStops.push({ offset: 1, color: normalizedStops[normalizedStops.length - 1].color });
|
|
12955
|
+
}
|
|
12956
|
+
const shadingColors = normalizedStops.map((s) => ({ offset: s.offset, color: s.color }));
|
|
12957
|
+
const patternKey = `bg-grad-${pageIndex}`;
|
|
12958
|
+
try {
|
|
12959
|
+
pdf.advancedAPI((doc) => {
|
|
12960
|
+
const isLinear = grad.type === "linear";
|
|
12961
|
+
const isConic = grad.type === "conic";
|
|
12962
|
+
if (isLinear || isConic) {
|
|
12963
|
+
const angleDeg = grad.angle ?? (isConic ? 0 : 90);
|
|
12964
|
+
const angleRad = angleDeg * Math.PI / 180;
|
|
12965
|
+
const sinA = Math.sin(angleRad);
|
|
12966
|
+
const cosA = Math.cos(angleRad);
|
|
12967
|
+
const corners = [[0, 0], [pageWidth, 0], [pageWidth, pageHeight], [0, pageHeight]];
|
|
12968
|
+
const projs = corners.map(([x, y]) => x * sinA - y * cosA);
|
|
12969
|
+
const minP = Math.min(...projs);
|
|
12970
|
+
const maxP = Math.max(...projs);
|
|
12971
|
+
const halfLen = (maxP - minP) / 2;
|
|
12972
|
+
const midX = pageWidth / 2;
|
|
12973
|
+
const midY = pageHeight / 2;
|
|
12974
|
+
let finalStops = shadingColors;
|
|
12975
|
+
if (isConic && shadingColors.length >= 2) {
|
|
12976
|
+
const reversed = [...shadingColors].reverse().map((s) => ({ offset: 0.5 + (1 - s.offset) * 0.5, color: s.color }));
|
|
12977
|
+
const firstHalf = shadingColors.map((s) => ({ offset: s.offset * 0.5, color: s.color }));
|
|
12978
|
+
finalStops = [...firstHalf, ...reversed.slice(1)];
|
|
12979
|
+
}
|
|
12980
|
+
doc.addShadingPattern(patternKey, new ShadingPattern("axial", [
|
|
12981
|
+
midX - sinA * halfLen,
|
|
12982
|
+
midY + cosA * halfLen,
|
|
12983
|
+
midX + sinA * halfLen,
|
|
12984
|
+
midY - cosA * halfLen
|
|
12985
|
+
], finalStops));
|
|
12986
|
+
} else {
|
|
12987
|
+
const cx = (grad.cx ?? 0.5) * pageWidth;
|
|
12988
|
+
const cy = (grad.cy ?? 0.5) * pageHeight;
|
|
12989
|
+
const maxR = (grad.r ?? 0.5) * Math.max(pageWidth, pageHeight);
|
|
12990
|
+
doc.addShadingPattern(patternKey, new ShadingPattern("radial", [cx, cy, 0, cx, cy, maxR], shadingColors));
|
|
12991
|
+
}
|
|
12992
|
+
doc.rect(0, 0, pageWidth, pageHeight);
|
|
12993
|
+
doc.fill({ key: patternKey, matrix: doc.Matrix(1, 0, 0, 1, 0, 0) });
|
|
12994
|
+
});
|
|
12995
|
+
} catch {
|
|
12996
|
+
const fallback = ((_b = colorStops[0]) == null ? void 0 : _b.color) || [255, 255, 255];
|
|
12997
|
+
pdf.setFillColor(fallback[0], fallback[1], fallback[2]);
|
|
12998
|
+
pdf.rect(0, 0, pageWidth, pageHeight, "F");
|
|
12999
|
+
}
|
|
13000
|
+
} else {
|
|
13001
|
+
const bgColor = parseColor(backgroundColor && backgroundColor !== "transparent" ? backgroundColor : "#ffffff");
|
|
13002
|
+
if (bgColor) {
|
|
13003
|
+
pdf.setFillColor(bgColor.r, bgColor.g, bgColor.b);
|
|
13004
|
+
pdf.rect(0, 0, pageWidth, pageHeight, "F");
|
|
13005
|
+
}
|
|
13006
|
+
}
|
|
13007
|
+
}
|
|
13008
|
+
async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
13009
|
+
var _a, _b;
|
|
13010
|
+
if (svgResults.length === 0) throw new Error("No pages to export");
|
|
13011
|
+
const { title, stripPageBackground } = options;
|
|
13012
|
+
const firstPage = svgResults[0];
|
|
13013
|
+
const orientation = firstPage.width > firstPage.height ? "landscape" : "portrait";
|
|
13014
|
+
const pdf = new jsPDF({
|
|
13015
|
+
orientation,
|
|
13016
|
+
unit: "px",
|
|
13017
|
+
format: [firstPage.width, firstPage.height],
|
|
13018
|
+
hotfixes: ["px_scaling"],
|
|
13019
|
+
compress: true
|
|
13020
|
+
});
|
|
13021
|
+
if (title) pdf.setProperties({ title, creator: "Pixldocs" });
|
|
13022
|
+
const fontBaseUrl = options.fontBaseUrl ?? (typeof window !== "undefined" ? window.location.origin + "/fonts/" : "/fonts/");
|
|
13023
|
+
const { extractFontFamiliesFromSvgs: extractFontFamiliesFromSvgs2 } = await Promise.resolve().then(() => pdfFonts);
|
|
13024
|
+
const fontFamilies = extractFontFamiliesFromSvgs2(svgResults.map((s) => s.svg));
|
|
13025
|
+
if (fontFamilies.size > 0) {
|
|
13026
|
+
await embedFontsInPdf(pdf, fontFamilies, fontBaseUrl);
|
|
13027
|
+
}
|
|
13028
|
+
for (let i = 0; i < svgResults.length; i++) {
|
|
13029
|
+
const page = svgResults[i];
|
|
13030
|
+
if (i > 0) {
|
|
13031
|
+
const pageOrientation = page.width > page.height ? "landscape" : "portrait";
|
|
13032
|
+
pdf.addPage([page.width, page.height], pageOrientation);
|
|
13033
|
+
}
|
|
13034
|
+
const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
|
|
13035
|
+
drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
|
|
13036
|
+
const shouldStripBg = stripPageBackground ?? hasGradient;
|
|
13037
|
+
let processedSvg = prepareLiveCanvasSvgForPdf(page.svg, page.width, page.height, `page-${i + 1}`, {
|
|
13038
|
+
stripPageBackground: shouldStripBg
|
|
13039
|
+
});
|
|
13040
|
+
if (processedSvg) {
|
|
13041
|
+
const svgStr = new XMLSerializer().serializeToString(processedSvg);
|
|
13042
|
+
const rewrittenSvg = rewriteSvgFontsForJsPDF(svgStr);
|
|
13043
|
+
const reParser = new DOMParser();
|
|
13044
|
+
const reDoc = reParser.parseFromString(rewrittenSvg, "image/svg+xml");
|
|
13045
|
+
processedSvg = reDoc.documentElement;
|
|
13046
|
+
}
|
|
13047
|
+
if (processedSvg) {
|
|
13048
|
+
pdf.setFillColor(0, 0, 0);
|
|
13049
|
+
pdf.setDrawColor(0, 0, 0);
|
|
13050
|
+
pdf.saveGraphicsState();
|
|
13051
|
+
setPdfColorFromSvg(pdf, processedSvg);
|
|
13052
|
+
await svg2pdfWithDomMount(processedSvg, pdf, svg2pdfOpts(0, 0, page.width, page.height));
|
|
13053
|
+
pdf.restoreGraphicsState();
|
|
13054
|
+
pdf.setFillColor(0, 0, 0);
|
|
13055
|
+
pdf.setDrawColor(0, 0, 0);
|
|
13056
|
+
}
|
|
13057
|
+
}
|
|
13058
|
+
const arrayBuffer = pdf.output("arraybuffer");
|
|
13059
|
+
const blob = new Blob([arrayBuffer], { type: "application/pdf" });
|
|
13060
|
+
return {
|
|
13061
|
+
blob,
|
|
13062
|
+
arrayBuffer,
|
|
13063
|
+
totalPages: svgResults.length,
|
|
13064
|
+
pages: svgResults.map((p) => ({ width: p.width, height: p.height }))
|
|
13065
|
+
};
|
|
13066
|
+
}
|
|
13067
|
+
const pdfExport = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
13068
|
+
__proto__: null,
|
|
13069
|
+
assemblePdfFromSvgs
|
|
13070
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
11204
13071
|
function collectImageUrls(config) {
|
|
11205
13072
|
const urls = [];
|
|
11206
13073
|
const walk = (nodes) => {
|
|
@@ -11278,17 +13145,29 @@ async function warmTemplateFromForm(options) {
|
|
|
11278
13145
|
await warmResolvedTemplateForPreview(resolved.config, { signal, imageProxyUrl });
|
|
11279
13146
|
}
|
|
11280
13147
|
export {
|
|
13148
|
+
FONT_FALLBACK_DEVANAGARI,
|
|
13149
|
+
FONT_FALLBACK_SYMBOLS,
|
|
13150
|
+
FONT_FILES,
|
|
11281
13151
|
PixldocsPreview,
|
|
11282
13152
|
PixldocsRenderer,
|
|
11283
13153
|
applyThemeToConfig,
|
|
13154
|
+
assemblePdfFromSvgs,
|
|
11284
13155
|
collectFontDescriptorsFromConfig,
|
|
11285
13156
|
collectFontsFromConfig,
|
|
11286
13157
|
collectImageUrls,
|
|
13158
|
+
embedFont,
|
|
13159
|
+
embedFontsForConfig,
|
|
13160
|
+
embedFontsInPdf,
|
|
11287
13161
|
ensureFontsForResolvedConfig,
|
|
13162
|
+
extractFontFamiliesFromSvgs,
|
|
13163
|
+
getEmbeddedJsPDFFontName,
|
|
13164
|
+
isFontAvailable,
|
|
11288
13165
|
loadGoogleFontCSS,
|
|
11289
13166
|
normalizeFontFamily,
|
|
13167
|
+
resolveFontWeight,
|
|
11290
13168
|
resolveFromForm,
|
|
11291
13169
|
resolveTemplateData,
|
|
13170
|
+
rewriteSvgFontsForJsPDF,
|
|
11292
13171
|
warmResolvedTemplateForPreview,
|
|
11293
13172
|
warmTemplateFromForm
|
|
11294
13173
|
};
|