@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.
- package/dist/src/core/parser.d.ts.map +1 -1
- package/dist/src/core/parser.js +1 -0
- package/dist/src/core/parser.js.map +1 -1
- package/dist/src/core/parser.test.js +2 -0
- package/dist/src/core/parser.test.js.map +1 -1
- package/dist/src/core/types.d.ts +4 -0
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/engines/pdf/pdfium-renderer.d.ts +11 -0
- package/dist/src/engines/pdf/pdfium-renderer.d.ts.map +1 -1
- package/dist/src/engines/pdf/pdfium-renderer.js +72 -0
- package/dist/src/engines/pdf/pdfium-renderer.js.map +1 -1
- package/dist/src/engines/pdf/pdfjs.d.ts.map +1 -1
- package/dist/src/engines/pdf/pdfjs.js +18 -1
- package/dist/src/engines/pdf/pdfjs.js.map +1 -1
- package/dist/src/engines/pdf/pdfjs.test.js +2 -0
- package/dist/src/engines/pdf/pdfjs.test.js.map +1 -1
- package/dist/src/output/json.d.ts.map +1 -1
- package/dist/src/output/json.js +1 -0
- package/dist/src/output/json.js.map +1 -1
- package/dist/src/output/json.test.js +63 -0
- package/dist/src/output/json.test.js.map +1 -1
- package/dist/src/processing/gridProjection.d.ts.map +1 -1
- package/dist/src/processing/gridProjection.js +212 -5
- package/dist/src/processing/gridProjection.js.map +1 -1
- package/dist/src/processing/searchItems.d.ts.map +1 -1
- package/dist/src/processing/searchItems.js +17 -2
- package/dist/src/processing/searchItems.js.map +1 -1
- package/dist/src/processing/searchItems.test.js +31 -2
- package/dist/src/processing/searchItems.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -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":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE/C,MAAM,OAAO,GAAG;IACd,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE;IAClE,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE;IAClE,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE;CACrE,CAAC;AAEF,MAAM,SAAS,GAAG,OAAO;KACtB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,wBAAwB;KAC1D,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;IACZ,6DAA6D;IAC7D,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;AAC5B,CAAC,CAAC;KACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACX,GAAG,EAAE,CAAC,CAAC,IAAI;IACX,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACZ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACZ,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7B,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACxB,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACxB,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;CAChC,CAAC,CAAC,CAAC;AAEN,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxC,IAAI,EAAE,CAAC,CAAC,IAAI;IACZ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACZ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACZ,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7B,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;
|
|
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;
|
|
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
|
-
|
|
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
|
|
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 &&
|
|
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 &&
|
|
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 &&
|
|
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)) {
|