kordoc 4.2.0 → 4.2.1

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 (95) hide show
  1. package/README.md +15 -8
  2. package/dist/{-SXQIZHYA.js → -BSO3CDQQ.js} +12 -10
  3. package/dist/{pdf-ocr-2Z7VZIFI.cjs → chunk-35U3MVA2.cjs} +129 -8
  4. package/dist/chunk-35U3MVA2.cjs.map +1 -0
  5. package/dist/{chunk-4VNLZ2GZ.js → chunk-54WVWWT4.js} +1 -1
  6. package/dist/{chunk-4VNLZ2GZ.js.map → chunk-54WVWWT4.js.map} +1 -1
  7. package/dist/{chunk-WF2E5P2G.js → chunk-7IMNZ2BL.js} +2 -2
  8. package/dist/{chunk-V6U6YS5B.js → chunk-BHILWIE6.js} +2 -2
  9. package/dist/{chunk-PLIY23LY.js → chunk-BKBYTPSL.js} +2 -2
  10. package/dist/{chunk-4JPPLIIV.js → chunk-EZHWPKCH.js} +8 -3
  11. package/dist/{chunk-4JPPLIIV.js.map → chunk-EZHWPKCH.js.map} +1 -1
  12. package/dist/{pdf-ocr-VYE4DHD4.js → chunk-F5ECB53I.js} +128 -9
  13. package/dist/chunk-F5ECB53I.js.map +1 -0
  14. package/dist/{chunk-JP5YH3Z4.js → chunk-HTCKGSSW.js} +2 -2
  15. package/dist/{chunk-JP5YH3Z4.js.map → chunk-HTCKGSSW.js.map} +1 -1
  16. package/dist/{pdf-ocr-FJFXFADQ.js → chunk-KRAYUNFM.js} +129 -7
  17. package/dist/chunk-KRAYUNFM.js.map +1 -0
  18. package/dist/{chunk-26AJJCFF.js → chunk-L5JWKIOT.js} +9 -4
  19. package/dist/{chunk-26AJJCFF.js.map → chunk-L5JWKIOT.js.map} +1 -1
  20. package/dist/{chunk-XTCT6KQ5.cjs → chunk-LSXXGUWA.cjs} +4 -4
  21. package/dist/{chunk-XTCT6KQ5.cjs.map → chunk-LSXXGUWA.cjs.map} +1 -1
  22. package/dist/{chunk-6SHO3BNV.js → chunk-PLTG6ZRF.js} +3 -3
  23. package/dist/{chunk-ELOV2GIJ.js → chunk-QOC7S5VE.js} +2 -2
  24. package/dist/{chunk-CMN3SYZ3.js → chunk-QSB2RTX5.js} +2 -2
  25. package/dist/{chunk-LHROM2BO.cjs → chunk-R22KDUKW.cjs} +15 -10
  26. package/dist/chunk-R22KDUKW.cjs.map +1 -0
  27. package/dist/{chunk-F2HYH62H.cjs → chunk-RBUBZ2TA.cjs} +2 -2
  28. package/dist/{chunk-F2HYH62H.cjs.map → chunk-RBUBZ2TA.cjs.map} +1 -1
  29. package/dist/{chunk-YOO6ET6M.js → chunk-TCJRGFYY.js} +11 -1
  30. package/dist/chunk-TCJRGFYY.js.map +1 -0
  31. package/dist/{chunk-WQLHPOMJ.js → chunk-WJSGYVFD.js} +3 -3
  32. package/dist/{chunk-IGGRLWT5.js → chunk-WWYAYZ5U.js} +28 -9
  33. package/dist/chunk-WWYAYZ5U.js.map +1 -0
  34. package/dist/{chunk-FSXLSHCW.js → chunk-Z6LPEWIX.js} +2 -2
  35. package/dist/chunks-LRFS5NJE.js +10 -0
  36. package/dist/cli.js +19 -19
  37. package/dist/cli.js.map +1 -1
  38. package/dist/{detect-YEZX2XCF.js → detect-FX2ZHKZP.js} +4 -2
  39. package/dist/image-ocr-DALT7PFQ.js +65 -0
  40. package/dist/image-ocr-DALT7PFQ.js.map +1 -0
  41. package/dist/image-ocr-N5Z32R4U.cjs +66 -0
  42. package/dist/image-ocr-N5Z32R4U.cjs.map +1 -0
  43. package/dist/image-ocr-SLUEM3FA.js +69 -0
  44. package/dist/image-ocr-SLUEM3FA.js.map +1 -0
  45. package/dist/index.cjs +176 -148
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.d.cts +4 -2
  48. package/dist/index.d.ts +4 -2
  49. package/dist/index.js +31 -3
  50. package/dist/index.js.map +1 -1
  51. package/dist/mcp.js +19 -19
  52. package/dist/mcp.js.map +1 -1
  53. package/dist/{parser-ND2YGQZR.js → parser-33TK5SMH.js} +5 -5
  54. package/dist/{parser-RBZHA6SY.js → parser-F5KY3YSD.js} +6 -6
  55. package/dist/{parser-WDZOMDG4.cjs → parser-R4CXIXRN.cjs} +24 -24
  56. package/dist/{parser-WDZOMDG4.cjs.map → parser-R4CXIXRN.cjs.map} +1 -1
  57. package/dist/pdf-ocr-34F5AQKK.js +12 -0
  58. package/dist/pdf-ocr-BXQZKU3N.js +15 -0
  59. package/dist/pdf-ocr-WGWZDHMV.cjs +13 -0
  60. package/dist/pdf-ocr-WGWZDHMV.cjs.map +1 -0
  61. package/dist/{profile-io-TWHDIVPL.js → profile-io-CBYHKLFU.js} +3 -3
  62. package/dist/{rasterize-W2NEZUSW.js → rasterize-AWMM2CSW.js} +2 -2
  63. package/dist/render-Y3IE2FIK.js +10 -0
  64. package/dist/render-Y3IE2FIK.js.map +1 -0
  65. package/dist/seal-7RXFCRMT.js +10 -0
  66. package/dist/seal-7RXFCRMT.js.map +1 -0
  67. package/dist/{watch-VWXJZT2R.js → watch-HKXCISVO.js} +10 -10
  68. package/package.json +1 -1
  69. package/dist/chunk-IGGRLWT5.js.map +0 -1
  70. package/dist/chunk-LHROM2BO.cjs.map +0 -1
  71. package/dist/chunk-YOO6ET6M.js.map +0 -1
  72. package/dist/chunks-ZQEFAZNC.js +0 -10
  73. package/dist/pdf-ocr-2Z7VZIFI.cjs.map +0 -1
  74. package/dist/pdf-ocr-FJFXFADQ.js.map +0 -1
  75. package/dist/pdf-ocr-VYE4DHD4.js.map +0 -1
  76. package/dist/render-4MG5QUDG.js +0 -10
  77. package/dist/seal-D2QNXJVO.js +0 -10
  78. /package/dist/{-SXQIZHYA.js.map → -BSO3CDQQ.js.map} +0 -0
  79. /package/dist/{chunk-WF2E5P2G.js.map → chunk-7IMNZ2BL.js.map} +0 -0
  80. /package/dist/{chunk-V6U6YS5B.js.map → chunk-BHILWIE6.js.map} +0 -0
  81. /package/dist/{chunk-PLIY23LY.js.map → chunk-BKBYTPSL.js.map} +0 -0
  82. /package/dist/{chunk-6SHO3BNV.js.map → chunk-PLTG6ZRF.js.map} +0 -0
  83. /package/dist/{chunk-ELOV2GIJ.js.map → chunk-QOC7S5VE.js.map} +0 -0
  84. /package/dist/{chunk-CMN3SYZ3.js.map → chunk-QSB2RTX5.js.map} +0 -0
  85. /package/dist/{chunk-WQLHPOMJ.js.map → chunk-WJSGYVFD.js.map} +0 -0
  86. /package/dist/{chunk-FSXLSHCW.js.map → chunk-Z6LPEWIX.js.map} +0 -0
  87. /package/dist/{chunks-ZQEFAZNC.js.map → chunks-LRFS5NJE.js.map} +0 -0
  88. /package/dist/{detect-YEZX2XCF.js.map → detect-FX2ZHKZP.js.map} +0 -0
  89. /package/dist/{parser-ND2YGQZR.js.map → parser-33TK5SMH.js.map} +0 -0
  90. /package/dist/{parser-RBZHA6SY.js.map → parser-F5KY3YSD.js.map} +0 -0
  91. /package/dist/{profile-io-TWHDIVPL.js.map → pdf-ocr-34F5AQKK.js.map} +0 -0
  92. /package/dist/{render-4MG5QUDG.js.map → pdf-ocr-BXQZKU3N.js.map} +0 -0
  93. /package/dist/{seal-D2QNXJVO.js.map → profile-io-CBYHKLFU.js.map} +0 -0
  94. /package/dist/{rasterize-W2NEZUSW.js.map → rasterize-AWMM2CSW.js.map} +0 -0
  95. /package/dist/{watch-VWXJZT2R.js.map → watch-HKXCISVO.js.map} +0 -0
