@pdf-testkit/core 0.1.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/dist/diff/diff.d.ts +9 -0
- package/dist/diff/diff.d.ts.map +1 -0
- package/dist/diff/diff.js +139 -0
- package/dist/diff/diff.js.map +1 -0
- package/dist/diff/match.d.ts +21 -0
- package/dist/diff/match.d.ts.map +1 -0
- package/dist/diff/match.js +133 -0
- package/dist/diff/match.js.map +1 -0
- package/dist/events.d.ts +79 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +11 -0
- package/dist/events.js.map +1 -0
- package/dist/extract/finalize.d.ts +16 -0
- package/dist/extract/finalize.d.ts.map +1 -0
- package/dist/extract/finalize.js +88 -0
- package/dist/extract/finalize.js.map +1 -0
- package/dist/extract/fromFormeLayout.d.ts +82 -0
- package/dist/extract/fromFormeLayout.d.ts.map +1 -0
- package/dist/extract/fromFormeLayout.js +324 -0
- package/dist/extract/fromFormeLayout.js.map +1 -0
- package/dist/extract/fromPdf.d.ts +15 -0
- package/dist/extract/fromPdf.d.ts.map +1 -0
- package/dist/extract/fromPdf.js +120 -0
- package/dist/extract/fromPdf.js.map +1 -0
- package/dist/extract/pdfjs/headings.d.ts +16 -0
- package/dist/extract/pdfjs/headings.d.ts.map +1 -0
- package/dist/extract/pdfjs/headings.js +39 -0
- package/dist/extract/pdfjs/headings.js.map +1 -0
- package/dist/extract/pdfjs/loadDocument.d.ts +32 -0
- package/dist/extract/pdfjs/loadDocument.d.ts.map +1 -0
- package/dist/extract/pdfjs/loadDocument.js +45 -0
- package/dist/extract/pdfjs/loadDocument.js.map +1 -0
- package/dist/extract/pdfjs/overflow.d.ts +16 -0
- package/dist/extract/pdfjs/overflow.d.ts.map +1 -0
- package/dist/extract/pdfjs/overflow.js +35 -0
- package/dist/extract/pdfjs/overflow.js.map +1 -0
- package/dist/extract/pdfjs/tables.d.ts +31 -0
- package/dist/extract/pdfjs/tables.d.ts.map +1 -0
- package/dist/extract/pdfjs/tables.js +142 -0
- package/dist/extract/pdfjs/tables.js.map +1 -0
- package/dist/extract/pdfjs/textRuns.d.ts +26 -0
- package/dist/extract/pdfjs/textRuns.d.ts.map +1 -0
- package/dist/extract/pdfjs/textRuns.js +69 -0
- package/dist/extract/pdfjs/textRuns.js.map +1 -0
- package/dist/extract/raw.d.ts +29 -0
- package/dist/extract/raw.d.ts.map +1 -0
- package/dist/extract/raw.js +2 -0
- package/dist/extract/raw.js.map +1 -0
- package/dist/geometry.d.ts +13 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +41 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/snapshot/io.d.ts +4 -0
- package/dist/snapshot/io.d.ts.map +1 -0
- package/dist/snapshot/io.js +12 -0
- package/dist/snapshot/io.js.map +1 -0
- package/dist/snapshot/load.d.ts +9 -0
- package/dist/snapshot/load.d.ts.map +1 -0
- package/dist/snapshot/load.js +25 -0
- package/dist/snapshot/load.js.map +1 -0
- package/dist/snapshot/serialize.d.ts +14 -0
- package/dist/snapshot/serialize.d.ts.map +1 -0
- package/dist/snapshot/serialize.js +31 -0
- package/dist/snapshot/serialize.js.map +1 -0
- package/dist/text/headingLevels.d.ts +11 -0
- package/dist/text/headingLevels.d.ts.map +1 -0
- package/dist/text/headingLevels.js +40 -0
- package/dist/text/headingLevels.js.map +1 -0
- package/dist/text/normalize.d.ts +17 -0
- package/dist/text/normalize.d.ts.map +1 -0
- package/dist/text/normalize.js +67 -0
- package/dist/text/normalize.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { computeOverflow } from '../geometry.js';
|
|
2
|
+
import { buildHeadingLevelMap } from '../text/headingLevels.js';
|
|
3
|
+
import { finalize } from './finalize.js';
|
|
4
|
+
/**
|
|
5
|
+
* Explicit disposition for every value of `@formepdf/core`'s `ElementNodeType`
|
|
6
|
+
* union. Every union member has a deliberate role here — none rely on the
|
|
7
|
+
* fallthrough. Audited against @formepdf/core 0.12.1; re-review whenever that
|
|
8
|
+
* dependency version bumps (the coverage test in formeNodeTypeCoverage.test.ts
|
|
9
|
+
* enforces that this table + FORME_INTENTIONALLY_UNMAPPED cover the whole union).
|
|
10
|
+
*
|
|
11
|
+
* Judgment calls (confirmed): charts + all graphics → opaque `image` regions;
|
|
12
|
+
* form controls → structural `container`; `Lbl` (list marker) → `text`.
|
|
13
|
+
*/
|
|
14
|
+
export const FORME_ROLE_BY_NODE_TYPE = {
|
|
15
|
+
// Text & headings
|
|
16
|
+
Text: 'text',
|
|
17
|
+
TextLine: 'text',
|
|
18
|
+
Lbl: 'text', // list marker (bullet/number) — diffable text
|
|
19
|
+
H1: 'heading',
|
|
20
|
+
H2: 'heading',
|
|
21
|
+
H3: 'heading',
|
|
22
|
+
H4: 'heading',
|
|
23
|
+
H5: 'heading',
|
|
24
|
+
H6: 'heading',
|
|
25
|
+
// Table primitives (no `Table` wrapper — synthesized from contiguous rows)
|
|
26
|
+
TableRow: 'row',
|
|
27
|
+
TableCell: 'cell',
|
|
28
|
+
// Structural containers / regions
|
|
29
|
+
View: 'container',
|
|
30
|
+
List: 'container',
|
|
31
|
+
ListItem: 'container',
|
|
32
|
+
FixedHeader: 'container',
|
|
33
|
+
FixedFooter: 'container',
|
|
34
|
+
// Interactive form controls — tracked as structural regions (the field's
|
|
35
|
+
// value is content, not asserted; presence/position is).
|
|
36
|
+
TextField: 'container',
|
|
37
|
+
Checkbox: 'container',
|
|
38
|
+
Dropdown: 'container',
|
|
39
|
+
RadioButton: 'container',
|
|
40
|
+
// Opaque graphic regions — presence/position diffed, internals ignored.
|
|
41
|
+
Image: 'image',
|
|
42
|
+
Svg: 'image',
|
|
43
|
+
Canvas: 'image',
|
|
44
|
+
QrCode: 'image',
|
|
45
|
+
Barcode: 'image',
|
|
46
|
+
Watermark: 'image',
|
|
47
|
+
BarChart: 'image',
|
|
48
|
+
LineChart: 'image',
|
|
49
|
+
PieChart: 'image',
|
|
50
|
+
AreaChart: 'image',
|
|
51
|
+
DotPlot: 'image',
|
|
52
|
+
// --- Synthetic aliases NOT in the @formepdf union, kept for consumers that
|
|
53
|
+
// hand-build a simplified LayoutInfo and for unit-test fixtures.
|
|
54
|
+
Heading: 'heading',
|
|
55
|
+
Table: 'table',
|
|
56
|
+
Row: 'row',
|
|
57
|
+
Cell: 'cell',
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Union members intentionally given no semantic role (out of scope for v0.1),
|
|
61
|
+
* with a one-line reason each. Currently empty — every ElementNodeType maps to a
|
|
62
|
+
* deliberate role above. Kept as the explicit opt-out mechanism and referenced
|
|
63
|
+
* by the coverage test so a future "don't test this" decision is visible, never
|
|
64
|
+
* a silent default.
|
|
65
|
+
*/
|
|
66
|
+
export const FORME_INTENTIONALLY_UNMAPPED = new Set([
|
|
67
|
+
// e.g. 'SomeFutureType', // reason it's out of scope
|
|
68
|
+
]);
|
|
69
|
+
function roleFor(nodeType) {
|
|
70
|
+
// Unknown (future) types fall back to `container`; the coverage test + the
|
|
71
|
+
// version-pin comment are what keep the known union fully dispositioned.
|
|
72
|
+
return FORME_ROLE_BY_NODE_TYPE[nodeType] ?? 'container';
|
|
73
|
+
}
|
|
74
|
+
/** Explicit heading level from an `H1`..`H6` tag, else null (fall back to size). */
|
|
75
|
+
function explicitLevel(nodeType) {
|
|
76
|
+
const m = /^H([1-6])$/.exec(nodeType);
|
|
77
|
+
return m ? Number(m[1]) : null;
|
|
78
|
+
}
|
|
79
|
+
/** Text-leaf roles fold their subtree into one node (text comes from TextLines). */
|
|
80
|
+
function isTextLeaf(role) {
|
|
81
|
+
return role === 'heading' || role === 'text' || role === 'cell';
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Leaf roles don't recurse into children. Text leaves fold to collect text;
|
|
85
|
+
* `image` folds as an OPAQUE graphic (charts, barcodes, etc.) — its internal
|
|
86
|
+
* labels are deliberately not captured as structural text.
|
|
87
|
+
*/
|
|
88
|
+
function isLeaf(role) {
|
|
89
|
+
return isTextLeaf(role) || role === 'image';
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Authoritative, heuristic-free extraction from FormePDF layout metadata. Roles,
|
|
93
|
+
* heading levels, and the content box are explicit, so every node is emitted at
|
|
94
|
+
* confidence 1.0. This is the reliable path the whole product is validated on
|
|
95
|
+
* before the fragile pdfjs path is touched.
|
|
96
|
+
*/
|
|
97
|
+
export function fromFormeLayout(layout, opts) {
|
|
98
|
+
const rawPages = [];
|
|
99
|
+
const rawNodes = [];
|
|
100
|
+
let counter = 0;
|
|
101
|
+
const nextId = () => `f${counter++}`;
|
|
102
|
+
// Font sizes of headings that lack an explicit H-level, for cluster fallback.
|
|
103
|
+
const headingSizes = [];
|
|
104
|
+
for (const page of layout.pages) {
|
|
105
|
+
walk(page.elements, (el) => {
|
|
106
|
+
if (roleFor(el.nodeType) === 'heading' && explicitLevel(el.nodeType) == null && el.style?.fontSize) {
|
|
107
|
+
headingSizes.push(el.style.fontSize);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const levelFor = buildHeadingLevelMap(headingSizes);
|
|
112
|
+
layout.pages.forEach((page, pageIndex) => {
|
|
113
|
+
const contentBox = {
|
|
114
|
+
x: page.contentX,
|
|
115
|
+
y: page.contentY,
|
|
116
|
+
width: page.contentWidth,
|
|
117
|
+
height: page.contentHeight,
|
|
118
|
+
};
|
|
119
|
+
rawPages.push({ index: pageIndex, width: page.width, height: page.height, contentBox });
|
|
120
|
+
const emit = (el, parentTempId, parentBBox) => {
|
|
121
|
+
const role = roleFor(el.nodeType);
|
|
122
|
+
const tempId = nextId();
|
|
123
|
+
const bbox = { x: el.x, y: el.y, width: el.width, height: el.height };
|
|
124
|
+
let overflow = null;
|
|
125
|
+
if (role === 'text' || role === 'heading') {
|
|
126
|
+
overflow = computeOverflow(bbox, contentBox, 'page-content');
|
|
127
|
+
}
|
|
128
|
+
else if (role === 'cell' && parentBBox) {
|
|
129
|
+
overflow = computeOverflow(bbox, parentBBox, 'parent');
|
|
130
|
+
}
|
|
131
|
+
const node = {
|
|
132
|
+
tempId,
|
|
133
|
+
parentTempId,
|
|
134
|
+
role,
|
|
135
|
+
pageIndex,
|
|
136
|
+
bbox,
|
|
137
|
+
text: isTextLeaf(role) ? collectText(el) : null,
|
|
138
|
+
font: fontFrom(el.style),
|
|
139
|
+
headingLevel: role === 'heading' ? explicitLevel(el.nodeType) ?? levelFor(el.style?.fontSize ?? 0) : null,
|
|
140
|
+
overflow,
|
|
141
|
+
confidence: 1,
|
|
142
|
+
};
|
|
143
|
+
if (role === 'table')
|
|
144
|
+
node.table = tableShape(el.children ?? []);
|
|
145
|
+
rawNodes.push(node);
|
|
146
|
+
// Leaf roles fold their subtree: text leaves already collected their text;
|
|
147
|
+
// image leaves are opaque graphics. Tables mark their children as
|
|
148
|
+
// already-in-a-table so rows aren't re-synthesized.
|
|
149
|
+
if (!isLeaf(role)) {
|
|
150
|
+
processChildren(el.children ?? [], tempId, bbox, role === 'table');
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
// Iterate a sibling list, synthesizing a table node around any run of
|
|
154
|
+
// contiguous TableRows that aren't already inside a Table.
|
|
155
|
+
const processChildren = (children, parentTempId, parentBBox, parentIsTable) => {
|
|
156
|
+
let i = 0;
|
|
157
|
+
while (i < children.length) {
|
|
158
|
+
const el = children[i];
|
|
159
|
+
if (roleFor(el.nodeType) === 'row' && !parentIsTable) {
|
|
160
|
+
const run = [];
|
|
161
|
+
let j = i;
|
|
162
|
+
while (j < children.length && roleFor(children[j].nodeType) === 'row') {
|
|
163
|
+
run.push(children[j]);
|
|
164
|
+
j++;
|
|
165
|
+
}
|
|
166
|
+
const tableTempId = nextId();
|
|
167
|
+
const bbox = unionBBox(run);
|
|
168
|
+
rawNodes.push({
|
|
169
|
+
tempId: tableTempId,
|
|
170
|
+
parentTempId,
|
|
171
|
+
role: 'table',
|
|
172
|
+
pageIndex,
|
|
173
|
+
bbox,
|
|
174
|
+
text: null,
|
|
175
|
+
font: null,
|
|
176
|
+
headingLevel: null,
|
|
177
|
+
overflow: null,
|
|
178
|
+
table: tableShape(run),
|
|
179
|
+
confidence: 1,
|
|
180
|
+
});
|
|
181
|
+
for (const row of run)
|
|
182
|
+
emit(row, tableTempId, bbox);
|
|
183
|
+
i = j;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
emit(el, parentTempId, parentBBox);
|
|
187
|
+
i++;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
processChildren(page.elements, null, null, false);
|
|
191
|
+
});
|
|
192
|
+
const snapshot = finalize('formepdf', rawPages, rawNodes, opts);
|
|
193
|
+
if (opts?.assertShape !== false)
|
|
194
|
+
assertShapeRecognized(layout, snapshot);
|
|
195
|
+
return snapshot;
|
|
196
|
+
}
|
|
197
|
+
/** Thrown when FormePDF's layout shape no longer matches what this extractor
|
|
198
|
+
* understands — a broken contract on the authoritative fast path, which must
|
|
199
|
+
* fail loudly rather than silently produce a wrong diff. */
|
|
200
|
+
export class FormeShapeError extends Error {
|
|
201
|
+
constructor(message) {
|
|
202
|
+
super(message);
|
|
203
|
+
this.name = 'FormeShapeError';
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Guard against silent misclassification when FormePDF's runtime layout shape
|
|
208
|
+
* drifts (as it has before: `H1`..`H6`, `TextLine`, and the missing `Table`
|
|
209
|
+
* wrapper were all undocumented). Rather than allow-listing every nodeType
|
|
210
|
+
* (FormePDF emits many, and the set isn't fully documented — a strict list would
|
|
211
|
+
* false-throw on the next benign addition), assert the invariants this extractor
|
|
212
|
+
* depends on. Verified against @formepdf/core 0.12.0 runtime output (2026-08).
|
|
213
|
+
*/
|
|
214
|
+
function assertShapeRecognized(layout, snapshot) {
|
|
215
|
+
const fragments = [];
|
|
216
|
+
const nodeTypesSeen = new Set();
|
|
217
|
+
let hasRow = false;
|
|
218
|
+
let hasCell = false;
|
|
219
|
+
let hasHeading = false;
|
|
220
|
+
// Custom traversal (not `walk`) so we can STOP at image subtrees: charts and
|
|
221
|
+
// other graphics are deliberately opaque, so their internal label text is not
|
|
222
|
+
// expected to be captured and must not count as a dropped fragment.
|
|
223
|
+
const visit = (el) => {
|
|
224
|
+
nodeTypesSeen.add(el.nodeType);
|
|
225
|
+
const role = roleFor(el.nodeType);
|
|
226
|
+
if (role === 'row')
|
|
227
|
+
hasRow = true;
|
|
228
|
+
if (role === 'cell')
|
|
229
|
+
hasCell = true;
|
|
230
|
+
if (role === 'heading')
|
|
231
|
+
hasHeading = true;
|
|
232
|
+
if (role === 'image')
|
|
233
|
+
return; // opaque graphic — do not descend or expect its text
|
|
234
|
+
if (typeof el.textContent === 'string') {
|
|
235
|
+
const t = el.textContent.replace(/\s+/g, ' ').trim().toLowerCase();
|
|
236
|
+
if (t)
|
|
237
|
+
fragments.push(t);
|
|
238
|
+
}
|
|
239
|
+
for (const child of el.children ?? [])
|
|
240
|
+
visit(child);
|
|
241
|
+
};
|
|
242
|
+
for (const page of layout.pages)
|
|
243
|
+
for (const el of page.elements)
|
|
244
|
+
visit(el);
|
|
245
|
+
const context = `Seen FormePDF nodeTypes: [${[...nodeTypesSeen].sort().join(', ')}].`;
|
|
246
|
+
// 1. Every text fragment in the layout must be captured somewhere. Aggregate
|
|
247
|
+
// (not per-node) so legitimately empty cells/blocks never false-trip.
|
|
248
|
+
if (fragments.length > 0) {
|
|
249
|
+
const haystack = snapshot.nodes.map((n) => n.normText ?? '').join('');
|
|
250
|
+
const missing = fragments.filter((f) => !haystack.includes(f));
|
|
251
|
+
if (missing.length > 0) {
|
|
252
|
+
throw new FormeShapeError(`fromFormeLayout dropped ${missing.length}/${fragments.length} text fragment(s) from the ` +
|
|
253
|
+
`FormePDF layout (e.g. ${JSON.stringify(missing.slice(0, 3))}). The layout node shape has ` +
|
|
254
|
+
`likely changed; the nodeType→role mapping needs updating. ${context}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// 2. Text/table carriers present in the layout must produce their roles.
|
|
258
|
+
const produced = new Set(snapshot.nodes.map((n) => n.role));
|
|
259
|
+
if (hasRow && !produced.has('row')) {
|
|
260
|
+
throw new FormeShapeError(`Layout has TableRow nodes but none were extracted as rows. ${context}`);
|
|
261
|
+
}
|
|
262
|
+
if (hasCell && !produced.has('cell')) {
|
|
263
|
+
throw new FormeShapeError(`Layout has TableCell nodes but none were extracted as cells. ${context}`);
|
|
264
|
+
}
|
|
265
|
+
if (hasHeading && !produced.has('heading')) {
|
|
266
|
+
throw new FormeShapeError(`Layout has H1–H6/Heading nodes but none were extracted as headings. ${context}`);
|
|
267
|
+
}
|
|
268
|
+
// 3. Table synthesis sanity: a table with zero rows is malformed.
|
|
269
|
+
for (const node of snapshot.nodes) {
|
|
270
|
+
if (node.role === 'table' && node.table && node.table.rows === 0) {
|
|
271
|
+
throw new FormeShapeError(`Synthesized a table with zero rows — row grouping is broken. ${context}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/** Gather text from a node's subtree (TextLine carries it), collapsing space. */
|
|
276
|
+
function collectText(el) {
|
|
277
|
+
const parts = [];
|
|
278
|
+
const rec = (n) => {
|
|
279
|
+
if (typeof n.textContent === 'string' && n.textContent.length)
|
|
280
|
+
parts.push(n.textContent);
|
|
281
|
+
for (const c of n.children ?? [])
|
|
282
|
+
rec(c);
|
|
283
|
+
};
|
|
284
|
+
rec(el);
|
|
285
|
+
const text = parts.join(' ').replace(/\s+/g, ' ').trim();
|
|
286
|
+
return text.length ? text : null;
|
|
287
|
+
}
|
|
288
|
+
function fontFrom(style) {
|
|
289
|
+
if (!style)
|
|
290
|
+
return null;
|
|
291
|
+
if (style.fontSize == null && style.fontWeight == null && style.fontFamily == null)
|
|
292
|
+
return null;
|
|
293
|
+
return {
|
|
294
|
+
size: style.fontSize ?? null,
|
|
295
|
+
weight: style.fontWeight ?? null,
|
|
296
|
+
family: style.fontFamily ?? null,
|
|
297
|
+
italic: style.fontStyle ? /italic|oblique/i.test(style.fontStyle) : undefined,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
/** rows = number of row children; cols = max cells across those rows. */
|
|
301
|
+
function tableShape(rows) {
|
|
302
|
+
const rowEls = rows.filter((c) => roleFor(c.nodeType) === 'row');
|
|
303
|
+
let cols = 0;
|
|
304
|
+
for (const row of rowEls) {
|
|
305
|
+
const cells = (row.children ?? []).filter((c) => roleFor(c.nodeType) === 'cell').length;
|
|
306
|
+
cols = Math.max(cols, cells);
|
|
307
|
+
}
|
|
308
|
+
return { rows: rowEls.length, cols };
|
|
309
|
+
}
|
|
310
|
+
function unionBBox(els) {
|
|
311
|
+
const minX = Math.min(...els.map((e) => e.x));
|
|
312
|
+
const maxX = Math.max(...els.map((e) => e.x + e.width));
|
|
313
|
+
const minY = Math.min(...els.map((e) => e.y));
|
|
314
|
+
const maxY = Math.max(...els.map((e) => e.y + e.height));
|
|
315
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
316
|
+
}
|
|
317
|
+
function walk(elements, fn) {
|
|
318
|
+
for (const el of elements) {
|
|
319
|
+
fn(el);
|
|
320
|
+
if (el.children?.length)
|
|
321
|
+
walk(el.children, fn);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
//# sourceMappingURL=fromFormeLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fromFormeLayout.js","sourceRoot":"","sources":["../../src/extract/fromFormeLayout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { StructuralSnapshot } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* General-producer extraction via pdfjs. Reliable for page-count, added/removed,
|
|
4
|
+
* moved-to-page, and heading hierarchy; best-effort (lower confidence) for table
|
|
5
|
+
* regions and overflow, since PDF carries neither a table nor a container concept.
|
|
6
|
+
* Everything converges through `finalize`, so the diff engine / matcher / CLI are
|
|
7
|
+
* identical to the FormePDF path.
|
|
8
|
+
*/
|
|
9
|
+
export declare function fromPdf(bytes: Uint8Array, opts?: {
|
|
10
|
+
source?: {
|
|
11
|
+
name?: string;
|
|
12
|
+
};
|
|
13
|
+
createdAt?: string;
|
|
14
|
+
}): Promise<StructuralSnapshot>;
|
|
15
|
+
//# sourceMappingURL=fromPdf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fromPdf.d.ts","sourceRoot":"","sources":["../../src/extract/fromPdf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAShE;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,UAAU,EACjB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACxD,OAAO,CAAC,kBAAkB,CAAC,CAoG7B"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { finalize } from './finalize.js';
|
|
2
|
+
import { loadDocument } from './pdfjs/loadDocument.js';
|
|
3
|
+
import { extractTextRuns } from './pdfjs/textRuns.js';
|
|
4
|
+
import { buildHeadingModel } from './pdfjs/headings.js';
|
|
5
|
+
import { detectTables } from './pdfjs/tables.js';
|
|
6
|
+
import { buildOverflowModel, inferContentBox } from './pdfjs/overflow.js';
|
|
7
|
+
/**
|
|
8
|
+
* General-producer extraction via pdfjs. Reliable for page-count, added/removed,
|
|
9
|
+
* moved-to-page, and heading hierarchy; best-effort (lower confidence) for table
|
|
10
|
+
* regions and overflow, since PDF carries neither a table nor a container concept.
|
|
11
|
+
* Everything converges through `finalize`, so the diff engine / matcher / CLI are
|
|
12
|
+
* identical to the FormePDF path.
|
|
13
|
+
*/
|
|
14
|
+
export async function fromPdf(bytes, opts) {
|
|
15
|
+
const doc = await loadDocument(bytes);
|
|
16
|
+
const perPage = [];
|
|
17
|
+
for (let i = 1; i <= doc.numPages; i++) {
|
|
18
|
+
const page = await doc.getPage(i);
|
|
19
|
+
perPage.push(await extractTextRuns(page));
|
|
20
|
+
}
|
|
21
|
+
// Heading model is doc-wide so levels are consistent across pages.
|
|
22
|
+
const headingModel = buildHeadingModel(perPage.flatMap((p) => p.runs));
|
|
23
|
+
const rawPages = [];
|
|
24
|
+
const rawNodes = [];
|
|
25
|
+
let counter = 0;
|
|
26
|
+
const nextId = () => `p${counter++}`;
|
|
27
|
+
perPage.forEach((pg, pageIndex) => {
|
|
28
|
+
rawPages.push({
|
|
29
|
+
index: pageIndex,
|
|
30
|
+
width: pg.width,
|
|
31
|
+
height: pg.height,
|
|
32
|
+
contentBox: inferContentBox(pg.runs, pg.width, pg.height),
|
|
33
|
+
});
|
|
34
|
+
const overflowOf = buildOverflowModel(pg.runs, pg.width);
|
|
35
|
+
const tables = detectTables(pg.runs);
|
|
36
|
+
const consumed = new Set();
|
|
37
|
+
for (const table of tables) {
|
|
38
|
+
const tableTempId = nextId();
|
|
39
|
+
rawNodes.push({
|
|
40
|
+
tempId: tableTempId,
|
|
41
|
+
parentTempId: null,
|
|
42
|
+
role: 'table',
|
|
43
|
+
pageIndex,
|
|
44
|
+
bbox: table.bbox,
|
|
45
|
+
text: null,
|
|
46
|
+
font: null,
|
|
47
|
+
headingLevel: null,
|
|
48
|
+
overflow: null,
|
|
49
|
+
table: { rows: table.rows.length, cols: table.cols },
|
|
50
|
+
confidence: 0.5,
|
|
51
|
+
});
|
|
52
|
+
for (const row of table.rows) {
|
|
53
|
+
const rowTempId = nextId();
|
|
54
|
+
rawNodes.push({
|
|
55
|
+
tempId: rowTempId,
|
|
56
|
+
parentTempId: tableTempId,
|
|
57
|
+
role: 'row',
|
|
58
|
+
pageIndex,
|
|
59
|
+
bbox: row.bbox,
|
|
60
|
+
text: null,
|
|
61
|
+
font: null,
|
|
62
|
+
headingLevel: null,
|
|
63
|
+
overflow: null,
|
|
64
|
+
confidence: 0.5,
|
|
65
|
+
});
|
|
66
|
+
for (const cell of row.cells) {
|
|
67
|
+
for (const r of cell.runs)
|
|
68
|
+
consumed.add(r);
|
|
69
|
+
rawNodes.push({
|
|
70
|
+
tempId: nextId(),
|
|
71
|
+
parentTempId: rowTempId,
|
|
72
|
+
role: 'cell',
|
|
73
|
+
pageIndex,
|
|
74
|
+
bbox: cell.bbox,
|
|
75
|
+
text: cell.text,
|
|
76
|
+
font: fontOf(cell.runs),
|
|
77
|
+
headingLevel: null,
|
|
78
|
+
overflow: null,
|
|
79
|
+
confidence: 0.5,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
for (const r of pg.runs) {
|
|
85
|
+
if (consumed.has(r))
|
|
86
|
+
continue;
|
|
87
|
+
const heading = headingModel.isHeading(r);
|
|
88
|
+
rawNodes.push({
|
|
89
|
+
tempId: nextId(),
|
|
90
|
+
parentTempId: null,
|
|
91
|
+
role: heading ? 'heading' : 'text',
|
|
92
|
+
pageIndex,
|
|
93
|
+
bbox: { x: r.x, y: r.y, width: r.width, height: r.height },
|
|
94
|
+
text: r.text,
|
|
95
|
+
font: {
|
|
96
|
+
size: r.fontSize,
|
|
97
|
+
weight: r.bold ? 700 : 400,
|
|
98
|
+
family: r.fontName || null,
|
|
99
|
+
italic: r.italic,
|
|
100
|
+
},
|
|
101
|
+
headingLevel: heading ? headingModel.levelOf(r) : null,
|
|
102
|
+
overflow: overflowOf(r),
|
|
103
|
+
confidence: heading ? headingModel.confidenceOf(r) : 0.9,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
return finalize('pdfjs', rawPages, rawNodes, opts);
|
|
108
|
+
}
|
|
109
|
+
function fontOf(runs) {
|
|
110
|
+
if (runs.length === 0)
|
|
111
|
+
return null;
|
|
112
|
+
const dominant = [...runs].sort((a, b) => b.charCount - a.charCount)[0];
|
|
113
|
+
return {
|
|
114
|
+
size: dominant.fontSize,
|
|
115
|
+
weight: dominant.bold ? 700 : 400,
|
|
116
|
+
family: dominant.fontName || null,
|
|
117
|
+
italic: dominant.italic,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=fromPdf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fromPdf.js","sourceRoot":"","sources":["../../src/extract/fromPdf.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAmB,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE1E;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,KAAiB,EACjB,IAAyD;IAEzD,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;IAEtC,MAAM,OAAO,GAA4D,EAAE,CAAC;IAC5E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,mEAAmE;IACnE,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAEvE,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,MAAM,GAAG,GAAW,EAAE,CAAC,IAAI,OAAO,EAAE,EAAE,CAAC;IAE7C,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE;QAChC,QAAQ,CAAC,IAAI,CAAC;YACZ,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,UAAU,EAAE,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC;SAC1D,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAc,CAAC;QAEvC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CAAC;gBACZ,MAAM,EAAE,WAAW;gBACnB,YAAY,EAAE,IAAI;gBAClB,IAAI,EAAE,OAAO;gBACb,SAAS;gBACT,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,IAAI;gBACV,YAAY,EAAE,IAAI;gBAClB,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;gBACpD,UAAU,EAAE,GAAG;aAChB,CAAC,CAAC;YACH,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBAC7B,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC;gBAC3B,QAAQ,CAAC,IAAI,CAAC;oBACZ,MAAM,EAAE,SAAS;oBACjB,YAAY,EAAE,WAAW;oBACzB,IAAI,EAAE,KAAK;oBACX,SAAS;oBACT,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,IAAI,EAAE,IAAI;oBACV,IAAI,EAAE,IAAI;oBACV,YAAY,EAAE,IAAI;oBAClB,QAAQ,EAAE,IAAI;oBACd,UAAU,EAAE,GAAG;iBAChB,CAAC,CAAC;gBACH,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;oBAC7B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI;wBAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC3C,QAAQ,CAAC,IAAI,CAAC;wBACZ,MAAM,EAAE,MAAM,EAAE;wBAChB,YAAY,EAAE,SAAS;wBACvB,IAAI,EAAE,MAAM;wBACZ,SAAS;wBACT,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;wBACvB,YAAY,EAAE,IAAI;wBAClB,QAAQ,EAAE,IAAI;wBACd,UAAU,EAAE,GAAG;qBAChB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,SAAS;YAC9B,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC;gBACZ,MAAM,EAAE,MAAM,EAAE;gBAChB,YAAY,EAAE,IAAI;gBAClB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;gBAClC,SAAS;gBACT,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;gBAC1D,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE;oBACJ,IAAI,EAAE,CAAC,CAAC,QAAQ;oBAChB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;oBAC1B,MAAM,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;oBAC1B,MAAM,EAAE,CAAC,CAAC,MAAM;iBACjB;gBACD,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;gBACtD,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;gBACvB,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;aACzD,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,MAAM,CAAC,IAAkB;IAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAe,CAAC;IACtF,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,QAAQ;QACvB,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;QACjC,MAAM,EAAE,QAAQ,CAAC,QAAQ,IAAI,IAAI;QACjC,MAAM,EAAE,QAAQ,CAAC,MAAM;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PdfTextRun } from './textRuns.js';
|
|
2
|
+
export interface HeadingModel {
|
|
3
|
+
bodySize: number;
|
|
4
|
+
isHeading(run: PdfTextRun): boolean;
|
|
5
|
+
levelOf(run: PdfTextRun): number;
|
|
6
|
+
confidenceOf(run: PdfTextRun): number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Infer heading levels for raw pdfjs runs by font-size clustering. The
|
|
10
|
+
* char-count-weighted modal size is the body baseline; runs meaningfully larger
|
|
11
|
+
* (or bold and slightly larger) are headings, ranked into H1..H6. Confidence is
|
|
12
|
+
* 0.8 when a run is size-separated, 0.5 when only weight-distinguished — lower
|
|
13
|
+
* than the FormePDF path, which knows heading roles outright.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildHeadingModel(runs: PdfTextRun[]): HeadingModel;
|
|
16
|
+
//# sourceMappingURL=headings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headings.d.ts","sourceRoot":"","sources":["../../../src/extract/pdfjs/headings.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC;IACpC,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAAC;IACjC,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAAC;CACvC;AAKD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,YAAY,CA6BlE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { round1 } from '../../geometry.js';
|
|
2
|
+
import { buildHeadingLevelMap } from '../../text/headingLevels.js';
|
|
3
|
+
const HEADING_RATIO = 1.15;
|
|
4
|
+
const BOLD_RATIO = 1.05;
|
|
5
|
+
/**
|
|
6
|
+
* Infer heading levels for raw pdfjs runs by font-size clustering. The
|
|
7
|
+
* char-count-weighted modal size is the body baseline; runs meaningfully larger
|
|
8
|
+
* (or bold and slightly larger) are headings, ranked into H1..H6. Confidence is
|
|
9
|
+
* 0.8 when a run is size-separated, 0.5 when only weight-distinguished — lower
|
|
10
|
+
* than the FormePDF path, which knows heading roles outright.
|
|
11
|
+
*/
|
|
12
|
+
export function buildHeadingModel(runs) {
|
|
13
|
+
const weightBySize = new Map();
|
|
14
|
+
for (const r of runs) {
|
|
15
|
+
const s = round1(r.fontSize);
|
|
16
|
+
weightBySize.set(s, (weightBySize.get(s) ?? 0) + r.charCount);
|
|
17
|
+
}
|
|
18
|
+
let bodySize = 0;
|
|
19
|
+
let bestWeight = -1;
|
|
20
|
+
for (const [size, w] of weightBySize) {
|
|
21
|
+
if (w > bestWeight) {
|
|
22
|
+
bestWeight = w;
|
|
23
|
+
bodySize = size;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const candidateSizes = [
|
|
27
|
+
...new Set(runs.filter((r) => r.fontSize > bodySize * HEADING_RATIO).map((r) => round1(r.fontSize))),
|
|
28
|
+
];
|
|
29
|
+
const levelFor = buildHeadingLevelMap(candidateSizes);
|
|
30
|
+
const sizeSeparated = (r) => r.fontSize > bodySize * HEADING_RATIO;
|
|
31
|
+
const boldSeparated = (r) => r.bold && r.fontSize >= bodySize * BOLD_RATIO;
|
|
32
|
+
return {
|
|
33
|
+
bodySize,
|
|
34
|
+
isHeading: (r) => sizeSeparated(r) || boldSeparated(r),
|
|
35
|
+
levelOf: (r) => (sizeSeparated(r) ? levelFor(round1(r.fontSize)) : 6),
|
|
36
|
+
confidenceOf: (r) => (sizeSeparated(r) ? 0.8 : 0.5),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=headings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headings.js","sourceRoot":"","sources":["../../../src/extract/pdfjs/headings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAUnE,MAAM,aAAa,GAAG,IAAI,CAAC;AAC3B,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAkB;IAClD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC7B,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC;IACpB,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,YAAY,EAAE,CAAC;QACrC,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC;YACnB,UAAU,GAAG,CAAC,CAAC;YACf,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IAED,MAAM,cAAc,GAAG;QACrB,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;KACrG,CAAC;IACF,MAAM,QAAQ,GAAG,oBAAoB,CAAC,cAAc,CAAC,CAAC;IAEtD,MAAM,aAAa,GAAG,CAAC,CAAa,EAAW,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;IACxF,MAAM,aAAa,GAAG,CAAC,CAAa,EAAW,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,IAAI,QAAQ,GAAG,UAAU,CAAC;IAEhG,OAAO;QACL,QAAQ;QACR,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;QACtD,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrE,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;KACpD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single most fragile integration point in the codebase: loading pdfjs in a
|
|
3
|
+
* Node context without a worker or DOM. Kept deliberately small and isolated so
|
|
4
|
+
* the rest of the extractor never touches pdfjs internals. `pdfjs-dist` is an
|
|
5
|
+
* optional peer dep, loaded lazily via a non-literal specifier so consumers that
|
|
6
|
+
* only diff FormePDF `LayoutInfo` never need it installed.
|
|
7
|
+
*/
|
|
8
|
+
export interface LoadedPdfPage {
|
|
9
|
+
getViewport(opts: {
|
|
10
|
+
scale: number;
|
|
11
|
+
}): {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
};
|
|
15
|
+
getTextContent(): Promise<{
|
|
16
|
+
items: PdfTextItem[];
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export interface PdfTextItem {
|
|
20
|
+
str: string;
|
|
21
|
+
transform: number[];
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
fontName?: string;
|
|
25
|
+
hasEOL?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface LoadedPdf {
|
|
28
|
+
numPages: number;
|
|
29
|
+
getPage(pageNumber: number): Promise<LoadedPdfPage>;
|
|
30
|
+
}
|
|
31
|
+
export declare function loadDocument(data: Uint8Array): Promise<LoadedPdf>;
|
|
32
|
+
//# sourceMappingURL=loadDocument.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadDocument.d.ts","sourceRoot":"","sources":["../../../src/extract/pdfjs/loadDocument.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2BH,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,cAAc,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACrD;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAevE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single most fragile integration point in the codebase: loading pdfjs in a
|
|
3
|
+
* Node context without a worker or DOM. Kept deliberately small and isolated so
|
|
4
|
+
* the rest of the extractor never touches pdfjs internals. `pdfjs-dist` is an
|
|
5
|
+
* optional peer dep, loaded lazily via a non-literal specifier so consumers that
|
|
6
|
+
* only diff FormePDF `LayoutInfo` never need it installed.
|
|
7
|
+
*/
|
|
8
|
+
let cached;
|
|
9
|
+
async function getPdfjs() {
|
|
10
|
+
if (cached)
|
|
11
|
+
return cached;
|
|
12
|
+
const candidates = ['pdfjs-dist/legacy/build/pdf.mjs', 'pdfjs-dist'];
|
|
13
|
+
let lastErr;
|
|
14
|
+
for (const spec of candidates) {
|
|
15
|
+
try {
|
|
16
|
+
// Non-literal specifier: keeps TS from statically resolving an optional dep.
|
|
17
|
+
const mod = (await import(/* @vite-ignore */ spec));
|
|
18
|
+
cached = mod.getDocument ? mod : mod.default;
|
|
19
|
+
if (cached?.getDocument)
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
lastErr = err;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
throw new Error('pdf-testkit: could not load "pdfjs-dist". Install it to diff non-FormePDF PDFs ' +
|
|
27
|
+
`(npm i pdfjs-dist). Original error: ${String(lastErr)}`);
|
|
28
|
+
}
|
|
29
|
+
export async function loadDocument(data) {
|
|
30
|
+
const pdfjs = await getPdfjs();
|
|
31
|
+
// In Node, the legacy build runs on the main thread via a built-in fake
|
|
32
|
+
// worker when workerSrc is left unset — so we deliberately don't touch
|
|
33
|
+
// GlobalWorkerOptions here (setting it to undefined fails pdfjs's validation).
|
|
34
|
+
const task = pdfjs.getDocument({
|
|
35
|
+
// pdfjs transfers (detaches) the `data` buffer to its worker; copy so the
|
|
36
|
+
// caller's Uint8Array stays usable and re-extraction never crashes.
|
|
37
|
+
data: data.slice(),
|
|
38
|
+
isEvalSupported: false,
|
|
39
|
+
disableFontFace: true,
|
|
40
|
+
useSystemFonts: false,
|
|
41
|
+
verbosity: 0, // errors only
|
|
42
|
+
});
|
|
43
|
+
return (await task.promise);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=loadDocument.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadDocument.js","sourceRoot":"","sources":["../../../src/extract/pdfjs/loadDocument.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,IAAI,MAA4B,CAAC;AAEjC,KAAK,UAAU,QAAQ;IACrB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,UAAU,GAAG,CAAC,iCAAiC,EAAE,YAAY,CAAC,CAAC;IACrE,IAAI,OAAgB,CAAC;IACrB,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,6EAA6E;YAC7E,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAa,CAAC;YAChE,MAAM,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;YAC7C,IAAI,MAAM,EAAE,WAAW;gBAAE,OAAO,MAAM,CAAC;QACzC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,GAAG,GAAG,CAAC;QAChB,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CACb,iFAAiF;QAC/E,uCAAuC,MAAM,CAAC,OAAO,CAAC,EAAE,CAC3D,CAAC;AACJ,CAAC;AAqBD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAgB;IACjD,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC/B,wEAAwE;IACxE,uEAAuE;IACvE,+EAA+E;IAC/E,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC;QAC7B,0EAA0E;QAC1E,oEAAoE;QACpE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;QAClB,eAAe,EAAE,KAAK;QACtB,eAAe,EAAE,IAAI;QACrB,cAAc,EAAE,KAAK;QACrB,SAAS,EAAE,CAAC,EAAE,cAAc;KAC7B,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAc,CAAC;AAC3C,CAAC"}
|