js.documents 14.5.0 → 14.6.1

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.
Files changed (42) hide show
  1. package/README.md +27 -3
  2. package/dist/{composition-plan-Cofo9qPI.d.cts → composition-plan-D7mR0HWB.d.cts} +5 -0
  3. package/dist/{composition-plan-BgsXTscN.cjs → composition-plan-DJQgPvBj.cjs} +5 -3
  4. package/dist/{composition-plan-mRolIOZY.js → composition-plan-DMTkmk8n.js} +5 -3
  5. package/dist/{composition-plan-B1Nn2JCQ.d.ts → composition-plan-DPZq6NhK.d.ts} +5 -0
  6. package/dist/convert/composition-plan.cjs +1 -1
  7. package/dist/convert/composition-plan.d.cts +1 -1
  8. package/dist/convert/composition-plan.d.ts +1 -1
  9. package/dist/convert/composition-plan.js +1 -1
  10. package/dist/convert/composition-to-pdf.cjs +1 -1
  11. package/dist/convert/composition-to-pdf.d.cts +1 -1
  12. package/dist/convert/composition-to-pdf.d.ts +1 -1
  13. package/dist/convert/composition-to-pdf.js +1 -1
  14. package/dist/convert/composition.cjs +1 -1
  15. package/dist/convert/composition.d.cts +1 -1
  16. package/dist/convert/composition.d.ts +1 -1
  17. package/dist/convert/composition.js +1 -1
  18. package/dist/convert/from-pdf.cjs +14 -4
  19. package/dist/convert/from-pdf.d.cts +9 -0
  20. package/dist/convert/from-pdf.d.ts +9 -0
  21. package/dist/convert/from-pdf.js +14 -4
  22. package/dist/convert/local.cjs +1 -1
  23. package/dist/convert/local.js +1 -1
  24. package/dist/edit/pdf/editor.d.cts +1 -1
  25. package/dist/edit/pdf/editor.d.ts +1 -1
  26. package/dist/index.cjs +8 -2
  27. package/dist/index.d.cts +3 -3
  28. package/dist/index.d.ts +3 -3
  29. package/dist/index.js +4 -4
  30. package/dist/layout/reading-order.cjs +202 -0
  31. package/dist/layout/reading-order.d.cts +40 -0
  32. package/dist/layout/reading-order.d.ts +40 -0
  33. package/dist/layout/reading-order.js +200 -0
  34. package/dist/layout/reconstruct-presentations-prod.cjs +1 -1
  35. package/dist/layout/reconstruct-presentations-prod.js +1 -1
  36. package/dist/layout/reconstruct-tables.cjs +1 -1
  37. package/dist/layout/reconstruct-tables.js +1 -1
  38. package/dist/layout/reconstruct.cjs +1 -1
  39. package/dist/layout/reconstruct.js +1 -1
  40. package/dist/{reconstruct-presentations-prod-CA4no_aw.cjs → reconstruct-presentations-prod-CsvGlvP2.cjs} +9 -5
  41. package/dist/{reconstruct-presentations-prod-CC8ct-5O.js → reconstruct-presentations-prod-D1KbGPxa.js} +9 -5
  42. package/package.json +2 -2
