kordoc 4.24.15 → 4.24.16

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 (124) hide show
  1. package/README.md +4 -4
  2. package/dist/{-CCZTES5C.js → -ZKOPHIGY.js} +11 -11
  3. package/dist/{chunk-XW7L76FE.js → chunk-2UXGDAWQ.js} +2 -2
  4. package/dist/{chunk-6WEHXC2D.js → chunk-3TXAIEXL.js} +46 -14
  5. package/dist/chunk-3TXAIEXL.js.map +1 -0
  6. package/dist/{chunk-T7MDUY5X.js → chunk-5Y7E5VTW.js} +2 -2
  7. package/dist/{chunk-UGO3UFXX.js → chunk-6K2SYTNJ.js} +23 -9
  8. package/dist/chunk-6K2SYTNJ.js.map +1 -0
  9. package/dist/{chunk-VSYLST4K.js → chunk-6KELCESN.js} +24 -10
  10. package/dist/chunk-6KELCESN.js.map +1 -0
  11. package/dist/{chunk-UV2ZS65C.js → chunk-6PPVAQ2N.js} +2 -2
  12. package/dist/{chunk-7Y4MVNYA.js → chunk-BHY2QAPM.js} +11 -11
  13. package/dist/{chunk-4ZNM7XRW.cjs → chunk-CCH6BUNI.cjs} +6 -6
  14. package/dist/{chunk-4ZNM7XRW.cjs.map → chunk-CCH6BUNI.cjs.map} +1 -1
  15. package/dist/{chunk-7YCKDE5X.js → chunk-DH564VPR.js} +2 -2
  16. package/dist/{chunk-E5H5WHJH.js → chunk-F3VIVCIF.js} +2 -2
  17. package/dist/{chunk-MTAQVHCB.js → chunk-FK7KGS5D.js} +2 -2
  18. package/dist/{chunk-6KQWC2KN.cjs → chunk-GPZMU2CM.cjs} +3 -3
  19. package/dist/{chunk-6KQWC2KN.cjs.map → chunk-GPZMU2CM.cjs.map} +1 -1
  20. package/dist/{chunk-IGLRJCO6.js → chunk-GYVSGOQW.js} +2 -2
  21. package/dist/{chunk-K37LMDT5.js → chunk-J5M5OW4S.js} +2 -2
  22. package/dist/{chunk-DULJ7PPP.js → chunk-JS5CL2ZI.js} +46 -14
  23. package/dist/chunk-JS5CL2ZI.js.map +1 -0
  24. package/dist/{chunk-Y3VNNGB2.js → chunk-K3OLWLXH.js} +2 -2
  25. package/dist/{chunk-PCHGHLUP.js → chunk-LPNWTWOQ.js} +2 -2
  26. package/dist/{chunk-GDE4YE2P.cjs → chunk-NS2F4DXC.cjs} +3 -3
  27. package/dist/{chunk-GDE4YE2P.cjs.map → chunk-NS2F4DXC.cjs.map} +1 -1
  28. package/dist/{chunk-VNB2IKVA.js → chunk-NUQ5B2ZM.js} +3 -3
  29. package/dist/{chunk-OICA67AT.cjs → chunk-NVOB6OHS.cjs} +2 -2
  30. package/dist/{chunk-OICA67AT.cjs.map → chunk-NVOB6OHS.cjs.map} +1 -1
  31. package/dist/{chunk-EY3PT2X7.js → chunk-QJA3KGRP.js} +2 -2
  32. package/dist/{chunk-KOHEEPQV.js → chunk-QOMLSZLM.js} +2 -2
  33. package/dist/{chunk-HZFYPOBJ.js → chunk-S2VWNC2W.js} +3 -3
  34. package/dist/{chunk-YAK4U7CC.cjs → chunk-SR6DJBPM.cjs} +45 -31
  35. package/dist/chunk-SR6DJBPM.cjs.map +1 -0
  36. package/dist/{chunk-4EVUCAW5.js → chunk-TSCQDCAR.js} +2 -2
  37. package/dist/{chunk-GZ3BY2LV.js → chunk-UCEGWDWX.js} +6 -6
  38. package/dist/{chunk-KMSLXG5F.js → chunk-V5R3PJQH.js} +2 -2
  39. package/dist/{chunk-SLHWOJNZ.js → chunk-VAMCM435.js} +2 -2
  40. package/dist/{chunk-X2XZXDBZ.cjs → chunk-X2SPQOI7.cjs} +134 -102
  41. package/dist/chunk-X2SPQOI7.cjs.map +1 -0
  42. package/dist/chunks-BHTYFFI2.js +10 -0
  43. package/dist/cli.js +30 -30
  44. package/dist/{formula-EW7XLBSA.js → formula-4C7ADOLE.js} +4 -4
  45. package/dist/{formula-54IFKOYU.js → formula-4Y7UWTEG.js} +3 -3
  46. package/dist/{formula-Q4MFVPEO.cjs → formula-KZWH4YUD.cjs} +9 -9
  47. package/dist/{formula-Q4MFVPEO.cjs.map → formula-KZWH4YUD.cjs.map} +1 -1
  48. package/dist/{image-ocr-GWF2XELH.js → image-ocr-AEX2L326.js} +9 -9
  49. package/dist/{image-ocr-I7UGQZF5.js → image-ocr-ASLUPAQG.js} +6 -6
  50. package/dist/{image-ocr-OGJ6A3ML.cjs → image-ocr-GT3NILUJ.cjs} +17 -17
  51. package/dist/{image-ocr-OGJ6A3ML.cjs.map → image-ocr-GT3NILUJ.cjs.map} +1 -1
  52. package/dist/index.cjs +360 -360
  53. package/dist/index.js +6 -6
  54. package/dist/mcp.js +23 -23
  55. package/dist/{model-bundle-43YHGZCC.js → model-bundle-2TXD77HN.js} +5 -5
  56. package/dist/{models-O3NS6OPX.js → models-WRJKLZA6.js} +5 -5
  57. package/dist/{parse-worker-v2-OXW3CQOW.js → parse-worker-v2-C2GR62SO.js} +12 -12
  58. package/dist/{parser-FMVOWRG4.cjs → parser-5R34V6PS.cjs} +159 -159
  59. package/dist/{parser-FMVOWRG4.cjs.map → parser-5R34V6PS.cjs.map} +1 -1
  60. package/dist/{parser-H6OY6UWW.js → parser-GFZILOKI.js} +12 -12
  61. package/dist/{parser-B3RVTCOY.js → parser-LU7BIHXD.js} +9 -9
  62. package/dist/pdf-ocr-QRBPEPOZ.cjs +35 -0
  63. package/dist/{pdf-ocr-5Z6GDYBQ.cjs.map → pdf-ocr-QRBPEPOZ.cjs.map} +1 -1
  64. package/dist/{pdf-ocr-NE6Y4I6O.js → pdf-ocr-U2ZRNQD4.js} +6 -6
  65. package/dist/{pdf-ocr-QHW74LO6.js → pdf-ocr-VNK6UIS2.js} +9 -9
  66. package/dist/{profile-io-2IOYOBGP.js → profile-io-J3IWFBCM.js} +3 -3
  67. package/dist/{rasterize-ZLPDGEZY.js → rasterize-23MJWOUQ.js} +3 -3
  68. package/dist/{redact-doc-CDFM5S7S.js → redact-doc-GGCEGT74.js} +11 -11
  69. package/dist/{render-VXAEYSJA.js → render-M2UAFQSI.js} +7 -7
  70. package/dist/seal-EHZTTMNE.js +10 -0
  71. package/dist/{setup-CBWVQJID.js → setup-D7JWID23.js} +3 -3
  72. package/dist/visual-2ZLXZ5NN.js +21 -0
  73. package/dist/{watch-2SA3CTRT.js → watch-E2XCUIA5.js} +12 -12
  74. package/package.json +1 -1
  75. package/dist/chunk-6WEHXC2D.js.map +0 -1
  76. package/dist/chunk-DULJ7PPP.js.map +0 -1
  77. package/dist/chunk-UGO3UFXX.js.map +0 -1
  78. package/dist/chunk-VSYLST4K.js.map +0 -1
  79. package/dist/chunk-X2XZXDBZ.cjs.map +0 -1
  80. package/dist/chunk-YAK4U7CC.cjs.map +0 -1
  81. package/dist/chunks-74SE5QB2.js +0 -10
  82. package/dist/pdf-ocr-5Z6GDYBQ.cjs +0 -35
  83. package/dist/seal-YSBFBEXC.js +0 -10
  84. package/dist/visual-MJVIFZHH.js +0 -21
  85. /package/dist/{-CCZTES5C.js.map → -ZKOPHIGY.js.map} +0 -0
  86. /package/dist/{chunk-XW7L76FE.js.map → chunk-2UXGDAWQ.js.map} +0 -0
  87. /package/dist/{chunk-T7MDUY5X.js.map → chunk-5Y7E5VTW.js.map} +0 -0
  88. /package/dist/{chunk-UV2ZS65C.js.map → chunk-6PPVAQ2N.js.map} +0 -0
  89. /package/dist/{chunk-7Y4MVNYA.js.map → chunk-BHY2QAPM.js.map} +0 -0
  90. /package/dist/{chunk-7YCKDE5X.js.map → chunk-DH564VPR.js.map} +0 -0
  91. /package/dist/{chunk-E5H5WHJH.js.map → chunk-F3VIVCIF.js.map} +0 -0
  92. /package/dist/{chunk-MTAQVHCB.js.map → chunk-FK7KGS5D.js.map} +0 -0
  93. /package/dist/{chunk-IGLRJCO6.js.map → chunk-GYVSGOQW.js.map} +0 -0
  94. /package/dist/{chunk-K37LMDT5.js.map → chunk-J5M5OW4S.js.map} +0 -0
  95. /package/dist/{chunk-Y3VNNGB2.js.map → chunk-K3OLWLXH.js.map} +0 -0
  96. /package/dist/{chunk-PCHGHLUP.js.map → chunk-LPNWTWOQ.js.map} +0 -0
  97. /package/dist/{chunk-VNB2IKVA.js.map → chunk-NUQ5B2ZM.js.map} +0 -0
  98. /package/dist/{chunk-EY3PT2X7.js.map → chunk-QJA3KGRP.js.map} +0 -0
  99. /package/dist/{chunk-KOHEEPQV.js.map → chunk-QOMLSZLM.js.map} +0 -0
  100. /package/dist/{chunk-HZFYPOBJ.js.map → chunk-S2VWNC2W.js.map} +0 -0
  101. /package/dist/{chunk-4EVUCAW5.js.map → chunk-TSCQDCAR.js.map} +0 -0
  102. /package/dist/{chunk-GZ3BY2LV.js.map → chunk-UCEGWDWX.js.map} +0 -0
  103. /package/dist/{chunk-KMSLXG5F.js.map → chunk-V5R3PJQH.js.map} +0 -0
  104. /package/dist/{chunk-SLHWOJNZ.js.map → chunk-VAMCM435.js.map} +0 -0
  105. /package/dist/{chunks-74SE5QB2.js.map → chunks-BHTYFFI2.js.map} +0 -0
  106. /package/dist/{formula-EW7XLBSA.js.map → formula-4C7ADOLE.js.map} +0 -0
  107. /package/dist/{formula-54IFKOYU.js.map → formula-4Y7UWTEG.js.map} +0 -0
  108. /package/dist/{image-ocr-GWF2XELH.js.map → image-ocr-AEX2L326.js.map} +0 -0
  109. /package/dist/{image-ocr-I7UGQZF5.js.map → image-ocr-ASLUPAQG.js.map} +0 -0
  110. /package/dist/{model-bundle-43YHGZCC.js.map → model-bundle-2TXD77HN.js.map} +0 -0
  111. /package/dist/{models-O3NS6OPX.js.map → models-WRJKLZA6.js.map} +0 -0
  112. /package/dist/{parse-worker-v2-OXW3CQOW.js.map → parse-worker-v2-C2GR62SO.js.map} +0 -0
  113. /package/dist/{parser-H6OY6UWW.js.map → parser-GFZILOKI.js.map} +0 -0
  114. /package/dist/{parser-B3RVTCOY.js.map → parser-LU7BIHXD.js.map} +0 -0
  115. /package/dist/{pdf-ocr-NE6Y4I6O.js.map → pdf-ocr-U2ZRNQD4.js.map} +0 -0
  116. /package/dist/{pdf-ocr-QHW74LO6.js.map → pdf-ocr-VNK6UIS2.js.map} +0 -0
  117. /package/dist/{profile-io-2IOYOBGP.js.map → profile-io-J3IWFBCM.js.map} +0 -0
  118. /package/dist/{rasterize-ZLPDGEZY.js.map → rasterize-23MJWOUQ.js.map} +0 -0
  119. /package/dist/{redact-doc-CDFM5S7S.js.map → redact-doc-GGCEGT74.js.map} +0 -0
  120. /package/dist/{render-VXAEYSJA.js.map → render-M2UAFQSI.js.map} +0 -0
  121. /package/dist/{seal-YSBFBEXC.js.map → seal-EHZTTMNE.js.map} +0 -0
  122. /package/dist/{setup-CBWVQJID.js.map → setup-D7JWID23.js.map} +0 -0
  123. /package/dist/{visual-MJVIFZHH.js.map → visual-2ZLXZ5NN.js.map} +0 -0
  124. /package/dist/{watch-2SA3CTRT.js.map → watch-E2XCUIA5.js.map} +0 -0
