pdf-parser.js 3.0.8 → 4.5.2

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 (240) hide show
  1. package/README.md +105 -54
  2. package/dist/{afm-widths-Dxucrg7D.js → afm-widths-BTu0IDp2.cjs} +1517 -4
  3. package/dist/{afm-widths-DyDq56Ph.d.cts → afm-widths-CneRyu5l.d.cts} +1 -1
  4. package/dist/{afm-widths-DyDq56Ph.d.ts → afm-widths-CneRyu5l.d.ts} +1 -1
  5. package/dist/{afm-widths-BoeTOK2r.cjs → afm-widths-De_QMWgC.js} +1416 -51
  6. package/dist/afm-widths.cjs +1 -1
  7. package/dist/afm-widths.d.cts +1 -1
  8. package/dist/afm-widths.d.ts +1 -1
  9. package/dist/afm-widths.js +1 -1
  10. package/dist/annotations.cjs +104 -0
  11. package/dist/annotations.d.cts +9 -0
  12. package/dist/annotations.d.ts +9 -0
  13. package/dist/annotations.js +103 -0
  14. package/dist/attachments.cjs +65 -0
  15. package/dist/attachments.d.cts +8 -0
  16. package/dist/attachments.d.ts +8 -0
  17. package/dist/attachments.js +64 -0
  18. package/dist/builtin-encoding.cjs +221 -0
  19. package/dist/builtin-encoding.d.cts +8 -0
  20. package/dist/builtin-encoding.d.ts +8 -0
  21. package/dist/builtin-encoding.js +220 -0
  22. package/dist/bytes/flate.cjs +1 -1
  23. package/dist/bytes/flate.js +1 -1
  24. package/dist/cff.cjs +14 -0
  25. package/dist/cff.d.cts +4 -1
  26. package/dist/cff.d.ts +4 -1
  27. package/dist/cff.js +12 -1
  28. package/dist/cmap-table.cjs +76 -13
  29. package/dist/cmap-table.d.cts +9 -1
  30. package/dist/cmap-table.d.ts +9 -1
  31. package/dist/cmap-table.js +77 -15
  32. package/dist/codec.cjs +1 -1
  33. package/dist/codec.d.cts +134 -0
  34. package/dist/codec.d.ts +134 -0
  35. package/dist/codec.js +1 -1
  36. package/dist/content-read.cjs +1 -1
  37. package/dist/content-read.d.cts +3 -3
  38. package/dist/content-read.d.ts +3 -3
  39. package/dist/content-read.js +1 -1
  40. package/dist/content-write.cjs +32 -10
  41. package/dist/content-write.d.cts +12 -5
  42. package/dist/content-write.d.ts +12 -5
  43. package/dist/content-write.js +32 -10
  44. package/dist/crypto/random.cjs +9 -0
  45. package/dist/crypto/random.d.cts +4 -0
  46. package/dist/crypto/random.d.ts +4 -0
  47. package/dist/crypto/random.js +8 -0
  48. package/dist/diagnostics.d.cts +1 -1
  49. package/dist/diagnostics.d.ts +1 -1
  50. package/dist/document.cjs +12 -3
  51. package/dist/document.d.cts +3 -1
  52. package/dist/document.d.ts +3 -1
  53. package/dist/document.js +12 -3
  54. package/dist/{embedded-font-fREdbxnr.d.ts → embedded-font-B4p9a3O3.d.ts} +3 -1
  55. package/dist/{embedded-font-BU6Jgcof.d.cts → embedded-font-oc65VGlr.d.cts} +3 -1
  56. package/dist/embedded-font-write.cjs +1 -1
  57. package/dist/embedded-font-write.d.cts +3 -3
  58. package/dist/embedded-font-write.d.ts +3 -3
  59. package/dist/embedded-font-write.js +1 -1
  60. package/dist/embedded-font.cjs +46 -15
  61. package/dist/embedded-font.d.cts +1 -1
  62. package/dist/embedded-font.d.ts +1 -1
  63. package/dist/embedded-font.js +46 -15
  64. package/dist/encoding.cjs +10 -1
  65. package/dist/encoding.d.cts +10 -1
  66. package/dist/encoding.d.ts +10 -1
  67. package/dist/encoding.js +2 -2
  68. package/dist/encrypt-write.cjs +234 -0
  69. package/dist/encrypt-write.d.cts +31 -0
  70. package/dist/encrypt-write.d.ts +31 -0
  71. package/dist/encrypt-write.js +231 -0
  72. package/dist/encrypt.cjs +51 -21
  73. package/dist/encrypt.d.cts +19 -3
  74. package/dist/encrypt.d.ts +19 -3
  75. package/dist/encrypt.js +36 -22
  76. package/dist/filters.cjs +18 -14
  77. package/dist/filters.d.cts +1 -1
  78. package/dist/filters.d.ts +1 -1
  79. package/dist/filters.js +18 -14
  80. package/dist/font-read.cjs +68 -13
  81. package/dist/font-read.d.cts +1 -1
  82. package/dist/font-read.d.ts +1 -1
  83. package/dist/font-read.js +69 -14
  84. package/dist/font-registry.cjs +1 -1
  85. package/dist/font-registry.d.cts +4 -4
  86. package/dist/font-registry.d.ts +4 -4
  87. package/dist/font-registry.js +1 -1
  88. package/dist/font-substitutes.d.cts +1 -1
  89. package/dist/font-substitutes.d.ts +1 -1
  90. package/dist/font-tables.cjs +31 -0
  91. package/dist/font-tables.d.cts +3 -1
  92. package/dist/font-tables.d.ts +3 -1
  93. package/dist/font-tables.js +31 -2
  94. package/dist/fonts.d.cts +2 -2
  95. package/dist/fonts.d.ts +2 -2
  96. package/dist/form.cjs +138 -0
  97. package/dist/form.d.cts +9 -0
  98. package/dist/form.d.ts +9 -0
  99. package/dist/form.js +137 -0
  100. package/dist/gsub-table-BRTQ8EUW.d.ts +10 -0
  101. package/dist/gsub-table-URczLd85.d.cts +10 -0
  102. package/dist/gsub-table.cjs +225 -0
  103. package/dist/gsub-table.d.cts +2 -0
  104. package/dist/gsub-table.d.ts +2 -0
  105. package/dist/gsub-table.js +224 -0
  106. package/dist/image/ccitt-encode.cjs +119 -0
  107. package/dist/image/ccitt-encode.d.cts +9 -0
  108. package/dist/image/ccitt-encode.d.ts +9 -0
  109. package/dist/image/ccitt-encode.js +118 -0
  110. package/dist/image/ccitt.cjs +3 -0
  111. package/dist/image/ccitt.d.cts +4 -1
  112. package/dist/image/ccitt.d.ts +4 -1
  113. package/dist/image/ccitt.js +1 -1
  114. package/dist/image/jbig2-bitmap.d.cts +1 -1
  115. package/dist/image/jbig2-bitmap.d.ts +1 -1
  116. package/dist/image/jbig2.cjs +3 -1
  117. package/dist/image/jbig2.js +3 -1
  118. package/dist/image/jp2-boxes.d.cts +1 -1
  119. package/dist/image/jp2-boxes.d.ts +1 -1
  120. package/dist/image/jpeg2000-codestream.d.cts +3 -3
  121. package/dist/image/jpeg2000-codestream.d.ts +3 -3
  122. package/dist/image/jpeg2000-t1.d.cts +1 -1
  123. package/dist/image/jpeg2000-t1.d.ts +1 -1
  124. package/dist/image/jpeg2000.cjs +1 -0
  125. package/dist/image/jpeg2000.d.cts +3 -0
  126. package/dist/image/jpeg2000.d.ts +3 -0
  127. package/dist/image/jpeg2000.js +1 -0
  128. package/dist/image/png-decode.cjs +1 -1
  129. package/dist/image/png-decode.js +1 -1
  130. package/dist/image/png-filter.d.cts +1 -1
  131. package/dist/image/png-filter.d.ts +1 -1
  132. package/dist/images-read.cjs +18 -12
  133. package/dist/images-read.d.cts +2 -2
  134. package/dist/images-read.d.ts +2 -2
  135. package/dist/images-read.js +15 -9
  136. package/dist/index.cjs +17 -4
  137. package/dist/index.d.cts +7 -6
  138. package/dist/index.d.ts +7 -6
  139. package/dist/index.js +6 -5
  140. package/dist/interpret.cjs +178 -56
  141. package/dist/interpret.d.cts +27 -12
  142. package/dist/interpret.d.ts +27 -12
  143. package/dist/interpret.js +178 -56
  144. package/dist/layout.cjs +149 -2
  145. package/dist/layout.d.cts +394 -1
  146. package/dist/layout.d.ts +394 -1
  147. package/dist/layout.js +140 -4
  148. package/dist/lexer.d.cts +9 -9
  149. package/dist/lexer.d.ts +9 -9
  150. package/dist/math-content-write.cjs +1 -1
  151. package/dist/math-content-write.js +1 -1
  152. package/dist/math-font-write.cjs +1 -1
  153. package/dist/math-font-write.d.cts +1 -1
  154. package/dist/math-font-write.d.ts +1 -1
  155. package/dist/math-font-write.js +1 -1
  156. package/dist/math-font.cjs +2 -2
  157. package/dist/math-font.d.cts +1 -1
  158. package/dist/math-font.d.ts +1 -1
  159. package/dist/math-font.js +2 -2
  160. package/dist/{math-stretch-a_rHNRvc.d.ts → math-stretch-BbC2o4Br.d.ts} +1 -1
  161. package/dist/{math-stretch-E26z6byT.d.cts → math-stretch-C2JanDAz.d.cts} +1 -1
  162. package/dist/math-stretch.d.cts +1 -1
  163. package/dist/math-stretch.d.ts +1 -1
  164. package/dist/measure.cjs +1 -1
  165. package/dist/measure.d.cts +1 -1
  166. package/dist/measure.d.ts +1 -1
  167. package/dist/measure.js +1 -1
  168. package/dist/names.cjs +41 -0
  169. package/dist/names.d.cts +11 -0
  170. package/dist/names.d.ts +11 -0
  171. package/dist/names.js +40 -0
  172. package/dist/navigation.cjs +210 -0
  173. package/dist/navigation.d.cts +18 -0
  174. package/dist/navigation.d.ts +18 -0
  175. package/dist/navigation.js +207 -0
  176. package/dist/notes-annotation-author.cjs +5 -0
  177. package/dist/notes-annotation-author.d.cts +4 -0
  178. package/dist/notes-annotation-author.d.ts +4 -0
  179. package/dist/notes-annotation-author.js +4 -0
  180. package/dist/objects-B7HdMeWS.d.cts +59 -0
  181. package/dist/objects-B7HdMeWS.d.ts +59 -0
  182. package/dist/objects.d.cts +1 -58
  183. package/dist/objects.d.ts +1 -58
  184. package/dist/optional-content.cjs +63 -0
  185. package/dist/optional-content.d.cts +12 -0
  186. package/dist/optional-content.d.ts +12 -0
  187. package/dist/optional-content.js +62 -0
  188. package/dist/parse.cjs +1 -1
  189. package/dist/parse.d.cts +2 -2
  190. package/dist/parse.d.ts +2 -2
  191. package/dist/parse.js +1 -1
  192. package/dist/pdf-text.cjs +21 -0
  193. package/dist/pdf-text.d.cts +5 -0
  194. package/dist/pdf-text.d.ts +5 -0
  195. package/dist/pdf-text.js +19 -0
  196. package/dist/predictors.d.cts +1 -1
  197. package/dist/predictors.d.ts +1 -1
  198. package/dist/read.cjs +287 -72
  199. package/dist/read.d.cts +2 -4
  200. package/dist/read.d.ts +2 -4
  201. package/dist/read.js +284 -67
  202. package/dist/serialize.cjs +5 -1
  203. package/dist/serialize.d.cts +3 -2
  204. package/dist/serialize.d.ts +3 -2
  205. package/dist/serialize.js +5 -2
  206. package/dist/sfnt-subset.cjs +10 -3
  207. package/dist/sfnt-subset.d.cts +1 -1
  208. package/dist/sfnt-subset.d.ts +1 -1
  209. package/dist/sfnt-subset.js +10 -3
  210. package/dist/structure.cjs +184 -0
  211. package/dist/structure.d.cts +12 -0
  212. package/dist/structure.d.ts +12 -0
  213. package/dist/structure.js +183 -0
  214. package/dist/tounicode.cjs +8 -3
  215. package/dist/tounicode.d.cts +2 -2
  216. package/dist/tounicode.d.ts +2 -2
  217. package/dist/tounicode.js +8 -3
  218. package/dist/util/base64.cjs +4 -4
  219. package/dist/util/base64.js +4 -4
  220. package/dist/winansi.cjs +1 -1
  221. package/dist/winansi.d.cts +1 -1
  222. package/dist/winansi.d.ts +1 -1
  223. package/dist/winansi.js +1 -1
  224. package/dist/write.cjs +464 -21
  225. package/dist/write.d.cts +4 -3
  226. package/dist/write.d.ts +4 -3
  227. package/dist/write.js +464 -20
  228. package/dist/xmp.cjs +46 -0
  229. package/dist/xmp.d.cts +14 -0
  230. package/dist/xmp.d.ts +14 -0
  231. package/dist/xmp.js +45 -0
  232. package/dist/xref.cjs +2 -2
  233. package/dist/xref.d.cts +3 -3
  234. package/dist/xref.d.ts +3 -3
  235. package/dist/xref.js +2 -2
  236. package/package.json +46 -31
  237. package/dist/image/png-encode.cjs +0 -64
  238. package/dist/image/png-encode.d.cts +0 -8
  239. package/dist/image/png-encode.d.ts +0 -8
  240. package/dist/image/png-encode.js +0 -63
