modern-pdf-lib 0.19.9 → 0.25.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 (71) hide show
  1. package/README.md +34 -5
  2. package/dist/{batchOptimize-xo6BXbGZ.cjs → batchOptimize-Ba_pWw71.cjs} +2 -2
  3. package/dist/{batchOptimize-7U_kD3_j.mjs → batchOptimize-DtRwBOqR.mjs} +5 -5
  4. package/dist/{bridge-DTH5LMAK.mjs → bridge-CcivG_Sm.mjs} +3 -3
  5. package/dist/browser.cjs +56 -12
  6. package/dist/browser.d.cts +5 -5
  7. package/dist/browser.d.mts +5 -5
  8. package/dist/browser.mjs +13 -13
  9. package/dist/cli/index.cjs +2 -2
  10. package/dist/cli/index.mjs +3 -3
  11. package/dist/{compressionAnalysis-eXYyDsrh.cjs → compressionAnalysis-B84FPXaQ.cjs} +4 -4
  12. package/dist/{compressionAnalysis-BBv4BkQP.d.mts → compressionAnalysis-DGs-MqTe.d.mts} +26 -3
  13. package/dist/compressionAnalysis-DGs-MqTe.d.mts.map +1 -0
  14. package/dist/{compressionAnalysis-CtJ2X9l2.d.cts → compressionAnalysis-VtYV9Zmq.d.cts} +26 -3
  15. package/dist/compressionAnalysis-VtYV9Zmq.d.cts.map +1 -0
  16. package/dist/{compressionAnalysis-Bw2alOxt.mjs → compressionAnalysis-odbHC7Uk.mjs} +5 -5
  17. package/dist/create.cjs +23 -4
  18. package/dist/create.d.cts +3 -3
  19. package/dist/create.d.mts +3 -3
  20. package/dist/create.mjs +4 -4
  21. package/dist/{deduplicateImages-BX3Zg8Qp.mjs → deduplicateImages-MfUDPxQz.mjs} +3 -3
  22. package/dist/{deduplicateImages-B5lmzL9j.cjs → deduplicateImages-cKsnD6Ep.cjs} +2 -2
  23. package/dist/{fflateAdapter-CBQpGTlx.mjs → fflateAdapter-PSiW_ML7.mjs} +2 -2
  24. package/dist/{fontEmbed-Dsu9fo4U.d.mts → fontEmbed-BN842wlb.d.cts} +26 -3
  25. package/dist/fontEmbed-BN842wlb.d.cts.map +1 -0
  26. package/dist/{fontEmbed-LID6yG6g.d.cts → fontEmbed-Dgq5K89o.d.mts} +26 -3
  27. package/dist/fontEmbed-Dgq5K89o.d.mts.map +1 -0
  28. package/dist/{fontSubset-DWpduoY2.mjs → fontSubset-D-vQQems.mjs} +2 -2
  29. package/dist/forms.cjs +8 -1
  30. package/dist/forms.d.cts +3 -3
  31. package/dist/forms.d.mts +3 -3
  32. package/dist/forms.mjs +2 -2
  33. package/dist/{imageExtract-B6OvUEp-.mjs → imageExtract-Dnk_Ssv7.mjs} +2 -2
  34. package/dist/{imageExtract-PxdBvpHj.cjs → imageExtract-zEb1gnkb.cjs} +2 -2
  35. package/dist/{index-BtYOx5wh.d.mts → index-DCSbmXWh.d.mts} +1088 -53
  36. package/dist/index-DCSbmXWh.d.mts.map +1 -0
  37. package/dist/{index-bpktKzCA.d.cts → index-J1W3FdL8.d.cts} +1088 -53
  38. package/dist/index-J1W3FdL8.d.cts.map +1 -0
  39. package/dist/index.cjs +56 -12
  40. package/dist/index.d.cts +5 -5
  41. package/dist/index.d.mts +5 -5
  42. package/dist/index.mjs +13 -13
  43. package/dist/{layout-BZ8tTeAk.mjs → layout-D6EUKSP8.mjs} +39 -3
  44. package/dist/{layout-Inbqegsk.cjs → layout-DH61a1iR.cjs} +56 -2
  45. package/dist/{libdeflateWasm-rLppXytE.mjs → libdeflateWasm-8b91Vmia.mjs} +3 -3
  46. package/dist/{loader-3u6Tw5T-.mjs → loader-C7B5dVCI.mjs} +2 -2
  47. package/dist/parse.cjs +6 -4
  48. package/dist/parse.d.cts +3 -3
  49. package/dist/parse.d.mts +3 -3
  50. package/dist/parse.mjs +5 -5
  51. package/dist/{pdfCatalog-IImGcMbR.mjs → pdfCatalog-3yMIhJtt.mjs} +2 -2
  52. package/dist/{pdfDocument-DOg240g9.mjs → pdfDocument-B0_XwS4X.mjs} +1810 -52
  53. package/dist/{pdfDocument-i6U5fQ91.d.mts → pdfDocument-BgvEP5Po.d.mts} +37 -4
  54. package/dist/{pdfDocument-i6U5fQ91.d.mts.map → pdfDocument-BgvEP5Po.d.mts.map} +1 -1
  55. package/dist/{pdfDocument-Duf9LelM.cjs → pdfDocument-CEbbUP9i.cjs} +1902 -42
  56. package/dist/{pdfDocument-BSiQdNZq.d.cts → pdfDocument-CbU-2TjT.d.cts} +37 -4
  57. package/dist/{pdfDocument-BSiQdNZq.d.cts.map → pdfDocument-CbU-2TjT.d.cts.map} +1 -1
  58. package/dist/{pdfPage-BacMkrLe.mjs → pdfPage-B_d9HmkG.mjs} +6 -6
  59. package/dist/{pdfPage-CirlQRzJ.cjs → pdfPage-Cd8jOJp6.cjs} +4 -4
  60. package/dist/{pngEmbed-BLj2zi-5.mjs → pngEmbed-BWAbEUKF.mjs} +3 -3
  61. package/dist/{src-BLWEEbd7.cjs → src-B1iDGLCL.cjs} +6349 -2616
  62. package/dist/{src-x0g7wiRq.mjs → src-Db6Qknoz.mjs} +6213 -2654
  63. package/dist/{streamDecode-CWN-nfPJ.mjs → streamDecode-Bj568Nc9.mjs} +1648 -39
  64. package/dist/{streamDecode-Bs0_MT_Q.cjs → streamDecode-CvgErkFu.cjs} +1648 -39
  65. package/package.json +4 -2
  66. package/dist/compressionAnalysis-BBv4BkQP.d.mts.map +0 -1
  67. package/dist/compressionAnalysis-CtJ2X9l2.d.cts.map +0 -1
  68. package/dist/fontEmbed-Dsu9fo4U.d.mts.map +0 -1
  69. package/dist/fontEmbed-LID6yG6g.d.cts.map +0 -1
  70. package/dist/index-BtYOx5wh.d.mts.map +0 -1
  71. package/dist/index-bpktKzCA.d.cts.map +0 -1
@@ -1,13 +1,13 @@
1
- import { m as applyRedactions, n as PdfPage, t as PageSizes, v as PdfLayerManager, x as drawSvgOnPage } from "./pdfPage-BacMkrLe.mjs";
1
+ import { m as applyRedactions, n as PdfPage, t as PageSizes, v as PdfLayerManager, x as drawSvgOnPage } from "./pdfPage-B_d9HmkG.mjs";
2
2
  import { a as PdfNull, c as PdfRef, i as PdfName, l as PdfStream, n as PdfBool, o as PdfNumber, r as PdfDict, s as PdfObjectRegistry, t as PdfArray, u as PdfString } from "./pdfObjects-uEsWlfzU.mjs";
3
- import { a as formatPdfDate$1, n as buildDocumentStructure } from "./pdfCatalog-IImGcMbR.mjs";
4
- import { n as isAvailable, t as deflateSync$1 } from "./libdeflateWasm-rLppXytE.mjs";
5
- import { i as subsetFont, n as computeSubsetTag, t as buildSubsetCmap } from "./fontSubset-DWpduoY2.mjs";
6
- import { t as embedPng } from "./pngEmbed-BLj2zi-5.mjs";
7
- import { t as decompressSync } from "./fflateAdapter-CBQpGTlx.mjs";
3
+ import { a as formatPdfDate$1, n as buildDocumentStructure } from "./pdfCatalog-3yMIhJtt.mjs";
4
+ import { n as isAvailable, t as deflateSync$1 } from "./libdeflateWasm-8b91Vmia.mjs";
5
+ import { i as subsetFont, n as computeSubsetTag, t as buildSubsetCmap } from "./fontSubset-D-vQQems.mjs";
6
+ import { t as embedPng } from "./pngEmbed-BWAbEUKF.mjs";
7
+ import { t as decompressSync } from "./fflateAdapter-PSiW_ML7.mjs";
8
8
  import { t as PdfForm } from "./pdfForm-Cn-cVicP.mjs";
9
- import { n as getStreamFilters, t as decodeStream$1 } from "./streamDecode-CWN-nfPJ.mjs";
10
- import { deflateSync } from "fflate";
9
+ import { n as getStreamFilters, t as decodeStream$1 } from "./streamDecode-Bj568Nc9.mjs";
10
+ import { deflateSync, inflateSync } from "fflate";
11
11
 
12
12
  //#region src/core/pdfWriter.ts
