kordoc 4.24.28 → 4.24.29

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 (177) hide show
  1. package/README.md +4 -4
  2. package/dist/{-R5BXEKN7.js → -YTEYPQVO.js} +21 -21
  3. package/dist/{chunk-AZE46MS5.js → chunk-2C5YWTFM.js} +129 -65
  4. package/dist/chunk-2C5YWTFM.js.map +1 -0
  5. package/dist/{chunk-FWVOXMFA.js → chunk-2GULNG4H.js} +2 -2
  6. package/dist/{chunk-3WWMQS26.cjs → chunk-2XDEZVXR.cjs} +3 -3
  7. package/dist/{chunk-3WWMQS26.cjs.map → chunk-2XDEZVXR.cjs.map} +1 -1
  8. package/dist/{chunk-2MZ73PTH.cjs → chunk-3LX3Z2IU.cjs} +77 -77
  9. package/dist/{chunk-2MZ73PTH.cjs.map → chunk-3LX3Z2IU.cjs.map} +1 -1
  10. package/dist/{chunk-6EC4PI6I.js → chunk-43ZKYBLE.js} +3 -3
  11. package/dist/{chunk-BWUC36DH.js → chunk-5ESCSCHK.js} +3 -3
  12. package/dist/{chunk-EW4RSALL.js → chunk-5WGI3CM7.js} +2 -2
  13. package/dist/{chunk-PNW4B5W5.js → chunk-5WTDJEBF.js} +193 -127
  14. package/dist/chunk-5WTDJEBF.js.map +1 -0
  15. package/dist/{chunk-KW2ZZ2YM.js → chunk-6ZLZSD4K.js} +15 -15
  16. package/dist/{chunk-WKWEETPH.js → chunk-AVVS4LUN.js} +6 -6
  17. package/dist/{chunk-PUJKIYSL.js → chunk-C76347JP.js} +10 -10
  18. package/dist/{chunk-LGJYCCIK.js → chunk-D2XW3ZPA.js} +3 -3
  19. package/dist/{chunk-PIFI3L4K.cjs → chunk-E3RHMA4S.cjs} +3 -3
  20. package/dist/{chunk-PIFI3L4K.cjs.map → chunk-E3RHMA4S.cjs.map} +1 -1
  21. package/dist/{chunk-K6Z6LKX4.js → chunk-EESZHYQI.js} +3 -3
  22. package/dist/{chunk-24XMCOWF.js → chunk-EOCAXPJK.js} +2 -2
  23. package/dist/{chunk-RSCXIVO4.js → chunk-EPFU32FJ.js} +5 -5
  24. package/dist/{chunk-NXX3ZNCD.js → chunk-EVOVHP7N.js} +2 -2
  25. package/dist/{chunk-W5FIJEBK.cjs → chunk-GOM2JGBN.cjs} +2 -2
  26. package/dist/{chunk-W5FIJEBK.cjs.map → chunk-GOM2JGBN.cjs.map} +1 -1
  27. package/dist/{chunk-H77XXKSA.js → chunk-J4BY3FPL.js} +2 -2
  28. package/dist/{chunk-XOIAIDR2.js → chunk-KDJQRKIG.js} +2 -2
  29. package/dist/{chunk-263KNYS6.js → chunk-L5QXYOFG.js} +2 -2
  30. package/dist/{chunk-E2HUJHVO.cjs → chunk-MHQUXIAN.cjs} +25 -25
  31. package/dist/{chunk-E2HUJHVO.cjs.map → chunk-MHQUXIAN.cjs.map} +1 -1
  32. package/dist/{chunk-W7OSON66.js → chunk-N3BE55JM.js} +4 -4
  33. package/dist/{chunk-7YTK74IH.cjs → chunk-N3TSKOKM.cjs} +183 -119
  34. package/dist/chunk-N3TSKOKM.cjs.map +1 -0
  35. package/dist/{chunk-IGHD2274.cjs → chunk-NXAZ3MK2.cjs} +6 -6
  36. package/dist/{chunk-IGHD2274.cjs.map → chunk-NXAZ3MK2.cjs.map} +1 -1
  37. package/dist/{chunk-2LYNOQQO.js → chunk-NXCCI36U.js} +2 -2
  38. package/dist/{chunk-XZ5BYEHI.js → chunk-O4YVSQM6.js} +190 -124
  39. package/dist/chunk-O4YVSQM6.js.map +1 -0
  40. package/dist/{chunk-X323YP65.js → chunk-O7VUAKBI.js} +2 -2
  41. package/dist/{chunk-7D3YXOZB.js → chunk-PID5JXOD.js} +2 -2
  42. package/dist/{chunk-L2E7FKSR.js → chunk-PKDOIMVL.js} +5 -3
  43. package/dist/{chunk-L2E7FKSR.js.map → chunk-PKDOIMVL.js.map} +1 -1
  44. package/dist/{chunk-ZOMGHI3B.js → chunk-QLOBJB2U.js} +2 -2
  45. package/dist/{chunk-KNJFLPCP.js → chunk-ST2UWIBG.js} +22 -9
  46. package/dist/chunk-ST2UWIBG.js.map +1 -0
  47. package/dist/{chunk-Z35AEUSH.js → chunk-UGGF6IJE.js} +760 -711
  48. package/dist/chunk-UGGF6IJE.js.map +1 -0
  49. package/dist/{chunk-O57FU2GJ.js → chunk-UXOY3ZSD.js} +2 -2
  50. package/dist/{chunk-GEJLVYIV.js → chunk-UZPJUNWR.js} +2 -2
  51. package/dist/{chunk-5NALEQEL.js → chunk-W2AYHPSA.js} +113 -63
  52. package/dist/chunk-W2AYHPSA.js.map +1 -0
  53. package/dist/{chunk-HATKKA2U.js → chunk-X6BBJLB4.js} +2 -2
  54. package/dist/{chunk-NVYIWJ5U.js → chunk-XNBHWXMW.js} +2 -2
  55. package/dist/{chunk-GEMWP24J.js → chunk-XUAR22CX.js} +2 -2
  56. package/dist/{chunk-JAAUNU4D.cjs → chunk-YXZWHSS7.cjs} +330 -264
  57. package/dist/chunk-YXZWHSS7.cjs.map +1 -0
  58. package/dist/{chunk-QXA6TBIT.js → chunk-YZA2BV7Q.js} +2 -2
  59. package/dist/{chunk-GLUA5OVR.js → chunk-ZKCK6QJA.js} +4 -4
  60. package/dist/{chunk-H7M6SO2O.js → chunk-ZMDYHLXJ.js} +2 -2
  61. package/dist/chunks-BETX5XAL.js +11 -0
  62. package/dist/cli.js +43 -43
  63. package/dist/{formula-TOVULTIT.js → formula-3GNA32DY.js} +3 -3
  64. package/dist/{formula-QJSZPODL.cjs → formula-XIE3WLFC.cjs} +9 -9
  65. package/dist/{formula-QJSZPODL.cjs.map → formula-XIE3WLFC.cjs.map} +1 -1
  66. package/dist/{formula-MF3OTYTH.js → formula-XL3CHOWQ.js} +4 -4
  67. package/dist/generator-7WYFZTA4.js +17 -0
  68. package/dist/generator-HR2PEYUQ.js +10 -0
  69. package/dist/generator-WF6B6PSQ.cjs +11 -0
  70. package/dist/{generator-2YABZHQ4.cjs.map → generator-WF6B6PSQ.cjs.map} +1 -1
  71. package/dist/{image-ocr-INZPDSJH.js → image-ocr-5XVAC6GR.js} +6 -6
  72. package/dist/{image-ocr-4YJU3TJG.cjs → image-ocr-CSF647B2.cjs} +17 -17
  73. package/dist/{image-ocr-4YJU3TJG.cjs.map → image-ocr-CSF647B2.cjs.map} +1 -1
  74. package/dist/{image-ocr-LJ3WXDKU.js → image-ocr-VFC3Q4FM.js} +9 -9
  75. package/dist/index.cjs +2033 -1984
  76. package/dist/index.cjs.map +1 -1
  77. package/dist/index.js +489 -440
  78. package/dist/index.js.map +1 -1
  79. package/dist/mcp.js +36 -36
  80. package/dist/memo-4LM7X6VB.js +17 -0
  81. package/dist/{model-bundle-PXUYQSHW.js → model-bundle-MCBVBVU7.js} +5 -5
  82. package/dist/{models-SBKYVIBF.js → models-ON7Z7IEP.js} +5 -5
  83. package/dist/{parse-worker-v2-LRC5HCT6.js → parse-worker-v2-POVKDQF5.js} +22 -22
  84. package/dist/{parser-H3C7RXWN.cjs → parser-2GSL7OHD.cjs} +157 -157
  85. package/dist/{parser-H3C7RXWN.cjs.map → parser-2GSL7OHD.cjs.map} +1 -1
  86. package/dist/{parser-OXELKPM7.js → parser-QMELSN43.js} +9 -9
  87. package/dist/{parser-ARQ34S4N.js → parser-Z4JFZXTE.js} +12 -12
  88. package/dist/{pdf-ocr-ZQHLCBSN.js → pdf-ocr-ALFFH3IC.js} +9 -9
  89. package/dist/{pdf-ocr-TTLDKJSL.js → pdf-ocr-FB5SXBC6.js} +6 -6
  90. package/dist/pdf-ocr-KICQ4Z6K.cjs +36 -0
  91. package/dist/{pdf-ocr-O5VNFKRB.cjs.map → pdf-ocr-KICQ4Z6K.cjs.map} +1 -1
  92. package/dist/{profile-io-QIFJ3WF3.js → profile-io-A5DGKHHA.js} +3 -3
  93. package/dist/{rasterize-EJUDQZTP.js → rasterize-MZXDLTQ4.js} +3 -3
  94. package/dist/{redact-doc-6JMEZOGL.js → redact-doc-35SXJXNS.js} +21 -21
  95. package/dist/{render-SV47YGRO.js → render-HUNWBMBQ.js} +12 -12
  96. package/dist/{rewrite-fallback-QZV4FRPE.js → rewrite-fallback-EWZ2A7FV.js} +13 -13
  97. package/dist/seal-IEPV2HCZ.js +16 -0
  98. package/dist/{setup-FQ22XI2R.js → setup-TWETT62G.js} +3 -3
  99. package/dist/to-hwpx-F34ECNAQ.cjs +16 -0
  100. package/dist/{to-hwpx-GEI76GUY.cjs.map → to-hwpx-F34ECNAQ.cjs.map} +1 -1
  101. package/dist/{to-hwpx-BTJOOZAD.js → to-hwpx-VUXMHSHY.js} +7 -7
  102. package/dist/{to-hwpx-3EVHIIRR.js → to-hwpx-XSXRNYWN.js} +4 -4
  103. package/dist/visual-3QIRJEEB.js +37 -0
  104. package/dist/{watch-CF76OEMZ.js → watch-NHVTKLJW.js} +22 -22
  105. package/package.json +1 -1
  106. package/dist/chunk-5NALEQEL.js.map +0 -1
  107. package/dist/chunk-7YTK74IH.cjs.map +0 -1
  108. package/dist/chunk-AZE46MS5.js.map +0 -1
  109. package/dist/chunk-JAAUNU4D.cjs.map +0 -1
  110. package/dist/chunk-KNJFLPCP.js.map +0 -1
  111. package/dist/chunk-PNW4B5W5.js.map +0 -1
  112. package/dist/chunk-XZ5BYEHI.js.map +0 -1
  113. package/dist/chunk-Z35AEUSH.js.map +0 -1
  114. package/dist/chunks-DFHM4S4R.js +0 -11
  115. package/dist/generator-2YABZHQ4.cjs +0 -11
  116. package/dist/generator-SH3TOHPH.js +0 -17
  117. package/dist/generator-SST2TDKE.js +0 -10
  118. package/dist/memo-DBSP7EDT.js +0 -17
  119. package/dist/pdf-ocr-O5VNFKRB.cjs +0 -36
  120. package/dist/seal-Z4E7DZ75.js +0 -16
  121. package/dist/to-hwpx-GEI76GUY.cjs +0 -16
  122. package/dist/visual-GGB2DRCT.js +0 -37
  123. /package/dist/{-R5BXEKN7.js.map → -YTEYPQVO.js.map} +0 -0
  124. /package/dist/{chunk-FWVOXMFA.js.map → chunk-2GULNG4H.js.map} +0 -0
  125. /package/dist/{chunk-6EC4PI6I.js.map → chunk-43ZKYBLE.js.map} +0 -0
  126. /package/dist/{chunk-BWUC36DH.js.map → chunk-5ESCSCHK.js.map} +0 -0
  127. /package/dist/{chunk-EW4RSALL.js.map → chunk-5WGI3CM7.js.map} +0 -0
  128. /package/dist/{chunk-KW2ZZ2YM.js.map → chunk-6ZLZSD4K.js.map} +0 -0
  129. /package/dist/{chunk-WKWEETPH.js.map → chunk-AVVS4LUN.js.map} +0 -0
  130. /package/dist/{chunk-PUJKIYSL.js.map → chunk-C76347JP.js.map} +0 -0
  131. /package/dist/{chunk-LGJYCCIK.js.map → chunk-D2XW3ZPA.js.map} +0 -0
  132. /package/dist/{chunk-K6Z6LKX4.js.map → chunk-EESZHYQI.js.map} +0 -0
  133. /package/dist/{chunk-24XMCOWF.js.map → chunk-EOCAXPJK.js.map} +0 -0
  134. /package/dist/{chunk-RSCXIVO4.js.map → chunk-EPFU32FJ.js.map} +0 -0
  135. /package/dist/{chunk-NXX3ZNCD.js.map → chunk-EVOVHP7N.js.map} +0 -0
  136. /package/dist/{chunk-H77XXKSA.js.map → chunk-J4BY3FPL.js.map} +0 -0
  137. /package/dist/{chunk-XOIAIDR2.js.map → chunk-KDJQRKIG.js.map} +0 -0
  138. /package/dist/{chunk-263KNYS6.js.map → chunk-L5QXYOFG.js.map} +0 -0
  139. /package/dist/{chunk-W7OSON66.js.map → chunk-N3BE55JM.js.map} +0 -0
  140. /package/dist/{chunk-2LYNOQQO.js.map → chunk-NXCCI36U.js.map} +0 -0
  141. /package/dist/{chunk-X323YP65.js.map → chunk-O7VUAKBI.js.map} +0 -0
  142. /package/dist/{chunk-7D3YXOZB.js.map → chunk-PID5JXOD.js.map} +0 -0
  143. /package/dist/{chunk-ZOMGHI3B.js.map → chunk-QLOBJB2U.js.map} +0 -0
  144. /package/dist/{chunk-O57FU2GJ.js.map → chunk-UXOY3ZSD.js.map} +0 -0
  145. /package/dist/{chunk-GEJLVYIV.js.map → chunk-UZPJUNWR.js.map} +0 -0
  146. /package/dist/{chunk-HATKKA2U.js.map → chunk-X6BBJLB4.js.map} +0 -0
  147. /package/dist/{chunk-NVYIWJ5U.js.map → chunk-XNBHWXMW.js.map} +0 -0
  148. /package/dist/{chunk-GEMWP24J.js.map → chunk-XUAR22CX.js.map} +0 -0
  149. /package/dist/{chunk-QXA6TBIT.js.map → chunk-YZA2BV7Q.js.map} +0 -0
  150. /package/dist/{chunk-GLUA5OVR.js.map → chunk-ZKCK6QJA.js.map} +0 -0
  151. /package/dist/{chunk-H7M6SO2O.js.map → chunk-ZMDYHLXJ.js.map} +0 -0
  152. /package/dist/{chunks-DFHM4S4R.js.map → chunks-BETX5XAL.js.map} +0 -0
  153. /package/dist/{formula-TOVULTIT.js.map → formula-3GNA32DY.js.map} +0 -0
  154. /package/dist/{formula-MF3OTYTH.js.map → formula-XL3CHOWQ.js.map} +0 -0
  155. /package/dist/{generator-SH3TOHPH.js.map → generator-7WYFZTA4.js.map} +0 -0
  156. /package/dist/{generator-SST2TDKE.js.map → generator-HR2PEYUQ.js.map} +0 -0
  157. /package/dist/{image-ocr-INZPDSJH.js.map → image-ocr-5XVAC6GR.js.map} +0 -0
  158. /package/dist/{image-ocr-LJ3WXDKU.js.map → image-ocr-VFC3Q4FM.js.map} +0 -0
  159. /package/dist/{memo-DBSP7EDT.js.map → memo-4LM7X6VB.js.map} +0 -0
  160. /package/dist/{model-bundle-PXUYQSHW.js.map → model-bundle-MCBVBVU7.js.map} +0 -0
  161. /package/dist/{models-SBKYVIBF.js.map → models-ON7Z7IEP.js.map} +0 -0
  162. /package/dist/{parse-worker-v2-LRC5HCT6.js.map → parse-worker-v2-POVKDQF5.js.map} +0 -0
  163. /package/dist/{parser-OXELKPM7.js.map → parser-QMELSN43.js.map} +0 -0
  164. /package/dist/{parser-ARQ34S4N.js.map → parser-Z4JFZXTE.js.map} +0 -0
  165. /package/dist/{pdf-ocr-TTLDKJSL.js.map → pdf-ocr-ALFFH3IC.js.map} +0 -0
  166. /package/dist/{pdf-ocr-ZQHLCBSN.js.map → pdf-ocr-FB5SXBC6.js.map} +0 -0
  167. /package/dist/{profile-io-QIFJ3WF3.js.map → profile-io-A5DGKHHA.js.map} +0 -0
  168. /package/dist/{rasterize-EJUDQZTP.js.map → rasterize-MZXDLTQ4.js.map} +0 -0
  169. /package/dist/{redact-doc-6JMEZOGL.js.map → redact-doc-35SXJXNS.js.map} +0 -0
  170. /package/dist/{render-SV47YGRO.js.map → render-HUNWBMBQ.js.map} +0 -0
  171. /package/dist/{rewrite-fallback-QZV4FRPE.js.map → rewrite-fallback-EWZ2A7FV.js.map} +0 -0
  172. /package/dist/{seal-Z4E7DZ75.js.map → seal-IEPV2HCZ.js.map} +0 -0
  173. /package/dist/{setup-FQ22XI2R.js.map → setup-TWETT62G.js.map} +0 -0
  174. /package/dist/{to-hwpx-3EVHIIRR.js.map → to-hwpx-VUXMHSHY.js.map} +0 -0
  175. /package/dist/{to-hwpx-BTJOOZAD.js.map → to-hwpx-XSXRNYWN.js.map} +0 -0
  176. /package/dist/{visual-GGB2DRCT.js.map → visual-3QIRJEEB.js.map} +0 -0
  177. /package/dist/{watch-CF76OEMZ.js.map → watch-NHVTKLJW.js.map} +0 -0
