modern-pdf-lib 0.22.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 (62) hide show
  1. package/README.md +22 -4
  2. package/dist/{batchOptimize-CxyY4fZe.mjs → batchOptimize-DtRwBOqR.mjs} +4 -4
  3. package/dist/{bridge-DTH5LMAK.mjs → bridge-CcivG_Sm.mjs} +3 -3
  4. package/dist/browser.cjs +50 -6
  5. package/dist/browser.d.cts +5 -5
  6. package/dist/browser.d.mts +5 -5
  7. package/dist/browser.mjs +11 -11
  8. package/dist/cli/index.mjs +3 -3
  9. package/dist/{compressionAnalysis-BBv4BkQP.d.mts → compressionAnalysis-DGs-MqTe.d.mts} +26 -3
  10. package/dist/compressionAnalysis-DGs-MqTe.d.mts.map +1 -0
  11. package/dist/{compressionAnalysis-CtJ2X9l2.d.cts → compressionAnalysis-VtYV9Zmq.d.cts} +26 -3
  12. package/dist/compressionAnalysis-VtYV9Zmq.d.cts.map +1 -0
  13. package/dist/{compressionAnalysis-ChkscEa1.mjs → compressionAnalysis-odbHC7Uk.mjs} +2 -2
  14. package/dist/create.cjs +22 -3
  15. package/dist/create.d.cts +3 -3
  16. package/dist/create.d.mts +3 -3
  17. package/dist/create.mjs +4 -4
  18. package/dist/{deduplicateImages-CmTeo6Tx.mjs → deduplicateImages-MfUDPxQz.mjs} +2 -2
  19. package/dist/{fflateAdapter-CBQpGTlx.mjs → fflateAdapter-PSiW_ML7.mjs} +2 -2
  20. package/dist/{fontEmbed-Dsu9fo4U.d.mts → fontEmbed-BN842wlb.d.cts} +26 -3
  21. package/dist/fontEmbed-BN842wlb.d.cts.map +1 -0
  22. package/dist/{fontEmbed-LID6yG6g.d.cts → fontEmbed-Dgq5K89o.d.mts} +26 -3
  23. package/dist/fontEmbed-Dgq5K89o.d.mts.map +1 -0
  24. package/dist/{fontSubset-DWpduoY2.mjs → fontSubset-D-vQQems.mjs} +2 -2
  25. package/dist/forms.cjs +8 -1
  26. package/dist/forms.d.cts +3 -3
  27. package/dist/forms.d.mts +3 -3
  28. package/dist/forms.mjs +2 -2
  29. package/dist/{index-BtYOx5wh.d.mts → index-DCSbmXWh.d.mts} +1088 -53
  30. package/dist/index-DCSbmXWh.d.mts.map +1 -0
  31. package/dist/{index-bpktKzCA.d.cts → index-J1W3FdL8.d.cts} +1088 -53
  32. package/dist/index-J1W3FdL8.d.cts.map +1 -0
  33. package/dist/index.cjs +50 -6
  34. package/dist/index.d.cts +5 -5
  35. package/dist/index.d.mts +5 -5
  36. package/dist/index.mjs +11 -11
  37. package/dist/{layout-DgX_0jfK.mjs → layout-D6EUKSP8.mjs} +39 -3
  38. package/dist/{layout-CuAVk_Or.cjs → layout-DH61a1iR.cjs} +55 -1
  39. package/dist/{libdeflateWasm-rLppXytE.mjs → libdeflateWasm-8b91Vmia.mjs} +3 -3
  40. package/dist/{loader-3u6Tw5T-.mjs → loader-C7B5dVCI.mjs} +2 -2
  41. package/dist/parse.cjs +3 -1
  42. package/dist/parse.d.cts +3 -3
  43. package/dist/parse.d.mts +3 -3
  44. package/dist/parse.mjs +3 -3
  45. package/dist/{pdfCatalog-IImGcMbR.mjs → pdfCatalog-3yMIhJtt.mjs} +2 -2
  46. package/dist/{pdfDocument-BFxHD_2u.mjs → pdfDocument-B0_XwS4X.mjs} +1712 -24
  47. package/dist/{pdfDocument-i6U5fQ91.d.mts → pdfDocument-BgvEP5Po.d.mts} +37 -4
  48. package/dist/{pdfDocument-i6U5fQ91.d.mts.map → pdfDocument-BgvEP5Po.d.mts.map} +1 -1
  49. package/dist/{pdfDocument-pmRXryVI.cjs → pdfDocument-CEbbUP9i.cjs} +1803 -13
  50. package/dist/{pdfDocument-BSiQdNZq.d.cts → pdfDocument-CbU-2TjT.d.cts} +37 -4
  51. package/dist/{pdfDocument-BSiQdNZq.d.cts.map → pdfDocument-CbU-2TjT.d.cts.map} +1 -1
  52. package/dist/{pdfPage-Cd8e7flb.mjs → pdfPage-B_d9HmkG.mjs} +3 -3
  53. package/dist/{pngEmbed-BLj2zi-5.mjs → pngEmbed-BWAbEUKF.mjs} +3 -3
  54. package/dist/{src-6L07EQsi.cjs → src-B1iDGLCL.cjs} +6408 -2675
  55. package/dist/{src-Dm4aaZ8q.mjs → src-Db6Qknoz.mjs} +6274 -2715
  56. package/package.json +4 -2
  57. package/dist/compressionAnalysis-BBv4BkQP.d.mts.map +0 -1
  58. package/dist/compressionAnalysis-CtJ2X9l2.d.cts.map +0 -1
  59. package/dist/fontEmbed-Dsu9fo4U.d.mts.map +0 -1
  60. package/dist/fontEmbed-LID6yG6g.d.cts.map +0 -1
  61. package/dist/index-BtYOx5wh.d.mts.map +0 -1
  62. 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-Cd8e7flb.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