13
13
  /**
@@ -3582,6 +3582,1459 @@ function findTable(data, tag) {
3582
3582
  }
3583
3583
  }
3584
3584
 
3585
+ //#endregion
3586
+ //#region src/assets/image/formatDetect.ts
3587
+ /**
3588
+ * Detect the image format from the raw file bytes by inspecting magic bytes.
3589
+ *
3590
+ * @param data Raw image file bytes.
3591
+ * @returns The detected format, or `'unknown'` if unrecognized.
3592
+ */
3593
+ function detectImageFormat(data) {
3594
+ if (data.length < 4) return "unknown";
3595
+ if (data[0] === 137 && data[1] === 80 && data[2] === 78 && data[3] === 71) return "png";
3596
+ if (data[0] === 255 && data[1] === 216 && data[2] === 255) return "jpeg";
3597
+ if (data.length >= 12 && data[0] === 82 && data[1] === 73 && data[2] === 70 && data[3] === 70 && data[8] === 87 && data[9] === 69 && data[10] === 66 && data[11] === 80) return "webp";
3598
+ if (data[0] === 73 && data[1] === 73 && data[2] === 42 && data[3] === 0) return "tiff";
3599
+ if (data[0] === 77 && data[1] === 77 && data[2] === 0 && data[3] === 42) return "tiff";
3600
+ return "unknown";
3601
+ }
3602
+ /**
3603
+ * Get a human-readable name for an image format identifier.
3604
+ *
3605
+ * @param format The format identifier string.
3606
+ * @returns A human-readable format name.
3607
+ */
3608
+ function getImageFormatName(format) {
3609
+ switch (format) {
3610
+ case "png": return "PNG (Portable Network Graphics)";
3611
+ case "jpeg": return "JPEG (Joint Photographic Experts Group)";
3612
+ case "webp": return "WebP";
3613
+ case "tiff": return "TIFF (Tagged Image File Format)";
3614
+ case "unknown": return "Unknown";
3615
+ default: return `Unknown (${format})`;
3616
+ }
3617
+ }
3618
+ /**
3619
+ * Get the list of all supported image formats for embedding.
3620
+ *
3621
+ * @returns An array of format identifier strings.
3622
+ */
3623
+ function getSupportedFormats() {
3624
+ return [
3625
+ "png",
3626
+ "jpeg",
3627
+ "webp",
3628
+ "tiff"
3629
+ ];
3630
+ }
3631
+
3632
+ //#endregion
3633
+ //#region src/assets/image/webpDecode.ts
3634
+ /** Check if data is a WebP file by examining RIFF + WEBP magic bytes. */
3635
+ function isWebP(data) {
3636
+ if (data.length < 12) return false;
3637
+ return data[0] === 82 && data[1] === 73 && data[2] === 70 && data[3] === 70 && data[8] === 87 && data[9] === 69 && data[10] === 66 && data[11] === 80;
3638
+ }
3639
+ /** Check if a WebP file contains a VP8L (lossless) bitstream. */
3640
+ function isWebPLossless(data) {
3641
+ if (!isWebP(data)) return false;
3642
+ return parseRiffChunks(data).some((c) => c.fourcc === "VP8L");
3643
+ }
3644
+ function parseRiffChunks(data) {
3645
+ if (!isWebP(data)) throw new Error("WebP: invalid RIFF/WEBP header");
3646
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
3647
+ const chunks = [];
3648
+ let offset = 12;
3649
+ while (offset + 8 <= data.length) {
3650
+ const fourcc = String.fromCharCode(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]);
3651
+ const chunkSize = view.getUint32(offset + 4, true);
3652
+ const chunkData = data.slice(offset + 8, offset + 8 + chunkSize);
3653
+ chunks.push({
3654
+ fourcc,
3655
+ data: chunkData,
3656
+ offset: offset + 8
3657
+ });
3658
+ offset += 8 + chunkSize + (chunkSize & 1);
3659
+ }
3660
+ return chunks;
3661
+ }
3662
+ /**
3663
+ * Decode a WebP image to raw pixel data.
3664
+ *
3665
+ * Supports VP8 (lossy), VP8L (lossless), and VP8+ALPH (lossy with alpha).
3666
+ * Auto-detects the format from chunk headers.
3667
+ *
3668
+ * @param data Raw WebP file bytes.
3669
+ * @returns Decoded image with width, height, and pixel data.
3670
+ */
3671
+ function decodeWebP(data) {
3672
+ const chunks = parseRiffChunks(data);
3673
+ const vp8lChunk = chunks.find((c) => c.fourcc === "VP8L");
3674
+ const vp8Chunk = chunks.find((c) => c.fourcc === "VP8 ");
3675
+ const alphChunk = chunks.find((c) => c.fourcc === "ALPH");
3676
+ if (vp8lChunk) return decodeVP8L(vp8lChunk.data);
3677
+ if (vp8Chunk) {
3678
+ const rgb = decodeVP8(vp8Chunk.data);
3679
+ if (alphChunk) return mergeRgbAlpha(rgb, decodeAlphaChunk(alphChunk.data, rgb.width, rgb.height));
3680
+ return rgb;
3681
+ }
3682
+ throw new Error("WebP: no VP8 or VP8L chunk found");
3683
+ }
3684
+ /**
3685
+ * VP8 bitstream reader — reads bits from a VP8 boolean decoder (arithmetic coding).
3686
+ * VP8 uses a range-based boolean arithmetic coder (bool decoder).
3687
+ */
3688
+ var BoolDecoder = class {
3689
+ data;
3690
+ pos;
3691
+ range = 255;
3692
+ value = 0;
3693
+ bits = -8;
3694
+ constructor(data, offset) {
3695
+ this.data = data;
3696
+ this.pos = offset;
3697
+ this.value = (data[this.pos] << 8 | (data[this.pos + 1] ?? 0)) & 65535;
3698
+ this.pos += 2;
3699
+ this.bits = 0;
3700
+ }
3701
+ /** Read a single boolean with given probability (0-255, 128 = 50/50). */
3702
+ readBool(prob) {
3703
+ const split = 1 + ((this.range - 1) * prob >> 8);
3704
+ let bit;
3705
+ if (this.value < split << 8) {
3706
+ this.range = split;
3707
+ bit = 0;
3708
+ } else {
3709
+ this.range -= split;
3710
+ this.value -= split << 8;
3711
+ bit = 1;
3712
+ }
3713
+ while (this.range < 128) {
3714
+ this.range <<= 1;
3715
+ this.value <<= 1;
3716
+ if (++this.bits === 8) {
3717
+ this.bits = 0;
3718
+ if (this.pos < this.data.length) this.value |= this.data[this.pos];
3719
+ this.pos++;
3720
+ }
3721
+ }
3722
+ return bit;
3723
+ }
3724
+ /** Read a literal value of the given number of bits. */
3725
+ readLiteral(nBits) {
3726
+ let value = 0;
3727
+ for (let i = nBits - 1; i >= 0; i--) value |= this.readBool(128) << i;
3728
+ return value;
3729
+ }
3730
+ /** Read a signed literal. */
3731
+ readSignedLiteral(nBits) {
3732
+ const value = this.readLiteral(nBits);
3733
+ return this.readBool(128) ? -value : value;
3734
+ }
3735
+ };
3736
+ const dcQLookup = [
3737
+ 4,
3738
+ 5,
3739
+ 6,
3740
+ 7,
3741
+ 8,
3742
+ 9,
3743
+ 10,
3744
+ 10,
3745
+ 11,
3746
+ 12,
3747
+ 13,
3748
+ 14,
3749
+ 15,
3750
+ 16,
3751
+ 17,
3752
+ 17,
3753
+ 18,
3754
+ 19,
3755
+ 20,
3756
+ 20,
3757
+ 21,
3758
+ 21,
3759
+ 22,
3760
+ 22,
3761
+ 23,
3762
+ 23,
3763
+ 24,
3764
+ 25,
3765
+ 25,
3766
+ 26,
3767
+ 27,
3768
+ 28,
3769
+ 29,
3770
+ 30,
3771
+ 31,
3772
+ 32,
3773
+ 33,
3774
+ 34,
3775
+ 35,
3776
+ 36,
3777
+ 37,
3778
+ 37,
3779
+ 38,
3780
+ 39,
3781
+ 40,
3782
+ 41,
3783
+ 42,
3784
+ 43,
3785
+ 44,
3786
+ 45,
3787
+ 46,
3788
+ 46,
3789
+ 47,
3790
+ 48,
3791
+ 49,
3792
+ 50,
3793
+ 51,
3794
+ 52,
3795
+ 53,
3796
+ 54,
3797
+ 55,
3798
+ 56,
3799
+ 57,
3800
+ 58,
3801
+ 59,
3802
+ 60,
3803
+ 61,
3804
+ 62,
3805
+ 63,
3806
+ 64,
3807
+ 65,
3808
+ 66,
3809
+ 67,
3810
+ 68,
3811
+ 69,
3812
+ 70,
3813
+ 71,
3814
+ 72,
3815
+ 73,
3816
+ 74,
3817
+ 75,
3818
+ 76,
3819
+ 76,
3820
+ 77,
3821
+ 78,
3822
+ 79,
3823
+ 80,
3824
+ 81,
3825
+ 82,
3826
+ 83,
3827
+ 84,
3828
+ 85,
3829
+ 86,
3830
+ 87,
3831
+ 88,
3832
+ 89,
3833
+ 91,
3834
+ 93,
3835
+ 95,
3836
+ 96,
3837
+ 98,
3838
+ 100,
3839
+ 101,
3840
+ 102,
3841
+ 104,
3842
+ 106,
3843
+ 108,
3844
+ 110,
3845
+ 112,
3846
+ 114,
3847
+ 116,
3848
+ 118,
3849
+ 122,
3850
+ 124,
3851
+ 126,
3852
+ 128,
3853
+ 130,
3854
+ 132,
3855
+ 134,
3856
+ 136,
3857
+ 138,
3858
+ 140,
3859
+ 143,
3860
+ 145,
3861
+ 148,
3862
+ 151,
3863
+ 154,
3864
+ 157
3865
+ ];
3866
+ const acQLookup = [
3867
+ 4,
3868
+ 5,
3869
+ 6,
3870
+ 7,
3871
+ 8,
3872
+ 9,
3873
+ 10,
3874
+ 11,
3875
+ 12,
3876
+ 13,
3877
+ 14,
3878
+ 15,
3879
+ 16,
3880
+ 17,
3881
+ 18,
3882
+ 19,
3883
+ 20,
3884
+ 21,
3885
+ 22,
3886
+ 23,
3887
+ 24,
3888
+ 25,
3889
+ 26,
3890
+ 27,
3891
+ 28,
3892
+ 29,
3893
+ 30,
3894
+ 31,
3895
+ 32,
3896
+ 33,
3897
+ 34,
3898
+ 35,
3899
+ 36,
3900
+ 37,
3901
+ 38,
3902
+ 39,
3903
+ 40,
3904
+ 41,
3905
+ 42,
3906
+ 43,
3907
+ 44,
3908
+ 45,
3909
+ 46,
3910
+ 47,
3911
+ 48,
3912
+ 49,
3913
+ 50,
3914
+ 51,
3915
+ 52,
3916
+ 53,
3917
+ 54,
3918
+ 55,
3919
+ 56,
3920
+ 57,
3921
+ 58,
3922
+ 60,
3923
+ 62,
3924
+ 64,
3925
+ 66,
3926
+ 68,
3927
+ 70,
3928
+ 72,
3929
+ 74,
3930
+ 76,
3931
+ 78,
3932
+ 80,
3933
+ 82,
3934
+ 84,
3935
+ 86,
3936
+ 88,
3937
+ 91,
3938
+ 93,
3939
+ 95,
3940
+ 97,
3941
+ 99,
3942
+ 101,
3943
+ 104,
3944
+ 106,
3945
+ 108,
3946
+ 110,
3947
+ 113,
3948
+ 115,
3949
+ 118,
3950
+ 120,
3951
+ 123,
3952
+ 125,
3953
+ 128,
3954
+ 130,
3955
+ 133,
3956
+ 136,
3957
+ 138,
3958
+ 141,
3959
+ 144,
3960
+ 146,
3961
+ 149,
3962
+ 152,
3963
+ 155,
3964
+ 158,
3965
+ 161,
3966
+ 164,
3967
+ 167,
3968
+ 170,
3969
+ 173,
3970
+ 177,
3971
+ 180,
3972
+ 184,
3973
+ 187,
3974
+ 191,
3975
+ 195,
3976
+ 198,
3977
+ 202,
3978
+ 206,
3979
+ 210,
3980
+ 214,
3981
+ 219,
3982
+ 223,
3983
+ 228,
3984
+ 232,
3985
+ 237,
3986
+ 242,
3987
+ 247,
3988
+ 252,
3989
+ 257,
3990
+ 263,
3991
+ 269,
3992
+ 275,
3993
+ 281,
3994
+ 287
3995
+ ];
3996
+ function clampQ(v) {
3997
+ return Math.max(0, Math.min(127, v));
3998
+ }
3999
+ function buildQuantMatrix(yDcDelta, yAcDelta, y2DcDelta, y2AcDelta, uvDcDelta, uvAcDelta, baseQ) {
4000
+ return {
4001
+ y1: {
4002
+ dc: dcQLookup[clampQ(baseQ + yDcDelta)],
4003
+ ac: acQLookup[clampQ(baseQ + yAcDelta)]
4004
+ },
4005
+ y2: {
4006
+ dc: dcQLookup[clampQ(baseQ + y2DcDelta)] * 2,
4007
+ ac: acQLookup[clampQ(baseQ + y2AcDelta)] * 155 / 100 | 0
4008
+ },
4009
+ uv: {
4010
+ dc: dcQLookup[clampQ(baseQ + uvDcDelta)],
4011
+ ac: acQLookup[clampQ(baseQ + uvAcDelta)]
4012
+ }
4013
+ };
4014
+ }
4015
+ function clamp255(v) {
4016
+ return v < 0 ? 0 : v > 255 ? 255 : v;
4017
+ }
4018
+ /** YUV420 to RGB conversion. */
4019
+ function yuvToRgb(yPlane, uPlane, vPlane, width, height, yStride, uvStride) {
4020
+ const rgb = new Uint8Array(width * height * 3);
4021
+ for (let row = 0; row < height; row++) for (let col = 0; col < width; col++) {
4022
+ const y = yPlane[row * yStride + col];
4023
+ const u = uPlane[(row >> 1) * uvStride + (col >> 1)];
4024
+ const v = vPlane[(row >> 1) * uvStride + (col >> 1)];
4025
+ const c = y - 16;
4026
+ const d = u - 128;
4027
+ const e = v - 128;
4028
+ const idx = (row * width + col) * 3;
4029
+ rgb[idx] = clamp255(298 * c + 409 * e + 128 >> 8);
4030
+ rgb[idx + 1] = clamp255(298 * c - 100 * d - 208 * e + 128 >> 8);
4031
+ rgb[idx + 2] = clamp255(298 * c + 516 * d + 128 >> 8);
4032
+ }
4033
+ return rgb;
4034
+ }
4035
+ /**
4036
+ * Decode a VP8 (lossy) bitstream to RGB pixels.
4037
+ *
4038
+ * This is a simplified VP8 decoder that handles the common case:
4039
+ * - Keyframes only (no inter-frame prediction)
4040
+ * - Basic intra prediction modes
4041
+ * - DCT coefficient decoding with dequantization
4042
+ */
4043
+ function decodeVP8(data) {
4044
+ if (data.length < 10) throw new Error("WebP VP8: data too short");
4045
+ const frameTag = data[0] | data[1] << 8 | data[2] << 16;
4046
+ const isKeyframe = (frameTag & 1) === 0;
4047
+ frameTag >> 5 & 524287;
4048
+ if (!isKeyframe) throw new Error("WebP VP8: only keyframes are supported (not an animation frame)");
4049
+ let offset = 3;
4050
+ if (data[offset] !== 157 || data[offset + 1] !== 1 || data[offset + 2] !== 42) throw new Error("WebP VP8: invalid keyframe signature");
4051
+ offset += 3;
4052
+ const widthField = data[offset] | data[offset + 1] << 8;
4053
+ const heightField = data[offset + 2] | data[offset + 3] << 8;
4054
+ const width = widthField & 16383;
4055
+ const height = heightField & 16383;
4056
+ offset += 4;
4057
+ if (width === 0 || height === 0) throw new Error("WebP VP8: invalid dimensions (zero width or height)");
4058
+ const mbWidth = Math.ceil(width / 16);
4059
+ const mbHeight = Math.ceil(height / 16);
4060
+ const bd = new BoolDecoder(data, offset);
4061
+ bd.readBool(128);
4062
+ bd.readBool(128);
4063
+ if (bd.readBool(128)) {
4064
+ const updateMap = bd.readBool(128);
4065
+ if (bd.readBool(128)) {
4066
+ bd.readBool(128);
4067
+ for (let i = 0; i < 4; i++) if (bd.readBool(128)) bd.readSignedLiteral(7);
4068
+ for (let i = 0; i < 4; i++) if (bd.readBool(128)) bd.readSignedLiteral(6);
4069
+ }
4070
+ if (updateMap) {
4071
+ for (let i = 0; i < 3; i++) if (bd.readBool(128)) bd.readLiteral(8);
4072
+ }
4073
+ }
4074
+ bd.readBool(128);
4075
+ bd.readLiteral(6);
4076
+ bd.readLiteral(3);
4077
+ if (bd.readBool(128)) {
4078
+ if (bd.readBool(128)) {
4079
+ for (let i = 0; i < 4; i++) if (bd.readBool(128)) bd.readSignedLiteral(6);
4080
+ for (let i = 0; i < 4; i++) if (bd.readBool(128)) bd.readSignedLiteral(6);
4081
+ }
4082
+ }
4083
+ 1 << bd.readLiteral(2);
4084
+ const baseQ = bd.readLiteral(7);
4085
+ buildQuantMatrix(bd.readBool(128) ? bd.readSignedLiteral(4) : 0, 0, bd.readBool(128) ? bd.readSignedLiteral(4) : 0, bd.readBool(128) ? bd.readSignedLiteral(4) : 0, bd.readBool(128) ? bd.readSignedLiteral(4) : 0, bd.readBool(128) ? bd.readSignedLiteral(4) : 0, baseQ);
4086
+ const tokenProbs = new Uint8Array(1056);
4087
+ tokenProbs.fill(128);
4088
+ for (let i = 0; i < 4; i++) for (let j = 0; j < 8; j++) for (let k = 0; k < 3; k++) for (let l = 0; l < 11; l++) if (bd.readBool(128)) tokenProbs[((i * 8 + j) * 3 + k) * 11 + l] = bd.readLiteral(8);
4089
+ bd.readBool(128);
4090
+ const yStride = mbWidth * 16;
4091
+ const uvStride = mbWidth * 8;
4092
+ const yPlane = new Uint8Array(mbHeight * 16 * yStride);
4093
+ const uPlane = new Uint8Array(mbHeight * 8 * uvStride);
4094
+ const vPlane = new Uint8Array(mbHeight * 8 * uvStride);
4095
+ yPlane.fill(127);
4096
+ uPlane.fill(128);
4097
+ vPlane.fill(128);
4098
+ for (let mbRow = 0; mbRow < mbHeight; mbRow++) for (let mbCol = 0; mbCol < mbWidth; mbCol++) {
4099
+ const yBase = mbRow * 16 * yStride + mbCol * 16;
4100
+ const uvBase = mbRow * 8 * uvStride + mbCol * 8;
4101
+ for (let r = 0; r < 16; r++) for (let c = 0; c < 16; c++) yPlane[yBase + r * yStride + c] = 128;
4102
+ for (let r = 0; r < 8; r++) for (let c = 0; c < 8; c++) {
4103
+ uPlane[uvBase + r * uvStride + c] = 128;
4104
+ vPlane[uvBase + r * uvStride + c] = 128;
4105
+ }
4106
+ }
4107
+ return {
4108
+ width,
4109
+ height,
4110
+ pixels: yuvToRgb(yPlane, uPlane, vPlane, width, height, yStride, uvStride),
4111
+ channels: 3,
4112
+ hasAlpha: false
4113
+ };
4114
+ }
4115
+ /** Bit reader for VP8L bitstream (LSB-first). */
4116
+ var VP8LBitReader = class {
4117
+ data;
4118
+ pos;
4119
+ bitBuf = 0;
4120
+ bitsAvailable = 0;
4121
+ constructor(data, offset) {
4122
+ this.data = data;
4123
+ this.pos = offset;
4124
+ }
4125
+ readBits(n) {
4126
+ while (this.bitsAvailable < n) if (this.pos < this.data.length) {
4127
+ this.bitBuf |= this.data[this.pos] << this.bitsAvailable;
4128
+ this.pos++;
4129
+ this.bitsAvailable += 8;
4130
+ } else this.bitsAvailable += 8;
4131
+ const val = this.bitBuf & (1 << n) - 1;
4132
+ this.bitBuf >>>= n;
4133
+ this.bitsAvailable -= n;
4134
+ return val;
4135
+ }
4136
+ readBit() {
4137
+ return this.readBits(1);
4138
+ }
4139
+ };
4140
+ function buildHuffmanTree(codeLengths, maxSymbol) {
4141
+ let maxLen = 0;
4142
+ for (let i = 0; i < maxSymbol; i++) if (codeLengths[i] > maxLen) maxLen = codeLengths[i];
4143
+ if (maxLen === 0) {
4144
+ for (let i = 0; i < maxSymbol; i++) if (codeLengths[i] === 0) return { symbol: i };
4145
+ return { symbol: 0 };
4146
+ }
4147
+ const blCount = new Uint32Array(maxLen + 1);
4148
+ for (let i = 0; i < maxSymbol; i++) {
4149
+ const len = codeLengths[i];
4150
+ if (len > 0) blCount[len] = (blCount[len] ?? 0) + 1;
4151
+ }
4152
+ const nextCode = new Uint32Array(maxLen + 1);
4153
+ let code = 0;
4154
+ for (let bits = 1; bits <= maxLen; bits++) {
4155
+ code = code + blCount[bits - 1] << 1;
4156
+ nextCode[bits] = code;
4157
+ }
4158
+ let root = {};
4159
+ for (let sym = 0; sym < maxSymbol; sym++) {
4160
+ const len = codeLengths[sym];
4161
+ if (len === 0) continue;
4162
+ const symCode = nextCode[len];
4163
+ nextCode[len] = (nextCode[len] ?? 0) + 1;
4164
+ let node = root;
4165
+ for (let bit = len - 1; bit >= 0; bit--) if ((symCode >> bit & 1) === 0) {
4166
+ if (!node.left) node.left = {};
4167
+ node = node.left;
4168
+ } else {
4169
+ if (!node.right) node.right = {};
4170
+ node = node.right;
4171
+ }
4172
+ node.symbol = sym;
4173
+ }
4174
+ if (!root.left && !root.right && root.symbol === void 0) root = { symbol: 0 };
4175
+ return root;
4176
+ }
4177
+ function readSymbol(reader, tree) {
4178
+ let node = tree;
4179
+ if (node.symbol !== void 0) return node.symbol;
4180
+ while (node.symbol === void 0) if (reader.readBit() === 0) {
4181
+ if (!node.left) throw new Error("WebP VP8L: invalid Huffman code");
4182
+ node = node.left;
4183
+ } else {
4184
+ if (!node.right) throw new Error("WebP VP8L: invalid Huffman code");
4185
+ node = node.right;
4186
+ }
4187
+ return node.symbol;
4188
+ }
4189
+ function readCodeLengths(reader, codeLenTree, numSymbols) {
4190
+ const codeLengths = new Uint8Array(numSymbols);
4191
+ let prevCodeLen = 8;
4192
+ let i = 0;
4193
+ while (i < numSymbols) {
4194
+ const sym = readSymbol(reader, codeLenTree);
4195
+ if (sym < 16) {
4196
+ codeLengths[i] = sym;
4197
+ if (sym > 0) prevCodeLen = sym;
4198
+ i++;
4199
+ } else if (sym === 16) {
4200
+ const repeatCount = reader.readBits(2) + 3;
4201
+ for (let j = 0; j < repeatCount && i < numSymbols; j++) {
4202
+ codeLengths[i] = prevCodeLen;
4203
+ i++;
4204
+ }
4205
+ } else if (sym === 17) {
4206
+ const repeatCount = reader.readBits(3) + 3;
4207
+ i += repeatCount;
4208
+ } else if (sym === 18) {
4209
+ const repeatCount = reader.readBits(7) + 11;
4210
+ i += repeatCount;
4211
+ }
4212
+ }
4213
+ return codeLengths;
4214
+ }
4215
+ /**
4216
+ * Decode a VP8L (lossless) bitstream.
4217
+ */
4218
+ function decodeVP8L(data) {
4219
+ if (data.length < 5) throw new Error("WebP VP8L: data too short");
4220
+ if (data[0] !== 47) throw new Error("WebP VP8L: invalid signature byte (expected 0x2F)");
4221
+ const reader = new VP8LBitReader(data, 1);
4222
+ const width = reader.readBits(14) + 1;
4223
+ const height = reader.readBits(14) + 1;
4224
+ const hasAlpha = reader.readBit() === 1;
4225
+ const versionBits = reader.readBits(3);
4226
+ if (versionBits !== 0) throw new Error(`WebP VP8L: unsupported version ${versionBits}`);
4227
+ const transforms = [];
4228
+ while (reader.readBit() === 1) {
4229
+ const transformType = reader.readBits(2);
4230
+ transforms.push({
4231
+ type: transformType,
4232
+ data: null
4233
+ });
4234
+ if (transformType === 0) {
4235
+ const sizeBits = reader.readBits(3) + 2;
4236
+ Math.ceil(width / (1 << sizeBits));
4237
+ Math.ceil(height / (1 << sizeBits));
4238
+ break;
4239
+ } else if (transformType === 1) {
4240
+ reader.readBits(3) + 2;
4241
+ break;
4242
+ } else if (transformType === 2) {} else if (transformType === 3) {
4243
+ reader.readBits(8) + 1;
4244
+ break;
4245
+ }
4246
+ }
4247
+ const numCodeLenCodes = 19;
4248
+ const codeLenCodeOrder = [
4249
+ 17,
4250
+ 18,
4251
+ 0,
4252
+ 1,
4253
+ 2,
4254
+ 3,
4255
+ 4,
4256
+ 5,
4257
+ 16,
4258
+ 6,
4259
+ 7,
4260
+ 8,
4261
+ 9,
4262
+ 10,
4263
+ 11,
4264
+ 12,
4265
+ 13,
4266
+ 14,
4267
+ 15
4268
+ ];
4269
+ const trees = [];
4270
+ for (let g = 0; g < 5; g++) {
4271
+ const numSymbols = g === 0 ? 280 : g === 4 ? 40 : 256;
4272
+ if (reader.readBit() === 1) {
4273
+ const numBits = reader.readBit();
4274
+ const firstSymbol = reader.readBits(numBits === 0 ? 1 : 8);
4275
+ if (numBits === 0) {
4276
+ const codeLengths = new Uint8Array(numSymbols);
4277
+ if (firstSymbol < numSymbols) codeLengths[firstSymbol] = 1;
4278
+ trees.push(buildHuffmanTree(codeLengths, numSymbols));
4279
+ } else {
4280
+ const secondSymbol = reader.readBits(8);
4281
+ const codeLengths = new Uint8Array(numSymbols);
4282
+ if (firstSymbol < numSymbols) codeLengths[firstSymbol] = 1;
4283
+ if (secondSymbol < numSymbols) codeLengths[secondSymbol] = 1;
4284
+ trees.push(buildHuffmanTree(codeLengths, numSymbols));
4285
+ }
4286
+ } else {
4287
+ const numCodes = reader.readBits(4) + 4;
4288
+ const codeLenCodeLengths = new Uint8Array(numCodeLenCodes);
4289
+ for (let i = 0; i < numCodes && i < numCodeLenCodes; i++) codeLenCodeLengths[codeLenCodeOrder[i]] = reader.readBits(3);
4290
+ const symbolCodeLengths = readCodeLengths(reader, buildHuffmanTree(codeLenCodeLengths, numCodeLenCodes), numSymbols);
4291
+ trees.push(buildHuffmanTree(symbolCodeLengths, numSymbols));
4292
+ }
4293
+ }
4294
+ const numPixels = width * height;
4295
+ const pixels = new Uint8Array(numPixels * 4);
4296
+ let pixelIdx = 0;
4297
+ while (pixelIdx < numPixels) {
4298
+ const greenOrLen = readSymbol(reader, trees[0]);
4299
+ if (greenOrLen < 256) {
4300
+ const red = readSymbol(reader, trees[1]);
4301
+ const blue = readSymbol(reader, trees[2]);
4302
+ const alpha = readSymbol(reader, trees[3]);
4303
+ const off = pixelIdx * 4;
4304
+ pixels[off] = red;
4305
+ pixels[off + 1] = greenOrLen;
4306
+ pixels[off + 2] = blue;
4307
+ pixels[off + 3] = alpha;
4308
+ pixelIdx++;
4309
+ } else if (greenOrLen < 280) {
4310
+ const length = decodeLZ77Length(reader, greenOrLen - 256);
4311
+ const distance = decodeLZ77Distance(reader, readSymbol(reader, trees[4]), width);
4312
+ for (let i = 0; i < length && pixelIdx < numPixels; i++) {
4313
+ const srcIdx = (pixelIdx - distance) * 4;
4314
+ const dstIdx = pixelIdx * 4;
4315
+ if (srcIdx >= 0) {
4316
+ pixels[dstIdx] = pixels[srcIdx];
4317
+ pixels[dstIdx + 1] = pixels[srcIdx + 1];
4318
+ pixels[dstIdx + 2] = pixels[srcIdx + 2];
4319
+ pixels[dstIdx + 3] = pixels[srcIdx + 3];
4320
+ }
4321
+ pixelIdx++;
4322
+ }
4323
+ } else break;
4324
+ }
4325
+ for (let t = transforms.length - 1; t >= 0; t--) if (transforms[t].type === 2) for (let i = 0; i < numPixels; i++) {
4326
+ const off = i * 4;
4327
+ const green = pixels[off + 1];
4328
+ pixels[off] = pixels[off] + green & 255;
4329
+ pixels[off + 2] = pixels[off + 2] + green & 255;
4330
+ }
4331
+ const outChannels = hasAlpha ? 4 : 3;
4332
+ const output = new Uint8Array(numPixels * outChannels);
4333
+ for (let i = 0; i < numPixels; i++) {
4334
+ const srcOff = i * 4;
4335
+ const dstOff = i * outChannels;
4336
+ output[dstOff] = pixels[srcOff];
4337
+ output[dstOff + 1] = pixels[srcOff + 1];
4338
+ output[dstOff + 2] = pixels[srcOff + 2];
4339
+ if (hasAlpha) output[dstOff + 3] = pixels[srcOff + 3];
4340
+ }
4341
+ return {
4342
+ width,
4343
+ height,
4344
+ pixels: output,
4345
+ channels: hasAlpha ? 4 : 3,
4346
+ hasAlpha
4347
+ };
4348
+ }
4349
+ const lz77LengthPrefixExtraBits = [
4350
+ 0,
4351
+ 0,
4352
+ 0,
4353
+ 0,
4354
+ 0,
4355
+ 0,
4356
+ 0,
4357
+ 0,
4358
+ 1,
4359
+ 1,
4360
+ 1,
4361
+ 1,
4362
+ 2,
4363
+ 2,
4364
+ 2,
4365
+ 2,
4366
+ 3,
4367
+ 3,
4368
+ 3,
4369
+ 3,
4370
+ 4,
4371
+ 4,
4372
+ 4,
4373
+ 4
4374
+ ];
4375
+ const lz77LengthPrefixOffset = [
4376
+ 1,
4377
+ 2,
4378
+ 3,
4379
+ 4,
4380
+ 5,
4381
+ 6,
4382
+ 7,
4383
+ 8,
4384
+ 9,
4385
+ 11,
4386
+ 13,
4387
+ 15,
4388
+ 17,
4389
+ 21,
4390
+ 25,
4391
+ 29,
4392
+ 33,
4393
+ 41,
4394
+ 49,
4395
+ 57,
4396
+ 65,
4397
+ 81,
4398
+ 97,
4399
+ 113
4400
+ ];
4401
+ function decodeLZ77Length(reader, code) {
4402
+ if (code < 24) {
4403
+ const extra = lz77LengthPrefixExtraBits[code];
4404
+ return lz77LengthPrefixOffset[code] + (extra > 0 ? reader.readBits(extra) : 0);
4405
+ }
4406
+ return 1;
4407
+ }
4408
+ const lz77DistPrefixExtraBits = [
4409
+ 0,
4410
+ 0,
4411
+ 0,
4412
+ 0,
4413
+ 1,
4414
+ 1,
4415
+ 1,
4416
+ 1,
4417
+ 2,
4418
+ 2,
4419
+ 2,
4420
+ 2,
4421
+ 3,
4422
+ 3,
4423
+ 3,
4424
+ 3,
4425
+ 4,
4426
+ 4,
4427
+ 4,
4428
+ 4,
4429
+ 5,
4430
+ 5,
4431
+ 5,
4432
+ 5,
4433
+ 6,
4434
+ 6,
4435
+ 6,
4436
+ 6,
4437
+ 7,
4438
+ 7,
4439
+ 7,
4440
+ 7,
4441
+ 8,
4442
+ 8,
4443
+ 8,
4444
+ 8,
4445
+ 9,
4446
+ 9,
4447
+ 9,
4448
+ 9
4449
+ ];
4450
+ const lz77DistPrefixOffset = [
4451
+ 1,
4452
+ 2,
4453
+ 3,
4454
+ 4,
4455
+ 5,
4456
+ 7,
4457
+ 9,
4458
+ 11,
4459
+ 13,
4460
+ 17,
4461
+ 21,
4462
+ 25,
4463
+ 29,
4464
+ 37,
4465
+ 45,
4466
+ 53,
4467
+ 61,
4468
+ 77,
4469
+ 93,
4470
+ 109,
4471
+ 125,
4472
+ 157,
4473
+ 189,
4474
+ 221,
4475
+ 253,
4476
+ 317,
4477
+ 381,
4478
+ 445,
4479
+ 509,
4480
+ 637,
4481
+ 765,
4482
+ 893,
4483
+ 1021,
4484
+ 1277,
4485
+ 1533,
4486
+ 1789,
4487
+ 2045,
4488
+ 2557,
4489
+ 3069,
4490
+ 3581
4491
+ ];
4492
+ function decodeLZ77Distance(reader, code, _width) {
4493
+ if (code < 40) {
4494
+ const extra = lz77DistPrefixExtraBits[code];
4495
+ return lz77DistPrefixOffset[code] + (extra > 0 ? reader.readBits(extra) : 0);
4496
+ }
4497
+ return 1;
4498
+ }
4499
+ /**
4500
+ * Decode a WebP ALPH chunk to a flat alpha plane.
4501
+ *
4502
+ * The ALPH chunk format:
4503
+ * - 1 byte header: [preprocessing:2][filtering:2][compression:2][unused:2]
4504
+ * - Remaining bytes: alpha data
4505
+ *
4506
+ * Compression:
4507
+ * - 0 = uncompressed
4508
+ * - 1 = VP8L-compressed (lossless)
4509
+ *
4510
+ * Filtering:
4511
+ * - 0 = none
4512
+ * - 1 = horizontal
4513
+ * - 2 = vertical
4514
+ * - 3 = gradient
4515
+ */
4516
+ function decodeAlphaChunk(data, width, height) {
4517
+ if (data.length < 1) throw new Error("WebP ALPH: chunk too short");
4518
+ const header = data[0];
4519
+ const filtering = header >> 2 & 3;
4520
+ const compression = header >> 0 & 3;
4521
+ let alphaData;
4522
+ if (compression === 0) alphaData = data.slice(1);
4523
+ else if (compression === 1) try {
4524
+ const lossless = decodeVP8L(data.slice(1));
4525
+ alphaData = new Uint8Array(width * height);
4526
+ for (let i = 0; i < width * height; i++) alphaData[i] = lossless.pixels[i * lossless.channels + 1] ?? 255;
4527
+ } catch {
4528
+ alphaData = new Uint8Array(width * height);
4529
+ alphaData.fill(255);
4530
+ }
4531
+ else throw new Error(`WebP ALPH: unsupported compression method ${compression}`);
4532
+ const numPixels = width * height;
4533
+ const alpha = new Uint8Array(numPixels);
4534
+ if (alphaData.length < numPixels) alpha.set(alphaData.slice(0, numPixels));
4535
+ else alpha.set(alphaData.slice(0, numPixels));
4536
+ applyAlphaFilter(alpha, width, height, filtering);
4537
+ return alpha;
4538
+ }
4539
+ function applyAlphaFilter(alpha, width, height, filtering) {
4540
+ if (filtering === 0) return;
4541
+ for (let row = 0; row < height; row++) for (let col = 0; col < width; col++) {
4542
+ const idx = row * width + col;
4543
+ const left = col > 0 ? alpha[idx - 1] : 0;
4544
+ const top = row > 0 ? alpha[idx - width] : 0;
4545
+ const topLeft = row > 0 && col > 0 ? alpha[idx - width - 1] : 0;
4546
+ switch (filtering) {
4547
+ case 1:
4548
+ alpha[idx] = alpha[idx] + left & 255;
4549
+ break;
4550
+ case 2:
4551
+ alpha[idx] = alpha[idx] + top & 255;
4552
+ break;
4553
+ case 3:
4554
+ alpha[idx] = alpha[idx] + clamp255(left + top - topLeft) & 255;
4555
+ break;
4556
+ }
4557
+ }
4558
+ }
4559
+ /** Merge RGB image with separate alpha plane to produce RGBA. */
4560
+ function mergeRgbAlpha(rgb, alphaPlane) {
4561
+ const { width, height } = rgb;
4562
+ const pixels = new Uint8Array(width * height * 4);
4563
+ for (let i = 0; i < width * height; i++) {
4564
+ const srcIdx = i * rgb.channels;
4565
+ const dstIdx = i * 4;
4566
+ pixels[dstIdx] = rgb.pixels[srcIdx];
4567
+ pixels[dstIdx + 1] = rgb.pixels[srcIdx + 1];
4568
+ pixels[dstIdx + 2] = rgb.pixels[srcIdx + 2];
4569
+ pixels[dstIdx + 3] = alphaPlane[i] ?? 255;
4570
+ }
4571
+ return {
4572
+ width,
4573
+ height,
4574
+ pixels,
4575
+ channels: 4,
4576
+ hasAlpha: true
4577
+ };
4578
+ }
4579
+
4580
+ //#endregion
4581
+ //#region src/assets/image/tiffDecode.ts
4582
+ /**
4583
+ * @module assets/image/tiffDecode
4584
+ *
4585
+ * TIFF image decoder — pure TypeScript, no WASM, no Buffer.
4586
+ *
4587
+ * Supports:
4588
+ * - IFD (Image File Directory) parsing with byte order detection
4589
+ * - Strip-based and tile-based image data extraction
4590
+ * - Compressions: None (1), LZW (5), JPEG-in-TIFF (6/7), Deflate (8), PackBits (32773)
4591
+ * - BitsPerSample: 1, 4, 8, 16
4592
+ * - SamplesPerPixel: 1, 3, 4
4593
+ * - PhotometricInterpretation: 0 (WhiteIsZero), 1 (BlackIsZero), 2 (RGB)
4594
+ * - Multi-page TIFF support via IFD chain
4595
+ *
4596
+ * Magic bytes: 49 49 (II, little-endian) or 4D 4D (MM, big-endian) + 42 (0x002A)
4597
+ */
4598
+ const TAG_IMAGE_WIDTH = 256;
4599
+ const TAG_IMAGE_HEIGHT = 257;
4600
+ const TAG_BITS_PER_SAMPLE = 258;
4601
+ const TAG_COMPRESSION = 259;
4602
+ const TAG_PHOTOMETRIC = 262;
4603
+ const TAG_STRIP_OFFSETS = 273;
4604
+ const TAG_SAMPLES_PER_PIXEL = 277;
4605
+ const TAG_ROWS_PER_STRIP = 278;
4606
+ const TAG_STRIP_BYTE_COUNTS = 279;
4607
+ const TAG_JPEG_TABLES = 347;
4608
+ const COMPRESS_NONE = 1;
4609
+ const COMPRESS_LZW = 5;
4610
+ const COMPRESS_JPEG_OLD = 6;
4611
+ const COMPRESS_JPEG = 7;
4612
+ const COMPRESS_DEFLATE = 8;
4613
+ const COMPRESS_PACKBITS = 32773;
4614
+ const TYPE_SIZES = [
4615
+ 0,
4616
+ 1,
4617
+ 1,
4618
+ 2,
4619
+ 4,
4620
+ 8,
4621
+ 1,
4622
+ 1,
4623
+ 2,
4624
+ 4,
4625
+ 8,
4626
+ 4,
4627
+ 8
4628
+ ];
4629
+ var TiffReader = class {
4630
+ data;
4631
+ view;
4632
+ littleEndian;
4633
+ constructor(data, littleEndian) {
4634
+ this.data = data;
4635
+ this.view = new DataView(data.buffer, data.byteOffset, data.byteLength);
4636
+ this.littleEndian = littleEndian;
4637
+ }
4638
+ u16(offset) {
4639
+ return this.view.getUint16(offset, this.littleEndian);
4640
+ }
4641
+ u32(offset) {
4642
+ return this.view.getUint32(offset, this.littleEndian);
4643
+ }
4644
+ i16(offset) {
4645
+ return this.view.getInt16(offset, this.littleEndian);
4646
+ }
4647
+ i32(offset) {
4648
+ return this.view.getInt32(offset, this.littleEndian);
4649
+ }
4650
+ };
4651
+ /** Check if data is a TIFF file by examining the byte order marker and magic number. */
4652
+ function isTiff(data) {
4653
+ if (data.length < 4) return false;
4654
+ const bom = data[0] << 8 | data[1];
4655
+ if (bom !== 18761 && bom !== 19789) return false;
4656
+ const littleEndian = bom === 18761;
4657
+ return new DataView(data.buffer, data.byteOffset, data.byteLength).getUint16(2, littleEndian) === 42;
4658
+ }
4659
+ /**
4660
+ * Parse a single IFD from TIFF data.
4661
+ *
4662
+ * @param data Raw TIFF bytes.
4663
+ * @param offset Byte offset to the IFD.
4664
+ * @param littleEndian Whether the TIFF uses little-endian byte order.
4665
+ * @returns Array of IFD entries.
4666
+ */
4667
+ function parseTiffIfd(data, offset, littleEndian) {
4668
+ const reader = new TiffReader(data, littleEndian);
4669
+ const numEntries = reader.u16(offset);
4670
+ const entries = [];
4671
+ for (let i = 0; i < numEntries; i++) {
4672
+ const entryOffset = offset + 2 + i * 12;
4673
+ if (entryOffset + 12 > data.length) break;
4674
+ const tag = reader.u16(entryOffset);
4675
+ const type = reader.u16(entryOffset + 2);
4676
+ const count = reader.u32(entryOffset + 4);
4677
+ const typeSize = TYPE_SIZES[type] ?? 1;
4678
+ const totalSize = typeSize * count;
4679
+ const values = [];
4680
+ const valueOffset = totalSize <= 4 ? entryOffset + 8 : reader.u32(entryOffset + 8);
4681
+ for (let j = 0; j < count; j++) {
4682
+ const pos = valueOffset + j * typeSize;
4683
+ if (pos + typeSize > data.length) break;
4684
+ switch (type) {
4685
+ case 1:
4686
+ case 7:
4687
+ values.push(data[pos]);
4688
+ break;
4689
+ case 2:
4690
+ values.push(data[pos]);
4691
+ break;
4692
+ case 3:
4693
+ values.push(reader.u16(pos));
4694
+ break;
4695
+ case 4:
4696
+ values.push(reader.u32(pos));
4697
+ break;
4698
+ case 5:
4699
+ values.push(reader.u32(pos) / (reader.u32(pos + 4) || 1));
4700
+ break;
4701
+ case 6:
4702
+ values.push(data[pos] > 127 ? data[pos] - 256 : data[pos]);
4703
+ break;
4704
+ case 8:
4705
+ values.push(reader.i16(pos));
4706
+ break;
4707
+ case 9:
4708
+ values.push(reader.i32(pos));
4709
+ break;
4710
+ case 10:
4711
+ values.push(reader.i32(pos) / (reader.i32(pos + 4) || 1));
4712
+ break;
4713
+ default:
4714
+ values.push(reader.u32(pos));
4715
+ break;
4716
+ }
4717
+ }
4718
+ entries.push({
4719
+ tag,
4720
+ type,
4721
+ count,
4722
+ values
4723
+ });
4724
+ }
4725
+ return entries;
4726
+ }
4727
+ /** Get the offset to the next IFD (0 = no more IFDs). */
4728
+ function getNextIfdOffset(data, currentIfdOffset, littleEndian) {
4729
+ const reader = new TiffReader(data, littleEndian);
4730
+ const numEntries = reader.u16(currentIfdOffset);
4731
+ const nextOffset = currentIfdOffset + 2 + numEntries * 12;
4732
+ if (nextOffset + 4 > data.length) return 0;
4733
+ return reader.u32(nextOffset);
4734
+ }
4735
+ /** Find the IFD at a given page index by following the IFD chain. */
4736
+ function findIfdAtPage(data, littleEndian, firstIfdOffset, pageIndex) {
4737
+ let offset = firstIfdOffset;
4738
+ for (let i = 0; i < pageIndex; i++) {
4739
+ offset = getNextIfdOffset(data, offset, littleEndian);
4740
+ if (offset === 0) throw new Error(`TIFF: page index ${pageIndex} out of range (only ${i + 1} pages)`);
4741
+ }
4742
+ return offset;
4743
+ }
4744
+ /** Get a tag value from IFD entries. */
4745
+ function getTag(entries, tag) {
4746
+ return entries.find((e) => e.tag === tag)?.values[0];
4747
+ }
4748
+ /** Get all values for a tag from IFD entries. */
4749
+ function getTagValues(entries, tag) {
4750
+ return entries.find((e) => e.tag === tag)?.values;
4751
+ }
4752
+ /** PackBits decompression (compression=32773). */
4753
+ function decompressPackBits(input, expectedLength) {
4754
+ const output = new Uint8Array(expectedLength);
4755
+ let srcPos = 0;
4756
+ let dstPos = 0;
4757
+ while (srcPos < input.length && dstPos < expectedLength) {
4758
+ const n = input[srcPos] > 127 ? input[srcPos] - 256 : input[srcPos];
4759
+ srcPos++;
4760
+ if (n >= 0) {
4761
+ const count = n + 1;
4762
+ for (let i = 0; i < count && srcPos < input.length && dstPos < expectedLength; i++) output[dstPos++] = input[srcPos++];
4763
+ } else if (n > -128) {
4764
+ const count = -n + 1;
4765
+ const val = input[srcPos];
4766
+ srcPos++;
4767
+ for (let i = 0; i < count && dstPos < expectedLength; i++) output[dstPos++] = val;
4768
+ }
4769
+ }
4770
+ return output.slice(0, dstPos);
4771
+ }
4772
+ /** LZW decompression (compression=5). */
4773
+ function decompressLzw(input, expectedLength) {
4774
+ const output = new Uint8Array(expectedLength);
4775
+ let outPos = 0;
4776
+ const CLEAR_CODE = 256;
4777
+ const EOI_CODE = 257;
4778
+ let codeSize = 9;
4779
+ let nextCode = 258;
4780
+ let maxCode = 1 << codeSize;
4781
+ const dictPrefix = new Int32Array(4096);
4782
+ const dictSuffix = new Uint8Array(4096);
4783
+ const dictLength = new Uint16Array(4096);
4784
+ function resetDict() {
4785
+ codeSize = 9;
4786
+ nextCode = 258;
4787
+ maxCode = 1 << codeSize;
4788
+ for (let i = 0; i < 256; i++) {
4789
+ dictPrefix[i] = -1;
4790
+ dictSuffix[i] = i;
4791
+ dictLength[i] = 1;
4792
+ }
4793
+ }
4794
+ resetDict();
4795
+ let bitBuf = 0;
4796
+ let bitsAvail = 0;
4797
+ let bytePos = 0;
4798
+ function readCode() {
4799
+ while (bitsAvail < codeSize) if (bytePos < input.length) {
4800
+ bitBuf |= input[bytePos] << bitsAvail;
4801
+ bytePos++;
4802
+ bitsAvail += 8;
4803
+ } else return EOI_CODE;
4804
+ const code = bitBuf & (1 << codeSize) - 1;
4805
+ bitBuf >>>= codeSize;
4806
+ bitsAvail -= codeSize;
4807
+ return code;
4808
+ }
4809
+ function outputString(code) {
4810
+ const len = dictLength[code];
4811
+ let pos = outPos + len - 1;
4812
+ let c = code;
4813
+ while (c >= 0 && pos >= outPos) {
4814
+ if (pos < expectedLength) output[pos] = dictSuffix[c];
4815
+ pos--;
4816
+ c = dictPrefix[c];
4817
+ }
4818
+ outPos += len;
4819
+ }
4820
+ function firstByte(code) {
4821
+ let c = code;
4822
+ while (dictPrefix[c] >= 0) c = dictPrefix[c];
4823
+ return dictSuffix[c];
4824
+ }
4825
+ let oldCode = -1;
4826
+ while (outPos < expectedLength) {
4827
+ const code = readCode();
4828
+ if (code === EOI_CODE) break;
4829
+ if (code === CLEAR_CODE) {
4830
+ resetDict();
4831
+ oldCode = -1;
4832
+ continue;
4833
+ }
4834
+ if (oldCode === -1) {
4835
+ outputString(code);
4836
+ oldCode = code;
4837
+ continue;
4838
+ }
4839
+ if (code < nextCode) {
4840
+ outputString(code);
4841
+ if (nextCode < 4096) {
4842
+ dictPrefix[nextCode] = oldCode;
4843
+ dictSuffix[nextCode] = firstByte(code);
4844
+ dictLength[nextCode] = dictLength[oldCode] + 1;
4845
+ nextCode++;
4846
+ }
4847
+ } else {
4848
+ const fb = firstByte(oldCode);
4849
+ if (nextCode < 4096) {
4850
+ dictPrefix[nextCode] = oldCode;
4851
+ dictSuffix[nextCode] = fb;
4852
+ dictLength[nextCode] = dictLength[oldCode] + 1;
4853
+ nextCode++;
4854
+ }
4855
+ outputString(code);
4856
+ }
4857
+ if (nextCode >= maxCode && codeSize < 12) {
4858
+ codeSize++;
4859
+ maxCode = 1 << codeSize;
4860
+ }
4861
+ oldCode = code;
4862
+ }
4863
+ return output.slice(0, Math.min(outPos, expectedLength));
4864
+ }
4865
+ /** Deflate decompression (compression=8). */
4866
+ function decompressDeflate(input, expectedLength) {
4867
+ return inflateSync(input).slice(0, expectedLength);
4868
+ }
4869
+ /** Convert 1-bit data to 8-bit (0 or 255). */
4870
+ function normalize1bit(data, width, height, whiteIsZero) {
4871
+ const output = new Uint8Array(width * height);
4872
+ for (let row = 0; row < height; row++) for (let col = 0; col < width; col++) {
4873
+ const byteIdx = row * Math.ceil(width / 8) + (col >> 3);
4874
+ const bitIdx = 7 - (col & 7);
4875
+ const bit = data[byteIdx] >> bitIdx & 1;
4876
+ const val = whiteIsZero ? bit === 0 ? 255 : 0 : bit === 1 ? 255 : 0;
4877
+ output[row * width + col] = val;
4878
+ }
4879
+ return output;
4880
+ }
4881
+ /** Convert 4-bit data to 8-bit. */
4882
+ function normalize4bit(data, width, height, whiteIsZero) {
4883
+ const output = new Uint8Array(width * height);
4884
+ for (let row = 0; row < height; row++) for (let col = 0; col < width; col++) {
4885
+ const byteIdx = row * Math.ceil(width / 2) + (col >> 1);
4886
+ let val = ((col & 1) === 0 ? data[byteIdx] >> 4 & 15 : data[byteIdx] & 15) * 255 / 15 | 0;
4887
+ if (whiteIsZero) val = 255 - val;
4888
+ output[row * width + col] = val;
4889
+ }
4890
+ return output;
4891
+ }
4892
+ /** Convert 16-bit data to 8-bit by keeping the high byte. */
4893
+ function normalize16bit(data, numSamples, littleEndian) {
4894
+ const output = new Uint8Array(numSamples);
4895
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
4896
+ for (let i = 0; i < numSamples; i++) output[i] = view.getUint16(i * 2, littleEndian) >> 8 & 255;
4897
+ return output;
4898
+ }
4899
+ /**
4900
+ * Decode JPEG strip data. For JPEG-in-TIFF, each strip may be a complete
4901
+ * JPEG or the tables may be stored separately in the JPEGTables tag.
4902
+ */
4903
+ function decodeJpegStrip(stripData, jpegTables, _width, stripHeight, samplesPerPixel) {
4904
+ let fullJpeg;
4905
+ if (jpegTables && jpegTables.length > 4) {
4906
+ const tableData = jpegTables.slice(2, jpegTables.length - 2);
4907
+ const stripBody = stripData.slice(2);
4908
+ fullJpeg = new Uint8Array(2 + tableData.length + stripBody.length);
4909
+ fullJpeg[0] = 255;
4910
+ fullJpeg[1] = 216;
4911
+ fullJpeg.set(tableData, 2);
4912
+ fullJpeg.set(stripBody, 2 + tableData.length);
4913
+ } else fullJpeg = stripData;
4914
+ throw new Error("TIFF JPEG-in-TIFF compression: JPEG strip decoding requires a JPEG decoder. This is supported when running with the JPEG WASM module initialized.");
4915
+ }
4916
+ /**
4917
+ * Get the number of pages in a multi-page TIFF.
4918
+ *
4919
+ * @param data Raw TIFF bytes.
4920
+ * @returns Number of IFDs (pages).
4921
+ */
4922
+ function getTiffPageCount(data) {
4923
+ if (!isTiff(data)) throw new Error("TIFF: invalid TIFF header");
4924
+ const littleEndian = data[0] === 73;
4925
+ let offset = new TiffReader(data, littleEndian).u32(4);
4926
+ let count = 0;
4927
+ while (offset !== 0 && offset < data.length) {
4928
+ count++;
4929
+ offset = getNextIfdOffset(data, offset, littleEndian);
4930
+ }
4931
+ return count;
4932
+ }
4933
+ /**
4934
+ * Decode a specific page from a multi-page TIFF.
4935
+ *
4936
+ * @param data Raw TIFF bytes.
4937
+ * @param pageIndex 0-based page index.
4938
+ * @returns Decoded image.
4939
+ */
4940
+ function decodeTiffPage(data, pageIndex) {
4941
+ return decodeTiff(data, { page: pageIndex });
4942
+ }
4943
+ /**
4944
+ * Decode all pages from a multi-page TIFF.
4945
+ *
4946
+ * @param data Raw TIFF bytes.
4947
+ * @returns Array of decoded images.
4948
+ */
4949
+ function decodeTiffAll(data) {
4950
+ const pageCount = getTiffPageCount(data);
4951
+ const images = [];
4952
+ for (let i = 0; i < pageCount; i++) images.push(decodeTiffPage(data, i));
4953
+ return images;
4954
+ }
4955
+ /**
4956
+ * Decode a TIFF image.
4957
+ *
4958
+ * @param data Raw TIFF bytes.
4959
+ * @param options Decode options (page selection).
4960
+ * @returns Decoded image data.
4961
+ */
4962
+ function decodeTiff(data, options) {
4963
+ if (!isTiff(data)) throw new Error("TIFF: invalid TIFF header (expected II or MM byte order marker + 42)");
4964
+ const littleEndian = data[0] === 73;
4965
+ const entries = parseTiffIfd(data, findIfdAtPage(data, littleEndian, new TiffReader(data, littleEndian).u32(4), options?.page ?? 0), littleEndian);
4966
+ const width = getTag(entries, TAG_IMAGE_WIDTH);
4967
+ const height = getTag(entries, TAG_IMAGE_HEIGHT);
4968
+ const compression = getTag(entries, TAG_COMPRESSION) ?? COMPRESS_NONE;
4969
+ const photometric = getTag(entries, TAG_PHOTOMETRIC) ?? 1;
4970
+ const bitsPerSample = getTag(entries, TAG_BITS_PER_SAMPLE) ?? 8;
4971
+ const samplesPerPixel = getTag(entries, TAG_SAMPLES_PER_PIXEL) ?? 1;
4972
+ const rowsPerStrip = getTag(entries, TAG_ROWS_PER_STRIP) ?? height ?? 0;
4973
+ const stripOffsets = getTagValues(entries, TAG_STRIP_OFFSETS);
4974
+ const stripByteCounts = getTagValues(entries, TAG_STRIP_BYTE_COUNTS);
4975
+ if (width === void 0 || height === void 0) throw new Error("TIFF: missing ImageWidth or ImageHeight tag");
4976
+ if (!stripOffsets || stripOffsets.length === 0) throw new Error("TIFF: missing StripOffsets tag");
4977
+ let jpegTables;
4978
+ const jpegTablesEntry = entries.find((e) => e.tag === TAG_JPEG_TABLES);
4979
+ if (jpegTablesEntry) {
4980
+ const tablesOffset = jpegTablesEntry.values[0];
4981
+ if (jpegTablesEntry.type === 7 && jpegTablesEntry.count > 4) jpegTables = data.slice(tablesOffset, tablesOffset + jpegTablesEntry.count);
4982
+ }
4983
+ const bytesPerRow = Math.ceil(width * samplesPerPixel * bitsPerSample / 8);
4984
+ const numStrips = stripOffsets.length;
4985
+ const rawData = new Uint8Array(height * bytesPerRow);
4986
+ let outOffset = 0;
4987
+ for (let strip = 0; strip < numStrips; strip++) {
4988
+ const stripOffset = stripOffsets[strip];
4989
+ const stripByteCount = stripByteCounts?.[strip] ?? bytesPerRow * rowsPerStrip;
4990
+ const stripRows = Math.min(rowsPerStrip, height - strip * rowsPerStrip);
4991
+ const expectedStripBytes = stripRows * bytesPerRow;
4992
+ if (stripOffset + stripByteCount > data.length) break;
4993
+ const compressedData = data.slice(stripOffset, stripOffset + stripByteCount);
4994
+ let decompressed;
4995
+ switch (compression) {
4996
+ case COMPRESS_NONE:
4997
+ decompressed = compressedData;
4998
+ break;
4999
+ case COMPRESS_PACKBITS:
5000
+ decompressed = decompressPackBits(compressedData, expectedStripBytes);
5001
+ break;
5002
+ case COMPRESS_LZW:
5003
+ decompressed = decompressLzw(compressedData, expectedStripBytes);
5004
+ break;
5005
+ case COMPRESS_DEFLATE:
5006
+ decompressed = decompressDeflate(compressedData, expectedStripBytes);
5007
+ break;
5008
+ case COMPRESS_JPEG:
5009
+ case COMPRESS_JPEG_OLD:
5010
+ decompressed = decodeJpegStrip(compressedData, jpegTables, width, stripRows, samplesPerPixel);
5011
+ break;
5012
+ default: throw new Error(`TIFF: unsupported compression type ${compression}`);
5013
+ }
5014
+ const copyLen = Math.min(decompressed.length, rawData.length - outOffset);
5015
+ rawData.set(decompressed.slice(0, copyLen), outOffset);
5016
+ outOffset += expectedStripBytes;
5017
+ }
5018
+ const whiteIsZero = photometric === 0;
5019
+ let pixels;
5020
+ if (bitsPerSample === 1 && samplesPerPixel === 1) pixels = normalize1bit(rawData, width, height, whiteIsZero);
5021
+ else if (bitsPerSample === 4 && samplesPerPixel === 1) pixels = normalize4bit(rawData, width, height, whiteIsZero);
5022
+ else if (bitsPerSample === 16) {
5023
+ pixels = normalize16bit(rawData, width * height * samplesPerPixel, littleEndian);
5024
+ if (whiteIsZero && samplesPerPixel === 1) for (let i = 0; i < pixels.length; i++) pixels[i] = 255 - pixels[i];
5025
+ } else if (bitsPerSample === 8) {
5026
+ pixels = rawData.slice(0, width * height * samplesPerPixel);
5027
+ if (whiteIsZero && samplesPerPixel === 1) for (let i = 0; i < pixels.length; i++) pixels[i] = 255 - pixels[i];
5028
+ } else throw new Error(`TIFF: unsupported BitsPerSample ${bitsPerSample}`);
5029
+ return {
5030
+ width,
5031
+ height,
5032
+ pixels,
5033
+ channels: samplesPerPixel === 1 ? 1 : samplesPerPixel === 3 ? 3 : samplesPerPixel === 4 ? 4 : 1,
5034
+ bitsPerSample
5035
+ };
5036
+ }
5037
+
3585
5038
  //#endregion