package/README.md CHANGED
@@ -110,13 +110,13 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
110
110
 
111
111
  ## 검증 결과
112
112
 
113
- **4.22.14 · 2026-10-19 검증**(렌더 배치·PDF 글·표·별표·OCR 은 4.24.24 · 2026-10-30, HWP → HWPX 변환은 4.24.26 · 2026-10-31). 고정 코퍼스와 참조 기준으로 측정한 결과입니다.
113
+ **4.22.14 · 2026-10-19 검증**(렌더 배치·PDF 글·표·별표·OCR 은 4.24.24 · 2026-10-30, HWP → HWPX 변환은 4.24.29 · 2026-10-31). 고정 코퍼스와 참조 기준으로 측정한 결과입니다.
114
114
 
115
115
  | 대상 | 규모 | 결과 |
116
116
  | --- | --- | --- |
117
117
  | HWPX | 2,424문서 · 10,342표 | 표 구조 일치 **10,342/10,342 · 100%** |
118
118
  | HWP 5.x ↔ HWPX | 1,130쌍 · 4,315표 | 짝 문서의 표 구조 일치 **100%** |
119
- | HWP 5.x → HWPX 변환 | 한글 저장 짝 264쌍 (속성 대조 232쌍) | 속성 일치 **99.19%** · 글 **264/264** · 한글 화면 대조 80문서 |
119
+ | HWP 5.x → HWPX 변환 | 한글 저장 짝 264쌍 (속성 대조 232쌍) | 속성 일치 **99.21%** · 완전 일치 **69/232** · 글 **264/264** · 한글 화면 대조 80문서 |
120
120
  | PDF 글 | 744쌍 | 글자 재현율 **99.883%** · 정확도 **99.678%** · 읽기 순서 **99.312%** · 어절 F1 **99.067%** |
