js.documents 7.2.3 → 7.2.5
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/layout/lattice.cjs +47 -21
- package/dist/layout/lattice.js +47 -21
- package/package.json +2 -2
package/dist/layout/lattice.cjs
CHANGED
|
@@ -106,24 +106,24 @@ function dedupeAxisLines(segments, descending) {
|
|
|
106
106
|
}
|
|
107
107
|
const MIN_GRIDLINE_COUNT_PER_AXIS = 3;
|
|
108
108
|
const EDGE_COVERAGE_RATIO = .9;
|
|
109
|
-
function
|
|
109
|
+
function unionCoverageRatio(ranges, aPt, bPt) {
|
|
110
110
|
const lo = Math.min(aPt, bPt);
|
|
111
111
|
const hi = Math.max(aPt, bPt);
|
|
112
112
|
if (hi <= lo) return 1;
|
|
113
|
-
let
|
|
113
|
+
let coveredPt = 0;
|
|
114
114
|
for (const range of ranges) {
|
|
115
115
|
const overlapLo = Math.max(range.startPt, lo);
|
|
116
116
|
const overlapHi = Math.min(range.endPt, hi);
|
|
117
|
-
if (overlapHi > overlapLo)
|
|
117
|
+
if (overlapHi > overlapLo) coveredPt += overlapHi - overlapLo;
|
|
118
118
|
}
|
|
119
|
-
return
|
|
119
|
+
return coveredPt / (hi - lo);
|
|
120
120
|
}
|
|
121
121
|
function hasClosedOuterRectangle(rowLines, columnLines) {
|
|
122
122
|
const leftXPt = columnLines[0].position;
|
|
123
123
|
const rightXPt = columnLines[columnLines.length - 1].position;
|
|
124
124
|
const topYPt = rowLines[0].position;
|
|
125
125
|
const bottomYPt = rowLines[rowLines.length - 1].position;
|
|
126
|
-
return
|
|
126
|
+
return unionCoverageRatio(rowLines[0].ranges, leftXPt, rightXPt) >= EDGE_COVERAGE_RATIO && unionCoverageRatio(rowLines[rowLines.length - 1].ranges, leftXPt, rightXPt) >= EDGE_COVERAGE_RATIO && unionCoverageRatio(columnLines[0].ranges, bottomYPt, topYPt) >= EDGE_COVERAGE_RATIO && unionCoverageRatio(columnLines[columnLines.length - 1].ranges, bottomYPt, topYPt) >= EDGE_COVERAGE_RATIO;
|
|
127
127
|
}
|
|
128
128
|
function unionFind(size) {
|
|
129
129
|
return Array.from({ length: size }, (_, i) => i);
|
|
@@ -154,7 +154,7 @@ function findCellRegions(rowLines, columnLines) {
|
|
|
154
154
|
const rowBottomPt = rowLines[i + 1].position;
|
|
155
155
|
for (let j = 0; j < colCount - 1; j++) {
|
|
156
156
|
const divider = columnLines[j + 1];
|
|
157
|
-
if (
|
|
157
|
+
if (unionCoverageRatio(divider.ranges, rowBottomPt, rowTopPt) < EDGE_COVERAGE_RATIO) union(parents, indexOf(i, j), indexOf(i, j + 1));
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
for (let j = 0; j < colCount; j++) {
|
|
@@ -162,7 +162,7 @@ function findCellRegions(rowLines, columnLines) {
|
|
|
162
162
|
const colRightPt = columnLines[j + 1].position;
|
|
163
163
|
for (let i = 0; i < rowCount - 1; i++) {
|
|
164
164
|
const divider = rowLines[i + 1];
|
|
165
|
-
if (
|
|
165
|
+
if (unionCoverageRatio(divider.ranges, colLeftPt, colRightPt) < EDGE_COVERAGE_RATIO) union(parents, indexOf(i, j), indexOf(i + 1, j));
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
const cellsByRoot = /* @__PURE__ */ new Map();
|
|
@@ -204,6 +204,22 @@ function findCellRegions(rowLines, columnLines) {
|
|
|
204
204
|
regions.sort((a, b) => a.rowStart - b.rowStart || a.colStart - b.colStart);
|
|
205
205
|
return regions;
|
|
206
206
|
}
|
|
207
|
+
function segmentsCross(h, v) {
|
|
208
|
+
return v.position >= h.startPt - POSITION_DEDUPE_TOLERANCE_PT && v.position <= h.endPt + POSITION_DEDUPE_TOLERANCE_PT && h.position >= v.startPt - POSITION_DEDUPE_TOLERANCE_PT && h.position <= v.endPt + POSITION_DEDUPE_TOLERANCE_PT;
|
|
209
|
+
}
|
|
210
|
+
function clusterSegments(horizontal, vertical) {
|
|
211
|
+
const all = [...horizontal, ...vertical];
|
|
212
|
+
const parents = unionFind(all.length);
|
|
213
|
+
for (let i = 0; i < horizontal.length; i++) for (let j = 0; j < vertical.length; j++) if (segmentsCross(horizontal[i], vertical[j])) union(parents, i, horizontal.length + j);
|
|
214
|
+
const clusters = /* @__PURE__ */ new Map();
|
|
215
|
+
for (let i = 0; i < all.length; i++) {
|
|
216
|
+
const root = findRoot(parents, i);
|
|
217
|
+
const cluster = clusters.get(root);
|
|
218
|
+
if (cluster === void 0) clusters.set(root, [all[i]]);
|
|
219
|
+
else cluster.push(all[i]);
|
|
220
|
+
}
|
|
221
|
+
return [...clusters.values()];
|
|
222
|
+
}
|
|
207
223
|
function detectGridLattice(items) {
|
|
208
224
|
const horizontal = [];
|
|
209
225
|
const vertical = [];
|
|
@@ -212,20 +228,30 @@ function detectGridLattice(items) {
|
|
|
212
228
|
if (classified === void 0) continue;
|
|
213
229
|
(classified.axis === "horizontal" ? horizontal : vertical).push(classified);
|
|
214
230
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
231
|
+
let best;
|
|
232
|
+
let bestAreaPt2 = 0;
|
|
233
|
+
for (const cluster of clusterSegments(horizontal, vertical)) {
|
|
234
|
+
const clusterHorizontal = cluster.filter((s) => s.axis === "horizontal");
|
|
235
|
+
const clusterVertical = cluster.filter((s) => s.axis === "vertical");
|
|
236
|
+
const rowLines = dedupeAxisLines(clusterHorizontal, true);
|
|
237
|
+
const columnLines = dedupeAxisLines(clusterVertical, false);
|
|
238
|
+
if (rowLines.length < MIN_GRIDLINE_COUNT_PER_AXIS || columnLines.length < MIN_GRIDLINE_COUNT_PER_AXIS) continue;
|
|
239
|
+
if (!hasClosedOuterRectangle(rowLines, columnLines)) continue;
|
|
240
|
+
const regions = findCellRegions(rowLines, columnLines);
|
|
241
|
+
if (regions === void 0) continue;
|
|
242
|
+
const areaPt2 = (columnLines[columnLines.length - 1].position - columnLines[0].position) * (rowLines[0].position - rowLines[rowLines.length - 1].position);
|
|
243
|
+
if (best !== void 0 && areaPt2 <= bestAreaPt2) continue;
|
|
244
|
+
const sourceItems = /* @__PURE__ */ new Set();
|
|
245
|
+
for (const line of [...rowLines, ...columnLines]) for (const item of line.items) sourceItems.add(item);
|
|
246
|
+
best = {
|
|
247
|
+
rowBoundariesDescPt: rowLines.map((l) => l.position),
|
|
248
|
+
columnBoundariesAscPt: columnLines.map((l) => l.position),
|
|
249
|
+
regions,
|
|
250
|
+
sourceItems
|
|
251
|
+
};
|
|
252
|
+
bestAreaPt2 = areaPt2;
|
|
253
|
+
}
|
|
254
|
+
return best;
|
|
229
255
|
}
|
|
230
256
|
const OUTER_EDGE_TOLERANCE_PT = 3;
|
|
231
257
|
function findRowIndex(rowBoundariesDescPt, yPt) {
|
package/dist/layout/lattice.js
CHANGED
|
@@ -105,24 +105,24 @@ function dedupeAxisLines(segments, descending) {
|
|
|
105
105
|
}
|
|
106
106
|
const MIN_GRIDLINE_COUNT_PER_AXIS = 3;
|
|
107
107
|
const EDGE_COVERAGE_RATIO = .9;
|
|
108
|
-
function
|
|
108
|
+
function unionCoverageRatio(ranges, aPt, bPt) {
|
|
109
109
|
const lo = Math.min(aPt, bPt);
|
|
110
110
|
const hi = Math.max(aPt, bPt);
|
|
111
111
|
if (hi <= lo) return 1;
|
|
112
|
-
let
|
|
112
|
+
let coveredPt = 0;
|
|
113
113
|
for (const range of ranges) {
|
|
114
114
|
const overlapLo = Math.max(range.startPt, lo);
|
|
115
115
|
const overlapHi = Math.min(range.endPt, hi);
|
|
116
|
-
if (overlapHi > overlapLo)
|
|
116
|
+
if (overlapHi > overlapLo) coveredPt += overlapHi - overlapLo;
|
|
117
117
|
}
|
|
118
|
-
return
|
|
118
|
+
return coveredPt / (hi - lo);
|
|
119
119
|
}
|
|
120
120
|
function hasClosedOuterRectangle(rowLines, columnLines) {
|
|
121
121
|
const leftXPt = columnLines[0].position;
|
|
122
122
|
const rightXPt = columnLines[columnLines.length - 1].position;
|
|
123
123
|
const topYPt = rowLines[0].position;
|
|
124
124
|
const bottomYPt = rowLines[rowLines.length - 1].position;
|
|
125
|
-
return
|
|
125
|
+
return unionCoverageRatio(rowLines[0].ranges, leftXPt, rightXPt) >= EDGE_COVERAGE_RATIO && unionCoverageRatio(rowLines[rowLines.length - 1].ranges, leftXPt, rightXPt) >= EDGE_COVERAGE_RATIO && unionCoverageRatio(columnLines[0].ranges, bottomYPt, topYPt) >= EDGE_COVERAGE_RATIO && unionCoverageRatio(columnLines[columnLines.length - 1].ranges, bottomYPt, topYPt) >= EDGE_COVERAGE_RATIO;
|
|
126
126
|
}
|
|
127
127
|
function unionFind(size) {
|
|
128
128
|
return Array.from({ length: size }, (_, i) => i);
|
|
@@ -153,7 +153,7 @@ function findCellRegions(rowLines, columnLines) {
|
|
|
153
153
|
const rowBottomPt = rowLines[i + 1].position;
|
|
154
154
|
for (let j = 0; j < colCount - 1; j++) {
|
|
155
155
|
const divider = columnLines[j + 1];
|
|
156
|
-
if (
|
|
156
|
+
if (unionCoverageRatio(divider.ranges, rowBottomPt, rowTopPt) < EDGE_COVERAGE_RATIO) union(parents, indexOf(i, j), indexOf(i, j + 1));
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
for (let j = 0; j < colCount; j++) {
|
|
@@ -161,7 +161,7 @@ function findCellRegions(rowLines, columnLines) {
|
|
|
161
161
|
const colRightPt = columnLines[j + 1].position;
|
|
162
162
|
for (let i = 0; i < rowCount - 1; i++) {
|
|
163
163
|
const divider = rowLines[i + 1];
|
|
164
|
-
if (
|
|
164
|
+
if (unionCoverageRatio(divider.ranges, colLeftPt, colRightPt) < EDGE_COVERAGE_RATIO) union(parents, indexOf(i, j), indexOf(i + 1, j));
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
const cellsByRoot = /* @__PURE__ */ new Map();
|
|
@@ -203,6 +203,22 @@ function findCellRegions(rowLines, columnLines) {
|
|
|
203
203
|
regions.sort((a, b) => a.rowStart - b.rowStart || a.colStart - b.colStart);
|
|
204
204
|
return regions;
|
|
205
205
|
}
|
|
206
|
+
function segmentsCross(h, v) {
|
|
207
|
+
return v.position >= h.startPt - POSITION_DEDUPE_TOLERANCE_PT && v.position <= h.endPt + POSITION_DEDUPE_TOLERANCE_PT && h.position >= v.startPt - POSITION_DEDUPE_TOLERANCE_PT && h.position <= v.endPt + POSITION_DEDUPE_TOLERANCE_PT;
|
|
208
|
+
}
|
|
209
|
+
function clusterSegments(horizontal, vertical) {
|
|
210
|
+
const all = [...horizontal, ...vertical];
|
|
211
|
+
const parents = unionFind(all.length);
|
|
212
|
+
for (let i = 0; i < horizontal.length; i++) for (let j = 0; j < vertical.length; j++) if (segmentsCross(horizontal[i], vertical[j])) union(parents, i, horizontal.length + j);
|
|
213
|
+
const clusters = /* @__PURE__ */ new Map();
|
|
214
|
+
for (let i = 0; i < all.length; i++) {
|
|
215
|
+
const root = findRoot(parents, i);
|
|
216
|
+
const cluster = clusters.get(root);
|
|
217
|
+
if (cluster === void 0) clusters.set(root, [all[i]]);
|
|
218
|
+
else cluster.push(all[i]);
|
|
219
|
+
}
|
|
220
|
+
return [...clusters.values()];
|
|
221
|
+
}
|
|
206
222
|
function detectGridLattice(items) {
|
|
207
223
|
const horizontal = [];
|
|
208
224
|
const vertical = [];
|
|
@@ -211,20 +227,30 @@ function detectGridLattice(items) {
|
|
|
211
227
|
if (classified === void 0) continue;
|
|
212
228
|
(classified.axis === "horizontal" ? horizontal : vertical).push(classified);
|
|
213
229
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
230
|
+
let best;
|
|
231
|
+
let bestAreaPt2 = 0;
|
|
232
|
+
for (const cluster of clusterSegments(horizontal, vertical)) {
|
|
233
|
+
const clusterHorizontal = cluster.filter((s) => s.axis === "horizontal");
|
|
234
|
+
const clusterVertical = cluster.filter((s) => s.axis === "vertical");
|
|
235
|
+
const rowLines = dedupeAxisLines(clusterHorizontal, true);
|
|
236
|
+
const columnLines = dedupeAxisLines(clusterVertical, false);
|
|
237
|
+
if (rowLines.length < MIN_GRIDLINE_COUNT_PER_AXIS || columnLines.length < MIN_GRIDLINE_COUNT_PER_AXIS) continue;
|
|
238
|
+
if (!hasClosedOuterRectangle(rowLines, columnLines)) continue;
|
|
239
|
+
const regions = findCellRegions(rowLines, columnLines);
|
|
240
|
+
if (regions === void 0) continue;
|
|
241
|
+
const areaPt2 = (columnLines[columnLines.length - 1].position - columnLines[0].position) * (rowLines[0].position - rowLines[rowLines.length - 1].position);
|
|
242
|
+
if (best !== void 0 && areaPt2 <= bestAreaPt2) continue;
|
|
243
|
+
const sourceItems = /* @__PURE__ */ new Set();
|
|
244
|
+
for (const line of [...rowLines, ...columnLines]) for (const item of line.items) sourceItems.add(item);
|
|
245
|
+
best = {
|
|
246
|
+
rowBoundariesDescPt: rowLines.map((l) => l.position),
|
|
247
|
+
columnBoundariesAscPt: columnLines.map((l) => l.position),
|
|
248
|
+
regions,
|
|
249
|
+
sourceItems
|
|
250
|
+
};
|
|
251
|
+
bestAreaPt2 = areaPt2;
|
|
252
|
+
}
|
|
253
|
+
return best;
|
|
228
254
|
}
|
|
229
255
|
const OUTER_EDGE_TOLERANCE_PT = 3;
|
|
230
256
|
function findRowIndex(rowBoundariesDescPt, yPt) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "js.documents",
|
|
3
|
-
"version": "7.2.
|
|
3
|
+
"version": "7.2.5",
|
|
4
4
|
"description": "Bidirectional docx/pptx <-> PDF conversion and a read+write editable OOXML document model, built on ooxml.js and Zod 4 codecs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"document-schema.js": "^7.0.0",
|
|
84
84
|
"fflate": "^0.8.3",
|
|
85
85
|
"markdown-codec": "^6.3.6",
|
|
86
|
-
"odf.js": "^7.
|
|
86
|
+
"odf.js": "^7.3.0",
|
|
87
87
|
"ooxml.js": "^8.2.0",
|
|
88
88
|
"pdf-codec": "^4.0.5",
|
|
89
89
|
"ppt-codec": "^1.2.6",
|