js.documents 14.4.56 → 14.4.57
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/codecs/read.cjs +2 -2
- package/dist/codecs/read.js +1 -1
- package/dist/composition-plan-CfvhXeOC.cjs +627 -0
- package/dist/composition-plan-DU9nPPN7.d.cts +102 -0
- package/dist/composition-plan-f0zaExUW.js +508 -0
- package/dist/composition-plan-l6QPO4FX.d.ts +102 -0
- package/dist/convert/composition-plan.cjs +7 -0
- package/dist/convert/composition-plan.d.cts +2 -0
- package/dist/convert/composition-plan.d.ts +2 -0
- package/dist/convert/composition-plan.js +2 -0
- package/dist/convert/composition-to-pdf.cjs +12 -12
- package/dist/convert/composition-to-pdf.d.cts +1 -1
- package/dist/convert/composition-to-pdf.d.ts +1 -1
- package/dist/convert/composition-to-pdf.js +2 -2
- package/dist/convert/composition.cjs +16 -511
- package/dist/convert/composition.d.cts +2 -85
- package/dist/convert/composition.d.ts +2 -85
- package/dist/convert/composition.js +2 -502
- package/dist/convert/convert.cjs +2 -2
- package/dist/convert/convert.js +1 -1
- package/dist/convert/from-package.cjs +3 -3
- package/dist/convert/from-package.js +2 -2
- package/dist/convert/from-pdf.cjs +18 -18
- package/dist/convert/from-pdf.js +2 -2
- package/dist/convert/local.cjs +3 -3
- package/dist/convert/local.js +1 -1
- package/dist/edit/odp/slide.cjs +4 -4
- package/dist/edit/odp/slide.d.cts +1 -1
- package/dist/edit/odp/slide.d.ts +1 -1
- package/dist/edit/odp/slide.js +1 -1
- package/dist/edit/odt/content.d.cts +1 -1
- package/dist/edit/odt/content.d.ts +1 -1
- package/dist/edit/odt/editor.cjs +4 -4
- package/dist/edit/odt/editor.d.cts +1 -1
- package/dist/edit/odt/editor.d.ts +1 -1
- package/dist/edit/odt/editor.js +1 -1
- package/dist/edit/odt/table-grid.cjs +23 -0
- package/dist/edit/odt/table-grid.d.cts +54 -0
- package/dist/edit/odt/table-grid.d.ts +54 -0
- package/dist/edit/odt/table-grid.js +2 -0
- package/dist/edit/odt/table.cjs +12 -653
- package/dist/edit/odt/table.d.cts +2 -2
- package/dist/edit/odt/table.d.ts +2 -2
- package/dist/edit/odt/table.js +2 -647
- package/dist/{evaluate-BbOsgdmN.d.cts → evaluate-BSEUxiUK.d.cts} +3 -1
- package/dist/evaluate-CEzsBx3w.cjs +564 -0
- package/dist/{evaluate-C7fmk69X.d.ts → evaluate-D8fG2ZeB.d.ts} +3 -1
- package/dist/evaluate-IK-3aMv5.js +445 -0
- package/dist/evaluate-columns-CyqKHkIW.d.cts +41 -0
- package/dist/evaluate-columns-cOo8fOfT.d.ts +41 -0
- package/dist/index.cjs +24 -24
- package/dist/index.d.cts +6 -5
- package/dist/index.d.ts +6 -5
- package/dist/index.js +8 -8
- package/dist/latex/lint.cjs +2 -2
- package/dist/latex/lint.js +1 -1
- package/dist/latex/lower-fold.cjs +6 -0
- package/dist/latex/lower-fold.d.cts +17 -0
- package/dist/latex/lower-fold.d.ts +17 -0
- package/dist/latex/lower-fold.js +2 -0
- package/dist/latex/lower.cjs +11 -617
- package/dist/latex/lower.d.cts +18 -1
- package/dist/latex/lower.d.ts +18 -1
- package/dist/latex/lower.js +2 -616
- package/dist/latex/symbols.d.cts +1 -15
- package/dist/latex/symbols.d.ts +1 -15
- package/dist/latex/temml.d.cts +1 -24
- package/dist/latex/temml.d.ts +1 -24
- package/dist/layout/engine.cjs +2 -2
- package/dist/layout/engine.js +1 -1
- package/dist/layout/reconstruct-lines.cjs +315 -0
- package/dist/layout/reconstruct-lines.d.cts +2 -0
- package/dist/layout/reconstruct-lines.d.ts +2 -0
- package/dist/layout/reconstruct-lines.js +297 -0
- package/dist/layout/reconstruct-presentations-prod.cjs +9 -0
- package/dist/layout/reconstruct-presentations-prod.d.cts +26 -0
- package/dist/layout/reconstruct-presentations-prod.d.ts +26 -0
- package/dist/layout/reconstruct-presentations-prod.js +2 -0
- package/dist/layout/reconstruct-tables.cjs +5 -0
- package/dist/layout/reconstruct-tables.d.cts +22 -0
- package/dist/layout/reconstruct-tables.d.ts +22 -0
- package/dist/layout/reconstruct-tables.js +2 -0
- package/dist/layout/reconstruct.cjs +11 -1545
- package/dist/layout/reconstruct.d.cts +2 -14
- package/dist/layout/reconstruct.d.ts +2 -14
- package/dist/layout/reconstruct.js +2 -1542
- package/dist/layout/shared.cjs +2 -2
- package/dist/layout/shared.js +1 -1
- package/dist/layout/sheets-render.cjs +19 -0
- package/dist/layout/sheets-render.d.cts +41 -0
- package/dist/layout/sheets-render.d.ts +41 -0
- package/dist/layout/sheets-render.js +2 -0
- package/dist/layout/sheets.cjs +10 -544
- package/dist/layout/sheets.d.cts +13 -2
- package/dist/layout/sheets.d.ts +13 -2
- package/dist/layout/sheets.js +2 -543
- package/dist/layout/slides.cjs +2 -2
- package/dist/layout/slides.js +1 -1
- package/dist/layout-DIJzJk4x.js +526 -0
- package/dist/layout-iuiyl_Fk.cjs +621 -0
- package/dist/layout-types-oSbHvZid.d.cts +13 -0
- package/dist/layout-types-oSbHvZid.d.ts +13 -0
- package/dist/lower-DCs3rWI7.js +618 -0
- package/dist/lower-DzOb13w4.cjs +701 -0
- package/dist/markdown/math.cjs +2 -2
- package/dist/markdown/math.js +1 -1
- package/dist/mathml/layout-stretch.cjs +16 -0
- package/dist/mathml/layout-stretch.d.cts +24 -0
- package/dist/mathml/layout-stretch.d.ts +24 -0
- package/dist/mathml/layout-stretch.js +2 -0
- package/dist/mathml/layout-types.d.cts +1 -12
- package/dist/mathml/layout-types.d.ts +1 -12
- package/dist/mathml/layout.cjs +3 -525
- package/dist/mathml/layout.d.cts +2 -2
- package/dist/mathml/layout.d.ts +2 -2
- package/dist/mathml/layout.js +1 -523
- package/dist/odb/formula/evaluate.d.cts +1 -1
- package/dist/odb/formula/evaluate.d.ts +1 -1
- package/dist/odb/report/render.d.cts +1 -1
- package/dist/odb/report/render.d.ts +1 -1
- package/dist/odb/report/source.cjs +2 -2
- package/dist/odb/report/source.d.cts +1 -1
- package/dist/odb/report/source.d.ts +1 -1
- package/dist/odb/report/source.js +1 -1
- package/dist/odb/sql/evaluate-columns.cjs +122 -0
- package/dist/odb/sql/evaluate-columns.d.cts +2 -0
- package/dist/odb/sql/evaluate-columns.d.ts +2 -0
- package/dist/odb/sql/evaluate-columns.js +114 -0
- package/dist/odb/sql/evaluate-predicates.cjs +16 -0
- package/dist/odb/sql/evaluate-predicates.d.cts +23 -0
- package/dist/odb/sql/evaluate-predicates.d.ts +23 -0
- package/dist/odb/sql/evaluate-predicates.js +2 -0
- package/dist/odb/sql/evaluate.cjs +7 -556
- package/dist/odb/sql/evaluate.d.cts +2 -2
- package/dist/odb/sql/evaluate.d.ts +2 -2
- package/dist/odb/sql/evaluate.js +2 -552
- package/dist/read-BSH--XB4.js +682 -0
- package/dist/read-CahCZMwG.cjs +759 -0
- package/dist/reconstruct-BKOCAedo.d.ts +29 -0
- package/dist/reconstruct-D4TEteZ6.d.cts +29 -0
- package/dist/reconstruct-lines-B7t66ICm.d.cts +33 -0
- package/dist/reconstruct-lines-B7t66ICm.d.ts +33 -0
- package/dist/reconstruct-presentations-prod-B5fkPiRZ.js +1256 -0
- package/dist/reconstruct-presentations-prod-X315aBmI.cjs +1375 -0
- package/dist/sheets-BQCpNXsE.cjs +700 -0
- package/dist/sheets-DWDvGN-g.js +545 -0
- package/dist/svg/read-geometry.cjs +10 -0
- package/dist/svg/read-geometry.d.cts +24 -0
- package/dist/svg/read-geometry.d.ts +24 -0
- package/dist/svg/read-geometry.js +2 -0
- package/dist/svg/read.cjs +6 -680
- package/dist/svg/read.d.cts +17 -2
- package/dist/svg/read.d.ts +17 -2
- package/dist/svg/read.js +2 -679
- package/dist/symbols-BlzXfLEe.d.cts +16 -0
- package/dist/symbols-CKm2r4D0.d.ts +16 -0
- package/dist/table-B5gSMY7w.js +649 -0
- package/dist/{table-DrE6jEWv.d.cts → table-BK_Ao-Y6.d.cts} +9 -1
- package/dist/{table-B5htMG3g.d.ts → table-CxY85YUj.d.ts} +9 -1
- package/dist/table-DqUIOSPV.cjs +840 -0
- package/dist/temml-1-I9N9DD.d.cts +25 -0
- package/dist/temml-1-I9N9DD.d.ts +25 -0
- package/package.json +1 -1
|
@@ -1,1542 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { stampFrame } from "./shared.js";
|
|
4
|
-
import { inferCellValue } from "./cell-typing.js";
|
|
5
|
-
import { throwIfAborted } from "../ports/abort.js";
|
|
6
|
-
import { detectGridLattice, findColumnIndex, findRowIndex } from "./lattice.js";
|
|
7
|
-
import { denseTableRows } from "document-schema.js";
|
|
8
|
-
import { resolveStandardFont } from "pdf-codec/fonts";
|
|
9
|
-
import { STANDARD_METRICS } from "pdf-codec/afm-widths";
|
|
10
|
-
import { runGapPt, runsShareBaseline } from "pdf-codec/text-group";
|
|
11
|
-
//#region src/layout/reconstruct.ts
|
|
12
|
-
const DEFAULT_COLUMN_WIDTH_FALLBACK_PT = 40;
|
|
13
|
-
const NO_ITEMS = /* @__PURE__ */ new Set();
|
|
14
|
-
const LARGE_GAP_EM_MULTIPLIER = 2;
|
|
15
|
-
const ZERO_MARGINS = {
|
|
16
|
-
topPt: 0,
|
|
17
|
-
rightPt: 0,
|
|
18
|
-
bottomPt: 0,
|
|
19
|
-
leftPt: 0
|
|
20
|
-
};
|
|
21
|
-
const LINE_BASELINE_TOLERANCE_FACTOR = .5;
|
|
22
|
-
const AFM_UNITS_PER_EM = 1e3;
|
|
23
|
-
const HALF_POINT_BUCKET_PT = .5;
|
|
24
|
-
function sharesBaseline(anchor, item) {
|
|
25
|
-
return runsShareBaseline(anchor, item, { baselineToleranceEm: LINE_BASELINE_TOLERANCE_FACTOR });
|
|
26
|
-
}
|
|
27
|
-
const DUPLICATE_PAINT_BUCKET_PT = .1;
|
|
28
|
-
function duplicatePaintKey(item) {
|
|
29
|
-
const xBucket = Math.round(item.xPt / DUPLICATE_PAINT_BUCKET_PT);
|
|
30
|
-
const yBucket = Math.round(item.yPt / DUPLICATE_PAINT_BUCKET_PT);
|
|
31
|
-
return `${item.text.trim()}|${String(xBucket)}|${String(yBucket)}`;
|
|
32
|
-
}
|
|
33
|
-
function dropDuplicatePaints(items) {
|
|
34
|
-
const seen = /* @__PURE__ */ new Set();
|
|
35
|
-
const kept = [];
|
|
36
|
-
for (const item of items) {
|
|
37
|
-
const key = duplicatePaintKey(item);
|
|
38
|
-
if (seen.has(key)) continue;
|
|
39
|
-
seen.add(key);
|
|
40
|
-
kept.push(item);
|
|
41
|
-
}
|
|
42
|
-
return kept;
|
|
43
|
-
}
|
|
44
|
-
function dropOverlappingRepeatsWithinLine(items) {
|
|
45
|
-
const rightEdgeByText = /* @__PURE__ */ new Map();
|
|
46
|
-
const kept = [];
|
|
47
|
-
for (const item of items) {
|
|
48
|
-
const textKey = item.text.trim();
|
|
49
|
-
const priorRightEdge = rightEdgeByText.get(textKey);
|
|
50
|
-
if (priorRightEdge !== void 0 && item.xPt < priorRightEdge) continue;
|
|
51
|
-
rightEdgeByText.set(textKey, item.xPt + (item.widthPt ?? 0));
|
|
52
|
-
kept.push(item);
|
|
53
|
-
}
|
|
54
|
-
return kept;
|
|
55
|
-
}
|
|
56
|
-
const REDRAW_PASS_REWIND_TOLERANCE_PT = 2;
|
|
57
|
-
const MIN_REDRAW_PASS_TEXT_LENGTH = 12;
|
|
58
|
-
const REDRAW_PASS_SIMILARITY_THRESHOLD = .6;
|
|
59
|
-
function groupByBaselineInDocumentOrder(items) {
|
|
60
|
-
const groups = [];
|
|
61
|
-
for (const item of items) {
|
|
62
|
-
const group = groups.find((g) => sharesBaseline(g.anchor, item));
|
|
63
|
-
if (group === void 0) groups.push({
|
|
64
|
-
anchor: item,
|
|
65
|
-
items: [item]
|
|
66
|
-
});
|
|
67
|
-
else group.items.push(item);
|
|
68
|
-
}
|
|
69
|
-
return groups.map((g) => g.items);
|
|
70
|
-
}
|
|
71
|
-
function splitIntoPasses(group) {
|
|
72
|
-
const passes = [];
|
|
73
|
-
for (const item of group) {
|
|
74
|
-
const current = passes.at(-1);
|
|
75
|
-
const itemRightPt = item.xPt + (item.widthPt ?? 0);
|
|
76
|
-
if (current !== void 0 && item.xPt >= current.endXPt - REDRAW_PASS_REWIND_TOLERANCE_PT) {
|
|
77
|
-
current.items.push(item);
|
|
78
|
-
current.endXPt = Math.max(current.endXPt, itemRightPt);
|
|
79
|
-
} else passes.push({
|
|
80
|
-
items: [item],
|
|
81
|
-
startXPt: item.xPt,
|
|
82
|
-
endXPt: itemRightPt
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
return passes;
|
|
86
|
-
}
|
|
87
|
-
function passText(pass) {
|
|
88
|
-
return pass.items.map((item) => item.text).join("").trim();
|
|
89
|
-
}
|
|
90
|
-
function passesOverlap(a, b) {
|
|
91
|
-
return a.startXPt < b.endXPt && b.startXPt < a.endXPt;
|
|
92
|
-
}
|
|
93
|
-
function levenshteinDistance(a, b) {
|
|
94
|
-
const memo = /* @__PURE__ */ new Map();
|
|
95
|
-
function distance(i, j) {
|
|
96
|
-
if (i === 0) return j;
|
|
97
|
-
if (j === 0) return i;
|
|
98
|
-
const key = `${String(i)}:${String(j)}`;
|
|
99
|
-
const cached = memo.get(key);
|
|
100
|
-
if (cached !== void 0) return cached;
|
|
101
|
-
const cost = a.charAt(i - 1) === b.charAt(j - 1) ? 0 : 1;
|
|
102
|
-
const result = Math.min(distance(i - 1, j) + 1, distance(i, j - 1) + 1, distance(i - 1, j - 1) + cost);
|
|
103
|
-
memo.set(key, result);
|
|
104
|
-
return result;
|
|
105
|
-
}
|
|
106
|
-
return distance(a.length, b.length);
|
|
107
|
-
}
|
|
108
|
-
function textSimilarity(a, b) {
|
|
109
|
-
const maxLength = Math.max(a.length, b.length);
|
|
110
|
-
return 1 - levenshteinDistance(a, b) / maxLength;
|
|
111
|
-
}
|
|
112
|
-
function dropFuzzyRedrawnPasses(items) {
|
|
113
|
-
const toDrop = /* @__PURE__ */ new Set();
|
|
114
|
-
for (const group of groupByBaselineInDocumentOrder(items)) {
|
|
115
|
-
const passes = splitIntoPasses(group);
|
|
116
|
-
if (passes.length < 2) continue;
|
|
117
|
-
const [first, ...rest] = passes;
|
|
118
|
-
if (first === void 0) continue;
|
|
119
|
-
const firstText = passText(first);
|
|
120
|
-
if (firstText.length < MIN_REDRAW_PASS_TEXT_LENGTH) continue;
|
|
121
|
-
for (const candidate of rest) {
|
|
122
|
-
const candidateText = passText(candidate);
|
|
123
|
-
if (candidateText.length < MIN_REDRAW_PASS_TEXT_LENGTH) continue;
|
|
124
|
-
if (!passesOverlap(first, candidate)) continue;
|
|
125
|
-
if (textSimilarity(firstText, candidateText) < REDRAW_PASS_SIMILARITY_THRESHOLD) continue;
|
|
126
|
-
for (const item of candidate.items) toDrop.add(item);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
if (toDrop.size === 0) return items;
|
|
130
|
-
return items.filter((item) => !toDrop.has(item));
|
|
131
|
-
}
|
|
132
|
-
function clusterIntoLines(items) {
|
|
133
|
-
const sorted = [...dropDuplicatePaints(dropFuzzyRedrawnPasses(items))].sort((a, b) => b.yPt - a.yPt || a.xPt - b.xPt);
|
|
134
|
-
const working = [];
|
|
135
|
-
for (const item of sorted) {
|
|
136
|
-
const line = working.find((l) => sharesBaseline(l.anchor, item));
|
|
137
|
-
if (line === void 0) working.push({
|
|
138
|
-
items: [item],
|
|
139
|
-
baselineY: item.yPt,
|
|
140
|
-
anchor: item
|
|
141
|
-
});
|
|
142
|
-
else line.items.push(item);
|
|
143
|
-
}
|
|
144
|
-
for (const line of working) {
|
|
145
|
-
line.items.sort((a, b) => a.xPt - b.xPt);
|
|
146
|
-
line.items = dropOverlappingRepeatsWithinLine(line.items);
|
|
147
|
-
}
|
|
148
|
-
working.sort((a, b) => b.baselineY - a.baselineY);
|
|
149
|
-
return working;
|
|
150
|
-
}
|
|
151
|
-
function textItemVerticalExtent(item) {
|
|
152
|
-
const { standardName } = resolveStandardFont(item.font.family, item.font.weight === "bold", item.font.style === "italic");
|
|
153
|
-
const metrics = STANDARD_METRICS[standardName];
|
|
154
|
-
return {
|
|
155
|
-
ascentPt: metrics.ascender / AFM_UNITS_PER_EM * item.sizePt,
|
|
156
|
-
descentPt: Math.abs(metrics.descender) / AFM_UNITS_PER_EM * item.sizePt
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
function textItemToContentRun(item) {
|
|
160
|
-
return {
|
|
161
|
-
text: item.text,
|
|
162
|
-
...item.font.weight === "bold" ? { bold: true } : {},
|
|
163
|
-
...item.font.style === "italic" ? { italic: true } : {},
|
|
164
|
-
fontFamily: item.font.family,
|
|
165
|
-
sizePt: item.sizePt,
|
|
166
|
-
color: item.color
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
const MIN_WORD_GAP_PT = .5;
|
|
170
|
-
function gapExceeds(previous, next, thresholdPt) {
|
|
171
|
-
const gap = runGapPt(previous, next);
|
|
172
|
-
return gap !== void 0 && gap > thresholdPt;
|
|
173
|
-
}
|
|
174
|
-
function textBoxOfItem(item, pageIndex) {
|
|
175
|
-
const { ascentPt, descentPt } = textItemVerticalExtent(item);
|
|
176
|
-
return {
|
|
177
|
-
pageIndex,
|
|
178
|
-
xPt: item.xPt,
|
|
179
|
-
yPt: item.yPt - descentPt,
|
|
180
|
-
widthPt: item.widthPt ?? 0,
|
|
181
|
-
heightPt: ascentPt + descentPt
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
function lineBox(line, pageIndex) {
|
|
185
|
-
let minX = Number.POSITIVE_INFINITY;
|
|
186
|
-
let maxX = Number.NEGATIVE_INFINITY;
|
|
187
|
-
let minY = Number.POSITIVE_INFINITY;
|
|
188
|
-
let maxY = Number.NEGATIVE_INFINITY;
|
|
189
|
-
for (const item of line.items) {
|
|
190
|
-
const { ascentPt, descentPt } = textItemVerticalExtent(item);
|
|
191
|
-
minX = Math.min(minX, item.xPt);
|
|
192
|
-
maxX = Math.max(maxX, item.xPt + (item.widthPt ?? 0));
|
|
193
|
-
minY = Math.min(minY, item.yPt - descentPt);
|
|
194
|
-
maxY = Math.max(maxY, item.yPt + ascentPt);
|
|
195
|
-
}
|
|
196
|
-
return {
|
|
197
|
-
pageIndex,
|
|
198
|
-
xPt: minX,
|
|
199
|
-
yPt: minY,
|
|
200
|
-
widthPt: maxX - minX,
|
|
201
|
-
heightPt: maxY - minY
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
function pushRunsForLine(runs, line, pageIndex) {
|
|
205
|
-
line.items.forEach((item, itemIndex) => {
|
|
206
|
-
if (itemIndex > 0) {
|
|
207
|
-
const prevItem = line.items[itemIndex - 1];
|
|
208
|
-
if (gapExceeds(prevItem, item, LARGE_GAP_EM_MULTIPLIER * item.sizePt)) runs.push({ text: " " });
|
|
209
|
-
else if (gapExceeds(prevItem, item, MIN_WORD_GAP_PT)) runs[runs.length - 1].text += " ";
|
|
210
|
-
}
|
|
211
|
-
const run = textItemToContentRun(item);
|
|
212
|
-
stampFrame(run, pageIndex, textBoxOfItem(item, pageIndex));
|
|
213
|
-
runs.push(run);
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
function bucketCounts(values, bucketSize) {
|
|
217
|
-
const counts = /* @__PURE__ */ new Map();
|
|
218
|
-
for (const v of values) {
|
|
219
|
-
const bucket = Math.round(v / bucketSize) * bucketSize;
|
|
220
|
-
counts.set(bucket, (counts.get(bucket) ?? 0) + 1);
|
|
221
|
-
}
|
|
222
|
-
return counts;
|
|
223
|
-
}
|
|
224
|
-
function modeOf(values, bucketSize) {
|
|
225
|
-
if (values.length === 0) return 0;
|
|
226
|
-
const counts = bucketCounts(values, bucketSize);
|
|
227
|
-
let bestBucket = values[0];
|
|
228
|
-
let bestCount = 0;
|
|
229
|
-
for (const [bucket, count] of counts) if (count > bestCount) {
|
|
230
|
-
bestBucket = bucket;
|
|
231
|
-
bestCount = count;
|
|
232
|
-
}
|
|
233
|
-
return bestBucket;
|
|
234
|
-
}
|
|
235
|
-
function modalLineGap(gaps) {
|
|
236
|
-
const counts = bucketCounts(gaps, HALF_POINT_BUCKET_PT);
|
|
237
|
-
let bestBucket = gaps[0];
|
|
238
|
-
let bestCount = 0;
|
|
239
|
-
for (const [bucket, count] of counts) if (count > bestCount) {
|
|
240
|
-
bestBucket = bucket;
|
|
241
|
-
bestCount = count;
|
|
242
|
-
}
|
|
243
|
-
return bestCount > 1 ? bestBucket : Math.min(...gaps);
|
|
244
|
-
}
|
|
245
|
-
const PARAGRAPH_GAP_MULTIPLIER = 1.25;
|
|
246
|
-
const NOMINAL_LINE_SPACING_RATIO = 1.2;
|
|
247
|
-
const MIN_LINES_FOR_GAP_MODE = 3;
|
|
248
|
-
function estimateModalLineSpacing(lines) {
|
|
249
|
-
if (lines.length < MIN_LINES_FOR_GAP_MODE) return modeOf(lines.map((l) => l.items[0].sizePt), HALF_POINT_BUCKET_PT) * NOMINAL_LINE_SPACING_RATIO;
|
|
250
|
-
const gaps = [];
|
|
251
|
-
for (let i = 1; i < lines.length; i++) gaps.push(lines[i - 1].baselineY - lines[i].baselineY);
|
|
252
|
-
return modalLineGap(gaps);
|
|
253
|
-
}
|
|
254
|
-
function reconstructWordprocessing(doc, options) {
|
|
255
|
-
const signal = options?.signal;
|
|
256
|
-
doc = dropHiddenLayerContent(doc);
|
|
257
|
-
const headingLevels = headingSizeLevels(doc);
|
|
258
|
-
const structure = indexStructure(doc);
|
|
259
|
-
const sections = [];
|
|
260
|
-
let currentGroup = [];
|
|
261
|
-
let groupStartPageIndex = 0;
|
|
262
|
-
for (const page of doc.pages) {
|
|
263
|
-
throwIfAborted(signal);
|
|
264
|
-
if (currentGroup.length > 0 && !samePageSize(currentGroup[0], page)) {
|
|
265
|
-
sections.push(buildSection(currentGroup, groupStartPageIndex, doc.images, headingLevels, doc.form, structure));
|
|
266
|
-
groupStartPageIndex += currentGroup.length;
|
|
267
|
-
currentGroup = [];
|
|
268
|
-
}
|
|
269
|
-
currentGroup.push(page);
|
|
270
|
-
}
|
|
271
|
-
if (currentGroup.length > 0) sections.push(buildSection(currentGroup, groupStartPageIndex, doc.images, headingLevels, doc.form, structure));
|
|
272
|
-
return {
|
|
273
|
-
kind: "wordprocessing",
|
|
274
|
-
metadata: doc.metadata,
|
|
275
|
-
sections
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
function layerOf(item) {
|
|
279
|
-
return item.kind === "link" || item.kind === "internalLink" ? void 0 : item.layer;
|
|
280
|
-
}
|
|
281
|
-
function dropHiddenLayerContent(doc) {
|
|
282
|
-
const hidden = new Set((doc.layers ?? []).filter((layer) => !layer.visible).map((layer) => layer.name));
|
|
283
|
-
if (hidden.size === 0) return doc;
|
|
284
|
-
return {
|
|
285
|
-
...doc,
|
|
286
|
-
pages: doc.pages.map((page) => ({
|
|
287
|
-
...page,
|
|
288
|
-
items: page.items.filter((item) => layerOf(item) === void 0 || !hidden.has(layerOf(item)))
|
|
289
|
-
}))
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
const HEADING_LEVELS = new Map([
|
|
293
|
-
"H1",
|
|
294
|
-
"H2",
|
|
295
|
-
"H3",
|
|
296
|
-
"H4",
|
|
297
|
-
"H5",
|
|
298
|
-
"H6"
|
|
299
|
-
].map((tag, index) => [tag, index + 1]));
|
|
300
|
-
const DIVISION_TYPES = /* @__PURE__ */ new Set([
|
|
301
|
-
"Part",
|
|
302
|
-
"Sect",
|
|
303
|
-
"Div"
|
|
304
|
-
]);
|
|
305
|
-
const CELL_TYPES = /* @__PURE__ */ new Set(["TD", "TH"]);
|
|
306
|
-
const ROW_TYPES = /* @__PURE__ */ new Set(["TR"]);
|
|
307
|
-
const TABLE_TYPES = /* @__PURE__ */ new Set(["Table"]);
|
|
308
|
-
function indexStructure(doc) {
|
|
309
|
-
if (doc.structure === void 0 || doc.structure.length === 0) return;
|
|
310
|
-
const byId = /* @__PURE__ */ new Map();
|
|
311
|
-
let order = 0;
|
|
312
|
-
const walk = (element, parent) => {
|
|
313
|
-
const node = {
|
|
314
|
-
id: element.id,
|
|
315
|
-
type: element.type,
|
|
316
|
-
parent,
|
|
317
|
-
order: order++
|
|
318
|
-
};
|
|
319
|
-
byId.set(element.id, node);
|
|
320
|
-
for (const child of element.children) walk(child, node);
|
|
321
|
-
};
|
|
322
|
-
for (const root of doc.structure) walk(root, void 0);
|
|
323
|
-
return { nodeOfItem: (item) => item.kind === "link" || item.kind === "internalLink" ? void 0 : byId.get(item.structure ?? "") };
|
|
324
|
-
}
|
|
325
|
-
function nearestOfType(node, types) {
|
|
326
|
-
for (let current = node; current !== void 0; current = current.parent) if (types.has(current.type)) return current;
|
|
327
|
-
}
|
|
328
|
-
function nearestHeadingLevel(node) {
|
|
329
|
-
for (let current = node; current !== void 0; current = current.parent) {
|
|
330
|
-
const level = HEADING_LEVELS.get(current.type);
|
|
331
|
-
if (level !== void 0) return level;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
function structureHeadingLevel(items, structure) {
|
|
335
|
-
if (items.length === 0 || items.some((item) => structure.nodeOfItem(item) === void 0)) return;
|
|
336
|
-
let level;
|
|
337
|
-
for (const item of items) {
|
|
338
|
-
const itemLevel = nearestHeadingLevel(structure.nodeOfItem(item));
|
|
339
|
-
if (itemLevel === void 0) return { level: void 0 };
|
|
340
|
-
if (level === void 0) level = itemLevel;
|
|
341
|
-
else if (level !== itemLevel) return;
|
|
342
|
-
}
|
|
343
|
-
return { level };
|
|
344
|
-
}
|
|
345
|
-
const HEADING_MIN_SIZE_DELTA_PT = 2;
|
|
346
|
-
const MAX_HEADING_LEVEL = 6;
|
|
347
|
-
function hasVisibleText(text) {
|
|
348
|
-
return text.trim().length > 0;
|
|
349
|
-
}
|
|
350
|
-
function headingSizeLevels(doc) {
|
|
351
|
-
const sizes = [];
|
|
352
|
-
for (const page of doc.pages) for (const item of page.items) if (item.kind === "text" && hasVisibleText(item.text)) sizes.push(item.sizePt);
|
|
353
|
-
if (sizes.length === 0) return /* @__PURE__ */ new Map();
|
|
354
|
-
const bodySizePt = modeOf(sizes, HALF_POINT_BUCKET_PT);
|
|
355
|
-
const headingBuckets = /* @__PURE__ */ new Set();
|
|
356
|
-
for (const size of sizes) {
|
|
357
|
-
const bucket = Math.round(size / HALF_POINT_BUCKET_PT) * HALF_POINT_BUCKET_PT;
|
|
358
|
-
if (bucket - bodySizePt >= HEADING_MIN_SIZE_DELTA_PT) headingBuckets.add(bucket);
|
|
359
|
-
}
|
|
360
|
-
const levels = /* @__PURE__ */ new Map();
|
|
361
|
-
[...headingBuckets].sort((a, b) => b - a).forEach((bucket, index) => {
|
|
362
|
-
levels.set(bucket, Math.min(index + 1, MAX_HEADING_LEVEL));
|
|
363
|
-
});
|
|
364
|
-
return levels;
|
|
365
|
-
}
|
|
366
|
-
function headingLevelOf(paragraph, levels) {
|
|
367
|
-
return levels.get(modeOf(paragraph.lines.flatMap((line) => line.items).filter((item) => hasVisibleText(item.text)).map((item) => item.sizePt), HALF_POINT_BUCKET_PT));
|
|
368
|
-
}
|
|
369
|
-
function samePageSize(a, b) {
|
|
370
|
-
return a.widthPt === b.widthPt && a.heightPt === b.heightPt;
|
|
371
|
-
}
|
|
372
|
-
function buildSection(pages, startPageIndex, images, headingLevels, form, structure) {
|
|
373
|
-
const blocks = [];
|
|
374
|
-
const divisionByBlock = /* @__PURE__ */ new WeakMap();
|
|
375
|
-
pages.forEach((page, i) => {
|
|
376
|
-
if (i > 0) blocks.push({ kind: "pageBreak" });
|
|
377
|
-
blocks.push(...reconstructPageBlocks(page, startPageIndex + i, images, headingLevels, form, structure, divisionByBlock));
|
|
378
|
-
});
|
|
379
|
-
return {
|
|
380
|
-
pageSize: {
|
|
381
|
-
widthPt: pages[0].widthPt,
|
|
382
|
-
heightPt: pages[0].heightPt
|
|
383
|
-
},
|
|
384
|
-
margins: ZERO_MARGINS,
|
|
385
|
-
blocks: wrapDivisionExtents(blocks, divisionByBlock)
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
function reconstructPageBlocks(page, pageIndex, images, headingLevels, form, structure, divisionByBlock) {
|
|
389
|
-
const recoveredTables = recoverTables(page, pageIndex, structure);
|
|
390
|
-
const consumedText = /* @__PURE__ */ new Set();
|
|
391
|
-
const claimedItems = /* @__PURE__ */ new Set();
|
|
392
|
-
for (const recovered of recoveredTables) {
|
|
393
|
-
for (const item of recovered.consumedText) consumedText.add(item);
|
|
394
|
-
for (const item of recovered.latticeItems) claimedItems.add(item);
|
|
395
|
-
}
|
|
396
|
-
const textItems = page.items.filter((i) => i.kind === "text" && !consumedText.has(i));
|
|
397
|
-
const imageItems = page.items.filter((i) => i.kind === "image");
|
|
398
|
-
const paragraphs = clusterIntoParagraphs(clusterIntoLines(textItems));
|
|
399
|
-
const recordDivisions = (block, items) => {
|
|
400
|
-
if (structure !== void 0) divisionByBlock.set(block, divisionChainOf(items, structure));
|
|
401
|
-
};
|
|
402
|
-
const positioned = [];
|
|
403
|
-
for (const paragraph of paragraphs) {
|
|
404
|
-
const paragraphItems = paragraph.lines.flatMap((line) => line.items);
|
|
405
|
-
const structural = structure === void 0 ? void 0 : structureHeadingLevel(paragraphItems, structure);
|
|
406
|
-
const block = paragraphToContentParagraph(paragraph, pageIndex, structural !== void 0 ? structural.level : headingLevelOf(paragraph, headingLevels));
|
|
407
|
-
recordDivisions(block, paragraphItems);
|
|
408
|
-
positioned.push({
|
|
409
|
-
yPt: paragraph.lines[0].baselineY,
|
|
410
|
-
block
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
for (const img of imageItems) {
|
|
414
|
-
const asset = images[img.imageId];
|
|
415
|
-
if (asset !== void 0) {
|
|
416
|
-
const block = {
|
|
417
|
-
kind: "image",
|
|
418
|
-
format: asset.format,
|
|
419
|
-
base64: asset.base64,
|
|
420
|
-
widthPt: img.widthPt,
|
|
421
|
-
heightPt: img.heightPt
|
|
422
|
-
};
|
|
423
|
-
stampFrame(block, pageIndex, {
|
|
424
|
-
xPt: img.xPt,
|
|
425
|
-
yPt: img.yPt,
|
|
426
|
-
widthPt: img.widthPt,
|
|
427
|
-
heightPt: img.heightPt
|
|
428
|
-
});
|
|
429
|
-
recordDivisions(block, [img]);
|
|
430
|
-
positioned.push({
|
|
431
|
-
yPt: img.yPt,
|
|
432
|
-
block
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
for (const recovered of recoveredTables) {
|
|
437
|
-
recordDivisions(recovered.table, [...recovered.consumedText]);
|
|
438
|
-
positioned.push({
|
|
439
|
-
yPt: recovered.topYPt,
|
|
440
|
-
block: recovered.table
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
const recoveredVectors = recoverPageVectors(page, pageIndex, claimedItems);
|
|
444
|
-
if (recoveredVectors !== void 0) {
|
|
445
|
-
const vectorItems = page.items.filter((item) => !claimedItems.has(item) && layoutItemToVector(item, page.heightPt) !== void 0);
|
|
446
|
-
recordDivisions(recoveredVectors.block, vectorItems);
|
|
447
|
-
positioned.push({
|
|
448
|
-
yPt: recoveredVectors.topYPt,
|
|
449
|
-
block: recoveredVectors.block
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
positioned.sort((a, b) => b.yPt - a.yPt);
|
|
453
|
-
const blocks = positioned.map((p) => p.block);
|
|
454
|
-
reconcileLinks(blocks, page, pageIndex);
|
|
455
|
-
appendAnnotationConstructs(blocks, page, pageIndex);
|
|
456
|
-
appendFormFieldConstructs(blocks, form, pageIndex);
|
|
457
|
-
return blocks;
|
|
458
|
-
}
|
|
459
|
-
function divisionChainOf(items, structure) {
|
|
460
|
-
let prefix;
|
|
461
|
-
for (const item of items) {
|
|
462
|
-
const chain = [];
|
|
463
|
-
for (let current = structure.nodeOfItem(item); current !== void 0; current = current.parent) if (DIVISION_TYPES.has(current.type)) chain.push(current.id);
|
|
464
|
-
chain.reverse();
|
|
465
|
-
if (prefix === void 0) {
|
|
466
|
-
prefix = chain;
|
|
467
|
-
continue;
|
|
468
|
-
}
|
|
469
|
-
let shared = 0;
|
|
470
|
-
while (shared < prefix.length && shared < chain.length && prefix[shared] === chain[shared]) shared += 1;
|
|
471
|
-
prefix = prefix.slice(0, shared);
|
|
472
|
-
}
|
|
473
|
-
return prefix ?? [];
|
|
474
|
-
}
|
|
475
|
-
function wrapDivisionExtents(blocks, divisionByBlock) {
|
|
476
|
-
const out = [];
|
|
477
|
-
const open = [];
|
|
478
|
-
for (const block of blocks) {
|
|
479
|
-
const chain = divisionByBlock.get(block);
|
|
480
|
-
if (chain !== void 0) {
|
|
481
|
-
while (open.length > 0 && !chain.includes(open[open.length - 1])) {
|
|
482
|
-
out.push({ kind: "constructEnd" });
|
|
483
|
-
open.pop();
|
|
484
|
-
}
|
|
485
|
-
for (const id of chain) {
|
|
486
|
-
if (open.includes(id)) continue;
|
|
487
|
-
out.push({
|
|
488
|
-
kind: "constructStart",
|
|
489
|
-
descriptor: { kind: "division" }
|
|
490
|
-
});
|
|
491
|
-
open.push(id);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
out.push(block);
|
|
495
|
-
}
|
|
496
|
-
while (open.length > 0) {
|
|
497
|
-
out.push({ kind: "constructEnd" });
|
|
498
|
-
open.pop();
|
|
499
|
-
}
|
|
500
|
-
return out;
|
|
501
|
-
}
|
|
502
|
-
function framesIntersect(a, b) {
|
|
503
|
-
return a.xPt < b.xPt + b.widthPt && b.xPt < a.xPt + a.widthPt && a.yPt < b.yPt + b.heightPt && b.yPt < a.yPt + a.heightPt;
|
|
504
|
-
}
|
|
505
|
-
function intersectionArea(a, b) {
|
|
506
|
-
const width = Math.min(a.xPt + a.widthPt, b.xPt + b.widthPt) - Math.max(a.xPt, b.xPt);
|
|
507
|
-
const height = Math.min(a.yPt + a.heightPt, b.yPt + b.heightPt) - Math.max(a.yPt, b.yPt);
|
|
508
|
-
return width > 0 && height > 0 ? width * height : 0;
|
|
509
|
-
}
|
|
510
|
-
function reconcileLinks(blocks, page, pageIndex) {
|
|
511
|
-
for (const item of page.items) {
|
|
512
|
-
if (item.kind !== "link" && item.kind !== "internalLink") continue;
|
|
513
|
-
if (item.kind === "link") {
|
|
514
|
-
let matchedRun = false;
|
|
515
|
-
for (const block of blocks) {
|
|
516
|
-
if (block.kind !== "paragraph") continue;
|
|
517
|
-
for (const run of block.runs) if ((run.frames ?? []).some((frame) => frame.pageIndex === pageIndex && framesIntersect(item, frame))) {
|
|
518
|
-
run.hyperlink = item.uri;
|
|
519
|
-
matchedRun = true;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
if (matchedRun) continue;
|
|
523
|
-
}
|
|
524
|
-
wrapBestBlock(blocks, item, pageIndex, linkDescriptor(item));
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
function linkDescriptor(item) {
|
|
528
|
-
if (item.kind === "link") return {
|
|
529
|
-
kind: "link",
|
|
530
|
-
target: {
|
|
531
|
-
kind: "external",
|
|
532
|
-
uri: item.uri
|
|
533
|
-
},
|
|
534
|
-
...item.title !== void 0 ? { title: item.title } : {}
|
|
535
|
-
};
|
|
536
|
-
return {
|
|
537
|
-
kind: "link",
|
|
538
|
-
target: {
|
|
539
|
-
kind: "internal",
|
|
540
|
-
anchor: item.destination
|
|
541
|
-
},
|
|
542
|
-
...item.title !== void 0 ? { title: item.title } : {}
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
function blockFramesOn(block, pageIndex) {
|
|
546
|
-
return block.kind === "constructStart" || block.kind === "constructEnd" ? [] : (block.frames ?? []).filter((frame) => frame.pageIndex === pageIndex);
|
|
547
|
-
}
|
|
548
|
-
function wrapBestBlock(blocks, rect, pageIndex, descriptor) {
|
|
549
|
-
let bestIndex = -1;
|
|
550
|
-
let bestArea = 0;
|
|
551
|
-
blocks.forEach((block, index) => {
|
|
552
|
-
const area = blockFramesOn(block, pageIndex).reduce((sum, frame) => sum + intersectionArea(rect, frame), 0);
|
|
553
|
-
if (area > bestArea) {
|
|
554
|
-
bestArea = area;
|
|
555
|
-
bestIndex = index;
|
|
556
|
-
}
|
|
557
|
-
});
|
|
558
|
-
const start = {
|
|
559
|
-
kind: "constructStart",
|
|
560
|
-
descriptor
|
|
561
|
-
};
|
|
562
|
-
const end = { kind: "constructEnd" };
|
|
563
|
-
if (bestIndex >= 0) {
|
|
564
|
-
blocks.splice(bestIndex, 0, start);
|
|
565
|
-
blocks.splice(bestIndex + 2, 0, end);
|
|
566
|
-
} else blocks.push(start, end);
|
|
567
|
-
}
|
|
568
|
-
function appendAnnotationConstructs(blocks, page, pageIndex) {
|
|
569
|
-
(page.annotations ?? []).forEach((annotation, annotIndex) => {
|
|
570
|
-
const key = `pdf-annot-${String(pageIndex)}-${String(annotIndex)}`;
|
|
571
|
-
blocks.push({
|
|
572
|
-
kind: "constructStart",
|
|
573
|
-
descriptor: {
|
|
574
|
-
kind: "anchor",
|
|
575
|
-
anchorType: "comment",
|
|
576
|
-
name: key,
|
|
577
|
-
definition: key,
|
|
578
|
-
...annotation.source !== void 0 ? { source: annotation.source } : {}
|
|
579
|
-
}
|
|
580
|
-
}, { kind: "constructEnd" });
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
function controlTypeOf(field) {
|
|
584
|
-
if (field.fieldType === "text") return "plainText";
|
|
585
|
-
if (field.fieldType === "button") return "button";
|
|
586
|
-
if (field.fieldType === "combobox") return "comboBox";
|
|
587
|
-
if (field.fieldType === "listbox") return "dropDown";
|
|
588
|
-
return "checkbox";
|
|
589
|
-
}
|
|
590
|
-
function appendFormFieldConstructs(blocks, form, pageIndex) {
|
|
591
|
-
const visit = (fields) => {
|
|
592
|
-
for (const field of fields) {
|
|
593
|
-
visit(field.children);
|
|
594
|
-
if (field.fieldType === "group" || field.fieldType === "signature") continue;
|
|
595
|
-
for (const widget of field.widgets) {
|
|
596
|
-
if (widget.pageIndex !== pageIndex) continue;
|
|
597
|
-
wrapBestBlock(blocks, widget, pageIndex, {
|
|
598
|
-
kind: "contentControl",
|
|
599
|
-
controlType: controlTypeOf(field),
|
|
600
|
-
tag: field.name,
|
|
601
|
-
...field.alias !== void 0 ? { alias: field.alias } : {},
|
|
602
|
-
...field.readOnly === true ? { lock: "content" } : {},
|
|
603
|
-
...field.value !== void 0 ? { value: field.value } : {},
|
|
604
|
-
...field.checked !== void 0 ? { checked: field.checked } : {},
|
|
605
|
-
...field.options !== void 0 ? { options: [...field.options] } : {}
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
|
-
visit(form ?? []);
|
|
611
|
-
}
|
|
612
|
-
function clusterIntoParagraphs(lines) {
|
|
613
|
-
if (lines.length === 0) return [];
|
|
614
|
-
const modalSpacing = estimateModalLineSpacing(lines);
|
|
615
|
-
const dominantLeftX = modeOf(lines.map((l) => l.items[0].xPt), 1);
|
|
616
|
-
const paragraphs = [{ lines: [lines[0]] }];
|
|
617
|
-
for (let i = 1; i < lines.length; i++) {
|
|
618
|
-
const prev = lines[i - 1];
|
|
619
|
-
const next = lines[i];
|
|
620
|
-
if (startsNewParagraph(prev, next, modalSpacing, dominantLeftX)) paragraphs.push({ lines: [next] });
|
|
621
|
-
else paragraphs[paragraphs.length - 1].lines.push(next);
|
|
622
|
-
}
|
|
623
|
-
return paragraphs;
|
|
624
|
-
}
|
|
625
|
-
function startsNewParagraph(prev, next, modalSpacing, dominantLeftX) {
|
|
626
|
-
if (prev.baselineY - next.baselineY > PARAGRAPH_GAP_MULTIPLIER * modalSpacing) return true;
|
|
627
|
-
if (!fontSizesClose(prev.items[0].sizePt, next.items[0].sizePt)) return true;
|
|
628
|
-
const nextLeft = next.items[0].xPt;
|
|
629
|
-
const prevLeft = prev.items[0].xPt;
|
|
630
|
-
const emPt = next.items[0].sizePt;
|
|
631
|
-
const nextIndented = Math.abs(nextLeft - dominantLeftX) > emPt;
|
|
632
|
-
const prevAtMargin = Math.abs(prevLeft - dominantLeftX) <= emPt;
|
|
633
|
-
return nextIndented && prevAtMargin;
|
|
634
|
-
}
|
|
635
|
-
const LEFT_ALIGN_TOLERANCE_PT = 2;
|
|
636
|
-
function paragraphToContentParagraph(paragraph, pageIndex, headingLevel) {
|
|
637
|
-
const dominantLeftX = modeOf(paragraph.lines.map((l) => l.items[0].xPt), 1);
|
|
638
|
-
const result = {
|
|
639
|
-
kind: "paragraph",
|
|
640
|
-
runs: [],
|
|
641
|
-
alignment: paragraph.lines.every((l) => Math.abs(l.items[0].xPt - dominantLeftX) <= LEFT_ALIGN_TOLERANCE_PT) ? "left" : void 0,
|
|
642
|
-
...headingLevel !== void 0 ? {
|
|
643
|
-
styleId: `Heading${String(headingLevel)}`,
|
|
644
|
-
headingLevel
|
|
645
|
-
} : {}
|
|
646
|
-
};
|
|
647
|
-
paragraph.lines.forEach((line, lineIndex) => {
|
|
648
|
-
stampFrame(result, pageIndex, lineBox(line, pageIndex));
|
|
649
|
-
if (lineIndex > 0) {
|
|
650
|
-
const lastRun = result.runs[result.runs.length - 1];
|
|
651
|
-
if (lastRun !== void 0) lastRun.text += " ";
|
|
652
|
-
}
|
|
653
|
-
pushRunsForLine(result.runs, line, pageIndex);
|
|
654
|
-
});
|
|
655
|
-
if (headingLevel !== void 0) result.runs = result.runs.map((run) => {
|
|
656
|
-
if (run.bold !== true) return run;
|
|
657
|
-
const withoutBold = { ...run };
|
|
658
|
-
delete withoutBold.bold;
|
|
659
|
-
return withoutBold;
|
|
660
|
-
});
|
|
661
|
-
return result;
|
|
662
|
-
}
|
|
663
|
-
function reconstructPresentation(doc, options) {
|
|
664
|
-
const signal = options?.signal;
|
|
665
|
-
const structure = indexStructure(doc);
|
|
666
|
-
const slides = doc.pages.map((page, pageIndex) => {
|
|
667
|
-
throwIfAborted(signal);
|
|
668
|
-
return reconstructSlide(page, pageIndex, doc.images, structure);
|
|
669
|
-
});
|
|
670
|
-
return {
|
|
671
|
-
kind: "presentation",
|
|
672
|
-
metadata: doc.metadata,
|
|
673
|
-
slides
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
function reconstructSlide(page, pageIndex, images, structure) {
|
|
677
|
-
const recoveredTables = recoverTables(page, pageIndex, structure);
|
|
678
|
-
const consumedText = /* @__PURE__ */ new Set();
|
|
679
|
-
const claimedItems = /* @__PURE__ */ new Set();
|
|
680
|
-
for (const recovered of recoveredTables) {
|
|
681
|
-
for (const item of recovered.consumedText) consumedText.add(item);
|
|
682
|
-
for (const item of recovered.latticeItems) claimedItems.add(item);
|
|
683
|
-
}
|
|
684
|
-
const textItems = page.items.filter((i) => i.kind === "text" && !consumedText.has(i));
|
|
685
|
-
const imageItems = page.items.filter((i) => i.kind === "image");
|
|
686
|
-
const textShapes = clusterIntoBlocks(clusterIntoLines(textItems)).map((block) => blockToShape(block, page.heightPt, pageIndex));
|
|
687
|
-
const imageShapes = [];
|
|
688
|
-
for (const img of imageItems) {
|
|
689
|
-
const shape = imageToShape(img, page.heightPt, pageIndex, images);
|
|
690
|
-
if (shape !== void 0) imageShapes.push(shape);
|
|
691
|
-
}
|
|
692
|
-
const recoveredVectors = recoverPageVectors(page, pageIndex, claimedItems);
|
|
693
|
-
const vectorShapes = recoveredVectors === void 0 ? [] : [wrapBlockInShape(recoveredVectors.block, {
|
|
694
|
-
xPt: 0,
|
|
695
|
-
yPt: 0,
|
|
696
|
-
widthPt: page.widthPt,
|
|
697
|
-
heightPt: page.heightPt
|
|
698
|
-
}, page.heightPt, pageIndex)];
|
|
699
|
-
const tableShapes = recoveredTables.map((recovered) => wrapBlockInShape(recovered.table, recovered.frame, page.heightPt, pageIndex));
|
|
700
|
-
return {
|
|
701
|
-
size: {
|
|
702
|
-
widthPt: page.widthPt,
|
|
703
|
-
heightPt: page.heightPt
|
|
704
|
-
},
|
|
705
|
-
shapes: [
|
|
706
|
-
...vectorShapes,
|
|
707
|
-
...imageShapes,
|
|
708
|
-
...tableShapes,
|
|
709
|
-
...textShapes
|
|
710
|
-
],
|
|
711
|
-
notes: page.notes ?? ""
|
|
712
|
-
};
|
|
713
|
-
}
|
|
714
|
-
function wrapBlockInShape(block, frame, pageHeightPt, pageIndex) {
|
|
715
|
-
const shape = {
|
|
716
|
-
frame,
|
|
717
|
-
insetLeftPt: 0,
|
|
718
|
-
insetTopPt: 0,
|
|
719
|
-
insetRightPt: 0,
|
|
720
|
-
insetBottomPt: 0,
|
|
721
|
-
blocks: [block]
|
|
722
|
-
};
|
|
723
|
-
stampFrame(shape, pageIndex, flipY(frame, pageHeightPt));
|
|
724
|
-
return shape;
|
|
725
|
-
}
|
|
726
|
-
function splitLineByLargeGaps(line) {
|
|
727
|
-
const segments = [];
|
|
728
|
-
let current = [];
|
|
729
|
-
line.items.forEach((item, i) => {
|
|
730
|
-
if (i > 0) {
|
|
731
|
-
const prev = line.items[i - 1];
|
|
732
|
-
if (gapExceeds(prev, item, LARGE_GAP_EM_MULTIPLIER * item.sizePt)) {
|
|
733
|
-
segments.push({
|
|
734
|
-
items: current,
|
|
735
|
-
baselineY: line.baselineY
|
|
736
|
-
});
|
|
737
|
-
current = [];
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
current.push(item);
|
|
741
|
-
});
|
|
742
|
-
if (current.length > 0) segments.push({
|
|
743
|
-
items: current,
|
|
744
|
-
baselineY: line.baselineY
|
|
745
|
-
});
|
|
746
|
-
return segments;
|
|
747
|
-
}
|
|
748
|
-
const FONT_SIZE_CLOSE_TOLERANCE_PT = 1;
|
|
749
|
-
const FONT_SIZE_CLOSE_TOLERANCE_RATIO = .15;
|
|
750
|
-
function fontSizesClose(a, b) {
|
|
751
|
-
return Math.abs(a - b) <= FONT_SIZE_CLOSE_TOLERANCE_PT || Math.abs(a - b) / Math.max(a, b) <= FONT_SIZE_CLOSE_TOLERANCE_RATIO;
|
|
752
|
-
}
|
|
753
|
-
function clusterIntoBlocks(pageLines) {
|
|
754
|
-
const segments = pageLines.flatMap(splitLineByLargeGaps);
|
|
755
|
-
const blocks = [];
|
|
756
|
-
for (const segment of segments) {
|
|
757
|
-
const leftX = segment.items[0].xPt;
|
|
758
|
-
const sizePt = segment.items[0].sizePt;
|
|
759
|
-
const matched = blocks.find((block) => {
|
|
760
|
-
const lastLine = block.lines[block.lines.length - 1];
|
|
761
|
-
const lastLeftX = lastLine.items[0].xPt;
|
|
762
|
-
const lastSizePt = lastLine.items[0].sizePt;
|
|
763
|
-
const gap = lastLine.baselineY - segment.baselineY;
|
|
764
|
-
if (gap <= 0) return false;
|
|
765
|
-
return Math.abs(leftX - lastLeftX) <= LEFT_ALIGN_TOLERANCE_PT && fontSizesClose(sizePt, lastSizePt) && gap <= PARAGRAPH_GAP_MULTIPLIER * lastSizePt;
|
|
766
|
-
});
|
|
767
|
-
if (matched !== void 0) matched.lines.push(segment);
|
|
768
|
-
else blocks.push({ lines: [segment] });
|
|
769
|
-
}
|
|
770
|
-
return blocks;
|
|
771
|
-
}
|
|
772
|
-
function computeBlockFrame(block, slideHeightPt) {
|
|
773
|
-
let minX = Number.POSITIVE_INFINITY;
|
|
774
|
-
let maxX = Number.NEGATIVE_INFINITY;
|
|
775
|
-
let minY = Number.POSITIVE_INFINITY;
|
|
776
|
-
let maxY = Number.NEGATIVE_INFINITY;
|
|
777
|
-
for (const line of block.lines) for (const item of line.items) {
|
|
778
|
-
const { ascentPt, descentPt } = textItemVerticalExtent(item);
|
|
779
|
-
minX = Math.min(minX, item.xPt);
|
|
780
|
-
maxX = Math.max(maxX, item.xPt + (item.widthPt ?? 0));
|
|
781
|
-
minY = Math.min(minY, item.yPt - descentPt);
|
|
782
|
-
maxY = Math.max(maxY, item.yPt + ascentPt);
|
|
783
|
-
}
|
|
784
|
-
return flipY({
|
|
785
|
-
xPt: minX,
|
|
786
|
-
yPt: minY,
|
|
787
|
-
widthPt: maxX - minX,
|
|
788
|
-
heightPt: maxY - minY
|
|
789
|
-
}, slideHeightPt);
|
|
790
|
-
}
|
|
791
|
-
function lineToParagraph(line, pageIndex) {
|
|
792
|
-
const paragraph = {
|
|
793
|
-
kind: "paragraph",
|
|
794
|
-
runs: []
|
|
795
|
-
};
|
|
796
|
-
stampFrame(paragraph, pageIndex, lineBox(line, pageIndex));
|
|
797
|
-
pushRunsForLine(paragraph.runs, line, pageIndex);
|
|
798
|
-
return paragraph;
|
|
799
|
-
}
|
|
800
|
-
function blockToShape(block, slideHeightPt, pageIndex) {
|
|
801
|
-
const shape = {
|
|
802
|
-
frame: computeBlockFrame(block, slideHeightPt),
|
|
803
|
-
insetLeftPt: 0,
|
|
804
|
-
insetTopPt: 0,
|
|
805
|
-
insetRightPt: 0,
|
|
806
|
-
insetBottomPt: 0,
|
|
807
|
-
blocks: block.lines.map((line) => lineToParagraph(line, pageIndex))
|
|
808
|
-
};
|
|
809
|
-
stampFrame(shape, pageIndex, flipY(shape.frame, slideHeightPt));
|
|
810
|
-
return shape;
|
|
811
|
-
}
|
|
812
|
-
function imageToShape(img, slideHeightPt, pageIndex, images) {
|
|
813
|
-
const asset = images[img.imageId];
|
|
814
|
-
if (asset === void 0) return;
|
|
815
|
-
const frame = flipY({
|
|
816
|
-
xPt: img.xPt,
|
|
817
|
-
yPt: img.yPt,
|
|
818
|
-
widthPt: img.widthPt,
|
|
819
|
-
heightPt: img.heightPt
|
|
820
|
-
}, slideHeightPt);
|
|
821
|
-
const block = {
|
|
822
|
-
kind: "image",
|
|
823
|
-
format: asset.format,
|
|
824
|
-
base64: asset.base64,
|
|
825
|
-
widthPt: img.widthPt,
|
|
826
|
-
heightPt: img.heightPt
|
|
827
|
-
};
|
|
828
|
-
stampFrame(block, pageIndex, {
|
|
829
|
-
xPt: img.xPt,
|
|
830
|
-
yPt: img.yPt,
|
|
831
|
-
widthPt: img.widthPt,
|
|
832
|
-
heightPt: img.heightPt
|
|
833
|
-
});
|
|
834
|
-
const shape = {
|
|
835
|
-
frame,
|
|
836
|
-
rotationDeg: img.rotationDeg !== void 0 ? -img.rotationDeg : void 0,
|
|
837
|
-
insetLeftPt: 0,
|
|
838
|
-
insetTopPt: 0,
|
|
839
|
-
insetRightPt: 0,
|
|
840
|
-
insetBottomPt: 0,
|
|
841
|
-
blocks: [block]
|
|
842
|
-
};
|
|
843
|
-
stampFrame(shape, pageIndex, {
|
|
844
|
-
xPt: img.xPt,
|
|
845
|
-
yPt: img.yPt,
|
|
846
|
-
widthPt: img.widthPt,
|
|
847
|
-
heightPt: img.heightPt
|
|
848
|
-
});
|
|
849
|
-
return shape;
|
|
850
|
-
}
|
|
851
|
-
function reconstructDrawing(doc, options) {
|
|
852
|
-
const signal = options?.signal;
|
|
853
|
-
const pages = doc.pages.map((page, pageIndex) => {
|
|
854
|
-
throwIfAborted(signal);
|
|
855
|
-
return reconstructDrawPage(page, pageIndex, doc.images);
|
|
856
|
-
});
|
|
857
|
-
return {
|
|
858
|
-
kind: "drawing",
|
|
859
|
-
metadata: doc.metadata,
|
|
860
|
-
pages
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
function reconstructDrawPage(page, pageIndex, images) {
|
|
864
|
-
const vectors = [];
|
|
865
|
-
const shapes = [];
|
|
866
|
-
let paintOrder = 0;
|
|
867
|
-
for (const item of page.items) {
|
|
868
|
-
const vector = layoutItemToVector(item, page.heightPt);
|
|
869
|
-
if (vector !== void 0) {
|
|
870
|
-
stampVectorFrame(vector, item, pageIndex);
|
|
871
|
-
vectors.push({
|
|
872
|
-
...vector,
|
|
873
|
-
paintOrder: paintOrder++
|
|
874
|
-
});
|
|
875
|
-
continue;
|
|
876
|
-
}
|
|
877
|
-
if (item.kind === "text") {
|
|
878
|
-
const shape = layoutTextToShape(item, page.heightPt, pageIndex);
|
|
879
|
-
stampFrame(shape, pageIndex, flipY(shape.frame, page.heightPt));
|
|
880
|
-
shapes.push({
|
|
881
|
-
...shape,
|
|
882
|
-
paintOrder: paintOrder++
|
|
883
|
-
});
|
|
884
|
-
} else if (item.kind === "image") {
|
|
885
|
-
const shape = imageToShape(item, page.heightPt, pageIndex, images);
|
|
886
|
-
if (shape !== void 0) shapes.push({
|
|
887
|
-
...shape,
|
|
888
|
-
paintOrder: paintOrder++
|
|
889
|
-
});
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
return {
|
|
893
|
-
size: {
|
|
894
|
-
widthPt: page.widthPt,
|
|
895
|
-
heightPt: page.heightPt
|
|
896
|
-
},
|
|
897
|
-
shapes,
|
|
898
|
-
vectors
|
|
899
|
-
};
|
|
900
|
-
}
|
|
901
|
-
function stampVectorFrame(vector, item, pageIndex) {
|
|
902
|
-
if (item.kind === "rect" || item.kind === "ellipse") {
|
|
903
|
-
stampFrame(vector, pageIndex, {
|
|
904
|
-
xPt: item.xPt,
|
|
905
|
-
yPt: item.yPt,
|
|
906
|
-
widthPt: item.widthPt,
|
|
907
|
-
heightPt: item.heightPt
|
|
908
|
-
});
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
if (item.kind === "line") {
|
|
912
|
-
stampFrame(vector, pageIndex, {
|
|
913
|
-
xPt: Math.min(item.x1Pt, item.x2Pt),
|
|
914
|
-
yPt: Math.min(item.y1Pt, item.y2Pt),
|
|
915
|
-
widthPt: Math.abs(item.x2Pt - item.x1Pt),
|
|
916
|
-
heightPt: Math.abs(item.y2Pt - item.y1Pt)
|
|
917
|
-
});
|
|
918
|
-
return;
|
|
919
|
-
}
|
|
920
|
-
if (item.kind !== "path") return;
|
|
921
|
-
const points = collectPathPoints(item.subpaths);
|
|
922
|
-
let minX = Number.POSITIVE_INFINITY;
|
|
923
|
-
let maxX = Number.NEGATIVE_INFINITY;
|
|
924
|
-
let minY = Number.POSITIVE_INFINITY;
|
|
925
|
-
let maxY = Number.NEGATIVE_INFINITY;
|
|
926
|
-
for (const point of points) {
|
|
927
|
-
minX = Math.min(minX, point.xPt);
|
|
928
|
-
maxX = Math.max(maxX, point.xPt);
|
|
929
|
-
minY = Math.min(minY, point.yPt);
|
|
930
|
-
maxY = Math.max(maxY, point.yPt);
|
|
931
|
-
}
|
|
932
|
-
stampFrame(vector, pageIndex, {
|
|
933
|
-
xPt: minX,
|
|
934
|
-
yPt: minY,
|
|
935
|
-
widthPt: maxX - minX,
|
|
936
|
-
heightPt: maxY - minY
|
|
937
|
-
});
|
|
938
|
-
}
|
|
939
|
-
function layoutItemToVector(item, pageHeightPt) {
|
|
940
|
-
if (item.kind === "rect") return layoutRectToVector(item, pageHeightPt);
|
|
941
|
-
if (item.kind === "ellipse") return layoutEllipseToVector(item, pageHeightPt);
|
|
942
|
-
if (item.kind === "line") return layoutLineToVector(item, pageHeightPt);
|
|
943
|
-
if (item.kind === "path") return layoutPathToVector(item, pageHeightPt);
|
|
944
|
-
}
|
|
945
|
-
function layoutRectToVector(item, pageHeightPt) {
|
|
946
|
-
return {
|
|
947
|
-
kind: "rect",
|
|
948
|
-
frame: flipY({
|
|
949
|
-
xPt: item.xPt,
|
|
950
|
-
yPt: item.yPt,
|
|
951
|
-
widthPt: item.widthPt,
|
|
952
|
-
heightPt: item.heightPt
|
|
953
|
-
}, pageHeightPt),
|
|
954
|
-
fill: item.fill,
|
|
955
|
-
stroke: item.stroke,
|
|
956
|
-
sourcePath: item.sourcePath
|
|
957
|
-
};
|
|
958
|
-
}
|
|
959
|
-
function layoutEllipseToVector(item, pageHeightPt) {
|
|
960
|
-
return {
|
|
961
|
-
kind: "ellipse",
|
|
962
|
-
frame: flipY({
|
|
963
|
-
xPt: item.xPt,
|
|
964
|
-
yPt: item.yPt,
|
|
965
|
-
widthPt: item.widthPt,
|
|
966
|
-
heightPt: item.heightPt
|
|
967
|
-
}, pageHeightPt),
|
|
968
|
-
fill: item.fill,
|
|
969
|
-
stroke: item.stroke,
|
|
970
|
-
sourcePath: item.sourcePath
|
|
971
|
-
};
|
|
972
|
-
}
|
|
973
|
-
function layoutLineToVector(item, pageHeightPt) {
|
|
974
|
-
return {
|
|
975
|
-
kind: "line",
|
|
976
|
-
from: {
|
|
977
|
-
xPt: item.x1Pt,
|
|
978
|
-
yPt: pageHeightPt - item.y1Pt
|
|
979
|
-
},
|
|
980
|
-
to: {
|
|
981
|
-
xPt: item.x2Pt,
|
|
982
|
-
yPt: pageHeightPt - item.y2Pt
|
|
983
|
-
},
|
|
984
|
-
stroke: {
|
|
985
|
-
color: item.color,
|
|
986
|
-
widthPt: item.widthPt
|
|
987
|
-
},
|
|
988
|
-
sourcePath: item.sourcePath
|
|
989
|
-
};
|
|
990
|
-
}
|
|
991
|
-
function collectPathPoints(subpaths) {
|
|
992
|
-
const points = [];
|
|
993
|
-
for (const subpath of subpaths) {
|
|
994
|
-
points.push({
|
|
995
|
-
xPt: subpath.startXPt,
|
|
996
|
-
yPt: subpath.startYPt
|
|
997
|
-
});
|
|
998
|
-
for (const segment of subpath.segments) {
|
|
999
|
-
if (segment.kind === "cubic") {
|
|
1000
|
-
points.push({
|
|
1001
|
-
xPt: segment.c1xPt,
|
|
1002
|
-
yPt: segment.c1yPt
|
|
1003
|
-
});
|
|
1004
|
-
points.push({
|
|
1005
|
-
xPt: segment.c2xPt,
|
|
1006
|
-
yPt: segment.c2yPt
|
|
1007
|
-
});
|
|
1008
|
-
}
|
|
1009
|
-
points.push({
|
|
1010
|
-
xPt: segment.xPt,
|
|
1011
|
-
yPt: segment.yPt
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
return points;
|
|
1016
|
-
}
|
|
1017
|
-
function pathBoundingFrame(points, pageHeightPt) {
|
|
1018
|
-
if (points.length === 0) return {
|
|
1019
|
-
xPt: 0,
|
|
1020
|
-
yPt: 0,
|
|
1021
|
-
widthPt: 0,
|
|
1022
|
-
heightPt: 0
|
|
1023
|
-
};
|
|
1024
|
-
let minX = Number.POSITIVE_INFINITY;
|
|
1025
|
-
let maxX = Number.NEGATIVE_INFINITY;
|
|
1026
|
-
let minYDown = Number.POSITIVE_INFINITY;
|
|
1027
|
-
let maxYDown = Number.NEGATIVE_INFINITY;
|
|
1028
|
-
for (const point of points) {
|
|
1029
|
-
const yDown = pageHeightPt - point.yPt;
|
|
1030
|
-
minX = Math.min(minX, point.xPt);
|
|
1031
|
-
maxX = Math.max(maxX, point.xPt);
|
|
1032
|
-
minYDown = Math.min(minYDown, yDown);
|
|
1033
|
-
maxYDown = Math.max(maxYDown, yDown);
|
|
1034
|
-
}
|
|
1035
|
-
return {
|
|
1036
|
-
xPt: minX,
|
|
1037
|
-
yPt: minYDown,
|
|
1038
|
-
widthPt: maxX - minX,
|
|
1039
|
-
heightPt: maxYDown - minYDown
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
function localizePathPoint(frame, point, pageHeightPt) {
|
|
1043
|
-
return {
|
|
1044
|
-
xPt: point.xPt - frame.xPt,
|
|
1045
|
-
yPt: pageHeightPt - frame.yPt - point.yPt
|
|
1046
|
-
};
|
|
1047
|
-
}
|
|
1048
|
-
function layoutPathToVector(item, pageHeightPt) {
|
|
1049
|
-
const frame = pathBoundingFrame(collectPathPoints(item.subpaths), pageHeightPt);
|
|
1050
|
-
return {
|
|
1051
|
-
kind: "path",
|
|
1052
|
-
frame,
|
|
1053
|
-
subpaths: item.subpaths.map((subpath) => ({
|
|
1054
|
-
start: localizePathPoint(frame, {
|
|
1055
|
-
xPt: subpath.startXPt,
|
|
1056
|
-
yPt: subpath.startYPt
|
|
1057
|
-
}, pageHeightPt),
|
|
1058
|
-
closed: subpath.closed,
|
|
1059
|
-
segments: subpath.segments.map((segment) => {
|
|
1060
|
-
if (segment.kind === "line") return {
|
|
1061
|
-
kind: "line",
|
|
1062
|
-
to: localizePathPoint(frame, {
|
|
1063
|
-
xPt: segment.xPt,
|
|
1064
|
-
yPt: segment.yPt
|
|
1065
|
-
}, pageHeightPt)
|
|
1066
|
-
};
|
|
1067
|
-
return {
|
|
1068
|
-
kind: "cubic",
|
|
1069
|
-
control1: localizePathPoint(frame, {
|
|
1070
|
-
xPt: segment.c1xPt,
|
|
1071
|
-
yPt: segment.c1yPt
|
|
1072
|
-
}, pageHeightPt),
|
|
1073
|
-
control2: localizePathPoint(frame, {
|
|
1074
|
-
xPt: segment.c2xPt,
|
|
1075
|
-
yPt: segment.c2yPt
|
|
1076
|
-
}, pageHeightPt),
|
|
1077
|
-
to: localizePathPoint(frame, {
|
|
1078
|
-
xPt: segment.xPt,
|
|
1079
|
-
yPt: segment.yPt
|
|
1080
|
-
}, pageHeightPt)
|
|
1081
|
-
};
|
|
1082
|
-
})
|
|
1083
|
-
})),
|
|
1084
|
-
fill: item.fill,
|
|
1085
|
-
fillRule: item.fillRule,
|
|
1086
|
-
stroke: item.stroke,
|
|
1087
|
-
sourcePath: item.sourcePath
|
|
1088
|
-
};
|
|
1089
|
-
}
|
|
1090
|
-
function layoutTextToShape(item, pageHeightPt, pageIndex) {
|
|
1091
|
-
const frame = computeBlockFrame({ lines: [{
|
|
1092
|
-
items: [item],
|
|
1093
|
-
baselineY: item.yPt
|
|
1094
|
-
}] }, pageHeightPt);
|
|
1095
|
-
const run = textItemToContentRun(item);
|
|
1096
|
-
stampFrame(run, pageIndex, textBoxOfItem(item, pageIndex));
|
|
1097
|
-
const paragraph = {
|
|
1098
|
-
kind: "paragraph",
|
|
1099
|
-
runs: [run]
|
|
1100
|
-
};
|
|
1101
|
-
stampFrame(paragraph, pageIndex, textBoxOfItem(item, pageIndex));
|
|
1102
|
-
return {
|
|
1103
|
-
frame,
|
|
1104
|
-
rotationDeg: item.rotationDeg !== void 0 ? -item.rotationDeg : void 0,
|
|
1105
|
-
insetLeftPt: 0,
|
|
1106
|
-
insetTopPt: 0,
|
|
1107
|
-
insetRightPt: 0,
|
|
1108
|
-
insetBottomPt: 0,
|
|
1109
|
-
blocks: [paragraph]
|
|
1110
|
-
};
|
|
1111
|
-
}
|
|
1112
|
-
function vectorTopYDownPt(vector) {
|
|
1113
|
-
return vector.kind === "line" ? Math.min(vector.from.yPt, vector.to.yPt) : vector.frame.yPt;
|
|
1114
|
-
}
|
|
1115
|
-
function recoverPageVectors(page, pageIndex, excluded) {
|
|
1116
|
-
const vectors = [];
|
|
1117
|
-
for (const item of page.items) {
|
|
1118
|
-
if (excluded.has(item)) continue;
|
|
1119
|
-
const vector = layoutItemToVector(item, page.heightPt);
|
|
1120
|
-
if (vector !== void 0) {
|
|
1121
|
-
stampVectorFrame(vector, item, pageIndex);
|
|
1122
|
-
vectors.push({
|
|
1123
|
-
...vector,
|
|
1124
|
-
paintOrder: vectors.length
|
|
1125
|
-
});
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
if (vectors.length === 0) return;
|
|
1129
|
-
const topYDownPt = Math.min(...vectors.map(vectorTopYDownPt));
|
|
1130
|
-
const block = buildDrawingBlock({
|
|
1131
|
-
widthPt: page.widthPt,
|
|
1132
|
-
heightPt: page.heightPt
|
|
1133
|
-
}, vectors);
|
|
1134
|
-
stampFrame(block, pageIndex, {
|
|
1135
|
-
xPt: 0,
|
|
1136
|
-
yPt: 0,
|
|
1137
|
-
widthPt: page.widthPt,
|
|
1138
|
-
heightPt: page.heightPt
|
|
1139
|
-
});
|
|
1140
|
-
return {
|
|
1141
|
-
block,
|
|
1142
|
-
topYPt: page.heightPt - topYDownPt
|
|
1143
|
-
};
|
|
1144
|
-
}
|
|
1145
|
-
function recoverTables(page, pageIndex, structure) {
|
|
1146
|
-
if (structure !== void 0) {
|
|
1147
|
-
const tagged = recoverTaggedTables(page, pageIndex, structure);
|
|
1148
|
-
if (tagged.length > 0) return tagged;
|
|
1149
|
-
}
|
|
1150
|
-
const lattice = recoverTable(page, pageIndex);
|
|
1151
|
-
return lattice === void 0 ? [] : [lattice];
|
|
1152
|
-
}
|
|
1153
|
-
function recoverTaggedTables(page, pageIndex, structure) {
|
|
1154
|
-
const cellsByTable = /* @__PURE__ */ new Map();
|
|
1155
|
-
for (const item of page.items) {
|
|
1156
|
-
if (item.kind !== "text") continue;
|
|
1157
|
-
const cell = nearestOfType(structure.nodeOfItem(item), CELL_TYPES);
|
|
1158
|
-
const row = nearestOfType(cell?.parent, ROW_TYPES);
|
|
1159
|
-
const table = nearestOfType(row?.parent, TABLE_TYPES);
|
|
1160
|
-
if (cell === void 0 || row === void 0 || table === void 0) continue;
|
|
1161
|
-
const entry = cellsByTable.get(table.id) ?? {
|
|
1162
|
-
table,
|
|
1163
|
-
cellsById: /* @__PURE__ */ new Map()
|
|
1164
|
-
};
|
|
1165
|
-
const existing = entry.cellsById.get(cell.id);
|
|
1166
|
-
if (existing === void 0) entry.cellsById.set(cell.id, {
|
|
1167
|
-
table,
|
|
1168
|
-
row,
|
|
1169
|
-
cell,
|
|
1170
|
-
items: [item]
|
|
1171
|
-
});
|
|
1172
|
-
else existing.items.push(item);
|
|
1173
|
-
cellsByTable.set(table.id, entry);
|
|
1174
|
-
}
|
|
1175
|
-
if (cellsByTable.size === 0) return [];
|
|
1176
|
-
const latticeItems = detectGridLattice(page.items)?.sourceItems ?? NO_ITEMS;
|
|
1177
|
-
const recovered = [];
|
|
1178
|
-
for (const { cellsById } of cellsByTable.values()) {
|
|
1179
|
-
const cells = [...cellsById.values()];
|
|
1180
|
-
const rowsById = /* @__PURE__ */ new Map();
|
|
1181
|
-
for (const cellEntry of cells) {
|
|
1182
|
-
const rowEntry = rowsById.get(cellEntry.row.id) ?? {
|
|
1183
|
-
row: cellEntry.row,
|
|
1184
|
-
cells: []
|
|
1185
|
-
};
|
|
1186
|
-
rowEntry.cells.push(cellEntry);
|
|
1187
|
-
rowsById.set(cellEntry.row.id, rowEntry);
|
|
1188
|
-
}
|
|
1189
|
-
const rows = [...rowsById.values()].sort((a, b) => a.row.order - b.row.order);
|
|
1190
|
-
for (const row of rows) row.cells.sort((a, b) => a.cell.order - b.cell.order);
|
|
1191
|
-
const columnCount = Math.max(...rows.map((row) => row.cells.length));
|
|
1192
|
-
const columns = [];
|
|
1193
|
-
for (let j = 0; j < columnCount; j++) {
|
|
1194
|
-
let minX = Number.POSITIVE_INFINITY;
|
|
1195
|
-
let maxX = Number.NEGATIVE_INFINITY;
|
|
1196
|
-
for (const row of rows) {
|
|
1197
|
-
const cellEntry = row.cells[j];
|
|
1198
|
-
if (cellEntry === void 0) continue;
|
|
1199
|
-
for (const item of cellEntry.items) {
|
|
1200
|
-
minX = Math.min(minX, item.xPt);
|
|
1201
|
-
maxX = Math.max(maxX, item.xPt + (item.widthPt ?? 0));
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
const width = maxX - minX;
|
|
1205
|
-
columns.push({ widthPt: width > 0 ? width : DEFAULT_COLUMN_WIDTH_FALLBACK_PT });
|
|
1206
|
-
}
|
|
1207
|
-
const allItems = cells.flatMap((cellEntry) => cellEntry.items);
|
|
1208
|
-
const contentRows = rows.map((row) => {
|
|
1209
|
-
const contentCells = [];
|
|
1210
|
-
for (let j = 0; j < columnCount; j++) {
|
|
1211
|
-
const cellEntry = row.cells[j];
|
|
1212
|
-
const cell = { blocks: cellBlocksFromItems(cellEntry?.items ?? [], pageIndex) };
|
|
1213
|
-
if (cellEntry !== void 0) stampFrame(cell, pageIndex, textItemsPdfBox(cellEntry.items));
|
|
1214
|
-
contentCells.push(cell);
|
|
1215
|
-
}
|
|
1216
|
-
return { cells: contentCells };
|
|
1217
|
-
});
|
|
1218
|
-
const box = textItemsPdfBox(allItems);
|
|
1219
|
-
const table = {
|
|
1220
|
-
kind: "table",
|
|
1221
|
-
rows: contentRows,
|
|
1222
|
-
columns
|
|
1223
|
-
};
|
|
1224
|
-
stampFrame(table, pageIndex, box);
|
|
1225
|
-
recovered.push({
|
|
1226
|
-
table,
|
|
1227
|
-
frame: flipY(box, page.heightPt),
|
|
1228
|
-
topYPt: box.yPt + box.heightPt,
|
|
1229
|
-
consumedText: new Set(allItems),
|
|
1230
|
-
latticeItems
|
|
1231
|
-
});
|
|
1232
|
-
}
|
|
1233
|
-
return recovered;
|
|
1234
|
-
}
|
|
1235
|
-
function textItemsPdfBox(items) {
|
|
1236
|
-
let minX = Number.POSITIVE_INFINITY;
|
|
1237
|
-
let maxX = Number.NEGATIVE_INFINITY;
|
|
1238
|
-
let minY = Number.POSITIVE_INFINITY;
|
|
1239
|
-
let maxY = Number.NEGATIVE_INFINITY;
|
|
1240
|
-
for (const item of items) {
|
|
1241
|
-
const { ascentPt, descentPt } = textItemVerticalExtent(item);
|
|
1242
|
-
minX = Math.min(minX, item.xPt);
|
|
1243
|
-
maxX = Math.max(maxX, item.xPt + (item.widthPt ?? 0));
|
|
1244
|
-
minY = Math.min(minY, item.yPt - descentPt);
|
|
1245
|
-
maxY = Math.max(maxY, item.yPt + ascentPt);
|
|
1246
|
-
}
|
|
1247
|
-
return {
|
|
1248
|
-
xPt: minX,
|
|
1249
|
-
yPt: minY,
|
|
1250
|
-
widthPt: maxX - minX,
|
|
1251
|
-
heightPt: maxY - minY
|
|
1252
|
-
};
|
|
1253
|
-
}
|
|
1254
|
-
function cellBlocksFromItems(items, pageIndex) {
|
|
1255
|
-
return clusterIntoLines(items).map((line) => lineToParagraph(line, pageIndex));
|
|
1256
|
-
}
|
|
1257
|
-
function indexRegions(lattice, rowCount, columnCount) {
|
|
1258
|
-
const regionAt = Array.from({ length: rowCount }, () => new Array(columnCount));
|
|
1259
|
-
for (const region of lattice.regions) for (let i = region.rowStart; i < region.rowEnd; i++) for (let j = region.colStart; j < region.colEnd; j++) regionAt[i][j] = region;
|
|
1260
|
-
return regionAt;
|
|
1261
|
-
}
|
|
1262
|
-
function recoverTable(page, pageIndex) {
|
|
1263
|
-
const lattice = detectGridLattice(page.items);
|
|
1264
|
-
if (lattice === void 0) return;
|
|
1265
|
-
const rowCount = lattice.rowBoundariesDescPt.length - 1;
|
|
1266
|
-
const columnCount = lattice.columnBoundariesAscPt.length - 1;
|
|
1267
|
-
const regionAt = indexRegions(lattice, rowCount, columnCount);
|
|
1268
|
-
const textByRegion = /* @__PURE__ */ new Map();
|
|
1269
|
-
const consumedText = /* @__PURE__ */ new Set();
|
|
1270
|
-
for (const item of page.items) {
|
|
1271
|
-
if (item.kind !== "text") continue;
|
|
1272
|
-
const row = findRowIndex(lattice.rowBoundariesDescPt, item.yPt);
|
|
1273
|
-
const column = findColumnIndex(lattice.columnBoundariesAscPt, item.xPt);
|
|
1274
|
-
if (row === void 0 || column === void 0) continue;
|
|
1275
|
-
const region = regionAt[row][column];
|
|
1276
|
-
const existing = textByRegion.get(region);
|
|
1277
|
-
if (existing === void 0) textByRegion.set(region, [item]);
|
|
1278
|
-
else existing.push(item);
|
|
1279
|
-
consumedText.add(item);
|
|
1280
|
-
}
|
|
1281
|
-
if (consumedText.size === 0) return;
|
|
1282
|
-
const columns = [];
|
|
1283
|
-
for (let j = 0; j < columnCount; j++) columns.push({ widthPt: lattice.columnBoundariesAscPt[j + 1] - lattice.columnBoundariesAscPt[j] });
|
|
1284
|
-
const positionedRows = [];
|
|
1285
|
-
for (let i = 0; i < rowCount; i++) {
|
|
1286
|
-
const positioned = [];
|
|
1287
|
-
for (let j = 0; j < columnCount; j++) {
|
|
1288
|
-
const region = regionAt[i][j];
|
|
1289
|
-
if (region.rowStart !== i || region.colStart !== j) continue;
|
|
1290
|
-
const colSpan = region.colEnd - region.colStart;
|
|
1291
|
-
const rowSpan = region.rowEnd - region.rowStart;
|
|
1292
|
-
const cell = {
|
|
1293
|
-
blocks: cellBlocksFromItems(textByRegion.get(region) ?? [], pageIndex),
|
|
1294
|
-
colSpan: colSpan > 1 ? colSpan : void 0,
|
|
1295
|
-
rowSpan: rowSpan > 1 ? rowSpan : void 0
|
|
1296
|
-
};
|
|
1297
|
-
const cellLeftXPt = lattice.columnBoundariesAscPt[region.colStart];
|
|
1298
|
-
const cellRightXPt = lattice.columnBoundariesAscPt[region.colEnd];
|
|
1299
|
-
const cellTopYPt = lattice.rowBoundariesDescPt[region.rowStart];
|
|
1300
|
-
const cellBottomYPt = lattice.rowBoundariesDescPt[region.rowEnd];
|
|
1301
|
-
stampFrame(cell, pageIndex, {
|
|
1302
|
-
xPt: cellLeftXPt,
|
|
1303
|
-
yPt: cellBottomYPt,
|
|
1304
|
-
widthPt: cellRightXPt - cellLeftXPt,
|
|
1305
|
-
heightPt: cellTopYPt - cellBottomYPt
|
|
1306
|
-
});
|
|
1307
|
-
positioned.push({
|
|
1308
|
-
columnIndex: j,
|
|
1309
|
-
cell
|
|
1310
|
-
});
|
|
1311
|
-
}
|
|
1312
|
-
positionedRows.push({
|
|
1313
|
-
cells: positioned,
|
|
1314
|
-
heightPt: lattice.rowBoundariesDescPt[i] - lattice.rowBoundariesDescPt[i + 1]
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
const rows = denseTableRows(positionedRows, columnCount);
|
|
1318
|
-
const leftXPt = lattice.columnBoundariesAscPt[0];
|
|
1319
|
-
const rightXPt = lattice.columnBoundariesAscPt[columnCount];
|
|
1320
|
-
const topYPt = lattice.rowBoundariesDescPt[0];
|
|
1321
|
-
const bottomYPt = lattice.rowBoundariesDescPt[rowCount];
|
|
1322
|
-
const pdfBox = {
|
|
1323
|
-
xPt: leftXPt,
|
|
1324
|
-
yPt: bottomYPt,
|
|
1325
|
-
widthPt: rightXPt - leftXPt,
|
|
1326
|
-
heightPt: topYPt - bottomYPt
|
|
1327
|
-
};
|
|
1328
|
-
const frame = flipY(pdfBox, page.heightPt);
|
|
1329
|
-
const table = {
|
|
1330
|
-
kind: "table",
|
|
1331
|
-
rows,
|
|
1332
|
-
columns
|
|
1333
|
-
};
|
|
1334
|
-
stampFrame(table, pageIndex, pdfBox);
|
|
1335
|
-
return {
|
|
1336
|
-
table,
|
|
1337
|
-
frame,
|
|
1338
|
-
topYPt,
|
|
1339
|
-
consumedText,
|
|
1340
|
-
latticeItems: lattice.sourceItems
|
|
1341
|
-
};
|
|
1342
|
-
}
|
|
1343
|
-
function joinCellText(items) {
|
|
1344
|
-
const sorted = [...items].sort((a, b) => a.xPt - b.xPt);
|
|
1345
|
-
let text = "";
|
|
1346
|
-
sorted.forEach((item, i) => {
|
|
1347
|
-
if (i > 0) {
|
|
1348
|
-
const prev = sorted[i - 1];
|
|
1349
|
-
if (gapExceeds(prev, item, MIN_WORD_GAP_PT)) text += " ";
|
|
1350
|
-
}
|
|
1351
|
-
text += item.text;
|
|
1352
|
-
});
|
|
1353
|
-
return text;
|
|
1354
|
-
}
|
|
1355
|
-
function groupKey(row, column) {
|
|
1356
|
-
return `${row},${column}`;
|
|
1357
|
-
}
|
|
1358
|
-
function addToGroup(groups, row, column, item) {
|
|
1359
|
-
const key = groupKey(row, column);
|
|
1360
|
-
const existing = groups.get(key);
|
|
1361
|
-
if (existing === void 0) groups.set(key, [item]);
|
|
1362
|
-
else existing.push(item);
|
|
1363
|
-
}
|
|
1364
|
-
function buildCellsFromGroups(groups, pageIndex, context) {
|
|
1365
|
-
const cells = [];
|
|
1366
|
-
for (const [key, items] of groups) {
|
|
1367
|
-
const displayText = joinCellText(items);
|
|
1368
|
-
if (displayText.length === 0) continue;
|
|
1369
|
-
const [rowPart, columnPart] = key.split(",");
|
|
1370
|
-
const row = Number(rowPart);
|
|
1371
|
-
const column = Number(columnPart);
|
|
1372
|
-
const cell = {
|
|
1373
|
-
row,
|
|
1374
|
-
column,
|
|
1375
|
-
value: inferredCellValue(displayText, row, column, context),
|
|
1376
|
-
displayText
|
|
1377
|
-
};
|
|
1378
|
-
stampFrame(cell, pageIndex, textItemsPdfBox(items));
|
|
1379
|
-
cells.push(cell);
|
|
1380
|
-
}
|
|
1381
|
-
cells.sort((a, b) => a.row - b.row || a.column - b.column);
|
|
1382
|
-
return cells;
|
|
1383
|
-
}
|
|
1384
|
-
function inferredCellValue(displayText, row, column, context) {
|
|
1385
|
-
const inference = inferCellValue(displayText);
|
|
1386
|
-
if (inference === void 0) return {
|
|
1387
|
-
kind: "string",
|
|
1388
|
-
value: displayText
|
|
1389
|
-
};
|
|
1390
|
-
const reported = {
|
|
1391
|
-
sheetIndex: context.sheetIndex,
|
|
1392
|
-
row,
|
|
1393
|
-
column,
|
|
1394
|
-
displayText,
|
|
1395
|
-
...inference
|
|
1396
|
-
};
|
|
1397
|
-
context.sink?.(reported);
|
|
1398
|
-
return inference.outcome === "retyped" ? inference.value : {
|
|
1399
|
-
kind: "string",
|
|
1400
|
-
value: displayText
|
|
1401
|
-
};
|
|
1402
|
-
}
|
|
1403
|
-
function buildGridFromLattice(textItems, lattice, pageIndex, context) {
|
|
1404
|
-
const groups = /* @__PURE__ */ new Map();
|
|
1405
|
-
for (const item of textItems) {
|
|
1406
|
-
const row = findRowIndex(lattice.rowBoundariesDescPt, item.yPt);
|
|
1407
|
-
const column = findColumnIndex(lattice.columnBoundariesAscPt, item.xPt);
|
|
1408
|
-
if (row === void 0 || column === void 0) continue;
|
|
1409
|
-
addToGroup(groups, row, column, item);
|
|
1410
|
-
}
|
|
1411
|
-
const columns = [];
|
|
1412
|
-
for (let j = 0; j < lattice.columnBoundariesAscPt.length - 1; j++) columns.push({
|
|
1413
|
-
index: j,
|
|
1414
|
-
widthPt: lattice.columnBoundariesAscPt[j + 1] - lattice.columnBoundariesAscPt[j]
|
|
1415
|
-
});
|
|
1416
|
-
const rows = [];
|
|
1417
|
-
for (let i = 0; i < lattice.rowBoundariesDescPt.length - 1; i++) rows.push({
|
|
1418
|
-
index: i,
|
|
1419
|
-
heightPt: lattice.rowBoundariesDescPt[i] - lattice.rowBoundariesDescPt[i + 1]
|
|
1420
|
-
});
|
|
1421
|
-
return {
|
|
1422
|
-
cells: buildCellsFromGroups(groups, pageIndex, context),
|
|
1423
|
-
columns,
|
|
1424
|
-
rows,
|
|
1425
|
-
gridlines: true
|
|
1426
|
-
};
|
|
1427
|
-
}
|
|
1428
|
-
const COLUMN_ALIGNMENT_TOLERANCE_PT = 3;
|
|
1429
|
-
const MIN_COLUMN_RECURRENCE = 2;
|
|
1430
|
-
function detectColumnPositions(segmentsByLine) {
|
|
1431
|
-
const allXs = segmentsByLine.flatMap((segments) => segments.map((segment) => segment.items[0].xPt));
|
|
1432
|
-
if (allXs.length === 0) return [];
|
|
1433
|
-
const counts = bucketCounts(allXs, COLUMN_ALIGNMENT_TOLERANCE_PT);
|
|
1434
|
-
const recurring = [...counts.entries()].filter(([, count]) => count >= MIN_COLUMN_RECURRENCE).map(([bucket]) => bucket);
|
|
1435
|
-
const positions = recurring.length > 0 ? recurring : [...counts.keys()];
|
|
1436
|
-
positions.sort((a, b) => a - b);
|
|
1437
|
-
return positions;
|
|
1438
|
-
}
|
|
1439
|
-
function nearestColumnIndex(positions, xPt) {
|
|
1440
|
-
let bestIndex = 0;
|
|
1441
|
-
let bestDistancePt = Number.POSITIVE_INFINITY;
|
|
1442
|
-
positions.forEach((position, index) => {
|
|
1443
|
-
const distancePt = Math.abs(position - xPt);
|
|
1444
|
-
if (distancePt < bestDistancePt) {
|
|
1445
|
-
bestDistancePt = distancePt;
|
|
1446
|
-
bestIndex = index;
|
|
1447
|
-
}
|
|
1448
|
-
});
|
|
1449
|
-
return bestIndex;
|
|
1450
|
-
}
|
|
1451
|
-
function lastColumnWidthPt(groups, columnIndex, anchorXPt) {
|
|
1452
|
-
let maxWidthPt = 0;
|
|
1453
|
-
for (const [key, items] of groups) {
|
|
1454
|
-
const [, columnPart] = key.split(",");
|
|
1455
|
-
if (Number(columnPart) !== columnIndex) continue;
|
|
1456
|
-
for (const item of items) maxWidthPt = Math.max(maxWidthPt, item.xPt + (item.widthPt ?? 0) - anchorXPt);
|
|
1457
|
-
}
|
|
1458
|
-
return maxWidthPt > 0 ? maxWidthPt : DEFAULT_COLUMN_WIDTH_FALLBACK_PT;
|
|
1459
|
-
}
|
|
1460
|
-
function buildGridFromTextClustering(textItems, pageIndex, context) {
|
|
1461
|
-
const lines = clusterIntoLines(textItems);
|
|
1462
|
-
if (lines.length === 0) return {
|
|
1463
|
-
cells: [],
|
|
1464
|
-
columns: [],
|
|
1465
|
-
rows: [],
|
|
1466
|
-
gridlines: false
|
|
1467
|
-
};
|
|
1468
|
-
const segmentsByLine = lines.map((l) => splitLineByLargeGaps(l));
|
|
1469
|
-
const columnPositions = detectColumnPositions(segmentsByLine);
|
|
1470
|
-
const groups = /* @__PURE__ */ new Map();
|
|
1471
|
-
segmentsByLine.forEach((segments, rowIndex) => {
|
|
1472
|
-
for (const segment of segments) {
|
|
1473
|
-
const key = groupKey(rowIndex, nearestColumnIndex(columnPositions, segment.items[0].xPt));
|
|
1474
|
-
const existing = groups.get(key);
|
|
1475
|
-
if (existing === void 0) groups.set(key, [...segment.items]);
|
|
1476
|
-
else existing.push(...segment.items);
|
|
1477
|
-
}
|
|
1478
|
-
});
|
|
1479
|
-
const nominalRowHeightPt = estimateModalLineSpacing(lines);
|
|
1480
|
-
const rows = lines.map((line, i) => {
|
|
1481
|
-
const nextBaselineY = lines[i + 1]?.baselineY;
|
|
1482
|
-
const heightPt = nextBaselineY !== void 0 ? line.baselineY - nextBaselineY : nominalRowHeightPt;
|
|
1483
|
-
return {
|
|
1484
|
-
index: i,
|
|
1485
|
-
heightPt: heightPt > 0 ? heightPt : nominalRowHeightPt
|
|
1486
|
-
};
|
|
1487
|
-
});
|
|
1488
|
-
const columns = columnPositions.map((position, j) => {
|
|
1489
|
-
const nextPosition = columnPositions[j + 1];
|
|
1490
|
-
return {
|
|
1491
|
-
index: j,
|
|
1492
|
-
widthPt: nextPosition !== void 0 ? nextPosition - position : lastColumnWidthPt(groups, j, position)
|
|
1493
|
-
};
|
|
1494
|
-
});
|
|
1495
|
-
return {
|
|
1496
|
-
cells: buildCellsFromGroups(groups, pageIndex, context),
|
|
1497
|
-
columns,
|
|
1498
|
-
rows,
|
|
1499
|
-
gridlines: false
|
|
1500
|
-
};
|
|
1501
|
-
}
|
|
1502
|
-
function reconstructSheet(page, pageIndex, sink) {
|
|
1503
|
-
const textItems = page.items.filter((i) => i.kind === "text");
|
|
1504
|
-
const lattice = detectGridLattice(page.items);
|
|
1505
|
-
const context = {
|
|
1506
|
-
sheetIndex: pageIndex,
|
|
1507
|
-
sink
|
|
1508
|
-
};
|
|
1509
|
-
const grid = lattice !== void 0 ? buildGridFromLattice(textItems, lattice, pageIndex, context) : buildGridFromTextClustering(textItems, pageIndex, context);
|
|
1510
|
-
const printSettings = {
|
|
1511
|
-
pageSize: {
|
|
1512
|
-
widthPt: page.widthPt,
|
|
1513
|
-
heightPt: page.heightPt
|
|
1514
|
-
},
|
|
1515
|
-
margins: ZERO_MARGINS,
|
|
1516
|
-
gridlines: grid.gridlines,
|
|
1517
|
-
headers: false,
|
|
1518
|
-
pageOrder: "downThenOver"
|
|
1519
|
-
};
|
|
1520
|
-
return {
|
|
1521
|
-
name: `Sheet${pageIndex + 1}`,
|
|
1522
|
-
cells: grid.cells,
|
|
1523
|
-
columns: grid.columns,
|
|
1524
|
-
rows: grid.rows,
|
|
1525
|
-
images: [],
|
|
1526
|
-
printSettings
|
|
1527
|
-
};
|
|
1528
|
-
}
|
|
1529
|
-
function reconstructSpreadsheet(doc, options) {
|
|
1530
|
-
const signal = options?.signal;
|
|
1531
|
-
const sheets = doc.pages.map((page, index) => {
|
|
1532
|
-
throwIfAborted(signal);
|
|
1533
|
-
return reconstructSheet(page, index, options?.onCellTypeInference);
|
|
1534
|
-
});
|
|
1535
|
-
return {
|
|
1536
|
-
kind: "spreadsheet",
|
|
1537
|
-
metadata: doc.metadata,
|
|
1538
|
-
sheets
|
|
1539
|
-
};
|
|
1540
|
-
}
|
|
1541
|
-
//#endregion
|
|
1542
|
-
export { reconstructDrawing, reconstructPresentation, reconstructSpreadsheet, reconstructWordprocessing };
|
|
1
|
+
import { _ as reconstructWordprocessing, c as CELL_TYPES, d as ROW_TYPES, f as TABLE_TYPES, g as reconstructSpreadsheet, h as nearestOfType, l as DEFAULT_COLUMN_WIDTH_FALLBACK_PT, m as indexStructure, p as ZERO_MARGINS, u as NO_ITEMS } from "../reconstruct-presentations-prod-B5fkPiRZ.js";
|
|
2
|
+
export { CELL_TYPES, DEFAULT_COLUMN_WIDTH_FALLBACK_PT, NO_ITEMS, ROW_TYPES, TABLE_TYPES, ZERO_MARGINS, indexStructure, nearestOfType, reconstructSpreadsheet, reconstructWordprocessing };
|