kordoc 4.21.19 → 4.21.21

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 (129) hide show
  1. package/README.md +7 -5
  2. package/dist/{-FLYHAUQ6.js → -ZYF6HX4M.js} +11 -11
  3. package/dist/{chunk-TC6DQLYN.js → chunk-2ZGP7A5T.js} +2 -2
  4. package/dist/{chunk-4VM6BT4W.js → chunk-3TCF5HPP.js} +2 -2
  5. package/dist/{chunk-2DNJW2HO.cjs → chunk-57VNFMMS.cjs} +3 -3
  6. package/dist/{chunk-2DNJW2HO.cjs.map → chunk-57VNFMMS.cjs.map} +1 -1
  7. package/dist/{chunk-OON4IJU2.js → chunk-5HTFWUJE.js} +2 -2
  8. package/dist/{chunk-AQ5GIBBH.js → chunk-7YAJCXCD.js} +2 -2
  9. package/dist/{chunk-3O4YC67B.js → chunk-BC54LBST.js} +3 -3
  10. package/dist/{chunk-GK4QLKNT.js → chunk-BG6LUCQL.js} +2 -2
  11. package/dist/{chunk-SM42XSI3.js → chunk-CY4QM2KQ.js} +2 -2
  12. package/dist/{chunk-KLKV47XO.cjs → chunk-DTZIZ5PP.cjs} +13 -13
  13. package/dist/{chunk-KLKV47XO.cjs.map → chunk-DTZIZ5PP.cjs.map} +1 -1
  14. package/dist/{chunk-INZGI6PI.js → chunk-FBJVDBMO.js} +2 -2
  15. package/dist/{chunk-Z2OOYQ4I.js → chunk-FZMGF6XU.js} +2 -2
  16. package/dist/{chunk-JGGYLUGD.cjs → chunk-H2MS4VG3.cjs} +3 -3
  17. package/dist/{chunk-JGGYLUGD.cjs.map → chunk-H2MS4VG3.cjs.map} +1 -1
  18. package/dist/{chunk-3PCAJWGK.js → chunk-HWIW3WK2.js} +42 -3
  19. package/dist/{chunk-3PCAJWGK.js.map → chunk-HWIW3WK2.js.map} +1 -1
  20. package/dist/{chunk-F6N7CDB7.js → chunk-J5PBI3ZC.js} +3 -3
  21. package/dist/{chunk-DQ2YGTRS.js → chunk-KBV4WFZ6.js} +145 -123
  22. package/dist/chunk-KBV4WFZ6.js.map +1 -0
  23. package/dist/{chunk-YDIVY65W.js → chunk-KTLHADU4.js} +2 -2
  24. package/dist/{chunk-3KW2Q655.cjs → chunk-MCUX2Y2C.cjs} +2 -2
  25. package/dist/{chunk-3KW2Q655.cjs.map → chunk-MCUX2Y2C.cjs.map} +1 -1
  26. package/dist/{chunk-X6WXU4LA.js → chunk-PTF4NCFM.js} +2 -2
  27. package/dist/{chunk-46PYORID.js → chunk-QHNVH4TC.js} +6 -6
  28. package/dist/{chunk-RYRUQ73F.js → chunk-RBRHO7WL.js} +2 -2
  29. package/dist/{chunk-CLAIAXMX.js → chunk-T3DTTK23.js} +2 -2
  30. package/dist/{chunk-DZVZVZAD.cjs → chunk-T7PN5D4D.cjs} +6 -6
  31. package/dist/{chunk-DZVZVZAD.cjs.map → chunk-T7PN5D4D.cjs.map} +1 -1
  32. package/dist/{chunk-EYLEVRHT.cjs → chunk-TMUUDMDH.cjs} +274 -172
  33. package/dist/chunk-TMUUDMDH.cjs.map +1 -0
  34. package/dist/{chunk-VIFY6DJZ.js → chunk-TRO4CQHJ.js} +4 -4
  35. package/dist/{chunk-OWLDTF5Q.js → chunk-WGMYVRSA.js} +2 -2
  36. package/dist/{chunk-AMXIYV73.js → chunk-YHPJTLCA.js} +2 -2
  37. package/dist/{chunk-QWOZRYUA.js → chunk-YM3K3LCD.js} +450 -110
  38. package/dist/chunk-YM3K3LCD.js.map +1 -0
  39. package/dist/{chunk-Y5OSPKBU.js → chunk-YQZOPT3A.js} +225 -43
  40. package/dist/chunk-YQZOPT3A.js.map +1 -0
  41. package/dist/{chunk-UDODNSDU.js → chunk-ZZIQWSGC.js} +2 -2
  42. package/dist/chunks-MDMJRCJ7.js +10 -0
  43. package/dist/cli.js +30 -30
  44. package/dist/{formula-2YYGN7UE.js → formula-6XNIXZ5L.js} +3 -3
  45. package/dist/{formula-EKXCURKO.cjs → formula-A3I5VAP7.cjs} +9 -9
  46. package/dist/{formula-EKXCURKO.cjs.map → formula-A3I5VAP7.cjs.map} +1 -1
  47. package/dist/{formula-Z5UPXBQM.js → formula-P7M7IH2L.js} +4 -4
  48. package/dist/{image-ocr-23R7RVHP.js → image-ocr-3C6W3KZO.js} +6 -6
  49. package/dist/{image-ocr-IMLFZ2JC.js → image-ocr-ITNY454I.js} +9 -9
  50. package/dist/{image-ocr-TE76KKNV.cjs → image-ocr-UJRSQ2T3.cjs} +15 -15
  51. package/dist/{image-ocr-TE76KKNV.cjs.map → image-ocr-UJRSQ2T3.cjs.map} +1 -1
  52. package/dist/index.cjs +1064 -687
  53. package/dist/index.cjs.map +1 -1
  54. package/dist/index.d.cts +1 -1
  55. package/dist/index.d.ts +1 -1
  56. package/dist/index.js +482 -105
  57. package/dist/index.js.map +1 -1
  58. package/dist/mcp.js +22 -22
  59. package/dist/{model-bundle-GTSRH2DY.js → model-bundle-LAWQH75O.js} +5 -5
  60. package/dist/{models-2J3NS7G2.js → models-6QTD2CFM.js} +5 -5
  61. package/dist/{parse-worker-v2-VO5UY3MP.js → parse-worker-v2-FEPJG3ER.js} +12 -12
  62. package/dist/{parser-FXGAKPUI.js → parser-56I364YM.js} +16 -8
  63. package/dist/{parser-JVUZ7EEV.js.map → parser-56I364YM.js.map} +1 -1
  64. package/dist/{parser-JVUZ7EEV.js → parser-KFCY3NIN.js} +19 -11
  65. package/dist/{parser-FXGAKPUI.js.map → parser-KFCY3NIN.js.map} +1 -1
  66. package/dist/{parser-D5VMCDLG.cjs → parser-VKWUMUML.cjs} +142 -134
  67. package/dist/parser-VKWUMUML.cjs.map +1 -0
  68. package/dist/pdf-ocr-MME37BL4.js +18 -0
  69. package/dist/pdf-ocr-OKAHNEJA.cjs +19 -0
  70. package/dist/{pdf-ocr-YFNUYBYJ.cjs.map → pdf-ocr-OKAHNEJA.cjs.map} +1 -1
  71. package/dist/pdf-ocr-ZZ6AJL6Z.js +22 -0
  72. package/dist/{profile-io-ULK73H2G.js → profile-io-OCITHUQF.js} +3 -3
  73. package/dist/{rasterize-FG3NX3GA.js → rasterize-SFCG4YOI.js} +3 -3
  74. package/dist/{redact-doc-NMKTKG24.js → redact-doc-5SMPXIGG.js} +11 -11
  75. package/dist/{render-GQUUGPOJ.js → render-FGPG5A2N.js} +7 -7
  76. package/dist/seal-GA7NZDTG.js +10 -0
  77. package/dist/{setup-PRBHD7JI.js → setup-JQVYZO7I.js} +3 -3
  78. package/dist/visual-YMG644YW.js +20 -0
  79. package/dist/{watch-LFSXNO2B.js → watch-C77BUSP7.js} +12 -12
  80. package/package.json +1 -1
  81. package/dist/chunk-DQ2YGTRS.js.map +0 -1
  82. package/dist/chunk-EYLEVRHT.cjs.map +0 -1
  83. package/dist/chunk-QWOZRYUA.js.map +0 -1
  84. package/dist/chunk-Y5OSPKBU.js.map +0 -1
  85. package/dist/chunks-J46DCTUC.js +0 -10
  86. package/dist/parser-D5VMCDLG.cjs.map +0 -1
  87. package/dist/pdf-ocr-364WQ5TY.js +0 -18
  88. package/dist/pdf-ocr-4MZELYCR.js +0 -22
  89. package/dist/pdf-ocr-YFNUYBYJ.cjs +0 -19
  90. package/dist/seal-EVHTG5GH.js +0 -10
  91. package/dist/visual-TCIR6MOG.js +0 -20
  92. /package/dist/{-FLYHAUQ6.js.map → -ZYF6HX4M.js.map} +0 -0
  93. /package/dist/{chunk-TC6DQLYN.js.map → chunk-2ZGP7A5T.js.map} +0 -0
  94. /package/dist/{chunk-4VM6BT4W.js.map → chunk-3TCF5HPP.js.map} +0 -0
  95. /package/dist/{chunk-OON4IJU2.js.map → chunk-5HTFWUJE.js.map} +0 -0
  96. /package/dist/{chunk-AQ5GIBBH.js.map → chunk-7YAJCXCD.js.map} +0 -0
  97. /package/dist/{chunk-3O4YC67B.js.map → chunk-BC54LBST.js.map} +0 -0
  98. /package/dist/{chunk-GK4QLKNT.js.map → chunk-BG6LUCQL.js.map} +0 -0
  99. /package/dist/{chunk-SM42XSI3.js.map → chunk-CY4QM2KQ.js.map} +0 -0
  100. /package/dist/{chunk-INZGI6PI.js.map → chunk-FBJVDBMO.js.map} +0 -0
  101. /package/dist/{chunk-Z2OOYQ4I.js.map → chunk-FZMGF6XU.js.map} +0 -0
  102. /package/dist/{chunk-F6N7CDB7.js.map → chunk-J5PBI3ZC.js.map} +0 -0
  103. /package/dist/{chunk-YDIVY65W.js.map → chunk-KTLHADU4.js.map} +0 -0
  104. /package/dist/{chunk-X6WXU4LA.js.map → chunk-PTF4NCFM.js.map} +0 -0
  105. /package/dist/{chunk-46PYORID.js.map → chunk-QHNVH4TC.js.map} +0 -0
  106. /package/dist/{chunk-RYRUQ73F.js.map → chunk-RBRHO7WL.js.map} +0 -0
  107. /package/dist/{chunk-CLAIAXMX.js.map → chunk-T3DTTK23.js.map} +0 -0
  108. /package/dist/{chunk-VIFY6DJZ.js.map → chunk-TRO4CQHJ.js.map} +0 -0
  109. /package/dist/{chunk-OWLDTF5Q.js.map → chunk-WGMYVRSA.js.map} +0 -0
  110. /package/dist/{chunk-AMXIYV73.js.map → chunk-YHPJTLCA.js.map} +0 -0
  111. /package/dist/{chunk-UDODNSDU.js.map → chunk-ZZIQWSGC.js.map} +0 -0
  112. /package/dist/{chunks-J46DCTUC.js.map → chunks-MDMJRCJ7.js.map} +0 -0
  113. /package/dist/{formula-2YYGN7UE.js.map → formula-6XNIXZ5L.js.map} +0 -0
  114. /package/dist/{formula-Z5UPXBQM.js.map → formula-P7M7IH2L.js.map} +0 -0
  115. /package/dist/{image-ocr-23R7RVHP.js.map → image-ocr-3C6W3KZO.js.map} +0 -0
  116. /package/dist/{image-ocr-IMLFZ2JC.js.map → image-ocr-ITNY454I.js.map} +0 -0
  117. /package/dist/{model-bundle-GTSRH2DY.js.map → model-bundle-LAWQH75O.js.map} +0 -0
  118. /package/dist/{models-2J3NS7G2.js.map → models-6QTD2CFM.js.map} +0 -0
  119. /package/dist/{parse-worker-v2-VO5UY3MP.js.map → parse-worker-v2-FEPJG3ER.js.map} +0 -0
  120. /package/dist/{pdf-ocr-364WQ5TY.js.map → pdf-ocr-MME37BL4.js.map} +0 -0
  121. /package/dist/{pdf-ocr-4MZELYCR.js.map → pdf-ocr-ZZ6AJL6Z.js.map} +0 -0
  122. /package/dist/{profile-io-ULK73H2G.js.map → profile-io-OCITHUQF.js.map} +0 -0
  123. /package/dist/{rasterize-FG3NX3GA.js.map → rasterize-SFCG4YOI.js.map} +0 -0
  124. /package/dist/{redact-doc-NMKTKG24.js.map → redact-doc-5SMPXIGG.js.map} +0 -0
  125. /package/dist/{render-GQUUGPOJ.js.map → render-FGPG5A2N.js.map} +0 -0
  126. /package/dist/{seal-EVHTG5GH.js.map → seal-GA7NZDTG.js.map} +0 -0
  127. /package/dist/{setup-PRBHD7JI.js.map → setup-JQVYZO7I.js.map} +0 -0
  128. /package/dist/{visual-TCIR6MOG.js.map → visual-YMG644YW.js.map} +0 -0
  129. /package/dist/{watch-LFSXNO2B.js.map → watch-C77BUSP7.js.map} +0 -0
