reamkit 1.1.0 → 1.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 (44) hide show
  1. package/README.md +9 -4
  2. package/dist/esm/{layout → core}/arc-to-bezier.d.ts +1 -1
  3. package/dist/esm/{layout → core}/arc-to-bezier.js +2 -2
  4. package/dist/esm/core/converter/project.js +2 -0
  5. package/dist/esm/core/document-model/index.d.ts +1 -1
  6. package/dist/esm/core/document-model/types.d.ts +58 -0
  7. package/dist/esm/{layout → core/drawingml}/chart-geometry.d.ts +1 -1
  8. package/dist/esm/{layout → core/drawingml}/preset-geometry.d.ts +2 -2
  9. package/dist/esm/{layout → core/drawingml}/preset-geometry.js +3 -3
  10. package/dist/esm/core/drawingml/shape-render.d.ts +8 -0
  11. package/dist/esm/core/drawingml/shape-render.js +71 -0
  12. package/dist/esm/core/ir/features.d.ts +1 -0
  13. package/dist/esm/core/ir/features.js +1 -0
  14. package/dist/esm/core/ir/flow.d.ts +3 -0
  15. package/dist/esm/core/links.d.ts +6 -0
  16. package/dist/esm/core/links.js +19 -0
  17. package/dist/esm/core/numbering/apply.js +3 -1
  18. package/dist/esm/core/style-cascade/index.d.ts +1 -0
  19. package/dist/esm/core/style-cascade/index.js +1 -0
  20. package/dist/esm/core/style-cascade/table.d.ts +2 -0
  21. package/dist/esm/core/style-cascade/table.js +161 -0
  22. package/dist/esm/core/vector.d.ts +2 -0
  23. package/dist/esm/core/vector.js +19 -1
  24. package/dist/esm/html/html-writer.js +188 -16
  25. package/dist/esm/layout/page-doc.d.ts +3 -0
  26. package/dist/esm/layout/styled-layout.d.ts +19 -3
  27. package/dist/esm/layout/styled-layout.js +533 -197
  28. package/dist/esm/pdf/struct-tree.d.ts +7 -1
  29. package/dist/esm/pdf/struct-tree.js +22 -6
  30. package/dist/esm/pdf/styled-page-emitter.d.ts +1 -1
  31. package/dist/esm/pdf/styled-page-emitter.js +161 -29
  32. package/dist/esm/pdf/xmp.d.ts +1 -0
  33. package/dist/esm/pdf/xmp.js +4 -0
  34. package/dist/esm/svg/svg-writer.js +2 -6
  35. package/dist/esm/word/document-parser.d.ts +3 -0
  36. package/dist/esm/word/document-parser.js +210 -23
  37. package/dist/esm/word/docx-reader.js +30 -4
  38. package/dist/esm/word/drawing-parser.d.ts +4 -1
  39. package/dist/esm/word/drawing-parser.js +53 -2
  40. package/dist/esm/word/index.d.ts +2 -2
  41. package/dist/esm/word/styles-parser.js +134 -1
  42. package/dist/esm/word/table-parser.js +35 -0
  43. package/package.json +1 -1
  44. /package/dist/esm/{layout → core/drawingml}/chart-geometry.js +0 -0
@@ -1,6 +1,6 @@
1
1
  import { PdfRef } from './objects.js';
2
2
  import { PdfDocument } from './writer.js';