package/README.md CHANGED
@@ -108,7 +108,7 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
108
108
 
109
109
  ## 검증 결과
110
110
 
111
- **4.22.14 · 2026-10-19 검증**(렌더 배치는 4.24.14, PDF 글·표·OCR 은 4.24.15 · 2026-10-28). 고정 코퍼스와 참조 기준으로 측정한 결과입니다.
111
+ **4.22.14 · 2026-10-19 검증**(렌더 배치는 4.24.14, PDF 글·표·OCR 은 4.24.16 · 2026-10-28). 고정 코퍼스와 참조 기준으로 측정한 결과입니다.
112
112
 
113
113
  | 대상 | 규모 | 결과 |
114
114
  | --- | --- | --- |
@@ -120,7 +120,7 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
120
120
  | PDF 중첩표 (텍스트층) | 29문서 · 101표 | 구조·칸 내용 **101/101 · 100%** |
121
121
  | 법령 별표 | 272건 · 346표 | HWP **346/346**, PDF **342/346 · 98.84%** |
122
122
  | PDF 전체 | 1,911문서 중 1,729건 채점 | 글 커버리지 **99.80%** |
123
- | OCR | 53문서 · 102쪽 · 67표 | CER **0.0255** · 글자 재현율 **99.23%** · 표 구조 일치 **26/67** |
123
+ | OCR | 53문서 · 102쪽 · 67표 | CER **0.0250** · 글자 재현율 **99.27%** · 표 구조 일치 **26/67** |
124
124
  | opendataloader-bench | PDF 200문서 | 종합 기본값 **0.964** · OCR 끔 **0.939** |