package/dist/write.js CHANGED
@@ -1,13 +1,19 @@
1
- import { a as winAnsiGlyphName, n as widthOfCode, t as STANDARD_METRICS } from "./afm-widths-Dxucrg7D.js";
2
- import { base64ToBytes } from "./util/base64.js";
1
+ import { n as widthOfCode, p as winAnsiGlyphName, t as STANDARD_METRICS } from "./afm-widths-De_QMWgC.js";
2
+ import { NOTES_ANNOTATION_AUTHOR } from "./notes-annotation-author.js";
3
+ import { pdfArray, pdfBool, pdfDict, pdfHexString, pdfLiteralString, pdfName, pdfNull, pdfNum, pdfRef, pdfStream } from "./objects.js";
3
4
  import { ByteWriter, concatBytes } from "./bytes/writer.js";
4
- import { pdfArray, pdfDict, pdfHexString, pdfName, pdfNum, pdfRef, pdfStream } from "./objects.js";
5
+ import { writeObject } from "./serialize.js";
6
+ import { ByteReader } from "./bytes/reader.js";
5
7
  import { deflate } from "./bytes/flate.js";
8
+ import { base64ToBytes } from "./util/base64.js";
9
+ import { parseValue } from "./parse.js";
6
10
  import { throwIfAborted } from "./util/abort.js";