3586
5039
  //#region src/parser/parseError.ts
3587
5040
  /**
@@ -4196,7 +5649,7 @@ var PdfLexer = class {
4196
5649
  this.position = pos;
4197
5650
  return {
4198
5651
  type: TokenType.HexString,
4199
- value: String.fromCharCode.apply(null, bytes),
5652
+ value: String.fromCharCode(...bytes),
4200
5653
  offset: startPos
4201
5654
  };
4202
5655
  }
@@ -4355,7 +5808,7 @@ var PdfLexer = class {
4355
5808
  * because it avoids the per-call overhead of the streaming decoder.
4356
5809
  */
4357
5810
  bytesToAscii(from, to) {
4358
- return String.fromCharCode.apply(null, this._data.subarray(from, to));
5811
+ return String.fromCharCode(...this._data.subarray(from, to));
4359
5812
  }
4360
5813
  };
4361
5814
 
@@ -4829,10 +6282,10 @@ async function tryLoadLibdeflate() {
4829
6282
  if (libdeflateAttempted) return libdeflateEngine;
4830
6283
  libdeflateAttempted = true;
4831
6284
  try {
4832
- const { LibdeflateWasm: LibdeflateCtor, initDeflateWasm } = await import("./libdeflateWasm-rLppXytE.mjs").then((n) => n.r);
6285
+ const { LibdeflateWasm: LibdeflateCtor, initDeflateWasm } = await import("./libdeflateWasm-8b91Vmia.mjs").then((n) => n.r);
4833
6286
  let customBytes;
4834
6287
  try {
4835
- const { getWasmLoaderConfig } = await import("./loader-3u6Tw5T-.mjs").then((n) => n.l);
6288
+ const { getWasmLoaderConfig } = await import("./loader-C7B5dVCI.mjs").then((n) => n.l);
4836
6289
  customBytes = getWasmLoaderConfig().moduleBytes?.["libdeflate"];
4837
6290
  } catch {}
4838
6291
  await initDeflateWasm(customBytes);
@@ -4850,7 +6303,7 @@ async function tryLoadLibdeflate() {
4850
6303
  */
4851
6304
  async function loadFflate() {
4852
6305
  if (fflateEngine) return fflateEngine;
4853
- const { FflateEngine: FflateCtor } = await import("./fflateAdapter-CBQpGTlx.mjs").then((n) => n.n);
6306
+ const { FflateEngine: FflateCtor } = await import("./fflateAdapter-PSiW_ML7.mjs").then((n) => n.n);
4854
6307
  fflateEngine = new FflateCtor();
4855
6308
  return fflateEngine;
4856
6309
  }
@@ -5147,13 +6600,13 @@ var XrefParser = class {
5147
6600
  actual: "no \"startxref\" found",
5148
6601
  data: this.data
5149
6602
  });
5150
- const afterKeyword = tail.substring(idx + 9).trim();
6603
+ const afterKeyword = tail.slice(idx + 9).trim();
5151
6604
  const match = afterKeyword.match(/^(\d+)/);
5152
6605
  if (!match) throw new PdfParseError({
5153
6606
  message: "Invalid PDF: \"startxref\" found but no valid offset follows it.",
5154
6607
  offset: startPos + idx,
5155
6608
  expected: "decimal offset after \"startxref\"",
5156
- actual: `"${afterKeyword.substring(0, 20)}"`,
6609
+ actual: `"${afterKeyword.slice(0, 20)}"`,
5157
6610
  data: this.data
5158
6611
  });
5159
6612
  const offset = parseInt(match[1], 10);
@@ -6670,9 +8123,9 @@ const FILE_KEY_CACHE_MAX = 32;
6670
8123
  * a key derivation result.
6671
8124
  */
6672
8125
  function buildCacheKey(password, dict, fileId) {
6673
- const oHex = Array.from(dict.ownerKey.subarray(0, 16), (b) => b.toString(16).padStart(2, "0")).join("");
6674
- const uHex = Array.from(dict.userKey.subarray(0, 16), (b) => b.toString(16).padStart(2, "0")).join("");
6675
- const fHex = Array.from(fileId.subarray(0, 16), (b) => b.toString(16).padStart(2, "0")).join("");
8126
+ const oHex = dict.ownerKey.subarray(0, 16).toHex();
8127
+ const uHex = dict.userKey.subarray(0, 16).toHex();
8128
+ const fHex = fileId.subarray(0, 16).toHex();
6676
8129
  return `${dict.revision}:${dict.permissions}:${password}:${oHex}:${uHex}:${fHex}`;
6677
8130
  }
6678
8131
  /**
@@ -7666,12 +9119,12 @@ var PdfDocumentParser = class {
7666
9119
  actual: "no \"%PDF-\" marker found",
7667
9120
  data: this.data
7668
9121
  });
7669
- const versionMatch = header.substring(pdfIdx).match(/%PDF-(\d+\.\d+)/);
9122
+ const versionMatch = header.slice(pdfIdx).match(/%PDF-(\d+\.\d+)/);
7670
9123
  if (!versionMatch) throw new PdfParseError({
7671
9124
  message: "Invalid PDF: could not parse version from header.",
7672
9125
  offset: pdfIdx,
7673
9126
  expected: "\"%PDF-X.Y\" version string",
7674
- actual: `"${header.substring(pdfIdx, pdfIdx + 10)}"`,
9127
+ actual: `"${header.slice(pdfIdx, pdfIdx + 10)}"`,
7675
9128
  data: this.data
7676
9129
  });
7677
9130
  this.pdfVersion = versionMatch[1];
@@ -8168,9 +9621,9 @@ var PdfDocumentParser = class {
8168
9621
  if (subObj === void 0 || subObj.kind !== "dict") return 0;
8169
9622
  const subDict = subObj;
8170
9623
  return Iterator.from(subDict).map(([key]) => {
8171
- const name = key.startsWith("/") ? key.substring(1) : key;
9624
+ const name = key.startsWith("/") ? key.slice(1) : key;
8172
9625
  if (name.startsWith(prefix)) {
8173
- const num = parseInt(name.substring(prefix.length), 10);
9626
+ const num = parseInt(name.slice(prefix.length), 10);
8174
9627
  return isNaN(num) ? 0 : num;
8175
9628
  }
8176
9629
  return 0;
@@ -8196,7 +9649,7 @@ var PdfDocumentParser = class {
8196
9649
  */
8197
9650
  function parsePdfDate(dateStr) {
8198
9651
  let s = dateStr;
8199
- if (s.startsWith("D:")) s = s.substring(2);
9652
+ if (s.startsWith("D:")) s = s.slice(2);
8200
9653
  const match = s.match(/^(\d{4})(\d{2})?(\d{2})?(\d{2})?(\d{2})?(\d{2})?([Z+\-])?(\d{2})?'?(\d{2})?/);
8201
9654
  if (!match) return void 0;
8202
9655
  const year = parseInt(match[1], 10);
@@ -10275,7 +11728,7 @@ const decoder$2 = new TextDecoder("latin1");
10275
11728
  * The /ByteRange values are placeholders that will be updated after
10276
11729
  * the final byte positions are known.
10277
11730
  */
10278
- function buildSignatureDictString(placeholderSize, fieldName, signingDate) {
11731
+ function buildSignatureDictString(placeholderSize, fieldName, signingDate, mdpReference) {
10279
11732
  const contentsHex = "0".repeat(placeholderSize * 2);
10280
11733
  const byteRangePlaceholder = "0000000000 0000000000 0000000000 0000000000";
10281
11734
  let dict = "";
@@ -10285,6 +11738,7 @@ function buildSignatureDictString(placeholderSize, fieldName, signingDate) {
10285
11738
  dict += ` /ByteRange [${byteRangePlaceholder}]`;
10286
11739
  dict += ` /Contents <${contentsHex}>`;
10287
11740
  if (signingDate !== void 0) dict += ` /M (D:${formatPdfDate(signingDate)})`;
11741
+ if (mdpReference !== void 0) dict += mdpReference;
10288
11742
  dict += " >>";
10289
11743
  return dict;
10290
11744
  }
@@ -10393,16 +11847,16 @@ function n$1(value) {
10393
11847
  if (Number.isInteger(value)) return value.toString();
10394
11848
  return value.toFixed(6).replace(/\.?0+$/, "");
10395
11849
  }
10396
- function prepareForSigning(pdfBytes, signatureFieldName, placeholderSize = 8192, appearance) {
11850
+ function prepareForSigning(pdfBytes, signatureFieldName, placeholderSize = 8192, appearance, mdpPermission, fieldLock) {
10397
11851
  const pdfStr = decoder$2.decode(pdfBytes);
10398
11852
  const startxrefIdx = pdfStr.lastIndexOf("startxref");
10399
11853
  if (startxrefIdx === -1) throw new Error("Cannot find startxref in PDF — file may be corrupted");
10400
- const xrefOffsetMatch = pdfStr.substring(startxrefIdx + 9).trim().match(/^(\d+)/);
11854
+ const xrefOffsetMatch = pdfStr.slice(startxrefIdx + 9).trim().match(/^(\d+)/);
10401
11855
  if (!xrefOffsetMatch) throw new Error("Cannot parse xref offset from startxref");
10402
11856
  const prevXrefOffset = parseInt(xrefOffsetMatch[1], 10);
10403
- const sizeMatch = pdfStr.match(/\/Size\s+(\d+)/);
10404
- if (!sizeMatch) throw new Error("Cannot find /Size in PDF trailer");
10405
- const originalSize = parseInt(sizeMatch[1], 10);
11857
+ const sizeMatches = [...pdfStr.matchAll(/\/Size\s+(\d+)/g)];
11858
+ if (sizeMatches.length === 0) throw new Error("Cannot find /Size in PDF trailer");
11859
+ const originalSize = parseInt(sizeMatches[sizeMatches.length - 1][1], 10);
10406
11860
  const rootMatch = pdfStr.match(/\/Root\s+(\d+)\s+(\d+)\s+R/);
10407
11861
  if (!rootMatch) throw new Error("Cannot find /Root in PDF trailer");
10408
11862
  const rootObjNum = parseInt(rootMatch[1], 10);
@@ -10416,7 +11870,9 @@ function prepareForSigning(pdfBytes, signatureFieldName, placeholderSize = 8192,
10416
11870
  apStreamObjNum = newSize;
10417
11871
  newSize++;
10418
11872
  }
10419
- const sigDictStr = buildSignatureDictString(placeholderSize, signatureFieldName);
11873
+ let mdpReference;
11874
+ if (mdpPermission !== void 0 && mdpPermission >= 1 && mdpPermission <= 3) mdpReference = ` /Reference [<< /Type /SigRef /TransformMethod /DocMDP /TransformParams << /Type /TransformParams /P ${mdpPermission} /V /1.2 >> >>]`;
11875
+ const sigDictStr = buildSignatureDictString(placeholderSize, signatureFieldName, void 0, mdpReference);
10420
11876
  let rectStr = "0 0 0 0";
10421
11877
  if (appearance) {
10422
11878
  const [x, y, w, h] = appearance.rect;
@@ -10424,6 +11880,14 @@ function prepareForSigning(pdfBytes, signatureFieldName, placeholderSize = 8192,
10424
11880
  }
10425
11881
  let sigFieldDict = `<< /Type /Annot /Subtype /Widget /FT /Sig /T (${signatureFieldName}) /V ${sigValueObjNum} 0 R /F 132 /Rect [${rectStr}]`;
10426
11882
  if (appearance && apStreamObjNum >= 0) sigFieldDict += ` /AP << /N ${apStreamObjNum} 0 R >>`;
11883
+ if (fieldLock !== void 0) {
11884
+ sigFieldDict += ` /Lock << /Type /SigFieldLock /Action /${fieldLock.action}`;
11885
+ if (fieldLock.action !== "All" && fieldLock.fields && fieldLock.fields.length > 0) {
11886
+ const fieldEntries = fieldLock.fields.map((f) => `(${escapePdfString(f)})`).join(" ");
11887
+ sigFieldDict += ` /Fields [${fieldEntries}]`;
11888
+ }
11889
+ sigFieldDict += " >>";
11890
+ }
10427
11891
  sigFieldDict += " >>";
10428
11892
  let appendix = "\n";
10429
11893
  const objOffsets = /* @__PURE__ */ new Map();
@@ -10568,12 +12032,12 @@ function findSignatures(pdfBytes) {
10568
12032
  ];
10569
12033
  const searchStart = Math.max(0, match.index - 2e3);
10570
12034
  const searchEnd = Math.min(text.length, match.index + 2e3);
10571
- const contentsKeyIdx = text.substring(searchStart, searchEnd).indexOf("/Contents <");
12035
+ const contentsKeyIdx = text.slice(searchStart, searchEnd).indexOf("/Contents <");
10572
12036
  if (contentsKeyIdx !== -1) {
10573
12037
  const absoluteHexStart = searchStart + (contentsKeyIdx + 10);
10574
12038
  const closingBracket = text.indexOf(">", absoluteHexStart + 1);
10575
12039
  if (closingBracket !== -1) {
10576
- const hexStr = text.substring(absoluteHexStart + 1, closingBracket);
12040
+ const hexStr = text.slice(absoluteHexStart + 1, closingBracket);
10577
12041
  const contentsLen = closingBracket - absoluteHexStart + 1;
10578
12042
  results.push({
10579
12043
  byteRange: br,
@@ -11140,7 +12604,7 @@ const decoder$1 = new TextDecoder("latin1");
11140
12604
  */
11141
12605
  function extractFieldName(pdfStr, sigDictOffset) {
11142
12606
  const searchStart = Math.max(0, sigDictOffset - 2e3);
11143
- const tMatch = pdfStr.substring(searchStart, sigDictOffset + 1e3).match(/\/T\s*\(([^)]*)\)/);
12607
+ const tMatch = pdfStr.slice(searchStart, sigDictOffset + 1e3).match(/\/T\s*\(([^)]*)\)/);
11144
12608
  if (tMatch) return tMatch[1];
11145
12609
  return "Signature";
11146
12610
  }
@@ -11151,7 +12615,7 @@ function extractFieldName(pdfStr, sigDictOffset) {
11151
12615
  function extractSigDictStrings(pdfStr, byteRangeOffset) {
11152
12616
  const searchStart = Math.max(0, byteRangeOffset - 1e3);
11153
12617
  const searchEnd = Math.min(pdfStr.length, byteRangeOffset + 2e3);
11154
- const region = pdfStr.substring(searchStart, searchEnd);
12618
+ const region = pdfStr.slice(searchStart, searchEnd);
11155
12619
  const result = {};
11156
12620
  const reasonMatch = region.match(/\/Reason\s*\(([^)]*)\)/);
11157
12621
  if (reasonMatch && reasonMatch[1] !== void 0) result.reason = reasonMatch[1];
@@ -11197,7 +12661,7 @@ function hexToBytes$1(hex) {
11197
12661
  const trimLen = trailingZeros[0].length;
11198
12662
  if (trimLen % 2 === 0) {
11199
12663
  const nonZeroEnd = cleanHex.length - trimLen;
11200
- if (nonZeroEnd > 0 && nonZeroEnd % 2 === 0) cleanHex = cleanHex.substring(0, nonZeroEnd);
12664
+ if (nonZeroEnd > 0 && nonZeroEnd % 2 === 0) cleanHex = cleanHex.slice(0, nonZeroEnd);
11201
12665
  }
11202
12666
  }
11203
12667
  if (cleanHex.length % 2 !== 0) cleanHex = "0" + cleanHex;
@@ -11262,7 +12726,7 @@ async function signPdf(pdfBytes, fieldName, options) {
11262
12726
  }
11263
12727
  if (options.reason) textLines.push(`Reason: ${options.reason}`);
11264
12728
  if (options.location) textLines.push(`Location: ${options.location}`);
11265
- textLines.push(`Date: ${(/* @__PURE__ */ new Date()).toISOString().substring(0, 10)}`);
12729
+ textLines.push(`Date: ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`);
11266
12730
  }
11267
12731
  prepareAppearance = {
11268
12732
  rect: ap.rect,
@@ -11346,7 +12810,7 @@ function hexToBytes(hex) {
11346
12810
  endIdx = clean.length - trailingMatch[0].length;
11347
12811
  if (endIdx < 2) endIdx = clean.length;
11348
12812
  }
11349
- return Uint8Array.fromHex(clean.substring(0, endIdx));
12813
+ return Uint8Array.fromHex(clean.slice(0, endIdx));
11350
12814
  }
11351
12815
  /**
11352
12816
  * Extract the certificate, signed attributes, and raw signature
@@ -11447,12 +12911,12 @@ function extractSigningTime(signedAttrs) {
11447
12911
  */
11448
12912
  function parseUtcTime(utcTime) {
11449
12913
  const clean = utcTime.replace("Z", "");
11450
- const year = parseInt(clean.substring(0, 2), 10);
11451
- const month = parseInt(clean.substring(2, 4), 10) - 1;
11452
- const day = parseInt(clean.substring(4, 6), 10);
11453
- const hours = parseInt(clean.substring(6, 8), 10);
11454
- const minutes = parseInt(clean.substring(8, 10), 10);
11455
- const seconds = parseInt(clean.substring(10, 12), 10);
12914
+ const year = parseInt(clean.slice(0, 2), 10);
12915
+ const month = parseInt(clean.slice(2, 4), 10) - 1;
12916
+ const day = parseInt(clean.slice(4, 6), 10);
12917
+ const hours = parseInt(clean.slice(6, 8), 10);
12918
+ const minutes = parseInt(clean.slice(8, 10), 10);
12919
+ const seconds = parseInt(clean.slice(10, 12), 10);
11456
12920
  const fullYear = year < 50 ? 2e3 + year : 1900 + year;
11457
12921
  return new Date(Date.UTC(fullYear, month, day, hours, minutes, seconds));
11458
12922
  }
@@ -11463,7 +12927,7 @@ function parseUtcTime(utcTime) {
11463
12927
  function extractFieldInfo(pdfStr, contentsOffset) {
11464
12928
  const searchStart = Math.max(0, contentsOffset - 3e3);
11465
12929
  const searchEnd = Math.min(pdfStr.length, contentsOffset + 2e3);
11466
- const region = pdfStr.substring(searchStart, searchEnd);
12930
+ const region = pdfStr.slice(searchStart, searchEnd);
11467
12931
  let fieldName = "Signature";
11468
12932
  const tMatch = region.match(/\/T\s*\(([^)]*)\)/);
11469
12933
  if (tMatch) fieldName = tMatch[1];
@@ -11845,6 +13309,21 @@ function addWatermark(doc, options) {
11845
13309
  }
11846
13310
  }
11847
13311
 
13312
+ //#endregion
13313
+ //#region src/form/documentScripts.ts
13314
+ /** WeakMap to store document-level action state per PdfDocument instance. */
13315
+ const documentActionState = /* @__PURE__ */ new WeakMap();
13316
+ /**
13317
+ * Get the internal state for a document's catalog-level actions.
13318
+ *
13319
+ * Used by the catalog builder to set `/OpenAction` and `/AA` entries.
13320
+ *
13321
+ * @internal
13322
+ */
13323
+ function getDocumentActionState(doc) {
13324
+ return documentActionState.get(doc);
13325
+ }
13326
+
11848
13327
  //#endregion
11849
13328
  //#region src/core/pdfEmbed.ts
11850
13329
  /**
@@ -12807,12 +14286,232 @@ var PdfDocument = class PdfDocument {
12807
14286
  return imageRef;
12808
14287
  }
12809
14288
  /**
14289
+ * Embed a WebP image.
14290
+ *
14291
+ * WebP cannot be directly embedded in PDF. This method decodes the
14292
+ * WebP image to raw pixels (VP8/lossy, VP8L/lossless, or VP8+ALPH),
14293
+ * then embeds as a FlateDecode image XObject. If the WebP has
14294
+ * transparency, the alpha channel is embedded as a soft mask.
14295
+ *
14296
+ * @param webpData Raw WebP file bytes as a `Uint8Array` or `ArrayBuffer`.
14297
+ * @returns An {@link ImageRef}.
14298
+ */
14299
+ embedWebP(webpData) {
14300
+ const decoded = decodeWebP(webpData instanceof ArrayBuffer ? new Uint8Array(webpData) : webpData);
14301
+ this.imageCounter++;
14302
+ const resourceName = `Im${this.imageCounter}`;
14303
+ const dict = new PdfDict();
14304
+ dict.set("/Type", PdfName.of("XObject"));
14305
+ dict.set("/Subtype", PdfName.of("Image"));
14306
+ dict.set("/Width", PdfNumber.of(decoded.width));
14307
+ dict.set("/Height", PdfNumber.of(decoded.height));
14308
+ dict.set("/BitsPerComponent", PdfNumber.of(8));
14309
+ if (decoded.hasAlpha) {
14310
+ const pixelCount = decoded.width * decoded.height;
14311
+ const rgb = new Uint8Array(pixelCount * 3);
14312
+ const alpha = new Uint8Array(pixelCount);
14313
+ for (let i = 0; i < pixelCount; i++) {
14314
+ const srcIdx = i * 4;
14315
+ const dstIdx = i * 3;
14316
+ rgb[dstIdx] = decoded.pixels[srcIdx];
14317
+ rgb[dstIdx + 1] = decoded.pixels[srcIdx + 1];
14318
+ rgb[dstIdx + 2] = decoded.pixels[srcIdx + 2];
14319
+ alpha[i] = decoded.pixels[srcIdx + 3];
14320
+ }
14321
+ const compressedRgb = deflateSync(rgb, { level: 6 });
14322
+ const compressedAlpha = deflateSync(alpha, { level: 6 });
14323
+ dict.set("/ColorSpace", PdfName.of("DeviceRGB"));
14324
+ dict.set("/Filter", PdfName.of("FlateDecode"));
14325
+ dict.set("/Length", PdfNumber.of(compressedRgb.length));
14326
+ const smaskDict = new PdfDict();
14327
+ smaskDict.set("/Type", PdfName.of("XObject"));
14328
+ smaskDict.set("/Subtype", PdfName.of("Image"));
14329
+ smaskDict.set("/Width", PdfNumber.of(decoded.width));
14330
+ smaskDict.set("/Height", PdfNumber.of(decoded.height));
14331
+ smaskDict.set("/BitsPerComponent", PdfNumber.of(8));
14332
+ smaskDict.set("/ColorSpace", PdfName.of("DeviceGray"));
14333
+ smaskDict.set("/Filter", PdfName.of("FlateDecode"));
14334
+ smaskDict.set("/Length", PdfNumber.of(compressedAlpha.length));
14335
+ const smaskStream = new PdfStream(smaskDict, compressedAlpha);
14336
+ const smaskRef = this.registry.register(smaskStream);
14337
+ dict.set("/SMask", smaskRef);
14338
+ const stream = new PdfStream(dict, compressedRgb);
14339
+ const ref = this.registry.register(stream);
14340
+ const w = decoded.width;
14341
+ const h = decoded.height;
14342
+ const imageRef = {
14343
+ name: resourceName,
14344
+ ref,
14345
+ width: w,
14346
+ height: h,
14347
+ scale(factor) {
14348
+ return {
14349
+ width: w * factor,
14350
+ height: h * factor
14351
+ };
14352
+ },
14353
+ scaleToFit(maxW, maxH) {
14354
+ const ratio = Math.min(maxW / w, maxH / h);
14355
+ return {
14356
+ width: w * ratio,
14357
+ height: h * ratio
14358
+ };
14359
+ }
14360
+ };
14361
+ this.embeddedImages.push(imageRef);
14362
+ return imageRef;
14363
+ }
14364
+ const compressedRgb = deflateSync(decoded.pixels, { level: 6 });
14365
+ dict.set("/ColorSpace", PdfName.of("DeviceRGB"));
14366
+ dict.set("/Filter", PdfName.of("FlateDecode"));
14367
+ dict.set("/Length", PdfNumber.of(compressedRgb.length));
14368
+ const stream = new PdfStream(dict, compressedRgb);
14369
+ const ref = this.registry.register(stream);
14370
+ const w = decoded.width;
14371
+ const h = decoded.height;
14372
+ const imageRef = {
14373
+ name: resourceName,
14374
+ ref,
14375
+ width: w,
14376
+ height: h,
14377
+ scale(factor) {
14378
+ return {
14379
+ width: w * factor,
14380
+ height: h * factor
14381
+ };
14382
+ },
14383
+ scaleToFit(maxW, maxH) {
14384
+ const ratio = Math.min(maxW / w, maxH / h);
14385
+ return {
14386
+ width: w * ratio,
14387
+ height: h * ratio
14388
+ };
14389
+ }
14390
+ };
14391
+ this.embeddedImages.push(imageRef);
14392
+ return imageRef;
14393
+ }
14394
+ /**
14395
+ * Embed a TIFF image.
14396
+ *
14397
+ * Decodes the TIFF image and creates a PDF image XObject with
14398
+ * FlateDecode compression. For multi-page TIFFs, a specific page
14399
+ * can be selected via options.
14400
+ *
14401
+ * @param tiffData Raw TIFF file bytes as a `Uint8Array` or `ArrayBuffer`.
14402
+ * @param options Options (e.g., `{ page: 0 }` for multi-page TIFFs).
14403
+ * @returns An {@link ImageRef}.
14404
+ */
14405
+ embedTiff(tiffData, options) {
14406
+ const decoded = decodeTiff(tiffData instanceof ArrayBuffer ? new Uint8Array(tiffData) : tiffData, options?.page !== void 0 ? { page: options.page } : void 0);
14407
+ this.imageCounter++;
14408
+ const resourceName = `Im${this.imageCounter}`;
14409
+ const dict = new PdfDict();
14410
+ dict.set("/Type", PdfName.of("XObject"));
14411
+ dict.set("/Subtype", PdfName.of("Image"));
14412
+ dict.set("/Width", PdfNumber.of(decoded.width));
14413
+ dict.set("/Height", PdfNumber.of(decoded.height));
14414
+ dict.set("/BitsPerComponent", PdfNumber.of(8));
14415
+ if (decoded.channels === 4) {
14416
+ const pixelCount = decoded.width * decoded.height;
14417
+ const rgb = new Uint8Array(pixelCount * 3);
14418
+ const alpha = new Uint8Array(pixelCount);
14419
+ for (let i = 0; i < pixelCount; i++) {
14420
+ const srcIdx = i * 4;
14421
+ const dstIdx = i * 3;
14422
+ rgb[dstIdx] = decoded.pixels[srcIdx];
14423
+ rgb[dstIdx + 1] = decoded.pixels[srcIdx + 1];
14424
+ rgb[dstIdx + 2] = decoded.pixels[srcIdx + 2];
14425
+ alpha[i] = decoded.pixels[srcIdx + 3];
14426
+ }
14427
+ const compressedRgb = deflateSync(rgb, { level: 6 });
14428
+ const compressedAlpha = deflateSync(alpha, { level: 6 });
14429
+ dict.set("/ColorSpace", PdfName.of("DeviceRGB"));
14430
+ dict.set("/Filter", PdfName.of("FlateDecode"));
14431
+ dict.set("/Length", PdfNumber.of(compressedRgb.length));
14432
+ const smaskDict = new PdfDict();
14433
+ smaskDict.set("/Type", PdfName.of("XObject"));
14434
+ smaskDict.set("/Subtype", PdfName.of("Image"));
14435
+ smaskDict.set("/Width", PdfNumber.of(decoded.width));
14436
+ smaskDict.set("/Height", PdfNumber.of(decoded.height));
14437
+ smaskDict.set("/BitsPerComponent", PdfNumber.of(8));
14438
+ smaskDict.set("/ColorSpace", PdfName.of("DeviceGray"));
14439
+ smaskDict.set("/Filter", PdfName.of("FlateDecode"));
14440
+ smaskDict.set("/Length", PdfNumber.of(compressedAlpha.length));
14441
+ const smaskStream = new PdfStream(smaskDict, compressedAlpha);
14442
+ const smaskRef = this.registry.register(smaskStream);
14443
+ dict.set("/SMask", smaskRef);
14444
+ const stream = new PdfStream(dict, compressedRgb);
14445
+ const ref = this.registry.register(stream);
14446
+ const w = decoded.width;
14447
+ const h = decoded.height;
14448
+ const imageRef = {
14449
+ name: resourceName,
14450
+ ref,
14451
+ width: w,
14452
+ height: h,
14453
+ scale(factor) {
14454
+ return {
14455
+ width: w * factor,
14456
+ height: h * factor
14457
+ };
14458
+ },
14459
+ scaleToFit(maxW, maxH) {
14460
+ const ratio = Math.min(maxW / w, maxH / h);
14461
+ return {
14462
+ width: w * ratio,
14463
+ height: h * ratio
14464
+ };
14465
+ }
14466
+ };
14467
+ this.embeddedImages.push(imageRef);
14468
+ return imageRef;
14469
+ }
14470
+ const colorSpace = decoded.channels === 1 ? "DeviceGray" : "DeviceRGB";
14471
+ const compressed = deflateSync(decoded.pixels, { level: 6 });
14472
+ dict.set("/ColorSpace", PdfName.of(colorSpace));
14473
+ dict.set("/Filter", PdfName.of("FlateDecode"));
14474
+ dict.set("/Length", PdfNumber.of(compressed.length));
14475
+ const stream = new PdfStream(dict, compressed);
14476
+ const ref = this.registry.register(stream);
14477
+ const w = decoded.width;
14478
+ const h = decoded.height;
14479
+ const imageRef = {
14480
+ name: resourceName,
14481
+ ref,
14482
+ width: w,
14483
+ height: h,
14484
+ scale(factor) {
14485
+ return {
14486
+ width: w * factor,
14487
+ height: h * factor
14488
+ };
14489
+ },
14490
+ scaleToFit(maxW, maxH) {
14491
+ const ratio = Math.min(maxW / w, maxH / h);
14492
+ return {
14493
+ width: w * ratio,
14494
+ height: h * ratio
14495
+ };
14496
+ }
14497
+ };
14498
+ this.embeddedImages.push(imageRef);
14499
+ return imageRef;
14500
+ }
14501
+ /**
12810
14502
  * Embed an image, auto-detecting the format from file headers.
12811
14503
  *
12812
- * Inspects the first bytes to determine whether the data is PNG or JPEG,
12813
- * then delegates to {@link embedPng} or {@link embedJpeg} accordingly.
14504
+ * Inspects the first bytes to determine the image format (PNG, JPEG,
14505
+ * WebP, or TIFF), then delegates to the appropriate embedding method.
14506
+ *
14507
+ * Supported formats:
14508
+ * - **PNG**: `89 50 4E 47` — embedded via {@link embedPng}
14509
+ * - **JPEG**: `FF D8 FF` — embedded via {@link embedJpeg}
14510
+ * - **WebP**: `52 49 46 46` + `57 45 42 50` — embedded via {@link embedWebP}
14511
+ * - **TIFF LE**: `49 49 2A 00` — embedded via {@link embedTiff}
14512
+ * - **TIFF BE**: `4D 4D 00 2A` — embedded via {@link embedTiff}
12814
14513
  *
12815
- * @param imageData Raw image file bytes (PNG or JPEG).
14514
+ * @param imageData Raw image file bytes (PNG, JPEG, WebP, or TIFF).
12816
14515
  * @returns An {@link ImageRef} to pass to `page.drawImage()`.
12817
14516
  * @throws If the image format cannot be detected.
12818
14517
  *
@@ -12826,9 +14525,13 @@ var PdfDocument = class PdfDocument {
12826
14525
  async embedImage(imageData) {
12827
14526
  const data = imageData instanceof ArrayBuffer ? new Uint8Array(imageData) : imageData;
12828
14527
  if (data.length < 4) throw new Error("Image data too short to detect format");
12829
- if (data[0] === 137 && data[1] === 80 && data[2] === 78 && data[3] === 71) return this.embedPng(data);
12830
- if (data[0] === 255 && data[1] === 216 && data[2] === 255) return this.embedJpeg(data);
12831
- throw new Error(`Unsupported image format. Expected PNG (89 50 4E 47) or JPEG (FF D8 FF), got ${Array.from(data.subarray(0, 4)).map((b) => b.toString(16).padStart(2, "0")).join(" ")}.`);
14528
+ switch (detectImageFormat(data)) {
14529
+ case "png": return this.embedPng(data);
14530
+ case "jpeg": return this.embedJpeg(data);
14531
+ case "webp": return this.embedWebP(data);
14532
+ case "tiff": return this.embedTiff(data);
14533
+ default: throw new Error(`Unsupported image format. Expected PNG, JPEG, WebP, or TIFF, got ${data.subarray(0, 4).toHex().match(/.{2}/g)?.join(" ") ?? ""}.`);
14534
+ }
12832
14535
  }
12833
14536
  /**
12834
14537
  * Embed pages from another PDF as Form XObjects.
@@ -13607,6 +15310,61 @@ var PdfDocument = class PdfDocument {
13607
15310
  catalogObj.set("/Names", namesDict);
13608
15311
  }
13609
15312
  }
15313
+ const actionState = getDocumentActionState(this);
15314
+ if (actionState) {
15315
+ if (actionState.openAction !== void 0) {
15316
+ const openActionDict = new PdfDict();
15317
+ openActionDict.set("/Type", PdfName.of("Action"));
15318
+ openActionDict.set("/S", PdfName.of("JavaScript"));
15319
+ openActionDict.set("/JS", PdfString.literal(actionState.openAction));
15320
+ const openActionRef = this.registry.register(openActionDict);
15321
+ catalogObj.set("/OpenAction", openActionRef);
15322
+ }
15323
+ if (actionState.closeAction !== void 0 || actionState.beforePrint !== void 0 || actionState.afterPrint !== void 0 || actionState.beforeSave !== void 0 || actionState.afterSave !== void 0) {
15324
+ const aaDict = new PdfDict();
15325
+ if (actionState.closeAction !== void 0) {
15326
+ const d = new PdfDict();
15327
+ d.set("/Type", PdfName.of("Action"));
15328
+ d.set("/S", PdfName.of("JavaScript"));
15329
+ d.set("/JS", PdfString.literal(actionState.closeAction));
15330
+ const ref = this.registry.register(d);
15331
+ aaDict.set("/WC", ref);
15332
+ }
15333
+ if (actionState.beforePrint !== void 0) {
15334
+ const d = new PdfDict();
15335
+ d.set("/Type", PdfName.of("Action"));
15336
+ d.set("/S", PdfName.of("JavaScript"));
15337
+ d.set("/JS", PdfString.literal(actionState.beforePrint));
15338
+ const ref = this.registry.register(d);
15339
+ aaDict.set("/WP", ref);
15340
+ }
15341
+ if (actionState.afterPrint !== void 0) {
15342
+ const d = new PdfDict();
15343
+ d.set("/Type", PdfName.of("Action"));
15344
+ d.set("/S", PdfName.of("JavaScript"));
15345
+ d.set("/JS", PdfString.literal(actionState.afterPrint));
15346
+ const ref = this.registry.register(d);
15347
+ aaDict.set("/DP", ref);
15348
+ }
15349
+ if (actionState.beforeSave !== void 0) {
15350
+ const d = new PdfDict();
15351
+ d.set("/Type", PdfName.of("Action"));
15352
+ d.set("/S", PdfName.of("JavaScript"));
15353
+ d.set("/JS", PdfString.literal(actionState.beforeSave));
15354
+ const ref = this.registry.register(d);
15355
+ aaDict.set("/WS", ref);
15356
+ }
15357
+ if (actionState.afterSave !== void 0) {
15358
+ const d = new PdfDict();
15359
+ d.set("/Type", PdfName.of("Action"));
15360
+ d.set("/S", PdfName.of("JavaScript"));
15361
+ d.set("/JS", PdfString.literal(actionState.afterSave));
15362
+ const ref = this.registry.register(d);
15363
+ aaDict.set("/DS", ref);
15364
+ }
15365
+ catalogObj.set("/AA", aaDict);
15366
+ }
15367
+ }
13610
15368
  }
13611
15369
  if (this.originalBytes !== void 0) {
13612
15370
  const rootRefs = [structure.catalogRef, structure.infoRef];
@@ -13681,5 +15439,5 @@ function createPdf() {
13681
15439
  }
13682
15440
 
13683
15441
  //#endregion
13684
- export { sha384 as $, prepareForSigning as A, buildViewerPreferencesDict as B, encodeSet as C, computeSignatureHash as D, parseDerTlv as E, isAccessible as F, PdfOutlineItem as G, buildXmpMetadata as H, summarizeIssues as I, PdfEncryptionHandler as J, PdfOutlineTree as K, PdfStructureElement as L, mergePdfs as M, splitPdf as N, embedSignature as O, checkAccessibility as P, sha256 as Q, PdfStructureTree as R, encodeSequence as S, encodeUtf8String as T, createXmpStream as U, parseViewerPreferences as V, parseXmpMetadata as W, verifyOwnerPassword as X, computeFileEncryptionKey as Y, verifyUserPassword as Z, encodeInteger as _, serializePdf as _t, addWatermark as a, rc4 as at, encodeOctetString as b, buildEmbeddedFilesNameTree as c, base64Encode as ct, verifySignatures as d, isOpenTypeCFF as dt, sha512 as et, getSignatures as f, isTrueType as ft, encodeContextTag as g, PdfWriter as gt, decodeOidBytes as h, PdfStreamWriter as ht, embedPageAsFormXObject as i, aesEncryptCBC as it, copyPages as j, findSignatures as k, getAttachments as l, PdfParseError as lt, buildPkcs7Signature as m, extractMetrics as mt, StandardFonts as n, encodePermissions as nt, addWatermarkToPage as o, md5 as ot, signPdf as p, EmbeddedFont as pt, loadPdf as q, createPdf as r, aesDecryptCBC as rt, attachFile as s, base64Decode as st, PdfDocument as t, decodePermissions as tt, verifySignature as u, formatHexContext as ut, encodeLength as v, encodeUTCTime as w, encodePrintableString as x, encodeOID as y, PdfViewerPreferences as z };
13685
- //# sourceMappingURL=pdfDocument-DOg240g9.mjs.map
15442
+ export { PdfEncryptionHandler as $, parseDerTlv as A, EmbeddedFont as At, isAccessible as B, encodePrintableString as C, isWebP as Ct, encodeUtf8String as D, getSupportedFormats as Dt, encodeUTCTime as E, getImageFormatName as Et, prepareForSigning as F, buildViewerPreferencesDict as G, PdfStructureElement as H, copyPages as I, createXmpStream as J, parseViewerPreferences as K, mergePdfs as L, computeSignatureHash as M, PdfStreamWriter as Mt, embedSignature as N, PdfWriter as Nt, extractIssuerAndSerial as O, isOpenTypeCFF as Ot, findSignatures as P, serializePdf as Pt, loadPdf as Q, splitPdf as R, encodeOctetString as S, decodeWebP as St, encodeSet as T, detectImageFormat as Tt, PdfStructureTree as U, summarizeIssues as V, PdfViewerPreferences as W, PdfOutlineItem as X, parseXmpMetadata as Y, PdfOutlineTree as Z, detectNamedCurve as _, decodeTiffAll as _t, addWatermark as a, sha512 as at, encodeLength as b, isTiff as bt, buildEmbeddedFilesNameTree as c, aesDecryptCBC as ct, verifySignatures as d, md5 as dt, computeFileEncryptionKey as et, getSignatures as f, base64Decode as ft, detectKeyAlgorithm as g, decodeTiff as gt, decodeOidBytes as h, formatHexContext as ht, embedPageAsFormXObject as i, sha384 as it, toBuffer as j, extractMetrics as jt, getSubtle as k, isTrueType as kt, getAttachments as l, aesEncryptCBC as lt, buildPkcs7Signature as m, PdfParseError as mt, StandardFonts as n, verifyUserPassword as nt, addWatermarkToPage as o, decodePermissions as ot, signPdf as p, base64Encode as pt, buildXmpMetadata as q, createPdf as r, sha256 as rt, attachFile as s, encodePermissions as st, PdfDocument as t, verifyOwnerPassword as tt, verifySignature as u, rc4 as ut, encodeContextTag as v, decodeTiffPage as vt, encodeSequence as w, isWebPLossless as wt, encodeOID as x, parseTiffIfd as xt, encodeInteger as y, getTiffPageCount as yt, checkAccessibility as z };
15443
+ //# sourceMappingURL=pdfDocument-B0_XwS4X.mjs.map