125
125
  | HWPX 렌더 배치 (4.24.14) | 한컴 PDF 짝 · 글 조각 90,840 · 그림 4,107 | 글 위치(±1.5pt) **87,643 · 96.5%** · 그림 위치(±2pt) **4,019 · 97.9%** |
126
126
 
@@ -128,15 +128,15 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
128
128
 
129
129
  ## 최근 업데이트
130
130
 
131
- 최신 배포: **[4.24.15](https://github.com/chrisryugj/kordoc/releases/tag/v4.24.15)** · 2026-10-28
131
+ 최신 배포: **[4.24.16](https://github.com/chrisryugj/kordoc/releases/tag/v4.24.16)** · 2026-10-28
132
132
 
133
133
  | 버전 | 주요 변경 | 수치 변화 |
134
134
  | --- | --- | --- |
135
+ | 4.24.16 | OCR: 짧은 목차 리더 ··, 과제 번호의 Ⅲ(파·피로 읽음)·네모 번호 앞 [ ·붙임표가 붙은 원문자 ①, 한글 뒤 로마 숫자 획 수(Ⅰ↔Ⅱ), 칸 테두리 앞·빈칸 긴 서식 칸 끝 닫는 괄호 | OCR CER 0.0255 → **0.0250** · 글자 재현율 99.23% → **99.27%** · 정밀도 99.53% → **99.54%** · 열화 입력 8종 개선(원본 0.0397 → **0.0394**, 스캔만 0.0692 → 0.0693) |
135
136
  | 4.24.15 | OCR: 검출기가 놓친 서식 빈칸 네모 □□-□□□·목차 줄 머리 대시·줄 끝 홑 쪽 번호, 큰 글머리 ■, 리터 ℓ, 작은 고리 。, 윗줄에 묻힌 줄 머리 가운뎃점, 빗금 칸 환각 · PDF: 줄 간격 넓은 중·일문 두 줄 묶음 문단 잇기 | OCR CER 0.0260 → **0.0255** · 글자 재현율 99.19% → **99.23%** · 열화 입력 8종 개선(원본 0.0405 → **0.0397**, 잡음만 0.0485 → 0.0486) · PDF 어절 F1 99.066% → **99.067%** |
136
137
  | 4.24.14 | 렌더: 칸 간격(`cellSpacing`) 표의 칸 자리 · OCR: 공백·따옴표로 읽은 홑낫표 「, 검출기가 놓친 쪽 번호, 라틴 약어 앞·C 로 읽은 줄 머리 ○, 고리만 든 칸 ○, 마름모 글머리 ◆·◇·◈, 서식 칸 끝 닫는 괄호 | 렌더 글 위치 87,577 → **87,643** · OCR CER 0.0263 → **0.0260** · 열화 입력 9종 모두 개선(원본 0.0409 → **0.0405**) |
137
138
  | 4.24.13 | 기관팩(`.kpack`): 기관 문서 몇 건으로 서식 묶음을 만들어 그 서식대로 새 문서 · OCR: 선 없는 표 칸 순서·넓게 벌린 균등배분, 글자 상자 안 획 조각, 줄 머리 □, 기간 날짜 끝점, 전화 기호 ☎ · PDF·HWP: 한컴 소프트 하이픈 붙임표(증감 칸 음수 부호) · patch 추가 문단 강조 서식·렌더 자란 표 겹침(#175) | 기관팩 처음 보는 문서 재현 서울 68.3% → **74.3%** · 광양 77.1% → **94.5%** · OCR CER 0.0281 → **0.0263** · 열화 입력 9종 모두 개선(원본 0.0429 → **0.0409**) |
138
139
  | 4.24.12 | OCR: 조직도 상자 연결선을 괘선으로(과·팀 상자 열 단위 읽기), 요일 앞 날짜 마침표, 목차 리더 잡티, 화살표 모양 ⇨·➔·▶, 쉼표로 읽은 」 | OCR CER 0.0306 → **0.0281** · 글자 재현율 99.12% → **99.14%** · 열화 입력 9종 모두 개선(원본 0.0475 → **0.0429**) |
139
- | 4.24.11 | OCR: 표 칸·행 경계를 가로지른 검출 박스 가르기, 날짜 쉼표, 직함 앞 전(前)·현(現) · 렌더: 쪽 번호 글자 크기 · 생성: 서울 방침서 제목 줄간격·요약 정렬 | OCR CER 0.0310 → **0.0306** · 글자 재현율 99.10% → **99.12%** · 렌더 글 위치 87,546 → **87,577** · 생성 재현 0.806 → **0.807** |
140
140
 
141
141
  이전 버전과 상세 내용은 [변경 이력](CHANGELOG.md)에 있습니다.
142
142
 
@@ -64,10 +64,10 @@ import {
64
64
  usesGaejosikMunche,
65
65
  usesLogicStructure,
66
66
  validateHwpx
67
- } from "./chunk-7Y4MVNYA.js";
67
+ } from "./chunk-BHY2QAPM.js";
68
68
  import {
69
69
  blocksToChunks
70
- } from "./chunk-XW7L76FE.js";
70
+ } from "./chunk-2UXGDAWQ.js";
71
71
  import {
72
72
  SPACE_EM_FIXED,
73
73
  SPACE_EM_FONT,
@@ -92,20 +92,20 @@ import {
92
92
  renderSceneToHtml,
93
93
  simulateWrap,
94
94
  simulateWrapKeepWord
95
- } from "./chunk-GZ3BY2LV.js";
96
- import "./chunk-E5H5WHJH.js";
95
+ } from "./chunk-UCEGWDWX.js";
96
+ import "./chunk-F3VIVCIF.js";
97
97
  import {
98
98
  blocksToPages
99
- } from "./chunk-MTAQVHCB.js";
99
+ } from "./chunk-FK7KGS5D.js";
100
100
  import "./chunk-VKVDMH7X.js";
101
101
  import "./chunk-VQFA55IC.js";
102
102
  import "./chunk-BYMPPVT3.js";
103
- import "./chunk-7YCKDE5X.js";
103
+ import "./chunk-DH564VPR.js";
104
104
  import {
105
105
  blocksToMarkdown,
106
106
  flattenLayoutTables,
107
107
  hasStructuredCellContent
108
- } from "./chunk-KOHEEPQV.js";
108
+ } from "./chunk-QOMLSZLM.js";
109
109
  import {
110
110
  ValueCursor,
111
111
  applySplices,
@@ -119,11 +119,11 @@ import {
119
119
  isLabelCell,
120
120
  placeSealHwpx,
121
121
  scanSectionXml
122
- } from "./chunk-HZFYPOBJ.js";
123
- import "./chunk-4EVUCAW5.js";
122
+ } from "./chunk-S2VWNC2W.js";
123
+ import "./chunk-TSCQDCAR.js";
124
124
  import {
125
125
  VERSION
126
- } from "./chunk-UV2ZS65C.js";
126
+ } from "./chunk-6PPVAQ2N.js";
127
127
  import {
128
128
  DEFAULT_REDACT_RULES,
129
129
  redactMarkdown,
@@ -239,4 +239,4 @@ export {
239
239
  usesLogicStructure,
240
240
  validateHwpx
241
241
  };
242
- //# sourceMappingURL=-CCZTES5C.js.map
242
+ //# sourceMappingURL=-ZKOPHIGY.js.map
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  assignTableIds,
4
4
  blocksToMarkdown
5
- } from "./chunk-KOHEEPQV.js";
5
+ } from "./chunk-QOMLSZLM.js";
6
6
 