11
+ import { randomBytes } from "./crypto/random.js";
12
+ import { createStandardEncryptor, encryptIndirectObject } from "./encrypt-write.js";
7
13
  import { readJpegInfo } from "./image/jpeg-info.js";
14
+ import { encodeCcittFax } from "./image/ccitt-encode.js";
8
15
  import { decodePng } from "./image/png-decode.js";
9
16
  import { collectEmbeddedGlyphs } from "./embedded-font.js";
10
- import { writeObject } from "./serialize.js";
11
17
  import { writeContentStream } from "./content-write.js";
12
18
  import { buildEmbeddedFontObjects } from "./embedded-font-write.js";
13
19
  import { resolveFaceWithRegistry } from "./font-registry.js";
@@ -28,6 +34,7 @@ const FLAG_SERIF = 2;
28
34
  const FLAG_NONSYMBOLIC = 32;
29
35
  const FLAG_ITALIC = 64;
30
36
  const FLAG_FORCE_BOLD = 262144;
37
+ const FILE_ID_BYTES = 16;
31
38
  function textToPdfString(text) {
32
39
  const bytes = new Uint8Array(2 + text.length * 2);
33
40
  bytes[0] = 254;
@@ -138,9 +145,57 @@ function pngImageDict(width, height, colorSpace, compress) {
138
145
  if (compress) entries.set("Filter", pdfName("FlateDecode"));
139
146
  return pdfDict(entries);
140
147
  }
148
+ function packBilevel(raw) {
149
+ const rowBytes = raw.width + 7 >> 3;
150
+ const packed = new Uint8Array(rowBytes * raw.height);
151
+ for (let y = 0; y < raw.height; y++) for (let x = 0; x < raw.width; x++) {
152
+ const sample = raw.data[y * raw.width + x] ?? 0;
153
+ if (sample !== 0 && sample !== 255) return;
154
+ if (sample === 255) {
155
+ const index = y * rowBytes + (x >> 3);
156
+ packed[index] = (packed[index] ?? 0) | 128 >> (x & 7);
157
+ }
158
+ }
159
+ return packed;
160
+ }
141
161
  function preparePngImage(bytes, compress) {
142
162
  const raw = decodePng(bytes);
143
163
  const colorSpace = raw.channels === 1 ? "DeviceGray" : "DeviceRGB";
164
+ if (compress && raw.channels === 1 && raw.alpha === void 0) {
165
+ const bilevel = packBilevel(raw);
166
+ if (bilevel !== void 0) {
167
+ const flate = deflate(raw.data);
168
+ const g4 = encodeCcittFax(bilevel, {
169
+ columns: raw.width,
170
+ rows: raw.height,
171
+ maxBytes: flate.length
172
+ });
173
+ if (g4 !== void 0) return {
174
+ dict: pdfDict(/* @__PURE__ */ new Map([
175
+ ["Type", pdfName("XObject")],
176
+ ["Subtype", pdfName("Image")],
177
+ ["Width", pdfNum(raw.width)],
178
+ ["Height", pdfNum(raw.height)],
179
+ ["ColorSpace", pdfName("DeviceGray")],
180
+ ["BitsPerComponent", pdfNum(1)],
181
+ ["Filter", pdfName("CCITTFaxDecode")],
182
+ ["DecodeParms", pdfDict(/* @__PURE__ */ new Map([
183
+ ["K", pdfNum(-1)],
184
+ ["Columns", pdfNum(raw.width)],
185
+ ["Rows", pdfNum(raw.height)],
186
+ ["BlackIs1", pdfBool(false)]
187
+ ]))]
188
+ ])),
189
+ raw: g4,
190
+ alpha: void 0
191
+ };
192
+ return {
193
+ dict: pngImageDict(raw.width, raw.height, colorSpace, true),
194
+ raw: flate,
195
+ alpha: void 0
196
+ };
197
+ }
198
+ }
144
199
  return {
145
200
  dict: pngImageDict(raw.width, raw.height, colorSpace, compress),
146
201
  raw: compress ? deflate(raw.data) : raw.data,
@@ -176,11 +231,59 @@ function buildLinkAnnotDict(link) {
176
231
  })
177
232
  });
178
233
  }
