@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.
Files changed (50) hide show
  1. package/dist/direct-engine-BeZ18SKz.cjs +2 -0
  2. package/dist/direct-engine-BeZ18SKz.cjs.map +1 -0
  3. package/dist/{direct-engine-DuLFAbiv.js → direct-engine-CB3k-o0I.js} +533 -9
  4. package/dist/direct-engine-CB3k-o0I.js.map +1 -0
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.js +11 -4
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/orchestrator/remote-executor.d.ts +5 -0
  10. package/dist/lib/pdfium/cdn-fonts.d.ts +50 -0
  11. package/dist/lib/pdfium/engine.d.ts +17 -2
  12. package/dist/lib/pdfium/font-fallback.d.ts +207 -0
  13. package/dist/lib/pdfium/index.cjs +1 -1
  14. package/dist/lib/pdfium/index.cjs.map +1 -1
  15. package/dist/lib/pdfium/index.d.ts +2 -0
  16. package/dist/lib/pdfium/index.js +55 -2
  17. package/dist/lib/pdfium/index.js.map +1 -1
  18. package/dist/lib/pdfium/runner.d.ts +5 -1
  19. package/dist/lib/pdfium/web/direct-engine.cjs +1 -1
  20. package/dist/lib/pdfium/web/direct-engine.d.ts +8 -0
  21. package/dist/lib/pdfium/web/direct-engine.js +1 -1
  22. package/dist/lib/pdfium/web/worker-engine.cjs +1 -1
  23. package/dist/lib/pdfium/web/worker-engine.cjs.map +1 -1
  24. package/dist/lib/pdfium/web/worker-engine.d.ts +8 -0
  25. package/dist/lib/pdfium/web/worker-engine.js +5 -4
  26. package/dist/lib/pdfium/web/worker-engine.js.map +1 -1
  27. package/dist/preact/index.cjs +1 -1
  28. package/dist/preact/index.cjs.map +1 -1
  29. package/dist/preact/index.js +14 -4
  30. package/dist/preact/index.js.map +1 -1
  31. package/dist/react/index.cjs +1 -1
  32. package/dist/react/index.cjs.map +1 -1
  33. package/dist/react/index.js +14 -4
  34. package/dist/react/index.js.map +1 -1
  35. package/dist/shared-preact/hooks/use-pdfium-engine.d.ts +5 -0
  36. package/dist/shared-react/hooks/use-pdfium-engine.d.ts +5 -0
  37. package/dist/svelte/hooks/use-pdfium-engine.svelte.d.ts +5 -0
  38. package/dist/svelte/index.cjs +1 -1
  39. package/dist/svelte/index.cjs.map +1 -1
  40. package/dist/svelte/index.js +8 -3
  41. package/dist/svelte/index.js.map +1 -1
  42. package/dist/vue/composables/use-pdfium-engine.d.ts +5 -0
  43. package/dist/vue/index.cjs +1 -1
  44. package/dist/vue/index.cjs.map +1 -1
  45. package/dist/vue/index.js +4 -4
  46. package/dist/vue/index.js.map +1 -1
  47. package/package.json +10 -3
  48. package/dist/direct-engine-DuLFAbiv.js.map +0 -1
  49. package/dist/direct-engine-JeNRkc7w.cjs +0 -2
  50. 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$1 = "PDFiumEngine";
384
- const LOG_CATEGORY$1 = "MemoryManager";
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$1, LOG_CATEGORY$1, `Freeing untracked pointer: ${ptr}`);
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$1,
445
- LOG_CATEGORY$1,
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$1, LOG_CATEGORY$1, ` - ${ptr}: ${alloc.size} bytes`, alloc.stack);
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
- const { logger = new NoopLogger() } = options;
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, { logger: options == null ? void 0 : options.logger });
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-DuLFAbiv.js.map
7308
+ //# sourceMappingURL=direct-engine-CB3k-o0I.js.map