kordoc 4.18.3 → 4.18.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 (145) hide show
  1. package/dist/{-WOKB25R2.js → -DDAVBMHD.js} +11 -11
  2. package/dist/{chunk-BGOR5GCF.js → chunk-274ZPMHK.js} +2 -2
  3. package/dist/{chunk-2ZBLQVAS.cjs → chunk-3WLZOJIE.cjs} +6 -6
  4. package/dist/chunk-3WLZOJIE.cjs.map +1 -0
  5. package/dist/{chunk-SHRRD2TD.cjs → chunk-3XSP7V5P.cjs} +2 -2
  6. package/dist/chunk-3XSP7V5P.cjs.map +1 -0
  7. package/dist/{chunk-6GLTGOP6.js → chunk-4IBY5LTJ.js} +2 -2
  8. package/dist/chunk-6H25SXDI.js +11 -0
  9. package/dist/chunk-6H25SXDI.js.map +1 -0
  10. package/dist/{chunk-CAN5P6N6.js → chunk-7GR2GCJF.js} +2 -2
  11. package/dist/{chunk-HZV52V2X.cjs → chunk-AVIZ55NQ.cjs} +3 -3
  12. package/dist/chunk-AVIZ55NQ.cjs.map +1 -0
  13. package/dist/chunk-DC6CTQTK.js +9 -0
  14. package/dist/chunk-DC6CTQTK.js.map +1 -0
  15. package/dist/{chunk-NES5U4JK.js → chunk-DUV7Y6IQ.js} +3 -3
  16. package/dist/{chunk-WN5YLP7H.cjs → chunk-E2644XCO.cjs} +693 -187
  17. package/dist/chunk-E2644XCO.cjs.map +1 -0
  18. package/dist/{chunk-3FZGL3IL.js → chunk-ELOPDQES.js} +2 -2
  19. package/dist/{chunk-2I2RTJJ5.js → chunk-F2GDLA45.js} +25 -35
  20. package/dist/chunk-F2GDLA45.js.map +1 -0
  21. package/dist/{chunk-VGDTONTB.js → chunk-F5YVCJVF.js} +2 -2
  22. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  23. package/dist/{chunk-RDBTOE5X.js → chunk-HRJJDNRD.js} +2 -2
  24. package/dist/{chunk-KSJ7GKNQ.js → chunk-IAXGGQGD.js} +2 -2
  25. package/dist/{chunk-IXX3WHIE.js → chunk-IBQCK4F3.js} +7 -3
  26. package/dist/chunk-IBQCK4F3.js.map +1 -0
  27. package/dist/chunk-J55UQC5H.cjs.map +1 -1
  28. package/dist/{chunk-J2A46VCA.js → chunk-KUUSP6OS.js} +576 -70
  29. package/dist/chunk-KUUSP6OS.js.map +1 -0
  30. package/dist/{chunk-RSDUH4XF.js → chunk-LGF2IO66.js} +2 -2
  31. package/dist/{chunk-BJ6RYYXV.js → chunk-MXA6YW2W.js} +577 -71
  32. package/dist/chunk-MXA6YW2W.js.map +1 -0
  33. package/dist/{chunk-ZD5WNQNC.cjs → chunk-OIUSF2VA.cjs} +16 -12
  34. package/dist/chunk-OIUSF2VA.cjs.map +1 -0
  35. package/dist/{chunk-AZQWESRH.js → chunk-QVCHFCT2.js} +2 -2
  36. package/dist/{chunk-W7P4GPOV.js → chunk-RCI7LY4N.js} +8 -4
  37. package/dist/chunk-RCI7LY4N.js.map +1 -0
  38. package/dist/{chunk-V4BKT65D.cjs → chunk-SVNBZEL6.cjs} +3 -3
  39. package/dist/chunk-SVNBZEL6.cjs.map +1 -0
  40. package/dist/{chunk-OOX2GZZ4.js → chunk-T2BJPT6D.js} +3 -3
  41. package/dist/{chunk-OOX2GZZ4.js.map → chunk-T2BJPT6D.js.map} +1 -1
  42. package/dist/chunk-TK3FDAEE.cjs +9 -0
  43. package/dist/chunk-TK3FDAEE.cjs.map +1 -0
  44. package/dist/{chunk-UVUKT3IQ.js → chunk-TMJVD6FW.js} +2 -2
  45. package/dist/{chunk-ZN3LHNJG.js → chunk-V5X4LLVM.js} +28 -27
  46. package/dist/chunk-V5X4LLVM.js.map +1 -0
  47. package/dist/{chunk-W3RADOLO.js → chunk-VTVK2JMI.js} +2 -2
  48. package/dist/{chunk-PSJLB3SZ.js → chunk-XG4SYOZL.js} +2 -2
  49. package/dist/{chunk-RRURZDEK.js → chunk-YCY2R4FM.js} +2 -2
  50. package/dist/{chunk-5X7XWYR2.js → chunk-Z2PPDQK2.js} +2 -2
  51. package/dist/chunks-5QTTAT5T.js +10 -0
  52. package/dist/cli.js +154 -115
  53. package/dist/cli.js.map +1 -1
  54. package/dist/{formula-QZAOKPBX.js → formula-7ZOZ5QJ6.js} +8 -4
  55. package/dist/{formula-QZAOKPBX.js.map → formula-7ZOZ5QJ6.js.map} +1 -1
  56. package/dist/{formula-GPCOJJXN.js → formula-HQFZEXFF.js} +7 -3
  57. package/dist/{formula-GPCOJJXN.js.map → formula-HQFZEXFF.js.map} +1 -1
  58. package/dist/{formula-BQ5RW5XD.cjs → formula-YYJQBKEN.cjs} +13 -9
  59. package/dist/formula-YYJQBKEN.cjs.map +1 -0
  60. package/dist/{image-ocr-POCME5I4.js → image-ocr-4BGX2EJJ.js} +7 -6
  61. package/dist/{image-ocr-POCME5I4.js.map → image-ocr-4BGX2EJJ.js.map} +1 -1
  62. package/dist/{image-ocr-VKIUBLBX.cjs → image-ocr-CC26Q5KG.cjs} +16 -15
  63. package/dist/image-ocr-CC26Q5KG.cjs.map +1 -0
  64. package/dist/{image-ocr-TWNNVTZS.js → image-ocr-RK3HJVCI.js} +10 -9
  65. package/dist/{image-ocr-TWNNVTZS.js.map → image-ocr-RK3HJVCI.js.map} +1 -1
  66. package/dist/index.cjs +338 -347
  67. package/dist/index.cjs.map +1 -1
  68. package/dist/index.js +42 -51
  69. package/dist/index.js.map +1 -1
  70. package/dist/mcp.js +22 -22
  71. package/dist/{model-bundle-THYUL7GG.js → model-bundle-VHRXG63R.js} +5 -5
  72. package/dist/{models-U22N4RXX.js → models-G3WA24SY.js} +5 -5
  73. package/dist/page-range-QHHFTL7X.cjs.map +1 -1
  74. package/dist/{parser-JOMFOZLH.cjs → parser-BGORCLIU.cjs} +449 -244
  75. package/dist/parser-BGORCLIU.cjs.map +1 -0
  76. package/dist/{parser-SCXRLOW7.js → parser-GFDGAVLV.js} +242 -37
  77. package/dist/parser-GFDGAVLV.js.map +1 -0
  78. package/dist/{parser-NKP2NCSV.js → parser-SOWTUOMK.js} +245 -40
  79. package/dist/parser-SOWTUOMK.js.map +1 -0
  80. package/dist/pdf-ocr-7IOOVR2I.js +20 -0
  81. package/dist/pdf-ocr-EJ2HNZN6.cjs +17 -0
  82. package/dist/pdf-ocr-EJ2HNZN6.cjs.map +1 -0
  83. package/dist/pdf-ocr-RACAZU3N.js +16 -0
  84. package/dist/{profile-io-UI3TZBYH.js → profile-io-Q2T47RVH.js} +3 -3
  85. package/dist/{rasterize-XMBV5H2I.js → rasterize-OAVMUTE6.js} +3 -3
  86. package/dist/{redact-doc-7ZZMHDBO.js → redact-doc-ECFOVR4X.js} +11 -11
  87. package/dist/{render-SWRTUDAV.js → render-NSKWZVTD.js} +7 -7
  88. package/dist/seal-A4MG7MPQ.js +10 -0
  89. package/dist/{setup-43JJEEU7.js → setup-REH2KZP2.js} +3 -3
  90. package/dist/visual-B56WQAGW.js +20 -0
  91. package/dist/{watch-NRATQ472.js → watch-JXDUZYBY.js} +12 -12
  92. package/package.json +1 -1
  93. package/dist/chunk-2I2RTJJ5.js.map +0 -1
  94. package/dist/chunk-2ZBLQVAS.cjs.map +0 -1
  95. package/dist/chunk-BJ6RYYXV.js.map +0 -1
  96. package/dist/chunk-HZV52V2X.cjs.map +0 -1
  97. package/dist/chunk-IXX3WHIE.js.map +0 -1
  98. package/dist/chunk-J2A46VCA.js.map +0 -1
  99. package/dist/chunk-SHRRD2TD.cjs.map +0 -1
  100. package/dist/chunk-V4BKT65D.cjs.map +0 -1
  101. package/dist/chunk-W7P4GPOV.js.map +0 -1
  102. package/dist/chunk-WN5YLP7H.cjs.map +0 -1
  103. package/dist/chunk-ZD5WNQNC.cjs.map +0 -1
  104. package/dist/chunk-ZN3LHNJG.js.map +0 -1
  105. package/dist/chunks-OQDRDICD.js +0 -10
  106. package/dist/formula-BQ5RW5XD.cjs.map +0 -1
  107. package/dist/image-ocr-VKIUBLBX.cjs.map +0 -1
  108. package/dist/parser-JOMFOZLH.cjs.map +0 -1
  109. package/dist/parser-NKP2NCSV.js.map +0 -1
  110. package/dist/parser-SCXRLOW7.js.map +0 -1
  111. package/dist/pdf-ocr-NF4AY5MI.cjs +0 -16
  112. package/dist/pdf-ocr-NF4AY5MI.cjs.map +0 -1
  113. package/dist/pdf-ocr-OLII3WAG.js +0 -15
  114. package/dist/pdf-ocr-VJL7ON2Q.js +0 -19
  115. package/dist/seal-UKKJZHKE.js +0 -10
  116. package/dist/visual-D2563HCJ.js +0 -20
  117. /package/dist/{-WOKB25R2.js.map → -DDAVBMHD.js.map} +0 -0
  118. /package/dist/{chunk-BGOR5GCF.js.map → chunk-274ZPMHK.js.map} +0 -0
  119. /package/dist/{chunk-6GLTGOP6.js.map → chunk-4IBY5LTJ.js.map} +0 -0
  120. /package/dist/{chunk-CAN5P6N6.js.map → chunk-7GR2GCJF.js.map} +0 -0
  121. /package/dist/{chunk-NES5U4JK.js.map → chunk-DUV7Y6IQ.js.map} +0 -0
  122. /package/dist/{chunk-3FZGL3IL.js.map → chunk-ELOPDQES.js.map} +0 -0
  123. /package/dist/{chunk-VGDTONTB.js.map → chunk-F5YVCJVF.js.map} +0 -0
  124. /package/dist/{chunk-RDBTOE5X.js.map → chunk-HRJJDNRD.js.map} +0 -0
  125. /package/dist/{chunk-KSJ7GKNQ.js.map → chunk-IAXGGQGD.js.map} +0 -0
  126. /package/dist/{chunk-RSDUH4XF.js.map → chunk-LGF2IO66.js.map} +0 -0
  127. /package/dist/{chunk-AZQWESRH.js.map → chunk-QVCHFCT2.js.map} +0 -0
  128. /package/dist/{chunk-UVUKT3IQ.js.map → chunk-TMJVD6FW.js.map} +0 -0
  129. /package/dist/{chunk-W3RADOLO.js.map → chunk-VTVK2JMI.js.map} +0 -0
  130. /package/dist/{chunk-PSJLB3SZ.js.map → chunk-XG4SYOZL.js.map} +0 -0
  131. /package/dist/{chunk-RRURZDEK.js.map → chunk-YCY2R4FM.js.map} +0 -0
  132. /package/dist/{chunk-5X7XWYR2.js.map → chunk-Z2PPDQK2.js.map} +0 -0
  133. /package/dist/{chunks-OQDRDICD.js.map → chunks-5QTTAT5T.js.map} +0 -0
  134. /package/dist/{model-bundle-THYUL7GG.js.map → model-bundle-VHRXG63R.js.map} +0 -0
  135. /package/dist/{models-U22N4RXX.js.map → models-G3WA24SY.js.map} +0 -0
  136. /package/dist/{pdf-ocr-OLII3WAG.js.map → pdf-ocr-7IOOVR2I.js.map} +0 -0
  137. /package/dist/{pdf-ocr-VJL7ON2Q.js.map → pdf-ocr-RACAZU3N.js.map} +0 -0
  138. /package/dist/{profile-io-UI3TZBYH.js.map → profile-io-Q2T47RVH.js.map} +0 -0
  139. /package/dist/{rasterize-XMBV5H2I.js.map → rasterize-OAVMUTE6.js.map} +0 -0
  140. /package/dist/{redact-doc-7ZZMHDBO.js.map → redact-doc-ECFOVR4X.js.map} +0 -0
  141. /package/dist/{render-SWRTUDAV.js.map → render-NSKWZVTD.js.map} +0 -0
  142. /package/dist/{seal-UKKJZHKE.js.map → seal-A4MG7MPQ.js.map} +0 -0
  143. /package/dist/{setup-43JJEEU7.js.map → setup-REH2KZP2.js.map} +0 -0
  144. /package/dist/{visual-D2563HCJ.js.map → visual-B56WQAGW.js.map} +0 -0
  145. /package/dist/{watch-NRATQ472.js.map → watch-JXDUZYBY.js.map} +0 -0