@@ -0,0 +1,200 @@
1
+ import { clusterIntoLines } from "./reconstruct-lines.js";
2
+ import { resolveStandardFont } from "pdf-codec/fonts";
3
+ import { afmWidthOfCode } from "pdf-codec/afm-widths";
4
+ //#region src/layout/reading-order.ts
5
+ const MIN_COLUMN_LINES = 3;
6
+ const MIN_PROSE_MEASURE_CHARS = 20;
7
+ const SPACE_CHAR_CODE = 32;
8
+ const AFM_UNITS_PER_EM = 1e3;
9
+ /**
10
+ * Splits a page's text items into reading-order flows at the column gutters the page's geometry states.
11
+ * @param items - The page's text items in content-stream order, after any table recovery has removed the text it claimed.
12
+ * @returns The flows in reading order, and a locator placing anything else among them. A page with no gutter yields one flow whose lines are `clusterIntoLines(items)`.
13
+ */
14
+ function readingOrder(items) {
15
+ const bands = segment(items);
16
+ const regions = [];
17
+ collectRegions(bands, [], regions);
18
+ return {
19
+ regions,
20
+ locate: (xPt, yPt) => locate(bands, xPt, yPt)
21
+ };
22
+ }
23
+ /**
24
+ * Orders two placed blocks for reading: by reading-order path first, then top to bottom by y.
25
+ * @returns Negative when `a` is read first, positive when `b` is, zero when neither precedes the other.
26
+ */
27
+ function compareReadingPosition(a, b) {
28
+ const length = Math.min(a.path.length, b.path.length);
29
+ for (let i = 0; i < length; i++) {
30
+ const difference = a.path[i] - b.path[i];
31
+ if (difference !== 0) return difference;
32
+ }
33
+ return a.path.length - b.path.length || b.yPt - a.yPt;
34
+ }
35
+ function segment(items) {
36
+ const lines = clusterIntoLines(items);
37
+ const split = findColumnSplit(lines);
38
+ if (split === void 0) return [flowBand(lines)];
39
+ const before = lines.slice(0, split.startLine);
40
+ const band = lines.slice(split.startLine, split.endLine);
41
+ const after = lines.slice(split.endLine);
42
+ return [
43
+ ...before.length > 0 ? segment(itemsOf(before)) : [],
44
+ {
45
+ kind: "columns",
46
+ gutterXPt: (split.loPt + split.hiPt) / 2,
47
+ left: segment(split.left),
48
+ right: segment(split.right),
49
+ topPt: band[0].baselineY,
50
+ bottomPt: band.at(-1).baselineY
51
+ },
52
+ ...after.length > 0 ? segment(itemsOf(after)) : []
53
+ ];
54
+ }
55
+ function flowBand(lines) {
56
+ return {
57
+ kind: "flow",
58
+ lines,
59
+ topPt: lines[0]?.baselineY ?? Number.POSITIVE_INFINITY,
60
+ bottomPt: lines.at(-1)?.baselineY ?? Number.NEGATIVE_INFINITY
61
+ };
62
+ }
63
+ function itemsOf(lines) {
64
+ return lines.flatMap((line) => line.items);
65
+ }
66
+ function collectRegions(bands, prefix, into) {
67
+ bands.forEach((band, index) => {
68
+ if (band.kind === "flow") into.push({
69
+ lines: band.lines,
70
+ path: [...prefix, index]
71
+ });
72
+ else {
73
+ collectRegions(band.left, [
74
+ ...prefix,
75
+ index,
76
+ 0
77
+ ], into);
78
+ collectRegions(band.right, [
79
+ ...prefix,
80
+ index,
81
+ 1
82
+ ], into);
83
+ }
84
+ });
85
+ }
86
+ function locate(bands, xPt, yPt) {
87
+ let index = bands.length - 1;
88
+ for (let i = 0; i + 1 < bands.length; i++) if (yPt >= (bands[i].bottomPt + bands[i + 1].topPt) / 2) {
89
+ index = i;
90
+ break;
91
+ }
92
+ const band = bands[index];
93
+ if (band.kind === "flow") return [index];
94
+ const side = xPt < band.gutterXPt ? 0 : 1;
95
+ return [
96
+ index,
97
+ side,
98
+ ...locate(side === 0 ? band.left : band.right, xPt, yPt)
99
+ ];
100
+ }
101
+ function findColumnSplit(lines) {
102
+ const items = itemsOf(lines);
103
+ if (lines.length < MIN_COLUMN_LINES || !items.every(isMeasurable)) return;
104
+ const runs = gutterRuns(lines, Math.min(...items.map(spaceAdvancePt))).sort((a, b) => b.endLine - b.startLine - (a.endLine - a.startLine) || b.hiPt - b.loPt - (a.hiPt - a.loPt) || a.startLine - b.startLine);
105
+ for (const run of runs) {
106
+ const runItems = itemsOf(lines.slice(run.startLine, run.endLine));
107
+ if (run.hiPt - run.loPt <= Math.max(...runItems.map(spaceAdvancePt))) continue;
108
+ const left = runItems.filter((item) => rightEdge(item) <= run.loPt);
109
+ const right = runItems.filter((item) => item.xPt >= run.hiPt);
110
+ if (isRunningProse(left, run.hiPt - run.loPt) && isRunningProse(right, run.hiPt - run.loPt)) return {
111
+ ...run,
112
+ left,
113
+ right
114
+ };
115
+ }
116
+ }
117
+ function isMeasurable(item) {
118
+ return item.widthPt !== void 0 && item.writingMode === void 0 && (item.rotationDeg ?? 0) === 0;
119
+ }
120
+ function rightEdge(item) {
121
+ return item.xPt + (item.widthPt ?? 0);
122
+ }
123
+ function spaceAdvancePt(item) {
124
+ const { standardName } = resolveStandardFont(item.font.family, item.font.weight === "bold", item.font.style === "italic");
125
+ const advance = afmWidthOfCode(standardName, SPACE_CHAR_CODE);
126
+ if (advance === void 0) throw new Error(`${standardName} has no AFM width for the space glyph`);
127
+ return advance / AFM_UNITS_PER_EM * item.sizePt;
128
+ }
129
+ function freeSpans(line) {
130
+ const sorted = [...line.items].sort((a, b) => a.xPt - b.xPt);
131
+ const spans = [];
132
+ let reachedPt = Number.NEGATIVE_INFINITY;
133
+ for (const item of sorted) {
134
+ if (item.xPt > reachedPt) spans.push({
135
+ loPt: reachedPt,
136
+ hiPt: item.xPt
137
+ });
138
+ reachedPt = Math.max(reachedPt, rightEdge(item));
139
+ }
140
+ spans.push({
141
+ loPt: reachedPt,
142
+ hiPt: Number.POSITIVE_INFINITY
143
+ });
144
+ return spans;
145
+ }
146
+ function gutterRuns(lines, minWidthPt) {
147
+ const runs = [];
148
+ let open = /* @__PURE__ */ new Map();
149
+ const record = (span, endLine) => {
150
+ if (Number.isFinite(span.loPt) && Number.isFinite(span.hiPt) && endLine - span.startLine >= MIN_COLUMN_LINES) runs.push({
151
+ ...span,
152
+ endLine
153
+ });
154
+ };
155
+ lines.forEach((line, lineIndex) => {
156
+ const next = /* @__PURE__ */ new Map();
157
+ const keep = (loPt, hiPt, startLine) => {
158
+ if (hiPt - loPt <= minWidthPt) return;
159
+ const key = `${String(loPt)}|${String(hiPt)}`;
160
+ const existing = next.get(key);
161
+ if (existing === void 0 || startLine < existing.startLine) next.set(key, {
162
+ loPt,
163
+ hiPt,
164
+ startLine
165
+ });
166
+ };
167
+ const spans = freeSpans(line);
168
+ for (const strip of open.values()) for (const span of spans) keep(Math.max(strip.loPt, span.loPt), Math.min(strip.hiPt, span.hiPt), strip.startLine);
169
+ for (const span of spans) keep(span.loPt, span.hiPt, lineIndex);
170
+ for (const [key, strip] of open) if (next.get(key)?.startLine !== strip.startLine) record(strip, lineIndex);
171
+ open = next;
172
+ });
173
+ for (const strip of open.values()) record(strip, lines.length);
174
+ return runs;
175
+ }
176
+ function isRunningProse(items, gutterWidthPt) {
177
+ const lines = clusterIntoLines(items);
178
+ if (lines.length < MIN_COLUMN_LINES) return false;
179
+ const characters = items.reduce((sum, item) => sum + item.text.length, 0);
180
+ const advancePt = items.reduce((sum, item) => sum + (item.widthPt ?? 0), 0);
181
+ if (characters === 0 || advancePt === 0) return false;
182
+ const leftPt = Math.min(...items.map((item) => item.xPt));
183
+ const rightPt = Math.max(...items.map(rightEdge));
184
+ if ((rightPt - leftPt) / (advancePt / characters) < MIN_PROSE_MEASURE_CHARS) return false;
185
+ for (const line of lines) for (const span of freeSpans(line)) if (Number.isFinite(span.loPt) && Number.isFinite(span.hiPt) && span.hiPt - span.loPt >= gutterWidthPt) return false;
186
+ let wrapped = 0;
187
+ for (let i = 0; i + 1 < lines.length; i++) {
188
+ const lineRightPt = Math.max(...lines[i].items.map(rightEdge));
189
+ const nextFirst = lines[i + 1].items[0];
190
+ if (rightPt - lineRightPt < firstWordWidthPt(nextFirst) + spaceAdvancePt(nextFirst)) wrapped++;
191
+ }
192
+ return wrapped * 2 > lines.length - 1;
193
+ }
194
+ function firstWordWidthPt(item) {
195
+ const text = item.text.trimStart();
196
+ const firstWord = text.split(/\s/u)[0] ?? text;
197
+ return text.length === 0 ? 0 : (item.widthPt ?? 0) * firstWord.length / item.text.length;
198
+ }
199
+ //#endregion
200
+ export { compareReadingPosition, readingOrder };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_reconstruct_presentations_prod = require("../reconstruct-presentations-prod-CA4no_aw.cjs");
2
+ const require_reconstruct_presentations_prod = require("../reconstruct-presentations-prod-CsvGlvP2.cjs");
3
3
  exports.layoutItemToVector = require_reconstruct_presentations_prod.layoutItemToVector;
