kordoc 4.14.2 → 4.14.4

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 (151) hide show
  1. package/README.md +51 -6
  2. package/dist/{-AQKXLFIM.js → -Z4TJ3QGK.js} +13 -11
  3. package/dist/{chunk-QOMNEWCQ.cjs → chunk-5LAZQCUJ.cjs} +305 -31
  4. package/dist/chunk-5LAZQCUJ.cjs.map +1 -0
  5. package/dist/{chunk-7IAQ4HOK.js → chunk-6BWU6SQX.js} +1 -1
  6. package/dist/chunk-6BWU6SQX.js.map +1 -0
  7. package/dist/{chunk-FOJZNMMK.js → chunk-6CUIXJOC.js} +1 -1
  8. package/dist/chunk-6CUIXJOC.js.map +1 -0
  9. package/dist/{chunk-ZWD734EY.js → chunk-7SE4EZ45.js} +2 -2
  10. package/dist/{chunk-TSFS5VKD.js → chunk-D4U2TXDC.js} +332 -141
  11. package/dist/chunk-D4U2TXDC.js.map +1 -0
  12. package/dist/chunk-DPWWXUOG.js +2222 -0
  13. package/dist/chunk-DPWWXUOG.js.map +1 -0
  14. package/dist/{chunk-GDW4YP7K.js → chunk-GLSBEEZJ.js} +2 -2
  15. package/dist/{chunk-JQEFP45L.js → chunk-GUJ4Q73I.js} +2 -2
  16. package/dist/{chunk-ZWOFQRIB.js → chunk-HIJUKZHM.js} +3 -3
  17. package/dist/chunk-IMAAFSAX.cjs +1352 -0
  18. package/dist/chunk-IMAAFSAX.cjs.map +1 -0
  19. package/dist/{chunk-TNCKOL2O.js → chunk-LCW7SEPG.js} +2 -2
  20. package/dist/chunk-LFSQAMSM.js +1352 -0
  21. package/dist/chunk-LFSQAMSM.js.map +1 -0
  22. package/dist/chunk-MG6DJEX4.js +1299 -0
  23. package/dist/chunk-MG6DJEX4.js.map +1 -0
  24. package/dist/{chunk-QC5T6D4J.js → chunk-NLU6LBLY.js} +299 -25
  25. package/dist/chunk-NLU6LBLY.js.map +1 -0
  26. package/dist/{chunk-EQZI77PP.cjs → chunk-QEJUY6SK.cjs} +3 -3
  27. package/dist/{chunk-EQZI77PP.cjs.map → chunk-QEJUY6SK.cjs.map} +1 -1
  28. package/dist/{chunk-VQ5W4MYO.js → chunk-QIF2VXBQ.js} +298 -24
  29. package/dist/chunk-QIF2VXBQ.js.map +1 -0
  30. package/dist/{chunk-UET462HB.js → chunk-TITDJWVZ.js} +2 -2
  31. package/dist/{chunk-247ANM72.cjs → chunk-USHQCF5T.cjs} +870 -147
  32. package/dist/chunk-USHQCF5T.cjs.map +1 -0
  33. package/dist/{chunk-C7FQBSON.js → chunk-V3DX4DUF.js} +2 -2
  34. package/dist/{chunk-DOGPOY4B.js → chunk-VDN7LMPL.js} +2 -2
  35. package/dist/{chunk-EDNJLUSE.js → chunk-VJIL6PIL.js} +2 -2
  36. package/dist/{chunk-L7DMSMAG.cjs → chunk-VWUYVEFN.cjs} +1 -1
  37. package/dist/chunk-VWUYVEFN.cjs.map +1 -0
  38. package/dist/{chunk-HR2XNERB.cjs → chunk-WJHAU73B.cjs} +2 -2
  39. package/dist/{chunk-HR2XNERB.cjs.map → chunk-WJHAU73B.cjs.map} +1 -1
  40. package/dist/{chunk-NS55SM7A.js → chunk-WJJGW5PL.js} +2 -2
  41. package/dist/{chunk-EISO3POT.js → chunk-XVXHXQIO.js} +788 -194
  42. package/dist/chunk-XVXHXQIO.js.map +1 -0
  43. package/dist/{chunk-ILU76UF3.js → chunk-YAKC46HZ.js} +2 -2
  44. package/dist/chunk-YAKC46HZ.js.map +1 -0
  45. package/dist/{chunk-3DUADAY2.js → chunk-YAVHVFRY.js} +851 -128
  46. package/dist/chunk-YAVHVFRY.js.map +1 -0
  47. package/dist/{chunk-A7QC2ZVP.js → chunk-YT3GC62E.js} +851 -128
  48. package/dist/chunk-YT3GC62E.js.map +1 -0
  49. package/dist/chunks-CCMRL4MJ.js +10 -0
  50. package/dist/cli.js +228 -97
  51. package/dist/cli.js.map +1 -1
  52. package/dist/{formula-PJJ6S3Z2.cjs → formula-5LOVHAKE.cjs} +9 -9
  53. package/dist/{formula-PJJ6S3Z2.cjs.map → formula-5LOVHAKE.cjs.map} +1 -1
  54. package/dist/{formula-JGFTXWYT.js → formula-7RANCW5L.js} +3 -3
  55. package/dist/{formula-5S7WWXGH.js → formula-7UYJOVTB.js} +4 -4
  56. package/dist/{image-ocr-WCAYXLOA.js → image-ocr-I6JOCATS.js} +34 -16
  57. package/dist/image-ocr-I6JOCATS.js.map +1 -0
  58. package/dist/{image-ocr-ZTYAGV3W.cjs → image-ocr-NYBJEOH2.cjs} +36 -18
  59. package/dist/image-ocr-NYBJEOH2.cjs.map +1 -0
  60. package/dist/{image-ocr-FLIL7MGN.js → image-ocr-ZV6PDBUQ.js} +32 -14
  61. package/dist/image-ocr-ZV6PDBUQ.js.map +1 -0
  62. package/dist/index.cjs +4048 -1216
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +66 -28
  65. package/dist/index.d.ts +66 -28
  66. package/dist/index.js +3487 -655
  67. package/dist/index.js.map +1 -1
  68. package/dist/mcp.js +74 -53
  69. package/dist/mcp.js.map +1 -1
  70. package/dist/{model-bundle-FSPZZ2EM.js → model-bundle-2C5IYDLE.js} +5 -5
  71. package/dist/{models-CJPAQK5R.js → models-SEQZHZFT.js} +5 -5
  72. package/dist/{parser-SCUTZAIJ.js → parser-3FNXEP6T.js} +708 -250
  73. package/dist/parser-3FNXEP6T.js.map +1 -0
  74. package/dist/{parser-A4TMPJAM.js → parser-FJBJXRJK.js} +708 -250
  75. package/dist/parser-FJBJXRJK.js.map +1 -0
  76. package/dist/{parser-VCXE4I5A.cjs → parser-HVEKF73B.cjs} +733 -275
  77. package/dist/parser-HVEKF73B.cjs.map +1 -0
  78. package/dist/pdf-ocr-JRDBJ6TA.cjs +14 -0
  79. package/dist/{pdf-ocr-MBZZ57LD.cjs.map → pdf-ocr-JRDBJ6TA.cjs.map} +1 -1
  80. package/dist/pdf-ocr-UUBWBEHL.js +16 -0
  81. package/dist/pdf-ocr-VJSF2SQC.js +13 -0
  82. package/dist/{profile-io-LBM263K7.js → profile-io-RUFZOZO6.js} +3 -3
  83. package/dist/{rasterize-46RG4ZF6.js → rasterize-IOYXR5SI.js} +3 -3
  84. package/dist/redact-NMIKVHMP.js +18 -0
  85. package/dist/redact-doc-QBHNJ2BU.js +1284 -0
  86. package/dist/redact-doc-QBHNJ2BU.js.map +1 -0
  87. package/dist/{render-NGP5T24S.js → render-YZ2TEC3N.js} +7 -7
  88. package/dist/seal-ECV44TUH.js +10 -0
  89. package/dist/{setup-AU4OCHNH.js → setup-MPIEP6XT.js} +3 -3
  90. package/dist/visual-ICMOWUCR.js +19 -0
  91. package/dist/{watch-MKPUCPXM.js → watch-RYO7MN5B.js} +12 -12
  92. package/package.json +2 -2
  93. package/dist/chunk-247ANM72.cjs.map +0 -1
  94. package/dist/chunk-3DUADAY2.js.map +0 -1
  95. package/dist/chunk-422427XJ.cjs +0 -571
  96. package/dist/chunk-422427XJ.cjs.map +0 -1
  97. package/dist/chunk-7IAQ4HOK.js.map +0 -1
  98. package/dist/chunk-A7QC2ZVP.js.map +0 -1
  99. package/dist/chunk-DZIXKL7E.js +0 -145
  100. package/dist/chunk-DZIXKL7E.js.map +0 -1
  101. package/dist/chunk-EISO3POT.js.map +0 -1
  102. package/dist/chunk-EP7KOI2V.js +0 -571
  103. package/dist/chunk-EP7KOI2V.js.map +0 -1
  104. package/dist/chunk-FOJZNMMK.js.map +0 -1
  105. package/dist/chunk-ILU76UF3.js.map +0 -1
  106. package/dist/chunk-KVWV4ULP.js +0 -516
  107. package/dist/chunk-KVWV4ULP.js.map +0 -1
  108. package/dist/chunk-L7DMSMAG.cjs.map +0 -1
  109. package/dist/chunk-QC5T6D4J.js.map +0 -1
  110. package/dist/chunk-QOMNEWCQ.cjs.map +0 -1
  111. package/dist/chunk-TSFS5VKD.js.map +0 -1
  112. package/dist/chunk-VQ5W4MYO.js.map +0 -1
  113. package/dist/chunks-SX77P5CV.js +0 -10
  114. package/dist/image-ocr-FLIL7MGN.js.map +0 -1
  115. package/dist/image-ocr-WCAYXLOA.js.map +0 -1
  116. package/dist/image-ocr-ZTYAGV3W.cjs.map +0 -1
  117. package/dist/parser-A4TMPJAM.js.map +0 -1
  118. package/dist/parser-SCUTZAIJ.js.map +0 -1
  119. package/dist/parser-VCXE4I5A.cjs.map +0 -1
  120. package/dist/pdf-ocr-76SAUXMZ.js +0 -13
  121. package/dist/pdf-ocr-CPU55CVF.js +0 -16
  122. package/dist/pdf-ocr-MBZZ57LD.cjs +0 -14
  123. package/dist/redact-7ILEAUTS.js +0 -12
  124. package/dist/seal-RGUPOLXD.js +0 -10
  125. package/dist/visual-NZLYIYEM.js +0 -19
  126. /package/dist/{-AQKXLFIM.js.map → -Z4TJ3QGK.js.map} +0 -0
  127. /package/dist/{chunk-ZWD734EY.js.map → chunk-7SE4EZ45.js.map} +0 -0
  128. /package/dist/{chunk-GDW4YP7K.js.map → chunk-GLSBEEZJ.js.map} +0 -0
  129. /package/dist/{chunk-JQEFP45L.js.map → chunk-GUJ4Q73I.js.map} +0 -0
  130. /package/dist/{chunk-ZWOFQRIB.js.map → chunk-HIJUKZHM.js.map} +0 -0
  131. /package/dist/{chunk-TNCKOL2O.js.map → chunk-LCW7SEPG.js.map} +0 -0
  132. /package/dist/{chunk-UET462HB.js.map → chunk-TITDJWVZ.js.map} +0 -0
  133. /package/dist/{chunk-C7FQBSON.js.map → chunk-V3DX4DUF.js.map} +0 -0
  134. /package/dist/{chunk-DOGPOY4B.js.map → chunk-VDN7LMPL.js.map} +0 -0
  135. /package/dist/{chunk-EDNJLUSE.js.map → chunk-VJIL6PIL.js.map} +0 -0
  136. /package/dist/{chunk-NS55SM7A.js.map → chunk-WJJGW5PL.js.map} +0 -0
  137. /package/dist/{chunks-SX77P5CV.js.map → chunks-CCMRL4MJ.js.map} +0 -0
  138. /package/dist/{formula-JGFTXWYT.js.map → formula-7RANCW5L.js.map} +0 -0
  139. /package/dist/{formula-5S7WWXGH.js.map → formula-7UYJOVTB.js.map} +0 -0
  140. /package/dist/{model-bundle-FSPZZ2EM.js.map → model-bundle-2C5IYDLE.js.map} +0 -0
  141. /package/dist/{models-CJPAQK5R.js.map → models-SEQZHZFT.js.map} +0 -0
  142. /package/dist/{pdf-ocr-76SAUXMZ.js.map → pdf-ocr-UUBWBEHL.js.map} +0 -0
  143. /package/dist/{pdf-ocr-CPU55CVF.js.map → pdf-ocr-VJSF2SQC.js.map} +0 -0
  144. /package/dist/{profile-io-LBM263K7.js.map → profile-io-RUFZOZO6.js.map} +0 -0
  145. /package/dist/{rasterize-46RG4ZF6.js.map → rasterize-IOYXR5SI.js.map} +0 -0
  146. /package/dist/{redact-7ILEAUTS.js.map → redact-NMIKVHMP.js.map} +0 -0
  147. /package/dist/{render-NGP5T24S.js.map → render-YZ2TEC3N.js.map} +0 -0
  148. /package/dist/{seal-RGUPOLXD.js.map → seal-ECV44TUH.js.map} +0 -0
  149. /package/dist/{setup-AU4OCHNH.js.map → setup-MPIEP6XT.js.map} +0 -0
  150. /package/dist/{visual-NZLYIYEM.js.map → visual-ICMOWUCR.js.map} +0 -0
  151. /package/dist/{watch-MKPUCPXM.js.map → watch-RYO7MN5B.js.map} +0 -0
@@ -1,12 +1,12 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
2
2
 
3
3
 
4
4
 
5
- var _chunkL7DMSMAGcjs = require('./chunk-L7DMSMAG.cjs');
5
+ var _chunkVWUYVEFNcjs = require('./chunk-VWUYVEFN.cjs');
6
6
 
7
7
 
8
8
 
9
- var _chunkHR2XNERBcjs = require('./chunk-HR2XNERB.cjs');
9
+ var _chunkWJHAU73Bcjs = require('./chunk-WJHAU73B.cjs');
10
10
 
11
11
  // src/pdf/image-regions.ts
12
12
  var _pdfmjs = require('pdfjs-dist/legacy/build/pdf.mjs');
