kordoc 4.24.36 → 4.24.38
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.
- package/README.md +4 -3
- package/dist/{-P5YOBEUM.js → -LPQSUCWH.js} +60 -60
- package/dist/{chunk-UX6WP55C.js → chunk-3NZP2VXB.js} +2 -2
- package/dist/{chunk-BPBY6762.js → chunk-5IYRVLGJ.js} +206 -18
- package/dist/chunk-5IYRVLGJ.js.map +1 -0
- package/dist/{chunk-U6NRQARP.js → chunk-5PONVN46.js} +7 -7
- package/dist/{chunk-JUFBKWYZ.cjs → chunk-6COUUT2E.cjs} +2 -2
- package/dist/{chunk-JUFBKWYZ.cjs.map → chunk-6COUUT2E.cjs.map} +1 -1
- package/dist/{chunk-WH33GYVU.js → chunk-6MTH2EYN.js} +19 -19
- package/dist/{chunk-NDKS7IDO.js → chunk-7F42AI4O.js} +2 -2
- package/dist/{chunk-KBU3KKZF.js → chunk-7F63OEHI.js} +2 -2
- package/dist/{chunk-VKZ3F3QB.cjs → chunk-ACQBUQB6.cjs} +404 -170
- package/dist/chunk-ACQBUQB6.cjs.map +1 -0
- package/dist/{chunk-U433NRGQ.js → chunk-AZ56HT3M.js} +3 -3
- package/dist/{chunk-PSA7XLT5.js → chunk-CDVDRC77.js} +2 -2
- package/dist/{chunk-ZPGXCXSX.js → chunk-FA3MQGIF.js} +2 -2
- package/dist/{chunk-2QKOHKAH.cjs → chunk-FZWI6S7M.cjs} +3 -3
- package/dist/{chunk-2QKOHKAH.cjs.map → chunk-FZWI6S7M.cjs.map} +1 -1
- package/dist/{chunk-WLMTCXAJ.js → chunk-G3JUKDMB.js} +2 -2
- package/dist/{chunk-VX3TCX6T.js → chunk-HWSJAYMR.js} +16 -7
- package/dist/chunk-HWSJAYMR.js.map +1 -0
- package/dist/{chunk-KDUI534B.js → chunk-IDCU74H5.js} +2 -2
- package/dist/{chunk-G5JSF2AY.js → chunk-IFWGHRCQ.js} +3 -3
- package/dist/chunk-IFWGHRCQ.js.map +1 -0
- package/dist/{chunk-VRXROMUB.js → chunk-ISMJQJOP.js} +253 -23
- package/dist/chunk-ISMJQJOP.js.map +1 -0
- package/dist/{chunk-ORDEO3KS.cjs → chunk-JEHCRYUT.cjs} +98 -98
- package/dist/{chunk-ORDEO3KS.cjs.map → chunk-JEHCRYUT.cjs.map} +1 -1
- package/dist/{chunk-IQJKLIJV.js → chunk-JIMG76FW.js} +3 -3
- package/dist/chunk-JIMG76FW.js.map +1 -0
- package/dist/{chunk-34BCKDAB.js → chunk-JL5REIEZ.js} +210 -22
- package/dist/chunk-JL5REIEZ.js.map +1 -0
- package/dist/{chunk-5LOELQQQ.js → chunk-LAKPAL53.js} +2 -2
- package/dist/{chunk-IJT4GDQX.js → chunk-MLXVSAR3.js} +2 -2
- package/dist/{chunk-MN5T7HCP.js → chunk-MNXKORB5.js} +7 -3
- package/dist/chunk-MNXKORB5.js.map +1 -0
- package/dist/{chunk-LMJNZEGE.js → chunk-MSRDRUOV.js} +2 -2
- package/dist/{chunk-EBYDC56L.js → chunk-OBZV23UV.js} +51 -51
- package/dist/{chunk-F4O2VM2W.js → chunk-ONC5LWD4.js} +18 -9
- package/dist/chunk-ONC5LWD4.js.map +1 -0
- package/dist/{chunk-MFBSYY52.js → chunk-ONL4UTGQ.js} +32 -32
- package/dist/{chunk-AZMS6M6S.js → chunk-ORIA2IFK.js} +50 -50
- package/dist/{chunk-B3WLIR4K.js → chunk-OYIGWP2N.js} +2 -2
- package/dist/{chunk-46M3WU3M.js → chunk-P4OK4W2F.js} +3 -3
- package/dist/{chunk-A7PYKEKI.cjs → chunk-Q7WPRN62.cjs} +69 -60
- package/dist/chunk-Q7WPRN62.cjs.map +1 -0
- package/dist/{chunk-TBHWTT3M.js → chunk-RLED4WS3.js} +2 -2
- package/dist/{chunk-TBHWTT3M.js.map → chunk-RLED4WS3.js.map} +1 -1
- package/dist/{chunk-D25PORBW.cjs → chunk-SOI7R4LF.cjs} +303 -115
- package/dist/chunk-SOI7R4LF.cjs.map +1 -0
- package/dist/{chunk-JYYA6APD.js → chunk-SORWBCEP.js} +8 -8
- package/dist/{chunk-JY7PXRHS.js → chunk-TQUO7JR5.js} +3 -3
- package/dist/{chunk-PZOF2YT5.js → chunk-UJFT2OED.js} +2 -2
- package/dist/{chunk-57GAB2RG.js → chunk-UPO7Y3KL.js} +2 -2
- package/dist/{chunk-FUAWTU6H.js → chunk-UQ2ZA3X4.js} +2 -2
- package/dist/{chunk-N5GRO67A.js → chunk-UQTQXXHU.js} +14 -14
- package/dist/{chunk-A3LJ7BI2.cjs → chunk-URSNWPD4.cjs} +6 -6
- package/dist/{chunk-A3LJ7BI2.cjs.map → chunk-URSNWPD4.cjs.map} +1 -1
- package/dist/{chunk-65C5646Y.cjs → chunk-V5CNQSVW.cjs} +3 -3
- package/dist/{chunk-65C5646Y.cjs.map → chunk-V5CNQSVW.cjs.map} +1 -1
- package/dist/{chunk-GB5PO5NX.js → chunk-WOGL3YQK.js} +2 -2
- package/dist/{chunk-TPGYFICT.js → chunk-XQPF6I6P.js} +2 -2
- package/dist/{chunk-DNDMC7WW.js → chunk-XVWPMKPH.js} +262 -28
- package/dist/chunk-XVWPMKPH.js.map +1 -0
- package/dist/{chunk-LI7GH25U.js → chunk-YPLKE5WG.js} +2 -2
- package/dist/{chunk-LI7GH25U.js.map → chunk-YPLKE5WG.js.map} +1 -1
- package/dist/{chunk-E6QNUE6M.cjs → chunk-ZTN3T3GH.cjs} +3 -3
- package/dist/chunk-ZTN3T3GH.cjs.map +1 -0
- package/dist/chunks-5L5OU6AI.js +11 -0
- package/dist/cli.js +63 -62
- package/dist/cli.js.map +1 -1
- package/dist/{formula-7NQ4T267.js → formula-AV7SNRB4.js} +20 -17
- package/dist/{formula-7NQ4T267.js.map → formula-AV7SNRB4.js.map} +1 -1
- package/dist/{formula-6KDGXS6C.js → formula-BMSREXB5.js} +19 -16
- package/dist/{formula-6KDGXS6C.js.map → formula-BMSREXB5.js.map} +1 -1
- package/dist/{formula-DBHDZM4H.cjs → formula-NQHARDPX.cjs} +25 -22
- package/dist/formula-NQHARDPX.cjs.map +1 -0
- package/dist/generator-4CSCP6YH.js +17 -0
- package/dist/generator-OC366G6M.cjs +11 -0
- package/dist/{generator-AZ7UQRHE.cjs.map → generator-OC366G6M.cjs.map} +1 -1
- package/dist/generator-UPESZL4M.js +10 -0
- package/dist/hancom-3CHPVF7H.js +84 -0
- package/dist/hancom-3CHPVF7H.js.map +1 -0
- package/dist/hancom-6Z7O3G4K.js +85 -0
- package/dist/hancom-6Z7O3G4K.js.map +1 -0
- package/dist/hancom-F5OHWSWU.cjs +85 -0
- package/dist/hancom-F5OHWSWU.cjs.map +1 -0
- package/dist/{image-ocr-GR3FWG3K.cjs → image-ocr-JQ4OEBBK.cjs} +98 -20
- package/dist/image-ocr-JQ4OEBBK.cjs.map +1 -0
- package/dist/{image-ocr-CEEHL43H.js → image-ocr-PE5NAWAR.js} +92 -14
- package/dist/image-ocr-PE5NAWAR.js.map +1 -0
- package/dist/{image-ocr-BMRS4KAW.js → image-ocr-YJPNUWXR.js} +87 -9
- package/dist/image-ocr-YJPNUWXR.js.map +1 -0
- package/dist/index.cjs +1111 -1111
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +71 -71
- package/dist/mcp.js +59 -58
- package/dist/mcp.js.map +1 -1
- package/dist/memo-OVXY467W.js +17 -0
- package/dist/{model-bundle-ZS54IR7N.js → model-bundle-AXHPS54Q.js} +5 -5
- package/dist/{models-6WPHCCXJ.js → models-CYRFBT43.js} +7 -5
- package/dist/{parse-worker-v2-Q5FGTPKF.js → parse-worker-v2-GUJQNNOF.js} +30 -30
- package/dist/parse-worker-v2-GUJQNNOF.js.map +1 -0
- package/dist/{parser-WV63YTSR.js → parser-533OXR3B.js} +19 -18
- package/dist/{parser-SMHLYJXN.js.map → parser-533OXR3B.js.map} +1 -1
- package/dist/{parser-5UAP4AO3.cjs → parser-JVJSUMCA.cjs} +197 -196
- package/dist/parser-JVJSUMCA.cjs.map +1 -0
- package/dist/{parser-SMHLYJXN.js → parser-S56VNTRV.js} +18 -17
- package/dist/{parser-WV63YTSR.js.map → parser-S56VNTRV.js.map} +1 -1
- package/dist/{pdf-ocr-E7RDHENX.js → pdf-ocr-FNW4IJWX.js} +11 -7
- package/dist/{pdf-ocr-5WTFJJZ6.js → pdf-ocr-JNR4HA7O.js} +15 -11
- package/dist/pdf-ocr-ZBKAXNIE.cjs +40 -0
- package/dist/pdf-ocr-ZBKAXNIE.cjs.map +1 -0
- package/dist/{profile-io-CCLANNVL.js → profile-io-GU5XFVSI.js} +3 -3
- package/dist/{rasterize-MZASSBE2.js → rasterize-XOHGVWKM.js} +3 -3
- package/dist/{redact-doc-42CDLQMK.js → redact-doc-G5K4NVUN.js} +38 -38
- package/dist/{render-MCK6Q6ZJ.js → render-J7VBXGFV.js} +14 -14
- package/dist/{rewrite-fallback-TKCGT3KA.js → rewrite-fallback-4QGM5F4V.js} +21 -21
- package/dist/seal-DSMAUDZ4.js +16 -0
- package/dist/{setup-6QDKNA5S.js → setup-R5IH4AGD.js} +3 -3
- package/dist/{to-hwpx-473Q2VSU.js → to-hwpx-5ENZWUTU.js} +9 -9
- package/dist/{to-hwpx-JM7ZHX6S.js → to-hwpx-I6LNQ4D4.js} +4 -4
- package/dist/to-hwpx-WCDMFRNN.cjs +16 -0
- package/dist/{to-hwpx-FHQLJL2B.cjs.map → to-hwpx-WCDMFRNN.cjs.map} +1 -1
- package/dist/visual-QFPNYNCF.js +37 -0
- package/dist/{watch-4CQCJXRJ.js → watch-UM5SMZQP.js} +28 -28
- package/package.json +1 -1
- package/dist/chunk-34BCKDAB.js.map +0 -1
- package/dist/chunk-A7PYKEKI.cjs.map +0 -1
- package/dist/chunk-BPBY6762.js.map +0 -1
- package/dist/chunk-D25PORBW.cjs.map +0 -1
- package/dist/chunk-DNDMC7WW.js.map +0 -1
- package/dist/chunk-E6QNUE6M.cjs.map +0 -1
- package/dist/chunk-F4O2VM2W.js.map +0 -1
- package/dist/chunk-G5JSF2AY.js.map +0 -1
- package/dist/chunk-IQJKLIJV.js.map +0 -1
- package/dist/chunk-MN5T7HCP.js.map +0 -1
- package/dist/chunk-VKZ3F3QB.cjs.map +0 -1
- package/dist/chunk-VRXROMUB.js.map +0 -1
- package/dist/chunk-VX3TCX6T.js.map +0 -1
- package/dist/chunks-GCOBHHXO.js +0 -11
- package/dist/formula-DBHDZM4H.cjs.map +0 -1
- package/dist/generator-AZ7UQRHE.cjs +0 -11
- package/dist/generator-OGOQGTEG.js +0 -10
- package/dist/generator-WUC766Y5.js +0 -17
- package/dist/image-ocr-BMRS4KAW.js.map +0 -1
- package/dist/image-ocr-CEEHL43H.js.map +0 -1
- package/dist/image-ocr-GR3FWG3K.cjs.map +0 -1
- package/dist/memo-5ZCEQWDF.js +0 -17
- package/dist/parse-worker-v2-Q5FGTPKF.js.map +0 -1
- package/dist/parser-5UAP4AO3.cjs.map +0 -1
- package/dist/pdf-ocr-JCNTIIYQ.cjs +0 -36
- package/dist/pdf-ocr-JCNTIIYQ.cjs.map +0 -1
- package/dist/seal-OZN5UW6W.js +0 -16
- package/dist/to-hwpx-FHQLJL2B.cjs +0 -16
- package/dist/visual-YLYML5VG.js +0 -37
- /package/dist/{-P5YOBEUM.js.map → -LPQSUCWH.js.map} +0 -0
- /package/dist/{chunk-UX6WP55C.js.map → chunk-3NZP2VXB.js.map} +0 -0
- /package/dist/{chunk-U6NRQARP.js.map → chunk-5PONVN46.js.map} +0 -0
- /package/dist/{chunk-WH33GYVU.js.map → chunk-6MTH2EYN.js.map} +0 -0
- /package/dist/{chunk-NDKS7IDO.js.map → chunk-7F42AI4O.js.map} +0 -0
- /package/dist/{chunk-KBU3KKZF.js.map → chunk-7F63OEHI.js.map} +0 -0
- /package/dist/{chunk-U433NRGQ.js.map → chunk-AZ56HT3M.js.map} +0 -0
- /package/dist/{chunk-PSA7XLT5.js.map → chunk-CDVDRC77.js.map} +0 -0
- /package/dist/{chunk-ZPGXCXSX.js.map → chunk-FA3MQGIF.js.map} +0 -0
- /package/dist/{chunk-WLMTCXAJ.js.map → chunk-G3JUKDMB.js.map} +0 -0
- /package/dist/{chunk-KDUI534B.js.map → chunk-IDCU74H5.js.map} +0 -0
- /package/dist/{chunk-5LOELQQQ.js.map → chunk-LAKPAL53.js.map} +0 -0
- /package/dist/{chunk-IJT4GDQX.js.map → chunk-MLXVSAR3.js.map} +0 -0
- /package/dist/{chunk-LMJNZEGE.js.map → chunk-MSRDRUOV.js.map} +0 -0
- /package/dist/{chunk-EBYDC56L.js.map → chunk-OBZV23UV.js.map} +0 -0
- /package/dist/{chunk-MFBSYY52.js.map → chunk-ONL4UTGQ.js.map} +0 -0
- /package/dist/{chunk-AZMS6M6S.js.map → chunk-ORIA2IFK.js.map} +0 -0
- /package/dist/{chunk-B3WLIR4K.js.map → chunk-OYIGWP2N.js.map} +0 -0
- /package/dist/{chunk-46M3WU3M.js.map → chunk-P4OK4W2F.js.map} +0 -0
- /package/dist/{chunk-JYYA6APD.js.map → chunk-SORWBCEP.js.map} +0 -0
- /package/dist/{chunk-JY7PXRHS.js.map → chunk-TQUO7JR5.js.map} +0 -0
- /package/dist/{chunk-PZOF2YT5.js.map → chunk-UJFT2OED.js.map} +0 -0
- /package/dist/{chunk-57GAB2RG.js.map → chunk-UPO7Y3KL.js.map} +0 -0
- /package/dist/{chunk-FUAWTU6H.js.map → chunk-UQ2ZA3X4.js.map} +0 -0
- /package/dist/{chunk-N5GRO67A.js.map → chunk-UQTQXXHU.js.map} +0 -0
- /package/dist/{chunk-GB5PO5NX.js.map → chunk-WOGL3YQK.js.map} +0 -0
- /package/dist/{chunk-TPGYFICT.js.map → chunk-XQPF6I6P.js.map} +0 -0
- /package/dist/{chunks-GCOBHHXO.js.map → chunks-5L5OU6AI.js.map} +0 -0
- /package/dist/{generator-OGOQGTEG.js.map → generator-4CSCP6YH.js.map} +0 -0
- /package/dist/{generator-WUC766Y5.js.map → generator-UPESZL4M.js.map} +0 -0
- /package/dist/{memo-5ZCEQWDF.js.map → memo-OVXY467W.js.map} +0 -0
- /package/dist/{model-bundle-ZS54IR7N.js.map → model-bundle-AXHPS54Q.js.map} +0 -0
- /package/dist/{models-6WPHCCXJ.js.map → models-CYRFBT43.js.map} +0 -0
- /package/dist/{pdf-ocr-5WTFJJZ6.js.map → pdf-ocr-FNW4IJWX.js.map} +0 -0
- /package/dist/{pdf-ocr-E7RDHENX.js.map → pdf-ocr-JNR4HA7O.js.map} +0 -0
- /package/dist/{profile-io-CCLANNVL.js.map → profile-io-GU5XFVSI.js.map} +0 -0
- /package/dist/{rasterize-MZASSBE2.js.map → rasterize-XOHGVWKM.js.map} +0 -0
- /package/dist/{redact-doc-42CDLQMK.js.map → redact-doc-G5K4NVUN.js.map} +0 -0
- /package/dist/{render-MCK6Q6ZJ.js.map → render-J7VBXGFV.js.map} +0 -0
- /package/dist/{rewrite-fallback-TKCGT3KA.js.map → rewrite-fallback-4QGM5F4V.js.map} +0 -0
- /package/dist/{seal-OZN5UW6W.js.map → seal-DSMAUDZ4.js.map} +0 -0
- /package/dist/{setup-6QDKNA5S.js.map → setup-R5IH4AGD.js.map} +0 -0
- /package/dist/{to-hwpx-473Q2VSU.js.map → to-hwpx-5ENZWUTU.js.map} +0 -0
- /package/dist/{to-hwpx-JM7ZHX6S.js.map → to-hwpx-I6LNQ4D4.js.map} +0 -0
- /package/dist/{visual-YLYML5VG.js.map → visual-QFPNYNCF.js.map} +0 -0
- /package/dist/{watch-4CQCJXRJ.js.map → watch-UM5SMZQP.js.map} +0 -0
package/README.md
CHANGED
|
@@ -125,6 +125,7 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
|
|
|
125
125
|
| 법령 별표 | 272건 · 346표 | HWP **346/346**, PDF **343/346 · 99.13%** |
|
|
126
126
|
| PDF 전체 | 1,911문서 중 1,729건 채점 | 글 커버리지 **99.80%** |
|
|
127
127
|
| OCR | 53문서 · 102쪽 · 66표 | CER **0.0239** · 글자 재현율 **99.32%** · 표 구조 일치 **34/66** |
|
|
128
|
+
| KoOCR-Bench v2.0c (외부) | 공개 877쪽 (표·글·손글씨·순서) | 종합 기본값 **0.810** · `ocrRec: "auto"` **0.831** · 제목 재현율 0.798 (4.24.38) |
|
|
128
129
|
| opendataloader-bench | PDF 200문서 | 종합 기본값 **0.964** · OCR 끔 **0.939** |
|
|
129
130
|
| HWPX 렌더 배치 | 한컴 PDF 짝 1,565문서(쪽 수 일치 1,508) · 글 조각 111,480 · 그림 4,300 | 글 위치(±1.5pt) **106,904 · 95.9%** · 그림 위치(±2pt) **4,213 · 98.0%** |
|
|
130
131
|
|
|
@@ -132,15 +133,15 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
|
|
|
132
133
|
|
|
133
134
|
## 최근 업데이트
|
|
134
135
|
|
|
135
|
-
최신 배포: **[4.24.
|
|
136
|
+
최신 배포: **[4.24.38](https://github.com/chrisryugj/kordoc/releases/tag/v4.24.38)** · 2026-11-02
|
|
136
137
|
|
|
137
138
|
| 버전 | 주요 변경 | 수치 변화 |
|
|
138
139
|
| --- | --- | --- |
|
|
140
|
+
| 4.24.38 | OCR: 스캔·이미지 쪽 제목 판정(위아래로 쌓인 장 제목 잇기) · 작은 1칸 상자 쪽 두 단 읽기 순서 · 문장 조각 가짜 표 · 겹친 상자 이음매 글자 · 이미지 수식 OCR(`formulaOcr`) · to-hwpx 한/글 자체 저장 엔진(`--engine hancom`, 팝업 없이) | KoOCR-Bench 종합 0.807 → **0.810**(`auto` **0.831**) · 제목 재현율 0 → .798 · 자체 벤치 문서별 그대로 |
|
|
141
|
+
| 4.24.37 | OCR 표: 통계표 묶음 안 빈칸 열·괘선 없는 본문 행 펼치기·행 합침 아래 행 가르기·이웃 칸 값 몰림·음영 머리 띠와 칠한 첫 열 경계 · 머리 행 있는 표를 차트로 풀던 것 · 시험지 문항 상자 풀기 · `ocrRec: "auto"`(손글씨 쪽만 손글씨 모델) | KoOCR-Bench v2.0c 공개 877쪽 종합 0.742 → **0.807**(`ocrRec: "auto"` **0.828**) · 자체 벤치 문서별 그대로 |
|
|
139
142
|
| 4.24.36 | PDF 띄어쓰기(한컴 PDF): 자간 줄인 글의 낱말 공백 되살림 · 공백 글리프 위에 덧찍은 쉼표("55만원,") · 날짜 "2026. 8. 28." 공백 유지 · 줄 끝에서 갈린 연도 "20⏎25년" | PDF 글 어절 F1 99.076 → **99.103%** · 그 밖 지표 그대로 |
|
|
140
143
|
| 4.24.35 | PDF: 자간 줄인 수치의 같은 숫자 둘("129.9") 지키기 · 글자마다 찍은 첨자 줄을 본문에 붙이기 · 수 가운데서 꺾인 줄("1,2⏎96억"·"(4.1⏎6.~5.16.)")과 칸 소수 잇기 · 표지 책등 외기둥 세로 글 | PDF 표 칸 완전 일치 0.99264 → **0.99267** · 칸 내용 0.98902 → **0.98905** · PDF 글 순서 99.359 → **99.360%** · 어절 F1 99.073 → **99.076%** · 그 밖 지표 그대로 |
|
|
141
144
|
| 4.24.34 | to-hwpx: 파일 여러 개·폴더 일괄 변환(하위 폴더, 이미 있는 .hwpx 건너뜀) · PDF: 기호 글꼴 작은 네모로 찍고 공백으로 적은 "·" 글머리 되살림 · 글자 단위로 나눈 줄 머리 어미("는데"·"졌다")·겹조사 잇기 | PDF 표 칸 완전 일치 0.99221 → **0.99264** · 칸 내용 0.98896 → **0.98902** · PDF 글 재현율 99.883 → **99.885%** · 순서 99.356 → **99.359%** · 어절 F1 99.071 → **99.073%** · 그 밖 지표 그대로 |
|
|
142
|
-
| 4.24.33 | PDF 표: 모아찍기 쪽 넘김에서 오른쪽 쪽 머리 상자로 넘어간 칸 글을 앞 칸에 잇기 · 칸을 한 겹 더 깐 1×1 클립(통계표 숫자 칸)을 중첩 표 대신 칸 글로 | PDF 표 칸 내용 일치 0.98794 → **0.98896** · 칸 완전 일치 0.99153 → **0.99221** · 그 밖 벤치 지표 그대로 |
|
|
143
|
-
| 4.24.32 | PDF·OCR 두 단: 같은 줄 격자 두 단(속기록·시험지)을 단으로 · 옆 단 머리 문항이 앞 선지 하위 목록이 되던 것 · 짝·홀 쪽에서 칸 순서가 뒤집히는 머리말 상자 걷기 | PDF 글 읽기 순서 99.348% → **99.356%** · 정확도 99.680% → **99.682%** · 어절 F1 99.069% → **99.071%** · OCR 정답(텍스트층) 회의록 두 단이 바로잡혀 CER 0.0237 → 0.0239(정답 변화, 채점 그대로) |
|
|
144
145
|
|
|
145
146
|
이전 버전과 상세 내용은 [변경 이력](CHANGELOG.md)에 있습니다.
|
|
146
147
|
|
|
@@ -53,34 +53,7 @@ import {
|
|
|
53
53
|
usesGaejosikMunche,
|
|
54
54
|
usesLogicStructure,
|
|
55
55
|
validateHwpx
|
|
56
|
-
} from "./chunk-
|
|
57
|
-
import {
|
|
58
|
-
blocksToPages
|
|
59
|
-
} from "./chunk-IJT4GDQX.js";
|
|
60
|
-
import {
|
|
61
|
-
extractClickHereFields,
|
|
62
|
-
patchHwp,
|
|
63
|
-
patchHwpx
|
|
64
|
-
} from "./chunk-EBYDC56L.js";
|
|
65
|
-
import {
|
|
66
|
-
addMemoHwpx
|
|
67
|
-
} from "./chunk-JYYA6APD.js";
|
|
68
|
-
import {
|
|
69
|
-
placeSealHwpx
|
|
70
|
-
} from "./chunk-U6NRQARP.js";
|
|
71
|
-
import "./chunk-UX6WP55C.js";
|
|
72
|
-
import {
|
|
73
|
-
convertToHwpx,
|
|
74
|
-
hwpToHwpx
|
|
75
|
-
} from "./chunk-F4O2VM2W.js";
|
|
76
|
-
import {
|
|
77
|
-
DEFAULT_REDACT_RULES,
|
|
78
|
-
redactMarkdown,
|
|
79
|
-
redactText
|
|
80
|
-
} from "./chunk-3WSNLH4B.js";
|
|
81
|
-
import {
|
|
82
|
-
blocksToChunks
|
|
83
|
-
} from "./chunk-ZPGXCXSX.js";
|
|
56
|
+
} from "./chunk-ORIA2IFK.js";
|
|
84
57
|
import {
|
|
85
58
|
blocksToPdf,
|
|
86
59
|
extractRenderedRegions,
|
|
@@ -91,25 +64,16 @@ import {
|
|
|
91
64
|
renderHwp5Pages,
|
|
92
65
|
renderHwpxToSvg,
|
|
93
66
|
renderSceneToHtml
|
|
94
|
-
} from "./chunk-
|
|
95
|
-
import "./chunk-46M3WU3M.js";
|
|
96
|
-
import "./chunk-B3WLIR4K.js";
|
|
97
|
-
import "./chunk-N5GRO67A.js";
|
|
98
|
-
import "./chunk-VKVDMH7X.js";
|
|
99
|
-
import "./chunk-FUAWTU6H.js";
|
|
100
|
-
import "./chunk-KDUI534B.js";
|
|
101
|
-
import "./chunk-VQFA55IC.js";
|
|
67
|
+
} from "./chunk-ONL4UTGQ.js";
|
|
102
68
|
import {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
import "./chunk-H7K5YHWQ.js";
|
|
112
|
-
import "./chunk-IQJKLIJV.js";
|
|
69
|
+
blocksToPages
|
|
70
|
+
} from "./chunk-MLXVSAR3.js";
|
|
71
|
+
import {
|
|
72
|
+
extractClickHereFields,
|
|
73
|
+
patchHwp,
|
|
74
|
+
patchHwpx
|
|
75
|
+
} from "./chunk-OBZV23UV.js";
|
|
76
|
+
import "./chunk-P4OK4W2F.js";
|
|
113
77
|
import {
|
|
114
78
|
AGENCY_COMMON_NAME,
|
|
115
79
|
PRESET_ALIAS,
|
|
@@ -119,7 +83,24 @@ import {
|
|
|
119
83
|
markdownToHwpx,
|
|
120
84
|
normalizeGongmunPreset,
|
|
121
85
|
placeTotalRow
|
|
122
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-6MTH2EYN.js";
|
|
87
|
+
import {
|
|
88
|
+
SPACE_EM_FIXED,
|
|
89
|
+
SPACE_EM_FONT,
|
|
90
|
+
charWidthEm1000,
|
|
91
|
+
fitRatioForFewerLines,
|
|
92
|
+
measureTextWidth,
|
|
93
|
+
simulateWrap,
|
|
94
|
+
simulateWrapKeepWord
|
|
95
|
+
} from "./chunk-UJFT2OED.js";
|
|
96
|
+
import {
|
|
97
|
+
addMemoHwpx
|
|
98
|
+
} from "./chunk-SORWBCEP.js";
|
|
99
|
+
import {
|
|
100
|
+
placeSealHwpx
|
|
101
|
+
} from "./chunk-5PONVN46.js";
|
|
102
|
+
import "./chunk-OYIGWP2N.js";
|
|
103
|
+
import "./chunk-3NZP2VXB.js";
|
|
123
104
|
import {
|
|
124
105
|
ValueCursor,
|
|
125
106
|
applySplices,
|
|
@@ -133,28 +114,47 @@ import {
|
|
|
133
114
|
isLabelCell,
|
|
134
115
|
scanSectionXml
|
|
135
116
|
} from "./chunk-3AHL6YEA.js";
|
|
117
|
+
import "./chunk-XQPF6I6P.js";
|
|
136
118
|
import {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
simulateWrap,
|
|
143
|
-
simulateWrapKeepWord
|
|
144
|
-
} from "./chunk-PZOF2YT5.js";
|
|
145
|
-
import "./chunk-TPGYFICT.js";
|
|
119
|
+
convertToHwpx,
|
|
120
|
+
hwpToHwpx
|
|
121
|
+
} from "./chunk-ONC5LWD4.js";
|
|
122
|
+
import "./chunk-UQTQXXHU.js";
|
|
123
|
+
import "./chunk-VKVDMH7X.js";
|
|
146
124
|
import "./chunk-OFVHQ2TZ.js";
|
|
125
|
+
import "./chunk-UQ2ZA3X4.js";
|
|
147
126
|
import "./chunk-WFKFG2RT.js";
|
|
148
|
-
import
|
|
127
|
+
import {
|
|
128
|
+
DEFAULT_REDACT_RULES,
|
|
129
|
+
redactMarkdown,
|
|
130
|
+
redactText
|
|
131
|
+
} from "./chunk-3WSNLH4B.js";
|
|
132
|
+
import {
|
|
133
|
+
blocksToChunks
|
|
134
|
+
} from "./chunk-FA3MQGIF.js";
|
|
135
|
+
import "./chunk-IDCU74H5.js";
|
|
136
|
+
import "./chunk-VQFA55IC.js";
|
|
137
|
+
import {
|
|
138
|
+
detectFormat,
|
|
139
|
+
detectOle2Format,
|
|
140
|
+
detectZipFormat,
|
|
141
|
+
isHwpxFile,
|
|
142
|
+
isOldHwpFile,
|
|
143
|
+
isPdfFile,
|
|
144
|
+
isZipFile
|
|
145
|
+
} from "./chunk-GHHVT4Q5.js";
|
|
146
|
+
import "./chunk-H7K5YHWQ.js";
|
|
147
|
+
import "./chunk-JIMG76FW.js";
|
|
148
|
+
import "./chunk-RLED4WS3.js";
|
|
149
149
|
import {
|
|
150
150
|
blocksToMarkdown,
|
|
151
151
|
flattenLayoutTables,
|
|
152
152
|
hasStructuredCellContent
|
|
153
|
-
} from "./chunk-
|
|
153
|
+
} from "./chunk-MSRDRUOV.js";
|
|
154
154
|
import "./chunk-KFF47XZ7.js";
|
|
155
155
|
import {
|
|
156
156
|
VERSION
|
|
157
|
-
} from "./chunk-
|
|
157
|
+
} from "./chunk-LAKPAL53.js";
|
|
158
158
|
export {
|
|
159
159
|
AGENCY_COMMON_NAME,
|
|
160
160
|
BUILTIN_TEMPLATES,
|
|
@@ -268,4 +268,4 @@ export {
|
|
|
268
268
|
usesLogicStructure,
|
|
269
269
|
validateHwpx
|
|
270
270
|
};
|
|
271
|
-
//# sourceMappingURL=-
|
|
271
|
+
//# sourceMappingURL=-LPQSUCWH.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
KordocError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-LAKPAL53.js";
|
|
5
5
|
|
|
6
6
|
// src/roundtrip/zip-patch.ts
|
|
7
7
|
import { deflateRawSync } from "zlib";
|
|
@@ -233,4 +233,4 @@ export {
|
|
|
233
233
|
readZipEntries,
|
|
234
234
|
patchZipEntries
|
|
235
235
|
};
|
|
236
|
-
//# sourceMappingURL=chunk-
|
|
236
|
+
//# sourceMappingURL=chunk-3NZP2VXB.js.map
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
findOcrTextGaps,
|
|
15
15
|
gapGlyphs,
|
|
16
16
|
grayCrop,
|
|
17
|
+
handwritingFallbackModels,
|
|
17
18
|
inkBounds,
|
|
18
19
|
inkStats,
|
|
19
20
|
leaderRuns,
|
|
@@ -33,17 +34,125 @@ import {
|
|
|
33
34
|
splitRowBands,
|
|
34
35
|
starRun,
|
|
35
36
|
tallInkCount
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-XVWPMKPH.js";
|
|
37
38
|
import {
|
|
38
39
|
validateOcrOptions
|
|
39
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-IFWGHRCQ.js";
|
|
40
41
|
import {
|
|
41
42
|
disableOrtTelemetry
|
|
42
43
|
} from "./chunk-DC6CTQTK.js";
|
|
43
44
|
import {
|
|
44
45
|
KordocError,
|
|
45
46
|
OPTIONAL_DEP_INSTALL_HINT
|
|
46
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-7F42AI4O.js";
|
|
48
|
+
|
|
49
|
+
// src/ocr/ocr-stacked-rows.ts
|
|
50
|
+
var NUMERIC = /^[-+−△▲▽▼]?[\d.,]+[%p]?$|^[-–—·∼~]$|^\([-+−△▲▽▼]?[\d.,]+\)$/;
|
|
51
|
+
var blank = () => ({ text: "", colSpan: 1, rowSpan: 1 });
|
|
52
|
+
function rowAnchors(t, r, coveredFromAbove) {
|
|
53
|
+
const out = [];
|
|
54
|
+
const row = t.cells[r] ?? [];
|
|
55
|
+
for (let c = 0; c < row.length; ) {
|
|
56
|
+
if (coveredFromAbove[c]) {
|
|
57
|
+
c++;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const cell = row[c];
|
|
61
|
+
out.push({ c, cell });
|
|
62
|
+
c += Math.max(1, cell.colSpan ?? 1);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function splitTable(t) {
|
|
67
|
+
let changed = false;
|
|
68
|
+
const cover = Array.from({ length: t.rows }, () => Array(t.cols).fill(null));
|
|
69
|
+
for (let r = 0; r < t.rows; r++) for (let c = 0; c < (t.cells[r] ?? []).length; c++) {
|
|
70
|
+
const cell = t.cells[r][c], rs = Math.max(1, cell.rowSpan ?? 1), cs = Math.max(1, cell.colSpan ?? 1);
|
|
71
|
+
if (cover[r][c]) continue;
|
|
72
|
+
for (let i = r + 1; i < Math.min(t.rows, r + rs); i++) for (let j = c; j < Math.min(t.cols, c + cs); j++) cover[i][j] = cell;
|
|
73
|
+
}
|
|
74
|
+
const newRows = [];
|
|
75
|
+
for (let r = 0; r < t.rows; r++) {
|
|
76
|
+
const row = t.cells[r] ?? [];
|
|
77
|
+
const anchors = rowAnchors(t, r, cover[r]);
|
|
78
|
+
const lines = anchors.map((a) => a.cell.text.split("\n").map((s) => s.trim()).filter(Boolean));
|
|
79
|
+
const counts = /* @__PURE__ */ new Map();
|
|
80
|
+
for (const ls of lines) if (ls.length >= 2) counts.set(ls.length, (counts.get(ls.length) ?? 0) + 1);
|
|
81
|
+
const [k, n] = [...counts].sort((a, b) => b[1] - a[1])[0] ?? [0, 0];
|
|
82
|
+
const nonEmpty = lines.filter((ls) => ls.length).length;
|
|
83
|
+
const near = (ls) => ls.length >= 2 && ls.length <= k && ls.length >= Math.ceil(k * 0.8);
|
|
84
|
+
const stacked = lines.filter(near);
|
|
85
|
+
const flat = stacked.flat();
|
|
86
|
+
const numericShare = flat.length ? flat.filter((s) => NUMERIC.test(s.replace(/\s+/g, ""))).length / flat.length : 0;
|
|
87
|
+
const spanOk = anchors.every((a, i) => (a.cell.rowSpan ?? 1) === 1 || lines[i].length <= 1);
|
|
88
|
+
const ok = spanOk && k >= 2 && n >= 2 && stacked.length * 2 >= nonEmpty && lines.every((ls) => ls.length <= 1 || near(ls)) && numericShare >= 0.6;
|
|
89
|
+
if (!ok) {
|
|
90
|
+
newRows.push(row);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const sub = Array.from({ length: k }, () => Array.from({ length: row.length }, blank));
|
|
94
|
+
anchors.forEach(({ c, cell }, idx) => {
|
|
95
|
+
const ls = lines[idx], cs = Math.max(1, cell.colSpan ?? 1);
|
|
96
|
+
if (ls.length >= 2) for (let i = 0; i < k; i++) sub[i][c] = { ...cell, text: ls[i] ?? "", colSpan: cs, rowSpan: 1 };
|
|
97
|
+
else {
|
|
98
|
+
cell.rowSpan = (cell.rowSpan ?? 1) + k - 1;
|
|
99
|
+
sub[0][c] = cell;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
for (const owner of new Set(cover[r].filter((x) => !!x))) owner.rowSpan = (owner.rowSpan ?? 1) + k - 1;
|
|
103
|
+
newRows.push(...sub);
|
|
104
|
+
changed = true;
|
|
105
|
+
}
|
|
106
|
+
if (changed) {
|
|
107
|
+
t.cells = newRows;
|
|
108
|
+
t.rows = newRows.length;
|
|
109
|
+
}
|
|
110
|
+
return changed;
|
|
111
|
+
}
|
|
112
|
+
function splitStackedOcrRows(blocks) {
|
|
113
|
+
for (const b of blocks) if (b.type === "table" && b.table) splitTable(b.table);
|
|
114
|
+
return blocks;
|
|
115
|
+
}
|
|
116
|
+
function unframeOcrLayoutTables(blocks, pageHeight) {
|
|
117
|
+
const out = [];
|
|
118
|
+
for (const b of blocks) {
|
|
119
|
+
const t = b.table;
|
|
120
|
+
if (b.type !== "table" || !t || !b.bbox || b.bbox.height < pageHeight * 0.5 || t.cols > 4) {
|
|
121
|
+
out.push(b);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const anchors = [];
|
|
125
|
+
const covered = Array.from({ length: t.rows }, () => /* @__PURE__ */ new Set());
|
|
126
|
+
for (let r = 0; r < t.rows; r++) for (let c = 0; c < (t.cells[r] ?? []).length; c++) {
|
|
127
|
+
if (covered[r].has(c)) continue;
|
|
128
|
+
const cell = t.cells[r][c];
|
|
129
|
+
const rs = Math.max(1, cell.rowSpan ?? 1), cs = Math.max(1, cell.colSpan ?? 1);
|
|
130
|
+
for (let i = r; i < Math.min(t.rows, r + rs); i++) for (let j = c; j < c + cs; j++) if (i !== r || j !== c) covered[i].add(j);
|
|
131
|
+
anchors.push({ r, c, cell });
|
|
132
|
+
}
|
|
133
|
+
const texts = anchors.map((a) => a.cell.text.trim()).filter(Boolean);
|
|
134
|
+
if (!texts.length) {
|
|
135
|
+
out.push(b);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const numeric = texts.filter((s) => NUMERIC.test(s.replace(/\s+/g, ""))).length;
|
|
139
|
+
const avg = texts.reduce((n, s) => n + s.length, 0) / texts.length;
|
|
140
|
+
if (numeric >= texts.length * 0.3 || avg < 15 || texts.filter((s) => /[①-⑤]/.test(s)).length < 2) {
|
|
141
|
+
out.push(b);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
anchors.sort((a, b2) => a.c - b2.c || a.r - b2.r);
|
|
145
|
+
for (const { cell } of anchors) {
|
|
146
|
+
if (cell.blocks?.length) {
|
|
147
|
+
out.push(...cell.blocks);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const text = cell.text.trim();
|
|
151
|
+
if (text) out.push({ type: "paragraph", text, pageNumber: b.pageNumber, bbox: b.bbox });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
47
156
|
|
|
48
157
|
// src/ocr/ruling-lines.ts
|
|
49
158
|
var INK_LUMA_MAX = 205;
|
|
@@ -122,6 +231,14 @@ function detectRulingLines(rgba, width, height, scale) {
|
|
|
122
231
|
if (lo - p.x1 <= chainEnd && p.x2 - hi <= chainEnd && cover >= (p.x2 - p.x1) * 0.5) fillH.push({ ...inside[0], x1: p.x1, x2: p.x2 });
|
|
123
232
|
}
|
|
124
233
|
}
|
|
234
|
+
for (const a of fill.horizontals) {
|
|
235
|
+
if (fillH.some((f) => f === a || Math.abs(f.y1 - a.y1) <= tol && f.x1 <= a.x1 + tol && f.x2 >= a.x2 - tol)) continue;
|
|
236
|
+
const p = ruleH.find((p2) => (Math.abs(p2.x1 - a.x1) <= tol || Math.abs(p2.x2 - a.x2) <= tol) && a.x1 >= p2.x1 - tol && a.x2 <= p2.x2 + tol && a.x2 - a.x1 >= (p2.x2 - p2.x1) * 0.7);
|
|
237
|
+
if (!p || ruleH.some((q) => Math.abs(q.y1 - a.y1) <= tol)) continue;
|
|
238
|
+
const loose = Math.abs(p.x1 - a.x1) <= tol ? a.x2 : a.x1;
|
|
239
|
+
const depthPx = Math.round(FILL_MIN_DEPTH_PT * scale);
|
|
240
|
+
if (fill.verticals.some((v) => Math.abs(v.x1 - loose) <= tol * 2 && Math.abs(v.y1 - a.y1) <= tol * 2 && v.y2 - v.y1 >= depthPx * 4)) fillH.push({ ...a, x1: p.x1, x2: p.x2 });
|
|
241
|
+
}
|
|
125
242
|
horizontals.push(...fillH);
|
|
126
243
|
const edgeH = [...ruleH, ...fillH];
|
|
127
244
|
const depth = Math.round(FILL_MIN_DEPTH_PT * scale);
|
|
@@ -131,6 +248,7 @@ function detectRulingLines(rgba, width, height, scale) {
|
|
|
131
248
|
const top = edgeH.filter((h) => h.x1 <= a.x1 + tol && h.x2 >= a.x1 - tol && h.y1 < a.y1 && h.y1 >= a.y1 - depth);
|
|
132
249
|
verticals.push({ ...a, y1: top.length ? Math.min(...top.map((h) => h.y1)) : a.y1 });
|
|
133
250
|
} else if (edgeH.some((p) => (Math.abs(p.x1 - a.x1) <= tol || Math.abs(p.x2 - a.x1) <= tol) && p.y1 >= a.y1 - tol && p.y1 <= a.y2 + tol)) verticals.push(a);
|
|
251
|
+
else if ([a.y1, a.y2].every((y) => edgeH.some((p) => Math.abs(p.y1 - y) <= tol * 2 && p.x1 < a.x1 - tol && p.x2 > a.x1 + tol)) && ruleH.some((p) => p.y1 > a.y1 + tol * 2 && p.y1 < a.y2 - tol * 2 && p.x1 < a.x1 - tol && p.x2 > a.x1 + tol)) verticals.push(a);
|
|
134
252
|
}
|
|
135
253
|
for (const v of shortV) {
|
|
136
254
|
if (!endsOn(v.x1, v.y1).length || !endsOn(v.x1, v.y2).length) continue;
|
|
@@ -428,11 +546,11 @@ function trimInklessEnds(rgba, pageW, box, text, steps, stepPx) {
|
|
|
428
546
|
for (let x = Math.max(0, Math.floor(cx - half)); x <= Math.min(w - 1, Math.ceil(cx + half)); x++) if (cols[x] && cols[x] < h * 0.9) return false;
|
|
429
547
|
return true;
|
|
430
548
|
};
|
|
431
|
-
const
|
|
549
|
+
const blank2 = (i) => !chars[i].trim();
|
|
432
550
|
const mark = (i) => /\p{P}/u.test(chars[i]);
|
|
433
551
|
let a = 0, b = chars.length;
|
|
434
|
-
while (a < b && (
|
|
435
|
-
while (b > a && (
|
|
552
|
+
while (a < b && (blank2(a) || !mark(a) && inkless(a))) a++;
|
|
553
|
+
while (b > a && (blank2(b - 1) || !mark(b - 1) && inkless(b - 1))) b--;
|
|
436
554
|
const cut = (from, to) => chars.slice(from, to).some((c) => c.trim());
|
|
437
555
|
if (a === b || !cut(0, a) && !cut(b, chars.length)) return { text, steps };
|
|
438
556
|
return { text: chars.slice(a, b).join(""), steps: steps.slice(a, b) };
|
|
@@ -1126,17 +1244,17 @@ function midBlankRow(gray, w, h, ink) {
|
|
|
1126
1244
|
const isInk = (v) => ink.darkInk ? v <= ink.threshold : v > ink.threshold;
|
|
1127
1245
|
const colInk = new Uint32Array(w);
|
|
1128
1246
|
for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) if (isInk(gray[y * w + x])) colInk[x]++;
|
|
1129
|
-
const
|
|
1247
|
+
const blank2 = (y) => {
|
|
1130
1248
|
let n = 0;
|
|
1131
1249
|
for (let x = 0; x < w; x++) if (colInk[x] < h * 0.85 && isInk(gray[y * w + x])) n++;
|
|
1132
1250
|
return n <= Math.max(1, w * 0.02);
|
|
1133
1251
|
};
|
|
1134
1252
|
let best = null;
|
|
1135
1253
|
for (let y = Math.floor(h * 0.3); y < Math.ceil(h * 0.7); y++) {
|
|
1136
|
-
if (!
|
|
1254
|
+
if (!blank2(y)) continue;
|
|
1137
1255
|
let a = y, b = y + 1;
|
|
1138
|
-
while (a > 0 &&
|
|
1139
|
-
while (b < h &&
|
|
1256
|
+
while (a > 0 && blank2(a - 1)) a--;
|
|
1257
|
+
while (b < h && blank2(b)) b++;
|
|
1140
1258
|
if (!best || Math.abs((a + b) / 2 - h / 2) < Math.abs((best[0] + best[1]) / 2 - h / 2)) best = [a, b];
|
|
1141
1259
|
y = b;
|
|
1142
1260
|
}
|
|
@@ -1938,12 +2056,27 @@ function builtinOcrConfig(o) {
|
|
|
1938
2056
|
if (!o || o.ocrDet === void 0 && o.ocrDetLongSide === void 0 && o.ocrRec === void 0 && o.ocrRecDict === void 0 && !o.ocrLines) return DEFAULT_BUILTIN_OCR;
|
|
1939
2057
|
const bad = validateOcrOptions(o);
|
|
1940
2058
|
if (bad) throw new KordocError(bad);
|
|
2059
|
+
const models = resolveOcrModels(o);
|
|
1941
2060
|
return {
|
|
1942
|
-
models
|
|
2061
|
+
models,
|
|
2062
|
+
...o.ocrRec === "auto" ? { handwriting: handwritingFallbackModels(models) } : {},
|
|
1943
2063
|
tuning: o.ocrDetLongSide === void 0 ? DEFAULT_OCR_TUNING : { ...DEFAULT_OCR_TUNING, detLongSide: o.ocrDetLongSide },
|
|
1944
2064
|
lines: o.ocrLines === "all" ? "all" : o.ocrLines ? "kept" : void 0
|
|
1945
2065
|
};
|
|
1946
2066
|
}
|
|
2067
|
+
var AUTO_REC_PAGE_CONF = 0.9;
|
|
2068
|
+
var AUTO_REC_GAIN = 0.06;
|
|
2069
|
+
async function recognizeOcrPage(engine, config, tuning, rgba, width, height, stats, cellRules, rowRules) {
|
|
2070
|
+
const items = await engine.recognizePage(rgba, width, height, stats, tuning, cellRules, rowRules);
|
|
2071
|
+
if (!config.handwriting) return items;
|
|
2072
|
+
const base = meanConfidence(items);
|
|
2073
|
+
if (base >= AUTO_REC_PAGE_CONF) return items;
|
|
2074
|
+
const altStats = { droppedLowConf: 0, ...stats.dropped ? { dropped: [] } : {} };
|
|
2075
|
+
const alt = await (await getOcrEngine(config.handwriting)).recognizePage(rgba, width, height, altStats, tuning, cellRules, rowRules);
|
|
2076
|
+
if (meanConfidence(alt) - base < AUTO_REC_GAIN) return items;
|
|
2077
|
+
Object.assign(stats, altStats);
|
|
2078
|
+
return alt;
|
|
2079
|
+
}
|
|
1947
2080
|
var announced = /* @__PURE__ */ new Set();
|
|
1948
2081
|
function reportModelDownload(p) {
|
|
1949
2082
|
if (p.phase !== "download" || announced.has(p.spec.filename)) return;
|
|
@@ -1974,6 +2107,7 @@ async function runPdfOcr(buffer, targets, mode, warnings, onProgress, detectTabl
|
|
|
1974
2107
|
() => import("@hyzyla/pdfium")
|
|
1975
2108
|
);
|
|
1976
2109
|
if (mode === "builtin") await ensureOcrModelsFor(config.models, reportModelDownload);
|
|
2110
|
+
if (mode === "builtin" && config.handwriting) await ensureOcrModelsFor(config.handwriting, reportModelDownload);
|
|
1977
2111
|
const engine = mode === "builtin" ? await getOcrEngine(config.models) : null;
|
|
1978
2112
|
const pdfium = await pdfiumMod.PDFiumLibrary.init();
|
|
1979
2113
|
const doc = await pdfium.loadDocument(new Uint8Array(buffer));
|
|
@@ -2023,12 +2157,14 @@ async function ocrOnePage(page, pageNo, mode, engine, warnings, detectTables, ve
|
|
|
2023
2157
|
const stats = { droppedLowConf: 0, ...config.lines === "all" ? { dropped: [] } : {} };
|
|
2024
2158
|
const ruling = vectorOps ? void 0 : detectRulingLines(upright, rw, rh, rh / pdfH);
|
|
2025
2159
|
const tuning = regions ? regionTuning(config.tuning) : config.tuning;
|
|
2026
|
-
const items = await
|
|
2160
|
+
const items = await recognizeOcrPage(
|
|
2161
|
+
engine,
|
|
2162
|
+
config,
|
|
2163
|
+
tuning,
|
|
2027
2164
|
upright,
|
|
2028
2165
|
rw,
|
|
2029
2166
|
rh,
|
|
2030
2167
|
stats,
|
|
2031
|
-
tuning,
|
|
2032
2168
|
ruling ? [...ruling.cellDividers ?? [], ...cellEdgeVerticals(ruling)] : void 0,
|
|
2033
2169
|
ruling ? cellEdgeHorizontals(ruling) : void 0
|
|
2034
2170
|
);
|
|
@@ -2175,6 +2311,7 @@ function groupOcrLines(items, figureRegion = false) {
|
|
|
2175
2311
|
function ocrItemsToBlocks(items, pageNumber, pdfW, pdfH, scale, extraLines, detectTables = true, opList = { fnArray: [], argsArray: [] }, figureRegion = false) {
|
|
2176
2312
|
const bottoms = items.map((it) => it.y + it.h);
|
|
2177
2313
|
const xs = items.map((it) => ({ x: it.x, r: it.x + it.w, space: false }));
|
|
2314
|
+
const texts = items.map((it) => it.text);
|
|
2178
2315
|
for (const line of groupOcrLines(items, figureRegion)) {
|
|
2179
2316
|
if (line.length < 2) continue;
|
|
2180
2317
|
const sorted = line.map((j) => items[j].y + items[j].h).sort((a, b) => a - b);
|
|
@@ -2183,6 +2320,13 @@ function ocrItemsToBlocks(items, pageNumber, pdfW, pdfH, scale, extraLines, dete
|
|
|
2183
2320
|
for (let k = 1; k < byX.length; k++) {
|
|
2184
2321
|
const L = xs[byX[k - 1]], R = xs[byX[k]];
|
|
2185
2322
|
if (R.x >= L.r) continue;
|
|
2323
|
+
const lt = [...texts[byX[k - 1]]], rt = [...texts[byX[k]]], per = items[byX[k]].w / Math.max(1, rt.length);
|
|
2324
|
+
for (let n = Math.min(3, rt.length, lt.length); n >= 1; n--) {
|
|
2325
|
+
if (lt.slice(-n).join("") === rt.slice(0, n).join("") && /[가-힣]/.test(rt[0]) && L.r - R.x >= per * n * 0.5) {
|
|
2326
|
+
texts[byX[k]] = rt.slice(n).join("");
|
|
2327
|
+
break;
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2186
2330
|
const mid = (R.x + L.r) / 2, half = Math.min(items[byX[k - 1]].h, items[byX[k]].h) * 0.15;
|
|
2187
2331
|
L.r = Math.max(L.x + 1, mid - half);
|
|
2188
2332
|
R.x = Math.min(R.r - 1, mid + half);
|
|
@@ -2192,7 +2336,7 @@ function ocrItemsToBlocks(items, pageNumber, pdfW, pdfH, scale, extraLines, dete
|
|
|
2192
2336
|
const norm = items.map((it, i) => {
|
|
2193
2337
|
const h = (figureRegion ? Math.max(1, bottoms[i] - it.y) : it.h) / scale;
|
|
2194
2338
|
const normalized = {
|
|
2195
|
-
text:
|
|
2339
|
+
text: texts[i],
|
|
2196
2340
|
x: Math.round(xs[i].x / scale),
|
|
2197
2341
|
// NormItem.y 는 pdfjs transform[5] = 베이스라인 (bottom-up) — 잉크 하단으로 근사
|
|
2198
2342
|
y: Math.round(pdfH - bottoms[i] / scale),
|
|
@@ -2206,8 +2350,50 @@ function ocrItemsToBlocks(items, pageNumber, pdfW, pdfH, scale, extraLines, dete
|
|
|
2206
2350
|
};
|
|
2207
2351
|
copyOcrTextGaps(it, normalized, 1 / scale);
|
|
2208
2352
|
return normalized;
|
|
2209
|
-
});
|
|
2210
|
-
|
|
2353
|
+
}).filter((it) => it.text);
|
|
2354
|
+
const blocks = unframeOcrLayoutTables(splitStackedOcrRows(extractPageBlocksWithLines(norm, pageNumber, opList, pdfW, pdfH, extraLines, detectTables)), pdfH);
|
|
2355
|
+
if (!figureRegion) markOcrHeadings(blocks);
|
|
2356
|
+
return blocks;
|
|
2357
|
+
}
|
|
2358
|
+
function markOcrHeadings(blocks) {
|
|
2359
|
+
const sized = blocks.filter((b) => b.type === "paragraph" && b.text && b.style?.fontSize);
|
|
2360
|
+
const weights = sized.map((b) => [b.style.fontSize, b.text.length]);
|
|
2361
|
+
const total = weights.reduce((n, [, w]) => n + w, 0);
|
|
2362
|
+
if (total < 100) return;
|
|
2363
|
+
weights.sort((a, b) => a[0] - b[0]);
|
|
2364
|
+
let acc = 0, body = 0;
|
|
2365
|
+
for (const [size, w] of weights) {
|
|
2366
|
+
acc += w;
|
|
2367
|
+
if (acc >= total / 2) {
|
|
2368
|
+
body = size;
|
|
2369
|
+
break;
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
if (!body) return;
|
|
2373
|
+
for (const b of sized) {
|
|
2374
|
+
const text = b.text.trim(), size = b.style.fontSize;
|
|
2375
|
+
const ratio = size / body;
|
|
2376
|
+
if (ratio < 1.3) continue;
|
|
2377
|
+
if (text.length < 2 || text.length > (ratio >= 1.5 ? 60 : 40) || /[.!?。]$|다\.?$/.test(text) || /^[\d\s.,%·-]+$/.test(text)) continue;
|
|
2378
|
+
if (b.bbox && b.bbox.height > size * (ratio >= 1.5 ? 3.2 : 1.6)) continue;
|
|
2379
|
+
b.type = "heading";
|
|
2380
|
+
b.level = ratio >= 1.5 ? 1 : 2;
|
|
2381
|
+
}
|
|
2382
|
+
for (let i = blocks.length - 1; i > 0; i--) {
|
|
2383
|
+
const a = blocks[i - 1], b = blocks[i];
|
|
2384
|
+
if (a.type !== "heading" || b.type !== "heading" || !a.bbox || !b.bbox) continue;
|
|
2385
|
+
const marker = /^(?:제\s*\d+\s*[장절편부]|chapter\s*\d+|part\s*\d+)$/i.test(a.text.trim());
|
|
2386
|
+
const sa = a.style?.fontSize ?? 0, sb = b.style?.fontSize ?? 0;
|
|
2387
|
+
if (!marker && (a.level !== b.level || Math.max(sa, sb) > Math.min(sa, sb) * 1.3)) continue;
|
|
2388
|
+
const gap = a.bbox.y - (b.bbox.y + b.bbox.height), size = Math.max(a.style?.fontSize ?? 0, b.style?.fontSize ?? 0);
|
|
2389
|
+
const across = Math.min(a.bbox.x + a.bbox.width, b.bbox.x + b.bbox.width) - Math.max(a.bbox.x, b.bbox.x);
|
|
2390
|
+
if (gap < 0 || gap > size * (marker ? 3 : 1.2) || across <= 0) continue;
|
|
2391
|
+
a.level = Math.min(a.level ?? 2, b.level ?? 2);
|
|
2392
|
+
a.text = `${a.text.trim()} ${b.text.trim()}`;
|
|
2393
|
+
const x = Math.min(a.bbox.x, b.bbox.x);
|
|
2394
|
+
a.bbox = { ...a.bbox, x, y: b.bbox.y, width: Math.max(a.bbox.x + a.bbox.width, b.bbox.x + b.bbox.width) - x, height: a.bbox.y + a.bbox.height - b.bbox.y };
|
|
2395
|
+
blocks.splice(i, 1);
|
|
2396
|
+
}
|
|
2211
2397
|
}
|
|
2212
2398
|
async function tryImport2(name, loader) {
|
|
2213
2399
|
try {
|
|
@@ -2252,6 +2438,7 @@ export {
|
|
|
2252
2438
|
MAX_OCR_PIXELS,
|
|
2253
2439
|
DEFAULT_BUILTIN_OCR,
|
|
2254
2440
|
builtinOcrConfig,
|
|
2441
|
+
recognizeOcrPage,
|
|
2255
2442
|
reportModelDownload,
|
|
2256
2443
|
toOcrLine,
|
|
2257
2444
|
pageLines,
|
|
@@ -2260,6 +2447,7 @@ export {
|
|
|
2260
2447
|
runPdfOcr,
|
|
2261
2448
|
ocrOnePage,
|
|
2262
2449
|
groupOcrLines,
|
|
2263
|
-
ocrItemsToBlocks
|
|
2450
|
+
ocrItemsToBlocks,
|
|
2451
|
+
markOcrHeadings
|
|
2264
2452
|
};
|
|
2265
|
-
//# sourceMappingURL=chunk-
|
|
2453
|
+
//# sourceMappingURL=chunk-5IYRVLGJ.js.map
|