4
4
  exports.lineToParagraph = require_reconstruct_presentations_prod.lineToParagraph;
5
5
  exports.reconstructDrawing = require_reconstruct_presentations_prod.reconstructDrawing;
@@ -1,2 +1,2 @@
1
- import { a as reconstructSheet, i as reconstructPresentation, n as lineToParagraph, o as recoverPageVectors, r as reconstructDrawing, s as splitLineByLargeGaps, t as layoutItemToVector } from "../reconstruct-presentations-prod-CC8ct-5O.js";
1
+ import { a as reconstructSheet, i as reconstructPresentation, n as lineToParagraph, o as recoverPageVectors, r as reconstructDrawing, s as splitLineByLargeGaps, t as layoutItemToVector } from "../reconstruct-presentations-prod-D1KbGPxa.js";
2
2
  export { layoutItemToVector, lineToParagraph, reconstructDrawing, reconstructPresentation, reconstructSheet, recoverPageVectors, splitLineByLargeGaps };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_reconstruct_presentations_prod = require("../reconstruct-presentations-prod-CA4no_aw.cjs");
2
+ const require_reconstruct_presentations_prod = require("../reconstruct-presentations-prod-CsvGlvP2.cjs");
3
3
  exports.buildGridFromLattice = require_reconstruct_presentations_prod.buildGridFromLattice;
