kordoc 4.24.9 → 4.24.10

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 (127) hide show
  1. package/README.md +5 -5
  2. package/dist/{-6LXREJIR.js → -H7GN7FIS.js} +11 -11
  3. package/dist/{chunk-NDC4AGLX.js → chunk-37JRATLZ.js} +100 -13
  4. package/dist/chunk-37JRATLZ.js.map +1 -0
  5. package/dist/{chunk-C6QK3PY2.js → chunk-3BRGHU2F.js} +2 -2
  6. package/dist/{chunk-C6QK3PY2.js.map → chunk-3BRGHU2F.js.map} +1 -1
  7. package/dist/{chunk-ESSLFMY3.js → chunk-4AKR7LBP.js} +6 -6
  8. package/dist/{chunk-BEPBXIKP.js → chunk-4TAOUMLJ.js} +2 -2
  9. package/dist/{chunk-W6R7HH2Q.js → chunk-ALCD3FB7.js} +2 -2
  10. package/dist/{chunk-SQCECEOH.js → chunk-CZGAGILH.js} +101 -14
  11. package/dist/chunk-CZGAGILH.js.map +1 -0
  12. package/dist/{chunk-SB4VN4TR.js → chunk-ENQWDN6M.js} +21 -7
  13. package/dist/chunk-ENQWDN6M.js.map +1 -0
  14. package/dist/{chunk-LVEY2XHM.js → chunk-HFNNRSAJ.js} +21 -7
  15. package/dist/chunk-HFNNRSAJ.js.map +1 -0
  16. package/dist/{chunk-ZFM7UP72.cjs → chunk-IV4ZRFHF.cjs} +82 -68
  17. package/dist/chunk-IV4ZRFHF.cjs.map +1 -0
  18. package/dist/{chunk-UVMVLE3M.cjs → chunk-JH3AA5TY.cjs} +3 -3
  19. package/dist/{chunk-UVMVLE3M.cjs.map → chunk-JH3AA5TY.cjs.map} +1 -1
  20. package/dist/{chunk-DF3YCAK6.js → chunk-LLKLJ2JF.js} +2 -2
  21. package/dist/{chunk-DF3YCAK6.js.map → chunk-LLKLJ2JF.js.map} +1 -1
  22. package/dist/{chunk-7NEBICPS.js → chunk-LMG7Y3TN.js} +2 -2
  23. package/dist/{chunk-WPA45TPL.js → chunk-NFJN75Y2.js} +2 -2
  24. package/dist/{chunk-YAKEEIR2.js → chunk-OZTG6NCW.js} +2 -2
  25. package/dist/{chunk-TO4T2M7R.js → chunk-PB6EOWE4.js} +3 -3
  26. package/dist/{chunk-O34AXZ4G.js → chunk-PDPHUGVP.js} +2 -2
  27. package/dist/{chunk-TY4PED6S.js → chunk-PSQJYUJC.js} +2 -2
  28. package/dist/{chunk-NSCYUL4P.cjs → chunk-QAHWMIBF.cjs} +2 -2
  29. package/dist/{chunk-NSCYUL4P.cjs.map → chunk-QAHWMIBF.cjs.map} +1 -1
  30. package/dist/{chunk-GINSLCL7.js → chunk-RNDG6RQU.js} +2 -2
  31. package/dist/{chunk-2A54AIAG.js → chunk-S4HE5OH5.js} +2 -2
  32. package/dist/{chunk-D5S5S6OP.js → chunk-TT6UHEDY.js} +2 -2
  33. package/dist/{chunk-VAR3NCSE.js → chunk-UK3CENY6.js} +11 -11
  34. package/dist/{chunk-A4TUSLGL.js → chunk-VAYHMKSC.js} +2 -2
  35. package/dist/{chunk-2WWQ6NU5.cjs → chunk-WKN5YUMP.cjs} +3 -3
  36. package/dist/{chunk-2WWQ6NU5.cjs.map → chunk-WKN5YUMP.cjs.map} +1 -1
  37. package/dist/{chunk-MSPBBDR5.js → chunk-WZWJCMM3.js} +2 -2
  38. package/dist/{chunk-TMHPNZ37.cjs → chunk-X5BFTWCB.cjs} +122 -35
  39. package/dist/chunk-X5BFTWCB.cjs.map +1 -0
  40. package/dist/{chunk-4BPHV36H.cjs → chunk-XFM4SX74.cjs} +6 -6
  41. package/dist/{chunk-4BPHV36H.cjs.map → chunk-XFM4SX74.cjs.map} +1 -1
  42. package/dist/{chunk-EF4MEYFE.js → chunk-XMAOBI35.js} +3 -3
  43. package/dist/{chunk-R3DNJRDD.js → chunk-YAKLWOT2.js} +2 -2
  44. package/dist/chunks-CMSL2XXG.js +10 -0
  45. package/dist/cli.js +30 -30
  46. package/dist/{formula-S7CTLTGZ.js → formula-P5VHY4YS.js} +3 -3
  47. package/dist/{formula-3SARACGW.cjs → formula-TBG6BYE2.cjs} +9 -9
  48. package/dist/{formula-3SARACGW.cjs.map → formula-TBG6BYE2.cjs.map} +1 -1
  49. package/dist/{formula-MDHYCNKI.js → formula-YCZOVUJU.js} +4 -4
  50. package/dist/{image-ocr-V6AQ4IAY.js → image-ocr-2UD6RWE6.js} +6 -6
  51. package/dist/{image-ocr-VDMEI7TD.js → image-ocr-3QCUKBTE.js} +9 -9
  52. package/dist/{image-ocr-2T4NBJ73.cjs → image-ocr-J6EWIQ73.cjs} +17 -17
  53. package/dist/{image-ocr-2T4NBJ73.cjs.map → image-ocr-J6EWIQ73.cjs.map} +1 -1
  54. package/dist/index.cjs +340 -340
  55. package/dist/index.js +6 -6
  56. package/dist/mcp.js +23 -23
  57. package/dist/{model-bundle-HCTCHMA2.js → model-bundle-EFAOVVYU.js} +5 -5
  58. package/dist/{models-NJROM7JD.js → models-SJXAHLSA.js} +5 -5
  59. package/dist/{parse-worker-v2-ALTGW2J3.js → parse-worker-v2-ZSSOTZVE.js} +12 -12
  60. package/dist/{parser-MY4WE64G.js → parser-3XHPJKL7.js} +11 -10
  61. package/dist/parser-3XHPJKL7.js.map +1 -0
  62. package/dist/{parser-6J5HFER5.js → parser-4I4MM5AJ.js} +14 -13
  63. package/dist/parser-4I4MM5AJ.js.map +1 -0
  64. package/dist/{parser-L3G6ON4U.cjs → parser-4MXHN43N.cjs} +161 -160
  65. package/dist/parser-4MXHN43N.cjs.map +1 -0
  66. package/dist/{pdf-ocr-HUSU2XMV.js → pdf-ocr-J6GXPLZJ.js} +6 -6
  67. package/dist/pdf-ocr-JPLZOU23.cjs +31 -0
  68. package/dist/{pdf-ocr-RF2SCGXD.cjs.map → pdf-ocr-JPLZOU23.cjs.map} +1 -1
  69. package/dist/{pdf-ocr-3VVSR4LN.js → pdf-ocr-QXZIMPQI.js} +9 -9
  70. package/dist/{profile-io-SQI3X7MD.js → profile-io-X7ZMPA7T.js} +3 -3
  71. package/dist/{rasterize-BHW5UZY2.js → rasterize-42GMMS3L.js} +3 -3
  72. package/dist/{redact-doc-KJ6M63BP.js → redact-doc-WCNALJSX.js} +11 -11
  73. package/dist/{render-Z6N2GGKL.js → render-2SSXV7MR.js} +7 -7
  74. package/dist/seal-ENUBZ7ZX.js +10 -0
  75. package/dist/{setup-MUBZ674O.js → setup-VY5MAK7O.js} +3 -3
  76. package/dist/visual-ON76FHWH.js +21 -0
  77. package/dist/{watch-D4AUDKVN.js → watch-JLCOQOAL.js} +12 -12
  78. package/package.json +1 -1
  79. package/dist/chunk-LVEY2XHM.js.map +0 -1
  80. package/dist/chunk-NDC4AGLX.js.map +0 -1
  81. package/dist/chunk-SB4VN4TR.js.map +0 -1
  82. package/dist/chunk-SQCECEOH.js.map +0 -1
  83. package/dist/chunk-TMHPNZ37.cjs.map +0 -1
  84. package/dist/chunk-ZFM7UP72.cjs.map +0 -1
  85. package/dist/chunks-L66VMJHU.js +0 -10
  86. package/dist/parser-6J5HFER5.js.map +0 -1
  87. package/dist/parser-L3G6ON4U.cjs.map +0 -1
  88. package/dist/parser-MY4WE64G.js.map +0 -1
  89. package/dist/pdf-ocr-RF2SCGXD.cjs +0 -31
  90. package/dist/seal-PM4624BB.js +0 -10
  91. package/dist/visual-AV46N5ZN.js +0 -21
  92. /package/dist/{-6LXREJIR.js.map → -H7GN7FIS.js.map} +0 -0
  93. /package/dist/{chunk-ESSLFMY3.js.map → chunk-4AKR7LBP.js.map} +0 -0
  94. /package/dist/{chunk-BEPBXIKP.js.map → chunk-4TAOUMLJ.js.map} +0 -0
  95. /package/dist/{chunk-W6R7HH2Q.js.map → chunk-ALCD3FB7.js.map} +0 -0
  96. /package/dist/{chunk-7NEBICPS.js.map → chunk-LMG7Y3TN.js.map} +0 -0
  97. /package/dist/{chunk-WPA45TPL.js.map → chunk-NFJN75Y2.js.map} +0 -0
  98. /package/dist/{chunk-YAKEEIR2.js.map → chunk-OZTG6NCW.js.map} +0 -0
  99. /package/dist/{chunk-TO4T2M7R.js.map → chunk-PB6EOWE4.js.map} +0 -0
  100. /package/dist/{chunk-O34AXZ4G.js.map → chunk-PDPHUGVP.js.map} +0 -0
  101. /package/dist/{chunk-TY4PED6S.js.map → chunk-PSQJYUJC.js.map} +0 -0
  102. /package/dist/{chunk-GINSLCL7.js.map → chunk-RNDG6RQU.js.map} +0 -0
  103. /package/dist/{chunk-2A54AIAG.js.map → chunk-S4HE5OH5.js.map} +0 -0
  104. /package/dist/{chunk-D5S5S6OP.js.map → chunk-TT6UHEDY.js.map} +0 -0
  105. /package/dist/{chunk-VAR3NCSE.js.map → chunk-UK3CENY6.js.map} +0 -0
  106. /package/dist/{chunk-A4TUSLGL.js.map → chunk-VAYHMKSC.js.map} +0 -0
  107. /package/dist/{chunk-MSPBBDR5.js.map → chunk-WZWJCMM3.js.map} +0 -0
  108. /package/dist/{chunk-EF4MEYFE.js.map → chunk-XMAOBI35.js.map} +0 -0
  109. /package/dist/{chunk-R3DNJRDD.js.map → chunk-YAKLWOT2.js.map} +0 -0
  110. /package/dist/{chunks-L66VMJHU.js.map → chunks-CMSL2XXG.js.map} +0 -0
  111. /package/dist/{formula-S7CTLTGZ.js.map → formula-P5VHY4YS.js.map} +0 -0
  112. /package/dist/{formula-MDHYCNKI.js.map → formula-YCZOVUJU.js.map} +0 -0
  113. /package/dist/{image-ocr-V6AQ4IAY.js.map → image-ocr-2UD6RWE6.js.map} +0 -0
  114. /package/dist/{image-ocr-VDMEI7TD.js.map → image-ocr-3QCUKBTE.js.map} +0 -0
  115. /package/dist/{model-bundle-HCTCHMA2.js.map → model-bundle-EFAOVVYU.js.map} +0 -0
  116. /package/dist/{models-NJROM7JD.js.map → models-SJXAHLSA.js.map} +0 -0
  117. /package/dist/{parse-worker-v2-ALTGW2J3.js.map → parse-worker-v2-ZSSOTZVE.js.map} +0 -0
  118. /package/dist/{pdf-ocr-3VVSR4LN.js.map → pdf-ocr-J6GXPLZJ.js.map} +0 -0
  119. /package/dist/{pdf-ocr-HUSU2XMV.js.map → pdf-ocr-QXZIMPQI.js.map} +0 -0
  120. /package/dist/{profile-io-SQI3X7MD.js.map → profile-io-X7ZMPA7T.js.map} +0 -0
  121. /package/dist/{rasterize-BHW5UZY2.js.map → rasterize-42GMMS3L.js.map} +0 -0
  122. /package/dist/{redact-doc-KJ6M63BP.js.map → redact-doc-WCNALJSX.js.map} +0 -0
  123. /package/dist/{render-Z6N2GGKL.js.map → render-2SSXV7MR.js.map} +0 -0
  124. /package/dist/{seal-PM4624BB.js.map → seal-ENUBZ7ZX.js.map} +0 -0
  125. /package/dist/{setup-MUBZ674O.js.map → setup-VY5MAK7O.js.map} +0 -0
  126. /package/dist/{visual-AV46N5ZN.js.map → visual-ON76FHWH.js.map} +0 -0
  127. /package/dist/{watch-D4AUDKVN.js.map → watch-JLCOQOAL.js.map} +0 -0