@@ -1,15 +1,88 @@
1
- #!/usr/bin/env node
2
1
  import {
3
2
  CELL_EDGES,
4
3
  HEADING_RATIO_H1,
5
4
  HEADING_RATIO_H2,
6
5
  HEADING_RATIO_H3,
7
6
  tidyScriptTags
8
- } from "./chunk-X6WXU4LA.js";
7
+ } from "./chunk-KTLHADU4.js";
8
+ import {
9
+ ensureModelsIn,
10
+ getModelsDir
11
+ } from "./chunk-FBJVDBMO.js";
9
12
  import {
10
13
  safeMax,
11
14
  safeMin
12
- } from "./chunk-Z2OOYQ4I.js";
15
+ } from "./chunk-ZZIQWSGC.js";
16
+
17
+ // src/ocr/models.ts
18
+ import { join } from "path";
19
+ import { stat } from "fs/promises";
20
+ var OCR_DET_MODEL = {
21
+ name: "PP-OCRv5 mobile det",
22
+ filename: "det.onnx",
23
+ url: "https://huggingface.co/PaddlePaddle/PP-OCRv5_mobile_det_onnx/resolve/main/inference.onnx",
24
+ sha256: "a431985659dc921974177a95adcfbb90fd9e51989a5e04d70d0b75f597b6e61d",
25
+ sizeMb: 5
26
+ };
27
+ var OCR_REC_MODEL = {
28
+ name: "PP-OCRv5 korean rec",
29
+ filename: "rec_korean.onnx",
30
+ url: "https://huggingface.co/PaddlePaddle/korean_PP-OCRv5_mobile_rec_onnx/resolve/main/inference.onnx",
31
+ sha256: "92f0b7785e64fc9090106a241cf4c1eb97472824558272751b88a2a4476d3a08",
32
+ sizeMb: 13
33
+ };
34
+ var OCR_REC_DICT = {
35
+ name: "PP-OCRv5 korean dict",
36
+ filename: "rec_korean.yml",
37
+ url: "https://huggingface.co/PaddlePaddle/korean_PP-OCRv5_mobile_rec_onnx/resolve/main/inference.yml",
38
+ sha256: "f757fa1c40e99edcf27e9cce879b93eb2a51fa46f5ef39095689b8c37dd75998",
39
+ sizeMb: 1
40
+ };
41
+ var ALL_OCR_MODELS = [OCR_DET_MODEL, OCR_REC_MODEL, OCR_REC_DICT];
42
+ function getOcrModelsDir() {
43
+ return getModelsDir("ppocr");
44
+ }
45
+ async function ensureOcrModels(onProgress) {
46
+ return ensureModelsIn(getOcrModelsDir(), ALL_OCR_MODELS, onProgress);
47
+ }
48
+ async function ocrModelsCached() {
49
+ const dir = getOcrModelsDir();
50
+ for (const spec of ALL_OCR_MODELS) {
51
+ try {
52
+ if (!(await stat(join(dir, spec.filename))).size) return false;
53
+ } catch {
54
+ return false;
55
+ }
56
+ }
57
+ return true;
58
+ }
59
+ function parseCharacterDict(yml) {
60
+ const lines = yml.split("\n");
61
+ const chars = [];
62
+ let inDict = false;
63
+ let dictIndent = -1;
64
+ for (const line of lines) {
65
+ if (!inDict) {
66
+ const m2 = /^(\s*)character_dict:\s*$/.exec(line);
67
+ if (m2) {
68
+ inDict = true;
69
+ dictIndent = m2[1].length;
70
+ }
71
+ continue;
72
+ }
73
+ const m = /^(\s*)- (.*)$/.exec(line);
74
+ if (m && m[1].length >= dictIndent) {
75
+ let v = m[2];
76
+ if (v.length >= 2 && (v.startsWith("'") && v.endsWith("'") || v.startsWith('"') && v.endsWith('"'))) {
77
+ v = v.slice(1, -1).replace(/''/g, "'");
78
+ }
79
+ chars.push(v);
80
+ continue;
81
+ }
82
+ if (line.trim() !== "") break;
83
+ }
84
+ return chars;
85
+ }
13
86
 