4
4
  exports.buildGridFromTextClustering = require_reconstruct_presentations_prod.buildGridFromTextClustering;
5
5
  exports.recoverTables = require_reconstruct_presentations_prod.recoverTables;
@@ -1,2 +1,2 @@
1
- import { b as recoverTables, v as buildGridFromLattice, y as buildGridFromTextClustering } from "../reconstruct-presentations-prod-CC8ct-5O.js";
1
+ import { b as recoverTables, v as buildGridFromLattice, y as buildGridFromTextClustering } from "../reconstruct-presentations-prod-D1KbGPxa.js";
2
2
  export { buildGridFromLattice, buildGridFromTextClustering, recoverTables };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_reconstruct_presentations_prod = require("../reconstruct-presentations-prod-CA4no_aw.cjs");
2
+ const require_reconstruct_presentations_prod = require("../reconstruct-presentations-prod-CsvGlvP2.cjs");
3
3
  exports.CELL_TYPES = require_reconstruct_presentations_prod.CELL_TYPES;
4
4
  exports.DEFAULT_COLUMN_WIDTH_FALLBACK_PT = require_reconstruct_presentations_prod.DEFAULT_COLUMN_WIDTH_FALLBACK_PT;
5
5
  exports.NO_ITEMS = require_reconstruct_presentations_prod.NO_ITEMS;
