@llamaindex/liteparse 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,6 +31,7 @@ const textItemsJSON = results.map((r) => ({
31
31
  height: r.bbox[3] - r.bbox[1],
32
32
  fontName: "OCR",
33
33
  fontSize: r.bbox[3] - r.bbox[1],
34
+ confidence: 1.0,
34
35
  }));
35
36
  const pages = [
36
37
  {
@@ -74,6 +75,40 @@ const pages = [
74
75
  boundingBoxes: [{ x1: 0, y1: 0, x2: 300, y2: 400 }],
75
76
  },
76
77
  ];
78
+ // Native PDF text item (confidence defaults to 1.0)
79
+ const nativeTextItem = {
80
+ str: "Native text",
81
+ x: 10,
82
+ y: 20,
83
+ width: 100,
84
+ height: 15,
85
+ w: 100,
86
+ h: 15,
87
+ fontName: "Helvetica",
88
+ fontSize: 12,
89
+ confidence: 1.0,
90
+ };
91
+ // OCR text item (confidence from OCR engine)
92
+ const ocrTextItem = {
93
+ str: "OCR detected text",
94
+ x: 10,
95
+ y: 50,
96
+ width: 150,
97
+ height: 20,
98
+ w: 150,
99
+ h: 20,
100
+ fontName: "OCR",
101
+ fontSize: 20,
102
+ confidence: 0.95,
103
+ };
104
+ const mixedPage = {
105
+ pageNum: 1,
106
+ width: 612,
107
+ height: 792,
108
+ text: "Native text\nOCR detected text",
109
+ textItems: [nativeTextItem, ocrTextItem],
110
+ boundingBoxes: [],
111
+ };
77
112
  const pagesJSON = {
78
113
  pages: [
79
114
  {
@@ -133,4 +168,32 @@ describe("test json utilities", () => {
133
168
  expect(result).toBe(JSON.stringify(pagesJSON, null, 2));
134
169
  });
135
170
  });
171
+ describe("confidence field", () => {
172
+ it("includes OCR confidence score for OCR items", () => {
173
+ const result = buildJSON([mixedPage]);
174
+ const items = result.pages[0].textItems;
175
+ const ocrItem = items.find((i) => i.text === "OCR detected text");
176
+ expect(ocrItem?.confidence).toBe(0.95);
177
+ });
178
+ it("defaults to 1.0 for native PDF items", () => {
179
+ const result = buildJSON([mixedPage]);
180
+ const items = result.pages[0].textItems;
181
+ const nativeItem = items.find((i) => i.text === "Native text");
182
+ expect(nativeItem?.confidence).toBe(1.0);
183
+ });
184
+ it("preserves confidence of 0.0", () => {
185
+ const zeroConfidenceItem = { ...ocrTextItem, confidence: 0.0 };
186
+ const page = { ...mixedPage, textItems: [zeroConfidenceItem] };
187
+ const result = buildJSON([page]);
188
+ const item = result.pages[0].textItems[0];
189
+ expect(item.confidence).toBe(0.0);
190
+ });
191
+ it("defaults to 1.0 when confidence is undefined", () => {
192
+ const { confidence: _confidence, ...itemWithoutConfidence } = nativeTextItem;
193
+ const page = { ...mixedPage, textItems: [itemWithoutConfidence] };
194
+ const result = buildJSON([page]);
195
+ const item = result.pages[0].textItems[0];
196
+ expect(item.confidence).toBe(1.0);
197
+ });
198
+ });
136
199
  //# sourceMappingURL=json.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"json.test.js","sourceRoot":"","sources":["../../../src/output/json.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"json.test.js","sourceRoot":"","sources":["../../../src/output/json.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"gridProjection.d.ts","sourceRoot":"","sources":["../../../src/processing/gridProjection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAe,eAAe,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAyBvD,KAAK,aAAa,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AAE/C,KAAK,WAAW,GAAG;IACjB,iBAAiB,EAAE,aAAa,CAAC;IACjC,mBAAmB,EAAE,aAAa,CAAC;IACnC,kBAAkB,EAAE,aAAa,CAAC;CACnC,CAAC;AA0pBF,wBAAgB,UAAU,CACxB,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,iBAAiB,EAAE,EAAE,CAmSvB;AAwFD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,QAAQ,EACd,eAAe,EAAE,iBAAiB,EAAE,EACpC,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,MAAM,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,WAAW,CAAA;CAAE,CAmjB5C;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,eAAe,GAAG,UAAU,EAAE,CAkD3F"}
1
+ {"version":3,"file":"gridProjection.d.ts","sourceRoot":"","sources":["../../../src/processing/gridProjection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAe,eAAe,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AA+CvD,KAAK,aAAa,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AAE/C,KAAK,WAAW,GAAG;IACjB,iBAAiB,EAAE,aAAa,CAAC;IACjC,mBAAmB,EAAE,aAAa,CAAC;IACnC,kBAAkB,EAAE,aAAa,CAAC;CACnC,CAAC;AA0pBF,wBAAgB,UAAU,CACxB,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,iBAAiB,EAAE,EAAE,CA0SvB;AA4MD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,QAAQ,EACd,eAAe,EAAE,iBAAiB,EAAE,EACpC,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,MAAM,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,WAAW,CAAA;CAAE,CAkpB5C;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,eAAe,GAAG,UAAU,EAAE,CAkD3F"}
@@ -6,6 +6,27 @@ import { applyMarkupTags } from "./markupUtils.js";
6
6
  const FLOATING_SPACES = 2;
7
7
  // Minimum spaces between snapped columns
8
8
  const COLUMN_SPACES = 4;
9
+ // --- Flowing text detection thresholds ---
10
+ // Max total anchors (left+right+center) before block is considered structured
11
+ const FLOWING_MAX_TOTAL_ANCHORS = 4;
12
+ // Max left anchors before block is considered structured
13
+ const FLOWING_MAX_LEFT_ANCHORS = 3;
14
+ // Minimum non-empty lines required to classify a block
15
+ const FLOWING_MIN_LINES = 3;
16
+ // Fraction of page width a line must span to count as "wide"
17
+ const FLOWING_WIDE_LINE_RATIO = 0.5;
18
+ // Fraction of lines that must be wide for a block to be flowing
19
+ const FLOWING_WIDE_LINE_THRESHOLD = 0.6;
20
+ // Multiplier on median char width for column gap detection
21
+ const FLOWING_COLUMN_GAP_MULTIPLIER = 4;
22
+ // Minimum items on a line to be classified as flowing in per-line detection
23
+ const FLOWING_MIN_LINE_ITEMS = 3;
24
+ // Height multiplier for word-break space threshold in flowing text
25
+ const FLOWING_SPACE_HEIGHT_RATIO = 0.15;
26
+ // Minimum absolute space threshold in flowing text
27
+ const FLOWING_SPACE_MIN_THRESHOLD = 0.3;
28
+ // Maximum indent (in character widths) for flowing text
29
+ const FLOWING_MAX_INDENT = 8;
9
30
  function roundAnchor(anchor) {
10
31
  // group anchor x-coord by nearest 1/4 unit
11
32
  return Math.round(anchor * 4) / 4;
@@ -739,7 +760,13 @@ export function bboxToLine(textBbox, medianWidth, medianHeight, pageWidth) {
739
760
  if (canMergeMarkup(previousLine, currentLine)) {
740
761
  // Don't merge adjacent numbers in tables - they're separate columns
741
762
  const bothAreNumbers = looksLikeTableNumber(previousLine.str) && looksLikeTableNumber(currentLine.str);
742
- if (!bothAreNumbers && currentLine.x - previousLine.x - previousLine.w <= mergeThreshold) {
763
+ // Check gap with BOTH rounded width (used elsewhere) and raw width from pageBbox.
764
+ // Only merge without space if both agree the gap is small enough. This prevents
765
+ // rounding artifacts from causing word fusions (e.g., "of" + "our" → "ofour"
766
+ // when Math.round(w) reduces the gap from 1.34 to 1.0)
767
+ const roundedGap = currentLine.x - previousLine.x - previousLine.w;
768
+ const rawGap = currentLine.x - previousLine.x - (previousLine.pageBbox?.w ?? previousLine.w);
769
+ if (!bothAreNumbers && roundedGap <= mergeThreshold && rawGap <= mergeThreshold) {
743
770
  // if same word but less than .7 of prev line
744
771
  if (currentLine.h != 0 && currentLine.h < previousLine.h * 0.7) {
745
772
  // and not starting with space
@@ -879,6 +906,96 @@ function updateForwardAnchors(bbox, nextBbox, snapMaps, forwardAnchors, lineLeng
879
906
  // we do not update center anchors since centered text may span between snapped columns
880
907
  updateForwardAnchorRightBound(snapMaps.floating, forwardAnchors.floating, rightBound, targetLength);
881
908
  }
909
+ /**
910
+ * Compute the maximum gap between adjacent items on a line.
911
+ */
912
+ function lineMaxGap(line) {
913
+ let maxGap = 0;
914
+ for (let gi = 1; gi < line.length; gi++) {
915
+ const gap = line[gi].x - (line[gi - 1].x + line[gi - 1].w);
916
+ if (gap > maxGap)
917
+ maxGap = gap;
918
+ }
919
+ return maxGap;
920
+ }
921
+ /**
922
+ * Render a single line as flowing text: join items with single spaces based on gap size.
923
+ * Sets bbox.rendered = true for each item.
924
+ */
925
+ function renderLineAsFlowingText(line, minX, medianWidth) {
926
+ const indent = Math.min(Math.max(Math.round((line[0].x - minX) / medianWidth), 0), FLOWING_MAX_INDENT);
927
+ let result = " ".repeat(indent);
928
+ for (let i = 0; i < line.length; i++) {
929
+ const bbox = line[i];
930
+ if (i > 0) {
931
+ const prevBbox = line[i - 1];
932
+ const gap = bbox.x - (prevBbox.x + prevBbox.w);
933
+ const spaceThreshold = Math.max(bbox.h * FLOWING_SPACE_HEIGHT_RATIO, FLOWING_SPACE_MIN_THRESHOLD);
934
+ if (gap > spaceThreshold && !result.endsWith(" ")) {
935
+ result += " ";
936
+ }
937
+ }
938
+ result += bbox.str;
939
+ bbox.rendered = true;
940
+ }
941
+ return result;
942
+ }
943
+ /**
944
+ * Classify whether a block of lines is flowing paragraph text or structured/tabular content.
945
+ * Flowing text gets a simpler rendering path that avoids grid projection artifacts.
946
+ */
947
+ function isFlowingTextBlock(blockLines, anchorLeft, anchorRight, anchorCenter, pageWidth) {
948
+ const leftAnchorCount = Object.keys(anchorLeft).length;
949
+ const rightAnchorCount = Object.keys(anchorRight).length;
950
+ const centerAnchorCount = Object.keys(anchorCenter).length;
951
+ // Multiple column anchors indicate structured/tabular content
952
+ if (leftAnchorCount + rightAnchorCount + centerAnchorCount > FLOWING_MAX_TOTAL_ANCHORS)
953
+ return false;
954
+ if (leftAnchorCount > FLOWING_MAX_LEFT_ANCHORS)
955
+ return false;
956
+ // Count non-empty lines and how many span most of the page width
957
+ let nonEmptyLines = 0;
958
+ let wideLines = 0;
959
+ for (const line of blockLines) {
960
+ if (line.length === 0)
961
+ continue;
962
+ nonEmptyLines++;
963
+ const lineStart = line[0].x;
964
+ const lineEnd = line[line.length - 1].x + line[line.length - 1].w;
965
+ if (lineEnd - lineStart > pageWidth * FLOWING_WIDE_LINE_RATIO)
966
+ wideLines++;
967
+ }
968
+ // Need enough lines to confidently classify
969
+ if (nonEmptyLines < FLOWING_MIN_LINES)
970
+ return false;
971
+ // Majority of lines should span most of page width for flowing text
972
+ return wideLines / nonEmptyLines > FLOWING_WIDE_LINE_THRESHOLD;
973
+ }
974
+ /**
975
+ * Render a flowing text block by joining items with single spaces.
976
+ * Avoids grid projection artifacts (excessive whitespace, fused words)
977
+ * that occur when applying column-alignment logic to paragraph text.
978
+ */
979
+ function renderFlowingBlock(lines, block, rawLines, medianWidth) {
980
+ // Find the block's left margin
981
+ let minX = Infinity;
982
+ for (let i = block.start; i < block.end; i++) {
983
+ if (lines[i].length > 0) {
984
+ minX = Math.min(minX, lines[i][0].x);
985
+ }
986
+ }
987
+ if (minX === Infinity)
988
+ minX = 0;
989
+ for (let lineIndex = block.start; lineIndex < block.end; lineIndex++) {
990
+ const line = lines[lineIndex];
991
+ if (!rawLines[lineIndex]) {
992
+ rawLines[lineIndex] = "";
993
+ }
994
+ if (line.length === 0)
995
+ continue;
996
+ rawLines[lineIndex] = renderLineAsFlowingText(line, minX, medianWidth);
997
+ }
998
+ }
882
999
  function getMedianTextBoxSize(lines) {
883
1000
  // calculate median textBox width
884
1001
  const widthList = [];
@@ -1000,7 +1117,18 @@ export function projectToGrid(config, page, projectionBoxes, prevAnchors, totalP
1000
1117
  }
1001
1118
  }
1002
1119
  for (const block of blocks) {
1003
- const { anchorLeft, anchorRight, anchorCenter } = extractAnchorsPointsFromLines(lines.slice(block.start, block.end), page);
1120
+ const blockLines = lines.slice(block.start, block.end);
1121
+ const { anchorLeft, anchorRight, anchorCenter } = extractAnchorsPointsFromLines(blockLines, page);
1122
+ // Block-level classification: if entire block is clearly flowing text,
1123
+ // render it simply and skip grid projection
1124
+ if (isFlowingTextBlock(blockLines, anchorLeft, anchorRight, anchorCenter, page.width)) {
1125
+ if (!config.preserveLayoutAlignmentAcrossPages) {
1126
+ const sizes = getMedianTextBoxSize(blockLines.flat());
1127
+ medianWidth = sizes.width;
1128
+ }
1129
+ renderFlowingBlock(lines, block, rawLines, medianWidth);
1130
+ continue;
1131
+ }
1004
1132
  const snapMaps = {
1005
1133
  left: [],
1006
1134
  right: [],
@@ -1099,6 +1227,69 @@ export function projectToGrid(config, page, projectionBoxes, prevAnchors, totalP
1099
1227
  snapMaps.center.sort((a, b) => a - b);
1100
1228
  snapMaps.right.sort((a, b) => a - b);
1101
1229
  snapMaps.left.sort((a, b) => a - b);
1230
+ // Per-line flowing text detection: pre-render lines that are clearly paragraph text
1231
+ // (spans page width, no large column gaps) with simple single-space joining.
1232
+ // This avoids grid projection artifacts on flowing text within mixed blocks.
1233
+ const flowingLines = new Set();
1234
+ {
1235
+ // Find block's left margin for indent calculation
1236
+ let blockMinX = Infinity;
1237
+ for (let li = block.start; li < block.end; li++) {
1238
+ if (lines[li].length > 0) {
1239
+ blockMinX = Math.min(blockMinX, lines[li][0].x);
1240
+ }
1241
+ }
1242
+ if (blockMinX === Infinity)
1243
+ blockMinX = 0;
1244
+ const columnGapThreshold = medianWidth * FLOWING_COLUMN_GAP_MULTIPLIER;
1245
+ // Helper to mark and render a line as flowing
1246
+ function markFlowing(lineIndex) {
1247
+ const line = lines[lineIndex];
1248
+ if (!rawLines[lineIndex]) {
1249
+ rawLines[lineIndex] = "";
1250
+ rawLinesDelta[lineIndex] = 0;
1251
+ }
1252
+ rawLines[lineIndex] = renderLineAsFlowingText(line, blockMinX, medianWidth);
1253
+ flowingLines.add(lineIndex);
1254
+ }
1255
+ // First pass: detect clearly flowing lines (wide, no column gaps, enough items)
1256
+ for (let lineIndex = block.start; lineIndex < block.end; lineIndex++) {
1257
+ const line = lines[lineIndex];
1258
+ if (line.length < FLOWING_MIN_LINE_ITEMS)
1259
+ continue;
1260
+ const lineStart = line[0].x;
1261
+ const lineEnd = line[line.length - 1].x + line[line.length - 1].w;
1262
+ const lineSpan = lineEnd - lineStart;
1263
+ if (lineSpan > page.width * FLOWING_WIDE_LINE_RATIO &&
1264
+ lineMaxGap(line) < columnGapThreshold) {
1265
+ markFlowing(lineIndex);
1266
+ }
1267
+ }
1268
+ // Second pass: extend flowing to adjacent continuation lines using
1269
+ // forward + backward sweeps (O(n) instead of iterating until convergence)
1270
+ // Forward sweep: propagate flowing status downward
1271
+ for (let lineIndex = block.start; lineIndex < block.end; lineIndex++) {
1272
+ if (flowingLines.has(lineIndex))
1273
+ continue;
1274
+ const line = lines[lineIndex];
1275
+ if (line.length === 0)
1276
+ continue;
1277
+ if (flowingLines.has(lineIndex - 1) && lineMaxGap(line) < columnGapThreshold) {
1278
+ markFlowing(lineIndex);
1279
+ }
1280
+ }
1281
+ // Backward sweep: propagate flowing status upward
1282
+ for (let lineIndex = block.end - 1; lineIndex >= block.start; lineIndex--) {
1283
+ if (flowingLines.has(lineIndex))
1284
+ continue;
1285
+ const line = lines[lineIndex];
1286
+ if (line.length === 0)
1287
+ continue;
1288
+ if (flowingLines.has(lineIndex + 1) && lineMaxGap(line) < columnGapThreshold) {
1289
+ markFlowing(lineIndex);
1290
+ }
1291
+ }
1292
+ }
1102
1293
  while (hasChanged || snapMaps.right.length || snapMaps.left.length || snapMaps.center.length) {
1103
1294
  hasChanged = false;
1104
1295
  for (let lineIndex = block.start; lineIndex < block.end; ++lineIndex) {
@@ -1170,7 +1361,9 @@ export function projectToGrid(config, page, projectionBoxes, prevAnchors, totalP
1170
1361
  (!snapMaps.center.length || snapMaps.left[0] <= snapMaps.center[0])) {
1171
1362
  const thisTurnSnap = [];
1172
1363
  for (const item of leftSnap) {
1173
- if (item.bbox.leftAnchor && parseFloat(item.bbox.leftAnchor) == snapMaps.left[0]) {
1364
+ if (item.bbox.leftAnchor &&
1365
+ parseFloat(item.bbox.leftAnchor) == snapMaps.left[0] &&
1366
+ !flowingLines.has(item.lineIndex)) {
1174
1367
  thisTurnSnap.push(item);
1175
1368
  }
1176
1369
  }
@@ -1207,6 +1400,8 @@ export function projectToGrid(config, page, projectionBoxes, prevAnchors, totalP
1207
1400
  forwardAnchors.left[snapMaps.left[0]] = targetX;
1208
1401
  for (const currentLeftSnapBox of thisTurnSnap) {
1209
1402
  const lineIndex = currentLeftSnapBox.lineIndex;
1403
+ if (flowingLines.has(lineIndex))
1404
+ continue;
1210
1405
  if (targetX > rawLines[lineIndex].length) {
1211
1406
  rawLines[lineIndex] += " ".repeat(targetX - rawLines[lineIndex].length);
1212
1407
  }
@@ -1219,6 +1414,8 @@ export function projectToGrid(config, page, projectionBoxes, prevAnchors, totalP
1219
1414
  updateForwardAnchors(currentLeftSnapBox.bbox, nextBbox, snapMaps, forwardAnchors, rawLines[lineIndex].length);
1220
1415
  }
1221
1416
  for (let index = block.start; index < block.end; ++index) {
1417
+ if (flowingLines.has(index))
1418
+ continue;
1222
1419
  const line = rawLines[index];
1223
1420
  if (line.length < targetX) {
1224
1421
  rawLines[index] += " ".repeat(targetX - line.length);
@@ -1232,7 +1429,9 @@ export function projectToGrid(config, page, projectionBoxes, prevAnchors, totalP
1232
1429
  const thisTurnSnap = [];
1233
1430
  hasChanged = true;
1234
1431
  for (const item of rightSnap) {
1235
- if (item.bbox.rightAnchor && parseFloat(item.bbox.rightAnchor) == snapMaps.right[0]) {
1432
+ if (item.bbox.rightAnchor &&
1433
+ parseFloat(item.bbox.rightAnchor) == snapMaps.right[0] &&
1434
+ !flowingLines.has(item.lineIndex)) {
1236
1435
  thisTurnSnap.push(item);
1237
1436
  }
1238
1437
  }
@@ -1264,6 +1463,8 @@ export function projectToGrid(config, page, projectionBoxes, prevAnchors, totalP
1264
1463
  forwardAnchors.right[snapMaps.right[0]] = targetX;
1265
1464
  for (const currentRightSnapBox of thisTurnSnap) {
1266
1465
  const lineIndex = currentRightSnapBox.lineIndex;
1466
+ if (flowingLines.has(lineIndex))
1467
+ continue;
1267
1468
  rawLines[lineIndex] = rawLines[lineIndex].trimEnd();
1268
1469
  if (targetX > rawLines[lineIndex].trimEnd().length + currentRightSnapBox.bbox.strLength) {
1269
1470
  rawLines[lineIndex] += " ".repeat(targetX - rawLines[lineIndex].length - currentRightSnapBox.bbox.strLength);
@@ -1277,6 +1478,8 @@ export function projectToGrid(config, page, projectionBoxes, prevAnchors, totalP
1277
1478
  updateForwardAnchors(currentRightSnapBox.bbox, nextBbox, snapMaps, forwardAnchors, rawLines[lineIndex].length);
1278
1479
  }
1279
1480
  for (let index = block.start; index < block.end; ++index) {
1481
+ if (flowingLines.has(index))
1482
+ continue;
1280
1483
  const line = rawLines[index];
1281
1484
  if (line.length < targetX) {
1282
1485
  rawLines[index] += " ".repeat(targetX - line.length);
@@ -1290,7 +1493,9 @@ export function projectToGrid(config, page, projectionBoxes, prevAnchors, totalP
1290
1493
  const thisTurnSnap = [];
1291
1494
  hasChanged = true;
1292
1495
  for (const item of centerSnap) {
1293
- if (item.bbox.centerAnchor && parseFloat(item.bbox.centerAnchor) == snapMaps.center[0]) {
1496
+ if (item.bbox.centerAnchor &&
1497
+ parseFloat(item.bbox.centerAnchor) == snapMaps.center[0] &&
1498
+ !flowingLines.has(item.lineIndex)) {
1294
1499
  thisTurnSnap.push(item);
1295
1500
  }
1296
1501
  }
@@ -1325,6 +1530,8 @@ export function projectToGrid(config, page, projectionBoxes, prevAnchors, totalP
1325
1530
  }
1326
1531
  forwardAnchors.center[snapMaps.center[0]] = targetX;
1327
1532
  for (const currentCenterSnapBox of thisTurnSnap) {
1533
+ if (flowingLines.has(currentCenterSnapBox.lineIndex))
1534
+ continue;
1328
1535
  if (targetX >
1329
1536
  rawLines[currentCenterSnapBox.lineIndex].length +
1330
1537
  Math.round(currentCenterSnapBox.bbox.strLength / 2)) {