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
package/dist/latex/temml.d.ts
CHANGED
|
@@ -1,25 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region src/latex/temml.d.ts
|
|
3
|
-
interface TemmlNode {
|
|
4
|
-
readonly type: string;
|
|
5
|
-
readonly [field: string]: unknown;
|
|
6
|
-
}
|
|
7
|
-
declare function isTemmlNode(value: unknown): value is TemmlNode;
|
|
8
|
-
declare function isTemmlNodeArray(value: unknown): value is TemmlNode[];
|
|
9
|
-
interface TemmlSourceSpan {
|
|
10
|
-
readonly start: number;
|
|
11
|
-
readonly end: number;
|
|
12
|
-
}
|
|
13
|
-
declare function sourceSpanOf(node: TemmlNode): TemmlSourceSpan | undefined;
|
|
14
|
-
declare function sourceSlice(input: string, span: TemmlSourceSpan | undefined): string;
|
|
15
|
-
type LatexParseResult = {
|
|
16
|
-
readonly status: "parsed";
|
|
17
|
-
readonly nodes: readonly TemmlNode[];
|
|
18
|
-
readonly mathml: readonly MathMlNode[];
|
|
19
|
-
} | {
|
|
20
|
-
readonly status: "unparseable";
|
|
21
|
-
readonly message: string;
|
|
22
|
-
};
|
|
23
|
-
declare function parseLatex(latex: string): LatexParseResult;
|
|
24
|
-
//#endregion
|
|
1
|
+
import { a as isTemmlNodeArray, c as sourceSpanOf, i as isTemmlNode, n as TemmlNode, o as parseLatex, r as TemmlSourceSpan, s as sourceSlice, t as LatexParseResult } from "../temml-1-I9N9DD.js";
|
|
25
2
|
export { LatexParseResult, TemmlNode, TemmlSourceSpan, isTemmlNode, isTemmlNodeArray, parseLatex, sourceSlice, sourceSpanOf };
|
package/dist/layout/engine.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_model_geometry = require("../model/geometry.cjs");
|
|
3
3
|
const require_model_formula = require("../model/formula.cjs");
|
|
4
|
-
const
|
|
4
|
+
const require_layout = require("../layout-iuiyl_Fk.cjs");
|
|
5
5
|
const require_layout_text_layout = require("./text-layout.cjs");
|
|
6
6
|
const require_layout_shared = require("./shared.cjs");
|
|
7
7
|
let document_schema_js = require("document-schema.js");
|
|
@@ -229,7 +229,7 @@ function layoutFormulaFlow(block, section, pages, state, contentLeftXDown, conte
|
|
|
229
229
|
}
|
|
230
230
|
const sizePt = require_layout_shared.formulaSizePtForFrame(formula.mathml, block.frame, mathMetricsAt);
|
|
231
231
|
const metrics = mathMetricsAt(sizePt);
|
|
232
|
-
const { box } =
|
|
232
|
+
const { box } = require_layout.layoutFormula(formula.mathml, {
|
|
233
233
|
metrics,
|
|
234
234
|
sizePt,
|
|
235
235
|
color: document_schema_js.COLOR_BLACK
|
package/dist/layout/engine.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { flipY } from "../model/geometry.js";
|
|
2
2
|
import { formulaOfBlock, formulaPlaceholderText } from "../model/formula.js";
|
|
3
|
-
import { layoutFormula } from "../
|
|
3
|
+
import { t as layoutFormula } from "../layout-DIJzJk4x.js";
|
|
4
4
|
import { wrapRunsToWidth } from "./text-layout.js";
|
|
5
5
|
import { alignmentOffsetPt, effectiveStyledRuns, estimateRowHeightPt, formulaSizePtForFrame, headingStyleFor, justifyLineGapsPt, layoutDocumentOf, lineNaturalHeightPt, packagePagesOf, pushCellBorderLines, registerImage, stampFragmentFrame, stampFrame, tableAnchorBoxes, textBoxForFragment } from "./shared.js";
|
|
6
6
|
import { COLOR_BLACK, resolveCellFillColor } from "document-schema.js";
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_layout_shared = require("./shared.cjs");
|
|
3
|
+
let pdf_codec_fonts = require("pdf-codec/fonts");
|
|
4
|
+
let pdf_codec_afm_widths = require("pdf-codec/afm-widths");
|
|
5
|
+
let pdf_codec_text_group = require("pdf-codec/text-group");
|
|
6
|
+
//#region src/layout/reconstruct-lines.ts
|
|
7
|
+
const LINE_BASELINE_TOLERANCE_FACTOR = .5;
|
|
8
|
+
const AFM_UNITS_PER_EM = 1e3;
|
|
9
|
+
const HALF_POINT_BUCKET_PT = .5;
|
|
10
|
+
function sharesBaseline(anchor, item) {
|
|
11
|
+
return (0, pdf_codec_text_group.runsShareBaseline)(anchor, item, { baselineToleranceEm: LINE_BASELINE_TOLERANCE_FACTOR });
|
|
12
|
+
}
|
|
13
|
+
const DUPLICATE_PAINT_BUCKET_PT = .1;
|
|
14
|
+
function duplicatePaintKey(item) {
|
|
15
|
+
const xBucket = Math.round(item.xPt / DUPLICATE_PAINT_BUCKET_PT);
|
|
16
|
+
const yBucket = Math.round(item.yPt / DUPLICATE_PAINT_BUCKET_PT);
|
|
17
|
+
return `${item.text.trim()}|${String(xBucket)}|${String(yBucket)}`;
|
|
18
|
+
}
|
|
19
|
+
function dropDuplicatePaints(items) {
|
|
20
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21
|
+
const kept = [];
|
|
22
|
+
for (const item of items) {
|
|
23
|
+
const key = duplicatePaintKey(item);
|
|
24
|
+
if (seen.has(key)) continue;
|
|
25
|
+
seen.add(key);
|
|
26
|
+
kept.push(item);
|
|
27
|
+
}
|
|
28
|
+
return kept;
|
|
29
|
+
}
|
|
30
|
+
function dropOverlappingRepeatsWithinLine(items) {
|
|
31
|
+
const rightEdgeByText = /* @__PURE__ */ new Map();
|
|
32
|
+
const kept = [];
|
|
33
|
+
for (const item of items) {
|
|
34
|
+
const textKey = item.text.trim();
|
|
35
|
+
const priorRightEdge = rightEdgeByText.get(textKey);
|
|
36
|
+
if (priorRightEdge !== void 0 && item.xPt < priorRightEdge) continue;
|
|
37
|
+
rightEdgeByText.set(textKey, item.xPt + (item.widthPt ?? 0));
|
|
38
|
+
kept.push(item);
|
|
39
|
+
}
|
|
40
|
+
return kept;
|
|
41
|
+
}
|
|
42
|
+
const REDRAW_PASS_REWIND_TOLERANCE_PT = 2;
|
|
43
|
+
const MIN_REDRAW_PASS_TEXT_LENGTH = 12;
|
|
44
|
+
const REDRAW_PASS_SIMILARITY_THRESHOLD = .6;
|
|
45
|
+
function groupByBaselineInDocumentOrder(items) {
|
|
46
|
+
const groups = [];
|
|
47
|
+
for (const item of items) {
|
|
48
|
+
const group = groups.find((g) => sharesBaseline(g.anchor, item));
|
|
49
|
+
if (group === void 0) groups.push({
|
|
50
|
+
anchor: item,
|
|
51
|
+
items: [item]
|
|
52
|
+
});
|
|
53
|
+
else group.items.push(item);
|
|
54
|
+
}
|
|
55
|
+
return groups.map((g) => g.items);
|
|
56
|
+
}
|
|
57
|
+
function splitIntoPasses(group) {
|
|
58
|
+
const passes = [];
|
|
59
|
+
for (const item of group) {
|
|
60
|
+
const current = passes.at(-1);
|
|
61
|
+
const itemRightPt = item.xPt + (item.widthPt ?? 0);
|
|
62
|
+
if (current !== void 0 && item.xPt >= current.endXPt - REDRAW_PASS_REWIND_TOLERANCE_PT) {
|
|
63
|
+
current.items.push(item);
|
|
64
|
+
current.endXPt = Math.max(current.endXPt, itemRightPt);
|
|
65
|
+
} else passes.push({
|
|
66
|
+
items: [item],
|
|
67
|
+
startXPt: item.xPt,
|
|
68
|
+
endXPt: itemRightPt
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return passes;
|
|
72
|
+
}
|
|
73
|
+
function passText(pass) {
|
|
74
|
+
return pass.items.map((item) => item.text).join("").trim();
|
|
75
|
+
}
|
|
76
|
+
function passesOverlap(a, b) {
|
|
77
|
+
return a.startXPt < b.endXPt && b.startXPt < a.endXPt;
|
|
78
|
+
}
|
|
79
|
+
function levenshteinDistance(a, b) {
|
|
80
|
+
const memo = /* @__PURE__ */ new Map();
|
|
81
|
+
function distance(i, j) {
|
|
82
|
+
if (i === 0) return j;
|
|
83
|
+
if (j === 0) return i;
|
|
84
|
+
const key = `${String(i)}:${String(j)}`;
|
|
85
|
+
const cached = memo.get(key);
|
|
86
|
+
if (cached !== void 0) return cached;
|
|
87
|
+
const cost = a.charAt(i - 1) === b.charAt(j - 1) ? 0 : 1;
|
|
88
|
+
const result = Math.min(distance(i - 1, j) + 1, distance(i, j - 1) + 1, distance(i - 1, j - 1) + cost);
|
|
89
|
+
memo.set(key, result);
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
return distance(a.length, b.length);
|
|
93
|
+
}
|
|
94
|
+
function textSimilarity(a, b) {
|
|
95
|
+
const maxLength = Math.max(a.length, b.length);
|
|
96
|
+
return 1 - levenshteinDistance(a, b) / maxLength;
|
|
97
|
+
}
|
|
98
|
+
function dropFuzzyRedrawnPasses(items) {
|
|
99
|
+
const toDrop = /* @__PURE__ */ new Set();
|
|
100
|
+
for (const group of groupByBaselineInDocumentOrder(items)) {
|
|
101
|
+
const passes = splitIntoPasses(group);
|
|
102
|
+
if (passes.length < 2) continue;
|
|
103
|
+
const [first, ...rest] = passes;
|
|
104
|
+
if (first === void 0) continue;
|
|
105
|
+
const firstText = passText(first);
|
|
106
|
+
if (firstText.length < MIN_REDRAW_PASS_TEXT_LENGTH) continue;
|
|
107
|
+
for (const candidate of rest) {
|
|
108
|
+
const candidateText = passText(candidate);
|
|
109
|
+
if (candidateText.length < MIN_REDRAW_PASS_TEXT_LENGTH) continue;
|
|
110
|
+
if (!passesOverlap(first, candidate)) continue;
|
|
111
|
+
if (textSimilarity(firstText, candidateText) < REDRAW_PASS_SIMILARITY_THRESHOLD) continue;
|
|
112
|
+
for (const item of candidate.items) toDrop.add(item);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (toDrop.size === 0) return items;
|
|
116
|
+
return items.filter((item) => !toDrop.has(item));
|
|
117
|
+
}
|
|
118
|
+
function clusterIntoLines(items) {
|
|
119
|
+
const sorted = [...dropDuplicatePaints(dropFuzzyRedrawnPasses(items))].sort((a, b) => b.yPt - a.yPt || a.xPt - b.xPt);
|
|
120
|
+
const working = [];
|
|
121
|
+
for (const item of sorted) {
|
|
122
|
+
const line = working.find((l) => sharesBaseline(l.anchor, item));
|
|
123
|
+
if (line === void 0) working.push({
|
|
124
|
+
items: [item],
|
|
125
|
+
baselineY: item.yPt,
|
|
126
|
+
anchor: item
|
|
127
|
+
});
|
|
128
|
+
else line.items.push(item);
|
|
129
|
+
}
|
|
130
|
+
for (const line of working) {
|
|
131
|
+
line.items.sort((a, b) => a.xPt - b.xPt);
|
|
132
|
+
line.items = dropOverlappingRepeatsWithinLine(line.items);
|
|
133
|
+
}
|
|
134
|
+
working.sort((a, b) => b.baselineY - a.baselineY);
|
|
135
|
+
return working;
|
|
136
|
+
}
|
|
137
|
+
function textItemVerticalExtent(item) {
|
|
138
|
+
const { standardName } = (0, pdf_codec_fonts.resolveStandardFont)(item.font.family, item.font.weight === "bold", item.font.style === "italic");
|
|
139
|
+
const metrics = pdf_codec_afm_widths.STANDARD_METRICS[standardName];
|
|
140
|
+
return {
|
|
141
|
+
ascentPt: metrics.ascender / AFM_UNITS_PER_EM * item.sizePt,
|
|
142
|
+
descentPt: Math.abs(metrics.descender) / AFM_UNITS_PER_EM * item.sizePt
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function textItemToContentRun(item) {
|
|
146
|
+
return {
|
|
147
|
+
text: item.text,
|
|
148
|
+
...item.font.weight === "bold" ? { bold: true } : {},
|
|
149
|
+
...item.font.style === "italic" ? { italic: true } : {},
|
|
150
|
+
fontFamily: item.font.family,
|
|
151
|
+
sizePt: item.sizePt,
|
|
152
|
+
color: item.color
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const MIN_WORD_GAP_PT = .5;
|
|
156
|
+
function gapExceeds(previous, next, thresholdPt) {
|
|
157
|
+
const gap = (0, pdf_codec_text_group.runGapPt)(previous, next);
|
|
158
|
+
return gap !== void 0 && gap > thresholdPt;
|
|
159
|
+
}
|
|
160
|
+
function textBoxOfItem(item, pageIndex) {
|
|
161
|
+
const { ascentPt, descentPt } = textItemVerticalExtent(item);
|
|
162
|
+
return {
|
|
163
|
+
pageIndex,
|
|
164
|
+
xPt: item.xPt,
|
|
165
|
+
yPt: item.yPt - descentPt,
|
|
166
|
+
widthPt: item.widthPt ?? 0,
|
|
167
|
+
heightPt: ascentPt + descentPt
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function lineBox(line, pageIndex) {
|
|
171
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
172
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
173
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
174
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
175
|
+
for (const item of line.items) {
|
|
176
|
+
const { ascentPt, descentPt } = textItemVerticalExtent(item);
|
|
177
|
+
minX = Math.min(minX, item.xPt);
|
|
178
|
+
maxX = Math.max(maxX, item.xPt + (item.widthPt ?? 0));
|
|
179
|
+
minY = Math.min(minY, item.yPt - descentPt);
|
|
180
|
+
maxY = Math.max(maxY, item.yPt + ascentPt);
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
pageIndex,
|
|
184
|
+
xPt: minX,
|
|
185
|
+
yPt: minY,
|
|
186
|
+
widthPt: maxX - minX,
|
|
187
|
+
heightPt: maxY - minY
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function pushRunsForLine(runs, line, pageIndex) {
|
|
191
|
+
line.items.forEach((item, itemIndex) => {
|
|
192
|
+
if (itemIndex > 0) {
|
|
193
|
+
const prevItem = line.items[itemIndex - 1];
|
|
194
|
+
if (gapExceeds(prevItem, item, 2 * item.sizePt)) runs.push({ text: " " });
|
|
195
|
+
else if (gapExceeds(prevItem, item, .5)) runs[runs.length - 1].text += " ";
|
|
196
|
+
}
|
|
197
|
+
const run = textItemToContentRun(item);
|
|
198
|
+
require_layout_shared.stampFrame(run, pageIndex, textBoxOfItem(item, pageIndex));
|
|
199
|
+
runs.push(run);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
function bucketCounts(values, bucketSize) {
|
|
203
|
+
const counts = /* @__PURE__ */ new Map();
|
|
204
|
+
for (const v of values) {
|
|
205
|
+
const bucket = Math.round(v / bucketSize) * bucketSize;
|
|
206
|
+
counts.set(bucket, (counts.get(bucket) ?? 0) + 1);
|
|
207
|
+
}
|
|
208
|
+
return counts;
|
|
209
|
+
}
|
|
210
|
+
function modeOf(values, bucketSize) {
|
|
211
|
+
if (values.length === 0) return 0;
|
|
212
|
+
const counts = bucketCounts(values, bucketSize);
|
|
213
|
+
let bestBucket = values[0];
|
|
214
|
+
let bestCount = 0;
|
|
215
|
+
for (const [bucket, count] of counts) if (count > bestCount) {
|
|
216
|
+
bestBucket = bucket;
|
|
217
|
+
bestCount = count;
|
|
218
|
+
}
|
|
219
|
+
return bestBucket;
|
|
220
|
+
}
|
|
221
|
+
function modalLineGap(gaps) {
|
|
222
|
+
const counts = bucketCounts(gaps, HALF_POINT_BUCKET_PT);
|
|
223
|
+
let bestBucket = gaps[0];
|
|
224
|
+
let bestCount = 0;
|
|
225
|
+
for (const [bucket, count] of counts) if (count > bestCount) {
|
|
226
|
+
bestBucket = bucket;
|
|
227
|
+
bestCount = count;
|
|
228
|
+
}
|
|
229
|
+
return bestCount > 1 ? bestBucket : Math.min(...gaps);
|
|
230
|
+
}
|
|
231
|
+
const LARGE_GAP_EM_MULTIPLIER = 2;
|
|
232
|
+
const FONT_SIZE_CLOSE_TOLERANCE_PT = 1;
|
|
233
|
+
const FONT_SIZE_CLOSE_TOLERANCE_RATIO = .15;
|
|
234
|
+
function fontSizesClose(a, b) {
|
|
235
|
+
return Math.abs(a - b) <= FONT_SIZE_CLOSE_TOLERANCE_PT || Math.abs(a - b) / Math.max(a, b) <= FONT_SIZE_CLOSE_TOLERANCE_RATIO;
|
|
236
|
+
}
|
|
237
|
+
const PARAGRAPH_GAP_MULTIPLIER = 1.25;
|
|
238
|
+
const NOMINAL_LINE_SPACING_RATIO = 1.2;
|
|
239
|
+
const MIN_LINES_FOR_GAP_MODE = 3;
|
|
240
|
+
function estimateModalLineSpacing(lines) {
|
|
241
|
+
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;
|
|
242
|
+
const gaps = [];
|
|
243
|
+
for (let i = 1; i < lines.length; i++) gaps.push(lines[i - 1].baselineY - lines[i].baselineY);
|
|
244
|
+
return modalLineGap(gaps);
|
|
245
|
+
}
|
|
246
|
+
function clusterIntoParagraphs(lines) {
|
|
247
|
+
if (lines.length === 0) return [];
|
|
248
|
+
const modalSpacing = estimateModalLineSpacing(lines);
|
|
249
|
+
const dominantLeftX = modeOf(lines.map((l) => l.items[0].xPt), 1);
|
|
250
|
+
const paragraphs = [{ lines: [lines[0]] }];
|
|
251
|
+
for (let i = 1; i < lines.length; i++) {
|
|
252
|
+
const prev = lines[i - 1];
|
|
253
|
+
const next = lines[i];
|
|
254
|
+
if (startsNewParagraph(prev, next, modalSpacing, dominantLeftX)) paragraphs.push({ lines: [next] });
|
|
255
|
+
else paragraphs[paragraphs.length - 1].lines.push(next);
|
|
256
|
+
}
|
|
257
|
+
return paragraphs;
|
|
258
|
+
}
|
|
259
|
+
function startsNewParagraph(prev, next, modalSpacing, dominantLeftX) {
|
|
260
|
+
if (prev.baselineY - next.baselineY > 1.25 * modalSpacing) return true;
|
|
261
|
+
if (!fontSizesClose(prev.items[0].sizePt, next.items[0].sizePt)) return true;
|
|
262
|
+
const nextLeft = next.items[0].xPt;
|
|
263
|
+
const prevLeft = prev.items[0].xPt;
|
|
264
|
+
const emPt = next.items[0].sizePt;
|
|
265
|
+
const nextIndented = Math.abs(nextLeft - dominantLeftX) > emPt;
|
|
266
|
+
const prevAtMargin = Math.abs(prevLeft - dominantLeftX) <= emPt;
|
|
267
|
+
return nextIndented && prevAtMargin;
|
|
268
|
+
}
|
|
269
|
+
const LEFT_ALIGN_TOLERANCE_PT = 2;
|
|
270
|
+
function paragraphToContentParagraph(paragraph, pageIndex, headingLevel) {
|
|
271
|
+
const dominantLeftX = modeOf(paragraph.lines.map((l) => l.items[0].xPt), 1);
|
|
272
|
+
const result = {
|
|
273
|
+
kind: "paragraph",
|
|
274
|
+
runs: [],
|
|
275
|
+
alignment: paragraph.lines.every((l) => Math.abs(l.items[0].xPt - dominantLeftX) <= 2) ? "left" : void 0,
|
|
276
|
+
...headingLevel !== void 0 ? {
|
|
277
|
+
styleId: `Heading${String(headingLevel)}`,
|
|
278
|
+
headingLevel
|
|
279
|
+
} : {}
|
|
280
|
+
};
|
|
281
|
+
paragraph.lines.forEach((line, lineIndex) => {
|
|
282
|
+
require_layout_shared.stampFrame(result, pageIndex, lineBox(line, pageIndex));
|
|
283
|
+
if (lineIndex > 0) {
|
|
284
|
+
const lastRun = result.runs[result.runs.length - 1];
|
|
285
|
+
if (lastRun !== void 0) lastRun.text += " ";
|
|
286
|
+
}
|
|
287
|
+
pushRunsForLine(result.runs, line, pageIndex);
|
|
288
|
+
});
|
|
289
|
+
if (headingLevel !== void 0) result.runs = result.runs.map((run) => {
|
|
290
|
+
if (run.bold !== true) return run;
|
|
291
|
+
const withoutBold = { ...run };
|
|
292
|
+
delete withoutBold.bold;
|
|
293
|
+
return withoutBold;
|
|
294
|
+
});
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
297
|
+
//#endregion
|
|
298
|
+
exports.HALF_POINT_BUCKET_PT = HALF_POINT_BUCKET_PT;
|
|
299
|
+
exports.LARGE_GAP_EM_MULTIPLIER = LARGE_GAP_EM_MULTIPLIER;
|
|
300
|
+
exports.LEFT_ALIGN_TOLERANCE_PT = LEFT_ALIGN_TOLERANCE_PT;
|
|
301
|
+
exports.MIN_WORD_GAP_PT = MIN_WORD_GAP_PT;
|
|
302
|
+
exports.PARAGRAPH_GAP_MULTIPLIER = PARAGRAPH_GAP_MULTIPLIER;
|
|
303
|
+
exports.bucketCounts = bucketCounts;
|
|
304
|
+
exports.clusterIntoLines = clusterIntoLines;
|
|
305
|
+
exports.clusterIntoParagraphs = clusterIntoParagraphs;
|
|
306
|
+
exports.estimateModalLineSpacing = estimateModalLineSpacing;
|
|
307
|
+
exports.fontSizesClose = fontSizesClose;
|
|
308
|
+
exports.gapExceeds = gapExceeds;
|
|
309
|
+
exports.lineBox = lineBox;
|
|
310
|
+
exports.modeOf = modeOf;
|
|
311
|
+
exports.paragraphToContentParagraph = paragraphToContentParagraph;
|
|
312
|
+
exports.pushRunsForLine = pushRunsForLine;
|
|
313
|
+
exports.textBoxOfItem = textBoxOfItem;
|
|
314
|
+
exports.textItemToContentRun = textItemToContentRun;
|
|
315
|
+
exports.textItemVerticalExtent = textItemVerticalExtent;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { _ as pushRunsForLine, a as PARAGRAPH_GAP_MULTIPLIER, b as textItemVerticalExtent, c as bucketCounts, d as estimateModalLineSpacing, f as fontSizesClose, g as paragraphToContentParagraph, h as modeOf, i as MIN_WORD_GAP_PT, l as clusterIntoLines, m as lineBox, n as LARGE_GAP_EM_MULTIPLIER, o as TextLine, p as gapExceeds, r as LEFT_ALIGN_TOLERANCE_PT, s as TextParagraph, t as HALF_POINT_BUCKET_PT, u as clusterIntoParagraphs, v as textBoxOfItem, y as textItemToContentRun } from "../reconstruct-lines-B7t66ICm.cjs";
|
|
2
|
+
export { HALF_POINT_BUCKET_PT, LARGE_GAP_EM_MULTIPLIER, LEFT_ALIGN_TOLERANCE_PT, MIN_WORD_GAP_PT, PARAGRAPH_GAP_MULTIPLIER, TextLine, TextParagraph, bucketCounts, clusterIntoLines, clusterIntoParagraphs, estimateModalLineSpacing, fontSizesClose, gapExceeds, lineBox, modeOf, paragraphToContentParagraph, pushRunsForLine, textBoxOfItem, textItemToContentRun, textItemVerticalExtent };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { _ as pushRunsForLine, a as PARAGRAPH_GAP_MULTIPLIER, b as textItemVerticalExtent, c as bucketCounts, d as estimateModalLineSpacing, f as fontSizesClose, g as paragraphToContentParagraph, h as modeOf, i as MIN_WORD_GAP_PT, l as clusterIntoLines, m as lineBox, n as LARGE_GAP_EM_MULTIPLIER, o as TextLine, p as gapExceeds, r as LEFT_ALIGN_TOLERANCE_PT, s as TextParagraph, t as HALF_POINT_BUCKET_PT, u as clusterIntoParagraphs, v as textBoxOfItem, y as textItemToContentRun } from "../reconstruct-lines-B7t66ICm.js";
|
|
2
|
+
export { HALF_POINT_BUCKET_PT, LARGE_GAP_EM_MULTIPLIER, LEFT_ALIGN_TOLERANCE_PT, MIN_WORD_GAP_PT, PARAGRAPH_GAP_MULTIPLIER, TextLine, TextParagraph, bucketCounts, clusterIntoLines, clusterIntoParagraphs, estimateModalLineSpacing, fontSizesClose, gapExceeds, lineBox, modeOf, paragraphToContentParagraph, pushRunsForLine, textBoxOfItem, textItemToContentRun, textItemVerticalExtent };
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { stampFrame } from "./shared.js";
|
|
2
|
+
import { resolveStandardFont } from "pdf-codec/fonts";
|
|
3
|
+
import { STANDARD_METRICS } from "pdf-codec/afm-widths";
|
|
4
|
+
import { runGapPt, runsShareBaseline } from "pdf-codec/text-group";
|
|
5
|
+
//#region src/layout/reconstruct-lines.ts
|
|
6
|
+
const LINE_BASELINE_TOLERANCE_FACTOR = .5;
|
|
7
|
+
const AFM_UNITS_PER_EM = 1e3;
|
|
8
|
+
const HALF_POINT_BUCKET_PT = .5;
|
|
9
|
+
function sharesBaseline(anchor, item) {
|
|
10
|
+
return runsShareBaseline(anchor, item, { baselineToleranceEm: LINE_BASELINE_TOLERANCE_FACTOR });
|
|
11
|
+
}
|
|
12
|
+
const DUPLICATE_PAINT_BUCKET_PT = .1;
|
|
13
|
+
function duplicatePaintKey(item) {
|
|
14
|
+
const xBucket = Math.round(item.xPt / DUPLICATE_PAINT_BUCKET_PT);
|
|
15
|
+
const yBucket = Math.round(item.yPt / DUPLICATE_PAINT_BUCKET_PT);
|
|
16
|
+
return `${item.text.trim()}|${String(xBucket)}|${String(yBucket)}`;
|
|
17
|
+
}
|
|
18
|
+
function dropDuplicatePaints(items) {
|
|
19
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20
|
+
const kept = [];
|
|
21
|
+
for (const item of items) {
|
|
22
|
+
const key = duplicatePaintKey(item);
|
|
23
|
+
if (seen.has(key)) continue;
|
|
24
|
+
seen.add(key);
|
|
25
|
+
kept.push(item);
|
|
26
|
+
}
|
|
27
|
+
return kept;
|
|
28
|
+
}
|
|
29
|
+
function dropOverlappingRepeatsWithinLine(items) {
|
|
30
|
+
const rightEdgeByText = /* @__PURE__ */ new Map();
|
|
31
|
+
const kept = [];
|
|
32
|
+
for (const item of items) {
|
|
33
|
+
const textKey = item.text.trim();
|
|
34
|
+
const priorRightEdge = rightEdgeByText.get(textKey);
|
|
35
|
+
if (priorRightEdge !== void 0 && item.xPt < priorRightEdge) continue;
|
|
36
|
+
rightEdgeByText.set(textKey, item.xPt + (item.widthPt ?? 0));
|
|
37
|
+
kept.push(item);
|
|
38
|
+
}
|
|
39
|
+
return kept;
|
|
40
|
+
}
|
|
41
|
+
const REDRAW_PASS_REWIND_TOLERANCE_PT = 2;
|
|
42
|
+
const MIN_REDRAW_PASS_TEXT_LENGTH = 12;
|
|
43
|
+
const REDRAW_PASS_SIMILARITY_THRESHOLD = .6;
|
|
44
|
+
function groupByBaselineInDocumentOrder(items) {
|
|
45
|
+
const groups = [];
|
|
46
|
+
for (const item of items) {
|
|
47
|
+
const group = groups.find((g) => sharesBaseline(g.anchor, item));
|
|
48
|
+
if (group === void 0) groups.push({
|
|
49
|
+
anchor: item,
|
|
50
|
+
items: [item]
|
|
51
|
+
});
|
|
52
|
+
else group.items.push(item);
|
|
53
|
+
}
|
|
54
|
+
return groups.map((g) => g.items);
|
|
55
|
+
}
|
|
56
|
+
function splitIntoPasses(group) {
|
|
57
|
+
const passes = [];
|
|
58
|
+
for (const item of group) {
|
|
59
|
+
const current = passes.at(-1);
|
|
60
|
+
const itemRightPt = item.xPt + (item.widthPt ?? 0);
|
|
61
|
+
if (current !== void 0 && item.xPt >= current.endXPt - REDRAW_PASS_REWIND_TOLERANCE_PT) {
|
|
62
|
+
current.items.push(item);
|
|
63
|
+
current.endXPt = Math.max(current.endXPt, itemRightPt);
|
|
64
|
+
} else passes.push({
|
|
65
|
+
items: [item],
|
|
66
|
+
startXPt: item.xPt,
|
|
67
|
+
endXPt: itemRightPt
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return passes;
|
|
71
|
+
}
|
|
72
|
+
function passText(pass) {
|
|
73
|
+
return pass.items.map((item) => item.text).join("").trim();
|
|
74
|
+
}
|
|
75
|
+
function passesOverlap(a, b) {
|
|
76
|
+
return a.startXPt < b.endXPt && b.startXPt < a.endXPt;
|
|
77
|
+
}
|
|
78
|
+
function levenshteinDistance(a, b) {
|
|
79
|
+
const memo = /* @__PURE__ */ new Map();
|
|
80
|
+
function distance(i, j) {
|
|
81
|
+
if (i === 0) return j;
|
|
82
|
+
if (j === 0) return i;
|
|
83
|
+
const key = `${String(i)}:${String(j)}`;
|
|
84
|
+
const cached = memo.get(key);
|
|
85
|
+
if (cached !== void 0) return cached;
|
|
86
|
+
const cost = a.charAt(i - 1) === b.charAt(j - 1) ? 0 : 1;
|
|
87
|
+
const result = Math.min(distance(i - 1, j) + 1, distance(i, j - 1) + 1, distance(i - 1, j - 1) + cost);
|
|
88
|
+
memo.set(key, result);
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
return distance(a.length, b.length);
|
|
92
|
+
}
|
|
93
|
+
function textSimilarity(a, b) {
|
|
94
|
+
const maxLength = Math.max(a.length, b.length);
|
|
95
|
+
return 1 - levenshteinDistance(a, b) / maxLength;
|
|
96
|
+
}
|
|
97
|
+
function dropFuzzyRedrawnPasses(items) {
|
|
98
|
+
const toDrop = /* @__PURE__ */ new Set();
|
|
99
|
+
for (const group of groupByBaselineInDocumentOrder(items)) {
|
|
100
|
+
const passes = splitIntoPasses(group);
|
|
101
|
+
if (passes.length < 2) continue;
|
|
102
|
+
const [first, ...rest] = passes;
|
|
103
|
+
if (first === void 0) continue;
|
|
104
|
+
const firstText = passText(first);
|
|
105
|
+
if (firstText.length < MIN_REDRAW_PASS_TEXT_LENGTH) continue;
|
|
106
|
+
for (const candidate of rest) {
|
|
107
|
+
const candidateText = passText(candidate);
|
|
108
|
+
if (candidateText.length < MIN_REDRAW_PASS_TEXT_LENGTH) continue;
|
|
109
|
+
if (!passesOverlap(first, candidate)) continue;
|
|
110
|
+
if (textSimilarity(firstText, candidateText) < REDRAW_PASS_SIMILARITY_THRESHOLD) continue;
|
|
111
|
+
for (const item of candidate.items) toDrop.add(item);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (toDrop.size === 0) return items;
|
|
115
|
+
return items.filter((item) => !toDrop.has(item));
|
|
116
|
+
}
|
|
117
|
+
function clusterIntoLines(items) {
|
|
118
|
+
const sorted = [...dropDuplicatePaints(dropFuzzyRedrawnPasses(items))].sort((a, b) => b.yPt - a.yPt || a.xPt - b.xPt);
|
|
119
|
+
const working = [];
|
|
120
|
+
for (const item of sorted) {
|
|
121
|
+
const line = working.find((l) => sharesBaseline(l.anchor, item));
|
|
122
|
+
if (line === void 0) working.push({
|
|
123
|
+
items: [item],
|
|
124
|
+
baselineY: item.yPt,
|
|
125
|
+
anchor: item
|
|
126
|
+
});
|
|
127
|
+
else line.items.push(item);
|
|
128
|
+
}
|
|
129
|
+
for (const line of working) {
|
|
130
|
+
line.items.sort((a, b) => a.xPt - b.xPt);
|
|
131
|
+
line.items = dropOverlappingRepeatsWithinLine(line.items);
|
|
132
|
+
}
|
|
133
|
+
working.sort((a, b) => b.baselineY - a.baselineY);
|
|
134
|
+
return working;
|
|
135
|
+
}
|
|
136
|
+
function textItemVerticalExtent(item) {
|
|
137
|
+
const { standardName } = resolveStandardFont(item.font.family, item.font.weight === "bold", item.font.style === "italic");
|
|
138
|
+
const metrics = STANDARD_METRICS[standardName];
|
|
139
|
+
return {
|
|
140
|
+
ascentPt: metrics.ascender / AFM_UNITS_PER_EM * item.sizePt,
|
|
141
|
+
descentPt: Math.abs(metrics.descender) / AFM_UNITS_PER_EM * item.sizePt
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function textItemToContentRun(item) {
|
|
145
|
+
return {
|
|
146
|
+
text: item.text,
|
|
147
|
+
...item.font.weight === "bold" ? { bold: true } : {},
|
|
148
|
+
...item.font.style === "italic" ? { italic: true } : {},
|
|
149
|
+
fontFamily: item.font.family,
|
|
150
|
+
sizePt: item.sizePt,
|
|
151
|
+
color: item.color
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const MIN_WORD_GAP_PT = .5;
|
|
155
|
+
function gapExceeds(previous, next, thresholdPt) {
|
|
156
|
+
const gap = runGapPt(previous, next);
|
|
157
|
+
return gap !== void 0 && gap > thresholdPt;
|
|
158
|
+
}
|
|
159
|
+
function textBoxOfItem(item, pageIndex) {
|
|
160
|
+
const { ascentPt, descentPt } = textItemVerticalExtent(item);
|
|
161
|
+
return {
|
|
162
|
+
pageIndex,
|
|
163
|
+
xPt: item.xPt,
|
|
164
|
+
yPt: item.yPt - descentPt,
|
|
165
|
+
widthPt: item.widthPt ?? 0,
|
|
166
|
+
heightPt: ascentPt + descentPt
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function lineBox(line, pageIndex) {
|
|
170
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
171
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
172
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
173
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
174
|
+
for (const item of line.items) {
|
|
175
|
+
const { ascentPt, descentPt } = textItemVerticalExtent(item);
|
|
176
|
+
minX = Math.min(minX, item.xPt);
|
|
177
|
+
maxX = Math.max(maxX, item.xPt + (item.widthPt ?? 0));
|
|
178
|
+
minY = Math.min(minY, item.yPt - descentPt);
|
|
179
|
+
maxY = Math.max(maxY, item.yPt + ascentPt);
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
pageIndex,
|
|
183
|
+
xPt: minX,
|
|
184
|
+
yPt: minY,
|
|
185
|
+
widthPt: maxX - minX,
|
|
186
|
+
heightPt: maxY - minY
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function pushRunsForLine(runs, line, pageIndex) {
|
|
190
|
+
line.items.forEach((item, itemIndex) => {
|
|
191
|
+
if (itemIndex > 0) {
|
|
192
|
+
const prevItem = line.items[itemIndex - 1];
|
|
193
|
+
if (gapExceeds(prevItem, item, 2 * item.sizePt)) runs.push({ text: " " });
|
|
194
|
+
else if (gapExceeds(prevItem, item, .5)) runs[runs.length - 1].text += " ";
|
|
195
|
+
}
|
|
196
|
+
const run = textItemToContentRun(item);
|
|
197
|
+
stampFrame(run, pageIndex, textBoxOfItem(item, pageIndex));
|
|
198
|
+
runs.push(run);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
function bucketCounts(values, bucketSize) {
|
|
202
|
+
const counts = /* @__PURE__ */ new Map();
|
|
203
|
+
for (const v of values) {
|
|
204
|
+
const bucket = Math.round(v / bucketSize) * bucketSize;
|
|
205
|
+
counts.set(bucket, (counts.get(bucket) ?? 0) + 1);
|
|
206
|
+
}
|
|
207
|
+
return counts;
|
|
208
|
+
}
|
|
209
|
+
function modeOf(values, bucketSize) {
|
|
210
|
+
if (values.length === 0) return 0;
|
|
211
|
+
const counts = bucketCounts(values, bucketSize);
|
|
212
|
+
let bestBucket = values[0];
|
|
213
|
+
let bestCount = 0;
|
|
214
|
+
for (const [bucket, count] of counts) if (count > bestCount) {
|
|
215
|
+
bestBucket = bucket;
|
|
216
|
+
bestCount = count;
|
|
217
|
+
}
|
|
218
|
+
return bestBucket;
|
|
219
|
+
}
|
|
220
|
+
function modalLineGap(gaps) {
|
|
221
|
+
const counts = bucketCounts(gaps, HALF_POINT_BUCKET_PT);
|
|
222
|
+
let bestBucket = gaps[0];
|
|
223
|
+
let bestCount = 0;
|
|
224
|
+
for (const [bucket, count] of counts) if (count > bestCount) {
|
|
225
|
+
bestBucket = bucket;
|
|
226
|
+
bestCount = count;
|
|
227
|
+
}
|
|
228
|
+
return bestCount > 1 ? bestBucket : Math.min(...gaps);
|
|
229
|
+
}
|
|
230
|
+
const LARGE_GAP_EM_MULTIPLIER = 2;
|
|
231
|
+
const FONT_SIZE_CLOSE_TOLERANCE_PT = 1;
|
|
232
|
+
const FONT_SIZE_CLOSE_TOLERANCE_RATIO = .15;
|
|
233
|
+
function fontSizesClose(a, b) {
|
|
234
|
+
return Math.abs(a - b) <= FONT_SIZE_CLOSE_TOLERANCE_PT || Math.abs(a - b) / Math.max(a, b) <= FONT_SIZE_CLOSE_TOLERANCE_RATIO;
|
|
235
|
+
}
|
|
236
|
+
const PARAGRAPH_GAP_MULTIPLIER = 1.25;
|
|
237
|
+
const NOMINAL_LINE_SPACING_RATIO = 1.2;
|
|
238
|
+
const MIN_LINES_FOR_GAP_MODE = 3;
|
|
239
|
+
function estimateModalLineSpacing(lines) {
|
|
240
|
+
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;
|
|
241
|
+
const gaps = [];
|
|
242
|
+
for (let i = 1; i < lines.length; i++) gaps.push(lines[i - 1].baselineY - lines[i].baselineY);
|
|
243
|
+
return modalLineGap(gaps);
|
|
244
|
+
}
|
|
245
|
+
function clusterIntoParagraphs(lines) {
|
|
246
|
+
if (lines.length === 0) return [];
|
|
247
|
+
const modalSpacing = estimateModalLineSpacing(lines);
|
|
248
|
+
const dominantLeftX = modeOf(lines.map((l) => l.items[0].xPt), 1);
|
|
249
|
+
const paragraphs = [{ lines: [lines[0]] }];
|
|
250
|
+
for (let i = 1; i < lines.length; i++) {
|
|
251
|
+
const prev = lines[i - 1];
|
|
252
|
+
const next = lines[i];
|
|
253
|
+
if (startsNewParagraph(prev, next, modalSpacing, dominantLeftX)) paragraphs.push({ lines: [next] });
|
|
254
|
+
else paragraphs[paragraphs.length - 1].lines.push(next);
|
|
255
|
+
}
|
|
256
|
+
return paragraphs;
|
|
257
|
+
}
|
|
258
|
+
function startsNewParagraph(prev, next, modalSpacing, dominantLeftX) {
|
|
259
|
+
if (prev.baselineY - next.baselineY > 1.25 * modalSpacing) return true;
|
|
260
|
+
if (!fontSizesClose(prev.items[0].sizePt, next.items[0].sizePt)) return true;
|
|
261
|
+
const nextLeft = next.items[0].xPt;
|
|
262
|
+
const prevLeft = prev.items[0].xPt;
|
|
263
|
+
const emPt = next.items[0].sizePt;
|
|
264
|
+
const nextIndented = Math.abs(nextLeft - dominantLeftX) > emPt;
|
|
265
|
+
const prevAtMargin = Math.abs(prevLeft - dominantLeftX) <= emPt;
|
|
266
|
+
return nextIndented && prevAtMargin;
|
|
267
|
+
}
|
|
268
|
+
const LEFT_ALIGN_TOLERANCE_PT = 2;
|
|
269
|
+
function paragraphToContentParagraph(paragraph, pageIndex, headingLevel) {
|
|
270
|
+
const dominantLeftX = modeOf(paragraph.lines.map((l) => l.items[0].xPt), 1);
|
|
271
|
+
const result = {
|
|
272
|
+
kind: "paragraph",
|
|
273
|
+
runs: [],
|
|
274
|
+
alignment: paragraph.lines.every((l) => Math.abs(l.items[0].xPt - dominantLeftX) <= 2) ? "left" : void 0,
|
|
275
|
+
...headingLevel !== void 0 ? {
|
|
276
|
+
styleId: `Heading${String(headingLevel)}`,
|
|
277
|
+
headingLevel
|
|
278
|
+
} : {}
|
|
279
|
+
};
|
|
280
|
+
paragraph.lines.forEach((line, lineIndex) => {
|
|
281
|
+
stampFrame(result, pageIndex, lineBox(line, pageIndex));
|
|
282
|
+
if (lineIndex > 0) {
|
|
283
|
+
const lastRun = result.runs[result.runs.length - 1];
|
|
284
|
+
if (lastRun !== void 0) lastRun.text += " ";
|
|
285
|
+
}
|
|
286
|
+
pushRunsForLine(result.runs, line, pageIndex);
|
|
287
|
+
});
|
|
288
|
+
if (headingLevel !== void 0) result.runs = result.runs.map((run) => {
|
|
289
|
+
if (run.bold !== true) return run;
|
|
290
|
+
const withoutBold = { ...run };
|
|
291
|
+
delete withoutBold.bold;
|
|
292
|
+
return withoutBold;
|
|
293
|
+
});
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
296
|
+
//#endregion
|
|
297
|
+
export { HALF_POINT_BUCKET_PT, LARGE_GAP_EM_MULTIPLIER, LEFT_ALIGN_TOLERANCE_PT, MIN_WORD_GAP_PT, PARAGRAPH_GAP_MULTIPLIER, bucketCounts, clusterIntoLines, clusterIntoParagraphs, estimateModalLineSpacing, fontSizesClose, gapExceeds, lineBox, modeOf, paragraphToContentParagraph, pushRunsForLine, textBoxOfItem, textItemToContentRun, textItemVerticalExtent };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_reconstruct_presentations_prod = require("../reconstruct-presentations-prod-X315aBmI.cjs");
|
|
3
|
+
exports.layoutItemToVector = require_reconstruct_presentations_prod.layoutItemToVector;
|
|
4
|
+
exports.lineToParagraph = require_reconstruct_presentations_prod.lineToParagraph;
|
|
5
|
+
exports.reconstructDrawing = require_reconstruct_presentations_prod.reconstructDrawing;
|
|
6
|
+
exports.reconstructPresentation = require_reconstruct_presentations_prod.reconstructPresentation;
|
|
7
|
+
exports.reconstructSheet = require_reconstruct_presentations_prod.reconstructSheet;
|
|
8
|
+
exports.recoverPageVectors = require_reconstruct_presentations_prod.recoverPageVectors;
|
|
9
|
+
exports.splitLineByLargeGaps = require_reconstruct_presentations_prod.splitLineByLargeGaps;
|