package/README.md CHANGED
@@ -105,19 +105,19 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
105
105
 
106
106
  ## 검증 결과
107
107
 
108
- **4.22.14 · 2026-10-19 검증**(렌더 배치·PDF 글·표·OCR 은 4.24.9 · 2026-10-26). 고정 코퍼스와 참조 기준으로 측정한 결과입니다.
108
+ **4.22.14 · 2026-10-19 검증**(렌더 배치·PDF 글·표·OCR 은 4.24.10 · 2026-10-26). 고정 코퍼스와 참조 기준으로 측정한 결과입니다.
109
109
 
110
110
  | 대상 | 규모 | 결과 |
111
111
  | --- | --- | --- |
112
112
  | HWPX | 2,424문서 · 10,342표 | 표 구조 일치 **10,342/10,342 · 100%** |
113
113
  | HWP 5.x ↔ HWPX | 1,130쌍 · 4,315표 | 짝 문서의 표 구조 일치 **100%** |
114
- | PDF 글 | 744쌍 | 글자 재현율 **99.881%** · 정확도 **99.676%** · 읽기 순서 **99.309%** · 어절 F1 **99.064%** |
114
+ | PDF 글 | 744쌍 | 글자 재현율 **99.881%** · 정확도 **99.677%** · 읽기 순서 **99.309%** · 어절 F1 **99.066%** |
115
115
  | PDF 표 | 708쌍 · 2,331표 | 표 탐지 **99.83%** · 구조 일치 **98.24%** · 칸 F1 **0.9919** |
