kordoc 4.12.2 → 4.13.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 (137) hide show
  1. package/README.md +32 -1
  2. package/dist/{-EZH6NKTE.js → -UZDRUWTX.js} +43 -22
  3. package/dist/{chunk-FBLMVHDK.js → chunk-27QN27I3.js} +2 -2
  4. package/dist/{chunk-MUYU4JI5.js → chunk-2B45S7FM.js} +2 -2
  5. package/dist/{chunk-LD2K4K5V.js → chunk-2RREQZ44.js} +1662 -652
  6. package/dist/chunk-2RREQZ44.js.map +1 -0
  7. package/dist/{chunk-OEYECZGV.js → chunk-3ABHPKYA.js} +10 -6
  8. package/dist/chunk-3ABHPKYA.js.map +1 -0
  9. package/dist/{chunk-QM2RSJ2S.js → chunk-3MCFJIN2.js} +5 -5
  10. package/dist/{chunk-JCMBQC5N.js → chunk-5VHLKNCE.js} +2 -2
  11. package/dist/{chunk-FVBR7SC3.js → chunk-6JXMIX3G.js} +2 -2
  12. package/dist/chunk-6JXMIX3G.js.map +1 -0
  13. package/dist/{chunk-5RPYBC2Q.js → chunk-6NLXGGNH.js} +37 -6
  14. package/dist/chunk-6NLXGGNH.js.map +1 -0
  15. package/dist/{chunk-2B7OIEJJ.js → chunk-AGBFCFQY.js} +10 -6
  16. package/dist/chunk-AGBFCFQY.js.map +1 -0
  17. package/dist/{rasterize-NRWP2C6L.js → chunk-BQLZOQES.js} +22 -6
  18. package/dist/chunk-BQLZOQES.js.map +1 -0
  19. package/dist/{chunk-ONNAHSPV.cjs → chunk-CKMK42FV.cjs} +18 -14
  20. package/dist/chunk-CKMK42FV.cjs.map +1 -0
  21. package/dist/{chunk-T7GRHAIW.cjs → chunk-COUGOFT3.cjs} +1 -1
  22. package/dist/chunk-COUGOFT3.cjs.map +1 -0
  23. package/dist/{chunk-2LO525TL.js → chunk-F3FEIYI7.js} +2 -2
  24. package/dist/{chunk-Q6ETEJFK.js → chunk-GWFX5ZD7.js} +11 -7
  25. package/dist/chunk-GWFX5ZD7.js.map +1 -0
  26. package/dist/{chunk-2HBYWA5X.js → chunk-H5JWPWQP.js} +2 -2
  27. package/dist/{chunk-N3DLQ2YH.js → chunk-HG5LXXCC.js} +1 -1
  28. package/dist/chunk-HG5LXXCC.js.map +1 -0
  29. package/dist/{chunk-KX7IYCCZ.js → chunk-IEJR23OA.js} +3 -3
  30. package/dist/{chunk-7XUXSDH5.js → chunk-ILDTN72S.js} +10 -6
  31. package/dist/chunk-ILDTN72S.js.map +1 -0
  32. package/dist/{chunk-QBCMFNHS.js → chunk-L3CEPNQS.js} +2 -2
  33. package/dist/{chunk-XXDZ2KTW.js → chunk-LP5RTYFM.js} +2 -2
  34. package/dist/{chunk-2LKYJ4G3.cjs → chunk-MCD45IHO.cjs} +6 -6
  35. package/dist/{chunk-2LKYJ4G3.cjs.map → chunk-MCD45IHO.cjs.map} +1 -1
  36. package/dist/{chunk-V5BUPZ6I.cjs → chunk-OJV7HNGJ.cjs} +13 -9
  37. package/dist/chunk-OJV7HNGJ.cjs.map +1 -0
  38. package/dist/{chunk-DBGEUDBY.js → chunk-OSLJ3A6D.js} +2 -2
  39. package/dist/{chunk-2LPBIW2B.cjs → chunk-S2VKZKUX.cjs} +3 -3
  40. package/dist/{chunk-2LPBIW2B.cjs.map → chunk-S2VKZKUX.cjs.map} +1 -1
  41. package/dist/{chunk-IOJX4Q63.js → chunk-T7AFLXGA.js} +786 -19
  42. package/dist/chunk-T7AFLXGA.js.map +1 -0
  43. package/dist/{chunk-UL2MDA5C.js → chunk-TA2LEFOF.js} +3 -3
  44. package/dist/{chunk-62IU4NV3.cjs → chunk-TAYCQE6K.cjs} +2 -2
  45. package/dist/{chunk-62IU4NV3.cjs.map → chunk-TAYCQE6K.cjs.map} +1 -1
  46. package/dist/{chunk-ONQHGZTS.js → chunk-XVIJLHCW.js} +1 -1
  47. package/dist/chunk-XVIJLHCW.js.map +1 -0
  48. package/dist/chunks-G3GK536Y.js +10 -0
  49. package/dist/cli.js +187 -38
  50. package/dist/cli.js.map +1 -1
  51. package/dist/{formula-6RQX4NMJ.js → formula-3T7HQA4O.js} +4 -4
  52. package/dist/{formula-NW33S4TA.js → formula-FWVAOSIK.js} +3 -3
  53. package/dist/{formula-NBEO6CFC.cjs → formula-YALEMZMF.cjs} +9 -9
  54. package/dist/{formula-NBEO6CFC.cjs.map → formula-YALEMZMF.cjs.map} +1 -1
  55. package/dist/{image-ocr-SO56VETS.js → image-ocr-2M7K3CE5.js} +8 -8
  56. package/dist/{image-ocr-V4KY373B.cjs → image-ocr-4EUZIF6M.cjs} +12 -12
  57. package/dist/{image-ocr-V4KY373B.cjs.map → image-ocr-4EUZIF6M.cjs.map} +1 -1
  58. package/dist/{image-ocr-CAVU2TNZ.js → image-ocr-X3I2HUK2.js} +6 -6
  59. package/dist/index.cjs +2349 -576
  60. package/dist/index.cjs.map +1 -1
  61. package/dist/index.d.cts +305 -12
  62. package/dist/index.d.ts +305 -12
  63. package/dist/index.js +1980 -207
  64. package/dist/index.js.map +1 -1
  65. package/dist/mcp.js +109 -35
  66. package/dist/mcp.js.map +1 -1
  67. package/dist/{model-bundle-EIJF34DR.js → model-bundle-XXYZ6ELQ.js} +5 -5
  68. package/dist/{models-6V4CPQXC.js → models-APDSXJW7.js} +5 -5
  69. package/dist/{parser-OMT25WH2.cjs → parser-4KE2FR5F.cjs} +60 -39
  70. package/dist/parser-4KE2FR5F.cjs.map +1 -0
  71. package/dist/{parser-OBHNXEQM.js → parser-T5R4YVZS.js} +32 -11
  72. package/dist/parser-T5R4YVZS.js.map +1 -0
  73. package/dist/{parser-GIREMEPD.js → parser-XKSOS6GY.js} +32 -11
  74. package/dist/parser-XKSOS6GY.js.map +1 -0
  75. package/dist/pdf-ocr-JZKCEKWX.cjs +14 -0
  76. package/dist/{pdf-ocr-TFYVK4FI.cjs.map → pdf-ocr-JZKCEKWX.cjs.map} +1 -1
  77. package/dist/pdf-ocr-X62B7YDV.js +13 -0
  78. package/dist/pdf-ocr-YDJQEGDS.js +16 -0
  79. package/dist/{profile-io-PZVMM66V.js → profile-io-Y24GOHWM.js} +3 -3
  80. package/dist/rasterize-QCOBWHAG.js +13 -0
  81. package/dist/render-DHFQQCSV.js +38 -0
  82. package/dist/seal-UTHFQPLO.js +10 -0
  83. package/dist/seal-UTHFQPLO.js.map +1 -0
  84. package/dist/{setup-V55AJP6H.js → setup-UWX3KH3G.js} +3 -3
  85. package/dist/visual-DF2KSPEC.js +19 -0
  86. package/dist/visual-DF2KSPEC.js.map +1 -0
  87. package/dist/{watch-7CQSMDDP.js → watch-4ZUTMC3Q.js} +15 -13
  88. package/dist/{watch-7CQSMDDP.js.map → watch-4ZUTMC3Q.js.map} +1 -1
  89. package/package.json +1 -1
  90. package/dist/chunk-2B7OIEJJ.js.map +0 -1
  91. package/dist/chunk-5RPYBC2Q.js.map +0 -1
  92. package/dist/chunk-7XUXSDH5.js.map +0 -1
  93. package/dist/chunk-FVBR7SC3.js.map +0 -1
  94. package/dist/chunk-IOJX4Q63.js.map +0 -1
  95. package/dist/chunk-LD2K4K5V.js.map +0 -1
  96. package/dist/chunk-N3DLQ2YH.js.map +0 -1
  97. package/dist/chunk-OEYECZGV.js.map +0 -1
  98. package/dist/chunk-ONNAHSPV.cjs.map +0 -1
  99. package/dist/chunk-ONQHGZTS.js.map +0 -1
  100. package/dist/chunk-Q6ETEJFK.js.map +0 -1
  101. package/dist/chunk-T7GRHAIW.cjs.map +0 -1
  102. package/dist/chunk-V5BUPZ6I.cjs.map +0 -1
  103. package/dist/chunks-TT7ZE5QQ.js +0 -10
  104. package/dist/parser-GIREMEPD.js.map +0 -1
  105. package/dist/parser-OBHNXEQM.js.map +0 -1
  106. package/dist/parser-OMT25WH2.cjs.map +0 -1
  107. package/dist/pdf-ocr-IRXQ5GBM.js +0 -13
  108. package/dist/pdf-ocr-SL4GCOGS.js +0 -16
  109. package/dist/pdf-ocr-TFYVK4FI.cjs +0 -14
  110. package/dist/rasterize-NRWP2C6L.js.map +0 -1
  111. package/dist/render-V5ZPTZQ7.js +0 -10
  112. package/dist/seal-LVG2DGAB.js +0 -10
  113. /package/dist/{-EZH6NKTE.js.map → -UZDRUWTX.js.map} +0 -0
  114. /package/dist/{chunk-FBLMVHDK.js.map → chunk-27QN27I3.js.map} +0 -0
  115. /package/dist/{chunk-MUYU4JI5.js.map → chunk-2B45S7FM.js.map} +0 -0
  116. /package/dist/{chunk-QM2RSJ2S.js.map → chunk-3MCFJIN2.js.map} +0 -0
  117. /package/dist/{chunk-JCMBQC5N.js.map → chunk-5VHLKNCE.js.map} +0 -0
  118. /package/dist/{chunk-2LO525TL.js.map → chunk-F3FEIYI7.js.map} +0 -0
  119. /package/dist/{chunk-2HBYWA5X.js.map → chunk-H5JWPWQP.js.map} +0 -0
  120. /package/dist/{chunk-KX7IYCCZ.js.map → chunk-IEJR23OA.js.map} +0 -0
  121. /package/dist/{chunk-QBCMFNHS.js.map → chunk-L3CEPNQS.js.map} +0 -0
  122. /package/dist/{chunk-XXDZ2KTW.js.map → chunk-LP5RTYFM.js.map} +0 -0
  123. /package/dist/{chunk-DBGEUDBY.js.map → chunk-OSLJ3A6D.js.map} +0 -0
  124. /package/dist/{chunk-UL2MDA5C.js.map → chunk-TA2LEFOF.js.map} +0 -0
  125. /package/dist/{chunks-TT7ZE5QQ.js.map → chunks-G3GK536Y.js.map} +0 -0
  126. /package/dist/{formula-6RQX4NMJ.js.map → formula-3T7HQA4O.js.map} +0 -0
  127. /package/dist/{formula-NW33S4TA.js.map → formula-FWVAOSIK.js.map} +0 -0
  128. /package/dist/{image-ocr-SO56VETS.js.map → image-ocr-2M7K3CE5.js.map} +0 -0
  129. /package/dist/{image-ocr-CAVU2TNZ.js.map → image-ocr-X3I2HUK2.js.map} +0 -0
  130. /package/dist/{model-bundle-EIJF34DR.js.map → model-bundle-XXYZ6ELQ.js.map} +0 -0
  131. /package/dist/{models-6V4CPQXC.js.map → models-APDSXJW7.js.map} +0 -0
  132. /package/dist/{pdf-ocr-IRXQ5GBM.js.map → pdf-ocr-X62B7YDV.js.map} +0 -0
  133. /package/dist/{pdf-ocr-SL4GCOGS.js.map → pdf-ocr-YDJQEGDS.js.map} +0 -0
  134. /package/dist/{profile-io-PZVMM66V.js.map → profile-io-Y24GOHWM.js.map} +0 -0
  135. /package/dist/{render-V5ZPTZQ7.js.map → rasterize-QCOBWHAG.js.map} +0 -0
  136. /package/dist/{seal-LVG2DGAB.js.map → render-DHFQQCSV.js.map} +0 -0
  137. /package/dist/{setup-V55AJP6H.js.map → setup-UWX3KH3G.js.map} +0 -0
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ parsePageRange
4
+ } from "./chunk-MOL7MDBG.js";
2
5
  import {
3
6
  DEFAULT_CHAR,
4
7
  DEFAULT_PARA_GEOM,
@@ -7,11 +10,19 @@ import {
7
10
  createXmlParser,
8
11
  findChildByLocalName,
9
12
  parseRenderStyles
10
- } from "./chunk-FVBR7SC3.js";
13
+ } from "./chunk-6JXMIX3G.js";
14
+ import {
15
+ blocksToMarkdown
16
+ } from "./chunk-GWFX5ZD7.js";
17
+ import {
18
+ loadSharp,
19
+ rasterizePageSvg
20
+ } from "./chunk-BQLZOQES.js";
11
21
  import {
12
22
  KordocError,
13
- precheckZipSize
14
- } from "./chunk-FBLMVHDK.js";
23
+ precheckZipSize,
24
+ toArrayBuffer
25
+ } from "./chunk-27QN27I3.js";
15
26
 