121
121
  | PDF 표 | 708쌍 · 2,331표 | 표 탐지 **99.83%** · 구조 일치 **98.24%** · 칸 F1 **0.9919** |
122
122
  | HWPX 재조판 | 다중줄 25,187문단 (12개 폴더) | 모든 줄 시작 일치 **24,941/25,187 · 99.02%** |
@@ -131,15 +131,15 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
131
131
 
132
132
  ## 최근 업데이트
133
133
 
134
- 최신 배포: **[4.24.28](https://github.com/chrisryugj/kordoc/releases/tag/v4.24.28)** · 2026-10-31
134
+ 최신 배포: **[4.24.29](https://github.com/chrisryugj/kordoc/releases/tag/v4.24.29)** · 2026-10-31
135
135
 
136
136
  | 버전 | 주요 변경 | 수치 변화 |
137
137
  | --- | --- | --- |
138
+ | 4.24.29 | to-hwpx: 한글이 저장한 꼴로 — 문단 글 방향(textDir)·같은 문단 모양 합치기·홀수 값 여백·탭의 글자 단위·OLE 이름·메모 확장·옛 판 테두리 0번 등 · patch: 새 글에 표시한 강조(원문에 없던 서식도), 한 문단 여러 곳 고칠 때 사이 글 서식 보존, HTML 표 칸 강조 표지가 글자로 박히던 것, HWP 칸 안 중첩 표 칸 · HWP 파서: 위첨자가 든 굵은 문단 강조 | 변환 속성 일치 0.99194 → **0.99214** · 완전 일치 14 → **69**/232 · patch 굵은 낱말 넣기 잔차 HWPX 241 → **121**/265 · HWP 표 칸 끝 붙이기 83 → **93**/93 · HWP·HWPX parse 대조 다른 단위 118 → **98** · 벤치 지표 그대로 |
138
139
  | 4.24.28 | 메모 읽기·달기(`memos`·`kordoc memo`·MCP `add_memo`, #180) · patch: 굵은 글·위첨자 끝에 붙인 글이 서식을 물려받던 것(HWP·HWPX), 글머리표 문단(#179), HWPX 탭·엔티티·PUA 문단과 HWP PUA·강제 줄바꿈 문단·표 칸은 바뀐 자리만 · to-hwpx: 원·네모 겹치기 번호(#178) · HWP 파서: 굵게·기울임·취소선·밑줄 표지 | patch 검증 잔차 HWPX 45 → **3**/540 · HWP 24 → **4**/140·37 → **0**/605(파서 강조 반영 뒤 기준) · HWP 대체본 원본 서식 90 → **94**/98 · HWP·HWPX parse 대조 다른 단위 390 → **118** · 벤치 지표 그대로 |
139
140
  | 4.24.27 | 서식 채우기·도장(`fill_form`·`place_seal`): HWP 5.x 서식도 원본 서식 그대로 · patch: HWP 대체본을 원본 서식으로(서식 그대로 바꾼 HWPX 에 반영), 누름틀 자리에 쓴 값은 누름틀에 채움(HWP·HWPX), 굵은 칸 GFM 표·여러 줄 1열 표·같은 글 문단 짝짓기 | patch 편집 반영 HWPX 539 → **540**/540 · 표 칸 465 → **467**/467 · HWP 132 → **140**/140 · HWP 대체본 원본 서식 0 → **90**/98 · 벤치 지표 그대로 |
140
141
  | 4.24.26 | HWP → HWPX 변환(`kordoc to-hwpx`·MCP `convert_to_hwpx`): HWP 5.x 를 서식 그대로 — 바탕쪽·표·그림·도형·연결 글상자·수식·필드·메모·양식 개체·차트까지 · patch(HWP): 탭·필드가 든 문단도 바뀐 글자만 · 마크다운: 목록 항목 첫머리 표지 이스케이프 | 변환 속성 일치 **0.992** · 글 **264/264**(한글 저장 짝) · 한글 화면 대조 80문서 · patch HWP 123 → **132**/140 · 벤치 지표 그대로 |
141
142
  | 4.24.25 | patch: 강제 줄바꿈 문단 수정, 좌표가 어긋난 자리(틀 표·제목 상자·첨자 문단)를 원문 글로 찾아 고침, 남은 편집은 원본 서식 대체본(`.rewrite.hwpx`) · 암호 HWPX 렌더 | patch 편집 반영(코퍼스 실험) HWPX 487 → **539**/540 · 표 칸 455 → **465**/467 · HWP 111 → **123**/140 · 벤치 지표 그대로 |
142
- | 4.24.24 | OCR 표: 머리 띠 안 짧은 칸 구분선 · 렌더: 칸을 벗어나는 개체, 칸 안 줄 정보 없는 문단 뒤 캐시 문단, 한 문단의 겹침 금지 어울림 표 쌓기·쪽 넘김 · COM 폴백 임시 폴더 정리(#177) | OCR 표 구조 일치 33 → **34**/67 · 렌더 쪽 수 일치 1,507 → **1,508** · 글 위치 106,818 → **106,904** · 그림 4,169 → **4,213**(문서별 하락 0) · 측정 예외 1건(변경 이력) · 나머지 지표 그대로 |
143
143
 
144
144
  이전 버전과 상세 내용은 [변경 이력](CHANGELOG.md)에 있습니다.
145
145
 
@@ -53,26 +53,26 @@ import {
53
53
  usesGaejosikMunche,
54
54
  usesLogicStructure,
55
55
  validateHwpx
56
- } from "./chunk-KW2ZZ2YM.js";
56
+ } from "./chunk-6ZLZSD4K.js";
57
57
  import {
58
58
  blocksToPages
59
- } from "./chunk-263KNYS6.js";
59
+ } from "./chunk-L5QXYOFG.js";
60
60
  import {
61
61
  extractClickHereFields,
62
62
  patchHwp,
63
63
  patchHwpx
64
- } from "./chunk-Z35AEUSH.js";
64
+ } from "./chunk-UGGF6IJE.js";
65
65
  import {
66
66
  addMemoHwpx
67
- } from "./chunk-WKWEETPH.js";
67
+ } from "./chunk-AVVS4LUN.js";
68
68
  import {
69
69
  placeSealHwpx
70
- } from "./chunk-RSCXIVO4.js";
71
- import "./chunk-QXA6TBIT.js";
70
+ } from "./chunk-EPFU32FJ.js";
71
+ import "./chunk-YZA2BV7Q.js";
72
72
  import {
73
73
  convertToHwpx,
74
74
  hwpToHwpx
75
- } from "./chunk-5NALEQEL.js";
75
+ } from "./chunk-W2AYHPSA.js";
76
76
  import {
77
77
  DEFAULT_REDACT_RULES,
78
78
  redactMarkdown,
@@ -80,7 +80,7 @@ import {
80
80
  } from "./chunk-3WSNLH4B.js";
81
81
  import {
82
82
  blocksToChunks
83
- } from "./chunk-GEJLVYIV.js";
83
+ } from "./chunk-UZPJUNWR.js";
84
84
  import {
85
85
  blocksToPdf,
86
86
  extractRenderedRegions,
@@ -91,13 +91,13 @@ import {
91
91
  renderHwp5Pages,
92
92
  renderHwpxToSvg,
93
93
  renderSceneToHtml
94
- } from "./chunk-PUJKIYSL.js";
95
- import "./chunk-6EC4PI6I.js";
96
- import "./chunk-2LYNOQQO.js";
97
- import "./chunk-KNJFLPCP.js";
94
+ } from "./chunk-C76347JP.js";
95
+ import "./chunk-43ZKYBLE.js";
96
+ import "./chunk-NXCCI36U.js";
97
+ import "./chunk-ST2UWIBG.js";
98
98
  import "./chunk-VKVDMH7X.js";
