@cj-tech-master/excelts 9.1.0 → 9.2.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 (147) hide show
  1. package/README.md +16 -1
  2. package/dist/browser/modules/archive/compression/crc32.js +1 -1
  3. package/dist/browser/modules/archive/crypto/aes.d.ts +0 -8
  4. package/dist/browser/modules/archive/crypto/aes.js +1 -20
  5. package/dist/browser/modules/archive/crypto/index.d.ts +2 -1
  6. package/dist/browser/modules/archive/crypto/index.js +3 -1
  7. package/dist/browser/modules/csv/parse/row-processor.d.ts +1 -1
  8. package/dist/browser/modules/csv/worker/worker-script.generated.js +1 -1
  9. package/dist/browser/modules/excel/utils/cell-matrix.js +1 -0
  10. package/dist/browser/modules/excel/utils/encryptor.browser.d.ts +4 -5
  11. package/dist/browser/modules/excel/utils/encryptor.browser.js +7 -12
  12. package/dist/browser/modules/excel/utils/encryptor.d.ts +1 -1
  13. package/dist/browser/modules/excel/utils/encryptor.js +4 -7
  14. package/dist/browser/modules/pdf/builder/document-builder.d.ts +517 -0
  15. package/dist/browser/modules/pdf/builder/document-builder.js +1493 -0
  16. package/dist/browser/modules/pdf/builder/form-appearance.d.ts +56 -0
  17. package/dist/browser/modules/pdf/builder/form-appearance.js +140 -0
  18. package/dist/browser/modules/pdf/builder/image-utils.d.ts +39 -0
  19. package/dist/browser/modules/pdf/builder/image-utils.js +129 -0
  20. package/dist/browser/modules/pdf/builder/pdf-editor.d.ts +230 -0
  21. package/dist/browser/modules/pdf/builder/pdf-editor.js +1574 -0
  22. package/dist/browser/modules/pdf/builder/resource-merger.d.ts +41 -0
  23. package/dist/browser/modules/pdf/builder/resource-merger.js +258 -0
  24. package/dist/browser/modules/pdf/core/digital-signature.d.ts +109 -0
  25. package/dist/browser/modules/pdf/core/digital-signature.js +659 -0
  26. package/dist/browser/modules/pdf/core/encryption.js +8 -7
  27. package/dist/browser/modules/pdf/core/pdf-object.d.ts +11 -0
  28. package/dist/browser/modules/pdf/core/pdf-object.js +38 -0
  29. package/dist/browser/modules/pdf/core/pdf-stream.d.ts +32 -0
  30. package/dist/browser/modules/pdf/core/pdf-stream.js +66 -0
  31. package/dist/browser/modules/pdf/core/pdf-writer.d.ts +55 -1
  32. package/dist/browser/modules/pdf/core/pdf-writer.js +271 -6
  33. package/dist/browser/modules/pdf/core/pdfa.d.ts +62 -0
  34. package/dist/browser/modules/pdf/core/pdfa.js +261 -0
  35. package/dist/browser/modules/pdf/index.d.ts +11 -0
  36. package/dist/browser/modules/pdf/index.js +9 -0
  37. package/dist/browser/modules/pdf/reader/bookmark-extractor.d.ts +35 -0
  38. package/dist/browser/modules/pdf/reader/bookmark-extractor.js +324 -0
  39. package/dist/browser/modules/pdf/reader/pdf-decrypt.js +6 -5
  40. package/dist/browser/modules/pdf/reader/pdf-reader.d.ts +17 -0
  41. package/dist/browser/modules/pdf/reader/pdf-reader.js +26 -2
  42. package/dist/browser/modules/pdf/reader/table-extractor.d.ts +69 -0
  43. package/dist/browser/modules/pdf/reader/table-extractor.js +365 -0
  44. package/dist/browser/modules/pdf/render/layout-engine.d.ts +21 -1
  45. package/dist/browser/modules/pdf/render/layout-engine.js +112 -5
  46. package/dist/browser/modules/pdf/render/page-renderer.d.ts +2 -9
  47. package/dist/browser/modules/pdf/render/page-renderer.js +62 -103
  48. package/dist/browser/modules/pdf/render/pdf-exporter.js +2 -61
  49. package/dist/browser/modules/pdf/render/style-converter.d.ts +4 -0
  50. package/dist/browser/modules/pdf/render/style-converter.js +1 -1
  51. package/dist/browser/modules/pdf/types.d.ts +14 -1
  52. package/dist/browser/modules/stream/browser/readable.js +8 -2
  53. package/dist/browser/utils/crypto.browser.d.ts +64 -0
  54. package/dist/browser/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +91 -101
  55. package/dist/browser/utils/crypto.d.ts +97 -0
  56. package/dist/browser/utils/crypto.js +209 -0
  57. package/dist/cjs/modules/archive/compression/crc32.js +1 -1
  58. package/dist/cjs/modules/archive/crypto/aes.js +2 -23
  59. package/dist/cjs/modules/archive/crypto/index.js +3 -1
  60. package/dist/cjs/modules/csv/worker/worker-script.generated.js +1 -1
  61. package/dist/cjs/modules/excel/utils/cell-matrix.js +1 -0
  62. package/dist/cjs/modules/excel/utils/encryptor.browser.js +7 -12
  63. package/dist/cjs/modules/excel/utils/encryptor.js +4 -10
  64. package/dist/cjs/modules/pdf/builder/document-builder.js +1532 -0
  65. package/dist/cjs/modules/pdf/builder/form-appearance.js +145 -0
  66. package/dist/cjs/modules/pdf/builder/image-utils.js +135 -0
  67. package/dist/cjs/modules/pdf/builder/pdf-editor.js +1612 -0
  68. package/dist/cjs/modules/pdf/builder/resource-merger.js +263 -0
  69. package/dist/cjs/modules/pdf/core/digital-signature.js +667 -0
  70. package/dist/cjs/modules/pdf/core/encryption.js +8 -7
  71. package/dist/cjs/modules/pdf/core/pdf-object.js +38 -0
  72. package/dist/cjs/modules/pdf/core/pdf-stream.js +66 -0
  73. package/dist/cjs/modules/pdf/core/pdf-writer.js +272 -6
  74. package/dist/cjs/modules/pdf/core/pdfa.js +266 -0
  75. package/dist/cjs/modules/pdf/index.js +19 -1
  76. package/dist/cjs/modules/pdf/reader/bookmark-extractor.js +327 -0
  77. package/dist/cjs/modules/pdf/reader/pdf-decrypt.js +6 -5
  78. package/dist/cjs/modules/pdf/reader/pdf-reader.js +26 -2
  79. package/dist/cjs/modules/pdf/reader/table-extractor.js +368 -0
  80. package/dist/cjs/modules/pdf/render/layout-engine.js +113 -4
  81. package/dist/cjs/modules/pdf/render/page-renderer.js +63 -105
  82. package/dist/cjs/modules/pdf/render/pdf-exporter.js +3 -62
  83. package/dist/cjs/modules/pdf/render/style-converter.js +1 -0
  84. package/dist/cjs/modules/stream/browser/readable.js +8 -2
  85. package/dist/cjs/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +95 -102
  86. package/dist/cjs/utils/crypto.js +228 -0
  87. package/dist/esm/modules/archive/compression/crc32.js +1 -1
  88. package/dist/esm/modules/archive/crypto/aes.js +1 -20
  89. package/dist/esm/modules/archive/crypto/index.js +3 -1
  90. package/dist/esm/modules/csv/worker/worker-script.generated.js +1 -1
  91. package/dist/esm/modules/excel/utils/cell-matrix.js +1 -0
  92. package/dist/esm/modules/excel/utils/encryptor.browser.js +7 -12
  93. package/dist/esm/modules/excel/utils/encryptor.js +4 -7
  94. package/dist/esm/modules/pdf/builder/document-builder.js +1493 -0
  95. package/dist/esm/modules/pdf/builder/form-appearance.js +140 -0
  96. package/dist/esm/modules/pdf/builder/image-utils.js +129 -0
  97. package/dist/esm/modules/pdf/builder/pdf-editor.js +1574 -0
  98. package/dist/esm/modules/pdf/builder/resource-merger.js +258 -0
  99. package/dist/esm/modules/pdf/core/digital-signature.js +659 -0
  100. package/dist/esm/modules/pdf/core/encryption.js +8 -7
  101. package/dist/esm/modules/pdf/core/pdf-object.js +38 -0
  102. package/dist/esm/modules/pdf/core/pdf-stream.js +66 -0
  103. package/dist/esm/modules/pdf/core/pdf-writer.js +271 -6
  104. package/dist/esm/modules/pdf/core/pdfa.js +261 -0
  105. package/dist/esm/modules/pdf/index.js +9 -0
  106. package/dist/esm/modules/pdf/reader/bookmark-extractor.js +324 -0
  107. package/dist/esm/modules/pdf/reader/pdf-decrypt.js +6 -5
  108. package/dist/esm/modules/pdf/reader/pdf-reader.js +26 -2
  109. package/dist/esm/modules/pdf/reader/table-extractor.js +365 -0
  110. package/dist/esm/modules/pdf/render/layout-engine.js +112 -5
  111. package/dist/esm/modules/pdf/render/page-renderer.js +62 -103
  112. package/dist/esm/modules/pdf/render/pdf-exporter.js +2 -61
  113. package/dist/esm/modules/pdf/render/style-converter.js +1 -1
  114. package/dist/esm/modules/stream/browser/readable.js +8 -2
  115. package/dist/esm/{modules/pdf/core/crypto.js → utils/crypto.browser.js} +91 -101
  116. package/dist/esm/utils/crypto.js +209 -0
  117. package/dist/iife/excelts.iife.js +1248 -1074
  118. package/dist/iife/excelts.iife.js.map +1 -1
  119. package/dist/iife/excelts.iife.min.js +53 -54
  120. package/dist/types/modules/archive/crypto/aes.d.ts +0 -8
  121. package/dist/types/modules/archive/crypto/index.d.ts +2 -1
  122. package/dist/types/modules/csv/parse/row-processor.d.ts +1 -1
  123. package/dist/types/modules/excel/utils/encryptor.browser.d.ts +4 -5
  124. package/dist/types/modules/excel/utils/encryptor.d.ts +1 -1
  125. package/dist/types/modules/pdf/builder/document-builder.d.ts +517 -0
  126. package/dist/types/modules/pdf/builder/form-appearance.d.ts +56 -0
  127. package/dist/types/modules/pdf/builder/image-utils.d.ts +39 -0
  128. package/dist/types/modules/pdf/builder/pdf-editor.d.ts +230 -0
  129. package/dist/types/modules/pdf/builder/resource-merger.d.ts +41 -0
  130. package/dist/types/modules/pdf/core/digital-signature.d.ts +109 -0
  131. package/dist/types/modules/pdf/core/pdf-object.d.ts +11 -0
  132. package/dist/types/modules/pdf/core/pdf-stream.d.ts +32 -0
  133. package/dist/types/modules/pdf/core/pdf-writer.d.ts +55 -1
  134. package/dist/types/modules/pdf/core/pdfa.d.ts +62 -0
  135. package/dist/types/modules/pdf/index.d.ts +11 -0
  136. package/dist/types/modules/pdf/reader/bookmark-extractor.d.ts +35 -0
  137. package/dist/types/modules/pdf/reader/pdf-reader.d.ts +17 -0
  138. package/dist/types/modules/pdf/reader/table-extractor.d.ts +69 -0
  139. package/dist/types/modules/pdf/render/layout-engine.d.ts +21 -1
  140. package/dist/types/modules/pdf/render/page-renderer.d.ts +2 -9
  141. package/dist/types/modules/pdf/render/style-converter.d.ts +4 -0
  142. package/dist/types/modules/pdf/types.d.ts +14 -1
  143. package/dist/types/utils/crypto.browser.d.ts +64 -0
  144. package/dist/types/utils/crypto.d.ts +97 -0
  145. package/package.json +110 -111
  146. package/dist/browser/modules/pdf/core/crypto.d.ts +0 -65
  147. package/dist/types/modules/pdf/core/crypto.d.ts +0 -65