@@ -1,2 +1,2 @@
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-CC8ct-5O.js";
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-D1KbGPxa.js";
2
2
  export { CELL_TYPES, DEFAULT_COLUMN_WIDTH_FALLBACK_PT, NO_ITEMS, ROW_TYPES, TABLE_TYPES, ZERO_MARGINS, indexStructure, nearestOfType, reconstructSpreadsheet, reconstructWordprocessing };
@@ -5,6 +5,7 @@ const require_layout_cell_typing = require("./layout/cell-typing.cjs");
5
5
  const require_ports_abort = require("./ports/abort.cjs");
6
6
  const require_layout_reconstruct_lines = require("./layout/reconstruct-lines.cjs");
7
7
  const require_layout_lattice = require("./layout/lattice.cjs");
8
+ const require_layout_reading_order = require("./layout/reading-order.cjs");
8
9
  let document_schema_js = require("document-schema.js");
9
10
  let pdf_codec_layout = require("pdf-codec/layout");
10
11
  //#region src/layout/reconstruct-tables.ts
@@ -519,19 +520,19 @@ function reconstructPageBlocks(page, pageIndex, images, headingLevels, form, str
519
520
  }
520
521
  const textItems = page.items.filter((i) => i.kind === "text" && !consumedText.has(i));
521
522
  const imageItems = page.items.filter((i) => i.kind === "image");
522
- const lines = require_layout_reconstruct_lines.clusterIntoLines(textItems);
523
- const paragraphs = require_layout_reconstruct_lines.clusterIntoParagraphs(lines);
523
+ const order = require_layout_reading_order.readingOrder(textItems);
524
524
  const recordDivisions = (block, items) => {
525
525
  if (structure !== void 0) divisionByBlock.set(block, divisionChainOf(items, structure));
526
526
  };
527
527
  const positioned = [];
