kordoc 4.3.1 → 4.4.0

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 (168) hide show
  1. package/NOTICE +176 -0
  2. package/README.md +936 -922
  3. package/THIRD_PARTY/apache-2.0.LICENSE +201 -0
  4. package/THIRD_PARTY/claw-hwp.LICENSE +21 -0
  5. package/THIRD_PARTY/hml-equation-parser.LICENSE +201 -0
  6. package/THIRD_PARTY/hml-equation-parser.txt +35 -0
  7. package/THIRD_PARTY/opendataloader-pdf.txt +32 -0
  8. package/THIRD_PARTY/pix2text.txt +17 -0
  9. package/THIRD_PARTY/rhwp-forms.txt +35 -0
  10. package/dist/{-RH6BEVTT.js → -R6NUMPRV.js} +11 -11
  11. package/dist/{chunk-3FFPHTXD.js → chunk-3H5X63BQ.js} +1 -1
  12. package/dist/chunk-3H5X63BQ.js.map +1 -0
  13. package/dist/{chunk-HZU7Y22R.js → chunk-5KLE3U23.js} +7 -4
  14. package/dist/chunk-5KLE3U23.js.map +1 -0
  15. package/dist/{chunk-6GBLFQMA.js → chunk-5RPYBC2Q.js} +1 -1
  16. package/dist/chunk-5RPYBC2Q.js.map +1 -0
  17. package/dist/{chunk-SA22NK56.js → chunk-65DYCXGC.js} +4 -4
  18. package/dist/chunk-65DYCXGC.js.map +1 -0
  19. package/dist/{chunk-W34QSJFF.js → chunk-7FCNOKOR.js} +1 -1
  20. package/dist/chunk-7FCNOKOR.js.map +1 -0
  21. package/dist/{chunk-ZSL6MQVE.js → chunk-A73RMJ6B.js} +1 -1
  22. package/dist/chunk-A73RMJ6B.js.map +1 -0
  23. package/dist/{chunk-5F5UCACZ.cjs → chunk-AB322K3O.cjs} +6 -6
  24. package/dist/chunk-AB322K3O.cjs.map +1 -0
  25. package/dist/chunk-DCZVOIEO.cjs.map +1 -1
  26. package/dist/{chunk-O5EK52TG.js → chunk-DZIXKL7E.js} +1 -1
  27. package/dist/chunk-DZIXKL7E.js.map +1 -0
  28. package/dist/{chunk-CD5X6UG5.js → chunk-GHGZU2LQ.js} +2 -2
  29. package/dist/chunk-GHGZU2LQ.js.map +1 -0
  30. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  31. package/dist/{chunk-6XPXIG57.js → chunk-GZDOWYJM.js} +2 -2
  32. package/dist/chunk-GZDOWYJM.js.map +1 -0
  33. package/dist/{chunk-VQB5P5KJ.cjs → chunk-H2KMJOB6.cjs} +2 -2
  34. package/dist/chunk-H2KMJOB6.cjs.map +1 -0
  35. package/dist/{chunk-YDCD4AV4.js → chunk-HFJF477F.js} +3 -3
  36. package/dist/chunk-HFJF477F.js.map +1 -0
  37. package/dist/{chunk-ZYYTU7NY.js → chunk-HNRULYUH.js} +2 -2
  38. package/dist/chunk-HNRULYUH.js.map +1 -0
  39. package/dist/chunk-MOL7MDBG.js +0 -0
  40. package/dist/{chunk-LEC2HG7A.js → chunk-ONS7JKVA.js} +2 -2
  41. package/dist/chunk-ONS7JKVA.js.map +1 -0
  42. package/dist/{chunk-ZJ75YDW7.js → chunk-P7YPCK7C.js} +2 -2
  43. package/dist/chunk-P7YPCK7C.js.map +1 -0
  44. package/dist/{chunk-BPJSTJBN.js → chunk-QXYB74QF.js} +24 -3
  45. package/dist/chunk-QXYB74QF.js.map +1 -0
  46. package/dist/{chunk-BYEQDLZS.js → chunk-RZURSA4N.js} +6 -4
  47. package/dist/chunk-RZURSA4N.js.map +1 -0
  48. package/dist/{chunk-7DZPPUQD.cjs → chunk-SKM6KZUH.cjs} +9 -9
  49. package/dist/chunk-SKM6KZUH.cjs.map +1 -0
  50. package/dist/{chunk-YNJDNP44.js → chunk-UAFSPWU7.js} +1 -1
  51. package/dist/chunk-UAFSPWU7.js.map +1 -0
  52. package/dist/{chunk-ZMKTKJZN.cjs → chunk-UDGPM5R5.cjs} +26 -5
  53. package/dist/chunk-UDGPM5R5.cjs.map +1 -0
  54. package/dist/{chunk-GTPEKBN6.js → chunk-V35DRUJC.js} +2 -2
  55. package/dist/chunk-V35DRUJC.js.map +1 -0
  56. package/dist/{chunk-HPRK67YB.js → chunk-W6CUD7V3.js} +3 -3
  57. package/dist/chunk-W6CUD7V3.js.map +1 -0
  58. package/dist/{chunk-FUXDD36A.js → chunk-XCIC7U6Y.js} +24 -3
  59. package/dist/chunk-XCIC7U6Y.js.map +1 -0
  60. package/dist/{chunk-RO4Y4BFI.js → chunk-YOZ7ZRCD.js} +366 -51
  61. package/dist/chunk-YOZ7ZRCD.js.map +1 -0
  62. package/dist/{chunk-PV3NVBGL.js → chunk-YVYU267E.js} +3 -3
  63. package/dist/chunk-YVYU267E.js.map +1 -0
  64. package/dist/{chunk-MGGU3ZRK.cjs → chunk-ZV5OKQ3Z.cjs} +1 -1
  65. package/dist/chunk-ZV5OKQ3Z.cjs.map +1 -0
  66. package/dist/chunks-QMGCI5DG.js +10 -0
  67. package/dist/cli.js +28 -24
  68. package/dist/cli.js.map +1 -1
  69. package/dist/{formula-IWV5IJ3Y.cjs → formula-CG4S7TWO.cjs} +8 -8
  70. package/dist/formula-CG4S7TWO.cjs.map +1 -0
  71. package/dist/{formula-7ZPC54JO.js → formula-JLYS73QL.js} +2 -2
  72. package/dist/formula-JLYS73QL.js.map +1 -0
  73. package/dist/{formula-EQRHSMYW.js → formula-LIVQSCMM.js} +2 -2
  74. package/dist/formula-LIVQSCMM.js.map +1 -0
  75. package/dist/{image-ocr-MGVXT6XD.cjs → image-ocr-F2BQA26V.cjs} +11 -11
  76. package/dist/image-ocr-F2BQA26V.cjs.map +1 -0
  77. package/dist/{image-ocr-6MO4FXJK.js → image-ocr-U2DRRFL3.js} +5 -5
  78. package/dist/image-ocr-U2DRRFL3.js.map +1 -0
  79. package/dist/{image-ocr-TWUU2RNG.js → image-ocr-XC52AQDV.js} +7 -7
  80. package/dist/image-ocr-XC52AQDV.js.map +1 -0
  81. package/dist/index.cjs +858 -537
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.d.cts +7 -0
  84. package/dist/index.d.ts +7 -0
  85. package/dist/index.js +373 -52
  86. package/dist/index.js.map +1 -1
  87. package/dist/mcp.js +24 -22
  88. package/dist/mcp.js.map +1 -1
  89. package/dist/{models-6VMAVZR6.js → models-6SIKLKRH.js} +3 -3
  90. package/dist/page-range-737B4EZW.js +0 -0
  91. package/dist/page-range-P7SDW6LR.cjs.map +1 -1
  92. package/dist/{parser-VR2BTUT7.js → parser-ESGFWWCT.js} +8 -8
  93. package/dist/parser-ESGFWWCT.js.map +1 -0
  94. package/dist/{parser-JFGLN4DA.cjs → parser-FFQN67O6.cjs} +25 -25
  95. package/dist/parser-FFQN67O6.cjs.map +1 -0
  96. package/dist/{parser-YA7HSSPK.js → parser-TFPGQWCC.js} +6 -6
  97. package/dist/parser-TFPGQWCC.js.map +1 -0
  98. package/dist/pdf-ocr-4R646OO6.js +12 -0
  99. package/dist/pdf-ocr-UQBZH3HE.cjs +13 -0
  100. package/dist/pdf-ocr-UQBZH3HE.cjs.map +1 -0
  101. package/dist/pdf-ocr-WE5TMRFU.js +15 -0
  102. package/dist/{profile-io-QPIMGVO3.js → profile-io-O6BDCUJN.js} +3 -3
  103. package/dist/{rasterize-AFYGNKXG.js → rasterize-V22VCCE7.js} +2 -2
  104. package/dist/rasterize-V22VCCE7.js.map +1 -0
  105. package/dist/{redact-W5K3ILQH.js → redact-7ILEAUTS.js} +2 -2
  106. package/dist/render-3BSVTTZE.js +10 -0
  107. package/dist/seal-6ZSEJVOD.js +10 -0
  108. package/dist/{setup-I4I75QJU.js → setup-GUQT5ELJ.js} +1 -1
  109. package/dist/setup-GUQT5ELJ.js.map +1 -0
  110. package/dist/{watch-D3JJEOAB.js → watch-HGKBICED.js} +11 -11
  111. package/dist/watch-HGKBICED.js.map +1 -0
  112. package/package.json +103 -101
  113. package/templates//352/260/204/354/235/264/352/270/260/354/225/210/353/254/270_/354/230/210/354/213/234/352/260/222.json +9 -9
  114. package/templates//354/235/274/353/260/230/352/270/260/354/225/210/353/254/270_/354/230/210/354/213/234/352/260/222.json +24 -24
  115. package/dist/chunk-3FFPHTXD.js.map +0 -1
  116. package/dist/chunk-5F5UCACZ.cjs.map +0 -1
  117. package/dist/chunk-6GBLFQMA.js.map +0 -1
  118. package/dist/chunk-6XPXIG57.js.map +0 -1
  119. package/dist/chunk-7DZPPUQD.cjs.map +0 -1
  120. package/dist/chunk-BPJSTJBN.js.map +0 -1
  121. package/dist/chunk-BYEQDLZS.js.map +0 -1
  122. package/dist/chunk-CD5X6UG5.js.map +0 -1
  123. package/dist/chunk-FUXDD36A.js.map +0 -1
  124. package/dist/chunk-GTPEKBN6.js.map +0 -1
  125. package/dist/chunk-HPRK67YB.js.map +0 -1
  126. package/dist/chunk-HZU7Y22R.js.map +0 -1
  127. package/dist/chunk-LEC2HG7A.js.map +0 -1
  128. package/dist/chunk-MGGU3ZRK.cjs.map +0 -1
  129. package/dist/chunk-O5EK52TG.js.map +0 -1
  130. package/dist/chunk-PV3NVBGL.js.map +0 -1
  131. package/dist/chunk-RO4Y4BFI.js.map +0 -1
  132. package/dist/chunk-SA22NK56.js.map +0 -1
  133. package/dist/chunk-VQB5P5KJ.cjs.map +0 -1
  134. package/dist/chunk-W34QSJFF.js.map +0 -1
  135. package/dist/chunk-YDCD4AV4.js.map +0 -1
  136. package/dist/chunk-YNJDNP44.js.map +0 -1
  137. package/dist/chunk-ZJ75YDW7.js.map +0 -1
  138. package/dist/chunk-ZMKTKJZN.cjs.map +0 -1
  139. package/dist/chunk-ZSL6MQVE.js.map +0 -1
  140. package/dist/chunk-ZYYTU7NY.js.map +0 -1
  141. package/dist/chunks-JEYQWXIZ.js +0 -10
  142. package/dist/formula-7ZPC54JO.js.map +0 -1
  143. package/dist/formula-EQRHSMYW.js.map +0 -1
  144. package/dist/formula-IWV5IJ3Y.cjs.map +0 -1
  145. package/dist/image-ocr-6MO4FXJK.js.map +0 -1
  146. package/dist/image-ocr-MGVXT6XD.cjs.map +0 -1
  147. package/dist/image-ocr-TWUU2RNG.js.map +0 -1
  148. package/dist/parser-JFGLN4DA.cjs.map +0 -1
  149. package/dist/parser-VR2BTUT7.js.map +0 -1
  150. package/dist/parser-YA7HSSPK.js.map +0 -1
  151. package/dist/pdf-ocr-4LISPZEM.cjs +0 -13
  152. package/dist/pdf-ocr-4LISPZEM.cjs.map +0 -1
  153. package/dist/pdf-ocr-AIWB2QCS.js +0 -12
  154. package/dist/pdf-ocr-QMOKUMC2.js +0 -15
  155. package/dist/rasterize-AFYGNKXG.js.map +0 -1
  156. package/dist/render-PSPTMZIZ.js +0 -10
  157. package/dist/seal-4XBJ7ISE.js +0 -10
  158. package/dist/setup-I4I75QJU.js.map +0 -1
  159. package/dist/watch-D3JJEOAB.js.map +0 -1
  160. /package/dist/{-RH6BEVTT.js.map → -R6NUMPRV.js.map} +0 -0
  161. /package/dist/{chunks-JEYQWXIZ.js.map → chunks-QMGCI5DG.js.map} +0 -0
  162. /package/dist/{models-6VMAVZR6.js.map → models-6SIKLKRH.js.map} +0 -0
  163. /package/dist/{pdf-ocr-AIWB2QCS.js.map → pdf-ocr-4R646OO6.js.map} +0 -0
  164. /package/dist/{pdf-ocr-QMOKUMC2.js.map → pdf-ocr-WE5TMRFU.js.map} +0 -0
  165. /package/dist/{profile-io-QPIMGVO3.js.map → profile-io-O6BDCUJN.js.map} +0 -0
  166. /package/dist/{redact-W5K3ILQH.js.map → redact-7ILEAUTS.js.map} +0 -0
  167. /package/dist/{render-PSPTMZIZ.js.map → render-3BSVTTZE.js.map} +0 -0
  168. /package/dist/{seal-4XBJ7ISE.js.map → seal-6ZSEJVOD.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/render/svg-render.ts","../src/render/layout.ts","../src/hwpx/text-metrics.ts","../src/render/reflow.ts"],"sourcesContent":["/**\r\n * 레이아웃 보존 렌더 — HWPX 조판 캐시(lineseg·cellAddr·hp:pos)를 SVG 절대배치로 그린다.\r\n *\r\n * 조판 엔진 없음: 한컴이 저장 시 기록한 좌표를 그대로 사용한다. 따라서\r\n * 한컴(또는 조판 캐시를 기록하는 편집기)에서 저장한 파일만 렌더 가능 —\r\n * markdownToHwpx 산출물엔 linesegarray가 없어 KordocError를 던진다.\r\n *\r\n * 좌표 산식(실측 검증 — .claude/plans/render-poc/findings.md):\r\n * - 단위 HWPUNIT(1/7200in), pt = /100. 최상위 문단 lineseg = 본문영역 로컬,\r\n * 셀 문단 = 셀 로컬. PARA 밀어내기 개체 anchor = 호스트vp − (omTop+h+omBottom) 역산.\r\n * - horzsize는 줄 \"영역\" 폭(텍스트 폭 아님) — 마지막 줄이 아닌 줄은 원본 줄바꿈에\r\n * 맞춰 textLength로 고정하고, 마지막 줄만 paraPr 정렬(LEFT 자연폭/CENTER/RIGHT/배분)을 적용.\r\n * - 좌표 속성엔 uint32로 저장된 음수가 섞여 있다(toInt32 필수).\r\n * - 표 열은 span 제약 경계 전파로, 행은 rs=1 max + 콘텐츠 초과 성장으로 푼다.\r\n *\r\n * 페이지: 최상위 lineseg vertpos는 페이지 로컬(페이지마다 0부터 리셋)이므로 역행\r\n * 지점을 페이지 경계로 감지, 전 페이지를 세로 스택으로 그린다(페이지별 흰 배경 +\r\n * 클립). 페이지에 걸친 표는 시작 페이지에서 잘린다(조판 캐시에 분할점이 없음).\r\n *\r\n * 범위: section0 한정(다중 구역은 첫 구역만), 수식·그리기개체 도형은 미지원(경고 수집).\r\n */\r\n\r\nimport JSZip from \"jszip\"\r\nimport { KordocError, precheckZipSize } from \"../utils.js\"\r\nimport { createXmlParser, findChildByLocalName, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES } from \"../hwpx/parser-shared.js\"\r\nimport { toInt32, solveBoundaries, solveRowHeights, type SpanConstraint } from \"./layout.js\"\r\nimport { measureTextWidth, type WrapMode } from \"../hwpx/text-metrics.js\"\r\nimport { parseRenderStyles, DEFAULT_CHAR, type RenderStyles, type RenderBorderEdge } from \"./head-styles.js\"\r\nimport { reflowSection } from \"./reflow.js\"\r\n\r\nexport interface RenderSvgOptions {\r\n /** 이미지 1장당 허용 최대 바이트 (기본 40MB) */\r\n maxImageBytes?: number\r\n /** 검색어 형광펜 — 텍스트 조각 내 매치 구간에 배경 rect (대소문자 무시).\r\n * charPr(스타일) 경계에 걸친 매치는 칠하지 못한다. */\r\n highlights?: string[]\r\n /** Tier-2 reflow — 조판 캐시(linesegarray) 없는 파일도 순수 TS 조판으로 렌더.\r\n * 캐시가 있으면 무시(한컴본은 캐시 재생). 기본 false(캐시 없으면 KordocError). */\r\n reflow?: boolean\r\n /** reflow 줄바꿈 폴백 모드 — 'keep'(어절) / 'charAll'(글자). 문단 paraPr에\r\n * breakSetting 선언이 있으면 그 값이 우선하며(BREAK_WORD=어절, KEEP_WORD=글자 —\r\n * 이름 역전 주의), 이 옵션은 선언 없는 문단에만 적용된다. */\r\n reflowMode?: WrapMode\r\n}\r\n\r\nexport interface RenderSvgResult {\r\n svg: string\r\n /** 페이지 폭 (pt) */\r\n width: number\r\n /** 전체 캔버스 높이 (pt) — 페이지 세로 스택 + 간격 */\r\n height: number\r\n /** 렌더된 페이지 수 */\r\n pageCount: number\r\n warnings: string[]\r\n stats: { texts: number; images: number; tables: number }\r\n}\r\n\r\n// ─── XML 헬퍼 ─────────────────────────────────────\r\n\r\nfunction ln(el: Element): string {\r\n return (el.tagName || \"\").replace(/^[^:]+:/, \"\")\r\n}\r\n\r\nfunction elements(el: Element): Element[] {\r\n const out: Element[] = []\r\n const children = el.childNodes\r\n if (!children) return out\r\n for (let i = 0; i < children.length; i++) {\r\n if (children[i].nodeType === 1) out.push(children[i] as Element)\r\n }\r\n return out\r\n}\r\n\r\nfunction num(el: Element | null, attr: string, fallback = 0): number {\r\n return el ? toInt32(el.getAttribute(attr) ?? undefined, fallback) : fallback\r\n}\r\n\r\nfunction findFirst(el: Element, name: string, depth = 0): Element | null {\r\n if (depth > 64) return null\r\n for (const ch of elements(el)) {\r\n if (ln(ch) === name) return ch\r\n const found = findFirst(ch, name, depth + 1)\r\n if (found) return found\r\n }\r\n return null\r\n}\r\n\r\nexport function escapeXml(s: string): string {\r\n return s\r\n // XML 1.0 금지 C0 제어문자 제거(탭 0x09·개행 0x0A·CR 0x0D는 유지) — 남기면 산출 SVG가\r\n // 불법 XML이라 뷰어·브라우저가 그 페이지 렌더를 통째로 중단한다(\"PCDATA invalid Char value\").\r\n // gen-ids.escapeXml·source-map.escapeXmlText와 같은 계약 (rhwp #3382 동종)\r\n .replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]/g, \"\")\r\n .replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\")\r\n}\r\n\r\n// ─── 내부 모델 ────────────────────────────────────\r\n\r\ninterface PageGeom { PW: number; PH: number; ML: number; MT: number; BODY_W: number; BODY_H: number }\r\n\r\nexport interface Seg { textpos: number; vertpos: number; horzpos: number; horzsize: number; textheight: number; baseline: number }\r\n\r\nexport interface ParaChar { ch: string; prId: string | null }\r\n\r\n/** 렌더 대상 개체 태그 — 이 외(도형류)는 경고 후 생략 */\r\nconst OBJ_TAGS = new Set([\"tbl\", \"pic\", \"container\", \"equation\", \"rect\", \"ellipse\", \"polygon\", \"curv\", \"line\", \"arc\", \"ole\", \"textart\"])\r\n\r\n/** omL/omR: TAC 인라인 표의 outMargin 좌/우(HWPUNIT) — 한글은 TAC 표를 \"outMargin 포함\r\n * 폭의 문자\"로 배치한다: 가로 전진폭 = om좌 + 표폭 + om우, 괘선(표 자체)은 pen + om좌\r\n * (rhwp #3396 동종 — 오라클 실측이 표뿐이라 표 외 개체는 0). */\r\ninterface ParaObj { el: Element; tag: string; index: number; inline: boolean; width: number; height: number; omL: number; omR: number }\r\n\r\nexport interface ParaModel { chars: ParaChar[]; segs: Seg[]; objs: ParaObj[]; paraPrId: string | null }\r\n\r\ninterface Ctx {\r\n /** 페이지별 SVG 버퍼 — emit()이 현재 페이지(page)로 라우팅 */\r\n pages: string[][]\r\n /** 현재 그리는 페이지 인덱스 — 최상위 문단만 갱신, 셀/중첩 콘텐츠는 호스트 페이지 상속 */\r\n page: number\r\n geom: PageGeom\r\n styles: RenderStyles\r\n images: Map<string, { dataUri: string; symId?: string; orgW?: number; orgH?: number }>\r\n /** 이미지 심볼 defs — dataURI는 여기 1회만, 본문은 <use> 참조 (occurrence당 재emit 금지) */\r\n defs: string[]\r\n /** 검색어 형광펜 (소문자 정규화, 빈 문자열 제거) */\r\n highlights: string[]\r\n warnings: string[]\r\n warned: Set<string>\r\n stats: { texts: number; images: number; tables: number }\r\n /** 셀/표 측정 메모 — 중첩표 지수 재계산 캡 (렌더 1회 공유) */\r\n extentMemo: ExtentMemo\r\n}\r\n\r\nconst pt = (u: number): string => String(Math.round(u) / 100)\r\n\r\nfunction emit(ctx: Ctx, s: string): void {\r\n ctx.pages[ctx.page].push(s)\r\n}\r\n\r\nfunction warnOnce(ctx: Ctx, key: string, msg: string): void {\r\n if (ctx.warned.has(key)) return\r\n ctx.warned.add(key)\r\n ctx.warnings.push(msg)\r\n}\r\n\r\n// ─── 문단 모델 구축 ────────────────────────────────\r\n\r\n/** hp:t 안에서 1슬롯을 차지하는 문자형 컨트롤 (HWP5 문자 스트림 모델) —\r\n * 탭(0x09)은 char가 아니라 inline 컨트롤 = 8슬롯(16바이트)이라 여기 넣으면 안 된다\r\n * (record.ts 0x09 처리의 i+=14와 같은 모델. 1슬롯로 세면 탭당 7슬롯씩 줄 경계가 밀린다) */\r\nconst CHAR_CTRL_1SLOT = new Set([\"lineBreak\", \"hyphen\", \"nbSpace\", \"fwSpace\"])\r\n\r\n/** lineseg textpos 정합용 0폭 필러 슬롯 — 컨트롤이 차지하는 문자 위치를 채운다 */\r\nfunction pushFillers(chars: ParaChar[], n: number, prId: string | null): void {\r\n for (let i = 0; i < n; i++) chars.push({ ch: \"\", prId })\r\n}\r\n\r\n/**\r\n * hp:t 내용을 슬롯 스트림으로 변환 — lineseg textpos 는 HWP5 문자 스트림 기준이라\r\n * 텍스트 1문자=1슬롯(서로게이트 쌍은 2), tab 등 문자형 컨트롤도 1슬롯을 차지한다.\r\n * markpen 등 래퍼 요소는 슬롯 없이 내용만 재귀한다.\r\n * (탭 폭은 탭스톱 미해석으로 0 — 경계 정합이 우선, 폭 오차는 줄 스케일이 흡수)\r\n */\r\nfunction pushTextSlots(t: Element, chars: ParaChar[], prId: string | null, depth: number): void {\r\n if (depth > 32) return\r\n const kids = t.childNodes\r\n if (!kids) return\r\n for (let i = 0; i < kids.length; i++) {\r\n const c = kids[i]\r\n if (c.nodeType === 3) {\r\n for (const cp of c.textContent ?? \"\") {\r\n chars.push({ ch: cp, prId })\r\n if (cp.length === 2) chars.push({ ch: \"\", prId }) // UTF-16 두 번째 유닛 슬롯\r\n }\r\n } else if (c.nodeType === 1) {\r\n const el = c as Element\r\n const tag = ln(el)\r\n if (tag === \"tab\") {\r\n pushFillers(chars, 8, prId) // inline 컨트롤 8슬롯 (전부 폭 0 — 탭스톱 미해석)\r\n } else if (CHAR_CTRL_1SLOT.has(tag)) {\r\n chars.push({ ch: tag === \"nbSpace\" || tag === \"fwSpace\" ? \" \" : \"\", prId })\r\n } else {\r\n pushTextSlots(el, chars, prId, depth + 1)\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport function buildPara(p: Element): ParaModel {\r\n const chars: ParaChar[] = []\r\n const objs: ParaObj[] = []\r\n let segs: Seg[] = []\r\n for (const runEl of elements(p)) {\r\n const tag = ln(runEl)\r\n if (tag === \"run\") {\r\n const prId = runEl.getAttribute(\"charPrIDRef\")\r\n for (const ch of elements(runEl)) {\r\n const cn = ln(ch)\r\n if (cn === \"t\") {\r\n pushTextSlots(ch, chars, prId, 0)\r\n } else if (OBJ_TAGS.has(cn)) {\r\n const sz = findChildByLocalName(ch, \"sz\")\r\n const pos = findChildByLocalName(ch, \"pos\")\r\n // 그리기 도형은 hp:sz가 없다 — curSz(>0) → orgSz 폴백\r\n const w = num(sz, \"width\") || num(findChildByLocalName(ch, \"curSz\"), \"width\") || num(findChildByLocalName(ch, \"orgSz\"), \"width\")\r\n const h = num(sz, \"height\") || num(findChildByLocalName(ch, \"curSz\"), \"height\") || num(findChildByLocalName(ch, \"orgSz\"), \"height\")\r\n const inline = pos?.getAttribute(\"treatAsChar\") === \"1\"\r\n // TAC 표만 outMargin 좌/우를 가로 배선 (ParaObj.omL 주석 — rhwp #3396 동종)\r\n const om = inline && cn === \"tbl\" ? findChildByLocalName(ch, \"outMargin\") : null\r\n objs.push({\r\n el: ch, tag: cn, index: chars.length,\r\n inline,\r\n width: w, height: h,\r\n omL: num(om, \"left\"), omR: num(om, \"right\"),\r\n })\r\n // 확장 컨트롤(GSO 등)은 문자 스트림에서 8슬롯 — 실측: 데모 코퍼스 1,132개\r\n // 멀티라인 문단에서 textpos 가 8슬롯 블록 중간에 걸린 경계 0건\r\n pushFillers(chars, 8, prId)\r\n } else {\r\n // secPr·ctrl(구역/단 정의)·필드 등 나머지 run 자식도 확장/인라인 컨트롤 8슬롯\r\n pushFillers(chars, 8, prId)\r\n }\r\n }\r\n } else if (tag === \"linesegarray\") {\r\n segs = elements(runEl).filter(s => ln(s) === \"lineseg\").map(s => ({\r\n textpos: num(s, \"textpos\"), vertpos: num(s, \"vertpos\"), horzpos: num(s, \"horzpos\"),\r\n horzsize: num(s, \"horzsize\"), textheight: num(s, \"textheight\", 1000), baseline: num(s, \"baseline\", 850),\r\n }))\r\n }\r\n }\r\n return { chars, segs, objs, paraPrId: p.getAttribute(\"paraPrIDRef\") }\r\n}\r\n\r\n// ─── 줄 렌더 (run별 charPr + 정렬) ──────────────────\r\n\r\ninterface LinePlan {\r\n seg: Seg\r\n /** 줄 시작 x 보정 (정렬) */\r\n xoff: number\r\n /** 텍스트 조각 폭 스케일 */\r\n scale: number\r\n start: number\r\n end: number\r\n}\r\n\r\nfunction charW(c: ParaChar, styles: RenderStyles): number {\r\n const st = (c.prId != null ? styles.charPr.get(c.prId) : undefined) ?? DEFAULT_CHAR\r\n return measureTextWidth(c.ch, st.height, st.ratio, { spacingPct: st.spacing })\r\n}\r\n\r\n/** 줄 자연폭 = 텍스트 조각 + 인라인 개체 폭 (개체 폭은 스케일 불변, TAC 표는 outMargin 좌/우 포함) */\r\nfunction lineNaturalWidth(m: ParaModel, styles: RenderStyles, start: number, end: number): { text: number; obj: number } {\r\n let text = 0\r\n for (let i = start; i < end && i < m.chars.length; i++) text += charW(m.chars[i], styles)\r\n let obj = 0\r\n for (const o of m.objs) if (o.inline && o.index >= start && o.index < end) obj += o.omL + o.width + o.omR\r\n return { text, obj }\r\n}\r\n\r\nfunction planLines(m: ParaModel, styles: RenderStyles): LinePlan[] {\r\n const align = (m.paraPrId != null ? styles.paraAlign.get(m.paraPrId) : undefined) ?? \"JUSTIFY\"\r\n const plans: LinePlan[] = []\r\n for (let i = 0; i < m.segs.length; i++) {\r\n const seg = m.segs[i]\r\n const start = seg.textpos\r\n const end = i + 1 < m.segs.length ? m.segs[i + 1].textpos : Math.max(m.chars.length, start)\r\n const nat = lineNaturalWidth(m, styles, start, end)\r\n const isLast = i === m.segs.length - 1\r\n let xoff = 0\r\n let scale = 1\r\n const avail = seg.horzsize - nat.obj\r\n if (nat.text > 0 && (!isLast || align === \"DISTRIBUTE\" || align === \"DISTRIBUTE_SPACE\")) {\r\n // 줄바꿈이 고정된 중간 줄·배분정렬 — 줄 영역 폭에 맞춰 고정 (원본 조판 재현)\r\n scale = avail > 0 ? avail / nat.text : 1\r\n } else if (nat.text + nat.obj > 0 && isLast) {\r\n const w = nat.text + nat.obj\r\n if (align === \"CENTER\") xoff = Math.max(0, (seg.horzsize - w) / 2)\r\n else if (align === \"RIGHT\") xoff = Math.max(0, seg.horzsize - w)\r\n }\r\n if (!Number.isFinite(scale) || scale <= 0) scale = 1\r\n scale = Math.min(4, Math.max(0.25, scale))\r\n plans.push({ seg, xoff, scale, start, end })\r\n }\r\n return plans\r\n}\r\n\r\n/** 줄 안 [start, upto) 구간의 전진폭 (텍스트×스케일 + 인라인 개체 — TAC 표는 outMargin 좌/우 포함) */\r\nfunction advanceTo(m: ParaModel, styles: RenderStyles, plan: LinePlan, upto: number): number {\r\n let x = 0\r\n for (let i = plan.start; i < upto && i < m.chars.length; i++) x += charW(m.chars[i], styles) * plan.scale\r\n for (const o of m.objs) if (o.inline && o.index >= plan.start && o.index < upto) x += o.omL + o.width + o.omR\r\n return x\r\n}\r\n\r\n// ─── 문단 드로잉 ───────────────────────────────────\r\n\r\n/**\r\n * @param segPages 최상위 문단 전용 — seg 인덱스별 페이지 배정 (vertpos 리셋 감지 결과).\r\n * 셀/중첩 콘텐츠는 전달하지 않아 호스트의 ctx.page 를 상속한다.\r\n */\r\nfunction drawPara(p: Element, ox: number, oy: number, areaW: number, ctx: Ctx, depth: number, segPages?: number[]): void {\r\n if (depth > 16) { warnOnce(ctx, \"depth\", \"중첩 깊이 16 초과 — 이하 생략\"); return }\r\n const m = buildPara(p)\r\n if (m.segs.length === 0) {\r\n // 조판 캐시 없는 문단 — 개체만이라도 문단 원점에 배치. 텍스트는 무음 생략 금지\r\n if (m.chars.some(c => c.ch !== \"\")) {\r\n warnOnce(ctx, \"no-lineseg\", \"조판 캐시 없는 문단 텍스트 생략 — reflow 옵션으로 합성 가능\")\r\n }\r\n for (const o of m.objs) drawObject(o, ox, oy, 0, areaW, ctx, depth)\r\n return\r\n }\r\n const plans = planLines(m, ctx.styles)\r\n const baseV = m.segs[0].vertpos\r\n\r\n for (let li = 0; li < plans.length; li++) {\r\n const plan = plans[li]\r\n if (segPages && segPages[li] !== undefined) ctx.page = segPages[li]\r\n const { seg } = plan\r\n // charPr 단위 조각으로 분할\r\n let i = plan.start\r\n let cursor = ox + seg.horzpos + plan.xoff\r\n const y = oy + seg.vertpos + seg.baseline\r\n while (i < plan.end && i < m.chars.length) {\r\n // 필러 슬롯(컨트롤·서로게이트 자리)은 그리지 않고 건너뛴다 —\r\n // 인라인 개체의 폭 전진은 개체 첫 슬롯에서 1회 수행\r\n if (m.chars[i].ch === \"\") {\r\n for (const o of m.objs) if (o.inline && o.index === i) cursor += o.omL + o.width + o.omR\r\n i++\r\n continue\r\n }\r\n const prId = m.chars[i].prId\r\n let j = i\r\n let piece = \"\"\r\n // 필러에서 멈추므로 piece 안은 실문자뿐 — 개체 경계 절단이 자연 발생\r\n while (j < plan.end && j < m.chars.length && m.chars[j].prId === prId && m.chars[j].ch !== \"\") { piece += m.chars[j].ch; j++ }\r\n // 연속 공백(2+) 경계 절단 — 공백 폭 오차(한컴 0.5em 고정 vs 뷰어 폰트)를\r\n // 공백 구간에 가둔다 (공무원 스페이스 정렬 원문에서 글자 벌어짐 방지)\r\n // (문자열 인덱스를 슬롯 오프셋으로 쓴다 — 서로게이트 쌍이 섞이면 1슬롯 오차, 무시)\r\n {\r\n const cut = piece.search(/ {2,}/)\r\n if (cut > 0) { piece = piece.slice(0, cut); j = i + cut }\r\n else if (cut === 0) {\r\n const runEnd = piece.match(/^ +/)![0].length\r\n piece = piece.slice(0, runEnd); j = i + runEnd\r\n }\r\n }\r\n const st = (prId != null ? ctx.styles.charPr.get(prId) : undefined) ?? DEFAULT_CHAR\r\n\r\n // 텍스트 세그먼트 1개를 렌더하고 전진폭 반환. hit=true 면 형광펜 배경 rect 를\r\n // 텍스트 앞에 깐다. 세그먼트마다 자체 textLength 를 쓰므로 rect(hit)와 글자가\r\n // 완전히 같은 폭·위치로 계산돼 형광펜이 어긋나지 않는다.\r\n const renderSeg = (text: string, cx: number, hit: boolean): number => {\r\n const sw = measureTextWidth(text, st.height, st.ratio, { spacingPct: st.spacing }) * plan.scale\r\n if (hit) {\r\n emit(ctx, `<rect x=\"${pt(cx)}\" y=\"${pt(oy + seg.vertpos)}\" width=\"${pt(sw)}\" height=\"${pt(seg.textheight)}\" fill=\"#ffd54f\" fill-opacity=\"0.45\"/>`)\r\n }\r\n if (text.trim().length > 0) {\r\n const attrs: string[] = [`x=\"${pt(cx)}\"`, `y=\"${pt(y)}\"`, `font-size=\"${pt(st.height)}\"`]\r\n if (st.fontFamily) attrs.push(`font-family=\"${escapeXml(st.fontFamily)}\"`)\r\n if ([...text].length > 1 && sw > 50) {\r\n attrs.push(`textLength=\"${pt(sw)}\"`, `lengthAdjust=\"${plan.scale < 1 ? \"spacingAndGlyphs\" : \"spacing\"}\"`)\r\n }\r\n if (st.bold) attrs.push(`font-weight=\"bold\"`)\r\n if (st.italic) attrs.push(`font-style=\"italic\"`)\r\n if (st.underline) attrs.push(`text-decoration=\"underline\"`)\r\n if (st.color) attrs.push(`fill=\"${escapeXml(st.color)}\"`)\r\n emit(ctx, `<text ${attrs.join(\" \")}>${escapeXml(text)}</text>`)\r\n ctx.stats.texts++\r\n }\r\n return sw\r\n }\r\n\r\n // 형광펜 매치 구간 수집 → 병합(겹침 제거) → [평문·매치·평문…] 분할 렌더\r\n const merged: Array<[number, number]> = []\r\n if (ctx.highlights.length > 0 && piece.trim().length > 0) {\r\n const found: Array<[number, number]> = []\r\n const lower = piece.toLowerCase()\r\n for (const term of ctx.highlights) {\r\n for (let f = lower.indexOf(term); f !== -1; f = lower.indexOf(term, f + term.length)) {\r\n found.push([f, f + term.length])\r\n }\r\n }\r\n found.sort((a, b) => a[0] - b[0])\r\n for (const [s, e] of found) {\r\n const tail = merged[merged.length - 1]\r\n if (tail && s <= tail[1]) tail[1] = Math.max(tail[1], e)\r\n else merged.push([s, e])\r\n }\r\n }\r\n\r\n if (merged.length === 0) {\r\n cursor += renderSeg(piece, cursor, false)\r\n } else {\r\n let segCur = cursor\r\n let last = 0\r\n for (const [s, e] of merged) {\r\n segCur += renderSeg(piece.slice(last, s), segCur, false)\r\n segCur += renderSeg(piece.slice(s, e), segCur, true)\r\n last = e\r\n }\r\n segCur += renderSeg(piece.slice(last), segCur, false)\r\n cursor = segCur\r\n }\r\n i = j\r\n }\r\n }\r\n\r\n // 개체 배치 — 인라인은 소속 줄 위치, 앵커는 hp:pos 해석\r\n for (const o of m.objs) {\r\n if (o.inline) {\r\n let planIdx = 0\r\n for (let k = 0; k < plans.length; k++) {\r\n const pl = plans[k]\r\n if (pl.start <= o.index && (o.index < pl.end || k === plans.length - 1)) planIdx = k\r\n }\r\n const plan = plans[planIdx]\r\n if (segPages && segPages[planIdx] !== undefined) ctx.page = segPages[planIdx]\r\n // TAC 표 괘선은 pen + outMargin좌 (advanceTo는 o.index 앞까지라 자신의 om 미포함)\r\n const x = ox + plan.seg.horzpos + plan.xoff + advanceTo(m, ctx.styles, plan, o.index) + o.omL\r\n // 개체가 줄보다 낮으면 baseline 위에 얹고, 줄을 채우는 개체(th==h)는 줄 상단\r\n const yTop = oy + plan.seg.vertpos + Math.max(0, plan.seg.baseline - o.height)\r\n drawObject(o, x, yTop, baseV, areaW, ctx, depth)\r\n } else {\r\n // 앵커 좌표는 첫 seg(baseV) 기준이므로 첫 seg 의 페이지에 귀속\r\n if (segPages && segPages[0] !== undefined) ctx.page = segPages[0]\r\n const { x, y } = anchorObject(o, ox, oy, baseV, areaW, ctx)\r\n drawObject(o, x, y, baseV, areaW, ctx, depth)\r\n }\r\n }\r\n}\r\n\r\n/** hp:pos 기준계 해석 → 개체 좌상단 절대좌표 (tac=0) */\r\nfunction anchorObject(o: ParaObj, ox: number, oy: number, baseV: number, areaW: number, ctx: Ctx): { x: number; y: number } {\r\n const { PW, PH, ML, MT, BODY_W, BODY_H } = ctx.geom\r\n const pos = findChildByLocalName(o.el, \"pos\")\r\n const om = findChildByLocalName(o.el, \"outMargin\")\r\n const omT = num(om, \"top\"), omB = num(om, \"bottom\")\r\n const w = o.width, h = o.height\r\n if (!pos) return { x: ox, y: oy + baseV }\r\n const vo = num(pos, \"vertOffset\")\r\n const ho = num(pos, \"horzOffset\")\r\n const vrel = pos.getAttribute(\"vertRelTo\") ?? \"PARA\"\r\n const hrel = pos.getAttribute(\"horzRelTo\") ?? \"PARA\"\r\n const va = pos.getAttribute(\"vertAlign\") ?? \"TOP\"\r\n const ha = pos.getAttribute(\"horzAlign\") ?? \"LEFT\"\r\n const wrap = o.el.getAttribute(\"textWrap\") ?? \"TOP_AND_BOTTOM\"\r\n\r\n let y: number\r\n if (vrel === \"PAPER\") {\r\n y = va === \"BOTTOM\" ? PH - h - vo : va === \"CENTER\" ? (PH - h) / 2 + vo : vo\r\n } else if (vrel === \"PAGE\") {\r\n y = va === \"BOTTOM\" ? MT + BODY_H - h - vo : va === \"CENTER\" ? MT + (BODY_H - h) / 2 + vo : MT + vo\r\n } else if (wrap === \"TOP_AND_BOTTOM\") {\r\n // PARA 밀어내기 역산 — 호스트 문단 vp가 개체(여백 포함)만큼 밀렸다는 모델 (실측 일치).\r\n // 음수면 밀지 않은 개체(빈 호스트 줄 등)로 보고 현재 흐름 y 사용.\r\n const pushed = baseV - (omT + h + omB)\r\n const anchor = pushed >= -100 ? pushed : baseV\r\n y = oy + anchor + omT + vo\r\n } else {\r\n // BEHIND_TEXT/IN_FRONT/SQUARE — 문단을 밀지 않는 개체는 문단 원점 흐름 배치\r\n y = oy + baseV + vo\r\n }\r\n\r\n let x: number\r\n if (hrel === \"PAGE\") {\r\n x = ha === \"RIGHT\" ? ML + BODY_W - w - ho : ha === \"CENTER\" ? ML + (BODY_W - w) / 2 + ho : ML + ho\r\n } else if (hrel === \"PAPER\") {\r\n x = ha === \"RIGHT\" ? PW - w - ho : ha === \"CENTER\" ? (PW - w) / 2 + ho : ho\r\n } else {\r\n // PARA/COLUMN — 현재 텍스트 영역 기준 (셀 안이면 셀 내부 폭. COLUMN을 페이지\r\n // 단으로 읽으면 셀 안 개체가 페이지 왼쪽으로 튄다 — 사진대지 우측 셀 실측)\r\n x = ha === \"RIGHT\" ? ox + areaW - w - ho : ha === \"CENTER\" ? ox + (areaW - w) / 2 + ho : ox + ho\r\n }\r\n return { x, y }\r\n}\r\n\r\nfunction drawObject(o: ParaObj, x: number, y: number, baseV: number, areaW: number, ctx: Ctx, depth: number): void {\r\n if (o.tag === \"tbl\") drawTable(o.el, x, y, ctx, depth + 1)\r\n else if (o.tag === \"pic\") drawPic(o.el, x, y, ctx)\r\n else if (o.tag === \"container\") {\r\n // 그리기개체 묶음 — 자식 개체를 컨테이너 원점 기준으로 재귀 배치\r\n for (const ch of elements(o.el)) {\r\n const tag = ln(ch)\r\n if (!OBJ_TAGS.has(tag)) continue\r\n const sz = findChildByLocalName(ch, \"sz\")\r\n const off = findChildByLocalName(ch, \"offset\")\r\n const sub: ParaObj = { el: ch, tag, index: 0, inline: true, width: num(sz, \"width\"), height: num(sz, \"height\"), omL: 0, omR: 0 }\r\n drawObject(sub, x + num(off, \"x\"), y + num(off, \"y\"), baseV, areaW, ctx, depth + 1)\r\n }\r\n } else if (o.tag === \"equation\") {\r\n warnOnce(ctx, \"equation\", \"수식 개체는 렌더 미지원 — 생략\")\r\n } else if (SHAPE_TAGS.has(o.tag)) {\r\n drawShape(o, x, y, ctx, depth)\r\n } else {\r\n warnOnce(ctx, `shape:${o.tag}`, `개체(${o.tag}) 렌더 미지원 — 생략`)\r\n }\r\n}\r\n\r\n// ─── 그리기 도형 (rect/ellipse/line/polygon/curv/arc) ────────────────\r\n// geometry 좌표는 개체 로컬(orgSz 기준). 실제 크기 = curSz(있으면)로 스케일.\r\n// lineShape=선(color/width/style), fillBrush>winBrush=채움(faceColor). 회전은 근사 생략.\r\n\r\nconst SHAPE_TAGS = new Set([\"rect\", \"ellipse\", \"line\", \"polygon\", \"curv\", \"arc\"])\r\n\r\n/** lineShape width(1/100 mm) → pt */\r\nfunction shapeStrokePt(v: number): number {\r\n return Math.max(0.2, (v / 100) * 2.834645)\r\n}\r\n\r\nfunction drawShape(o: ParaObj, x: number, y: number, ctx: Ctx, depth: number): void {\r\n const el = o.el\r\n const orgSz = findChildByLocalName(el, \"orgSz\")\r\n const curSz = findChildByLocalName(el, \"curSz\")\r\n const ow = num(orgSz, \"width\"), oh = num(orgSz, \"height\")\r\n const w = num(curSz, \"width\") || ow || o.width\r\n const h = num(curSz, \"height\") || oh || o.height\r\n const sx = ow > 0 ? w / ow : 1\r\n const sy = oh > 0 ? h / oh : 1\r\n\r\n const lineShape = findChildByLocalName(el, \"lineShape\")\r\n const lstyle = lineShape?.getAttribute(\"style\") ?? \"SOLID\"\r\n const strokeCol = lineShape?.getAttribute(\"color\") || \"#000000\"\r\n const hasStroke = lstyle !== \"NONE\"\r\n const strokeW = hasStroke ? shapeStrokePt(lineShape ? num(lineShape, \"width\") : 33) : 0\r\n const dash = /DASH|DOT/.test(lstyle) ? ` stroke-dasharray=\"${lstyle.includes(\"DOT\") ? \"1,1.5\" : \"3,1.5\"}\"` : \"\"\r\n const strokeAttr = hasStroke ? ` stroke=\"${escapeXml(strokeCol)}\" stroke-width=\"${strokeW.toFixed(2)}\"${dash}` : \"\"\r\n\r\n const fillBrush = findChildByLocalName(el, \"fillBrush\")\r\n const winBrush = fillBrush ? findChildByLocalName(fillBrush, \"winBrush\") : null\r\n const face = winBrush?.getAttribute(\"faceColor\")\r\n const fill = face && face.toLowerCase() !== \"none\" ? face : \"none\"\r\n const fillAttr = ` fill=\"${fill === \"none\" ? \"none\" : escapeXml(fill)}\"`\r\n\r\n if (o.tag === \"rect\") {\r\n emit(ctx, `<rect x=\"${pt(x)}\" y=\"${pt(y)}\" width=\"${pt(w)}\" height=\"${pt(h)}\"${fillAttr}${strokeAttr}/>`)\r\n } else if (o.tag === \"ellipse\") {\r\n emit(ctx, `<ellipse cx=\"${pt(x + w / 2)}\" cy=\"${pt(y + h / 2)}\" rx=\"${pt(w / 2)}\" ry=\"${pt(h / 2)}\"${fillAttr}${strokeAttr}/>`)\r\n } else if (o.tag === \"line\") {\r\n const s = findChildByLocalName(el, \"startPt\"), e = findChildByLocalName(el, \"endPt\")\r\n const x1 = x + num(s, \"x\") * sx, y1 = y + num(s, \"y\") * sy\r\n const x2 = x + num(e, \"x\") * sx, y2 = y + num(e, \"y\") * sy\r\n emit(ctx, `<line x1=\"${pt(x1)}\" y1=\"${pt(y1)}\" x2=\"${pt(x2)}\" y2=\"${pt(y2)}\" stroke=\"${escapeXml(strokeCol)}\" stroke-width=\"${(strokeW || 0.3).toFixed(2)}\"${dash}/>`)\r\n } else if (o.tag === \"polygon\" || o.tag === \"curv\") {\r\n const pts: string[] = []\r\n for (const c of elements(el)) if (ln(c) === \"pt\") pts.push(`${pt(x + num(c, \"x\") * sx)},${pt(y + num(c, \"y\") * sy)}`)\r\n if (pts.length >= 2) emit(ctx, `<polygon points=\"${pts.join(\" \")}\"${fillAttr}${strokeAttr}/>`)\r\n } else if (o.tag === \"arc\") {\r\n // 호는 외접 박스 타원으로 근사 (start/sweep 각 미해석)\r\n emit(ctx, `<ellipse cx=\"${pt(x + w / 2)}\" cy=\"${pt(y + h / 2)}\" rx=\"${pt(w / 2)}\" ry=\"${pt(h / 2)}\" fill=\"none\"${strokeAttr || ` stroke=\"${escapeXml(strokeCol)}\" stroke-width=\"0.3\"`}/>`)\r\n }\r\n\r\n // 도형 안 텍스트(drawText>subList) — 조판 캐시 있으면 그린다\r\n const dt = findChildByLocalName(el, \"drawText\")\r\n const sub = dt ? findChildByLocalName(dt, \"subList\") : null\r\n if (sub) {\r\n for (const p of elements(sub)) if (ln(p) === \"p\") drawPara(p, x, y, w, ctx, depth + 1)\r\n }\r\n}\r\n\r\n// ─── 표 ───────────────────────────────────────────\r\n\r\ninterface CellModel {\r\n el: Element\r\n ca: number; ra: number; cs: number; rs: number\r\n w: number; h: number\r\n bfId: string | null\r\n sub: Element | null\r\n marginL: number; marginR: number; marginT: number; marginB: number\r\n}\r\n\r\n/**\r\n * 셀/표 측정 메모 — drawTable(rowH·yoff)과 cellContentExtent↔measureTableHeight 상호재귀가\r\n * 중첩 단계마다 하위 표를 재측정해 지수적으로 불어나는 것을 캡. 렌더 1회 안에서만 공유\r\n * (reflow의 DOM 변형은 드로잉 시작 전에 끝나므로 캐시가 stale해지지 않는다).\r\n */\r\nexport interface ExtentMemo { cell: WeakMap<Element, number>; table: WeakMap<Element, number> }\r\n\r\n/** 셀 콘텐츠 세로 범위 — 줄(vp+th) + 인라인 개체(중첩표·treatAsChar) + PARA 앵커 개체(anchor+h) 최대값 */\r\nfunction cellContentExtent(cell: CellModel, memo?: ExtentMemo): number {\r\n if (!cell.sub) return 0\r\n const hit = memo?.cell.get(cell.el)\r\n if (hit !== undefined) return hit\r\n let ext = 0\r\n for (const p of elements(cell.sub)) {\r\n if (ln(p) !== \"p\") continue\r\n const m = buildPara(p)\r\n for (const s of m.segs) ext = Math.max(ext, s.vertpos + s.textheight)\r\n const baseV = m.segs[0]?.vertpos ?? 0\r\n for (const o of m.objs) {\r\n if (o.inline) {\r\n // 인라인 개체(중첩 표·treatAsChar 이미지)는 줄 위치에서 개체 높이만큼 아래로 뻗는다.\r\n // 이를 빼먹으면 중첩 표를 담은 셀 높이가 과소측정돼 표지 중첩표가 겹친다(리뷰: 셀 성장 누락).\r\n const h = o.tag === \"tbl\" ? Math.max(o.height, measureTableHeight(o.el, memo)) : o.height\r\n ext = Math.max(ext, baseV + h)\r\n continue\r\n }\r\n const pos = findChildByLocalName(o.el, \"pos\")\r\n if ((pos?.getAttribute(\"vertRelTo\") ?? \"PARA\") !== \"PARA\") continue\r\n const om = findChildByLocalName(o.el, \"outMargin\")\r\n const pushed = baseV - (num(om, \"top\") + o.height + num(om, \"bottom\"))\r\n const anchor = pushed >= -100 ? pushed : baseV\r\n ext = Math.max(ext, anchor + num(om, \"top\") + num(pos, \"vertOffset\") + o.height)\r\n }\r\n }\r\n memo?.cell.set(cell.el, ext)\r\n return ext\r\n}\r\n\r\nfunction edgeLine(x1: number, y1: number, x2: number, y2: number, e: RenderBorderEdge): string {\r\n const dash = /DASH|DOT/.test(e.type) ? ` stroke-dasharray=\"${e.type.includes(\"DOT\") ? \"1,1.5\" : \"3,1.5\"}\"` : \"\"\r\n return `<line x1=\"${pt(x1)}\" y1=\"${pt(y1)}\" x2=\"${pt(x2)}\" y2=\"${pt(y2)}\" stroke=\"${escapeXml(e.color)}\" stroke-width=\"${e.widthPt.toFixed(2)}\"${dash}/>`\r\n}\r\n\r\n/** tbl의 셀 모델 수집 — drawTable과 measureTableHeight가 같은 셀 해석을 공유 */\r\nfunction collectCells(tbl: Element): CellModel[] {\r\n const inMargin = findChildByLocalName(tbl, \"inMargin\")\r\n const defL = num(inMargin, \"left\", 141), defR = num(inMargin, \"right\", 141)\r\n const defT = num(inMargin, \"top\", 141), defB = num(inMargin, \"bottom\", 141)\r\n\r\n const cells: CellModel[] = []\r\n for (const tr of elements(tbl)) {\r\n if (ln(tr) !== \"tr\") continue\r\n for (const tc of elements(tr)) {\r\n if (ln(tc) !== \"tc\") continue\r\n const addr = findChildByLocalName(tc, \"cellAddr\")\r\n const span = findChildByLocalName(tc, \"cellSpan\")\r\n const csz = findChildByLocalName(tc, \"cellSz\")\r\n const cm = findChildByLocalName(tc, \"cellMargin\")\r\n if (!addr || !csz) continue\r\n cells.push({\r\n el: tc,\r\n // 음수 주소(uint32 역변환·손상 입력) 방어 — colX/rowY 인덱스 이탈로 NaN 좌표 방지\r\n ca: Math.max(0, num(addr, \"colAddr\")), ra: Math.max(0, num(addr, \"rowAddr\")),\r\n cs: Math.max(1, num(span, \"colSpan\", 1)), rs: Math.max(1, num(span, \"rowSpan\", 1)),\r\n w: num(csz, \"width\"), h: num(csz, \"height\"),\r\n bfId: tc.getAttribute(\"borderFillIDRef\"),\r\n sub: findChildByLocalName(tc, \"subList\"),\r\n marginL: cm ? num(cm, \"left\", defL) : defL, marginR: cm ? num(cm, \"right\", defR) : defR,\r\n marginT: cm ? num(cm, \"top\", defT) : defT, marginB: cm ? num(cm, \"bottom\", defB) : defB,\r\n })\r\n }\r\n }\r\n return cells\r\n}\r\n\r\n/**\r\n * 표 실효 높이(HWPUNIT) — drawTable의 rowH 모델(solveRowHeights + 셀 콘텐츠 성장) 그대로.\r\n * 선언 hp:sz는 셀 콘텐츠로 자란 높이를 모르므로, reflow가 표 뒤 문단을 실제 그려질\r\n * 표 바닥 아래로 배치할 때 이 값을 쓴다. 셀 lineseg가 있어야 성장분이 측정된다.\r\n */\r\nexport function measureTableHeight(tbl: Element, memo?: ExtentMemo): number {\r\n const hit = memo?.table.get(tbl)\r\n if (hit !== undefined) return hit\r\n const cells = collectCells(tbl)\r\n if (cells.length === 0 || cells.length > 4096) return 0\r\n const nRows = Math.max(...cells.map(c => c.ra + c.rs))\r\n const rowH = solveRowHeights(\r\n cells.map(c => ({ rowAddr: c.ra, rowSpan: c.rs, height: c.h, contentH: c.rs === 1 ? cellContentExtent(c, memo) : undefined })),\r\n nRows,\r\n )\r\n let sum = 0\r\n for (const h of rowH) sum += h\r\n memo?.table.set(tbl, sum)\r\n return sum\r\n}\r\n\r\nfunction drawTable(tbl: Element, tx: number, ty: number, ctx: Ctx, depth: number): void {\r\n if (depth > 16) { warnOnce(ctx, \"depth\", \"중첩 깊이 16 초과 — 이하 생략\"); return }\r\n ctx.stats.tables++\r\n const tblSz = findChildByLocalName(tbl, \"sz\")\r\n const cells = collectCells(tbl)\r\n if (cells.length === 0 || cells.length > 4096) return\r\n\r\n const nCols = Math.max(...cells.map(c => c.ca + c.cs))\r\n const nRows = Math.max(...cells.map(c => c.ra + c.rs))\r\n const colCons: SpanConstraint[] = cells.map(c => ({ a: c.ca, b: c.ca + c.cs, size: c.w }))\r\n const colX = solveBoundaries(colCons, nCols, num(tblSz, \"width\") || undefined)\r\n const rowH = solveRowHeights(\r\n cells.map(c => ({ rowAddr: c.ra, rowSpan: c.rs, height: c.h, contentH: c.rs === 1 ? cellContentExtent(c, ctx.extentMemo) : undefined })),\r\n nRows,\r\n )\r\n const rowY: number[] = [0]\r\n for (let r = 0; r < nRows; r++) rowY.push(rowY[r] + rowH[r])\r\n\r\n // 1패스: 배경 → 2패스: 콘텐츠 → 3패스: 테두리 (테두리가 배경/콘텐츠 위)\r\n const geom = cells.map(c => ({\r\n c,\r\n x: tx + colX[c.ca], y: ty + rowY[c.ra],\r\n w: colX[Math.min(c.ca + c.cs, nCols)] - colX[c.ca],\r\n h: rowY[Math.min(c.ra + c.rs, nRows)] - rowY[c.ra],\r\n }))\r\n for (const g of geom) {\r\n const bf = g.c.bfId != null ? ctx.styles.borderFill.get(g.c.bfId) : undefined\r\n if (bf?.fill) emit(ctx, `<rect x=\"${pt(g.x)}\" y=\"${pt(g.y)}\" width=\"${pt(g.w)}\" height=\"${pt(g.h)}\" fill=\"${escapeXml(bf.fill)}\"/>`)\r\n }\r\n for (const g of geom) {\r\n const { c } = g\r\n if (!c.sub) continue\r\n const innerH = g.h - c.marginT - c.marginB\r\n const extent = cellContentExtent(c, ctx.extentMemo)\r\n const va = c.sub.getAttribute(\"vertAlign\") ?? \"TOP\"\r\n let yoff = 0\r\n if (va === \"CENTER\") yoff = Math.max(0, (innerH - extent) / 2)\r\n else if (va === \"BOTTOM\") yoff = Math.max(0, innerH - extent)\r\n for (const p of elements(c.sub)) {\r\n if (ln(p) !== \"p\") continue\r\n drawPara(p, g.x + c.marginL, g.y + c.marginT + yoff, g.w - c.marginL - c.marginR, ctx, depth + 1)\r\n }\r\n }\r\n for (const g of geom) {\r\n const bf = g.c.bfId != null ? ctx.styles.borderFill.get(g.c.bfId) : undefined\r\n if (!bf) continue\r\n if (bf.top) emit(ctx, edgeLine(g.x, g.y, g.x + g.w, g.y, bf.top))\r\n if (bf.bottom) emit(ctx, edgeLine(g.x, g.y + g.h, g.x + g.w, g.y + g.h, bf.bottom))\r\n if (bf.left) emit(ctx, edgeLine(g.x, g.y, g.x, g.y + g.h, bf.left))\r\n if (bf.right) emit(ctx, edgeLine(g.x + g.w, g.y, g.x + g.w, g.y + g.h, bf.right))\r\n }\r\n}\r\n\r\n// ─── 이미지 ───────────────────────────────────────\r\n\r\n/**\r\n * 이미지 심볼 등록(바이너리당 1회) — dataURI를 defs에 한 번만 넣고 <use>로 참조한다.\r\n * occurrence마다 dataURI를 재emit하면 반복 참조 문서에서 SVG 문자열이 기하급수로\r\n * 커져 RangeError/OOM (소형 입력 DoS). viewBox 100×100 + preserveAspectRatio none\r\n * 이라 <use width/height>가 기존 <image width/height> stretch와 동일하게 스케일된다.\r\n */\r\nfunction imageSymbol(loaded: { dataUri: string; symId?: string }, ctx: Ctx): string {\r\n if (!loaded.symId) {\r\n loaded.symId = `bin${ctx.defs.length}`\r\n ctx.defs.push(\r\n `<symbol id=\"${loaded.symId}\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\">` +\r\n `<image width=\"100\" height=\"100\" preserveAspectRatio=\"none\" href=\"${loaded.dataUri}\"/></symbol>`,\r\n )\r\n }\r\n return loaded.symId\r\n}\r\n\r\nfunction drawPic(pic: Element, x: number, y: number, ctx: Ctx): void {\r\n const sz = findChildByLocalName(pic, \"sz\")\r\n const w = num(sz, \"width\", 5669), h = num(sz, \"height\", 5669)\r\n const img = findFirst(pic, \"img\")\r\n const ref = img?.getAttribute(\"binaryItemIDRef\")\r\n const loaded = ref != null ? ctx.images.get(ref) : undefined\r\n if (!loaded) {\r\n emit(ctx, `<rect x=\"${pt(x)}\" y=\"${pt(y)}\" width=\"${pt(w)}\" height=\"${pt(h)}\" fill=\"#eee\" stroke=\"#c00\" stroke-width=\"0.5\"/>`)\r\n warnOnce(ctx, `img:${ref}`, `이미지 바이너리 누락: ${ref ?? \"(ref 없음)\"}`)\r\n return\r\n }\r\n ctx.stats.images++\r\n // imgClip 좌표계는 imgDim(이미지 내용 상자) 기준이다 — orgSz(최초 삽입 크기)가 아니다.\r\n // 실측(데모 코퍼스 pic 267개): clip==dim 254개(크롭 없음)·실제 크롭 8개 모두 dim 기준.\r\n // orgSz 로 비교하면 리사이즈된 로고(dim<org)가 좌상단 코너로 잘못 잘려 로고가 깨진다.\r\n const clip = findChildByLocalName(pic, \"imgClip\")\r\n const imgDim = findChildByLocalName(pic, \"imgDim\")\r\n const orgSz = findChildByLocalName(pic, \"orgSz\")\r\n const dimW = num(imgDim, \"dimwidth\"), dimH = num(imgDim, \"dimheight\")\r\n // 참조(전체 내용) 공간: imgDim 우선, 없으면 orgSz 폴백\r\n const refW = dimW > 0 ? dimW : num(orgSz, \"width\")\r\n const refH = dimH > 0 ? dimH : num(orgSz, \"height\")\r\n const cl = num(clip, \"left\"), ct = num(clip, \"top\")\r\n const cr = num(clip, \"right\", refW), cb = num(clip, \"bottom\", refH)\r\n const cropped =\r\n refW > 0 && refH > 0 && clip != null && (cl > 0 || ct > 0 || cr < refW || cb < refH) && cr > cl && cb > ct\r\n const symId = imageSymbol(loaded, ctx)\r\n if (cropped) {\r\n // 참조 좌표계 viewBox로 크롭 창을 내고, 이미지는 전체 내용 크기로 깐다\r\n emit(ctx,\r\n `<svg x=\"${pt(x)}\" y=\"${pt(y)}\" width=\"${pt(w)}\" height=\"${pt(h)}\" viewBox=\"${pt(cl)} ${pt(ct)} ${pt(cr - cl)} ${pt(cb - ct)}\" preserveAspectRatio=\"none\">` +\r\n `<use href=\"#${symId}\" x=\"0\" y=\"0\" width=\"${pt(refW)}\" height=\"${pt(refH)}\"/></svg>`,\r\n )\r\n } else {\r\n emit(ctx, `<use href=\"#${symId}\" x=\"${pt(x)}\" y=\"${pt(y)}\" width=\"${pt(w)}\" height=\"${pt(h)}\"/>`)\r\n }\r\n}\r\n\r\nfunction sniffMime(name: string, bytes: Uint8Array): string {\r\n const lower = name.toLowerCase()\r\n if (lower.endsWith(\".png\") || (bytes.length > 4 && bytes[0] === 0x89 && bytes[1] === 0x50)) return \"image/png\"\r\n if (lower.endsWith(\".bmp\") || (bytes.length > 2 && bytes[0] === 0x42 && bytes[1] === 0x4d)) return \"image/bmp\"\r\n if (lower.endsWith(\".gif\") || (bytes.length > 3 && bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46)) return \"image/gif\"\r\n if (lower.endsWith(\".svg\")) return \"image/svg+xml\"\r\n if (bytes.length > 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) return \"image/jpeg\"\r\n return \"image/jpeg\"\r\n}\r\n\r\n// ─── 엔트리 ───────────────────────────────────────\r\n\r\n/** 구역 하나의 페이지 지오메트리 (HWPUNIT) */\r\nfunction readSectionGeom(root: Element): PageGeom {\r\n const pagePr = findFirst(root, \"pagePr\")\r\n const margin = pagePr ? findChildByLocalName(pagePr, \"margin\") : null\r\n let PW = num(pagePr, \"width\", 59528), PH = num(pagePr, \"height\", 84188)\r\n // 용지 방향 — width/height는 용지 원방향(세로) 치수로 저장되고 landscape=\"NARROWLY\"가\r\n // 가로(90° 회전)를 뜻한다(WIDELY=세로). 무시하면 가로 문서의 오른쪽이 잘린다\r\n // (실측: 가로 A4 문서 lineseg 줄폭 78520 = 84188 − 좌우마진, 세로폭 59528 초과).\r\n if (pagePr?.getAttribute(\"landscape\") === \"NARROWLY\" && PW < PH) {\r\n const t = PW; PW = PH; PH = t\r\n }\r\n const ML = num(margin, \"left\", 8504)\r\n const MT = num(margin, \"top\", 5668) + num(margin, \"header\", 0)\r\n const BODY_H = PH - MT - num(margin, \"bottom\", 4252) - num(margin, \"footer\", 0)\r\n const BODY_W = PW - ML - num(margin, \"right\", 8504)\r\n return { PW, PH, ML, MT, BODY_W, BODY_H }\r\n}\r\n\r\n/** 렌더된 구역 — 페이지 버퍼 + 페이지 크기(구역별 pagePr 상이 가능) */\r\ninterface RenderedSection { pages: string[][]; PW: number; pageH: number; clipId: string }\r\n\r\n/**\r\n * 구역 하나를 렌더 → 페이지 버퍼. 공유 자원(styles/images/defs/warnings/stats)은 ctx로 넘겨\r\n * 이미지 심볼·통계·경고가 전 구역에 누적되게 한다(dataURI 중복·페이지 카운트 정합).\r\n */\r\nfunction renderSectionToPages(\r\n root: Element,\r\n geom: PageGeom,\r\n ctxBase: Omit<Ctx, \"pages\" | \"page\" | \"geom\">,\r\n doReflow: boolean,\r\n reflowMode: WrapMode,\r\n): { pages: string[][]; pageH: number } {\r\n const { PW, PH, ML, MT, BODY_W, BODY_H } = geom\r\n // Tier-2 reflow — 캐시 없는 문단에 linesegarray 합성 주입. 혼합 캐시 문서(한컴\r\n // 저장본을 프로그램 편집해 일부 문단만 캐시 없음)도 reflow 옵션이면 진입한다 —\r\n // 전량 캐시 문서는 전 문단 skip(Tier-1 무회귀)이라 no-op.\r\n if (doReflow) reflowSection(root, ctxBase.styles, { BODY_W, BODY_H }, reflowMode)\r\n\r\n // 페이지 분할 프리패스 — 최상위 lineseg vertpos는 페이지 로컬(페이지마다 0부터)이라\r\n // 역행 지점이 곧 페이지 경계다. 다단(colCount>1)은 단 이동도 vertpos가 리셋되지만\r\n // horzpos가 오른쪽으로 점프하므로, horzpos가 왼쪽으로 돌아올 때만 새 페이지로 본다.\r\n // vertpos \"동일\"도 문단 첫 seg + horzpos 비전진이면 경계다 — 페이지 전체가 표 하나인\r\n // 문단이 연속되면 vertpos가 매 페이지 0으로 같아서 strict 역행만으론 못 가른다\r\n // (의사일정표류: v0 문단 연속 → 뒤 페이지들이 전부 한 페이지에 겹침).\r\n // 문단 내부의 vertpos 동일 seg는 개체 좌우로 갈라진 같은 줄(h 우측 점프)이라 제외.\r\n const colPr = findFirst(root, \"colPr\")\r\n const multiCol = num(colPr, \"colCount\", 1) > 1\r\n const paraSegPages = new Map<Element, number[]>()\r\n let nPages = 1\r\n let maxTopV = 0\r\n {\r\n let prevV = Number.NEGATIVE_INFINITY\r\n let prevH = Number.NEGATIVE_INFINITY\r\n let cur = 0\r\n for (const p of elements(root)) {\r\n if (ln(p) !== \"p\") continue\r\n const lsa = findChildByLocalName(p, \"linesegarray\")\r\n const segEls = lsa ? elements(lsa).filter(s => ln(s) === \"lineseg\") : []\r\n const pagesOf: number[] = []\r\n let paraFirst = true\r\n for (const s of segEls) {\r\n const v = num(s, \"vertpos\")\r\n const h = num(s, \"horzpos\")\r\n const brk = v < prevV\r\n ? (!multiCol || h <= prevH)\r\n : (paraFirst && v === prevV && h <= prevH)\r\n if (brk) cur++\r\n paraFirst = false\r\n pagesOf.push(cur)\r\n maxTopV = Math.max(maxTopV, v + num(s, \"textheight\", 1000))\r\n prevV = v\r\n prevH = h\r\n }\r\n paraSegPages.set(p, pagesOf)\r\n nPages = Math.max(nPages, cur + 1)\r\n }\r\n }\r\n\r\n const ctx: Ctx = {\r\n ...ctxBase,\r\n pages: Array.from({ length: nPages }, () => []),\r\n page: 0,\r\n geom,\r\n }\r\n for (const p of elements(root)) {\r\n if (ln(p) !== \"p\") continue\r\n drawPara(p, ML, MT, BODY_W, ctx, 0, paraSegPages.get(p))\r\n }\r\n\r\n // 리셋이 없는데 본문이 페이지를 넘는 파일(누적 vertpos 기록본) 방어 —\r\n // 한 페이지로 두되 캔버스만 내용 끝까지 늘려 잘림을 막는다.\r\n const pageH = nPages === 1 ? Math.max(PH, MT + maxTopV + 2000) : PH\r\n return { pages: ctx.pages, pageH }\r\n}\r\n\r\n/**\r\n * HWPX(한컴 저장본) → 레이아웃 보존 SVG. **전 구역(section*)을 세로 스택으로** 렌더한다.\r\n * 조판 캐시(linesegarray)가 없는 구역은 reflow 옵션으로 합성 조판(없으면 그 구역 생략);\r\n * 렌더 가능한 구역이 하나도 없으면 KordocError.\r\n */\r\nexport async function renderHwpxToSvg(input: ArrayBuffer | Uint8Array, options?: RenderSvgOptions): Promise<RenderSvgResult> {\r\n const maxImg = options?.maxImageBytes ?? 40 * 1024 * 1024\r\n // 압축폭탄 가드 — 파서 진입점과 동일하게 압축해제 전 central directory 선언 크기를 검사한다.\r\n // 렌더 이미지 캡은 f.async 로 엔트리를 전량 압축해제한 뒤에야 크기를 보므로, 단일 BinData\r\n // 압축폭탄(수 GB 선언)이 캡을 우회해 OOM 을 유발하던 것을 원천 차단한다 (reflow-1).\r\n const ab = input instanceof Uint8Array\r\n ? input.buffer.slice(input.byteOffset, input.byteOffset + input.byteLength) as ArrayBuffer\r\n : input\r\n precheckZipSize(ab, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES)\r\n let zip: JSZip\r\n try {\r\n zip = await JSZip.loadAsync(input)\r\n } catch {\r\n throw new KordocError(\"HWPX(ZIP) 형식이 아닙니다 — 렌더는 HWPX만 지원\")\r\n }\r\n // 모든 구역 파일 (section0, section1, … — 이름 정렬)\r\n const secFiles = zip.file(/Contents\\/section\\d+\\.xml$/i).sort((a, b) => a.name.localeCompare(b.name))\r\n if (secFiles.length === 0) throw new KordocError(\"Contents/section0.xml 없음 — HWPX가 아니거나 손상됨\")\r\n\r\n const warnings: string[] = []\r\n const headFile = zip.file(\"Contents/header.xml\") ?? zip.file(\"Contents/head.xml\")\r\n const styles: RenderStyles = headFile\r\n ? parseRenderStyles(await headFile.async(\"string\"))\r\n : { charPr: new Map(), paraAlign: new Map(), paraGeom: new Map(), borderFill: new Map() }\r\n if (!headFile) warnings.push(\"header.xml 없음 — 기본 스타일로 렌더\")\r\n\r\n // 구역 XML 선로딩 + 크기 가드\r\n const secXmls: string[] = []\r\n for (const f of secFiles) {\r\n const xml = await f.async(\"string\")\r\n if (xml.length > MAX_DECOMPRESS_SIZE) throw new KordocError(\"섹션 XML이 허용 크기를 초과\")\r\n secXmls.push(xml)\r\n }\r\n\r\n // BinData 매니페스트 (id → href) — content.hpf 우선, 파일명 휴리스틱 폴백\r\n const binmap = new Map<string, string>()\r\n const hpf = zip.file(/content\\.hpf$/i)[0]\r\n if (hpf) {\r\n const man = await hpf.async(\"string\")\r\n for (const m of man.matchAll(/<[^>]*\\bid=\"([^\"]+)\"[^>]*\\bhref=\"(BinData\\/[^\"]+)\"[^>]*>/g)) binmap.set(m[1], m[2])\r\n for (const m of man.matchAll(/<[^>]*\\bhref=\"(BinData\\/[^\"]+)\"[^>]*\\bid=\"([^\"]+)\"[^>]*>/g)) binmap.set(m[2], m[1])\r\n }\r\n // 참조된 이미지만 선로딩 — 전 구역 ref 합집합 (DOM 워크 전에 async 구간 종료).\r\n // 장당 캡(maxImg) 외에 개수·누적 바이트 캡 — distinct 다수/대형 반복 참조로\r\n // 렌더 경로에서만 OOM 가능하던 구멍(파서 경로의 ZIP bomb 가드에 상응)\r\n const MAX_IMAGE_REFS = 256\r\n const MAX_TOTAL_IMAGE_BYTES = 128 * 1024 * 1024\r\n const images: Ctx[\"images\"] = new Map()\r\n const refs = new Set<string>()\r\n for (const xml of secXmls) for (const m of xml.matchAll(/binaryItemIDRef=\"([^\"]+)\"/g)) refs.add(m[1])\r\n let totalImgBytes = 0\r\n for (const ref of refs) {\r\n if (images.size >= MAX_IMAGE_REFS) {\r\n warnings.push(`이미지 ${refs.size}종 중 ${MAX_IMAGE_REFS}종만 로딩 — 개수 한도 초과분 생략`)\r\n break\r\n }\r\n let href = binmap.get(ref)\r\n if (!href) {\r\n const cand = zip.file(new RegExp(`BinData/.*${ref.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}`, \"i\"))[0]\r\n href = cand?.name\r\n }\r\n if (!href) continue\r\n const f = zip.file(href) ?? zip.file(\"Contents/\" + href)\r\n if (!f) continue\r\n const bytes = await f.async(\"uint8array\")\r\n if (bytes.length > maxImg) {\r\n warnings.push(`이미지 ${href} ${(bytes.length / 1048576).toFixed(1)}MB — 한도 초과로 생략`)\r\n continue\r\n }\r\n if (totalImgBytes + bytes.length > MAX_TOTAL_IMAGE_BYTES) {\r\n warnings.push(`이미지 누적 ${Math.round(MAX_TOTAL_IMAGE_BYTES / 1048576)}MB 한도 초과 — 이후 생략`)\r\n break\r\n }\r\n totalImgBytes += bytes.length\r\n images.set(ref, { dataUri: `data:${sniffMime(href, bytes)};base64,${Buffer.from(bytes).toString(\"base64\")}` })\r\n }\r\n\r\n // 전 구역 공유 컨텍스트 자원 (이미지 심볼 defs·통계·경고를 누적)\r\n const ctxBase: Omit<Ctx, \"pages\" | \"page\" | \"geom\"> = {\r\n styles, images, defs: [],\r\n highlights: (options?.highlights ?? []).map(s => s.trim().toLowerCase()).filter(s => s.length > 0),\r\n warnings, warned: new Set(), stats: { texts: 0, images: 0, tables: 0 },\r\n extentMemo: { cell: new WeakMap(), table: new WeakMap() },\r\n }\r\n\r\n // 구역별 렌더\r\n const rendered: RenderedSection[] = []\r\n let noCacheSkipped = false\r\n for (let si = 0; si < secXmls.length; si++) {\r\n const secXml = secXmls[si]\r\n // 태그 마크업만 매치 — 본문 텍스트에 \"linesegarray\"가 있어도 캐시로 오판하지 않는다\r\n // (본문의 <는 XML에서 &lt;로 이스케이프되므로 리터럴 <…linesegarray는 태그뿐)\r\n const hasCache = /<(?:[A-Za-z][\\w.-]*:)?linesegarray[\\s/>]/.test(secXml)\r\n if (!hasCache && !options?.reflow) {\r\n noCacheSkipped = true\r\n warnings.push(`구역 ${si}: 조판 캐시 없음 — reflow 옵션 필요, 생략`)\r\n continue\r\n }\r\n const doc = createXmlParser().parseFromString(secXml, \"text/xml\")\r\n const root = doc.documentElement as unknown as Element\r\n if (!root) { warnings.push(`구역 ${si} XML 파싱 실패 — 생략`); continue }\r\n const geom = readSectionGeom(root)\r\n const { pages, pageH } = renderSectionToPages(root, geom, ctxBase, !!options?.reflow, options?.reflowMode ?? \"keep\")\r\n rendered.push({ pages, PW: geom.PW, pageH, clipId: `pgclip${si}` })\r\n }\r\n\r\n if (rendered.length === 0) {\r\n if (noCacheSkipped) {\r\n throw new KordocError(\"조판 캐시(linesegarray) 없음 — 한컴에서 저장한 HWPX만 렌더 가능 (reflow 옵션으로 합성 렌더 가능)\")\r\n }\r\n throw new KordocError(\"렌더할 구역이 없습니다 — HWPX가 손상되었을 수 있습니다\")\r\n }\r\n\r\n // 전 구역 페이지를 세로 스택으로 조립 (구역마다 page 크기 상이 가능 → 구역별 clip)\r\n const GAP = 2400 // 페이지 사이 시각 간격 (24pt)\r\n const clipDefs: string[] = []\r\n const groups: string[] = []\r\n let y = 0\r\n let maxPW = 0\r\n let pageNo = 0\r\n for (const rs of rendered) {\r\n maxPW = Math.max(maxPW, rs.PW)\r\n clipDefs.push(`<clipPath id=\"${rs.clipId}\"><rect x=\"0\" y=\"0\" width=\"${pt(rs.PW)}\" height=\"${pt(rs.pageH)}\"/></clipPath>`)\r\n for (const buf of rs.pages) {\r\n pageNo++\r\n groups.push(\r\n `<g data-page=\"${pageNo}\" transform=\"translate(0 ${pt(y)})\">` +\r\n `<rect width=\"${pt(rs.PW)}\" height=\"${pt(rs.pageH)}\" fill=\"white\" stroke=\"#c9c7c4\" stroke-width=\"0.75\"/>` +\r\n `<g clip-path=\"url(#${rs.clipId})\">\\n${buf.join(\"\\n\")}\\n</g></g>`,\r\n )\r\n y += rs.pageH + GAP\r\n }\r\n }\r\n const totalH = Math.max(0, y - GAP)\r\n\r\n // width/height는 pt 단위 명시 — 단위 없는 px로 두면 A4 실물(96dpi 기준)보다 25% 작게 보인다 (v3.10.1)\r\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 ${pt(maxPW)} ${pt(totalH)}\" width=\"${pt(maxPW)}pt\" height=\"${pt(totalH)}pt\" font-family=\"'HCR Batang','함초롬바탕','Hancom Batang',AppleMyungjo,'Noto Serif CJK KR',serif\" xml:space=\"preserve\">\\n` +\r\n `<defs>${clipDefs.join(\"\")}${ctxBase.defs.join(\"\")}</defs>\\n` +\r\n `${groups.join(\"\\n\")}\\n</svg>`\r\n return { svg, width: Math.round(maxPW) / 100, height: Math.round(totalH) / 100, pageCount: pageNo, warnings, stats: ctxBase.stats }\r\n}\r\n","/**\r\n * 레이아웃 보존 렌더 — 순수 계산 유틸 (XML 무접촉).\r\n * 좌표 산식은 .claude/plans/render-poc/findings.md에서 실측 검증된 모델.\r\n * 단위: HWPUNIT(1/7200in), pt 변환은 /100.\r\n */\r\n\r\n/** HWPX 좌표 속성은 uint32로 저장된 음수가 섞여 있다 (예: vertOffset=4294967103 = -193) */\r\nexport function toInt32(v: string | undefined, fallback = 0): number {\r\n if (v == null || v === \"\") return fallback\r\n const n = Number(v)\r\n if (!Number.isFinite(n)) return fallback\r\n return n > 0x7fffffff ? n - 0x100000000 : n\r\n}\r\n\r\n/** 셀 하나가 주는 경계 제약: boundary[a] + size = boundary[b] */\r\nexport interface SpanConstraint {\r\n a: number\r\n b: number\r\n size: number\r\n}\r\n\r\n/**\r\n * 표 열 경계 솔버 — 경계 전파.\r\n * 결재문서 트레일러처럼 41열 그리드에 span-1 셀이 거의 없어도,\r\n * x[ca+cs] = x[ca] + w 제약을 고정점까지 전파하면 전 경계가 풀린다 (실측 검증).\r\n * 미해결 경계는 인접 확정 경계 사이 균등 보간.\r\n */\r\nexport function solveBoundaries(constraints: SpanConstraint[], count: number, total?: number): number[] {\r\n const x = new Array<number | undefined>(count + 1).fill(undefined)\r\n x[0] = 0\r\n if (total != null && total > 0) x[count] = total\r\n let changed = true\r\n let guard = 0\r\n while (changed && guard++ < count + 8) {\r\n changed = false\r\n for (const c of constraints) {\r\n if (c.a < 0 || c.b > count || c.a >= c.b) continue\r\n const xa = x[c.a]\r\n const xb = x[c.b]\r\n if (xa != null && xb == null) {\r\n x[c.b] = xa + c.size\r\n changed = true\r\n } else if (xb != null && xa == null) {\r\n x[c.a] = xb - c.size\r\n changed = true\r\n }\r\n }\r\n }\r\n // 잔여 미해결 경계 — 좌우 확정 경계 사이 균등 보간\r\n let i = 0\r\n while (i <= count) {\r\n if (x[i] != null) { i++; continue }\r\n let lo = i - 1\r\n let hi = i\r\n while (hi <= count && x[hi] == null) hi++\r\n const loV = x[lo] as number\r\n const hiV = hi <= count ? (x[hi] as number) : loV + (hi - lo) * 1000\r\n const n = hi - lo\r\n for (let k = 1; k < n; k++) x[lo + k] = loV + ((hiV - loV) * k) / n\r\n if (hi > count) x[count] = hiV\r\n i = hi\r\n }\r\n // 단조 보정 (모순 제약 방어)\r\n const out = x as number[]\r\n for (let k = 1; k <= count; k++) if (out[k] < out[k - 1]) out[k] = out[k - 1]\r\n return out\r\n}\r\n\r\n/**\r\n * 표 행 높이 솔버 — rowSpan=1 셀의 max가 기본, rowSpan>1은 잔여 균등분배.\r\n * h=1 더미 셀(헤어라인 행 장식)이 섞이므로 열과 달리 max 방식이 안전.\r\n * grow: 셀 콘텐츠(사진 등)가 설계 높이를 넘으면 초과분만큼 행이 자란다 —\r\n * 사진대지 실측: 설계 16441 + 사진 22209 → 행 22209, 표 sz 합치 정확 일치.\r\n */\r\nexport function solveRowHeights(\r\n cells: { rowAddr: number; rowSpan: number; height: number; contentH?: number }[],\r\n rowCount: number,\r\n): number[] {\r\n const h = new Array<number>(rowCount).fill(0)\r\n for (const c of cells) {\r\n if (c.rowSpan === 1 && c.rowAddr >= 0 && c.rowAddr < rowCount) {\r\n h[c.rowAddr] = Math.max(h[c.rowAddr], c.height)\r\n }\r\n }\r\n // rowSpan>1 셀 — 포함 행 중 미확정(0) 행에 잔여 균등분배\r\n for (const c of cells) {\r\n if (c.rowSpan <= 1) continue\r\n const rows: number[] = []\r\n for (let r = c.rowAddr; r < Math.min(c.rowAddr + c.rowSpan, rowCount); r++) rows.push(r)\r\n const known = rows.reduce((s, r) => s + h[r], 0)\r\n const missing = rows.filter(r => h[r] === 0)\r\n if (missing.length > 0 && c.height > known) {\r\n const each = (c.height - known) / missing.length\r\n for (const r of missing) h[r] = each\r\n }\r\n }\r\n // 콘텐츠 초과 성장 (rowSpan=1 셀만 — 사진 셀 케이스)\r\n for (const c of cells) {\r\n if (c.rowSpan === 1 && c.contentH != null && c.rowAddr >= 0 && c.rowAddr < rowCount) {\r\n if (c.contentH > h[c.rowAddr]) h[c.rowAddr] = c.contentH\r\n }\r\n }\r\n return h\r\n}\r\n\r\n// 자연폭 계산은 hwpx/text-metrics.ts의 함초롬바탕 실측 advance 테이블(measureTextWidth)을 재사용한다.\r\n","/**\r\n * 한글 조판 텍스트 폭 계산 — 함초롬바탕(HCR Batang) 실측 advance 테이블\r\n *\r\n * 공문서 표준 본문 글꼴인 함초롬바탕 정품 TTF(한컴 공개 배포)의 hmtx advance를\r\n * upem=1000 기준으로 추출한 값이다. Bold도 advance가 Regular와 완전히 동일함을\r\n * 전수 확인했다(한컴이 굵기 간 폭을 통일해 제작). 한글 음절 11,172자 전수 = 970,\r\n * 한자 = 1000, 전각형·원문자·도형·화살표·단위기호 = 970으로 균일하다.\r\n *\r\n * 단위: em×1000. 실제 폭(HWPUNIT) = w/1000 × charPr.height × ratio(장평)/100.\r\n * (1em = 글자크기 = charPr.height HWPUNIT — 1pt = 100 HWPUNIT이므로)\r\n *\r\n * 공백: HWP는 charPr useFontSpace=0(기본)일 때 글꼴의 space advance(0.30em) 대신\r\n * 반각 고정폭(0.50em)을 쓴다 — kordoc 생성 문서는 모두 useFontSpace=0이므로\r\n * 기본 SPACE_EM=500. (글꼴값을 쓰려면 measure 옵션 fontSpace로 300 지정)\r\n *\r\n * 다른 글꼴(맑은 고딕 등)도 한글=전각 균일·숫자≈0.55em의 동일 부류 구조라\r\n * 이 테이블로 근사한다(오차 수 % 이내 — 공문서 본문은 어차피 함초롬바탕 관행).\r\n */\r\n\r\n/** ASCII 0x20~0x7E advance (em×1000). 0x20은 useFontSpace=1일 때의 글꼴값(300) */\r\nconst ASCII_W = [\r\n 300, 320, 320, 610, 610, 830, 724, 320, 320, 320, 550, 550, 320, 550, 320, 550, // 0x20-0x2F\r\n 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, 320, 320, 550, 550, 550, 550, // 0x30-0x3F\r\n 830, 706, 605, 685, 719, 627, 617, 683, 734, 305, 315, 660, 605, 839, 734, 732, // 0x40-0x4F\r\n 603, 705, 660, 627, 664, 731, 706, 910, 705, 705, 626, 320, 550, 320, 550, 550, // 0x50-0x5F\r\n 320, 569, 597, 552, 597, 536, 356, 562, 635, 287, 288, 582, 287, 907, 635, 588, // 0x60-0x6F\r\n 597, 579, 478, 496, 356, 635, 563, 720, 542, 543, 486, 320, 320, 320, 550, 0, // 0x70-0x7E(+DEL)\r\n]\r\n\r\n/** 개별 실측 예외 기호 (em×1000) */\r\nconst SYM_W: Record<number, number> = {\r\n 0xa0: 300, 0xa3: 568, 0xa5: 707, 0xa7: 498, 0xab: 440, 0xac: 564, 0xb0: 291,\r\n 0xb1: 798, 0xb6: 606, 0xb7: 320, 0xbb: 440, 0xd7: 617, 0xf7: 678,\r\n 0x2013: 625, 0x2014: 875, 0x2015: 875, 0x2018: 320, 0x2019: 320, 0x201c: 480, 0x201d: 480,\r\n 0x2020: 558, 0x2021: 438, 0x2025: 640, 0x2026: 960, 0x2030: 988, 0x2032: 335, 0x2033: 474,\r\n 0x203b: 770, 0x20ac: 656, 0x261c: 1012, 0x261e: 1012,\r\n}\r\n\r\n/** 코드포인트의 advance(em×1000). 미상 문자는 CJK권 970 / 라틴권 550 폴백 */\r\nexport function charWidthEm1000(cp: number): number {\r\n if (cp >= 0x20 && cp <= 0x7e) return ASCII_W[cp - 0x20]\r\n const sym = SYM_W[cp]\r\n if (sym !== undefined) return sym\r\n if (cp >= 0xac00 && cp <= 0xd7a3) return 970 // 한글 음절 (전수 균일 확인)\r\n if (cp >= 0x1100 && cp <= 0x11ff) return 970 // 옛한글 자모\r\n if (cp >= 0x3131 && cp <= 0x318e) return 970 // 호환 자모 (ㆍ 포함)\r\n if ((cp >= 0x4e00 && cp <= 0x9fff) || (cp >= 0xf900 && cp <= 0xfaff)) return 1000 // 한자\r\n if ((cp >= 0x3008 && cp <= 0x3011) || (cp >= 0x3014 && cp <= 0x301b)) return 500 // 「」『』〈〉《》〔〕【】\r\n if (cp === 0x3000) return 970 // 전각 공백\r\n if (cp >= 0x2160 && cp <= 0x2183) return 970 // 로마숫자 Ⅰ~Ⅻ (한글 글꼴 전각)\r\n if (cp >= 0x2190 && cp <= 0x22ff) return 970 // 화살표·수학 기호\r\n if (cp >= 0x2460 && cp <= 0x24ff) return 970 // 원문자 ①⑴\r\n if (cp >= 0x25a0 && cp <= 0x26ff) return 970 // 도형 □○◆★\r\n if (cp >= 0x3200 && cp <= 0x33ff) return 970 // 괄호한글 ㉮·단위 ㎡㎏\r\n if (cp >= 0xff01 && cp <= 0xff60) return 970 // 전각형 !~\r\n return cp >= 0x2e80 ? 970 : 550\r\n}\r\n\r\n/** HWP 공백 폭(em×1000) — useFontSpace=0(기본): 반각 고정 500 / =1: 글꼴값 300 */\r\nexport const SPACE_EM_FIXED = 500\r\nexport const SPACE_EM_FONT = 300\r\n\r\n/**\r\n * 폭 테이블 클래스 — 'hcr'(함초롬 실측, 기본) / 'fixedPitch'(고정폭 글꼴:\r\n * ASCII 0.5em·그 외 1.0em). 굴림체·돋움체·바탕체·궁서체('체' 접미 = 고정폭)가\r\n * 대상 — 전자결재 변환기 산출물의 지배 본문 글꼴. 한글이 HCR(0.97em)보다 3%\r\n * 넓어 함초롬 테이블로 재면 줄당 1~2자 과대적재로 wrap 지점이 어긋난다\r\n * (bench/verify-linebreak.mjs seoul 코퍼스 실측: fixedPitch 테이블로 74/75 일치).\r\n */\r\nexport type FaceClass = \"hcr\" | \"fixedPitch\"\r\n\r\n/** HWP 글꼴명 → 폭 테이블 클래스. 미상/미지정은 hcr (기존 동작 불변) */\r\nexport function faceClassOf(face: string | null | undefined): FaceClass {\r\n return face && /^(굴림체|돋움체|바탕체|궁서체)$/.test(face.trim()) ? \"fixedPitch\" : \"hcr\"\r\n}\r\n\r\n/** 고정폭 글꼴 advance(em×1000) — ASCII 반각 500, 그 외 전각 1000 */\r\nfunction fixedPitchWidthEm1000(cp: number): number {\r\n return cp < 0x80 ? 500 : 1000\r\n}\r\n\r\nexport interface MeasureOptions {\r\n /** 공백 폭(em×1000). 기본 SPACE_EM_FIXED(500) = useFontSpace 0 */\r\n spaceEm?: number\r\n /** 자간(charPr spacing %) — 글자폭의 %가 문자마다 추가 */\r\n spacingPct?: number\r\n /** 폭 테이블 클래스 — 기본 'hcr' (함초롬 실측 테이블) */\r\n faceClass?: FaceClass\r\n}\r\n\r\n/**\r\n * 텍스트 폭(HWPUNIT). height=charPr height(pt×100), ratioPct=장평 %.\r\n * 결과는 float — 호출부에서 비교 시 ±0.5 HWPUNIT 오차 허용 권장.\r\n */\r\nexport function measureTextWidth(\r\n text: string,\r\n height: number,\r\n ratioPct: number,\r\n opts?: MeasureOptions,\r\n): number {\r\n const spaceEm = opts?.spaceEm ?? SPACE_EM_FIXED\r\n const spacing = opts?.spacingPct ?? 0\r\n const widthEm = opts?.faceClass === \"fixedPitch\" ? fixedPitchWidthEm1000 : charWidthEm1000\r\n let em = 0\r\n for (const ch of text) {\r\n const cp = ch.codePointAt(0)!\r\n const w = cp === 0x20 ? spaceEm : widthEm(cp)\r\n em += w * (1 + spacing / 100)\r\n }\r\n return (em / 1000) * height * (ratioPct / 100)\r\n}\r\n\r\n// ─── 줄바꿈 시뮬레이션 (한컴 조판 모델 — 실측 linesegarray 98% 일치 검증) ───\r\n//\r\n// 검증: bench/verify-linebreak.mjs — 서울 정보소통광장 실제 결재문서의 linesegarray\r\n// (한컴 계열 조판기가 계산한 줄 시작 오프셋)와 대조. 고정폭 글꼴 버킷에서 98%\r\n// (56/57 줄바꿈점, 미스는 코퍼스 좌표계 노이즈) 일치. 이 과정에서 확정된 규칙:\r\n// - 공백 폭 = 0.5em 고정(useFontSpace=0), 장평·자간 모두 공백에도 적용\r\n// - 자간 = 글자폭 × (1+spacing/100)\r\n// - 줄 끝 공백은 hang (줄바꿈을 유발하지 않음)\r\n// - 금칙: 시작금칙(닫는 부호 줄머리 금지)은 직전 글자 1개를 동반해 다음 줄로\r\n// (밀어내기), 끝금칙(여는 괄호 줄끝 금지)은 그 글자를 다음 줄로 내림\r\n\r\n/** 줄머리 금지(시작금칙) 문자 — 한컴 기본 */\r\nconst FORBID_START = new Set([...\"!%),.:;?]}¢°′″℃〉》」』】〕!%),.:;?]}₩~…·、。〃\"])\r\n/** 줄끝 금지(끝금칙) 문자 — 한컴 기본 */\r\nconst FORBID_END = new Set([...\"$([{£¥〈《「『【〔$([{₩\"])\r\n\r\nexport type WrapMode = \"keep\" | \"charAll\"\r\n\r\nexport interface WrapResult {\r\n /** 줄 수 */\r\n lines: number\r\n /** 각 줄의 시작 오프셋(UTF-16) — [0, …] */\r\n starts: number[]\r\n /** 마지막 줄 텍스트 폭(HWPUNIT) */\r\n lastLineWidth: number\r\n}\r\n\r\n/**\r\n * 문단 줄바꿈 시뮬레이션.\r\n * mode 'keep' = 어절 단위(공문서 모드 — 저장 속성 breakNonLatinWord=\"BREAK_WORD\", 이름 역전 주의),\r\n * mode 'charAll' = 글자 단위(breakNonLatinWord=\"KEEP_WORD\" — 한글 기본값·전자결재 변환기).\r\n * 한 어절이 줄보다 길면 keep에서도 글자 단위로 강제 분해(한컴 동일).\r\n *\r\n * @param text 문단 전체 텍스트(항목 부호 포함)\r\n * @param firstWidth 첫 줄 가용 폭(HWPUNIT)\r\n * @param contWidth 둘째 줄부터 가용 폭(HWPUNIT) — 내어쓰기 반영\r\n * @param height charPr height (pt×100)\r\n * @param ratioPct 장평 %\r\n */\r\nexport function simulateWrap(\r\n text: string,\r\n firstWidth: number,\r\n contWidth: number,\r\n height: number,\r\n ratioPct: number,\r\n mode: WrapMode = \"keep\",\r\n opts?: MeasureOptions,\r\n): WrapResult {\r\n const EPS = 0.5\r\n const spaceEm = opts?.spaceEm ?? SPACE_EM_FIXED\r\n const spacing = opts?.spacingPct ?? 0\r\n const widthEm = opts?.faceClass === \"fixedPitch\" ? fixedPitchWidthEm1000 : charWidthEm1000\r\n const k = (height * ratioPct) / 100 / 1000\r\n const cwCp = (cp: number): number =>\r\n (cp === 0x20 ? spaceEm : widthEm(cp)) * (1 + spacing / 100) * k\r\n const charW = (ch: string): number => cwCp(ch.codePointAt(0)!)\r\n const rangeW = (from: number, to: number): number => {\r\n let w = 0\r\n for (const ch of text.slice(from, to)) w += charW(ch)\r\n return w\r\n }\r\n\r\n // u 플래그 필수 — 없으면 astral 문자(𝐀·이모지 등)가 서로게이트 반쪽 2개로 쪼개져 폭이 2배로 계산된다\r\n const units = text.match(mode === \"keep\" ? / +|[^ ]+/gu : / +|[^ ]/gu) ?? []\r\n\r\n const starts = [0]\r\n let lineW = 0\r\n let avail = firstWidth\r\n let pos = 0\r\n const lineStart = (): number => starts[starts.length - 1]\r\n\r\n /** 유닛(시작 unitPos, 폭 w)이 안 들어갈 때 줄바꿈 + 금칙 보정 */\r\n const breakBefore = (unitPos: number, w: number): void => {\r\n let bp = unitPos\r\n const u = text[unitPos]\r\n // 시작금칙: 줄머리 금지 문자면 직전 글자 1개를 함께 내린다 (밀어내기)\r\n if (u !== undefined && FORBID_START.has(u) && bp - 1 > lineStart() && text[bp - 1] !== \" \") bp--\r\n // 끝금칙: 남는 줄 끝이 여는 괄호류면 그 글자(들)도 함께 내린다\r\n while (bp - 1 > lineStart() && FORBID_END.has(text[bp - 1])) bp--\r\n if (bp <= lineStart()) bp = unitPos\r\n starts.push(bp)\r\n avail = contWidth\r\n lineW = rangeW(bp, unitPos) + w\r\n }\r\n\r\n for (const u of units) {\r\n if (u[0] === \" \") {\r\n lineW += charW(\" \") * u.length // 줄 끝 공백은 hang\r\n pos += u.length\r\n continue\r\n }\r\n const w = rangeW(pos, pos + u.length)\r\n if (lineW + w <= avail + EPS) {\r\n lineW += w\r\n pos += u.length\r\n continue\r\n }\r\n if (lineW === 0 || w > contWidth + EPS) {\r\n // 빈 줄이거나 다음 줄에도 안 들어가는 초장 유닛 — 글자 단위 강제 분해\r\n let sub = 0\r\n for (const ch of u) {\r\n const c = charW(ch)\r\n if (lineW + c > avail + EPS && lineW > 0) breakBefore(pos + sub, 0)\r\n lineW += c\r\n sub += ch.length\r\n }\r\n pos += u.length\r\n continue\r\n }\r\n breakBefore(pos, w)\r\n pos += u.length\r\n }\r\n return { lines: starts.length, starts, lastLineWidth: lineW }\r\n}\r\n\r\n/** @deprecated simulateWrap(text, …, 'keep') 별칭 — 하위 호환 */\r\nexport function simulateWrapKeepWord(\r\n text: string,\r\n firstWidth: number,\r\n contWidth: number,\r\n height: number,\r\n ratioPct: number,\r\n opts?: MeasureOptions,\r\n): WrapResult {\r\n return simulateWrap(text, firstWidth, contWidth, height, ratioPct, \"keep\", opts)\r\n}\r\n\r\n/**\r\n * 한두 글자(짧은 꼬리)가 다음 줄로 넘어간 문단을 장평 축소로 한 줄 줄일 수 있는지\r\n * 탐색. baseRatio에서 줄 수 N≥2일 때 r=baseRatio-1…minRatio를 내려가며 처음으로\r\n * 줄 수가 줄어드는(가장 큰) r을 반환. 불가능하면 null.\r\n * (실무 관행: 공무원이 문단 장평을 95→92 등으로 줄여 orphan을 위로 당기는 조작의 자동화.\r\n * keep 모드로 판정 — 글자 단위 조판은 항상 keep 이하의 줄 수라 함께 만족된다.)\r\n */\r\nexport function fitRatioForFewerLines(\r\n text: string,\r\n firstWidth: number,\r\n contWidth: number,\r\n height: number,\r\n baseRatio: number,\r\n minRatio: number,\r\n opts?: MeasureOptions,\r\n): number | null {\r\n const base = simulateWrap(text, firstWidth, contWidth, height, baseRatio, \"keep\", opts)\r\n if (base.lines < 2) return null\r\n for (let r = baseRatio - 1; r >= minRatio; r--) {\r\n const sim = simulateWrap(text, firstWidth, contWidth, height, r, \"keep\", opts)\r\n if (sim.lines < base.lines) return r\r\n }\r\n return null\r\n}\r\n","/**\r\n * Tier-2 reflow — 조판 캐시(linesegarray)가 없는 문단에 좌표를 합성 주입한다.\r\n *\r\n * 한컴은 저장 시 각 줄의 좌표(vertpos/horzpos/…)를 linesegarray로 캐시한다.\r\n * markdownToHwpx 산출물·에이전트 생성본·편집본엔 이 캐시가 없어 svg-render가\r\n * KordocError로 거부한다. reflow는 `simulateWrap`(수평, 실측 98% 일치)과 세로 모델\r\n * (실측 역설계 — `.claude/plans/render-poc/findings.md`)로 lineseg를 계산해 DOM\r\n * `<hp:p>`에 `<hp:linesegarray>`를 append → 그 뒤는 기존 렌더 파이프가 그대로 소비한다.\r\n *\r\n * 세로 모델(HWPUNIT): textheight = 줄 지배 charPr.height, baseline = round(0.85×th),\r\n * 줄 pitch = round(th × lineSpacing%/100), spacing(leading) = pitch − th.\r\n * 문단 세로 흐름 = 본문영역 로컬 누적(다음문단 = 이전끝 + pitch + next + prev).\r\n *\r\n * 원칙: 한컴본 캐시는 절대 건드리지 않는다(Tier-1 무회귀). segs가 있는 문단은 건너뛴다.\r\n * Phase 3(v4.0.4): 개체 세로 흐름 — float(TOP_AND_BOTTOM)는 텍스트를 outMargin 포함\r\n * 개체 아래로 밀고, PAGE/PAPER 앵커·BEHIND/IN_FRONT는 흐름 불참, inline 표는 실효높이\r\n * +leading 전진. 혼합 캐시 문서는 캐시 문단의 한컴 좌표로 커서를 이어 받는다\r\n * (seoul 코퍼스 자기일관성 59/59 — 36264961 전 문단 d=0 실측).\r\n */\r\n\r\nimport { buildPara, measureTableHeight } from \"./svg-render.js\"\r\nimport { simulateWrap, faceClassOf, type WrapMode } from \"../hwpx/text-metrics.js\"\r\nimport { DEFAULT_CHAR, DEFAULT_PARA_GEOM, type RenderStyles, type RenderParaGeom } from \"./head-styles.js\"\r\nimport { findChildByLocalName } from \"../hwpx/parser-shared.js\"\r\nimport { toInt32 } from \"./layout.js\"\r\n\r\n/** lineseg flags 고정값 (한컴 저장본 실측 — 0x60000) */\r\nconst LINESEG_FLAGS = \"393216\"\r\n/** baseline / textheight 비율 (실측 94/94 일치) */\r\nconst BASELINE_RATIO = 0.85\r\n\r\nfunction ln(el: Element): string {\r\n return (el.tagName || \"\").replace(/^[^:]+:/, \"\")\r\n}\r\n\r\nfunction elements(el: Element): Element[] {\r\n const out: Element[] = []\r\n const kids = el.childNodes\r\n if (!kids) return out\r\n for (let i = 0; i < kids.length; i++) if (kids[i].nodeType === 1) out.push(kids[i] as Element)\r\n return out\r\n}\r\n\r\nfunction num(el: Element | null, attr: string, fallback = 0): number {\r\n return el ? toInt32(el.getAttribute(attr) ?? undefined, fallback) : fallback\r\n}\r\n\r\n/** 문단의 합성 linesegarray 줄들의 vertpos를 delta만큼 이동 (페이지 로컬 리셋용) */\r\nfunction shiftParaVert(p: Element, delta: number): void {\r\n for (const lsa of elements(p)) {\r\n if (ln(lsa) !== \"linesegarray\") continue\r\n for (const seg of elements(lsa)) {\r\n if (ln(seg) !== \"lineseg\") continue\r\n seg.setAttribute(\"vertpos\", String(num(seg, \"vertpos\") + delta))\r\n }\r\n }\r\n}\r\n\r\nexport interface ReflowGeom {\r\n BODY_W: number\r\n BODY_H: number\r\n}\r\n\r\n/** 줄 pitch(다음 줄 vertpos 증분, HWPUNIT) — lineSpacing type별 */\r\nfunction pitchFor(height: number, geom: RenderParaGeom): number {\r\n const v = geom.lineSpacingValue\r\n switch (geom.lineSpacingType) {\r\n case \"PERCENT\": return Math.round((height * v) / 100)\r\n case \"FIXED\": return v > 0 ? v : Math.round(height * 1.6) // 고정 줄높이(HWPUNIT)\r\n case \"AT_LEAST\": return Math.max(v, height)\r\n default: return Math.round(height * 1.6) // BETWEEN_LINES 등 — 기본 160% 근사\r\n }\r\n}\r\n\r\n/**\r\n * 문단 하나의 linesegarray를 합성해 p에 삽입.\r\n * @returns 세로 흐름 갱신값 (캐시 있어 건너뛴 경우 null)\r\n */\r\nfunction reflowPara(\r\n p: Element,\r\n doc: Document,\r\n styles: RenderStyles,\r\n areaW: number,\r\n startV: number,\r\n mode: WrapMode,\r\n): { paraBottom: number; spaceAfter: number } | null {\r\n const m = buildPara(p)\r\n if (m.segs.length > 0) return null // 이미 캐시 있음 — Tier-1 무회귀\r\n\r\n // 실텍스트 + UTF-16 유닛 → chars 슬롯 인덱스 매핑 (서로게이트 쌍은 슬롯 1개, 유닛 2개)\r\n const realIdx: number[] = []\r\n let text = \"\"\r\n for (let i = 0; i < m.chars.length; i++) {\r\n const ch = m.chars[i].ch\r\n if (ch === \"\") continue\r\n for (let u = 0; u < ch.length; u++) realIdx.push(i)\r\n text += ch\r\n }\r\n\r\n const geom = styles.paraGeom.get(m.paraPrId ?? \"\") ?? DEFAULT_PARA_GEOM\r\n // 문단 지배 charPr — 첫 실문자 우선(height/장평/자간)\r\n let domChar = DEFAULT_CHAR\r\n for (const c of m.chars) {\r\n if (c.ch !== \"\" && c.prId != null) {\r\n const st = styles.charPr.get(c.prId)\r\n if (st) { domChar = st; break }\r\n }\r\n }\r\n // 실문자가 없는 문단(빈 줄·개체 전용)도 run의 charPrIDRef가 줄높이를 지배한다 —\r\n // DEFAULT_CHAR(1000)로 재면 빈 문단 pitch가 본문(예: 1300→2080)보다 작아 이후\r\n // 문단 전체가 위로 밀린다 (seoul 코퍼스 36264961 실측 −480×빈줄 누적)\r\n if (domChar === DEFAULT_CHAR) {\r\n for (const run of elements(p)) {\r\n if (ln(run) !== \"run\") continue\r\n const st = styles.charPr.get(run.getAttribute(\"charPrIDRef\") ?? \"\")\r\n if (st) { domChar = st; break }\r\n }\r\n }\r\n const height = domChar.height || 1000\r\n const ratio = domChar.ratio || 100\r\n const spacingPct = domChar.spacing || 0\r\n\r\n const marginL = geom.marginLeft\r\n const avail = Math.max(1000, areaW - marginL - geom.marginRight)\r\n // hanging(intent<0): 둘째 줄부터 |intent| 더 들어감 → contWidth 축소·contHorz 우측 이동\r\n const firstWidth = avail\r\n const contWidth = Math.max(500, avail + Math.min(0, geom.marginIntent))\r\n const contHorz = marginL - Math.min(0, geom.marginIntent)\r\n\r\n // 문단 paraPr의 breakSetting이 있으면 그 선언(어절/글자)을 따르고, 없으면 호출자 모드\r\n const paraMode = geom.wrapMode ?? mode\r\n // 폭 테이블: 지배 charPr 글꼴이 고정폭(굴림체류)이면 전용 클래스 — 함초롬 테이블(한글\r\n // 0.97em)로 재면 줄당 1~2자 과대적재로 wrap이 어긋난다 (seoul 코퍼스 3건 실측)\r\n const faceClass = faceClassOf(domChar.face)\r\n const wrap = text.length === 0\r\n ? { lines: 1, starts: [0], lastLineWidth: 0 }\r\n : simulateWrap(text, firstWidth, contWidth, height, ratio, paraMode, { spacingPct, faceClass })\r\n\r\n const pitch = pitchFor(height, geom)\r\n const baseline = Math.round(height * BASELINE_RATIO)\r\n const spacing = Math.max(0, pitch - height)\r\n\r\n // ── 개체(표·이미지) 세로 흐름 분류 (Phase 3 — 한컴 실측 모델, 36264961) ──\r\n // · float(treatAsChar=0) + TOP_AND_BOTTOM + PARA 앵커: 개체가 문단 상단을 차지하고\r\n // 텍스트는 outTop+개체높이+outBottom 아래부터 흐른다 (두문 결재표 실측:\r\n // 140+16653+852=17645 정확 일치)\r\n // · BEHIND_TEXT/IN_FRONT_OF_TEXT 또는 PAGE/PAPER 앵커: 본문 흐름에 불참\r\n // (페이지 하단 직인 스탬프가 커서를 밀던 것 제거)\r\n // · inline(treatAsChar=1): 줄 하나로 취급 — outMargin 포함 높이 + 줄 leading(spacing)\r\n // 만큼 전진 (실측: 표끝→다음 문단 간격 = 성장 포함 표높이 + spacing)\r\n let floatBelow = 0 // 텍스트 시작을 아래로 미는 float 개체 바닥 (문단 로컬)\r\n let objBottom = startV\r\n for (const o of m.objs) {\r\n const effH = o.tag === \"tbl\" ? Math.max(o.height, measureTableHeight(o.el)) : o.height\r\n const pos = findChildByLocalName(o.el, \"pos\")\r\n const om = findChildByLocalName(o.el, \"outMargin\")\r\n const outT = num(om, \"top\"), outB = num(om, \"bottom\")\r\n if (o.inline) {\r\n objBottom = Math.max(objBottom, startV + outT + effH + outB + spacing)\r\n continue\r\n }\r\n const wrapAttr = o.el.getAttribute(\"textWrap\") ?? \"\"\r\n if (wrapAttr === \"BEHIND_TEXT\" || wrapAttr === \"IN_FRONT_OF_TEXT\") continue\r\n const vertRel = pos?.getAttribute(\"vertRelTo\") ?? \"PARA\"\r\n if (vertRel === \"PAGE\" || vertRel === \"PAPER\") continue\r\n const vo = Math.max(0, num(pos, \"vertOffset\"))\r\n if (wrapAttr === \"TOP_AND_BOTTOM\") {\r\n floatBelow = Math.max(floatBelow, vo + outT + effH + outB)\r\n } else {\r\n objBottom = Math.max(objBottom, startV + vo + outT + effH + outB)\r\n }\r\n }\r\n const textStartV = startV + floatBelow\r\n\r\n const lsa = doc.createElement(\"hp:linesegarray\")\r\n for (let li = 0; li < wrap.starts.length; li++) {\r\n const startReal = wrap.starts[li]\r\n // 실텍스트 없는 문단(인라인 표·개체만)의 textpos는 0 — chars.length로 폴백하면\r\n // planLines의 plan.start가 개체 index보다 커져 advanceTo 가로 전진에서 개체가\r\n // 전부 빠지고 같은 x에 겹쳐 그려진다 (공문 결재란 라벨표∩스탬프표 겹침의 원인)\r\n const textpos = startReal < realIdx.length ? realIdx[startReal] : 0\r\n const vertpos = textStartV + li * pitch\r\n const isFirst = li === 0\r\n const seg = doc.createElement(\"hp:lineseg\")\r\n seg.setAttribute(\"textpos\", String(textpos))\r\n seg.setAttribute(\"vertpos\", String(vertpos))\r\n seg.setAttribute(\"vertsize\", String(height))\r\n seg.setAttribute(\"textheight\", String(height))\r\n seg.setAttribute(\"baseline\", String(baseline))\r\n seg.setAttribute(\"spacing\", String(spacing))\r\n seg.setAttribute(\"horzpos\", String(isFirst ? marginL : contHorz))\r\n seg.setAttribute(\"horzsize\", String(isFirst ? firstWidth : contWidth))\r\n seg.setAttribute(\"flags\", LINESEG_FLAGS)\r\n lsa.appendChild(seg)\r\n }\r\n p.appendChild(lsa)\r\n\r\n // 문단 바닥 = 텍스트 줄 흐름(float 개체 아래부터)과 개체 바닥 중 큰 쪽.\r\n // 표는 셀 콘텐츠 성장으로 선언 sz보다 커질 수 있어 drawTable과 같은 실효 높이를 쓴다\r\n // (셀 lineseg 필요 — reflowBlockFlow가 reflowTablesIn을 먼저 돌린다).\r\n const textBottom = textStartV + wrap.starts.length * pitch\r\n return { paraBottom: Math.max(textBottom, objBottom), spaceAfter: geom.spaceAfter }\r\n}\r\n\r\n/** 문단 run 안의 표를 찾아 각 셀 subList를 셀 로컬로 reflow (중첩 재귀) */\r\nfunction reflowTablesIn(p: Element, doc: Document, styles: RenderStyles, mode: WrapMode, counter: { n: number }): void {\r\n for (const run of elements(p)) {\r\n if (ln(run) !== \"run\") continue\r\n for (const obj of elements(run)) {\r\n if (ln(obj) !== \"tbl\") continue\r\n for (const tr of elements(obj)) {\r\n if (ln(tr) !== \"tr\") continue\r\n for (const tc of elements(tr)) {\r\n if (ln(tc) !== \"tc\") continue\r\n const csz = findChildByLocalName(tc, \"cellSz\")\r\n const cm = findChildByLocalName(tc, \"cellMargin\")\r\n const cellW = num(csz, \"width\")\r\n const mL = cm ? num(cm, \"left\", 141) : 141\r\n const mR = cm ? num(cm, \"right\", 141) : 141\r\n const areaW = Math.max(500, cellW - mL - mR)\r\n const sub = findChildByLocalName(tc, \"subList\")\r\n if (sub) reflowBlockFlow(sub, doc, styles, areaW, mode, counter, 0)\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * 한 블록 컨테이너(본문 root 또는 셀 subList) 안 문단들을 세로 흐름으로 reflow.\r\n * @param bodyH 최상위(본문)일 때만 >0 — 문단 단위 자동 페이지 나눔(vertpos 페이지 로컬 리셋).\r\n * 셀 subList는 0(페이지 나눔 없음).\r\n */\r\nfunction reflowBlockFlow(\r\n container: Element,\r\n doc: Document,\r\n styles: RenderStyles,\r\n areaW: number,\r\n mode: WrapMode,\r\n counter: { n: number },\r\n bodyH: number,\r\n): void {\r\n let cursorV = 0\r\n let prevSpaceAfter = 0\r\n for (const p of elements(container)) {\r\n if (ln(p) !== \"p\") continue\r\n // 문단 안 표 셀을 먼저 셀 로컬 좌표로 reflow (본문 세로 흐름과 무관) —\r\n // reflowPara의 표 실효높이 측정이 셀 lineseg를 읽으므로 호스트 문단보다 앞서야 한다\r\n reflowTablesIn(p, doc, styles, mode, counter)\r\n const g = styles.paraGeom.get(p.getAttribute(\"paraPrIDRef\") ?? \"\")\r\n const startV = cursorV + prevSpaceAfter + (g?.spaceBefore ?? 0)\r\n const res = reflowPara(p, doc, styles, areaW, startV, mode)\r\n if (!res) {\r\n // 캐시 보유 문단(Tier-1) — 한컴 실좌표로 커서를 전진시킨다. 혼합 캐시 문서\r\n // (한컴 저장본을 프로그램 편집해 일부 문단만 캐시가 없는 경우)에서 캐시 없는\r\n // 문단이 흐름 위치 대신 0에 겹쳐 그려지던 결함 수정 (36264961 실측: 캐시 문단\r\n // p18 57165+1300+780 → 캐시 없는 p19가 정확히 59245에 붙는다).\r\n const lsa = findChildByLocalName(p, \"linesegarray\")\r\n if (lsa) {\r\n let bottom = Number.NEGATIVE_INFINITY\r\n for (const seg of elements(lsa)) {\r\n if (ln(seg) !== \"lineseg\") continue\r\n const th = Math.max(num(seg, \"vertsize\", 1000), num(seg, \"textheight\", 1000))\r\n bottom = Math.max(bottom, num(seg, \"vertpos\") + th + num(seg, \"spacing\"))\r\n }\r\n if (Number.isFinite(bottom)) {\r\n cursorV = bottom\r\n prevSpaceAfter = g?.spaceAfter ?? 0\r\n }\r\n }\r\n continue\r\n }\r\n const paraH = res.paraBottom - startV\r\n // 페이지 넘김: 문단이 현재 페이지를 넘치고, 문단 자체는 한 페이지에 들어가면 다음 페이지로.\r\n if (bodyH > 0 && startV > 0 && res.paraBottom > bodyH && paraH <= bodyH) {\r\n shiftParaVert(p, -startV) // 새 페이지 상단(로컬 0)으로 이동 → 프리패스가 vertpos 역행 감지\r\n cursorV = paraH\r\n } else {\r\n cursorV = res.paraBottom\r\n }\r\n prevSpaceAfter = res.spaceAfter\r\n counter.n++\r\n }\r\n}\r\n\r\n/**\r\n * section root의 조판 캐시 없는 문단에 linesegarray를 합성 주입한다(표 셀 재귀 포함).\r\n * 반환: 합성한 문단 수.\r\n * (Phase 2~3: 최상위 텍스트 + 표 셀 내부. 개체 밀어내기·자동 페이지 분할은 후속.)\r\n */\r\nexport function reflowSection(\r\n root: Element,\r\n styles: RenderStyles,\r\n geom: ReflowGeom,\r\n mode: WrapMode = \"keep\",\r\n): number {\r\n const doc = root.ownerDocument as unknown as Document\r\n const counter = { n: 0 }\r\n reflowBlockFlow(root, doc, styles, geom.BODY_W, mode, counter, geom.BODY_H)\r\n return counter.n\r\n}\r\n"],"mappings":"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","names":["charW","ln","elements","num"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["c:\\github_project\\kordoc\\dist\\chunk-VQB5P5KJ.cjs"],"names":[],"mappings":"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","file":"C:\\github_project\\kordoc\\dist\\chunk-VQB5P5KJ.cjs","sourcesContent":[null]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/image/transcode.ts"],"sourcesContent":["/**\r\n * 순수 JS BMP → PNG 트랜스코더 + 마크다운 이미지 인라이너.\r\n *\r\n * HWP5 BinData 임베드 이미지는 비압축 BMP(수 MB)인 경우가 많다. AI 에이전트가\r\n * 자체 완결형 마크다운을 받도록, BMP 를 PNG(무손실 압축)로 변환한 뒤 base64\r\n * data URI 로 마크다운에 인라인한다.\r\n *\r\n * 의존성 최소화 원칙 — Node 내장(node:zlib, Buffer)만 사용한다.\r\n */\r\n\r\nimport { deflateSync } from \"node:zlib\"\r\n\r\n// ─── CRC32 (PNG 청크용) ──────────────────────────────\r\n\r\nconst CRC_TABLE = (() => {\r\n const table = new Uint32Array(256)\r\n for (let n = 0; n < 256; n++) {\r\n let c = n\r\n for (let k = 0; k < 8; k++) {\r\n c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1)\r\n }\r\n table[n] = c >>> 0\r\n }\r\n return table\r\n})()\r\n\r\n/** 표준 PNG CRC32 (다항식 0xEDB88320) */\r\nfunction crc32(bytes: Uint8Array): number {\r\n let c = 0xffffffff\r\n for (let i = 0; i < bytes.length; i++) {\r\n c = CRC_TABLE[(c ^ bytes[i]) & 0xff] ^ (c >>> 8)\r\n }\r\n return (c ^ 0xffffffff) >>> 0\r\n}\r\n\r\n// ─── BMP 디코드 ──────────────────────────────────────\r\n\r\nconst BI_RGB = 0\r\n/** 폭·높이 상한 — 비정상 헤더에 의한 과대 할당 방지 */\r\nconst MAX_DIM = 0x7fff\r\n/**\r\n * 총 픽셀(W×H) 상한 — MAX_DIM 은 각 변만 제한하므로 곱의 폭주(과대 할당 + 긴 deflateSync\r\n * 동기 블로킹)를 별도로 차단한다. raw 저장 BMP 는 상위 inflate 100MB 캡을 우회하므로 필요.\r\n * 36MP = A4 전면 600dpi 스캔(≈35MP)까지 허용 — 그 이상은 rgba+raw 로 300MB 를 넘겨\r\n * MCP 서버 이벤트루프를 수 초 세우므로 원본 바이트 폴백으로 돌린다.\r\n */\r\nconst MAX_PIXELS = 36_000_000\r\n\r\n/**\r\n * 비압축 BMP(24/32bpp, BI_RGB) → PNG(8bit RGBA).\r\n *\r\n * 지원: BITMAPFILEHEADER + BITMAPINFOHEADER(biSize>=40), biBitCount 24/32,\r\n * biCompression BI_RGB, bottom-up(양수 biHeight)/top-down(음수), 24bpp 4바이트 행 패딩.\r\n * 미지원 변형(팔레트/8bpp·RLE·BITFIELDS·OS/2 헤더 등)은 null 을 반환하여\r\n * 호출부가 원본 바이트로 폴백하게 한다.\r\n */\r\nexport function bmpToPng(bmp: Uint8Array): Uint8Array | null {\r\n // BITMAPFILEHEADER(14) + BITMAPINFOHEADER(40)\r\n if (bmp.length < 54) return null\r\n if (bmp[0] !== 0x42 || bmp[1] !== 0x4d) return null // \"BM\"\r\n\r\n const dv = new DataView(bmp.buffer, bmp.byteOffset, bmp.byteLength)\r\n const dataOffset = dv.getUint32(10, true)\r\n const headerSize = dv.getUint32(14, true)\r\n if (headerSize < 40) return null // OS/2 BITMAPCOREHEADER 등 미지원\r\n\r\n const width = dv.getInt32(18, true)\r\n const rawHeight = dv.getInt32(22, true)\r\n const bitCount = dv.getUint16(28, true)\r\n const compression = dv.getUint32(30, true)\r\n\r\n if (compression !== BI_RGB) return null // RLE / BITFIELDS 미지원\r\n if (bitCount !== 24 && bitCount !== 32) return null // 팔레트 / 8bpp 등 미지원\r\n if (width <= 0 || rawHeight === 0) return null\r\n if (width > MAX_DIM || Math.abs(rawHeight) > MAX_DIM) return null\r\n\r\n const topDown = rawHeight < 0\r\n const height = Math.abs(rawHeight)\r\n // 총 픽셀 상한 검사 — rgba/raw 할당·deflate 전에 조기 차단 (각 변은 MAX_DIM 이하여도 곱은 폭주 가능)\r\n if (width * height > MAX_PIXELS) return null\r\n const bytesPerPixel = bitCount >> 3\r\n // 행 스트라이드 — 4바이트 경계 패딩 (24bpp 에서 유효)\r\n const rowStride = (width * bytesPerPixel + 3) & ~3\r\n if (dataOffset + rowStride * height > bmp.length) return null // 잘린 파일\r\n\r\n const rgba = new Uint8Array(width * height * 4)\r\n let anyAlpha = 0\r\n\r\n for (let y = 0; y < height; y++) {\r\n // bottom-up 은 첫 행이 이미지 맨 아래 → 뒤집어 읽는다\r\n const srcRow = topDown ? y : height - 1 - y\r\n let src = dataOffset + srcRow * rowStride\r\n let dst = y * width * 4\r\n for (let x = 0; x < width; x++) {\r\n // BMP 픽셀은 BGR(A) 순\r\n rgba[dst] = bmp[src + 2] // R\r\n rgba[dst + 1] = bmp[src + 1] // G\r\n rgba[dst + 2] = bmp[src] // B\r\n const a = bitCount === 32 ? bmp[src + 3] : 255\r\n rgba[dst + 3] = a\r\n anyAlpha |= a\r\n src += bytesPerPixel\r\n dst += 4\r\n }\r\n }\r\n\r\n // 32bpp BI_RGB 의 4번째 바이트는 \"미정의\" — 전부 0 이면 전면 투명으로 오해되므로\r\n // 불투명(255)으로 승격한다. 실제 알파가 있으면(anyAlpha!=0) 그대로 보존.\r\n if (bitCount === 32 && anyAlpha === 0) {\r\n for (let i = 3; i < rgba.length; i += 4) rgba[i] = 255\r\n }\r\n\r\n return encodePng(width, height, rgba)\r\n}\r\n\r\n// ─── PNG 인코드 (8bit RGBA, color type 6) ────────────\r\n\r\nconst PNG_SIGNATURE = Uint8Array.of(0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a)\r\n\r\n/** [4B 길이][4B 타입][데이터][4B CRC] 청크 조립. CRC 는 (타입+데이터) 기준. */\r\nfunction chunk(type: string, data: Uint8Array): Uint8Array {\r\n const body = new Uint8Array(4 + data.length)\r\n body[0] = type.charCodeAt(0)\r\n body[1] = type.charCodeAt(1)\r\n body[2] = type.charCodeAt(2)\r\n body[3] = type.charCodeAt(3)\r\n body.set(data, 4)\r\n\r\n const out = new Uint8Array(8 + data.length + 4)\r\n const dv = new DataView(out.buffer)\r\n dv.setUint32(0, data.length, false) // 길이(데이터만, big-endian)\r\n out.set(body, 4)\r\n dv.setUint32(8 + data.length, crc32(body), false)\r\n return out\r\n}\r\n\r\n/** 8bit RGBA 픽셀 버퍼 → PNG (PDF 이미지 XObject 추출에서도 사용) */\r\nexport function encodePng(width: number, height: number, rgba: Uint8Array): Uint8Array {\r\n // IHDR: width, height, bit depth 8, color type 6(RGBA), compression 0, filter 0, interlace 0\r\n const ihdr = new Uint8Array(13)\r\n const iv = new DataView(ihdr.buffer)\r\n iv.setUint32(0, width, false)\r\n iv.setUint32(4, height, false)\r\n ihdr[8] = 8\r\n ihdr[9] = 6\r\n\r\n // IDAT: 각 스캔라인 앞에 필터 바이트 0(None) 을 붙인 raw 데이터를 zlib deflate\r\n const stride = width * 4\r\n const raw = new Uint8Array((stride + 1) * height)\r\n for (let y = 0; y < height; y++) {\r\n const rowStart = y * (stride + 1)\r\n raw[rowStart] = 0 // filter: None\r\n raw.set(rgba.subarray(y * stride, y * stride + stride), rowStart + 1)\r\n }\r\n const idat = deflateSync(raw)\r\n\r\n const ihdrChunk = chunk(\"IHDR\", ihdr)\r\n const idatChunk = chunk(\"IDAT\", idat)\r\n const iendChunk = chunk(\"IEND\", new Uint8Array(0))\r\n\r\n const out = new Uint8Array(PNG_SIGNATURE.length + ihdrChunk.length + idatChunk.length + iendChunk.length)\r\n let o = 0\r\n out.set(PNG_SIGNATURE, o); o += PNG_SIGNATURE.length\r\n out.set(ihdrChunk, o); o += ihdrChunk.length\r\n out.set(idatChunk, o); o += idatChunk.length\r\n out.set(iendChunk, o)\r\n return out\r\n}\r\n\r\n// ─── 마크다운 이미지 인라이너 ────────────────────────\r\n\r\ninterface InlineImage {\r\n filename: string\r\n data: Uint8Array\r\n mimeType: string\r\n}\r\n\r\n/**\r\n * 마크다운의 이미지 참조를 base64 data URI 로 치환해 자체 완결형 마크다운을 만든다.\r\n * 두 방출 형태를 모두 커버한다:\r\n * - `![image](FILENAME)` / `![image](images/FILENAME)` — 일반 문단 (CLI 접두사 포함)\r\n * - `<img src=\"FILENAME\">` — 병합/중첩 표 셀 (table/builder.ts HTML 표 경로).\r\n * 이걸 빼면 CLI `--inline-images` 가 이미지 저장을 생략하면서 표 셀 이미지만\r\n * dangling 참조로 유실된다.\r\n *\r\n * @param opts.compress 기본 true. `image/bmp` 는 PNG 로 트랜스코딩 후 인라인하며,\r\n * 트랜스코딩 실패 시 원본 바이트+원본 MIME 으로 폴백한다.\r\n */\r\nexport function inlineImagesIntoMarkdown(\r\n markdown: string,\r\n images: ReadonlyArray<InlineImage>,\r\n opts?: { compress?: boolean },\r\n): string {\r\n const compress = opts?.compress !== false\r\n // 파일명 → data URI 사전 구축 후 단일 패스 치환 — 이미지 k개마다 전문 재스캔하던\r\n // O(k²) 제거. 맵에 없는 파일명 참조는 원문 그대로 둔다 (기존 계약 동일).\r\n const uris = new Map<string, string>()\r\n for (const img of images) {\r\n let bytes = img.data\r\n let mime = img.mimeType\r\n if (compress && mime === \"image/bmp\") {\r\n const png = bmpToPng(img.data)\r\n if (png) {\r\n bytes = png\r\n mime = \"image/png\"\r\n }\r\n }\r\n uris.set(img.filename, `data:${mime};base64,${Buffer.from(bytes).toString(\"base64\")}`)\r\n }\r\n if (uris.size === 0) return markdown\r\n // FILENAME 과 images/FILENAME 접두사를 모두 정확한 파일명 기준으로 치환\r\n let out = markdown.replace(/!\\[image\\]\\((?:images\\/)?([^()\\s]+)\\)/g, (m, name: string) => {\r\n const uri = uris.get(name)\r\n return uri !== undefined ? `![image](${uri})` : m\r\n })\r\n out = out.replace(/(<img\\b[^>]*\\bsrc=\")(?:images\\/)?([^\"]*)(\")/g, (m, pre: string, name: string, post: string) => {\r\n const uri = uris.get(name)\r\n return uri !== undefined ? `${pre}${uri}${post}` : m\r\n })\r\n return out\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ocr/ruling-lines.ts","../src/ocr/engine.ts","../src/ocr/pdf-ocr.ts"],"sourcesContent":["/**\r\n * 래스터 괘선 감지 — 스캔/이미지 페이지의 픽셀에서 표 괘선(수평/수직 선)을\r\n * 찾아 선 기반 표 파이프라인(line-detector → table-grid)에 공급한다.\r\n *\r\n * PDF 그래픽 ops 가 없는 OCR 경로는 종전에 클러스터 감지기만 탔는데,\r\n * 병합 라벨 셀 + 다중줄 서술형 서식(정부 제출 서식류)은 라인 클러스터로\r\n * 행 경계를 잡을 수 없다. 괘선은 이미지에 실존하므로 이진화 + 런렝스로\r\n * 직접 감지한다 — ML 없음, 축 정렬 전제(스캔 스큐 보정은 스코프 밖).\r\n *\r\n * 오탐 방어 3겹 (실측: 우수사례 제출 서식 스캔 — 진짜 괘선은 길고 얇음):\r\n * - 최소 길이 20pt: 글리프 획(가로 ≤한 글자폭·세로 ≤글자높이)은 걸러짐\r\n * - 두께 상한 2.5pt: 굵은 제목 획(6~13px)·텍스트 줄 밴드·채운 색상바 탈락\r\n * - 양측 잉크 포위 제외: 색상바(붙임 박스 등) 안 흰 글자 틈새 슬리버 탈락\r\n */\r\n\r\nimport type { LineSegment } from \"../pdf/line-types.js\"\r\n\r\n/** 잉크 판정 휘도 상한 — 셀 배경 음영(회색 ~220)은 통과, 실선(진회~검정·남색)만 잉크 */\r\nconst INK_LUMA_MAX = 190\r\n/** 최소 선 길이 (pt) — 최소 셀 변(≈7mm)과 대형 글리프 획(≤1em) 사이 */\r\nconst MIN_LINE_LENGTH_PT = 20\r\n/** 선 두께 상한 (pt) — 진짜 괘선(0.12~0.7mm ≈ 0.3~2pt)과 굵은 글리프 획(2pt+) 분리 */\r\nconst MAX_LINE_WIDTH_PT = 2.5\r\n/** 런 내 허용 끊김 (px) — 스캔 노이즈/JPEG 아티팩트 */\r\nconst GAP_TOL_PX = 2\r\n/** 밴드 병합 시 요구하는 x(또는 y) 범위 겹침 비율 (짧은 쪽 기준) */\r\nconst BAND_OVERLAP_RATIO = 0.5\r\n/** 밴드 양측(±2px)이 이 비율 이상 잉크면 채운 영역 내부 슬리버로 판정 */\r\nconst SURROUND_INK_RATIO = 0.35\r\n\r\n/** 픽셀 공간(top-left origin) 선분 — 두께는 밴드 픽셀 수 */\r\nexport interface PxSegment {\r\n x1: number; y1: number\r\n x2: number; y2: number\r\n thicknessPx: number\r\n}\r\n\r\nexport interface RulingLines {\r\n horizontals: PxSegment[]\r\n verticals: PxSegment[]\r\n}\r\n\r\n/**\r\n * RGBA 래스터에서 수평/수직 괘선 감지.\r\n * @param scale 렌더 스케일 (px/pt) — 길이·두께 임계를 pt 기준으로 환산\r\n */\r\nexport function detectRulingLines(\r\n rgba: Uint8Array,\r\n width: number,\r\n height: number,\r\n scale: number,\r\n): RulingLines {\r\n const minLenPx = Math.round(MIN_LINE_LENGTH_PT * scale)\r\n const maxThickPx = Math.max(1, Math.floor(MAX_LINE_WIDTH_PT * scale))\r\n\r\n // 잉크 마스크 1회 구축 — 수평/수직 두 패스가 공유\r\n const ink = new Uint8Array(width * height)\r\n for (let p = 0, i = 0; p < ink.length; p++, i += 4) {\r\n // ITU-R BT.601 휘도 근사 (정수 시프트)\r\n const luma = (rgba[i] * 77 + rgba[i + 1] * 150 + rgba[i + 2] * 29) >> 8\r\n if (luma <= INK_LUMA_MAX && rgba[i + 3] >= 128) ink[p] = 1\r\n }\r\n\r\n const horizontals = detectBands(ink, width, height, minLenPx, maxThickPx, false)\r\n const verticals = detectBands(ink, width, height, minLenPx, maxThickPx, true)\r\n return { horizontals, verticals }\r\n}\r\n\r\n/** 열린 밴드 — 인접 스캔라인의 런을 누적 */\r\ninterface Band {\r\n lo: number // 런 진행축 시작 (h: x1, v: y1)\r\n hi: number // 런 진행축 끝\r\n first: number // 직교축 시작 스캔라인 (h: yTop, v: xLeft)\r\n last: number // 직교축 마지막 스캔라인\r\n}\r\n\r\n/**\r\n * 스캔라인 런렝스 → 인접 라인 밴드 병합 → 두께 필터 → 선분 방출.\r\n * transpose=false 면 수평선(행 스캔), true 면 수직선(열 스캔).\r\n */\r\nfunction detectBands(\r\n ink: Uint8Array,\r\n width: number,\r\n height: number,\r\n minLenPx: number,\r\n maxThickPx: number,\r\n transpose: boolean,\r\n): PxSegment[] {\r\n const lines = transpose ? width : height // 스캔라인 개수 (직교축)\r\n const span = transpose ? height : width // 런 진행축 길이\r\n const at = transpose\r\n ? (line: number, pos: number) => ink[pos * width + line]\r\n : (line: number, pos: number) => ink[line * width + pos]\r\n\r\n const out: PxSegment[] = []\r\n let open: Band[] = []\r\n\r\n /** 밴드 양측(±2px 스캔라인)의 잉크 비율 — 채운 색상바 안 흰 글자 틈새 슬리버 판별 */\r\n const surroundInkRatio = (b: Band, side: number): number => {\r\n if (side < 0 || side >= lines) return 0\r\n let dark = 0, total = 0\r\n for (let pos = b.lo; pos <= b.hi; pos += 3) {\r\n total++\r\n if (at(side, pos) === 1) dark++\r\n }\r\n return total > 0 ? dark / total : 0\r\n }\r\n\r\n const emit = (b: Band) => {\r\n const thick = b.last - b.first + 1\r\n if (thick > maxThickPx) return // 색상바·텍스트 밴드\r\n if (\r\n surroundInkRatio(b, b.first - 2) >= SURROUND_INK_RATIO &&\r\n surroundInkRatio(b, b.last + 2) >= SURROUND_INK_RATIO\r\n ) return // 채운 영역 내부 슬리버\r\n const center = (b.first + b.last) / 2\r\n out.push(\r\n transpose\r\n ? { x1: center, y1: b.lo, x2: center, y2: b.hi, thicknessPx: thick }\r\n : { x1: b.lo, y1: center, x2: b.hi, y2: center, thicknessPx: thick },\r\n )\r\n }\r\n\r\n for (let line = 0; line < lines; line++) {\r\n // 1) 이 스캔라인의 잉크 런 수집 (GAP_TOL_PX 이하 끊김 허용)\r\n const runs: Array<{ lo: number; hi: number }> = []\r\n let runStart = -1\r\n let gap = 0\r\n for (let pos = 0; pos <= span; pos++) {\r\n const on = pos < span && at(line, pos) === 1\r\n if (on) {\r\n if (runStart < 0) runStart = pos\r\n gap = 0\r\n } else if (runStart >= 0) {\r\n if (++gap > GAP_TOL_PX || pos >= span) {\r\n const hi = pos - gap\r\n if (hi - runStart + 1 >= minLenPx) runs.push({ lo: runStart, hi })\r\n runStart = -1\r\n gap = 0\r\n }\r\n }\r\n }\r\n\r\n // 2) 열린 밴드와 병합 — 직전 스캔라인까지 이어졌고 범위가 겹치면 확장\r\n const next: Band[] = []\r\n const used = new Set<number>()\r\n for (const band of open) {\r\n if (band.last !== line - 1) { emit(band); continue } // 연속 끊김 → 확정\r\n let merged = false\r\n for (let r = 0; r < runs.length; r++) {\r\n if (used.has(r)) continue\r\n const run = runs[r]\r\n const overlap = Math.min(band.hi, run.hi) - Math.max(band.lo, run.lo) + 1\r\n const shorter = Math.min(band.hi - band.lo, run.hi - run.lo) + 1\r\n if (overlap >= shorter * BAND_OVERLAP_RATIO) {\r\n band.lo = Math.min(band.lo, run.lo)\r\n band.hi = Math.max(band.hi, run.hi)\r\n band.last = line\r\n next.push(band)\r\n used.add(r)\r\n merged = true\r\n break\r\n }\r\n }\r\n if (!merged) emit(band)\r\n }\r\n for (let r = 0; r < runs.length; r++) {\r\n if (!used.has(r)) next.push({ lo: runs[r].lo, hi: runs[r].hi, first: line, last: line })\r\n }\r\n open = next\r\n }\r\n for (const band of open) emit(band)\r\n return out\r\n}\r\n\r\n/**\r\n * 픽셀 선분 → PDF pt LineSegment (bottom-up, classifyAndAdd 규약:\r\n * 수평선 y1==y2·x1<x2, 수직선 x1==x2·y1<y2).\r\n */\r\nexport function rulingToPdfLines(\r\n ruling: RulingLines,\r\n scale: number,\r\n pdfHeight: number,\r\n): { horizontals: LineSegment[]; verticals: LineSegment[] } {\r\n const horizontals: LineSegment[] = ruling.horizontals.map(s => {\r\n const y = pdfHeight - (s.y1 + s.y2) / 2 / scale\r\n return {\r\n x1: Math.min(s.x1, s.x2) / scale,\r\n y1: y,\r\n x2: Math.max(s.x1, s.x2) / scale,\r\n y2: y,\r\n lineWidth: s.thicknessPx / scale,\r\n }\r\n })\r\n const verticals: LineSegment[] = ruling.verticals.map(s => {\r\n const x = (s.x1 + s.x2) / 2 / scale\r\n const yA = pdfHeight - Math.max(s.y1, s.y2) / scale\r\n const yB = pdfHeight - Math.min(s.y1, s.y2) / scale\r\n return { x1: x, y1: yA, x2: x, y2: yB, lineWidth: s.thicknessPx / scale }\r\n })\r\n return { horizontals, verticals }\r\n}\r\n","/**\r\n * 내장 텍스트 OCR 엔진 — PP-OCRv5 korean (det DBNet + rec SVTR/CTC) ONNX 추론.\r\n *\r\n * 파이프라인: 페이지 RGBA → det(선 검출) → 라인 crop → rec(CTC 인식) → OcrItem[]\r\n * (좌표는 입력 픽셀 기준 top-left origin — 호출자가 PDF 좌표계로 변환).\r\n *\r\n * 전·후처리는 공식 inference.yml 스펙 그대로:\r\n * - det: BGR, 긴 변 960 리사이즈(32 배수), mean/std [0.485,0.456,0.406]/[0.229,0.224,0.225],\r\n * DBPostProcess thresh 0.3 / box_thresh 0.6 / unclip_ratio 1.5\r\n * - rec: BGR, 높이 48 고정 비율 리사이즈 + 우측 zero-pad, (x/255-0.5)/0.5,\r\n * CTC 디코드 (blank=0, 1..N=사전, N+1=공백), text_score 0.5\r\n * DB 후처리의 contour+minAreaRect 는 축정렬 connected-component bbox 로 근사\r\n * (공문서 스캔은 수평 텍스트가 지배적 — 회전 텍스트는 v1 범위 밖).\r\n *\r\n * 의존성(onnxruntime-node, sharp)은 optional — 미설치 시 create()가 명확한 에러.\r\n * 모델 미다운로드 시에도 즉시 실패 — 호출자가 ensureOcrModels() 먼저.\r\n */\r\n\r\nimport type { InferenceSession } from \"onnxruntime-node\"\r\nimport { readFile } from \"fs/promises\"\r\nimport { join } from \"path\"\r\nimport {\r\n OCR_DET_MODEL,\r\n OCR_REC_MODEL,\r\n OCR_REC_DICT,\r\n getOcrModelsDir,\r\n parseCharacterDict,\r\n} from \"./models.js\"\r\n\r\n/** OCR 인식 결과 한 줄 — 좌표는 입력 이미지 픽셀 (top-left origin, y down) */\r\nexport interface OcrItem {\r\n text: string\r\n x: number\r\n y: number\r\n w: number\r\n h: number\r\n /** CTC 평균 신뢰도 0~1 */\r\n confidence: number\r\n}\r\n\r\n/** det 입력 긴 변 (공식 resize_long) */\r\nconst DET_LONG_SIDE = 960\r\nconst DET_THRESH = 0.3\r\nconst DET_BOX_THRESH = 0.6\r\nconst DET_UNCLIP_RATIO = 1.5\r\nconst DET_MIN_SIZE = 3\r\nconst DET_MAX_BOXES = 1000\r\nconst REC_HEIGHT = 48\r\nconst REC_MIN_WIDTH = 320\r\nconst REC_MAX_WIDTH = 3200\r\nconst TEXT_SCORE = 0.5\r\n\r\n// det: BGR 채널 순서에 yml 기재 순서 그대로 적용 (mean[0]→B)\r\nconst DET_MEAN = [0.485, 0.456, 0.406]\r\nconst DET_STD = [0.229, 0.224, 0.225]\r\n\r\ntype SharpFactory = (\r\n input: Uint8Array | Buffer,\r\n options?: { raw?: { width: number; height: number; channels: number } },\r\n) => SharpChain\r\ninterface SharpChain {\r\n extract(region: { left: number; top: number; width: number; height: number }): SharpChain\r\n resize(w: number, h: number, opts?: { fit?: string }): SharpChain\r\n removeAlpha(): SharpChain\r\n raw(): { toBuffer(): Promise<Buffer> }\r\n}\r\n\r\nexport class OcrEngine {\r\n private det: InferenceSession\r\n private rec: InferenceSession\r\n private dict: string[]\r\n private ort: typeof import(\"onnxruntime-node\")\r\n private sharp: SharpFactory\r\n\r\n private constructor(parts: {\r\n det: InferenceSession\r\n rec: InferenceSession\r\n dict: string[]\r\n ort: typeof import(\"onnxruntime-node\")\r\n sharp: SharpFactory\r\n }) {\r\n this.det = parts.det\r\n this.rec = parts.rec\r\n this.dict = parts.dict\r\n this.ort = parts.ort\r\n this.sharp = parts.sharp\r\n }\r\n\r\n static async create(): Promise<OcrEngine> {\r\n const [ortMod, sharpModRaw] = await Promise.all([\r\n tryImport<typeof import(\"onnxruntime-node\")>(\"onnxruntime-node\", () => import(\"onnxruntime-node\")),\r\n tryImport<{ default?: SharpFactory } & SharpFactory>(\r\n \"sharp\",\r\n () => import(\"sharp\") as unknown as Promise<{ default?: SharpFactory } & SharpFactory>,\r\n ),\r\n ])\r\n const sharpAny = sharpModRaw as { default?: SharpFactory } | SharpFactory\r\n const sharpMod: SharpFactory =\r\n typeof sharpAny === \"function\" ? sharpAny : (sharpAny.default ?? (sharpAny as unknown as SharpFactory))\r\n\r\n const dir = getOcrModelsDir()\r\n const sessionOpts: import(\"onnxruntime-node\").InferenceSession.SessionOptions = {\r\n graphOptimizationLevel: \"all\",\r\n executionProviders: [\"cpu\"],\r\n logSeverityLevel: 3, // paddle2onnx 변환 잔여물 W 로그 폭주 억제\r\n }\r\n const [det, rec, dictYml] = await Promise.all([\r\n ortMod.InferenceSession.create(join(dir, OCR_DET_MODEL.filename), sessionOpts),\r\n ortMod.InferenceSession.create(join(dir, OCR_REC_MODEL.filename), sessionOpts),\r\n readFile(join(dir, OCR_REC_DICT.filename), \"utf-8\"),\r\n ])\r\n const dict = parseCharacterDict(dictYml)\r\n if (dict.length === 0) throw new Error(\"OCR 사전 파싱 실패 — 모델 캐시를 삭제 후 재다운로드하세요\")\r\n\r\n return new OcrEngine({ det, rec, dict, ort: ortMod, sharp: sharpMod })\r\n }\r\n\r\n /** onnxruntime-node 1.14+ InferenceSession.release() — 구버전은 무시 */\r\n async destroy(): Promise<void> {\r\n for (const s of [this.det, this.rec]) {\r\n const rel = (s as unknown as { release?: () => Promise<void> }).release\r\n if (typeof rel === \"function\") {\r\n try { await rel.call(s) } catch { /* ignore */ }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 페이지 RGBA 픽셀 → 텍스트 라인 인식.\r\n * 반환 좌표는 입력 픽셀 기준. 라인은 위→아래, 좌→우 정렬.\r\n */\r\n async recognizePage(rgba: Uint8Array, width: number, height: number): Promise<OcrItem[]> {\r\n if (width < DET_MIN_SIZE || height < DET_MIN_SIZE) return []\r\n const boxes = await this.detect(rgba, width, height)\r\n const items: OcrItem[] = []\r\n for (const b of boxes) {\r\n const r = await this.recognizeLine(rgba, width, height, b)\r\n if (r && r.confidence >= TEXT_SCORE && r.text.trim()) items.push(r)\r\n }\r\n items.sort((a, b) => (a.y - b.y) || (a.x - b.x))\r\n return items\r\n }\r\n\r\n // ─── det ─────────────────────────────────────────────\r\n\r\n private async detect(\r\n rgba: Uint8Array,\r\n width: number,\r\n height: number,\r\n ): Promise<Array<{ x: number; y: number; w: number; h: number }>> {\r\n const ratio = DET_LONG_SIDE / Math.max(width, height)\r\n const dw = Math.max(32, Math.round((width * ratio) / 32) * 32)\r\n const dh = Math.max(32, Math.round((height * ratio) / 32) * 32)\r\n\r\n const rgb = await this.sharp(rgba, { raw: { width, height, channels: 4 } })\r\n .resize(dw, dh, { fit: \"fill\" })\r\n .removeAlpha()\r\n .raw()\r\n .toBuffer()\r\n\r\n // HWC RGB → CHW BGR float32 정규화\r\n const plane = dw * dh\r\n const input = new Float32Array(3 * plane)\r\n for (let i = 0; i < plane; i++) {\r\n const r = rgb[i * 3] / 255\r\n const g = rgb[i * 3 + 1] / 255\r\n const b = rgb[i * 3 + 2] / 255\r\n input[i] = (b - DET_MEAN[0]) / DET_STD[0]\r\n input[plane + i] = (g - DET_MEAN[1]) / DET_STD[1]\r\n input[2 * plane + i] = (r - DET_MEAN[2]) / DET_STD[2]\r\n }\r\n\r\n const tensor = new this.ort.Tensor(\"float32\", input, [1, 3, dh, dw])\r\n const out = await this.det.run({ [this.det.inputNames[0]]: tensor })\r\n const probMap = out[this.det.outputNames[0]].data as Float32Array\r\n\r\n const rawBoxes = componentBoxes(probMap, dw, dh)\r\n const sx = width / dw\r\n const sy = height / dh\r\n const boxes: Array<{ x: number; y: number; w: number; h: number }> = []\r\n for (const rb of rawBoxes.slice(0, DET_MAX_BOXES)) {\r\n // unclip: DB 는 학습 시 텍스트 영역을 수축시키므로 검출 박스를 되팽창\r\n const bw = rb.x2 - rb.x1 + 1\r\n const bh = rb.y2 - rb.y1 + 1\r\n const delta = (bw * bh * DET_UNCLIP_RATIO) / (2 * (bw + bh))\r\n const x1 = Math.max(0, Math.floor((rb.x1 - delta) * sx))\r\n const y1 = Math.max(0, Math.floor((rb.y1 - delta) * sy))\r\n const x2 = Math.min(width, Math.ceil((rb.x2 + 1 + delta) * sx))\r\n const y2 = Math.min(height, Math.ceil((rb.y2 + 1 + delta) * sy))\r\n if (x2 - x1 < DET_MIN_SIZE || y2 - y1 < DET_MIN_SIZE) continue\r\n boxes.push({ x: x1, y: y1, w: x2 - x1, h: y2 - y1 })\r\n }\r\n return boxes\r\n }\r\n\r\n // ─── rec ─────────────────────────────────────────────\r\n\r\n private async recognizeLine(\r\n rgba: Uint8Array,\r\n width: number,\r\n height: number,\r\n box: { x: number; y: number; w: number; h: number },\r\n ): Promise<OcrItem | null> {\r\n const rw = Math.min(REC_MAX_WIDTH, Math.max(16, Math.round((box.w * REC_HEIGHT) / box.h)))\r\n const padded = Math.max(REC_MIN_WIDTH, rw)\r\n\r\n const rgb = await this.sharp(rgba, { raw: { width, height, channels: 4 } })\r\n .extract({ left: box.x, top: box.y, width: box.w, height: box.h })\r\n .resize(rw, REC_HEIGHT, { fit: \"fill\" })\r\n .removeAlpha()\r\n .raw()\r\n .toBuffer()\r\n\r\n // HWC RGB → CHW BGR, (x/255-0.5)/0.5, 우측 zero-pad\r\n const plane = padded * REC_HEIGHT\r\n const input = new Float32Array(3 * plane) // pad 영역은 0 (=정규화 후 회색 아님 주의: PP 도 0 pad)\r\n for (let y = 0; y < REC_HEIGHT; y++) {\r\n for (let x = 0; x < rw; x++) {\r\n const src = (y * rw + x) * 3\r\n const dst = y * padded + x\r\n input[dst] = rgb[src + 2] / 255 / 0.5 - 1 // B\r\n input[plane + dst] = rgb[src + 1] / 255 / 0.5 - 1 // G\r\n input[2 * plane + dst] = rgb[src] / 255 / 0.5 - 1 // R\r\n }\r\n }\r\n\r\n const tensor = new this.ort.Tensor(\"float32\", input, [1, 3, REC_HEIGHT, padded])\r\n const out = await this.rec.run({ [this.rec.inputNames[0]]: tensor })\r\n const logits = out[this.rec.outputNames[0]]\r\n const [, T, C] = logits.dims as number[]\r\n const data = logits.data as Float32Array\r\n\r\n const decoded = ctcDecode(data, T, C, this.dict)\r\n if (!decoded) return null\r\n return { text: decoded.text, x: box.x, y: box.y, w: box.w, h: box.h, confidence: decoded.confidence }\r\n }\r\n}\r\n\r\n/** CTC greedy 디코드 — 연속 중복 붕괴 → blank(0) 제거 → 사전 매핑 (테스트용 export) */\r\nexport function ctcDecode(\r\n data: Float32Array,\r\n T: number,\r\n C: number,\r\n dict: string[],\r\n): { text: string; confidence: number } | null {\r\n let text = \"\"\r\n let confSum = 0\r\n let confCount = 0\r\n let prev = -1\r\n for (let t = 0; t < T; t++) {\r\n const off = t * C\r\n let best = 0\r\n let bestV = data[off]\r\n for (let c = 1; c < C; c++) {\r\n const v = data[off + c]\r\n if (v > bestV) { bestV = v; best = c }\r\n }\r\n const repeat = best === prev\r\n prev = best\r\n if (best === 0 || repeat) continue\r\n // 모델 출력이 softmax 확률이 아니면 (>1) 해당 스텝만 정규화\r\n let p = bestV\r\n if (p > 1.0001 || p < 0) {\r\n let denom = 0\r\n for (let c = 0; c < C; c++) denom += Math.exp(data[off + c] - bestV)\r\n p = 1 / denom\r\n }\r\n confSum += p\r\n confCount++\r\n if (best >= 1 && best <= dict.length) text += dict[best - 1]\r\n else if (best === dict.length + 1) text += \" \"\r\n }\r\n if (!text) return null\r\n return { text, confidence: confCount > 0 ? confSum / confCount : 0 }\r\n}\r\n\r\n/** 이진화 확률맵의 4-연결 성분 bbox (score = 성분 평균 확률, 테스트용 export) */\r\nexport function componentBoxes(\r\n prob: Float32Array,\r\n w: number,\r\n h: number,\r\n): Array<{ x1: number; y1: number; x2: number; y2: number }> {\r\n const visited = new Uint8Array(w * h)\r\n const boxes: Array<{ x1: number; y1: number; x2: number; y2: number; score: number }> = []\r\n const stack: number[] = []\r\n\r\n for (let start = 0; start < w * h; start++) {\r\n if (visited[start] || prob[start] <= DET_THRESH) continue\r\n let x1 = start % w, x2 = x1, y1 = (start / w) | 0, y2 = y1\r\n let sum = 0\r\n let count = 0\r\n stack.length = 0\r\n stack.push(start)\r\n visited[start] = 1\r\n while (stack.length) {\r\n const p = stack.pop()!\r\n const px = p % w\r\n const py = (p / w) | 0\r\n sum += prob[p]\r\n count++\r\n if (px < x1) x1 = px\r\n if (px > x2) x2 = px\r\n if (py < y1) y1 = py\r\n if (py > y2) y2 = py\r\n // 4-이웃\r\n if (px > 0 && !visited[p - 1] && prob[p - 1] > DET_THRESH) { visited[p - 1] = 1; stack.push(p - 1) }\r\n if (px < w - 1 && !visited[p + 1] && prob[p + 1] > DET_THRESH) { visited[p + 1] = 1; stack.push(p + 1) }\r\n if (py > 0 && !visited[p - w] && prob[p - w] > DET_THRESH) { visited[p - w] = 1; stack.push(p - w) }\r\n if (py < h - 1 && !visited[p + w] && prob[p + w] > DET_THRESH) { visited[p + w] = 1; stack.push(p + w) }\r\n }\r\n if (x2 - x1 + 1 < DET_MIN_SIZE && y2 - y1 + 1 < DET_MIN_SIZE) continue\r\n boxes.push({ x1, y1, x2, y2, score: sum / count })\r\n }\r\n\r\n return boxes\r\n .filter(b => b.score >= DET_BOX_THRESH)\r\n .sort((a, b) => (a.y1 - b.y1) || (a.x1 - b.x1))\r\n}\r\n\r\nasync function tryImport<T>(name: string, loader: () => Promise<T>): Promise<T> {\r\n try {\r\n return await loader()\r\n } catch (e) {\r\n throw new Error(\r\n `내장 OCR 을 사용하려면 optional dependency '${name}' 이 필요합니다. ` +\r\n `\\`npm install ${name}\\` 후 다시 실행하세요. 원인: ${(e as Error).message}`,\r\n )\r\n }\r\n}\r\n\r\n// ─── 엔진 싱글턴 (watch/서버 장기 실행에서 세션 재사용) ───\r\nlet enginePromise: Promise<OcrEngine> | null = null\r\n\r\nexport function getOcrEngine(): Promise<OcrEngine> {\r\n if (!enginePromise) {\r\n enginePromise = OcrEngine.create().catch(err => {\r\n enginePromise = null // 실패는 캐시하지 않음 — 모델 설치 후 재시도 가능\r\n throw err\r\n })\r\n }\r\n return enginePromise\r\n}\r\n","/**\r\n * PDF OCR 브릿지 — 대상 페이지를 pdfium 으로 래스터해 내장 엔진 또는\r\n * 사용자 OcrProvider 로 인식하고, 페이지별 IRBlock[] 을 돌려준다.\r\n *\r\n * - 내장 엔진: OcrItem 좌표를 PDF 포인트로 환산해 기존 블록 파이프라인\r\n * (extractPageBlocksWithLines — xy-cut 읽기순서·클러스터 표 감지)에 태운다.\r\n * 스캔 문서도 표 구조 복원이 가능한 이유.\r\n * - 사용자 프로바이더: 페이지 PNG → 텍스트 → 페이지당 paragraph 블록 (종전 계약).\r\n *\r\n * 에러 계약 (v4.1.0 리뷰 F6/F7):\r\n * - 환경 오류(의존성·모델 미설치, PDF 오픈 실패)는 throw — 호출자가 NEEDS_OCR 폴백.\r\n * - 페이지 단위 실패는 본문 오염 대신 warnings(OCR_FAILED) 로 기록하고 계속.\r\n */\r\n\r\nimport type { IRBlock, OcrProvider, ParseWarning } from \"../types.js\"\r\nimport type { NormItem } from \"../pdf/text-line.js\"\r\nimport type { LineSegment } from \"../pdf/line-types.js\"\r\nimport { extractPageBlocksWithLines } from \"../pdf/page-blocks.js\"\r\nimport { detectRulingLines, rulingToPdfLines } from \"./ruling-lines.js\"\r\nimport { getOcrEngine, type OcrItem } from \"./engine.js\"\r\nimport { ensureOcrModels } from \"./models.js\"\r\n\r\n/** OCR 렌더 스케일 (72dpi × 3 = 216dpi) — 10pt 본문이 rec 입력 높이(48px)에 근접 */\r\nconst OCR_RENDER_SCALE = 3\r\n/** 페이지 하나당 OCR 타임아웃 — det+rec 수십 라인 기준 넉넉히 */\r\nconst PAGE_TIMEOUT_MS = 120_000\r\n\r\nexport type OcrMode = \"builtin\" | OcrProvider\r\n\r\n/**\r\n * 대상 페이지들을 OCR 해 페이지별 블록 맵 반환.\r\n * @param buffer 원본 PDF (pdfjs 가 detach 하기 전에 clone 해 둔 것)\r\n * @param targets 1-based 페이지 번호 집합\r\n */\r\nexport async function runPdfOcr(\r\n buffer: ArrayBuffer,\r\n targets: Set<number>,\r\n mode: OcrMode,\r\n warnings: ParseWarning[],\r\n onProgress?: (current: number, total: number) => void,\r\n): Promise<Map<number, IRBlock[]>> {\r\n const result = new Map<number, IRBlock[]>()\r\n if (targets.size === 0) return result\r\n\r\n // 환경 준비 — 실패는 그대로 throw (호출자가 NEEDS_OCR 폴백)\r\n const pdfiumMod = await tryImport<typeof import(\"@hyzyla/pdfium\")>(\r\n \"@hyzyla/pdfium\",\r\n () => import(\"@hyzyla/pdfium\"),\r\n )\r\n if (mode === \"builtin\") {\r\n await ensureOcrModels(p => {\r\n if (p.phase === \"download\" && p.downloaded === 0) {\r\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 다운로드 중 (~${p.spec.sizeMb}MB)...\\n`)\r\n }\r\n })\r\n }\r\n const engine = mode === \"builtin\" ? await getOcrEngine() : null\r\n\r\n const pdfium = await pdfiumMod.PDFiumLibrary.init()\r\n const doc = await pdfium.loadDocument(new Uint8Array(buffer))\r\n try {\r\n let done = 0\r\n for (const page of doc.pages()) {\r\n // pdfium page.number 는 0-based pageIndex — 대외 계약(1-based)으로 환산\r\n const pageNo = page.number + 1\r\n if (!targets.has(pageNo)) continue\r\n onProgress?.(++done, targets.size)\r\n try {\r\n const blocks = await withTimeout(\r\n ocrOnePage(page, pageNo, mode, engine, warnings),\r\n PAGE_TIMEOUT_MS,\r\n `OCR 페이지 ${pageNo} 타임아웃 (${PAGE_TIMEOUT_MS / 1000}초)`,\r\n )\r\n result.set(pageNo, blocks)\r\n } catch (e) {\r\n warnings.push({\r\n page: pageNo,\r\n message: `페이지 ${pageNo} OCR 실패: ${e instanceof Error ? e.message : String(e)}`,\r\n code: \"OCR_FAILED\",\r\n })\r\n }\r\n }\r\n } finally {\r\n doc.destroy()\r\n pdfium.destroy()\r\n }\r\n return result\r\n}\r\n\r\nasync function ocrOnePage(\r\n page: import(\"@hyzyla/pdfium\").PDFiumPage,\r\n pageNo: number,\r\n mode: OcrMode,\r\n engine: Awaited<ReturnType<typeof getOcrEngine>> | null,\r\n warnings: ParseWarning[],\r\n): Promise<IRBlock[]> {\r\n const { originalWidth: pdfW, originalHeight: pdfH } = page.getOriginalSize()\r\n const rendered = await page.render({\r\n scale: OCR_RENDER_SCALE,\r\n render: async ({ data }) => data,\r\n })\r\n const { data: bgra, width: rw, height: rh } = rendered\r\n const rgba = bgraToRgba(bgra)\r\n\r\n if (mode === \"builtin\") {\r\n const items = await engine!.recognizePage(rgba, rw, rh)\r\n // 래스터에서 표 괘선 감지 — 스캔본 병합셀 서식도 선 기반 표 파이프라인을 탄다\r\n const scale = rh / pdfH\r\n const ruling = detectRulingLines(rgba, rw, rh, scale)\r\n const extraLines = rulingToPdfLines(ruling, scale, pdfH)\r\n return ocrItemsToBlocks(items, pageNo, pdfW, pdfH, scale, extraLines)\r\n }\r\n\r\n // 사용자 프로바이더 — PNG 인코딩 후 호출, 페이지당 paragraph (종전 계약)\r\n type SharpPngFactory = (\r\n input: Uint8Array,\r\n opts: { raw: { width: number; height: number; channels: number } },\r\n ) => { png(): { toBuffer(): Promise<Buffer> } }\r\n const sharpModRaw = await tryImport<{ default?: SharpPngFactory } & SharpPngFactory>(\r\n \"sharp\",\r\n () => import(\"sharp\") as unknown as Promise<{ default?: SharpPngFactory } & SharpPngFactory>,\r\n )\r\n const sharpAny = sharpModRaw as { default?: SharpPngFactory } | SharpPngFactory\r\n const sharp: SharpPngFactory =\r\n typeof sharpAny === \"function\" ? sharpAny : (sharpAny.default ?? (sharpAny as unknown as SharpPngFactory))\r\n const png = await sharp(rgba, { raw: { width: rw, height: rh, channels: 4 } })\r\n .png()\r\n .toBuffer()\r\n\r\n const text = await mode(new Uint8Array(png), pageNo, \"image/png\")\r\n if (!text.trim()) {\r\n warnings.push({ page: pageNo, message: `페이지 ${pageNo} OCR 결과 없음`, code: \"OCR_FAILED\" })\r\n return []\r\n }\r\n return [{ type: \"paragraph\", text: text.trim(), pageNumber: pageNo }]\r\n}\r\n\r\n/**\r\n * OcrItem(렌더 픽셀, top-left origin) → NormItem(PDF pt, bottom-up baseline)\r\n * 으로 환산해 기존 블록 파이프라인에 태운다. 괘선은 그래픽 ops 대신\r\n * 래스터 감지 결과(extraLines)로 공급 — 없으면 클러스터 감지기 몫이다.\r\n * (이미지 직접 입력 경로 image-ocr.ts 와 공유)\r\n */\r\nexport function ocrItemsToBlocks(\r\n items: OcrItem[],\r\n pageNumber: number,\r\n pdfW: number,\r\n pdfH: number,\r\n scale: number,\r\n extraLines?: { horizontals: LineSegment[]; verticals: LineSegment[] },\r\n): IRBlock[] {\r\n const norm: NormItem[] = items.map(it => {\r\n const h = it.h / scale\r\n return {\r\n text: it.text,\r\n x: Math.round(it.x / scale),\r\n // NormItem.y 는 pdfjs transform[5] = 베이스라인 (bottom-up) — 박스 하단으로 근사\r\n y: Math.round(pdfH - (it.y + it.h) / scale),\r\n w: Math.round(it.w / scale),\r\n h: Math.round(h),\r\n fontSize: Math.max(1, Math.round(h * 0.8)), // 박스높이는 어센더+디센더 포함 — 글자크기 근사\r\n fontName: \"ocr\",\r\n isHidden: false,\r\n }\r\n })\r\n return extractPageBlocksWithLines(norm, pageNumber, { fnArray: [], argsArray: [] }, pdfW, pdfH, extraLines)\r\n}\r\n\r\nasync function tryImport<T>(name: string, loader: () => Promise<T>): Promise<T> {\r\n try {\r\n return await loader()\r\n } catch (e) {\r\n throw new Error(\r\n `OCR 을 사용하려면 optional dependency '${name}' 이 필요합니다. ` +\r\n `\\`npm install ${name}\\` 후 다시 실행하세요. 원인: ${(e as Error).message}`,\r\n )\r\n }\r\n}\r\n\r\nasync function withTimeout<T>(promise: Promise<T>, ms: number, msg: string): Promise<T> {\r\n // 타임아웃 패배 후 원 promise 의 사후 reject 가 unhandled rejection 이 되지 않게 흡수\r\n promise.catch(() => {})\r\n let timer: NodeJS.Timeout | undefined\r\n try {\r\n return await Promise.race([\r\n promise,\r\n new Promise<never>((_, reject) => {\r\n timer = setTimeout(() => reject(new Error(msg)), ms)\r\n }),\r\n ])\r\n } finally {\r\n if (timer) clearTimeout(timer)\r\n }\r\n}\r\n\r\n/** pdfium BGRA → RGBA */\r\nfunction bgraToRgba(bgra: Uint8Array): Uint8Array {\r\n const out = new Uint8Array(bgra.length)\r\n for (let i = 0; i < bgra.length; i += 4) {\r\n out[i] = bgra[i + 2]\r\n out[i + 1] = bgra[i + 1]\r\n out[i + 2] = bgra[i]\r\n out[i + 3] = bgra[i + 3]\r\n }\r\n return out\r\n}\r\n"],"mappings":"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","names":["tryImport"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pdf/formula/models.ts"],"sourcesContent":["/**\r\n * 수식 OCR 모델 자동 다운로드 + SHA-256 검증\r\n *\r\n * 캐시 위치: `~/.cache/kordoc/models/pix2text/`\r\n * 총 ~155MB (MFD 44MB + MFR encoder 87MB + MFR decoder 30MB + tokenizer 40KB)\r\n *\r\n * HF URL + SHA 는 Docufinder archive/rust-formula-ocr-wip 에서 검증 완료됨.\r\n * 모델 버전 갱신 시 URL + SHA 를 함께 갱신해야 한다.\r\n */\r\n\r\nimport { createHash } from \"crypto\"\r\nimport { createReadStream } from \"fs\"\r\nimport { mkdir, stat, unlink, rename } from \"fs/promises\"\r\nimport { createWriteStream } from \"fs\"\r\nimport { homedir } from \"os\"\r\nimport { join, dirname } from \"path\"\r\nimport { pipeline } from \"stream/promises\"\r\nimport { Readable } from \"stream\"\r\n\r\nexport interface ModelSpec {\r\n name: string\r\n filename: string\r\n url: string\r\n sha256: string\r\n sizeMb: number\r\n}\r\n\r\n/** 모델 스펙 (SHA-256 은 실제 다운로드로 검증됨 — 변경 금지) */\r\nexport const MFD_MODEL: ModelSpec = {\r\n name: \"Pix2Text MFD\",\r\n filename: \"mfd.onnx\",\r\n url: \"https://huggingface.co/breezedeus/pix2text-mfd/resolve/main/mfd-v20240618.onnx\",\r\n sha256: \"51a8854743b17ae654729af8db82a630c1ccfa06debf4856c8b28055f87d02c1\",\r\n sizeMb: 42,\r\n}\r\n\r\nexport const MFR_ENCODER_MODEL: ModelSpec = {\r\n name: \"Pix2Text MFR encoder\",\r\n filename: \"encoder_model.onnx\",\r\n url: \"https://huggingface.co/breezedeus/pix2text-mfr/resolve/main/encoder_model.onnx\",\r\n sha256: \"bd8d5c322792e9ec45793af5569e9748f82a3d728a9e00213dbfc56c1486f37d\",\r\n sizeMb: 87,\r\n}\r\n\r\nexport const MFR_DECODER_MODEL: ModelSpec = {\r\n name: \"Pix2Text MFR decoder\",\r\n filename: \"decoder_model.onnx\",\r\n url: \"https://huggingface.co/breezedeus/pix2text-mfr/resolve/main/decoder_model.onnx\",\r\n sha256: \"fd0f92d7a012f3dae41e1ac79421aea0ea888b5a66cb3f9a004e424f82f3daed\",\r\n sizeMb: 30,\r\n}\r\n\r\nexport const MFR_TOKENIZER: ModelSpec = {\r\n name: \"Pix2Text MFR tokenizer\",\r\n filename: \"tokenizer.json\",\r\n url: \"https://huggingface.co/breezedeus/pix2text-mfr/resolve/main/tokenizer.json\",\r\n sha256: \"3e2ab757277d22639bec28c9d7972e352d3d1dba223051fa674002dc5ab64df3\",\r\n sizeMb: 1,\r\n}\r\n\r\nexport const ALL_FORMULA_MODELS: ReadonlyArray<ModelSpec> = [\r\n MFD_MODEL,\r\n MFR_ENCODER_MODEL,\r\n MFR_DECODER_MODEL,\r\n MFR_TOKENIZER,\r\n]\r\n\r\n/**\r\n * 모델 캐시 하위 디렉토리 경로. 환경 변수 `KORDOC_MODEL_CACHE` 가 설정되면\r\n * 해당 경로를 우선 사용, 없으면 `~/.cache/kordoc/models/<subdir>/`.\r\n * (수식 OCR 외 텍스트 OCR 등 다른 모델군도 공용 — subdir 로 격리)\r\n */\r\nexport function getModelsDir(subdir: string): string {\r\n const override = process.env.KORDOC_MODEL_CACHE\r\n if (override && override.trim()) {\r\n return join(override, subdir)\r\n }\r\n return join(homedir(), \".cache\", \"kordoc\", \"models\", subdir)\r\n}\r\n\r\nexport function getFormulaModelsDir(): string {\r\n return getModelsDir(\"pix2text\")\r\n}\r\n\r\nexport interface ModelStatus {\r\n spec: ModelSpec\r\n localPath: string\r\n exists: boolean\r\n /** SHA 검증까지 끝났는가 (exists && valid) */\r\n verified: boolean\r\n /** 검증 실패 시 이유 */\r\n invalidReason?: string\r\n}\r\n\r\n/** 지정 모델군의 존재/유효성 상태 반환 (다운로드 없이 확인만) */\r\nexport async function getModelStatusIn(dir: string, specs: ReadonlyArray<ModelSpec>): Promise<ModelStatus[]> {\r\n const result: ModelStatus[] = []\r\n for (const spec of specs) {\r\n const localPath = join(dir, spec.filename)\r\n let exists = false\r\n try {\r\n const s = await stat(localPath)\r\n exists = s.isFile() && s.size > 0\r\n } catch {\r\n exists = false\r\n }\r\n if (!exists) {\r\n result.push({ spec, localPath, exists: false, verified: false })\r\n continue\r\n }\r\n try {\r\n const actual = await sha256OfFile(localPath)\r\n if (actual === spec.sha256) {\r\n result.push({ spec, localPath, exists: true, verified: true })\r\n } else {\r\n result.push({\r\n spec,\r\n localPath,\r\n exists: true,\r\n verified: false,\r\n invalidReason: `SHA256 mismatch: expected ${spec.sha256}, got ${actual}`,\r\n })\r\n }\r\n } catch (e) {\r\n result.push({\r\n spec,\r\n localPath,\r\n exists: true,\r\n verified: false,\r\n invalidReason: `SHA compute failed: ${(e as Error).message}`,\r\n })\r\n }\r\n }\r\n return result\r\n}\r\n\r\n/** 모든 수식 모델의 존재/유효성 상태 반환 (다운로드 없이 확인만) */\r\nexport async function getFormulaModelStatus(): Promise<ModelStatus[]> {\r\n return getModelStatusIn(getFormulaModelsDir(), ALL_FORMULA_MODELS)\r\n}\r\n\r\nexport interface DownloadProgress {\r\n spec: ModelSpec\r\n /** 현재까지 다운로드한 바이트 */\r\n downloaded: number\r\n /** 전체 바이트 (알 수 있으면) */\r\n total: number | null\r\n /** \"download\" | \"verify\" | \"done\" | \"skip\" */\r\n phase: \"download\" | \"verify\" | \"done\" | \"skip\" | \"error\"\r\n message?: string\r\n}\r\n\r\nexport type ProgressHandler = (p: DownloadProgress) => void\r\n\r\n/**\r\n * 지정 모델군을 다운로드/검증한다.\r\n * - 이미 있고 SHA 일치 → skip\r\n * - 없음 → 다운로드 후 SHA 검증. 실패 시 파일 삭제.\r\n */\r\nexport async function ensureModelsIn(dir: string, specs: ReadonlyArray<ModelSpec>, onProgress?: ProgressHandler): Promise<void> {\r\n await mkdir(dir, { recursive: true })\r\n\r\n for (const spec of specs) {\r\n const localPath = join(dir, spec.filename)\r\n\r\n if (await isExistingValid(localPath, spec.sha256)) {\r\n onProgress?.({\r\n spec,\r\n downloaded: 0,\r\n total: null,\r\n phase: \"skip\",\r\n message: \"이미 존재 + SHA 일치\",\r\n })\r\n continue\r\n }\r\n\r\n // 기존 파일 있지만 SHA 불일치 → 삭제\r\n try {\r\n await unlink(localPath)\r\n } catch {\r\n // 없을 수 있음\r\n }\r\n\r\n await downloadToFile(spec, localPath, onProgress)\r\n }\r\n}\r\n\r\n/** 필요한 모든 수식 모델을 다운로드/검증한다. */\r\nexport async function ensureFormulaModels(onProgress?: ProgressHandler): Promise<void> {\r\n return ensureModelsIn(getFormulaModelsDir(), ALL_FORMULA_MODELS, onProgress)\r\n}\r\n\r\n/** 단일 모델만 확인/다운로드 (진단 UI 에서 개별 상태 새로고침용) */\r\nexport async function ensureSingleModel(spec: ModelSpec, onProgress?: ProgressHandler): Promise<void> {\r\n const dir = getFormulaModelsDir()\r\n await mkdir(dir, { recursive: true })\r\n const localPath = join(dir, spec.filename)\r\n if (await isExistingValid(localPath, spec.sha256)) {\r\n onProgress?.({ spec, downloaded: 0, total: null, phase: \"skip\" })\r\n return\r\n }\r\n try {\r\n await unlink(localPath)\r\n } catch {\r\n // 재다운로드 전 손상/잔존 파일 정리 best-effort — 애초에 없으면 실패해도 무방\r\n }\r\n await downloadToFile(spec, localPath, onProgress)\r\n}\r\n\r\nasync function isExistingValid(localPath: string, sha256Expected: string): Promise<boolean> {\r\n try {\r\n const s = await stat(localPath)\r\n if (!s.isFile() || s.size === 0) return false\r\n } catch {\r\n return false\r\n }\r\n try {\r\n const actual = await sha256OfFile(localPath)\r\n return actual === sha256Expected\r\n } catch {\r\n return false\r\n }\r\n}\r\n\r\nasync function downloadToFile(\r\n spec: ModelSpec,\r\n localPath: string,\r\n onProgress?: ProgressHandler,\r\n): Promise<void> {\r\n // 먼저 .part 로 받고 검증 후 rename — 중단된 다운로드가 \"정상 파일\"로 오인되는 걸 방지\r\n const partPath = `${localPath}.part`\r\n await mkdir(dirname(localPath), { recursive: true })\r\n\r\n const resp = await fetch(spec.url, {\r\n headers: {\r\n // HF CDN 은 UA 없으면 가끔 403 을 뱉는다\r\n \"User-Agent\": \"kordoc-formula-ocr/1.0 (+https://github.com/chrisryugj/kordoc)\",\r\n },\r\n })\r\n if (!resp.ok || !resp.body) {\r\n throw new Error(\r\n `${spec.name} 다운로드 실패: HTTP ${resp.status} ${resp.statusText} (${spec.url})`,\r\n )\r\n }\r\n\r\n const lenHeader = resp.headers.get(\"content-length\")\r\n const total = lenHeader ? Number.parseInt(lenHeader, 10) : null\r\n let downloaded = 0\r\n\r\n const ws = createWriteStream(partPath)\r\n try {\r\n const reader = Readable.fromWeb(resp.body as unknown as import(\"stream/web\").ReadableStream)\r\n reader.on(\"data\", (chunk: Buffer | Uint8Array) => {\r\n downloaded += chunk.length\r\n onProgress?.({\r\n spec,\r\n downloaded,\r\n total,\r\n phase: \"download\",\r\n })\r\n })\r\n await pipeline(reader, ws)\r\n } catch (e) {\r\n try {\r\n await unlink(partPath)\r\n } catch {\r\n // .part 임시파일 정리 best-effort — 본 에러(스트리밍 실패)를 가리지 않도록 무시\r\n }\r\n throw new Error(`${spec.name} 스트리밍 실패: ${(e as Error).message}`)\r\n }\r\n\r\n onProgress?.({\r\n spec,\r\n downloaded,\r\n total,\r\n phase: \"verify\",\r\n })\r\n\r\n // SHA 검증\r\n let actual: string\r\n try {\r\n actual = await sha256OfFile(partPath)\r\n } catch (e) {\r\n try {\r\n await unlink(partPath)\r\n } catch {\r\n // .part 임시파일 정리 best-effort — 본 에러(SHA 계산 실패)를 가리지 않도록 무시\r\n }\r\n throw new Error(`${spec.name} SHA 계산 실패: ${(e as Error).message}`)\r\n }\r\n\r\n if (actual !== spec.sha256) {\r\n try {\r\n await unlink(partPath)\r\n } catch {\r\n // 오염된 .part 정리 best-effort — 본 에러(SHA mismatch)를 가리지 않도록 무시\r\n }\r\n throw new Error(\r\n `${spec.name} SHA256 mismatch: expected ${spec.sha256}, got ${actual} — 모델 URL 이 오염되었거나 전송 중 손상되었습니다.`,\r\n )\r\n }\r\n\r\n await rename(partPath, localPath)\r\n onProgress?.({\r\n spec,\r\n downloaded,\r\n total,\r\n phase: \"done\",\r\n })\r\n}\r\n\r\nasync function sha256OfFile(p: string): Promise<string> {\r\n const h = createHash(\"sha256\")\r\n const stream = createReadStream(p)\r\n await pipeline(stream, async function* (src) {\r\n for await (const chunk of src) {\r\n h.update(chunk)\r\n // yield 안 함 (소비만)\r\n }\r\n })\r\n return h.digest(\"hex\")\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["/** kordoc 공용 유틸리티 */\r\n\r\n/** 빌드 타임에 tsup define으로 주입되는 버전 */\r\ndeclare const __KORDOC_VERSION__: string\r\nexport const VERSION: string = typeof __KORDOC_VERSION__ !== \"undefined\" ? __KORDOC_VERSION__ : \"0.0.0-dev\"\r\n\r\n/**\r\n * Node.js Buffer → ArrayBuffer 변환\r\n * pool Buffer의 공유 ArrayBuffer 문제를 안전하게 처리.\r\n * offset=0이고 전체 ArrayBuffer를 차지하면 복사 없이 직접 반환.\r\n */\r\nexport function toArrayBuffer(buf: Buffer): ArrayBuffer {\r\n if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {\r\n return buf.buffer as ArrayBuffer\r\n }\r\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer\r\n}\r\n\r\n/**\r\n * kordoc 내부 에러 클래스 — 사용자에게 노출해도 안전한 메시지만 포함.\r\n * MCP 에러 정제에서 instanceof로 판별하여 allowlist 패턴 매칭 없이 안전하게 통과.\r\n */\r\nexport class KordocError extends Error {\r\n constructor(message: string) {\r\n super(message)\r\n this.name = \"KordocError\"\r\n }\r\n}\r\n\r\n/**\r\n * 에러 메시지 정제 — KordocError는 그대로, 나머지는 일반 메시지로 대체.\r\n * 파일시스템 경로, 스택 트레이스 등 내부 정보 노출 방지.\r\n */\r\nexport function sanitizeError(err: unknown): string {\r\n if (err instanceof KordocError) return err.message\r\n return \"문서 처리 중 오류가 발생했습니다\"\r\n}\r\n\r\n/**\r\n * ZIP 엔트리 경로의 경로 순회 여부 판별.\r\n * 백슬래시 정규화, .., 절대경로, Windows 드라이브 문자 모두 차단.\r\n */\r\nexport function isPathTraversal(name: string): boolean {\r\n if (name.includes(\"\\x00\")) return true\r\n const normalized = name.replace(/\\\\/g, \"/\")\r\n const segments = normalized.split(\"/\")\r\n return segments.some(s => s === \"..\") || normalized.startsWith(\"/\") || /^[A-Za-z]:/.test(normalized)\r\n}\r\n\r\n// ─── HWPX 섹션 href 해석 (parser/roundtrip 공용) ────────────────────\r\n\r\n/**\r\n * manifest href를 본문 섹션 경로(`Contents/sectionN.xml`)로 정규화.\r\n * 비본문 XML(header/script/settings)·path traversal·드라이브 경로는 null로 거른다.\r\n * 백슬래시 구분자를 슬래시로 통일해 parser와 roundtrip이 동일한 목록을 만든다.\r\n */\r\nexport function normalizeSectionHref(href: string): string | null {\r\n if (!href) return null\r\n let normalized = href.replace(/\\\\/g, \"/\").replace(/^\\/+/, \"\")\r\n if (isPathTraversal(normalized)) return null\r\n if (/^[Ss]ection\\d+\\.xml$/.test(normalized)) normalized = \"Contents/\" + normalized\r\n return /(?:^|\\/)[Ss]ection\\d+\\.xml$/.test(normalized) ? normalized : null\r\n}\r\n\r\n/** sectionN.xml을 N 숫자 순서로 정렬 (section10 > section2). */\r\nexport function compareSectionPaths(a: string, b: string): number {\r\n const ai = Number(a.match(/[Ss]ection(\\d+)\\.xml$/)?.[1] ?? Number.MAX_SAFE_INTEGER)\r\n const bi = Number(b.match(/[Ss]ection(\\d+)\\.xml$/)?.[1] ?? Number.MAX_SAFE_INTEGER)\r\n return ai === bi ? a.localeCompare(b) : ai - bi\r\n}\r\n\r\n// ─── ZIP 안전 로딩 (ZIP bomb 방지) ────────────────────\r\n\r\n/**\r\n * ZIP bomb 사전 검사 — Central Directory에서 비압축 합계와 엔트리 수 확인.\r\n * HWPX/XLSX/DOCX 등 모든 ZIP 기반 포맷에서 공통 사용.\r\n */\r\nexport function precheckZipSize(\r\n buffer: ArrayBuffer,\r\n maxUncompressedSize = 256 * 1024 * 1024, // parser-shared MAX_DECOMPRESS_SIZE 와 동기\r\n maxEntries = 500,\r\n): { totalUncompressed: number; entryCount: number } {\r\n try {\r\n const data = new DataView(buffer)\r\n const len = buffer.byteLength\r\n // EOCD 시그니처 역방향 스캔\r\n let eocdOffset = -1\r\n for (let i = len - 22; i >= Math.max(0, len - 65557); i--) {\r\n if (data.getUint32(i, true) === 0x06054b50) { eocdOffset = i; break }\r\n }\r\n if (eocdOffset < 0) return { totalUncompressed: 0, entryCount: 0 }\r\n\r\n const entryCount = data.getUint16(eocdOffset + 10, true)\r\n if (entryCount > maxEntries) {\r\n throw new KordocError(`ZIP 엔트리 수 초과: ${entryCount} (최대 ${maxEntries})`)\r\n }\r\n\r\n const cdSize = data.getUint32(eocdOffset + 12, true)\r\n const cdOffset = data.getUint32(eocdOffset + 16, true)\r\n if (cdOffset + cdSize > len) return { totalUncompressed: 0, entryCount }\r\n\r\n let totalUncompressed = 0\r\n let pos = cdOffset\r\n for (let i = 0; i < entryCount && pos + 46 <= cdOffset + cdSize; i++) {\r\n if (data.getUint32(pos, true) !== 0x02014b50) break\r\n totalUncompressed += data.getUint32(pos + 24, true)\r\n const nameLen = data.getUint16(pos + 28, true)\r\n const extraLen = data.getUint16(pos + 30, true)\r\n const commentLen = data.getUint16(pos + 32, true)\r\n pos += 46 + nameLen + extraLen + commentLen\r\n }\r\n\r\n if (totalUncompressed > maxUncompressedSize) {\r\n throw new KordocError(`ZIP 비압축 크기 초과: ${(totalUncompressed / 1024 / 1024).toFixed(1)}MB (최대 ${maxUncompressedSize / 1024 / 1024}MB)`)\r\n }\r\n\r\n return { totalUncompressed, entryCount }\r\n } catch (err) {\r\n if (err instanceof KordocError) throw err\r\n return { totalUncompressed: 0, entryCount: 0 }\r\n }\r\n}\r\n\r\n/** XXE/Billion Laughs 방지 — DOCTYPE 제거 (내부 DTD 서브셋 포함) */\r\nexport function stripDtd(xml: string): string {\r\n return xml.replace(/<!DOCTYPE\\s[^[>]*(\\[[\\s\\S]*?\\])?\\s*>/gi, \"\")\r\n}\r\n\r\n/** 하이퍼링크 URL 살균 — javascript: 등 XSS 위험 스킴 차단 */\r\nconst SAFE_HREF_RE = /^(?:https?:|mailto:|tel:|#)/i\r\nexport function sanitizeHref(href: string): string | null {\r\n const trimmed = href.trim()\r\n if (!trimmed || !SAFE_HREF_RE.test(trimmed)) return null\r\n // 괄호 percent-encoding — 마크다운 링크 목적지에서 불균형 ')'는 링크를 조기 종료시켜\r\n // 문법이 깨진다 (원문 하이퍼링크에 ')'가 박힌 실문서 존재). %28/%29는 의미 동일.\r\n return trimmed.replace(/\\(/g, \"%28\").replace(/\\)/g, \"%29\")\r\n}\r\n\r\n// ─── 안전한 min/max (스택 오버플로 방지) ─────────────\r\n\r\n/** Math.min(...arr) 대체 — 대형 배열에서 스택 오버플로 방지 */\r\nexport function safeMin(arr: number[]): number {\r\n let min = Infinity\r\n for (let i = 0; i < arr.length; i++) if (arr[i] < min) min = arr[i]\r\n return min\r\n}\r\n\r\n/** Math.max(...arr) 대체 — 대형 배열에서 스택 오버플로 방지 */\r\nexport function safeMax(arr: number[]): number {\r\n let max = -Infinity\r\n for (let i = 0; i < arr.length; i++) if (arr[i] > max) max = arr[i]\r\n return max\r\n}\r\n\r\n// ─── 에러 분류 ──────────────────────────────────────\r\n\r\nimport type { ErrorCode } from \"./types.js\"\r\n\r\n/** 에러를 구조화된 ErrorCode로 분류 — KordocError 메시지 패턴 매칭 */\r\nexport function classifyError(err: unknown): ErrorCode {\r\n if (!(err instanceof Error)) return \"PARSE_ERROR\"\r\n const msg = err.message\r\n // DRM 을 암호화보다 먼저 — \"DRM 암호화된 HWPX…\" 류 메시지가 ENCRYPTED 로 떨어지지 않도록\r\n if (msg.includes(\"DRM\")) return \"DRM_PROTECTED\"\r\n if (msg.includes(\"암호화\") || msg.includes(\"암호로 보호\")) return \"ENCRYPTED\"\r\n if (msg.includes(\"optional dependency\")) return \"MISSING_DEPENDENCY\"\r\n if (msg.includes(\"ZIP bomb\") || msg.includes(\"ZIP 비압축 크기 초과\") || msg.includes(\"ZIP 엔트리 수 초과\")) return \"ZIP_BOMB\"\r\n if (msg.includes(\"bomb\") || msg.includes(\"크기 초과\") || msg.includes(\"압축 해제\")) return \"DECOMPRESSION_BOMB\"\r\n if (msg.includes(\"이미지 기반\")) return \"IMAGE_BASED_PDF\"\r\n if (msg.includes(\"섹션\") && (msg.includes(\"찾을 수 없\") || msg.includes(\"없음\"))) return \"NO_SECTIONS\"\r\n if (msg.includes(\"시그니처\") || msg.includes(\"복구할 수 없\")) return \"CORRUPTED\"\r\n return \"PARSE_ERROR\"\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["c:\\github_project\\kordoc\\dist\\chunk-ZMKTKJZN.cjs"],"names":[],"mappings":"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A;AACA,QAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,MAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,YAAA;AACA,UAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"C:\\github_project\\kordoc\\dist\\chunk-ZMKTKJZN.cjs","sourcesContent":[null]}