16
27
  // src/render/svg-render.ts
17
28
  import JSZip from "jszip";
@@ -251,13 +262,29 @@ var SPACE_EM_FONT = 300;
251
262
  function faceClassOf(face) {
252
263
  return face && /^(굴림체|돋움체|바탕체|궁서체)$/.test(face.trim()) ? "fixedPitch" : "hcr";
253
264
  }
265
+ function faceClassForGen(face) {
266
+ if (!face) return "hcr";
267
+ const f = face.trim();
268
+ if (/^(굴림체|돋움체|바탕체|궁서체)$/.test(f)) return "fixedPitch";
269
+ if (/^(한컴돋움|맑은 고딕|HY견고딕|HY헤드라인M|HY중고딕|한양중고딕|나눔고딕|나눔스퀘어|돋움|굴림)$/.test(f)) return "gothic";
270
+ return "hcr";
271
+ }
272
+ function gothicWidthEm1000(cp) {
273
+ if (cp >= 128) return 1e3;
274
+ if (cp >= 65 && cp <= 90) return 720;
275
+ if (cp >= 97 && cp <= 122) return 560;
276
+ if (cp >= 48 && cp <= 57) return 580;
277
+ if (cp === 40 || cp === 41 || cp === 91 || cp === 93) return 350;
278
+ if (cp === 46 || cp === 44 || cp === 58 || cp === 59 || cp === 39) return 280;
279
+ return 500;
280
+ }
254
281
  function fixedPitchWidthEm1000(cp) {
255
282
  return cp < 128 ? 500 : 1e3;
256
283
  }
