@embedpdf/engines 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/direct-engine-BeZ18SKz.cjs +2 -0
- package/dist/direct-engine-BeZ18SKz.cjs.map +1 -0
- package/dist/{direct-engine-DuLFAbiv.js → direct-engine-CB3k-o0I.js} +533 -9
- package/dist/direct-engine-CB3k-o0I.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/lib/orchestrator/remote-executor.d.ts +5 -0
- package/dist/lib/pdfium/cdn-fonts.d.ts +50 -0
- package/dist/lib/pdfium/engine.d.ts +17 -2
- package/dist/lib/pdfium/font-fallback.d.ts +207 -0
- package/dist/lib/pdfium/index.cjs +1 -1
- package/dist/lib/pdfium/index.cjs.map +1 -1
- package/dist/lib/pdfium/index.d.ts +2 -0
- package/dist/lib/pdfium/index.js +55 -2
- package/dist/lib/pdfium/index.js.map +1 -1
- package/dist/lib/pdfium/runner.d.ts +5 -1
- package/dist/lib/pdfium/web/direct-engine.cjs +1 -1
- package/dist/lib/pdfium/web/direct-engine.d.ts +8 -0
- package/dist/lib/pdfium/web/direct-engine.js +1 -1
- package/dist/lib/pdfium/web/worker-engine.cjs +1 -1
- package/dist/lib/pdfium/web/worker-engine.cjs.map +1 -1
- package/dist/lib/pdfium/web/worker-engine.d.ts +8 -0
- package/dist/lib/pdfium/web/worker-engine.js +5 -4
- package/dist/lib/pdfium/web/worker-engine.js.map +1 -1
- package/dist/preact/index.cjs +1 -1
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.js +14 -4
- package/dist/preact/index.js.map +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +14 -4
- package/dist/react/index.js.map +1 -1
- package/dist/shared-preact/hooks/use-pdfium-engine.d.ts +5 -0
- package/dist/shared-react/hooks/use-pdfium-engine.d.ts +5 -0
- package/dist/svelte/hooks/use-pdfium-engine.svelte.d.ts +5 -0
- package/dist/svelte/index.cjs +1 -1
- package/dist/svelte/index.cjs.map +1 -1
- package/dist/svelte/index.js +8 -3
- package/dist/svelte/index.js.map +1 -1
- package/dist/vue/composables/use-pdfium-engine.d.ts +5 -0
- package/dist/vue/index.cjs +1 -1
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.js +4 -4
- package/dist/vue/index.js.map +1 -1
- package/package.json +10 -3
- package/dist/direct-engine-DuLFAbiv.js.map +0 -1
- package/dist/direct-engine-JeNRkc7w.cjs +0 -2
- package/dist/direct-engine-JeNRkc7w.cjs.map +0 -1
|
@@ -380,8 +380,8 @@ const MEMORY_LIMITS = {
|
|
|
380
380
|
const LIMITS = {
|
|
381
381
|
MEMORY: MEMORY_LIMITS
|
|
382
382
|
};
|
|
383
|
-
const LOG_SOURCE$
|
|
384
|
-
const LOG_CATEGORY$
|
|
383
|
+
const LOG_SOURCE$2 = "PDFiumEngine";
|
|
384
|
+
const LOG_CATEGORY$2 = "MemoryManager";
|
|
385
385
|
class MemoryManager {
|
|
386
386
|
constructor(pdfiumModule, logger) {
|
|
387
387
|
this.pdfiumModule = pdfiumModule;
|
|
@@ -418,7 +418,7 @@ class MemoryManager {
|
|
|
418
418
|
free(ptr) {
|
|
419
419
|
const allocation = this.allocations.get(ptr);
|
|
420
420
|
if (!allocation) {
|
|
421
|
-
this.logger.warn(LOG_SOURCE$
|
|
421
|
+
this.logger.warn(LOG_SOURCE$2, LOG_CATEGORY$2, `Freeing untracked pointer: ${ptr}`);
|
|
422
422
|
} else {
|
|
423
423
|
this.totalAllocated -= allocation.size;
|
|
424
424
|
this.allocations.delete(ptr);
|
|
@@ -441,16 +441,494 @@ class MemoryManager {
|
|
|
441
441
|
checkLeaks() {
|
|
442
442
|
if (this.allocations.size > 0) {
|
|
443
443
|
this.logger.warn(
|
|
444
|
-
LOG_SOURCE$
|
|
445
|
-
LOG_CATEGORY$
|
|
444
|
+
LOG_SOURCE$2,
|
|
445
|
+
LOG_CATEGORY$2,
|
|
446
446
|
`Potential memory leak: ${this.allocations.size} unfreed allocations`
|
|
447
447
|
);
|
|
448
448
|
for (const [ptr, alloc] of this.allocations) {
|
|
449
|
-
this.logger.warn(LOG_SOURCE$
|
|
449
|
+
this.logger.warn(LOG_SOURCE$2, LOG_CATEGORY$2, ` - ${ptr}: ${alloc.size} bytes`, alloc.stack);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
const SYSFONTINFO_SIZE = 36;
|
|
455
|
+
const OFFSET_VERSION = 0;
|
|
456
|
+
const OFFSET_RELEASE = 4;
|
|
457
|
+
const OFFSET_ENUMFONTS = 8;
|
|
458
|
+
const OFFSET_MAPFONT = 12;
|
|
459
|
+
const OFFSET_GETFONT = 16;
|
|
460
|
+
const OFFSET_GETFONTDATA = 20;
|
|
461
|
+
const OFFSET_GETFACENAME = 24;
|
|
462
|
+
const OFFSET_GETFONTCHARSET = 28;
|
|
463
|
+
const OFFSET_DELETEFONT = 32;
|
|
464
|
+
const LOG_SOURCE$1 = "pdfium";
|
|
465
|
+
const LOG_CATEGORY$1 = "font-fallback";
|
|
466
|
+
class FontFallbackManager {
|
|
467
|
+
constructor(config, logger = new NoopLogger()) {
|
|
468
|
+
this.fontHandles = /* @__PURE__ */ new Map();
|
|
469
|
+
this.fontCache = /* @__PURE__ */ new Map();
|
|
470
|
+
this.nextHandleId = 1;
|
|
471
|
+
this.module = null;
|
|
472
|
+
this.enabled = false;
|
|
473
|
+
this.structPtr = 0;
|
|
474
|
+
this.releaseFnPtr = 0;
|
|
475
|
+
this.enumFontsFnPtr = 0;
|
|
476
|
+
this.mapFontFnPtr = 0;
|
|
477
|
+
this.getFontFnPtr = 0;
|
|
478
|
+
this.getFontDataFnPtr = 0;
|
|
479
|
+
this.getFaceNameFnPtr = 0;
|
|
480
|
+
this.getFontCharsetFnPtr = 0;
|
|
481
|
+
this.deleteFontFnPtr = 0;
|
|
482
|
+
this.fontConfig = config;
|
|
483
|
+
this.logger = logger;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Initialize the font fallback system and attach to PDFium module
|
|
487
|
+
*/
|
|
488
|
+
initialize(module) {
|
|
489
|
+
if (this.enabled) {
|
|
490
|
+
this.logger.warn(LOG_SOURCE$1, LOG_CATEGORY$1, "Font fallback already initialized");
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
this.module = module;
|
|
494
|
+
const pdfium = module.pdfium;
|
|
495
|
+
if (typeof pdfium.addFunction !== "function") {
|
|
496
|
+
this.logger.error(
|
|
497
|
+
LOG_SOURCE$1,
|
|
498
|
+
LOG_CATEGORY$1,
|
|
499
|
+
"addFunction not available. Make sure WASM is compiled with -sALLOW_TABLE_GROWTH"
|
|
500
|
+
);
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
try {
|
|
504
|
+
this.structPtr = pdfium.wasmExports.malloc(SYSFONTINFO_SIZE);
|
|
505
|
+
if (!this.structPtr) {
|
|
506
|
+
throw new Error("Failed to allocate FPDF_SYSFONTINFO struct");
|
|
507
|
+
}
|
|
508
|
+
for (let i = 0; i < SYSFONTINFO_SIZE; i++) {
|
|
509
|
+
pdfium.setValue(this.structPtr + i, 0, "i8");
|
|
510
|
+
}
|
|
511
|
+
this.releaseFnPtr = pdfium.addFunction((_pThis) => {
|
|
512
|
+
}, "vi");
|
|
513
|
+
this.enumFontsFnPtr = pdfium.addFunction((_pThis, _pMapper) => {
|
|
514
|
+
}, "vii");
|
|
515
|
+
this.mapFontFnPtr = pdfium.addFunction(
|
|
516
|
+
(_pThis, weight, bItalic, charset, pitchFamily, facePtr, bExactPtr) => {
|
|
517
|
+
const face = facePtr ? pdfium.UTF8ToString(facePtr) : "";
|
|
518
|
+
const handle = this.mapFont(weight, bItalic, charset, pitchFamily, face);
|
|
519
|
+
if (bExactPtr) {
|
|
520
|
+
pdfium.setValue(bExactPtr, 0, "i32");
|
|
521
|
+
}
|
|
522
|
+
return handle;
|
|
523
|
+
},
|
|
524
|
+
"iiiiiiii"
|
|
525
|
+
);
|
|
526
|
+
this.getFontFnPtr = pdfium.addFunction((_pThis, facePtr) => {
|
|
527
|
+
const face = facePtr ? pdfium.UTF8ToString(facePtr) : "";
|
|
528
|
+
return this.mapFont(400, 0, 0, 0, face);
|
|
529
|
+
}, "iii");
|
|
530
|
+
this.getFontDataFnPtr = pdfium.addFunction(
|
|
531
|
+
(_pThis, hFont, table, buffer, bufSize) => {
|
|
532
|
+
return this.getFontData(hFont, table, buffer, bufSize);
|
|
533
|
+
},
|
|
534
|
+
"iiiiii"
|
|
535
|
+
);
|
|
536
|
+
this.getFaceNameFnPtr = pdfium.addFunction(
|
|
537
|
+
(_pThis, _hFont, _buffer, _bufSize) => {
|
|
538
|
+
return 0;
|
|
539
|
+
},
|
|
540
|
+
"iiiii"
|
|
541
|
+
);
|
|
542
|
+
this.getFontCharsetFnPtr = pdfium.addFunction((_pThis, hFont) => {
|
|
543
|
+
const handle = this.fontHandles.get(hFont);
|
|
544
|
+
return (handle == null ? void 0 : handle.charset) ?? 0;
|
|
545
|
+
}, "iii");
|
|
546
|
+
this.deleteFontFnPtr = pdfium.addFunction((_pThis, hFont) => {
|
|
547
|
+
this.deleteFont(hFont);
|
|
548
|
+
}, "vii");
|
|
549
|
+
pdfium.setValue(this.structPtr + OFFSET_VERSION, 1, "i32");
|
|
550
|
+
pdfium.setValue(this.structPtr + OFFSET_RELEASE, this.releaseFnPtr, "i32");
|
|
551
|
+
pdfium.setValue(this.structPtr + OFFSET_ENUMFONTS, this.enumFontsFnPtr, "i32");
|
|
552
|
+
pdfium.setValue(this.structPtr + OFFSET_MAPFONT, this.mapFontFnPtr, "i32");
|
|
553
|
+
pdfium.setValue(this.structPtr + OFFSET_GETFONT, this.getFontFnPtr, "i32");
|
|
554
|
+
pdfium.setValue(this.structPtr + OFFSET_GETFONTDATA, this.getFontDataFnPtr, "i32");
|
|
555
|
+
pdfium.setValue(this.structPtr + OFFSET_GETFACENAME, this.getFaceNameFnPtr, "i32");
|
|
556
|
+
pdfium.setValue(this.structPtr + OFFSET_GETFONTCHARSET, this.getFontCharsetFnPtr, "i32");
|
|
557
|
+
pdfium.setValue(this.structPtr + OFFSET_DELETEFONT, this.deleteFontFnPtr, "i32");
|
|
558
|
+
module.FPDF_SetSystemFontInfo(this.structPtr);
|
|
559
|
+
this.enabled = true;
|
|
560
|
+
this.logger.info(
|
|
561
|
+
LOG_SOURCE$1,
|
|
562
|
+
LOG_CATEGORY$1,
|
|
563
|
+
"Font fallback system initialized (pure TypeScript)",
|
|
564
|
+
Object.keys(this.fontConfig.fonts)
|
|
565
|
+
);
|
|
566
|
+
} catch (error) {
|
|
567
|
+
this.logger.error(LOG_SOURCE$1, LOG_CATEGORY$1, "Failed to initialize font fallback", error);
|
|
568
|
+
this.cleanup();
|
|
569
|
+
throw error;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Disable the font fallback system and clean up resources
|
|
574
|
+
*/
|
|
575
|
+
disable() {
|
|
576
|
+
if (!this.enabled || !this.module) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
this.module.FPDF_SetSystemFontInfo(0);
|
|
580
|
+
this.cleanup();
|
|
581
|
+
this.enabled = false;
|
|
582
|
+
this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, "Font fallback system disabled");
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Clean up allocated resources
|
|
586
|
+
*/
|
|
587
|
+
cleanup() {
|
|
588
|
+
if (!this.module) return;
|
|
589
|
+
const pdfium = this.module.pdfium;
|
|
590
|
+
if (this.structPtr) {
|
|
591
|
+
pdfium.wasmExports.free(this.structPtr);
|
|
592
|
+
this.structPtr = 0;
|
|
593
|
+
}
|
|
594
|
+
const removeIfExists = (ptr) => {
|
|
595
|
+
if (ptr && typeof pdfium.removeFunction === "function") {
|
|
596
|
+
try {
|
|
597
|
+
pdfium.removeFunction(ptr);
|
|
598
|
+
} catch {
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
removeIfExists(this.releaseFnPtr);
|
|
603
|
+
removeIfExists(this.enumFontsFnPtr);
|
|
604
|
+
removeIfExists(this.mapFontFnPtr);
|
|
605
|
+
removeIfExists(this.getFontFnPtr);
|
|
606
|
+
removeIfExists(this.getFontDataFnPtr);
|
|
607
|
+
removeIfExists(this.getFaceNameFnPtr);
|
|
608
|
+
removeIfExists(this.getFontCharsetFnPtr);
|
|
609
|
+
removeIfExists(this.deleteFontFnPtr);
|
|
610
|
+
this.releaseFnPtr = 0;
|
|
611
|
+
this.enumFontsFnPtr = 0;
|
|
612
|
+
this.mapFontFnPtr = 0;
|
|
613
|
+
this.getFontFnPtr = 0;
|
|
614
|
+
this.getFontDataFnPtr = 0;
|
|
615
|
+
this.getFaceNameFnPtr = 0;
|
|
616
|
+
this.getFontCharsetFnPtr = 0;
|
|
617
|
+
this.deleteFontFnPtr = 0;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Check if font fallback is enabled
|
|
621
|
+
*/
|
|
622
|
+
isEnabled() {
|
|
623
|
+
return this.enabled;
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Get statistics about font loading
|
|
627
|
+
*/
|
|
628
|
+
getStats() {
|
|
629
|
+
return {
|
|
630
|
+
handleCount: this.fontHandles.size,
|
|
631
|
+
cacheSize: this.fontCache.size,
|
|
632
|
+
cachedUrls: Array.from(this.fontCache.keys())
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Pre-load fonts for specific charsets (optional optimization)
|
|
637
|
+
* This can be called to warm the cache before rendering
|
|
638
|
+
*/
|
|
639
|
+
async preloadFonts(charsets) {
|
|
640
|
+
const urls = charsets.map((charset) => this.getFontUrlForCharset(charset)).filter((url) => url !== null);
|
|
641
|
+
const uniqueUrls = [...new Set(urls)];
|
|
642
|
+
await Promise.all(
|
|
643
|
+
uniqueUrls.map(async (url) => {
|
|
644
|
+
if (!this.fontCache.has(url)) {
|
|
645
|
+
try {
|
|
646
|
+
const data = await this.fetchFontAsync(url);
|
|
647
|
+
if (data) {
|
|
648
|
+
this.fontCache.set(url, data);
|
|
649
|
+
this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, `Pre-loaded font: ${url}`);
|
|
650
|
+
}
|
|
651
|
+
} catch (error) {
|
|
652
|
+
this.logger.warn(LOG_SOURCE$1, LOG_CATEGORY$1, `Failed to pre-load font: ${url}`, error);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
})
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
// ============================================================================
|
|
659
|
+
// PDFium Callback Implementations
|
|
660
|
+
// ============================================================================
|
|
661
|
+
/**
|
|
662
|
+
* MapFont - called by PDFium when it needs a font
|
|
663
|
+
*/
|
|
664
|
+
mapFont(weight, bItalic, charset, pitchFamily, face) {
|
|
665
|
+
const italic = bItalic !== 0;
|
|
666
|
+
this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, "MapFont called", {
|
|
667
|
+
weight,
|
|
668
|
+
italic,
|
|
669
|
+
charset,
|
|
670
|
+
pitchFamily,
|
|
671
|
+
face
|
|
672
|
+
});
|
|
673
|
+
const result = this.findBestFontMatch(charset, weight, italic);
|
|
674
|
+
if (!result) {
|
|
675
|
+
this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, `No font configured for charset ${charset}`);
|
|
676
|
+
return 0;
|
|
677
|
+
}
|
|
678
|
+
const handle = {
|
|
679
|
+
id: this.nextHandleId++,
|
|
680
|
+
charset,
|
|
681
|
+
weight,
|
|
682
|
+
italic,
|
|
683
|
+
url: result.url,
|
|
684
|
+
data: null
|
|
685
|
+
};
|
|
686
|
+
this.fontHandles.set(handle.id, handle);
|
|
687
|
+
this.logger.debug(
|
|
688
|
+
LOG_SOURCE$1,
|
|
689
|
+
LOG_CATEGORY$1,
|
|
690
|
+
`Created font handle ${handle.id} for ${result.url} (requested: weight=${weight}, italic=${italic}, matched: weight=${result.matchedWeight}, italic=${result.matchedItalic})`
|
|
691
|
+
);
|
|
692
|
+
return handle.id;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* GetFontData - called by PDFium to get font bytes
|
|
696
|
+
*/
|
|
697
|
+
getFontData(fontHandle, table, bufferPtr, bufSize) {
|
|
698
|
+
const handle = this.fontHandles.get(fontHandle);
|
|
699
|
+
if (!handle) {
|
|
700
|
+
this.logger.warn(LOG_SOURCE$1, LOG_CATEGORY$1, `Unknown font handle: ${fontHandle}`);
|
|
701
|
+
return 0;
|
|
702
|
+
}
|
|
703
|
+
if (!handle.data) {
|
|
704
|
+
if (this.fontCache.has(handle.url)) {
|
|
705
|
+
handle.data = this.fontCache.get(handle.url);
|
|
706
|
+
} else {
|
|
707
|
+
handle.data = this.fetchFontSync(handle.url);
|
|
708
|
+
if (handle.data) {
|
|
709
|
+
this.fontCache.set(handle.url, handle.data);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (!handle.data) {
|
|
714
|
+
this.logger.warn(LOG_SOURCE$1, LOG_CATEGORY$1, `Failed to load font: ${handle.url}`);
|
|
715
|
+
return 0;
|
|
716
|
+
}
|
|
717
|
+
const fontData = handle.data;
|
|
718
|
+
if (table !== 0) {
|
|
719
|
+
this.logger.debug(
|
|
720
|
+
LOG_SOURCE$1,
|
|
721
|
+
LOG_CATEGORY$1,
|
|
722
|
+
`Table ${table} requested - returning 0 to request whole file`
|
|
723
|
+
);
|
|
724
|
+
return 0;
|
|
725
|
+
}
|
|
726
|
+
if (bufferPtr === 0 || bufSize < fontData.length) {
|
|
727
|
+
return fontData.length;
|
|
728
|
+
}
|
|
729
|
+
if (this.module) {
|
|
730
|
+
const heap = this.module.pdfium.HEAPU8;
|
|
731
|
+
heap.set(fontData, bufferPtr);
|
|
732
|
+
this.logger.debug(
|
|
733
|
+
LOG_SOURCE$1,
|
|
734
|
+
LOG_CATEGORY$1,
|
|
735
|
+
`Copied ${fontData.length} bytes to buffer for handle ${fontHandle}`
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
return fontData.length;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* DeleteFont - called by PDFium when done with a font
|
|
742
|
+
*/
|
|
743
|
+
deleteFont(fontHandle) {
|
|
744
|
+
const handle = this.fontHandles.get(fontHandle);
|
|
745
|
+
if (handle) {
|
|
746
|
+
this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, `Deleting font handle ${fontHandle}`);
|
|
747
|
+
this.fontHandles.delete(fontHandle);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
// ============================================================================
|
|
751
|
+
// Helper Methods
|
|
752
|
+
// ============================================================================
|
|
753
|
+
/**
|
|
754
|
+
* Find the best matching font variant for the given parameters
|
|
755
|
+
*/
|
|
756
|
+
findBestFontMatch(charset, requestedWeight, requestedItalic) {
|
|
757
|
+
const { fonts, defaultFont, baseUrl } = this.fontConfig;
|
|
758
|
+
const entry = fonts[charset] ?? defaultFont;
|
|
759
|
+
if (!entry) {
|
|
760
|
+
return null;
|
|
761
|
+
}
|
|
762
|
+
const variants = this.normalizeToVariants(entry);
|
|
763
|
+
if (variants.length === 0) {
|
|
764
|
+
return null;
|
|
765
|
+
}
|
|
766
|
+
const best = this.selectBestVariant(variants, requestedWeight, requestedItalic);
|
|
767
|
+
let url = best.url;
|
|
768
|
+
if (baseUrl && !url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("/")) {
|
|
769
|
+
url = `${baseUrl}/${url}`;
|
|
770
|
+
}
|
|
771
|
+
return {
|
|
772
|
+
url,
|
|
773
|
+
matchedWeight: best.weight ?? 400,
|
|
774
|
+
matchedItalic: best.italic ?? false
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Normalize a FontEntry to an array of FontVariants
|
|
779
|
+
*/
|
|
780
|
+
normalizeToVariants(entry) {
|
|
781
|
+
if (typeof entry === "string") {
|
|
782
|
+
return [{ url: entry, weight: 400, italic: false }];
|
|
783
|
+
}
|
|
784
|
+
if (Array.isArray(entry)) {
|
|
785
|
+
return entry.map((v) => ({
|
|
786
|
+
url: v.url,
|
|
787
|
+
weight: v.weight ?? 400,
|
|
788
|
+
italic: v.italic ?? false
|
|
789
|
+
}));
|
|
790
|
+
}
|
|
791
|
+
return [{ url: entry.url, weight: entry.weight ?? 400, italic: entry.italic ?? false }];
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Select the best matching variant based on weight and italic
|
|
795
|
+
* Uses CSS font matching algorithm principles:
|
|
796
|
+
* 1. Exact italic match preferred
|
|
797
|
+
* 2. Closest weight (with bias toward bolder for weights >= 400)
|
|
798
|
+
*/
|
|
799
|
+
selectBestVariant(variants, requestedWeight, requestedItalic) {
|
|
800
|
+
if (variants.length === 1) {
|
|
801
|
+
return variants[0];
|
|
802
|
+
}
|
|
803
|
+
const italicMatches = variants.filter((v) => (v.italic ?? false) === requestedItalic);
|
|
804
|
+
const candidates = italicMatches.length > 0 ? italicMatches : variants;
|
|
805
|
+
let bestMatch = candidates[0];
|
|
806
|
+
let bestDistance = Math.abs((bestMatch.weight ?? 400) - requestedWeight);
|
|
807
|
+
for (const variant of candidates) {
|
|
808
|
+
const variantWeight = variant.weight ?? 400;
|
|
809
|
+
const distance = Math.abs(variantWeight - requestedWeight);
|
|
810
|
+
if (distance < bestDistance) {
|
|
811
|
+
bestMatch = variant;
|
|
812
|
+
bestDistance = distance;
|
|
813
|
+
} else if (distance === bestDistance) {
|
|
814
|
+
const currentWeight = bestMatch.weight ?? 400;
|
|
815
|
+
if (requestedWeight >= 500) {
|
|
816
|
+
if (variantWeight > currentWeight) {
|
|
817
|
+
bestMatch = variant;
|
|
818
|
+
}
|
|
819
|
+
} else {
|
|
820
|
+
if (variantWeight < currentWeight) {
|
|
821
|
+
bestMatch = variant;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return bestMatch;
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Get font URL for a charset (backward compatible helper)
|
|
830
|
+
*/
|
|
831
|
+
getFontUrlForCharset(charset) {
|
|
832
|
+
const result = this.findBestFontMatch(charset, 400, false);
|
|
833
|
+
return (result == null ? void 0 : result.url) ?? null;
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Fetch font data synchronously
|
|
837
|
+
* Uses custom fontLoader if provided, otherwise falls back to XMLHttpRequest (browser)
|
|
838
|
+
*/
|
|
839
|
+
fetchFontSync(pathOrUrl) {
|
|
840
|
+
this.logger.debug(LOG_SOURCE$1, LOG_CATEGORY$1, `Fetching font synchronously: ${pathOrUrl}`);
|
|
841
|
+
if (this.fontConfig.fontLoader) {
|
|
842
|
+
try {
|
|
843
|
+
const data = this.fontConfig.fontLoader(pathOrUrl);
|
|
844
|
+
if (data) {
|
|
845
|
+
this.logger.info(
|
|
846
|
+
LOG_SOURCE$1,
|
|
847
|
+
LOG_CATEGORY$1,
|
|
848
|
+
`Loaded font via custom loader: ${pathOrUrl} (${data.length} bytes)`
|
|
849
|
+
);
|
|
850
|
+
} else {
|
|
851
|
+
this.logger.warn(
|
|
852
|
+
LOG_SOURCE$1,
|
|
853
|
+
LOG_CATEGORY$1,
|
|
854
|
+
`Custom font loader returned null for: ${pathOrUrl}`
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
return data;
|
|
858
|
+
} catch (error) {
|
|
859
|
+
this.logger.error(
|
|
860
|
+
LOG_SOURCE$1,
|
|
861
|
+
LOG_CATEGORY$1,
|
|
862
|
+
`Error in custom font loader: ${pathOrUrl}`,
|
|
863
|
+
error
|
|
864
|
+
);
|
|
865
|
+
return null;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
try {
|
|
869
|
+
const xhr = new XMLHttpRequest();
|
|
870
|
+
xhr.open("GET", pathOrUrl, false);
|
|
871
|
+
xhr.responseType = "arraybuffer";
|
|
872
|
+
xhr.send();
|
|
873
|
+
if (xhr.status === 200) {
|
|
874
|
+
const data = new Uint8Array(xhr.response);
|
|
875
|
+
this.logger.info(
|
|
876
|
+
LOG_SOURCE$1,
|
|
877
|
+
LOG_CATEGORY$1,
|
|
878
|
+
`Loaded font: ${pathOrUrl} (${data.length} bytes)`
|
|
879
|
+
);
|
|
880
|
+
return data;
|
|
881
|
+
} else {
|
|
882
|
+
this.logger.error(
|
|
883
|
+
LOG_SOURCE$1,
|
|
884
|
+
LOG_CATEGORY$1,
|
|
885
|
+
`Failed to load font: ${pathOrUrl} (HTTP ${xhr.status})`
|
|
886
|
+
);
|
|
887
|
+
return null;
|
|
888
|
+
}
|
|
889
|
+
} catch (error) {
|
|
890
|
+
this.logger.error(LOG_SOURCE$1, LOG_CATEGORY$1, `Error fetching font: ${pathOrUrl}`, error);
|
|
891
|
+
return null;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Fetch font data asynchronously (for preloading)
|
|
896
|
+
* Uses custom fontLoader if provided, otherwise falls back to fetch API
|
|
897
|
+
*/
|
|
898
|
+
async fetchFontAsync(pathOrUrl) {
|
|
899
|
+
if (this.fontConfig.fontLoader) {
|
|
900
|
+
try {
|
|
901
|
+
return this.fontConfig.fontLoader(pathOrUrl);
|
|
902
|
+
} catch {
|
|
903
|
+
return null;
|
|
450
904
|
}
|
|
451
905
|
}
|
|
906
|
+
try {
|
|
907
|
+
const response = await fetch(pathOrUrl);
|
|
908
|
+
if (response.ok) {
|
|
909
|
+
const buffer = await response.arrayBuffer();
|
|
910
|
+
return new Uint8Array(buffer);
|
|
911
|
+
}
|
|
912
|
+
return null;
|
|
913
|
+
} catch {
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
452
916
|
}
|
|
453
917
|
}
|
|
918
|
+
function createNodeFontLoader(fs, path, basePath) {
|
|
919
|
+
return (fontPath) => {
|
|
920
|
+
try {
|
|
921
|
+
const fullPath = path.join(basePath, fontPath);
|
|
922
|
+
const data = fs.readFileSync(fullPath);
|
|
923
|
+
if (data instanceof Uint8Array) {
|
|
924
|
+
return data;
|
|
925
|
+
}
|
|
926
|
+
return new Uint8Array(data);
|
|
927
|
+
} catch {
|
|
928
|
+
return null;
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
}
|
|
454
932
|
var BitmapFormat = /* @__PURE__ */ ((BitmapFormat2) => {
|
|
455
933
|
BitmapFormat2[BitmapFormat2["Bitmap_Gray"] = 1] = "Bitmap_Gray";
|
|
456
934
|
BitmapFormat2[BitmapFormat2["Bitmap_BGR"] = 2] = "Bitmap_BGR";
|
|
@@ -494,7 +972,8 @@ class PdfiumNative {
|
|
|
494
972
|
constructor(pdfiumModule, options = {}) {
|
|
495
973
|
this.pdfiumModule = pdfiumModule;
|
|
496
974
|
this.memoryLeakCheckInterval = null;
|
|
497
|
-
|
|
975
|
+
this.fontFallbackManager = null;
|
|
976
|
+
const { logger = new NoopLogger(), fontFallback } = options;
|
|
498
977
|
this.logger = logger;
|
|
499
978
|
this.memoryManager = new MemoryManager(this.pdfiumModule, this.logger);
|
|
500
979
|
this.cache = new PdfCache(this.pdfiumModule, this.memoryManager);
|
|
@@ -507,6 +986,11 @@ class PdfiumNative {
|
|
|
507
986
|
this.logger.perf(LOG_SOURCE, LOG_CATEGORY, `Initialize`, "Begin", "General");
|
|
508
987
|
this.pdfiumModule.PDFiumExt_Init();
|
|
509
988
|
this.logger.perf(LOG_SOURCE, LOG_CATEGORY, `Initialize`, "End", "General");
|
|
989
|
+
if (fontFallback) {
|
|
990
|
+
this.fontFallbackManager = new FontFallbackManager(fontFallback, this.logger);
|
|
991
|
+
this.fontFallbackManager.initialize(this.pdfiumModule);
|
|
992
|
+
this.logger.info(LOG_SOURCE, LOG_CATEGORY, "Font fallback system enabled");
|
|
993
|
+
}
|
|
510
994
|
}
|
|
511
995
|
/**
|
|
512
996
|
* {@inheritDoc @embedpdf/models!PdfEngine.destroy}
|
|
@@ -516,6 +1000,10 @@ class PdfiumNative {
|
|
|
516
1000
|
destroy() {
|
|
517
1001
|
this.logger.debug(LOG_SOURCE, LOG_CATEGORY, "destroy");
|
|
518
1002
|
this.logger.perf(LOG_SOURCE, LOG_CATEGORY, `Destroy`, "Begin", "General");
|
|
1003
|
+
if (this.fontFallbackManager) {
|
|
1004
|
+
this.fontFallbackManager.disable();
|
|
1005
|
+
this.fontFallbackManager = null;
|
|
1006
|
+
}
|
|
519
1007
|
this.pdfiumModule.FPDF_DestroyLibrary();
|
|
520
1008
|
if (this.memoryLeakCheckInterval) {
|
|
521
1009
|
clearInterval(this.memoryLeakCheckInterval);
|
|
@@ -524,6 +1012,13 @@ class PdfiumNative {
|
|
|
524
1012
|
this.logger.perf(LOG_SOURCE, LOG_CATEGORY, `Destroy`, "End", "General");
|
|
525
1013
|
return PdfTaskHelper.resolve(true);
|
|
526
1014
|
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Get the font fallback manager instance
|
|
1017
|
+
* Useful for pre-loading fonts or checking stats
|
|
1018
|
+
*/
|
|
1019
|
+
getFontFallbackManager() {
|
|
1020
|
+
return this.fontFallbackManager;
|
|
1021
|
+
}
|
|
527
1022
|
/** Write a UTF-16LE (WIDESTRING) to wasm, call `fn(ptr)`, then free. */
|
|
528
1023
|
withWString(value, fn) {
|
|
529
1024
|
const length = (value.length + 1) * 2;
|
|
@@ -2108,6 +2603,9 @@ class PdfiumNative {
|
|
|
2108
2603
|
if (!this.setAnnotString(annotationPtr, "Contents", annotation.contents ?? "")) {
|
|
2109
2604
|
return false;
|
|
2110
2605
|
}
|
|
2606
|
+
if (annotation.custom && !this.setAnnotCustom(annotationPtr, annotation.custom)) {
|
|
2607
|
+
return false;
|
|
2608
|
+
}
|
|
2111
2609
|
if (!this.setAnnotString(annotationPtr, "T", annotation.author || "")) {
|
|
2112
2610
|
return false;
|
|
2113
2611
|
}
|
|
@@ -2148,6 +2646,9 @@ class PdfiumNative {
|
|
|
2148
2646
|
if (annotation.created && !this.setAnnotationDate(annotationPtr, "CreationDate", annotation.created)) {
|
|
2149
2647
|
return false;
|
|
2150
2648
|
}
|
|
2649
|
+
if (annotation.custom && !this.setAnnotCustom(annotationPtr, annotation.custom)) {
|
|
2650
|
+
return false;
|
|
2651
|
+
}
|
|
2151
2652
|
if (annotation.flags && !this.setAnnotationFlags(annotationPtr, annotation.flags)) {
|
|
2152
2653
|
return false;
|
|
2153
2654
|
}
|
|
@@ -2210,6 +2711,9 @@ class PdfiumNative {
|
|
|
2210
2711
|
if (annotation.created && !this.setAnnotationDate(annotationPtr, "CreationDate", annotation.created)) {
|
|
2211
2712
|
return false;
|
|
2212
2713
|
}
|
|
2714
|
+
if (annotation.custom && !this.setAnnotCustom(annotationPtr, annotation.custom)) {
|
|
2715
|
+
return false;
|
|
2716
|
+
}
|
|
2213
2717
|
if (annotation.flags && !this.setAnnotationFlags(annotationPtr, annotation.flags)) {
|
|
2214
2718
|
return false;
|
|
2215
2719
|
}
|
|
@@ -2255,6 +2759,9 @@ class PdfiumNative {
|
|
|
2255
2759
|
if (annotation.created && !this.setAnnotationDate(annotationPtr, "CreationDate", annotation.created)) {
|
|
2256
2760
|
return false;
|
|
2257
2761
|
}
|
|
2762
|
+
if (annotation.custom && !this.setAnnotCustom(annotationPtr, annotation.custom)) {
|
|
2763
|
+
return false;
|
|
2764
|
+
}
|
|
2258
2765
|
if (annotation.flags && !this.setAnnotationFlags(annotationPtr, annotation.flags)) {
|
|
2259
2766
|
return false;
|
|
2260
2767
|
}
|
|
@@ -2329,6 +2836,9 @@ class PdfiumNative {
|
|
|
2329
2836
|
if (annotation.created && !this.setAnnotationDate(annotationPtr, "CreationDate", annotation.created)) {
|
|
2330
2837
|
return false;
|
|
2331
2838
|
}
|
|
2839
|
+
if (annotation.custom && !this.setAnnotCustom(annotationPtr, annotation.custom)) {
|
|
2840
|
+
return false;
|
|
2841
|
+
}
|
|
2332
2842
|
if (annotation.modified && !this.setAnnotationDate(annotationPtr, "M", annotation.modified)) {
|
|
2333
2843
|
return false;
|
|
2334
2844
|
}
|
|
@@ -2397,6 +2907,9 @@ class PdfiumNative {
|
|
|
2397
2907
|
if (annotation.created && !this.setAnnotationDate(annotationPtr, "CreationDate", annotation.created)) {
|
|
2398
2908
|
return false;
|
|
2399
2909
|
}
|
|
2910
|
+
if (annotation.custom && !this.setAnnotCustom(annotationPtr, annotation.custom)) {
|
|
2911
|
+
return false;
|
|
2912
|
+
}
|
|
2400
2913
|
if (annotation.modified && !this.setAnnotationDate(annotationPtr, "M", annotation.modified)) {
|
|
2401
2914
|
return false;
|
|
2402
2915
|
}
|
|
@@ -2497,6 +3010,9 @@ class PdfiumNative {
|
|
|
2497
3010
|
if (annotation.created && !this.setAnnotationDate(annotationPtr, "CreationDate", annotation.created)) {
|
|
2498
3011
|
return false;
|
|
2499
3012
|
}
|
|
3013
|
+
if (annotation.custom && !this.setAnnotCustom(annotationPtr, annotation.custom)) {
|
|
3014
|
+
return false;
|
|
3015
|
+
}
|
|
2500
3016
|
if (annotation.flags && !this.setAnnotationFlags(annotationPtr, annotation.flags)) {
|
|
2501
3017
|
return false;
|
|
2502
3018
|
}
|
|
@@ -2506,6 +3022,9 @@ class PdfiumNative {
|
|
|
2506
3022
|
if (annotation.icon && !this.setAnnotationIcon(annotationPtr, annotation.icon)) {
|
|
2507
3023
|
return false;
|
|
2508
3024
|
}
|
|
3025
|
+
if (!this.setAnnotString(annotationPtr, "T", annotation.author || "")) {
|
|
3026
|
+
return false;
|
|
3027
|
+
}
|
|
2509
3028
|
if (annotation.subject && !this.setAnnotString(annotationPtr, "Subj", annotation.subject)) {
|
|
2510
3029
|
return false;
|
|
2511
3030
|
}
|
|
@@ -6764,7 +7283,10 @@ async function createPdfiumEngine(wasmUrl, options) {
|
|
|
6764
7283
|
const response = await fetch(wasmUrl);
|
|
6765
7284
|
const wasmBinary = await response.arrayBuffer();
|
|
6766
7285
|
const wasmModule = await init({ wasmBinary });
|
|
6767
|
-
const native = new PdfiumNative(wasmModule, {
|
|
7286
|
+
const native = new PdfiumNative(wasmModule, {
|
|
7287
|
+
logger: options == null ? void 0 : options.logger,
|
|
7288
|
+
fontFallback: options == null ? void 0 : options.fontFallback
|
|
7289
|
+
});
|
|
6768
7290
|
return new PdfEngine(native, {
|
|
6769
7291
|
imageConverter: browserImageDataToBlobConverter,
|
|
6770
7292
|
logger: options == null ? void 0 : options.logger
|
|
@@ -6772,13 +7294,15 @@ async function createPdfiumEngine(wasmUrl, options) {
|
|
|
6772
7294
|
}
|
|
6773
7295
|
export {
|
|
6774
7296
|
BitmapFormat as B,
|
|
7297
|
+
FontFallbackManager as F,
|
|
6775
7298
|
PdfiumErrorCode as P,
|
|
6776
7299
|
RenderFlag as R,
|
|
6777
7300
|
PdfiumNative as a,
|
|
6778
7301
|
readArrayBuffer as b,
|
|
6779
7302
|
createPdfiumEngine as c,
|
|
6780
7303
|
computeFormDrawParams as d,
|
|
7304
|
+
createNodeFontLoader as e,
|
|
6781
7305
|
isValidCustomKey as i,
|
|
6782
7306
|
readString as r
|
|
6783
7307
|
};
|
|
6784
|
-
//# sourceMappingURL=direct-engine-
|
|
7308
|
+
//# sourceMappingURL=direct-engine-CB3k-o0I.js.map
|