@@ -4,15 +4,15 @@ import {
4
4
  HEADING_RATIO_H2,
5
5
  HEADING_RATIO_H3,
6
6
  tidyScriptTags
7
- } from "./chunk-PSJLB3SZ.js";
7
+ } from "./chunk-XG4SYOZL.js";
8
8
  import {
9
9
  ensureModelsIn,
10
10
  getModelsDir
11
- } from "./chunk-3FZGL3IL.js";
11
+ } from "./chunk-ELOPDQES.js";
12
12
  import {
13
13
  safeMax,
14
14
  safeMin
15
- } from "./chunk-CAN5P6N6.js";
15
+ } from "./chunk-7GR2GCJF.js";
16
16
 
17
17
  // src/ocr/models.ts
18
18
  import { join } from "path";
@@ -488,13 +488,13 @@ function classifyAndAdd(seg, lineWidth, horizontals, verticals, fromFill = false
488
488
  verticals.push({ x1: x, y1, x2: x, y2, lineWidth, fromFill });
489
489
  }
490
490
  }
491
- function preprocessLines(horizontals, verticals) {
491
+ function preprocessLines(horizontals, verticals, nonRules) {
492
492
  let h = horizontals.filter((l) => l.lineWidth <= MAX_LINE_WIDTH);
493
493
  let v = verticals.filter((l) => l.lineWidth <= MAX_LINE_WIDTH);
494
494
  h = dropShadingStacks(h, "h");
495
495
  v = dropShadingStacks(v, "v");
496
- h = mergeParallelLines(h, "h");
497
- v = mergeParallelLines(v, "v");
496
+ h = mergeParallelLines(h, "h", nonRules);
497
+ v = mergeParallelLines(v, "v", nonRules);
498
498
  return { horizontals: h, verticals: v };
499
499
  }
500
500
  var STACK_GAP = 2;
@@ -654,15 +654,15 @@ function closeOpenTableEdges(horizontals, verticals) {
654
654
  const hasInterior = verticals.some((v) => v.x1 > x1 + EDGE_INSET && v.x1 < x2 - EDGE_INSET && crossCount(v) >= 2);
655
655
  if (!hasInterior) continue;
656
656
  for (const edgeX of [x1, x2]) {
657
- const closed = verticals.some((v) => Math.abs(v.x1 - edgeX) <= EDGE_NEAR && v.y1 <= yMax + EDGE_CONNECT_TOL && v.y2 >= yMin - EDGE_CONNECT_TOL);
658
- if (!closed) {
657
+ const closed2 = verticals.some((v) => Math.abs(v.x1 - edgeX) <= EDGE_NEAR && v.y1 <= yMax + EDGE_CONNECT_TOL && v.y2 >= yMin - EDGE_CONNECT_TOL);
658
+ if (!closed2) {
659
659
  synthesized.push({ x1: edgeX, y1: yMin, x2: edgeX, y2: yMax, lineWidth: 0.5 });
660
660
  }
661
661
  }
662
662
  }
663
663
  return synthesized.length ? [...verticals, ...synthesized] : verticals;
664
664
  }
665
- function mergeParallelLines(lines, dir) {
665
+ function mergeParallelLines(lines, dir, nonRules) {
666
666
  if (lines.length <= 1) return lines;
667
667
  const sorted = [...lines].sort((a, b) => {
668
668
  const posA = dir === "h" ? a.y1 : a.x1;
@@ -685,6 +685,7 @@ function mergeParallelLines(lines, dir) {
685
685
  const overlap2 = Math.min(prevEnd, currEnd) - Math.max(prevStart, currStart);
686
686
  const minLen = Math.min(prevEnd - prevStart, currEnd - currStart);
687
687
  if (overlap2 > minLen * 0.3) {
688
+ if (nonRules?.has(prev) && !nonRules.has(curr)) nonRules.delete(prev);
688
689
  if (dir === "h") {
689
690
  prev.x1 = Math.min(prev.x1, curr.x1);
690
691
  prev.x2 = Math.max(prev.x2, curr.x2);
@@ -4197,7 +4198,12 @@ function detectSpecialKoreanTables(blocks) {
4197
4198
  flushKvTable();
4198
4199
  return result;
4199
4200
  }
4200
- function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables = false) {
4201
+ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables = false, context = []) {
4202
+ if (context.length && !tables) {
4203
+ const removed = removeHeaderFooterBlocks([...blocks, ...context], pageHeights, [], notes).filter((index) => index < blocks.length);
4204
+ if (removed.length) warnings.push({ message: `${removed.length}\uAC1C \uBA38\uB9AC\uAE00/\uBC14\uB2E5\uAE00 \uC694\uC18C \uC81C\uAC70\uB428`, code: "HIDDEN_TEXT_FILTERED" });
4205
+ return removed;
4206
+ }
4201
4207
  const ZONE_RATIO = 0.12;
4202
4208
  const MIN_REPEAT2 = 3;
4203
4209
  const topEntries = [];
@@ -4277,6 +4283,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
4277
4283
 
4278
4284
  // src/pdf/table-meta.ts
4279
4285
  var CLIP_TABLES = /* @__PURE__ */ new WeakSet();
4286
+ var FRAME_TITLE_BLOCKS = /* @__PURE__ */ new WeakMap();
4280
4287
  var TABLE_COLXS = /* @__PURE__ */ new WeakMap();
4281
4288
  var TABLE_ROWYS = /* @__PURE__ */ new WeakMap();
4282
4289
  var TABLE_TAIL = /* @__PURE__ */ new WeakMap();
@@ -4384,6 +4391,262 @@ function mergeSliverColumns(grid, colXs, maxWidth) {
4384
4391
  return merged;
4385
4392
  }
4386
4393
 
4394
+ // src/pdf/image-bullets.ts
4395
+ import { OPS as OPS3, ImageKind } from "pdfjs-dist/legacy/build/pdf.mjs";
4396
+ var multiply = (m, t) => [
4397
+ m[0] * t[0] + m[2] * t[1],
4398
+ m[1] * t[0] + m[3] * t[1],
4399
+ m[0] * t[2] + m[2] * t[3],
4400
+ m[1] * t[2] + m[3] * t[3],
4401
+ m[0] * t[4] + m[2] * t[5] + m[4],
4402
+ m[1] * t[4] + m[3] * t[5] + m[5]
4403
+ ];
4404
+ function hollowCircle(image) {
4405
+ if (!image?.data || image.width < 16 || image.width > 128 || image.height < 16 || image.height > 128 || Math.abs(image.width - image.height) > Math.min(image.width, image.height) * 0.1) return false;
4406
+ const stride = image.kind === ImageKind.RGB_24BPP ? 3 : image.kind === ImageKind.RGBA_32BPP ? 4 : 0;
4407
+ const { width, height, data } = image;
4408
+ if (!stride || data.length < width * height * stride) return false;
4409
+ const dark = [];
4410
+ let white = 0;
4411
+ for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
4412
+ const i = (y * width + x) * stride;
4413
+ if (stride === 4 && data[i + 3] < 240) return false;
4414
+ const min = Math.min(data[i], data[i + 1], data[i + 2]), max = Math.max(data[i], data[i + 1], data[i + 2]);
4415
+ if (max - min > 15) return false;
4416
+ if (min >= 235) white++;
4417
+ if (max < 180) dark.push({ x, y });
4418
+ }
4419
+ if (white < width * height * 0.65 || dark.length < width * height * 0.025 || dark.length > width * height * 0.3) return false;
4420
+ const x0 = Math.min(...dark.map((p) => p.x)), x1 = Math.max(...dark.map((p) => p.x));
4421
+ const y0 = Math.min(...dark.map((p) => p.y)), y1 = Math.max(...dark.map((p) => p.y));
4422
+ const w = x1 - x0 + 1, h = y1 - y0 + 1, radius = (w + h) / 4;
4423
+ const cx = (x0 + x1) / 2, cy = (y0 + y1) / 2;
4424
+ if (Math.abs(w - h) > Math.min(w, h) * 0.15 || w < width * 0.4 || w > width * 0.85 || h < height * 0.4 || h > height * 0.85 || x0 < width * 0.04 || y0 < height * 0.04 || x1 >= width * 0.96 || y1 >= height * 0.96 || Math.abs(cx - width / 2) > width * 0.15 || Math.abs(cy - height / 2) > height * 0.15) return false;
4425
+ const sectors = /* @__PURE__ */ new Set();
4426
+ for (const point of dark) {
4427
+ const r = Math.hypot(point.x - cx, point.y - cy) / radius;
4428
+ if (r < 0.65 || r > 1.15) return false;
4429
+ sectors.add(Math.floor((Math.atan2(point.y - cy, point.x - cx) + Math.PI) / (Math.PI * 2) * 8) % 8);
4430
+ }
4431
+ return sectors.size === 8;
4432
+ }
4433
+ async function resolveImagePixels(page, id) {
4434
+ const objects = id.startsWith("g_") ? page.commonObjs : page.objs;
4435
+ return new Promise((resolve) => {
4436
+ const timer = setTimeout(() => resolve(null), 5e3);
4437
+ try {
4438
+ objects.get(id, (value) => {
4439
+ clearTimeout(timer);
4440
+ resolve(value ?? null);
4441
+ });
4442
+ } catch {
4443
+ clearTimeout(timer);
4444
+ resolve(null);
4445
+ }
4446
+ });
4447
+ }
4448
+ function smallVisibleImagePaints(fnArray, argsArray) {
4449
+ const paints = [];
4450
+ let ctm = [1, 0, 0, 1, 0, 0];
4451
+ let alpha = 1, clip = null, unknownClip = false;
4452
+ const stack = [];
4453
+ let pathRect, pendingClip = false;
4454
+ const intersectClip = (box) => {
4455
+ clip = clip ? {
4456
+ x1: Math.max(clip.x1, box.x1),
4457
+ y1: Math.max(clip.y1, box.y1),
4458
+ x2: Math.min(clip.x2, box.x2),
4459
+ y2: Math.min(clip.y2, box.y2)
4460
+ } : box;
4461
+ };
4462
+ const rectangle = (x, y, w, h) => extractImageRegions(
4463
+ [OPS3.transform, OPS3.transform, OPS3.paintImageXObject],
4464
+ [ctm, [w, 0, 0, h, x, y], ["bounds"]]
4465
+ )[0];
4466
+ for (let i = 0; i < fnArray.length; i++) {
4467
+ const op = fnArray[i], args = argsArray[i];
4468
+ if (op === OPS3.save || op === OPS3.paintFormXObjectBegin) {
4469
+ stack.push({ ctm, alpha, clip, unknownClip });
4470
+ const matrix = op === OPS3.paintFormXObjectBegin ? args?.[0] : void 0;
4471
+ if (Array.isArray(matrix) && matrix.length >= 6) ctm = multiply(ctm, matrix);
4472
+ const bounds = op === OPS3.paintFormXObjectBegin ? args?.[1] : void 0;
4473
+ if (Array.isArray(bounds) && bounds.length === 4) {
4474
+ const box = rectangle(bounds[0], bounds[1], bounds[2] - bounds[0], bounds[3] - bounds[1]);
4475
+ if (box && ctm[1] === 0 && ctm[2] === 0) intersectClip(box);
4476
+ else unknownClip = true;
4477
+ }
4478
+ } else if (op === OPS3.restore || op === OPS3.paintFormXObjectEnd) {
4479
+ const state = stack.pop();
4480
+ ctm = state?.ctm ?? [1, 0, 0, 1, 0, 0];
4481
+ alpha = state?.alpha ?? 1;
4482
+ clip = state?.clip ?? null;
4483
+ unknownClip = state?.unknownClip ?? false;
4484
+ } else if (op === OPS3.setGState) {
4485
+ for (const [key, value] of args?.[0] ?? []) {
4486
+ if (key === "ca") alpha = typeof value === "number" ? value : 0;
4487
+ }
4488
+ } else if (op === OPS3.constructPath) {
4489
+ const [operations, coordinates] = args;
4490
+ pathRect = pathRect === void 0 && operations?.length === 1 && operations[0] === OPS3.rectangle && coordinates?.length >= 4 && ctm[1] === 0 && ctm[2] === 0 ? rectangle(coordinates[0], coordinates[1], coordinates[2], coordinates[3]) : null;
4491
+ } else if (op === OPS3.clip || op === OPS3.eoClip) pendingClip = true;
4492
+ else if ([
4493
+ OPS3.endPath,
4494
+ OPS3.stroke,
4495
+ OPS3.closeStroke,
4496
+ OPS3.fill,
4497
+ OPS3.eoFill,
4498
+ OPS3.fillStroke,
4499
+ OPS3.eoFillStroke,
4500
+ OPS3.closeFillStroke,
4501
+ OPS3.closeEOFillStroke
4502
+ ].includes(op)) {
4503
+ if (pendingClip) {
4504
+ if (pathRect) intersectClip(pathRect);
4505
+ else unknownClip = true;
4506
+ }
4507
+ pendingClip = false;
4508
+ pathRect = void 0;
4509
+ } else if (op === OPS3.transform && Array.isArray(args) && args.length >= 6) ctm = multiply(ctm, args);
4510
+ else if (op === OPS3.paintImageXObject && typeof args?.[0] === "string") {
4511
+ if (typeof args[1] !== "number" || typeof args[2] !== "number" || args[1] < 16 || args[1] > 128 || args[2] < 16 || args[2] > 128) continue;
4512
+ const box = extractImageRegions([OPS3.transform, OPS3.paintImageXObject], [ctm, args])[0];
4513
+ if (!box || ctm[1] !== 0 || ctm[2] !== 0 || alpha < 0.99 || unknownClip || clip && (box.x1 + (box.x2 - box.x1) * 0.03 < clip.x1 || box.y1 + (box.y2 - box.y1) * 0.03 < clip.y1 || box.x2 - (box.x2 - box.x1) * 0.03 > clip.x2 || box.y2 - (box.y2 - box.y1) * 0.03 > clip.y2)) continue;
4514
+ const width = box.x2 - box.x1, height = box.y2 - box.y1;
4515
+ if (width < 3 || width > 24 || height < 3 || height > 24 || width / height < 0.5 || width / height > 2) continue;
4516
+ paints.push({ id: args[0], box, mirrored: ctm[0] < 0 });
4517
+ }
4518
+ }
4519
+ return paints;
4520
+ }
4521
+ async function restoreImageBullets(items, page, fnArray, argsArray, shapes = /* @__PURE__ */ new Map()) {
4522
+ const candidates = [];
4523
+ for (const { id, box } of smallVisibleImagePaints(fnArray, argsArray)) {
4524
+ const width = box.x2 - box.x1, height = box.y2 - box.y1;
4525
+ if (Math.abs(width - height) > Math.min(width, height) * 0.1) continue;
4526
+ const line = items.filter((item) => !item.isHidden && item.fontSize > 0 && item.x >= box.x2 && item.x - box.x2 <= item.fontSize * 0.7 && Math.abs(item.y + item.h / 2 - (box.y1 + box.y2) / 2) <= item.fontSize * 0.4 && height >= item.fontSize * 0.5 && height <= item.fontSize * 1.2).sort((a, b) => a.x - b.x)[0];
4527
+ if (!line || /^[○●•◦□■∙]/.test(line.text.trim()) || !/\p{L}/u.test(line.text)) continue;
4528
+ const row = items.filter((item) => Math.abs(item.y - line.y) <= 2 && item.x >= line.x);
4529
+ if (row.reduce((n, item) => n + (item.text.match(/\p{L}/gu)?.length ?? 0), 0) < 12 || items.some((item) => item !== line && Math.abs(item.y - line.y) <= 2 && item.x < line.x)) continue;
4530
+ candidates.push({ id, x: box.x1, width, line });
4531
+ }
4532
+ let restored = 0;
4533
+ const used = /* @__PURE__ */ new Set();
4534
+ for (const candidate of candidates) {
4535
+ const same = candidates.filter((other) => other.id === candidate.id && other.line !== candidate.line && Math.abs(other.line.x - candidate.line.x) <= 1 && Math.abs(other.x - candidate.x) <= 1 && Math.abs(other.width - candidate.width) <= 1 && other.line.fontSize === candidate.line.fontSize && Math.abs(other.line.y - candidate.line.y) >= candidate.line.fontSize * 2);
4536
+ const numbered = items.filter((item) => !item.isHidden && /^[①-⑮]\s*/.test(item.text.trim()) && item.fontName === candidate.line.fontName && item.fontSize === candidate.line.fontSize && Math.abs(item.x - candidate.x) <= 1 && (item.text.match(/\p{L}/gu)?.length ?? 0) >= 12).sort((a, b) => b.y - a.y);
4537
+ const numberedList = numbered.some((item, index) => index > 0 && item.text.trim().charCodeAt(0) === numbered[index - 1].text.trim().charCodeAt(0) + 1);
4538
+ if (!same.length && !numberedList || used.has(candidate.line)) continue;
4539
+ if (!shapes.has(candidate.id)) shapes.set(candidate.id, hollowCircle(await resolveImagePixels(page, candidate.id)));
4540
+ if (!shapes.get(candidate.id)) continue;
4541
+ used.add(candidate.line);
4542
+ items.push({ ...candidate.line, text: "\u25CB", x: candidate.x, w: candidate.width, strike: false, underline: false, hasSpaceBefore: false, syntheticSpace: false });
4543
+ restored++;
4544
+ }
4545
+ return restored;
4546
+ }
4547
+
4548
+ // src/pdf/flow-boxes.ts
4549
+ import { ImageKind as ImageKind2 } from "pdfjs-dist/legacy/build/pdf.mjs";
4550
+ var contains2 = (outer, inner, tolerance = 1) => inner.x1 >= outer.x1 - tolerance && inner.x2 <= outer.x2 + tolerance && inner.y1 >= outer.y1 - tolerance && inner.y2 <= outer.y2 + tolerance;
4551
+ function closed(grid, hs, vs) {
4552
+ const b = grid.bbox;
4553
+ return [b.y1, b.y2].every((y) => hs.some((h) => Math.abs(h.y1 - y) <= 1 && h.x1 <= b.x1 + 1 && h.x2 >= b.x2 - 1)) && [b.x1, b.x2].every((x) => vs.some((v) => Math.abs(v.x1 - x) <= 1 && v.y1 <= b.y1 + 1 && v.y2 >= b.y2 - 1));
4554
+ }
4555
+ function groupFlowBoxUnits(blocks, grids, hs, vs, images) {
4556
+ const candidates = grids.filter((g) => g.bbox.y2 - g.bbox.y1 >= 30 && closed(g, hs, vs) && !grids.some((other) => other !== g && contains2(other.bbox, g.bbox, 0) && (other.bbox.x2 - other.bbox.x1) * (other.bbox.y2 - other.bbox.y1) > (g.bbox.x2 - g.bbox.x1) * (g.bbox.y2 - g.bbox.y1) + 1));
4557
+ const bands = [], visited = /* @__PURE__ */ new Set();
4558
+ for (const first of candidates) {
4559
+ if (visited.has(first)) continue;
4560
+ const row = candidates.filter((g) => Math.abs(g.bbox.y1 - first.bbox.y1) <= 1 && Math.abs(g.bbox.y2 - first.bbox.y2) <= 1).sort((a, b) => a.bbox.x1 - b.bbox.x1);
4561
+ row.forEach((g) => visited.add(g));
4562
+ if (row.length < 4 || row.filter((g) => g.rowYs.length === 2 && g.colXs.length === 2).length < 3) continue;
4563
+ const connectors = [];
4564
+ for (let i = 1; i < row.length; i++) {
4565
+ const left = row[i - 1].bbox, right = row[i].bbox, gap = right.x1 - left.x2;
4566
+ if (gap < 4 || gap > Math.min(left.x2 - left.x1, right.x2 - right.x1) * 0.6) break;
4567
+ const centerX = (left.x2 + right.x1) / 2, centerY = (left.y1 + left.y2) / 2;
4568
+ const connector = images.find((p) => {
4569
+ const w = p.x2 - p.x1, h = p.y2 - p.y1;
4570
+ return p.x1 >= left.x2 && p.x2 <= right.x1 && w >= gap * 0.4 && w <= gap * 0.9 && h >= 3 && h <= (left.y2 - left.y1) * 0.2 && w / h >= 0.8 && w / h <= 1.6 && Math.abs((p.x1 + p.x2) / 2 - centerX) <= gap * 0.15 && Math.abs((p.y1 + p.y2) / 2 - centerY) <= (left.y2 - left.y1) * 0.1;
4571
+ });
4572
+ if (!connector) break;
4573
+ connectors.push(connector);
4574
+ }
4575
+ if (connectors.length !== row.length - 1 || connectors.some((p) => Math.abs(p.x2 - p.x1 - (connectors[0].x2 - connectors[0].x1)) > (connectors[0].x2 - connectors[0].x1) * 0.2 || Math.abs(p.y2 - p.y1 - (connectors[0].y2 - connectors[0].y1)) > (connectors[0].y2 - connectors[0].y1) * 0.2)) continue;
4576
+ bands.push(row);
4577
+ }
4578
+ const members = /* @__PURE__ */ new Map();
4579
+ for (const band of bands) {
4580
+ const columns = band.map((g) => blocks.filter((b) => b.bbox && contains2(g.bbox, {
4581
+ x1: b.bbox.x,
4582
+ y1: b.bbox.y,
4583
+ x2: b.bbox.x + b.bbox.width,
4584
+ y2: b.bbox.y + b.bbox.height
4585
+ })).sort((a, b) => b.bbox.y + b.bbox.height - a.bbox.y - a.bbox.height || a.bbox.x - b.bbox.x));
4586
+ if (columns.some((column) => !column.length)) continue;
4587
+ const unit = columns.flat();
4588
+ for (const block of unit) members.set(block, unit);
4589
+ }
4590
+ const units = [], emitted = /* @__PURE__ */ new Set();
4591
+ for (const block of blocks) {
4592
+ const unit = members.get(block);
4593
+ if (!unit) units.push([block]);
4594
+ else if (!emitted.has(unit)) {
4595
+ units.push(unit);
4596
+ emitted.add(unit);
4597
+ }
4598
+ }
4599
+ return units;
4600
+ }
4601
+ function arrowDirection(image) {
4602
+ if (!image?.data || image.width < 16 || image.width > 128 || image.height < 16 || image.height > 128) return 0;
4603
+ const { width, height, data } = image;
4604
+ const stride = image.kind === ImageKind2.RGB_24BPP ? 3 : image.kind === ImageKind2.RGBA_32BPP ? 4 : 0;
4605
+ if (!stride || data.length < width * height * stride) return 0;
4606
+ const ink = [];
4607
+ let white = 0;
4608
+ for (let y = 0; y < height; y++) for (let x = 0; x < width; x++) {
4609
+ const offset = (y * width + x) * stride;
4610
+ if (stride === 4 && data[offset + 3] < 240) return 0;
4611
+ const min = Math.min(data[offset], data[offset + 1], data[offset + 2]);
4612
+ if (min >= 235) white++;
4613
+ if (min < 230) ink.push({ x, y });
4614
+ }
4615
+ if (white < width * height * 0.55 || !ink.length) return 0;
4616
+ const x0 = Math.min(...ink.map((p) => p.x)), x1 = Math.max(...ink.map((p) => p.x));
4617
+ const y0 = Math.min(...ink.map((p) => p.y)), y1 = Math.max(...ink.map((p) => p.y));
4618
+ const w = x1 - x0 + 1, h = y1 - y0 + 1, centerY = (y0 + y1) / 2;
4619
+ if (w < width * 0.5 || h < height * 0.5 || x0 < width * 0.04 || y0 < height * 0.04 || x1 >= width * 0.96 || y1 >= height * 0.96) return 0;
4620
+ const pointsRight = (mirror) => {
4621
+ const points = ink.map((p) => ({ x: mirror ? x0 + x1 - p.x : p.x, y: p.y }));
4622
+ const tail = points.filter((p) => p.x <= x0 + w * 0.25), tip = points.filter((p) => p.x >= x1 - w * 0.1);
4623
+ if (!tail.length || !tip.length) return false;
4624
+ const span = (points2) => Math.max(...points2.map((p) => p.y)) - Math.min(...points2.map((p) => p.y)) + 1;
4625
+ if (span(tail) > h * 0.4 || span(tip) > h * 0.45 || Math.abs((Math.max(...tail.map((p) => p.y)) + Math.min(...tail.map((p) => p.y))) / 2 - centerY) > h * 0.1 || Math.abs((Math.max(...tip.map((p) => p.y)) + Math.min(...tip.map((p) => p.y))) / 2 - centerY) > h * 0.1) return false;
4626
+ let head = 0;
4627
+ for (let x = Math.ceil(x0 + w * 0.45); x <= x0 + w * 0.75; x++) {
4628
+ const column = points.filter((p) => p.x === x);
4629
+ if (column.length) head = Math.max(head, span(column));
4630
+ }
4631
+ const middle = new Set(points.filter((p) => Math.abs(p.y - centerY) <= 1).map((p) => p.x));
4632
+ return head >= h * 0.8 && middle.size >= w * 0.9;
4633
+ };
4634
+ return pointsRight(false) ? 1 : pointsRight(true) ? -1 : 0;
4635
+ }
4636
+ async function detectRightArrowRegions(page, fnArray, argsArray, directions = /* @__PURE__ */ new Map()) {
4637
+ const regions = [];
4638
+ const paints = smallVisibleImagePaints(fnArray, argsArray);
4639
+ for (const paint of paints) {
4640
+ const row = paints.filter((other) => other.id === paint.id && Math.abs(other.box.y1 - paint.box.y1) <= 1 && Math.abs(other.box.y2 - paint.box.y2) <= 1 && Math.abs(other.box.x2 - other.box.x1 - (paint.box.x2 - paint.box.x1)) <= 1);
4641
+ const positions = new Set(row.map((other) => Math.round(other.box.x1)));
4642
+ if (positions.size < 3) continue;
4643
+ if (!directions.has(paint.id)) directions.set(paint.id, arrowDirection(await resolveImagePixels(page, paint.id)));
4644
+ const direction = directions.get(paint.id) ?? 0;
4645
+ if (direction && (paint.mirrored ? -direction : direction) === 1) regions.push(paint.box);
4646
+ }
4647
+ return regions;
4648
+ }
4649
+
4387
4650
  // src/pdf/side-tabs.ts
4388
4651
  var BAND = 0.12;
4389
4652
  var MAX_CHARS = 10;
@@ -4398,7 +4661,8 @@ function isSideTabTable(box, table, others, pageWidth, pageHeight) {
4398
4661
  if (!side) return false;
4399
4662
  const texts = table.cells.flat().map((c) => c.text.replace(/\s+/g, ""));
4400
4663
  if (!texts.some(Boolean) || texts.some((t) => [...t].length > TAB_CELL_CHARS)) return false;
4401
- return others.every((it) => it.y < box.y1 || it.y > box.y2 || (side === "R" ? it.x + it.w <= box.x1 + 1 : it.x >= box.x2 - 1));
4664
+ const overlap2 = others.filter((it) => it.y >= box.y1 && it.y <= box.y2);
4665
+ return overlap2.length > 0 && overlap2.every((it) => side === "R" ? it.x + it.w <= box.x1 + 1 : it.x >= box.x2 - 1);
4402
4666
  }
4403
4667
  function removeSideTabs(blocks, pageWidths) {
4404
4668
  const edges = /* @__PURE__ */ new Map();
@@ -4427,7 +4691,7 @@ function removeSideTabs(blocks, pageWidths) {
4427
4691
  }
4428
4692
  if (!w || !area || !b.bbox || !text || [...text].length > MAX_CHARS) return null;
4429
4693
  const side = b.bbox.x + b.bbox.width <= Math.min(w * BAND, area.left - 1) ? "L" : b.bbox.x >= Math.max(w * (1 - BAND), area.right + 1) ? "R" : null;
4430
- return side && text.replace(/\s+/g, "");
4694
+ return side && `${side}\0${text.replace(/\s+/g, "")}`;
4431
4695
  };
4432
4696
  const pages = /* @__PURE__ */ new Map();
4433
4697
  for (const b of blocks) {
@@ -4634,15 +4898,39 @@ function sideTabGlyphs(items) {
4634
4898
  if (c) c.push(it);
4635
4899
  else cols.push([it]);
4636
4900
  }
4901
+ const cands = [];
4637
4902
  for (const col of cols) {
4638
- if (col.length < SIDE_TAB_MIN) continue;
4903
+ if (col.length < 2) continue;
4639
4904
  if (col.filter((g) => /[\p{L}\p{N}]/u.test(g.text)).length < col.length * 0.8) continue;
4640
4905
  col.sort((a, b) => b.y - a.y);
4641
4906
  const fs = [...col.map((i) => i.fontSize)].sort((a, b) => a - b)[col.length >> 1];
4642
4907
  if (col.slice(1).some((it, k) => col[k].y - it.y > fs * 3)) continue;
4908
+ cands.push({ col, fs });
4909
+ }
4910
+ const bands = [];
4911
+ for (const c of cands.sort((a, b) => a.col[0].x - b.col[0].x)) {
4912
+ const last = bands[bands.length - 1];
4913
+ if (last) {
4914
+ const lastRight = Math.max(...last.col.map((i) => i.x + i.w));
4915
+ const gap = Math.min(...c.col.map((i) => i.x)) - lastRight;
4916
+ const lTop = Math.max(...last.col.map((i) => i.y)), lBot = Math.min(...last.col.map((i) => i.y));
4917
+ const cTop = c.col[0].y, cBot = c.col[c.col.length - 1].y;
4918
+ if (gap <= Math.max(last.fs, c.fs) * 1.5 && Math.min(lTop, cTop) >= Math.max(lBot, cBot)) {
4919
+ last.col.push(...c.col);
4920
+ last.fs = Math.max(last.fs, c.fs);
4921
+ last.anchored ||= c.col.length >= SIDE_TAB_MIN;
4922
+ continue;
4923
+ }
4924
+ }
4925
+ bands.push({ col: [...c.col], fs: c.fs, anchored: c.col.length >= SIDE_TAB_MIN });
4926
+ }
4927
+ for (const { col, fs, anchored } of bands) {
4928
+ if (!anchored) continue;
4929
+ col.sort((a, b) => b.y - a.y);
4643
4930
  const members = new Set(col);
4644
4931
  const top = col[0].y + fs, bottom = col[col.length - 1].y - fs;
4645
- const others = items.filter((i) => !members.has(i) && i.y <= top && i.y >= bottom);
4932
+ const others = items.filter((i) => !members.has(i) && i.text.trim() && i.y <= top && i.y >= bottom);
4933
+ if (!others.length) continue;
4646
4934
  const left = Math.min(...col.map((i) => i.x)), right = Math.max(...col.map((i) => i.x + i.w));
4647
4935
  const rest = items.filter((i) => !members.has(i) && i.text.trim());
4648
4936
  const outside = rest.every((i) => i.x >= right + fs) || rest.every((i) => i.x + i.w <= left - fs);
@@ -5903,13 +6191,44 @@ var UNDER_SPAN_OVERLAP_RATIO = 0.8;
5903
6191
  var UNDER_BOX_PAIR_MIN_EM = 0.5;
5904
6192
  var UNDER_BOX_PAIR_MAX_EM = 2.2;
5905
6193
  var UNDER_BOX_PAIR_OVERLAP = 0.8;
5906
- function markUnderlineItems(items, horizontals, verticals) {
6194
+ function markUnderlineItems(items, horizontals, verticals, nonRules) {
5907
6195
  const underlines = [];
6196
+ if (nonRules?.size) horizontals = horizontals.filter((line) => !nonRules.has(line));
5908
6197
  if (items.length === 0 || horizontals.length === 0) return underlines;
6198
+ const tightOwners = /* @__PURE__ */ new Map();
6199
+ const tightlyOwned = (line) => {
6200
+ const cached = tightOwners.get(line);
6201
+ if (cached !== void 0) return cached;
6202
+ const owners = items.filter((item) => {
6203
+ const below = item.y - line.y1;
6204
+ return item.w > 0 && item.text.trim() && below >= 0.5 && below <= 3 && Math.min(line.x2, item.x + item.w) > Math.max(line.x1, item.x);
6205
+ }).sort((a, b) => a.x - b.x);
6206
+ let owned = owners.length > 0 && (Math.abs(owners[0].x - line.x1) <= UNDER_GRID_EPS || owners.length === 1 && line.x1 > owners[0].x && line.x1 - owners[0].x <= Math.max(owners[0].h, owners[0].fontSize, 1) * 3) && Math.abs(owners[owners.length - 1].x + owners[owners.length - 1].w - line.x2) <= UNDER_GRID_EPS;
6207
+ for (let i = 1; owned && i < owners.length; i++) {
6208
+ const em = Math.max(owners[i].h, owners[i].fontSize, 1);
6209
+ if (owners[i].x - (owners[i - 1].x + owners[i - 1].w) > em * UNDER_COLUMN_GAP_EM) owned = false;
6210
+ }
6211
+ tightOwners.set(line, owned);
6212
+ return owned;
6213
+ };
6214
+ const paragraphUnderline = (line) => {
6215
+ if (!tightlyOwned(line)) return false;
6216
+ const width = line.x2 - line.x1;
6217
+ const ys = [];
6218
+ for (const other of horizontals) {
6219
+ const overlap2 = Math.min(line.x2, other.x2) - Math.max(line.x1, other.x1);
6220
+ if (other.lineWidth > UNDER_MAX_THICKNESS || overlap2 / Math.max(width, other.x2 - other.x1) < UNDER_SPAN_OVERLAP_RATIO || !tightlyOwned(other)) continue;
6221
+ if (!ys.some((y) => Math.abs(y - other.y1) < UNDER_GRID_EPS)) ys.push(other.y1);
6222
+ if (ys.length >= UNDER_REPEATED_SPAN_LEVELS) return true;
6223
+ }
6224
+ return false;
6225
+ };
5909
6226
  for (const line of horizontals) {
5910
6227
  if (line.lineWidth > UNDER_MAX_THICKNESS) continue;
5911
6228
  const enclosed = insideTallCell(line, verticals, 0);
5912
- if (!enclosed && (touchesVertical(line, verticals) || isRepeatedSpanRule(line, horizontals))) continue;
6229
+ const repeated = isRepeatedSpanRule(line, horizontals);
6230
+ const textSeries = repeated && paragraphUnderline(line);
6231
+ if (!enclosed && (touchesVertical(line, verticals) || repeated && !textSeries)) continue;
5913
6232
  const matches = [];
5914
6233
  for (const item of items) {
5915
6234
  const h = item.h > 0 ? item.h : item.fontSize;
@@ -5929,11 +6248,11 @@ function markUnderlineItems(items, horizontals, verticals) {
5929
6248
  covered += m.w;
5930
6249
  }
5931
6250
  const inset = enclosed && insideTallCell(line, verticals, maxH);
5932
- if (enclosed && !inset && (touchesVertical(line, verticals) || isRepeatedSpanRule(line, horizontals))) continue;
6251
+ if (enclosed && !inset && (touchesVertical(line, verticals) || repeated && !textSeries)) continue;
5933
6252
  const pad = Math.max(maxH * UNDER_OWNER_PAD_EM, UNDER_OWNER_PAD_MIN_PT);
5934
6253
  if (line.x1 < x1 - pad || line.x2 > x2 + pad) continue;
5935
6254
  if (covered < (line.x2 - line.x1) * UNDER_MIN_COVERAGE) continue;
5936
- if (hasBoxTopPair(line, maxH, horizontals, inset ? items : void 0)) continue;
6255
+ if (hasBoxTopPair(line, maxH, horizontals, inset || textSeries || tightlyOwned(line) ? items : void 0)) continue;
5937
6256
  matches.sort((a, b) => a.x - b.x);
5938
6257
  let hole = false;
5939
6258
  for (let i = 1; i < matches.length; i++) {
@@ -5964,6 +6283,7 @@ function touchesVertical(line, verticals) {
5964
6283
  for (const v of verticals) {
5965
6284
  if (v.x1 < line.x1 - UNDER_GRID_EPS || v.x1 > line.x2 + UNDER_GRID_EPS) continue;
5966
6285
  const lo = Math.min(v.y1, v.y2), hi = Math.max(v.y1, v.y2);
6286
+ if (hi - lo <= UNDER_GRID_EPS) continue;
5967
6287
  if (lo <= line.y1 + UNDER_GRID_EPS && hi >= line.y1 - UNDER_GRID_EPS) return true;
5968
6288
  }
5969
6289
  return false;
@@ -6173,6 +6493,57 @@ function isPageFrameGrid(grid, cells, pageWidth, pageHeight, items = []) {
6173
6493
  return inner.length === 0 || crossing >= 1 && crossing >= inBig.length * 0.01;
6174
6494
  }
6175
6495
 
6496
+ // src/pdf/shaded-open-table.ts
6497
+ function closeShadedTableEdges(clipGrids, horizontals, verticals, fillRects) {
6498
+ const near = (a, b) => Math.abs(a - b) <= 1.5;
6499
+ let hs = horizontals, vs = verticals;
6500
+ const restored = [];
6501
+ for (const grid of clipGrids) {
6502
+ if (grid.clipParent || grid.rowYs.length !== 2 || grid.colXs.length < 3 || !grid.cells?.length || grid.cells.some((c) => c.filler || c.rowSpan !== 1 || c.colSpan !== 1)) continue;
6503
+ const { x1, x2, y1: mid, y2: top } = grid.bbox;
6504
+ if (!grid.cells.every((c) => fillRects.some((f) => near(f.x1, c.bbox.x1) && near(f.x2, c.bbox.x2) && near(f.y1, c.bbox.y1) && near(f.y2, c.bbox.y2)))) continue;
6505
+ const topRule = hs.find((h) => near(h.y1, top) && near(h.x1, x1) && near(h.x2, x2));
6506
+ if (!topRule) continue;
6507
+ const dividers = grid.colXs.slice(1, -1).map((x) => vs.find((v) => near(v.x1, x) && near(v.y2, top) && v.y1 <= mid - 6));
6508
+ if (dividers.some((v) => !v)) continue;
6509
+ const bottom = dividers[0].y1;
6510
+ if (!dividers.every((v) => near(v.y1, bottom))) continue;
6511
+ const bottomRule = hs.find((h) => near(h.y1, bottom) && near(h.x1, x1) && near(h.x2, x2));
6512
+ if (!bottomRule) continue;
6513
+ const missing = [x1, x2].filter((x) => !vs.some((v) => near(v.x1, x) && v.y1 <= bottom + 1.5 && v.y2 >= top - 1.5));
6514
+ if (!missing.length) continue;
6515
+ restored.push({ x1, x2, y1: bottom, y2: top });
6516
+ vs = vs.concat(missing.map((x) => ({ x1: x, x2: x, y1: bottom, y2: top, lineWidth: topRule.lineWidth })));
6517
+ if (!hs.some((h) => near(h.y1, mid) && near(h.x1, x1) && near(h.x2, x2))) {
6518
+ hs = hs.concat({ x1, x2, y1: mid, y2: mid, lineWidth: topRule.lineWidth });
6519
+ }
6520
+ }
6521
+ return { horizontals: hs, verticals: vs, restored };
6522
+ }
6523
+ function nestRestoredShadedGrids(grids, restored, horizontals, verticals) {
6524
+ const near = (a, b) => Math.abs(a - b) <= 1.5;
6525
+ if (restored.length === 0) return;
6526
+ const nested = /* @__PURE__ */ new Set();
6527
+ for (const grid of grids) {
6528
+ const b = grid.bbox;
6529
+ if (!restored.some((r) => near(r.x1, b.x1) && near(r.x2, b.x2) && near(r.y1, b.y1) && near(r.y2, b.y2))) continue;
6530
+ if (grids.some((g) => g !== grid && b.x1 - g.bbox.x1 >= 0.8 && g.bbox.x2 - b.x2 >= 0.8 && b.y1 - g.bbox.y1 >= 0.8 && g.bbox.y2 - b.y2 >= 0.8)) {
6531
+ grid.lineNested = true;
6532
+ nested.add(grid);
6533
+ }
6534
+ }
6535
+ for (const frame of grids) {
6536
+ const b = frame.bbox;
6537
+ if (frame.lineNested || ![...nested].some((g) => g.bbox.x1 > b.x1 && g.bbox.x2 < b.x2 && g.bbox.y1 > b.y1 && g.bbox.y2 < b.y2)) continue;
6538
+ const fullH = horizontals.filter((h) => near(h.x1, b.x1) && near(h.x2, b.x2) && h.y1 >= b.y1 - 1.5 && h.y1 <= b.y2 + 1.5);
6539
+ if (!fullH.some((h) => near(h.y1, b.y1)) || !fullH.some((h) => near(h.y1, b.y2)) || fullH.some((h) => h.y1 > b.y1 + 1.5 && h.y1 < b.y2 - 1.5)) continue;
6540
+ const fullV = verticals.filter((v) => v.y1 <= b.y1 + 1.5 && v.y2 >= b.y2 - 1.5 && v.x1 >= b.x1 - 1.5 && v.x1 <= b.x2 + 1.5);
6541
+ if (!fullV.some((v) => near(v.x1, b.x1)) || !fullV.some((v) => near(v.x1, b.x2)) || fullV.some((v) => v.x1 > b.x1 + 1.5 && v.x1 < b.x2 - 1.5)) continue;
6542
+ frame.colXs = [b.x1, b.x2];
6543
+ frame.rowYs = [b.y2, b.y1];
6544
+ }
6545
+ }
6546
+
6176
6547
  // src/pdf/open-table-ends.ts
6177
6548
  var ALIGN_TOL = 3;
6178
6549
  var MIN_RULES = 3;
@@ -6508,6 +6879,140 @@ function detectTextBoxTables(boxes, items, pageNum) {
6508
6879
  }];
6509
6880
  }
6510
6881
 
6882
+ // src/pdf/frame-cell-blocks.ts
6883
+ var FRAME_READING_UNITS = /* @__PURE__ */ new WeakMap();
6884
+ var FRAME_SOURCE_BOUNDS = /* @__PURE__ */ new WeakMap();
6885
+ function recordFrameReadingUnit(blocks, bbox) {
6886
+ for (const block of blocks) FRAME_SOURCE_BOUNDS.set(block, bbox);
6887
+ if (blocks.length < 2) return;
6888
+ const unit = { blocks, bbox };
6889
+ for (const block of blocks) FRAME_READING_UNITS.set(block, unit);
6890
+ }
6891
+ function frameLayoutBoxes(blocks) {
6892
+ const boxes = [], seen2 = /* @__PURE__ */ new Set();
6893
+ for (const block of blocks) {
6894
+ const frame = FRAME_SOURCE_BOUNDS.get(block);
6895
+ if (frame) {
6896
+ if (!seen2.has(frame)) {
6897
+ boxes.push(frame);
6898
+ seen2.add(frame);
6899
+ }
6900
+ } else if (block.bbox) boxes.push(block.bbox);
6901
+ }
6902
+ return boxes;
6903
+ }
6904
+ function groupFrameParagraphUnits(units, frames) {
6905
+ const source = /* @__PURE__ */ new Map();
6906
+ for (const unit of units) for (const block of unit) source.set(block, unit);
6907
+ const members = /* @__PURE__ */ new Map(), emitted = /* @__PURE__ */ new Set();
6908
+ for (const frame of frames) {
6909
+ if (frame.length < 2 || frame.some((block) => block.type !== "paragraph" || source.get(block)?.length !== 1)) continue;
6910
+ for (const block of frame) members.set(block, frame);
6911
+ }
6912
+ const out = [];
6913
+ for (const unit of units) {
6914
+ const frame = unit.length === 1 ? members.get(unit[0]) : void 0;
6915
+ if (!frame) out.push(unit);
6916
+ else if (!emitted.has(frame)) {
6917
+ out.push(frame);
6918
+ emitted.add(frame);
6919
+ }
6920
+ }
6921
+ for (const unit of out) {
6922
+ if (unit.length < 2 || FRAME_READING_UNITS.get(unit[0])?.blocks === unit) continue;
6923
+ const bs = unit.map((b) => b.bbox).filter((b) => !!b);
6924
+ if (bs.length !== unit.length) continue;
6925
+ const x = Math.min(...bs.map((b) => b.x)), y = Math.min(...bs.map((b) => b.y));
6926
+ recordFrameReadingUnit(unit, {
6927
+ page: bs[0].page,
6928
+ x,
6929
+ y,
6930
+ width: Math.max(...bs.map((b) => b.x + b.width)) - x,
6931
+ height: Math.max(...bs.map((b) => b.y + b.height)) - y
6932
+ });
6933
+ }
6934
+ return out;
6935
+ }
6936
+ function recordFrameTitle(table, source, pageNum) {
6937
+ if (!CLIP_TABLES.has(table) || table.rows !== 1 || table.cols !== 3 || source.length < 2) return;
6938
+ const cells = table.cells[0];
6939
+ if (cells.length !== 3 || cells.some((c) => c.colSpan !== 1 || c.rowSpan !== 1 || c.blocks?.length || c.text.includes("\n"))) return;
6940
+ const [label, spacer, title] = cells;
6941
+ if (!/^(?:붙임|별첨|첨부|부록)\s*\d{1,3}$/.test(label.text.trim()) || spacer.text.trim() || !title.text.trim()) return;
6942
+ if (cells.some((c) => {
6943
+ const e = CELL_EDGES.get(c);
6944
+ return !e || e.t || e.b || e.l || e.r;
6945
+ })) return;
6946
+ const xs = TABLE_COLXS.get(table), style = dominantStyle(source), fs = style?.fontSize ?? 0;
6947
+ if (!xs || xs.length !== 4 || fs <= 0) return;
6948
+ const width = xs[3] - xs[0], gap = xs[2] - xs[1];
6949
+ if (width < fs * 12 || gap <= 0 || gap > fs * 1.5 || xs[1] - xs[0] > width * 0.25 || xs[3] - xs[2] < width * 0.6) return;
6950
+ if (source.some((i) => i.fontName !== source[0].fontName || Math.abs(i.fontSize - fs) > fs * 0.15)) return;
6951
+ if (groupByY([...source].sort((a, b) => b.y - a.y)).length !== 1) return;
6952
+ FRAME_TITLE_BLOCKS.set(table, {
6953
+ type: "paragraph",
6954
+ text: `${label.text.trim()} ${title.text.trim()}`,
6955
+ pageNumber: pageNum,
6956
+ bbox: computeBBox(source, pageNum),
6957
+ style
6958
+ });
6959
+ }
6960
+ var FRAME_RECT_TOL = 1.5;
6961
+ function takePendingNested(pending, cellBox, clipCell) {
6962
+ const out = [];
6963
+ for (let i = pending.length - 1; i >= 0; i--) {
6964
+ const p = pending[i].parent;
6965
+ if (pending[i].contained ? p.x1 >= cellBox.x1 - FRAME_RECT_TOL && p.x2 <= cellBox.x2 + FRAME_RECT_TOL && p.y1 >= cellBox.y1 - FRAME_RECT_TOL && p.y2 <= cellBox.y2 + FRAME_RECT_TOL : clipCell && Math.abs(p.x1 - cellBox.x1) <= FRAME_RECT_TOL && Math.abs(p.x2 - cellBox.x2) <= FRAME_RECT_TOL && Math.abs(p.y1 - cellBox.y1) <= FRAME_RECT_TOL && Math.abs(p.y2 - cellBox.y2) <= FRAME_RECT_TOL) {
6966
+ out.push(pending[i].block);
6967
+ pending.splice(i, 1);
6968
+ }
6969
+ }
6970
+ return out;
6971
+ }
6972
+ function buildFrameCellBlocks(cellItems, nested, pageNum, lex) {
6973
+ const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
6974
+ const blocks = [];
6975
+ let rest = [...cellItems];
6976
+ const pushParagraphs = (items) => {
6977
+ if (items.length === 0) return;
6978
+ const source = items.map((it) => ({ ...it, isHidden: false })).sort((a, b) => b.y - a.y || a.x - b.x);
6979
+ const paragraphs = [];
6980
+ pushLineParagraphs(paragraphs, mergeSuperscriptLines(groupByY(source)), pageNum, lex);
6981
+ for (const block of paragraphs) {
6982
+ block.text = cleanCellText(block.text ?? "");
6983
+ if (block.text) blocks.push(block);
6984
+ }
6985
+ };
6986
+ for (const tb of tables) {
6987
+ const bottom = tb.bbox.y;
6988
+ pushParagraphs(rest.filter((it) => it.y >= bottom));
6989
+ rest = rest.filter((it) => it.y < bottom);
6990
+ blocks.push(tb);
6991
+ }
6992
+ pushParagraphs(rest);
6993
+ const text = blocks.map((b) => b.type === "table" && b.table ? b.table.cells.flat().map((c) => c.text).filter(Boolean).join("\n") : b.text ?? "").filter(Boolean).join("\n");
6994
+ return { blocks, text };
6995
+ }
6996
+
6997
+ // src/pdf/nested-shaded-headers.ts
6998
+ function extendNestedShadedHeaders(clipGrids, lineGrids, horizontals, verticals, fills) {
6999
+ const near = (a, b) => Math.abs(a - b) <= 1.5;
7000
+ const contains3 = (a, b) => b.x1 >= a.x1 - 1.5 && b.x2 <= a.x2 + 1.5 && b.y1 >= a.y1 - 1.5 && b.y2 <= a.y2 + 1.5;
7001
+ const extended = [];
7002
+ for (let i = 0; i < clipGrids.length; i++) {
7003
+ const c = clipGrids[i], parent = c.clipParent;
7004
+ if (!parent || c.rowYs.length !== 2 || c.colXs.length < 3 || !c.cells?.length || c.cells.some((cell) => cell.filler || cell.rowSpan !== 1 || cell.colSpan !== 1)) continue;
7005
+ if (!clipGrids.some((g) => g.rowYs.length === 2 && g.colXs.length === 2 && near(g.bbox.x1, parent.x1) && near(g.bbox.x2, parent.x2) && near(g.bbox.y1, parent.y1) && near(g.bbox.y2, parent.y2))) continue;
7006
+ if (!c.cells.every((cell) => fills.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)))) continue;
7007
+ const host = lineGrids.find((l) => l.rowYs.length > 2 && l.colXs.length === c.colXs.length && c.colXs.every((x, k) => near(x, l.colXs[k])) && c.rowYs.every((y, k) => near(y, l.rowYs[k])) && contains3(parent, l.bbox) && l.rowYs.every((y) => horizontals.some((h) => near(h.y1, y) && near(h.x1, l.bbox.x1) && near(h.x2, l.bbox.x2))) && l.colXs.every((x) => verticals.some((v) => near(v.x1, x) && v.y1 <= l.bbox.y1 + 1.5 && v.y2 >= l.bbox.y2 - 1.5)) && !clipGrids.some((o) => o !== c && !contains3(o.bbox, l.bbox) && Math.min(o.bbox.x2, l.bbox.x2) > Math.max(o.bbox.x1, l.bbox.x1) && Math.min(o.bbox.y2, l.bbox.y2) > Math.max(o.bbox.y1, l.bbox.y1)));
7008
+ if (!host) continue;
7009
+ const grid = { ...host, clipParent: parent, cells: extractCells(host, horizontals, verticals) };
7010
+ clipGrids[i] = grid;
7011
+ extended.push(grid);
7012
+ }
7013
+ return extended;
7014
+ }
7015
+
6511
7016
  // src/pdf/page-regions.ts
6512
7017
  function splitTwoColumnProse(items, cutX) {
6513
7018
  const left = [];
@@ -6835,7 +7340,7 @@ function figureColumnBands(items, figures) {
6835
7340
  }
6836
7341
 
6837
7342
  // src/pdf/page-blocks.ts
6838
- function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon) {
7343
+ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeight, extraLines, detectTables = true, carry, lexicon, verifiedRightArrows = []) {
6839
7344
  if (items.length === 0) {
6840
7345
  if (carry) carry.clip = void 0;
6841
7346
  return [];
@@ -6843,7 +7348,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
6843
7348
  const tab = sideTabGlyphs(items);
6844
7349
  if (tab.size) {
6845
7350
  const glyphs = [...tab].sort((a, b) => b.y - a.y).map((g) => ({ type: "paragraph", text: g.text.trim(), pageNumber: pageNum, bbox: computeBBox([g], pageNum), style: dominantStyle([g]) }));
6846
- return [...glyphs, ...extractPageBlocksWithLines(items.filter((i) => !tab.has(i)), pageNum, opList, pageWidth, pageHeight, extraLines, detectTables, carry, lexicon)];
7351
+ return [...glyphs, ...extractPageBlocksWithLines(items.filter((i) => !tab.has(i)), pageNum, opList, pageWidth, pageHeight, extraLines, detectTables, carry, lexicon, verifiedRightArrows)];
6847
7352
  }
6848
7353
  const lex = lexicon ?? new WrapLexicon();
6849
7354
  for (const line of streamLines(items)) lex.addLine(mergeLineSimple(line));
@@ -6871,19 +7376,28 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
6871
7376
  }
6872
7377
  ;
6873
7378
  ({ horizontals, verticals } = filterPageBorderLines(horizontals, verticals, pageWidth, pageHeight));
6874
- ({ horizontals, verticals } = preprocessLines(horizontals, verticals));
7379
+ ({ horizontals, verticals } = preprocessLines(horizontals, verticals, extracted.nonRules));
7380
+ markStrikethroughItems(items, horizontals);
7381
+ wrapStrikethroughRuns(items);
7382
+ const underlines = new Set(markUnderlineItems(items, horizontals, verticals, extracted.nonRules));
7383
+ if (underlines.size) horizontals = horizontals.filter((l) => !underlines.has(l));
7384
+ wrapUnderlineRuns(items);
6875
7385
  horizontals = closeOpenTableEnds(horizontals, verticals, items.every((it) => it.seq !== void 0));
6876
7386
  verticals = closeOpenTableEdges(horizontals, verticals);
6877
7387
  verticals = bridgeSplitColumnVerticals(horizontals, verticals);
6878
7388
  if (detectTables && clipGrids.length === 0) verticals = bridgeSkippedRowVerticals(horizontals, verticals, items);
6879
7389
  if (detectTables && clipGrids.length === 0) ({ horizontals, verticals } = extendHeaderBoxRows(horizontals, verticals, items));
6880
- markStrikethroughItems(items, horizontals);
6881
- wrapStrikethroughRuns(items);
6882
- const underlines = new Set(markUnderlineItems(items, horizontals, verticals));
6883
- if (underlines.size) horizontals = horizontals.filter((l) => !underlines.has(l));
6884
- wrapUnderlineRuns(items);
7390
+ const shadedEdges = detectTables ? closeShadedTableEdges(clipGrids, horizontals, verticals, extracted.fillRects) : void 0;
7391
+ if (shadedEdges) ({ horizontals, verticals } = shadedEdges);
6885
7392
  const lineGrids = detectTables ? buildTableGrids(horizontals, verticals) : [];
7393
+ if (shadedEdges) nestRestoredShadedGrids(lineGrids, shadedEdges.restored, horizontals, verticals);
6886
7394
  const tableClipGrids = dropHeadBandClipGrids(dropInsetClipGrids(dropShadingClipGrids(clipGrids, lineGrids, extracted.fillRects, verticals), lineGrids), lineGrids);
7395
+ recordClipCellEdges(
7396
+ extendNestedShadedHeaders(tableClipGrids, lineGrids, horizontals, verticals, extracted.fillRects),
7397
+ extracted.horizontals.concat(extracted.shortH),
7398
+ extracted.verticals.concat(extracted.shortV),
7399
+ extracted.nonRules
7400
+ );
6887
7401
  const grids = [...tableClipGrids, ...dropGridsInside(lineGrids, tableClipGrids, clipResult.containers)];
6888
7402
  const figures = () => extractImageRegions(opList.fnArray, opList.argsArray, true).filter((r) => r.x2 - r.x1 >= 40 && r.y2 - r.y1 >= 40).map((r) => ({ x: r.x1, y: r.y1, w: r.x2 - r.x1, h: r.y2 - r.y1 }));
6889
7403
  if (grids.length === 1 && grids[0].rowYs.length === 2 && grids[0].colXs.length === 2 && grids[0].bbox.x2 - grids[0].bbox.x1 > pageWidth * 1.2 && grids[0].bbox.y2 - grids[0].bbox.y1 > pageHeight * 1.2) {
@@ -6893,7 +7407,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
6893
7407
  if (detectTables && clipGrids.length === 0 && ruled.length === 0 && lineGrids.length === 0) ruled.push(...detectTextBoxTables(extracted.hiddenBoxes, items, pageNum));
6894
7408
  if (ruled.length > 0) {
6895
7409
  const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
6896
- return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules);
7410
+ return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules, verifiedRightArrows);
6897
7411
  }
6898
7412
  if (detectTables && stackedTableBands(items)) {
6899
7413
  return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
@@ -6904,7 +7418,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
6904
7418
  }
6905
7419
  if (grids.length > 0) {
6906
7420
  const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
6907
- return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules);
7421
+ return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules, verifiedRightArrows);
6908
7422
  }
6909
7423
  return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
6910
7424
  }
@@ -7009,42 +7523,10 @@ function isSparseProseGrid(table) {
7009
7523
  const prose = filled.filter((t) => t.length >= 60 && /[.!?。]/.test(t)).reduce((n, t) => n + t.length, 0);
7010
7524
  return prose >= chars * 0.6;
7011
7525
  }
7012
- var FRAME_RECT_TOL = 1.5;
7013
- function takePendingNested(pending, cellBox, clipCell) {
7014
- const out = [];
7015
- for (let i = pending.length - 1; i >= 0; i--) {
7016
- const p = pending[i].parent;
7017
- if (pending[i].contained ? p.x1 >= cellBox.x1 - FRAME_RECT_TOL && p.x2 <= cellBox.x2 + FRAME_RECT_TOL && p.y1 >= cellBox.y1 - FRAME_RECT_TOL && p.y2 <= cellBox.y2 + FRAME_RECT_TOL : clipCell && Math.abs(p.x1 - cellBox.x1) <= FRAME_RECT_TOL && Math.abs(p.x2 - cellBox.x2) <= FRAME_RECT_TOL && Math.abs(p.y1 - cellBox.y1) <= FRAME_RECT_TOL && Math.abs(p.y2 - cellBox.y2) <= FRAME_RECT_TOL) {
7018
- out.push(pending[i].block);
7019
- pending.splice(i, 1);
7020
- }
7021
- }
7022
- return out;
7023
- }
7024
- function buildFrameCellBlocks(cellItems, nested, pageNum, wrap) {
7025
- const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
7026
- const blocks = [];
7027
- let rest = [...cellItems];
7028
- const pushParagraphs = (items) => {
7029
- if (items.length === 0) return;
7030
- for (const line of cleanCellText(cellTextToString(items, wrap)).split("\n")) {
7031
- const t = line.trim();
7032
- if (t) blocks.push({ type: "paragraph", text: t, pageNumber: pageNum });
7033
- }
7034
- };
7035
- for (const tb of tables) {
7036
- const bottom = tb.bbox.y;
7037
- pushParagraphs(rest.filter((it) => it.y >= bottom));
7038
- rest = rest.filter((it) => it.y < bottom);
7039
- blocks.push(tb);
7040
- }
7041
- pushParagraphs(rest);
7042
- const text = blocks.map((b) => b.type === "table" && b.table ? b.table.cells.flat().map((c) => c.text).filter(Boolean).join("\n") : b.text ?? "").filter(Boolean).join("\n");
7043
- return { blocks, text };
7044
- }
7045
- function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = [], rawRules = horizontals) {
7526
+ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = [], rawRules = horizontals, verifiedRightArrows = []) {
7046
7527
  const ocrPage = items.length > 0 && items.every((i) => i.fontName === "ocr");
7047
7528
  const blocks = [];
7529
+ const frameParagraphUnits = [];
7048
7530
  const usedItems = /* @__PURE__ */ new Set();
7049
7531
  for (const r of ruled) {
7050
7532
  for (const it of r.items) usedItems.add(it);
@@ -7101,7 +7583,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
7101
7583
  const nested = pendingNested.length ? takePendingNested(pendingNested, cell.bbox, !!grid.cells) : [];
7102
7584
  if (nested.length > 0) {
7103
7585
  nestedAttached = true;
7104
- const built = buildFrameCellBlocks(cellItems, nested, pageNum, { box: cell.bbox, lex });
7586
+ const built = buildFrameCellBlocks(cellItems, nested, pageNum, lex);
7105
7587
  irGrid[cell.row][cell.col] = { text: built.text, colSpan: cell.colSpan, rowSpan: cell.rowSpan, blocks: built.blocks };
7106
7588
  if (cellItems.length) recordCellLines(irGrid[cell.row][cell.col], cellItems);
7107
7589
  takeClipCellEdges(cell, irGrid[cell.row][cell.col]);
@@ -7112,6 +7594,9 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
7112
7594
  colSpan: cell.colSpan,
7113
7595
  rowSpan: cell.rowSpan
7114
7596
  };
7597
+ if (numRows === 1 && numCols === 1 && cellItems.length) {
7598
+ irGrid[cell.row][cell.col].blocks = buildFrameCellBlocks(cellItems, [], pageNum, lex).blocks;
7599
+ }
7115
7600
  const b = cell.bbox;
7116
7601
  const isBackdrop = (r) => r.x1 <= b.x1 + 1 && r.x2 >= b.x2 - 1 && r.y1 <= b.y1 + 1 && r.y2 >= b.y2 - 1;
7117
7602
  if (imageRegions.some((r) => {
@@ -7147,7 +7632,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
7147
7632
  }
7148
7633
  if (!rebuiltUsed && attachUnitRow(items, grid, finalGrid, numCols, usedItems)) finalRows++;
7149
7634
  let semanticOneColumn = false;
7150
- if (!grid.cells && numCols === 1 && numGridRows >= 2) {
7635
+ if (!grid.cells && !nestedAttached && numCols === 1 && numGridRows >= 2) {
7151
7636
  const populatedRows = finalGrid.filter((row) => row[0]?.text.trim());
7152
7637
  if (populatedRows.length >= 4) {
7153
7638
  const fontSizes = tableItems.map((item) => item.fontSize).filter((size) => size > 0).sort((a, b) => a - b);
@@ -7200,6 +7685,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
7200
7685
  recordRowRules(irTable, grid.cells, grid.bbox, rawRules);
7201
7686
  }
7202
7687
  TABLE_COLXS.set(irTable, grid.colXs);
7688
+ if (grid.cells) recordFrameTitle(irTable, tableItems, pageNum);
7203
7689
  if (grid.cells && finalRows === numRows) TABLE_ROWYS.set(irTable, grid.rowYs);
7204
7690
  if (grid.continues) CONT_PARTS.set(irTable, grid.continues);
7205
7691
  const hasContent = finalGrid.some((row) => row.some((cell) => cell.text.trim() !== ""));
@@ -7251,7 +7737,14 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
7251
7737
  continue;
7252
7738
  }
7253
7739
  }
7254
- if (!grid.cells && shouldDemoteTable(irTable)) {
7740
+ if (!grid.cells && !nestedAttached && shouldDemoteTable(irTable)) {
7741
+ const paragraphs = numRows === 1 && numCols === 1 ? irTable.cells[0]?.[0]?.blocks : void 0;
7742
+ if (paragraphs?.length) {
7743
+ blocks.push(...paragraphs);
7744
+ frameParagraphUnits.push(paragraphs);
7745
+ recordFrameReadingUnit(paragraphs, tableBbox);
7746
+ continue;
7747
+ }
7255
7748
  const demoted = demoteTableToText(irTable);
7256
7749
  if (demoted) {
7257
7750
  const text = numGridRows === 1 ? "\n" + demoted + "\n" : demoted;
@@ -7305,9 +7798,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
7305
7798
  }
7306
7799
  {
7307
7800
  const rects = remaining.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }));
7308
- for (const b of blocks) {
7309
- 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 });
7310
- }
7801
+ for (const b of frameLayoutBoxes(blocks.filter((b2) => !(b2.table && EMPTY_PARTS.has(b2.table))))) rects.push({ x: b.x, y: b.y, w: b.width, h: b.height });
7311
7802
  gutterX = detectColumnGutter(rects) ?? findRuledColumnDivider(
7312
7803
  blocks.filter((b) => b.type === "table" && b.bbox && b.table && !EMPTY_PARTS.has(b.table)).map((b) => ({ x: b.bbox.x, y: b.bbox.y, w: b.bbox.width, h: b.bbox.height })),
7313
7804
  horizontals,
@@ -7354,7 +7845,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
7354
7845
  finalTextBlocks = detectListBlocks(textBlocks);
7355
7846
  }
7356
7847
  }
7357
- const units = blocks.map((b) => [b]);
7848
+ const units = groupFrameParagraphUnits(groupFlowBoxUnits(blocks, grids, horizontals, verticals, verifiedRightArrows), frameParagraphUnits);
7358
7849
  let off = 0;
7359
7850
  for (const size of groupSizes) {
7360
7851
  const unit = finalTextBlocks.slice(off, off + size);
@@ -7493,7 +7984,7 @@ function mergeAdjacentTableBlocks(blocks) {
7493
7984
  table: merged,
7494
7985
  bbox: { ...pb, y: cb.y, height: pb.y + pb.height - cb.y }
7495
7986
  };
7496
- } else if (prev.type === "table" && curr.type === "table" && prev.table && curr.table && prev.table.cols === curr.table.cols && prev.table.renderAsTable === curr.table.renderAsTable && !CLIP_TABLES.has(prev.table) && !CLIP_TABLES.has(curr.table)) {
7987
+ } else if (prev.type === "table" && curr.type === "table" && prev.table && curr.table && prev.table.cols === curr.table.cols && prev.table.renderAsTable === curr.table.renderAsTable && !CLIP_TABLES.has(prev.table) && !CLIP_TABLES.has(curr.table) && !separateRepeatedHeadings(prev, curr)) {
7497
7988
  const merged = {
7498
7989
  rows: prev.table.rows + curr.table.rows,
7499
7990
  cols: prev.table.cols,
@@ -7508,6 +7999,12 @@ function mergeAdjacentTableBlocks(blocks) {
7508
7999
  }
7509
8000
  return result;
7510
8001
  }
8002
+ function separateRepeatedHeadings(upper, lower) {
8003
+ const u = upper.table, d = lower.table, ub = upper.bbox, db = lower.bbox;
8004
+ if (!ub || !db || ub.page !== db.page || u.rows < 2 || d.rows < 2 || !u.hasHeader || !d.hasHeader || ub.y - (db.y + db.height) <= 1 || Math.abs(ub.x - db.x) > 1 || Math.abs(ub.width - db.width) > 1) return false;
8005
+ const a = u.cells[0], b = d.cells[0], norm = (text) => text.replace(/<\/?u>|~~|\s+/g, "");
8006
+ return a.filter((cell) => norm(cell.text)).length >= 2 && a.length === b.length && a.every((cell, c) => cell.colSpan === b[c].colSpan && cell.rowSpan === b[c].rowSpan && norm(cell.text) === norm(b[c].text));
8007
+ }
7511
8008
  function streamLines(items) {
7512
8009
  if (items.some((i) => i.seq === void 0)) return groupByY([...items].sort((a, b) => b.y - a.y || a.x - b.x));
7513
8010
  const lines = [];
@@ -7692,7 +8189,11 @@ export {
7692
8189
  extractImageRegions,
7693
8190
  filterHiddenText,
7694
8191
  collapseEvenSpacing,
8192
+ computeBBox,
8193
+ dominantStyle,
7695
8194
  normalizeItems,
8195
+ groupByY,
8196
+ mergeLineSimple,
7696
8197
  WrapLexicon,
7697
8198
  startsNewItem,
7698
8199
  wrapJoiner,
@@ -7713,6 +8214,7 @@ export {
7713
8214
  detectKoreanListBlocks,
7714
8215
  removeHeaderFooterBlocks,
7715
8216
  CLIP_TABLES,
8217
+ FRAME_TITLE_BLOCKS,
7716
8218
  TABLE_COLXS,
7717
8219
  TABLE_ROWYS,
7718
8220
  TABLE_TAIL,
@@ -7726,7 +8228,11 @@ export {
7726
8228
  trimTrailingEmptyTableCols,
7727
8229
  NO_EDGES,
7728
8230
  joinCellEdges,
8231
+ FRAME_READING_UNITS,
8232
+ recordFrameReadingUnit,
8233
+ restoreImageBullets,
8234
+ detectRightArrowRegions,
7729
8235
  removeSideTabs,
7730
8236
  extractPageBlocksWithLines
7731
8237
  };
7732
- //# sourceMappingURL=chunk-BJ6RYYXV.js.map
8238
+ //# sourceMappingURL=chunk-MXA6YW2W.js.map