257
284
  function measureTextWidth(text, height, ratioPct, opts) {
258
285
  const spaceEm = opts?.spaceEm ?? SPACE_EM_FIXED;
259
286
  const spacing = opts?.spacingPct ?? 0;
260
- const widthEm = opts?.faceClass === "fixedPitch" ? fixedPitchWidthEm1000 : charWidthEm1000;
287
+ const widthEm = opts?.faceClass === "fixedPitch" ? fixedPitchWidthEm1000 : opts?.faceClass === "gothic" ? gothicWidthEm1000 : charWidthEm1000;
261
288
  let em = 0;
262
289
  for (const ch of text) {
263
290
  const cp = ch.codePointAt(0);
@@ -272,7 +299,7 @@ function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "kee
272
299
  const EPS = 0.5;
273
300
  const spaceEm = opts?.spaceEm ?? SPACE_EM_FIXED;
274
301
  const spacing = opts?.spacingPct ?? 0;
275
- const widthEm = opts?.faceClass === "fixedPitch" ? fixedPitchWidthEm1000 : charWidthEm1000;
302
+ const widthEm = opts?.faceClass === "fixedPitch" ? fixedPitchWidthEm1000 : opts?.faceClass === "gothic" ? gothicWidthEm1000 : charWidthEm1000;
276
303
  const k = height * ratioPct / 100 / 1e3;
277
304
  const cwCp = (cp) => (cp === 32 ? spaceEm : widthEm(cp)) * (1 + spacing / 100) * k;
278
305
  const charW2 = (ch) => cwCp(ch.codePointAt(0));
@@ -534,6 +561,36 @@ function reflowSection(root, styles, geom, mode = "keep") {
534
561
  return counter.n;
535
562
  }
536
563
 
564
+ // src/render/scene.ts
565
+ function regionId(type, seq) {
566
+ return `${type}-${String(seq).padStart(6, "0")}`;
567
+ }
568
+ function unionBBox(a, b) {
569
+ const x = Math.min(a.x, b.x), y = Math.min(a.y, b.y);
570
+ return { page: a.page, x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };
571
+ }
572
+ var RegionCollector = class {
573
+ regions = [];
574
+ counters = /* @__PURE__ */ new Map();
575
+ add(type, bbox, extra = {}) {
576
+ const seq = (this.counters.get(type) ?? 0) + 1;
577
+ this.counters.set(type, seq);
578
+ const id = regionId(type, seq);
579
+ const region = { id, type, page: bbox.page, regions: [bbox] };
580
+ if (extra.sourceId) region.sourceId = extra.sourceId;
581
+ if (extra.parentId) region.parentId = extra.parentId;
582
+ this.regions.push(region);
583
+ return id;
584
+ }
585
+ addFragment(id, bbox) {
586
+ const r = this.regions.find((x) => x.id === id);
587
+ if (!r) return;
588
+ const same = r.regions.find((f) => f.page === bbox.page);
589
+ if (same) Object.assign(same, unionBBox(same, bbox));
590
+ else r.regions.push(bbox);
591
+ }
592
+ };
593
+
537
594
  // src/render/svg-render.ts
538
595
  function ln2(el) {
539
596
  return (el.tagName || "").replace(/^[^:]+:/, "");
@@ -564,6 +621,20 @@ function escapeXml(s) {
564
621
  }
565
622
  var OBJ_TAGS = /* @__PURE__ */ new Set(["tbl", "pic", "container", "equation", "rect", "ellipse", "polygon", "curv", "line", "arc", "ole", "textart"]);
566
623
  var pt = (u) => String(Math.round(u) / 100);
624
+ var ptNum = (u) => Math.round(u) / 100;
625
+ function pageNo(ctx) {
626
+ return ctx.pageBase + ctx.page + 1;
627
+ }
628
+ function bboxOf(ctx, x, y, w, h) {
629
+ const clippedH = Math.max(0, Math.min(h, ctx.pageH - y));
630
+ return { page: pageNo(ctx), x: ptNum(x), y: ptNum(y), width: ptNum(Math.max(0, w)), height: ptNum(clippedH) };
631
+ }
632
+ function regionOpenTag(id, type, page) {
633
+ return `<g data-kordoc-id="${id}" data-kordoc-type="${type}" data-kordoc-page="${page}">`;
634
+ }
635
+ function parentId(ctx) {
636
+ return ctx.parentStack.length ? ctx.parentStack[ctx.parentStack.length - 1] : void 0;
637
+ }
567
638
  function emit(ctx, s) {
568
639
  ctx.pages[ctx.page].push(s);
569
640
  }
@@ -704,10 +775,23 @@ function drawPara(p, ox, oy, areaW, ctx, depth, segPages) {
704
775
  }
705
776
  const plans = planLines(m, ctx.styles);
706
777
  const baseV = m.segs[0].vertpos;
778
+ const hasText = m.chars.some((c) => c.ch !== "" && c.ch.trim() !== "");
779
+ let paraRegionId = null;
780
+ let gOpenOn = -1;
707
781
  for (let li = 0; li < plans.length; li++) {
708
782
  const plan = plans[li];
709
783
  if (segPages && segPages[li] !== void 0) ctx.page = segPages[li];
710
784
  const { seg } = plan;
785
+ if (hasText) {
786
+ const lineBox = bboxOf(ctx, ox + seg.horzpos, oy + seg.vertpos, seg.horzsize, seg.textheight);
787
+ if (paraRegionId === null) paraRegionId = ctx.regions.add("paragraph", lineBox, { parentId: parentId(ctx) });
788
+ else ctx.regions.addFragment(paraRegionId, lineBox);
789
+ if (gOpenOn !== ctx.page) {
790
+ if (gOpenOn >= 0) ctx.pages[gOpenOn].push("</g>");
791
+ emit(ctx, regionOpenTag(paraRegionId, "paragraph", pageNo(ctx)));
792
+ gOpenOn = ctx.page;
793
+ }
794
+ }
711
795
  let i = plan.start;
712
796
  let cursor = ox + seg.horzpos + plan.xoff;
713
797
  const y = oy + seg.vertpos + seg.baseline;
@@ -788,6 +872,8 @@ function drawPara(p, ox, oy, areaW, ctx, depth, segPages) {
788
872
  i = j;
789
873
  }
790
874
  }
875
+ if (gOpenOn >= 0) ctx.pages[gOpenOn].push("</g>");
876
+ if (paraRegionId) ctx.parentStack.push(paraRegionId);
791
877
  for (const o of m.objs) {
792
878
  if (o.inline) {
793
879
  let planIdx = 0;
@@ -806,6 +892,7 @@ function drawPara(p, ox, oy, areaW, ctx, depth, segPages) {
806
892
  drawObject(o, x, y, baseV, areaW, ctx, depth);
807
893
  }
808
894
  }
895
+ if (paraRegionId) ctx.parentStack.pop();
809
896
  }
810
897
  function anchorObject(o, ox, oy, baseV, areaW, ctx) {
811
898
  const { PW, PH, ML, MT, BODY_W, BODY_H } = ctx.geom;
@@ -888,6 +975,10 @@ function drawShape(o, x, y, ctx, depth) {
888
975
  const face = winBrush?.getAttribute("faceColor");
889
976
  const fill = face && face.toLowerCase() !== "none" ? face : "none";
890
977
  const fillAttr = ` fill="${fill === "none" ? "none" : escapeXml(fill)}"`;
978
+ ctx.stats.shapes++;
979
+ const shapeId = ctx.regions.add("shape", bboxOf(ctx, x, y, w, h), { parentId: parentId(ctx) });
980
+ emit(ctx, regionOpenTag(shapeId, "shape", pageNo(ctx)));
981
+ ctx.parentStack.push(shapeId);
891
982
  if (o.tag === "rect") {
892
983
  emit(ctx, `<rect x="${pt(x)}" y="${pt(y)}" width="${pt(w)}" height="${pt(h)}"${fillAttr}${strokeAttr}/>`);
893
984
  } else if (o.tag === "ellipse") {
@@ -909,6 +1000,8 @@ function drawShape(o, x, y, ctx, depth) {
909
1000
  if (sub) {
910
1001
  for (const p of elements2(sub)) if (ln2(p) === "p") drawPara(p, x, y, w, ctx, depth + 1);
911
1002
  }
1003
+ ctx.parentStack.pop();
1004
+ emit(ctx, "</g>");
912
1005
  }
913
1006
  function cellContentExtent(cell, memo) {
914
1007
  if (!cell.sub) return 0;
@@ -1009,6 +1102,11 @@ function drawTable(tbl, tx, ty, ctx, depth) {
1009
1102
  );
1010
1103
  const rowY = [0];
1011
1104
  for (let r = 0; r < nRows; r++) rowY.push(rowY[r] + rowH[r]);
1105
+ const tblH = rowY[nRows];
1106
+ if (ty + tblH > ctx.pageH + 100) warnOnce(ctx, "table-split", "\uD398\uC774\uC9C0\uC5D0 \uAC78\uCE5C \uD45C \u2014 \uBD84\uD560 \uC9C0\uC624\uBA54\uD2B8\uB9AC\uAC00 \uC5C6\uC5B4 \uC2DC\uC791 \uD398\uC774\uC9C0 \uC601\uC5ED\uB9CC region \uC73C\uB85C \uAE30\uB85D");
1107
+ const tblId = ctx.regions.add("table", bboxOf(ctx, tx, ty, colX[nCols], tblH), { sourceId: tbl.getAttribute("id") ?? void 0, parentId: parentId(ctx) });
1108
+ emit(ctx, regionOpenTag(tblId, "table", pageNo(ctx)));
1109
+ ctx.parentStack.push(tblId);
1012
1110
  const geom = cells.map((c) => ({
1013
1111
  c,
1014
1112
  x: tx + colX[c.ca],
@@ -1042,6 +1140,8 @@ function drawTable(tbl, tx, ty, ctx, depth) {
1042
1140
  if (bf.left) emit(ctx, edgeLine(g.x, g.y, g.x, g.y + g.h, bf.left));
1043
1141
  if (bf.right) emit(ctx, edgeLine(g.x + g.w, g.y, g.x + g.w, g.y + g.h, bf.right));
1044
1142
  }
1143
+ ctx.parentStack.pop();
1144
+ emit(ctx, "</g>");
1045
1145
  }
1046
1146
  function imageSymbol(loaded, ctx) {
1047
1147
  if (!loaded.symId) {
@@ -1058,9 +1158,12 @@ function drawPic(pic, x, y, ctx) {
1058
1158
  const img = findFirst(pic, "img");
1059
1159
  const ref = img?.getAttribute("binaryItemIDRef");
1060
1160
  const loaded = ref != null ? ctx.images.get(ref) : void 0;
1161
+ const imgId = ctx.regions.add("image", bboxOf(ctx, x, y, w, h), { sourceId: ref ?? void 0, parentId: parentId(ctx) });
1162
+ emit(ctx, regionOpenTag(imgId, "image", pageNo(ctx)));
1061
1163
  if (!loaded) {
1062
1164
  emit(ctx, `<rect x="${pt(x)}" y="${pt(y)}" width="${pt(w)}" height="${pt(h)}" fill="#eee" stroke="#c00" stroke-width="0.5"/>`);
1063
1165
  warnOnce(ctx, `img:${ref}`, `\uC774\uBBF8\uC9C0 \uBC14\uC774\uB108\uB9AC \uB204\uB77D: ${ref ?? "(ref \uC5C6\uC74C)"}`);
1166
+ emit(ctx, "</g>");
1064
1167
  return;
1065
1168
  }
1066
1169
  ctx.stats.images++;
@@ -1082,6 +1185,7 @@ function drawPic(pic, x, y, ctx) {
1082
1185
  } else {
1083
1186
  emit(ctx, `<use href="#${symId}" x="${pt(x)}" y="${pt(y)}" width="${pt(w)}" height="${pt(h)}"/>`);
1084
1187
  }
1188
+ emit(ctx, "</g>");
1085
1189
  }
1086
1190
  function sniffMime(name, bytes) {
1087
1191
  const lower = name.toLowerCase();
@@ -1140,20 +1244,22 @@ function renderSectionToPages(root, geom, ctxBase, doReflow, reflowMode) {
1140
1244
  nPages = Math.max(nPages, cur + 1);
1141
1245
  }
1142
1246
  }
1247
+ const pageH = nPages === 1 ? Math.max(PH, MT + maxTopV + 2e3) : PH;
1143
1248
  const ctx = {
1144
1249
  ...ctxBase,
1145
1250
  pages: Array.from({ length: nPages }, () => []),
1146
1251
  page: 0,
1147
- geom
1252
+ geom,
1253
+ pageH
1148
1254
  };
1149
1255
  for (const p of elements2(root)) {
1150
1256
  if (ln2(p) !== "p") continue;
1151
1257
  drawPara(p, ML, MT, BODY_W, ctx, 0, paraSegPages.get(p));
1152
1258
  }
1153
- const pageH = nPages === 1 ? Math.max(PH, MT + maxTopV + 2e3) : PH;
1154
1259
  return { pages: ctx.pages, pageH };
1155
1260
  }
1156
- async function renderHwpxToSvg(input, options) {
1261
+ var SVG_FONT_FAMILY = `'HCR Batang','\uD568\uCD08\uB86C\uBC14\uD0D5','Hancom Batang',AppleMyungjo,'Noto Serif CJK KR',serif`;
1262
+ async function renderHwpxInternal(input, options) {
1157
1263
  const maxImg = options?.maxImageBytes ?? 40 * 1024 * 1024;
1158
1264
  const ab = input instanceof Uint8Array ? input.buffer.slice(input.byteOffset, input.byteOffset + input.byteLength) : input;
1159
1265
  precheckZipSize(ab, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES);
@@ -1220,8 +1326,11 @@ async function renderHwpxToSvg(input, options) {
1220
1326
  highlights: (options?.highlights ?? []).map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0),
1221
1327
  warnings,
1222
1328
  warned: /* @__PURE__ */ new Set(),
1223
- stats: { texts: 0, images: 0, tables: 0 },
1224
- extentMemo: { cell: /* @__PURE__ */ new WeakMap(), table: /* @__PURE__ */ new WeakMap() }
1329
+ stats: { texts: 0, images: 0, tables: 0, shapes: 0 },
1330
+ extentMemo: { cell: /* @__PURE__ */ new WeakMap(), table: /* @__PURE__ */ new WeakMap() },
1331
+ regions: new RegionCollector(),
1332
+ parentStack: [],
1333
+ pageBase: 0
1225
1334
  };
1226
1335
  const rendered = [];
1227
1336
  let noCacheSkipped = false;
@@ -1242,6 +1351,7 @@ async function renderHwpxToSvg(input, options) {
1242
1351
  const geom = readSectionGeom(root);
1243
1352
  const { pages, pageH } = renderSectionToPages(root, geom, ctxBase, !!options?.reflow, options?.reflowMode ?? "keep");
1244
1353
  rendered.push({ pages, PW: geom.PW, pageH, clipId: `pgclip${si}` });
1354
+ ctxBase.pageBase += pages.length;
1245
1355
  }
1246
1356
  if (rendered.length === 0) {
1247
1357
  if (noCacheSkipped) {
@@ -1249,19 +1359,23 @@ async function renderHwpxToSvg(input, options) {
1249
1359
  }
1250
1360
  throw new KordocError("\uB80C\uB354\uD560 \uAD6C\uC5ED\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 HWPX\uAC00 \uC190\uC0C1\uB418\uC5C8\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4");
1251
1361
  }
1362
+ return { sections: rendered, defs: ctxBase.defs, warnings, stats: ctxBase.stats, regions: ctxBase.regions.regions };
1363
+ }
1364
+ async function renderHwpxToSvg(input, options) {
1365
+ const r = await renderHwpxInternal(input, options);
1252
1366
  const GAP = 2400;
1253
1367
  const clipDefs = [];
1254
1368
  const groups = [];
1255
1369
  let y = 0;
1256
1370
  let maxPW = 0;
1257
- let pageNo = 0;
1258
- for (const rs of rendered) {
1371
+ let pageNo2 = 0;
1372
+ for (const rs of r.sections) {
1259
1373
  maxPW = Math.max(maxPW, rs.PW);
1260
1374
  clipDefs.push(`<clipPath id="${rs.clipId}"><rect x="0" y="0" width="${pt(rs.PW)}" height="${pt(rs.pageH)}"/></clipPath>`);
1261
1375
  for (const buf of rs.pages) {
1262
- pageNo++;
1376
+ pageNo2++;
1263
1377
  groups.push(
1264
- `<g data-page="${pageNo}" transform="translate(0 ${pt(y)})"><rect width="${pt(rs.PW)}" height="${pt(rs.pageH)}" fill="white" stroke="#c9c7c4" stroke-width="0.75"/><g clip-path="url(#${rs.clipId})">
1378
+ `<g data-page="${pageNo2}" transform="translate(0 ${pt(y)})"><rect width="${pt(rs.PW)}" height="${pt(rs.pageH)}" fill="white" stroke="#c9c7c4" stroke-width="0.75"/><g clip-path="url(#${rs.clipId})">
1265
1379
  ${buf.join("\n")}
1266
1380
  </g></g>`
1267
1381
  );
@@ -1269,21 +1383,674 @@ ${buf.join("\n")}
1269
1383
  }
1270
1384
  }
1271
1385
  const totalH = Math.max(0, y - GAP);
1272
- 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','\uD568\uCD08\uB86C\uBC14\uD0D5','Hancom Batang',AppleMyungjo,'Noto Serif CJK KR',serif" xml:space="preserve">
1273
- <defs>${clipDefs.join("")}${ctxBase.defs.join("")}</defs>
1386
+ 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="${SVG_FONT_FAMILY}" xml:space="preserve">
1387
+ <defs>${clipDefs.join("")}${r.defs.join("")}</defs>
1274
1388
  ${groups.join("\n")}
1275
1389
  </svg>`;
1276
- return { svg, width: Math.round(maxPW) / 100, height: Math.round(totalH) / 100, pageCount: pageNo, warnings, stats: ctxBase.stats };
1390
+ return { svg, width: Math.round(maxPW) / 100, height: Math.round(totalH) / 100, pageCount: pageNo2, warnings: r.warnings, stats: r.stats, regions: r.regions };
1391
+ }
1392
+ async function renderHwpxPages(input, options, select) {
1393
+ const r = await renderHwpxInternal(input, options);
1394
+ const pages = [];
1395
+ const pageSvgs = /* @__PURE__ */ new Map();
1396
+ const pageCount = r.sections.reduce((n, rs) => n + rs.pages.length, 0);
1397
+ const chosen = typeof select === "function" ? select(pageCount) : select;
1398
+ let pageNo2 = 0;
1399
+ for (const rs of r.sections) {
1400
+ for (const buf of rs.pages) {
1401
+ pageNo2++;
1402
+ pages.push({ page: pageNo2, width: ptNum(rs.PW), height: ptNum(rs.pageH) });
1403
+ if (chosen && !chosen.has(pageNo2)) continue;
1404
+ const body = buf.join("\n");
1405
+ const used = /* @__PURE__ */ new Set();
1406
+ for (const m of body.matchAll(/href="#(bin\d+)"/g)) used.add(m[1]);
1407
+ const defs = r.defs.filter((d) => {
1408
+ const m = /<symbol id="(bin\d+)"/.exec(d);
1409
+ return m ? used.has(m[1]) : true;
1410
+ });
1411
+ const clipId = `pgclip${pageNo2}`;
1412
+ pageSvgs.set(
1413
+ pageNo2,
1414
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${pt(rs.PW)} ${pt(rs.pageH)}" width="${pt(rs.PW)}pt" height="${pt(rs.pageH)}pt" font-family="${SVG_FONT_FAMILY}" xml:space="preserve" data-page="${pageNo2}">
1415
+ <defs><clipPath id="${clipId}"><rect x="0" y="0" width="${pt(rs.PW)}" height="${pt(rs.pageH)}"/></clipPath>${defs.join("")}</defs>
1416
+ <rect width="${pt(rs.PW)}" height="${pt(rs.pageH)}" fill="white"/>
1417
+ <g clip-path="url(#${clipId})">
1418
+ ${body}
1419
+ </g>
1420
+ </svg>`
1421
+ );
1422
+ }
1423
+ }
1424
+ const scene = { format: "hwpx", pages, regions: r.regions, warnings: r.warnings, stats: { texts: r.stats.texts, tables: r.stats.tables, images: r.stats.images, shapes: r.stats.shapes } };
1425
+ return { scene, pageSvgs };
1426
+ }
1427
+
1428
+ // src/render/document.ts
1429
+ import { readFile } from "fs/promises";
1430
+
1431
+ // src/detect.ts
1432
+ import JSZip2 from "jszip";
1433
+
1434
+ // src/hwp5/cfb-lenient.ts
1435
+ var CFB_MAGIC = Buffer.from([208, 207, 17, 224, 161, 177, 26, 225]);
1436
+ var END_OF_CHAIN = 4294967294;
1437
+ var FREE_SECT = 4294967295;
1438
+ var MAX_CHAIN_LENGTH = 1e6;
1439
+ var MAX_DIR_ENTRIES = 1e5;
1440
+ var MAX_STREAM_SIZE = 100 * 1024 * 1024;
1441
+ function parseLenientCfb(data) {
1442
+ if (data.length < 512) throw new Error("CFB \uD30C\uC77C\uC774 \uB108\uBB34 \uC9E7\uC2B5\uB2C8\uB2E4 (\uCD5C\uC18C 512\uBC14\uC774\uD2B8)");
1443
+ if (!data.subarray(0, 8).equals(CFB_MAGIC)) throw new Error("CFB \uB9E4\uC9C1 \uBC14\uC774\uD2B8 \uBD88\uC77C\uCE58");
1444
+ const sectorSizeShift = data.readUInt16LE(30);
1445
+ if (sectorSizeShift < 7 || sectorSizeShift > 16) throw new Error("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uC139\uD130 \uD06C\uAE30 \uC2DC\uD504\uD2B8: " + sectorSizeShift);
1446
+ const sectorSize = 1 << sectorSizeShift;
1447
+ const miniSectorSizeShift = data.readUInt16LE(32);
1448
+ if (miniSectorSizeShift > 16) throw new Error("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uBBF8\uB2C8 \uC139\uD130 \uD06C\uAE30 \uC2DC\uD504\uD2B8: " + miniSectorSizeShift);
1449
+ const miniSectorSize = 1 << miniSectorSizeShift;
1450
+ const headerFatSectorCount = data.readUInt32LE(44);
1451
+ if (headerFatSectorCount > 1e4) throw new Error("FAT \uC139\uD130 \uC218\uAC00 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4: " + headerFatSectorCount);
1452
+ const maxRealSectors = Math.ceil(Math.max(0, data.length - 512) / sectorSize);
1453
+ const maxFatSectors = Math.max(1, Math.ceil(maxRealSectors / (sectorSize / 4)));
1454
+ const fatSectorCount = Math.min(headerFatSectorCount, maxFatSectors);
1455
+ const firstDirSector = data.readUInt32LE(48);
1456
+ const miniStreamCutoff = data.readUInt32LE(56);
1457
+ const firstMiniFatSector = data.readUInt32LE(60);
1458
+ const miniFatSectorCount = data.readUInt32LE(64);
1459
+ const firstDifatSector = data.readUInt32LE(68);
1460
+ const difatSectorCount = data.readUInt32LE(72);
1461
+ function sectorOffset(id) {
1462
+ return 512 + id * sectorSize;
1463
+ }
1464
+ function readSectorData(id) {
1465
+ const off = sectorOffset(id);
1466
+ if (off + sectorSize > data.length) return Buffer.alloc(0);
1467
+ return data.subarray(off, off + sectorSize);
1468
+ }
1469
+ const fatSectors = [];
1470
+ for (let i = 0; i < 109 && fatSectors.length < fatSectorCount; i++) {
1471
+ const sid = data.readUInt32LE(76 + i * 4);
1472
+ if (sid === FREE_SECT || sid === END_OF_CHAIN) break;
1473
+ fatSectors.push(sid);
1474
+ }
1475
+ let difatSector = firstDifatSector;
1476
+ const visitedDifat = /* @__PURE__ */ new Set();
1477
+ for (let d = 0; d < difatSectorCount && difatSector !== END_OF_CHAIN && difatSector !== FREE_SECT; d++) {
1478
+ if (visitedDifat.has(difatSector)) break;
1479
+ visitedDifat.add(difatSector);
1480
+ const buf = readSectorData(difatSector);
1481
+ if (buf.length < sectorSize) break;
1482
+ const entriesPerSector = sectorSize / 4 - 1;
1483
+ for (let i = 0; i < entriesPerSector && fatSectors.length < fatSectorCount; i++) {
1484
+ const sid = buf.readUInt32LE(i * 4);
1485
+ if (sid === FREE_SECT || sid === END_OF_CHAIN) continue;
1486
+ fatSectors.push(sid);
1487
+ }
1488
+ difatSector = buf.readUInt32LE(entriesPerSector * 4);
1489
+ }
1490
+ const entriesPerFatSector = sectorSize / 4;
1491
+ const fatTable = new Uint32Array(fatSectors.length * entriesPerFatSector);
1492
+ for (let fi = 0; fi < fatSectors.length; fi++) {
1493
+ const buf = readSectorData(fatSectors[fi]);
1494
+ for (let i = 0; i < entriesPerFatSector; i++) {
1495
+ fatTable[fi * entriesPerFatSector + i] = i * 4 + 3 < buf.length ? buf.readUInt32LE(i * 4) : FREE_SECT;
1496
+ }
1497
+ }
1498
+ function readChain(startSector, maxBytes) {
1499
+ if (startSector === END_OF_CHAIN || startSector === FREE_SECT) return Buffer.alloc(0);
1500
+ if (maxBytes > MAX_STREAM_SIZE) throw new Error("\uC2A4\uD2B8\uB9BC\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4");
1501
+ const chunks = [];
1502
+ let current = startSector;
1503
+ let totalRead = 0;
1504
+ const visited = /* @__PURE__ */ new Set();
1505
+ while (current !== END_OF_CHAIN && current !== FREE_SECT && totalRead < maxBytes) {
1506
+ if (visited.has(current)) break;
1507
+ if (visited.size > MAX_CHAIN_LENGTH) break;
1508
+ visited.add(current);
1509
+ const buf = readSectorData(current);
1510
+ const remaining = maxBytes - totalRead;
1511
+ chunks.push(remaining < sectorSize ? buf.subarray(0, remaining) : buf);
1512
+ totalRead += Math.min(buf.length, remaining);
1513
+ current = current < fatTable.length ? fatTable[current] : END_OF_CHAIN;
1514
+ }
1515
+ return Buffer.concat(chunks);
1516
+ }
1517
+ let miniFatTable = null;
1518
+ function getMiniFatTable() {
1519
+ if (miniFatTable) return miniFatTable;
1520
+ if (miniFatSectorCount === 0 || firstMiniFatSector === END_OF_CHAIN) {
1521
+ miniFatTable = new Uint32Array(0);
1522
+ return miniFatTable;
1523
+ }
1524
+ const miniFatData = readChain(firstMiniFatSector, miniFatSectorCount * sectorSize);
1525
+ const entries = miniFatData.length / 4;
1526
+ miniFatTable = new Uint32Array(entries);
1527
+ for (let i = 0; i < entries; i++) {
1528
+ miniFatTable[i] = miniFatData.readUInt32LE(i * 4);
1529
+ }
1530
+ return miniFatTable;
1531
+ }
1532
+ const dirData = readChain(firstDirSector, MAX_DIR_ENTRIES * 128);
1533
+ const dirEntries = [];
1534
+ for (let offset = 0; offset + 128 <= dirData.length && dirEntries.length < MAX_DIR_ENTRIES; offset += 128) {
1535
+ const nameLen = dirData.readUInt16LE(offset + 64);
1536
+ if (nameLen <= 0 || nameLen > 64) {
1537
+ dirEntries.push({ name: "", type: 0, startSector: 0, size: 0 });
1538
+ continue;
1539
+ }
1540
+ const nameBytes = nameLen - 2;
1541
+ const name = nameBytes > 0 ? dirData.subarray(offset, offset + nameBytes).toString("utf16le") : "";
1542
+ const type = dirData[offset + 66];
1543
+ const startSector = dirData.readUInt32LE(offset + 116);
1544
+ const size = dirData.readUInt32LE(offset + 120);
1545
+ dirEntries.push({ name, type, startSector, size });
1546
+ }
1547
+ let miniStreamData = null;
1548
+ function getMiniStream() {
1549
+ if (miniStreamData) return miniStreamData;
1550
+ const root = dirEntries[0];
1551
+ if (!root || root.type !== 5) {
1552
+ miniStreamData = Buffer.alloc(0);
1553
+ return miniStreamData;
1554
+ }
1555
+ miniStreamData = readChain(root.startSector, root.size || MAX_STREAM_SIZE);
1556
+ return miniStreamData;
1557
+ }
1558
+ function readMiniStream(startSector, size) {
1559
+ const mft = getMiniFatTable();
1560
+ const ms = getMiniStream();
1561
+ if (mft.length === 0 || ms.length === 0) return Buffer.alloc(0);
1562
+ const chunks = [];
1563
+ let current = startSector;
1564
+ let totalRead = 0;
1565
+ const visited = /* @__PURE__ */ new Set();
1566
+ while (current !== END_OF_CHAIN && current !== FREE_SECT && totalRead < size) {
1567
+ if (visited.has(current)) break;
1568
+ if (visited.size > MAX_CHAIN_LENGTH) break;
1569
+ visited.add(current);
1570
+ const off = current * miniSectorSize;
1571
+ const remaining = size - totalRead;
1572
+ const chunkSize = Math.min(miniSectorSize, remaining);
1573
+ if (off + chunkSize <= ms.length) {
1574
+ chunks.push(ms.subarray(off, off + chunkSize));
1575
+ }
1576
+ totalRead += chunkSize;
1577
+ current = current < mft.length ? mft[current] : END_OF_CHAIN;
1578
+ }
1579
+ return Buffer.concat(chunks);
1580
+ }
1581
+ function readStreamData(entry) {
1582
+ if (entry.size === 0) return Buffer.alloc(0);
1583
+ if (entry.size < miniStreamCutoff) {
1584
+ const miniResult = readMiniStream(entry.startSector, entry.size);
1585
+ if (miniResult.length > 0) return miniResult;
1586
+ }
1587
+ return readChain(entry.startSector, entry.size);
1588
+ }
1589
+ function findEntryByPath(path) {
1590
+ const parts = path.replace(/^\//, "").split("/");
1591
+ if (parts.length === 1) {
1592
+ return dirEntries.find((e) => e.name === parts[0] && e.type === 2) ?? null;
1593
+ }
1594
+ const storageName = parts[0];
1595
+ const streamName = parts.slice(1).join("/");
1596
+ for (const e of dirEntries) {
1597
+ if (e.type === 2 && e.name === streamName) {
1598
+ return e;
1599
+ }
1600
+ }
1601
+ const lastPart = parts[parts.length - 1];
1602
+ return dirEntries.find((e) => e.type === 2 && e.name === lastPart) ?? null;
1603
+ }
1604
+ return {
1605
+ findStream(path) {
1606
+ const normalized = path.replace(/^\//, "");
1607
+ const entry = findEntryByPath(normalized);
1608
+ if (!entry || entry.type !== 2) return null;
1609
+ const stream = readStreamData(entry);
1610
+ return stream.length > 0 ? stream : null;
1611
+ },
1612
+ entries() {
1613
+ return dirEntries.filter((e) => e.type === 2);
1614
+ }
1615
+ };
1616
+ }
1617
+
1618
+ // src/detect.ts
1619
+ function magicBytes(buffer) {
1620
+ return new Uint8Array(buffer, 0, Math.min(4, buffer.byteLength));
1621
+ }
1622
+ function isZipFile(buffer) {
1623
+ const b = magicBytes(buffer);
1624
+ return b[0] === 80 && b[1] === 75 && b[2] === 3 && b[3] === 4;
1625
+ }
1626
+ function isHwpxFile(buffer) {
1627
+ return isZipFile(buffer);
1628
+ }
1629
+ function isOldHwpFile(buffer) {
1630
+ const b = magicBytes(buffer);
1631
+ return b[0] === 208 && b[1] === 207 && b[2] === 17 && b[3] === 224;
1632
+ }
1633
+ var HWP3_PREFIX = new TextEncoder().encode("HWP Document File V3.00");
1634
+ function isHwp3File(buffer) {
1635
+ if (buffer.byteLength < HWP3_PREFIX.length) return false;
1636
+ const head = new Uint8Array(buffer, 0, HWP3_PREFIX.length);
1637
+ for (let i = 0; i < HWP3_PREFIX.length; i++) {
1638
+ if (head[i] !== HWP3_PREFIX[i]) return false;
1639
+ }
1640
+ return true;
1641
+ }
1642
+ function isPdfFile(buffer) {
1643
+ const b = magicBytes(buffer);
1644
+ return b[0] === 37 && b[1] === 80 && b[2] === 68 && b[3] === 70;
1645
+ }
1646
+ function isImageFile(buffer) {
1647
+ if (buffer.byteLength < 12) return false;
1648
+ const b = new Uint8Array(buffer, 0, 12);
1649
+ if (b[0] === 137 && b[1] === 80 && b[2] === 78 && b[3] === 71) return true;
1650
+ if (b[0] === 255 && b[1] === 216 && b[2] === 255) return true;
1651
+ if (b[0] === 82 && b[1] === 73 && b[2] === 70 && b[3] === 70 && b[8] === 87 && b[9] === 69 && b[10] === 66 && b[11] === 80) return true;
1652
+ return false;
1653
+ }
1654
+ function isHwpmlFile(buffer) {
1655
+ const bytes = new Uint8Array(buffer, 0, Math.min(512, buffer.byteLength));
1656
+ const head = new TextDecoder("utf-8", { fatal: false }).decode(bytes).replace(/^\uFEFF/, "");
1657
+ return head.trimStart().startsWith("<?xml") && head.includes("<HWPML");
1658
+ }
1659
+ function detectFormat(buffer) {
1660
+ if (buffer.byteLength < 4) return "unknown";
1661
+ if (isHwp3File(buffer)) return "hwp3";
1662
+ if (isZipFile(buffer)) return "hwpx";
1663
+ if (isOldHwpFile(buffer)) return "hwp";
1664
+ if (isPdfFile(buffer)) return "pdf";
1665
+ if (isHwpmlFile(buffer)) return "hwpml";
1666
+ if (isImageFile(buffer)) return "image";
1667
+ return "unknown";
1668
+ }
1669
+ function detectOle2Format(buffer) {
1670
+ try {
1671
+ const cfb = parseLenientCfb(Buffer.from(buffer));
1672
+ const names = cfb.entries().map((e) => e.name);
1673
+ if (names.includes("Workbook") || names.includes("Book")) return "xls";
1674
+ if (names.includes("FileHeader")) return "hwp";
1675
+ if (names.some((n) => n === "DocInfo" || n.startsWith("Section"))) return "hwp";
1676
+ return "unknown";
1677
+ } catch {
1678
+ return "unknown";
1679
+ }
1680
+ }
1681
+ async function detectZipFormat(buffer) {
1682
+ try {
1683
+ const zip = await JSZip2.loadAsync(buffer);
1684
+ if (zip.file("xl/workbook.xml")) return "xlsx";
1685
+ if (zip.file("word/document.xml")) return "docx";
1686
+ if (zip.file("Contents/content.hpf") || zip.file("mimetype")) return "hwpx";
1687
+ const hasSection = Object.keys(zip.files).some((f) => f.startsWith("Contents/"));
1688
+ if (hasSection) return "hwpx";
1689
+ return "unknown";
1690
+ } catch {
1691
+ return "unknown";
1692
+ }
1693
+ }
1694
+
1695
+ // src/render/html.ts
1696
+ function renderSceneToHtml(scene, pageSvgs, options = {}) {
1697
+ const title = escapeXml(options.title ?? "kordoc");
1698
+ const first = scene.pages.find((p) => pageSvgs.has(p.page)) ?? scene.pages[0];
1699
+ const pageSize = first ? `${first.width}pt ${first.height}pt` : "auto";
1700
+ const pages = [...pageSvgs.keys()].sort((a, b) => a - b).map((n) => {
1701
+ const meta = scene.pages.find((p) => p.page === n);
1702
+ const size = meta ? ` style="width:${meta.width}pt;height:${meta.height}pt"` : "";
1703
+ return `<div class="kordoc-page" data-page="${n}"${size}>${pageSvgs.get(n)}</div>`;
1704
+ });
1705
+ return `<!doctype html>
1706
+ <html lang="ko">
1707
+ <head>
1708
+ <meta charset="utf-8">
1709
+ <meta name="viewport" content="width=device-width, initial-scale=1">
1710
+ <title>${title}</title>
1711
+ <style>
1712
+ html, body { margin: 0; background: #e9e8e6; }
1713
+ .kordoc-document { display: flex; flex-direction: column; align-items: center; gap: 16px; padding: 16px 0; }
1714
+ .kordoc-page { position: relative; background: white; box-shadow: 0 1px 4px rgba(0,0,0,.25); }
1715
+ .kordoc-page > svg { display: block; width: 100%; height: 100%; }
1716
+ @page { size: ${pageSize}; margin: 0; }
1717
+ @media print {
1718
+ html, body { background: white; }
1719
+ .kordoc-document { gap: 0; padding: 0; }
1720
+ .kordoc-page { box-shadow: none; break-after: page; page-break-after: always; }
1721
+ .kordoc-page:last-child { break-after: auto; page-break-after: auto; }
1722
+ }
1723
+ </style>
1724
+ </head>
1725
+ <body>
1726
+ <div class="kordoc-document">
1727
+ ${pages.join("\n")}
1728
+ </div>
1729
+ </body>
1730
+ </html>
1731
+ `;
1732
+ }
1733
+
1734
+ // src/print/renderer.ts
1735
+ import { existsSync } from "fs";
1736
+ import MarkdownIt from "markdown-it";
1737
+ var PRESETS = {
1738
+ default: `
1739
+ @page { size: A4; margin: 20mm; }
1740
+ body { font-family: 'Pretendard', 'Malgun Gothic', '\uB9D1\uC740 \uACE0\uB515', sans-serif; font-size: 11pt; line-height: 1.6; color: #111; }
1741
+ h1 { font-size: 20pt; margin: 1em 0 0.5em; }
1742
+ h2 { font-size: 16pt; margin: 1em 0 0.4em; }
1743
+ h3 { font-size: 13pt; margin: 0.8em 0 0.3em; }
1744
+ p { margin: 0.4em 0; }
1745
+ table { border-collapse: collapse; margin: 0.6em 0; width: 100%; }
1746
+ th, td { border: 1px solid #555; padding: 4px 8px; text-align: left; vertical-align: top; }
1747
+ th { background: #f0f0f0; }
1748
+ code { background: #f5f5f5; padding: 1px 4px; border-radius: 2px; font-family: 'D2Coding', Consolas, monospace; }
1749
+ pre { background: #f5f5f5; padding: 8px; border-radius: 4px; overflow-x: auto; }
1750
+ blockquote { border-left: 3px solid #ccc; padding-left: 12px; color: #555; margin: 0.6em 0; }
1751
+ img { max-width: 100%; }
1752
+ `,
1753
+ "gov-formal": `
1754
+ @page { size: A4; margin: 25mm 20mm; }
1755
+ body { font-family: '\uD568\uCD08\uB86C\uBC14\uD0D5', 'HCR Batang', 'Batang', 'Malgun Gothic', serif; font-size: 11pt; line-height: 1.7; color: #000; }
1756
+ h1 { font-size: 18pt; text-align: center; margin: 0.5em 0 1em; letter-spacing: 0.05em; }
1757
+ h2 { font-size: 14pt; margin: 1em 0 0.4em; border-bottom: 1px solid #999; padding-bottom: 2px; }
1758
+ h3 { font-size: 12pt; margin: 0.8em 0 0.3em; }
1759
+ p { margin: 0.3em 0; text-indent: 1em; }
1760
+ table { border-collapse: collapse; margin: 0.8em 0; width: 100%; }
1761
+ th, td { border: 1px solid #000; padding: 5px 8px; vertical-align: top; }
1762
+ th { background: #e8e8e8; font-weight: normal; }
1763
+ blockquote { border-left: 2px solid #555; padding-left: 12px; margin: 0.6em 0; }
1764
+ `,
1765
+ compact: `
1766
+ @page { size: A4; margin: 10mm; }
1767
+ body { font-family: 'Pretendard', 'Malgun Gothic', sans-serif; font-size: 9pt; line-height: 1.4; color: #111; }
1768
+ h1 { font-size: 14pt; margin: 0.5em 0 0.3em; }
1769
+ h2 { font-size: 12pt; margin: 0.5em 0 0.3em; }
1770
+ h3 { font-size: 10pt; margin: 0.4em 0 0.2em; }
1771
+ p { margin: 0.2em 0; }
1772
+ table { border-collapse: collapse; margin: 0.3em 0; width: 100%; font-size: 8pt; }
1773
+ th, td { border: 1px solid #777; padding: 2px 4px; }
1774
+ th { background: #f0f0f0; }
1775
+ `
1776
+ };
1777
+ var md = new MarkdownIt({
1778
+ html: true,
1779
+ linkify: true,
1780
+ breaks: false
1781
+ });
1782
+ function renderHtml(markdown, options) {
1783
+ const preset = options?.preset ?? "default";
1784
+ const css = PRESETS[preset] + (options?.extraCss ?? "");
1785
+ const body = md.render(markdown);
1786
+ const watermark = options?.watermark ? `<div class="watermark">${escapeHtml(options.watermark)}</div>` : "";
1787
+ const watermarkCss = options?.watermark ? `
1788
+ .watermark {
1789
+ position: fixed;
1790
+ top: 50%; left: 50%;
1791
+ transform: translate(-50%, -50%) rotate(-30deg);
1792
+ font-size: 80pt;
1793
+ color: rgba(0,0,0,0.08);
1794
+ pointer-events: none;
1795
+ z-index: 9999;
1796
+ white-space: nowrap;
1797
+ }` : "";
1798
+ return `<!DOCTYPE html>
1799
+ <html lang="ko">
1800
+ <head>
1801
+ <meta charset="utf-8">
1802
+ <style>${css}${watermarkCss}</style>
1803
+ </head>
1804
+ <body>
1805
+ ${watermark}
1806
+ ${body}
1807
+ </body>
1808
+ </html>`;
1809
+ }
1810
+ function escapeHtml(s) {
1811
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
1812
+ }
1813
+ async function htmlToPdf(html, options) {
1814
+ let puppeteer;
1815
+ try {
1816
+ puppeteer = await import("puppeteer-core");
1817
+ } catch {
1818
+ throw new KordocError(
1819
+ "PDF \uC0DD\uC131\uC5D0 puppeteer-core\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC124\uCE58: npm install puppeteer-core"
1820
+ );
1821
+ }
1822
+ const executablePath = process.env.PUPPETEER_EXECUTABLE_PATH ?? findChromiumPath();
1823
+ if (!executablePath) {
1824
+ throw new KordocError(
1825
+ "Chromium \uC2E4\uD589 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. PUPPETEER_EXECUTABLE_PATH \uD658\uACBD\uBCC0\uC218\uB97C \uC124\uC815\uD558\uC138\uC694."
1826
+ );
1827
+ }
1828
+ const browser = await puppeteer.default.launch({
1829
+ executablePath,
1830
+ headless: true,
1831
+ args: ["--no-sandbox", "--disable-setuid-sandbox"]
1832
+ });
1833
+ try {
1834
+ const page = await browser.newPage();
1835
+ await page.setContent(html, { waitUntil: "networkidle0" });
1836
+ const margin = options?.margin;
1837
+ const pdf = await page.pdf({
1838
+ format: options?.pageSize ?? "A4",
1839
+ landscape: options?.orientation === "landscape",
1840
+ printBackground: true,
1841
+ margin: margin ? {
1842
+ top: toCss(margin.top),
1843
+ right: toCss(margin.right),
1844
+ bottom: toCss(margin.bottom),
1845
+ left: toCss(margin.left)
1846
+ } : void 0,
1847
+ displayHeaderFooter: !!(options?.header || options?.footer),
1848
+ headerTemplate: options?.header ?? "<div></div>",
1849
+ footerTemplate: options?.footer ?? '<div style="font-size:8pt;width:100%;text-align:center;color:#777;"><span class="pageNumber"></span>/<span class="totalPages"></span></div>'
1850
+ });
1851
+ return Buffer.from(pdf);
1852
+ } finally {
1853
+ await browser.close();
1854
+ }
1855
+ }
1856
+ function toCss(v) {
1857
+ return typeof v === "number" ? `${v}mm` : v;
1858
+ }
1859
+ function findChromiumPath() {
1860
+ const win = [
1861
+ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
1862
+ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
1863
+ process.env.LOCALAPPDATA + "\\Google\\Chrome\\Application\\chrome.exe",
1864
+ "C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
1865
+ "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"
1866
+ ];
1867
+ const mac = [
1868
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
1869
+ "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
1870
+ ];
1871
+ const linux = ["/usr/bin/google-chrome", "/usr/bin/chromium-browser", "/usr/bin/chromium"];
1872
+ const candidates = process.platform === "win32" ? win : process.platform === "darwin" ? mac : linux;
1873
+ for (const p of candidates) {
1874
+ if (p && existsSync(p)) return p;
1875
+ }
1876
+ return null;
1877
+ }
1878
+ async function markdownToPdf(markdown, options) {
1879
+ const html = renderHtml(markdown, options);
1880
+ return htmlToPdf(html, options);
1881
+ }
1882
+ async function blocksToPdf(blocks, options) {
1883
+ const markdown = blocksToMarkdown(blocks);
1884
+ return markdownToPdf(markdown, options);
1885
+ }
1886
+
1887
+ // src/render/pdf.ts
1888
+ async function renderHtmlToPdf(html, options = {}) {
1889
+ let puppeteer;
1890
+ try {
1891
+ puppeteer = await import("puppeteer-core");
1892
+ } catch {
1893
+ throw new KordocError("PDF \uB80C\uB354\uC5D0\uB294 puppeteer-core \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 (npm install puppeteer-core). SVG/HTML/PNG \uB294 Chromium \uC5C6\uC774 \uB429\uB2C8\uB2E4");
1894
+ }
1895
+ const executablePath = options.browserExecutablePath ?? process.env.PUPPETEER_EXECUTABLE_PATH ?? findChromiumPath();
1896
+ if (!executablePath) {
1897
+ throw new KordocError("Chromium \uC2E4\uD589 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 browserExecutablePath \uC635\uC158 \uB610\uB294 PUPPETEER_EXECUTABLE_PATH \uD658\uACBD\uBCC0\uC218\uB97C \uC9C0\uC815\uD558\uC138\uC694");
1898
+ }
1899
+ const browser = await puppeteer.default.launch({ executablePath, headless: true, args: ["--no-sandbox", "--disable-setuid-sandbox"] });
1900
+ try {
1901
+ const page = await browser.newPage();
1902
+ await page.setContent(html, { waitUntil: "load" });
1903
+ const pdf = await page.pdf({ printBackground: true, preferCSSPageSize: true });
1904
+ return Buffer.from(pdf);
1905
+ } finally {
1906
+ await browser.close();
1907
+ }
1908
+ }
1909
+
1910
+ // src/render/document.ts
1911
+ async function loadBuffer(input) {
1912
+ if (typeof input === "string") {
1913
+ try {
1914
+ return toArrayBuffer(await readFile(input));
1915
+ } catch (err) {
1916
+ const code = err instanceof Error && "code" in err ? err.code : void 0;
1917
+ throw new KordocError(code === "ENOENT" ? `\uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}` : `\uD30C\uC77C \uC77D\uAE30 \uC2E4\uD328: ${input}`);
1918
+ }
1919
+ }
1920
+ if (Buffer.isBuffer(input)) return toArrayBuffer(input);
1921
+ if (input instanceof Uint8Array) return input.buffer.slice(input.byteOffset, input.byteOffset + input.byteLength);
1922
+ return input;
1923
+ }
1924
+ async function sourceFormatOf(buffer) {
1925
+ const format = detectFormat(buffer);
1926
+ if (format === "hwpx") {
1927
+ const zip = await detectZipFormat(buffer);
1928
+ if (zip === "hwpx" || zip === "unknown") return "hwpx";
1929
+ throw new KordocError(`\uB80C\uB354 \uBBF8\uC9C0\uC6D0 \uD615\uC2DD(${zip}) \u2014 \uB808\uC774\uC544\uC6C3 \uB80C\uB354\uB294 HWPX \uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4`);
1930
+ }
1931
+ if (format === "hwp") throw new KordocError("HWP5 \uB808\uC774\uC544\uC6C3 \uB80C\uB354\uB294 \uC544\uC9C1 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2014 \uD55C\uCEF4\uC5D0\uC11C HWPX \uB85C \uC800\uC7A5\uD55C \uB4A4 \uB80C\uB354\uD558\uC138\uC694 (#75 \uD6C4\uC18D)");
1932
+ throw new KordocError(`\uB80C\uB354 \uBBF8\uC9C0\uC6D0 \uD615\uC2DD(${format}) \u2014 \uB808\uC774\uC544\uC6C3 \uB80C\uB354\uB294 HWPX \uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4`);
1933
+ }
1934
+ async function renderDocumentToScene(input, options = {}) {
1935
+ const buffer = await loadBuffer(input);
1936
+ const source = await sourceFormatOf(buffer);
1937
+ if (source !== "hwpx") throw new KordocError("HWP5 \uB808\uC774\uC544\uC6C3 \uB80C\uB354\uB294 \uC544\uC9C1 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
1938
+ const select = options.pages !== void 0 ? (pageCount) => {
1939
+ const set = parsePageRange(options.pages, pageCount);
1940
+ if (set.size === 0) throw new KordocError(`\uC120\uD0DD\uD55C \uD398\uC774\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uBB38\uC11C\uB294 ${pageCount}\uCABD (pages: ${JSON.stringify(options.pages)})`);
1941
+ return set;
1942
+ } : void 0;
1943
+ const { scene, pageSvgs } = await renderHwpxPages(buffer, {
1944
+ reflow: options.reflow ?? true,
1945
+ reflowMode: options.reflowMode,
1946
+ highlights: options.highlights,
1947
+ maxImageBytes: options.maxImageBytes
1948
+ }, select);
1949
+ return { scene, pageSvgs };
1950
+ }
1951
+ async function renderDocument(input, options) {
1952
+ const { scene, pageSvgs } = await renderDocumentToScene(input, options);
1953
+ const pageNos = [...pageSvgs.keys()].sort((a, b) => a - b);
1954
+ const sizeOf = (n) => scene.pages.find((p) => p.page === n);
1955
+ const assets = [];
1956
+ switch (options.format) {
1957
+ case "svg":
1958
+ for (const n of pageNos) {
1959
+ const p = sizeOf(n);
1960
+ assets.push({ format: "svg", page: n, data: pageSvgs.get(n), width: p.width, height: p.height, mimeType: "image/svg+xml" });
1961
+ }
1962
+ break;
1963
+ case "html":
1964
+ assets.push({ format: "html", data: renderSceneToHtml(scene, pageSvgs, { title: options.title }), mimeType: "text/html" });
1965
+ break;
1966
+ case "png":
1967
+ case "jpeg":
1968
+ for (const n of pageNos) {
1969
+ const p = sizeOf(n);
1970
+ const r = await rasterizePageSvg(pageSvgs.get(n), p.width, p.height, { format: options.format, maxWidthPx: options.maxWidthPx, quality: options.quality });
1971
+ assets.push({ format: options.format, page: n, data: r.data, width: r.widthPx, height: r.heightPx, scale: r.scale, mimeType: r.mimeType });
1972
+ }
1973
+ break;
1974
+ case "pdf": {
1975
+ const html = renderSceneToHtml(scene, pageSvgs, { title: options.title });
1976
+ assets.push({ format: "pdf", data: await renderHtmlToPdf(html, { browserExecutablePath: options.browserExecutablePath }), mimeType: "application/pdf" });
1977
+ break;
1978
+ }
1979
+ default:
1980
+ throw new KordocError(`\uC54C \uC218 \uC5C6\uB294 \uB80C\uB354 \uD3EC\uB9F7: ${String(options.format)} (svg|html|png|jpeg|pdf)`);
1981
+ }
1982
+ return { scene, assets };
1983
+ }
1984
+
1985
+ // src/render/regions.ts
1986
+ function cropRect(bbox, scale, pageWidthPx, pageHeightPx, paddingPt = 0) {
1987
+ const W = Math.max(1, Math.floor(pageWidthPx)), H = Math.max(1, Math.floor(pageHeightPx));
1988
+ const clamp = (v, hi) => Math.min(Math.max(0, v), hi);
1989
+ let left = clamp(Math.floor((bbox.x - paddingPt) * scale), W - 1);
1990
+ let top = clamp(Math.floor((bbox.y - paddingPt) * scale), H - 1);
1991
+ const right = clamp(Math.ceil((bbox.x + bbox.width + paddingPt) * scale), W);
1992
+ const bottom = clamp(Math.ceil((bbox.y + bbox.height + paddingPt) * scale), H);
1993
+ const width = Math.max(1, right - left), height = Math.max(1, bottom - top);
1994
+ if (left + width > W) left = W - width;
1995
+ if (top + height > H) top = H - height;
1996
+ return { left, top, width, height };
1997
+ }
1998
+ async function extractRenderedRegions(input, options = {}) {
1999
+ const { scene, pageSvgs } = await renderDocumentToScene(input, { pages: options.pages, reflow: options.reflow, reflowMode: options.reflowMode });
2000
+ const types = options.types ? new Set(options.types) : null;
2001
+ const format = options.format ?? "png";
2002
+ const wanted = scene.regions.filter((r) => (!types || types.has(r.type)) && (!options.filter || options.filter(r)));
2003
+ const byPage = /* @__PURE__ */ new Map();
2004
+ for (const r of wanted) for (const b of r.regions) if (pageSvgs.has(b.page)) (byPage.get(b.page) ?? byPage.set(b.page, []).get(b.page)).push({ region: r, bbox: b });
2005
+ if (byPage.size === 0) return [];
2006
+ const sharp = await loadSharp();
2007
+ const out = [];
2008
+ for (const [page, items] of [...byPage.entries()].sort((a, b) => a[0] - b[0])) {
2009
+ const meta = scene.pages.find((p) => p.page === page);
2010
+ if (!meta) throw new KordocError(`\uD398\uC774\uC9C0 ${page} \uBA54\uD0C0 \uC5C6\uC74C`);
2011
+ const raster = await rasterizePageSvg(pageSvgs.get(page), meta.width, meta.height, { format, maxWidthPx: options.maxWidthPx, quality: options.quality });
2012
+ for (const { region, bbox } of items) {
2013
+ const rect = cropRect(bbox, raster.scale, raster.widthPx, raster.heightPx, options.paddingPt ?? 0);
2014
+ const pipeline = sharp(raster.data).extract(rect);
2015
+ const data = format === "jpeg" ? await pipeline.jpeg({ quality: options.quality ?? 85 }).toBuffer() : await pipeline.png().toBuffer();
2016
+ out.push({ region, page, bbox, mimeType: raster.mimeType, data, widthPx: rect.width, heightPx: rect.height });
2017
+ }
2018
+ }
2019
+ const order = new Map(scene.regions.map((r, i) => [r.id, i]));
2020
+ out.sort((a, b) => order.get(a.region.id) - order.get(b.region.id) || a.page - b.page);
2021
+ return out;
1277
2022
  }
1278
2023
 
1279
2024
  export {
2025
+ parseLenientCfb,
2026
+ isZipFile,
2027
+ isHwpxFile,
2028
+ isOldHwpFile,
2029
+ isPdfFile,
2030
+ detectFormat,
2031
+ detectOle2Format,
2032
+ detectZipFormat,
1280
2033
  charWidthEm1000,
1281
2034
  SPACE_EM_FIXED,
1282
2035
  SPACE_EM_FONT,
2036
+ faceClassForGen,
1283
2037
  measureTextWidth,
1284
2038
  simulateWrap,
1285
2039
  simulateWrapKeepWord,
1286
2040
  fitRatioForFewerLines,
1287
- renderHwpxToSvg
2041
+ renderHtml,
2042
+ markdownToPdf,
2043
+ blocksToPdf,
2044
+ regionId,
2045
+ unionBBox,
2046
+ RegionCollector,
2047
+ renderHwpxToSvg,
2048
+ renderHwpxPages,
2049
+ renderSceneToHtml,
2050
+ renderHtmlToPdf,
2051
+ renderDocumentToScene,
2052
+ renderDocument,
2053
+ cropRect,
2054
+ extractRenderedRegions
1288
2055
  };
1289
- //# sourceMappingURL=chunk-IOJX4Q63.js.map
2056
+ //# sourceMappingURL=chunk-T7AFLXGA.js.map