528
- for (const paragraph of paragraphs) {
528
+ for (const { lines, path } of order.regions) for (const paragraph of require_layout_reconstruct_lines.clusterIntoParagraphs(lines)) {
529
529
  const paragraphItems = paragraph.lines.flatMap((line) => line.items);
530
530
  const structural = structure === void 0 ? void 0 : structureHeadingLevel(paragraphItems, structure);
531
531
  const headingLevel = structural !== void 0 ? structural.level : headingLevelOf(paragraph, headingLevels);
532
532
  const block = require_layout_reconstruct_lines.paragraphToContentParagraph(paragraph, pageIndex, headingLevel);
533
533
  recordDivisions(block, paragraphItems);
534
534
  positioned.push({
535
+ path,
535
536
  yPt: paragraph.lines[0].baselineY,
536
537
  block
537
538
  });
@@ -554,6 +555,7 @@ function reconstructPageBlocks(page, pageIndex, images, headingLevels, form, str
554
555
  });
555
556
  recordDivisions(block, [img]);
556
557
  positioned.push({
558
+ path: order.locate(img.xPt + img.widthPt / 2, img.yPt),
557
559
  yPt: img.yPt,
558
560
  block
559
561
  });
@@ -562,6 +564,7 @@ function reconstructPageBlocks(page, pageIndex, images, headingLevels, form, str
562
564
  for (const recovered of recoveredTables) {
563
565
  recordDivisions(recovered.table, [...recovered.consumedText]);
564
566
  positioned.push({
567
+ path: order.locate(recovered.frame.xPt + recovered.frame.widthPt / 2, recovered.topYPt),
565
568
  yPt: recovered.topYPt,
566
569
  block: recovered.table
567
570
  });
@@ -571,11 +574,12 @@ function reconstructPageBlocks(page, pageIndex, images, headingLevels, form, str
571
574
  const vectorItems = page.items.filter((item) => !claimedItems.has(item) && layoutItemToVector(item, page.heightPt) !== void 0);
572
575
  recordDivisions(recoveredVectors.block, vectorItems);
573
576
  positioned.push({
577
+ path: order.locate(Number.NEGATIVE_INFINITY, recoveredVectors.topYPt),
574
578
  yPt: recoveredVectors.topYPt,
575
579
  block: recoveredVectors.block
576
580
  });
577
581
  }
578
- positioned.sort((a, b) => b.yPt - a.yPt);
582
+ positioned.sort(require_layout_reading_order.compareReadingPosition);
579
583
  const blocks = positioned.map((p) => p.block);
580
584
  reconcileLinks(blocks, page, pageIndex);
581
585
  appendAnnotationConstructs(blocks, page, pageIndex);
@@ -772,7 +776,7 @@ function reconstructSlide(page, pageIndex, images, structure) {
772
776
  }
773
777
  const textItems = page.items.filter((i) => i.kind === "text" && !consumedText.has(i));
774
778
  const imageItems = page.items.filter((i) => i.kind === "image");
775
- const textShapes = clusterIntoBlocks(require_layout_reconstruct_lines.clusterIntoLines(textItems)).map((block) => blockToShape(block, page.heightPt, pageIndex));
779
+ const textShapes = require_layout_reading_order.readingOrder(textItems).regions.flatMap((region) => clusterIntoBlocks(region.lines)).map((block) => blockToShape(block, page.heightPt, pageIndex));
776
780
  const imageShapes = [];
777
781
  for (const img of imageItems) {
778
782
  const shape = imageToShape(img, page.heightPt, pageIndex, images);
@@ -5,6 +5,7 @@ import { inferCellValue } from "./layout/cell-typing.js";
5
5
  import { throwIfAborted } from "./ports/abort.js";
6
6
  import { HALF_POINT_BUCKET_PT, bucketCounts, clusterIntoLines, clusterIntoParagraphs, estimateModalLineSpacing, fontSizesClose, gapExceeds, lineBox, modeOf, paragraphToContentParagraph, pushRunsForLine, textBoxOfItem, textItemToContentRun, textItemVerticalExtent } from "./layout/reconstruct-lines.js";
7
7
  import { detectGridLattice, findColumnIndex, findRowIndex } from "./layout/lattice.js";
8
+ import { compareReadingPosition, readingOrder } from "./layout/reading-order.js";
8
9
  import { denseTableRows } from "document-schema.js";
9
10
  import { sourcePageIndex } from "pdf-codec/layout";
10
11
  //#region src/layout/reconstruct-tables.ts
@@ -519,19 +520,19 @@ function reconstructPageBlocks(page, pageIndex, images, headingLevels, form, str
519
520
  }
520
521
  const textItems = page.items.filter((i) => i.kind === "text" && !consumedText.has(i));
521
522
  const imageItems = page.items.filter((i) => i.kind === "image");
522
- const lines = clusterIntoLines(textItems);
523
- const paragraphs = clusterIntoParagraphs(lines);
523
+ const order = readingOrder(textItems);
524
524
  const recordDivisions = (block, items) => {
525
525
  if (structure !== void 0) divisionByBlock.set(block, divisionChainOf(items, structure));
526
526
  };
527
527
  const positioned = [];
528
- for (const paragraph of paragraphs) {
528
+ for (const { lines, path } of order.regions) for (const paragraph of clusterIntoParagraphs(lines)) {
529
529
  const paragraphItems = paragraph.lines.flatMap((line) => line.items);
530
530
  const structural = structure === void 0 ? void 0 : structureHeadingLevel(paragraphItems, structure);
531
531
  const headingLevel = structural !== void 0 ? structural.level : headingLevelOf(paragraph, headingLevels);
532
532
  const block = paragraphToContentParagraph(paragraph, pageIndex, headingLevel);
533
533
  recordDivisions(block, paragraphItems);
534
534
  positioned.push({
535
+ path,
535
536
  yPt: paragraph.lines[0].baselineY,
536
537
  block
537
538
  });
@@ -554,6 +555,7 @@ function reconstructPageBlocks(page, pageIndex, images, headingLevels, form, str
554
555
  });
555
556
  recordDivisions(block, [img]);
556
557
  positioned.push({
558
+ path: order.locate(img.xPt + img.widthPt / 2, img.yPt),
557
559
  yPt: img.yPt,
558
560
  block
559
561
  });
@@ -562,6 +564,7 @@ function reconstructPageBlocks(page, pageIndex, images, headingLevels, form, str
562
564
  for (const recovered of recoveredTables) {
563
565
  recordDivisions(recovered.table, [...recovered.consumedText]);
564
566
  positioned.push({
567
+ path: order.locate(recovered.frame.xPt + recovered.frame.widthPt / 2, recovered.topYPt),
565
568
  yPt: recovered.topYPt,
566
569
  block: recovered.table
567
570
  });
@@ -571,11 +574,12 @@ function reconstructPageBlocks(page, pageIndex, images, headingLevels, form, str
571
574
  const vectorItems = page.items.filter((item) => !claimedItems.has(item) && layoutItemToVector(item, page.heightPt) !== void 0);
572
575
  recordDivisions(recoveredVectors.block, vectorItems);
573
576
  positioned.push({
577
+ path: order.locate(Number.NEGATIVE_INFINITY, recoveredVectors.topYPt),
574
578
  yPt: recoveredVectors.topYPt,
575
579
  block: recoveredVectors.block
576
580
  });
577
581
  }
578
- positioned.sort((a, b) => b.yPt - a.yPt);
582
+ positioned.sort(compareReadingPosition);
579
583
  const blocks = positioned.map((p) => p.block);
580
584
  reconcileLinks(blocks, page, pageIndex);
581
585
  appendAnnotationConstructs(blocks, page, pageIndex);
@@ -772,7 +776,7 @@ function reconstructSlide(page, pageIndex, images, structure) {
772
776
  }
773
777
  const textItems = page.items.filter((i) => i.kind === "text" && !consumedText.has(i));
774
778
  const imageItems = page.items.filter((i) => i.kind === "image");
775
- const textShapes = clusterIntoBlocks(clusterIntoLines(textItems)).map((block) => blockToShape(block, page.heightPt, pageIndex));
779
+ const textShapes = readingOrder(textItems).regions.flatMap((region) => clusterIntoBlocks(region.lines)).map((block) => blockToShape(block, page.heightPt, pageIndex));
776
780
  const imageShapes = [];
777
781
  for (const img of imageItems) {
778
782
  const shape = imageToShape(img, page.heightPt, pageIndex, images);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js.documents",
3
- "version": "14.5.0",
3
+ "version": "14.6.1",
4
4
  "description": "Converts between docx, pptx, odt, odp, ods, odg, xlsx, csv, svg, markdown, rtf, doc, xls, ppt and PDF through one shared, Zod-typed content schema (wpd read-only), plus read+write editors for OOXML and OpenDocument. Worker-isomorphic.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -86,7 +86,7 @@
86
86
  "markdown-codec": "11.1.16",
87
87
  "odf.js": "11.2.2",
88
88
  "ooxml.js": "12.2.32",
89
- "pdf-codec": "5.4.0",
89
+ "pdf-codec": "5.5.0",
90
90
  "ppt-codec": "2.2.23",
91
91
  "rtf-codec": "8.1.24",
92
92
  "temml": "0.13.4",