7
7
  // src/chunks.ts
8
8
  var LIST_MARKER_RE = /^(?:[□■◇◆○◎●◦ㅇ•▪▸▶※-]|\d{1,3}[.)]|[가나다라마바사아자차카타파하][.)]|\([가나다라마바사아자차카타파하0-9]{1,3}\)|[①-⑳㉮-㉻㈎-㈛])\s/;
@@ -82,4 +82,4 @@ function blocksToChunks(blocks, options) {
82
82
  export {
83
83
  blocksToChunks
84
84
  };
85
- //# sourceMappingURL=chunk-XW7L76FE.js.map
85
+ //# sourceMappingURL=chunk-2UXGDAWQ.js.map
@@ -30,7 +30,7 @@ import {
30
30
  splitRowBands,
31
31
  starRun,
32
32
  tallInkCount
33
- } from "./chunk-UGO3UFXX.js";
33
+ } from "./chunk-6K2SYTNJ.js";
34
34
  import {
35
35
  validateOcrOptions
36
36
  } from "./chunk-BYMPPVT3.js";
@@ -41,11 +41,11 @@ import {
41
41
  ocrSourcePath,
42
42
  parseCharacterDict,
43
43
  resolveOcrModels
44
- } from "./chunk-K37LMDT5.js";
44
+ } from "./chunk-J5M5OW4S.js";
45
45
  import {
46
46
  KordocError,
47
47
  OPTIONAL_DEP_INSTALL_HINT
48
- } from "./chunk-UV2ZS65C.js";
48
+ } from "./chunk-6PPVAQ2N.js";
49
49
 