3
- export type StructType = 'Document' | 'Part' | 'Sect' | 'H1' | 'H2' | 'H3' | 'H4' | 'H5' | 'H6' | 'P' | 'L' | 'LI' | 'Lbl' | 'LBody' | 'Table' | 'TR' | 'TH' | 'TD' | 'Caption' | 'Figure' | 'Span';
3
+ export type StructType = 'Document' | 'Part' | 'Sect' | 'H1' | 'H2' | 'H3' | 'H4' | 'H5' | 'H6' | 'P' | 'L' | 'LI' | 'Lbl' | 'LBody' | 'Table' | 'TR' | 'TH' | 'TD' | 'Caption' | 'Figure' | 'Link' | 'Note' | 'Span';
4
4
  interface Mcref {
5
5
  readonly pageIndex: number;
6
6
  readonly mcid: number;
@@ -10,6 +10,10 @@ export declare class StructNode {
10
10
  type: StructType;
11
11
  readonly children: Array<StructNode>;
12
12
  readonly mcrefs: Array<Mcref>;
13
+ readonly objrs: Array<{
14
+ readonly annotRef: PdfRef;
15
+ readonly pageIndex: number;
16
+ }>;
13
17
  parent: StructNode | null;
14
18
  ref: PdfRef | null;
15
19
  alt: string | null;
@@ -26,6 +30,8 @@ export declare class StructTreeBuilder {
26
30
  create(type: StructType, parent: StructNode | null): StructNode;
27
31
  node(id: number): StructNode;
28
32
  addMcref(nodeId: number, pageIndex: number, mcid: number): void;
33
+ private readonly annotParents;
34
+ addAnnotParent(key: number, nodeId: number): void;
29
35
  emit(doc: PdfDocument, pageRefs: ReadonlyArray<PdfRef>): PdfRef;
30
36
  }
31
37
  export {};
@@ -3,6 +3,7 @@ import { PDF_NULL, dict, name, unicodeString } from "./objects.js";
3
3
  var StructNode = class {
4
4
  children = [];
5
5
  mcrefs = [];
6
+ objrs = [];
6
7
  parent = null;
7
8
  ref = null;
8
9
  alt = null;
@@ -39,6 +40,13 @@ var StructTreeBuilder = class {
39
40
  mcid
40
41
  });
41
42
  }
43
+ annotParents = [];
44
+ addAnnotParent(key, nodeId) {
45
+ this.annotParents.push({
46
+ key,
47
+ nodeId
48
+ });
49
+ }
42
50
  emit(doc, pageRefs) {
43
51
  const order = [];
44
52
  const walk = (n) => {
@@ -52,6 +60,7 @@ var StructTreeBuilder = class {
52
60
  Type: name("StructElem"),
53
61
  S: name(n.type)
54
62
  });
63
+ if (n.type === "Note") d.set("ID", `note-${n.id}`);
55
64
  n.ref = doc.add(d);
56
65
  dicts.set(n.id, d);
57
66
  }
@@ -60,7 +69,7 @@ var StructTreeBuilder = class {
60
69
  for (const n of order) {
61
70
  const d = dicts.get(n.id);
62
71
  d.set("P", n.parent ? n.parent.ref : rootRef);
63
- const firstPage = n.mcrefs.length > 0 ? n.mcrefs[0].pageIndex : void 0;
72
+ const firstPage = n.mcrefs.length > 0 ? n.mcrefs[0].pageIndex : n.objrs.length > 0 ? n.objrs[0].pageIndex : void 0;
64
73
  if (firstPage !== void 0) d.set("Pg", pageRefs[firstPage]);
65
74
  const kids = [];
66
75
  for (const c of n.children) kids.push(c.ref);
@@ -69,6 +78,11 @@ var StructTreeBuilder = class {
69
78
  Pg: pageRefs[m.pageIndex],
70
79
  MCID: m.mcid
71
80
  }));
81
+ for (const o of n.objrs) kids.push(dict({
82
+ Type: name("OBJR"),
83
+ Pg: pageRefs[o.pageIndex],
84
+ Obj: o.annotRef
85
+ }));
72
86
  if (kids.length === 1) d.set("K", kids[0]);
73
87
  else if (kids.length > 1) d.set("K", kids);
74
88
  if (n.alt !== null) d.set("Alt", unicodeString(n.alt));
@@ -90,14 +104,16 @@ var StructTreeBuilder = class {
90
104
  }
91
105
  arr[m.mcid] = n.ref;
92
106
  }