@@ -0,0 +1,266 @@
1
+ "use strict";
2
+ /**
3
+ * PDF/A-1b compliance utilities.
4
+ *
5
+ * Provides XMP metadata stream writing and OutputIntent creation for
6
+ * PDF/A-1b (ISO 19005-1, Level B) conformance.
7
+ *
8
+ * **Limitations:**
9
+ * - Type1 base fonts (Helvetica, Times-Roman, Courier, etc.) are NOT embedded.
10
+ * PDF/A-1b strictly requires all fonts to be embedded. Documents using only
11
+ * CIDFonts (embedded TrueType via `embedFont()`) are fully compliant.
12
+ * Documents using base Type1 fonts will pass structural validation but may
13
+ * fail strict PDF/A font-embedding checks.
14
+ *
15
+ * @see ISO 19005-1:2005 — Document management — Electronic document file
16
+ * format for long-term preservation — Part 1: Use of PDF 1.4 (PDF/A-1)
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.sRGB_ICC_PROFILE = void 0;
20
+ exports.writePdfAMetadata = writePdfAMetadata;
21
+ exports.writePdfAOutputIntent = writePdfAOutputIntent;
22
+ const pdf_object_1 = require("./pdf-object");
23
+ // =============================================================================
24
+ // sRGB ICC Profile
25
+ // =============================================================================
26
+ /**
27
+ * Minimal sRGB ICC profile (v2.1.0).
28
+ *
29
+ * This is a valid ICC profile with the correct header structure, profile
30
+ * signature, and a minimal tag table. It identifies the color space as RGB
31
+ * with the sRGB rendering intent. The profile is intentionally minimal
32
+ * (~128 bytes) — enough to satisfy PDF/A-1b OutputIntent requirements.
33
+ *
34
+ * Structure:
35
+ * - 128-byte header (profile size, preferred CMM, version, device class,
36
+ * color space, PCS, creation date, signature, platform, flags, etc.)
37
+ * - Tag table with 0 tags (profile is header-only for minimal compliance)
38
+ *
39
+ * @see ICC.1:2001-04 — File Format for Color Profiles (v2)
40
+ */
41
+ exports.sRGB_ICC_PROFILE = buildMinimalSrgbProfile();
42
+ function buildMinimalSrgbProfile() {
43
+ // ICC profile header is exactly 128 bytes
44
+ // We add a tag table with 3 required tags: desc, wtpt, cprt
45
+ // Each tag table entry is 12 bytes
46
+ const TAG_COUNT = 3;
47
+ const TAG_TABLE_SIZE = 4 + TAG_COUNT * 12; // 4 (count) + 3 * 12 (entries)
48
+ // Tag data — description, white point, copyright
49
+ const descData = buildTextDescriptionTag("sRGB IEC61966-2.1");
50
+ const wtptData = buildXYZTag(0.9505, 1.0, 1.089); // D50 white point
51
+ const cprtData = buildTextTag("No copyright");
52
+ const descOffset = 128 + TAG_TABLE_SIZE;
53
+ const wtptOffset = descOffset + descData.length;
54
+ const cprtOffset = wtptOffset + wtptData.length;
55
+ const profileSize = cprtOffset + cprtData.length;
56
+ const buf = new Uint8Array(profileSize);
57
+ const view = new DataView(buf.buffer);
58
+ // --- Header (128 bytes) ---
59
+ view.setUint32(0, profileSize); // Profile size
60
+ // Preferred CMM: none (0)
61
+ view.setUint8(8, 2); // Major version 2
62
+ view.setUint8(9, 0x10); // Minor version 1.0
63
+ // Profile/Device class: 'mntr' (monitor)
64
+ writeAscii(buf, 12, "mntr");
65
+ // Color space: 'RGB '
66
+ writeAscii(buf, 16, "RGB ");
67
+ // Profile Connection Space: 'XYZ '
68
+ writeAscii(buf, 20, "XYZ ");
69
+ // Creation date/time (2000-01-01 00:00:00)
70
+ view.setUint16(24, 2000); // year
71
+ view.setUint16(26, 1); // month
72
+ view.setUint16(28, 1); // day
73
+ // hour, minute, second = 0 (already zero)
74
+ // File signature: 'acsp'
75
+ writeAscii(buf, 36, "acsp");
76
+ // Primary platform: 'APPL'
77
+ writeAscii(buf, 40, "APPL");
78
+ // Rendering intent: 0 = Perceptual
79
+ view.setUint32(64, 0);
80
+ // PCS illuminant (D50 XYZ): X=0.9642, Y=1.0, Z=0.8249
81
+ writeS15Fixed16(view, 68, 0.9642);
82
+ writeS15Fixed16(view, 72, 1.0);
83
+ writeS15Fixed16(view, 76, 0.8249);
84
+ // --- Tag table ---
85
+ const tagTableOffset = 128;
86
+ view.setUint32(tagTableOffset, TAG_COUNT);
87
+ // Tag 1: 'desc' (profile description)
88
+ writeAscii(buf, tagTableOffset + 4, "desc");
89
+ view.setUint32(tagTableOffset + 8, descOffset);
90
+ view.setUint32(tagTableOffset + 12, descData.length);
91
+ // Tag 2: 'wtpt' (media white point)
92
+ writeAscii(buf, tagTableOffset + 16, "wtpt");
93
+ view.setUint32(tagTableOffset + 20, wtptOffset);
94
+ view.setUint32(tagTableOffset + 24, wtptData.length);
95
+ // Tag 3: 'cprt' (copyright)
96
+ writeAscii(buf, tagTableOffset + 28, "cprt");
97
+ view.setUint32(tagTableOffset + 32, cprtOffset);
98
+ view.setUint32(tagTableOffset + 36, cprtData.length);
99
+ // --- Tag data ---
100
+ buf.set(descData, descOffset);
101
+ buf.set(wtptData, wtptOffset);
102
+ buf.set(cprtData, cprtOffset);
103
+ return buf;
104
+ }
105
+ /** Write a 4-character ASCII string at the given offset. */
106
+ function writeAscii(buf, offset, str) {
107
+ for (let i = 0; i < str.length; i++) {
108
+ buf[offset + i] = str.charCodeAt(i);
109
+ }
110
+ }
111
+ /** Write an s15Fixed16Number (ICC fixed-point) at the given offset. */
112
+ function writeS15Fixed16(view, offset, value) {
113
+ const fixed = Math.round(value * 65536);
114
+ view.setInt32(offset, fixed);
115
+ }
116
+ /**
117
+ * Build an ICC 'desc' (textDescription) tag.
118
+ * Type signature: 'desc', followed by ASCII string.
119
+ */
120
+ function buildTextDescriptionTag(text) {
121
+ // desc type: 4 (sig) + 4 (reserved) + 4 (ASCII count) + N (ASCII) + padding
122
+ const asciiLen = text.length + 1; // include null terminator
123
+ // Total: sig(4) + reserved(4) + count(4) + ascii(asciiLen) + unicode_count(4) + scriptcode_count(2) + scriptcode(67)
124
+ // Simplified: just ASCII portion for minimal profile
125
+ const totalLen = 4 + 4 + 4 + asciiLen + 4 + 4 + 2 + 67;
126
+ const buf = new Uint8Array(totalLen);
127
+ const view = new DataView(buf.buffer);
128
+ writeAscii(buf, 0, "desc");
129
+ // reserved: 0 (already zero)
130
+ view.setUint32(8, asciiLen);
131
+ for (let i = 0; i < text.length; i++) {
132
+ buf[12 + i] = text.charCodeAt(i);
133
+ }
134
+ // null terminator at 12 + text.length is already 0
135
+ // Unicode count = 0, scriptcode count = 0 — all zeros
136
+ return buf;
137
+ }
138
+ /** Build an ICC 'XYZ ' tag for a single XYZ triplet. */
139
+ function buildXYZTag(x, y, z) {
140
+ const buf = new Uint8Array(20); // sig(4) + reserved(4) + X(4) + Y(4) + Z(4)
141
+ const view = new DataView(buf.buffer);
142
+ writeAscii(buf, 0, "XYZ ");
143
+ // reserved: 0
144
+ writeS15Fixed16(view, 8, x);
145
+ writeS15Fixed16(view, 12, y);
146
+ writeS15Fixed16(view, 16, z);
147
+ return buf;
148
+ }
149
+ /** Build an ICC 'text' tag. */
150
+ function buildTextTag(text) {
151
+ const asciiLen = text.length + 1; // include null terminator
152
+ const buf = new Uint8Array(4 + 4 + asciiLen); // sig(4) + reserved(4) + text
153
+ writeAscii(buf, 0, "text");
154
+ for (let i = 0; i < text.length; i++) {
155
+ buf[8 + i] = text.charCodeAt(i);
156
+ }
157
+ return buf;
158
+ }
159
+ // =============================================================================
160
+ // XMP Metadata Writer
161
+ // =============================================================================
162
+ /**
163
+ * Write a PDF/A-1b XMP metadata stream as an indirect object.
164
+ *
165
+ * The XMP packet contains:
166
+ * - `dc:title` — document title
167
+ * - `dc:creator` — document author
168
+ * - `xmp:CreatorTool` — creating application
169
+ * - `pdf:Producer` — PDF producer
170
+ * - `pdfaid:part` — PDF/A part (1)
171
+ * - `pdfaid:conformance` — PDF/A conformance level (B)
172
+ *
173
+ * @returns The object number of the XMP metadata stream.
174
+ */
175
+ function writePdfAMetadata(writer, metadata) {
176
+ const now = new Date();
177
+ const isoDate = now.toISOString().replace(/\.\d{3}Z$/, "Z");
178
+ const title = escapeXml(metadata.title ?? "");
179
+ const author = escapeXml(metadata.author ?? "");
180
+ const subject = escapeXml(metadata.subject ?? "");
181
+ const creator = escapeXml(metadata.creator ?? "excelts");
182
+ const producer = "excelts";
183
+ const xmp = [
184
+ '<?xpacket begin="\uFEFF" id="W5M0MpCehiHzreSzNTczkc9d"?>',
185
+ '<x:xmpmeta xmlns:x="adobe:ns:meta/">',
186
+ '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">',
187
+ '<rdf:Description rdf:about=""',
188
+ ' xmlns:dc="http://purl.org/dc/elements/1.1/"',
189
+ ' xmlns:xmp="http://ns.adobe.com/xap/1.0/"',
190
+ ' xmlns:pdf="http://ns.adobe.com/pdf/1.3/"',
191
+ ' xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/">',
192
+ " <dc:title>",
193
+ ' <rdf:Alt><rdf:li xml:lang="x-default">' + title + "</rdf:li></rdf:Alt>",
194
+ " </dc:title>",
195
+ " <dc:creator>",
196
+ " <rdf:Seq><rdf:li>" + author + "</rdf:li></rdf:Seq>",
197
+ " </dc:creator>",
198
+ " <dc:description>",
199
+ ' <rdf:Alt><rdf:li xml:lang="x-default">' + subject + "</rdf:li></rdf:Alt>",
200
+ " </dc:description>",
201
+ " <xmp:CreatorTool>" + creator + "</xmp:CreatorTool>",
202
+ " <xmp:CreateDate>" + isoDate + "</xmp:CreateDate>",
203
+ " <xmp:ModifyDate>" + isoDate + "</xmp:ModifyDate>",
204
+ " <pdf:Producer>" + producer + "</pdf:Producer>",
205
+ " <pdfaid:part>1</pdfaid:part>",
206
+ " <pdfaid:conformance>B</pdfaid:conformance>",
207
+ "</rdf:Description>",
208
+ "</rdf:RDF>",
209
+ "</x:xmpmeta>",
210
+ '<?xpacket end="w"?>'
211
+ ].join("\n");
212
+ const encoder = new TextEncoder();
213
+ const xmpBytes = encoder.encode(xmp);
214
+ const objNum = writer.allocObject();
215
+ const dict = new pdf_object_1.PdfDict()
216
+ .set("Type", "/Metadata")
217
+ .set("Subtype", "/XML")
218
+ .set("Length", (0, pdf_object_1.pdfNumber)(xmpBytes.length));
219
+ // XMP metadata must NOT be compressed for PDF/A compliance
220
+ // (and for general discoverability by search tools)
221
+ writer.addStreamObject(objNum, dict, xmpBytes, { compress: false });
222
+ return objNum;
223
+ }
224
+ // =============================================================================
225
+ // OutputIntent Writer
226
+ // =============================================================================
227
+ /**
228
+ * Write a PDF/A-1b OutputIntent with an embedded sRGB ICC profile.
229
+ *
230
+ * Creates two objects:
231
+ * 1. The ICC profile stream
232
+ * 2. The OutputIntent dictionary referencing the profile
233
+ *
234
+ * @returns The object number of the OutputIntent dictionary.
235
+ */
236
+ function writePdfAOutputIntent(writer) {
237
+ // Write ICC profile stream
238
+ const iccObjNum = writer.allocObject();
239
+ const iccDict = new pdf_object_1.PdfDict()
240
+ .set("N", (0, pdf_object_1.pdfNumber)(3)) // 3 components (RGB)
241
+ .set("Length", (0, pdf_object_1.pdfNumber)(exports.sRGB_ICC_PROFILE.length));
242
+ writer.addStreamObject(iccObjNum, iccDict, exports.sRGB_ICC_PROFILE);
243
+ // Write OutputIntent dictionary
244
+ const intentObjNum = writer.allocObject();
245
+ const intentDict = new pdf_object_1.PdfDict()
246
+ .set("Type", "/OutputIntent")
247
+ .set("S", "/GTS_PDFA1")
248
+ .set("OutputConditionIdentifier", "(sRGB IEC61966-2.1)")
249
+ .set("RegistryName", "(http://www.color.org)")
250
+ .set("Info", "(sRGB IEC61966-2.1)")
251
+ .set("DestOutputProfile", (0, pdf_object_1.pdfRef)(iccObjNum));
252
+ writer.addObject(intentObjNum, intentDict);
253
+ return intentObjNum;
254
+ }
255
+ // =============================================================================
256
+ // Helpers
257
+ // =============================================================================
258
+ /** Escape XML special characters for XMP content. */
259
+ function escapeXml(str) {
260
+ return str
261
+ .replace(/&/g, "&amp;")
262
+ .replace(/</g, "&lt;")
263
+ .replace(/>/g, "&gt;")
264
+ .replace(/"/g, "&quot;")
265
+ .replace(/'/g, "&apos;");
266
+ }
@@ -42,7 +42,7 @@
42
42
  * @module pdf
43
43
  */
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
- exports.isPdfError = exports.PdfStructureError = exports.PdfFontError = exports.PdfRenderError = exports.PdfError = exports.PageSizes = exports.readPdf = exports.excelToPdf = exports.pdf = void 0;
45
+ exports.isPdfError = exports.PdfStructureError = exports.PdfFontError = exports.PdfRenderError = exports.PdfError = exports.PageSizes = exports.asn1Parse = exports.buildSignatureDictPlaceholder = exports.signPdf = exports.verifyPdfSignature = exports.PdfEditorPage = exports.PdfEditor = exports.parseSvgPath = exports.PdfPageBuilder = exports.PdfDocumentBuilder = exports.readPdf = exports.excelToPdf = exports.pdf = void 0;
46
46
  // =============================================================================
47
47
  // Public API — Writing
48
48
  // =============================================================================
@@ -58,6 +58,24 @@ Object.defineProperty(exports, "excelToPdf", { enumerable: true, get: function (
58
58
  /** Read a PDF file and extract text, images, and metadata. */
59
59
  var pdf_reader_1 = require("./reader/pdf-reader");
60
60
  Object.defineProperty(exports, "readPdf", { enumerable: true, get: function () { return pdf_reader_1.readPdf; } });
61
+ // =============================================================================
62
+ // Public API — Building (free-form content)
63
+ // =============================================================================
64
+ /** Build PDFs with free text positioning, vector drawing, and images. */
65
+ var document_builder_1 = require("./builder/document-builder");
66
+ Object.defineProperty(exports, "PdfDocumentBuilder", { enumerable: true, get: function () { return document_builder_1.PdfDocumentBuilder; } });
67
+ Object.defineProperty(exports, "PdfPageBuilder", { enumerable: true, get: function () { return document_builder_1.PdfPageBuilder; } });
68
+ Object.defineProperty(exports, "parseSvgPath", { enumerable: true, get: function () { return document_builder_1.parseSvgPath; } });
69
+ /** Edit existing PDFs: overlay content, fill forms, copy/merge pages. */
70
+ var pdf_editor_1 = require("./builder/pdf-editor");
71
+ Object.defineProperty(exports, "PdfEditor", { enumerable: true, get: function () { return pdf_editor_1.PdfEditor; } });
72
+ Object.defineProperty(exports, "PdfEditorPage", { enumerable: true, get: function () { return pdf_editor_1.PdfEditorPage; } });
73
+ /** Digital signatures — verify and sign PDF documents. */
74
+ var digital_signature_1 = require("./core/digital-signature");
75
+ Object.defineProperty(exports, "verifyPdfSignature", { enumerable: true, get: function () { return digital_signature_1.verifyPdfSignature; } });
76
+ Object.defineProperty(exports, "signPdf", { enumerable: true, get: function () { return digital_signature_1.signPdf; } });
77
+ Object.defineProperty(exports, "buildSignatureDictPlaceholder", { enumerable: true, get: function () { return digital_signature_1.buildSignatureDictPlaceholder; } });
78
+ Object.defineProperty(exports, "asn1Parse", { enumerable: true, get: function () { return digital_signature_1.asn1Parse; } });
61
79
  var types_1 = require("./types");
62
80
  Object.defineProperty(exports, "PageSizes", { enumerable: true, get: function () { return types_1.PageSizes; } });
63
81
  // =============================================================================
@@ -0,0 +1,327 @@
1
+ "use strict";
2
+ /**
3
+ * PDF bookmark (outline) extractor.
4
+ *
5
+ * Extracts the document outline tree from a PDF's `/Outlines` dictionary.
6
+ * Each outline item has a title, a target page index, and optional children
7
+ * forming a hierarchical bookmark tree.
8
+ *
9
+ * Supports:
10
+ * - Direct destinations (`/Dest` as array or named destination)
11
+ * - Action-based destinations (`/A << /S /GoTo /D ... >>`)
12
+ * - Nested bookmarks (children via `/First`/`/Last` chains)
13
+ * - Circular reference protection
14
+ *
15
+ * @see PDF Reference 1.7, §12.3 - Document-Level Navigation
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.extractBookmarks = extractBookmarks;
19
+ const pdf_parser_1 = require("./pdf-parser");
20
+ const reader_utils_1 = require("./reader-utils");
21
+ // =============================================================================
22
+ // Constants
23
+ // =============================================================================
24
+ /** Maximum depth for recursive outline traversal to prevent stack overflow. */
25
+ const MAX_OUTLINE_DEPTH = 100;
26
+ /** Maximum number of siblings at any level to prevent infinite /Next chains. */
27
+ const MAX_SIBLINGS = 10000;
28
+ // =============================================================================
29
+ // Public API
30
+ // =============================================================================
31
+ /**
32
+ * Extract bookmarks (outlines) from a PDF document.
33
+ *
34
+ * Reads the `/Outlines` dictionary from the catalog and recursively
35
+ * traverses the outline tree following `/First` → `/Next` chains.
36
+ *
37
+ * @param doc - The PDF document
38
+ * @returns Array of top-level bookmarks with nested children
39
+ */
40
+ function extractBookmarks(doc) {
41
+ try {
42
+ const catalog = doc.getCatalog();
43
+ const outlinesObj = catalog.get("Outlines");
44
+ if (!outlinesObj) {
45
+ return [];
46
+ }
47
+ const outlinesDict = doc.derefDict(outlinesObj);
48
+ if (!outlinesDict) {
49
+ return [];
50
+ }
51
+ // Build a page reference → index map for resolving destinations
52
+ const pageMap = buildPageMap(doc);
53
+ // The outline root's /First points to the first top-level item
54
+ const visited = new Set();
55
+ return collectSiblings(outlinesDict, doc, pageMap, visited, 0);
56
+ }
57
+ catch {
58
+ return [];
59
+ }
60
+ }
61
+ // =============================================================================
62
+ // Page Map
63
+ // =============================================================================
64
+ /**
65
+ * Build a map from page object reference identity to 0-based page index.
66
+ *
67
+ * We map by object number since page dicts resolved from different refs
68
+ * will share the same objNum.
69
+ */
70
+ function buildPageMap(doc) {
71
+ const pages = doc.getPagesWithObjInfo();
72
+ const map = new Map();
73
+ for (let i = 0; i < pages.length; i++) {
74
+ const { objNum } = pages[i];
75
+ if (objNum !== 0) {
76
+ map.set(objNum, i);
77
+ }
78
+ }
79
+ return map;
80
+ }
81
+ // =============================================================================
82
+ // Outline Tree Traversal
83
+ // =============================================================================
84
+ /**
85
+ * Collect the sibling chain starting from the `/First` child of a parent node.
86
+ */
87
+ function collectSiblings(parentDict, doc, pageMap, visited, depth) {
88
+ if (depth > MAX_OUTLINE_DEPTH) {
89
+ return [];
90
+ }
91
+ const firstObj = parentDict.get("First");
92
+ if (!firstObj) {
93
+ return [];
94
+ }
95
+ const bookmarks = [];
96
+ let currentObj = firstObj;
97
+ let count = 0;
98
+ while (currentObj != null && count < MAX_SIBLINGS) {
99
+ count++;
100
+ // Guard against circular references using object numbers
101
+ if ((0, pdf_parser_1.isPdfRef)(currentObj)) {
102
+ if (visited.has(currentObj.objNum)) {
103
+ break;
104
+ }
105
+ visited.add(currentObj.objNum);
106
+ }
107
+ const itemDict = doc.derefDict(currentObj);
108
+ if (!itemDict) {
109
+ break;
110
+ }
111
+ const bookmark = parseOutlineItem(itemDict, doc, pageMap, visited, depth);
112
+ if (bookmark) {
113
+ bookmarks.push(bookmark);
114
+ }
115
+ // Follow /Next to the next sibling
116
+ currentObj = itemDict.get("Next");
117
+ }
118
+ return bookmarks;
119
+ }
120
+ /**
121
+ * Parse a single outline item dictionary into a PdfBookmark.
122
+ */
123
+ function parseOutlineItem(dict, doc, pageMap, visited, depth) {
124
+ // Extract title — required per spec
125
+ const title = getOutlineTitle(dict, doc);
126
+ if (!title) {
127
+ return null;
128
+ }
129
+ // Resolve destination to a page index
130
+ const pageIndex = resolveDestination(dict, doc, pageMap);
131
+ // Collect children (nested bookmarks)
132
+ const children = collectSiblings(dict, doc, pageMap, visited, depth + 1);
133
+ return { title, pageIndex, children };
134
+ }
135
+ // =============================================================================
136
+ // Title Extraction
137
+ // =============================================================================
138
+ /**
139
+ * Extract the title string from an outline item dictionary.
140
+ * The /Title entry is a text string (may be Uint8Array or string).
141
+ */
142
+ function getOutlineTitle(dict, doc) {
143
+ return (0, reader_utils_1.getDictStringValue)(dict, "Title", doc);
144
+ }
145
+ // =============================================================================
146
+ // Destination Resolution
147
+ // =============================================================================
148
+ /**
149
+ * Resolve an outline item's destination to a 0-based page index.
150
+ *
151
+ * Checks /Dest first, then falls back to /A (action) with /S /GoTo.
152
+ * Returns -1 if the destination cannot be resolved.
153
+ */
154
+ function resolveDestination(dict, doc, pageMap) {
155
+ // 1. Try /Dest (direct destination)
156
+ const destObj = dict.get("Dest");
157
+ if (destObj != null) {
158
+ const pageIndex = resolveDestValue(destObj, doc, pageMap);
159
+ if (pageIndex >= 0) {
160
+ return pageIndex;
161
+ }
162
+ }
163
+ // 2. Try /A (action dictionary) with /S /GoTo
164
+ const actionObj = dict.get("A");
165
+ if (actionObj != null) {
166
+ const actionDict = doc.derefDict(actionObj);
167
+ if (actionDict) {
168
+ const actionType = (0, pdf_parser_1.dictGetName)(actionDict, "S");
169
+ if (actionType === "GoTo") {
170
+ const actionDest = actionDict.get("D");
171
+ if (actionDest != null) {
172
+ return resolveDestValue(actionDest, doc, pageMap);
173
+ }
174
+ }
175
+ }
176
+ }
177
+ return -1;
178
+ }
179
+ /**
180
+ * Resolve a destination value (from /Dest or /A.D) to a page index.
181
+ *
182
+ * Destination formats (PDF Reference 1.7, §12.3.2):
183
+ * - Array: `[pageRef /XYZ left top zoom]`, `[pageRef /Fit]`, etc.
184
+ * - Named string: looked up in the document's /Dests or /Names.Dests
185
+ */
186
+ function resolveDestValue(destObj, doc, pageMap) {
187
+ const resolved = doc.deref(destObj);
188
+ if (resolved == null) {
189
+ return -1;
190
+ }
191
+ // Array destination: first element is the page reference
192
+ if ((0, pdf_parser_1.isPdfArray)(resolved) && resolved.length >= 1) {
193
+ return resolvePageRef(resolved[0], doc, pageMap);
194
+ }
195
+ // Named destination (string) — look up in /Dests or /Names tree
196
+ if (typeof resolved === "string") {
197
+ return resolveNamedDest(resolved, doc, pageMap);
198
+ }
199
+ // Byte string named destination
200
+ if (resolved instanceof Uint8Array) {
201
+ const name = (0, pdf_parser_1.decodePdfStringBytes)(resolved);
202
+ return resolveNamedDest(name, doc, pageMap);
203
+ }
204
+ return -1;
205
+ }
206
+ /**
207
+ * Resolve a page reference (from the first element of a dest array) to a page index.
208
+ */
209
+ function resolvePageRef(pageObj, doc, pageMap) {
210
+ // If it's a direct reference, use the object number
211
+ if ((0, pdf_parser_1.isPdfRef)(pageObj)) {
212
+ const idx = pageMap.get(pageObj.objNum);
213
+ return idx !== undefined ? idx : -1;
214
+ }
215
+ // If it's a page number (integer), use it directly as 0-based index
216
+ if (typeof pageObj === "number" && Number.isInteger(pageObj)) {
217
+ return pageObj;
218
+ }
219
+ return -1;
220
+ }
221
+ /**
222
+ * Look up a named destination in the catalog's /Dests dictionary
223
+ * or /Names.Dests name tree.
224
+ */
225
+ function resolveNamedDest(name, doc, pageMap) {
226
+ const catalog = doc.getCatalog();
227
+ // 1. Try /Dests dictionary (older PDFs)
228
+ const destsObj = catalog.get("Dests");
229
+ if (destsObj != null) {
230
+ const destsDict = doc.derefDict(destsObj);
231
+ if (destsDict) {
232
+ const entry = destsDict.get(name);
233
+ if (entry != null) {
234
+ return resolveDestEntry(entry, doc, pageMap);
235
+ }
236
+ }
237
+ }
238
+ // 2. Try /Names.Dests name tree (PDF 1.2+)
239
+ const namesObj = catalog.get("Names");
240
+ if (namesObj != null) {
241
+ const namesDict = doc.derefDict(namesObj);
242
+ if (namesDict) {
243
+ const destsTreeObj = namesDict.get("Dests");
244
+ if (destsTreeObj != null) {
245
+ const value = lookupNameTree(destsTreeObj, name, doc);
246
+ if (value != null) {
247
+ return resolveDestEntry(value, doc, pageMap);
248
+ }
249
+ }
250
+ }
251
+ }
252
+ return -1;
253
+ }
254
+ /**
255
+ * Resolve a destination entry value. It may be a dict with /D key,
256
+ * or a direct array destination.
257
+ */
258
+ function resolveDestEntry(entry, doc, pageMap) {
259
+ const resolved = doc.deref(entry);
260
+ if (resolved == null) {
261
+ return -1;
262
+ }
263
+ // Direct array destination
264
+ if ((0, pdf_parser_1.isPdfArray)(resolved) && resolved.length >= 1) {
265
+ return resolvePageRef(resolved[0], doc, pageMap);
266
+ }
267
+ // Dictionary with /D entry (destination dictionary)
268
+ if (resolved instanceof Map) {
269
+ const d = resolved.get("D");
270
+ if (d != null) {
271
+ return resolveDestValue(d, doc, pageMap);
272
+ }
273
+ }
274
+ return -1;
275
+ }
276
+ /**
277
+ * Look up a key in a PDF name tree.
278
+ *
279
+ * Name trees use either /Names (leaf) or /Kids (intermediate) arrays.
280
+ * /Names is an array of alternating [key, value, key, value, ...] pairs.
281
+ *
282
+ * @see PDF Reference 1.7, §7.9.6 - Name Trees
283
+ */
284
+ function lookupNameTree(treeObj, name, doc, depth = 0) {
285
+ if (depth > MAX_OUTLINE_DEPTH) {
286
+ return null;
287
+ }
288
+ const treeDict = doc.derefDict(treeObj);
289
+ if (!treeDict) {
290
+ return null;
291
+ }
292
+ // Check leaf /Names array
293
+ const namesArr = treeDict.get("Names");
294
+ if (namesArr != null) {
295
+ const resolved = doc.deref(namesArr);
296
+ if ((0, pdf_parser_1.isPdfArray)(resolved)) {
297
+ // Alternating [key, value, key, value, ...]
298
+ for (let i = 0; i + 1 < resolved.length; i += 2) {
299
+ const key = doc.deref(resolved[i]);
300
+ let keyStr = null;
301
+ if (typeof key === "string") {
302
+ keyStr = key;
303
+ }
304
+ else if (key instanceof Uint8Array) {
305
+ keyStr = (0, pdf_parser_1.decodePdfStringBytes)(key);
306
+ }
307
+ if (keyStr === name) {
308
+ return resolved[i + 1];
309
+ }
310
+ }
311
+ }
312
+ }
313
+ // Check intermediate /Kids array
314
+ const kidsArr = treeDict.get("Kids");
315
+ if (kidsArr != null) {
316
+ const resolved = doc.deref(kidsArr);
317
+ if ((0, pdf_parser_1.isPdfArray)(resolved)) {
318
+ for (const kid of resolved) {
319
+ const result = lookupNameTree(kid, name, doc, depth + 1);
320
+ if (result != null) {
321
+ return result;
322
+ }
323
+ }
324
+ }
325
+ }
326
+ return null;
327
+ }
@@ -14,7 +14,8 @@
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.initDecryption = initDecryption;
16
16
  exports.isEncrypted = isEncrypted;
17
- const crypto_1 = require("../core/crypto");
17
+ const crypto_1 = require("../../../utils/crypto.js");
18
+ const binary_1 = require("../../../utils/binary.js");
18
19
  const pdf_parser_1 = require("./pdf-parser");
19
20
  const errors_1 = require("../errors");
20
21
  // =============================================================================
@@ -168,13 +169,13 @@ function tryUserPasswordV5(passwordBytes, uValue, ueValue) {
168
169
  const uValidationSalt = uValue.subarray(32, 40);
169
170
  const uKeySalt = uValue.subarray(40, 48);
170
171
  // Validate: SHA-256(password + validation salt) == first 32 bytes of U
171
- const validateInput = (0, crypto_1.concatArrays)(passwordBytes, uValidationSalt);
172
+ const validateInput = (0, binary_1.concatUint8Arrays)([passwordBytes, uValidationSalt]);
172
173
  const computedHash = (0, crypto_1.sha256)(validateInput);
173
174
  if (!arraysEqual(computedHash, uHash)) {
174
175
  return null;
175
176
  }
176
177
  // Derive key: SHA-256(password + key salt) => use as AES-256 key to decrypt UE
177
- const keyInput = (0, crypto_1.concatArrays)(passwordBytes, uKeySalt);
178
+ const keyInput = (0, binary_1.concatUint8Arrays)([passwordBytes, uKeySalt]);
178
179
  const keyHash = (0, crypto_1.sha256)(keyInput);
179
180
  // Decrypt UE with this key using AES-256-CBC with zero IV
180
181
  const zeroIv = new Uint8Array(16);
@@ -192,13 +193,13 @@ function tryOwnerPasswordV5(passwordBytes, oValue, oeValue, uValue) {
192
193
  const oKeySalt = oValue.subarray(40, 48);
193
194
  const u48 = uValue.subarray(0, 48);
194
195
  // Validate: SHA-256(password + validation salt + U(0..47)) == first 32 bytes of O
195
- const validateInput = (0, crypto_1.concatArrays)(passwordBytes, oValidationSalt, u48);
196
+ const validateInput = (0, binary_1.concatUint8Arrays)([passwordBytes, oValidationSalt, u48]);
196
197
  const computedHash = (0, crypto_1.sha256)(validateInput);
197
198
  if (!arraysEqual(computedHash, oHash)) {
198
199
  return null;
199
200
  }
200
201
  // Derive key: SHA-256(password + key salt + U(0..47))
201
- const keyInput = (0, crypto_1.concatArrays)(passwordBytes, oKeySalt, u48);
202
+ const keyInput = (0, binary_1.concatUint8Arrays)([passwordBytes, oKeySalt, u48]);
202
203
  const keyHash = (0, crypto_1.sha256)(keyInput);
203
204
  // Decrypt OE with this key using AES-256-CBC with zero IV
204
205
  const zeroIv = new Uint8Array(16);