99
- import "./chunk-L2E7FKSR.js";
100
- import "./chunk-24XMCOWF.js";
99
+ import "./chunk-PKDOIMVL.js";
100
+ import "./chunk-EOCAXPJK.js";
101
101
  import "./chunk-VQFA55IC.js";
102
102
  import {
103
103
  detectFormat,
@@ -119,7 +119,7 @@ import {
119
119
  markdownToHwpx,
120
120
  normalizeGongmunPreset,
121
121
  placeTotalRow
122
- } from "./chunk-PNW4B5W5.js";
122
+ } from "./chunk-5WTDJEBF.js";
123
123
  import {
124
124
  ValueCursor,
125
125
  applySplices,
@@ -141,20 +141,20 @@ import {
141
141
  measureTextWidth,
142
142
  simulateWrap,
143
143
  simulateWrapKeepWord
144
- } from "./chunk-EW4RSALL.js";
145
- import "./chunk-NXX3ZNCD.js";
144
+ } from "./chunk-5WGI3CM7.js";
145
+ import "./chunk-EVOVHP7N.js";
146
146
  import "./chunk-OFVHQ2TZ.js";
147
147
  import "./chunk-WFKFG2RT.js";
148
- import "./chunk-GEMWP24J.js";
148
+ import "./chunk-XUAR22CX.js";
149
149
  import {
150
150
  blocksToMarkdown,
151
151
  flattenLayoutTables,
152
152
  hasStructuredCellContent
153
- } from "./chunk-NVYIWJ5U.js";
153
+ } from "./chunk-XNBHWXMW.js";
154
154
  import "./chunk-KFF47XZ7.js";
155
155
  import {
156
156
  VERSION
157
- } from "./chunk-7D3YXOZB.js";
157
+ } from "./chunk-PID5JXOD.js";
158
158
  export {
159
159
  AGENCY_COMMON_NAME,
160
160
  BUILTIN_TEMPLATES,
@@ -268,4 +268,4 @@ export {
268
268
  usesLogicStructure,
269
269
  validateHwpx
270
270
  };
271
- //# sourceMappingURL=-R5BXEKN7.js.map
271
+ //# sourceMappingURL=-YTEYPQVO.js.map
@@ -39,12 +39,12 @@ import {
39
39
  sanitizeText,
40
40
  tidyScriptTags,
41
41
  unframeLayoutTables
42
- } from "./chunk-O57FU2GJ.js";
42
+ } from "./chunk-UXOY3ZSD.js";
43
43
  import {
44
44
  KordocError,
45
45
  VERSION,
46
46
  sanitizeHref
47
- } from "./chunk-XOIAIDR2.js";
47
+ } from "./chunk-KDJQRKIG.js";
48
48
 
49
49
  // src/hwp5/to-hwpx/index.ts
50
50
  import JSZip from "jszip";
@@ -306,11 +306,13 @@ function appendParaText(state, data2, resolveControl) {
306
306
  };