@@ -6,10 +6,11 @@ import {
6
6
  isHwp3File,
7
7
  isHwpmlFile,
8
8
  isHwpxFile,
9
+ isImageFile,
9
10
  isOldHwpFile,
10
11
  isPdfFile,
11
12
  isZipFile
12
- } from "./chunk-YOO6ET6M.js";
13
+ } from "./chunk-TCJRGFYY.js";
13
14
  export {
14
15
  detectFormat,
15
16
  detectOle2Format,
@@ -17,8 +18,9 @@ export {
17
18
  isHwp3File,
18
19
  isHwpmlFile,
19
20
  isHwpxFile,
21
+ isImageFile,
20
22
  isOldHwpFile,
21
23
  isPdfFile,
22
24
  isZipFile
23
25
  };
24
- //# sourceMappingURL=detect-YEZX2XCF.js.map
26
+ //# sourceMappingURL=detect-FX2ZHKZP.js.map
@@ -0,0 +1,65 @@
1
+ import {
2
+ detectRulingLines,
3
+ ensureOcrModels,
4
+ getOcrEngine,
5
+ ocrItemsToBlocks,
6
+ rulingToPdfLines
7
+ } from "./chunk-KRAYUNFM.js";
8
+ import "./chunk-J2RZ444H.js";
9
+ import "./chunk-EZHWPKCH.js";
10
+ import "./chunk-HTCKGSSW.js";
11
+
12
+ // src/ocr/image-ocr.ts
13
+ var IMAGE_SCALE = 3;
14
+ async function parseImageDocument(buffer, options) {
15
+ const warnings = [];
16
+ if (typeof options?.ocr === "function") {
17
+ const text = await options.ocr(new Uint8Array(buffer), 1, detectImageMime(buffer));
18
+ if (!text.trim()) {
19
+ warnings.push({ page: 1, message: "OCR \uACB0\uACFC \uC5C6\uC74C", code: "OCR_FAILED" });
20
+ return { blocks: [], warnings };
21
+ }
22
+ return { blocks: [{ type: "paragraph", text: text.trim(), pageNumber: 1 }], warnings };
23
+ }
24
+ const { data, width, height } = await decodeToRgba(buffer);
25
+ await ensureOcrModels((p) => {
26
+ if (p.phase === "download" && p.downloaded === 0) {
27
+ process.stderr.write(`[kordoc-ocr] ${p.spec.name} \uB2E4\uC6B4\uB85C\uB4DC \uC911 (~${p.spec.sizeMb}MB)...
28
+ `);
29
+ }
30
+ });
31
+ const engine = await getOcrEngine();
32
+ const items = await engine.recognizePage(data, width, height);
33
+ if (items.length === 0) {
34
+ warnings.push({ page: 1, message: "\uC774\uBBF8\uC9C0\uC5D0\uC11C \uD14D\uC2A4\uD2B8\uB97C \uC778\uC2DD\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", code: "OCR_FAILED" });
35
+ return { blocks: [], warnings };
36
+ }
37
+ const pdfW = width / IMAGE_SCALE;
38
+ const pdfH = height / IMAGE_SCALE;
39
+ const ruling = detectRulingLines(data, width, height, IMAGE_SCALE);
40
+ const extraLines = rulingToPdfLines(ruling, IMAGE_SCALE, pdfH);
41
+ return { blocks: ocrItemsToBlocks(items, 1, pdfW, pdfH, IMAGE_SCALE, extraLines), warnings };
42
+ }
43
+ async function decodeToRgba(buffer) {
44
+ let sharp;
45
+ try {
46
+ const mod = await import("sharp");
47
+ sharp = typeof mod === "function" ? mod : mod.default ?? mod;
48
+ } catch (e) {
49
+ throw new Error(
50
+ `\uC774\uBBF8\uC9C0 \uD30C\uC2F1\uC5D0\uB294 optional dependency 'sharp' \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \`npm install sharp\` \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694. \uC6D0\uC778: ${e.message}`
51
+ );
52
+ }
53
+ const { data, info } = await sharp(Buffer.from(buffer)).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
54
+ return { data: new Uint8Array(data.buffer, data.byteOffset, data.byteLength), width: info.width, height: info.height };
55
+ }
56
+ function detectImageMime(buffer) {
57
+ const b = new Uint8Array(buffer, 0, Math.min(12, buffer.byteLength));
58
+ if (b[0] === 255 && b[1] === 216) return "image/jpeg";
59
+ if (b[0] === 82 && b[1] === 73) return "image/webp";
60
+ return "image/png";
61
+ }
62
+ export {
63
+ parseImageDocument
64
+ };
65
+ //# sourceMappingURL=image-ocr-DALT7PFQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ocr/image-ocr.ts"],"sourcesContent":["/**\n * 이미지 직접 입력 OCR — PNG/JPEG/WebP 를 PDF 래핑 없이 바로 파싱한다.\n *\n * 이미지는 텍스트층이 없으므로 OCR 이 항상 필요하다 — `--ocr` 플래그 없이도\n * 내장 엔진(PP-OCRv5 korean)을 기본 적용하고, OcrProvider 가 주어지면 위임한다.\n * 좌표는 216dpi(스케일 3) 가정으로 PDF pt 공간에 환산해 기존 블록 파이프라인\n * (괘선 감지 → 선 기반 표 → 클러스터 → xy-cut)을 그대로 태운다.\n *\n * 디코딩은 optional dependency `sharp` — 미설치면 MISSING_DEPENDENCY 안내.\n */\n\nimport type { IRBlock, ParseOptions, ParseWarning } from \"../types.js\"\nimport { getOcrEngine } from \"./engine.js\"\nimport { ensureOcrModels } from \"./models.js\"\nimport { detectRulingLines, rulingToPdfLines } from \"./ruling-lines.js\"\nimport { ocrItemsToBlocks } from \"./pdf-ocr.js\"\n\n/** 좌표 환산 스케일 (px/pt) — PDF OCR 렌더(216dpi)와 동일 기준 */\nconst IMAGE_SCALE = 3\n\nexport interface ImageOcrResult {\n blocks: IRBlock[]\n warnings: ParseWarning[]\n}\n\n/** 이미지 버퍼 → OCR → IRBlock[] (표 괘선 감지 포함) */\nexport async function parseImageDocument(\n buffer: ArrayBuffer,\n options?: ParseOptions,\n): Promise<ImageOcrResult> {\n const warnings: ParseWarning[] = []\n\n // 사용자 OcrProvider — 원본 바이트 그대로 위임 (종전 PDF 경로와 같은 계약)\n if (typeof options?.ocr === \"function\") {\n const text = await options.ocr(new Uint8Array(buffer), 1, detectImageMime(buffer))\n if (!text.trim()) {\n warnings.push({ page: 1, message: \"OCR 결과 없음\", code: \"OCR_FAILED\" })\n return { blocks: [], warnings }\n }\n return { blocks: [{ type: \"paragraph\", text: text.trim(), pageNumber: 1 }], warnings }\n }\n\n const { data, width, height } = await decodeToRgba(buffer)\n\n await ensureOcrModels(p => {\n if (p.phase === \"download\" && p.downloaded === 0) {\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 다운로드 중 (~${p.spec.sizeMb}MB)...\\n`)\n }\n })\n const engine = await getOcrEngine()\n const items = await engine.recognizePage(data, width, height)\n if (items.length === 0) {\n warnings.push({ page: 1, message: \"이미지에서 텍스트를 인식하지 못했습니다\", code: \"OCR_FAILED\" })\n return { blocks: [], warnings }\n }\n\n const pdfW = width / IMAGE_SCALE\n const pdfH = height / IMAGE_SCALE\n const ruling = detectRulingLines(data, width, height, IMAGE_SCALE)\n const extraLines = rulingToPdfLines(ruling, IMAGE_SCALE, pdfH)\n return { blocks: ocrItemsToBlocks(items, 1, pdfW, pdfH, IMAGE_SCALE, extraLines), warnings }\n}\n\n/** sharp 로 RGBA 디코딩 — 미설치는 MISSING_DEPENDENCY 로 분류되도록 안내 메시지 throw */\nasync function decodeToRgba(\n buffer: ArrayBuffer,\n): Promise<{ data: Uint8Array; width: number; height: number }> {\n type SharpFactory = (input: Buffer) => {\n ensureAlpha(): { raw(): { toBuffer(opts: { resolveWithObject: true }): Promise<{ data: Buffer; info: { width: number; height: number } }> } }\n }\n let sharp: SharpFactory\n try {\n const mod = (await import(\"sharp\")) as unknown as { default?: SharpFactory } & SharpFactory\n sharp = typeof mod === \"function\" ? mod : (mod.default ?? (mod as unknown as SharpFactory))\n } catch (e) {\n throw new Error(\n \"이미지 파싱에는 optional dependency 'sharp' 가 필요합니다. \" +\n `\\`npm install sharp\\` 후 다시 실행하세요. 원인: ${(e as Error).message}`,\n )\n }\n const { data, info } = await sharp(Buffer.from(buffer)).ensureAlpha().raw().toBuffer({ resolveWithObject: true })\n return { data: new Uint8Array(data.buffer, data.byteOffset, data.byteLength), width: info.width, height: info.height }\n}\n\n/** OcrProvider 계약용 mime 판별 */\nfunction detectImageMime(buffer: ArrayBuffer): string {\n const b = new Uint8Array(buffer, 0, Math.min(12, buffer.byteLength))\n if (b[0] === 0xff && b[1] === 0xd8) return \"image/jpeg\"\n if (b[0] === 0x52 && b[1] === 0x49) return \"image/webp\"\n return \"image/png\"\n}\n"],"mappings":";;;;;;;;;;;;AAkBA,IAAM,cAAc;AAQpB,eAAsB,mBACpB,QACA,SACyB;AACzB,QAAM,WAA2B,CAAC;AAGlC,MAAI,OAAO,SAAS,QAAQ,YAAY;AACtC,UAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,WAAW,MAAM,GAAG,GAAG,gBAAgB,MAAM,CAAC;AACjF,QAAI,CAAC,KAAK,KAAK,GAAG;AAChB,eAAS,KAAK,EAAE,MAAM,GAAG,SAAS,iCAAa,MAAM,aAAa,CAAC;AACnE,aAAO,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,IAChC;AACA,WAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,aAAa,MAAM,KAAK,KAAK,GAAG,YAAY,EAAE,CAAC,GAAG,SAAS;AAAA,EACvF;AAEA,QAAM,EAAE,MAAM,OAAO,OAAO,IAAI,MAAM,aAAa,MAAM;AAEzD,QAAM,gBAAgB,OAAK;AACzB,QAAI,EAAE,UAAU,cAAc,EAAE,eAAe,GAAG;AAChD,cAAQ,OAAO,MAAM,gBAAgB,EAAE,KAAK,IAAI,sCAAa,EAAE,KAAK,MAAM;AAAA,CAAU;AAAA,IACtF;AAAA,EACF,CAAC;AACD,QAAM,SAAS,MAAM,aAAa;AAClC,QAAM,QAAQ,MAAM,OAAO,cAAc,MAAM,OAAO,MAAM;AAC5D,MAAI,MAAM,WAAW,GAAG;AACtB,aAAS,KAAK,EAAE,MAAM,GAAG,SAAS,mHAAyB,MAAM,aAAa,CAAC;AAC/E,WAAO,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,EAChC;AAEA,QAAM,OAAO,QAAQ;AACrB,QAAM,OAAO,SAAS;AACtB,QAAM,SAAS,kBAAkB,MAAM,OAAO,QAAQ,WAAW;AACjE,QAAM,aAAa,iBAAiB,QAAQ,aAAa,IAAI;AAC7D,SAAO,EAAE,QAAQ,iBAAiB,OAAO,GAAG,MAAM,MAAM,aAAa,UAAU,GAAG,SAAS;AAC7F;AAGA,eAAe,aACb,QAC8D;AAI9D,MAAI;AACJ,MAAI;AACF,UAAM,MAAO,MAAM,OAAO,OAAO;AACjC,YAAQ,OAAO,QAAQ,aAAa,MAAO,IAAI,WAAY;AAAA,EAC7D,SAAS,GAAG;AACV,UAAM,IAAI;AAAA,MACR,0MAC4C,EAAY,OAAO;AAAA,IACjE;AAAA,EACF;AACA,QAAM,EAAE,MAAM,KAAK,IAAI,MAAM,MAAM,OAAO,KAAK,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,KAAK,CAAC;AAChH,SAAO,EAAE,MAAM,IAAI,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,GAAG,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO;AACvH;AAGA,SAAS,gBAAgB,QAA6B;AACpD,QAAM,IAAI,IAAI,WAAW,QAAQ,GAAG,KAAK,IAAI,IAAI,OAAO,UAAU,CAAC;AACnE,MAAI,EAAE,CAAC,MAAM,OAAQ,EAAE,CAAC,MAAM,IAAM,QAAO;AAC3C,MAAI,EAAE,CAAC,MAAM,MAAQ,EAAE,CAAC,MAAM,GAAM,QAAO;AAC3C,SAAO;AACT;","names":[]}
@@ -0,0 +1,66 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+
7
+ var _chunk35U3MVA2cjs = require('./chunk-35U3MVA2.cjs');
8
+ require('./chunk-H7OWEYH2.cjs');
9
+ require('./chunk-R22KDUKW.cjs');
10
+ require('./chunk-RBUBZ2TA.cjs');
11
+ require('./chunk-GS7T56RP.cjs');
12
+
13
+ // src/ocr/image-ocr.ts
14
+ var IMAGE_SCALE = 3;
15
+ async function parseImageDocument(buffer, options) {
16
+ const warnings = [];
17
+ if (typeof _optionalChain([options, 'optionalAccess', _ => _.ocr]) === "function") {
18
+ const text = await options.ocr(new Uint8Array(buffer), 1, detectImageMime(buffer));
19
+ if (!text.trim()) {
20
+ warnings.push({ page: 1, message: "OCR \uACB0\uACFC \uC5C6\uC74C", code: "OCR_FAILED" });
21
+ return { blocks: [], warnings };
22
+ }
23
+ return { blocks: [{ type: "paragraph", text: text.trim(), pageNumber: 1 }], warnings };
24
+ }
25
+ const { data, width, height } = await decodeToRgba(buffer);
26
+ await _chunk35U3MVA2cjs.ensureOcrModels.call(void 0, (p) => {
27
+ if (p.phase === "download" && p.downloaded === 0) {
28
+ process.stderr.write(`[kordoc-ocr] ${p.spec.name} \uB2E4\uC6B4\uB85C\uB4DC \uC911 (~${p.spec.sizeMb}MB)...
29
+ `);
30
+ }
31
+ });
32
+ const engine = await _chunk35U3MVA2cjs.getOcrEngine.call(void 0, );
33
+ const items = await engine.recognizePage(data, width, height);
34
+ if (items.length === 0) {
35
+ warnings.push({ page: 1, message: "\uC774\uBBF8\uC9C0\uC5D0\uC11C \uD14D\uC2A4\uD2B8\uB97C \uC778\uC2DD\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", code: "OCR_FAILED" });
36
+ return { blocks: [], warnings };
37
+ }
38
+ const pdfW = width / IMAGE_SCALE;
39
+ const pdfH = height / IMAGE_SCALE;
40
+ const ruling = _chunk35U3MVA2cjs.detectRulingLines.call(void 0, data, width, height, IMAGE_SCALE);
41
+ const extraLines = _chunk35U3MVA2cjs.rulingToPdfLines.call(void 0, ruling, IMAGE_SCALE, pdfH);
42
+ return { blocks: _chunk35U3MVA2cjs.ocrItemsToBlocks.call(void 0, items, 1, pdfW, pdfH, IMAGE_SCALE, extraLines), warnings };
43
+ }
44
+ async function decodeToRgba(buffer) {
45
+ let sharp;
46
+ try {
47
+ const mod = await Promise.resolve().then(() => _interopRequireWildcard(require("sharp")));
48
+ sharp = typeof mod === "function" ? mod : _nullishCoalesce(mod.default, () => ( mod));
49
+ } catch (e) {
50
+ throw new Error(
51
+ `\uC774\uBBF8\uC9C0 \uD30C\uC2F1\uC5D0\uB294 optional dependency 'sharp' \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \`npm install sharp\` \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694. \uC6D0\uC778: ${e.message}`
52
+ );
53
+ }
54
+ const { data, info } = await sharp(Buffer.from(buffer)).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
55
+ return { data: new Uint8Array(data.buffer, data.byteOffset, data.byteLength), width: info.width, height: info.height };
56
+ }
57
+ function detectImageMime(buffer) {
58
+ const b = new Uint8Array(buffer, 0, Math.min(12, buffer.byteLength));
59
+ if (b[0] === 255 && b[1] === 216) return "image/jpeg";
60
+ if (b[0] === 82 && b[1] === 73) return "image/webp";
61
+ return "image/png";
62
+ }
63
+
64
+
65
+ exports.parseImageDocument = parseImageDocument;
66
+ //# sourceMappingURL=image-ocr-N5Z32R4U.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/chris_gomdori/workspace/kordoc/dist/image-ocr-N5Z32R4U.cjs","../src/ocr/image-ocr.ts"],"names":[],"mappings":"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","file":"/Users/chris_gomdori/workspace/kordoc/dist/image-ocr-N5Z32R4U.cjs","sourcesContent":[null,"/**\n * 이미지 직접 입력 OCR — PNG/JPEG/WebP 를 PDF 래핑 없이 바로 파싱한다.\n *\n * 이미지는 텍스트층이 없으므로 OCR 이 항상 필요하다 — `--ocr` 플래그 없이도\n * 내장 엔진(PP-OCRv5 korean)을 기본 적용하고, OcrProvider 가 주어지면 위임한다.\n * 좌표는 216dpi(스케일 3) 가정으로 PDF pt 공간에 환산해 기존 블록 파이프라인\n * (괘선 감지 → 선 기반 표 → 클러스터 → xy-cut)을 그대로 태운다.\n *\n * 디코딩은 optional dependency `sharp` — 미설치면 MISSING_DEPENDENCY 안내.\n */\n\nimport type { IRBlock, ParseOptions, ParseWarning } from \"../types.js\"\nimport { getOcrEngine } from \"./engine.js\"\nimport { ensureOcrModels } from \"./models.js\"\nimport { detectRulingLines, rulingToPdfLines } from \"./ruling-lines.js\"\nimport { ocrItemsToBlocks } from \"./pdf-ocr.js\"\n\n/** 좌표 환산 스케일 (px/pt) — PDF OCR 렌더(216dpi)와 동일 기준 */\nconst IMAGE_SCALE = 3\n\nexport interface ImageOcrResult {\n blocks: IRBlock[]\n warnings: ParseWarning[]\n}\n\n/** 이미지 버퍼 → OCR → IRBlock[] (표 괘선 감지 포함) */\nexport async function parseImageDocument(\n buffer: ArrayBuffer,\n options?: ParseOptions,\n): Promise<ImageOcrResult> {\n const warnings: ParseWarning[] = []\n\n // 사용자 OcrProvider — 원본 바이트 그대로 위임 (종전 PDF 경로와 같은 계약)\n if (typeof options?.ocr === \"function\") {\n const text = await options.ocr(new Uint8Array(buffer), 1, detectImageMime(buffer))\n if (!text.trim()) {\n warnings.push({ page: 1, message: \"OCR 결과 없음\", code: \"OCR_FAILED\" })\n return { blocks: [], warnings }\n }\n return { blocks: [{ type: \"paragraph\", text: text.trim(), pageNumber: 1 }], warnings }\n }\n\n const { data, width, height } = await decodeToRgba(buffer)\n\n await ensureOcrModels(p => {\n if (p.phase === \"download\" && p.downloaded === 0) {\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 다운로드 중 (~${p.spec.sizeMb}MB)...\\n`)\n }\n })\n const engine = await getOcrEngine()\n const items = await engine.recognizePage(data, width, height)\n if (items.length === 0) {\n warnings.push({ page: 1, message: \"이미지에서 텍스트를 인식하지 못했습니다\", code: \"OCR_FAILED\" })\n return { blocks: [], warnings }\n }\n\n const pdfW = width / IMAGE_SCALE\n const pdfH = height / IMAGE_SCALE\n const ruling = detectRulingLines(data, width, height, IMAGE_SCALE)\n const extraLines = rulingToPdfLines(ruling, IMAGE_SCALE, pdfH)\n return { blocks: ocrItemsToBlocks(items, 1, pdfW, pdfH, IMAGE_SCALE, extraLines), warnings }\n}\n\n/** sharp 로 RGBA 디코딩 — 미설치는 MISSING_DEPENDENCY 로 분류되도록 안내 메시지 throw */\nasync function decodeToRgba(\n buffer: ArrayBuffer,\n): Promise<{ data: Uint8Array; width: number; height: number }> {\n type SharpFactory = (input: Buffer) => {\n ensureAlpha(): { raw(): { toBuffer(opts: { resolveWithObject: true }): Promise<{ data: Buffer; info: { width: number; height: number } }> } }\n }\n let sharp: SharpFactory\n try {\n const mod = (await import(\"sharp\")) as unknown as { default?: SharpFactory } & SharpFactory\n sharp = typeof mod === \"function\" ? mod : (mod.default ?? (mod as unknown as SharpFactory))\n } catch (e) {\n throw new Error(\n \"이미지 파싱에는 optional dependency 'sharp' 가 필요합니다. \" +\n `\\`npm install sharp\\` 후 다시 실행하세요. 원인: ${(e as Error).message}`,\n )\n }\n const { data, info } = await sharp(Buffer.from(buffer)).ensureAlpha().raw().toBuffer({ resolveWithObject: true })\n return { data: new Uint8Array(data.buffer, data.byteOffset, data.byteLength), width: info.width, height: info.height }\n}\n\n/** OcrProvider 계약용 mime 판별 */\nfunction detectImageMime(buffer: ArrayBuffer): string {\n const b = new Uint8Array(buffer, 0, Math.min(12, buffer.byteLength))\n if (b[0] === 0xff && b[1] === 0xd8) return \"image/jpeg\"\n if (b[0] === 0x52 && b[1] === 0x49) return \"image/webp\"\n return \"image/png\"\n}\n"]}
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ detectRulingLines,
4
+ getOcrEngine,
5
+ ocrItemsToBlocks,
6
+ rulingToPdfLines
7
+ } from "./chunk-F5ECB53I.js";
8
+ import {
9
+ ensureOcrModels
10
+ } from "./chunk-GEPINOL6.js";
11
+ import "./chunk-NNDVFNMJ.js";
12
+ import "./chunk-L5JWKIOT.js";
13
+ import "./chunk-54WVWWT4.js";
14
+ import "./chunk-Z6LPEWIX.js";
15
+
16
+ // src/ocr/image-ocr.ts
17
+ var IMAGE_SCALE = 3;
18
+ async function parseImageDocument(buffer, options) {
19
+ const warnings = [];
20
+ if (typeof options?.ocr === "function") {
21
+ const text = await options.ocr(new Uint8Array(buffer), 1, detectImageMime(buffer));
22
+ if (!text.trim()) {
23
+ warnings.push({ page: 1, message: "OCR \uACB0\uACFC \uC5C6\uC74C", code: "OCR_FAILED" });
24
+ return { blocks: [], warnings };
25
+ }
26
+ return { blocks: [{ type: "paragraph", text: text.trim(), pageNumber: 1 }], warnings };
27
+ }
28
+ const { data, width, height } = await decodeToRgba(buffer);
29
+ await ensureOcrModels((p) => {
30
+ if (p.phase === "download" && p.downloaded === 0) {
31
+ process.stderr.write(`[kordoc-ocr] ${p.spec.name} \uB2E4\uC6B4\uB85C\uB4DC \uC911 (~${p.spec.sizeMb}MB)...
32
+ `);
33
+ }
34
+ });
35
+ const engine = await getOcrEngine();
36
+ const items = await engine.recognizePage(data, width, height);
37
+ if (items.length === 0) {
38
+ warnings.push({ page: 1, message: "\uC774\uBBF8\uC9C0\uC5D0\uC11C \uD14D\uC2A4\uD2B8\uB97C \uC778\uC2DD\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", code: "OCR_FAILED" });
39
+ return { blocks: [], warnings };
40
+ }
41
+ const pdfW = width / IMAGE_SCALE;
42
+ const pdfH = height / IMAGE_SCALE;
43
+ const ruling = detectRulingLines(data, width, height, IMAGE_SCALE);
44
+ const extraLines = rulingToPdfLines(ruling, IMAGE_SCALE, pdfH);
45
+ return { blocks: ocrItemsToBlocks(items, 1, pdfW, pdfH, IMAGE_SCALE, extraLines), warnings };
46
+ }
47
+ async function decodeToRgba(buffer) {
48
+ let sharp;
49
+ try {
50
+ const mod = await import("sharp");
51
+ sharp = typeof mod === "function" ? mod : mod.default ?? mod;
52
+ } catch (e) {
53
+ throw new Error(
54
+ `\uC774\uBBF8\uC9C0 \uD30C\uC2F1\uC5D0\uB294 optional dependency 'sharp' \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \`npm install sharp\` \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694. \uC6D0\uC778: ${e.message}`
55
+ );
56
+ }
57
+ const { data, info } = await sharp(Buffer.from(buffer)).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
58
+ return { data: new Uint8Array(data.buffer, data.byteOffset, data.byteLength), width: info.width, height: info.height };
59
+ }
60
+ function detectImageMime(buffer) {
61
+ const b = new Uint8Array(buffer, 0, Math.min(12, buffer.byteLength));
62
+ if (b[0] === 255 && b[1] === 216) return "image/jpeg";
63
+ if (b[0] === 82 && b[1] === 73) return "image/webp";
64
+ return "image/png";
65
+ }
66
+ export {
67
+ parseImageDocument
68
+ };
69
+ //# sourceMappingURL=image-ocr-SLUEM3FA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ocr/image-ocr.ts"],"sourcesContent":["/**\n * 이미지 직접 입력 OCR — PNG/JPEG/WebP 를 PDF 래핑 없이 바로 파싱한다.\n *\n * 이미지는 텍스트층이 없으므로 OCR 이 항상 필요하다 — `--ocr` 플래그 없이도\n * 내장 엔진(PP-OCRv5 korean)을 기본 적용하고, OcrProvider 가 주어지면 위임한다.\n * 좌표는 216dpi(스케일 3) 가정으로 PDF pt 공간에 환산해 기존 블록 파이프라인\n * (괘선 감지 → 선 기반 표 → 클러스터 → xy-cut)을 그대로 태운다.\n *\n * 디코딩은 optional dependency `sharp` — 미설치면 MISSING_DEPENDENCY 안내.\n */\n\nimport type { IRBlock, ParseOptions, ParseWarning } from \"../types.js\"\nimport { getOcrEngine } from \"./engine.js\"\nimport { ensureOcrModels } from \"./models.js\"\nimport { detectRulingLines, rulingToPdfLines } from \"./ruling-lines.js\"\nimport { ocrItemsToBlocks } from \"./pdf-ocr.js\"\n\n/** 좌표 환산 스케일 (px/pt) — PDF OCR 렌더(216dpi)와 동일 기준 */\nconst IMAGE_SCALE = 3\n\nexport interface ImageOcrResult {\n blocks: IRBlock[]\n warnings: ParseWarning[]\n}\n\n/** 이미지 버퍼 → OCR → IRBlock[] (표 괘선 감지 포함) */\nexport async function parseImageDocument(\n buffer: ArrayBuffer,\n options?: ParseOptions,\n): Promise<ImageOcrResult> {\n const warnings: ParseWarning[] = []\n\n // 사용자 OcrProvider — 원본 바이트 그대로 위임 (종전 PDF 경로와 같은 계약)\n if (typeof options?.ocr === \"function\") {\n const text = await options.ocr(new Uint8Array(buffer), 1, detectImageMime(buffer))\n if (!text.trim()) {\n warnings.push({ page: 1, message: \"OCR 결과 없음\", code: \"OCR_FAILED\" })\n return { blocks: [], warnings }\n }\n return { blocks: [{ type: \"paragraph\", text: text.trim(), pageNumber: 1 }], warnings }\n }\n\n const { data, width, height } = await decodeToRgba(buffer)\n\n await ensureOcrModels(p => {\n if (p.phase === \"download\" && p.downloaded === 0) {\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 다운로드 중 (~${p.spec.sizeMb}MB)...\\n`)\n }\n })\n const engine = await getOcrEngine()\n const items = await engine.recognizePage(data, width, height)\n if (items.length === 0) {\n warnings.push({ page: 1, message: \"이미지에서 텍스트를 인식하지 못했습니다\", code: \"OCR_FAILED\" })\n return { blocks: [], warnings }\n }\n\n const pdfW = width / IMAGE_SCALE\n const pdfH = height / IMAGE_SCALE\n const ruling = detectRulingLines(data, width, height, IMAGE_SCALE)\n const extraLines = rulingToPdfLines(ruling, IMAGE_SCALE, pdfH)\n return { blocks: ocrItemsToBlocks(items, 1, pdfW, pdfH, IMAGE_SCALE, extraLines), warnings }\n}\n\n/** sharp 로 RGBA 디코딩 — 미설치는 MISSING_DEPENDENCY 로 분류되도록 안내 메시지 throw */\nasync function decodeToRgba(\n buffer: ArrayBuffer,\n): Promise<{ data: Uint8Array; width: number; height: number }> {\n type SharpFactory = (input: Buffer) => {\n ensureAlpha(): { raw(): { toBuffer(opts: { resolveWithObject: true }): Promise<{ data: Buffer; info: { width: number; height: number } }> } }\n }\n let sharp: SharpFactory\n try {\n const mod = (await import(\"sharp\")) as unknown as { default?: SharpFactory } & SharpFactory\n sharp = typeof mod === \"function\" ? mod : (mod.default ?? (mod as unknown as SharpFactory))\n } catch (e) {\n throw new Error(\n \"이미지 파싱에는 optional dependency 'sharp' 가 필요합니다. \" +\n `\\`npm install sharp\\` 후 다시 실행하세요. 원인: ${(e as Error).message}`,\n )\n }\n const { data, info } = await sharp(Buffer.from(buffer)).ensureAlpha().raw().toBuffer({ resolveWithObject: true })\n return { data: new Uint8Array(data.buffer, data.byteOffset, data.byteLength), width: info.width, height: info.height }\n}\n\n/** OcrProvider 계약용 mime 판별 */\nfunction detectImageMime(buffer: ArrayBuffer): string {\n const b = new Uint8Array(buffer, 0, Math.min(12, buffer.byteLength))\n if (b[0] === 0xff && b[1] === 0xd8) return \"image/jpeg\"\n if (b[0] === 0x52 && b[1] === 0x49) return \"image/webp\"\n return \"image/png\"\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,IAAM,cAAc;AAQpB,eAAsB,mBACpB,QACA,SACyB;AACzB,QAAM,WAA2B,CAAC;AAGlC,MAAI,OAAO,SAAS,QAAQ,YAAY;AACtC,UAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,WAAW,MAAM,GAAG,GAAG,gBAAgB,MAAM,CAAC;AACjF,QAAI,CAAC,KAAK,KAAK,GAAG;AAChB,eAAS,KAAK,EAAE,MAAM,GAAG,SAAS,iCAAa,MAAM,aAAa,CAAC;AACnE,aAAO,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,IAChC;AACA,WAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,aAAa,MAAM,KAAK,KAAK,GAAG,YAAY,EAAE,CAAC,GAAG,SAAS;AAAA,EACvF;AAEA,QAAM,EAAE,MAAM,OAAO,OAAO,IAAI,MAAM,aAAa,MAAM;AAEzD,QAAM,gBAAgB,OAAK;AACzB,QAAI,EAAE,UAAU,cAAc,EAAE,eAAe,GAAG;AAChD,cAAQ,OAAO,MAAM,gBAAgB,EAAE,KAAK,IAAI,sCAAa,EAAE,KAAK,MAAM;AAAA,CAAU;AAAA,IACtF;AAAA,EACF,CAAC;AACD,QAAM,SAAS,MAAM,aAAa;AAClC,QAAM,QAAQ,MAAM,OAAO,cAAc,MAAM,OAAO,MAAM;AAC5D,MAAI,MAAM,WAAW,GAAG;AACtB,aAAS,KAAK,EAAE,MAAM,GAAG,SAAS,mHAAyB,MAAM,aAAa,CAAC;AAC/E,WAAO,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,EAChC;AAEA,QAAM,OAAO,QAAQ;AACrB,QAAM,OAAO,SAAS;AACtB,QAAM,SAAS,kBAAkB,MAAM,OAAO,QAAQ,WAAW;AACjE,QAAM,aAAa,iBAAiB,QAAQ,aAAa,IAAI;AAC7D,SAAO,EAAE,QAAQ,iBAAiB,OAAO,GAAG,MAAM,MAAM,aAAa,UAAU,GAAG,SAAS;AAC7F;AAGA,eAAe,aACb,QAC8D;AAI9D,MAAI;AACJ,MAAI;AACF,UAAM,MAAO,MAAM,OAAO,OAAO;AACjC,YAAQ,OAAO,QAAQ,aAAa,MAAO,IAAI,WAAY;AAAA,EAC7D,SAAS,GAAG;AACV,UAAM,IAAI;AAAA,MACR,0MAC4C,EAAY,OAAO;AAAA,IACjE;AAAA,EACF;AACA,QAAM,EAAE,MAAM,KAAK,IAAI,MAAM,MAAM,OAAO,KAAK,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,KAAK,CAAC;AAChH,SAAO,EAAE,MAAM,IAAI,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,GAAG,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO;AACvH;AAGA,SAAS,gBAAgB,QAA6B;AACpD,QAAM,IAAI,IAAI,WAAW,QAAQ,GAAG,KAAK,IAAI,IAAI,OAAO,UAAU,CAAC;AACnE,MAAI,EAAE,CAAC,MAAM,OAAQ,EAAE,CAAC,MAAM,IAAM,QAAO;AAC3C,MAAI,EAAE,CAAC,MAAM,MAAQ,EAAE,CAAC,MAAM,GAAM,QAAO;AAC3C,SAAO;AACT;","names":[]}