kordoc 4.17.1 → 4.17.2

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 (133) hide show
  1. package/README.md +3 -0
  2. package/dist/{-UNMTWAEI.js → -2UA2JHVA.js} +10 -10
  3. package/dist/{chunk-B4PUQ4FP.js → chunk-2XHXABCX.js} +2 -2
  4. package/dist/{chunk-MPAN6S5O.js → chunk-3N272C5L.js} +243 -114
  5. package/dist/chunk-3N272C5L.js.map +1 -0
  6. package/dist/{chunk-EULS3PDF.js → chunk-4HRJISJF.js} +3 -3
  7. package/dist/{chunk-KBIQGGNY.js → chunk-4TSYMJDL.js} +242 -113
  8. package/dist/chunk-4TSYMJDL.js.map +1 -0
  9. package/dist/{chunk-3M2BMQJY.js → chunk-5JZEY5IL.js} +119 -77
  10. package/dist/chunk-5JZEY5IL.js.map +1 -0
  11. package/dist/{chunk-5FCLQVT5.cjs → chunk-6DOCSYEM.cjs} +113 -71
  12. package/dist/chunk-6DOCSYEM.cjs.map +1 -0
  13. package/dist/{chunk-N6MPDM55.js → chunk-6OCKAXIS.js} +2 -2
  14. package/dist/{chunk-QXNQ2HNB.js → chunk-A2W2JQ3S.js} +2 -2
  15. package/dist/{chunk-66YTQ3NQ.js → chunk-C4MVZXB5.js} +2 -2
  16. package/dist/{chunk-GYHY2YLV.js → chunk-FGL4IGOT.js} +4 -4
  17. package/dist/{chunk-BEJYCCDN.cjs → chunk-GPC72VSF.cjs} +6 -6
  18. package/dist/chunk-GPC72VSF.cjs.map +1 -0
  19. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  20. package/dist/{chunk-FMP4POMD.js → chunk-GYTL6WT3.js} +3 -3
  21. package/dist/{chunk-4NH45EEB.cjs → chunk-HAW2VL62.cjs} +12 -12
  22. package/dist/chunk-HAW2VL62.cjs.map +1 -0
  23. package/dist/chunk-J55UQC5H.cjs.map +1 -1
  24. package/dist/{chunk-ELNYQRBN.js → chunk-JY2NBFIG.js} +14 -12
  25. package/dist/chunk-JY2NBFIG.js.map +1 -0
  26. package/dist/{chunk-BQAJHAWR.js → chunk-KQIYC2ZU.js} +2 -2
  27. package/dist/{chunk-GRHSVGSB.cjs → chunk-KZVQK5NS.cjs} +2 -2
  28. package/dist/chunk-KZVQK5NS.cjs.map +1 -0
  29. package/dist/{chunk-AUFO5LVN.js → chunk-MDCTITUG.js} +2 -2
  30. package/dist/{chunk-OVSCNCT6.js → chunk-O4CB7D2Q.js} +2 -2
  31. package/dist/{chunk-3J3BJIOZ.js → chunk-SDRKHEVT.js} +2 -2
  32. package/dist/{chunk-HAPCN7BD.js → chunk-VU26WGE5.js} +37 -15
  33. package/dist/chunk-VU26WGE5.js.map +1 -0
  34. package/dist/{chunk-BHUYJBSQ.js → chunk-WJLICIYV.js} +2 -2
  35. package/dist/{chunk-ZRXQDJPM.cjs → chunk-WWMKIHF7.cjs} +336 -207
  36. package/dist/chunk-WWMKIHF7.cjs.map +1 -0
  37. package/dist/{chunk-MY6Q2HFW.js → chunk-XZA6X34R.js} +121 -77
  38. package/dist/chunk-XZA6X34R.js.map +1 -0
  39. package/dist/{chunk-4CSY3QUO.js → chunk-YGKC6E6A.js} +2 -2
  40. package/dist/chunk-YIANW5QX.cjs.map +1 -1
  41. package/dist/{chunk-E6TJNN2U.js → chunk-ZDX5PIWR.js} +2 -2
  42. package/dist/chunks-EBWJR55V.js +10 -0
  43. package/dist/cli.js +25 -25
  44. package/dist/{formula-K7UF5MBF.cjs → formula-5RETDCIC.cjs} +9 -9
  45. package/dist/formula-5RETDCIC.cjs.map +1 -0
  46. package/dist/{formula-VH545WNH.js → formula-MBLN2DG4.js} +4 -4
  47. package/dist/{formula-3GB47YTH.js → formula-QZZDW5GW.js} +3 -3
  48. package/dist/{image-ocr-6AKQWAU2.js → image-ocr-CJSO3QSR.js} +7 -7
  49. package/dist/{image-ocr-VJFZCFAI.js → image-ocr-EREKAS47.js} +5 -5
  50. package/dist/{image-ocr-ZPQTFYSK.cjs → image-ocr-PSPVRLB5.cjs} +14 -14
  51. package/dist/image-ocr-PSPVRLB5.cjs.map +1 -0
  52. package/dist/index.cjs +612 -588
  53. package/dist/index.cjs.map +1 -1
  54. package/dist/index.js +41 -17
  55. package/dist/index.js.map +1 -1
  56. package/dist/mcp.js +21 -21
  57. package/dist/{model-bundle-P2XOZ76Q.js → model-bundle-MA4MMCRJ.js} +5 -5
  58. package/dist/{models-GPHBC2YJ.js → models-SEJ7LNSN.js} +5 -5
  59. package/dist/page-range-QHHFTL7X.cjs.map +1 -1
  60. package/dist/{parser-YIIRSBZS.js → parser-M5WHRX25.js} +40 -22
  61. package/dist/parser-M5WHRX25.js.map +1 -0
  62. package/dist/{parser-6SPYH3RU.cjs → parser-QILYPWSI.cjs} +211 -193
  63. package/dist/parser-QILYPWSI.cjs.map +1 -0
  64. package/dist/{parser-BVUFTU2O.js → parser-VH3F4EQU.js} +37 -19
  65. package/dist/parser-VH3F4EQU.js.map +1 -0
  66. package/dist/pdf-ocr-3SZUM3CN.cjs +16 -0
  67. package/dist/pdf-ocr-3SZUM3CN.cjs.map +1 -0
  68. package/dist/pdf-ocr-QB2TB5W5.js +18 -0
  69. package/dist/pdf-ocr-XC33L43D.js +15 -0
  70. package/dist/{profile-io-GU45HTYP.js → profile-io-5YB627EO.js} +3 -3
  71. package/dist/{rasterize-OWHFWG6R.js → rasterize-V2XHHS2I.js} +3 -3
  72. package/dist/{redact-doc-YTP6AAUP.js → redact-doc-5MK5L5IQ.js} +10 -10
  73. package/dist/{render-525LXDMV.js → render-SYZMHYK6.js} +6 -6
  74. package/dist/seal-IPKIQHYB.js +10 -0
  75. package/dist/{setup-NOXZLS7G.js → setup-ZPLJENSK.js} +3 -3
  76. package/dist/visual-RTTGNOAE.js +20 -0
  77. package/dist/{watch-NDRTCLVT.js → watch-FNWHVKK3.js} +11 -11
  78. package/package.json +1 -1
  79. package/dist/chunk-3M2BMQJY.js.map +0 -1
  80. package/dist/chunk-4NH45EEB.cjs.map +0 -1
  81. package/dist/chunk-5FCLQVT5.cjs.map +0 -1
  82. package/dist/chunk-BEJYCCDN.cjs.map +0 -1
  83. package/dist/chunk-ELNYQRBN.js.map +0 -1
  84. package/dist/chunk-GRHSVGSB.cjs.map +0 -1
  85. package/dist/chunk-HAPCN7BD.js.map +0 -1
  86. package/dist/chunk-KBIQGGNY.js.map +0 -1
  87. package/dist/chunk-MPAN6S5O.js.map +0 -1
  88. package/dist/chunk-MY6Q2HFW.js.map +0 -1
  89. package/dist/chunk-ZRXQDJPM.cjs.map +0 -1
  90. package/dist/chunks-P5Y7V73K.js +0 -10
  91. package/dist/formula-K7UF5MBF.cjs.map +0 -1
  92. package/dist/image-ocr-ZPQTFYSK.cjs.map +0 -1
  93. package/dist/parser-6SPYH3RU.cjs.map +0 -1
  94. package/dist/parser-BVUFTU2O.js.map +0 -1
  95. package/dist/parser-YIIRSBZS.js.map +0 -1
  96. package/dist/pdf-ocr-5YBMXW54.js +0 -18
  97. package/dist/pdf-ocr-EAVNHK3V.js +0 -15
  98. package/dist/pdf-ocr-J5GB5BW6.cjs +0 -16
  99. package/dist/pdf-ocr-J5GB5BW6.cjs.map +0 -1
  100. package/dist/seal-S4KJGZUI.js +0 -10
  101. package/dist/visual-AU3NH6EO.js +0 -20
  102. /package/dist/{-UNMTWAEI.js.map → -2UA2JHVA.js.map} +0 -0
  103. /package/dist/{chunk-B4PUQ4FP.js.map → chunk-2XHXABCX.js.map} +0 -0
  104. /package/dist/{chunk-EULS3PDF.js.map → chunk-4HRJISJF.js.map} +0 -0
  105. /package/dist/{chunk-N6MPDM55.js.map → chunk-6OCKAXIS.js.map} +0 -0
  106. /package/dist/{chunk-QXNQ2HNB.js.map → chunk-A2W2JQ3S.js.map} +0 -0
  107. /package/dist/{chunk-66YTQ3NQ.js.map → chunk-C4MVZXB5.js.map} +0 -0
  108. /package/dist/{chunk-GYHY2YLV.js.map → chunk-FGL4IGOT.js.map} +0 -0
  109. /package/dist/{chunk-FMP4POMD.js.map → chunk-GYTL6WT3.js.map} +0 -0
  110. /package/dist/{chunk-BQAJHAWR.js.map → chunk-KQIYC2ZU.js.map} +0 -0
  111. /package/dist/{chunk-AUFO5LVN.js.map → chunk-MDCTITUG.js.map} +0 -0
  112. /package/dist/{chunk-OVSCNCT6.js.map → chunk-O4CB7D2Q.js.map} +0 -0
  113. /package/dist/{chunk-3J3BJIOZ.js.map → chunk-SDRKHEVT.js.map} +0 -0
  114. /package/dist/{chunk-BHUYJBSQ.js.map → chunk-WJLICIYV.js.map} +0 -0
  115. /package/dist/{chunk-4CSY3QUO.js.map → chunk-YGKC6E6A.js.map} +0 -0
  116. /package/dist/{chunk-E6TJNN2U.js.map → chunk-ZDX5PIWR.js.map} +0 -0
  117. /package/dist/{chunks-P5Y7V73K.js.map → chunks-EBWJR55V.js.map} +0 -0
  118. /package/dist/{formula-VH545WNH.js.map → formula-MBLN2DG4.js.map} +0 -0
  119. /package/dist/{formula-3GB47YTH.js.map → formula-QZZDW5GW.js.map} +0 -0
  120. /package/dist/{image-ocr-6AKQWAU2.js.map → image-ocr-CJSO3QSR.js.map} +0 -0
  121. /package/dist/{image-ocr-VJFZCFAI.js.map → image-ocr-EREKAS47.js.map} +0 -0
  122. /package/dist/{model-bundle-P2XOZ76Q.js.map → model-bundle-MA4MMCRJ.js.map} +0 -0
  123. /package/dist/{models-GPHBC2YJ.js.map → models-SEJ7LNSN.js.map} +0 -0
  124. /package/dist/{pdf-ocr-5YBMXW54.js.map → pdf-ocr-QB2TB5W5.js.map} +0 -0
  125. /package/dist/{pdf-ocr-EAVNHK3V.js.map → pdf-ocr-XC33L43D.js.map} +0 -0
  126. /package/dist/{profile-io-GU45HTYP.js.map → profile-io-5YB627EO.js.map} +0 -0
  127. /package/dist/{rasterize-OWHFWG6R.js.map → rasterize-V2XHHS2I.js.map} +0 -0
  128. /package/dist/{redact-doc-YTP6AAUP.js.map → redact-doc-5MK5L5IQ.js.map} +0 -0
  129. /package/dist/{render-525LXDMV.js.map → render-SYZMHYK6.js.map} +0 -0
  130. /package/dist/{seal-S4KJGZUI.js.map → seal-IPKIQHYB.js.map} +0 -0
  131. /package/dist/{setup-NOXZLS7G.js.map → setup-ZPLJENSK.js.map} +0 -0
  132. /package/dist/{visual-AU3NH6EO.js.map → visual-RTTGNOAE.js.map} +0 -0
  133. /package/dist/{watch-NDRTCLVT.js.map → watch-FNWHVKK3.js.map} +0 -0
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  parseRenderStyles
4
- } from "./chunk-B4PUQ4FP.js";
4
+ } from "./chunk-2XHXABCX.js";
5
5
  import {
6
6
  KordocError,
7
7
  precheckZipSize
8
- } from "./chunk-QXNQ2HNB.js";
8
+ } from "./chunk-A2W2JQ3S.js";
9
9
 