116
116
  | HWPX 재조판 | 다중줄 25,187문단 (12개 폴더) | 모든 줄 시작 일치 **24,941/25,187 · 99.02%** |
117
117
  | PDF 중첩표 (텍스트층) | 29문서 · 101표 | 구조·칸 내용 **101/101 · 100%** |
118
118
  | 법령 별표 | 272건 · 346표 | HWP **346/346**, PDF **342/346 · 98.84%** |
119
119
  | PDF 전체 | 1,911문서 중 1,729건 채점 | 글 커버리지 **99.80%** |
120
- | OCR | 53문서 · 102쪽 · 67표 | CER **0.0313** · 글자 재현율 **99.06%** · 표 구조 일치 **25/67** |
120
+ | OCR | 53문서 · 102쪽 · 67표 | CER **0.0310** · 글자 재현율 **99.10%** · 표 구조 일치 **25/67** |
121
121
  | opendataloader-bench | PDF 200문서 | 종합 기본값 **0.964** · OCR 끔 **0.939** |
122
122
  | HWPX 렌더 배치 (4.24.8) | 한컴 PDF 짝 · 글 조각 90,906 · 그림 4,107 | 글 위치(±1.5pt) **87,620 · 96.4%** · 그림 위치(±2pt) **4,019 · 97.9%** |