50
50
  // src/ocr/ruling-lines.ts
51
51
  var INK_LUMA_MAX = 205;
@@ -535,6 +535,14 @@ function gaps({ chars, cx, gray, w, h, ink }) {
535
535
  const pitch = d.length >= 2 ? d.sort((a, b) => a - b)[d.length >> 1] : bandH;
536
536
  const nearTo = (g) => (i) => Math.abs(cx(i) - (g.x0 + g.x1) / 2) <= Math.max(pitch * 0.45, (g.x1 - g.x0) / 2 + 1);
537
537
  const loose = glyphs.filter((g) => /^[\u00b7.]/.test(g.mark) && !live.some(nearTo(g)));
538
+ const tail = [...live].reverse().findIndex((i) => !/^\d$/.test(chars[i]));
539
+ if (tail >= 1 && tail <= 3 && tail < live.length) {
540
+ const prev = live[live.length - 1 - tail], num = live[live.length - tail];
541
+ const run = loose.filter((g) => (g.x0 + g.x1) / 2 > cx(prev) && (g.x0 + g.x1) / 2 < cx(num));
542
+ const mark = run[0]?.mark[0];
543
+ if (run.length >= 2 && run.length <= 3 && run.every((g) => g.mark[0] === mark) && /^[가-힣?)]$/.test(chars[prev]) && !glyphs.some((g) => !run.includes(g) && (g.x0 + g.x1) / 2 > cx(prev) && (g.x0 + g.x1) / 2 < cx(num)))
544
+ chars[prev] += " " + mark.repeat(run.length) + " ";
545
+ }
538
546
  for (const g of glyphs.sort((a, b) => a.x0 - b.x0)) {
539
547
  const mid = (g.x0 + g.x1) / 2;
540
548
  const near = nearTo(g);
@@ -612,13 +620,14 @@ function roman({ chars, cx, gray, w, h, ink }) {
612
620
  if (serifOne(gray, w, h, ink, cx(i))) chars[i] = "\u2160";
613
621
  }
614
622
  for (let i = 0; i < chars.length; i++) {
615
- if (chars[i] !== "|" || chars[i - 1] === "|" || chars[i + 1] === "|") continue;
623
+ const hangul = /^[파피]$/.test(chars[i]);
624
+ if (chars[i] !== "|" && !hangul || chars[i - 1] === "|" || chars[i + 1] === "|") continue;
616
625
  let p = i - 1, q = i + 1;
617
626
  while (p >= 0 && !chars[p].trim()) p--;
618
627
  while (q < chars.length && !chars[q].trim()) q++;
619
- const glued = /[가-힣]$/.test(chars[i - 1] ?? "") || (chars[i + 1] ?? "") === "." || chars[p] === "-" && chars[q] === "-";
628
+ const glued = hangul ? chars[p] === "(" && chars[q] === "-" : /[가-힣]$/.test(chars[i - 1] ?? "") || (chars[i + 1] ?? "") === "." || chars[p] === "-" && chars[q] === "-";
620
629
  if (!glued) continue;
621
- const n = romanStems(gray, w, h, ink, p >= 0 ? cx(p) : -Infinity, q < chars.length ? cx(q) : Infinity);
630
+ const n = romanStems(gray, w, h, ink, p >= 0 ? cx(p) : -Infinity, q < chars.length ? cx(q) : Infinity, /[가-힣]$/.test(chars[p] ?? ""));
622
631
  if (n) chars[i] = String.fromCharCode(8543 + n);
623
632
  }
624
633
  const inRoman = (i) => ROMAN.test(chars[i]) || chars[i] === "1" && (ROMAN.test(chars[i - 1] ?? "") || ROMAN.test(chars[i + 1] ?? ""));
@@ -633,7 +642,7 @@ function roman({ chars, cx, gray, w, h, ink }) {
633
642
  continue;
634
643
  }
635
644
  let e = s;
636
- while (e < chars.length && inRoman(e)) e++;
645
+ while (e < chars.length && (inRoman(e) || e > s && chars[e] === "|" && chars[e + 1] !== "|")) e++;
637
646
  const tok = chars.slice(s, e).join("");
638
647
  if (e < chars.length && /^[A-Za-z]/.test(chars[e])) {
639
648
  s = e;
@@ -642,7 +651,7 @@ function roman({ chars, cx, gray, w, h, ink }) {
642
651
  let p = s - 1, q = e;
643
652
  while (p >= 0 && !chars[p].trim()) p--;
644
653
  while (q < chars.length && !chars[q].trim()) q++;
645
- const n = romanStems(gray, w, h, ink, p >= 0 ? cx(p) : -Infinity, q < chars.length ? cx(q) : Infinity);
654
+ const n = romanStems(gray, w, h, ink, p >= 0 ? cx(p) : -Infinity, q < chars.length ? cx(q) : Infinity, /[가-힣]$/.test(chars[p] ?? ""));
646
655
  const canon = n ? [["\u2160", "I"], ["\u2161", "II"], ["\u2162", "III"]][n - 1] : null;
647
656
  if (canon && !canon.includes(tok)) {
648
657
  chars[s] = canon[0];
@@ -663,6 +672,7 @@ function restoreSymbols(text, ringDecided = false) {
663
672
  s = s.replace(/(^|[^\uac00-\ud7a3])(전|현)\(\s?\)(?=\S)/g, (_, a, b) => `${a}${b}(${b === "\uC804" ? "\u524D" : "\u73FE"})`);
664
673
  if (/[가-힣]/.test(s)) s = s.replace(/(\d)l(?![A-Za-z])/g, "$1\u2113");
665
674
  s = s.replace(/([((])\s?[A-Za-z@&]\s?(?=(?:0\d{1,2}-)?\d{3,4}-\d{4}\b)/g, "$1\u260E");
675
+ if (!s.includes("]")) s = s.replace(/^\[(?=[\u2460-\u2473])/, "");
666
676
  return smartQuotes(dateDots(dateCommas(joinDigitGroups(s))));
667
677
  }
668
678
  function dateCommas(s) {
@@ -1114,11 +1124,28 @@ function closingParens(rgba, width, items) {
1114
1124
  if ((t.match(/\(/g)?.length ?? 0) <= (t.match(/\)/g)?.length ?? 0) || !/\([^()]*$/.test(t)) continue;
1115
1125
  const x0 = it.x + it.w + 2;
1116
1126
  const next = items.filter((o) => o !== it && o.x >= x0 && o.y < it.y + it.h && o.y + o.h > it.y).reduce((m, o) => Math.min(m, o.x), Infinity);
1117
- const x1 = Math.min(width, next, x0 + it.h * 8);
1127
+ let x1 = Math.min(width, next, x0 + it.h * 16);
1128
+ const pageH = Math.floor(rgba.length / 4 / width);
1129
+ const colInk = (x) => {
1130
+ let k = 0;
1131
+ for (let y = it.y; y < it.y + it.h; y++) if (dark(x, y)) k++;
1132
+ return k;
1133
+ };
1134
+ for (let x = x0; x < x1; x++) if (colInk(x) >= it.h * 0.9) {
1135
+ x1 = x;
1136
+ while (x1 > x0 && colInk(x1 - 1) >= it.h * 0.5) x1--;
1137
+ break;
1138
+ }
1139
+ const ruleRow = /* @__PURE__ */ new Set();
1140
+ for (let y = it.y; y < it.y + it.h; y++) {
1141
+ let k = 0;
1142
+ for (let x = x0; x < x1; x++) if (dark(x, y)) k++;
1143
+ if (k > (x1 - x0) * 0.8) for (const d of [-1, 0, 1]) ruleRow.add(y + d);
1144
+ }
1118
1145
  let minX = Infinity, maxX = -1, minY = Infinity, maxY = -1, cols = 0, prevOn = false, runs = 0;
1119
1146
  for (let x = x0; x < x1; x++) {
1120
1147
  let on = false;
1121
- for (let y = it.y; y < it.y + it.h; y++) if (dark(x, y)) {
1148
+ for (let y = it.y; y < it.y + it.h; y++) if (!ruleRow.has(y) && dark(x, y)) {
1122
1149
  on = true;
1123
1150
  if (y < minY) minY = y;
1124
1151
  if (y > maxY) maxY = y;
@@ -1132,9 +1159,14 @@ function closingParens(rgba, width, items) {
1132
1159
  prevOn = on;
1133
1160
  }
1134
1161
  if (runs !== 1 || maxX - minX + 1 > it.h * 0.5 || maxY - minY + 1 < it.h * 0.6) continue;
1135
- let rule = false;
1136
- for (let x = minX; x <= maxX && !rule; x++) rule = minY > 1 && dark(x, minY - 2) || dark(x, Math.min(maxY + 2, Math.floor(rgba.length / 4 / width) - 1));
1137
- if (rule) continue;
1162
+ const inkRow = (y) => {
1163
+ for (let x = minX; x <= maxX; x++) if (dark(x, y)) return true;
1164
+ return false;
1165
+ };
1166
+ let over = 0;
1167
+ for (let y = minY - 1; y >= 0 && !ruleRow.has(y) && inkRow(y) && over <= it.h; y--) over++;
1168
+ for (let y = maxY + 1; y < pageH && !ruleRow.has(y) && inkRow(y) && over <= it.h; y++) over++;
1169
+ if (over > it.h * 0.6) continue;
1138
1170
  const meanX = (ya, yb) => {
1139
1171
  let sx = 0, k = 0;
1140
1172
  for (let y = ya; y < yb; y++) for (let x = minX; x <= maxX; x++) if (dark(x, y)) {
@@ -2064,4 +2096,4 @@ export {
2064
2096
  groupOcrLines,
2065
2097
  ocrItemsToBlocks
2066
2098
  };
2067
- //# sourceMappingURL=chunk-6WEHXC2D.js.map
2099
+ //# sourceMappingURL=chunk-3TXAIEXL.js.map