10
10
  // src/form/seal.ts
11
11
  import JSZip from "jszip";
@@ -1057,4 +1057,4 @@ export {
1057
1057
  patchZipEntries,
1058
1058
  placeSealHwpx
1059
1059
  };
1060
- //# sourceMappingURL=chunk-EULS3PDF.js.map
1060
+ //# sourceMappingURL=chunk-4HRJISJF.js.map
@@ -9,7 +9,7 @@ import {
9
9
  import {
10
10
  safeMax,
11
11
  safeMin
12
- } from "./chunk-QXNQ2HNB.js";
12
+ } from "./chunk-A2W2JQ3S.js";
13
13
 
14
14
  // src/pdf/line-extract.ts
15
15
  import { OPS } from "pdfjs-dist/legacy/build/pdf.mjs";
@@ -655,19 +655,34 @@ function multiplyTransform(m, t) {
655
655
  m[1] * t[4] + m[3] * t[5] + m[5]
656
656
  ];
657
657
  }
658
- function extractImageRegions(fnArray, argsArray) {
658
+ function transformedRect(ctm, x, y, w, h) {
659
+ const corners = [[x, y], [x + w, y], [x, y + h], [x + w, y + h]];
660
+ const xs = corners.map(([u, v]) => ctm[0] * u + ctm[2] * v + ctm[4]);
661
+ const ys = corners.map(([u, v]) => ctm[1] * u + ctm[3] * v + ctm[5]);
662
+ return { x1: Math.min(...xs), y1: Math.min(...ys), x2: Math.max(...xs), y2: Math.max(...ys) };
663
+ }
664
+ function intersect(a, b) {
665
+ return b ? { 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) } : a;
666
+ }
667
+ function extractImageRegions(fnArray, argsArray, respectClip = false) {
659
668
  const regions = [];
660
669
  let ctm = [1, 0, 0, 1, 0, 0];
670
+ let clip = null;
661
671
  const stack = [];
672
+ let pathRect;
673
+ let pendingClip = false;
662
674
  for (let i = 0; i < fnArray.length; i++) {
663
675
  const op = fnArray[i];
664
676
  switch (op) {
665
677
  case OPS2.save:
666
- stack.push(ctm);
678
+ stack.push({ ctm, clip });
667
679
  break;
668
- case OPS2.restore:
669
- ctm = stack.pop() || [1, 0, 0, 1, 0, 0];
680
+ case OPS2.restore: {
681
+ const state = stack.pop();
682
+ ctm = state?.ctm ?? [1, 0, 0, 1, 0, 0];
683
+ clip = state?.clip ?? null;
670
684
  break;
685
+ }
671
686
  case OPS2.transform: {
672
687
  const t = argsArray[i];
673
688
  if (Array.isArray(t) && t.length >= 6) ctm = multiplyTransform(ctm, t);
@@ -675,28 +690,44 @@ function extractImageRegions(fnArray, argsArray) {
675
690
  }
676
691
  // Form XObject 는 /Matrix 공간에서 그린다 — pdfjs 인자 [matrix, bbox], End 에서 복원 (line-extract.ts 와 같음)
677
692
  case OPS2.paintFormXObjectBegin: {
678
- stack.push(ctm);
693
+ stack.push({ ctm, clip });
679
694
  const m = argsArray[i]?.[0];
680
695
  if (Array.isArray(m) && m.length >= 6) ctm = multiplyTransform(ctm, m);
681
696
  break;
682
697
  }
683
- case OPS2.paintFormXObjectEnd:
684
- ctm = stack.pop() || [1, 0, 0, 1, 0, 0];
698
+ case OPS2.paintFormXObjectEnd: {
699
+ const state = stack.pop();
700
+ ctm = state?.ctm ?? [1, 0, 0, 1, 0, 0];
701
+ clip = state?.clip ?? null;
702
+ break;
703
+ }
704
+ case OPS2.constructPath: {
705
+ const [ops, coords] = argsArray[i];
706
+ pathRect = pathRect === void 0 && ops?.length === 1 && ops[0] === OPS2.rectangle && coords?.length >= 4 ? transformedRect(ctm, coords[0], coords[1], coords[2], coords[3]) : null;
707
+ break;
708
+ }
709
+ case OPS2.clip:
710
+ case OPS2.eoClip:
711
+ pendingClip = true;
712
+ break;
713
+ case OPS2.endPath:
714
+ case OPS2.stroke:
715
+ case OPS2.closeStroke:
716
+ case OPS2.fill:
717
+ case OPS2.eoFill:
718
+ case OPS2.fillStroke:
719
+ case OPS2.eoFillStroke:
720
+ case OPS2.closeFillStroke:
721
+ case OPS2.closeEOFillStroke:
722
+ if (respectClip && pendingClip && pathRect) clip = intersect(pathRect, clip);
723
+ pathRect = void 0;
724
+ pendingClip = false;
685
725
  break;
686
726
  case OPS2.paintImageXObject:
687
727
  case OPS2.paintInlineImageXObject:
688
728
  case OPS2.paintImageMaskXObject:
689
729
  case OPS2.paintImageXObjectRepeat: {
690
- const corners = [[0, 0], [1, 0], [0, 1], [1, 1]];
691
- let x1 = Infinity, y1 = Infinity, x2 = -Infinity, y2 = -Infinity;
692
- for (const [u, v] of corners) {
693
- const x = ctm[0] * u + ctm[2] * v + ctm[4];
694
- const y = ctm[1] * u + ctm[3] * v + ctm[5];
695
- if (x < x1) x1 = x;
696
- if (x > x2) x2 = x;
697
- if (y < y1) y1 = y;
698
- if (y > y2) y2 = y;
699
- }
730
+ const { x1, y1, x2, y2 } = intersect(transformedRect(ctm, 0, 0, 1, 1), clip);
700
731
  if (x2 - x1 > 0 && y2 - y1 > 0) regions.push({ x1, y1, x2, y2 });
701
732
  break;
702
733
  }
@@ -2205,6 +2236,10 @@ function cellLineFills(box, contentLeft, cellRight, lineRight, fontSize) {
2205
2236
  // src/pdf/cell-text.ts
2206
2237
  var REGION_LABELS = /* @__PURE__ */ new Set(["\uC11C\uC6B8", "\uBD80\uC0B0", "\uB300\uAD6C", "\uC778\uCC9C", "\uAD11\uC8FC", "\uB300\uC804", "\uC6B8\uC0B0", "\uC138\uC885", "\uACBD\uAE30", "\uAC15\uC6D0", "\uCDA9\uBD81", "\uCDA9\uB0A8", "\uC804\uBD81", "\uC804\uB0A8", "\uACBD\uBD81", "\uACBD\uB0A8", "\uC81C\uC8FC", "\uC804\uAD6D"]);
2207
2238
  var CELL_PADDING = 2;
2239
+ function cleanCellText(text) {
2240
+ const stripped = text.replace(/^[\s]*[-–—]\s*\d+\s*[-–—][\s]*$/gm, "").trim();
2241
+ return stripped.split("\n").map((line) => collapseEvenSpacing(line)).join("\n");
2242
+ }
2208
2243
  var SPACE_GAP_RATIO = 0.17;
2209
2244
  function spaceGapThreshold(fontSize) {
2210
2245
  return Math.max(fontSize * SPACE_GAP_RATIO, 1);
@@ -2214,11 +2249,12 @@ function mapTextToCells(items, cells) {
2214
2249
  for (const cell of cells) {
2215
2250
  result.set(cell, []);
2216
2251
  }
2252
+ const candidates = items.length * cells.length >= 5e3 ? cellBandLookup(cells) : () => cells;
2217
2253
  for (const item of items) {
2218
2254
  const pad = CELL_PADDING;
2219
2255
  let bestCell = null;
2220
2256
  let bestScore = 0;
2221
- for (const cell of cells) {
2257
+ for (const cell of candidates(item.y - pad, item.y + (item.h || item.fontSize) + pad)) {
2222
2258
  const ix1 = Math.max(item.x, cell.bbox.x1 - pad);
2223
2259
  const ix2 = Math.min(item.x + item.w, cell.bbox.x2 + pad);
2224
2260
  const iy1 = Math.max(item.y, cell.bbox.y1 - pad);
@@ -2239,6 +2275,39 @@ function mapTextToCells(items, cells) {
2239
2275
  keepWordsInOneCell(result);
2240
2276
  return result;
2241
2277
  }
2278
+ function cellBandLookup(cells) {
2279
+ const sorted = cells.map((cell, index) => ({ cell, index })).sort((a, b) => a.cell.bbox.y1 - b.cell.bbox.y1);
2280
+ const build = (start, end) => {
2281
+ let lo = Infinity, hi = -Infinity;
2282
+ for (let i = start; i < end; i++) {
2283
+ lo = Math.min(lo, sorted[i].cell.bbox.y1);
2284
+ hi = Math.max(hi, sorted[i].cell.bbox.y2);
2285
+ }
2286
+ const band = { start, end, lo, hi };
2287
+ if (end - start > 8) {
2288
+ const mid = start + end >> 1;
2289
+ band.left = build(start, mid);
2290
+ band.right = build(mid, end);
2291
+ }
2292
+ return band;
2293
+ };
2294
+ const root = build(0, sorted.length);
2295
+ return (lo, hi) => {
2296
+ const found = [];
2297
+ const visit = (band) => {
2298
+ if (band.hi <= lo || band.lo >= hi) return;
2299
+ if (band.left && band.right) {
2300
+ visit(band.left);
2301
+ visit(band.right);
2302
+ } else for (let i = band.start; i < band.end; i++) {
2303
+ const entry = sorted[i];
2304
+ if (entry.cell.bbox.y2 > lo && entry.cell.bbox.y1 < hi) found.push(entry);
2305
+ }
2306
+ };
2307
+ visit(root);
2308
+ return found.sort((a, b) => a.index - b.index).map((entry) => entry.cell);
2309
+ };
2310
+ }
2242
2311
  function keepWordsInOneCell(result) {
2243
2312
  const owner = /* @__PURE__ */ new Map();
2244
2313
  for (const [cell, arr] of result) for (const it of arr) owner.set(it, cell);
@@ -2294,9 +2363,8 @@ function cellTextToString(items, wrap) {
2294
2363
  }
2295
2364
  }
2296
2365
  lines.push(curLine);
2297
- const merged = mergeSuperscriptRows(lines);
2298
- const textLines = merged.map((line) => {
2299
- const s = sortLineByX(line);
2366
+ const merged = mergeSuperscriptRows(lines).map((line) => sortLineByX(line));
2367
+ const textLines = merged.map((s) => {
2300
2368
  if (s.length === 1) return s[0].text;
2301
2369
  if (s.length === 2 && /^[가-힣]$/.test(s[0].text) && /^[가-힣]$/.test(s[1].text) && !!wrap?.lex && (wrap.lex.isWord(s[0].text + s[1].text) || wrap.lex.evidence(s[0].text, s[1].text) === "" || REGION_LABELS.has(s[0].text + s[1].text)) && s[1].x - (s[0].x + s[0].w) >= Math.max(s[0].fontSize, s[1].fontSize) * 1.5 && s[1].x + s[1].w - s[0].x >= wrap.box.x2 - wrap.box.x1 - Math.max(s[0].fontSize, s[1].fontSize) * 2) return s[0].text + s[1].text;
2302
2370
  const evenSpaced = detectEvenSpacedItems(s, true);
@@ -2320,16 +2388,16 @@ function cellTextToString(items, wrap) {
2320
2388
  }
2321
2389
  return result;
2322
2390
  });
2323
- const scripted = (s) => tagScripts(s, merged.map((l) => sortLineByX([...l])));
2391
+ const scripted = (s) => tagScripts(s, merged);
2324
2392
  if (!wrap) return scripted(mergeCellTextLines(textLines));
2325
2393
  let contentLeft = Infinity;
2326
2394
  for (const it of items) if (it.x < contentLeft) contentLeft = it.x;
2327
- const lineEnds = merged.map((line) => {
2328
- const s = sortLineByX(line);
2395
+ const lineEnds = merged.map((s) => {
2329
2396
  let right = -Infinity;
2330
2397
  for (const it of s) if (it.x + it.w > right) right = it.x + it.w;
2331
2398
  const first = s[0];
2332
- return { right, fontSize: first.fontSize, firstCharW: first.w / Math.max(1, [...first.text].length) };
2399
+ const visible = first.text.replace(/<\/?u>|~~/g, "");
2400
+ return { right, fontSize: first.fontSize, firstCharW: first.w / Math.max(1, [...visible].length) };
2333
2401
  });
2334
2402
  let cellRight = -Infinity;
2335
2403
  for (const e of lineEnds) if (e.right > cellRight) cellRight = e.right;
@@ -2373,15 +2441,16 @@ function mergeSuperscriptRows(lines) {
2373
2441
  function detectEvenSpacedItems(items, cellLine = false) {
2374
2442
  const result = new Array(items.length).fill(false);
2375
2443
  if (items.length < 3) return result;
2376
- if (cellLine && items.every((it) => /^[가-힣]$/.test(it.text)) && items.slice(1).every((it) => !it.hasSpaceBefore || it.syntheticSpace) && items.slice(1).every((it, k) => it.x - (items[k].x + items[k].w) >= it.fontSize * 0.1)) {
2377
- markEvenRun(items, result, 0, items.length);
2444
+ const visible = items.map((it) => it.text.replace(/<\/?u>|~~/g, ""));
2445
+ if (cellLine && visible.every((text) => /^[가-힣]$/.test(text)) && items.slice(1).every((it) => !it.hasSpaceBefore || it.syntheticSpace) && items.slice(1).every((it, k) => it.x - (items[k].x + items[k].w) >= it.fontSize * 0.1)) {
2446
+ markEvenRun(items, visible, result, 0, items.length);
2378
2447
  if (result.some(Boolean)) return result;
2379
2448
  }
2380
2449
  let runStart = -1;
2381
2450
  for (let i = 0; i < items.length; i++) {
2382
- const isShortKorean = /^[가-힣]{1}$/.test(items[i].text) || /^[\d]{1}$/.test(items[i].text);
2451
+ const isShortKorean = /^[가-힣]{1}$/.test(visible[i]) || /^[\d]{1}$/.test(visible[i]);
2383
2452
  if (isShortKorean && runStart >= 0 && items[i].hasSpaceBefore) {
2384
- if (i - runStart >= 3) markEvenRun(items, result, runStart, i);
2453
+ if (i - runStart >= 3) markEvenRun(items, visible, result, runStart, i);
2385
2454
  runStart = i;
2386
2455
  continue;
2387
2456
  }
@@ -2389,7 +2458,7 @@ function detectEvenSpacedItems(items, cellLine = false) {
2389
2458
  const gap = items[i].x - (items[i - 1].x + items[i - 1].w);
2390
2459
  const maxRunGap = Math.max(items[i].fontSize * 3, 30);
2391
2460
  if (gap > maxRunGap) {
2392
- if (i - runStart >= 3) markEvenRun(items, result, runStart, i);
2461
+ if (i - runStart >= 3) markEvenRun(items, visible, result, runStart, i);
2393
2462
  runStart = i;
2394
2463
  continue;
2395
2464
  }
@@ -2398,19 +2467,19 @@ function detectEvenSpacedItems(items, cellLine = false) {
2398
2467
  if (runStart < 0) runStart = i;
2399
2468
  } else {
2400
2469
  if (runStart >= 0 && i - runStart >= 3) {
2401
- markEvenRun(items, result, runStart, i);
2470
+ markEvenRun(items, visible, result, runStart, i);
2402
2471
  }
2403
2472
  runStart = -1;
2404
2473
  }
2405
2474
  }
2406
2475
  if (runStart >= 0 && items.length - runStart >= 3) {
2407
- markEvenRun(items, result, runStart, items.length);
2476
+ markEvenRun(items, visible, result, runStart, items.length);
2408
2477
  }
2409
2478
  return result;
2410
2479
  }
2411
- function markEvenRun(items, result, start, end) {
2480
+ function markEvenRun(items, visible, result, start, end) {
2412
2481
  let dateOnly = true;
2413
- for (let i = start; i < end; i++) if (!/^[년월일시분초]$/.test(items[i].text)) {
2482
+ for (let i = start; i < end; i++) if (!/^[년월일시분초]$/.test(visible[i])) {
2414
2483
  dateOnly = false;
2415
2484
  break;
2416
2485
  }
@@ -2632,14 +2701,20 @@ function filterHiddenText(items, pageWidth, pageHeight, originX = 0, originY = 0
2632
2701
  return { visible, hiddenCount };
2633
2702
  }
2634
2703
  function collapseEvenSpacing(text, whole = true) {
2635
- const tokens = text.split(" ");
2636
- const singleCharCount = tokens.filter((t) => t.length === 1).length;
2637
- if (whole && tokens.length >= 3 && singleCharCount / tokens.length >= 0.7 && !isDateUnitBlank(tokens)) {
2638
- return tokens.join("");
2704
+ if (whole) {
2705
+ const tokens = text.split(" ");
2706
+ const visible = tokens.map((t) => t.replace(/<\/?u>|~~/g, ""));
2707
+ const singleCharCount = visible.filter((t) => t.length === 1).length;
2708
+ if (tokens.length >= 3 && singleCharCount / tokens.length >= 0.7 && !isDateUnitBlank(visible)) return tokens.join("");
2639
2709
  }
2640
2710
  return text.replace(
2641
2711
  /(?<![^\s>])[가-힣](?: [가-힣\d]){2,}(?![^\s<])/g,
2642
- (match) => isDateUnitBlank(match.split(" ")) ? match : match.replace(/ /g, "")
2712
+ (match, offset) => {
2713
+ const before = text.slice(0, offset).replace(/(?:<\/?u>|~~)+$/, "");
2714
+ const after = text.slice(offset + match.length).replace(/^(?:<\/?u>|~~)+/, "");
2715
+ if (/\S$/.test(before) || /^\S/.test(after)) return match;
2716
+ return isDateUnitBlank(match.split(" ")) ? match : match.replace(/ /g, "");
2717
+ }
2643
2718
  );
2644
2719
  }
2645
2720
  function isDateUnitBlank(tokens) {
@@ -5002,27 +5077,6 @@ function splitEdgeSpannedColumns(items, gapThreshold, depth) {
5002
5077
  ];
5003
5078
  }
5004
5079
 
5005
- // src/pdf/blank-fills.ts
5006
- var FILL_EDGE_GAP = 6;
5007
- var FILL_MAX_THICKNESS = 2;
5008
- function fillBlanks(items, horizontals, verticals = []) {
5009
- const widened = /* @__PURE__ */ new Map();
5010
- const used = /* @__PURE__ */ new Set();
5011
- for (const h of horizontals) {
5012
- if (h.lineWidth > FILL_MAX_THICKNESS || Math.abs(h.y1 - h.y2) > 1) continue;
5013
- const x1 = Math.min(h.x1, h.x2), x2 = Math.max(h.x1, h.x2);
5014
- const row = items.filter((i) => i.y >= h.y1 && i.y - h.y1 <= Math.max(3, i.fontSize * 0.5));
5015
- const left = row.find((i) => i.x + i.w <= x1 + 1 && x1 - (i.x + i.w) <= FILL_EDGE_GAP);
5016
- const right = row.find((i) => i.x >= x2 - 1 && i.x - x2 <= FILL_EDGE_GAP);
5017
- if (!left || !right || widened.has(left) || row.some((i) => i.x < x2 && i.x + i.w > x1) || x2 - x1 < 2 * left.fontSize) continue;
5018
- if (verticals.some((v) => (Math.abs(v.x1 - x1) <= 3 || Math.abs(v.x1 - x2) <= 3) && Math.min(v.y1, v.y2) - 3 <= h.y1 && Math.max(v.y1, v.y2) + 3 >= h.y1)) continue;
5019
- widened.set(left, { ...left, text: left.text.trimEnd() + " ", w: x2 - left.x });
5020
- used.add(h);
5021
- }
5022
- if (!used.size) return { items, horizontals };
5023
- return { items: items.map((i) => widened.get(i) ?? i), horizontals: horizontals.filter((h) => !used.has(h)) };
5024
- }
5025
-
5026
5080
  // src/pdf/two-column.ts
5027
5081
  var GUTTER_SCAN_LO = 0.3;
5028
5082
  var GUTTER_SCAN_HI = 0.7;
@@ -5257,6 +5311,55 @@ function orderByPanels(units, rectOf, gutters) {
5257
5311
  return ordered;
5258
5312
  }
5259
5313
 
5314
+ // src/pdf/image-panels.ts
5315
+ function splitImagePanels(items, figures) {
5316
+ if (figures.length === 0) return null;
5317
+ const rects = items.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }));
5318
+ const cuts = detectPanelGutters([...rects, ...figures]);
5319
+ if (!cuts || cuts.length !== 2 || items.some((i) => cuts.some((x) => i.x < x && i.x + i.w > x))) return null;
5320
+ const groups = [
5321
+ items.filter((i) => i.x + i.w <= cuts[0]),
5322
+ items.filter((i) => i.x >= cuts[0] && i.x + i.w <= cuts[1]),
5323
+ items.filter((i) => i.x >= cuts[1])
5324
+ ];
5325
+ const rows = groupByY(items);
5326
+ const sharedRows = rows.filter((row) => new Set(row.map((i) => i.x >= cuts[1] ? 2 : i.x >= cuts[0] ? 1 : 0)).size === 3).length;
5327
+ if (sharedRows / Math.min(...groups.map((group) => groupByY(group).length)) > 0.65) return null;
5328
+ for (const row of rows) {
5329
+ const ordered = [...row].sort((a, b) => a.x - b.x);
5330
+ let start = ordered[0].x, end = start + ordered[0].w, height = ordered[0].h || ordered[0].fontSize;
5331
+ for (const i of ordered.slice(1)) {
5332
+ const h = i.h || i.fontSize;
5333
+ if (i.x - end > Math.max(height, h) * 2) start = i.x;
5334
+ end = Math.max(end, i.x + i.w);
5335
+ height = h;
5336
+ if (cuts.some((x) => start < x && end > x)) return null;
5337
+ }
5338
+ }
5339
+ return groups;
5340
+ }
5341
+
5342
+ // src/pdf/blank-fills.ts
5343
+ var FILL_EDGE_GAP = 6;
5344
+ var FILL_MAX_THICKNESS = 2;
5345
+ function fillBlanks(items, horizontals, verticals = []) {
5346
+ const widened = /* @__PURE__ */ new Map();
5347
+ const used = /* @__PURE__ */ new Set();
5348
+ for (const h of horizontals) {
5349
+ if (h.lineWidth > FILL_MAX_THICKNESS || Math.abs(h.y1 - h.y2) > 1) continue;
5350
+ const x1 = Math.min(h.x1, h.x2), x2 = Math.max(h.x1, h.x2);
5351
+ const row = items.filter((i) => i.y >= h.y1 && i.y - h.y1 <= Math.max(3, i.fontSize * 0.5));
5352
+ const left = row.find((i) => i.x + i.w <= x1 + 1 && x1 - (i.x + i.w) <= FILL_EDGE_GAP);
5353
+ const right = row.find((i) => i.x >= x2 - 1 && i.x - x2 <= FILL_EDGE_GAP);
5354
+ if (!left || !right || widened.has(left) || row.some((i) => i.x < x2 && i.x + i.w > x1) || x2 - x1 < 2 * left.fontSize) continue;
5355
+ if (verticals.some((v) => (Math.abs(v.x1 - x1) <= 3 || Math.abs(v.x1 - x2) <= 3) && Math.min(v.y1, v.y2) - 3 <= h.y1 && Math.max(v.y1, v.y2) + 3 >= h.y1)) continue;
5356
+ widened.set(left, { ...left, text: left.text.trimEnd() + " ", w: x2 - left.x });
5357
+ used.add(h);
5358
+ }
5359
+ if (!used.size) return { items, horizontals };
5360
+ return { items: items.map((i) => widened.get(i) ?? i), horizontals: horizontals.filter((h) => !used.has(h)) };
5361
+ }
5362
+
5260
5363
  // src/pdf/columns.ts
5261
5364
  function isProseSpread(items) {
5262
5365
  if (items.length < 3) return false;
@@ -5502,8 +5605,8 @@ function markUnderlineItems(items, horizontals, verticals) {
5502
5605
  if (items.length === 0 || horizontals.length === 0) return underlines;
5503
5606
  for (const line of horizontals) {
5504
5607
  if (line.lineWidth > UNDER_MAX_THICKNESS) continue;
5505
- if (touchesVertical(line, verticals)) continue;
5506
- if (isRepeatedSpanRule(line, horizontals)) continue;
5608
+ const enclosed = insideTallCell(line, verticals, 0);
5609
+ if (!enclosed && (touchesVertical(line, verticals) || isRepeatedSpanRule(line, horizontals))) continue;
5507
5610
  const matches = [];
5508
5611
  for (const item of items) {
5509
5612
  const h = item.h > 0 ? item.h : item.fontSize;
@@ -5522,10 +5625,12 @@ function markUnderlineItems(items, horizontals, verticals) {
5522
5625
  maxH = Math.max(maxH, m.h > 0 ? m.h : m.fontSize);
5523
5626
  covered += m.w;
5524
5627
  }
5628
+ const inset = enclosed && insideTallCell(line, verticals, maxH);
5629
+ if (enclosed && !inset && (touchesVertical(line, verticals) || isRepeatedSpanRule(line, horizontals))) continue;
5525
5630
  const pad = Math.max(maxH * UNDER_OWNER_PAD_EM, UNDER_OWNER_PAD_MIN_PT);
5526
5631
  if (line.x1 < x1 - pad || line.x2 > x2 + pad) continue;
5527
5632
  if (covered < (line.x2 - line.x1) * UNDER_MIN_COVERAGE) continue;
5528
- if (hasBoxTopPair(line, maxH, horizontals)) continue;
5633
+ if (hasBoxTopPair(line, maxH, horizontals, inset ? items : void 0)) continue;
5529
5634
  matches.sort((a, b) => a.x - b.x);
5530
5635
  let hole = false;
5531
5636
  for (let i = 1; i < matches.length; i++) {
@@ -5540,6 +5645,18 @@ function markUnderlineItems(items, horizontals, verticals) {
5540
5645
  }
5541
5646
  return underlines;
5542
5647
  }
5648
+ function insideTallCell(line, verticals, em) {
5649
+ let left = false, right = false;
5650
+ for (const v of verticals) {
5651
+ const lo = Math.min(v.y1, v.y2), hi = Math.max(v.y1, v.y2);
5652
+ if (lo > line.y1 || hi < line.y1) continue;
5653
+ if (v.x1 >= line.x1 - 0.5 && v.x1 <= line.x2 + 0.5) return false;
5654
+ if (hi - lo <= em * UNDER_BOX_PAIR_MAX_EM) continue;
5655
+ if (v.x1 < line.x1 - 0.5) left = true;
5656
+ if (v.x1 > line.x2 + 0.5) right = true;
5657
+ }
5658
+ return left && right;
5659
+ }
5543
5660
  function touchesVertical(line, verticals) {
5544
5661
  for (const v of verticals) {
5545
5662
  if (v.x1 < line.x1 - UNDER_GRID_EPS || v.x1 > line.x2 + UNDER_GRID_EPS) continue;
@@ -5548,7 +5665,7 @@ function touchesVertical(line, verticals) {
5548
5665
  }
5549
5666
  return false;
5550
5667
  }
5551
- function hasBoxTopPair(line, maxH, horizontals) {
5668
+ function hasBoxTopPair(line, maxH, horizontals, cellItems) {
5552
5669
  const w = line.x2 - line.x1;
5553
5670
  if (w <= 0) return false;
5554
5671
  for (const o of horizontals) {
@@ -5558,7 +5675,13 @@ function hasBoxTopPair(line, maxH, horizontals) {
5558
5675
  const ow = o.x2 - o.x1;
5559
5676
  if (ow <= 0) continue;
5560
5677
  const overlap2 = Math.min(line.x2, o.x2) - Math.max(line.x1, o.x1);
5561
- if (overlap2 / Math.max(w, ow) >= UNDER_BOX_PAIR_OVERLAP) return true;
5678
+ if (overlap2 / Math.max(w, ow) < UNDER_BOX_PAIR_OVERLAP) continue;
5679
+ const covered = cellItems?.reduce((sum, item) => {
5680
+ const below = item.y - o.y1;
5681
+ if (below < 0.5 || below > 3 || !item.text.trim()) return sum;
5682
+ return sum + Math.max(0, Math.min(o.x2, item.x + item.w) - Math.max(o.x1, item.x));
5683
+ }, 0) ?? 0;
5684
+ if (covered < ow * UNDER_MIN_COVERAGE) return true;
5562
5685
  }
5563
5686
  return false;
5564
5687
  }
@@ -5639,21 +5762,21 @@ function rules(lines, dir) {
5639
5762
  const sorted = [...lines].sort((a, b) => dir === "h" ? a.y1 - b.y1 : a.x1 - b.x1);
5640
5763
  return { dir, pos: sorted.map((l) => dir === "h" ? l.y1 : l.x1), lines: sorted };
5641
5764
  }
5642
- function seen(r, at, a1, a2) {
5765
+ function seen(r, at, a1, a2, near = EDGE_NEAR2) {
5643
5766
  const len = a2 - a1;
5644
5767
  if (len <= 0) return false;
5645
- const covered = coverage(r, at, a1, a2);
5768
+ const covered = coverage(r, at, a1, a2, near);
5646
5769
  return covered >= len * EDGE_COVER && len - covered <= EDGE_SLACK;
5647
5770
  }
5648
- function coverage(r, at, a1, a2) {
5771
+ function coverage(r, at, a1, a2, near) {
5649
5772
  let i = 0, j = r.pos.length;
5650
5773
  while (i < j) {
5651
5774
  const m = i + j >> 1;
5652
- if (r.pos[m] < at - EDGE_NEAR2) i = m + 1;
5775
+ if (r.pos[m] < at - near) i = m + 1;
5653
5776
  else j = m;
5654
5777
  }
5655
5778
  const spans = [];
5656
- for (; i < r.pos.length && r.pos[i] <= at + EDGE_NEAR2; i++) {
5779
+ for (; i < r.pos.length && r.pos[i] <= at + near; i++) {
5657
5780
  const l = r.lines[i];
5658
5781
  const l1 = r.dir === "h" ? Math.min(l.x1, l.x2) : Math.min(l.y1, l.y2), l2 = r.dir === "h" ? Math.max(l.x1, l.x2) : Math.max(l.y1, l.y2);
5659
5782
  const lo = Math.max(a1, l1), hi = Math.min(a2, l2);
@@ -5673,10 +5796,10 @@ function coverage(r, at, a1, a2) {
5673
5796
  }
5674
5797
  return covered + e - s;
5675
5798
  }
5676
- function edgesOf(box, h, v) {
5799
+ function edgesOf(box, h, v, hNear = EDGE_NEAR2) {
5677
5800
  return {
5678
- t: seen(h, box.y2, box.x1, box.x2),
5679
- b: seen(h, box.y1, box.x1, box.x2),
5801
+ t: seen(h, box.y2, box.x1, box.x2, hNear),
5802
+ b: seen(h, box.y1, box.x1, box.x2, hNear),
5680
5803
  l: seen(v, box.x1, box.y1, box.y2),
5681
5804
  r: seen(v, box.x2, box.y1, box.y2)
5682
5805
  };
@@ -5685,7 +5808,10 @@ function recordClipCellEdges(grids, horizontals, verticals, nonRules) {
5685
5808
  if (!grids.some((g) => g.cells)) return;
5686
5809
  const h = rules(nonRules?.size ? horizontals.filter((l) => !nonRules.has(l)) : horizontals, "h");
5687
5810
  const v = rules(nonRules?.size ? verticals.filter((l) => !nonRules.has(l)) : verticals, "v");
5688
- for (const g of grids) for (const c of g.cells ?? []) CLIP_CELL_EDGES.set(c, edgesOf(c.bbox, h, v));
5811
+ for (const g of grids) for (const c of g.cells ?? []) {
5812
+ const near = c.filler ? Math.min(EDGE_NEAR2, (c.bbox.y2 - c.bbox.y1) / 3) : EDGE_NEAR2;
5813
+ CLIP_CELL_EDGES.set(c, edgesOf(c.bbox, h, v, near));
5814
+ }
5689
5815
  }
5690
5816
  function takeClipCellEdges(from, to) {
5691
5817
  const e = CLIP_CELL_EDGES.get(from);
@@ -5697,6 +5823,36 @@ function joinCellEdges(a, b) {
5697
5823
  CELL_EDGES.set(a, { t: u.t, b: d.b, l: u.l || d.l, r: u.r || d.r });
5698
5824
  }
5699
5825
 
5826
+ // src/pdf/table-unit-row.ts
5827
+ var UNIT = /^\s*\(\s*단위\s*[::]/;
5828
+ function rebuildUnitLine(items, grid) {
5829
+ const nearby = items.filter((item) => item.y >= grid.bbox.y2 && item.y - grid.bbox.y2 <= 18 && item.x >= grid.bbox.x1 - 3 && item.x + item.w <= grid.bbox.x2 + 3);
5830
+ for (const y of [...new Set(nearby.map((item) => Math.round(item.y)))].sort((a, b) => a - b)) {
5831
+ const line = nearby.filter((item) => Math.abs(item.y - y) <= 1).sort((a, b) => a.x - b.x);
5832
+ if (UNIT.test(line.map((item) => item.text).join(""))) return line;
5833
+ }
5834
+ return [];
5835
+ }
5836
+ function prependUnitRow(cells, cols, line, usedItems) {
5837
+ const text = cleanCellText(line.map((item) => item.text).join(""));
5838
+ cells.unshift(Array.from({ length: cols }, (_, c) => ({ text: c === 0 ? text : "", colSpan: c === 0 ? cols : 1, rowSpan: 1 })));
5839
+ for (const cell of cells[0]) CELL_EDGES.set(cell, NO_EDGES);
5840
+ for (const item of line) usedItems.add(item);
5841
+ }
5842
+ function attachUnitRow(items, grid, cells, cols, usedItems) {
5843
+ const all = cells.flat();
5844
+ if (all.filter((c) => c.text.trim()).length * 2 < all.length || UNIT.test(cells[0]?.[0]?.text ?? "")) return false;
5845
+ const above = items.filter((it) => !usedItems.has(it) && it.y >= grid.bbox.y2 && it.y - grid.bbox.y2 <= 8 && it.x >= grid.bbox.x1 - 3 && it.x + it.w <= grid.bbox.x2 + 3);
5846
+ let nearest = Infinity;
5847
+ for (const it of above) nearest = Math.min(nearest, it.y);
5848
+ const line = above.filter((it) => Math.abs(it.y - nearest) <= 1).sort((a, b) => a.x - b.x);
5849
+ const text = line.map((it) => it.text).join("");
5850
+ const inset = line.length ? grid.bbox.x2 - (line[line.length - 1].x + line[line.length - 1].w) : 0;
5851
+ if (!line.length || !UNIT.test(text) || inset < 4.6 || inset > 5.6) return false;
5852
+ prependUnitRow(cells, cols, line, usedItems);
5853
+ return true;
5854
+ }
5855
+
5700
5856
  // src/pdf/page-frame.ts
5701
5857
  function isPageFrameGrid(grid, cells, pageWidth, pageHeight, items = []) {
5702
5858
  const b = grid.bbox;
@@ -6421,8 +6577,9 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
6421
6577
  const lineGrids = detectTables ? buildTableGrids(horizontals, verticals) : [];
6422
6578
  const tableClipGrids = dropHeadBandClipGrids(dropInsetClipGrids(dropShadingClipGrids(clipGrids, lineGrids, extracted.fillRects, verticals), lineGrids), lineGrids);
6423
6579
  const grids = [...tableClipGrids, ...dropGridsInside(lineGrids, tableClipGrids, clipResult.containers)];
6580
+ 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 }));
6424
6581
  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) {
6425
- return extractPageBlocksFallback(items, pageNum, true, detectTables, lex);
6582
+ return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
6426
6583
  }
6427
6584
  const ruled = detectTables && clipGrids.length === 0 ? detectRuledBandTables(horizontals, verticals, items, pageNum) : [];
6428
6585
  if (detectTables && clipGrids.length === 0 && ruled.length === 0 && lineGrids.length === 0) ruled.push(...detectTextBoxTables(extracted.hiddenBoxes, items, pageNum));
@@ -6431,7 +6588,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
6431
6588
  return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, ruled, rawRules);
6432
6589
  }
6433
6590
  if (detectTables && stackedTableBands(items)) {
6434
- return extractPageBlocksFallback(items, pageNum, true, detectTables, lex);
6591
+ return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
6435
6592
  }
6436
6593
  const sidebar = splitSidebarTitleRegion(items);
6437
6594
  if (sidebar && grids.every((grid) => grid.rowYs.length === 2 && grid.colXs.length === 2 && !items.some((item) => item.x + item.w / 2 >= grid.bbox.x1 && item.x + item.w / 2 <= grid.bbox.x2 && item.y + item.h / 2 >= grid.bbox.y1 && item.y + item.h / 2 <= grid.bbox.y2))) {
@@ -6441,8 +6598,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
6441
6598
  const imageRegions = extractImageRegions(opList.fnArray, opList.argsArray).filter((r) => r.x2 - r.x1 >= 8 && r.y2 - r.y1 >= 8);
6442
6599
  return extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions, lex, [], rawRules);
6443
6600
  }
6444
- const figures = extractImageRegions(opList.fnArray, opList.argsArray).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 }));
6445
- return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures);
6601
+ return extractPageBlocksFallback(items, pageNum, true, detectTables, lex, figures());
6446
6602
  }
6447
6603
  var STRIKE_MAX_THICKNESS = 2;
6448
6604
  var STRIKE_MAX_THICKNESS_RATIO = 0.25;
@@ -6545,10 +6701,6 @@ function isSparseProseGrid(table) {
6545
6701
  const prose = filled.filter((t) => t.length >= 60 && /[.!?。]/.test(t)).reduce((n, t) => n + t.length, 0);
6546
6702
  return prose >= chars * 0.6;
6547
6703
  }
6548
- function cleanCellText(text) {
6549
- const stripped = text.replace(/^[\s]*[-–—]\s*\d+\s*[-–—][\s]*$/gm, "").trim();
6550
- return stripped.split("\n").map((line) => collapseEvenSpacing(line)).join("\n");
6551
- }
6552
6704
  var FRAME_RECT_TOL = 1.5;
6553
6705
  function takePendingNested(pending, cellBox, clipCell) {
6554
6706
  const out = [];
@@ -6661,25 +6813,13 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
6661
6813
  markImageCell(irGrid[cell.row][cell.col]);
6662
6814
  }
6663
6815
  if (cell.filler && !cellItems.length) FILLER_CELLS.add(irGrid[cell.row][cell.col]);
6664
- if (grid.cells && cellItems.length) recordCellLines(irGrid[cell.row][cell.col], cellItems);
6816
+ if (cellItems.length) recordCellLines(irGrid[cell.row][cell.col], cellItems);
6665
6817
  takeClipCellEdges(cell, irGrid[cell.row][cell.col]);
6666
6818
  }
6667
6819
  let finalGrid = irGrid;
6668
6820
  let finalRows = numRows;
6669
6821
  let rebuiltUsed = false;
6670
- let unitLine = [];
6671
- let unitText = "";
6672
- if (!grid.cells && numRows >= 3 && numRows <= 5 && numCols >= 3) {
6673
- const nearby = items.filter((item) => item.y >= grid.bbox.y2 && item.y - grid.bbox.y2 <= 18 && item.x >= grid.bbox.x1 - 3 && item.x + item.w <= grid.bbox.x2 + 3);
6674
- for (const y of [...new Set(nearby.map((item) => Math.round(item.y)))].sort((a, b) => a - b)) {
6675
- const line = nearby.filter((item) => Math.abs(item.y - y) <= 1).sort((a, b) => a.x - b.x);
6676
- const text = line.map((item) => item.text).join("");
6677
- if (!/^\s*\(\s*단위\s*[::]/.test(text)) continue;
6678
- unitLine = line;
6679
- unitText = text;
6680
- break;
6681
- }
6682
- }
6822
+ const unitLine = !grid.cells && numRows >= 3 && numRows <= 5 && numCols >= 3 ? rebuildUnitLine(items, grid) : [];
6683
6823
  if (!grid.cells && numRows <= 5 && numCols >= 3 && !nestedAttached && (numRows <= 2 || unitLine.length > 0)) {
6684
6824
  const rebuilt = normalizeUndersegmentedTable(irGrid, grid.colXs, textItems, grid.rowYs);
6685
6825
  if (rebuilt) {
@@ -6694,23 +6834,10 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
6694
6834
  }
6695
6835
  }
6696
6836
  if (unitLine.length > 0 && rebuiltUsed && !/^\s*\(\s*단위\s*[::]/.test(finalGrid[0]?.[0]?.text ?? "")) {
6697
- finalGrid.unshift(Array.from({ length: numCols }, (_, c) => ({ text: c === 0 ? cleanCellText(unitText) : "", colSpan: c === 0 ? numCols : 1, rowSpan: 1 })));
6837
+ prependUnitRow(finalGrid, numCols, unitLine, usedItems);
6698
6838
  finalRows++;
6699
- for (const item of unitLine) usedItems.add(item);
6700
- }
6701
- const filledCells = finalGrid.flat().filter((c) => c.text.trim()).length;
6702
- if (!rebuiltUsed && filledCells * 2 >= finalGrid.flat().length && !/^\s*\(\s*단위\s*[::]/.test(finalGrid[0]?.[0]?.text ?? "")) {
6703
- const above = items.filter((it) => !usedItems.has(it) && it.y >= grid.bbox.y2 && it.y - grid.bbox.y2 <= 8 && it.x >= grid.bbox.x1 - 3 && it.x + it.w <= grid.bbox.x2 + 3);
6704
- const line = above.filter((it) => Math.abs(it.y - Math.min(...above.map((a) => a.y))) <= 1).sort((a, b) => a.x - b.x);
6705
- const text = line.map((it) => it.text).join("");
6706
- const inset = line.length ? grid.bbox.x2 - (line[line.length - 1].x + line[line.length - 1].w) : 0;
6707
- if (line.length && /^\s*\(\s*단위\s*[::]/.test(text) && inset >= 4.6 && inset <= 5.6) {
6708
- finalGrid.unshift(Array.from({ length: numCols }, (_, c) => ({ text: c === 0 ? cleanCellText(text) : "", colSpan: c === 0 ? numCols : 1, rowSpan: 1 })));
6709
- if (grid.cells) for (const u of finalGrid[0]) CELL_EDGES.set(u, NO_EDGES);
6710
- finalRows++;
6711
- for (const item of line) usedItems.add(item);
6712
- }
6713
6839
  }
6840
+ if (!rebuiltUsed && attachUnitRow(items, grid, finalGrid, numCols, usedItems)) finalRows++;
6714
6841
  let semanticOneColumn = false;
6715
6842
  if (!grid.cells && numCols === 1 && numGridRows >= 2) {
6716
6843
  const populatedRows = finalGrid.filter((row) => row[0]?.text.trim());
@@ -7159,6 +7286,8 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
7159
7286
  syntheticSpace: i.syntheticSpace
7160
7287
  }));
7161
7288
  const textRects = items.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }));
7289
+ const imagePanels = fullPage ? splitImagePanels(items, figures) : null;
7290
+ if (imagePanels) return imagePanels.flatMap((group) => extractPageBlocksFallback(group, pageNum, false, detectTables, lex));
7162
7291
  const earlyProseCut = fullPage && detectTables ? findTwoColumnProseCutX(clusterItems) ?? persistentGutter(textRects) ?? (figures.length > 0 ? detectColumnGutter([...textRects, ...figures]) : null) : null;
7163
7292
  if (earlyProseCut !== null) {
7164
7293
  const band = topTableBand(items);
@@ -7275,4 +7404,4 @@ export {
7275
7404
  joinCellEdges,
7276
7405
  extractPageBlocksWithLines
7277
7406
  };
7278
- //# sourceMappingURL=chunk-KBIQGGNY.js.map
7407
+ //# sourceMappingURL=chunk-4TSYMJDL.js.map