123
123
 
@@ -125,15 +125,15 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
125
125
 
126
126
  ## 최근 업데이트
127
127
 
128
- 최신 배포: **[4.24.9](https://github.com/chrisryugj/kordoc/releases/tag/v4.24.9)** · 2026-10-26
128
+ 최신 배포: **[4.24.10](https://github.com/chrisryugj/kordoc/releases/tag/v4.24.10)** · 2026-10-26
129
129
 
130
130
  | 버전 | 주요 변경 | 수치 변화 |
131
131
  | --- | --- | --- |
132
+ | 4.24.10 | 보안: 데모 lockfile 의 zod·fast-uri, 정부 GitLab 미러 복구(Java SDK `kordoc-pom.xml`) · OCR: 줄 머리 ▣·❐·‣, `\|` 로 읽은 로마 숫자, 날짜 끝 마침표 · PDF: 세로쓰기 、。, 그러데이션 배경 괘선, 중·일문 자동 간격 | OCR CER 0.0313 → **0.0310** · 글자 재현율 99.06% → **99.10%** · 열화 입력 9종 모두 개선(스캔 0.0734 → **0.0730**) · PDF 어절 F1 99.064% → **99.066%** |
132
133
  | 4.24.9 | 견본 서식·patch 행 추가 표의 행마다 이중선 · OCR: 통째로 빠진 줄 머리 ○ · PDF: 쪽을 넘는 표가 다음 쪽 첫 행을 삼키던 것 | OCR CER 0.0314 → **0.0313** · 흐린 입력 OCR CER 0.0638 → **0.0635** · PDF 표 구조 98.20% → **98.24%** |
133
134
  | 4.24.8 | 보안: 알려진 의존성 취약점 6건 → 0건(zod 4, MCP SDK 하위 의존성), 출시·CI 에 `npm audit` 게이트 · OCR: 숫자로 읽은 줄 머리 고리 글머리, 다음 글자와 맞닿은 「 · PDF: 머리 칸에만 클립을 건 통계표 | `npm audit` 6 → **0** · OCR CER 0.0327 → **0.0314** · 흐린 입력 OCR CER 0.0663 → **0.0638** · PDF 글 순서 99.307% → **99.309%** |
134
135
  | 4.24.7 | 견본 생성: 목차 상자를 요약 상자로 쓰지 않음, 부호 문단 아래 들여 쓴 목록 단계 · HWPML: 묶음·고정폭 빈칸과 강제 줄바꿈 · OCR: 줄 끝 배경 무늬, 머리행에 붙은 숫자 열, 붙임표·줄표 길이 | OCR CER 0.0332 → **0.0327** · 글자 재현율 99.02% → **99.04%** |
135
136
  | 4.24.6 | OCR: 예산 사업명세서의 목·내역 하위 행, 칸마다 갈린 색 머리 띠, 칸 안 위아래 두 줄 뒤집힘 · PDF: 쪽 바깥 넉 자 세로 탭 · 렌더: 쪽 번호 새로 시작 · HWPX: 들여 써 저장한 XML 의 공백 | OCR CER 0.0409 → **0.0332** · OCR 표 구조 24 → **25/67** · 렌더 글 위치 87,509 → **87,620** · PDF 글 순서 99.302% → **99.307%** |
136
- | 4.24.5 | PDF: 분수 막대 수식 복원, 고정폭 글줄의 가짜 무괘선 표, 덧찍은 목차 쪽 번호 · OCR: 선 없이 쌓은 하위 행, 색 머리 띠 안 흰 구분선, 글의 밑줄 표지 · HWPX·HWP: 표 아래 캡션 차례 | PDF 글 순서 99.247% → **99.302%** · 별표 수식 7 → **11/11** · OCR 표 구조 21 → **24/67** |
137
137
 
138
138
  이전 버전과 상세 내용은 [변경 이력](CHANGELOG.md)에 있습니다.
139
139
 
@@ -58,10 +58,10 @@ import {
58
58
  usesGaejosikMunche,
59
59
  usesLogicStructure,
60
60
  validateHwpx
61
- } from "./chunk-VAR3NCSE.js";
61
+ } from "./chunk-UK3CENY6.js";
62
62
  import {
63
63
  blocksToChunks
64
- } from "./chunk-A4TUSLGL.js";
64
+ } from "./chunk-VAYHMKSC.js";
65
65
  import {
66
66
  SPACE_EM_FIXED,
67
67
  SPACE_EM_FONT,
@@ -86,20 +86,20 @@ import {
86
86
  renderSceneToHtml,
87
87
  simulateWrap,
88
88
  simulateWrapKeepWord
89
- } from "./chunk-ESSLFMY3.js";
90
- import "./chunk-WPA45TPL.js";
89
+ } from "./chunk-4AKR7LBP.js";
90
+ import "./chunk-NFJN75Y2.js";
91
91
  import {
92
92
  blocksToPages
93
- } from "./chunk-MSPBBDR5.js";
93
+ } from "./chunk-WZWJCMM3.js";
94
94
  import "./chunk-VKVDMH7X.js";