93
- const sortedKeys = [...perPage.keys()].sort((a, b) => a - b);
94
- const nums = [];
95
- for (const k of sortedKeys) {
96
- const arr = perPage.get(k);
107
+ const entries = /* @__PURE__ */ new Map();
108
+ for (const [k, arr] of perPage) {
97
109
  const dense = [];
98
110
  for (let i = 0; i < arr.length; i++) dense.push(arr[i] ?? PDF_NULL);
99
- nums.push(k, dense);
111
+ entries.set(k, dense);
100
112
  }
113
+ for (const a of this.annotParents) entries.set(a.key, this.node(a.nodeId).ref);
114
+ const sortedKeys = [...entries.keys()].sort((a, b) => a - b);
115
+ const nums = [];
116
+ for (const k of sortedKeys) nums.push(k, entries.get(k));
101
117
  const parentTreeRef = doc.add(dict({ Nums: nums }));
102
118
  rootDict.set("K", this.root.ref);
103
119
  rootDict.set("ParentTree", parentTreeRef);
@@ -1,6 +1,6 @@
1
1
  import { LaidOutPdfDocument, StyledRenderOptions } from '../layout/styled-layout.js';
2
2
  import { PdfDocument } from './writer.js';
3
- type EmitOptions = Pick<StyledRenderOptions, 'attachments' | 'info' | 'language' | 'signaturePlaceholder'>;
3
+ type EmitOptions = Pick<StyledRenderOptions, 'attachments' | 'info' | 'language' | 'pdfUA' | 'signaturePlaceholder'>;
4
4
  export declare function emitStyledPdf(laid: LaidOutPdfDocument, options: EmitOptions, doc: PdfDocument): Uint8Array;
5
5
  export interface PageTagging {
6
6
  next: number;
@@ -5,6 +5,7 @@ import { reverseByCodePoint } from "../core/bidi/index.js";
5
5
  import "../layout/styled-layout.js";
6
6
  import { paintPlan } from "../layout/page-doc.js";
7
7
  import { emitVectorShape } from "./vector-graphics.js";
8
+ import { sanitizeHref } from "../core/links.js";
8
9
  import { embedAssociatedFile } from "./embedded-file.js";
9
10
  import { buildSrgbIccProfile } from "./icc-profile.js";
10
11
  import { addImage } from "./image-xobject.js";
@@ -15,6 +16,10 @@ var encoder = new TextEncoder();
15
16
  function emitStyledPdf(laid, options, doc) {
16
17
  const { pages: renderedPages } = laid;
17
18
  const { structBuilder, sectionCtxs, pdfaProfile, tagged } = laid.pdf;
19
+ const docInfo = options.pdfUA && !options.info?.title ? {
20
+ ...options.info,
21
+ title: "Untitled document"
22
+ } : options.info;
18
23
  const embeddedFonts = embedFontResources(doc, laid, pdfaProfile);
19
24
  const embeddedImages = embedImageResources(doc, laid);
20
25
  const pagesDict = dict({
@@ -24,6 +29,8 @@ function emitStyledPdf(laid, options, doc) {
24
29
  });
25
30
  const pagesRef = doc.add(pagesDict);
26
31
  let firstPageDict;
32
+ let firstPageAnnots;
33
+ let annotParentCount = 0;
27
34
  const fontResourceDict = buildFontResourceDict(laid.fontResources, embeddedFonts);
28
35
  const xobjectResourceDict = buildXObjectResourceDict(laid.imageResources, embeddedImages);
29
36
  const resourcesDict = dict({
@@ -43,6 +50,7 @@ function emitStyledPdf(laid, options, doc) {
43
50
  });
44
51
  }
45
52
  const pageRefs = [];
53
+ const referencedAnchors = /* @__PURE__ */ new Set();
46
54
  renderedPages.forEach((page, pageIndex) => {
47
55
  let pageTagging;
48
56
  if (structBuilder) {
@@ -54,7 +62,7 @@ function emitStyledPdf(laid, options, doc) {
54
62
  tagFor: (structId) => builder.node(structId).type
55
63
  };
56
64
  }
57
- const contentBytes = emitPageContent(page, pageTagging);
65
+ const { content: contentBytes, links } = emitPageContent(page, pageTagging);
58
66
  const contentsRef = doc.add(stream({}, contentBytes));
59
67
  const pageEntries = {
60
68
  Type: name("Page"),
@@ -68,6 +76,53 @@ function emitStyledPdf(laid, options, doc) {
68
76
  Resources: resourcesDict,
69
77
  Contents: ref(contentsRef.id)
70
78
  };
79
+ if (links.length > 0) {
80
+ const annots = [];
81
+ for (const l of links) {
82
+ if (structBuilder && l.structId === void 0) continue;
83
+ const entries = {
84
+ Type: name("Annot"),
85
+ Subtype: name("Link"),
86
+ Rect: [
87
+ l.rect[0],
88
+ l.rect[1],
89
+ l.rect[2],
90
+ l.rect[3]
91
+ ],
92
+ Border: [
93
+ 0,
94
+ 0,
95
+ 0
96
+ ],
97
+ F: 4,
98
+ A: l.href !== void 0 ? dict({
99
+ S: name("URI"),
100
+ URI: l.href
101
+ }) : dict({
102
+ S: name("GoTo"),
103
+ D: l.anchor ?? ""
104
+ }),
105
+ Contents: l.text !== "" ? l.text : l.href ?? l.anchor ?? ""
106
+ };
107
+ if (l.anchor !== void 0) referencedAnchors.add(l.anchor);
108
+ if (structBuilder && l.structId !== void 0) entries["StructParent"] = renderedPages.length + annotParentCount;
109
+ const annotRef = doc.add(dict(entries));
110
+ if (structBuilder && l.structId !== void 0) {
111
+ const linkNode = structBuilder.create("Link", structBuilder.node(l.structId));
112
+ linkNode.objrs.push({
113
+ annotRef,
114
+ pageIndex
115
+ });
116
+ structBuilder.addAnnotParent(renderedPages.length + annotParentCount, linkNode.id);
117
+ annotParentCount++;
118
+ }
119
+ annots.push(ref(annotRef.id));
120
+ }
121
+ if (annots.length > 0) {
122
+ pageEntries["Annots"] = annots;
123
+ if (pageIndex === 0) firstPageAnnots = annots;
124
+ }
125
+ }
71
126
  if (transparencyGroup) pageEntries["Group"] = transparencyGroup;
72
127
  if (pageTagging?.assigned) {
73
128
  pageEntries["StructParents"] = pageIndex;
@@ -98,29 +153,28 @@ function emitStyledPdf(laid, options, doc) {
98
153
  }
99
154
  pagesDict.set("Count", pageRefs.length);
100
155
  pagesDict.set("Kids", pageRefs);
156
+ const namesTreeEntries = {};
101
157
  const catalogEntries = {
102
158
  Type: name("Catalog"),
103
159
  Pages: ref(pagesRef.id)
104
160
  };
105
- if (pdfaProfile) {
106
- catalogEntries["OutputIntents"] = [ref(doc.add(dict({
107
- Type: name("OutputIntent"),
108
- S: name("GTS_PDFA1"),
109
- OutputConditionIdentifier: "sRGB",
110
- Info: "sRGB IEC61966-2.1",
111
- DestOutputProfile: ref(pdfaIccRef.id)
112
- })).id)];
113
- catalogEntries["Metadata"] = ref(doc.add(stream({
114
- Type: name("Metadata"),
115
- Subtype: name("XML")
116
- }, buildXmpPacket(xmpFromInfo(options.info, pdfaProfile)))).id);
117
- }
161
+ if (pdfaProfile) catalogEntries["OutputIntents"] = [ref(doc.add(dict({
162
+ Type: name("OutputIntent"),
163
+ S: name("GTS_PDFA1"),
164
+ OutputConditionIdentifier: "sRGB",
165
+ Info: "sRGB IEC61966-2.1",
166
+ DestOutputProfile: ref(pdfaIccRef.id)
167
+ })).id)];
168
+ if (pdfaProfile || options.pdfUA) catalogEntries["Metadata"] = ref(doc.add(stream({
169
+ Type: name("Metadata"),
170
+ Subtype: name("XML")
171
+ }, buildXmpPacket(xmpFromInfo(docInfo, pdfaProfile, options.pdfUA === true)))).id);
118
172
  if (tagged && structBuilder) {
119
173
  const structRootRef = structBuilder.emit(doc, pageRefs);
120
174
  catalogEntries["MarkInfo"] = dict({ Marked: true });
121
175
  catalogEntries["StructTreeRoot"] = ref(structRootRef.id);
122
176
  catalogEntries["Lang"] = options.language ?? "en-US";
123
- if (options.info?.title) catalogEntries["ViewerPreferences"] = dict({ DisplayDocTitle: true });
177
+ if (docInfo?.title) catalogEntries["ViewerPreferences"] = dict({ DisplayDocTitle: true });
124
178
  }
125
179
  if (options.attachments?.length && (!pdfaProfile || pdfaProfile.part === 3)) {
126
180
  const embedded = options.attachments.map((file) => ({
@@ -131,25 +185,46 @@ function emitStyledPdf(laid, options, doc) {
131
185
  const sorted = [...embedded].sort((a, b) => a.file.name < b.file.name ? -1 : a.file.name > b.file.name ? 1 : 0);
132
186
  const names = [];
133
187
  for (const e of sorted) names.push(e.file.name, ref(e.ref.id));
134
- catalogEntries["Names"] = dict({ EmbeddedFiles: ref(doc.add(dict({ Names: names })).id) });
188
+ namesTreeEntries["EmbeddedFiles"] = ref(doc.add(dict({ Names: names })).id);
189
+ }
190
+ const bookmarkDests = laid.pdf.bookmarks;
191
+ const destNames = [...referencedAnchors].filter((n) => bookmarkDests.has(n)).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
192
+ if (destNames.length > 0) {
193
+ const names = [];
194
+ for (const destName of destNames) {
195
+ const pos = bookmarkDests.get(destName);
196
+ const pageRef = pageRefs[pos.pageIdx];
197
+ if (!pageRef) continue;
198
+ names.push(destName, [
199
+ ref(pageRef.id),
200
+ name("FitH"),
201
+ pos.yTopPt
202
+ ]);
203
+ }
204
+ namesTreeEntries["Dests"] = ref(doc.add(dict({ Names: names })).id);
135
205
  }
206
+ if (Object.keys(namesTreeEntries).length > 0) catalogEntries["Names"] = dict(namesTreeEntries);
136
207
  if (options.signaturePlaceholder && firstPageDict) {
137
208
  const { fieldRef, acroForm } = addSignaturePlaceholder(doc, options.signaturePlaceholder, pageRefs[0]);
138
- firstPageDict.set("Annots", [ref(fieldRef.id)]);
209
+ if (firstPageAnnots) firstPageAnnots.push(ref(fieldRef.id));
210
+ else firstPageDict.set("Annots", [ref(fieldRef.id)]);
139
211
  catalogEntries["AcroForm"] = acroForm;
140
212
  }
141
213
  const catalogRef = doc.add(dict(catalogEntries));
142
- const infoRef = buildInfoDict(doc, options.info);
214
+ const infoRef = buildInfoDict(doc, docInfo);
143
215
  return doc.build(catalogRef, infoRef, { ...pdfaProfile ? {
144
216
  version: pdfaProfile.version,
145
217
  id: true
146
218
  } : {} });
147
219
  }
148
220
  var DEFAULT_PRODUCER = "Ream";
149
- function xmpFromInfo(info, p) {
221
+ function xmpFromInfo(info, p, pdfUA = false) {
150
222
  return {
151
- pdfaPart: p ? String(p.part) : "1",
152
- pdfaConformance: p ? p.level.toUpperCase() : "B",
223
+ ...p ? {
224
+ pdfaPart: String(p.part),
225
+ pdfaConformance: p.level.toUpperCase()
226
+ } : {},
227
+ ...pdfUA ? { pdfuaPart: "1" } : {},
153
228
  producer: info?.producer ?? DEFAULT_PRODUCER,
154
229
  ...info?.title ? { title: info.title } : {},
155
230
  ...info?.author ? { author: info.author } : {},
@@ -195,14 +270,14 @@ function defaultPageCtx() {
195
270
  contentWidth: 451,
196
271
  pageContentHeight: 698,
197
272
  headerSet: {
198
- default: [],
199
- first: [],
200
- even: []
273
+ default: { commands: [] },
274
+ first: { commands: [] },
275
+ even: { commands: [] }
201
276
  },
202
277
  footerSet: {
203
- default: [],
204
- first: [],
205
- even: []
278
+ default: { commands: [] },
279
+ first: { commands: [] },
280
+ even: { commands: [] }
206
281
  },
207
282
  titlePg: false,
208
283
  evenAndOddHeaders: false
@@ -270,7 +345,11 @@ function emitTaggedRuns(out, cmds, tagging, body) {
270
345
  }
271
346
  function emitPageContent(page, tagging) {
272
347
  const commands = page.commands;
273
- if (commands.length === 0) return new Uint8Array(0);
348
+ const links = [];
349
+ if (commands.length === 0) return {
350
+ content: new Uint8Array(0),
351
+ links
352
+ };
274
353
  const H = page.height;
275
354
  const out = [];
276
355
  const plan = paintPlan(commands);
@@ -453,6 +532,47 @@ function emitPageContent(page, tagging) {
453
532
  const line = cmd.line;
454
533
  const originX = cmd.originX;
455
534
  const baselineY = H - cmd.baselineY;
535
+ const lineFs = line.maxFontSizePt || 12;
536
+ const linkAscent = Math.max(lineFs, line.mathAscentPt ?? 0);
537
+ const linkDescent = Math.max(lineFs * .2, line.mathDescentPt ?? 0);
538
+ let linkHref;
539
+ let linkAnchor;
540
+ let linkText = "";
541
+ let linkX0 = 0;
542
+ let linkX1 = 0;
543
+ const flushLink = () => {
544
+ if (linkHref === void 0 && linkAnchor === void 0) return;
545
+ const safe = linkHref !== void 0 ? sanitizeHref(linkHref) : void 0;
546
+ const target = safe !== void 0 ? { href: safe } : linkAnchor !== void 0 ? { anchor: linkAnchor } : void 0;
547
+ if (target) links.push({
548
+ ...target,
549
+ text: linkText.trim(),
550
+ rect: [
551
+ linkX0,
552
+ baselineY - linkDescent,
553
+ linkX1,
554
+ baselineY + linkAscent
555
+ ],
556
+ ...cmd.structId !== void 0 ? { structId: cmd.structId } : {}
557
+ });
558
+ linkHref = void 0;
559
+ linkAnchor = void 0;
560
+ linkText = "";
561
+ };
562
+ const trackLink = (href, anchor, text, x0, x1) => {
563
+ if (href !== linkHref || anchor !== linkAnchor) {
564
+ flushLink();
565
+ if (href !== void 0 || anchor !== void 0) {
566
+ linkHref = href;
567
+ linkAnchor = anchor;
568
+ linkX0 = x0;
569
+ }
570
+ }
571
+ if (href !== void 0 || anchor !== void 0) {
572
+ linkX1 = x1;
573
+ linkText += text;
574
+ }
575
+ };
456
576
  const extraPerSpace = computeJustifyExtra(line);
457
577
  const hasImageToken = line.tokens.some((t) => t.kind === "image");
458
578
  const hasMathToken = line.tokens.some((t) => t.kind === "math");
@@ -467,11 +587,13 @@ function emitPageContent(page, tagging) {
467
587
  for (const ti of order) {
468
588
  const tok = line.tokens[ti];
469
589
  if (tok.kind === "image") {
590
+ flushLink();
470
591
  emitImageToken(tok, x, baselineY);
471
592
  x += tok.widthPt;
472
593
  continue;
473
594
  }
474
595
  if (tok.kind === "math") {
596
+ flushLink();
475
597
  emitMathToken(tok, x, baselineY);
476
598
  x += tok.widthPt;
477
599
  continue;
@@ -483,21 +605,28 @@ function emitPageContent(page, tagging) {
483
605
  switchFontIfNeeded(tok);
484
606
  out.push(`1 0 0 1 ${formatNumber(x)} ${formatNumber(baselineY)} Tm`);
485
607
  out.push(`<${encodeToken(tok)}> Tj`);
608
+ const tokenX0 = x;
486
609
  x += tok.widthPt;
487
610
  if (tok.isSpace) x += extraPerSpace;
611
+ trackLink(tok.href, tok.anchor, tok.text, tokenX0, x);
488
612
  }
613
+ flushLink();
489
614
  } else {
490
615
  if (!inBT) {
491
616
  out.push("BT");
492
617
  inBT = true;
493
618
  }
494
619
  out.push(`1 0 0 1 ${formatNumber(originX)} ${formatNumber(baselineY)} Tm`);
620
+ let x = originX;
495
621
  for (const tok of line.tokens) {
496
622
  if (tok.kind !== "text") continue;
497
623
  switchFontIfNeeded(tok);
498
624
  const hex = tok.font.measure.encodeTextAsCidHex(tok.text);
499
625
  out.push(`<${hex}> Tj`);
626
+ trackLink(tok.href, tok.anchor, tok.text, x, x + tok.widthPt);
627
+ x += tok.widthPt;
500
628
  }
629
+ flushLink();
501
630
  }
502
631
  };
503
632
  if (tagging) for (const cmd of lines) {
@@ -527,7 +656,10 @@ function emitPageContent(page, tagging) {
527
656
  if (inBT) out.push("ET");
528
657
  }
529
658
  }
530
- return encoder.encode(out.join("\n"));
659
+ return {
660
+ content: encoder.encode(out.join("\n")),
661
+ links
662
+ };
531
663
  }
532
664
  function lineVisualOrder(line) {
533
665
  return reorderVisual(line.tokens.map((t) => t.bidiLevel));
@@ -8,6 +8,7 @@ export interface XmpInput {
8
8
  readonly createDate?: Date;
9
9
  readonly modifyDate?: Date;
10
10
  readonly pdfaPart?: '1' | '2' | '3';
11
+ readonly pdfuaPart?: '1';
11
12
  readonly pdfaConformance?: 'A' | 'B' | 'U';
12
13
  }
13
14
  export declare function buildXmpPacket(input: XmpInput): Uint8Array;
@@ -9,6 +9,10 @@ function xmpDate(d) {
9
9
  function buildXmpPacket(input) {
10
10
  const props = [];
11
11
  if (input.pdfaPart) props.push(` <rdf:Description rdf:about="" xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/">`, ` <pdfaid:part>${input.pdfaPart}</pdfaid:part>`, ` <pdfaid:conformance>${input.pdfaConformance ?? "B"}</pdfaid:conformance>`, ` </rdf:Description>`);
12
+ if (input.pdfuaPart) {
13
+ props.push(` <rdf:Description rdf:about="" xmlns:pdfuaid="http://www.aiim.org/pdfua/ns/id/">`, ` <pdfuaid:part>${input.pdfuaPart}</pdfuaid:part>`, ` </rdf:Description>`);
14
+ if (input.pdfaPart) props.push(` <rdf:Description rdf:about="" xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/" xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#" xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#">`, ` <pdfaExtension:schemas>`, ` <rdf:Bag>`, ` <rdf:li rdf:parseType="Resource">`, ` <pdfaSchema:namespaceURI>http://www.aiim.org/pdfua/ns/id/</pdfaSchema:namespaceURI>`, ` <pdfaSchema:prefix>pdfuaid</pdfaSchema:prefix>`, ` <pdfaSchema:schema>PDF/UA identification schema</pdfaSchema:schema>`, ` <pdfaSchema:property>`, ` <rdf:Seq>`, ` <rdf:li rdf:parseType="Resource">`, ` <pdfaProperty:category>internal</pdfaProperty:category>`, ` <pdfaProperty:description>PDF/UA version identifier</pdfaProperty:description>`, ` <pdfaProperty:name>part</pdfaProperty:name>`, ` <pdfaProperty:valueType>Integer</pdfaProperty:valueType>`, ` </rdf:li>`, ` </rdf:Seq>`, ` </pdfaSchema:property>`, ` </rdf:li>`, ` </rdf:Bag>`, ` </pdfaExtension:schemas>`, ` </rdf:Description>`);
15
+ }
12
16
  const dc = [];
13
17
  if (input.title) dc.push(` <dc:title><rdf:Alt><rdf:li xml:lang="x-default">${escapeXml(input.title)}</rdf:li></rdf:Alt></dc:title>`);
14
18
  if (input.author) dc.push(` <dc:creator><rdf:Seq><rdf:li>${escapeXml(input.author)}</rdf:li></rdf:Seq></dc:creator>`);
@@ -1,4 +1,5 @@
1
1
  import { FEATURES } from "../core/ir/features.js";
2
+ import { svgPathData } from "../core/vector.js";
2
3
  import { paintPlan } from "../layout/page-doc.js";
3
4
  import { toBase64 } from "../core/bytes.js";
4
5
  //#region src/svg/svg-writer.ts
@@ -106,12 +107,7 @@ function emitShape(out, shape) {
106
107
  }
107
108
  }
108
109
  function pathData(segments) {
109
- const parts = [];
110
- for (const s of segments) if (s.op === "move") parts.push(`M ${fmt(s.x)} ${fmt(s.y)}`);
111
- else if (s.op === "line") parts.push(`L ${fmt(s.x)} ${fmt(s.y)}`);
112
- else if (s.op === "cubic") parts.push(`C ${fmt(s.x1)} ${fmt(s.y1)} ${fmt(s.x2)} ${fmt(s.y2)} ${fmt(s.x)} ${fmt(s.y)}`);
113
- else parts.push("Z");
114
- return parts.join(" ");
110
+ return svgPathData(segments, fmt);
115
111
  }
116
112
  function imageHref(resourceName, laid) {
117
113
  if (!resourceName) return void 0;
@@ -3,9 +3,11 @@ import { ColorResolver } from '../core/drawingml/colors.js';
3
3
  import { ResourceId } from '../core/ir/index.js';
4
4
  import { PoNode } from '../core/po-helpers.js';
5
5
  export type ImageResolver = (relId: string) => ResourceId | undefined;
6
+ export type HyperlinkResolver = (relId: string) => string | undefined;
6
7
  export interface ParseContext {
7
8
  readonly resolveColor: ColorResolver;
8
9
  readonly resolveImage?: ImageResolver;
10
+ readonly resolveHyperlink?: HyperlinkResolver;
9
11
  }
10
12
  export declare const DEFAULT_PARSE_CONTEXT: ParseContext;
11
13
  export declare function parseDocument(documentXml: Uint8Array, ctx?: ParseContext): Array<BodyElement>;
@@ -14,3 +16,4 @@ export declare function parseSection(documentXml: Uint8Array): SectionProperties
14
16
  export declare function parseSections(documentXml: Uint8Array): Array<Section>;
15
17
  export declare function parseHeaderFooter(xml: Uint8Array, ctx?: ParseContext): Array<BodyElement>;
16
18
  export declare function parseBodyElements(children: ReadonlyArray<PoNode>, ctx?: ParseContext): Array<BodyElement>;
19
+ export declare function parseNotes(notesXml: Uint8Array, rootTag: 'w:footnotes' | 'w:endnotes', noteTag: 'w:footnote' | 'w:endnote', ctx?: ParseContext): Map<string, Array<BodyElement>>;