234
+ function destinationViewArray(target) {
235
+ const n = (value) => value === void 0 ? pdfNull() : pdfNum(value);
236
+ if (target.kind === "xyz") return [
237
+ pdfName("XYZ"),
238
+ n(target.leftPt),
239
+ n(target.topPt),
240
+ n(target.zoom)
241
+ ];
242
+ if (target.kind === "fitH") return [pdfName("FitH"), n(target.topPt)];
243
+ if (target.kind === "fitV") return [pdfName("FitV"), n(target.leftPt)];
244
+ if (target.kind === "fitR") return [
245
+ pdfName("FitR"),
246
+ n(target.leftPt),
247
+ n(target.bottomPt),
248
+ n(target.rightPt),
249
+ n(target.topPt)
250
+ ];
251
+ if (target.kind === "fitBH") return [pdfName("FitBH"), n(target.topPt)];
252
+ if (target.kind === "fitBV") return [pdfName("FitBV"), n(target.leftPt)];
253
+ return [pdfName(target.kind === "fitB" ? "FitB" : "Fit")];
254
+ }
255
+ function resolveDestinationArray(doc, pageAllocs, name, what) {
256
+ const destination = doc.destinations?.find((d) => d.name === name);
257
+ if (destination === void 0) throw new Error(`${what} names destination "${name}", which the document's destinations table does not carry -- this is a caller-invariant violation`);
258
+ const targetPage = pageAllocs[destination.pageIndex];
259
+ if (targetPage === void 0) throw new Error(`destination "${destination.name}" names page index ${destination.pageIndex}, which is beyond the document's own pages -- this is a caller-invariant violation`);
260
+ return [pdfRef(targetPage.pageNum, 0), ...destinationViewArray(destination.target)];
261
+ }
262
+ function buildInternalLinkAnnotDict(link, doc, pageAllocs) {
263
+ return pdfDict({
264
+ Type: pdfName("Annot"),
265
+ Subtype: pdfName("Link"),
266
+ Rect: pdfArray([
267
+ link.xPt,
268
+ link.yPt,
269
+ link.xPt + link.widthPt,
270
+ link.yPt + link.heightPt
271
+ ].map((v) => pdfNum(v))),
272
+ Border: pdfArray([
273
+ 0,
274
+ 0,
275
+ 0
276
+ ].map((v) => pdfNum(v))),
277
+ Dest: pdfArray(resolveDestinationArray(doc, pageAllocs, link.destination, "internal link"))
278
+ });
279
+ }
179
280
  function isLinkItem(item) {
180
281
  return item.kind === "link";
181
282
  }
283
+ function isInternalLinkItem(item) {
284
+ return item.kind === "internalLink";
285
+ }
182
286
  const NOTES_ANNOTATION_HIDDEN_FLAG = 2;