9
  import { n as getStreamFilters, t as decodeStream$1 } from "./streamDecode-Bj568Nc9.mjs";
10
- import { deflateSync } from "fflate";
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
  /**
@@ -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
  }
@@ -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
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();
@@ -12822,12 +14286,232 @@ var PdfDocument = class PdfDocument {
12822
14286
  return imageRef;
12823
14287
  }
12824
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
+ /**
12825
14502
  * Embed an image, auto-detecting the format from file headers.
12826
14503
  *
12827
- * Inspects the first bytes to determine whether the data is PNG or JPEG,
12828
- * 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}
12829
14513
  *
12830
- * @param imageData Raw image file bytes (PNG or JPEG).
14514
+ * @param imageData Raw image file bytes (PNG, JPEG, WebP, or TIFF).
12831
14515
  * @returns An {@link ImageRef} to pass to `page.drawImage()`.
12832
14516
  * @throws If the image format cannot be detected.
12833
14517
  *
@@ -12841,9 +14525,13 @@ var PdfDocument = class PdfDocument {
12841
14525
  async embedImage(imageData) {
12842
14526
  const data = imageData instanceof ArrayBuffer ? new Uint8Array(imageData) : imageData;
12843
14527
  if (data.length < 4) throw new Error("Image data too short to detect format");
12844
- if (data[0] === 137 && data[1] === 80 && data[2] === 78 && data[3] === 71) return this.embedPng(data);
12845
- if (data[0] === 255 && data[1] === 216 && data[2] === 255) return this.embedJpeg(data);
12846
- throw new Error(`Unsupported image format. Expected PNG (89 50 4E 47) or JPEG (FF D8 FF), got ${data.subarray(0, 4).toHex().match(/.{2}/g)?.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
+ }
12847
14535
  }
12848
14536
  /**
12849
14537
  * Embed pages from another PDF as Form XObjects.
@@ -13751,5 +15439,5 @@ function createPdf() {
13751
15439
  }
13752
15440
 
13753
15441
  //#endregion
13754
- 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 };
13755
- //# sourceMappingURL=pdfDocument-BFxHD_2u.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