95
95
  import "./chunk-VQFA55IC.js";
96
96
  import "./chunk-BYMPPVT3.js";
97
- import "./chunk-GINSLCL7.js";
97
+ import "./chunk-RNDG6RQU.js";
98
98
  import {
99
99
  blocksToMarkdown,
100
100
  flattenLayoutTables,
101
101
  hasStructuredCellContent
102
- } from "./chunk-D5S5S6OP.js";
102
+ } from "./chunk-TT6UHEDY.js";
103
103
  import {
104
104
  ValueCursor,
105
105
  applySplices,
@@ -113,11 +113,11 @@ import {
113
113
  isLabelCell,
114
114
  placeSealHwpx,
115
115
  scanSectionXml
116
- } from "./chunk-TO4T2M7R.js";
117
- import "./chunk-2A54AIAG.js";
116
+ } from "./chunk-PB6EOWE4.js";
117
+ import "./chunk-S4HE5OH5.js";
118
118
  import {
119
119
  VERSION
120
- } from "./chunk-C6QK3PY2.js";
120
+ } from "./chunk-3BRGHU2F.js";
121
121
  import {
122
122
  DEFAULT_REDACT_RULES,
123
123
  redactMarkdown,
@@ -227,4 +227,4 @@ export {
227
227
  usesLogicStructure,
228
228
  validateHwpx
229
229
  };
230
- //# sourceMappingURL=-6LXREJIR.js.map
230
+ //# sourceMappingURL=-H7GN7FIS.js.map
@@ -6,11 +6,11 @@ import {
6
6
  HEADING_RATIO_H3,
7
7
  tidyScriptTags,
8
8
  toTex
9
- } from "./chunk-GINSLCL7.js";
9
+ } from "./chunk-RNDG6RQU.js";
10
10
  import {
11
11
  safeMax,
12
12
  safeMin
13
- } from "./chunk-C6QK3PY2.js";
13
+ } from "./chunk-3BRGHU2F.js";
14
14
 
15
15
  // src/ocr/line-split.ts