307
307
  while (i + 1 < data2.length) {
308
308
  const ch3 = data2.readUInt16LE(i);
309
+ const script = state.scriptAt ? ch3 >= 32 ? state.scriptAt(wbase + i / 2) : null : void 0;
310
+ if (script !== void 0 && state.script && state.script !== script) setScript(null);
309
311
  if (state.emphAt && ch3 >= 32) {
310
312
  const key = state.emphAt(wbase + i / 2), runs = state.emphRuns ??= [];
311
313
  if (runs.length === 0 || runs[runs.length - 1][1] !== key) runs.push([base + result.length, key]);
312
314
  }
313
- if (state.scriptAt) setScript(ch3 >= 32 ? state.scriptAt(wbase + i / 2) : null);
315
+ if (script !== void 0) setScript(script);
314
316
  i += 2;
315
317
  switch (ch3) {
316
318
  // ── char 타입 (2바이트만, 확장 데이터 없음) ──
@@ -1789,7 +1791,7 @@ function emitParagraphBlocks(p) {
1789
1791
  if (p.tocEntry) TOC_ENTRY_BLOCKS.add(block);
1790
1792
  if (style2) {
1791
1793
  block.style = style2;
1792
- if (style2.strike || style2.underline) block.text = headMarker ? `${headMarker} ${decorate(trimmed)}` : decorate(trimmed);
1794
+ if ((style2.strike || style2.underline) && !block.spans) block.text = headMarker ? `${headMarker} ${decorate(trimmed)}` : decorate(trimmed);
1793
1795
  }
1794
1796
  if (footnotes.length > 0) block.footnoteText = footnotes.join("; ");
1795
1797
  if (footnoteBlocks) block.footnoteBlocks = footnoteBlocks;
@@ -1938,6 +1940,9 @@ var CTRL_OLE = cid("ole ");
1938
1940
  var FIELD_HLK = cid("%hlk");
1939
1941
  var FIELD_CLK = cid("%clk");
1940
1942
  var FIELD_UNK = cid("%unk");
1943
+ var NO_SPAN_CTRLS = /* @__PURE__ */ new Set([cid("tbl "), cid("gso "), cid("eqed"), cid("form"), cid("ole "), cid("tcps"), cid("tdut"), cid("idxm")]);
1944
+ var TEXT_CTRLS = /* @__PURE__ */ new Set([cid("fn "), cid("en "), cid("head"), cid("foot"), cid("tcmt")]);
1945
+ var isFieldCtrl = (id) => id >>> 24 === 37;
1941
1946
  var KNOWN_CTRL_IDS = /* @__PURE__ */ new Set([
1942
1947
  CTRL_TBL,
1943
1948
  CTRL_GSO,
@@ -2147,7 +2152,17 @@ function parseParagraph(records, start, end, ctx) {
2147
2152
  text = tidyScriptTags(text);
2148
2153
  const toc = takeTocLeaders(text);
2149
2154
  text = toc.text;
2150
- const spans = !inlined && !fieldsApplied && !toc.tocEntry ? emphasisSpans(state, text) : void 0;
2155
+ const holdsText = (c) => {
2156
+ for (let k = c.childStart; k < c.childEnd; k++) {
2157
+ if (records[k].tagId !== TAG_PARA_TEXT) continue;
2158
+ const st = createParaTextState();
2159
+ appendParaText(st, records[k].data);
2160
+ if (st.text.trim()) return true;
2161
+ }
2162
+ return false;
2163
+ };
2164
+ const noSpan = ctx.plainText || inlined || fieldsApplied || toc.tocEntry || text.includes("\n") || ctrls.some((c) => NO_SPAN_CTRLS.has(c.id) || isFieldCtrl(c.id) || TEXT_CTRLS.has(c.id) && holdsText(c));
2165
+ const spans = !noSpan ? emphasisSpans(state, text) : void 0;
2151
2166
  if (memoAnchors.length) {
2152
2167
  const plain = (t) => resolveLiteralLt(t.replaceAll(LITERAL_DOLLAR_MARK, "$")).replace(/\\</g, "<").replace(/[ \t]+/g, " ").trim();
2153
2168
  const paragraph = plain(text.replaceAll(INLINE_TABLE_MARK, ""));
@@ -2483,7 +2498,7 @@ function parseCell(records, lhIdx, end, ctx) {
2483
2498
  if (cs > 0) colSpan = Math.min(cs, MAX_COLS);
2484
2499
  if (rs > 0) rowSpan = Math.min(rs, MAX_ROWS);
2485
2500
  }
2486
- const blocks = ctx.depth < MAX_NEST_DEPTH ? parseParagraphList(records, lhIdx + 1, end, { ...ctx, depth: ctx.depth + 1 }) : [];
2501
+ const blocks = ctx.depth < MAX_NEST_DEPTH ? parseParagraphList(records, lhIdx + 1, end, { ...ctx, depth: ctx.depth + 1, plainText: false }) : [];
2487
2502
  const { text, hasStructure } = cellTextFromBlocks(blocks);
2488
2503
  const cell = { text, colSpan, rowSpan, colAddr, rowAddr };
2489
2504
  if (hasStructure && blocks.length > 0) cell.blocks = blocks;
@@ -2552,7 +2567,7 @@ function parseGsoControl(ctrl2, records, ctx) {
2552
2567
  }
2553
2568
  }
2554
2569
  if (textListIdx >= 0) {
2555
- blocks.push(...parseParagraphList(records, textListIdx + 1, childEnd, { ...ctx, depth: ctx.depth + 1 }));
2570
+ blocks.push(...parseParagraphList(records, textListIdx + 1, childEnd, { ...ctx, depth: ctx.depth + 1, plainText: true }));
2556
2571
  }
2557
2572
  return blocks;
2558
2573
  }
@@ -3494,7 +3509,7 @@ function borderFill(r, id, ref) {
3494
3509
  const left = side(), right = side(), top = side(), bottom = side();
3495
3510
  const dType = c.u8(), dWidth = c.u8(), dColor = c.u32();
3496
3511
  const slash = bits(a, 2, 3), back = bits(a, 5, 3);
3497
- let inner = el("hh:slash", [["type", pick(SLASH_TYPES, slash)], ["Crooked", bits(a, 8, 2) ? 1 : 0], ["isCounter", bit(a, 11)]]) + el("hh:backSlash", [["type", pick(SLASH_TYPES, back)], ["Crooked", bit(a, 10)], ["isCounter", bit(a, 12)]]) + el("hh:leftBorder", left) + el("hh:rightBorder", right) + el("hh:topBorder", top) + el("hh:bottomBorder", bottom);
3512
+ let inner = el("hh:slash", [["type", pick(SLASH_TYPES, slash)], ["Crooked", bits(a, 8, 2)], ["isCounter", bit(a, 11)]]) + el("hh:backSlash", [["type", pick(SLASH_TYPES, back)], ["Crooked", 0], ["isCounter", bit(a, 12)]]) + el("hh:leftBorder", left) + el("hh:rightBorder", right) + el("hh:topBorder", top) + el("hh:bottomBorder", bottom);
3498
3513
  if (dType) inner += el("hh:diagonal", [["type", pick(BORDER_TYPES, dType)], ["width", pick(BORDER_WIDTHS, dWidth)], ["color", color(dColor)]]);
3499
3514
  inner += fillBrushXml(c, ref);
3500
3515
  return el("hh:borderFill", [
@@ -3502,7 +3517,7 @@ function borderFill(r, id, ref) {
3502
3517
  ["threeD", bit(a, 0)],
3503
3518
  ["shadow", bit(a, 1)],
3504
3519
  ["centerLine", bit(a, 13) ? "VERTICAL" : "NONE"],
3505
- ["breakCellSeparateLine", bit(a, 14)]
3520
+ ["breakCellSeparateLine", bit(a, 10)]
3506
3521
  ], inner);
3507
3522
  }
3508
3523
  function charPr(r, id) {
@@ -3526,7 +3541,7 @@ function charPr(r, id) {
3526
3541
  inner += el("hh:underline", [
3527
3542
  ["type", underType === 2 ? "NONE" : pick(UNDERLINE_TYPES, underType)],
3528
3543
  ["shape", underType === 2 ? "SOLID" : pick(LINE_SHAPES, bits(a, 4, 4))],
3529
- ["color", color(underColor)]
3544
+ ["color", underType === 2 ? "#000000" : color(underColor)]
3530
3545
  ]);
3531
3546
  inner += el("hh:strikeout", [["shape", bits(a, 18, 3) ? pick(LINE_SHAPES, bits(a, 26, 4)) : "NONE"], ["color", color(strikeColor)]]);
3532
3547
  inner += el("hh:outline", [["type", pick(OUTLINE_TYPES, bits(a, 8, 3))]]);
@@ -3555,7 +3570,7 @@ function tabPr(r, id) {
3555
3570
  const pos = c.i32(), type = c.u8(), leader = c.u8();
3556
3571
  c.skip(2);
3557
3572
  const common = [["type", pick(TAB_TYPES, type)], ["leader", pick(BORDER_TYPES, leader)]];
3558
- inner += unitSwitch(el("hh:tabItem", [["pos", Math.trunc(pos / 2)], ...common, ["unit", "HWPUNIT"]]), el("hh:tabItem", [["pos", pos], ...common]));
3573
+ inner += unitSwitch(el("hh:tabItem", [["pos", Math.trunc(pos / 2)], ...common, ["unit", pos % 2 ? "CHAR" : "HWPUNIT"]]), el("hh:tabItem", [["pos", pos], ...common]));
3559
3574
  }
3560
3575
  return el("hh:tabPr", [["id", id], ["autoTabLeft", bit(a, 0)], ["autoTabRight", bit(a, 1)]], inner || void 0);
3561
3576
  }
@@ -3597,16 +3612,13 @@ function bullet(r, id) {
3597
3612
  const head = paraHeadAttrs(c);
3598
3613
  const ch3 = String.fromCharCode(c.u16());
3599
3614
  const imageId = c.i32();
3600
- const imgStart = c.o;
3601
- c.skip(4);
3602
- const checked = c.rest >= 2 ? c.u16() : 0;
3615
+ const checked = r.data.length >= 24 ? r.data.readUInt16LE(r.data.length - 2) : 0;
3603
3616
  let inner = el("hh:paraHead", [["level", 0], ...head]);
3604
3617
  if (imageId) inner = el("hc:img", []) + inner;
3605
- void imgStart;
3606
3618
  return el("hh:bullet", [
3607
3619
  ["id", id],
3608
3620
  ["char", ch3],
3609
- ...checked ? [["checkedChar", String.fromCharCode(checked)]] : [],
3621
+ ...checked > 32 ? [["checkedChar", String.fromCharCode(checked)]] : [],
3610
3622
  ["useImage", imageId ? 1 : 0]
3611
3623
  ], inner);
3612
3624
  }
@@ -3625,10 +3637,9 @@ function paraPr(r, id) {
3625
3637
  const level = r.data.length >= 58 ? c.u32() : bits(a1, 25, 3);
3626
3638
  const headType = pick(HEADING_TYPES, bits(a1, 23, 2));
3627
3639
  const heading = level >= 7 ? `<hp:switch><hp:case hp:required-namespace="http://www.hancom.co.kr/hwpml/2016/paragraph">${el("hh:heading", [["type", headType], ["idRef", headId], ["level", level]])}</hp:case><hp:default>${el("hh:heading", [["type", "NONE"], ["idRef", 0], ["level", 0]])}</hp:default></hp:switch>` : el("hh:heading", [["type", headType], ["idRef", headId], ["level", level]]);
3628
- const margins = (div, unit) => {
3629
- const u = unit ? [["unit", "HWPUNIT"]] : [["unit", "HWPUNIT"]];
3630
- const v = (x) => div === 1 ? x : Math.trunc(x / div);
3631
- return "<hh:margin>" + el("hc:intent", [["value", v(indent)], ...u]) + el("hc:left", [["value", v(left)], ...u]) + el("hc:right", [["value", v(right)], ...u]) + el("hc:prev", [["value", v(prev)], ...u]) + el("hc:next", [["value", v(next)], ...u]) + "</hh:margin>";
3640
+ const margins = (div) => {
3641
+ const m = (tag, x) => el(tag, [["value", div === 1 ? x : Math.trunc(x / div)], ["unit", div !== 1 && x % 2 ? "CHAR" : "HWPUNIT"]]);
3642
+ return "<hh:margin>" + m("hc:intent", indent) + m("hc:left", left) + m("hc:right", right) + m("hc:prev", prev) + m("hc:next", next) + "</hh:margin>";
3632
3643
  };
3633
3644
  const lineSpacing = (div) => el("hh:lineSpacing", [
3634
3645
  ["type", pick(LINE_SPACINGS, spType)],
@@ -3643,7 +3654,7 @@ function paraPr(r, id) {
3643
3654
  ["keepLines", bit(a1, 18)],
3644
3655
  ["pageBreakBefore", bit(a1, 19)],
3645
3656
  ["lineWrap", pick(LINE_WRAPS, bits(a2, 0, 2))]
3646
- ]) + el("hh:autoSpacing", [["eAsianEng", bit(a2, 4)], ["eAsianNum", bit(a2, 5)]]) + unitSwitch(margins(2, true) + lineSpacing(2), margins(1, true) + lineSpacing(1)) + el("hh:border", [
3657
+ ]) + el("hh:autoSpacing", [["eAsianEng", bit(a2, 4)], ["eAsianNum", bit(a2, 5)]]) + unitSwitch(margins(2) + lineSpacing(2), margins(1) + lineSpacing(1)) + el("hh:border", [
3647
3658
  ["borderFillIDRef", borderFillId],
3648
3659
  ["offsetLeft", off[0]],
3649
3660
  ["offsetRight", off[1]],
@@ -3659,10 +3670,11 @@ function paraPr(r, id) {
3659
3670
  ["fontLineHeight", bit(a1, 22)],
3660
3671
  ["snapToGrid", bit(a1, 8)],
3661
3672
  ["suppressLineNumbers", bit(a2, 2)],
3662
- ["checked", 0]
3673
+ ["checked", 0],
3674
+ ["textDir", bit(a2, 3) ? "LTR" : "AUTO"]
3663
3675
  ], inner);
3664
3676
  }
3665
- function style(r, id) {
3677
+ function style(r, id, paraIds) {
3666
3678
  const c = new Cur(r.data);
3667
3679
  const name = c.str(), engName = c.str();
3668
3680
  const a = c.u8(), nextId = c.u8(), langId = c.i16(), paraShape = c.u16(), charShape = c.u16();
@@ -3671,7 +3683,7 @@ function style(r, id) {
3671
3683
  ["type", bits(a, 0, 2) === 1 ? "CHAR" : "PARA"],
3672
3684
  ["name", name],
3673
3685
  ["engName", engName],
3674
- ["paraPrIDRef", paraShape],
3686
+ ["paraPrIDRef", paraIds[paraShape] ?? paraShape],
3675
3687
  ["charPrIDRef", charShape],
3676
3688
  ["nextStyleIDRef", nextId],
3677
3689
  ["langID", langId],
@@ -3699,26 +3711,40 @@ function docProps(recs) {
3699
3711
  const begin = [c.u16(), c.u16(), c.u16(), c.u16(), c.u16(), c.u16()];
3700
3712
  return { secCnt, begin, caret: [c.u32(), c.u32(), c.u32()] };
3701
3713
  }
3702
- function headerXml(recs, linkInfo, ref, secCnt) {
3703
- const props = docProps(recs);
3714
+ var SLOT = {
3715
+ [TAG.BORDER_FILL]: 8,
3716
+ [TAG.CHAR_SHAPE]: 9,
3717
+ [TAG.TAB_DEF]: 10,
3718
+ [TAG.NUMBERING]: 11,
3719
+ [TAG.BULLET]: 12,
3720
+ [TAG.PARA_SHAPE]: 13,
3721
+ [TAG.STYLE]: 14,
3722
+ [TAG.MEMO_SHAPE]: 15
3723
+ };
3724
+ function idCounts(recs) {
3704
3725
  const idm = new Cur(recs.find((r) => r.tagId === TAG.ID_MAPPINGS)?.data ?? Buffer.alloc(0));
3705
3726
  const counts = [];
3706
3727
  while (idm.rest >= 4) counts.push(idm.i32());
3707
- const SLOT = {
3708
- [TAG.BORDER_FILL]: 8,
3709
- [TAG.CHAR_SHAPE]: 9,
3710
- [TAG.TAB_DEF]: 10,
3711
- [TAG.NUMBERING]: 11,
3712
- [TAG.BULLET]: 12,
3713
- [TAG.PARA_SHAPE]: 13,
3714
- [TAG.STYLE]: 14,
3715
- [TAG.MEMO_SHAPE]: 15
3716
- };
3717
- const of = (tag) => {
3718
- const all = recs.filter((r) => r.tagId === tag);
3719
- const n = counts[SLOT[tag] ?? -1];
3720
- return n !== void 0 && n >= 0 ? all.slice(0, n) : all;
3721
- };
3728
+ return counts;
3729
+ }
3730
+ function recordsOf(recs, counts, tag) {
3731
+ const all = recs.filter((r) => r.tagId === tag);
3732
+ const n = counts[SLOT[tag] ?? -1];
3733
+ return n !== void 0 && n >= 0 ? all.slice(0, n) : all;
3734
+ }
3735
+ function paraShapeIds(recs) {
3736
+ const seen = /* @__PURE__ */ new Map();
3737
+ return recordsOf(recs, idCounts(recs), TAG.PARA_SHAPE).map((r) => {
3738
+ const k = r.data.toString("hex");
3739
+ if (!seen.has(k)) seen.set(k, seen.size);
3740
+ return seen.get(k);
3741
+ });
3742
+ }
3743
+ function headerXml(recs, linkInfo, ref, secCnt) {
3744
+ const props = docProps(recs);
3745
+ const counts = idCounts(recs);
3746
+ const of = (tag) => recordsOf(recs, counts, tag);
3747
+ const paraIds = paraShapeIds(recs);
3722
3748
  const list = (name, items) => items.length ? el(name, [["itemCnt", items.length]], items.join("")) : "";
3723
3749
  const [bPage, bFoot, bEnd, bPic, bTbl, bEq] = props.begin;
3724
3750
  let refList = fontFaces(of(TAG.FACE_NAME), counts.slice(1, 8));
@@ -3727,8 +3753,8 @@ function headerXml(recs, linkInfo, ref, secCnt) {
3727
3753
  refList += list("hh:tabProperties", of(TAG.TAB_DEF).map((r, i) => tabPr(r, i)));
3728
3754
  refList += list("hh:numberings", of(TAG.NUMBERING).map((r, i) => numbering(r, i + 1)));
3729
3755
  refList += list("hh:bullets", of(TAG.BULLET).map((r, i) => bullet(r, i + 1)));
3730
- refList += list("hh:paraProperties", of(TAG.PARA_SHAPE).map((r, i) => paraPr(r, i)));
3731
- refList += list("hh:styles", of(TAG.STYLE).map((r, i) => style(r, i)));
3756
+ refList += list("hh:paraProperties", of(TAG.PARA_SHAPE).flatMap((r, i) => paraIds.indexOf(paraIds[i]) === i ? [paraPr(r, paraIds[i])] : []));
3757
+ refList += list("hh:styles", of(TAG.STYLE).map((r, i) => style(r, i, paraIds)));
3732
3758
  refList += list("hh:memoProperties", of(TAG.MEMO_SHAPE).map((r, i) => memoPr(r, i + 1)));
3733
3759
  const compat = new Cur(recs.find((r) => r.tagId === TAG.COMPATIBLE_DOCUMENT)?.data ?? Buffer.alloc(0)).u32();
3734
3760
  const track = new Cur(recs.find((r) => r.tagId === TAG.TRACKCHANGE)?.data ?? Buffer.alloc(0)).u32();
@@ -3782,12 +3808,12 @@ function params(type, prop, command) {
3782
3808
  if (type === "BOOKMARK") return `<hp:parameters cnt="1" name="">${items[0]}</hp:parameters>`;
3783
3809
  items.push(str("Command", command, preserve));
3784
3810
  if (type === "CLICK_HERE") {
3785
- items.push(str("Direction", wstringValue(command, "Direction")));
3811
+ if (/Direction:wstring:/.test(command)) items.push(str("Direction", wstringValue(command, "Direction")));
3786
3812
  const help = wstringValue(command, "HelpState");
3787
3813
  if (help) items.push(str("HelpState", help));
3788
3814
  } else if (type === "HYPERLINK") {
3789
3815
  const parts = command.split(/(?<!\\);/);
3790
- items.push(str("Path", parts[0].replace(/\\(.)/g, "$1")));
3816
+ if (parts[0]) items.push(str("Path", parts[0].replace(/\\(.)/g, "$1")));
3791
3817
  items.push(str("Category", LINK_CATEGORIES[Number(parts[1])] ?? LINK_CATEGORIES[1]));
3792
3818
  items.push(str("TargetType", LINK_TARGETS[Number(parts[2])] ?? LINK_TARGETS[0]));
3793
3819
  items.push(str("DocOpenType", LINK_OPENS[Number(parts[3])] ?? LINK_OPENS[0]));
@@ -3977,14 +4003,14 @@ var pt = (name, c) => el(name, [["x", c.i32()], ["y", c.i32()]]);
3977
4003
  function shapeHref(comp) {
3978
4004
  const cd = comp.kids.find((x) => x.rec.tagId === TAG_CTRL_DATA);
3979
4005
  const v = cd ? subSet(readParamSet(cd.rec.data, { o: 0 }), 623)?.[613] : void 0;
3980
- return typeof v === "string" ? v : "";
4006
+ return typeof v === "string" ? v.replace(/\\:/g, ":") : "";
3981
4007
  }
3982
4008
  function shapeXml(comp, o, description, ctx, caption) {
3983
4009
  const k = readComponent(comp);
3984
4010
  const sub = (tag) => new Cur(comp.kids.find((x) => x.rec.tagId === tag)?.rec.data ?? Buffer.alloc(0));
3985
4011
  const head = o ? objHeadAttrs(o) : [["id", 0], ["zOrder", 0], ["numberingType", "NONE"], ["textWrap", "TOP_AND_BOTTOM"], ["textFlow", "BOTH_SIDES"], ["lock", 0], ["dropcapstyle", "None"]];
3986
4012
  const comment = o && description ? `<hp:shapeComment>${escText(description)}</hp:shapeComment>` : "";
3987
- const tail = (o ? objPlacementXml(o) + caption : "") + comment;
4013
+ const tail = o ? objPlacementXml(o) + comment + caption : comment;
3988
4014
  const common = componentHeadXml(k);
3989
4015
  const href = shapeHref(comp);
3990
4016
  if (k.kind === "$pic") {
@@ -4104,6 +4130,7 @@ function oleXml(comp, k, head, common, o, caption, comment, ctx) {
4104
4130
  const r = new Cur(comp.kids.find((x) => x.rec.tagId === TAG_SHAPE.OLE)?.rec.data ?? Buffer.alloc(0));
4105
4131
  const a = r.u32(), ex = r.i32(), ey = r.i32(), binId = r.u16();
4106
4132
  const lineColor = r.u32(), lineWidth = r.i32(), la = r.u32();
4133
+ const instId = r.rest >= 4 ? r.u32() : 0;
4107
4134
  const line = el("hp:lineShape", [
4108
4135
  ["color", color(lineColor)],
4109
4136
  ["width", lineWidth],
@@ -4126,9 +4153,9 @@ function oleXml(comp, k, head, common, o, caption, comment, ctx) {
4126
4153
  ...head,
4127
4154
  ["href", shapeHref(comp)],
4128
4155
  ["groupLevel", k.groupLevel],
4129
- ["instid", 0],
4156
+ ["instid", instId],
4130
4157
  ["objectType", pick(OLE_TYPES, bits(a, 16, 6))],
4131
- ["binaryItemIDRef", ctx.oleRef(binId, !!chart)],
4158
+ ["binaryItemIDRef", ctx.oleRef(binId)],
4132
4159
  ["hasMoniker", bit(a, 8)],
4133
4160
  ["drawAspect", OLE_ASPECTS[bits(a, 0, 8)] ?? "CONTENT"],
4134
4161
  ["eqBaseLine", bits(a, 9, 7)]
@@ -4220,10 +4247,11 @@ function otherControlXml(id, node, ctx) {
4220
4247
  case "fn ":
4221
4248
  case "en ": {
4222
4249
  const c = data(node);
4223
- const number = c.u32() & 65535, prefix = c.u16(), suffix = c.u16();
4224
- c.u32();
4250
+ const num = c.u32(), prefix = c.u16(), suffix = c.u16();
4251
+ const flag = c.u32();
4225
4252
  const instId = c.u32();
4226
- const attrs2 = [["number", number]];
4253
+ const attrs2 = [...flag ? [["flag", flag]] : [], ["number", num & 65535]];
4254
+ if (num >>> 16) attrs2.push(["userChar", num >>> 16]);
4227
4255
  if (id === "en " || prefix) attrs2.push(["prefixChar", prefix]);
4228
4256
  attrs2.push(["suffixChar", suffix], ["instId", instId]);
4229
4257
  return ctrl(el(id === "fn " ? "hp:footNote" : "hp:endNote", attrs2, subListXml(node, ctx, false)));
@@ -4694,7 +4722,7 @@ function paragraphXml(p, ctx) {
4694
4722
  }
4695
4723
  return el("hp:p", [
4696
4724
  ["id", instanceId],
4697
- ["paraPrIDRef", paraShape],
4725
+ ["paraPrIDRef", ctx.paraIds[paraShape] ?? paraShape],
4698
4726
  ["styleIDRef", styleId],
4699
4727
  ["pageBreak", bit(breaks, 2)],
4700
4728
  ["columnBreak", bit(breaks, 3)],
@@ -4906,6 +4934,7 @@ function secPrXml(node, ctx) {
4906
4934
  }
4907
4935
  }
4908
4936
  const data2 = node.kids.find((k) => k.rec.tagId === TAG2.CTRL_DATA);
4937
+ const memoShape = node.rec.data.length >= 38 ? node.rec.data.readUInt32LE(34) : ctx.memoShapes ? 1 : 0;
4909
4938
  return el(
4910
4939
  "hp:secPr",
4911
4940
  [
@@ -4914,9 +4943,9 @@ function secPrXml(node, ctx) {
4914
4943
  ["spaceColumns", spaceColumns],
4915
4944
  ["tabStop", tabStop],
4916
4945
  ["tabStopVal", Math.trunc(tabStop / 2)],
4917
- ["tabStopUnit", "HWPUNIT"],
4946
+ ["tabStopUnit", tabStop % 2 ? "CHAR" : "HWPUNIT"],
4918
4947
  ["outlineShapeIDRef", outline],
4919
- ["memoShapeIDRef", ctx.memoShapes ? 1 : 0],
4948
+ ["memoShapeIDRef", memoShape],
4920
4949
  ["textVerticalWidthHead", 0],
4921
4950
  ["masterPageCnt", masters.length]
4922
4951
  ],
@@ -5073,6 +5102,34 @@ function scriptParts(data2) {
5073
5102
  }
5074
5103
  return [parts[0], parts[1]];
5075
5104
  }
5105
+ function memoExtendedXml(raw, compressed) {
5106
+ if (!raw) return null;
5107
+ let rec;
5108
+ try {
5109
+ rec = readRecords(compressed ? decompressStream(raw) : raw).find((r) => r.tagId === 101);
5110
+ } catch {
5111
+ return null;
5112
+ }
5113
+ if (!rec || rec.data.length < 4) return null;
5114
+ const c = new Cur(rec.data);
5115
+ const memos = [];
5116
+ for (let n = c.u32(); n > 0 && c.rest >= 8; n--) memos.push(el("he:memo", [["id", c.u32()], ["parentId", c.u32()]]));
5117
+ return memos.length ? XML_DECL + `<he:memosEx xmlns:he="http://www.hancom.co.kr/hwpml/2021/extended">${memos.join("")}</he:memosEx>` : null;
5118
+ }
5119
+ var EMPTY_BORDER_FILL = '<hh:borderFill id="1" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0"><hh:slash type="NONE" Crooked="0" isCounter="0"/><hh:backSlash type="NONE" Crooked="0" isCounter="0"/>' + ["left", "right", "top", "bottom"].map((s) => `<hh:${s}Border type="NONE" width="0.1 mm" color="#000000"/>`).join("") + '<hh:diagonal type="SOLID" width="0.1 mm" color="#000000"/></hh:borderFill>';
5120
+ function shiftZeroBorderFill(parts) {
5121
+ if (![...parts.values()].some((x) => x.includes('borderFillIDRef="0"'))) return parts;
5122
+ const out = /* @__PURE__ */ new Map();
5123
+ for (const [name, xml] of parts) {
5124
+ let x = xml.replace(/borderFillIDRef="(\d+)"/g, (_, n) => `borderFillIDRef="${Number(n) + 1}"`);
5125
+ if (name === "Contents/header.xml") {
5126
+ x = x.replace(/<hh:borderFill id="(\d+)"/g, (_, n) => `<hh:borderFill id="${Number(n) + 1}"`);
5127
+ x = x.includes("<hh:borderFills ") ? x.replace(/<hh:borderFills itemCnt="(\d+)">/, (_, n) => `<hh:borderFills itemCnt="${Number(n) + 1}">${EMPTY_BORDER_FILL}`) : x.replace("</hh:fontfaces>", `</hh:fontfaces><hh:borderFills itemCnt="1">${EMPTY_BORDER_FILL}</hh:borderFills>`);
5128
+ }
5129
+ out.set(name, x);
5130
+ }
5131
+ return out;
5132
+ }
5076
5133
  var V13_DEFAULT_SCRIPT = "function OnDocument_New()\r\n{\r\n //todo : \r\n}\r\n\r\n";
5077
5134
  async function hwpToHwpx(input, options) {
5078
5135
  const buffer = Buffer.from(input instanceof ArrayBuffer ? new Uint8Array(input) : input);
@@ -5095,11 +5152,12 @@ async function hwpToHwpx(input, options) {
5095
5152
  const refs = /* @__PURE__ */ new Map();
5096
5153
  const refer = (binId, kind) => {
5097
5154
  let r = refs.get(binId);
5098
- if (!r) refs.set(binId, r = { id: `${kind === "chart" ? "ole" : "image"}${refs.size + 1}`, kind });
5155
+ if (!r) refs.set(binId, r = { id: `${kind}${refs.size + 1}`, kind });
5099
5156
  return r.id;
5100
5157
  };
5101
5158
  const ctx = {
5102
5159
  memoShapes: docInfo.filter((r) => r.tagId === TAG_MEMO_SHAPE).length,
5160
+ paraIds: paraShapeIds(docInfo),
5103
5161
  fields: { stack: [] },
5104
5162
  masterPages: [],
5105
5163
  tailMasters: [],
@@ -5115,7 +5173,7 @@ async function hwpToHwpx(input, options) {
5115
5173
  return name;
5116
5174
  },
5117
5175
  binRef: (binId) => refer(binId, "image"),
5118
- oleRef: (binId, chart) => refer(binId, chart ? "chart" : "ole")
5176
+ oleRef: (binId) => refer(binId, "ole")
5119
5177
  };
5120
5178
  const zip = new JSZip();
5121
5179
  zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
@@ -5135,34 +5193,40 @@ async function hwpToHwpx(input, options) {
5135
5193
  ]),
5136
5194
  { compression: "STORE" }
5137
5195
  );
5138
- zip.file("Contents/header.xml", headerXml(docInfo, link, ctx.binRef, sections.length));
5196
+ const parts = /* @__PURE__ */ new Map([["Contents/header.xml", headerXml(docInfo, link, ctx.binRef, sections.length)]]);
5139
5197
  const sectionNames = [];
5140
5198
  const sectionItems = [];
5141
5199
  sections.forEach((recs, i) => {
5142
5200
  const name = `Contents/section${i}.xml`;
5143
5201
  const mp0 = ctx.masterPages.length;
5144
- zip.file(name, sectionXml(recordTree(recs ?? []), ctx));
5202
+ parts.set(name, sectionXml(recordTree(recs ?? []), ctx));
5145
5203
  for (let k = mp0; k < ctx.masterPages.length; k++) {
5146
- zip.file(`Contents/masterpage${k}.xml`, ctx.masterPages[k]);
5204
+ parts.set(`Contents/masterpage${k}.xml`, ctx.masterPages[k]);
5147
5205
  sectionItems.push(el("opf:item", [["id", `masterpage${k}`], ["href", `Contents/masterpage${k}.xml`], ["media-type", "application/xml"]]));
5148
5206
  }
5149
5207
  sectionNames.push(name);
5150
5208
  sectionItems.push(el("opf:item", [["id", `section${i}`], ["href", name], ["media-type", "application/xml"]]));
5151
5209
  });
5210
+ for (const [name, xml] of shiftZeroBorderFill(parts)) zip.file(name, xml);
5152
5211
  for (const b of items) if (!refs.has(b.index)) refer(b.index, b.ole ? "ole" : "image");
5153
5212
  const manifest = [el("opf:item", [["id", "header"], ["href", "Contents/header.xml"], ["media-type", "application/xml"]])];
5213
+ const memoEx = memoExtendedXml(c.findStream("/MemoExtended"), c.compressed);
5214
+ if (memoEx) {
5215
+ zip.file("Contents/memoExtended.xml", memoEx);
5216
+ manifest.push(el("opf:item", [["id", "memoextended"], ["href", "Contents/memoExtended.xml"], ["media-type", "application/xml"]]));
5217
+ }
5154
5218
  for (const [binId, r] of refs) {
5155
5219
  const b = items.find((x) => x.index === binId);
5156
5220
  const data2 = b && bins.get(b.storageId);
5157
5221
  if (!b || !data2) continue;
5158
- const ext = r.kind === "chart" ? "ole" : r.kind === "ole" ? "OLE" : /\.([^.]+)$/.exec(data2.name)?.[1] ?? b.ext;
5222
+ const ext = r.kind === "ole" ? "ole" : /\.([^.]+)$/.exec(data2.name)?.[1] ?? b.ext;
5159
5223
  const name = `BinData/${r.id}.${ext}`;
5160
5224
  zip.file(name, data2.data, /^(png|jpe?g|gif)$/i.test(ext) ? { compression: "STORE" } : void 0);
5161
5225
  manifest.push(el("opf:item", [
5162
5226
  ["id", r.id],
5163
5227
  ["href", name],
5164
- ["media-type", r.kind === "chart" ? "application/ole" : r.kind === "ole" ? "application/octet-stream" : `image/${ext.toLowerCase()}`],
5165
- ["isEmbeded", r.kind === "chart" ? 0 : 1]
5228
+ ["media-type", r.kind === "ole" ? "application/ole" : `image/${ext.toLowerCase()}`],
5229
+ ["isEmbeded", r.kind === "ole" ? 0 : 1]
5166
5230
  ]));
5167
5231
  }
5168
5232
  manifest.push(...sectionItems);
@@ -5208,7 +5272,7 @@ async function convertToHwpx(input, options) {
5208
5272
  if (format === "hwpx") return { data: bytes, mode: "preserve", warnings: ["\uC774\uBBF8 HWPX \uBB38\uC11C\uC785\uB2C8\uB2E4 \u2014 \uADF8\uB300\uB85C \uB461\uB2C8\uB2E4"] };
5209
5273
  if (format !== "hwp3" && format !== "hwpml") throw new KordocError(`HWP \uBB38\uC11C\uAC00 \uC544\uB2D9\uB2C8\uB2E4 (${format})`);
5210
5274
  const { parse } = await import("./index.js");
5211
- const { markdownToHwpx } = await import("./generator-SST2TDKE.js");
5275
+ const { markdownToHwpx } = await import("./generator-HR2PEYUQ.js");
5212
5276
  const parsed = await parse(ab, { password: options?.password });
5213
5277
  if (!parsed.success) throw new KordocError(parsed.error ?? "\uBB38\uC11C\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4");
5214
5278
  return {
@@ -5270,4 +5334,4 @@ export {
5270
5334
  hwpToHwpx,
5271
5335
  convertToHwpx
5272
5336
  };
5273
- //# sourceMappingURL=chunk-AZE46MS5.js.map
5337
+ //# sourceMappingURL=chunk-2C5YWTFM.js.map