14
87
  // src/pdf/line-extract.ts
15
88
  import { OPS } from "pdfjs-dist/legacy/build/pdf.mjs";
@@ -1871,7 +1944,7 @@ function dropGridsInside(lineGrids, clipGrids, containers = [], verticals = [])
1871
1944
  const ga = area(g);
1872
1945
  return ga > 0 && ix * iy / ga >= 0.5;
1873
1946
  };
1874
- const inside = (c, g) => c.x1 >= g.x1 - 1 && c.x2 <= g.x2 + 1 && c.y1 >= g.y1 - 1 && c.y2 <= g.y2 + 1;
1947
+ const inside = (c, g) => c.x1 >= g.x1 - 3 && c.x2 <= g.x2 + 3 && c.y1 >= g.y1 - 3 && c.y2 <= g.y2 + 3;
1875
1948
  const stackedOnly = (g) => {
1876
1949
  const stacked = clipGrids.filter((c) => inside(c.bbox, g.bbox)).sort((a, b) => a.bbox.y1 - b.bbox.y1);
1877
1950
  if (stacked.length < 2 || g.colXs.length < 3 || stacked.reduce((s, c) => s + area(c.bbox), 0) < area(g.bbox) * 0.5) return false;
@@ -3342,6 +3415,49 @@ function isExamLayoutTable(table) {
3342
3415
  return layout >= texts.length * 0.6;
3343
3416
  }
3344
3417
 
3418
+ // src/pdf/cluster-cell-text.ts
3419
+ function clusterCellLines(items) {
3420
+ const hOf = (i) => i.h > 0 ? i.h : i.fontSize;
3421
+ const lines = [];
3422
+ for (const it of [...items].sort((a, b) => b.y - a.y || a.x - b.x)) {
3423
+ const bottom = it.y, top = it.y + hOf(it);
3424
+ const line = lines.find((l) => Math.min(l.top, top) - Math.max(l.bottom, bottom) >= Math.min(l.top - l.bottom, top - bottom) * 0.5);
3425
+ if (line) {
3426
+ line.items.push(it);
3427
+ line.bottom = Math.min(line.bottom, bottom);
3428
+ line.top = Math.max(line.top, top);
3429
+ } else lines.push({ bottom, top, items: [it] });
3430
+ }
3431
+ return lines.sort((a, b) => b.top - a.top).map(({ items: line }) => {
3432
+ line.sort((a, b) => a.x - b.x);
3433
+ let s = line[0].text;
3434
+ for (let i = 1; i < line.length; i++) {
3435
+ const gap = line[i].x - (line[i - 1].x + line[i - 1].w);
3436
+ const fs = (line[i].fontSize + line[i - 1].fontSize) / 2;
3437
+ s += (!isCjkLatinAutospace(line[i - 1].text, line[i].text, gap, fs) && (line[i].hasSpaceBefore && gap >= fs * 0.05 || gap > spaceGapThreshold(fs)) ? " " : "") + line[i].text;
3438
+ }
3439
+ const last = line.reduce((a, b) => b.x + b.w > a.x + a.w ? b : a);
3440
+ return {
3441
+ text: s,
3442
+ left: line[0].x,
3443
+ right: last.x + last.w,
3444
+ fontSize: line[0].fontSize,
3445
+ spaceAfter: last.spaceAfter,
3446
+ firstCharW: line[0].w / Math.max(1, [...line[0].text.replace(/<\/?u>|~~/g, "")].length)
3447
+ };
3448
+ });
3449
+ }
3450
+ var WRAP_INDENT_MAX = 3;
3451
+ function joinClusterCellLines(lines, box, lex) {
3452
+ let out = lines[0]?.text ?? "";
3453
+ for (let i = 1; i < lines.length; i++) {
3454
+ const a = lines[i - 1], b = lines[i];
3455
+ const join2 = !a.spaceAfter && cellLineWraps(box, box.x1, a.right, a.fontSize, b.firstCharW) && a.left - box.x1 <= WRAP_INDENT_MAX * a.fontSize && b.left - box.x1 <= WRAP_INDENT_MAX * b.fontSize && /<\/u>$/.test(a.text) === /^<u>/.test(b.text) && !startsNewItem(out, b.text) && wrapJoiner(out, b.text, lex, false) === "";
3456
+ out += (join2 ? "" : " ") + b.text;
3457
+ }
3458
+ return out;
3459
+ }
3460
+
3345
3461
  // src/pdf/cluster-detector.ts
3346
3462
  var Y_TOL = 3;
3347
3463
  var COL_CLUSTER_TOL = 15;
@@ -3350,7 +3466,7 @@ var MIN_COLS = 2;
3350
3466
  var MIN_GAP_FACTOR = 2;
3351
3467
  var MIN_GAP_ABSOLUTE = 20;
3352
3468
  var MIN_COL_FILL_RATIO = 0.4;
3353
- function detectClusterTables(items, pageNum, rejected) {
3469
+ function detectClusterTables(items, pageNum, rejected, lex) {
3354
3470
  const tab = sideTabGlyphs(items);
3355
3471
  if (tab.size) items = items.filter((i) => !tab.has(i));
3356
3472
  if (items.length < MIN_ROWS * MIN_COLS) return [];
@@ -3371,7 +3487,7 @@ function detectClusterTables(items, pageNum, rejected) {
3371
3487
  const mergedRows = mergeMultiLineRows(headerAndBelow, columns);
3372
3488
  const tableRegions = findTableRegionsByHeader(mergedRows, columns, headerItems);
3373
3489
  for (const region of tableRegions) {
3374
- const table = buildClusterTable(region.rows, columns, pageNum);
3490
+ const table = buildClusterTable(region.rows, columns, pageNum, lex);
3375
3491
  if (table) {
3376
3492
  expandUsedItems(table.usedItems, originMap);
3377
3493
  results.push(table);
@@ -3386,8 +3502,8 @@ function detectClusterTables(items, pageNum, rejected) {
3386
3502
  const tableRegions = findTableRegions(rows, columns);
3387
3503
  for (const region of tableRegions) {
3388
3504
  const own = extractColumnClusters(region.rows.filter((row) => hasSuspiciousGaps(row)));
3389
- const ownTable = own.length >= MIN_COLS && own.length < columns.length ? buildClusterTable(mergeMultiLineRows(region.rows, own), own, pageNum) : null;
3390
- const table = ownTable && ownTable.table.cells.every((row, r) => row.every((cell) => (r === 0 || cell.colSpan >= ownTable.table.cols || cell.text.trim().length <= 30) && !/\p{Co}/u.test(cell.text))) ? ownTable : buildClusterTable(mergeMultiLineRows(region.rows, columns), columns, pageNum);
3505
+ const ownTable = own.length >= MIN_COLS && own.length < columns.length ? buildClusterTable(mergeMultiLineRows(region.rows, own), own, pageNum, lex) : null;
3506
+ const table = ownTable && ownTable.table.cells.every((row, r) => row.every((cell) => (r === 0 || cell.colSpan >= ownTable.table.cols || cell.text.trim().length <= 30) && !/\p{Co}/u.test(cell.text))) ? ownTable : buildClusterTable(mergeMultiLineRows(region.rows, columns), columns, pageNum, lex);
3391
3507
  if (table) {
3392
3508
  expandUsedItems(table.usedItems, originMap);
3393
3509
  results.push(table);
@@ -4084,7 +4200,7 @@ function assignRowItems(items, columns, numCols, headerFace) {
4084
4200
  }
4085
4201
  return result;
4086
4202
  }
4087
- function buildClusterTable(rows, columns, pageNum) {
4203
+ function buildClusterTable(rows, columns, pageNum, lex) {
4088
4204
  const numCols = columns.length;
4089
4205
  const numRows = rows.length;
4090
4206
  if (numRows < MIN_ROWS || numCols < MIN_COLS) return null;
@@ -4093,6 +4209,7 @@ function buildClusterTable(rows, columns, pageNum) {
4093
4209
  () => Array.from({ length: numCols }, () => ({ text: "", colSpan: 1, rowSpan: 1 }))
4094
4210
  );
4095
4211
  const usedItems = /* @__PURE__ */ new Set();
4212
+ const lines = cells.map((row) => row.map(() => []));
4096
4213
  const headFaces = new Set(rows[0]?.items.map((i) => i.fontName));
4097
4214
  const headerFace = headFaces.size === 1 && rows.slice(1).every((row) => row.items.every((i) => !headFaces.has(i.fontName))) ? [...headFaces][0] : void 0;
4098
4215
  for (let r = 0; r < numRows; r++) {
@@ -4104,12 +4221,18 @@ function buildClusterTable(rows, columns, pageNum) {
4104
4221
  }
4105
4222
  const assignments = assignRowItems(row.items, columns, numCols, r === 0 ? headerFace : void 0);
4106
4223
  for (const { col, items } of assignments) {
4107
- const text = joinCellItems(items);
4108
- const existing = cells[r][col].text;
4109
- cells[r][col].text = existing ? existing + " " + text : text;
4224
+ const cell = lines[r][col];
4225
+ if (cell.length) cell[cell.length - 1].spaceAfter = true;
4226
+ cell.push(...clusterCellLines(items));
4110
4227
  for (const item of items) usedItems.add(item);
4111
4228
  }
4112
4229
  }
4230
+ const boxes = columns.map((_, c) => {
4231
+ const col = lines.flatMap((row) => row[c]);
4232
+ return { x1: Math.min(...col.map((l) => l.left)), x2: Math.max(...col.map((l) => l.right)) };
4233
+ });
4234
+ const textOf = (r, c) => joinClusterCellLines(lines[r][c], boxes[c], lex);
4235
+ for (let r = 0; r < numRows; r++) for (let c = 0; c < numCols; c++) if (lines[r][c].length) cells[r][c].text = textOf(r, c);
4113
4236
  let emptyRows = 0;
4114
4237
  for (const row of cells) {
4115
4238
  if (row.every((c) => c.text === "")) emptyRows++;
@@ -4129,9 +4252,9 @@ function buildClusterTable(rows, columns, pageNum) {
4129
4252
  if (cells[pr].some((c) => c.text.trim())) {
4130
4253
  if (cells[pr][0].colSpan > 1) break;
4131
4254
  for (let c = 0; c < numCols; c++) {
4132
- const prev = cells[pr][c].text.trim();
4133
- const curr = cells[r][c].text.trim();
4134
- if (curr) cells[pr][c].text = prev ? prev + " " + curr : curr;
4255
+ if (!cells[r][c].text.trim()) continue;
4256
+ lines[pr][c].push(...lines[r][c]);
4257
+ cells[pr][c].text = textOf(pr, c);
4135
4258
  }
4136
4259
  for (let c = 0; c < numCols; c++) cells[r][c].text = "";
4137
4260
  break;
@@ -4178,29 +4301,6 @@ function buildClusterTable(rows, columns, pageNum) {
4178
4301
  usedItems
4179
4302
  };
4180
4303
  }
4181
- function joinCellItems(items) {
4182
- const hOf = (i) => i.h > 0 ? i.h : i.fontSize;
4183
- const lines = [];
4184
- for (const it of [...items].sort((a, b) => b.y - a.y || a.x - b.x)) {
4185
- const bottom = it.y, top = it.y + hOf(it);
4186
- const line = lines.find((l) => Math.min(l.top, top) - Math.max(l.bottom, bottom) >= Math.min(l.top - l.bottom, top - bottom) * 0.5);
4187
- if (line) {
4188
- line.items.push(it);
4189
- line.bottom = Math.min(line.bottom, bottom);
4190
- line.top = Math.max(line.top, top);
4191
- } else lines.push({ bottom, top, items: [it] });
4192
- }
4193
- return lines.sort((a, b) => b.top - a.top).map(({ items: line }) => {
4194
- line.sort((a, b) => a.x - b.x);
4195
- let s = line[0].text;
4196
- for (let i = 1; i < line.length; i++) {
4197
- const gap = line[i].x - (line[i - 1].x + line[i - 1].w);
4198
- const fs = (line[i].fontSize + line[i - 1].fontSize) / 2;
4199
- s += (!isCjkLatinAutospace(line[i - 1].text, line[i].text, gap, fs) && (line[i].hasSpaceBefore && gap >= fs * 0.05 || gap > spaceGapThreshold(fs)) ? " " : "") + line[i].text;
4200
- }
4201
- return s;
4202
- }).join(" ");
4203
- }
4204
4304
 
4205
4305
  // src/pdf/page-regions.ts
4206
4306
  function splitTwoColumnProse(items, cutX) {
@@ -5644,6 +5744,20 @@ function detectSpecialKoreanTables(blocks) {
5644
5744
  flushKvTable();
5645
5745
  return result;
5646
5746
  }
5747
+ function tracksPages(occ) {
5748
+ const nums = occ.map((o) => [...o.text.matchAll(/\d+/g)].map((m) => +m[0]));
5749
+ if (!nums.length || nums.some((n) => n.length !== nums[0].length)) return false;
5750
+ return nums[0].some((_, j) => new Set(occ.map((o, k) => o.page - nums[k][j])).size === 1);
5751
+ }
5752
+ function looseVaryingNumber(occ) {
5753
+ const nums = occ.map((o) => [...o.text.matchAll(/\d+/g)]);
5754
+ if (!nums.length || nums.some((n) => n.length !== nums[0].length)) return false;
5755
+ const loose = (text, m) => !/\p{L}/u.test(text[m.index - 1] ?? " ") && !/\p{L}/u.test(text[m.index + m[0].length] ?? " ");
5756
+ for (let j = 0; j < nums[0].length; j++) {
5757
+ if (new Set(nums.map((n) => n[j][0])).size > 1 && occ.every((o, k) => loose(o.text, nums[k][j]))) return true;
5758
+ }
5759
+ return false;
5760
+ }
5647
5761
  function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables = false, context = []) {
5648
5762
  if (context.length && !tables) {
5649
5763
  const removed = removeHeaderFooterBlocks([...blocks, ...context], pageHeights, [], notes).filter((index) => index < blocks.length);
@@ -5673,6 +5787,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
5673
5787
  const patternCount = /* @__PURE__ */ new Map();
5674
5788
  const patternPages = /* @__PURE__ */ new Map();
5675
5789
  const patternNumbers = /* @__PURE__ */ new Map();
5790
+ const patternOcc = /* @__PURE__ */ new Map();
5676
5791
  for (const e of entries) {
5677
5792
  const norm = e.text.replace(/\d+/g, "#");
5678
5793
  patternCount.set(norm, (patternCount.get(norm) || 0) + 1);
@@ -5682,13 +5797,18 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
5682
5797
  const pages = patternPages.get(norm) || /* @__PURE__ */ new Set();
5683
5798
  pages.add(e.page);
5684
5799
  patternPages.set(norm, pages);
5800
+ patternOcc.set(norm, [...patternOcc.get(norm) ?? [], e]);
5685
5801
  }
5686
5802
  const repeatedPatterns = /* @__PURE__ */ new Set();
5687
5803
  for (const [p, count] of patternCount) {
5688
5804
  const pages = [...patternPages.get(p) ?? []];
5689
5805
  const span2 = pages.length ? Math.max(...pages) - Math.min(...pages) + 1 : 0;
5690
- const pageNumbered = !tables && (patternNumbers.get(p)?.size ?? 0) > 1;
5691
- if (count >= MIN_REPEAT2 && pages.length >= MIN_REPEAT2 && (pages.length >= span2 * 0.4 || pageNumbered)) {
5806
+ const varying = !tables && (patternNumbers.get(p)?.size ?? 0) > 1;
5807
+ const occ = patternOcc.get(p) ?? [];
5808
+ const dense = pages.length >= span2 * 0.4;
5809
+ const loose = looseVaryingNumber(occ) && (entries === bottomEntries || dense || tracksPages(occ));
5810
+ const pageNumbered = varying && (loose || dense && new Set(occ.map((o) => o.text)).size * 2 <= occ.length);
5811
+ if (count >= MIN_REPEAT2 && pages.length >= MIN_REPEAT2 && (varying ? pageNumbered : dense)) {
5692
5812
  repeatedPatterns.add(p);
5693
5813
  }
5694
5814
  }
@@ -5726,6 +5846,59 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
5726
5846
  }
5727
5847
  return [...removeSet].sort((a, b) => a - b);
5728
5848
  }
5849
+ function runningLinePatterns(removed, pageHeights) {
5850
+ const occ = /* @__PURE__ */ new Map();
5851
+ for (const b of removed) {
5852
+ const ph = b.bbox && b.pageNumber ? pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber) : void 0;
5853
+ const key = b.text ? runningKey(b.text) : "";
5854
+ if (!ph || !b.bbox || !b.pageNumber || !/\p{L}/u.test(key) || ph - b.bbox.y <= ph * 0.5) continue;
5855
+ (occ.get(key) ?? occ.set(key, []).get(key)).push({ page: b.pageNumber, nums: (b.text.match(/\d+/g) ?? []).join(",") });
5856
+ }
5857
+ const out = /* @__PURE__ */ new Map();
5858
+ for (const [key, list] of occ) {
5859
+ if (!pageNumberAtEnd(key)) continue;
5860
+ const offsets = new Set(list.map((o) => o.page - +o.nums));
5861
+ if (offsets.size === 1) out.set(key, [...offsets][0]);
5862
+ }
5863
+ return out;
5864
+ }
5865
+ var runningKey = (s) => s.replace(/\d+/g, "#").replace(/\s+/g, " ").trim();
5866
+ var pageNumberAtEnd = (key) => (key.match(/#/g) ?? []).length === 1 && /#\s*[)\]]?$/.test(key);
5867
+ function stripAbsorbedRunningLines(blocks, pageHeights, running) {
5868
+ if (!running.size) return blocks;
5869
+ const matches = (line, page) => {
5870
+ const offset = running.get(runningKey(line));
5871
+ return offset !== void 0 && page - +(line.match(/\d+/g) ?? []).pop() === offset;
5872
+ };
5873
+ const out = [];
5874
+ for (const b of blocks) {
5875
+ const ph = b.bbox && b.pageNumber ? pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber) : void 0;
5876
+ if (!ph || !b.bbox || !b.pageNumber || b.bbox.y > ph * 0.12) {
5877
+ out.push(b);
5878
+ continue;
5879
+ }
5880
+ if (b.type === "paragraph" && b.text) {
5881
+ const lines = b.text.split("\n");
5882
+ let hi = lines.length;
5883
+ while (hi > 0 && !lines[hi - 1].trim()) hi--;
5884
+ if (hi > 0 && matches(lines[hi - 1], b.pageNumber)) {
5885
+ const text = lines.slice(0, hi - 1).join("\n").trim();
5886
+ if (!text) continue;
5887
+ b.text = text;
5888
+ }
5889
+ } else if (b.type === "table" && b.table && b.table.cells.length) {
5890
+ const t = b.table, last = t.cells.length - 1;
5891
+ if (matches(t.cells[last].map((c) => c.text.trim()).filter(Boolean).join(" "), b.pageNumber) && !t.cells.slice(0, last).some((row, i) => row.some((c) => i + (c.rowSpan || 1) - 1 >= last))) {
5892
+ t.cells.pop();
5893
+ if (!t.cells.length) continue;
5894
+ t.rows = t.cells.length;
5895
+ t.hasHeader = t.hasHeader && t.rows > 1;
5896
+ }
5897
+ }
5898
+ out.push(b);
5899
+ }
5900
+ return out;
5901
+ }
5729
5902
 
5730
5903
  // src/pdf/table-meta.ts
5731
5904
  var CLIP_TABLES = /* @__PURE__ */ new WeakSet();
@@ -8201,7 +8374,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
8201
8374
  spaceAfter: i.spaceAfter
8202
8375
  }));
8203
8376
  const proseColumns = findTwoColumnProseCutX(clusterItems) !== null || detectPersistentColumnGutter(remaining.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }))) !== null;
8204
- const clusterResults = (proseColumns ? [] : detectClusterTables(clusterItems, pageNum)).filter((cr) => {
8377
+ const clusterResults = (proseColumns ? [] : detectClusterTables(clusterItems, pageNum, void 0, lex)).filter((cr) => {
8205
8378
  const b = cr.bbox;
8206
8379
  const overlapX = (x) => Math.min(x.x + x.width, b.x + b.width) - Math.max(x.x, b.x);
8207
8380
  return !blocks.some((x) => x.bbox && x.bbox.y >= b.y - 2 && x.bbox.y + x.bbox.height <= b.y + b.height + 2 && (x.type === "paragraph" ? (x.text?.match(/\p{L}/gu)?.length ?? 0) >= 10 && overlapX(x.bbox) >= 0.8 * b.width : x.type === "table" && !ocrPage && x.table?.cols === cr.table.cols && overlapX(x.bbox) >= 0.5 * Math.min(x.bbox.width, b.width)));
@@ -8553,7 +8726,7 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
8553
8726
  if (regions) return regions.flatMap((region) => extractPageBlocksFallback(region, pageNum, false, detectTables, lex));
8554
8727
  }
8555
8728
  const rejected = { prose: 0 };
8556
- const clusterResults = detectTables ? detectClusterTables(clusterItems, pageNum, rejected) : [];
8729
+ const clusterResults = detectTables ? detectClusterTables(clusterItems, pageNum, rejected, lex) : [];
8557
8730
  if (clusterResults.length > 0) {
8558
8731
  const ciToIdx = /* @__PURE__ */ new Map();
8559
8732
  for (let ci = 0; ci < clusterItems.length; ci++) ciToIdx.set(clusterItems[ci], ci);
@@ -8738,6 +8911,13 @@ function rowParagraphs(block) {
8738
8911
  }
8739
8912
 
8740
8913
  export {
8914
+ OCR_DET_MODEL,
8915
+ OCR_REC_MODEL,
8916
+ OCR_REC_DICT,
8917
+ getOcrModelsDir,
8918
+ ensureOcrModels,
8919
+ ocrModelsCached,
8920
+ parseCharacterDict,
8741
8921
  extractLines,
8742
8922
  extractImageRegions,
8743
8923
  filterHiddenText,
@@ -8767,6 +8947,8 @@ export {
8767
8947
  detectTableCaptions,
8768
8948
  detectKoreanListBlocks,
8769
8949
  removeHeaderFooterBlocks,
8950
+ runningLinePatterns,
8951
+ stripAbsorbedRunningLines,
8770
8952
  CLIP_TABLES,
8771
8953
  FRAME_TITLE_BLOCKS,
8772
8954
  TABLE_COLXS,
@@ -8789,4 +8971,4 @@ export {
8789
8971
  UNRULED_REGION_TABLES,
8790
8972
  mergeOcrImageRegions
8791
8973
  };
8792
- //# sourceMappingURL=chunk-Y5OSPKBU.js.map
8974
+ //# sourceMappingURL=chunk-YQZOPT3A.js.map