16
16
  function grayCrop(rgba, pageW, box) {
@@ -507,7 +507,8 @@ function gapGlyphs(gray, w, h, ink) {
507
507
  const speck = Math.max(3, bh * 0.08);
508
508
  const dot = ch <= bh * 0.25 && cw <= bh * 0.25 && ch >= speck && cw >= speck && cw >= ch * 0.6 && cw <= ch * 1.6;
509
509
  const small = ch <= bh * 0.25 && cw <= bh * 0.25 && ch >= 2 && cw >= 2 && cw >= ch * 0.6 && cw <= ch * 1.6 && fill >= 0.6 && cy >= 0.3 && cy <= 0.7;
510
- if (!apart && !abut && !(nearlyApart && ch >= bh * 0.6)) {
510
+ const flushDot = !apart && dot && fill >= 0.6 && cy >= 0.75 && cw >= ch * 0.8 && !others.some((o) => o.x0 < c.x1 && o.x1 > c.x0);
511
+ if (!apart && !abut && !flushDot && !(nearlyApart && ch >= bh * 0.6)) {
511
512
  if (small) out.push({ x0: c.x0, x1: c.x1, mark: "\xB7" });
512
513
  continue;
513
514
  }
@@ -524,7 +525,8 @@ function gapGlyphs(gray, w, h, ink) {
524
525
  if (c.y1 >= bandB - bh * 0.15 && bottom >= 0.7 && top <= 0.5 && stem(c.y0, c.y1 - band) >= 0.65) return "\u300D";
525
526
  return null;
526
527
  };
527
- if (!apart && !abut) {
528
+ if (flushDot) mark = ".";
529
+ else if (!apart && !abut) {
528
530
  } else if (abut) {
529
531
  if (fill < 0.5) mark = bracket();
530
532
  } else if (dot && fill >= 0.6 && cy >= 0.3 && cy <= 0.7) mark = "\xB7";
@@ -716,6 +718,29 @@ function leadingBullet(gray, w, h, ink, firstX) {
716
718
  const cl = cand.filter((c) => c.x0 < first.x1 && c.x1 > first.x0);
717
719
  const x0 = Math.min(...cl.map((c) => c.x0)), x1 = Math.max(...cl.map((c) => c.x1)), y0 = Math.min(...cl.map((c) => c.y0)), y1 = Math.max(...cl.map((c) => c.y1));
718
720
  const cw = x1 - x0, ch = y1 - y0;
721
+ if (cl.length === 1 && cw >= ch * 0.55 && cw <= ch * 1.1 && ch >= charH * 0.3 && ch <= charH * 0.7) {
722
+ const runs = [];
723
+ let aligned = true;
724
+ for (let y = y0; y < y1 && aligned; y++) {
725
+ let first2 = -1, last = -1, segs = 0, prev = false;
726
+ for (let x = x0; x < x1; x++) {
727
+ const on = label[y * w + x] === cl[0].id;
728
+ if (on) {
729
+ if (!prev) segs++;
730
+ if (first2 < 0) first2 = x;
731
+ last = x;
732
+ }
733
+ prev = on;
734
+ }
735
+ aligned = segs === 1 && first2 - x0 <= Math.max(1, cw * 0.15);
736
+ runs.push(last - first2 + 1);
737
+ }
738
+ const peak = runs.indexOf(Math.max(...runs));
739
+ if (aligned && Math.abs(peak - ch / 2) <= ch * 0.2 && runs[0] <= cw * 0.45 && runs[runs.length - 1] <= cw * 0.45 && Math.max(...runs) >= cw * 0.85) {
740
+ const next2 = cand.find((c) => c.x0 >= x1);
741
+ if (!next2 || next2.x0 - x1 >= ch * 0.3) return { mark: "\u2023", covers: firstX <= x1 + ch * 0.3 };
742
+ }
743
+ }
719
744
  if (cw < ch * 0.8 || cw > ch * 1.25) return null;
720
745
  const next = cand.find((c) => c.x0 >= x1);
721
746
  if (next && next.x0 - x1 < ch * 0.3) return null;
@@ -750,8 +775,32 @@ function leadingBullet(gray, w, h, ink, firstX) {
750
775
  }
751
776
  }
752
777
  const hollowSquare = cl.length === 1 && fill < 0.5 && midRuns === 2 && edgeFull(y0, 1) && edgeFull(y1 - 1, -1);
778
+ const core = cl.length === 2 ? cl.find((b) => cl.some((a) => a !== b && b.x0 > a.x0 && b.x1 < a.x1 && b.y0 > a.y0 && b.y1 < a.y1)) : void 0;
779
+ const coreFill = (() => {
780
+ if (!core) return 0;
781
+ let k = 0;
782
+ for (let y = core.y0; y < core.y1; y++) for (let x = core.x0; x < core.x1; x++) if (label[y * w + x] === core.id) k++;
783
+ return k / ((core.x1 - core.x0) * (core.y1 - core.y0));
784
+ })();
785
+ const filledSquare = !!core && coreFill >= 0.85 && ring(core) && Math.abs(core.x0 + core.x1 - (x0 + x1)) <= cw * 0.2 && Math.abs(core.y0 + core.y1 - (y0 + y1)) <= ch * 0.2 && edgeFull(y0, 1) && edgeFull(y1 - 1, -1);
786
+ const run = (x, y, dx, dy) => {
787
+ let n = 0;
788
+ while (x >= x0 && x < x1 && y >= y0 && y < y1 && cl.some((c) => label[y * w + x] === c.id)) {
789
+ n++;
790
+ x += dx;
791
+ y += dy;
792
+ }
793
+ return n;
794
+ };
795
+ const my0 = y0 + (ch >> 1), mx0 = x0 + (cw >> 1);
796
+ const thin = (a, b) => a > 0 && b >= a * 1.8 && b - a >= Math.max(3, ch * 0.08);
797
+ const boxed = cl.length === 1 && midRuns === 2 && edgeFull(y0, 1) && edgeFull(y1 - 1, -1) && thin(run(x0, my0, 1, 0), run(x1 - 1, my0, -1, 0));
798
+ const top = run(mx0, y0, 0, 1), bottom = run(mx0, y1 - 1, 0, -1);
799
+ const shadow = !boxed ? null : thin(bottom, top) ? "\u2750" : thin(top, bottom) ? "\u274F" : null;
753
800
  let mark = null;
754
- if (hollowSquare && rel >= 0.6 && rel <= 0.92) mark = "\u25A1";
801
+ if (shadow && rel >= 0.6 && rel <= 0.92) mark = shadow;
802
+ else if (hollowSquare && rel >= 0.6 && rel <= 0.92) mark = "\u25A1";
803
+ else if (filledSquare && rel >= 0.6 && rel <= 0.92) mark = "\u25A3";
755
804
  else if (nested && fill < 0.45 && rel >= 0.6) mark = "\u25CE";
756
805
  else if (cl.length === 1 && fill >= 0.9 && rel >= 0.28 && rel <= 0.6) mark = "\u25AA";
757
806
  else if (cl.length === 1 && fill >= 0.65 && fill <= 0.88 && rel >= 0.5 && rel <= 0.8) mark = "\u25CF";
@@ -1096,9 +1145,10 @@ function extractLines(fnArray, argsArray) {
1096
1145
  break;
1097
1146
  }
1098
1147
  }
1148
+ const gradient = gradientBands(horizontals, verticals);
1099
1149
  return {
1100
- horizontals: chainShortSegments(horizontals, thinShortH, "h", (l) => thinFill.has(l)),
1101
- verticals: chainShortSegments(verticals, thinShortV, "v", (l) => thinFill.has(l)),
1150
+ horizontals: chainShortSegments(horizontals.filter((l) => !gradient.has(l)), thinShortH, "h", (l) => thinFill.has(l)),
1151
+ verticals: chainShortSegments(verticals.filter((l) => !gradient.has(l)), thinShortV, "v", (l) => thinFill.has(l)),
1102
1152
  clipRects,
1103
1153
  fillRects,
1104
1154
  hiddenBoxes,
@@ -1107,6 +1157,39 @@ function extractLines(fnArray, argsArray) {
1107
1157
  nonRules
1108
1158
  };
1109
1159
  }
1160
+ var GRADIENT_MIN_EDGES = 8;
1161
+ var GRADIENT_PITCH = 1;
1162
+ function gradientBands(horizontals, verticals) {
1163
+ const out = /* @__PURE__ */ new Set();
1164
+ for (const [lines, dir] of [[horizontals, "h"], [verticals, "v"]]) {
1165
+ const pos = (l) => dir === "h" ? l.y1 : l.x1;
1166
+ const span2 = (l) => dir === "h" ? `${Math.round(l.x1)}|${Math.round(l.x2)}` : `${Math.round(l.y1)}|${Math.round(l.y2)}`;
1167
+ const groups = /* @__PURE__ */ new Map();
1168
+ for (const l of lines) if (l.fromFill) {
1169
+ const k = span2(l);
1170
+ const g = groups.get(k);
1171
+ if (g) g.push(l);
1172
+ else groups.set(k, [l]);
1173
+ }
1174
+ for (const g of groups.values()) {
1175
+ if (g.length < GRADIENT_MIN_EDGES) continue;
1176
+ g.sort((a, b) => pos(a) - pos(b));
1177
+ let run = [g[0]];
1178
+ const flush = () => {
1179
+ if (run.length >= GRADIENT_MIN_EDGES) for (const l of run) out.add(l);
1180
+ };
1181
+ for (let i = 1; i < g.length; i++) {
1182
+ if (pos(g[i]) - pos(g[i - 1]) <= GRADIENT_PITCH) run.push(g[i]);
1183
+ else {
1184
+ flush();
1185
+ run = [g[i]];
1186
+ }
1187
+ }
1188
+ flush();
1189
+ }
1190
+ }
1191
+ return out;
1192
+ }
1110
1193
  var SHORT_CHAIN_POS_TOL = 0.5;
1111
1194
  var SHORT_CHAIN_GAP = 0.2;
1112
1195
  function chainShortSegments(longs, shorts, dir, chainable = (l) => !l.fromFill) {
@@ -3473,6 +3556,7 @@ function cellTextToString(items, wrap) {
3473
3556
  if (s.length === 1) return s[0].text;
3474
3557
  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;
3475
3558
  const evenSpaced = detectEvenSpacedItems(s, true);
3559
+ const hangulLine = s.some((it) => /[가-힣]/.test(it.text));
3476
3560
  let result = s[0].text;
3477
3561
  for (let j = 1; j < s.length; j++) {
3478
3562
  if (evenSpaced[j]) {
@@ -3481,7 +3565,7 @@ function cellTextToString(items, wrap) {
3481
3565
  }
3482
3566
  const gap = s[j].x - (s[j - 1].x + s[j - 1].w);
3483
3567
  const avgFs = (s[j].fontSize + s[j - 1].fontSize) / 2;
3484
- if (isCjkLatinAutospace(s[j - 1].text, s[j].text, gap, avgFs)) {
3568
+ if (isCjkLatinAutospace(s[j - 1].text, s[j].text, gap, avgFs, hangulLine)) {
3485
3569
  result += s[j].text;
3486
3570
  } else if (s[j].hasSpaceBefore && gap >= avgFs * 0.05) {
3487
3571
  result += " " + s[j].text;
@@ -3820,8 +3904,9 @@ function sortLineByX(items) {
3820
3904
  }
3821
3905
  return items;
3822
3906
  }
3823
- function isCjkLatinAutospace(prevText, nextText, gap, fontSize) {
3824
- if (!(gap < fontSize * 0.3)) return false;
3907
+ function isCjkLatinAutospace(prevText, nextText, gap, fontSize, hangulLine = false) {
3908
+ if (!(gap < fontSize * 0.35)) return false;
3909
+ if (hangulLine) return false;
3825
3910
  const a = prevText.slice(-1), b = nextText[0] ?? "";
3826
3911
  const cjk = /[\u3040-\u30ff\u3400-\u9fff\uf900-\ufaff]/, latin = /[A-Za-z0-9]/;
3827
3912
  return cjk.test(a) && latin.test(b) || latin.test(a) && cjk.test(b);
@@ -4161,6 +4246,7 @@ function mergeLineSimple(items) {
4161
4246
  if (items.length <= 1) return items[0]?.text || "";
4162
4247
  const sorted = sortLineByX([...items]);
4163
4248
  const isEvenSpaced = detectEvenSpacedItems(sorted);
4249
+ const hangulLine = sorted.some((it) => /[가-힣]/.test(it.text));
4164
4250
  let result = sorted[0].text;
4165
4251
  for (let i = 1; i < sorted.length; i++) {
4166
4252
  const gap = sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w);
@@ -4175,7 +4261,7 @@ function mergeLineSimple(items) {
4175
4261
  result += sorted[i].text;
4176
4262
  continue;
4177
4263
  }
4178
- if (isCjkLatinAutospace(sorted[i - 1].text, sorted[i].text, gap, avgFs)) {
4264
+ if (isCjkLatinAutospace(sorted[i - 1].text, sorted[i].text, gap, avgFs, hangulLine)) {
4179
4265
  result += sorted[i].text;
4180
4266
  continue;
4181
4267
  }
@@ -4341,11 +4427,12 @@ function clusterCellLines(items) {
4341
4427
  }
4342
4428
  return lines.sort((a, b) => b.top - a.top).map(({ items: line }) => {
4343
4429
  line.sort((a, b) => a.x - b.x);
4430
+ const hangulLine = line.some((it) => /[가-힣]/.test(it.text));
4344
4431
  let s = line[0].text;
4345
4432
  for (let i = 1; i < line.length; i++) {
4346
4433
  const gap = line[i].x - (line[i - 1].x + line[i - 1].w);
4347
4434
  const fs = (line[i].fontSize + line[i - 1].fontSize) / 2;
4348
- s += (!isCjkLatinAutospace(line[i - 1].text, line[i].text, gap, fs) && (line[i].hasSpaceBefore && gap >= fs * 0.05 || gap > spaceGapThreshold(fs)) ? " " : "") + line[i].text;
4435
+ s += (!isCjkLatinAutospace(line[i - 1].text, line[i].text, gap, fs, hangulLine) && (line[i].hasSpaceBefore && gap >= fs * 0.05 || gap > spaceGapThreshold(fs)) ? " " : "") + line[i].text;
4349
4436
  }
4350
4437
  const last = line.reduce((a, b) => b.x + b.w > a.x + a.w ? b : a);
4351
4438
  return {
@@ -10095,4 +10182,4 @@ export {
10095
10182
  UNRULED_REGION_TABLES,
10096
10183
  mergeOcrImageRegions
10097
10184
  };
10098
- //# sourceMappingURL=chunk-NDC4AGLX.js.map
10185
+ //# sourceMappingURL=chunk-37JRATLZ.js.map