@@ -68,7 +68,11 @@ var MAX_LINE_WIDTH = 5;
68
68
  function extractLines(fnArray, argsArray) {
69
69
  const horizontals = [];
70
70
  const verticals = [];
71
+ const shortH = [];
72
+ const shortV = [];
71
73
  const clipRects = [];
74
+ const fillRects = [];
75
+ let pathRects = [];
72
76
  let pendingClip = false;
73
77
  let lineWidth = 1;
74
78
  let ctm = [1, 0, 0, 1, 0, 0];
@@ -84,6 +88,8 @@ function extractLines(fnArray, argsArray) {
84
88
  currentPath.push({ x1: tx1, y1: ty1, x2: tx2, y2: ty2 });
85
89
  }
86
90
  function pushRectangle(rx, ry, rw, rh) {
91
+ const [ax, ay] = applyCtm(rx, ry), [bx, by] = applyCtm(rx + rw, ry + rh);
92
+ pathRects.push({ x1: Math.min(ax, bx), y1: Math.min(ay, by), x2: Math.max(ax, bx), y2: Math.max(ay, by) });
87
93
  const effH = Math.abs(rh) * Math.hypot(ctm[2], ctm[3]);
88
94
  const effW = Math.abs(rw) * Math.hypot(ctm[0], ctm[1]);
89
95
  if (effH < ORIENTATION_TOL * 2) {
@@ -97,7 +103,12 @@ function extractLines(fnArray, argsArray) {
97
103
  pushSeg(rx, ry + rh, rx, ry);
98
104
  }
99
105
  }
100
- function flushPath(isStroke, fromFill = false) {
106
+ function flushPath(isStroke, fromFill = false, filled = fromFill) {
107
+ if (filled) {
108
+ if (pathRects.length) for (const r of pathRects) fillRects.push(r);
109
+ else captureClipRect(currentPath, fillRects, 0.3, 0.3);
110
+ }
111
+ pathRects = [];
101
112
  if (!isStroke) {
102
113
  if (pendingClip) captureClipRect(currentPath, clipRects);
103
114
  pendingClip = false;
@@ -107,7 +118,7 @@ function extractLines(fnArray, argsArray) {
107
118
  pendingClip = false;
108
119
  const effWidth = lineWidth * ctmScale();
109
120
  for (const seg of currentPath) {
110
- classifyAndAdd(seg, effWidth, horizontals, verticals, fromFill);
121
+ classifyAndAdd(seg, effWidth, horizontals, verticals, fromFill, fromFill ? void 0 : { h: shortH, v: shortV });
111
122
  }
112
123
  currentPath = [];
113
124
  }
@@ -208,7 +219,7 @@ function extractLines(fnArray, argsArray) {
208
219
  } else if (afterOp === _pdfmjs.OPS.fill || afterOp === _pdfmjs.OPS.eoFill) {
209
220
  flushPath(true, true);
210
221
  } else if (afterOp === _pdfmjs.OPS.fillStroke || afterOp === _pdfmjs.OPS.eoFillStroke || afterOp === _pdfmjs.OPS.closeFillStroke || afterOp === _pdfmjs.OPS.closeEOFillStroke) {
211
- flushPath(true);
222
+ flushPath(true, false, true);
212
223
  } else if (afterOp === _pdfmjs.OPS.endPath) {
213
224
  flushPath(false);
214
225
  }
@@ -227,7 +238,7 @@ function extractLines(fnArray, argsArray) {
227
238
  case _pdfmjs.OPS.eoFillStroke:
228
239
  case _pdfmjs.OPS.closeFillStroke:
229
240
  case _pdfmjs.OPS.closeEOFillStroke:
230
- flushPath(true);
241
+ flushPath(true, false, true);
231
242
  break;
232
243
  case _pdfmjs.OPS.endPath:
233
244
  flushPath(false);
@@ -238,11 +249,60 @@ function extractLines(fnArray, argsArray) {
238
249
  break;
239
250
  }
240
251
  }
241
- return { horizontals, verticals, clipRects };
252
+ return { horizontals, verticals, clipRects, fillRects, shortH, shortV };
253
+ }
254
+ var SHORT_CHAIN_POS_TOL = 0.5;
255
+ var SHORT_CHAIN_GAP = 0.2;
256
+ function chainShortSegments(longs, shorts, dir) {
257
+ if (shorts.length === 0) return longs;
258
+ const pos = (l) => dir === "h" ? l.y1 : l.x1;
259
+ const lo = (l) => dir === "h" ? l.x1 : l.y1;
260
+ const hi = (l) => dir === "h" ? l.x2 : l.y2;
261
+ const shortSet = new Set(shorts);
262
+ const all = [...longs.filter((l) => !l.fromFill), ...shorts].sort((a, b) => pos(a) - pos(b) || lo(a) - lo(b));
263
+ const absorbed = /* @__PURE__ */ new Set();
264
+ const chained = [];
265
+ const flush = (chain) => {
266
+ if (!chain.some((l) => shortSet.has(l))) return;
267
+ let s = Infinity, e = -Infinity, p = 0, w = 0;
268
+ for (const l of chain) {
269
+ s = Math.min(s, lo(l));
270
+ e = Math.max(e, hi(l));
271
+ p += pos(l);
272
+ w = Math.max(w, l.lineWidth);
273
+ }
274
+ if (e - s < MIN_LINE_LENGTH) return;
275
+ p /= chain.length;
276
+ for (const l of chain) absorbed.add(l);
277
+ chained.push(dir === "h" ? { x1: s, y1: p, x2: e, y2: p, lineWidth: w } : { x1: p, y1: s, x2: p, y2: e, lineWidth: w });
278
+ };
279
+ let band = [];
280
+ const flushBand = () => {
281
+ band.sort((a, b) => lo(a) - lo(b));
282
+ let chain = [];
283
+ let end = -Infinity;
284
+ for (const l of band) {
285
+ if (chain.length && lo(l) > end + SHORT_CHAIN_GAP) {
286
+ flush(chain);
287
+ chain = [];
288
+ }
289
+ chain.push(l);
290
+ end = chain.length === 1 ? hi(l) : Math.max(end, hi(l));
291
+ }
292
+ if (chain.length) flush(chain);
293
+ band = [];
294
+ };
295
+ for (const l of all) {
296
+ if (band.length && pos(l) - pos(band[0]) > SHORT_CHAIN_POS_TOL) flushBand();
297
+ band.push(l);
298
+ }
299
+ if (band.length) flushBand();
300
+ if (chained.length === 0) return longs;
301
+ return [...longs.filter((l) => !absorbed.has(l)), ...chained];
242
302
  }
243
303
  var CLIP_MIN_W = 4;
244
304
  var CLIP_MIN_H = 2;
245
- function captureClipRect(path, out) {
305
+ function captureClipRect(path, out, minW = CLIP_MIN_W, minH = CLIP_MIN_H) {
246
306
  if (path.length < 3 || path.length > 5) return;
247
307
  let x1 = Infinity, y1 = Infinity, x2 = -Infinity, y2 = -Infinity;
248
308
  for (const s of path) {
@@ -253,14 +313,24 @@ function captureClipRect(path, out) {
253
313
  y1 = Math.min(y1, s.y1, s.y2);
254
314
  y2 = Math.max(y2, s.y1, s.y2);
255
315
  }
256
- if (x2 - x1 < CLIP_MIN_W || y2 - y1 < CLIP_MIN_H) return;
316
+ if (x2 - x1 < minW || y2 - y1 < minH) return;
257
317
  out.push({ x1, y1, x2, y2 });
258
318
  }
259
- function classifyAndAdd(seg, lineWidth, horizontals, verticals, fromFill = false) {
319
+ function classifyAndAdd(seg, lineWidth, horizontals, verticals, fromFill = false, short) {
260
320
  const dx = Math.abs(seg.x2 - seg.x1);
261
321
  const dy = Math.abs(seg.y2 - seg.y1);
262
322
  const length = Math.sqrt(dx * dx + dy * dy);
263
- if (length < MIN_LINE_LENGTH) return;
323
+ if (length < MIN_LINE_LENGTH) {
324
+ if (!short || length <= 0) return;
325
+ if (dy <= ORIENTATION_TOL && dx > dy) {
326
+ const y = (seg.y1 + seg.y2) / 2;
327
+ short.h.push({ x1: Math.min(seg.x1, seg.x2), y1: y, x2: Math.max(seg.x1, seg.x2), y2: y, lineWidth });
328
+ } else if (dx <= ORIENTATION_TOL && dy > dx) {
329
+ const x = (seg.x1 + seg.x2) / 2;
330
+ short.v.push({ x1: x, y1: Math.min(seg.y1, seg.y2), x2: x, y2: Math.max(seg.y1, seg.y2), lineWidth });
331
+ }
332
+ return;
333
+ }
264
334
  if (dy <= ORIENTATION_TOL) {
265
335
  const y = (seg.y1 + seg.y2) / 2;
266
336
  const x1 = Math.min(seg.x1, seg.x2);
@@ -741,6 +811,23 @@ function buildTableGrids(horizontals, verticals) {
741
811
  }
742
812
  return mergeAdjacentGrids(grids);
743
813
  }
814
+ var SHADE_CLIP_TOL = 1.5;
815
+ var SHADE_CLIP_MAX_AREA = 0.5;
816
+ function dropShadingClipGrids(clipGrids, lineGrids, fillRects, verticals = []) {
817
+ if (clipGrids.length === 0 || lineGrids.length === 0 || fillRects.length === 0) return clipGrids;
818
+ const near = (a, b) => Math.abs(a - b) <= SHADE_CLIP_TOL;
819
+ const area = (b) => Math.max(0, b.x2 - b.x1) * Math.max(0, b.y2 - b.y1);
820
+ const inter = (a, b) => area({ x1: Math.max(a.x1, b.x1), y1: Math.max(a.y1, b.y1), x2: Math.min(a.x2, b.x2), y2: Math.min(a.y2, b.y2) });
821
+ return clipGrids.filter((c) => {
822
+ if (!_optionalChain([c, 'access', _4 => _4.cells, 'optionalAccess', _5 => _5.length]) || c.clipParent) return true;
823
+ const shaded = c.cells.every((cell) => fillRects.some((f) => near(f.x1, cell.bbox.x1) && near(f.x2, cell.bbox.x2) && near(f.y1, cell.bbox.y1) && near(f.y2, cell.bbox.y2)));
824
+ if (!shaded) return true;
825
+ const ruled = c.cells.every((cell) => cell.bbox.x2 >= c.bbox.x2 - SHADE_CLIP_TOL || verticals.some((v) => Math.abs(v.x1 - cell.bbox.x2) <= SHADE_CLIP_TOL * 2 && Math.min(v.y2, cell.bbox.y2) - Math.max(v.y1, cell.bbox.y1) >= (cell.bbox.y2 - cell.bbox.y1) * 0.75));
826
+ if (!ruled) return true;
827
+ const host = lineGrids.find((l) => c.bbox.x1 >= l.bbox.x1 - SHADE_CLIP_TOL && c.bbox.x2 <= l.bbox.x2 + SHADE_CLIP_TOL && c.bbox.y1 >= l.bbox.y1 - SHADE_CLIP_TOL && c.bbox.y2 <= l.bbox.y2 + SHADE_CLIP_TOL && c.colXs.every((x) => l.colXs.some((lx) => near(lx, x))) && clipGrids.reduce((s, o) => s + inter(o.bbox, l.bbox), 0) <= area(l.bbox) * SHADE_CLIP_MAX_AREA);
828
+ return !host;
829
+ });
830
+ }
744
831
  function enforceMinWidth(colXs, minWidth) {
745
832
  if (colXs.length <= 2) return colXs;
746
833
  const result = [colXs[0]];
@@ -960,20 +1047,25 @@ function linesIntersect(a, b) {
960
1047
 
961
1048
  // src/pdf/clip-cells.ts
962
1049
  var CLIP_EDGE_TOL = 1.5;
1050
+ var CLIP_ADJ_GAP = 0.15;
963
1051
  var CLIP_MIN_GROUP = 2;
964
1052
  var CLIP_MAX_PAGE_FRAC = 0.75;
1053
+ var STRADDLE_MIN = 0.1;
965
1054
  var TITLED_FRAME_MIN_TOP = 0.2;
966
1055
  var TITLED_FRAME_MIN_WIDTH = 0.6;
967
1056
  var HEADER_BAND = 0.08;
968
1057
  var CLIP_MIN_W2 = 4;
1058
+ var NARROW_FILL_MIN_W = 1;
969
1059
  var CLIP_MIN_H2 = 2;
970
1060
  var STROKE_NEAR = 2;
971
1061
  var STROKE_COVER = 0.5;
972
1062
  var CLIP_MIN_INVISIBLE = 0;
1063
+ var CLIP_COORD_TOL = 0.3;
973
1064
  var overlap = (a1, a2, b1, b2) => Math.min(a2, b2) - Math.max(a1, b1);
974
1065
  function adjacent(a, b) {
975
- if ((Math.abs(a.x2 - b.x1) <= CLIP_EDGE_TOL || Math.abs(b.x2 - a.x1) <= CLIP_EDGE_TOL) && overlap(a.y1, a.y2, b.y1, b.y2) > CLIP_EDGE_TOL) return true;
976
- if ((Math.abs(a.y2 - b.y1) <= CLIP_EDGE_TOL || Math.abs(b.y2 - a.y1) <= CLIP_EDGE_TOL) && overlap(a.x1, a.x2, b.x1, b.x2) > CLIP_EDGE_TOL) return true;
1066
+ const al = (u, v) => Math.abs(u - v) <= CLIP_COORD_TOL;
1067
+ if ((Math.abs(a.x2 - b.x1) <= CLIP_ADJ_GAP || Math.abs(b.x2 - a.x1) <= CLIP_ADJ_GAP) && overlap(a.y1, a.y2, b.y1, b.y2) > CLIP_EDGE_TOL && (al(a.y1, b.y1) || al(a.y2, b.y2))) return true;
1068
+ if ((Math.abs(a.y2 - b.y1) <= CLIP_ADJ_GAP || Math.abs(b.y2 - a.y1) <= CLIP_ADJ_GAP) && overlap(a.x1, a.x2, b.x1, b.x2) > CLIP_EDGE_TOL && (al(a.x1, b.x1) || al(a.x2, b.x2))) return true;
977
1069
  return false;
978
1070
  }
979
1071
  function contains(a, b) {
@@ -984,7 +1076,7 @@ function clusterCoords(values) {
984
1076
  const out = [];
985
1077
  let run = [];
986
1078
  for (const v of sorted) {
987
- if (run.length > 0 && v - run[run.length - 1] > CLIP_EDGE_TOL) {
1079
+ if (run.length > 0 && v - run[run.length - 1] > CLIP_COORD_TOL) {
988
1080
  out.push(run.reduce((s, x) => s + x, 0) / run.length);
989
1081
  run = [];
990
1082
  }
@@ -1010,7 +1102,8 @@ function edgeStroked(lines, dir, pos, a1, a2) {
1010
1102
  }
1011
1103
  return false;
1012
1104
  }
1013
- function buildClipCellGrids(rects, strokedH, strokedV, pageWidth, pageHeight, textPoints = []) {
1105
+ var CONT_X_TOL = 0.1;
1106
+ function buildClipCellGrids(rects, strokedH, strokedV, pageWidth, pageHeight, textPoints = [], fillRects = [], prev = { lastCells: [], clips: [] }) {
1014
1107
  const pageArea = pageWidth * pageHeight;
1015
1108
  const sameRect = (a, b) => Math.abs(a.x1 - b.x1) <= CLIP_EDGE_TOL && Math.abs(a.x2 - b.x2) <= CLIP_EDGE_TOL && Math.abs(a.y1 - b.y1) <= CLIP_EDGE_TOL && Math.abs(a.y2 - b.y2) <= CLIP_EDGE_TOL;
1016
1109
  const cells = [];
@@ -1019,17 +1112,55 @@ function buildClipCellGrids(rects, strokedH, strokedV, pageWidth, pageHeight, te
1019
1112
  if (pageArea > 0 && (r.x2 - r.x1) * (r.y2 - r.y1) >= pageArea * CLIP_MAX_PAGE_FRAC) continue;
1020
1113
  if (!cells.some((c) => sameRect(c, r))) cells.push(r);
1021
1114
  }
1022
- if (cells.length < 1) return { grids: [], containers: [] };
1115
+ if (cells.length < 1) return { grids: [], containers: [], page: { lastCells: [], clips: [] } };
1023
1116
  const parent = new Array(cells.length).fill(-1);
1117
+ const area = (r) => (r.x2 - r.x1) * (r.y2 - r.y1);
1118
+ const straddles = (a, b) => {
1119
+ const ix = overlap(a.x1, a.x2, b.x1, b.x2), iy = overlap(a.y1, a.y2, b.y1, b.y2);
1120
+ if (ix <= CLIP_EDGE_TOL || iy <= CLIP_EDGE_TOL || contains(a, b) || contains(b, a)) return false;
1121
+ const inside = ix * iy / area(b);
1122
+ return inside > STRADDLE_MIN && inside < 1 - STRADDLE_MIN;
1123
+ };
1124
+ const canParent = cells.map((a, i) => !cells.some((b, j) => i !== j && straddles(a, b)));
1024
1125
  for (let i = 0; i < cells.length; i++) {
1025
1126
  for (let j = 0; j < cells.length; j++) {
1026
- if (i === j || !contains(cells[j], cells[i])) continue;
1127
+ if (i === j || !canParent[j] || area(cells[j]) <= area(cells[i]) || !contains(cells[j], cells[i])) continue;
1027
1128
  const cur = parent[i];
1028
1129
  if (cur < 0 || contains(cells[cur], cells[j])) parent[i] = j;
1029
1130
  }
1030
1131
  }
1132
+ const ruledGaps = findRuledGaps(cells, parent, strokedH, strokedV);
1031
1133
  const isContainer = new Array(cells.length).fill(false);
1032
1134
  for (const p of parent) if (p >= 0) isContainer[p] = true;
1135
+ const tileParent = new Array(cells.length).fill(false);
1136
+ const tableClip = new Array(cells.length).fill(false);
1137
+ for (let p = 0; p < cells.length; p++) {
1138
+ if (!isContainer[p]) continue;
1139
+ let n = 0, x1 = Infinity, y1 = Infinity, x2 = -Infinity, y2 = -Infinity;
1140
+ for (let i = 0; i < cells.length; i++) {
1141
+ if (parent[i] !== p) continue;
1142
+ const k = cells[i];
1143
+ n++;
1144
+ x1 = Math.min(x1, k.x1);
1145
+ y1 = Math.min(y1, k.y1);
1146
+ x2 = Math.max(x2, k.x2);
1147
+ y2 = Math.max(y2, k.y2);
1148
+ }
1149
+ if (n < CLIP_MIN_GROUP) continue;
1150
+ const c = cells[p];
1151
+ if (Math.max(Math.abs(x1 - c.x1), Math.abs(x2 - c.x2), Math.abs(y1 - c.y1), Math.abs(y2 - c.y2)) <= CLIP_COORD_TOL) tileParent[p] = true;
1152
+ }
1153
+ for (let p = 0; p < cells.length; p++) {
1154
+ if (tileParent[p]) tableClip[p] = !cells.some((q, i) => i !== p && parent[i] === parent[p] && !tileParent[i] && adjacent(q, cells[p]));
1155
+ }
1156
+ const effParent = (i) => {
1157
+ let p = parent[i];
1158
+ for (let steps = 0; p >= 0 && steps <= cells.length; steps++) {
1159
+ if (!tableClip[p] && (isGridMember(p) || loneFrame(p) || continues(p))) return p;
1160
+ p = parent[p];
1161
+ }
1162
+ return -1;
1163
+ };
1033
1164
  const root = cells.map((_, i) => i);
1034
1165
  const find = (i) => {
1035
1166
  while (root[i] !== i) {
@@ -1039,14 +1170,20 @@ function buildClipCellGrids(rects, strokedH, strokedV, pageWidth, pageHeight, te
1039
1170
  return i;
1040
1171
  };
1041
1172
  for (let i = 0; i < cells.length; i++) {
1173
+ if (tableClip[i]) continue;
1042
1174
  for (let j = i + 1; j < cells.length; j++) {
1043
- if (parent[i] !== parent[j]) continue;
1175
+ if (tableClip[j] || parent[i] !== parent[j]) continue;
1044
1176
  if (adjacent(cells[i], cells[j])) {
1045
1177
  const ra = find(i), rb = find(j);
1046
1178
  if (ra !== rb) root[ra] = rb;
1047
1179
  }
1048
1180
  }
1049
1181
  }
1182
+ for (const g of ruledGaps) {
1183
+ if (tableClip[g.i] || tableClip[g.j]) continue;
1184
+ const ra = find(g.i), rb = find(g.j);
1185
+ if (ra !== rb) root[ra] = rb;
1186
+ }
1050
1187
  const groups = /* @__PURE__ */ new Map();
1051
1188
  for (let i = 0; i < cells.length; i++) {
1052
1189
  const r = find(i);
@@ -1055,19 +1192,32 @@ function buildClipCellGrids(rects, strokedH, strokedV, pageWidth, pageHeight, te
1055
1192
  else groups.set(r, [i]);
1056
1193
  }
1057
1194
  const containers = cells.filter((_, i) => isContainer[i]);
1058
- const groupSize = (i) => _nullishCoalesce(_optionalChain([groups, 'access', _4 => _4.get, 'call', _5 => _5(find(i)), 'optionalAccess', _6 => _6.length]), () => ( 0));
1195
+ const groupSize = (i) => _nullishCoalesce(_optionalChain([groups, 'access', _6 => _6.get, 'call', _7 => _7(find(i)), 'optionalAccess', _8 => _8.length]), () => ( 0));
1059
1196
  const isGridMember = (i) => groupSize(i) >= CLIP_MIN_GROUP;
1060
1197
  const framed = (r) => edgeStroked(strokedH, "h", r.y1, r.x1, r.x2) && edgeStroked(strokedH, "h", r.y2, r.x1, r.x2) && edgeStroked(strokedV, "v", r.x1, r.y1, r.y2) && edgeStroked(strokedV, "v", r.x2, r.y1, r.y2);
1061
1198
  const titledFrame = (r) => r.y1 >= pageHeight * TITLED_FRAME_MIN_TOP && r.x2 - r.x1 >= pageWidth * TITLED_FRAME_MIN_WIDTH && textPoints.some((p) => p.y < r.y1 && p.y > pageHeight * HEADER_BAND && p.x >= r.x1 - CLIP_EDGE_TOL && p.x <= r.x2 + CLIP_EDGE_TOL) && textPoints.some((p) => p.x > r.x1 && p.x < r.x2 && p.y > r.y1 && p.y < r.y2);
1062
1199
  const loneFrame = (i) => isContainer[i] && !isGridMember(i) && (framed(cells[i]) || titledFrame(cells[i]));
1063
- const parentAttachable = (i) => parent[i] >= 0 && (isGridMember(parent[i]) || loneFrame(parent[i]));
1200
+ const headY = pageHeight * (1 - HEADER_BAND);
1201
+ const continues = (i) => {
1202
+ if (!prev.lastCells.length || parent[i] >= 0 || tableClip[i] || isGridMember(i)) return void 0;
1203
+ const c = cells[i];
1204
+ const from = prev.lastCells.find((b) => Math.abs(b.x1 - c.x1) <= CONT_X_TOL && Math.abs(b.x2 - c.x2) <= CONT_X_TOL);
1205
+ if (!from) return void 0;
1206
+ if (prev.clips.some((k) => sameRect(k, c) && !sameRect(k, from))) return void 0;
1207
+ if (textPoints.some((p) => p.y > c.y2 && p.y < headY)) return void 0;
1208
+ if (cells.some((o) => o.y1 >= c.y2 - CLIP_EDGE_TOL && (o.y1 + o.y2) / 2 < headY)) return void 0;
1209
+ return from;
1210
+ };
1211
+ const parentAttachable = (i) => effParent(i) >= 0;
1064
1212
  const onlyChild = (i) => parent[i] >= 0 && parent.filter((p) => p === parent[i]).length === 1;
1065
1213
  const grids = [];
1066
1214
  for (const idxs of groups.values()) {
1067
1215
  const first = idxs[0];
1068
- const parentRect = parentAttachable(first) ? cells[parent[first]] : void 0;
1216
+ if (tableClip[first]) continue;
1217
+ const parentRect = parentAttachable(first) ? cells[effParent(first)] : void 0;
1069
1218
  if (idxs.length < CLIP_MIN_GROUP) {
1070
- if (!loneFrame(first) && !((parentRect || onlyChild(first)) && framed(cells[first]))) continue;
1219
+ const from = continues(first);
1220
+ if (!from && !loneFrame(first) && !((parentRect || onlyChild(first)) && framed(cells[first]))) continue;
1071
1221
  const r = cells[first];
1072
1222
  grids.push({
1073
1223
  rowYs: [r.y2, r.y1],
@@ -1075,11 +1225,13 @@ function buildClipCellGrids(rects, strokedH, strokedV, pageWidth, pageHeight, te
1075
1225
  bbox: { x1: r.x1, y1: r.y1, x2: r.x2, y2: r.y2 },
1076
1226
  vertexRadius: 1,
1077
1227
  cells: [{ row: 0, col: 0, rowSpan: 1, colSpan: 1, bbox: { x1: r.x1, y1: r.y1, x2: r.x2, y2: r.y2 } }],
1078
- ...parentRect ? { clipParent: parentRect } : {}
1228
+ ...parentRect ? { clipParent: parentRect } : {},
1229
+ ...from ? { continues: from } : {}
1079
1230
  });
1080
1231
  continue;
1081
1232
  }
1082
- const members = idxs.map((i) => cells[i]);
1233
+ const gs = ruledGaps.filter((g) => find(g.i) === find(first));
1234
+ const members = gs.length ? closeGaps(idxs.map((i) => cells[i]), gs) : idxs.map((i) => cells[i]);
1083
1235
  let edges = 0, invisible = 0;
1084
1236
  for (const r of members) {
1085
1237
  edges += 4;
@@ -1111,19 +1263,178 @@ function buildClipCellGrids(rects, strokedH, strokedV, pageWidth, pageHeight, te
1111
1263
  for (let rr = 0; rr < numRows; rr++) {
1112
1264
  for (let cc = 0; cc < numCols; cc++) {
1113
1265
  if (occupied[rr][cc]) continue;
1114
- out.push({ row: rr, col: cc, rowSpan: 1, colSpan: 1, bbox: { x1: colXs[cc], y1: rowYs[rr + 1], x2: colXs[cc + 1], y2: rowYs[rr] } });
1266
+ out.push({ row: rr, col: cc, rowSpan: 1, colSpan: 1, bbox: { x1: colXs[cc], y1: rowYs[rr + 1], x2: colXs[cc + 1], y2: rowYs[rr] }, filler: true });
1115
1267
  }
1116
1268
  }
1269
+ addNarrowEdgeCols(colXs, rowYs, out, fillRects);
1117
1270
  grids.push({
1118
1271
  rowYs,
1119
1272
  colXs,
1120
- bbox: { x1: colXs[0], y1: rowYs[numRows], x2: colXs[numCols], y2: rowYs[0] },
1273
+ bbox: { x1: colXs[0], y1: rowYs[numRows], x2: colXs[colXs.length - 1], y2: rowYs[0] },
1121
1274
  vertexRadius: 1,
1122
1275
  cells: out,
1123
1276
  ...parentRect ? { clipParent: parentRect } : {}
1124
1277
  });
1125
1278
  }
1126
- return { grids, containers };
1279
+ const tops = grids.filter((g) => !g.clipParent).flatMap((g) => g.cells.filter((c) => !c.filler).map((c) => c.bbox));
1280
+ let lastCells = [];
1281
+ if (tops.length) {
1282
+ const bottom = Math.min(...tops.map((b) => b.y1));
1283
+ const footY = pageHeight * HEADER_BAND;
1284
+ const below = (y) => y < bottom - CLIP_EDGE_TOL && y > footY;
1285
+ if (!textPoints.some((p) => below(p.y)) && !cells.some((o) => o.y2 < bottom && below((o.y1 + o.y2) / 2))) {
1286
+ lastCells = tops.filter((b) => Math.abs(b.y1 - bottom) <= CLIP_COORD_TOL && !cells.some((k) => Math.abs(k.x1 - b.x1) <= CONT_X_TOL && Math.abs(k.x2 - b.x2) <= CONT_X_TOL && k.y2 > b.y2 + CLIP_EDGE_TOL && contains(k, b)));
1287
+ }
1288
+ }
1289
+ return { grids, containers, page: { lastCells, clips: cells } };
1290
+ }
1291
+ var CLIP_SPACING_MAX = 3;
1292
+ function findRuledGaps(cells, parent, strokedH, strokedV) {
1293
+ const al = (u, v) => Math.abs(u - v) <= CLIP_COORD_TOL;
1294
+ const occupied = (i, j, x1, y1, x2, y2) => cells.some((k, n) => n !== i && n !== j && parent[n] === parent[i] && overlap(k.x1, k.x2, x1, x2) > CLIP_ADJ_GAP && overlap(k.y1, k.y2, y1, y2) > CLIP_ADJ_GAP);
1295
+ const gapBetween = (i, j) => {
1296
+ const a = cells[i], b = cells[j];
1297
+ const gv = a.y1 - b.y2;
1298
+ if (gv > CLIP_ADJ_GAP && gv <= CLIP_SPACING_MAX && overlap(a.x1, a.x2, b.x1, b.x2) > CLIP_EDGE_TOL && (al(a.x1, b.x1) || al(a.x2, b.x2)) && !occupied(i, j, Math.max(a.x1, b.x1), b.y2, Math.min(a.x2, b.x2), a.y1)) {
1299
+ const e1 = Math.max(a.x1, b.x1), e2 = Math.min(a.x2, b.x2);
1300
+ return { i, j, axis: "y", lo: b.y2, hi: a.y1, e1, e2, to: ruleEnd(strokedH, "h", b.y2, a.y1, e1, e2) };
1301
+ }
1302
+ const gh = b.x1 - a.x2;
1303
+ if (gh > CLIP_ADJ_GAP && gh <= CLIP_SPACING_MAX && overlap(a.y1, a.y2, b.y1, b.y2) > CLIP_EDGE_TOL && (al(a.y1, b.y1) || al(a.y2, b.y2)) && !occupied(i, j, a.x2, Math.max(a.y1, b.y1), b.x1, Math.min(a.y2, b.y2))) {
1304
+ const e1 = Math.max(a.y1, b.y1), e2 = Math.min(a.y2, b.y2);
1305
+ return { i, j, axis: "x", lo: a.x2, hi: b.x1, e1, e2, to: ruleEnd(strokedV, "v", a.x2, b.x1, e1, e2) };
1306
+ }
1307
+ return void 0;
1308
+ };
1309
+ const ruled = (g) => (g.axis === "y" ? strokedH : strokedV).some((l) => {
1310
+ const pos = g.axis === "y" ? l.y1 : l.x1;
1311
+ return (Math.abs(pos - g.lo) <= 0.5 || Math.abs(pos - g.hi) <= 0.5) && (g.axis === "y" ? overlap(l.x1, l.x2, g.e1, g.e2) : overlap(l.y1, l.y2, g.e1, g.e2)) >= (g.e2 - g.e1) * STROKE_COVER;
1312
+ });
1313
+ const root = cells.map((_, i) => i);
1314
+ const find = (i) => {
1315
+ while (root[i] !== i) {
1316
+ root[i] = root[root[i]];
1317
+ i = root[i];
1318
+ }
1319
+ return i;
1320
+ };
1321
+ const found = [];
1322
+ const widths = /* @__PURE__ */ new Map();
1323
+ const link = (g) => {
1324
+ found.push(g);
1325
+ const ri = find(g.i), rj = find(g.j);
1326
+ const w = [..._nullishCoalesce(widths.get(rj), () => ( [])), ...ri !== rj ? _nullishCoalesce(widths.get(ri), () => ( [])) : [], { axis: g.axis, w: g.hi - g.lo }];
1327
+ root[ri] = rj;
1328
+ widths.set(rj, w);
1329
+ };
1330
+ const cand = [];
1331
+ for (let i = 0; i < cells.length; i++) {
1332
+ for (let j = 0; j < cells.length; j++) {
1333
+ if (i === j || parent[i] !== parent[j]) continue;
1334
+ const g = gapBetween(i, j);
1335
+ if (!g) continue;
1336
+ const a = cells[i], b = cells[j];
1337
+ const both = g.axis === "y" ? al(a.x1, b.x1) && al(a.x2, b.x2) : al(a.y1, b.y1) && al(a.y2, b.y2);
1338
+ const isRuled = ruled(g);
1339
+ if (both && isRuled) link(g);
1340
+ else if (both || isRuled) cand.push([g, both]);
1341
+ }
1342
+ }
1343
+ if (!found.length) return [];
1344
+ for (let grew = true; grew; ) {
1345
+ grew = false;
1346
+ for (let k = cand.length - 1; k >= 0; k--) {
1347
+ const [g, both] = cand[k], w = g.hi - g.lo;
1348
+ if (![find(g.i), find(g.j)].some((r) => (_nullishCoalesce(widths.get(r), () => ( []))).some((s) => (both || s.axis === g.axis) && Math.abs(s.w - w) <= CLIP_COORD_TOL))) continue;
1349
+ link(g);
1350
+ cand.splice(k, 1);
1351
+ grew = true;
1352
+ }
1353
+ }
1354
+ return found;
1355
+ }
1356
+ function ruleEnd(lines, dir, lo, hi, e1, e2) {
1357
+ const at = (p) => lines.some((l) => Math.abs((dir === "h" ? l.y1 : l.x1) - p) <= 0.5 && (dir === "h" ? overlap(l.x1, l.x2, e1, e2) : overlap(l.y1, l.y2, e1, e2)) >= (e2 - e1) * STROKE_COVER);
1358
+ const atLo = at(lo), atHi = at(hi);
1359
+ return atLo && !atHi ? lo : atHi && !atLo ? hi : (lo + hi) / 2;
1360
+ }
1361
+ function closeGaps(members, gaps) {
1362
+ const al = (u, v) => Math.abs(u - v) <= CLIP_COORD_TOL;
1363
+ const lines = [];
1364
+ for (const g of gaps) {
1365
+ const l = lines.find((k) => k.axis === g.axis && al(k.lo, g.lo) && al(k.hi, g.hi));
1366
+ if (l) {
1367
+ l.e1 = Math.min(l.e1, g.e1);
1368
+ l.e2 = Math.max(l.e2, g.e2);
1369
+ } else lines.push({ ...g });
1370
+ }
1371
+ const out = members.map((r) => ({ ...r }));
1372
+ for (const l of lines) {
1373
+ const shared = (p) => members.some((u) => members.some((v) => u !== v && (l.axis === "y" ? Math.abs(u.y1 - v.y2) <= CLIP_ADJ_GAP && al(u.y1, p) && overlap(u.x1, u.x2, v.x1, v.x2) > CLIP_EDGE_TOL : Math.abs(u.x2 - v.x1) <= CLIP_ADJ_GAP && al(u.x2, p) && overlap(u.y1, u.y2, v.y1, v.y2) > CLIP_EDGE_TOL)));
1374
+ const atLo = shared(l.lo), atHi = shared(l.hi);
1375
+ const to = atLo && !atHi ? l.lo : atHi && !atLo ? l.hi : l.to;
1376
+ const onEdge = (r) => l.axis === "y" ? al(r.y2, l.lo) || al(r.y1, l.hi) : al(r.x2, l.lo) || al(r.x1, l.hi);
1377
+ const span = (r) => l.axis === "y" ? [r.x1, r.x2] : [r.y1, r.y2];
1378
+ const take = /* @__PURE__ */ new Set();
1379
+ for (let grew = true; grew; ) {
1380
+ grew = false;
1381
+ for (let n = 0; n < members.length; n++) {
1382
+ if (take.has(n) || !onEdge(members[n])) continue;
1383
+ const [a1, a2] = span(members[n]);
1384
+ if (overlap(a1, a2, l.e1, l.e2) <= -(CLIP_SPACING_MAX + CLIP_COORD_TOL)) continue;
1385
+ take.add(n);
1386
+ l.e1 = Math.min(l.e1, a1);
1387
+ l.e2 = Math.max(l.e2, a2);
1388
+ grew = true;
1389
+ }
1390
+ }
1391
+ for (const n of take) {
1392
+ const r = members[n], s = out[n];
1393
+ if (l.axis === "y") {
1394
+ if (al(r.y2, l.lo)) s.y2 = to;
1395
+ if (al(r.y1, l.hi)) s.y1 = to;
1396
+ } else {
1397
+ if (al(r.x2, l.lo)) s.x2 = to;
1398
+ if (al(r.x1, l.hi)) s.x1 = to;
1399
+ }
1400
+ }
1401
+ }
1402
+ return out;
1403
+ }
1404
+ function addNarrowEdgeCols(colXs, rowYs, out, fills) {
1405
+ if (!fills.length) return;
1406
+ const rowIdx = (y) => {
1407
+ const i = nearestIndex(rowYs, y);
1408
+ return Math.abs(rowYs[i] - y) <= CLIP_COORD_TOL ? i : -1;
1409
+ };
1410
+ for (const side of ["l", "r"]) {
1411
+ const edge = side === "l" ? colXs[0] : colXs[colXs.length - 1];
1412
+ const hits = fills.filter((f) => {
1413
+ const w = f.x2 - f.x1;
1414
+ if (w < NARROW_FILL_MIN_W || w >= CLIP_MIN_W2 || Math.abs((side === "l" ? f.x2 : f.x1) - edge) > CLIP_COORD_TOL) return false;
1415
+ const r0 = rowIdx(f.y2), r1 = rowIdx(f.y1);
1416
+ return r0 >= 0 && r1 > r0;
1417
+ });
1418
+ if (!hits.length) continue;
1419
+ let x = side === "l" ? Infinity : -Infinity;
1420
+ for (const f of hits) x = side === "l" ? Math.min(x, f.x1) : Math.max(x, f.x2);
1421
+ if (side === "l") {
1422
+ colXs.unshift(x);
1423
+ for (const c of out) c.col++;
1424
+ } else colXs.push(x);
1425
+ const col = side === "l" ? 0 : colXs.length - 2;
1426
+ const [cx1, cx2] = [colXs[col], colXs[col + 1]];
1427
+ const taken = new Array(rowYs.length - 1).fill(false);
1428
+ for (const f of hits) {
1429
+ const r0 = rowIdx(f.y2), r1 = rowIdx(f.y1);
1430
+ if (taken.slice(r0, r1).some(Boolean)) continue;
1431
+ taken.fill(true, r0, r1);
1432
+ out.push({ row: r0, col, rowSpan: r1 - r0, colSpan: 1, bbox: { x1: cx1, y1: rowYs[r1], x2: cx2, y2: rowYs[r0] } });
1433
+ }
1434
+ for (let r = 0; r < taken.length; r++) {
1435
+ if (!taken[r]) out.push({ row: r, col, rowSpan: 1, colSpan: 1, bbox: { x1: cx1, y1: rowYs[r + 1], x2: cx2, y2: rowYs[r] }, filler: true });
1436
+ }
1437
+ }
1127
1438
  }
1128
1439
  function dropGridsInside(lineGrids, clipGrids, containers = []) {
1129
1440
  if (clipGrids.length === 0 && containers.length === 0) return lineGrids;
@@ -1241,6 +1552,165 @@ function hasHorizontalLine(horizontals, y, leftX, rightX, vertexRadius) {
1241
1552
  return false;
1242
1553
  }
1243
1554
 
1555
+ // src/pdf/line-wrap.ts
1556
+ var MARKUP = /<\/?u>|~~/g;
1557
+ var bump = (m, k) => {
1558
+ m.set(k, (_nullishCoalesce(m.get(k), () => ( 0))) + 1);
1559
+ };
1560
+ var pairKey = (a, b) => a * 65536 + b;
1561
+ var bump2 = (m, k1, k2) => {
1562
+ let inner = m.get(k1);
1563
+ if (!inner) m.set(k1, inner = /* @__PURE__ */ new Map());
1564
+ bump(inner, k2);
1565
+ };
1566
+ var WrapLexicon = (_class = class {constructor() { _class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this); }
1567
+ __init() {this.joined1 = /* @__PURE__ */ new Map()}
1568
+ __init2() {this.joined2 = /* @__PURE__ */ new Map()}
1569
+ __init3() {this.spaced1 = /* @__PURE__ */ new Map()}
1570
+ __init4() {this.spaced2 = /* @__PURE__ */ new Map()}
1571
+ /** 줄 안(줄 첫·끝 어절 제외 — 꺾인 조각일 수 있다) 홀로 선 어절 수 — 한 음절 조각이 낱말("등"·"및"·"그")인지 가른다 */
1572
+ __init5() {this.words = /* @__PURE__ */ new Map()}
1573
+ /** 줄 글 한 줄을 증거로 더한다 — 탭(큰 갭)으로 나뉜 조각은 다른 칸·단이라 조각 사이는 어절 경계 증거로 쓰지 않는다 */
1574
+ addLine(text) {
1575
+ for (const seg of text.replace(MARKUP, "").split(" ")) {
1576
+ const toks = seg.split(" ").filter((t) => t && !t.includes("]("));
1577
+ for (let i = 0; i < toks.length; i++) {
1578
+ const t = toks[i], n = t.length;
1579
+ if (i > 0 && i < toks.length - 1) bump(this.words, t);
1580
+ for (let a = 0; a + 1 < n; a++) {
1581
+ const c1 = t.charCodeAt(a), c2 = t.charCodeAt(a + 1);
1582
+ bump(this.joined1, pairKey(c1, c2));
1583
+ if (a >= 1 && a + 2 < n) bump2(this.joined2, pairKey(t.charCodeAt(a - 1), c1), pairKey(c2, t.charCodeAt(a + 2)));
1584
+ }
1585
+ if (i + 1 < toks.length) {
1586
+ const u = toks[i + 1];
1587
+ bump(this.spaced1, pairKey(t.charCodeAt(n - 1), u.charCodeAt(0)));
1588
+ if (n >= 2 && u.length >= 2) bump2(this.spaced2, pairKey(t.charCodeAt(n - 2), t.charCodeAt(n - 1)), pairKey(u.charCodeAt(0), u.charCodeAt(1)));
1589
+ }
1590
+ }
1591
+ }
1592
+ }
1593
+ /** 문서 줄 안에서 홀로 선 어절로 나온 적 있나 */
1594
+ isWord(word) {
1595
+ return (_nullishCoalesce(this.words.get(word), () => ( 0))) > 0;
1596
+ }
1597
+ /** 꺾인 자리 증거: "" 붙음 · " " 띄움 · null 모름 (두 글자 증거가 갈리거나 없으면 한 글자) */
1598
+ evidence(left, right) {
1599
+ const n = left.length;
1600
+ if (n >= 2 && right.length >= 2) {
1601
+ const k1 = pairKey(left.charCodeAt(n - 2), left.charCodeAt(n - 1)), k2 = pairKey(right.charCodeAt(0), right.charCodeAt(1));
1602
+ const v = decideCounts(_nullishCoalesce(_optionalChain([this, 'access', _9 => _9.joined2, 'access', _10 => _10.get, 'call', _11 => _11(k1), 'optionalAccess', _12 => _12.get, 'call', _13 => _13(k2)]), () => ( 0)), _nullishCoalesce(_optionalChain([this, 'access', _14 => _14.spaced2, 'access', _15 => _15.get, 'call', _16 => _16(k1), 'optionalAccess', _17 => _17.get, 'call', _18 => _18(k2)]), () => ( 0)));
1603
+ if (v !== null) return v;
1604
+ }
1605
+ if (n && right.length) {
1606
+ const k = pairKey(left.charCodeAt(n - 1), right.charCodeAt(0));
1607
+ return decideCounts(_nullishCoalesce(this.joined1.get(k), () => ( 0)), _nullishCoalesce(this.spaced1.get(k), () => ( 0)));
1608
+ }
1609
+ return null;
1610
+ }
1611
+ }, _class);
1612
+ var decideCounts = (joined, spaced) => joined && !spaced ? "" : spaced && !joined ? " " : null;
1613
+ var hasBatchim = (c) => {
1614
+ const k = c.charCodeAt(0) - 44032;
1615
+ return k >= 0 && k < 11172 && k % 28 !== 0;
1616
+ };
1617
+ var CLOSE_TAIL = /[’”」』)\]〉》>]+$/;
1618
+ var TAIL = "[.,)\u300D\u300F\u2019\u201D]*";
1619
+ var PARTICLE = new RegExp(`^(?:\uB2E4\\.|\uC758|\uC5D0|\uC5D0\uC11C|\uC5D0\uB294|\uC5D0\uAC8C|\uC5D0\uB3C4|\uC5D0\uC11C\uB294|\uAE4C\uC9C0|\uBD80\uD130|\uCC98\uB7FC|\uB9C8\uB2E4|\uB9CC|\uB3C4|\uB4E4|\uB4E4\uC774|\uB4E4\uC758|\uB4E4\uC740|\uB4E4\uC744|\uB4E4\uC5D0\uAC8C|\uC11C\uB294|\uC11C\uB3C4|\uB77C\uACE0|\uB77C\uBA70|\uC740|\uB294|\uC744|\uB97C|\uC73C\uB85C|\uB85C|\uC73C\uB85C\uC11C|\uB85C\uC11C|\uC73C\uB85C\uC368|\uB85C\uC368)${TAIL}$`);
1620
+ var PARTICLE_AFTER_CONS = new RegExp(`^(?:\uC774|\uACFC|\uC774\uB2E4|\uC774\uBA70|\uC774\uACE0|\uC774\uB098|\uC774\uB77C\uB294|\uC774\uB77C\uACE0|\uC774\uB77C\uBA70)${TAIL}$`);
1621
+ var PARTICLE_AFTER_VOWEL = new RegExp(`^(?:\uAC00|\uC640|\uB77C\uB294)${TAIL}$`);
1622
+ var VERB_FORM = new RegExp(`^(?:\uD558\uB294|\uD558\uC5EC|\uD558\uACE0|\uD558\uBA70|\uD558\uC600\uB2E4|\uD558\uC600\uC73C\uBA70|\uD558\uC600\uACE0|\uD558\uC600\uB2E4\uACE0|\uD588\uB2E4|\uD588\uC73C\uBA70|\uD588\uACE0|\uD588\uB2E4\uACE0|\uD588\uB2E4\uBA70|\uD55C\uB2E4|\uD55C\uB2E4\uACE0|\uD55C\uB2E4\uBA70|\uD55C\uB2E4\uB294|\uD560|\uD568|\uD558\uACA0\uB2E4|\uD558\uACA0\uB2E4\uACE0|\uD558\uACA0\uC2B5\uB2C8\uB2E4|\uD558\uAE30\uB85C|\uD558\uBA74|\uD558\uBA74\uC11C|\uD558\uB3C4\uB85D|\uD574\uC57C|\uB418\uB294|\uB418\uC5B4|\uB41C|\uB41C\uB2E4|\uB41C\uB2E4\uACE0|\uB41C\uB2E4\uB294|\uB418\uC5C8\uB2E4|\uB418\uC5C8\uC73C\uBA70|\uB418\uC5C8\uACE0|\uB410\uB2E4|\uB410\uC73C\uBA70|\uB418\uBA70|\uB418\uACE0|\uB418\uBA74|\uB428|\uB3FC)${TAIL}$`);
1623
+ var AUX_BEFORE = /(?:야|록|로|게|도|히|자|를|을|면|서|고|며|지|라)$/;
1624
+ var BECOME = /^[되된됐됨돼]/;
1625
+ var STANDALONE_SYLLABLE = /^(?:및|등|수|것|그|이|저|더|또|각|약|총|중|간|때|뿐|듯|채|전|후|내|외|한|두|세|네|몇|새|첫|온|본|곧|꼭|잘|못|안|좀|늘|다|왜|뭐|시|할|데|뒤|된)$/;
1626
+ var DATE_DAY_END = /(?:^|\s)\d*월\s+\d*일$/;
1627
+ var COUNTER = /^(?:명|일|월|년|개|원|건|회|차|호|조|항|층|톤|대|곳|시|분|초|배|위|점|주|종|억|만|천|%|퍼센트)/;
1628
+ function endsAsWord(word) {
1629
+ const h = word.replace(CLOSE_TAIL, "");
1630
+ if (!/^[가-힣]{2,}$/.test(h)) return false;
1631
+ if (/(?:을|를|는|은|히|른|할|야|게|의)$/.test(h)) return true;
1632
+ const prev = h[h.length - 2];
1633
+ if (/(?:이|과)$/.test(h)) return hasBatchim(prev);
1634
+ if (/(?:가|와)$/.test(h)) return !hasBatchim(prev);
1635
+ return false;
1636
+ }
1637
+ function particleContinues(left, right) {
1638
+ const h = left.replace(CLOSE_TAIL, "");
1639
+ const last = h[h.length - 1];
1640
+ if (!last || !/[가-힣A-Za-z0-9]/.test(last)) return false;
1641
+ if (PARTICLE.test(right)) return true;
1642
+ if (!/[가-힣]/.test(last)) return false;
1643
+ if (PARTICLE_AFTER_CONS.test(right)) return hasBatchim(last);
1644
+ if (PARTICLE_AFTER_VOWEL.test(right)) return !hasBatchim(last);
1645
+ return VERB_FORM.test(right) && !AUX_BEFORE.test(h) && !(last === "\uC774" && BECOME.test(right));
1646
+ }
1647
+ var ITEM_HEAD = /^(?:[□■◆◇○●◎◦▪▫•※▶▷►❍❏❑✓✔➢➤☞]|[①-⑳]|[-–·∙ㆍ*](?=\s)|\(?\d{1,2}[.)](?!\d)|\(?[가-하][.)]|\([가-하\d]{1,2}\)|[ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ]|제\d+[조항호장절])/;
1648
+ function startsNewItem(prevText, nextText) {
1649
+ const t = nextText.replace(MARKUP, "").trimStart();
1650
+ return ITEM_HEAD.test(t) && !(/^다\./.test(t) && /[가-힣]$/.test(prevText.replace(MARKUP, "").trimEnd()));
1651
+ }
1652
+ function wrapJoiner(prevText, nextText, lex) {
1653
+ const prev = prevText.replace(MARKUP, "").trimEnd(), next = nextText.replace(MARKUP, "").trimStart();
1654
+ const a = prev[prev.length - 1], b = next[0];
1655
+ if (!a || !b || /[,;:!?]/.test(a) || DATE_DAY_END.test(prev) && b !== "(") return " ";
1656
+ let s = prev.length;
1657
+ while (s > 0 && !/\s/.test(prev[s - 1])) s--;
1658
+ const left = prev.slice(s), right = next.match(/^\S+/)[0];
1659
+ if (particleContinues(left, right)) return "";
1660
+ if (endsAsWord(left)) return " ";
1661
+ if (/[·ㆍ‧-]/.test(a) && /[가-힣A-Za-z0-9]/.test(b)) return "";
1662
+ if (/[A-Za-z]/.test(a) && /[A-Za-z]/.test(b) || /\d/.test(a) && /\d/.test(b)) return " ";
1663
+ const ev = _optionalChain([lex, 'optionalAccess', _19 => _19.evidence, 'call', _20 => _20(left, right)]);
1664
+ if (ev != null) return ev;
1665
+ if (/\d$/.test(left) && COUNTER.test(right)) return "";
1666
+ if (lex && /^[가-힣]$/.test(left) && /^[가-힣]/.test(right) && !STANDALONE_SYLLABLE.test(left) && ([...right].length === 1 || !lex.isWord(left))) return "";
1667
+ const r1 = right.replace(/[.,)」』’”]+$/, "");
1668
+ if (lex && /[가-힣]$/.test(left) && /^[가-힣]$/.test(r1) && !STANDALONE_SYLLABLE.test(r1) && !lex.isWord(r1) && !lex.isWord(right)) return "";
1669
+ return " ";
1670
+ }
1671
+ var PARA_LAST_LINE = /* @__PURE__ */ new WeakMap();
1672
+ function joinPageBreakWraps(blocks, lex) {
1673
+ const pageRight = /* @__PURE__ */ new Map();
1674
+ for (const b of blocks) {
1675
+ if (b.type !== "paragraph" || !b.bbox || !b.pageNumber) continue;
1676
+ pageRight.set(b.pageNumber, Math.max(_nullishCoalesce(pageRight.get(b.pageNumber), () => ( -Infinity)), b.bbox.x + b.bbox.width));
1677
+ }
1678
+ for (let i = blocks.length - 1; i > 0; i--) {
1679
+ const a = blocks[i - 1], b = blocks[i];
1680
+ if (!a.pageNumber || b.pageNumber !== a.pageNumber + 1 || !a.text || !b.text) continue;
1681
+ if (a.type !== "paragraph" && a.type !== "list" || b.type !== "paragraph") continue;
1682
+ const last = a.bbox && PARA_LAST_LINE.get(a.bbox), fs = last ? last.fontSize : 0;
1683
+ if (!last || fs <= 0 || (_nullishCoalesce(pageRight.get(a.pageNumber), () => ( Infinity))) - last.right >= BODY_FULL_TOL * fs) continue;
1684
+ if (last.width < BODY_MIN_WIDTH_EM * fs || Math.abs((_nullishCoalesce(_optionalChain([b, 'access', _21 => _21.style, 'optionalAccess', _22 => _22.fontSize]), () => ( 0))) - fs) > 0.15 * fs) continue;
1685
+ if (startsNewItem(a.text, b.text)) continue;
1686
+ a.text += wrapJoiner(a.text, b.text, lex) + b.text;
1687
+ const bl = b.bbox && PARA_LAST_LINE.get(b.bbox);
1688
+ if (bl) PARA_LAST_LINE.set(a.bbox, bl);
1689
+ else PARA_LAST_LINE.delete(a.bbox);
1690
+ blocks.splice(i, 1);
1691
+ }
1692
+ }
1693
+ var BODY_FULL_TOL = 0.25;
1694
+ var BODY_MIN_WIDTH_EM = 12;
1695
+ var BODY_MAX_PITCH_EM = 2;
1696
+ function bodyLineJoins(lines, lex) {
1697
+ let right = -Infinity;
1698
+ for (const l of lines) if (l.right > right) right = l.right;
1699
+ const out = [];
1700
+ for (let i = 0; i + 1 < lines.length; i++) {
1701
+ const a = lines[i], b = lines[i + 1];
1702
+ const fs = a.fontSize;
1703
+ const wraps = fs > 0 && right - a.right < BODY_FULL_TOL * fs && a.right - a.left >= BODY_MIN_WIDTH_EM * fs && a.y - b.y > 0 && a.y - b.y < BODY_MAX_PITCH_EM * fs && Math.abs(b.fontSize - fs) <= 0.15 * fs && !startsNewItem(a.text, b.text);
1704
+ out.push(wraps ? wrapJoiner(a.text, b.text, lex) : "\n");
1705
+ }
1706
+ return out;
1707
+ }
1708
+ var CELL_PAD_MAX = 6;
1709
+ function cellLineWraps(box, contentLeft, prevRight, fontSize, nextFirstCharW) {
1710
+ const pad = Math.min(CELL_PAD_MAX, Math.max(0, contentLeft - box.x1));
1711
+ return fontSize > 0 && prevRight + nextFirstCharW - (box.x2 - pad) > 0.5 * fontSize;
1712
+ }
1713
+
1244
1714
  // src/pdf/cell-text.ts
1245
1715
  var CELL_PADDING = 2;
1246
1716
  var SPACE_GAP_RATIO = 0.17;
@@ -1274,9 +1744,47 @@ function mapTextToCells(items, cells) {
1274
1744
  result.get(bestCell).push(item);
1275
1745
  }
1276
1746
  }
1747
+ keepWordsInOneCell(result);
1277
1748
  return result;
1278
1749
  }
1279
- function cellTextToString(items) {
1750
+ function keepWordsInOneCell(result) {
1751
+ const owner = /* @__PURE__ */ new Map();
1752
+ for (const [cell, arr] of result) for (const it of arr) owner.set(it, cell);
1753
+ if (result.size < 2 || owner.size < 2) return;
1754
+ const all = [...owner.keys()].sort((a, b) => b.y - a.y || a.x - b.x);
1755
+ for (let i = 0; i < all.length; ) {
1756
+ let j = i + 1;
1757
+ while (j < all.length && Math.abs(all[j].y - all[i].y) <= 1) j++;
1758
+ const line = all.slice(i, j).sort((a, b) => a.x - b.x);
1759
+ for (let k = 0; k < line.length; ) {
1760
+ let e = k + 1;
1761
+ while (e < line.length && !line[e].hasSpaceBefore && line[e].x - (line[e - 1].x + line[e - 1].w) <= spaceGapThreshold((line[e].fontSize + line[e - 1].fontSize) / 2)) e++;
1762
+ const word = line.slice(k, e);
1763
+ const width = /* @__PURE__ */ new Map();
1764
+ for (const it of word) {
1765
+ const c = owner.get(it);
1766
+ width.set(c, (_nullishCoalesce(width.get(c), () => ( 0))) + it.w);
1767
+ }
1768
+ const crosses = word.some((it) => {
1769
+ const b = owner.get(it).bbox;
1770
+ return it.x < b.x1 - 1 || it.x + it.w > b.x2 + 1;
1771
+ });
1772
+ if (width.size > 1 && crosses) {
1773
+ const target = [...width].sort((a, b) => b[1] - a[1])[0][0];
1774
+ for (const it of word) {
1775
+ const c = owner.get(it);
1776
+ if (c === target) continue;
1777
+ result.set(c, result.get(c).filter((x) => x !== it));
1778
+ result.get(target).push(it);
1779
+ owner.set(it, target);
1780
+ }
1781
+ }
1782
+ k = e;
1783
+ }
1784
+ i = j;
1785
+ }
1786
+ }
1787
+ function cellTextToString(items, wrap) {
1280
1788
  if (items.length === 0) return "";
1281
1789
  if (items.length === 1) return items[0].text;
1282
1790
  const sorted = [...items].sort((a, b) => b.y - a.y || a.x - b.x);
@@ -1296,7 +1804,7 @@ function cellTextToString(items) {
1296
1804
  lines.push(curLine);
1297
1805
  const merged = mergeSuperscriptRows(lines);
1298
1806
  const textLines = merged.map((line) => {
1299
- const s = line.sort((a, b) => a.x - b.x);
1807
+ const s = sortLineByX(line);
1300
1808
  if (s.length === 1) return s[0].text;
1301
1809
  const evenSpaced = detectEvenSpacedItems(s);
1302
1810
  let result = s[0].text;
@@ -1317,7 +1825,18 @@ function cellTextToString(items) {
1317
1825
  }
1318
1826
  return result;
1319
1827
  });
1320
- return mergeCellTextLines(textLines);
1828
+ if (!wrap) return mergeCellTextLines(textLines);
1829
+ let contentLeft = Infinity;
1830
+ for (const it of items) if (it.x < contentLeft) contentLeft = it.x;
1831
+ const lineEnds = merged.map((line) => {
1832
+ const s = sortLineByX(line);
1833
+ let right = -Infinity;
1834
+ for (const it of s) if (it.x + it.w > right) right = it.x + it.w;
1835
+ const first = s[0];
1836
+ return { right, fontSize: first.fontSize, firstCharW: first.w / Math.max(1, [...first.text].length) };
1837
+ });
1838
+ const wraps = lineEnds.slice(0, -1).map((a, i) => cellLineWraps(wrap.box, contentLeft, a.right, a.fontSize, lineEnds[i + 1].firstCharW));
1839
+ return mergeCellTextLines(textLines, { wraps, lex: wrap.lex });
1321
1840
  }
1322
1841
  function mergeSuperscriptRows(lines) {
1323
1842
  if (lines.length <= 1) return lines;
@@ -1406,19 +1925,19 @@ function markEvenRun(items, result, start, end) {
1406
1925
  }
1407
1926
  }
1408
1927
  }
1409
- function mergeCellTextLines(textLines) {
1928
+ function mergeCellTextLines(textLines, wrap) {
1410
1929
  if (textLines.length <= 1) return textLines[0] || "";
1411
1930
  const merged = [textLines[0]];
1412
1931
  for (let i = 1; i < textLines.length; i++) {
1413
1932
  const prev = merged[merged.length - 1];
1414
1933
  const curr = textLines[i];
1415
- if (/[가-힣]$/.test(prev) && /^[가-힣]+$/.test(curr) && curr.length <= 8 && !curr.includes(" ")) {
1934
+ if (wrap ? wrap.wraps[i - 1] && !startsNewItem(prev, curr) && wrapJoiner(prev, curr, wrap.lex) === "" : /[가-힣]$/.test(prev) && /^[가-힣]+$/.test(curr) && curr.length <= 8 && !curr.includes(" ")) {
1416
1935
  merged[merged.length - 1] = prev + curr;
1417
1936
  } else if (curr.trim().length <= 3 && /^[)\]%}]/.test(curr.trim())) {
1418
1937
  merged[merged.length - 1] = prev + curr.trim();
1419
- } else if (/[,(]$/.test(prev.trim()) && curr.trim().length <= 15) {
1938
+ } else if (!wrap && /[,(]$/.test(prev.trim()) && curr.trim().length <= 15) {
1420
1939
  merged[merged.length - 1] = prev + curr.trim();
1421
- } else if (/[\d,]$/.test(prev) && /^[\d,]+[)\]]?$/.test(curr.trim()) && curr.trim().length <= 10) {
1940
+ } else if (/[\d,]$/.test(prev) && /^[\d,]+[)\]]?$/.test(curr.trim()) && curr.trim().length <= 10 && !(/\d,\d{3}$/.test(prev) && /^\d/.test(curr.trim())) && !(/(?:^|[^\d,])\d{1,3}$/.test(prev) && /^(\d{1,3}(,\d{3})+|\d{1,3})$/.test(curr.trim()))) {
1422
1941
  merged[merged.length - 1] = prev + curr.trim();
1423
1942
  } else {
1424
1943
  merged.push(curr);
@@ -1538,11 +2057,24 @@ function normalizeUndersegmentedTable(originalCells, colXs, items) {
1538
2057
  return n;
1539
2058
  };
1540
2059
  if (countNonEmptyRows(rebuilt) <= countNonEmptyRows(originalCells)) return null;
1541
- if (countNonEmptyCols(rebuilt, numCols) < countNonEmptyCols(originalCells, numCols)) return null;
2060
+ const origBody = numRows > 1 ? originalCells.slice(1) : originalCells;
2061
+ if (countNonEmptyCols(rebuilt, numCols) < countNonEmptyCols(origBody, numCols)) return null;
1542
2062
  return rebuilt;
1543
2063
  }
1544
2064
 
1545
2065
  // src/pdf/text-line.ts
2066
+ function sortLineByX(items) {
2067
+ items.sort((a, b) => a.x - b.x);
2068
+ for (let i = 1; i < items.length; i++) {
2069
+ for (let j = i; j > 0; j--) {
2070
+ const a = items[j - 1], b = items[j];
2071
+ if (b.x - a.x > 1 || a.seq === void 0 || b.seq === void 0 || b.seq >= a.seq) break;
2072
+ items[j - 1] = b;
2073
+ items[j] = a;
2074
+ }
2075
+ }
2076
+ return items;
2077
+ }
1546
2078
  function filterHiddenText(items, pageWidth, pageHeight) {
1547
2079
  let hiddenCount = 0;
1548
2080
  const visible = [];
@@ -1599,13 +2131,15 @@ function dominantStyle(items) {
1599
2131
  }
1600
2132
  }
1601
2133
  if (dominantSize === 0) return void 0;
1602
- const fontName = _optionalChain([items, 'access', _7 => _7.find, 'call', _8 => _8((i) => i.fontSize === dominantSize), 'optionalAccess', _9 => _9.fontName]) || void 0;
2134
+ const fontName = _optionalChain([items, 'access', _23 => _23.find, 'call', _24 => _24((i) => i.fontSize === dominantSize), 'optionalAccess', _25 => _25.fontName]) || void 0;
1603
2135
  return fontName ? { fontSize: dominantSize, fontName } : { fontSize: dominantSize };
1604
2136
  }
1605
2137
  function normalizeItems(rawItems) {
1606
2138
  const items = [];
1607
2139
  const spacePositions = [];
2140
+ let seq = 0;
1608
2141
  for (const i of rawItems) {
2142
+ seq++;
1609
2143
  if (typeof i.str !== "string") continue;
1610
2144
  const x = Math.round(i.transform[4]);
1611
2145
  const y = Math.round(i.transform[5]);
@@ -1625,11 +2159,11 @@ function normalizeItems(rawItems) {
1625
2159
  }
1626
2160
  const split = splitEvenSpacedItem(text, x, w, fontSize);
1627
2161
  if (split) {
1628
- for (const s of split) {
1629
- items.push({ text: s.text, x: s.x, y, w: s.w, h, fontSize, fontName: i.fontName || "", isHidden });
1630
- }
2162
+ split.forEach((s, k) => {
2163
+ items.push({ text: s.text, x: s.x, y, w: s.w, h, fontSize, fontName: i.fontName || "", isHidden, seq: seq + k / 1e3 });
2164
+ });
1631
2165
  } else {
1632
- items.push({ text, x, y, w, h, fontSize, fontName: i.fontName || "", isHidden });
2166
+ items.push({ text, x, y, w, h, fontSize, fontName: i.fontName || "", isHidden, seq });
1633
2167
  }
1634
2168
  }
1635
2169
  const sorted = items.sort((a, b) => b.y - a.y || a.x - b.x);
@@ -1647,6 +2181,7 @@ function normalizeItems(rawItems) {
1647
2181
  }
1648
2182
  if (!isDup) deduped.push(sorted[i]);
1649
2183
  }
2184
+ splitOverlaidRuns(deduped);
1650
2185
  if (spacePositions.length > 0) {
1651
2186
  for (const sp of spacePositions) {
1652
2187
  let nearest = null;
@@ -1662,6 +2197,98 @@ function normalizeItems(rawItems) {
1662
2197
  }
1663
2198
  return deduped;
1664
2199
  }
2200
+ var WORD_SPACE_EM = 0.3;
2201
+ var OVERLAY_DUP_EM = 0.5;
2202
+ var OVERLAY_FIT_EM = 0.6;
2203
+ function glyphUnits(s) {
2204
+ let u = 0;
2205
+ for (const ch of s) u += (_nullishCoalesce(ch.codePointAt(0), () => ( 0))) >= 8592 ? 1 : 0.5;
2206
+ return u;
2207
+ }
2208
+ function splitOverlaidRuns(items) {
2209
+ let replaced = null;
2210
+ for (let ci = 0; ci < items.length; ci++) {
2211
+ const c = items[ci];
2212
+ if (c.w <= 0 || !/\S\s+\S/.test(c.text)) continue;
2213
+ const overlays = [];
2214
+ for (let j = ci - 1; j >= 0 && items[j].y - c.y <= 1; j--) if (isInside(items[j], c)) overlays.push(items[j]);
2215
+ for (let j = ci + 1; j < items.length && c.y - items[j].y <= 1; j++) if (isInside(items[j], c)) overlays.push(items[j]);
2216
+ if (overlays.length === 0) continue;
2217
+ const pieces = splitAroundOverlays(c, overlays);
2218
+ if (pieces) (replaced ??= /* @__PURE__ */ new Map()).set(c, pieces);
2219
+ }
2220
+ if (!replaced) return;
2221
+ const out = [];
2222
+ for (const it of items) {
2223
+ const p = replaced.get(it);
2224
+ if (p) out.push(...p);
2225
+ else out.push(it);
2226
+ }
2227
+ items.length = 0;
2228
+ items.push(...out.sort((a, b) => b.y - a.y || a.x - b.x));
2229
+ }
2230
+ function isInside(o, c) {
2231
+ return o.x >= c.x + 1 && o.x + o.w <= c.x + c.w + 1 && o.w < c.w;
2232
+ }
2233
+ function splitAroundOverlays(c, overlays) {
2234
+ const words = c.text.split(/\s+/);
2235
+ const fs = c.fontSize > 0 ? c.fontSize : c.h > 0 ? c.h : 10;
2236
+ const ws = WORD_SPACE_EM * fs;
2237
+ const totalU = words.reduce((s, w) => s + glyphUnits(w), 0);
2238
+ if (totalU <= 0) return null;
2239
+ const a0 = (c.w - (words.length - 1) * ws) / totalU;
2240
+ const ov = overlays.filter((o) => {
2241
+ for (let at = c.text.indexOf(o.text); at >= 0; at = c.text.indexOf(o.text, at + 1)) {
2242
+ const prefix = c.text.slice(0, at);
2243
+ const est = c.x + glyphUnits(prefix.replace(/\s+/g, "")) * a0 + (_nullishCoalesce(_optionalChain([prefix, 'access', _26 => _26.match, 'call', _27 => _27(/\s+/g), 'optionalAccess', _28 => _28.length]), () => ( 0))) * ws;
2244
+ if (Math.abs(est - o.x) <= OVERLAY_DUP_EM * fs) return false;
2245
+ }
2246
+ return true;
2247
+ }).sort((p2, q) => p2.x - q.x);
2248
+ if (ov.length === 0) return null;
2249
+ const holes = Math.min(ov.length, words.length - 1);
2250
+ let ovW = 0;
2251
+ for (const o of ov) ovW += o.w;
2252
+ const a = (c.w - ovW - (words.length - 1 - holes) * ws) / totalU;
2253
+ if (!(a > 0)) return null;
2254
+ const starts = [], ends = [], holeAfter = [];
2255
+ let p = c.x;
2256
+ let k = 0;
2257
+ let assigned = 0;
2258
+ for (let i = 0; i < words.length; i++) {
2259
+ starts.push(p);
2260
+ p += glyphUnits(words[i]) * a;
2261
+ ends.push(p);
2262
+ if (i === words.length - 1) break;
2263
+ while (k < ov.length && ov[k].x < p - a * 0.6) k++;
2264
+ const half = glyphUnits(words[i + 1]) * a / 2;
2265
+ let hole = false;
2266
+ while (k < ov.length && ov[k].x < p + half) {
2267
+ hole = true;
2268
+ p = Math.max(p, ov[k].x + ov[k].w);
2269
+ k++;
2270
+ }
2271
+ holeAfter.push(hole);
2272
+ if (hole) assigned++;
2273
+ else p += ws;
2274
+ }
2275
+ if (assigned === 0 || Math.abs(p - (c.x + c.w)) > Math.max(3, OVERLAY_FIT_EM * fs)) return null;
2276
+ const pieces = [];
2277
+ for (let s = 0; s < words.length; ) {
2278
+ let e = s;
2279
+ while (e < words.length - 1 && !holeAfter[e]) e++;
2280
+ pieces.push({
2281
+ ...c,
2282
+ text: words.slice(s, e + 1).join(" "),
2283
+ x: Math.round(starts[s]),
2284
+ w: Math.max(1, Math.round(ends[e] - starts[s])),
2285
+ hasSpaceBefore: s === 0 ? c.hasSpaceBefore : false,
2286
+ seq: c.seq === void 0 ? void 0 : c.seq + pieces.length / 1e4
2287
+ });
2288
+ s = e + 1;
2289
+ }
2290
+ return pieces;
2291
+ }
1665
2292
  function splitEvenSpacedItem(text, itemX, itemW, fontSize) {
1666
2293
  if (!/^[가-힣\d](?: [가-힣\d]){2,}$/.test(text)) return null;
1667
2294
  const chars = text.split(" ");
@@ -1726,8 +2353,8 @@ function mergeSuperscriptLines(lines) {
1726
2353
  return result;
1727
2354
  }
1728
2355
  function mergeLineSimple(items) {
1729
- if (items.length <= 1) return _optionalChain([items, 'access', _10 => _10[0], 'optionalAccess', _11 => _11.text]) || "";
1730
- const sorted = [...items].sort((a, b) => a.x - b.x);
2356
+ if (items.length <= 1) return _optionalChain([items, 'access', _29 => _29[0], 'optionalAccess', _30 => _30.text]) || "";
2357
+ const sorted = sortLineByX([...items]);
1731
2358
  const isEvenSpaced = detectEvenSpacedItems(sorted);
1732
2359
  let result = sorted[0].text;
1733
2360
  for (let i = 1; i < sorted.length; i++) {
@@ -1775,15 +2402,15 @@ function computeMedianFontSizeFromFreq(freq) {
1775
2402
  }
1776
2403
  function detectHeadings(blocks, medianFontSize) {
1777
2404
  for (const block of blocks) {
1778
- if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access', _12 => _12.style, 'optionalAccess', _13 => _13.fontSize])) continue;
2405
+ if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access', _31 => _31.style, 'optionalAccess', _32 => _32.fontSize])) continue;
1779
2406
  const text = block.text.trim();
1780
2407
  if (text.length === 0 || text.length > 200) continue;
1781
2408
  if (/^\d+$/.test(text)) continue;
1782
2409
  const ratio = block.style.fontSize / medianFontSize;
1783
2410
  let level = 0;
1784
- if (ratio >= _chunkL7DMSMAGcjs.HEADING_RATIO_H1) level = 1;
1785
- else if (ratio >= _chunkL7DMSMAGcjs.HEADING_RATIO_H2) level = 2;
1786
- else if (ratio >= _chunkL7DMSMAGcjs.HEADING_RATIO_H3) level = 3;
2411
+ if (ratio >= _chunkVWUYVEFNcjs.HEADING_RATIO_H1) level = 1;
2412
+ else if (ratio >= _chunkVWUYVEFNcjs.HEADING_RATIO_H2) level = 2;
2413
+ else if (ratio >= _chunkVWUYVEFNcjs.HEADING_RATIO_H3) level = 3;
1787
2414
  if (level > 0) {
1788
2415
  block.type = "heading";
1789
2416
  block.level = level;
@@ -1836,7 +2463,7 @@ function detectMarkerHeadings(blocks) {
1836
2463
  block.level = 4;
1837
2464
  continue;
1838
2465
  }
1839
- if (/^[가-힣]{2,6}$/.test(text) && _optionalChain([block, 'access', _14 => _14.style, 'optionalAccess', _15 => _15.fontSize])) {
2466
+ if (/^[가-힣]{2,6}$/.test(text) && _optionalChain([block, 'access', _33 => _33.style, 'optionalAccess', _34 => _34.fontSize])) {
1840
2467
  const prev = blocks[i - 1];
1841
2468
  const next = blocks[i + 1];
1842
2469
  const prevIsStructural = !prev || prev.type === "table" || prev.type === "heading" || prev.type === "separator";
@@ -2091,7 +2718,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings) {
2091
2718
  const bottomEntries = [];
2092
2719
  for (let bi = 0; bi < blocks.length; bi++) {
2093
2720
  const b = blocks[bi];
2094
- if (!b.bbox || !b.pageNumber || !_optionalChain([b, 'access', _16 => _16.text, 'optionalAccess', _17 => _17.trim, 'call', _18 => _18()])) continue;
2721
+ if (!b.bbox || !b.pageNumber || !_optionalChain([b, 'access', _35 => _35.text, 'optionalAccess', _36 => _36.trim, 'call', _37 => _37()])) continue;
2095
2722
  const ph = pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber);
2096
2723
  if (!ph) continue;
2097
2724
  const blockTop = ph - (b.bbox.y + b.bbox.height);
@@ -2114,7 +2741,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings) {
2114
2741
  }
2115
2742
  const repeatedPatterns = /* @__PURE__ */ new Set();
2116
2743
  for (const [p, count] of patternCount) {
2117
- if (count >= MIN_REPEAT && (_nullishCoalesce(_optionalChain([patternPages, 'access', _19 => _19.get, 'call', _20 => _20(p), 'optionalAccess', _21 => _21.size]), () => ( 0))) >= MIN_REPEAT) {
2744
+ if (count >= MIN_REPEAT && (_nullishCoalesce(_optionalChain([patternPages, 'access', _38 => _38.get, 'call', _39 => _39(p), 'optionalAccess', _40 => _40.size]), () => ( 0))) >= MIN_REPEAT) {
2118
2745
  repeatedPatterns.add(p);
2119
2746
  }
2120
2747
  }
@@ -2128,7 +2755,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings) {
2128
2755
  if (bi === e.blockIdx) continue;
2129
2756
  const o = blocks[bi];
2130
2757
  if (!o.bbox || o.bbox.page !== cb.page) continue;
2131
- const oNorm = _optionalChain([o, 'access', _22 => _22.text, 'optionalAccess', _23 => _23.trim, 'call', _24 => _24(), 'access', _25 => _25.replace, 'call', _26 => _26(/\d+/g, "#")]);
2758
+ const oNorm = _optionalChain([o, 'access', _41 => _41.text, 'optionalAccess', _42 => _42.trim, 'call', _43 => _43(), 'access', _44 => _44.replace, 'call', _45 => _45(/\d+/g, "#")]);
2132
2759
  if (oNorm && repeatedPatterns.has(oNorm)) continue;
2133
2760
  const overlap2 = Math.min(cb.y + cb.height, o.bbox.y + o.bbox.height) - Math.max(cb.y, o.bbox.y);
2134
2761
  if (overlap2 >= cb.height * 0.5) {
@@ -2145,6 +2772,53 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings) {
2145
2772
  return [...removeSet].sort((a, b) => a - b);
2146
2773
  }
2147
2774
 
2775
+ // src/pdf/table-meta.ts
2776
+ var CLIP_TABLES = /* @__PURE__ */ new WeakSet();
2777
+ var TABLE_COLXS = /* @__PURE__ */ new WeakMap();
2778
+ var EMPTY_PARTS = /* @__PURE__ */ new WeakSet();
2779
+ var IMAGE_CELLS = /* @__PURE__ */ new WeakSet();
2780
+ var FILLER_CELLS = /* @__PURE__ */ new WeakSet();
2781
+ var CONT_PARTS = /* @__PURE__ */ new WeakMap();
2782
+ var CELL_LINES = /* @__PURE__ */ new WeakMap();
2783
+ function recordCellLines(cell, items) {
2784
+ const lines = [];
2785
+ for (const it of [...items].sort((a, b) => b.y - a.y)) {
2786
+ const fs = it.fontSize || it.h;
2787
+ const last = lines[lines.length - 1];
2788
+ if (last && Math.abs(last.y - it.y) <= Math.max(3, Math.min(fs, last.h) * 0.6)) {
2789
+ last.l = Math.min(last.l, it.x);
2790
+ last.r = Math.max(last.r, it.x + it.w);
2791
+ last.h = Math.max(last.h, fs);
2792
+ } else lines.push({ y: it.y, l: it.x, r: it.x + it.w, h: fs });
2793
+ }
2794
+ CELL_LINES.set(cell, lines);
2795
+ }
2796
+
2797
+ // src/pdf/table-trim.ts
2798
+ function markImageCell(cell) {
2799
+ IMAGE_CELLS.add(cell);
2800
+ }
2801
+ var emptyCell = (cell) => !cell || !_optionalChain([cell, 'access', _46 => _46.text, 'optionalAccess', _47 => _47.trim, 'call', _48 => _48()]) && !_optionalChain([cell, 'access', _49 => _49.blocks, 'optionalAccess', _50 => _50.length]) && !IMAGE_CELLS.has(cell);
2802
+ function trimTable(table) {
2803
+ let cols = table.cols;
2804
+ while (cols > 0 && table.cells.every((row) => emptyCell(row[cols - 1]))) cols--;
2805
+ if (cols === table.cols || cols === 0) return;
2806
+ table.cells = table.cells.map((row) => row.slice(0, cols));
2807
+ for (const row of table.cells) {
2808
+ for (let c = 0; c < row.length; c++) {
2809
+ if (c + row[c].colSpan > cols) row[c].colSpan = cols - c;
2810
+ }
2811
+ }
2812
+ table.cols = cols;
2813
+ }
2814
+ function trimTrailingEmptyTableCols(blocks) {
2815
+ for (const b of blocks) {
2816
+ if (b.type !== "table" || !b.table) continue;
2817
+ for (const row of b.table.cells) for (const cell of row) if (_optionalChain([cell, 'access', _51 => _51.blocks, 'optionalAccess', _52 => _52.length])) trimTrailingEmptyTableCols(cell.blocks);
2818
+ trimTable(b.table);
2819
+ }
2820
+ }
2821
+
2148
2822
  // src/pdf/cluster-detector.ts
2149
2823
  var Y_TOL = 3;
2150
2824
  var COL_CLUSTER_TOL = 15;
@@ -2199,12 +2873,12 @@ function isTwoColumnProse(r) {
2199
2873
  if (t.rows < 8) return false;
2200
2874
  const dense = [];
2201
2875
  for (let c = 0; c < t.cols; c++) {
2202
- const filled = t.cells.filter((row) => _optionalChain([row, 'access', _27 => _27[c], 'optionalAccess', _28 => _28.text, 'access', _29 => _29.trim, 'call', _30 => _30()])).length;
2876
+ const filled = t.cells.filter((row) => _optionalChain([row, 'access', _53 => _53[c], 'optionalAccess', _54 => _54.text, 'access', _55 => _55.trim, 'call', _56 => _56()])).length;
2203
2877
  if (filled / t.rows >= 0.3) dense.push(c);
2204
2878
  }
2205
2879
  if (dense.length !== 2) return false;
2206
2880
  for (const c of dense) {
2207
- const lens = t.cells.map((row) => _nullishCoalesce(_optionalChain([row, 'access', _31 => _31[c], 'optionalAccess', _32 => _32.text, 'access', _33 => _33.replace, 'call', _34 => _34(/\s+/g, ""), 'access', _35 => _35.length]), () => ( 0))).filter((n) => n > 0);
2881
+ const lens = t.cells.map((row) => _nullishCoalesce(_optionalChain([row, 'access', _57 => _57[c], 'optionalAccess', _58 => _58.text, 'access', _59 => _59.replace, 'call', _60 => _60(/\s+/g, ""), 'access', _61 => _61.length]), () => ( 0))).filter((n) => n > 0);
2208
2882
  const avg = lens.reduce((s, v) => s + v, 0) / (lens.length || 1);
2209
2883
  if (avg < 12) return false;
2210
2884
  }
@@ -2241,18 +2915,16 @@ function findTwoColumnProseCutX(items) {
2241
2915
  const right = [];
2242
2916
  let twoSide = 0;
2243
2917
  for (const line of lines) {
2244
- let hasL = false;
2245
- let hasR = false;
2918
+ const L = [], R = [];
2246
2919
  for (const i of line.items) {
2247
- if (i.x + i.w <= cutX) {
2248
- left.push(i);
2249
- hasL = true;
2250
- } else if (i.x >= cutX) {
2251
- right.push(i);
2252
- hasR = true;
2253
- }
2920
+ if (i.x + i.w <= cutX) L.push(i);
2921
+ else if (i.x >= cutX) R.push(i);
2922
+ }
2923
+ if (L.length && R.length) {
2924
+ twoSide++;
2925
+ left.push(...L);
2926
+ right.push(...R);
2254
2927
  }
2255
- if (hasL && hasR) twoSide++;
2256
2928
  }
2257
2929
  if (twoSide / lines.length < 0.55) return null;
2258
2930
  if (left.length < 5 || right.length < 5) return null;
@@ -2662,7 +3334,7 @@ function buildClusterTable(rows, columns, pageNum) {
2662
3334
  }
2663
3335
  const assignments = assignRowItems(row.items, columns, numCols);
2664
3336
  for (const { col, items } of assignments) {
2665
- const text = items.map((i) => i.text).join(" ");
3337
+ const text = joinCellItems(items);
2666
3338
  const existing = cells[r][col].text;
2667
3339
  cells[r][col].text = existing ? existing + " " + text : text;
2668
3340
  for (const item of items) usedItems.add(item);
@@ -2681,10 +3353,11 @@ function buildClusterTable(rows, columns, pageNum) {
2681
3353
  const nonEmptyCols = cells[r].filter((c) => c.text.trim()).length;
2682
3354
  if (nonEmptyCols !== 1) continue;
2683
3355
  if (cells[r][0].text.trim() !== "") continue;
2684
- const contentText = _optionalChain([cells, 'access', _36 => _36[r], 'access', _37 => _37.find, 'call', _38 => _38((c) => c.text.trim()), 'optionalAccess', _39 => _39.text, 'access', _40 => _40.trim, 'call', _41 => _41()]) || "";
3356
+ const contentText = _optionalChain([cells, 'access', _62 => _62[r], 'access', _63 => _63.find, 'call', _64 => _64((c) => c.text.trim()), 'optionalAccess', _65 => _65.text, 'access', _66 => _66.trim, 'call', _67 => _67()]) || "";
2685
3357
  if (/^[○●▶\-·]/.test(contentText)) continue;
2686
3358
  for (let pr = r - 1; pr >= 0; pr--) {
2687
3359
  if (cells[pr].some((c) => c.text.trim())) {
3360
+ if (cells[pr][0].colSpan > 1) break;
2688
3361
  for (let c = 0; c < numCols; c++) {
2689
3362
  const prev = cells[pr][c].text.trim();
2690
3363
  const curr = cells[r][c].text.trim();
@@ -2735,6 +3408,29 @@ function buildClusterTable(rows, columns, pageNum) {
2735
3408
  usedItems
2736
3409
  };
2737
3410
  }
3411
+ function joinCellItems(items) {
3412
+ const hOf = (i) => i.h > 0 ? i.h : i.fontSize;
3413
+ const lines = [];
3414
+ for (const it of [...items].sort((a, b) => b.y - a.y || a.x - b.x)) {
3415
+ const bottom = it.y, top = it.y + hOf(it);
3416
+ 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);
3417
+ if (line) {
3418
+ line.items.push(it);
3419
+ line.bottom = Math.min(line.bottom, bottom);
3420
+ line.top = Math.max(line.top, top);
3421
+ } else lines.push({ bottom, top, items: [it] });
3422
+ }
3423
+ return lines.sort((a, b) => b.top - a.top).map(({ items: line }) => {
3424
+ line.sort((a, b) => a.x - b.x);
3425
+ let s = line[0].text;
3426
+ for (let i = 1; i < line.length; i++) {
3427
+ const gap = line[i].x - (line[i - 1].x + line[i - 1].w);
3428
+ const fs = (line[i].fontSize + line[i - 1].fontSize) / 2;
3429
+ s += (line[i].hasSpaceBefore && gap >= fs * 0.05 || gap > spaceGapThreshold(fs) ? " " : "") + line[i].text;
3430
+ }
3431
+ return s;
3432
+ }).join(" ");
3433
+ }
2738
3434
 
2739
3435
  // src/pdf/xy-cut.ts
2740
3436
  var MAX_XYCUT_DEPTH = 50;
@@ -3046,14 +3742,14 @@ function isProseSpread(items) {
3046
3742
  for (let i = 1; i < sorted.length; i++) {
3047
3743
  gaps.push(sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w));
3048
3744
  }
3049
- const maxGap = _chunkHR2XNERBcjs.safeMax.call(void 0, gaps);
3745
+ const maxGap = _chunkWJHAU73Bcjs.safeMax.call(void 0, gaps);
3050
3746
  const avgLen = items.reduce((s, i) => s + i.text.length, 0) / items.length;
3051
3747
  return maxGap < 40 && avgLen < 5;
3052
3748
  }
3053
3749
  function detectColumns(yLines) {
3054
3750
  const allItems = yLines.flat();
3055
3751
  if (allItems.length === 0) return null;
3056
- const pageWidth = _chunkHR2XNERBcjs.safeMax.call(void 0, allItems.map((i) => i.x + i.w)) - _chunkHR2XNERBcjs.safeMin.call(void 0, allItems.map((i) => i.x));
3752
+ const pageWidth = _chunkWJHAU73Bcjs.safeMax.call(void 0, allItems.map((i) => i.x + i.w)) - _chunkWJHAU73Bcjs.safeMin.call(void 0, allItems.map((i) => i.x));
3057
3753
  if (pageWidth < 100) return null;
3058
3754
  let bigoLineIdx = -1;
3059
3755
  for (let i = 0; i < yLines.length; i++) {
@@ -3067,7 +3763,10 @@ function detectColumns(yLines) {
3067
3763
  const xClusters = [];
3068
3764
  for (const line of tableYLines) {
3069
3765
  if (isProseSpread(line)) continue;
3070
- for (const item of line) {
3766
+ const byX = [...line].sort((a, b) => a.x - b.x);
3767
+ for (let k = 0; k < byX.length; k++) {
3768
+ const item = byX[k];
3769
+ if (k > 0 && item.x - (byX[k - 1].x + byX[k - 1].w) < Math.max(item.fontSize, byX[k - 1].fontSize)) continue;
3071
3770
  let found = false;
3072
3771
  for (const c of xClusters) {
3073
3772
  if (Math.abs(item.x - c.center) <= CLUSTER_TOL) {
@@ -3372,12 +4071,26 @@ function wrapUnderlineRuns(items) {
3372
4071
  }
3373
4072
 
3374
4073
  // src/pdf/page-blocks.ts
3375
- function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true) {
3376
- if (items.length === 0) return [];
4074
+ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon) {
4075
+ if (items.length === 0) {
4076
+ if (carry) carry.clip = void 0;
4077
+ return [];
4078
+ }
4079
+ const lex = _nullishCoalesce(lexicon, () => ( new WrapLexicon()));
4080
+ for (const line of streamLines(items)) lex.addLine(mergeLineSimple(line));
3377
4081
  const extracted = extractLines(opList.fnArray, opList.argsArray);
3378
4082
  let { horizontals, verticals } = extracted;
3379
- const clipResult = detectTables ? buildClipCellGrids(extracted.clipRects, horizontals, verticals, pageWidth, pageHeight, items.map((it) => ({ x: it.x + it.w / 2, y: it.y + it.h / 2 }))) : { grids: [], containers: [] };
4083
+ const prevPage = _optionalChain([carry, 'optionalAccess', _68 => _68.page]) === pageNum - 1 ? carry.clip : void 0;
4084
+ const clipResult = detectTables ? buildClipCellGrids(extracted.clipRects, horizontals, verticals, pageWidth, pageHeight, items.map((it) => ({ x: it.x + it.w / 2, y: it.y + it.h / 2 })), extracted.fillRects, prevPage) : { grids: [], containers: [], page: void 0 };
4085
+ if (carry) {
4086
+ carry.page = pageNum;
4087
+ carry.clip = clipResult.page;
4088
+ }
3380
4089
  const clipGrids = clipResult.grids;
4090
+ if (clipGrids.length === 0) {
4091
+ horizontals = chainShortSegments(horizontals, extracted.shortH, "h");
4092
+ verticals = chainShortSegments(verticals, extracted.shortV, "v");
4093
+ }
3381
4094
  if (extraLines) {
3382
4095
  horizontals = horizontals.concat(extraLines.horizontals);
3383
4096
  verticals = verticals.concat(extraLines.verticals);
@@ -3392,11 +4105,13 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
3392
4105
  markUnderlineItems(items, horizontals, verticals);
3393
4106
  wrapUnderlineRuns(items);
3394
4107
  const lineGrids = detectTables ? buildTableGrids(horizontals, verticals) : [];
3395
- const grids = [...clipGrids, ...dropGridsInside(lineGrids, clipGrids, clipResult.containers)];
4108
+ const tableClipGrids = dropShadingClipGrids(clipGrids, lineGrids, extracted.fillRects, verticals);
4109
+ const grids = [...tableClipGrids, ...dropGridsInside(lineGrids, tableClipGrids, clipResult.containers)];
3396
4110
  if (grids.length > 0) {
3397
- return extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals);
4111
+ const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
4112
+ return extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals, imageRegions, lex);
3398
4113
  }
3399
- return extractPageBlocksFallback(items, pageNum, true, detectTables);
4114
+ return extractPageBlocksFallback(items, pageNum, true, detectTables, lex);
3400
4115
  }
3401
4116
  var STRIKE_MAX_THICKNESS = 2;
3402
4117
  var STRIKE_MAX_THICKNESS_RATIO = 0.25;
@@ -3505,13 +4220,13 @@ function takePendingNested(pending, cellBox) {
3505
4220
  }
3506
4221
  return out;
3507
4222
  }
3508
- function buildFrameCellBlocks(cellItems, nested, pageNum) {
4223
+ function buildFrameCellBlocks(cellItems, nested, pageNum, wrap) {
3509
4224
  const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
3510
4225
  const blocks = [];
3511
4226
  let rest = [...cellItems];
3512
4227
  const pushParagraphs = (items) => {
3513
4228
  if (items.length === 0) return;
3514
- for (const line of cleanCellText(cellTextToString(items)).split("\n")) {
4229
+ for (const line of cleanCellText(cellTextToString(items, wrap)).split("\n")) {
3515
4230
  const t = line.trim();
3516
4231
  if (t) blocks.push({ type: "paragraph", text: t, pageNumber: pageNum });
3517
4232
  }
@@ -3526,7 +4241,7 @@ function buildFrameCellBlocks(cellItems, nested, pageNum) {
3526
4241
  const text = blocks.map((b) => b.type === "table" && b.table ? b.table.cells.flat().map((c) => c.text).filter(Boolean).join("\n") : _nullishCoalesce(b.text, () => ( ""))).filter(Boolean).join("\n");
3527
4242
  return { blocks, text };
3528
4243
  }
3529
- function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
4244
+ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals, imageRegions = [], lex) {
3530
4245
  const blocks = [];
3531
4246
  const usedItems = /* @__PURE__ */ new Set();
3532
4247
  const pendingNested = [];
@@ -3558,7 +4273,8 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3558
4273
  h: i.h,
3559
4274
  fontSize: i.fontSize,
3560
4275
  fontName: i.fontName,
3561
- hasSpaceBefore: i.hasSpaceBefore
4276
+ hasSpaceBefore: i.hasSpaceBefore,
4277
+ seq: i.seq
3562
4278
  }));
3563
4279
  const cellTextMap = mapTextToCells(textItems, cells);
3564
4280
  const assignedItems = /* @__PURE__ */ new Set();
@@ -3575,20 +4291,31 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3575
4291
  const nested = grid.cells ? takePendingNested(pendingNested, cell.bbox) : [];
3576
4292
  if (nested.length > 0) {
3577
4293
  nestedAttached = true;
3578
- const built = buildFrameCellBlocks(cellItems, nested, pageNum);
4294
+ const built = buildFrameCellBlocks(cellItems, nested, pageNum, { box: cell.bbox, lex });
3579
4295
  irGrid[cell.row][cell.col] = { text: built.text, colSpan: cell.colSpan, rowSpan: cell.rowSpan, blocks: built.blocks };
4296
+ if (cellItems.length) recordCellLines(irGrid[cell.row][cell.col], cellItems);
3580
4297
  continue;
3581
4298
  }
3582
4299
  irGrid[cell.row][cell.col] = {
3583
- text: cleanCellText(cellTextToString(cellItems)),
4300
+ text: cleanCellText(cellTextToString(cellItems, { box: cell.bbox, lex })),
3584
4301
  colSpan: cell.colSpan,
3585
4302
  rowSpan: cell.rowSpan
3586
4303
  };
4304
+ const b = cell.bbox;
4305
+ const isBackdrop = (r) => r.x1 <= b.x1 + 1 && r.x2 >= b.x2 - 1 && r.y1 <= b.y1 + 1 && r.y2 >= b.y2 - 1;
4306
+ if (imageRegions.some((r) => {
4307
+ const cx = (r.x1 + r.x2) / 2, cy = (r.y1 + r.y2) / 2;
4308
+ return cx > b.x1 && cx < b.x2 && cy > b.y1 && cy < b.y2 && !isBackdrop(r);
4309
+ })) {
4310
+ markImageCell(irGrid[cell.row][cell.col]);
4311
+ }
4312
+ if (cell.filler && !cellItems.length) FILLER_CELLS.add(irGrid[cell.row][cell.col]);
4313
+ if (grid.cells && cellItems.length) recordCellLines(irGrid[cell.row][cell.col], cellItems);
3587
4314
  }
3588
4315
  let finalGrid = irGrid;
3589
4316
  let finalRows = numRows;
3590
4317
  let rebuiltUsed = false;
3591
- if (numRows <= 2 && numCols >= 3 && !nestedAttached) {
4318
+ if (!grid.cells && numRows <= 2 && numCols >= 3 && !nestedAttached) {
3592
4319
  const rebuilt = normalizeUndersegmentedTable(irGrid, grid.colXs, textItems);
3593
4320
  if (rebuilt) {
3594
4321
  rebuiltUsed = true;
@@ -3607,8 +4334,12 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3607
4334
  cells: finalGrid,
3608
4335
  hasHeader: finalRows > 1
3609
4336
  };
4337
+ TABLE_COLXS.set(irTable, grid.colXs);
4338
+ if (grid.continues) CONT_PARTS.set(irTable, grid.continues);
3610
4339
  const hasContent = finalGrid.some((row) => row.some((cell) => cell.text.trim() !== ""));
3611
- if (!hasContent) continue;
4340
+ const emptyPart = !hasContent && !!grid.cells && !grid.clipParent && !nestedAttached;
4341
+ if (!hasContent && !emptyPart) continue;
4342
+ if (emptyPart) EMPTY_PARTS.add(irTable);
3612
4343
  if (grid.clipParent) {
3613
4344
  const nb = { page: pageNum, x: grid.bbox.x1, y: grid.bbox.y1, width: grid.bbox.x2 - grid.bbox.x1, height: grid.bbox.y2 - grid.bbox.y1 };
3614
4345
  pendingNested.push({ parent: grid.clipParent, block: { type: "table", table: irTable, pageNumber: pageNum, bbox: nb } });
@@ -3633,6 +4364,7 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3633
4364
  }
3634
4365
  continue;
3635
4366
  }
4367
+ if (grid.cells) CLIP_TABLES.add(irTable);
3636
4368
  blocks.push({ type: "table", table: irTable, pageNumber: pageNum, bbox: tableBbox });
3637
4369
  }
3638
4370
  for (const p of pendingNested) blocks.push(p.block);
@@ -3670,7 +4402,7 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3670
4402
  {
3671
4403
  const rects = remaining.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }));
3672
4404
  for (const b of blocks) {
3673
- if (b.bbox) rects.push({ x: b.bbox.x, y: b.bbox.y, w: b.bbox.width, h: b.bbox.height });
4405
+ if (b.bbox && !(b.table && EMPTY_PARTS.has(b.table))) rects.push({ x: b.bbox.x, y: b.bbox.y, w: b.bbox.width, h: b.bbox.height });
3674
4406
  }
3675
4407
  gutterX = detectColumnGutter(rects);
3676
4408
  }
@@ -3678,7 +4410,7 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3678
4410
  if (gutterX !== null) {
3679
4411
  const gx = gutterX;
3680
4412
  const allY = remaining.map((i) => i.y);
3681
- const pageH = _chunkHR2XNERBcjs.safeMax.call(void 0, allY) - _chunkHR2XNERBcjs.safeMin.call(void 0, allY);
4413
+ const pageH = _chunkWJHAU73Bcjs.safeMax.call(void 0, allY) - _chunkWJHAU73Bcjs.safeMin.call(void 0, allY);
3682
4414
  const gapThreshold = Math.max(15, pageH * 0.03);
3683
4415
  const sides = [
3684
4416
  remaining.filter((i) => i.x + i.w <= gx),
@@ -3690,7 +4422,7 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3690
4422
  if (side.length === 0) continue;
3691
4423
  for (const group of xyCutOrder(side, gapThreshold)) {
3692
4424
  if (group.length === 0) continue;
3693
- const groupBlocks = extractPageBlocksFallback(group, pageNum);
4425
+ const groupBlocks = extractPageBlocksFallback(group, pageNum, false, true, lex);
3694
4426
  for (const b of groupBlocks) textBlocks.push(b);
3695
4427
  groupSizes.push(groupBlocks.length);
3696
4428
  }
@@ -3698,12 +4430,12 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3698
4430
  finalTextBlocks = detectListBlocks(textBlocks);
3699
4431
  } else {
3700
4432
  const allY = remaining.map((i) => i.y);
3701
- const pageH = _chunkHR2XNERBcjs.safeMax.call(void 0, allY) - _chunkHR2XNERBcjs.safeMin.call(void 0, allY);
4433
+ const pageH = _chunkWJHAU73Bcjs.safeMax.call(void 0, allY) - _chunkWJHAU73Bcjs.safeMin.call(void 0, allY);
3702
4434
  const groups = xyCutOrder(remaining, Math.max(15, pageH * 0.03));
3703
4435
  const textBlocks = [];
3704
4436
  for (const group of groups) {
3705
4437
  if (group.length === 0) continue;
3706
- const groupBlocks = extractPageBlocksFallback(group, pageNum);
4438
+ const groupBlocks = extractPageBlocksFallback(group, pageNum, false, true, lex);
3707
4439
  for (const b of groupBlocks) textBlocks.push(b);
3708
4440
  groupSizes.push(groupBlocks.length);
3709
4441
  }
@@ -3747,53 +4479,13 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
3747
4479
  for (const u of units) for (const b of u) ordered.push(b);
3748
4480
  return mergeAdjacentTableBlocks(ordered);
3749
4481
  }
3750
- var NEIGHBOR_TABLE_EPSILON = 0.2;
3751
- function mergeCrossPageTables(blocks) {
3752
- for (let i = blocks.length - 2; i >= 0; i--) {
3753
- const prev = blocks[i];
3754
- const curr = blocks[i + 1];
3755
- if (prev.type !== "table" || curr.type !== "table" || !prev.table || !curr.table) continue;
3756
- if (!prev.pageNumber || !curr.pageNumber || curr.pageNumber !== prev.pageNumber + 1) continue;
3757
- if (prev.table.cols !== curr.table.cols) continue;
3758
- if (!prev.bbox || !curr.bbox) continue;
3759
- const width = Math.max(prev.bbox.width, curr.bbox.width, 1);
3760
- const leftDiff = Math.abs(prev.bbox.x - curr.bbox.x);
3761
- const rightDiff = Math.abs(prev.bbox.x + prev.bbox.width - (curr.bbox.x + curr.bbox.width));
3762
- if (leftDiff > width * NEIGHBOR_TABLE_EPSILON || rightDiff > width * NEIGHBOR_TABLE_EPSILON) continue;
3763
- let currCells = curr.table.cells;
3764
- if (currCells.length > 1 && prev.table.cells.length > 0 && rowTextsEqual(prev.table.cells[0], currCells[0])) {
3765
- currCells = currCells.slice(1);
3766
- }
3767
- if (currCells.length === 0) {
3768
- blocks.splice(i + 1, 1);
3769
- continue;
3770
- }
3771
- const merged = {
3772
- rows: prev.table.rows + currCells.length,
3773
- cols: prev.table.cols,
3774
- cells: [...prev.table.cells, ...currCells],
3775
- hasHeader: prev.table.hasHeader,
3776
- caption: prev.table.caption
3777
- };
3778
- blocks[i] = { ...prev, table: merged };
3779
- blocks.splice(i + 1, 1);
3780
- }
3781
- }
3782
- function rowTextsEqual(a, b) {
3783
- if (a.length !== b.length) return false;
3784
- const norm = (t) => t.replace(/\s+/g, "");
3785
- for (let i = 0; i < a.length; i++) {
3786
- if (norm(a[i].text) !== norm(b[i].text)) return false;
3787
- }
3788
- return a.some((c) => c.text.trim() !== "");
3789
- }
3790
4482
  function mergeAdjacentTableBlocks(blocks) {
3791
4483
  if (blocks.length <= 1) return blocks;
3792
4484
  const result = [blocks[0]];
3793
4485
  for (let i = 1; i < blocks.length; i++) {
3794
4486
  const prev = result[result.length - 1];
3795
4487
  const curr = blocks[i];
3796
- if (prev.type === "table" && curr.type === "table" && prev.table && curr.table && prev.table.cols === curr.table.cols) {
4488
+ if (prev.type === "table" && curr.type === "table" && prev.table && curr.table && prev.table.cols === curr.table.cols && !CLIP_TABLES.has(prev.table) && !CLIP_TABLES.has(curr.table)) {
3797
4489
  const merged = {
3798
4490
  rows: prev.table.rows + curr.table.rows,
3799
4491
  cols: prev.table.cols,
@@ -3853,7 +4545,42 @@ function splitTwoColumnProse(items, cutX) {
3853
4545
  }
3854
4546
  return groups;
3855
4547
  }
3856
- function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTables = true) {
4548
+ function streamLines(items) {
4549
+ if (items.some((i) => i.seq === void 0)) return groupByY([...items].sort((a, b) => b.y - a.y || a.x - b.x));
4550
+ const lines = [];
4551
+ let cur = [];
4552
+ for (const it of [...items].sort((a, b) => a.seq - b.seq)) {
4553
+ const last = cur[cur.length - 1];
4554
+ if (last && (Math.abs(it.y - last.y) > 3 || it.x < last.x - 1 || it.x - (last.x + last.w) > Math.max(2 * it.fontSize, 30))) {
4555
+ lines.push(cur);
4556
+ cur = [];
4557
+ }
4558
+ cur.push(it);
4559
+ }
4560
+ if (cur.length) lines.push(cur);
4561
+ return lines;
4562
+ }
4563
+ function pushLineParagraphs(out, yLines, pageNum, lex) {
4564
+ const lines = yLines.map((items) => ({ items, text: mergeLineSimple(items) })).filter((l) => l.text.trim());
4565
+ const geo = lines.map((l) => {
4566
+ const b = computeBBox(l.items, pageNum);
4567
+ return { text: l.text, left: b.x, right: b.x + b.width, y: l.items.reduce((s, i) => s + i.y, 0) / l.items.length, fontSize: _nullishCoalesce(_optionalChain([dominantStyle, 'call', _69 => _69(l.items), 'optionalAccess', _70 => _70.fontSize]), () => ( 0)) };
4568
+ });
4569
+ const joins = bodyLineJoins(geo, lex);
4570
+ for (let i = 0; i < lines.length; ) {
4571
+ let text = lines[i].text;
4572
+ const items = [...lines[i].items];
4573
+ for (; i + 1 < lines.length && joins[i] !== "\n"; i++) {
4574
+ text += joins[i] + lines[i + 1].text;
4575
+ items.push(...lines[i + 1].items);
4576
+ }
4577
+ const block = { type: "paragraph", text, pageNumber: pageNum, bbox: computeBBox(items, pageNum), style: dominantStyle(items) };
4578
+ PARA_LAST_LINE.set(block.bbox, { right: geo[i].right, width: geo[i].right - geo[i].left, fontSize: geo[i].fontSize });
4579
+ out.push(block);
4580
+ i++;
4581
+ }
4582
+ }
4583
+ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTables = true, lex) {
3857
4584
  if (items.length === 0) return [];
3858
4585
  const blocks = [];
3859
4586
  const clusterItems = items.map((i) => ({
@@ -3879,15 +4606,7 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
3879
4606
  blocks.push({ type: "table", table: cr.table, pageNumber: pageNum, bbox: cr.bbox });
3880
4607
  }
3881
4608
  const remaining = items.filter((_, idx) => !usedIndices.has(idx));
3882
- if (remaining.length > 0) {
3883
- const yLines = mergeSuperscriptLines(groupByY(remaining));
3884
- for (const line of yLines) {
3885
- const text = mergeLineSimple(line);
3886
- if (!text.trim()) continue;
3887
- const bbox = computeBBox(line, pageNum);
3888
- blocks.push({ type: "paragraph", text, pageNumber: pageNum, bbox, style: dominantStyle(line) });
3889
- }
3890
- }
4609
+ if (remaining.length > 0) pushLineParagraphs(blocks, mergeSuperscriptLines(groupByY(remaining)), pageNum, lex);
3891
4610
  blocks.sort((a, b) => {
3892
4611
  const ay = a.bbox ? a.bbox.y + a.bbox.height : 0;
3893
4612
  const by = b.bbox ? b.bbox.y + b.bbox.height : 0;
@@ -3906,7 +4625,7 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
3906
4625
  blocks.push({ type: "paragraph", text: tableText, pageNumber: pageNum, bbox, style: dominantStyle(items) });
3907
4626
  } else {
3908
4627
  const allY = items.map((i) => i.y);
3909
- const pageHeight = _chunkHR2XNERBcjs.safeMax.call(void 0, allY) - _chunkHR2XNERBcjs.safeMin.call(void 0, allY);
4628
+ const pageHeight = _chunkWJHAU73Bcjs.safeMax.call(void 0, allY) - _chunkWJHAU73Bcjs.safeMin.call(void 0, allY);
3910
4629
  const gapThreshold = Math.max(15, pageHeight * 0.03);
3911
4630
  const orderedGroups = proseCutX !== null ? splitTwoColumnProse(items, proseCutX) : xyCutOrder(items, gapThreshold);
3912
4631
  for (const group of orderedGroups) {
@@ -3918,12 +4637,7 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
3918
4637
  const bbox = computeBBox(group, pageNum);
3919
4638
  blocks.push({ type: "paragraph", text: tableText, pageNumber: pageNum, bbox, style: dominantStyle(group) });
3920
4639
  } else {
3921
- for (const line of yLines) {
3922
- const text = mergeLineSimple(line);
3923
- if (!text.trim()) continue;
3924
- const bbox = computeBBox(line, pageNum);
3925
- blocks.push({ type: "paragraph", text, pageNumber: pageNum, bbox, style: dominantStyle(line) });
3926
- }
4640
+ pushLineParagraphs(blocks, yLines, pageNum, lex);
3927
4641
  }
3928
4642
  }
3929
4643
  }
@@ -3944,5 +4658,14 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
3944
4658
 
3945
4659
 
3946
4660
 
3947
- exports.extractImageRegions = extractImageRegions; exports.filterHiddenText = filterHiddenText; exports.collapseEvenSpacing = collapseEvenSpacing; exports.normalizeItems = normalizeItems; exports.computeMedianFontSizeFromFreq = computeMedianFontSizeFromFreq; exports.detectHeadings = detectHeadings; exports.detectMarkerHeadings = detectMarkerHeadings; exports.detectTableCaptions = detectTableCaptions; exports.detectKoreanListBlocks = detectKoreanListBlocks; exports.removeHeaderFooterBlocks = removeHeaderFooterBlocks; exports.extractPageBlocksWithLines = extractPageBlocksWithLines; exports.mergeCrossPageTables = mergeCrossPageTables;
3948
- //# sourceMappingURL=chunk-247ANM72.cjs.map
4661
+
4662
+
4663
+
4664
+
4665
+
4666
+
4667
+
4668
+
4669
+
4670
+ exports.extractImageRegions = extractImageRegions; exports.filterHiddenText = filterHiddenText; exports.collapseEvenSpacing = collapseEvenSpacing; exports.normalizeItems = normalizeItems; exports.WrapLexicon = WrapLexicon; exports.joinPageBreakWraps = joinPageBreakWraps; exports.computeMedianFontSizeFromFreq = computeMedianFontSizeFromFreq; exports.detectHeadings = detectHeadings; exports.detectMarkerHeadings = detectMarkerHeadings; exports.detectTableCaptions = detectTableCaptions; exports.detectKoreanListBlocks = detectKoreanListBlocks; exports.removeHeaderFooterBlocks = removeHeaderFooterBlocks; exports.CLIP_TABLES = CLIP_TABLES; exports.TABLE_COLXS = TABLE_COLXS; exports.EMPTY_PARTS = EMPTY_PARTS; exports.IMAGE_CELLS = IMAGE_CELLS; exports.FILLER_CELLS = FILLER_CELLS; exports.CONT_PARTS = CONT_PARTS; exports.CELL_LINES = CELL_LINES; exports.trimTrailingEmptyTableCols = trimTrailingEmptyTableCols; exports.extractPageBlocksWithLines = extractPageBlocksWithLines;
4671
+ //# sourceMappingURL=chunk-USHQCF5T.cjs.map