183
- const NOTES_ANNOTATION_AUTHOR = "documents.js:notes";
184
287
  function buildNotesAnnotDict(notes) {
185
288
  return pdfDict({
186
289
  Type: pdfName("Annot"),
@@ -199,6 +302,24 @@ function buildNotesAnnotDict(notes) {
199
302
  function xrefEntry(offset, generation, inUse) {
200
303
  return `${offset.toString().padStart(10, "0")} ${generation.toString().padStart(5, "0")} ${inUse ? "n" : "f"} \n`;
201
304
  }
305
+ function parseResidueRow(residue) {
306
+ const reader = new ByteReader(new TextEncoder().encode(residue.xml));
307
+ return parseValue(reader, () => {});
308
+ }
309
+ function objectContainsReference(obj) {
310
+ if (obj.kind === "ref") return true;
311
+ if (obj.kind === "array") return obj.items.some(objectContainsReference);
312
+ if (obj.kind === "dict") return [...obj.entries.values()].some(objectContainsReference);
313
+ if (obj.kind === "stream") return [...obj.dict.entries.values()].some(objectContainsReference);
314
+ return false;
315
+ }
316
+ function restoreResidueRow(source, key) {
317
+ const row = source?.[key];
318
+ if (row === void 0) return;
319
+ const parsed = parseResidueRow(row);
320
+ if (parsed === void 0 || objectContainsReference(parsed)) return;
321
+ return parsed;
322
+ }
202
323
  function writePdf(doc, options = {}) {
203
324
  const compress = options.compress ?? true;
204
325
  const registry = options.fonts;
@@ -271,13 +392,99 @@ function writePdf(doc, options = {}) {
271
392
  pageNum: nextObjNum++,
272
393
  contentsNum: nextObjNum++
273
394
  }));
395
+ const encryptDictNum = options.encryption === void 0 ? void 0 : nextObjNum++;
396
+ const attachmentAllocs = (doc.attachments ?? []).map(() => ({
397
+ fileNum: nextObjNum++,
398
+ specNum: nextObjNum++
399
+ }));
400
+ const attachmentsNamesNum = attachmentAllocs.length > 0 ? nextObjNum++ : void 0;
401
+ const outlineRootNum = (doc.outline ?? []).length > 0 ? nextObjNum++ : void 0;
402
+ const outlineItemNums = [];
403
+ if (outlineRootNum !== void 0) {
404
+ const countItems = (items) => {
405
+ let n = 0;
406
+ for (const item of items) n += 1 + countItems(item.children);
407
+ return n;
408
+ };
409
+ for (let i = 0; i < countItems(doc.outline ?? []); i += 1) outlineItemNums.push(nextObjNum++);
410
+ }
411
+ const layerNumByName = /* @__PURE__ */ new Map();
412
+ for (const layer of doc.layers ?? []) layerNumByName.set(layer.name, nextObjNum++);
413
+ const formObjectNums = [];
414
+ const countFieldObjects = (fields) => {
415
+ let n = 0;
416
+ for (const field of fields) n += 1 + (field.fieldType !== "group" && field.widgets.length > 1 ? field.widgets.length - 1 : 0) + countFieldObjects(field.children);
417
+ return n;
418
+ };
419
+ for (let i = 0; i < countFieldObjects(doc.form ?? []); i += 1) formObjectNums.push(nextObjNum++);
420
+ const formNumByField = /* @__PURE__ */ new Map();
421
+ const formExtraWidgetNums = /* @__PURE__ */ new Map();
422
+ let formNumCursor = 0;
423
+ const claimFormNums = (fields) => {
424
+ for (const field of fields) {
425
+ formNumByField.set(field, formObjectNums[formNumCursor++]);
426
+ if (field.fieldType !== "group" && field.widgets.length > 1) formExtraWidgetNums.set(field, field.widgets.slice(1).map(() => formObjectNums[formNumCursor++]));
427
+ claimFormNums(field.children);
428
+ }
429
+ };
430
+ claimFormNums(doc.form ?? []);
431
+ const formNumOf = (field) => {
432
+ const num = formNumByField.get(field);
433
+ if (num === void 0) throw new Error("AcroForm field object number was not claimed -- this is a writePdf internal invariant violation");
434
+ return num;
435
+ };
436
+ const structElementNumById = /* @__PURE__ */ new Map();
437
+ const countElements = (elements) => {
438
+ let n = 0;
439
+ for (const element of elements) {
440
+ structElementNumById.set(element.id, nextObjNum++);
441
+ n += 1 + countElements(element.children);
442
+ }
443
+ return n;
444
+ };
445
+ const structElementCount = countElements(doc.structure ?? []);
446
+ const structRootNum = structElementCount > 0 ? nextObjNum++ : void 0;
447
+ const structParentTreeNum = structElementCount > 0 ? nextObjNum++ : void 0;
448
+ const residueXmpNum = doc.source?.xmp !== void 0 ? nextObjNum++ : void 0;
274
449
  const objects = [];
450
+ const catalogEntries = [["Type", pdfName("Catalog")], ["Pages", pdfRef(pagesNum, 0)]];
451
+ if (attachmentsNamesNum !== void 0) catalogEntries.push(["Names", pdfRef(attachmentsNamesNum, 0)]);
452
+ if (outlineRootNum !== void 0) catalogEntries.push(["Outlines", pdfRef(outlineRootNum, 0)]);
453
+ if (layerNumByName.size > 0) {
454
+ const ocgRefs = [...layerNumByName.values()].map((num) => pdfRef(num, 0));
455
+ const visible = [];
456
+ const hidden = [];
457
+ for (const layer of doc.layers ?? []) {
458
+ const num = layerNumByName.get(layer.name);
459
+ (layer.visible ? visible : hidden).push(pdfRef(num, 0));
460
+ }
461
+ const defaultConfigEntries = [];
462
+ if (visible.length > 0) defaultConfigEntries.push(["ON", pdfArray(visible)]);
463
+ if (hidden.length > 0) defaultConfigEntries.push(["OFF", pdfArray(hidden)]);
464
+ catalogEntries.push(["OCProperties", pdfDict({
465
+ OCGs: pdfArray(ocgRefs),
466
+ D: pdfDict(Object.fromEntries(defaultConfigEntries))
467
+ })]);
468
+ }
469
+ if (doc.form !== void 0 && doc.form.length > 0) catalogEntries.push(["AcroForm", pdfDict({ Fields: pdfArray(doc.form.map((field) => pdfRef(formNumOf(field), 0))) })]);
470
+ if (structRootNum !== void 0) catalogEntries.push(["StructTreeRoot", pdfRef(structRootNum, 0)]);
471
+ if (residueXmpNum !== void 0) catalogEntries.push(["Metadata", pdfRef(residueXmpNum, 0)]);
472
+ const trailerIdRestore = restoreResidueRow(doc.source, "trailer-id");
473
+ for (const [rowKey, catalogKey] of [
474
+ ["viewer-preferences", "ViewerPreferences"],
475
+ ["page-mode", "PageMode"],
476
+ ["page-layout", "PageLayout"],
477
+ ["output-intents", "OutputIntents"],
478
+ ["piece-info", "PieceInfo"],
479
+ ["legal", "Legal"],
480
+ ["collection", "Collection"]
481
+ ]) {
482
+ const restored = restoreResidueRow(doc.source, rowKey);
483
+ if (restored !== void 0) catalogEntries.push([catalogKey, restored]);
484
+ }
275
485
  objects.push({
276
486
  num: catalogNum,
277
- value: pdfDict({
278
- Type: pdfName("Catalog"),
279
- Pages: pdfRef(pagesNum, 0)
280
- })
487
+ value: pdfDict(Object.fromEntries(catalogEntries))
281
488
  });
282
489
  objects.push({
283
490
  num: pagesNum,
@@ -291,6 +498,185 @@ function writePdf(doc, options = {}) {
291
498
  num: infoNum,
292
499
  value: buildInfoDict(doc)
293
500
  });
501
+ for (const [index, attachment] of (doc.attachments ?? []).entries()) {
502
+ const alloc = attachmentAllocs[index];
503
+ const fileEntries = [["Type", pdfName("EmbeddedFile")]];
504
+ if (attachment.mimeType !== void 0) fileEntries.push(["Subtype", pdfName(attachment.mimeType)]);
505
+ objects.push({
506
+ num: alloc.fileNum,
507
+ value: pdfStream(pdfDict(Object.fromEntries(fileEntries)), base64ToBytes(attachment.base64))
508
+ });
509
+ const specEntries = [
510
+ ["Type", pdfName("Filespec")],
511
+ ["F", pdfLiteralString(new TextEncoder().encode(attachment.name))],
512
+ ["EF", pdfDict({ F: pdfRef(alloc.fileNum, 0) })]
513
+ ];
514
+ if (attachment.description !== void 0) specEntries.push(["Desc", pdfLiteralString(new TextEncoder().encode(attachment.description))]);
515
+ objects.push({
516
+ num: alloc.specNum,
517
+ value: pdfDict(Object.fromEntries(specEntries))
518
+ });
519
+ }
520
+ if (attachmentsNamesNum !== void 0) {
521
+ const names = [];
522
+ for (const [index, attachment] of (doc.attachments ?? []).entries()) {
523
+ names.push(pdfLiteralString(new TextEncoder().encode(attachment.name)));
524
+ names.push(pdfRef(attachmentAllocs[index].specNum, 0));
525
+ }
526
+ objects.push({
527
+ num: attachmentsNamesNum,
528
+ value: pdfDict({ EmbeddedFiles: pdfDict({ Names: pdfArray(names) }) })
529
+ });
530
+ }
531
+ if (outlineRootNum !== void 0 && (doc.outline ?? []).length > 0) {
532
+ let itemCursor = 0;
533
+ const emitItems = (items, parentNum) => {
534
+ const siblingNums = [];
535
+ let prevNum;
536
+ for (const item of items) {
537
+ const ownNum = outlineItemNums[itemCursor];
538
+ itemCursor += 1;
539
+ siblingNums.push(ownNum);
540
+ const childNums = emitItems(item.children, ownNum);
541
+ const entries = [["Title", pdfLiteralString(new TextEncoder().encode(item.title))], ["Parent", pdfRef(parentNum, 0)]];
542
+ if (item.destination !== void 0) entries.push(["Dest", pdfArray(resolveDestinationArray(doc, pageAllocs, item.destination, `outline item "${item.title}"`))]);
543
+ if (prevNum !== void 0) entries.push(["Prev", pdfRef(prevNum, 0)]);
544
+ if (siblingNums.length < items.length) entries.push(["Next", pdfRef(outlineItemNums[itemCursor], 0)]);
545
+ if (childNums.length > 0) {
546
+ entries.push(["First", pdfRef(childNums[0], 0)]);
547
+ entries.push(["Last", pdfRef(childNums[childNums.length - 1], 0)]);
548
+ entries.push(["Count", pdfNum(childNums.length)]);
549
+ }
550
+ objects.push({
551
+ num: ownNum,
552
+ value: pdfDict(Object.fromEntries(entries))
553
+ });
554
+ prevNum = ownNum;
555
+ }
556
+ return siblingNums;
557
+ };
558
+ const topLevelNums = emitItems(doc.outline ?? [], outlineRootNum);
559
+ objects.push({
560
+ num: outlineRootNum,
561
+ value: pdfDict({
562
+ Type: pdfName("Outlines"),
563
+ First: pdfRef(topLevelNums[0], 0),
564
+ Last: pdfRef(topLevelNums[topLevelNums.length - 1], 0)
565
+ })
566
+ });
567
+ }
568
+ for (const layer of doc.layers ?? []) {
569
+ const num = layerNumByName.get(layer.name);
570
+ objects.push({
571
+ num,
572
+ value: pdfDict({
573
+ Type: pdfName("OCG"),
574
+ Name: pdfLiteralString(new TextEncoder().encode(layer.name))
575
+ })
576
+ });
577
+ }
578
+ const widgetRectArray = (widget) => pdfArray([
579
+ widget.xPt,
580
+ widget.yPt,
581
+ widget.xPt + widget.widthPt,
582
+ widget.yPt + widget.heightPt
583
+ ].map((n) => pdfNum(n)));
584
+ const widgetDict = (widget) => pdfDict({
585
+ Subtype: pdfName("Widget"),
586
+ Rect: widgetRectArray(widget),
587
+ P: pdfRef(pageAllocs[widget.pageIndex].pageNum, 0)
588
+ });
589
+ const FIELD_TYPE_PDF_NAME = {
590
+ text: "Tx",
591
+ checkbox: "Btn",
592
+ radio: "Btn",
593
+ button: "Btn",
594
+ listbox: "Ch",
595
+ combobox: "Ch",
596
+ signature: "Sig"
597
+ };
598
+ const emitFormFieldObjects = (fields, parentName) => {
599
+ for (const field of fields) {
600
+ const ownName = parentName.length > 0 && field.name.startsWith(`${parentName}.`) ? field.name.slice(parentName.length + 1) : field.name;
601
+ const entries = [];
602
+ if (ownName.length > 0) entries.push(["T", pdfLiteralString(new TextEncoder().encode(ownName))]);
603
+ if (field.alias !== void 0) entries.push(["TU", pdfLiteralString(new TextEncoder().encode(field.alias))]);
604
+ if (field.fieldType === "group") entries.push(["Kids", pdfArray(field.children.map((child) => pdfRef(formNumOf(child), 0)))]);
605
+ else {
606
+ entries.push(["FT", pdfName(FIELD_TYPE_PDF_NAME[field.fieldType])]);
607
+ const FLAG_READ_ONLY = 1;
608
+ const FLAG_PUSHBUTTON = 4;
609
+ const FLAG_RADIO = 32768;
610
+ const FLAG_COMBO = 131072;
611
+ let flags = 0;
612
+ if (field.readOnly === true) flags |= FLAG_READ_ONLY;
613
+ if (field.fieldType === "button") flags |= FLAG_PUSHBUTTON;
614
+ if (field.fieldType === "radio") flags |= FLAG_RADIO;
615
+ if (field.fieldType === "combobox") flags |= FLAG_COMBO;
616
+ if (flags !== 0) entries.push(["Ff", pdfNum(flags)]);
617
+ if (field.fieldType === "text" || field.fieldType === "listbox" || field.fieldType === "combobox") {
618
+ if (field.value !== void 0) entries.push(["V", pdfLiteralString(new TextEncoder().encode(field.value))]);
619
+ } else if (field.fieldType === "checkbox" || field.fieldType === "radio") entries.push(["V", pdfName(field.checked === false || field.value === void 0 ? field.value ?? (field.checked === true ? "Yes" : "Off") : field.value)]);
620
+ if (field.options !== void 0) entries.push(["Opt", pdfArray(field.options.map((option) => pdfLiteralString(new TextEncoder().encode(option))))]);
621
+ const firstWidget = field.widgets[0];
622
+ if (field.widgets.length === 1 && firstWidget !== void 0) {
623
+ entries.push(["Subtype", pdfName("Widget")]);
624
+ entries.push(["Rect", widgetRectArray(firstWidget)]);
625
+ entries.push(["P", pdfRef(pageAllocs[firstWidget.pageIndex].pageNum, 0)]);
626
+ } else if (field.widgets.length > 1 && firstWidget !== void 0) {
627
+ const extraNums = formExtraWidgetNums.get(field) ?? [];
628
+ entries.push(["Kids", pdfArray([widgetDict(firstWidget), ...extraNums.map((num) => pdfRef(num, 0))])]);
629
+ }
630
+ }
631
+ objects.push({
632
+ num: formNumOf(field),
633
+ value: pdfDict(Object.fromEntries(entries))
634
+ });
635
+ const extraNums = formExtraWidgetNums.get(field) ?? [];
636
+ for (const [index, num] of extraNums.entries()) {
637
+ const widget = field.widgets[index + 1];
638
+ objects.push({
639
+ num,
640
+ value: widgetDict(widget)
641
+ });
642
+ }
643
+ emitFormFieldObjects(field.children, field.name);
644
+ }
645
+ };
646
+ emitFormFieldObjects(doc.form ?? [], "");
647
+ if (structRootNum !== void 0 && structParentTreeNum !== void 0) {
648
+ const emitStructureElement = (element, parentNum) => {
649
+ const entries = [
650
+ ["Type", pdfName("StructElem")],
651
+ ["S", pdfName(element.type)],
652
+ ["P", pdfRef(parentNum, 0)]
653
+ ];
654
+ if (element.title !== void 0) entries.push(["T", pdfLiteralString(new TextEncoder().encode(element.title))]);
655
+ if (element.language !== void 0) entries.push(["Lang", pdfLiteralString(new TextEncoder().encode(element.language))]);
656
+ if (element.alt !== void 0) entries.push(["Alt", pdfLiteralString(new TextEncoder().encode(element.alt))]);
657
+ if (element.actualText !== void 0) entries.push(["ActualText", pdfLiteralString(new TextEncoder().encode(element.actualText))]);
658
+ if (element.children.length > 0) entries.push(["K", pdfArray(element.children.map((child) => {
659
+ const num = structElementNumById.get(child.id);
660
+ if (num === void 0) throw new Error(`structure element "${child.id}" was not allocated -- this is a writePdf internal invariant violation`);
661
+ return pdfRef(num, 0);
662
+ }))]);
663
+ const ownNum = structElementNumById.get(element.id);
664
+ if (ownNum === void 0) throw new Error(`structure element "${element.id}" was not allocated -- this is a writePdf internal invariant violation`);
665
+ objects.push({
666
+ num: ownNum,
667
+ value: pdfDict(Object.fromEntries(entries))
668
+ });
669
+ for (const child of element.children) emitStructureElement(child, ownNum);
670
+ };
671
+ for (const element of doc.structure ?? []) emitStructureElement(element, structRootNum);
672
+ }
673
+ if (residueXmpNum !== void 0 && doc.source?.xmp !== void 0) objects.push({
674
+ num: residueXmpNum,
675
+ value: pdfStream(pdfDict({
676
+ Type: pdfName("Metadata"),
677
+ Subtype: pdfName("XML")
678
+ }), new TextEncoder().encode(doc.source.xmp.xml))
679
+ });
294
680
  for (const [standardName, alloc] of fontAllocs) {
295
681
  const { font, descriptor } = buildFontObjects(standardName, pdfRef(alloc.descNum, 0));
296
682
  objects.push({
@@ -346,9 +732,10 @@ function writePdf(doc, options = {}) {
346
732
  });
347
733
  }
348
734
  for (const [face, alloc] of embeddedAllocs) {
349
- const subset = subsetSfnt(face.font, [...alloc.codePoints].sort((a, b) => a - b));
735
+ const usedGlyphs = collectEmbeddedGlyphs(alloc.texts, face);
736
+ const subset = subsetSfnt(face.font, [...alloc.codePoints].sort((a, b) => a - b), [...usedGlyphs.keys()].sort((a, b) => a - b));
350
737
  if (subset === void 0) throw new Error(`font "${face.postScriptName}" resolved to an embeddable face, but its glyph outlines could not be subsetted -- only TrueType-outline ('glyf') fonts can be embedded, so supply a TrueType face for this family or drop it from the registry`);
351
- const built = buildEmbeddedFontObjects(face, subset, collectEmbeddedGlyphs(alloc.texts, face), {
738
+ const built = buildEmbeddedFontObjects(face, subset, usedGlyphs, {
352
739
  cidFontRef: pdfRef(alloc.cidFontNum, 0),
353
740
  descriptorRef: pdfRef(alloc.descriptorNum, 0),
354
741
  fontFileRef: pdfRef(alloc.fontFileNum, 0),
@@ -384,6 +771,7 @@ function writePdf(doc, options = {}) {
384
771
  }
385
772
  if (imageAllocs.size > 0) resourceEntries.set("XObject", pdfDict(new Map([...imageAllocs.values()].map((alloc) => [alloc.resourceName, pdfRef(alloc.imageNum, 0)]))));
386
773
  const resourcesDict = pdfDict(resourceEntries);
774
+ const markedStructureByPage = /* @__PURE__ */ new Map();
387
775
  const formulasByPage = /* @__PURE__ */ new Map();
388
776
  for (const formula of formulas) {
389
777
  const forPage = formulasByPage.get(formula.pageIndex);
@@ -420,7 +808,14 @@ function writePdf(doc, options = {}) {
420
808
  doc.pages.forEach((page, pageIndex) => {
421
809
  throwIfAborted(options.signal);
422
810
  const { pageNum, contentsNum } = pageAllocs[pageIndex];
423
- const { bytes: contentBytes, substitutions, missingGlyphs } = writeContentStream(page.items, context);
811
+ let pageMcid = 0;
812
+ const pageContext = {
813
+ ...context,
814
+ nextMcid: () => pageMcid++,
815
+ layerObjectNumberOf: (name) => layerNumByName.get(name)
816
+ };
817
+ const { bytes: contentBytes, substitutions, missingGlyphs, markedStructure } = writeContentStream(page.items, pageContext);
818
+ if (markedStructure.length > 0) markedStructureByPage.set(pageIndex, [...markedStructure]);
424
819
  for (const substitution of substitutions) options.onSubstitution?.(substitution, { pageIndex });
425
820
  for (const missing of missingGlyphs) options.onMissingGlyph?.(missing, { pageIndex });
426
821
  const pageFormulas = formulasByPage.get(pageIndex);
@@ -435,7 +830,7 @@ function writePdf(doc, options = {}) {
435
830
  num: contentsNum,
436
831
  value: pdfStream(contentsDict, finalContentBytes)
437
832
  });
438
- const annots = page.items.filter(isLinkItem).map((link) => buildLinkAnnotDict(link));
833
+ const annots = [...page.items.filter(isLinkItem).map((link) => buildLinkAnnotDict(link)), ...page.items.filter(isInternalLinkItem).map((link) => buildInternalLinkAnnotDict(link, doc, pageAllocs))];
439
834
  if (page.notes !== void 0 && page.notes.length > 0) annots.push(buildNotesAnnotDict(page.notes));
440
835
  const pageEntries = /* @__PURE__ */ new Map([
441
836
  ["Type", pdfName("Page")],
@@ -450,15 +845,59 @@ function writePdf(doc, options = {}) {
450
845
  ["Contents", pdfRef(contentsNum, 0)]
451
846
  ]);
452
847
  if (annots.length > 0) pageEntries.set("Annots", pdfArray(annots));
848
+ if ((markedStructureByPage.get(pageIndex) ?? []).length > 0) pageEntries.set("StructParents", pdfNum(pageIndex));
453
849
  objects.push({
454
850
  num: pageNum,
455
851
  value: pdfDict(pageEntries)
456
852
  });
457
853
  });
854
+ if (structRootNum !== void 0 && structParentTreeNum !== void 0) {
855
+ const nums = [];
856
+ for (const [pageIndex, marks] of markedStructureByPage) {
857
+ const maxMcid = Math.max(...marks.map((mark) => mark.mcid));
858
+ const byMcid = Array.from({ length: maxMcid + 1 }, () => pdfNull());
859
+ for (const mark of marks) {
860
+ const elementNum = structElementNumById.get(mark.structureId);
861
+ if (elementNum !== void 0) byMcid[mark.mcid] = pdfRef(elementNum, 0);
862
+ }
863
+ nums.push(pdfNum(pageIndex), pdfArray(byMcid));
864
+ }
865
+ objects.push({
866
+ num: structParentTreeNum,
867
+ value: pdfDict({ Nums: pdfArray(nums) })
868
+ });
869
+ const rootEntries = [
870
+ ["Type", pdfName("StructTreeRoot")],
871
+ ["K", pdfArray((doc.structure ?? []).map((element) => {
872
+ const num = structElementNumById.get(element.id);
873
+ if (num === void 0) throw new Error(`structure element "${element.id}" was not allocated -- this is a writePdf internal invariant violation`);
874
+ return pdfRef(num, 0);
875
+ }))],
876
+ ["ParentTree", pdfRef(structParentTreeNum, 0)]
877
+ ];
878
+ objects.push({
879
+ num: structRootNum,
880
+ value: pdfDict(Object.fromEntries(rootEntries))
881
+ });
882
+ }
883
+ let fileId;
884
+ let encryptedObjects = objects;
885
+ if (options.encryption !== void 0 && encryptDictNum !== void 0) {
886
+ fileId = randomBytes(FILE_ID_BYTES);
887
+ const encryptor = createStandardEncryptor(options.encryption, fileId);
888
+ encryptedObjects = objects.map(({ num, value }) => ({
889
+ num,
890
+ value: encryptIndirectObject(value, num, 0, encryptor)
891
+ }));
892
+ encryptedObjects.push({
893
+ num: encryptDictNum,
894
+ value: encryptor.encryptDict
895
+ });
896
+ }
458
897
  const writer = new ByteWriter();
459
898
  writer.writeAscii("%PDF-1.7\n");
460
899
  const offsets = /* @__PURE__ */ new Map();
461
- for (const { num, value } of objects) {
900
+ for (const { num, value } of encryptedObjects) {
462
901
  offsets.set(num, writer.length);
463
902
  writer.writeAscii(`${num} 0 obj\n`);
464
903
  writeObject(writer, value);
@@ -474,16 +913,21 @@ function writePdf(doc, options = {}) {
474
913
  if (offset === void 0) throw new Error(`object ${num} was allocated but never written -- this is a writePdf internal invariant violation`);
475
914
  writer.writeAscii(xrefEntry(offset, 0, true));
476
915
  }
916
+ const trailerEntries = /* @__PURE__ */ new Map([
917
+ ["Size", pdfNum(maxObjNum + 1)],
918
+ ["Root", pdfRef(catalogNum, 0)],
919
+ ["Info", pdfRef(infoNum, 0)]
920
+ ]);
921
+ if (fileId !== void 0 && encryptDictNum !== void 0) {
922
+ trailerEntries.set("ID", pdfArray([pdfHexString(fileId), pdfHexString(fileId)]));
923
+ trailerEntries.set("Encrypt", pdfRef(encryptDictNum, 0));
924
+ } else if (trailerIdRestore !== void 0) trailerEntries.set("ID", trailerIdRestore);
477
925
  writer.writeAscii("trailer\n");
478
- writeObject(writer, pdfDict({
479
- Size: pdfNum(maxObjNum + 1),
480
- Root: pdfRef(catalogNum, 0),
481
- Info: pdfRef(infoNum, 0)
482
- }));
926
+ writeObject(writer, pdfDict(trailerEntries));
483
927
  writer.writeAscii("\nstartxref\n");
484
928
  writer.writeAscii(`${xrefOffset}\n`);
485
929
  writer.writeAscii("%%EOF");
486
930
  return writer.toBytes();
487
931
  }
488
932
  //#endregion
489
- export { NOTES_ANNOTATION_AUTHOR, writePdf };
933
+ export { writePdf };
package/dist/xmp.cjs ADDED
@@ -0,0 +1,46 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/xmp.ts
3
+ function readXmpMetadata(packet) {
4
+ return {
5
+ ...field(xmpValue(packet, "dc:title"), "title"),
6
+ ...field(xmpValue(packet, "dc:creator"), "author"),
7
+ ...field(xmpValue(packet, "dc:description"), "subject"),
8
+ ...field(xmpValue(packet, "xmp:CreatorTool"), "creator"),
9
+ ...field(xmpValue(packet, "pdf:Producer"), "producer"),
10
+ ...field(xmpValue(packet, "xmp:CreateDate"), "createdIso"),
11
+ ...field(xmpValue(packet, "xmp:ModifyDate"), "modifiedIso"),
12
+ ...keywordsOf(packet)
13
+ };
14
+ }
15
+ function xmpValue(packet, element) {
16
+ const match = new RegExp(`<${element}(?:\\s[^>]*)?>([\\s\\S]*?)</${element}>`).exec(packet);
17
+ if (match === null) return;
18
+ const inner = match[1] ?? "";
19
+ const items = listItems(inner);
20
+ if (items.length > 0) return items;
21
+ const text = inner.trim();
22
+ return text.length > 0 ? text : void 0;
23
+ }
24
+ function listItems(inner) {
25
+ const items = [];
26
+ const pattern = /<rdf:li(?:\s[^>]*)?>([\s\S]*?)<\/rdf:li>/g;
27
+ let match;
28
+ while ((match = pattern.exec(inner)) !== null) {
29
+ const text = (match[1] ?? "").trim();
30
+ if (text.length > 0) items.push(text);
31
+ }
32
+ return items;
33
+ }
34
+ function field(value, key) {
35
+ if (typeof value === "string") return { [key]: value };
36
+ if (Array.isArray(value) && value.length > 0) return { [key]: value.join(", ") };
37
+ return {};
38
+ }
39
+ function keywordsOf(packet) {
40
+ const match = (/* @__PURE__ */ new RegExp("<dc:subject(?:\\s[^>]*)?>([\\s\\S]*?)</dc:subject>")).exec(packet);
41
+ if (match === null) return {};
42
+ const items = listItems(match[1] ?? "");
43
+ return items.length > 0 ? { keywords: items } : {};
44
+ }
45
+ //#endregion
46
+ exports.readXmpMetadata = readXmpMetadata;
package/dist/xmp.d.cts ADDED
@@ -0,0 +1,14 @@
1
+ //#region src/xmp.d.ts
2
+ interface XmpMetadata {
3
+ readonly title?: string;
4
+ readonly author?: string;
5
+ readonly subject?: string;
6
+ readonly keywords?: string[];
7
+ readonly creator?: string;
8
+ readonly producer?: string;
9
+ readonly createdIso?: string;
10
+ readonly modifiedIso?: string;
11
+ }
12
+ declare function readXmpMetadata(packet: string): XmpMetadata;
13
+ //#endregion
14
+ export { XmpMetadata, readXmpMetadata };
package/dist/xmp.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ //#region src/xmp.d.ts
2
+ interface XmpMetadata {
3
+ readonly title?: string;
4
+ readonly author?: string;
5
+ readonly subject?: string;
6
+ readonly keywords?: string[];
7
+ readonly creator?: string;
8
+ readonly producer?: string;
9
+ readonly createdIso?: string;
10
+ readonly modifiedIso?: string;
11
+ }
12
+ declare function readXmpMetadata(packet: string): XmpMetadata;
13
+ //#endregion
14
+ export { XmpMetadata, readXmpMetadata };