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.
- package/README.md +9 -4
- package/dist/esm/{layout → core}/arc-to-bezier.d.ts +1 -1
- package/dist/esm/{layout → core}/arc-to-bezier.js +2 -2
- package/dist/esm/core/converter/project.js +2 -0
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +58 -0
- package/dist/esm/{layout → core/drawingml}/chart-geometry.d.ts +1 -1
- package/dist/esm/{layout → core/drawingml}/preset-geometry.d.ts +2 -2
- package/dist/esm/{layout → core/drawingml}/preset-geometry.js +3 -3
- package/dist/esm/core/drawingml/shape-render.d.ts +8 -0
- package/dist/esm/core/drawingml/shape-render.js +71 -0
- package/dist/esm/core/ir/features.d.ts +1 -0
- package/dist/esm/core/ir/features.js +1 -0
- package/dist/esm/core/ir/flow.d.ts +3 -0
- package/dist/esm/core/links.d.ts +6 -0
- package/dist/esm/core/links.js +19 -0
- package/dist/esm/core/numbering/apply.js +3 -1
- package/dist/esm/core/style-cascade/index.d.ts +1 -0
- package/dist/esm/core/style-cascade/index.js +1 -0
- package/dist/esm/core/style-cascade/table.d.ts +2 -0
- package/dist/esm/core/style-cascade/table.js +161 -0
- package/dist/esm/core/vector.d.ts +2 -0
- package/dist/esm/core/vector.js +19 -1
- package/dist/esm/html/html-writer.js +188 -16
- package/dist/esm/layout/page-doc.d.ts +3 -0
- package/dist/esm/layout/styled-layout.d.ts +19 -3
- package/dist/esm/layout/styled-layout.js +533 -197
- package/dist/esm/pdf/struct-tree.d.ts +7 -1
- package/dist/esm/pdf/struct-tree.js +22 -6
- package/dist/esm/pdf/styled-page-emitter.d.ts +1 -1
- package/dist/esm/pdf/styled-page-emitter.js +161 -29
- package/dist/esm/pdf/xmp.d.ts +1 -0
- package/dist/esm/pdf/xmp.js +4 -0
- package/dist/esm/svg/svg-writer.js +2 -6
- package/dist/esm/word/document-parser.d.ts +3 -0
- package/dist/esm/word/document-parser.js +210 -23
- package/dist/esm/word/docx-reader.js +30 -4
- package/dist/esm/word/drawing-parser.d.ts +4 -1
- package/dist/esm/word/drawing-parser.js +53 -2
- package/dist/esm/word/index.d.ts +2 -2
- package/dist/esm/word/styles-parser.js +134 -1
- package/dist/esm/word/table-parser.js +35 -0
- package/package.json +1 -1
- /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
|
|
94
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
152
|
-
|
|
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
|
-
|
|
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
|
|
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));
|
package/dist/esm/pdf/xmp.d.ts
CHANGED
|
@@ -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;
|
package/dist/esm/pdf/xmp.js
CHANGED
|
@@ -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
|
-
|
|
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>>;
|