kordoc 4.14.0 → 4.14.2
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 +18 -2
- package/dist/{-SLX6IB6Y.js → -AQKXLFIM.js} +10 -10
- package/dist/{chunk-WAPKUYGP.cjs → chunk-247ANM72.cjs} +11 -11
- package/dist/chunk-247ANM72.cjs.map +1 -0
- package/dist/{chunk-EOTAPX2M.js → chunk-3DUADAY2.js} +3 -3
- package/dist/{chunk-B7MOYHVR.cjs → chunk-422427XJ.cjs} +6 -6
- package/dist/chunk-422427XJ.cjs.map +1 -0
- package/dist/{chunk-HG5LXXCC.js → chunk-7IAQ4HOK.js} +1 -1
- package/dist/{chunk-XVIJLHCW.js.map → chunk-7IAQ4HOK.js.map} +1 -1
- package/dist/{chunk-JIQWI7S2.js → chunk-A7QC2ZVP.js} +3 -3
- package/dist/{chunk-HCHA3Y2T.js → chunk-C7FQBSON.js} +2 -2
- package/dist/chunk-DCZVOIEO.cjs.map +1 -1
- package/dist/{chunk-7VUHZFGQ.js → chunk-DOGPOY4B.js} +2 -2
- package/dist/{chunk-6T6MB5ON.js → chunk-EDNJLUSE.js} +2 -2
- package/dist/{chunk-EMQZX5QQ.js → chunk-EISO3POT.js} +301 -124
- package/dist/chunk-EISO3POT.js.map +1 -0
- package/dist/{chunk-LCGAO5LF.js → chunk-EP7KOI2V.js} +3 -3
- package/dist/{chunk-WRIHDGGY.cjs → chunk-EQZI77PP.cjs} +3 -3
- package/dist/chunk-EQZI77PP.cjs.map +1 -0
- package/dist/{chunk-XVIJLHCW.js → chunk-FOJZNMMK.js} +1 -1
- package/dist/{chunk-HG5LXXCC.js.map → chunk-FOJZNMMK.js.map} +1 -1
- package/dist/{chunk-PLXNW3J4.js → chunk-GDW4YP7K.js} +2 -2
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-ANKDK5DF.cjs → chunk-HR2XNERB.cjs} +2 -2
- package/dist/chunk-HR2XNERB.cjs.map +1 -0
- package/dist/{chunk-3U3PJGVO.js → chunk-ILU76UF3.js} +13 -2
- package/dist/chunk-ILU76UF3.js.map +1 -0
- package/dist/{chunk-J3SM7VLM.js → chunk-JQEFP45L.js} +2 -2
- package/dist/{chunk-M5NRJMA4.js → chunk-KVWV4ULP.js} +3 -3
- package/dist/{chunk-COUGOFT3.cjs → chunk-L7DMSMAG.cjs} +1 -1
- package/dist/chunk-L7DMSMAG.cjs.map +1 -0
- package/dist/{chunk-GMX6EKCY.js → chunk-NS55SM7A.js} +2 -2
- package/dist/{chunk-XH34WJKB.js → chunk-QC5T6D4J.js} +2 -2
- package/dist/{chunk-STLNL53H.cjs → chunk-QOMNEWCQ.cjs} +4 -4
- package/dist/chunk-QOMNEWCQ.cjs.map +1 -0
- package/dist/{chunk-CDQJKMZ5.js → chunk-TNCKOL2O.js} +2 -2
- package/dist/{chunk-HH7T6SMB.js → chunk-TSFS5VKD.js} +3072 -1721
- package/dist/chunk-TSFS5VKD.js.map +1 -0
- package/dist/{chunk-RCTWZYAM.js → chunk-UET462HB.js} +2 -2
- package/dist/{chunk-A2JDWBKG.js → chunk-VQ5W4MYO.js} +2 -2
- package/dist/{chunk-ZWTEE63A.js → chunk-ZWD734EY.js} +2 -2
- package/dist/{chunk-UBNJXMYX.js → chunk-ZWOFQRIB.js} +14 -6
- package/dist/chunk-ZWOFQRIB.js.map +1 -0
- package/dist/chunks-SX77P5CV.js +10 -0
- package/dist/cli.js +1066 -1038
- package/dist/cli.js.map +1 -1
- package/dist/{formula-VSZIJZXP.js → formula-5S7WWXGH.js} +4 -4
- package/dist/{formula-VYDTA27M.js → formula-JGFTXWYT.js} +3 -3
- package/dist/{formula-TAYYDV73.cjs → formula-PJJ6S3Z2.cjs} +9 -9
- package/dist/formula-PJJ6S3Z2.cjs.map +1 -0
- package/dist/{image-ocr-5WBAIBPQ.js → image-ocr-FLIL7MGN.js} +6 -6
- package/dist/{image-ocr-N6IBZJAK.js → image-ocr-WCAYXLOA.js} +8 -8
- package/dist/{image-ocr-ZX4W2RBS.cjs → image-ocr-ZTYAGV3W.cjs} +12 -12
- package/dist/image-ocr-ZTYAGV3W.cjs.map +1 -0
- package/dist/index.cjs +3010 -1465
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -6
- package/dist/index.d.ts +11 -6
- package/dist/index.js +2547 -1002
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +973 -932
- package/dist/mcp.js.map +1 -1
- package/dist/{model-bundle-5CBFVIXA.js → model-bundle-FSPZZ2EM.js} +5 -5
- package/dist/{models-L74RBKK3.js → models-CJPAQK5R.js} +5 -5
- package/dist/page-range-P7SDW6LR.cjs.map +1 -1
- package/dist/{parser-66NMJUOG.js → parser-A4TMPJAM.js} +7 -7
- package/dist/{parser-BK66Y5JD.js → parser-SCUTZAIJ.js} +7 -7
- package/dist/{parser-WM2DMVLY.cjs → parser-VCXE4I5A.cjs} +27 -27
- package/dist/parser-VCXE4I5A.cjs.map +1 -0
- package/dist/pdf-ocr-76SAUXMZ.js +13 -0
- package/dist/pdf-ocr-CPU55CVF.js +16 -0
- package/dist/pdf-ocr-MBZZ57LD.cjs +14 -0
- package/dist/pdf-ocr-MBZZ57LD.cjs.map +1 -0
- package/dist/{profile-io-JZ3FDHDK.js → profile-io-LBM263K7.js} +3 -3
- package/dist/{rasterize-33WOOVSM.js → rasterize-46RG4ZF6.js} +3 -3
- package/dist/{render-MLN4ZLVD.js → render-NGP5T24S.js} +7 -7
- package/dist/seal-RGUPOLXD.js +10 -0
- package/dist/{setup-G6AEN4J7.js → setup-AU4OCHNH.js} +3 -3
- package/dist/visual-NZLYIYEM.js +19 -0
- package/dist/{watch-OY6XKGC5.js → watch-MKPUCPXM.js} +11 -11
- package/package.json +2 -2
- package/dist/chunk-3U3PJGVO.js.map +0 -1
- package/dist/chunk-ANKDK5DF.cjs.map +0 -1
- package/dist/chunk-B7MOYHVR.cjs.map +0 -1
- package/dist/chunk-COUGOFT3.cjs.map +0 -1
- package/dist/chunk-EMQZX5QQ.js.map +0 -1
- package/dist/chunk-HH7T6SMB.js.map +0 -1
- package/dist/chunk-STLNL53H.cjs.map +0 -1
- package/dist/chunk-UBNJXMYX.js.map +0 -1
- package/dist/chunk-WAPKUYGP.cjs.map +0 -1
- package/dist/chunk-WRIHDGGY.cjs.map +0 -1
- package/dist/chunks-PEHRXW2P.js +0 -10
- package/dist/formula-TAYYDV73.cjs.map +0 -1
- package/dist/image-ocr-ZX4W2RBS.cjs.map +0 -1
- package/dist/parser-WM2DMVLY.cjs.map +0 -1
- package/dist/pdf-ocr-322MBLDK.js +0 -16
- package/dist/pdf-ocr-A4UBXLM2.js +0 -13
- package/dist/pdf-ocr-G4TBDUYL.cjs +0 -14
- package/dist/pdf-ocr-G4TBDUYL.cjs.map +0 -1
- package/dist/seal-JQWSNHRG.js +0 -10
- package/dist/visual-VZ7QGAUC.js +0 -19
- /package/dist/{-SLX6IB6Y.js.map → -AQKXLFIM.js.map} +0 -0
- /package/dist/{chunk-EOTAPX2M.js.map → chunk-3DUADAY2.js.map} +0 -0
- /package/dist/{chunk-JIQWI7S2.js.map → chunk-A7QC2ZVP.js.map} +0 -0
- /package/dist/{chunk-HCHA3Y2T.js.map → chunk-C7FQBSON.js.map} +0 -0
- /package/dist/{chunk-7VUHZFGQ.js.map → chunk-DOGPOY4B.js.map} +0 -0
- /package/dist/{chunk-6T6MB5ON.js.map → chunk-EDNJLUSE.js.map} +0 -0
- /package/dist/{chunk-LCGAO5LF.js.map → chunk-EP7KOI2V.js.map} +0 -0
- /package/dist/{chunk-PLXNW3J4.js.map → chunk-GDW4YP7K.js.map} +0 -0
- /package/dist/{chunk-J3SM7VLM.js.map → chunk-JQEFP45L.js.map} +0 -0
- /package/dist/{chunk-M5NRJMA4.js.map → chunk-KVWV4ULP.js.map} +0 -0
- /package/dist/{chunk-GMX6EKCY.js.map → chunk-NS55SM7A.js.map} +0 -0
- /package/dist/{chunk-XH34WJKB.js.map → chunk-QC5T6D4J.js.map} +0 -0
- /package/dist/{chunk-CDQJKMZ5.js.map → chunk-TNCKOL2O.js.map} +0 -0
- /package/dist/{chunk-RCTWZYAM.js.map → chunk-UET462HB.js.map} +0 -0
- /package/dist/{chunk-A2JDWBKG.js.map → chunk-VQ5W4MYO.js.map} +0 -0
- /package/dist/{chunk-ZWTEE63A.js.map → chunk-ZWD734EY.js.map} +0 -0
- /package/dist/{chunks-PEHRXW2P.js.map → chunks-SX77P5CV.js.map} +0 -0
- /package/dist/{formula-VSZIJZXP.js.map → formula-5S7WWXGH.js.map} +0 -0
- /package/dist/{formula-VYDTA27M.js.map → formula-JGFTXWYT.js.map} +0 -0
- /package/dist/{image-ocr-5WBAIBPQ.js.map → image-ocr-FLIL7MGN.js.map} +0 -0
- /package/dist/{image-ocr-N6IBZJAK.js.map → image-ocr-WCAYXLOA.js.map} +0 -0
- /package/dist/{model-bundle-5CBFVIXA.js.map → model-bundle-FSPZZ2EM.js.map} +0 -0
- /package/dist/{models-L74RBKK3.js.map → models-CJPAQK5R.js.map} +0 -0
- /package/dist/{parser-66NMJUOG.js.map → parser-A4TMPJAM.js.map} +0 -0
- /package/dist/{parser-BK66Y5JD.js.map → parser-SCUTZAIJ.js.map} +0 -0
- /package/dist/{pdf-ocr-322MBLDK.js.map → pdf-ocr-76SAUXMZ.js.map} +0 -0
- /package/dist/{pdf-ocr-A4UBXLM2.js.map → pdf-ocr-CPU55CVF.js.map} +0 -0
- /package/dist/{profile-io-JZ3FDHDK.js.map → profile-io-LBM263K7.js.map} +0 -0
- /package/dist/{rasterize-33WOOVSM.js.map → rasterize-46RG4ZF6.js.map} +0 -0
- /package/dist/{render-MLN4ZLVD.js.map → render-NGP5T24S.js.map} +0 -0
- /package/dist/{seal-JQWSNHRG.js.map → seal-RGUPOLXD.js.map} +0 -0
- /package/dist/{setup-G6AEN4J7.js.map → setup-AU4OCHNH.js.map} +0 -0
- /package/dist/{visual-VZ7QGAUC.js.map → visual-NZLYIYEM.js.map} +0 -0
- /package/dist/{watch-OY6XKGC5.js.map → watch-MKPUCPXM.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
hasStructuredCellContent,
|
|
10
10
|
inlineImagesIntoMarkdown,
|
|
11
11
|
mapPuaText
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-VQ5W4MYO.js";
|
|
13
13
|
import {
|
|
14
14
|
parsePageRange
|
|
15
15
|
} from "./chunk-GE43BE46.js";
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
HEADING_RATIO_H1,
|
|
18
18
|
HEADING_RATIO_H2,
|
|
19
19
|
HEADING_RATIO_H3
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-FOJZNMMK.js";
|
|
21
21
|
import {
|
|
22
22
|
KordocError,
|
|
23
23
|
VERSION,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
sanitizeHref,
|
|
31
31
|
stripDtd,
|
|
32
32
|
toArrayBuffer
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-JQEFP45L.js";
|
|
34
34
|
|
|
35
35
|
// src/index.ts
|
|
36
36
|
import { readFile as readFile3 } from "fs/promises";
|
|
@@ -290,6 +290,7 @@ async function detectZipFormat(buffer) {
|
|
|
290
290
|
const zip = await JSZip.loadAsync(buffer);
|
|
291
291
|
if (zip.file("xl/workbook.xml")) return "xlsx";
|
|
292
292
|
if (zip.file("word/document.xml")) return "docx";
|
|
293
|
+
if (zip.file("ppt/presentation.xml")) return "pptx";
|
|
293
294
|
if (zip.file("Contents/content.hpf") || zip.file("mimetype")) return "hwpx";
|
|
294
295
|
const hasSection = Object.keys(zip.files).some((f) => f.startsWith("Contents/"));
|
|
295
296
|
if (hasSection) return "hwpx";
|
|
@@ -2350,8 +2351,10 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
2350
2351
|
text += "\n";
|
|
2351
2352
|
break;
|
|
2352
2353
|
// 강제 줄바꿈 — ref 추출기·소스맵 스캐너와 동일 모델
|
|
2354
|
+
// 고정폭·묶음 빈칸 — 묶음 빈칸(nbSpace)을 빠뜨리면 "2026.<nbSpace/>9." 가 "2026.9." 로 붙는다
|
|
2353
2355
|
case "fwSpace":
|
|
2354
2356
|
case "hwSpace":
|
|
2357
|
+
case "nbSpace":
|
|
2355
2358
|
text += " ";
|
|
2356
2359
|
break;
|
|
2357
2360
|
// 테이블 자체는 walkSection에서 처리 — 글자취급(inline) 표만 경계 마커를 남겨
|
|
@@ -2527,7 +2530,11 @@ function extractRunSpans(para2, ctx, mode, requireMixed) {
|
|
|
2527
2530
|
for (let k = 0; k < (tkids?.length ?? 0); k++) {
|
|
2528
2531
|
const tk = tkids[k];
|
|
2529
2532
|
if (tk.nodeType === 3 || tk.nodeType === 4) text += tk.textContent || "";
|
|
2530
|
-
else if (tk.nodeType === 1)
|
|
2533
|
+
else if (tk.nodeType === 1) {
|
|
2534
|
+
const ttag = (tk.tagName || tk.localName || "").replace(/^[^:]+:/, "");
|
|
2535
|
+
if (ttag === "tab" || ttag === "fwSpace" || ttag === "hwSpace" || ttag === "nbSpace") text += " ";
|
|
2536
|
+
else return null;
|
|
2537
|
+
}
|
|
2531
2538
|
}
|
|
2532
2539
|
} else if (rtag === "secPr" || rtag === "colPr") {
|
|
2533
2540
|
} else if (rtag === "ctrl") {
|
|
@@ -3345,6 +3352,20 @@ function parseDublinCoreMetadata(xml, metadata) {
|
|
|
3345
3352
|
}
|
|
3346
3353
|
|
|
3347
3354
|
// src/hwpx/parser.ts
|
|
3355
|
+
function assignSectionPage(block, sectionNum) {
|
|
3356
|
+
const pending = [block];
|
|
3357
|
+
while (pending.length > 0) {
|
|
3358
|
+
const current = pending.pop();
|
|
3359
|
+
current.pageNumber = sectionNum;
|
|
3360
|
+
for (const child of current.children ?? []) pending.push(child);
|
|
3361
|
+
for (const caption of current.table?.captionBlocks ?? []) pending.push(caption);
|
|
3362
|
+
for (const row of current.table?.cells ?? []) {
|
|
3363
|
+
for (const cell2 of row) {
|
|
3364
|
+
for (const child of cell2.blocks ?? []) pending.push(child);
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3348
3369
|
async function parseHwpxDocument(buffer, options) {
|
|
3349
3370
|
precheckZipSize(buffer, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES);
|
|
3350
3371
|
let zip;
|
|
@@ -3412,7 +3433,7 @@ async function parseHwpxDocument(buffer, options) {
|
|
|
3412
3433
|
metadata.pageCount = layoutPages ? Math.max(shared.pageState.base, 1) : sectionPaths.length;
|
|
3413
3434
|
if (!layoutPages) {
|
|
3414
3435
|
for (const r of sectionRanges) {
|
|
3415
|
-
for (let b = r.start; b < r.end; b++) allBlocks[b]
|
|
3436
|
+
for (let b = r.start; b < r.end; b++) assignSectionPage(allBlocks[b], r.sectionNum);
|
|
3416
3437
|
}
|
|
3417
3438
|
}
|
|
3418
3439
|
if (options?.pages) {
|
|
@@ -3431,167 +3452,6 @@ async function parseHwpxDocument(buffer, options) {
|
|
|
3431
3452
|
return { markdown, blocks, metadata, outline: outline.length > 0 ? outline : void 0, warnings: warnings.length > 0 ? warnings : void 0, images: images.length > 0 ? images : void 0 };
|
|
3432
3453
|
}
|
|
3433
3454
|
|
|
3434
|
-
// src/hwp5/numbering.ts
|
|
3435
|
-
var NumberingState = class {
|
|
3436
|
-
currentId = 0;
|
|
3437
|
-
counters = [0, 0, 0, 0, 0, 0, 0];
|
|
3438
|
-
history = /* @__PURE__ */ new Map();
|
|
3439
|
-
/** 번호 문단 처리: 카운터 갱신 후 수준별 카운터 스냅샷 반환 */
|
|
3440
|
-
advance(numberingId, level) {
|
|
3441
|
-
const lv = Math.min(Math.max(level, 0), 6);
|
|
3442
|
-
if (this.currentId !== numberingId) {
|
|
3443
|
-
if (this.currentId !== 0) this.history.set(this.currentId, [...this.counters]);
|
|
3444
|
-
const saved = this.history.get(numberingId);
|
|
3445
|
-
if (saved) {
|
|
3446
|
-
this.counters = [...saved];
|
|
3447
|
-
} else {
|
|
3448
|
-
const prev = this.counters;
|
|
3449
|
-
this.counters = [0, 0, 0, 0, 0, 0, 0];
|
|
3450
|
-
for (let i = 0; i < lv; i++) this.counters[i] = prev[i];
|
|
3451
|
-
}
|
|
3452
|
-
this.currentId = numberingId;
|
|
3453
|
-
}
|
|
3454
|
-
this.counters[lv]++;
|
|
3455
|
-
for (let i = lv + 1; i < 7; i++) this.counters[i] = 0;
|
|
3456
|
-
return [...this.counters];
|
|
3457
|
-
}
|
|
3458
|
-
};
|
|
3459
|
-
function headFormatToNumFmt(code) {
|
|
3460
|
-
switch (code) {
|
|
3461
|
-
case 1:
|
|
3462
|
-
return "circled";
|
|
3463
|
-
case 2:
|
|
3464
|
-
return "romanUpper";
|
|
3465
|
-
case 3:
|
|
3466
|
-
return "romanLower";
|
|
3467
|
-
case 4:
|
|
3468
|
-
return "latinUpper";
|
|
3469
|
-
case 5:
|
|
3470
|
-
return "latinLower";
|
|
3471
|
-
case 8:
|
|
3472
|
-
return "ganada";
|
|
3473
|
-
case 9:
|
|
3474
|
-
return "circledGanada";
|
|
3475
|
-
case 10:
|
|
3476
|
-
return "jamo";
|
|
3477
|
-
case 11:
|
|
3478
|
-
return "circledJamo";
|
|
3479
|
-
case 12:
|
|
3480
|
-
return "hangulNum";
|
|
3481
|
-
case 13:
|
|
3482
|
-
return "hanjaNum";
|
|
3483
|
-
default:
|
|
3484
|
-
return "digit";
|
|
3485
|
-
}
|
|
3486
|
-
}
|
|
3487
|
-
function shapeFormatToNumFmt(code) {
|
|
3488
|
-
switch (code) {
|
|
3489
|
-
case 1:
|
|
3490
|
-
return "circled";
|
|
3491
|
-
case 2:
|
|
3492
|
-
return "romanUpper";
|
|
3493
|
-
case 3:
|
|
3494
|
-
return "romanLower";
|
|
3495
|
-
case 4:
|
|
3496
|
-
return "latinUpper";
|
|
3497
|
-
case 5:
|
|
3498
|
-
return "latinLower";
|
|
3499
|
-
case 6:
|
|
3500
|
-
return "ganada";
|
|
3501
|
-
case 7:
|
|
3502
|
-
return "hangulNum";
|
|
3503
|
-
case 8:
|
|
3504
|
-
return "hanjaNum";
|
|
3505
|
-
default:
|
|
3506
|
-
return "digit";
|
|
3507
|
-
}
|
|
3508
|
-
}
|
|
3509
|
-
var JAMO = "\u3131\u3134\u3137\u3139\u3141\u3142\u3145\u3147\u3148\u314A\u314B\u314C\u314D\u314E";
|
|
3510
|
-
var CIRCLED_JAMO = "\u3260\u3261\u3262\u3263\u3264\u3265\u3266\u3267\u3268\u3269\u326A\u326B\u326C\u326D";
|
|
3511
|
-
function fromTable(n, table2) {
|
|
3512
|
-
return n >= 1 && n <= table2.length ? table2[n - 1] : String(n);
|
|
3513
|
-
}
|
|
3514
|
-
function formatLatin(n, upper) {
|
|
3515
|
-
if (n <= 0) return "";
|
|
3516
|
-
let result = "";
|
|
3517
|
-
let num4 = n;
|
|
3518
|
-
while (num4 > 0) {
|
|
3519
|
-
num4--;
|
|
3520
|
-
result = String.fromCharCode((upper ? 65 : 97) + num4 % 26) + result;
|
|
3521
|
-
num4 = Math.floor(num4 / 26);
|
|
3522
|
-
}
|
|
3523
|
-
return result;
|
|
3524
|
-
}
|
|
3525
|
-
function formatEastAsianNumber(n, digits, units, zero) {
|
|
3526
|
-
if (n === 0) return zero;
|
|
3527
|
-
if (n < 0 || n > 99999) return String(n);
|
|
3528
|
-
let result = "";
|
|
3529
|
-
let num4 = n;
|
|
3530
|
-
let unit = 0;
|
|
3531
|
-
while (num4 > 0) {
|
|
3532
|
-
const d = num4 % 10;
|
|
3533
|
-
if (d > 0) {
|
|
3534
|
-
const digitStr = d === 1 && unit > 0 ? "" : digits[d];
|
|
3535
|
-
result = digitStr + units[unit] + result;
|
|
3536
|
-
}
|
|
3537
|
-
num4 = Math.floor(num4 / 10);
|
|
3538
|
-
unit++;
|
|
3539
|
-
}
|
|
3540
|
-
return result;
|
|
3541
|
-
}
|
|
3542
|
-
var HANGUL_DIGITS = ["", "\uC77C", "\uC774", "\uC0BC", "\uC0AC", "\uC624", "\uC721", "\uCE60", "\uD314", "\uAD6C"];
|
|
3543
|
-
var HANGUL_UNITS = ["", "\uC2ED", "\uBC31", "\uCC9C", "\uB9CC"];
|
|
3544
|
-
var HANJA_DIGITS = ["", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D", "\u4E03", "\u516B", "\u4E5D"];
|
|
3545
|
-
var HANJA_UNITS = ["", "\u5341", "\u767E", "\u5343", "\u842C"];
|
|
3546
|
-
function formatNumber(n, fmt) {
|
|
3547
|
-
switch (fmt) {
|
|
3548
|
-
case "circled":
|
|
3549
|
-
return n >= 1 ? circledNumber(n - 1) : String(n);
|
|
3550
|
-
case "romanUpper":
|
|
3551
|
-
return romanNumeral(n, true);
|
|
3552
|
-
case "romanLower":
|
|
3553
|
-
return romanNumeral(n, false);
|
|
3554
|
-
case "latinUpper":
|
|
3555
|
-
return formatLatin(n, true) || String(n);
|
|
3556
|
-
case "latinLower":
|
|
3557
|
-
return formatLatin(n, false) || String(n);
|
|
3558
|
-
case "ganada":
|
|
3559
|
-
return n >= 1 ? hangulOrdinal(n - 1) : String(n);
|
|
3560
|
-
case "circledGanada":
|
|
3561
|
-
return n >= 1 ? circledHangul(n - 1) : String(n);
|
|
3562
|
-
case "jamo":
|
|
3563
|
-
return fromTable(n, JAMO);
|
|
3564
|
-
case "circledJamo":
|
|
3565
|
-
return fromTable(n, CIRCLED_JAMO);
|
|
3566
|
-
case "hangulNum":
|
|
3567
|
-
return formatEastAsianNumber(n, HANGUL_DIGITS, HANGUL_UNITS, "\uC601");
|
|
3568
|
-
case "hanjaNum":
|
|
3569
|
-
return formatEastAsianNumber(n, HANJA_DIGITS, HANJA_UNITS, "\u96F6");
|
|
3570
|
-
default:
|
|
3571
|
-
return String(n);
|
|
3572
|
-
}
|
|
3573
|
-
}
|
|
3574
|
-
function expandNumberingFormat(formatStr, counters, numbering) {
|
|
3575
|
-
let result = "";
|
|
3576
|
-
let i = 0;
|
|
3577
|
-
while (i < formatStr.length) {
|
|
3578
|
-
const ch = formatStr[i];
|
|
3579
|
-
if (ch === "^" && i + 1 < formatStr.length && formatStr[i + 1] >= "1" && formatStr[i + 1] <= "7") {
|
|
3580
|
-
const levelRef = formatStr.charCodeAt(i + 1) - 48;
|
|
3581
|
-
const idx = levelRef - 1;
|
|
3582
|
-
const counterVal = counters[idx] ?? 0;
|
|
3583
|
-
const start = numbering.startNumbers[idx] ?? 1;
|
|
3584
|
-
const num4 = counterVal > 0 ? start - 1 + counterVal : start;
|
|
3585
|
-
result += formatNumber(num4, headFormatToNumFmt(numbering.numberFormats[idx] ?? 0));
|
|
3586
|
-
i += 2;
|
|
3587
|
-
continue;
|
|
3588
|
-
}
|
|
3589
|
-
result += ch;
|
|
3590
|
-
i++;
|
|
3591
|
-
}
|
|
3592
|
-
return result;
|
|
3593
|
-
}
|
|
3594
|
-
|
|
3595
3455
|
// src/hwp5/aes.ts
|
|
3596
3456
|
var S_BOX = new Uint8Array([
|
|
3597
3457
|
99,
|
|
@@ -4295,78 +4155,6 @@ function decryptViewText(viewTextRaw, compressed) {
|
|
|
4295
4155
|
return Buffer.from(decrypted);
|
|
4296
4156
|
}
|
|
4297
4157
|
|
|
4298
|
-
// src/hwp5/equation.ts
|
|
4299
|
-
var WORD_ALIASES = {
|
|
4300
|
-
// 삼각/로그 함수 — 정본 맵 부재
|
|
4301
|
-
sin: "\\sin",
|
|
4302
|
-
cos: "\\cos",
|
|
4303
|
-
tan: "\\tan",
|
|
4304
|
-
sec: "\\sec",
|
|
4305
|
-
csc: "\\csc",
|
|
4306
|
-
cot: "\\cot",
|
|
4307
|
-
log: "\\log",
|
|
4308
|
-
ln: "\\ln",
|
|
4309
|
-
// 연산자·관계 기호 (정본은 대문자 키만 보유)
|
|
4310
|
-
divide: "\\div",
|
|
4311
|
-
div: "\\div",
|
|
4312
|
-
le: "\\leq",
|
|
4313
|
-
ge: "\\geq",
|
|
4314
|
-
geq: "\\geq",
|
|
4315
|
-
deg: "^\\circ",
|
|
4316
|
-
rarrow: "\\rightarrow",
|
|
4317
|
-
lrarrow: "\\leftrightarrow",
|
|
4318
|
-
rightarrow: "\\rightarrow",
|
|
4319
|
-
leftarrow: "\\leftarrow",
|
|
4320
|
-
in: "\\in",
|
|
4321
|
-
notin: "\\notin",
|
|
4322
|
-
emptyset: "\\emptyset",
|
|
4323
|
-
subset: "\\subset",
|
|
4324
|
-
nsubset: "\\nsubseteq",
|
|
4325
|
-
cup: "\\cup",
|
|
4326
|
-
cap: "\\cap",
|
|
4327
|
-
smallinter: "\\cap",
|
|
4328
|
-
smallsum: "\\sum",
|
|
4329
|
-
sim: "\\sim",
|
|
4330
|
-
circ: "\\circ",
|
|
4331
|
-
bot: "\\perp",
|
|
4332
|
-
partial: "\\partial",
|
|
4333
|
-
nabla: "\\nabla",
|
|
4334
|
-
angle: "\\angle",
|
|
4335
|
-
triangle: "\\triangle",
|
|
4336
|
-
inf: "\\infty",
|
|
4337
|
-
left: "\\left",
|
|
4338
|
-
right: "\\right",
|
|
4339
|
-
// 글꼴 지시자 — 제거
|
|
4340
|
-
rm: "",
|
|
4341
|
-
it: ""
|
|
4342
|
-
};
|
|
4343
|
-
var STRUCTURAL_FOLD = /* @__PURE__ */ new Set(["over", "root", "of"]);
|
|
4344
|
-
function normalizeWords(input) {
|
|
4345
|
-
return input.replace(/(?<![\\A-Za-z0-9])([A-Za-z][A-Za-z0-9]*)(?![A-Za-z0-9])/g, (word) => {
|
|
4346
|
-
if (Object.hasOwn(CONVERT_MAP, word) || Object.hasOwn(MIDDLE_CONVERT_MAP, word)) return word;
|
|
4347
|
-
const lower = word.toLowerCase();
|
|
4348
|
-
if (STRUCTURAL_FOLD.has(lower)) return lower;
|
|
4349
|
-
if (Object.hasOwn(WORD_ALIASES, lower)) return WORD_ALIASES[lower];
|
|
4350
|
-
if (lower !== word && (Object.hasOwn(CONVERT_MAP, lower) || Object.hasOwn(MIDDLE_CONVERT_MAP, lower))) return lower;
|
|
4351
|
-
return word;
|
|
4352
|
-
});
|
|
4353
|
-
}
|
|
4354
|
-
function normalizeScripts(input) {
|
|
4355
|
-
return input.replace(/\s*\^\s*/g, "^").replace(/\s*_\s*/g, "_").replace(/\^(?!\{)([^\s{}_^]+)/g, "^{$1}").replace(/_(?!\{)([^\s{}_^]+)/g, "_{$1}").replace(/([_^])/g, " $1 ");
|
|
4356
|
-
}
|
|
4357
|
-
function normalizeOperators(input) {
|
|
4358
|
-
return input.replace(/\+-/g, " \\pm ").replace(/-\+/g, " \\mp ").replace(/\/\//g, " \\parallel ").replace(/!=/g, " \\neq ").replace(/<=/g, " \\leq ").replace(/>=/g, " \\geq ").replace(/==/g, " \\equiv ").replace(/△/g, " \\triangle ").replace(/□/g, " \\square ").replace(/‧/g, " \\cdot ");
|
|
4359
|
-
}
|
|
4360
|
-
function hwpEquationToLatex(equation) {
|
|
4361
|
-
let s = equation.replace(/\0/g, "").replace(/\s+/g, " ").trim();
|
|
4362
|
-
if (!s) return "";
|
|
4363
|
-
s = normalizeScripts(s);
|
|
4364
|
-
s = normalizeOperators(s);
|
|
4365
|
-
s = normalizeWords(s);
|
|
4366
|
-
s = s.replace(/\broot\s+(?!\{)(\S+)\s+of(?![A-Za-z0-9])/gi, "root { $1 } of");
|
|
4367
|
-
return hmlToLatex(s).replace(/\s+/g, " ").trim();
|
|
4368
|
-
}
|
|
4369
|
-
|
|
4370
4158
|
// src/hwp5/pw-crypto.ts
|
|
4371
4159
|
import { createCipheriv, createHash as createHash2 } from "crypto";
|
|
4372
4160
|
var ENCRYPT_VERSION_OFFSET = 44;
|
|
@@ -4573,12 +4361,240 @@ function indexHwp5Tables(records, base = 0) {
|
|
|
4573
4361
|
return { ids, count: n };
|
|
4574
4362
|
}
|
|
4575
4363
|
|
|
4576
|
-
// src/hwp5/
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4364
|
+
// src/hwp5/numbering.ts
|
|
4365
|
+
var NumberingState = class {
|
|
4366
|
+
currentId = 0;
|
|
4367
|
+
counters = [0, 0, 0, 0, 0, 0, 0];
|
|
4368
|
+
history = /* @__PURE__ */ new Map();
|
|
4369
|
+
/** 번호 문단 처리: 카운터 갱신 후 수준별 카운터 스냅샷 반환 */
|
|
4370
|
+
advance(numberingId, level) {
|
|
4371
|
+
const lv = Math.min(Math.max(level, 0), 6);
|
|
4372
|
+
if (this.currentId !== numberingId) {
|
|
4373
|
+
if (this.currentId !== 0) this.history.set(this.currentId, [...this.counters]);
|
|
4374
|
+
const saved = this.history.get(numberingId);
|
|
4375
|
+
if (saved) {
|
|
4376
|
+
this.counters = [...saved];
|
|
4377
|
+
} else {
|
|
4378
|
+
const prev = this.counters;
|
|
4379
|
+
this.counters = [0, 0, 0, 0, 0, 0, 0];
|
|
4380
|
+
for (let i = 0; i < lv; i++) this.counters[i] = prev[i];
|
|
4381
|
+
}
|
|
4382
|
+
this.currentId = numberingId;
|
|
4383
|
+
}
|
|
4384
|
+
this.counters[lv]++;
|
|
4385
|
+
for (let i = lv + 1; i < 7; i++) this.counters[i] = 0;
|
|
4386
|
+
return [...this.counters];
|
|
4387
|
+
}
|
|
4388
|
+
};
|
|
4389
|
+
function headFormatToNumFmt(code) {
|
|
4390
|
+
switch (code) {
|
|
4391
|
+
case 1:
|
|
4392
|
+
return "circled";
|
|
4393
|
+
case 2:
|
|
4394
|
+
return "romanUpper";
|
|
4395
|
+
case 3:
|
|
4396
|
+
return "romanLower";
|
|
4397
|
+
case 4:
|
|
4398
|
+
return "latinUpper";
|
|
4399
|
+
case 5:
|
|
4400
|
+
return "latinLower";
|
|
4401
|
+
case 8:
|
|
4402
|
+
return "ganada";
|
|
4403
|
+
case 9:
|
|
4404
|
+
return "circledGanada";
|
|
4405
|
+
case 10:
|
|
4406
|
+
return "jamo";
|
|
4407
|
+
case 11:
|
|
4408
|
+
return "circledJamo";
|
|
4409
|
+
case 12:
|
|
4410
|
+
return "hangulNum";
|
|
4411
|
+
case 13:
|
|
4412
|
+
return "hanjaNum";
|
|
4413
|
+
default:
|
|
4414
|
+
return "digit";
|
|
4415
|
+
}
|
|
4416
|
+
}
|
|
4417
|
+
function shapeFormatToNumFmt(code) {
|
|
4418
|
+
switch (code) {
|
|
4419
|
+
case 1:
|
|
4420
|
+
return "circled";
|
|
4421
|
+
case 2:
|
|
4422
|
+
return "romanUpper";
|
|
4423
|
+
case 3:
|
|
4424
|
+
return "romanLower";
|
|
4425
|
+
case 4:
|
|
4426
|
+
return "latinUpper";
|
|
4427
|
+
case 5:
|
|
4428
|
+
return "latinLower";
|
|
4429
|
+
case 6:
|
|
4430
|
+
return "ganada";
|
|
4431
|
+
case 7:
|
|
4432
|
+
return "hangulNum";
|
|
4433
|
+
case 8:
|
|
4434
|
+
return "hanjaNum";
|
|
4435
|
+
default:
|
|
4436
|
+
return "digit";
|
|
4437
|
+
}
|
|
4438
|
+
}
|
|
4439
|
+
var JAMO = "\u3131\u3134\u3137\u3139\u3141\u3142\u3145\u3147\u3148\u314A\u314B\u314C\u314D\u314E";
|
|
4440
|
+
var CIRCLED_JAMO = "\u3260\u3261\u3262\u3263\u3264\u3265\u3266\u3267\u3268\u3269\u326A\u326B\u326C\u326D";
|
|
4441
|
+
function fromTable(n, table2) {
|
|
4442
|
+
return n >= 1 && n <= table2.length ? table2[n - 1] : String(n);
|
|
4443
|
+
}
|
|
4444
|
+
function formatLatin(n, upper) {
|
|
4445
|
+
if (n <= 0) return "";
|
|
4446
|
+
let result = "";
|
|
4447
|
+
let num4 = n;
|
|
4448
|
+
while (num4 > 0) {
|
|
4449
|
+
num4--;
|
|
4450
|
+
result = String.fromCharCode((upper ? 65 : 97) + num4 % 26) + result;
|
|
4451
|
+
num4 = Math.floor(num4 / 26);
|
|
4452
|
+
}
|
|
4453
|
+
return result;
|
|
4454
|
+
}
|
|
4455
|
+
function formatEastAsianNumber(n, digits, units, zero) {
|
|
4456
|
+
if (n === 0) return zero;
|
|
4457
|
+
if (n < 0 || n > 99999) return String(n);
|
|
4458
|
+
let result = "";
|
|
4459
|
+
let num4 = n;
|
|
4460
|
+
let unit = 0;
|
|
4461
|
+
while (num4 > 0) {
|
|
4462
|
+
const d = num4 % 10;
|
|
4463
|
+
if (d > 0) {
|
|
4464
|
+
const digitStr = d === 1 && unit > 0 ? "" : digits[d];
|
|
4465
|
+
result = digitStr + units[unit] + result;
|
|
4466
|
+
}
|
|
4467
|
+
num4 = Math.floor(num4 / 10);
|
|
4468
|
+
unit++;
|
|
4469
|
+
}
|
|
4470
|
+
return result;
|
|
4471
|
+
}
|
|
4472
|
+
var HANGUL_DIGITS = ["", "\uC77C", "\uC774", "\uC0BC", "\uC0AC", "\uC624", "\uC721", "\uCE60", "\uD314", "\uAD6C"];
|
|
4473
|
+
var HANGUL_UNITS = ["", "\uC2ED", "\uBC31", "\uCC9C", "\uB9CC"];
|
|
4474
|
+
var HANJA_DIGITS = ["", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D", "\u4E03", "\u516B", "\u4E5D"];
|
|
4475
|
+
var HANJA_UNITS = ["", "\u5341", "\u767E", "\u5343", "\u842C"];
|
|
4476
|
+
function formatNumber(n, fmt) {
|
|
4477
|
+
switch (fmt) {
|
|
4478
|
+
case "circled":
|
|
4479
|
+
return n >= 1 ? circledNumber(n - 1) : String(n);
|
|
4480
|
+
case "romanUpper":
|
|
4481
|
+
return romanNumeral(n, true);
|
|
4482
|
+
case "romanLower":
|
|
4483
|
+
return romanNumeral(n, false);
|
|
4484
|
+
case "latinUpper":
|
|
4485
|
+
return formatLatin(n, true) || String(n);
|
|
4486
|
+
case "latinLower":
|
|
4487
|
+
return formatLatin(n, false) || String(n);
|
|
4488
|
+
case "ganada":
|
|
4489
|
+
return n >= 1 ? hangulOrdinal(n - 1) : String(n);
|
|
4490
|
+
case "circledGanada":
|
|
4491
|
+
return n >= 1 ? circledHangul(n - 1) : String(n);
|
|
4492
|
+
case "jamo":
|
|
4493
|
+
return fromTable(n, JAMO);
|
|
4494
|
+
case "circledJamo":
|
|
4495
|
+
return fromTable(n, CIRCLED_JAMO);
|
|
4496
|
+
case "hangulNum":
|
|
4497
|
+
return formatEastAsianNumber(n, HANGUL_DIGITS, HANGUL_UNITS, "\uC601");
|
|
4498
|
+
case "hanjaNum":
|
|
4499
|
+
return formatEastAsianNumber(n, HANJA_DIGITS, HANJA_UNITS, "\u96F6");
|
|
4500
|
+
default:
|
|
4501
|
+
return String(n);
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
function expandNumberingFormat(formatStr, counters, numbering) {
|
|
4505
|
+
let result = "";
|
|
4506
|
+
let i = 0;
|
|
4507
|
+
while (i < formatStr.length) {
|
|
4508
|
+
const ch = formatStr[i];
|
|
4509
|
+
if (ch === "^" && i + 1 < formatStr.length && formatStr[i + 1] >= "1" && formatStr[i + 1] <= "7") {
|
|
4510
|
+
const levelRef = formatStr.charCodeAt(i + 1) - 48;
|
|
4511
|
+
const idx = levelRef - 1;
|
|
4512
|
+
const counterVal = counters[idx] ?? 0;
|
|
4513
|
+
const start = numbering.startNumbers[idx] ?? 1;
|
|
4514
|
+
const num4 = counterVal > 0 ? start - 1 + counterVal : start;
|
|
4515
|
+
result += formatNumber(num4, headFormatToNumFmt(numbering.numberFormats[idx] ?? 0));
|
|
4516
|
+
i += 2;
|
|
4517
|
+
continue;
|
|
4518
|
+
}
|
|
4519
|
+
result += ch;
|
|
4520
|
+
i++;
|
|
4521
|
+
}
|
|
4522
|
+
return result;
|
|
4523
|
+
}
|
|
4524
|
+
|
|
4525
|
+
// src/hwp5/equation.ts
|
|
4526
|
+
var WORD_ALIASES = {
|
|
4527
|
+
// 삼각/로그 함수 — 정본 맵 부재
|
|
4528
|
+
sin: "\\sin",
|
|
4529
|
+
cos: "\\cos",
|
|
4530
|
+
tan: "\\tan",
|
|
4531
|
+
sec: "\\sec",
|
|
4532
|
+
csc: "\\csc",
|
|
4533
|
+
cot: "\\cot",
|
|
4534
|
+
log: "\\log",
|
|
4535
|
+
ln: "\\ln",
|
|
4536
|
+
// 연산자·관계 기호 (정본은 대문자 키만 보유)
|
|
4537
|
+
divide: "\\div",
|
|
4538
|
+
div: "\\div",
|
|
4539
|
+
le: "\\leq",
|
|
4540
|
+
ge: "\\geq",
|
|
4541
|
+
geq: "\\geq",
|
|
4542
|
+
deg: "^\\circ",
|
|
4543
|
+
rarrow: "\\rightarrow",
|
|
4544
|
+
lrarrow: "\\leftrightarrow",
|
|
4545
|
+
rightarrow: "\\rightarrow",
|
|
4546
|
+
leftarrow: "\\leftarrow",
|
|
4547
|
+
in: "\\in",
|
|
4548
|
+
notin: "\\notin",
|
|
4549
|
+
emptyset: "\\emptyset",
|
|
4550
|
+
subset: "\\subset",
|
|
4551
|
+
nsubset: "\\nsubseteq",
|
|
4552
|
+
cup: "\\cup",
|
|
4553
|
+
cap: "\\cap",
|
|
4554
|
+
smallinter: "\\cap",
|
|
4555
|
+
smallsum: "\\sum",
|
|
4556
|
+
sim: "\\sim",
|
|
4557
|
+
circ: "\\circ",
|
|
4558
|
+
bot: "\\perp",
|
|
4559
|
+
partial: "\\partial",
|
|
4560
|
+
nabla: "\\nabla",
|
|
4561
|
+
angle: "\\angle",
|
|
4562
|
+
triangle: "\\triangle",
|
|
4563
|
+
inf: "\\infty",
|
|
4564
|
+
left: "\\left",
|
|
4565
|
+
right: "\\right",
|
|
4566
|
+
// 글꼴 지시자 — 제거
|
|
4567
|
+
rm: "",
|
|
4568
|
+
it: ""
|
|
4569
|
+
};
|
|
4570
|
+
var STRUCTURAL_FOLD = /* @__PURE__ */ new Set(["over", "root", "of"]);
|
|
4571
|
+
function normalizeWords(input) {
|
|
4572
|
+
return input.replace(/(?<![\\A-Za-z0-9])([A-Za-z][A-Za-z0-9]*)(?![A-Za-z0-9])/g, (word) => {
|
|
4573
|
+
if (Object.hasOwn(CONVERT_MAP, word) || Object.hasOwn(MIDDLE_CONVERT_MAP, word)) return word;
|
|
4574
|
+
const lower = word.toLowerCase();
|
|
4575
|
+
if (STRUCTURAL_FOLD.has(lower)) return lower;
|
|
4576
|
+
if (Object.hasOwn(WORD_ALIASES, lower)) return WORD_ALIASES[lower];
|
|
4577
|
+
if (lower !== word && (Object.hasOwn(CONVERT_MAP, lower) || Object.hasOwn(MIDDLE_CONVERT_MAP, lower))) return lower;
|
|
4578
|
+
return word;
|
|
4579
|
+
});
|
|
4580
|
+
}
|
|
4581
|
+
function normalizeScripts(input) {
|
|
4582
|
+
return input.replace(/\s*\^\s*/g, "^").replace(/\s*_\s*/g, "_").replace(/\^(?!\{)([^\s{}_^]+)/g, "^{$1}").replace(/_(?!\{)([^\s{}_^]+)/g, "_{$1}").replace(/([_^])/g, " $1 ");
|
|
4583
|
+
}
|
|
4584
|
+
function normalizeOperators(input) {
|
|
4585
|
+
return input.replace(/\+-/g, " \\pm ").replace(/-\+/g, " \\mp ").replace(/\/\//g, " \\parallel ").replace(/!=/g, " \\neq ").replace(/<=/g, " \\leq ").replace(/>=/g, " \\geq ").replace(/==/g, " \\equiv ").replace(/△/g, " \\triangle ").replace(/□/g, " \\square ").replace(/‧/g, " \\cdot ");
|
|
4586
|
+
}
|
|
4587
|
+
function hwpEquationToLatex(equation) {
|
|
4588
|
+
let s = equation.replace(/\0/g, "").replace(/\s+/g, " ").trim();
|
|
4589
|
+
if (!s) return "";
|
|
4590
|
+
s = normalizeScripts(s);
|
|
4591
|
+
s = normalizeOperators(s);
|
|
4592
|
+
s = normalizeWords(s);
|
|
4593
|
+
s = s.replace(/\broot\s+(?!\{)(\S+)\s+of(?![A-Za-z0-9])/gi, "root { $1 } of");
|
|
4594
|
+
return hmlToLatex(s).replace(/\s+/g, " ").trim();
|
|
4595
|
+
}
|
|
4596
|
+
|
|
4597
|
+
// src/hwp5/body.ts
|
|
4582
4598
|
var MAX_NEST_DEPTH = 8;
|
|
4583
4599
|
function cid(s) {
|
|
4584
4600
|
return (s.charCodeAt(0) << 24 | s.charCodeAt(1) << 16 | s.charCodeAt(2) << 8 | s.charCodeAt(3)) >>> 0;
|
|
@@ -4639,366 +4655,6 @@ function normalizeCtrlId(raw) {
|
|
|
4639
4655
|
if (KNOWN_CTRL_IDS.has(sw) || isFieldCtrlId(sw)) return sw;
|
|
4640
4656
|
return raw;
|
|
4641
4657
|
}
|
|
4642
|
-
function openHwp5Container(buffer, options) {
|
|
4643
|
-
let cfb = null;
|
|
4644
|
-
let lenientCfb = null;
|
|
4645
|
-
const warnings = [];
|
|
4646
|
-
try {
|
|
4647
|
-
cfb = CFB.parse(buffer);
|
|
4648
|
-
} catch {
|
|
4649
|
-
try {
|
|
4650
|
-
lenientCfb = parseLenientCfb(buffer);
|
|
4651
|
-
warnings.push({ message: "\uC190\uC0C1\uB41C CFB \uCEE8\uD14C\uC774\uB108 \u2014 lenient \uBAA8\uB4DC\uB85C \uBCF5\uAD6C", code: "LENIENT_CFB_RECOVERY" });
|
|
4652
|
-
} catch {
|
|
4653
|
-
throw new KordocError("CFB \uCEE8\uD14C\uC774\uB108 \uD30C\uC2F1 \uC2E4\uD328 (strict \uBC0F lenient \uBAA8\uB450)");
|
|
4654
|
-
}
|
|
4655
|
-
}
|
|
4656
|
-
const readRawStream = (path) => {
|
|
4657
|
-
if (cfb) {
|
|
4658
|
-
const entry = CFB.find(cfb, path);
|
|
4659
|
-
return entry?.content ? Buffer.from(entry.content) : null;
|
|
4660
|
-
}
|
|
4661
|
-
return lenientCfb.findStream(path);
|
|
4662
|
-
};
|
|
4663
|
-
const headerData = readRawStream("/FileHeader");
|
|
4664
|
-
if (!headerData) throw new KordocError("FileHeader \uC2A4\uD2B8\uB9BC \uC5C6\uC74C");
|
|
4665
|
-
const header = parseFileHeader(headerData);
|
|
4666
|
-
if (header.signature !== "HWP Document File") throw new KordocError("HWP \uC2DC\uADF8\uB2C8\uCC98 \uBD88\uC77C\uCE58");
|
|
4667
|
-
if (header.flags & FLAG_DRM) throw new KordocError("DRM \uBCF4\uD638\uB41C HWP\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
4668
|
-
const encrypted = (header.flags & FLAG_ENCRYPTED) !== 0;
|
|
4669
|
-
if (encrypted) {
|
|
4670
|
-
if (!options?.password) {
|
|
4671
|
-
throw new KordocError("\uC554\uD638\uB85C \uBCF4\uD638\uB41C HWP \uBB38\uC11C\uC785\uB2C8\uB2E4. password \uC635\uC158\uC5D0 \uC5F4\uAE30 \uC554\uD638\uB97C \uC9C0\uC815\uD558\uC138\uC694.");
|
|
4672
|
-
}
|
|
4673
|
-
assertSupportedEncryptVersion(readEncryptVersion(headerData));
|
|
4674
|
-
}
|
|
4675
|
-
const password = encrypted ? options.password : void 0;
|
|
4676
|
-
const findStream = (path) => {
|
|
4677
|
-
const raw = readRawStream(path);
|
|
4678
|
-
if (!raw || !password) return raw;
|
|
4679
|
-
return decryptPasswordStream(raw, password);
|
|
4680
|
-
};
|
|
4681
|
-
const compressed = (header.flags & FLAG_COMPRESSED) !== 0;
|
|
4682
|
-
const distribution = (header.flags & FLAG_DISTRIBUTION) !== 0;
|
|
4683
|
-
if (encrypted) {
|
|
4684
|
-
const rawDocInfo = findStream("/DocInfo");
|
|
4685
|
-
if (!rawDocInfo) throw new KordocError("DocInfo \uC2A4\uD2B8\uB9BC \uC5C6\uC74C");
|
|
4686
|
-
let docInfoData;
|
|
4687
|
-
try {
|
|
4688
|
-
docInfoData = compressed ? decompressStream(rawDocInfo) : rawDocInfo;
|
|
4689
|
-
} catch {
|
|
4690
|
-
throw new KordocError("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uAC70\uB098 \uC554\uD638\uD654 \uB370\uC774\uD130\uAC00 \uC190\uC0C1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
4691
|
-
}
|
|
4692
|
-
assertDecryptedDocInfo(docInfoData, readRecords);
|
|
4693
|
-
}
|
|
4694
|
-
return { cfb, lenientCfb, header, compressed, distribution, encrypted, findStream, warnings };
|
|
4695
|
-
}
|
|
4696
|
-
function readHwp5DocInfoRecords(c) {
|
|
4697
|
-
try {
|
|
4698
|
-
const raw = c.findStream("/DocInfo");
|
|
4699
|
-
if (!raw) return null;
|
|
4700
|
-
return readRecords(c.compressed ? decompressStream(raw) : raw);
|
|
4701
|
-
} catch {
|
|
4702
|
-
return null;
|
|
4703
|
-
}
|
|
4704
|
-
}
|
|
4705
|
-
function readHwp5SectionStreams(c) {
|
|
4706
|
-
return c.distribution ? c.cfb ? findViewTextSections(c.cfb, c.compressed) : findViewTextSectionsLenient(c.lenientCfb, c.compressed) : c.encrypted ? findSectionsVia(c.findStream) : c.cfb ? findSections(c.cfb) : findSectionsLenient(c.lenientCfb, c.compressed);
|
|
4707
|
-
}
|
|
4708
|
-
function readHwp5SectionRecords(c, sections, warnings) {
|
|
4709
|
-
const out = [];
|
|
4710
|
-
let totalDecompressed = 0;
|
|
4711
|
-
for (let si = 0; si < sections.length; si++) {
|
|
4712
|
-
try {
|
|
4713
|
-
const data = !c.distribution && c.compressed ? decompressStream(Buffer.from(sections[si])) : Buffer.from(sections[si]);
|
|
4714
|
-
totalDecompressed += data.length;
|
|
4715
|
-
if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
|
|
4716
|
-
out.push(readRecords(data));
|
|
4717
|
-
} catch (secErr) {
|
|
4718
|
-
if (secErr instanceof KordocError) throw secErr;
|
|
4719
|
-
out.push(null);
|
|
4720
|
-
warnings.push({ page: si + 1, message: `\uC139\uC158 ${si + 1} \uD30C\uC2F1 \uC2E4\uD328: ${secErr instanceof Error ? secErr.message : "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}`, code: "PARTIAL_PARSE" });
|
|
4721
|
-
}
|
|
4722
|
-
}
|
|
4723
|
-
return out;
|
|
4724
|
-
}
|
|
4725
|
-
function readHwp5BinData(c) {
|
|
4726
|
-
return c.cfb ? collectHwp5BinData(c.cfb.FileIndex) : collectHwp5BinDataLenient(c.lenientCfb);
|
|
4727
|
-
}
|
|
4728
|
-
function parseHwp5Document(buffer, options) {
|
|
4729
|
-
const c = openHwp5Container(buffer, options);
|
|
4730
|
-
const { cfb, lenientCfb, compressed, encrypted, findStream, warnings } = c;
|
|
4731
|
-
const metadata = {
|
|
4732
|
-
version: `${c.header.versionMajor}.x`
|
|
4733
|
-
};
|
|
4734
|
-
if (cfb) extractHwp5Metadata(cfb, metadata);
|
|
4735
|
-
const docInfo = cfb && !encrypted ? parseDocInfoStream(cfb, compressed) : parseDocInfoFromStream(findStream("/DocInfo"), compressed);
|
|
4736
|
-
const sections = readHwp5SectionStreams(c);
|
|
4737
|
-
if (sections.length === 0) throw new KordocError("\uC139\uC158 \uC2A4\uD2B8\uB9BC\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
4738
|
-
const sectionRecords = readHwp5SectionRecords(c, sections, warnings);
|
|
4739
|
-
const sectionDetects = sectionRecords.map((r) => r ? detectHwp5SectionPages(r) : null);
|
|
4740
|
-
const sectionTableIds = [];
|
|
4741
|
-
{
|
|
4742
|
-
let base = 0;
|
|
4743
|
-
for (const r of sectionRecords) {
|
|
4744
|
-
const ix = indexHwp5Tables(r ?? [], base);
|
|
4745
|
-
sectionTableIds.push(ix.ids);
|
|
4746
|
-
base += ix.count;
|
|
4747
|
-
}
|
|
4748
|
-
}
|
|
4749
|
-
const layoutPages = sectionDetects.length > 0 && sectionDetects.every((d) => d != null && d.usable);
|
|
4750
|
-
metadata.pageMode = layoutPages ? "layout" : "section";
|
|
4751
|
-
metadata.pageCount = layoutPages ? Math.max(sectionDetects.reduce((sum, d) => sum + (d?.pages ?? 0), 0), 1) : sections.length;
|
|
4752
|
-
const pageFilter = options?.pages ? parsePageRange(options.pages, metadata.pageCount) : null;
|
|
4753
|
-
if (pageFilter && !layoutPages) {
|
|
4754
|
-
warnings.push({ code: "PAGE_BOUNDARY_APPROXIMATE", message: "\uC870\uD310 \uCE90\uC2DC\uAC00 \uC5C6\uC5B4 pages \uD544\uD130\uB97C \uC139\uC158 \uB2E8\uC704 \uADFC\uC0AC\uB85C \uC801\uC6A9\uD588\uC2B5\uB2C8\uB2E4" });
|
|
4755
|
-
}
|
|
4756
|
-
let bodyBlocks = [];
|
|
4757
|
-
const doc = createHwp5DocState();
|
|
4758
|
-
doc.keepTrailingEmptyCols = options?.keepTrailingEmptyCols;
|
|
4759
|
-
let parsedSections = 0;
|
|
4760
|
-
let pageBase = 0;
|
|
4761
|
-
for (let si = 0; si < sections.length; si++) {
|
|
4762
|
-
const records = sectionRecords[si];
|
|
4763
|
-
if (!records) continue;
|
|
4764
|
-
const detect = sectionDetects[si];
|
|
4765
|
-
if (!layoutPages && pageFilter && !pageFilter.has(si + 1)) continue;
|
|
4766
|
-
try {
|
|
4767
|
-
const sectionBlocks = parseSection(
|
|
4768
|
-
records,
|
|
4769
|
-
docInfo,
|
|
4770
|
-
warnings,
|
|
4771
|
-
si + 1,
|
|
4772
|
-
doc,
|
|
4773
|
-
layoutPages ? { base: pageBase, pageAtPara: detect.pageAtPara } : void 0,
|
|
4774
|
-
sectionTableIds[si]
|
|
4775
|
-
);
|
|
4776
|
-
bodyBlocks.push(...sectionBlocks);
|
|
4777
|
-
parsedSections++;
|
|
4778
|
-
options?.onProgress?.(parsedSections, sections.length);
|
|
4779
|
-
} catch (secErr) {
|
|
4780
|
-
if (secErr instanceof KordocError) throw secErr;
|
|
4781
|
-
warnings.push({ page: si + 1, message: `\uC139\uC158 ${si + 1} \uD30C\uC2F1 \uC2E4\uD328: ${secErr instanceof Error ? secErr.message : "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}`, code: "PARTIAL_PARSE" });
|
|
4782
|
-
} finally {
|
|
4783
|
-
pageBase += detect.pages;
|
|
4784
|
-
}
|
|
4785
|
-
}
|
|
4786
|
-
if (pageFilter && layoutPages) {
|
|
4787
|
-
bodyBlocks = bodyBlocks.filter((b) => b.pageNumber != null && pageFilter.has(b.pageNumber));
|
|
4788
|
-
}
|
|
4789
|
-
const blocks = [...doc.headerBlocks, ...bodyBlocks, ...doc.footerBlocks];
|
|
4790
|
-
const images = cfb ? extractHwp5Images(cfb.FileIndex, blocks, warnings, !pageFilter) : extractHwp5ImagesLenient(lenientCfb, blocks, warnings, !pageFilter);
|
|
4791
|
-
let flatBlocks = flattenLayoutTables(blocks);
|
|
4792
|
-
if (options?.dedupeRunningHeaders) {
|
|
4793
|
-
const deduped = dedupeRunningHeaders(flatBlocks);
|
|
4794
|
-
const removed = flatBlocks.length - deduped.length;
|
|
4795
|
-
if (removed > 0) warnings.push({ message: `\uBC18\uBCF5 \uB7EC\uB2DD \uD5E4\uB354 ${removed}\uAC1C \uC81C\uAC70`, code: "HIDDEN_TEXT_FILTERED" });
|
|
4796
|
-
flatBlocks = deduped;
|
|
4797
|
-
}
|
|
4798
|
-
if (docInfo) {
|
|
4799
|
-
detectHwp5Headings(flatBlocks, docInfo);
|
|
4800
|
-
}
|
|
4801
|
-
const outline = flatBlocks.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
|
|
4802
|
-
let markdown = blocksToMarkdown(flatBlocks);
|
|
4803
|
-
if (options?.inlineImages && images.length > 0) {
|
|
4804
|
-
try {
|
|
4805
|
-
markdown = inlineImagesIntoMarkdown(markdown, images, { compress: true });
|
|
4806
|
-
} catch (inlineErr) {
|
|
4807
|
-
warnings.push({ message: `\uC774\uBBF8\uC9C0 \uC778\uB77C\uC778 \uC2E4\uD328 \u2014 \uC6D0\uBCF8 \uD30C\uC77C \uCC38\uC870\uB85C \uD3F4\uBC31: ${inlineErr instanceof Error ? inlineErr.message : "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}`, code: "SKIPPED_IMAGE" });
|
|
4808
|
-
}
|
|
4809
|
-
}
|
|
4810
|
-
return { markdown, blocks: flatBlocks, metadata, outline: outline.length > 0 ? outline : void 0, warnings: warnings.length > 0 ? warnings : void 0, images: images.length > 0 ? images : void 0 };
|
|
4811
|
-
}
|
|
4812
|
-
function parseDocInfoStream(cfb, compressed) {
|
|
4813
|
-
try {
|
|
4814
|
-
const entry = CFB.find(cfb, "/DocInfo");
|
|
4815
|
-
if (!entry?.content) return null;
|
|
4816
|
-
const data = compressed ? decompressStream(Buffer.from(entry.content)) : Buffer.from(entry.content);
|
|
4817
|
-
const records = readRecords(data);
|
|
4818
|
-
return parseDocInfo(records);
|
|
4819
|
-
} catch {
|
|
4820
|
-
return null;
|
|
4821
|
-
}
|
|
4822
|
-
}
|
|
4823
|
-
function parseDocInfoFromStream(raw, compressed) {
|
|
4824
|
-
if (!raw) return null;
|
|
4825
|
-
try {
|
|
4826
|
-
const data = compressed ? decompressStream(raw) : raw;
|
|
4827
|
-
return parseDocInfo(readRecords(data));
|
|
4828
|
-
} catch {
|
|
4829
|
-
return null;
|
|
4830
|
-
}
|
|
4831
|
-
}
|
|
4832
|
-
function detectHwp5Headings(blocks, docInfo) {
|
|
4833
|
-
let baseFontSize = 0;
|
|
4834
|
-
const sizeFreq = /* @__PURE__ */ new Map();
|
|
4835
|
-
for (const b of blocks) {
|
|
4836
|
-
if (b.style?.fontSize && b.text) {
|
|
4837
|
-
sizeFreq.set(b.style.fontSize, (sizeFreq.get(b.style.fontSize) || 0) + b.text.length);
|
|
4838
|
-
}
|
|
4839
|
-
}
|
|
4840
|
-
let maxWeight = 0;
|
|
4841
|
-
for (const [size, weight] of sizeFreq) {
|
|
4842
|
-
if (weight > maxWeight) {
|
|
4843
|
-
maxWeight = weight;
|
|
4844
|
-
baseFontSize = size;
|
|
4845
|
-
}
|
|
4846
|
-
}
|
|
4847
|
-
if (baseFontSize === 0) {
|
|
4848
|
-
for (const style of docInfo.styles) {
|
|
4849
|
-
const name = (style.nameKo || style.name).toLowerCase();
|
|
4850
|
-
if (name.includes("\uBC14\uD0D5") || name.includes("\uBCF8\uBB38") || name === "normal" || name === "body") {
|
|
4851
|
-
const cs = docInfo.charShapes[style.charShapeId];
|
|
4852
|
-
if (cs?.fontSize > 0) {
|
|
4853
|
-
baseFontSize = cs.fontSize / 10;
|
|
4854
|
-
break;
|
|
4855
|
-
}
|
|
4856
|
-
}
|
|
4857
|
-
}
|
|
4858
|
-
}
|
|
4859
|
-
if (baseFontSize <= 0) return;
|
|
4860
|
-
for (const block of blocks) {
|
|
4861
|
-
if (block.type === "heading") continue;
|
|
4862
|
-
if (block.type !== "paragraph" || !block.text) continue;
|
|
4863
|
-
const text = block.text.trim();
|
|
4864
|
-
if (text.length === 0 || text.length > 200) continue;
|
|
4865
|
-
if (/^\d+$/.test(text)) continue;
|
|
4866
|
-
let level = 0;
|
|
4867
|
-
if (block.style?.fontSize && baseFontSize > 0) {
|
|
4868
|
-
const ratio = block.style.fontSize / baseFontSize;
|
|
4869
|
-
if (ratio >= HEADING_RATIO_H1) level = 1;
|
|
4870
|
-
else if (ratio >= HEADING_RATIO_H2) level = 2;
|
|
4871
|
-
else if (ratio >= HEADING_RATIO_H3) level = 3;
|
|
4872
|
-
}
|
|
4873
|
-
if (/^제\d+[장절편]\s/.test(text) && text.length <= 50) {
|
|
4874
|
-
if (level === 0) level = 2;
|
|
4875
|
-
} else if (/^제\d+(조의?\d*)\s*[\((]/.test(text) && text.length <= 80) {
|
|
4876
|
-
if (level === 0) level = 3;
|
|
4877
|
-
}
|
|
4878
|
-
if (level > 0) {
|
|
4879
|
-
block.type = "heading";
|
|
4880
|
-
block.level = level;
|
|
4881
|
-
}
|
|
4882
|
-
}
|
|
4883
|
-
}
|
|
4884
|
-
function extractHwp5Metadata(cfb, metadata) {
|
|
4885
|
-
try {
|
|
4886
|
-
const summaryEntry = CFB.find(cfb, "/HwpSummaryInformation") || CFB.find(cfb, "/SummaryInformation");
|
|
4887
|
-
if (!summaryEntry?.content) return;
|
|
4888
|
-
const data = Buffer.from(summaryEntry.content);
|
|
4889
|
-
if (data.length < 48) return;
|
|
4890
|
-
const numSets = data.readUInt32LE(24);
|
|
4891
|
-
if (numSets === 0) return;
|
|
4892
|
-
const setOffset = data.readUInt32LE(44);
|
|
4893
|
-
if (setOffset >= data.length - 8) return;
|
|
4894
|
-
const numProps = data.readUInt32LE(setOffset + 4);
|
|
4895
|
-
if (numProps === 0 || numProps > 100) return;
|
|
4896
|
-
for (let i = 0; i < numProps; i++) {
|
|
4897
|
-
const entryOffset = setOffset + 8 + i * 8;
|
|
4898
|
-
if (entryOffset + 8 > data.length) break;
|
|
4899
|
-
const propId = data.readUInt32LE(entryOffset);
|
|
4900
|
-
const propOffset = setOffset + data.readUInt32LE(entryOffset + 4);
|
|
4901
|
-
if (propOffset + 8 > data.length) continue;
|
|
4902
|
-
if (propId !== 2 && propId !== 4 && propId !== 6) continue;
|
|
4903
|
-
const propType = data.readUInt32LE(propOffset);
|
|
4904
|
-
if (propType !== 30) continue;
|
|
4905
|
-
const strLen = data.readUInt32LE(propOffset + 4);
|
|
4906
|
-
if (strLen === 0 || strLen > 1e4 || propOffset + 8 + strLen > data.length) continue;
|
|
4907
|
-
const str = data.subarray(propOffset + 8, propOffset + 8 + strLen).toString("utf8").replace(/\0+$/, "").trim();
|
|
4908
|
-
if (!str) continue;
|
|
4909
|
-
if (propId === 2) metadata.title = str;
|
|
4910
|
-
else if (propId === 4) metadata.author = str;
|
|
4911
|
-
else if (propId === 6) metadata.description = str;
|
|
4912
|
-
}
|
|
4913
|
-
} catch {
|
|
4914
|
-
}
|
|
4915
|
-
}
|
|
4916
|
-
function findViewTextSections(cfb, compressed) {
|
|
4917
|
-
const sections = [];
|
|
4918
|
-
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
4919
|
-
const entry = CFB.find(cfb, `/ViewText/Section${i}`);
|
|
4920
|
-
if (!entry?.content) break;
|
|
4921
|
-
try {
|
|
4922
|
-
const decrypted = decryptViewText(Buffer.from(entry.content), compressed);
|
|
4923
|
-
sections.push({ idx: i, content: decrypted });
|
|
4924
|
-
} catch {
|
|
4925
|
-
break;
|
|
4926
|
-
}
|
|
4927
|
-
}
|
|
4928
|
-
return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
|
|
4929
|
-
}
|
|
4930
|
-
function findSectionsVia(read) {
|
|
4931
|
-
const sections = [];
|
|
4932
|
-
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
4933
|
-
const raw = read(`/BodyText/Section${i}`);
|
|
4934
|
-
if (!raw) break;
|
|
4935
|
-
sections.push(raw);
|
|
4936
|
-
}
|
|
4937
|
-
return sections;
|
|
4938
|
-
}
|
|
4939
|
-
function findSections(cfb) {
|
|
4940
|
-
const sections = [];
|
|
4941
|
-
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
4942
|
-
const entry = CFB.find(cfb, `/BodyText/Section${i}`);
|
|
4943
|
-
if (!entry?.content) break;
|
|
4944
|
-
sections.push({ idx: i, content: Buffer.from(entry.content) });
|
|
4945
|
-
}
|
|
4946
|
-
if (sections.length === 0 && cfb.FileIndex) {
|
|
4947
|
-
for (const entry of cfb.FileIndex) {
|
|
4948
|
-
if (sections.length >= MAX_SECTIONS) break;
|
|
4949
|
-
if (entry.name?.startsWith("Section") && entry.content) {
|
|
4950
|
-
const idx = parseInt(entry.name.replace("Section", ""), 10) || 0;
|
|
4951
|
-
sections.push({ idx, content: Buffer.from(entry.content) });
|
|
4952
|
-
}
|
|
4953
|
-
}
|
|
4954
|
-
}
|
|
4955
|
-
return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
|
|
4956
|
-
}
|
|
4957
|
-
function findSectionsLenient(lcfb, compressed) {
|
|
4958
|
-
const sections = [];
|
|
4959
|
-
let totalDecompressed = 0;
|
|
4960
|
-
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
4961
|
-
const raw = lcfb.findStream(`/BodyText/Section${i}`) ?? lcfb.findStream(`Section${i}`);
|
|
4962
|
-
if (!raw) break;
|
|
4963
|
-
const content = compressed ? decompressStream(raw) : raw;
|
|
4964
|
-
totalDecompressed += content.length;
|
|
4965
|
-
if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
|
|
4966
|
-
sections.push({ idx: i, content });
|
|
4967
|
-
}
|
|
4968
|
-
if (sections.length === 0) {
|
|
4969
|
-
for (const e of lcfb.entries()) {
|
|
4970
|
-
if (sections.length >= MAX_SECTIONS) break;
|
|
4971
|
-
if (e.name.startsWith("Section")) {
|
|
4972
|
-
const idx = parseInt(e.name.replace("Section", ""), 10) || 0;
|
|
4973
|
-
const raw = lcfb.findStream(e.name);
|
|
4974
|
-
if (raw) {
|
|
4975
|
-
const content = compressed ? decompressStream(raw) : raw;
|
|
4976
|
-
totalDecompressed += content.length;
|
|
4977
|
-
if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
|
|
4978
|
-
sections.push({ idx, content });
|
|
4979
|
-
}
|
|
4980
|
-
}
|
|
4981
|
-
}
|
|
4982
|
-
}
|
|
4983
|
-
return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
|
|
4984
|
-
}
|
|
4985
|
-
function findViewTextSectionsLenient(lcfb, compressed) {
|
|
4986
|
-
const sections = [];
|
|
4987
|
-
let totalDecompressed = 0;
|
|
4988
|
-
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
4989
|
-
const raw = lcfb.findStream(`/ViewText/Section${i}`) ?? lcfb.findStream(`Section${i}`);
|
|
4990
|
-
if (!raw) break;
|
|
4991
|
-
try {
|
|
4992
|
-
const content = decryptViewText(raw, compressed);
|
|
4993
|
-
totalDecompressed += content.length;
|
|
4994
|
-
if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
|
|
4995
|
-
sections.push({ idx: i, content });
|
|
4996
|
-
} catch {
|
|
4997
|
-
break;
|
|
4998
|
-
}
|
|
4999
|
-
}
|
|
5000
|
-
return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
|
|
5001
|
-
}
|
|
5002
4658
|
function formatEquationForMarkdown(equation) {
|
|
5003
4659
|
const normalized = hwpEquationToLatex(equation);
|
|
5004
4660
|
if (!normalized) return "";
|
|
@@ -5566,6 +5222,373 @@ function hasRealUnderline(attrFlags) {
|
|
|
5566
5222
|
return (attrFlags >> 2 & 3) === 1;
|
|
5567
5223
|
}
|
|
5568
5224
|
|
|
5225
|
+
// src/hwp5/parser.ts
|
|
5226
|
+
import { createRequire } from "module";
|
|
5227
|
+
var require2 = createRequire(import.meta.url);
|
|
5228
|
+
var CFB = require2("cfb");
|
|
5229
|
+
var MAX_SECTIONS = 100;
|
|
5230
|
+
var MAX_TOTAL_DECOMPRESS = 100 * 1024 * 1024;
|
|
5231
|
+
function openHwp5Container(buffer, options) {
|
|
5232
|
+
let cfb = null;
|
|
5233
|
+
let lenientCfb = null;
|
|
5234
|
+
const warnings = [];
|
|
5235
|
+
try {
|
|
5236
|
+
cfb = CFB.parse(buffer);
|
|
5237
|
+
} catch {
|
|
5238
|
+
try {
|
|
5239
|
+
lenientCfb = parseLenientCfb(buffer);
|
|
5240
|
+
warnings.push({ message: "\uC190\uC0C1\uB41C CFB \uCEE8\uD14C\uC774\uB108 \u2014 lenient \uBAA8\uB4DC\uB85C \uBCF5\uAD6C", code: "LENIENT_CFB_RECOVERY" });
|
|
5241
|
+
} catch {
|
|
5242
|
+
throw new KordocError("CFB \uCEE8\uD14C\uC774\uB108 \uD30C\uC2F1 \uC2E4\uD328 (strict \uBC0F lenient \uBAA8\uB450)");
|
|
5243
|
+
}
|
|
5244
|
+
}
|
|
5245
|
+
const readRawStream = (path) => {
|
|
5246
|
+
if (cfb) {
|
|
5247
|
+
const entry = CFB.find(cfb, path);
|
|
5248
|
+
return entry?.content ? Buffer.from(entry.content) : null;
|
|
5249
|
+
}
|
|
5250
|
+
return lenientCfb.findStream(path);
|
|
5251
|
+
};
|
|
5252
|
+
const headerData = readRawStream("/FileHeader");
|
|
5253
|
+
if (!headerData) throw new KordocError("FileHeader \uC2A4\uD2B8\uB9BC \uC5C6\uC74C");
|
|
5254
|
+
const header = parseFileHeader(headerData);
|
|
5255
|
+
if (header.signature !== "HWP Document File") throw new KordocError("HWP \uC2DC\uADF8\uB2C8\uCC98 \uBD88\uC77C\uCE58");
|
|
5256
|
+
if (header.flags & FLAG_DRM) throw new KordocError("DRM \uBCF4\uD638\uB41C HWP\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
5257
|
+
const encrypted = (header.flags & FLAG_ENCRYPTED) !== 0;
|
|
5258
|
+
if (encrypted) {
|
|
5259
|
+
if (!options?.password) {
|
|
5260
|
+
throw new KordocError("\uC554\uD638\uB85C \uBCF4\uD638\uB41C HWP \uBB38\uC11C\uC785\uB2C8\uB2E4. password \uC635\uC158\uC5D0 \uC5F4\uAE30 \uC554\uD638\uB97C \uC9C0\uC815\uD558\uC138\uC694.");
|
|
5261
|
+
}
|
|
5262
|
+
assertSupportedEncryptVersion(readEncryptVersion(headerData));
|
|
5263
|
+
}
|
|
5264
|
+
const password = encrypted ? options.password : void 0;
|
|
5265
|
+
const findStream = (path) => {
|
|
5266
|
+
const raw = readRawStream(path);
|
|
5267
|
+
if (!raw || !password) return raw;
|
|
5268
|
+
return decryptPasswordStream(raw, password);
|
|
5269
|
+
};
|
|
5270
|
+
const compressed = (header.flags & FLAG_COMPRESSED) !== 0;
|
|
5271
|
+
const distribution = (header.flags & FLAG_DISTRIBUTION) !== 0;
|
|
5272
|
+
if (encrypted) {
|
|
5273
|
+
const rawDocInfo = findStream("/DocInfo");
|
|
5274
|
+
if (!rawDocInfo) throw new KordocError("DocInfo \uC2A4\uD2B8\uB9BC \uC5C6\uC74C");
|
|
5275
|
+
let docInfoData;
|
|
5276
|
+
try {
|
|
5277
|
+
docInfoData = compressed ? decompressStream(rawDocInfo) : rawDocInfo;
|
|
5278
|
+
} catch {
|
|
5279
|
+
throw new KordocError("\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uAC70\uB098 \uC554\uD638\uD654 \uB370\uC774\uD130\uAC00 \uC190\uC0C1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
5280
|
+
}
|
|
5281
|
+
assertDecryptedDocInfo(docInfoData, readRecords);
|
|
5282
|
+
}
|
|
5283
|
+
return { cfb, lenientCfb, header, compressed, distribution, encrypted, findStream, warnings };
|
|
5284
|
+
}
|
|
5285
|
+
function readHwp5DocInfoRecords(c) {
|
|
5286
|
+
try {
|
|
5287
|
+
const raw = c.findStream("/DocInfo");
|
|
5288
|
+
if (!raw) return null;
|
|
5289
|
+
return readRecords(c.compressed ? decompressStream(raw) : raw);
|
|
5290
|
+
} catch {
|
|
5291
|
+
return null;
|
|
5292
|
+
}
|
|
5293
|
+
}
|
|
5294
|
+
function readHwp5SectionStreams(c) {
|
|
5295
|
+
return c.distribution ? c.cfb ? findViewTextSections(c.cfb, c.compressed) : findViewTextSectionsLenient(c.lenientCfb, c.compressed) : c.encrypted ? findSectionsVia(c.findStream) : c.cfb ? findSections(c.cfb) : findSectionsLenient(c.lenientCfb, c.compressed);
|
|
5296
|
+
}
|
|
5297
|
+
function readHwp5SectionRecords(c, sections, warnings) {
|
|
5298
|
+
const out = [];
|
|
5299
|
+
let totalDecompressed = 0;
|
|
5300
|
+
for (let si = 0; si < sections.length; si++) {
|
|
5301
|
+
try {
|
|
5302
|
+
const data = !c.distribution && c.compressed ? decompressStream(Buffer.from(sections[si])) : Buffer.from(sections[si]);
|
|
5303
|
+
totalDecompressed += data.length;
|
|
5304
|
+
if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
|
|
5305
|
+
out.push(readRecords(data));
|
|
5306
|
+
} catch (secErr) {
|
|
5307
|
+
if (secErr instanceof KordocError) throw secErr;
|
|
5308
|
+
out.push(null);
|
|
5309
|
+
warnings.push({ page: si + 1, message: `\uC139\uC158 ${si + 1} \uD30C\uC2F1 \uC2E4\uD328: ${secErr instanceof Error ? secErr.message : "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}`, code: "PARTIAL_PARSE" });
|
|
5310
|
+
}
|
|
5311
|
+
}
|
|
5312
|
+
return out;
|
|
5313
|
+
}
|
|
5314
|
+
function readHwp5BinData(c) {
|
|
5315
|
+
return c.cfb ? collectHwp5BinData(c.cfb.FileIndex) : collectHwp5BinDataLenient(c.lenientCfb);
|
|
5316
|
+
}
|
|
5317
|
+
function parseHwp5Document(buffer, options) {
|
|
5318
|
+
const c = openHwp5Container(buffer, options);
|
|
5319
|
+
const { cfb, lenientCfb, compressed, encrypted, findStream, warnings } = c;
|
|
5320
|
+
const metadata = {
|
|
5321
|
+
version: `${c.header.versionMajor}.x`
|
|
5322
|
+
};
|
|
5323
|
+
if (cfb) extractHwp5Metadata(cfb, metadata);
|
|
5324
|
+
const docInfo = cfb && !encrypted ? parseDocInfoStream(cfb, compressed) : parseDocInfoFromStream(findStream("/DocInfo"), compressed);
|
|
5325
|
+
const sections = readHwp5SectionStreams(c);
|
|
5326
|
+
if (sections.length === 0) throw new KordocError("\uC139\uC158 \uC2A4\uD2B8\uB9BC\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
5327
|
+
const sectionRecords = readHwp5SectionRecords(c, sections, warnings);
|
|
5328
|
+
const sectionDetects = sectionRecords.map((r) => r ? detectHwp5SectionPages(r) : null);
|
|
5329
|
+
const sectionTableIds = [];
|
|
5330
|
+
{
|
|
5331
|
+
let base = 0;
|
|
5332
|
+
for (const r of sectionRecords) {
|
|
5333
|
+
const ix = indexHwp5Tables(r ?? [], base);
|
|
5334
|
+
sectionTableIds.push(ix.ids);
|
|
5335
|
+
base += ix.count;
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
5338
|
+
const layoutPages = sectionDetects.length > 0 && sectionDetects.every((d) => d != null && d.usable);
|
|
5339
|
+
metadata.pageMode = layoutPages ? "layout" : "section";
|
|
5340
|
+
metadata.pageCount = layoutPages ? Math.max(sectionDetects.reduce((sum, d) => sum + (d?.pages ?? 0), 0), 1) : sections.length;
|
|
5341
|
+
const pageFilter = options?.pages ? parsePageRange(options.pages, metadata.pageCount) : null;
|
|
5342
|
+
if (pageFilter && !layoutPages) {
|
|
5343
|
+
warnings.push({ code: "PAGE_BOUNDARY_APPROXIMATE", message: "\uC870\uD310 \uCE90\uC2DC\uAC00 \uC5C6\uC5B4 pages \uD544\uD130\uB97C \uC139\uC158 \uB2E8\uC704 \uADFC\uC0AC\uB85C \uC801\uC6A9\uD588\uC2B5\uB2C8\uB2E4" });
|
|
5344
|
+
}
|
|
5345
|
+
let bodyBlocks = [];
|
|
5346
|
+
const doc = createHwp5DocState();
|
|
5347
|
+
doc.keepTrailingEmptyCols = options?.keepTrailingEmptyCols;
|
|
5348
|
+
let parsedSections = 0;
|
|
5349
|
+
let pageBase = 0;
|
|
5350
|
+
for (let si = 0; si < sections.length; si++) {
|
|
5351
|
+
const records = sectionRecords[si];
|
|
5352
|
+
if (!records) continue;
|
|
5353
|
+
const detect = sectionDetects[si];
|
|
5354
|
+
if (!layoutPages && pageFilter && !pageFilter.has(si + 1)) continue;
|
|
5355
|
+
try {
|
|
5356
|
+
const sectionBlocks = parseSection(
|
|
5357
|
+
records,
|
|
5358
|
+
docInfo,
|
|
5359
|
+
warnings,
|
|
5360
|
+
si + 1,
|
|
5361
|
+
doc,
|
|
5362
|
+
layoutPages ? { base: pageBase, pageAtPara: detect.pageAtPara } : void 0,
|
|
5363
|
+
sectionTableIds[si]
|
|
5364
|
+
);
|
|
5365
|
+
bodyBlocks.push(...sectionBlocks);
|
|
5366
|
+
parsedSections++;
|
|
5367
|
+
options?.onProgress?.(parsedSections, sections.length);
|
|
5368
|
+
} catch (secErr) {
|
|
5369
|
+
if (secErr instanceof KordocError) throw secErr;
|
|
5370
|
+
warnings.push({ page: si + 1, message: `\uC139\uC158 ${si + 1} \uD30C\uC2F1 \uC2E4\uD328: ${secErr instanceof Error ? secErr.message : "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}`, code: "PARTIAL_PARSE" });
|
|
5371
|
+
} finally {
|
|
5372
|
+
pageBase += detect.pages;
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
if (pageFilter && layoutPages) {
|
|
5376
|
+
bodyBlocks = bodyBlocks.filter((b) => b.pageNumber != null && pageFilter.has(b.pageNumber));
|
|
5377
|
+
}
|
|
5378
|
+
const blocks = [...doc.headerBlocks, ...bodyBlocks, ...doc.footerBlocks];
|
|
5379
|
+
const images = cfb ? extractHwp5Images(cfb.FileIndex, blocks, warnings, !pageFilter) : extractHwp5ImagesLenient(lenientCfb, blocks, warnings, !pageFilter);
|
|
5380
|
+
let flatBlocks = flattenLayoutTables(blocks);
|
|
5381
|
+
if (options?.dedupeRunningHeaders) {
|
|
5382
|
+
const deduped = dedupeRunningHeaders(flatBlocks);
|
|
5383
|
+
const removed = flatBlocks.length - deduped.length;
|
|
5384
|
+
if (removed > 0) warnings.push({ message: `\uBC18\uBCF5 \uB7EC\uB2DD \uD5E4\uB354 ${removed}\uAC1C \uC81C\uAC70`, code: "HIDDEN_TEXT_FILTERED" });
|
|
5385
|
+
flatBlocks = deduped;
|
|
5386
|
+
}
|
|
5387
|
+
if (docInfo) {
|
|
5388
|
+
detectHwp5Headings(flatBlocks, docInfo);
|
|
5389
|
+
}
|
|
5390
|
+
const outline = flatBlocks.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
|
|
5391
|
+
let markdown = blocksToMarkdown(flatBlocks);
|
|
5392
|
+
if (options?.inlineImages && images.length > 0) {
|
|
5393
|
+
try {
|
|
5394
|
+
markdown = inlineImagesIntoMarkdown(markdown, images, { compress: true });
|
|
5395
|
+
} catch (inlineErr) {
|
|
5396
|
+
warnings.push({ message: `\uC774\uBBF8\uC9C0 \uC778\uB77C\uC778 \uC2E4\uD328 \u2014 \uC6D0\uBCF8 \uD30C\uC77C \uCC38\uC870\uB85C \uD3F4\uBC31: ${inlineErr instanceof Error ? inlineErr.message : "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}`, code: "SKIPPED_IMAGE" });
|
|
5397
|
+
}
|
|
5398
|
+
}
|
|
5399
|
+
return { markdown, blocks: flatBlocks, metadata, outline: outline.length > 0 ? outline : void 0, warnings: warnings.length > 0 ? warnings : void 0, images: images.length > 0 ? images : void 0 };
|
|
5400
|
+
}
|
|
5401
|
+
function parseDocInfoStream(cfb, compressed) {
|
|
5402
|
+
try {
|
|
5403
|
+
const entry = CFB.find(cfb, "/DocInfo");
|
|
5404
|
+
if (!entry?.content) return null;
|
|
5405
|
+
const data = compressed ? decompressStream(Buffer.from(entry.content)) : Buffer.from(entry.content);
|
|
5406
|
+
const records = readRecords(data);
|
|
5407
|
+
return parseDocInfo(records);
|
|
5408
|
+
} catch {
|
|
5409
|
+
return null;
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5412
|
+
function parseDocInfoFromStream(raw, compressed) {
|
|
5413
|
+
if (!raw) return null;
|
|
5414
|
+
try {
|
|
5415
|
+
const data = compressed ? decompressStream(raw) : raw;
|
|
5416
|
+
return parseDocInfo(readRecords(data));
|
|
5417
|
+
} catch {
|
|
5418
|
+
return null;
|
|
5419
|
+
}
|
|
5420
|
+
}
|
|
5421
|
+
function detectHwp5Headings(blocks, docInfo) {
|
|
5422
|
+
let baseFontSize = 0;
|
|
5423
|
+
const sizeFreq = /* @__PURE__ */ new Map();
|
|
5424
|
+
for (const b of blocks) {
|
|
5425
|
+
if (b.style?.fontSize && b.text) {
|
|
5426
|
+
sizeFreq.set(b.style.fontSize, (sizeFreq.get(b.style.fontSize) || 0) + b.text.length);
|
|
5427
|
+
}
|
|
5428
|
+
}
|
|
5429
|
+
let maxWeight = 0;
|
|
5430
|
+
for (const [size, weight] of sizeFreq) {
|
|
5431
|
+
if (weight > maxWeight) {
|
|
5432
|
+
maxWeight = weight;
|
|
5433
|
+
baseFontSize = size;
|
|
5434
|
+
}
|
|
5435
|
+
}
|
|
5436
|
+
if (baseFontSize === 0) {
|
|
5437
|
+
for (const style of docInfo.styles) {
|
|
5438
|
+
const name = (style.nameKo || style.name).toLowerCase();
|
|
5439
|
+
if (name.includes("\uBC14\uD0D5") || name.includes("\uBCF8\uBB38") || name === "normal" || name === "body") {
|
|
5440
|
+
const cs = docInfo.charShapes[style.charShapeId];
|
|
5441
|
+
if (cs?.fontSize > 0) {
|
|
5442
|
+
baseFontSize = cs.fontSize / 10;
|
|
5443
|
+
break;
|
|
5444
|
+
}
|
|
5445
|
+
}
|
|
5446
|
+
}
|
|
5447
|
+
}
|
|
5448
|
+
if (baseFontSize <= 0) return;
|
|
5449
|
+
for (const block of blocks) {
|
|
5450
|
+
if (block.type === "heading") continue;
|
|
5451
|
+
if (block.type !== "paragraph" || !block.text) continue;
|
|
5452
|
+
const text = block.text.trim();
|
|
5453
|
+
if (text.length === 0 || text.length > 200) continue;
|
|
5454
|
+
if (/^\d+$/.test(text)) continue;
|
|
5455
|
+
let level = 0;
|
|
5456
|
+
if (block.style?.fontSize && baseFontSize > 0) {
|
|
5457
|
+
const ratio = block.style.fontSize / baseFontSize;
|
|
5458
|
+
if (ratio >= HEADING_RATIO_H1) level = 1;
|
|
5459
|
+
else if (ratio >= HEADING_RATIO_H2) level = 2;
|
|
5460
|
+
else if (ratio >= HEADING_RATIO_H3) level = 3;
|
|
5461
|
+
}
|
|
5462
|
+
if (/^제\d+[장절편]\s/.test(text) && text.length <= 50) {
|
|
5463
|
+
if (level === 0) level = 2;
|
|
5464
|
+
} else if (/^제\d+(조의?\d*)\s*[\((]/.test(text) && text.length <= 80) {
|
|
5465
|
+
if (level === 0) level = 3;
|
|
5466
|
+
}
|
|
5467
|
+
if (level > 0) {
|
|
5468
|
+
block.type = "heading";
|
|
5469
|
+
block.level = level;
|
|
5470
|
+
}
|
|
5471
|
+
}
|
|
5472
|
+
}
|
|
5473
|
+
function extractHwp5Metadata(cfb, metadata) {
|
|
5474
|
+
try {
|
|
5475
|
+
const summaryEntry = CFB.find(cfb, "/HwpSummaryInformation") || CFB.find(cfb, "/SummaryInformation");
|
|
5476
|
+
if (!summaryEntry?.content) return;
|
|
5477
|
+
const data = Buffer.from(summaryEntry.content);
|
|
5478
|
+
if (data.length < 48) return;
|
|
5479
|
+
const numSets = data.readUInt32LE(24);
|
|
5480
|
+
if (numSets === 0) return;
|
|
5481
|
+
const setOffset = data.readUInt32LE(44);
|
|
5482
|
+
if (setOffset >= data.length - 8) return;
|
|
5483
|
+
const numProps = data.readUInt32LE(setOffset + 4);
|
|
5484
|
+
if (numProps === 0 || numProps > 100) return;
|
|
5485
|
+
for (let i = 0; i < numProps; i++) {
|
|
5486
|
+
const entryOffset = setOffset + 8 + i * 8;
|
|
5487
|
+
if (entryOffset + 8 > data.length) break;
|
|
5488
|
+
const propId = data.readUInt32LE(entryOffset);
|
|
5489
|
+
const propOffset = setOffset + data.readUInt32LE(entryOffset + 4);
|
|
5490
|
+
if (propOffset + 8 > data.length) continue;
|
|
5491
|
+
if (propId !== 2 && propId !== 4 && propId !== 6) continue;
|
|
5492
|
+
const propType = data.readUInt32LE(propOffset);
|
|
5493
|
+
if (propType !== 30) continue;
|
|
5494
|
+
const strLen = data.readUInt32LE(propOffset + 4);
|
|
5495
|
+
if (strLen === 0 || strLen > 1e4 || propOffset + 8 + strLen > data.length) continue;
|
|
5496
|
+
const str = data.subarray(propOffset + 8, propOffset + 8 + strLen).toString("utf8").replace(/\0+$/, "").trim();
|
|
5497
|
+
if (!str) continue;
|
|
5498
|
+
if (propId === 2) metadata.title = str;
|
|
5499
|
+
else if (propId === 4) metadata.author = str;
|
|
5500
|
+
else if (propId === 6) metadata.description = str;
|
|
5501
|
+
}
|
|
5502
|
+
} catch {
|
|
5503
|
+
}
|
|
5504
|
+
}
|
|
5505
|
+
function findViewTextSections(cfb, compressed) {
|
|
5506
|
+
const sections = [];
|
|
5507
|
+
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
5508
|
+
const entry = CFB.find(cfb, `/ViewText/Section${i}`);
|
|
5509
|
+
if (!entry?.content) break;
|
|
5510
|
+
try {
|
|
5511
|
+
const decrypted = decryptViewText(Buffer.from(entry.content), compressed);
|
|
5512
|
+
sections.push({ idx: i, content: decrypted });
|
|
5513
|
+
} catch {
|
|
5514
|
+
break;
|
|
5515
|
+
}
|
|
5516
|
+
}
|
|
5517
|
+
return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
|
|
5518
|
+
}
|
|
5519
|
+
function findSectionsVia(read) {
|
|
5520
|
+
const sections = [];
|
|
5521
|
+
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
5522
|
+
const raw = read(`/BodyText/Section${i}`);
|
|
5523
|
+
if (!raw) break;
|
|
5524
|
+
sections.push(raw);
|
|
5525
|
+
}
|
|
5526
|
+
return sections;
|
|
5527
|
+
}
|
|
5528
|
+
function findSections(cfb) {
|
|
5529
|
+
const sections = [];
|
|
5530
|
+
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
5531
|
+
const entry = CFB.find(cfb, `/BodyText/Section${i}`);
|
|
5532
|
+
if (!entry?.content) break;
|
|
5533
|
+
sections.push({ idx: i, content: Buffer.from(entry.content) });
|
|
5534
|
+
}
|
|
5535
|
+
if (sections.length === 0 && cfb.FileIndex) {
|
|
5536
|
+
for (const entry of cfb.FileIndex) {
|
|
5537
|
+
if (sections.length >= MAX_SECTIONS) break;
|
|
5538
|
+
if (entry.name?.startsWith("Section") && entry.content) {
|
|
5539
|
+
const idx = parseInt(entry.name.replace("Section", ""), 10) || 0;
|
|
5540
|
+
sections.push({ idx, content: Buffer.from(entry.content) });
|
|
5541
|
+
}
|
|
5542
|
+
}
|
|
5543
|
+
}
|
|
5544
|
+
return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
|
|
5545
|
+
}
|
|
5546
|
+
function findSectionsLenient(lcfb, compressed) {
|
|
5547
|
+
const sections = [];
|
|
5548
|
+
let totalDecompressed = 0;
|
|
5549
|
+
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
5550
|
+
const raw = lcfb.findStream(`/BodyText/Section${i}`) ?? lcfb.findStream(`Section${i}`);
|
|
5551
|
+
if (!raw) break;
|
|
5552
|
+
const content = compressed ? decompressStream(raw) : raw;
|
|
5553
|
+
totalDecompressed += content.length;
|
|
5554
|
+
if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
|
|
5555
|
+
sections.push({ idx: i, content });
|
|
5556
|
+
}
|
|
5557
|
+
if (sections.length === 0) {
|
|
5558
|
+
for (const e of lcfb.entries()) {
|
|
5559
|
+
if (sections.length >= MAX_SECTIONS) break;
|
|
5560
|
+
if (e.name.startsWith("Section")) {
|
|
5561
|
+
const idx = parseInt(e.name.replace("Section", ""), 10) || 0;
|
|
5562
|
+
const raw = lcfb.findStream(e.name);
|
|
5563
|
+
if (raw) {
|
|
5564
|
+
const content = compressed ? decompressStream(raw) : raw;
|
|
5565
|
+
totalDecompressed += content.length;
|
|
5566
|
+
if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
|
|
5567
|
+
sections.push({ idx, content });
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
}
|
|
5572
|
+
return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
|
|
5573
|
+
}
|
|
5574
|
+
function findViewTextSectionsLenient(lcfb, compressed) {
|
|
5575
|
+
const sections = [];
|
|
5576
|
+
let totalDecompressed = 0;
|
|
5577
|
+
for (let i = 0; i < MAX_SECTIONS; i++) {
|
|
5578
|
+
const raw = lcfb.findStream(`/ViewText/Section${i}`) ?? lcfb.findStream(`Section${i}`);
|
|
5579
|
+
if (!raw) break;
|
|
5580
|
+
try {
|
|
5581
|
+
const content = decryptViewText(raw, compressed);
|
|
5582
|
+
totalDecompressed += content.length;
|
|
5583
|
+
if (totalDecompressed > MAX_TOTAL_DECOMPRESS) throw new KordocError("\uCD1D \uC555\uCD95 \uD574\uC81C \uD06C\uAE30 \uCD08\uACFC (decompression bomb \uC758\uC2EC)");
|
|
5584
|
+
sections.push({ idx: i, content });
|
|
5585
|
+
} catch {
|
|
5586
|
+
break;
|
|
5587
|
+
}
|
|
5588
|
+
}
|
|
5589
|
+
return sections.sort((a, b) => a.idx - b.idx).map((s) => s.content);
|
|
5590
|
+
}
|
|
5591
|
+
|
|
5569
5592
|
// src/hwp3/parser.ts
|
|
5570
5593
|
import { inflateRawSync as inflateRawSync5 } from "zlib";
|
|
5571
5594
|
|
|
@@ -21524,7 +21547,7 @@ function decodeXmlEntities(text) {
|
|
|
21524
21547
|
}
|
|
21525
21548
|
function tContentToText(raw) {
|
|
21526
21549
|
return decodeXmlEntities(
|
|
21527
|
-
raw.replace(/<\/?(?:[A-Za-z0-9_]+:)?(?:tab|fwSpace|hwSpace|br|lineBreak)(?:\s[^>]*)?\/?>/g, " ").replace(/<[^>]*>/g, "")
|
|
21550
|
+
raw.replace(/<\/?(?:[A-Za-z0-9_]+:)?(?:tab|fwSpace|hwSpace|nbSpace|br|lineBreak)(?:\s[^>]*)?\/?>/g, " ").replace(/<[^>]*>/g, "")
|
|
21528
21551
|
);
|
|
21529
21552
|
}
|
|
21530
21553
|
var TAG_RE = /<!--[\s\S]*?-->|<!\[CDATA\[[\s\S]*?\]\]>|<\?[\s\S]*?\?>|<!(?:"[^"]*"|'[^']*'|[^>"'])*>|<\/([^\s>]+)\s*>|<([^\s/>!?]+)((?:"[^"]*"|'[^']*'|[^>"'])*?)(\/?)>/g;
|
|
@@ -21692,7 +21715,7 @@ function scanSectionXml(xml, sectionIndex) {
|
|
|
21692
21715
|
if (local === "t") {
|
|
21693
21716
|
const para2 = owningPara();
|
|
21694
21717
|
if (para2) para2.tRanges.push({ contentStart: m.index, contentEnd: m.index + full.length, selfClosing: true, prefix: prefixOf(qname) });
|
|
21695
|
-
} else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "br" || local === "lineBreak") {
|
|
21718
|
+
} else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "nbSpace" || local === "br" || local === "lineBreak") {
|
|
21696
21719
|
if (!pendingT) {
|
|
21697
21720
|
const para2 = owningPara();
|
|
21698
21721
|
if (para2) para2.text += " ";
|
|
@@ -21793,7 +21816,7 @@ function scanSectionXml(xml, sectionIndex) {
|
|
|
21793
21816
|
if (stack.some((f) => f.local === "ctrl")) {
|
|
21794
21817
|
ctrlSubStack.push({ kind: local, texts: [] });
|
|
21795
21818
|
}
|
|
21796
|
-
} else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "br" || local === "lineBreak") {
|
|
21819
|
+
} else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "nbSpace" || local === "br" || local === "lineBreak") {
|
|
21797
21820
|
const para2 = owningPara();
|
|
21798
21821
|
if (para2) para2.text += " ";
|
|
21799
21822
|
}
|
|
@@ -21937,6 +21960,13 @@ function buildParagraphSplices(para2, newText, xml) {
|
|
|
21937
21960
|
}
|
|
21938
21961
|
return newText ? null : [];
|
|
21939
21962
|
}
|
|
21963
|
+
function markerRunSplices(para2, xml, newText) {
|
|
21964
|
+
const first = para2.tRanges[0];
|
|
21965
|
+
if (!first || first.selfClosing || para2.tRanges.length < 2) return null;
|
|
21966
|
+
const m = /^([^<&\s]{1,6})<(?:\w+:)?tab\b[^>]*\/>$/.exec(xml.slice(first.contentStart, first.contentEnd));
|
|
21967
|
+
if (!m || !newText.startsWith(m[1] + " ")) return null;
|
|
21968
|
+
return buildParagraphSplices({ ...para2, tRanges: para2.tRanges.slice(1) }, newText.slice(m[1].length + 1), xml);
|
|
21969
|
+
}
|
|
21940
21970
|
function paraTText(para2, xml) {
|
|
21941
21971
|
let text = "";
|
|
21942
21972
|
for (const t of para2.tRanges) {
|
|
@@ -22836,6 +22866,1277 @@ function blocksToPages(blocks) {
|
|
|
22836
22866
|
// src/hwpx/generator.ts
|
|
22837
22867
|
import JSZip8 from "jszip";
|
|
22838
22868
|
|
|
22869
|
+
// src/hwpx/font-metrics.ts
|
|
22870
|
+
var FONTS = {
|
|
22871
|
+
"\uD55C\uCEF4\uB3CB\uC6C0": {
|
|
22872
|
+
cjk: 1e3,
|
|
22873
|
+
ascii: [
|
|
22874
|
+
500,
|
|
22875
|
+
334,
|
|
22876
|
+
415,
|
|
22877
|
+
625,
|
|
22878
|
+
500,
|
|
22879
|
+
915,
|
|
22880
|
+
709,
|
|
22881
|
+
290,
|
|
22882
|
+
375,
|
|
22883
|
+
375,
|
|
22884
|
+
583,
|
|
22885
|
+
580,
|
|
22886
|
+
375,
|
|
22887
|
+
590,
|
|
22888
|
+
375,
|
|
22889
|
+
415,
|
|
22890
|
+
583,
|
|
22891
|
+
583,
|
|
22892
|
+
583,
|
|
22893
|
+
583,
|
|
22894
|
+
583,
|
|
22895
|
+
583,
|
|
22896
|
+
583,
|
|
22897
|
+
583,
|
|
22898
|
+
583,
|
|
22899
|
+
583,
|
|
22900
|
+
340,
|
|
22901
|
+
340,
|
|
22902
|
+
625,
|
|
22903
|
+
584,
|
|
22904
|
+
625,
|
|
22905
|
+
583,
|
|
22906
|
+
1e3,
|
|
22907
|
+
665,
|
|
22908
|
+
680,
|
|
22909
|
+
720,
|
|
22910
|
+
725,
|
|
22911
|
+
629,
|
|
22912
|
+
600,
|
|
22913
|
+
750,
|
|
22914
|
+
724,
|
|
22915
|
+
259,
|
|
22916
|
+
484,
|
|
22917
|
+
655,
|
|
22918
|
+
540,
|
|
22919
|
+
810,
|
|
22920
|
+
695,
|
|
22921
|
+
750,
|
|
22922
|
+
644,
|
|
22923
|
+
750,
|
|
22924
|
+
668,
|
|
22925
|
+
640,
|
|
22926
|
+
583,
|
|
22927
|
+
725,
|
|
22928
|
+
600,
|
|
22929
|
+
894,
|
|
22930
|
+
604,
|
|
22931
|
+
600,
|
|
22932
|
+
604,
|
|
22933
|
+
500,
|
|
22934
|
+
333,
|
|
22935
|
+
500,
|
|
22936
|
+
625,
|
|
22937
|
+
500,
|
|
22938
|
+
330,
|
|
22939
|
+
583,
|
|
22940
|
+
600,
|
|
22941
|
+
560,
|
|
22942
|
+
600,
|
|
22943
|
+
560,
|
|
22944
|
+
344,
|
|
22945
|
+
599,
|
|
22946
|
+
560,
|
|
22947
|
+
229,
|
|
22948
|
+
229,
|
|
22949
|
+
510,
|
|
22950
|
+
230,
|
|
22951
|
+
800,
|
|
22952
|
+
568,
|
|
22953
|
+
600,
|
|
22954
|
+
600,
|
|
22955
|
+
600,
|
|
22956
|
+
320,
|
|
22957
|
+
515,
|
|
22958
|
+
313,
|
|
22959
|
+
568,
|
|
22960
|
+
475,
|
|
22961
|
+
725,
|
|
22962
|
+
479,
|
|
22963
|
+
480,
|
|
22964
|
+
480,
|
|
22965
|
+
500,
|
|
22966
|
+
500,
|
|
22967
|
+
500,
|
|
22968
|
+
790
|
|
22969
|
+
],
|
|
22970
|
+
ex: {
|
|
22971
|
+
167: 561,
|
|
22972
|
+
176: 405,
|
|
22973
|
+
177: 833,
|
|
22974
|
+
180: 333,
|
|
22975
|
+
183: 331,
|
|
22976
|
+
215: 833,
|
|
22977
|
+
247: 833,
|
|
22978
|
+
8208: 261,
|
|
22979
|
+
8209: 314,
|
|
22980
|
+
8210: 431,
|
|
22981
|
+
8211: 500,
|
|
22982
|
+
8212: 687,
|
|
22983
|
+
8214: 429,
|
|
22984
|
+
8215: 548,
|
|
22985
|
+
8216: 291,
|
|
22986
|
+
8217: 291,
|
|
22987
|
+
8218: 291,
|
|
22988
|
+
8219: 291,
|
|
22989
|
+
8220: 458,
|
|
22990
|
+
8221: 458,
|
|
22991
|
+
8222: 458,
|
|
22992
|
+
8223: 458,
|
|
22993
|
+
8224: 562,
|
|
22994
|
+
8225: 562,
|
|
22995
|
+
8226: 463,
|
|
22996
|
+
8227: 466,
|
|
22997
|
+
8228: 174,
|
|
22998
|
+
8229: 566,
|
|
22999
|
+
8230: 830,
|
|
23000
|
+
8231: 301,
|
|
23001
|
+
8239: 500,
|
|
23002
|
+
8242: 335,
|
|
23003
|
+
8243: 563,
|
|
23004
|
+
8244: 734,
|
|
23005
|
+
8245: 335,
|
|
23006
|
+
8246: 563,
|
|
23007
|
+
8247: 734,
|
|
23008
|
+
8248: 408,
|
|
23009
|
+
8249: 375,
|
|
23010
|
+
8250: 375,
|
|
23011
|
+
8252: 625,
|
|
23012
|
+
8253: 465,
|
|
23013
|
+
8254: 500,
|
|
23014
|
+
8255: 804,
|
|
23015
|
+
8256: 804,
|
|
23016
|
+
8257: 356,
|
|
23017
|
+
8259: 224,
|
|
23018
|
+
8260: 734,
|
|
23019
|
+
8261: 320,
|
|
23020
|
+
8262: 320,
|
|
23021
|
+
8264: 656,
|
|
23022
|
+
8265: 656,
|
|
23023
|
+
8266: 456,
|
|
23024
|
+
8267: 562,
|
|
23025
|
+
8268: 562,
|
|
23026
|
+
8269: 562,
|
|
23027
|
+
8272: 804,
|
|
23028
|
+
8728: 500,
|
|
23029
|
+
8729: 500
|
|
23030
|
+
}
|
|
23031
|
+
},
|
|
23032
|
+
"HY\uACAC\uACE0\uB515": {
|
|
23033
|
+
cjk: 1e3,
|
|
23034
|
+
ascii: [
|
|
23035
|
+
500,
|
|
23036
|
+
416,
|
|
23037
|
+
583,
|
|
23038
|
+
708,
|
|
23039
|
+
625,
|
|
23040
|
+
958,
|
|
23041
|
+
791,
|
|
23042
|
+
333,
|
|
23043
|
+
458,
|
|
23044
|
+
458,
|
|
23045
|
+
541,
|
|
23046
|
+
666,
|
|
23047
|
+
375,
|
|
23048
|
+
666,
|
|
23049
|
+
375,
|
|
23050
|
+
416,
|
|
23051
|
+
625,
|
|
23052
|
+
625,
|
|
23053
|
+
625,
|
|
23054
|
+
625,
|
|
23055
|
+
625,
|
|
23056
|
+
625,
|
|
23057
|
+
625,
|
|
23058
|
+
625,
|
|
23059
|
+
625,
|
|
23060
|
+
625,
|
|
23061
|
+
375,
|
|
23062
|
+
375,
|
|
23063
|
+
583,
|
|
23064
|
+
666,
|
|
23065
|
+
583,
|
|
23066
|
+
708,
|
|
23067
|
+
1e3,
|
|
23068
|
+
791,
|
|
23069
|
+
791,
|
|
23070
|
+
791,
|
|
23071
|
+
791,
|
|
23072
|
+
708,
|
|
23073
|
+
666,
|
|
23074
|
+
833,
|
|
23075
|
+
791,
|
|
23076
|
+
375,
|
|
23077
|
+
583,
|
|
23078
|
+
833,
|
|
23079
|
+
666,
|
|
23080
|
+
875,
|
|
23081
|
+
791,
|
|
23082
|
+
833,
|
|
23083
|
+
708,
|
|
23084
|
+
833,
|
|
23085
|
+
791,
|
|
23086
|
+
750,
|
|
23087
|
+
708,
|
|
23088
|
+
791,
|
|
23089
|
+
708,
|
|
23090
|
+
1e3,
|
|
23091
|
+
750,
|
|
23092
|
+
750,
|
|
23093
|
+
708,
|
|
23094
|
+
458,
|
|
23095
|
+
416,
|
|
23096
|
+
458,
|
|
23097
|
+
541,
|
|
23098
|
+
500,
|
|
23099
|
+
250,
|
|
23100
|
+
625,
|
|
23101
|
+
666,
|
|
23102
|
+
625,
|
|
23103
|
+
666,
|
|
23104
|
+
625,
|
|
23105
|
+
375,
|
|
23106
|
+
666,
|
|
23107
|
+
666,
|
|
23108
|
+
375,
|
|
23109
|
+
333,
|
|
23110
|
+
666,
|
|
23111
|
+
375,
|
|
23112
|
+
958,
|
|
23113
|
+
666,
|
|
23114
|
+
666,
|
|
23115
|
+
666,
|
|
23116
|
+
666,
|
|
23117
|
+
458,
|
|
23118
|
+
625,
|
|
23119
|
+
416,
|
|
23120
|
+
666,
|
|
23121
|
+
625,
|
|
23122
|
+
833,
|
|
23123
|
+
625,
|
|
23124
|
+
625,
|
|
23125
|
+
583,
|
|
23126
|
+
500,
|
|
23127
|
+
375,
|
|
23128
|
+
500,
|
|
23129
|
+
666
|
|
23130
|
+
],
|
|
23131
|
+
ex: {}
|
|
23132
|
+
},
|
|
23133
|
+
"\uD734\uBA3C\uBA85\uC870": {
|
|
23134
|
+
cjk: 1e3,
|
|
23135
|
+
ascii: [
|
|
23136
|
+
500,
|
|
23137
|
+
203,
|
|
23138
|
+
500,
|
|
23139
|
+
656,
|
|
23140
|
+
504,
|
|
23141
|
+
750,
|
|
23142
|
+
770,
|
|
23143
|
+
289,
|
|
23144
|
+
313,
|
|
23145
|
+
313,
|
|
23146
|
+
500,
|
|
23147
|
+
500,
|
|
23148
|
+
270,
|
|
23149
|
+
500,
|
|
23150
|
+
270,
|
|
23151
|
+
313,
|
|
23152
|
+
500,
|
|
23153
|
+
500,
|
|
23154
|
+
500,
|
|
23155
|
+
500,
|
|
23156
|
+
500,
|
|
23157
|
+
500,
|
|
23158
|
+
500,
|
|
23159
|
+
500,
|
|
23160
|
+
500,
|
|
23161
|
+
500,
|
|
23162
|
+
270,
|
|
23163
|
+
270,
|
|
23164
|
+
500,
|
|
23165
|
+
500,
|
|
23166
|
+
500,
|
|
23167
|
+
430,
|
|
23168
|
+
777,
|
|
23169
|
+
660,
|
|
23170
|
+
602,
|
|
23171
|
+
641,
|
|
23172
|
+
680,
|
|
23173
|
+
625,
|
|
23174
|
+
582,
|
|
23175
|
+
703,
|
|
23176
|
+
680,
|
|
23177
|
+
258,
|
|
23178
|
+
395,
|
|
23179
|
+
645,
|
|
23180
|
+
578,
|
|
23181
|
+
781,
|
|
23182
|
+
691,
|
|
23183
|
+
715,
|
|
23184
|
+
574,
|
|
23185
|
+
688,
|
|
23186
|
+
652,
|
|
23187
|
+
496,
|
|
23188
|
+
625,
|
|
23189
|
+
676,
|
|
23190
|
+
664,
|
|
23191
|
+
934,
|
|
23192
|
+
711,
|
|
23193
|
+
672,
|
|
23194
|
+
598,
|
|
23195
|
+
320,
|
|
23196
|
+
313,
|
|
23197
|
+
320,
|
|
23198
|
+
363,
|
|
23199
|
+
500,
|
|
23200
|
+
324,
|
|
23201
|
+
508,
|
|
23202
|
+
543,
|
|
23203
|
+
484,
|
|
23204
|
+
508,
|
|
23205
|
+
523,
|
|
23206
|
+
391,
|
|
23207
|
+
516,
|
|
23208
|
+
555,
|
|
23209
|
+
250,
|
|
23210
|
+
266,
|
|
23211
|
+
523,
|
|
23212
|
+
250,
|
|
23213
|
+
797,
|
|
23214
|
+
551,
|
|
23215
|
+
512,
|
|
23216
|
+
539,
|
|
23217
|
+
539,
|
|
23218
|
+
402,
|
|
23219
|
+
410,
|
|
23220
|
+
340,
|
|
23221
|
+
539,
|
|
23222
|
+
539,
|
|
23223
|
+
723,
|
|
23224
|
+
488,
|
|
23225
|
+
512,
|
|
23226
|
+
453,
|
|
23227
|
+
293,
|
|
23228
|
+
203,
|
|
23229
|
+
293,
|
|
23230
|
+
500
|
|
23231
|
+
],
|
|
23232
|
+
ex: {}
|
|
23233
|
+
},
|
|
23234
|
+
"HY\uD5E4\uB4DC\uB77C\uC778M": {
|
|
23235
|
+
cjk: 1e3,
|
|
23236
|
+
ascii: [
|
|
23237
|
+
500,
|
|
23238
|
+
250,
|
|
23239
|
+
375,
|
|
23240
|
+
833,
|
|
23241
|
+
584,
|
|
23242
|
+
798,
|
|
23243
|
+
583,
|
|
23244
|
+
208,
|
|
23245
|
+
291,
|
|
23246
|
+
294,
|
|
23247
|
+
480,
|
|
23248
|
+
587,
|
|
23249
|
+
238,
|
|
23250
|
+
503,
|
|
23251
|
+
242,
|
|
23252
|
+
384,
|
|
23253
|
+
583,
|
|
23254
|
+
583,
|
|
23255
|
+
583,
|
|
23256
|
+
583,
|
|
23257
|
+
583,
|
|
23258
|
+
583,
|
|
23259
|
+
583,
|
|
23260
|
+
583,
|
|
23261
|
+
583,
|
|
23262
|
+
583,
|
|
23263
|
+
265,
|
|
23264
|
+
265,
|
|
23265
|
+
582,
|
|
23266
|
+
587,
|
|
23267
|
+
588,
|
|
23268
|
+
583,
|
|
23269
|
+
853,
|
|
23270
|
+
583,
|
|
23271
|
+
629,
|
|
23272
|
+
629,
|
|
23273
|
+
629,
|
|
23274
|
+
506,
|
|
23275
|
+
486,
|
|
23276
|
+
636,
|
|
23277
|
+
635,
|
|
23278
|
+
290,
|
|
23279
|
+
509,
|
|
23280
|
+
605,
|
|
23281
|
+
461,
|
|
23282
|
+
806,
|
|
23283
|
+
614,
|
|
23284
|
+
621,
|
|
23285
|
+
566,
|
|
23286
|
+
621,
|
|
23287
|
+
596,
|
|
23288
|
+
592,
|
|
23289
|
+
520,
|
|
23290
|
+
625,
|
|
23291
|
+
625,
|
|
23292
|
+
917,
|
|
23293
|
+
583,
|
|
23294
|
+
552,
|
|
23295
|
+
485,
|
|
23296
|
+
323,
|
|
23297
|
+
384,
|
|
23298
|
+
322,
|
|
23299
|
+
542,
|
|
23300
|
+
500,
|
|
23301
|
+
324,
|
|
23302
|
+
583,
|
|
23303
|
+
583,
|
|
23304
|
+
579,
|
|
23305
|
+
583,
|
|
23306
|
+
617,
|
|
23307
|
+
423,
|
|
23308
|
+
592,
|
|
23309
|
+
601,
|
|
23310
|
+
283,
|
|
23311
|
+
338,
|
|
23312
|
+
542,
|
|
23313
|
+
281,
|
|
23314
|
+
847,
|
|
23315
|
+
589,
|
|
23316
|
+
625,
|
|
23317
|
+
594,
|
|
23318
|
+
594,
|
|
23319
|
+
405,
|
|
23320
|
+
542,
|
|
23321
|
+
418,
|
|
23322
|
+
599,
|
|
23323
|
+
542,
|
|
23324
|
+
792,
|
|
23325
|
+
500,
|
|
23326
|
+
579,
|
|
23327
|
+
447,
|
|
23328
|
+
417,
|
|
23329
|
+
292,
|
|
23330
|
+
417,
|
|
23331
|
+
708
|
|
23332
|
+
],
|
|
23333
|
+
ex: {}
|
|
23334
|
+
},
|
|
23335
|
+
"\uAD74\uB9BC\uCCB4": {
|
|
23336
|
+
cjk: 1e3,
|
|
23337
|
+
ascii: [
|
|
23338
|
+
500,
|
|
23339
|
+
500,
|
|
23340
|
+
500,
|
|
23341
|
+
500,
|
|
23342
|
+
500,
|
|
23343
|
+
500,
|
|
23344
|
+
500,
|
|
23345
|
+
500,
|
|
23346
|
+
500,
|
|
23347
|
+
500,
|
|
23348
|
+
500,
|
|
23349
|
+
500,
|
|
23350
|
+
500,
|
|
23351
|
+
500,
|
|
23352
|
+
500,
|
|
23353
|
+
500,
|
|
23354
|
+
500,
|
|
23355
|
+
500,
|
|
23356
|
+
500,
|
|
23357
|
+
500,
|
|
23358
|
+
500,
|
|
23359
|
+
500,
|
|
23360
|
+
500,
|
|
23361
|
+
500,
|
|
23362
|
+
500,
|
|
23363
|
+
500,
|
|
23364
|
+
500,
|
|
23365
|
+
500,
|
|
23366
|
+
500,
|
|
23367
|
+
500,
|
|
23368
|
+
500,
|
|
23369
|
+
500,
|
|
23370
|
+
500,
|
|
23371
|
+
500,
|
|
23372
|
+
500,
|
|
23373
|
+
500,
|
|
23374
|
+
500,
|
|
23375
|
+
500,
|
|
23376
|
+
500,
|
|
23377
|
+
500,
|
|
23378
|
+
500,
|
|
23379
|
+
500,
|
|
23380
|
+
500,
|
|
23381
|
+
500,
|
|
23382
|
+
500,
|
|
23383
|
+
500,
|
|
23384
|
+
500,
|
|
23385
|
+
500,
|
|
23386
|
+
500,
|
|
23387
|
+
500,
|
|
23388
|
+
500,
|
|
23389
|
+
500,
|
|
23390
|
+
500,
|
|
23391
|
+
500,
|
|
23392
|
+
500,
|
|
23393
|
+
500,
|
|
23394
|
+
500,
|
|
23395
|
+
500,
|
|
23396
|
+
500,
|
|
23397
|
+
500,
|
|
23398
|
+
500,
|
|
23399
|
+
500,
|
|
23400
|
+
500,
|
|
23401
|
+
500,
|
|
23402
|
+
500,
|
|
23403
|
+
500,
|
|
23404
|
+
500,
|
|
23405
|
+
500,
|
|
23406
|
+
500,
|
|
23407
|
+
500,
|
|
23408
|
+
500,
|
|
23409
|
+
500,
|
|
23410
|
+
500,
|
|
23411
|
+
500,
|
|
23412
|
+
500,
|
|
23413
|
+
500,
|
|
23414
|
+
500,
|
|
23415
|
+
500,
|
|
23416
|
+
500,
|
|
23417
|
+
500,
|
|
23418
|
+
500,
|
|
23419
|
+
500,
|
|
23420
|
+
500,
|
|
23421
|
+
500,
|
|
23422
|
+
500,
|
|
23423
|
+
500,
|
|
23424
|
+
500,
|
|
23425
|
+
500,
|
|
23426
|
+
500,
|
|
23427
|
+
500,
|
|
23428
|
+
500,
|
|
23429
|
+
500,
|
|
23430
|
+
500,
|
|
23431
|
+
500,
|
|
23432
|
+
500
|
|
23433
|
+
],
|
|
23434
|
+
ex: {
|
|
23435
|
+
8211: 500,
|
|
23436
|
+
8212: 500,
|
|
23437
|
+
8215: 500,
|
|
23438
|
+
8218: 500,
|
|
23439
|
+
8219: 500,
|
|
23440
|
+
8222: 500,
|
|
23441
|
+
8226: 500,
|
|
23442
|
+
8249: 500,
|
|
23443
|
+
8250: 500,
|
|
23444
|
+
8252: 500,
|
|
23445
|
+
8254: 500,
|
|
23446
|
+
8260: 500,
|
|
23447
|
+
8453: 500,
|
|
23448
|
+
8494: 500,
|
|
23449
|
+
8616: 500,
|
|
23450
|
+
8710: 500,
|
|
23451
|
+
8722: 500,
|
|
23452
|
+
8725: 500,
|
|
23453
|
+
8729: 500,
|
|
23454
|
+
8735: 500,
|
|
23455
|
+
8776: 500,
|
|
23456
|
+
9552: 500,
|
|
23457
|
+
9553: 500,
|
|
23458
|
+
9554: 500,
|
|
23459
|
+
9555: 500,
|
|
23460
|
+
9556: 500,
|
|
23461
|
+
9557: 500,
|
|
23462
|
+
9558: 500,
|
|
23463
|
+
9559: 500,
|
|
23464
|
+
9560: 500,
|
|
23465
|
+
9561: 500,
|
|
23466
|
+
9562: 500,
|
|
23467
|
+
9563: 500,
|
|
23468
|
+
9564: 500,
|
|
23469
|
+
9565: 500,
|
|
23470
|
+
9566: 500,
|
|
23471
|
+
9567: 500,
|
|
23472
|
+
9568: 500,
|
|
23473
|
+
9569: 500,
|
|
23474
|
+
9570: 500,
|
|
23475
|
+
9571: 500,
|
|
23476
|
+
9572: 500,
|
|
23477
|
+
9573: 500,
|
|
23478
|
+
9574: 500,
|
|
23479
|
+
9575: 500,
|
|
23480
|
+
9576: 500,
|
|
23481
|
+
9577: 500,
|
|
23482
|
+
9578: 500,
|
|
23483
|
+
9579: 500,
|
|
23484
|
+
9580: 500,
|
|
23485
|
+
9600: 500,
|
|
23486
|
+
9604: 500,
|
|
23487
|
+
9608: 500,
|
|
23488
|
+
9612: 500,
|
|
23489
|
+
9616: 500,
|
|
23490
|
+
9617: 500,
|
|
23491
|
+
9619: 500,
|
|
23492
|
+
9642: 500,
|
|
23493
|
+
9643: 500,
|
|
23494
|
+
9644: 500,
|
|
23495
|
+
9658: 500,
|
|
23496
|
+
9668: 500,
|
|
23497
|
+
9674: 500,
|
|
23498
|
+
9688: 500,
|
|
23499
|
+
9689: 500,
|
|
23500
|
+
9702: 500,
|
|
23501
|
+
9786: 500,
|
|
23502
|
+
9787: 500,
|
|
23503
|
+
9788: 500,
|
|
23504
|
+
9830: 500,
|
|
23505
|
+
9835: 500
|
|
23506
|
+
}
|
|
23507
|
+
},
|
|
23508
|
+
"\uAD74\uB9BC": {
|
|
23509
|
+
cjk: 1e3,
|
|
23510
|
+
ascii: [
|
|
23511
|
+
500,
|
|
23512
|
+
333,
|
|
23513
|
+
375,
|
|
23514
|
+
750,
|
|
23515
|
+
598,
|
|
23516
|
+
875,
|
|
23517
|
+
688,
|
|
23518
|
+
283,
|
|
23519
|
+
375,
|
|
23520
|
+
375,
|
|
23521
|
+
500,
|
|
23522
|
+
625,
|
|
23523
|
+
334,
|
|
23524
|
+
625,
|
|
23525
|
+
334,
|
|
23526
|
+
417,
|
|
23527
|
+
574,
|
|
23528
|
+
574,
|
|
23529
|
+
574,
|
|
23530
|
+
574,
|
|
23531
|
+
574,
|
|
23532
|
+
574,
|
|
23533
|
+
574,
|
|
23534
|
+
574,
|
|
23535
|
+
574,
|
|
23536
|
+
574,
|
|
23537
|
+
334,
|
|
23538
|
+
334,
|
|
23539
|
+
625,
|
|
23540
|
+
625,
|
|
23541
|
+
625,
|
|
23542
|
+
542,
|
|
23543
|
+
1e3,
|
|
23544
|
+
646,
|
|
23545
|
+
677,
|
|
23546
|
+
718,
|
|
23547
|
+
722,
|
|
23548
|
+
625,
|
|
23549
|
+
596,
|
|
23550
|
+
770,
|
|
23551
|
+
730,
|
|
23552
|
+
270,
|
|
23553
|
+
500,
|
|
23554
|
+
635,
|
|
23555
|
+
543,
|
|
23556
|
+
813,
|
|
23557
|
+
699,
|
|
23558
|
+
770,
|
|
23559
|
+
637,
|
|
23560
|
+
773,
|
|
23561
|
+
666,
|
|
23562
|
+
633,
|
|
23563
|
+
582,
|
|
23564
|
+
711,
|
|
23565
|
+
600,
|
|
23566
|
+
895,
|
|
23567
|
+
625,
|
|
23568
|
+
625,
|
|
23569
|
+
625,
|
|
23570
|
+
500,
|
|
23571
|
+
917,
|
|
23572
|
+
500,
|
|
23573
|
+
542,
|
|
23574
|
+
500,
|
|
23575
|
+
333,
|
|
23576
|
+
563,
|
|
23577
|
+
605,
|
|
23578
|
+
572,
|
|
23579
|
+
605,
|
|
23580
|
+
567,
|
|
23581
|
+
342,
|
|
23582
|
+
605,
|
|
23583
|
+
571,
|
|
23584
|
+
241,
|
|
23585
|
+
241,
|
|
23586
|
+
500,
|
|
23587
|
+
231,
|
|
23588
|
+
861,
|
|
23589
|
+
580,
|
|
23590
|
+
605,
|
|
23591
|
+
605,
|
|
23592
|
+
605,
|
|
23593
|
+
333,
|
|
23594
|
+
525,
|
|
23595
|
+
313,
|
|
23596
|
+
570,
|
|
23597
|
+
500,
|
|
23598
|
+
750,
|
|
23599
|
+
500,
|
|
23600
|
+
500,
|
|
23601
|
+
500,
|
|
23602
|
+
500,
|
|
23603
|
+
500,
|
|
23604
|
+
500,
|
|
23605
|
+
792
|
|
23606
|
+
],
|
|
23607
|
+
ex: {
|
|
23608
|
+
167: 563,
|
|
23609
|
+
176: 375,
|
|
23610
|
+
177: 833,
|
|
23611
|
+
180: 375,
|
|
23612
|
+
183: 375,
|
|
23613
|
+
215: 833,
|
|
23614
|
+
247: 833,
|
|
23615
|
+
8211: 500,
|
|
23616
|
+
8213: 688,
|
|
23617
|
+
8215: 500,
|
|
23618
|
+
8216: 333,
|
|
23619
|
+
8217: 333,
|
|
23620
|
+
8218: 333,
|
|
23621
|
+
8219: 333,
|
|
23622
|
+
8220: 500,
|
|
23623
|
+
8221: 500,
|
|
23624
|
+
8222: 500,
|
|
23625
|
+
8224: 563,
|
|
23626
|
+
8225: 563,
|
|
23627
|
+
8226: 375,
|
|
23628
|
+
8242: 375,
|
|
23629
|
+
8243: 500,
|
|
23630
|
+
8249: 375,
|
|
23631
|
+
8250: 375,
|
|
23632
|
+
8252: 625,
|
|
23633
|
+
8254: 500,
|
|
23634
|
+
8260: 417,
|
|
23635
|
+
8453: 846,
|
|
23636
|
+
8467: 500,
|
|
23637
|
+
8486: 750,
|
|
23638
|
+
8494: 750,
|
|
23639
|
+
8539: 563,
|
|
23640
|
+
8540: 563,
|
|
23641
|
+
8541: 563,
|
|
23642
|
+
8542: 563,
|
|
23643
|
+
8593: 750,
|
|
23644
|
+
8595: 750,
|
|
23645
|
+
8597: 750,
|
|
23646
|
+
8616: 750,
|
|
23647
|
+
8706: 563,
|
|
23648
|
+
8710: 613,
|
|
23649
|
+
8719: 688,
|
|
23650
|
+
8721: 813,
|
|
23651
|
+
8722: 833,
|
|
23652
|
+
8725: 417,
|
|
23653
|
+
8729: 250,
|
|
23654
|
+
8730: 549,
|
|
23655
|
+
8734: 913,
|
|
23656
|
+
8735: 982,
|
|
23657
|
+
8745: 719,
|
|
23658
|
+
8747: 375,
|
|
23659
|
+
8776: 833,
|
|
23660
|
+
8800: 833,
|
|
23661
|
+
8801: 833,
|
|
23662
|
+
8804: 833,
|
|
23663
|
+
8805: 833,
|
|
23664
|
+
9632: 890,
|
|
23665
|
+
9633: 890,
|
|
23666
|
+
9642: 375,
|
|
23667
|
+
9643: 375,
|
|
23668
|
+
9650: 914,
|
|
23669
|
+
9658: 750,
|
|
23670
|
+
9660: 914,
|
|
23671
|
+
9668: 750,
|
|
23672
|
+
9674: 774,
|
|
23673
|
+
9702: 375,
|
|
23674
|
+
9788: 916,
|
|
23675
|
+
9792: 625,
|
|
23676
|
+
9794: 625,
|
|
23677
|
+
9824: 750,
|
|
23678
|
+
9827: 844,
|
|
23679
|
+
9829: 793,
|
|
23680
|
+
9830: 774,
|
|
23681
|
+
9834: 688,
|
|
23682
|
+
9835: 763
|
|
23683
|
+
}
|
|
23684
|
+
},
|
|
23685
|
+
"\uB9D1\uC740 \uACE0\uB515": {
|
|
23686
|
+
cjk: 1e3,
|
|
23687
|
+
ascii: [
|
|
23688
|
+
500,
|
|
23689
|
+
289,
|
|
23690
|
+
395,
|
|
23691
|
+
606,
|
|
23692
|
+
551,
|
|
23693
|
+
836,
|
|
23694
|
+
818,
|
|
23695
|
+
232,
|
|
23696
|
+
305,
|
|
23697
|
+
305,
|
|
23698
|
+
425,
|
|
23699
|
+
701,
|
|
23700
|
+
219,
|
|
23701
|
+
410,
|
|
23702
|
+
219,
|
|
23703
|
+
396,
|
|
23704
|
+
551,
|
|
23705
|
+
551,
|
|
23706
|
+
551,
|
|
23707
|
+
551,
|
|
23708
|
+
551,
|
|
23709
|
+
551,
|
|
23710
|
+
551,
|
|
23711
|
+
551,
|
|
23712
|
+
551,
|
|
23713
|
+
551,
|
|
23714
|
+
219,
|
|
23715
|
+
219,
|
|
23716
|
+
701,
|
|
23717
|
+
701,
|
|
23718
|
+
701,
|
|
23719
|
+
460,
|
|
23720
|
+
979,
|
|
23721
|
+
658,
|
|
23722
|
+
583,
|
|
23723
|
+
635,
|
|
23724
|
+
717,
|
|
23725
|
+
517,
|
|
23726
|
+
499,
|
|
23727
|
+
702,
|
|
23728
|
+
725,
|
|
23729
|
+
270,
|
|
23730
|
+
360,
|
|
23731
|
+
590,
|
|
23732
|
+
480,
|
|
23733
|
+
917,
|
|
23734
|
+
765,
|
|
23735
|
+
773,
|
|
23736
|
+
571,
|
|
23737
|
+
773,
|
|
23738
|
+
610,
|
|
23739
|
+
543,
|
|
23740
|
+
534,
|
|
23741
|
+
703,
|
|
23742
|
+
634,
|
|
23743
|
+
954,
|
|
23744
|
+
601,
|
|
23745
|
+
563,
|
|
23746
|
+
583,
|
|
23747
|
+
305,
|
|
23748
|
+
764,
|
|
23749
|
+
305,
|
|
23750
|
+
701,
|
|
23751
|
+
426,
|
|
23752
|
+
272,
|
|
23753
|
+
520,
|
|
23754
|
+
601,
|
|
23755
|
+
473,
|
|
23756
|
+
602,
|
|
23757
|
+
535,
|
|
23758
|
+
316,
|
|
23759
|
+
602,
|
|
23760
|
+
579,
|
|
23761
|
+
246,
|
|
23762
|
+
246,
|
|
23763
|
+
506,
|
|
23764
|
+
246,
|
|
23765
|
+
880,
|
|
23766
|
+
578,
|
|
23767
|
+
599,
|
|
23768
|
+
601,
|
|
23769
|
+
602,
|
|
23770
|
+
354,
|
|
23771
|
+
433,
|
|
23772
|
+
345,
|
|
23773
|
+
578,
|
|
23774
|
+
487,
|
|
23775
|
+
736,
|
|
23776
|
+
465,
|
|
23777
|
+
493,
|
|
23778
|
+
462,
|
|
23779
|
+
305,
|
|
23780
|
+
239,
|
|
23781
|
+
305,
|
|
23782
|
+
701
|
|
23783
|
+
],
|
|
23784
|
+
ex: {
|
|
23785
|
+
167: 458,
|
|
23786
|
+
176: 387,
|
|
23787
|
+
177: 701,
|
|
23788
|
+
180: 288,
|
|
23789
|
+
183: 219,
|
|
23790
|
+
215: 701,
|
|
23791
|
+
247: 701,
|
|
23792
|
+
8211: 513,
|
|
23793
|
+
8212: 1026,
|
|
23794
|
+
8216: 231,
|
|
23795
|
+
8217: 231,
|
|
23796
|
+
8218: 231,
|
|
23797
|
+
8220: 379,
|
|
23798
|
+
8221: 379,
|
|
23799
|
+
8222: 379,
|
|
23800
|
+
8224: 382,
|
|
23801
|
+
8225: 382,
|
|
23802
|
+
8226: 417,
|
|
23803
|
+
8229: 437,
|
|
23804
|
+
8230: 740,
|
|
23805
|
+
8240: 1238,
|
|
23806
|
+
8242: 231,
|
|
23807
|
+
8243: 379,
|
|
23808
|
+
8249: 322,
|
|
23809
|
+
8250: 322,
|
|
23810
|
+
8251: 800,
|
|
23811
|
+
8252: 578,
|
|
23812
|
+
8263: 920,
|
|
23813
|
+
8264: 749,
|
|
23814
|
+
8265: 749,
|
|
23815
|
+
8451: 950,
|
|
23816
|
+
8457: 950,
|
|
23817
|
+
8467: 332,
|
|
23818
|
+
8470: 1146,
|
|
23819
|
+
8481: 950,
|
|
23820
|
+
8482: 793,
|
|
23821
|
+
8486: 774,
|
|
23822
|
+
8491: 696,
|
|
23823
|
+
8531: 950,
|
|
23824
|
+
8532: 950,
|
|
23825
|
+
8539: 943,
|
|
23826
|
+
8540: 981,
|
|
23827
|
+
8541: 982,
|
|
23828
|
+
8542: 913,
|
|
23829
|
+
8544: 950,
|
|
23830
|
+
8545: 950,
|
|
23831
|
+
8546: 950,
|
|
23832
|
+
8547: 950,
|
|
23833
|
+
8548: 950,
|
|
23834
|
+
8549: 950,
|
|
23835
|
+
8550: 950,
|
|
23836
|
+
8551: 950,
|
|
23837
|
+
8552: 950,
|
|
23838
|
+
8553: 950,
|
|
23839
|
+
8560: 950,
|
|
23840
|
+
8561: 950,
|
|
23841
|
+
8562: 950,
|
|
23842
|
+
8563: 950,
|
|
23843
|
+
8564: 950,
|
|
23844
|
+
8565: 950,
|
|
23845
|
+
8566: 950,
|
|
23846
|
+
8567: 950,
|
|
23847
|
+
8568: 950,
|
|
23848
|
+
8569: 950,
|
|
23849
|
+
8592: 950,
|
|
23850
|
+
8593: 950,
|
|
23851
|
+
8594: 950,
|
|
23852
|
+
8595: 950,
|
|
23853
|
+
8596: 950,
|
|
23854
|
+
8597: 950,
|
|
23855
|
+
8598: 950,
|
|
23856
|
+
8599: 950,
|
|
23857
|
+
8600: 950,
|
|
23858
|
+
8601: 950,
|
|
23859
|
+
8658: 950,
|
|
23860
|
+
8660: 950,
|
|
23861
|
+
8704: 696,
|
|
23862
|
+
8706: 546,
|
|
23863
|
+
8707: 548,
|
|
23864
|
+
8711: 713,
|
|
23865
|
+
8712: 950,
|
|
23866
|
+
8715: 950,
|
|
23867
|
+
8719: 771,
|
|
23868
|
+
8721: 631,
|
|
23869
|
+
8729: 315,
|
|
23870
|
+
8730: 667,
|
|
23871
|
+
8733: 838,
|
|
23872
|
+
8734: 839,
|
|
23873
|
+
8736: 667,
|
|
23874
|
+
8741: 684,
|
|
23875
|
+
8743: 684,
|
|
23876
|
+
8744: 684,
|
|
23877
|
+
8745: 950,
|
|
23878
|
+
8746: 950,
|
|
23879
|
+
8747: 551,
|
|
23880
|
+
8748: 950,
|
|
23881
|
+
8750: 545,
|
|
23882
|
+
8756: 667,
|
|
23883
|
+
8757: 667,
|
|
23884
|
+
8764: 684,
|
|
23885
|
+
8765: 684,
|
|
23886
|
+
8786: 684,
|
|
23887
|
+
8800: 701,
|
|
23888
|
+
8801: 684,
|
|
23889
|
+
8804: 701,
|
|
23890
|
+
8805: 701,
|
|
23891
|
+
8810: 950,
|
|
23892
|
+
8811: 950,
|
|
23893
|
+
8834: 950,
|
|
23894
|
+
8835: 950,
|
|
23895
|
+
8838: 950,
|
|
23896
|
+
8839: 950,
|
|
23897
|
+
8857: 950,
|
|
23898
|
+
8869: 950,
|
|
23899
|
+
9676: 594,
|
|
23900
|
+
9792: 625,
|
|
23901
|
+
9794: 715,
|
|
23902
|
+
9833: 538,
|
|
23903
|
+
9834: 688,
|
|
23904
|
+
9836: 932,
|
|
23905
|
+
9837: 573,
|
|
23906
|
+
12296: 542,
|
|
23907
|
+
12297: 542,
|
|
23908
|
+
12298: 596,
|
|
23909
|
+
12299: 596,
|
|
23910
|
+
12300: 571,
|
|
23911
|
+
12301: 571,
|
|
23912
|
+
12302: 517,
|
|
23913
|
+
12303: 517,
|
|
23914
|
+
12304: 518,
|
|
23915
|
+
12305: 518,
|
|
23916
|
+
12308: 488,
|
|
23917
|
+
12309: 488,
|
|
23918
|
+
12334: 333,
|
|
23919
|
+
12335: 333
|
|
23920
|
+
}
|
|
23921
|
+
},
|
|
23922
|
+
"\uD568\uCD08\uB86C\uB3CB\uC6C0": {
|
|
23923
|
+
cjk: 970,
|
|
23924
|
+
ascii: [
|
|
23925
|
+
500,
|
|
23926
|
+
333,
|
|
23927
|
+
339,
|
|
23928
|
+
686,
|
|
23929
|
+
626,
|
|
23930
|
+
853,
|
|
23931
|
+
761,
|
|
23932
|
+
260,
|
|
23933
|
+
313,
|
|
23934
|
+
313,
|
|
23935
|
+
498,
|
|
23936
|
+
548,
|
|
23937
|
+
258,
|
|
23938
|
+
466,
|
|
23939
|
+
270,
|
|
23940
|
+
374,
|
|
23941
|
+
550,
|
|
23942
|
+
550,
|
|
23943
|
+
550,
|
|
23944
|
+
550,
|
|
23945
|
+
550,
|
|
23946
|
+
550,
|
|
23947
|
+
550,
|
|
23948
|
+
550,
|
|
23949
|
+
550,
|
|
23950
|
+
550,
|
|
23951
|
+
312,
|
|
23952
|
+
312,
|
|
23953
|
+
600,
|
|
23954
|
+
534,
|
|
23955
|
+
600,
|
|
23956
|
+
570,
|
|
23957
|
+
865,
|
|
23958
|
+
654,
|
|
23959
|
+
664,
|
|
23960
|
+
633,
|
|
23961
|
+
701,
|
|
23962
|
+
625,
|
|
23963
|
+
609,
|
|
23964
|
+
645,
|
|
23965
|
+
694,
|
|
23966
|
+
317,
|
|
23967
|
+
515,
|
|
23968
|
+
664,
|
|
23969
|
+
584,
|
|
23970
|
+
826,
|
|
23971
|
+
728,
|
|
23972
|
+
676,
|
|
23973
|
+
660,
|
|
23974
|
+
681,
|
|
23975
|
+
683,
|
|
23976
|
+
617,
|
|
23977
|
+
573,
|
|
23978
|
+
702,
|
|
23979
|
+
594,
|
|
23980
|
+
897,
|
|
23981
|
+
607,
|
|
23982
|
+
581,
|
|
23983
|
+
584,
|
|
23984
|
+
338,
|
|
23985
|
+
373,
|
|
23986
|
+
329,
|
|
23987
|
+
562,
|
|
23988
|
+
532,
|
|
23989
|
+
373,
|
|
23990
|
+
563,
|
|
23991
|
+
581,
|
|
23992
|
+
513,
|
|
23993
|
+
578,
|
|
23994
|
+
567,
|
|
23995
|
+
336,
|
|
23996
|
+
563,
|
|
23997
|
+
594,
|
|
23998
|
+
271,
|
|
23999
|
+
268,
|
|
24000
|
+
559,
|
|
24001
|
+
258,
|
|
24002
|
+
919,
|
|
24003
|
+
595,
|
|
24004
|
+
582,
|
|
24005
|
+
552,
|
|
24006
|
+
552,
|
|
24007
|
+
427,
|
|
24008
|
+
513,
|
|
24009
|
+
349,
|
|
24010
|
+
595,
|
|
24011
|
+
469,
|
|
24012
|
+
760,
|
|
24013
|
+
483,
|
|
24014
|
+
466,
|
|
24015
|
+
479,
|
|
24016
|
+
372,
|
|
24017
|
+
342,
|
|
24018
|
+
372,
|
|
24019
|
+
546
|
|
24020
|
+
],
|
|
24021
|
+
ex: {
|
|
24022
|
+
167: 486,
|
|
24023
|
+
176: 306,
|
|
24024
|
+
177: 782,
|
|
24025
|
+
180: 240,
|
|
24026
|
+
183: 294,
|
|
24027
|
+
215: 587,
|
|
24028
|
+
247: 670,
|
|
24029
|
+
8208: 237,
|
|
24030
|
+
8209: 300,
|
|
24031
|
+
8210: 398,
|
|
24032
|
+
8211: 348,
|
|
24033
|
+
8212: 522,
|
|
24034
|
+
8213: 672,
|
|
24035
|
+
8214: 368,
|
|
24036
|
+
8215: 419,
|
|
24037
|
+
8216: 288,
|
|
24038
|
+
8217: 288,
|
|
24039
|
+
8218: 288,
|
|
24040
|
+
8219: 288,
|
|
24041
|
+
8220: 451,
|
|
24042
|
+
8221: 453,
|
|
24043
|
+
8222: 451,
|
|
24044
|
+
8223: 488,
|
|
24045
|
+
8224: 518,
|
|
24046
|
+
8225: 448,
|
|
24047
|
+
8226: 586,
|
|
24048
|
+
8227: 590,
|
|
24049
|
+
8228: 288,
|
|
24050
|
+
8229: 544,
|
|
24051
|
+
8230: 702,
|
|
24052
|
+
8231: 288,
|
|
24053
|
+
8240: 892,
|
|
24054
|
+
8241: 956,
|
|
24055
|
+
8242: 304,
|
|
24056
|
+
8243: 488,
|
|
24057
|
+
8244: 550,
|
|
24058
|
+
8245: 304,
|
|
24059
|
+
8246: 488,
|
|
24060
|
+
8247: 544,
|
|
24061
|
+
8248: 494,
|
|
24062
|
+
8249: 448,
|
|
24063
|
+
8250: 448,
|
|
24064
|
+
8251: 690,
|
|
24065
|
+
8252: 502,
|
|
24066
|
+
8253: 556,
|
|
24067
|
+
8254: 348,
|
|
24068
|
+
8255: 941,
|
|
24069
|
+
8256: 941,
|
|
24070
|
+
8257: 517,
|
|
24071
|
+
8258: 764,
|
|
24072
|
+
8259: 681,
|
|
24073
|
+
8260: 359,
|
|
24074
|
+
8261: 343,
|
|
24075
|
+
8262: 343,
|
|
24076
|
+
8263: 930,
|
|
24077
|
+
8264: 688,
|
|
24078
|
+
8265: 712,
|
|
24079
|
+
8266: 549,
|
|
24080
|
+
8267: 543,
|
|
24081
|
+
8268: 573,
|
|
24082
|
+
8269: 573,
|
|
24083
|
+
8270: 551,
|
|
24084
|
+
8271: 297,
|
|
24085
|
+
8272: 941,
|
|
24086
|
+
8273: 436,
|
|
24087
|
+
8274: 610,
|
|
24088
|
+
8275: 523,
|
|
24089
|
+
8276: 941,
|
|
24090
|
+
8277: 468,
|
|
24091
|
+
8278: 595,
|
|
24092
|
+
8279: 625,
|
|
24093
|
+
8280: 690,
|
|
24094
|
+
8281: 690,
|
|
24095
|
+
8282: 494,
|
|
24096
|
+
8283: 630,
|
|
24097
|
+
8284: 678,
|
|
24098
|
+
8285: 494,
|
|
24099
|
+
8286: 494,
|
|
24100
|
+
8501: 520,
|
|
24101
|
+
8502: 526,
|
|
24102
|
+
8503: 320,
|
|
24103
|
+
8504: 471,
|
|
24104
|
+
9756: 1012,
|
|
24105
|
+
9758: 1012,
|
|
24106
|
+
12296: 500,
|
|
24107
|
+
12297: 500,
|
|
24108
|
+
12298: 500,
|
|
24109
|
+
12299: 500,
|
|
24110
|
+
12300: 500,
|
|
24111
|
+
12301: 500,
|
|
24112
|
+
12302: 500,
|
|
24113
|
+
12303: 500,
|
|
24114
|
+
12304: 500,
|
|
24115
|
+
12305: 500,
|
|
24116
|
+
12308: 500,
|
|
24117
|
+
12309: 500,
|
|
24118
|
+
12310: 500,
|
|
24119
|
+
12311: 500,
|
|
24120
|
+
12312: 500,
|
|
24121
|
+
12313: 500,
|
|
24122
|
+
12314: 500,
|
|
24123
|
+
12315: 500,
|
|
24124
|
+
12332: 246,
|
|
24125
|
+
12333: 246,
|
|
24126
|
+
12351: 485
|
|
24127
|
+
}
|
|
24128
|
+
}
|
|
24129
|
+
};
|
|
24130
|
+
function hasFontMetrics(face) {
|
|
24131
|
+
return !!face && Object.prototype.hasOwnProperty.call(FONTS, face.trim());
|
|
24132
|
+
}
|
|
24133
|
+
function fontAdvanceEm1000(face, cp) {
|
|
24134
|
+
const m = FONTS[face.trim()];
|
|
24135
|
+
if (!m) return null;
|
|
24136
|
+
if (cp >= 32 && cp <= 126) return m.ascii[cp - 32];
|
|
24137
|
+
return m.ex[cp] ?? m.cjk;
|
|
24138
|
+
}
|
|
24139
|
+
|
|
22839
24140
|
// src/hwpx/text-metrics.ts
|
|
22840
24141
|
var ASCII_W = [
|
|
22841
24142
|
300,
|
|
@@ -22995,11 +24296,13 @@ function charWidthEm1000(cp) {
|
|
|
22995
24296
|
var SPACE_EM_FIXED = 500;
|
|
22996
24297
|
var SPACE_EM_FONT = 300;
|
|
22997
24298
|
function faceClassOf(face) {
|
|
24299
|
+
if (face && hasFontMetrics(face)) return `font:${face.trim()}`;
|
|
22998
24300
|
return face && /^(굴림체|돋움체|바탕체|궁서체)$/.test(face.trim()) ? "fixedPitch" : "hcr";
|
|
22999
24301
|
}
|
|
23000
24302
|
function faceClassForGen(face) {
|
|
23001
24303
|
if (!face) return "hcr";
|
|
23002
24304
|
const f = face.trim();
|
|
24305
|
+
if (hasFontMetrics(f)) return `font:${f}`;
|
|
23003
24306
|
if (/^(굴림체|돋움체|바탕체|궁서체)$/.test(f)) return "fixedPitch";
|
|
23004
24307
|
if (/^(한컴돋움|맑은 고딕|HY견고딕|HY헤드라인M|HY중고딕|한양중고딕|나눔고딕|나눔스퀘어|돋움|굴림)$/.test(f)) return "gothic";
|
|
23005
24308
|
return "hcr";
|
|
@@ -23016,14 +24319,26 @@ function gothicWidthEm1000(cp) {
|
|
|
23016
24319
|
function fixedPitchWidthEm1000(cp) {
|
|
23017
24320
|
return cp < 128 ? 500 : 1e3;
|
|
23018
24321
|
}
|
|
24322
|
+
function widthFnOf(faceClass) {
|
|
24323
|
+
if (faceClass === "fixedPitch") return fixedPitchWidthEm1000;
|
|
24324
|
+
if (faceClass === "gothic") return gothicWidthEm1000;
|
|
24325
|
+
if (faceClass?.startsWith("font:")) {
|
|
24326
|
+
const face = faceClass.slice(5);
|
|
24327
|
+
return (cp) => fontAdvanceEm1000(face, cp) ?? gothicWidthEm1000(cp);
|
|
24328
|
+
}
|
|
24329
|
+
return charWidthEm1000;
|
|
24330
|
+
}
|
|
24331
|
+
function isSpaceCp(cp) {
|
|
24332
|
+
return cp === 32 || cp === 160;
|
|
24333
|
+
}
|
|
23019
24334
|
function measureTextWidth(text, height, ratioPct, opts) {
|
|
23020
24335
|
const spaceEm = opts?.spaceEm ?? SPACE_EM_FIXED;
|
|
23021
24336
|
const spacing = opts?.spacingPct ?? 0;
|
|
23022
|
-
const widthEm = opts?.faceClass
|
|
24337
|
+
const widthEm = widthFnOf(opts?.faceClass);
|
|
23023
24338
|
let em = 0;
|
|
23024
24339
|
for (const ch of text) {
|
|
23025
24340
|
const cp = ch.codePointAt(0);
|
|
23026
|
-
const w = cp
|
|
24341
|
+
const w = isSpaceCp(cp) ? spaceEm : widthEm(cp);
|
|
23027
24342
|
em += w * (1 + spacing / 100);
|
|
23028
24343
|
}
|
|
23029
24344
|
return em / 1e3 * height * (ratioPct / 100);
|
|
@@ -23034,16 +24349,24 @@ function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "kee
|
|
|
23034
24349
|
const EPS = 0.5;
|
|
23035
24350
|
const spaceEm = opts?.spaceEm ?? SPACE_EM_FIXED;
|
|
23036
24351
|
const spacing = opts?.spacingPct ?? 0;
|
|
23037
|
-
const widthEm = opts?.faceClass
|
|
24352
|
+
const widthEm = widthFnOf(opts?.faceClass);
|
|
23038
24353
|
const k = height * ratioPct / 100 / 1e3;
|
|
23039
|
-
const
|
|
23040
|
-
const
|
|
24354
|
+
const unitW = opts?.widths;
|
|
24355
|
+
const charWAt = (i, ch) => {
|
|
24356
|
+
if (unitW) return (unitW[i] ?? 0) + (ch.length === 2 ? unitW[i + 1] ?? 0 : 0);
|
|
24357
|
+
const cp = ch.codePointAt(0);
|
|
24358
|
+
return (isSpaceCp(cp) ? spaceEm : widthEm(cp)) * (1 + spacing / 100) * k;
|
|
24359
|
+
};
|
|
23041
24360
|
const rangeW = (from, to) => {
|
|
23042
24361
|
let w = 0;
|
|
23043
|
-
for (
|
|
24362
|
+
for (let i = from; i < to; ) {
|
|
24363
|
+
const ch = String.fromCodePoint(text.codePointAt(i));
|
|
24364
|
+
w += charWAt(i, ch);
|
|
24365
|
+
i += ch.length;
|
|
24366
|
+
}
|
|
23044
24367
|
return w;
|
|
23045
24368
|
};
|
|
23046
|
-
const units = text.match(mode === "keep" ? / +|[^ ]+/gu : / +|[^ ]
|
|
24369
|
+
const units = text.match(mode === "keep" ? / +|[^ ]+/gu : / +|(?:[\x21-\x7e]+|[^ ])(?:\u00a0(?:[\x21-\x7e]+|[^ \u00a0])?)*/gu) ?? [];
|
|
23047
24370
|
const starts = [0];
|
|
23048
24371
|
let lineW = 0;
|
|
23049
24372
|
let avail = firstWidth;
|
|
@@ -23061,7 +24384,7 @@ function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "kee
|
|
|
23061
24384
|
};
|
|
23062
24385
|
for (const u of units) {
|
|
23063
24386
|
if (u[0] === " ") {
|
|
23064
|
-
lineW +=
|
|
24387
|
+
lineW += rangeW(pos, pos + u.length);
|
|
23065
24388
|
pos += u.length;
|
|
23066
24389
|
continue;
|
|
23067
24390
|
}
|
|
@@ -23072,9 +24395,10 @@ function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "kee
|
|
|
23072
24395
|
continue;
|
|
23073
24396
|
}
|
|
23074
24397
|
if (lineW === 0 || w > contWidth + EPS) {
|
|
24398
|
+
if (mode === "keep" && lineW > 0) breakBefore(pos, 0);
|
|
23075
24399
|
let sub = 0;
|
|
23076
24400
|
for (const ch of u) {
|
|
23077
|
-
const c =
|
|
24401
|
+
const c = charWAt(pos + sub, ch);
|
|
23078
24402
|
if (lineW + c > avail + EPS && lineW > 0) breakBefore(pos + sub, 0);
|
|
23079
24403
|
lineW += c;
|
|
23080
24404
|
sub += ch.length;
|
|
@@ -23572,6 +24896,9 @@ function resolveTheme(theme) {
|
|
|
23572
24896
|
function escapeXml(text) {
|
|
23573
24897
|
return text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
23574
24898
|
}
|
|
24899
|
+
function escapeTextXml(text) {
|
|
24900
|
+
return escapeXml(text).replace(/\u00a0/g, "<hp:nbSpace/>");
|
|
24901
|
+
}
|
|
23575
24902
|
function headingParaPrId(level) {
|
|
23576
24903
|
if (level === 1) return PARA_H1;
|
|
23577
24904
|
if (level === 2) return PARA_H2;
|
|
@@ -23598,14 +24925,14 @@ function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_C
|
|
|
23598
24925
|
</hh:charPr>`;
|
|
23599
24926
|
}
|
|
23600
24927
|
function paraPr(id, opts = {}) {
|
|
23601
|
-
const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, right = 0, keepWord = false, keepWithNext = false, outlineLevel } = opts;
|
|
24928
|
+
const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, right = 0, keepWord = false, keepWithNext = false, outlineLevel, autoTab = false, widowOrphan = false } = opts;
|
|
23602
24929
|
const breakNonLatin = keepWord ? "BREAK_WORD" : "KEEP_WORD";
|
|
23603
24930
|
const snapGrid = keepWord ? "0" : "1";
|
|
23604
24931
|
const heading = outlineLevel !== void 0 ? `<hh:heading type="OUTLINE" idRef="0" level="${outlineLevel}"/>` : `<hh:heading type="NONE" idRef="0" level="0"/>`;
|
|
23605
|
-
return ` <hh:paraPr id="${id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="${snapGrid}" suppressLineNumbers="0" checked="0" textDir="AUTO">
|
|
24932
|
+
return ` <hh:paraPr id="${id}" tabPrIDRef="${autoTab ? 1 : 0}" condense="0" fontLineHeight="0" snapToGrid="${snapGrid}" suppressLineNumbers="0" checked="0" textDir="AUTO">
|
|
23606
24933
|
<hh:align horizontal="${align}" vertical="BASELINE"/>
|
|
23607
24934
|
${heading}
|
|
23608
|
-
<hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="${breakNonLatin}" widowOrphan="0" keepWithNext="${keepWithNext ? 1 : 0}" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
|
|
24935
|
+
<hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="${breakNonLatin}" widowOrphan="${widowOrphan ? 1 : 0}" keepWithNext="${keepWithNext ? 1 : 0}" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
|
|
23609
24936
|
<hh:autoSpacing eAsianEng="0" eAsianNum="0"/>
|
|
23610
24937
|
<hh:margin><hc:intent value="${indent}" unit="HWPUNIT"/><hc:left value="${left}" unit="HWPUNIT"/><hc:right value="${right}" unit="HWPUNIT"/><hc:prev value="${spaceBefore}" unit="HWPUNIT"/><hc:next value="${spaceAfter}" unit="HWPUNIT"/></hh:margin>
|
|
23611
24938
|
<hh:lineSpacing type="PERCENT" value="${lineSpacing}"/>
|
|
@@ -24064,7 +25391,7 @@ function generateRuns(text, defaultCharPr = CHAR_NORMAL, mapCharId) {
|
|
|
24064
25391
|
}
|
|
24065
25392
|
}
|
|
24066
25393
|
const charId = span.code || span.bold || span.italic ? spanToCharPrId(span) : defaultCharPr;
|
|
24067
|
-
out.push(`<hp:run charPrIDRef="${mapped(charId)}"><hp:t>${
|
|
25394
|
+
out.push(`<hp:run charPrIDRef="${mapped(charId)}"><hp:t>${escapeTextXml(span.text)}</hp:t></hp:run>`);
|
|
24068
25395
|
}
|
|
24069
25396
|
closeField();
|
|
24070
25397
|
return out.join("");
|
|
@@ -24291,7 +25618,7 @@ ${base2.join("\n")}
|
|
|
24291
25618
|
const ls = gongmun.lineSpacing;
|
|
24292
25619
|
const titleAlign = gongmun.centerTitle ? "CENTER" : "LEFT";
|
|
24293
25620
|
const h2MarkerWidth = markerWidth(gongmun.h2Marker === "box" ? "\u25A1" : "1.", 1600);
|
|
24294
|
-
const h2Geom = gongmun.h2Marker !== "none" ? { spaceBefore: Math.round(gongmun.bodyHeight * 2), spaceAfter: 0, indent: -h2MarkerWidth } : { spaceBefore: 600, spaceAfter: 150 };
|
|
25621
|
+
const h2Geom = gongmun.h2Marker !== "none" ? { spaceBefore: Math.round(gongmun.bodyHeight * 2), spaceAfter: 0, indent: -h2MarkerWidth, autoTab: true } : { spaceBefore: 600, spaceAfter: 150 };
|
|
24295
25622
|
const h3Left = gongmun.h2Marker !== "none" ? h2MarkerWidth : 0;
|
|
24296
25623
|
const base = [
|
|
24297
25624
|
paraPr(0, { lineSpacing: ls, keepWord: true }),
|
|
@@ -24311,7 +25638,7 @@ ${base2.join("\n")}
|
|
|
24311
25638
|
const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset), levelMarkerHeight(gongmun, d));
|
|
24312
25639
|
const sectionGap = gongmun.numbering === "gaejosik" || gongmun.numbering === "report" ? gaejosikSpaceBefore(d, gongmun.bodyHeight) : 0;
|
|
24313
25640
|
const keepNext = (gongmun.numbering === "gaejosik" || gongmun.numbering === "report") && d === 0;
|
|
24314
|
-
base.push(paraPr(GONGMUN_LIST_BASE + d, { align: listAlign, lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext }));
|
|
25641
|
+
base.push(paraPr(GONGMUN_LIST_BASE + d, { align: listAlign, lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext, autoTab: true }));
|
|
24315
25642
|
}
|
|
24316
25643
|
base.push(paraPr(GONGMUN_CENTER, { align: "CENTER", lineSpacing: ls, keepWord: true }));
|
|
24317
25644
|
base.push(paraPr(GONGMUN_RIGHT, { align: "RIGHT", lineSpacing: ls, keepWord: true }));
|
|
@@ -24321,7 +25648,7 @@ ${base2.join("\n")}
|
|
|
24321
25648
|
const cham = gaejosikChamIndent(gongmun.bodyHeight, gongmun.sizes);
|
|
24322
25649
|
const toc = gaejosikTocItemIndent(gongmun.bodyHeight, gongmun.sizes);
|
|
24323
25650
|
base.push(
|
|
24324
|
-
paraPr(GJ_PARA_CHAM, { align: "LEFT", lineSpacing: ls, left: cham.left, indent: cham.indent, spaceBefore: gaejosikSpaceBefore(3, gongmun.bodyHeight), keepWord: true }),
|
|
25651
|
+
paraPr(GJ_PARA_CHAM, { align: "LEFT", lineSpacing: ls, left: cham.left, indent: cham.indent, spaceBefore: gaejosikSpaceBefore(3, gongmun.bodyHeight), keepWord: true, autoTab: true }),
|
|
24325
25652
|
paraPr(GJ_PARA_COVER, { align: "CENTER", lineSpacing: 130, keepWord: true }),
|
|
24326
25653
|
paraPr(GJ_PARA_TOC_ITEM, { align: "LEFT", lineSpacing: 160, left: toc.left, indent: toc.indent, spaceBefore: 1800, keepWord: true }),
|
|
24327
25654
|
// 장 헤더는 다음 문단과 같은 쪽에 — 쪽 하단 고아 헤더 방지 (실렌더 확인 이슈)
|
|
@@ -24342,7 +25669,7 @@ ${base2.join("\n")}
|
|
|
24342
25669
|
const { left } = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset));
|
|
24343
25670
|
const sectionGap = gongmun.numbering === "gaejosik" || gongmun.numbering === "report" ? gaejosikSpaceBefore(depth, gongmun.bodyHeight) : 0;
|
|
24344
25671
|
const keepNext = (gongmun.numbering === "gaejosik" || gongmun.numbering === "report") && depth === 0;
|
|
24345
|
-
base.push(paraPr(GONGMUN_LIST_VARIANT_BASE + vi, { align: listAlign, lineSpacing: ls, left, indent: -widthHu, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext }));
|
|
25672
|
+
base.push(paraPr(GONGMUN_LIST_VARIANT_BASE + vi, { align: listAlign, lineSpacing: ls, left, indent: -widthHu, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext, autoTab: true }));
|
|
24346
25673
|
}
|
|
24347
25674
|
assertSequentialIds(base, "paraPr", 0);
|
|
24348
25675
|
return `<hh:paraProperties itemCnt="${base.length}">
|
|
@@ -24475,6 +25802,10 @@ function buildStyles(gongmun) {
|
|
|
24475
25802
|
${items.join("\n ")}
|
|
24476
25803
|
</hh:styles>`;
|
|
24477
25804
|
}
|
|
25805
|
+
var TAB_PROPS_GONGMUN = `<hh:tabProperties itemCnt="2">
|
|
25806
|
+
<hh:tabPr id="0" autoTabLeft="0" autoTabRight="0"/>
|
|
25807
|
+
<hh:tabPr id="1" autoTabLeft="1" autoTabRight="0"/>
|
|
25808
|
+
</hh:tabProperties>`;
|
|
24478
25809
|
function generateHeaderXml(theme, gongmun, ratioVariants = [], extraBorderFills = [], extraCharPrXmls = [], listIndentVariants = [], extraFonts = [], v5 = null) {
|
|
24479
25810
|
const bodyFace = v5?.bodyFace ?? gongmun?.fonts.body ?? (gongmun?.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD568\uCD08\uB86C\uBC14\uD0D5");
|
|
24480
25811
|
const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants, extraCharPrXmls, !!v5);
|
|
@@ -24486,7 +25817,7 @@ function generateHeaderXml(theme, gongmun, ratioVariants = [], extraBorderFills
|
|
|
24486
25817
|
${buildFontFaces(gongmun, bodyFace, extraFonts, !!v5)}
|
|
24487
25818
|
${buildBorderFills(gongmun, extraBorderFills, !!v5)}
|
|
24488
25819
|
${charPropsXml}
|
|
24489
|
-
|
|
25820
|
+
${v5 || gongmun ? TAB_PROPS_GONGMUN : `<hh:tabProperties itemCnt="0"/>`}
|
|
24490
25821
|
${buildNumberings()}
|
|
24491
25822
|
<hh:bullets itemCnt="0"/>
|
|
24492
25823
|
${paraPropsXml}
|
|
@@ -24882,7 +26213,7 @@ function buildGaejosikCover(title, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH) {
|
|
|
24882
26213
|
const sz = gaejosikSizes(gongmun.bodyHeight, gongmun.sizes);
|
|
24883
26214
|
const innerW = g.totalW - 282;
|
|
24884
26215
|
const titleCharPr = simulateWrap(title, innerW, innerW, sz.coverTitle, 100, "keep").lines > 2 ? GJ_CHAR_COVER_SUB : GJ_CHAR_COVER_TITLE;
|
|
24885
|
-
const titlePara = `<hp:p paraPrIDRef="${GJ_PARA_COVER}" styleIDRef="0"><hp:run charPrIDRef="${titleCharPr}"><hp:t>${
|
|
26216
|
+
const titlePara = `<hp:p paraPrIDRef="${GJ_PARA_COVER}" styleIDRef="0"><hp:run charPrIDRef="${titleCharPr}"><hp:t>${escapeTextXml(title)}</hp:t></hp:run></hp:p>`;
|
|
24886
26217
|
const barEmpty = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR);
|
|
24887
26218
|
const topRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, colSpan: 2, row: 0, w: g.topDarkW, h: g.barH, paras: barEmpty }) + cell({ bf: GJ_BF_BAR_LIGHT, col: 2, row: 0, w: g.topLightW, h: g.barH, paras: barEmpty });
|
|
24888
26219
|
const titleRow = cell({ bf: 1, col: 0, colSpan: 3, row: 1, w: g.totalW, h: g.titleH, paras: titlePara, name: "__kordoc_h1" });
|
|
@@ -24891,7 +26222,7 @@ function buildGaejosikCover(title, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH) {
|
|
|
24891
26222
|
const host2 = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${tbl2}</hp:run></hp:p>`;
|
|
24892
26223
|
const date = gongmun.cover?.date ?? formatGaejosikDate(/* @__PURE__ */ new Date());
|
|
24893
26224
|
const org = gongmun.cover?.org ?? "";
|
|
24894
|
-
const sub = (t) => `<hp:p paraPrIDRef="${GJ_PARA_COVER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_COVER_SUB}"><hp:t>${
|
|
26225
|
+
const sub = (t) => `<hp:p paraPrIDRef="${GJ_PARA_COVER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_COVER_SUB}"><hp:t>${escapeTextXml(t)}</hp:t></hp:run></hp:p>`;
|
|
24895
26226
|
const subEmpty = emptyPara(GJ_PARA_COVER, false, GJ_CHAR_COVER_SUB);
|
|
24896
26227
|
return [
|
|
24897
26228
|
...Array(5).fill(emptyPara()),
|
|
@@ -24916,7 +26247,7 @@ function buildGaejosikToc(chapters, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH) {
|
|
|
24916
26247
|
const boxW = Math.round(TOC_GEOM.boxW * bodyWidth / GAEJOSIK_BASE_WIDTH);
|
|
24917
26248
|
const label = buildTocBanner(gongmun, bodyWidth);
|
|
24918
26249
|
const items = chapters.map(
|
|
24919
|
-
(title, i) => `<hp:p paraPrIDRef="${GJ_PARA_TOC_ITEM}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_TOC_ROMAN}"><hp:t>${chapterRoman(i + 1)}</hp:t></hp:run><hp:run charPrIDRef="${GJ_CHAR_TOC_ITEM}"><hp:t>. ${
|
|
26250
|
+
(title, i) => `<hp:p paraPrIDRef="${GJ_PARA_TOC_ITEM}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_TOC_ROMAN}"><hp:t>${chapterRoman(i + 1)}</hp:t></hp:run><hp:run charPrIDRef="${GJ_CHAR_TOC_ITEM}"><hp:t>. ${escapeTextXml(title)}</hp:t></hp:run></hp:p>`
|
|
24920
26251
|
).join("");
|
|
24921
26252
|
const box = table(
|
|
24922
26253
|
[cell({ bf: GJ_BF_TOC_BOX, col: 0, w: boxW, h: TOC_GEOM.boxH, paras: items, name: "__kordoc_toc" })],
|
|
@@ -24933,7 +26264,7 @@ function buildGaejosikBodyTitle(title, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH)
|
|
|
24933
26264
|
const g = coverGeom(gongmun.bodyHeight, gongmun.sizes, bodyWidth);
|
|
24934
26265
|
const bt = bodyTitleGeom(gongmun.bodyHeight, gongmun.sizes);
|
|
24935
26266
|
const barEmpty = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR);
|
|
24936
|
-
const titlePara = `<hp:p paraPrIDRef="${GONGMUN_CENTER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_BODY_TITLE}"><hp:t>${
|
|
26267
|
+
const titlePara = `<hp:p paraPrIDRef="${GONGMUN_CENTER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_BODY_TITLE}"><hp:t>${escapeTextXml(title)}</hp:t></hp:run></hp:p>`;
|
|
24937
26268
|
const topRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, colSpan: 2, row: 0, w: g.topDarkW, h: bt.barH, paras: barEmpty }) + cell({ bf: GJ_BF_BAR_LIGHT, col: 2, row: 0, w: g.topLightW, h: bt.barH, paras: barEmpty });
|
|
24938
26269
|
const titleRow = cell({ bf: 1, col: 0, colSpan: 3, row: 1, w: g.totalW, h: bt.titleH, paras: titlePara, name: "__kordoc_skip" });
|
|
24939
26270
|
const botRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, row: 2, w: g.botDarkW, h: bt.barH, paras: barEmpty }) + cell({ bf: GJ_BF_BAR_LIGHT, col: 1, colSpan: 2, row: 2, w: g.botLightW, h: bt.barH, paras: barEmpty });
|
|
@@ -24943,7 +26274,7 @@ function buildGaejosikBodyTitle(title, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH)
|
|
|
24943
26274
|
function buildGaejosikChapter(n, title, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH, srcLevel = 2) {
|
|
24944
26275
|
const g = gongmun ? chapterGeom(gongmun.bodyHeight, gongmun.sizes, bodyWidth) : chapterGeom(1500, {}, bodyWidth);
|
|
24945
26276
|
const numPara = `<hp:p paraPrIDRef="${GONGMUN_CENTER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_CHAPTER_NUM}"><hp:t>${chapterRoman(n)}</hp:t></hp:run></hp:p>`;
|
|
24946
|
-
const titlePara = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_CHAPTER_TITLE}"><hp:t> ${
|
|
26277
|
+
const titlePara = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_CHAPTER_TITLE}"><hp:t> ${escapeTextXml(title)}</hp:t></hp:run></hp:p>`;
|
|
24947
26278
|
const row = cell({ bf: GJ_BF_CHAPTER_NUM, col: 0, w: g.numW, h: g.rowH, paras: numPara }) + cell({ bf: GJ_BF_CHAPTER_GAP, col: 1, w: g.gapW, h: g.rowH }) + cell({ bf: GJ_BF_CHAPTER_TITLE, col: 2, w: g.titleW, h: g.rowH, paras: titlePara, name: `__kordoc_h${Math.min(Math.max(srcLevel, 1), 6)}` });
|
|
24948
26279
|
const tbl2 = table([row], g.numW + g.gapW + g.titleW, g.rowH, 3, 1, bodyWidth);
|
|
24949
26280
|
return `<hp:p paraPrIDRef="${GJ_PARA_CHAPTER}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${tbl2}</hp:run></hp:p>`;
|
|
@@ -25910,7 +27241,7 @@ function cellContentWidth(text, charHeight) {
|
|
|
25910
27241
|
function cellMinWordWidth(text, charHeight) {
|
|
25911
27242
|
let max = 0;
|
|
25912
27243
|
for (const seg of text.replace(/!\[[^\]]*\]\([^)\s]+\)/g, "").replace(/\*\*|__|`/g, "").split(/<br\s*\/?>/i)) {
|
|
25913
|
-
for (const word of seg.trim().split(
|
|
27244
|
+
for (const word of seg.trim().split(/[ \t]+/)) {
|
|
25914
27245
|
const w = measureTextWidth(word, charHeight, 100, { faceClass: curFace });
|
|
25915
27246
|
if (w > max) max = w;
|
|
25916
27247
|
}
|
|
@@ -25928,7 +27259,10 @@ function colRoles(headers) {
|
|
|
25928
27259
|
if (roles.length >= 3 && roles.includes("content") && roles[last] === null) roles[last] = "remark";
|
|
25929
27260
|
return roles;
|
|
25930
27261
|
}
|
|
25931
|
-
function
|
|
27262
|
+
function colSlack(faceClass) {
|
|
27263
|
+
return faceClass.startsWith("font:") ? 1.03 : 1.12;
|
|
27264
|
+
}
|
|
27265
|
+
function computeColWidths(colMax, totalWidth, colMinWord = [], roles = [], slack = 1.12) {
|
|
25932
27266
|
const colCnt = colMax.length;
|
|
25933
27267
|
const minW = Math.min(Math.max(2e3, Math.round(totalWidth * 0.06)), Math.floor(totalWidth / colCnt));
|
|
25934
27268
|
const cap = Math.round(totalWidth * 0.8);
|
|
@@ -25942,7 +27276,7 @@ function computeColWidths(colMax, totalWidth, colMinWord = [], roles = []) {
|
|
|
25942
27276
|
let sumFloorFree = floor.reduce((a, b) => a + b, 0);
|
|
25943
27277
|
for (const i of [...raw.keys()].sort((a, b) => raw[a] - raw[b])) {
|
|
25944
27278
|
if (free.size <= 1) break;
|
|
25945
|
-
const fixed = roles[i] === "remark" ? Math.min(Math.round(raw[i] *
|
|
27279
|
+
const fixed = roles[i] === "remark" ? Math.min(Math.round(raw[i] * slack), capOf[i]) : Math.round(raw[i] * slack);
|
|
25946
27280
|
if (budget - fixed < sumFloorFree - floor[i]) break;
|
|
25947
27281
|
widths[i] = fixed;
|
|
25948
27282
|
free.delete(i);
|
|
@@ -26015,7 +27349,7 @@ function requiredTableWidth(rows, charHeight, faceClass = "hcr") {
|
|
|
26015
27349
|
if (w > colMax[c]) colMax[c] = w;
|
|
26016
27350
|
});
|
|
26017
27351
|
curFace = prev;
|
|
26018
|
-
return colMax.reduce((a, w) => a + Math.round((w + CELL_PAD) *
|
|
27352
|
+
return colMax.reduce((a, w) => a + Math.round((w + CELL_PAD) * colSlack(faceClass)), 0);
|
|
26019
27353
|
}
|
|
26020
27354
|
function generateTable(rows, theme, style = null, remap = null, seq = 0, images = null) {
|
|
26021
27355
|
curFace = style?.faceClass ?? "hcr";
|
|
@@ -26037,7 +27371,7 @@ function generateTable(rows, theme, style = null, remap = null, seq = 0, images
|
|
|
26037
27371
|
if (mw > colMinWord[c]) colMinWord[c] = mw;
|
|
26038
27372
|
}));
|
|
26039
27373
|
const roles = style ? colRoles(rows[0] ?? []) : [];
|
|
26040
|
-
const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalW, colMinWord, roles);
|
|
27374
|
+
const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalW, colMinWord, roles, colSlack(curFace));
|
|
26041
27375
|
const colCentered = colWidths.map((w, c) => roles[c] !== "content" && colMaxBody[c] + CELL_PAD <= w);
|
|
26042
27376
|
const labelCol0 = !!reg && colCnt === 2 && colCentered[0] && rows.every((r) => (r[0] ?? "").replace(/\*\*|__|`/g, "").length <= 12);
|
|
26043
27377
|
const tblId = nextTableId();
|
|
@@ -26137,6 +27471,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
|
|
|
26137
27471
|
const { placed, rowCnt, colCnt } = layoutHtmlRows(rows);
|
|
26138
27472
|
if (rowCnt === 0 || colCnt === 0) return null;
|
|
26139
27473
|
const measureH = style?.charHeight ?? 1e3;
|
|
27474
|
+
curFace = style?.faceClass ?? "hcr";
|
|
26140
27475
|
const first = placed.find((p) => p.r === 0 && p.c === 0) ?? placed[0];
|
|
26141
27476
|
const row0 = Array.from({ length: colCnt }, () => "");
|
|
26142
27477
|
for (const cell2 of placed) {
|
|
@@ -26149,7 +27484,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
|
|
|
26149
27484
|
const cellParsed = placed.map((cell2) => htmlCellInnerToLines(cell2.inner));
|
|
26150
27485
|
const cellLines = cellParsed.map((p) => p.lines);
|
|
26151
27486
|
placed.forEach((cell2, i) => {
|
|
26152
|
-
const w = Math.max(...cellLines[i].map((l) => measureTextWidth(unescapeHtml(l).trim(), measureH, 100)), 0) / cell2.colSpan;
|
|
27487
|
+
const w = Math.max(...cellLines[i].map((l) => measureTextWidth(unescapeHtml(l).trim(), measureH, 100, { faceClass: curFace })), 0) / cell2.colSpan;
|
|
26153
27488
|
const mw = cell2.colSpan === 1 ? Math.max(...cellLines[i].map((l) => cellMinWordWidth(unescapeHtml(l), measureH)), 0) : 0;
|
|
26154
27489
|
for (let dc = 0; dc < cell2.colSpan; dc++) {
|
|
26155
27490
|
const c = cell2.c + dc;
|
|
@@ -26161,7 +27496,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
|
|
|
26161
27496
|
const headers = Array.from({ length: colCnt }, () => "");
|
|
26162
27497
|
for (const [i, cell2] of placed.entries()) if (cell2.r === 0 && cell2.c < colCnt) headers[cell2.c] = unescapeHtml(cellLines[i].join(" "));
|
|
26163
27498
|
const roles = style ? colRoles(headers) : [];
|
|
26164
|
-
const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalWidth, colMinWord, roles);
|
|
27499
|
+
const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalWidth, colMinWord, roles, colSlack(curFace));
|
|
26165
27500
|
const colCentered = colWidths.map((w, c) => roles[c] !== "content" && colMaxBody[c] + CELL_PAD <= w);
|
|
26166
27501
|
const cellH = style ? Math.round(measureH * 1.6) + 282 : 1500;
|
|
26167
27502
|
const tblW = colWidths.reduce((a, b) => a + b, 0);
|
|
@@ -26190,7 +27525,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
|
|
|
26190
27525
|
const segLines = segTexts.map((t) => htmlCellInnerToLines(t).lines);
|
|
26191
27526
|
const usable = Math.max(spanW(cell2) - CELL_PAD, 1e3);
|
|
26192
27527
|
let wrapLines = 0;
|
|
26193
|
-
for (const line of lines) wrapLines += Math.max(1, Math.ceil(measureTextWidth(unescapeHtml(line).trim(), measureH, 100) / usable));
|
|
27528
|
+
for (const line of lines) wrapLines += Math.max(1, Math.ceil(measureTextWidth(unescapeHtml(line).trim(), measureH, 100, { faceClass: curFace }) / usable));
|
|
26194
27529
|
const lineH = style ? Math.round(measureH * 1.6) : 800;
|
|
26195
27530
|
const contentH = Math.max(cellH * rowSpan, Math.max(wrapLines, 1) * lineH + nestedH);
|
|
26196
27531
|
const cellHeight = Math.max(prof?.cellH.get(`${cell2.r},${cell2.c}`) ?? 0, contentH);
|
|
@@ -26219,7 +27554,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
|
|
|
26219
27554
|
}
|
|
26220
27555
|
}
|
|
26221
27556
|
if (!images || text.trim() || picUrls.length === 0) {
|
|
26222
|
-
paras.push(`<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${
|
|
27557
|
+
paras.push(`<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${escapeTextXml(text)}</hp:t></hp:run></hp:p>`);
|
|
26223
27558
|
}
|
|
26224
27559
|
};
|
|
26225
27560
|
segLines.forEach((seg, si) => {
|
|
@@ -26278,7 +27613,7 @@ function tc(opts) {
|
|
|
26278
27613
|
return `<hp:tc name="${opts.name ?? ""}" header="0" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="${opts.bf}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="${opts.vAlign ?? "CENTER"}" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${opts.paras}</hp:subList><hp:cellAddr colAddr="${opts.col}" rowAddr="${opts.row}"/><hp:cellSpan colSpan="${opts.colSpan ?? 1}" rowSpan="${opts.rowSpan ?? 1}"/><hp:cellSz width="${opts.w}" height="${opts.h}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
|
|
26279
27614
|
}
|
|
26280
27615
|
function para(text, paraPrId, charPrId) {
|
|
26281
|
-
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${
|
|
27616
|
+
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${escapeTextXml(text)}</hp:t></hp:run></hp:p>`;
|
|
26282
27617
|
}
|
|
26283
27618
|
var APPROVAL_COL_W = 7085;
|
|
26284
27619
|
var APPROVAL_LABEL_H = 1300;
|
|
@@ -26854,6 +28189,16 @@ function buildPreamble(blocks, ctx) {
|
|
|
26854
28189
|
ctx.paraXmls.push(...preamble);
|
|
26855
28190
|
}
|
|
26856
28191
|
}
|
|
28192
|
+
function markedParagraph(marker, content, paraPrId, charPrId, halfEm, mapCharId, styleId = 0) {
|
|
28193
|
+
const cid4 = mapCharId ? mapCharId(charPrId) : charPrId;
|
|
28194
|
+
const run = `<hp:run charPrIDRef="${cid4}"><hp:t>${escapeTextXml(marker)}<hp:tab width="${Math.round(halfEm)}" leader="0" type="1"/></hp:t></hp:run>`;
|
|
28195
|
+
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="${styleId}">${run}${generateRuns(content, charPrId, mapCharId)}</hp:p>`;
|
|
28196
|
+
}
|
|
28197
|
+
function refParagraph(text, ctx) {
|
|
28198
|
+
const m = /^(※|\*(?=\s))\s*/.exec(text);
|
|
28199
|
+
const [mk, rest] = m ? [m[1], text.slice(m[0].length)] : ["\u203B", text];
|
|
28200
|
+
return markedParagraph(mk, rest, GJ_PARA_CHAM, GJ_CHAR_CHAM, ctx.gongmun.bodyHeight / 2, ctx.chamMap);
|
|
28201
|
+
}
|
|
26857
28202
|
function renderHeading(block, blockIdx, ctx) {
|
|
26858
28203
|
const { gongmun, dfIds, tableStyle, bfReg, measured, richAssets, gjBodyW } = ctx;
|
|
26859
28204
|
if (gongmun && blockIdx === ctx.coverH1Idx) return "";
|
|
@@ -26880,24 +28225,27 @@ function renderHeading(block, blockIdx, ctx) {
|
|
|
26880
28225
|
ctx.chapterNo = no >= 0 ? no + 1 : ctx.chapterNo + 1;
|
|
26881
28226
|
return buildGaejosikChapter(ctx.chapterNo, stripChapterNumber(block.text || ""), gongmun, gjBodyW, lvl);
|
|
26882
28227
|
} else if (lvl === 3) {
|
|
26883
|
-
return
|
|
26884
|
-
|
|
28228
|
+
return markedParagraph(
|
|
28229
|
+
"\u25A1",
|
|
28230
|
+
block.text || "",
|
|
26885
28231
|
GONGMUN_LIST_BASE,
|
|
26886
28232
|
GJ_CHAR_DAE,
|
|
28233
|
+
gongmun.bodyHeight / 2,
|
|
26887
28234
|
(id) => id === CHAR_BOLD ? GJ_CHAR_DAE_BOLD : id
|
|
26888
28235
|
);
|
|
26889
28236
|
}
|
|
26890
|
-
return
|
|
28237
|
+
return markedParagraph(gongmun.bullet2, block.text || "", GONGMUN_LIST_BASE + 1, CHAR_NORMAL, gongmun.bodyHeight / 2);
|
|
26891
28238
|
}
|
|
26892
28239
|
const pId = headingParaPrId(block.level || 1);
|
|
26893
28240
|
const cId = headingCharPrId(block.level || 1);
|
|
26894
28241
|
const styleId = gongmun ? Math.min(block.level || 1, 4) : 0;
|
|
26895
|
-
let hText = block.text || "";
|
|
26896
28242
|
if (gongmun && (block.level || 1) === 2 && gongmun.h2Marker !== "none") {
|
|
26897
|
-
const title = stripChapterNumber(
|
|
26898
|
-
|
|
28243
|
+
const title = stripChapterNumber(block.text || "");
|
|
28244
|
+
const mk = gongmun.h2Marker === "box" ? "\u25A1" : `${++ctx.h2Seq}.`;
|
|
28245
|
+
if (mk.length > 2) return generateParagraph(`${mk} ${title}`, pId, cId, void 0, styleId);
|
|
28246
|
+
return markedParagraph(mk, title, pId, cId, gongmun.bodyHeight / 2, void 0, styleId);
|
|
26899
28247
|
}
|
|
26900
|
-
return generateParagraph(
|
|
28248
|
+
return generateParagraph(block.text || "", pId, cId, void 0, styleId);
|
|
26901
28249
|
}
|
|
26902
28250
|
function renderParagraph(block, blockIdx, ctx) {
|
|
26903
28251
|
const { gongmun, measured, fit, vBase } = ctx;
|
|
@@ -26915,7 +28263,7 @@ function renderParagraph(block, blockIdx, ctx) {
|
|
|
26915
28263
|
}
|
|
26916
28264
|
const pTrim = (block.text || "").trimStart();
|
|
26917
28265
|
if (measured && (pTrim.startsWith("\u203B") || /^\*\s/.test(pTrim))) {
|
|
26918
|
-
return
|
|
28266
|
+
return refParagraph((block.text || "").trim(), ctx);
|
|
26919
28267
|
}
|
|
26920
28268
|
const ctr = gongmun && /^<center>([\s\S]*)<\/center>$/i.exec((block.text || "").trim());
|
|
26921
28269
|
const rgt = gongmun && /^<right>([\s\S]*)<\/right>$/i.exec((block.text || "").trim());
|
|
@@ -26954,7 +28302,7 @@ function renderEquation(block, blockIdx, ctx) {
|
|
|
26954
28302
|
function renderBlockquote(block, ctx) {
|
|
26955
28303
|
if (ctx.measured) {
|
|
26956
28304
|
const t = (block.text || "").replace(/\n+/g, " ").trim();
|
|
26957
|
-
return t ?
|
|
28305
|
+
return t ? refParagraph(t, ctx) : "";
|
|
26958
28306
|
}
|
|
26959
28307
|
const quoteChar = ctx.theme.hasQuoteOption ? CHAR_QUOTE : CHAR_NORMAL;
|
|
26960
28308
|
return (block.text || "").split("\n").map((line) => generateParagraph(line, PARA_QUOTE, quoteChar)).join("\n ");
|
|
@@ -26967,12 +28315,11 @@ function renderListItem(block, blockIdx, ctx) {
|
|
|
26967
28315
|
const marker2 = info?.marker ?? "";
|
|
26968
28316
|
const content = block.text || "";
|
|
26969
28317
|
if (measured && content.trimStart().startsWith("\u203B")) {
|
|
26970
|
-
return
|
|
28318
|
+
return refParagraph(content.trim(), ctx);
|
|
26971
28319
|
}
|
|
26972
28320
|
if (measured && block.marker === "*") {
|
|
26973
|
-
return
|
|
28321
|
+
return refParagraph(`* ${content.trim()}`, ctx);
|
|
26974
28322
|
}
|
|
26975
|
-
const text = marker2 ? `${marker2} ${content}` : content;
|
|
26976
28323
|
const listParaPr = marker2 ? info?.indentVariant !== void 0 ? GONGMUN_LIST_VARIANT_BASE + info.indentVariant : GONGMUN_LIST_BASE + depth : GONGMUN_LIST_PLAIN_BASE + depth;
|
|
26977
28324
|
let listCharPr = gongmun.numbering === "report" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL;
|
|
26978
28325
|
let mapId = fit ? variantMapper(fit, blockIdx, vBase) : void 0;
|
|
@@ -26992,7 +28339,7 @@ function renderListItem(block, blockIdx, ctx) {
|
|
|
26992
28339
|
listCharPr = lv.normal;
|
|
26993
28340
|
mapId = (id) => id === CHAR_BOLD ? lv.bold : id === CHAR_NORMAL ? lv.normal : id;
|
|
26994
28341
|
}
|
|
26995
|
-
return generateParagraph(
|
|
28342
|
+
return marker2 ? markedParagraph(marker2, content, listParaPr, listCharPr, gongmun.bodyHeight / 2, mapId) : generateParagraph(content, listParaPr, listCharPr, mapId);
|
|
26996
28343
|
}
|
|
26997
28344
|
const indent = block.indent || 0;
|
|
26998
28345
|
let marker;
|
|
@@ -27249,7 +28596,7 @@ var StyleRegistry = class {
|
|
|
27249
28596
|
return id;
|
|
27250
28597
|
}
|
|
27251
28598
|
para(spec) {
|
|
27252
|
-
const key = `${spec.align ?? "JUSTIFY"}|${spec.left ?? 0}|${spec.right ?? 0}|${spec.indent ?? 0}|${spec.before ?? 0}|${spec.after ?? 0}|${spec.lineSp ?? 160}|${spec.keepWithNext ? 1 : 0}|${spec.keepWord === false ? 0 : 1}`;
|
|
28599
|
+
const key = `${spec.align ?? "JUSTIFY"}|${spec.left ?? 0}|${spec.right ?? 0}|${spec.indent ?? 0}|${spec.before ?? 0}|${spec.after ?? 0}|${spec.lineSp ?? 160}|${spec.keepWithNext ? 1 : 0}|${spec.keepWord === false ? 0 : 1}|${spec.autoTab ? 1 : 0}|${spec.widowOrphan ? 1 : 0}`;
|
|
27253
28600
|
const hit = this.paras.get(key);
|
|
27254
28601
|
if (hit !== void 0) return hit;
|
|
27255
28602
|
const id = this.paraBase + this.paraXmls.length;
|
|
@@ -27262,7 +28609,9 @@ var StyleRegistry = class {
|
|
|
27262
28609
|
spaceAfter: spec.after ?? 0,
|
|
27263
28610
|
lineSpacing: spec.lineSp ?? 160,
|
|
27264
28611
|
keepWithNext: !!spec.keepWithNext,
|
|
27265
|
-
keepWord: spec.keepWord !== false
|
|
28612
|
+
keepWord: spec.keepWord !== false,
|
|
28613
|
+
autoTab: !!spec.autoTab,
|
|
28614
|
+
widowOrphan: !!spec.widowOrphan
|
|
27266
28615
|
}));
|
|
27267
28616
|
this.paras.set(key, id);
|
|
27268
28617
|
return id;
|
|
@@ -27416,11 +28765,6 @@ function applySchemeOverrides(s, g) {
|
|
|
27416
28765
|
function taHu(pt2) {
|
|
27417
28766
|
return Math.round(pt2 * 50);
|
|
27418
28767
|
}
|
|
27419
|
-
function levelGeometry(style, marker) {
|
|
27420
|
-
const left = style.leadTa * taHu(style.pt);
|
|
27421
|
-
const indent = marker ? -markerWidth(marker, style.pt * 100) : 0;
|
|
27422
|
-
return { left, indent };
|
|
27423
|
-
}
|
|
27424
28768
|
function pickScheme(g, bodyHasBoxMarkers) {
|
|
27425
28769
|
if (g.preset === "ministry") {
|
|
27426
28770
|
return applySchemeOverrides(ministryScheme(g.bodyPtExplicit ? g.bodyHeight / 100 : 15, g.lineSpacingExplicit ? g.lineSpacing : 145), g);
|
|
@@ -27645,9 +28989,12 @@ function buildOutline(blocks, opts) {
|
|
|
27645
28989
|
// src/hwpx/fit-line.ts
|
|
27646
28990
|
var RATIOS = [100, 97, 95, 92, 90, 87, 85];
|
|
27647
28991
|
var SPACINGS = [0, -3, -5];
|
|
28992
|
+
function safety(faceClass, approx) {
|
|
28993
|
+
return faceClass.startsWith("font:") ? 0.98 : approx;
|
|
28994
|
+
}
|
|
27648
28995
|
function fitOneLine(text, font, pt2, availHu, minPt = Math.max(pt2 - 3, 10), minRatio = 85) {
|
|
27649
28996
|
const faceClass = faceClassForGen(font);
|
|
27650
|
-
const avail = availHu * 0.98;
|
|
28997
|
+
const avail = availHu * safety(faceClass, 0.98);
|
|
27651
28998
|
const fits = (p, r, s) => measureTextWidth(text, p * 100, r, { spacingPct: s, faceClass }) <= avail;
|
|
27652
28999
|
if (fits(pt2, 100, 0)) return { pt: pt2, ratio: 100, spacing: 0, overflow: false };
|
|
27653
29000
|
const ratios = RATIOS.filter((r) => r >= minRatio);
|
|
@@ -27658,27 +29005,139 @@ function fitOneLine(text, font, pt2, availHu, minPt = Math.max(pt2 - 3, 10), min
|
|
|
27658
29005
|
}
|
|
27659
29006
|
return { pt: minPt, ratio: ratios[ratios.length - 1], spacing: SPACINGS[SPACINGS.length - 1], overflow: true };
|
|
27660
29007
|
}
|
|
27661
|
-
|
|
29008
|
+
var SQUEEZE = (() => {
|
|
29009
|
+
const out = [];
|
|
29010
|
+
for (let sp = -1; sp >= -12; sp--) out.push([100, sp]);
|
|
29011
|
+
for (const r of [97, 95, 92, 90, 88]) for (let sp = 0; sp >= -12; sp--) out.push([r, sp]);
|
|
29012
|
+
return out;
|
|
29013
|
+
})();
|
|
29014
|
+
var LOOSE_LIMIT = 1;
|
|
29015
|
+
var PULL_TAIL = 0.5;
|
|
29016
|
+
var PULL_MAX = 0.15;
|
|
29017
|
+
var squeezeOf = (r, sp) => 1 - r / 100 * (1 + sp / 100);
|
|
29018
|
+
var ORPHAN_RATIO = 0.22;
|
|
29019
|
+
var ORPHAN_COST = 1.5;
|
|
29020
|
+
var COMPRESS_COST = 10;
|
|
29021
|
+
function worstLooseness(text, starts, firstW, contW, h, ratio, spacing, faceClass) {
|
|
29022
|
+
const spaceW = 0.5 * h * (ratio / 100) * (1 + spacing / 100);
|
|
29023
|
+
let worst = 0;
|
|
29024
|
+
for (let i = 0; i + 1 < starts.length; i++) {
|
|
29025
|
+
const seg = text.slice(starts[i], starts[i + 1]).replace(/ +$/, "");
|
|
29026
|
+
const slack = (i === 0 ? firstW : contW) - measureTextWidth(seg, h, ratio, { faceClass, spacingPct: spacing });
|
|
29027
|
+
const spaces = (seg.match(/ /g) ?? []).length;
|
|
29028
|
+
worst = Math.max(worst, slack / (Math.max(spaces, 1) * spaceW));
|
|
29029
|
+
}
|
|
29030
|
+
return worst;
|
|
29031
|
+
}
|
|
29032
|
+
function fitParagraph(text, font, pt2, firstW, contW, minRatio = 88, orphanRatio = ORPHAN_RATIO) {
|
|
27662
29033
|
const faceClass = faceClassForGen(font);
|
|
27663
29034
|
const h = pt2 * 100;
|
|
27664
|
-
const
|
|
27665
|
-
const
|
|
27666
|
-
const
|
|
27667
|
-
|
|
27668
|
-
|
|
27669
|
-
|
|
27670
|
-
|
|
27671
|
-
|
|
27672
|
-
|
|
27673
|
-
|
|
29035
|
+
const k = safety(faceClass, 0.95);
|
|
29036
|
+
const f = firstW * k, c = contW * k;
|
|
29037
|
+
const ladder = [[100, 0], ...SQUEEZE.filter(([r]) => r >= minRatio)];
|
|
29038
|
+
const base = simulateWrap(text, f, c, h, 100, "keep", { faceClass });
|
|
29039
|
+
if (base.lines < 2) return null;
|
|
29040
|
+
if (base.lastLineWidth <= c * PULL_TAIL) {
|
|
29041
|
+
let pull = null;
|
|
29042
|
+
for (const [r, sp] of ladder) {
|
|
29043
|
+
const amt = squeezeOf(r, sp);
|
|
29044
|
+
if (amt > PULL_MAX + 1e-9 || pull && amt >= pull.amt - 1e-9) continue;
|
|
29045
|
+
const w = simulateWrap(text, f, c, h, r, "keep", { faceClass, spacingPct: sp });
|
|
29046
|
+
if (w.lines < base.lines && worstLooseness(text, w.starts, f, c, h, r, sp, faceClass) <= LOOSE_LIMIT) pull = { r, sp, amt };
|
|
29047
|
+
}
|
|
29048
|
+
if (pull) return { ratio: pull.r, spacing: pull.sp };
|
|
29049
|
+
}
|
|
29050
|
+
let baseLines = 0;
|
|
29051
|
+
let best = null;
|
|
29052
|
+
for (const [r, sp] of ladder) {
|
|
29053
|
+
const w = simulateWrap(text, f, c, h, r, "keep", { faceClass, spacingPct: sp });
|
|
29054
|
+
if (!best) {
|
|
29055
|
+
if (w.lines < 2) return null;
|
|
29056
|
+
baseLines = w.lines;
|
|
29057
|
+
}
|
|
29058
|
+
if (w.lines > baseLines) continue;
|
|
29059
|
+
const orphan = w.lines > 1 && w.lastLineWidth <= contW * orphanRatio;
|
|
29060
|
+
const loose = worstLooseness(text, w.starts, f, c, h, r, sp, faceClass);
|
|
29061
|
+
const cost = Math.max(0, loose - LOOSE_LIMIT) + (orphan ? ORPHAN_COST : 0) + squeezeOf(r, sp) * COMPRESS_COST;
|
|
29062
|
+
if (!best || cost < best.cost - 1e-9) best = { r, sp, cost };
|
|
29063
|
+
}
|
|
29064
|
+
return best && (best.r !== 100 || best.sp !== 0) ? { ratio: best.r, spacing: best.sp } : null;
|
|
29065
|
+
}
|
|
29066
|
+
var LIST_BREAK = /* @__PURE__ */ new Set([..."\xB7,\u3001/"]);
|
|
29067
|
+
function fitCharBreaks(text, font, pt2, firstW, contW, minRatio = 88) {
|
|
29068
|
+
const faceClass = faceClassForGen(font);
|
|
29069
|
+
const h = pt2 * 100;
|
|
29070
|
+
const k = safety(faceClass, 0.95);
|
|
29071
|
+
if (!text.split(/ +/).some((w) => measureTextWidth(w, h, 100, { faceClass }) > contW * k)) return null;
|
|
29072
|
+
let best = null;
|
|
29073
|
+
for (const [r, sp] of [[100, 0], ...SQUEEZE.filter(([r2]) => r2 >= minRatio)]) {
|
|
29074
|
+
const amt = squeezeOf(r, sp);
|
|
29075
|
+
if (amt > PULL_MAX + 1e-9 || best && amt >= best.amt - 1e-9) continue;
|
|
29076
|
+
const wrapAt = (s) => simulateWrap(text, firstW * s, contW * s, h, r, "charAll", { faceClass, spacingPct: sp }).starts;
|
|
29077
|
+
const starts = wrapAt(1);
|
|
29078
|
+
if (wrapAt(0.99).join() !== starts.join() || wrapAt(1.01).join() !== starts.join()) continue;
|
|
29079
|
+
if (!starts.slice(1).every((s) => text[s - 1] === " " || LIST_BREAK.has(text[s - 1]))) continue;
|
|
29080
|
+
if (worstLooseness(text, starts, firstW, contW, h, r, sp, faceClass) > LOOSE_LIMIT) continue;
|
|
29081
|
+
best = { r, sp, amt };
|
|
29082
|
+
}
|
|
29083
|
+
return best ? { ratio: best.r, spacing: best.sp } : null;
|
|
29084
|
+
}
|
|
29085
|
+
|
|
29086
|
+
// src/hwpx/gen-marker.ts
|
|
29087
|
+
function markerLayout(font, pt2, leadTa, marker) {
|
|
29088
|
+
const left = leadTa * taHu(pt2);
|
|
29089
|
+
if (!marker) return { left, hang: 0, markerW: 0 };
|
|
29090
|
+
const markerW = Math.round(measureTextWidth(marker, pt2 * 100, 100, { faceClass: faceClassForGen(font) }));
|
|
29091
|
+
return { left, hang: markerW + taHu(pt2), markerW };
|
|
29092
|
+
}
|
|
29093
|
+
function markerRunXml(marker, charPr2, lay) {
|
|
29094
|
+
return `<hp:run charPrIDRef="${charPr2}"><hp:t>${escapeTextXml(marker)}<hp:tab width="${lay.hang - lay.markerW}" leader="0" type="1"/></hp:t></hp:run>`;
|
|
29095
|
+
}
|
|
29096
|
+
|
|
29097
|
+
// src/hwpx/gongmun-typo.ts
|
|
29098
|
+
var NBSP = "\xA0";
|
|
29099
|
+
var OPENER_BEFORE = /[\s(\[{>「『〈《【〔‘“·/:,~—–-]/u;
|
|
29100
|
+
function bindSpaces(s) {
|
|
29101
|
+
return s.replace(/(\d{4}|['’]\d{2})\. (\d{1,2})\. (\d{1,2})\.(?!\d)/g, `$1.${NBSP}$2.${NBSP}$3.`).replace(/(\d{4}|['’]\d{2})\. (\d{1,2})\.(?!\d)/g, `$1.${NBSP}$2.`).replace(/(?<![\d.])(\d{1,2})\. (\d{1,2})\.(?!\d)/g, `$1.${NBSP}$2.`).replace(/(\d{1,2}:\d{2}) ([~∼-]) (\d{1,2}:\d{2})/g, `$1${NBSP}$2${NBSP}$3`).replace(/(\d(?:조|억|만|천)?) 원/g, `$1${NBSP}\uC6D0`);
|
|
29102
|
+
}
|
|
29103
|
+
function neighbor(s, i, dir) {
|
|
29104
|
+
for (let k = i + dir; k >= 0 && k < s.length; k += dir) if (!/[*_~]/.test(s[k])) return s[k];
|
|
29105
|
+
return "";
|
|
29106
|
+
}
|
|
29107
|
+
function curlQuotes(s, before = "") {
|
|
29108
|
+
let out = "";
|
|
29109
|
+
for (let i = 0; i < s.length; i++) {
|
|
29110
|
+
const c = s[i];
|
|
29111
|
+
if (c !== "'" && c !== '"') {
|
|
29112
|
+
out += c;
|
|
29113
|
+
continue;
|
|
29114
|
+
}
|
|
29115
|
+
const prev = neighbor(s, i, -1) || before;
|
|
29116
|
+
const opening = prev === "" || OPENER_BEFORE.test(prev);
|
|
29117
|
+
if (c === "'") {
|
|
29118
|
+
if (opening && /^\d{2}(?![\d'])/.test(s.slice(i + 1))) {
|
|
29119
|
+
out += "\u2019";
|
|
29120
|
+
continue;
|
|
29121
|
+
}
|
|
29122
|
+
out += opening ? "\u2018" : "\u2019";
|
|
29123
|
+
} else {
|
|
29124
|
+
out += opening ? "\u201C" : "\u201D";
|
|
29125
|
+
}
|
|
27674
29126
|
}
|
|
27675
|
-
|
|
27676
|
-
|
|
27677
|
-
|
|
27678
|
-
|
|
27679
|
-
|
|
29127
|
+
return out;
|
|
29128
|
+
}
|
|
29129
|
+
function polishGongmunText(text) {
|
|
29130
|
+
if (!text) return text;
|
|
29131
|
+
let out = "";
|
|
29132
|
+
for (const [i, seg] of text.split(/(`[^`]*`|\]\([^)]*\))/).entries()) {
|
|
29133
|
+
out += i % 2 === 1 ? seg : curlQuotes(bindSpaces(seg), out.replace(/[*_~]+$/, "").slice(-1));
|
|
27680
29134
|
}
|
|
27681
|
-
return
|
|
29135
|
+
return out;
|
|
29136
|
+
}
|
|
29137
|
+
function polishGongmunBlock(b) {
|
|
29138
|
+
if (b.type === "table") return b.rows ? { ...b, rows: b.rows.map((r) => r.map(polishGongmunText)) } : b;
|
|
29139
|
+
if (b.type === "paragraph" || b.type === "heading" || b.type === "list_item" || b.type === "blockquote") return b.text ? { ...b, text: polishGongmunText(b.text) } : b;
|
|
29140
|
+
return b;
|
|
27682
29141
|
}
|
|
27683
29142
|
|
|
27684
29143
|
// src/hwpx/gen-frame-seoul.ts
|
|
@@ -27895,13 +29354,13 @@ function buildSummaryBox(text, ctx) {
|
|
|
27895
29354
|
const { reg, bf, frame } = ctx;
|
|
27896
29355
|
const w = ctx.W - 566;
|
|
27897
29356
|
const avail = w - 280 - SUMMARY_PAD * 2;
|
|
27898
|
-
const p = reg.para({ align: "JUSTIFY", lineSp: 160, left: SUMMARY_PAD, right: SUMMARY_PAD
|
|
29357
|
+
const p = reg.para({ align: "JUSTIFY", lineSp: 160, left: SUMMARY_PAD, right: SUMMARY_PAD });
|
|
27899
29358
|
const bodies = text.split("\n").map((l) => l.trim().replace(/^[□■○ㅇ◦●\-–ㆍ·•]\s*/u, "")).filter(Boolean);
|
|
27900
29359
|
let lines = 0;
|
|
27901
29360
|
const paras = bodies.map((b) => {
|
|
27902
|
-
const f =
|
|
29361
|
+
const f = fitParagraph(b, frame.summaryFont, frame.summaryPt, avail, avail);
|
|
27903
29362
|
const c = reg.char({ font: frame.summaryFont, pt: frame.summaryPt, bold: true, ratio: f?.ratio ?? 100, spacing: f?.spacing ?? 0 });
|
|
27904
|
-
lines += simulateWrap(b, avail * 0.
|
|
29363
|
+
lines += simulateWrap(b, avail * 0.995, avail * 0.995, frame.summaryPt * 100, f?.ratio ?? 100, "keep", { faceClass: faceClassForGen(frame.summaryFont), spacingPct: f?.spacing ?? 0 }).lines;
|
|
27905
29364
|
return para(b, p, c);
|
|
27906
29365
|
});
|
|
27907
29366
|
const h = lines * Math.round(frame.summaryPt * 100 * 1.6) + 280 + 600;
|
|
@@ -27994,11 +29453,11 @@ function ministryRuns(marker, text, ctx, base, keywordColor, emphasisColor) {
|
|
|
27994
29453
|
const { reg } = ctx;
|
|
27995
29454
|
const baseId = reg.char(base);
|
|
27996
29455
|
const mapper = inlineMapper(reg, base, emphasisColor);
|
|
27997
|
-
let out = marker ? `<hp:run charPrIDRef="${baseId}"><hp:t>${
|
|
29456
|
+
let out = marker ? `<hp:run charPrIDRef="${baseId}"><hp:t>${escapeTextXml(marker + " ")}</hp:t></hp:run>` : "";
|
|
27998
29457
|
const m = KEYWORD_RE.exec(text);
|
|
27999
29458
|
if (m) {
|
|
28000
29459
|
const kw = reg.char({ ...base, bold: true, color: keywordColor ?? base.color });
|
|
28001
|
-
out += `<hp:run charPrIDRef="${kw}"><hp:t>${
|
|
29460
|
+
out += `<hp:run charPrIDRef="${kw}"><hp:t>${escapeTextXml(m[1] + " ")}</hp:t></hp:run>`;
|
|
28002
29461
|
text = text.slice(m[0].length);
|
|
28003
29462
|
}
|
|
28004
29463
|
return out + generateRuns(text, baseId, mapper);
|
|
@@ -28055,8 +29514,8 @@ function buildMinistryToc(chapters, ctx) {
|
|
|
28055
29514
|
const cCh = reg.char({ font: MINISTRY.headFont, pt: t.chapterPt });
|
|
28056
29515
|
const cSub = reg.char({ font: MINISTRY.headFont, pt: t.subPt });
|
|
28057
29516
|
const pLabel = reg.para({ align: "LEFT", lineSp: 130, left: pad, before: 1200, after: 2400 });
|
|
28058
|
-
const pCh = reg.para({ align: "LEFT", lineSp: 130, left: pad, before: 2e3
|
|
28059
|
-
const pSub = reg.para({ align: "LEFT", lineSp: 130, left: pad + 1400, before: 1200
|
|
29517
|
+
const pCh = reg.para({ align: "LEFT", lineSp: 130, left: pad, before: 2e3 });
|
|
29518
|
+
const pSub = reg.para({ align: "LEFT", lineSp: 130, left: pad + 1400, before: 1200 });
|
|
28060
29519
|
const paras = [para("\uBAA9 \uCC28", pLabel, cLabel)];
|
|
28061
29520
|
let h = 1200 + Math.round(t.labelPt * 130) + 2400;
|
|
28062
29521
|
let roman = 0;
|
|
@@ -28136,10 +29595,10 @@ function buildMinistryItemBand(n, text, ctx, before) {
|
|
|
28136
29595
|
const w = ctx.W;
|
|
28137
29596
|
const band = bf.get({ t: s.line, b: s.line, l: NONE, r: NONE, fill: s.fill });
|
|
28138
29597
|
const base = { font: MINISTRY.bandFont, pt: s.pt, bold: false };
|
|
28139
|
-
const f =
|
|
28140
|
-
const styled = f ? { ...base, ratio: f.ratio, spacing: f.spacing }
|
|
29598
|
+
const f = fitOneLine(plain(text), MINISTRY.bandFont, s.pt, w - 1800, s.pt);
|
|
29599
|
+
const styled = f.overflow || f.ratio === 100 && f.spacing === 0 ? base : { ...base, ratio: f.ratio, spacing: f.spacing };
|
|
28141
29600
|
const runs = ministryRuns(circledNumber(n - 1), text, ctx, styled, MINISTRY.blue, MINISTRY.blue);
|
|
28142
|
-
const p = reg.para({ align: "LEFT", lineSp: 130, left: 300
|
|
29601
|
+
const p = reg.para({ align: "LEFT", lineSp: 130, left: 300 });
|
|
28143
29602
|
const cell2 = tc({ bf: band, row: 0, col: 0, w, h: s.h, paras: `<hp:p paraPrIDRef="${p}" styleIDRef="0">${runs}</hp:p>`, name: "__kordoc_h5" });
|
|
28144
29603
|
return host(ftbl([cell2], w, s.h, 1, { bottomGap: 700 }), reg.para({ align: "LEFT", lineSp: 100, before, keepWithNext: true }), reg.char(base));
|
|
28145
29604
|
}
|
|
@@ -28148,20 +29607,21 @@ function buildMinistrySummaryBox(text, ctx) {
|
|
|
28148
29607
|
const s = MINISTRY.summary;
|
|
28149
29608
|
const w = ctx.W - 600;
|
|
28150
29609
|
const avail = w - 280 - 600;
|
|
28151
|
-
const
|
|
28152
|
-
const
|
|
29610
|
+
const lay = markerLayout(MINISTRY.bodyFont, s.pt, 0, "\u25AA");
|
|
29611
|
+
const pItem = reg.para({ align: "LEFT", lineSp: 140, left: 300, right: 300, indent: -lay.hang, autoTab: true });
|
|
29612
|
+
const pRef = reg.para({ align: "LEFT", lineSp: 130, left: 300 + lay.hang, right: 300 });
|
|
28153
29613
|
const baseItem = { font: MINISTRY.bodyFont, pt: s.pt, bold: false };
|
|
28154
29614
|
const cRef = reg.char({ font: MINISTRY.refFont, pt: s.refPt });
|
|
28155
29615
|
let h = 0;
|
|
28156
29616
|
const paras = text.split("\n").map((raw) => raw.trim()).filter(Boolean).map((line) => {
|
|
28157
29617
|
const isRef = /^(\*|※)/.test(line);
|
|
28158
29618
|
if (isRef) {
|
|
28159
|
-
h += Math.round(s.refPt * 100 * 1.3) * simulateWrap(line, avail, avail, s.refPt * 100, 100, "
|
|
29619
|
+
h += Math.round(s.refPt * 100 * 1.3) * simulateWrap(line, avail - lay.hang, avail - lay.hang, s.refPt * 100, 100, "keep", { faceClass: faceClassForGen(MINISTRY.refFont) }).lines;
|
|
28160
29620
|
return `<hp:p paraPrIDRef="${pRef}" styleIDRef="0">${generateRuns(line, cRef, inlineMapper(reg, { font: MINISTRY.refFont, pt: s.refPt, bold: false }))}</hp:p>`;
|
|
28161
29621
|
}
|
|
28162
29622
|
const body = line.replace(/^[▪■□○ㅇ●\-–ㆍ·•]\s*/u, "");
|
|
28163
|
-
h += Math.round(s.pt * 100 * 1.4) * simulateWrap(plain(body), avail, avail, s.pt * 100, 100, "
|
|
28164
|
-
return `<hp:p paraPrIDRef="${pItem}" styleIDRef="0">${
|
|
29623
|
+
h += Math.round(s.pt * 100 * 1.4) * simulateWrap(plain(body), avail - lay.hang, avail - lay.hang, s.pt * 100, 100, "keep", { faceClass: faceClassForGen(MINISTRY.bodyFont) }).lines;
|
|
29624
|
+
return `<hp:p paraPrIDRef="${pItem}" styleIDRef="0">${markerRunXml("\u25AA", reg.char(baseItem), lay)}${ministryRuns("", body, ctx, baseItem, MINISTRY.blue)}</hp:p>`;
|
|
28165
29625
|
});
|
|
28166
29626
|
h += 280 + 600;
|
|
28167
29627
|
const box = bf.get({ t: "thin", b: "thin", l: "thin", r: "thin", fill: s.fill });
|
|
@@ -28213,7 +29673,8 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
|
|
|
28213
29673
|
const pre = buildOutline(blocks, isMinistry ? { gaejosik: true, consumeTitle: true, summaryFromQuote: true, quoteBox: true, headingFrames: true, keepMarkers: true } : { gaejosik: true, consumeTitle: true, summaryFromQuote: isReport });
|
|
28214
29674
|
const scheme = pickScheme(g, pre.hasBoxMarkers);
|
|
28215
29675
|
const gaejosik = scheme.kind === "gaejosik";
|
|
28216
|
-
const
|
|
29676
|
+
const raw = gaejosik ? pre : buildOutline(blocks, { gaejosik: false, consumeTitle: true, summaryFromQuote: false });
|
|
29677
|
+
const outline = { ...raw, title: raw.title && polishGongmunText(raw.title), nodes: raw.nodes.map(polishNode) };
|
|
28217
29678
|
const frame = { reg, bf: bfReg, frame: scheme.frame, W };
|
|
28218
29679
|
const lineHu = (st) => Math.round(st.pt * 100 * ((st.lineSp ?? scheme.lineSp) / 100));
|
|
28219
29680
|
const paras = [];
|
|
@@ -28237,15 +29698,16 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
|
|
|
28237
29698
|
let frontKind = "start";
|
|
28238
29699
|
const pushSummary = (t) => {
|
|
28239
29700
|
frontKind = "summary";
|
|
28240
|
-
const box = buildSummaryBox(t, frame);
|
|
29701
|
+
const box = buildSummaryBox(polishGongmunText(t), frame);
|
|
28241
29702
|
if (box.lines > 3) warnings.push(`\uC694\uC57D\uBC15\uC2A4\uAC00 ${box.lines}\uC904\uC785\uB2C8\uB2E4 \u2014 \uBCF4\uACE0 \uBAA9\uC801\uC744 \uD55C \uBB38\uC7A5(\uC27C\uD45C \uD5C8\uC6A9) 3\uC904 \uC774\uB0B4 "\u2026\uD558\uACE0\uC790 \uD568"\uC73C\uB85C \uC904\uC774\uC138\uC694`);
|
|
28242
29703
|
paras.push(box.xml);
|
|
28243
29704
|
};
|
|
28244
|
-
const docTitle = g.docHead?.title ?? outline.title ?? "";
|
|
29705
|
+
const docTitle = polishGongmunText(g.docHead?.title ?? outline.title ?? "");
|
|
29706
|
+
const reportInfo = g.reportInfo && polishGongmunText(g.reportInfo);
|
|
28245
29707
|
if (preset === "official") {
|
|
28246
29708
|
if (g.docHead) paras.push(buildDocHeadTable({ ...g.docHead, title: docTitle }, frame));
|
|
28247
29709
|
else if (outline.title) paras.push(generateParagraph(outline.title, reg.para({ align: "CENTER", lineSp: scheme.lineSp, after: lineHu(scheme.body) }), reg.char({ font: scheme.body.font, pt: scheme.body.pt + 2, bold: true }), void 0, 1));
|
|
28248
|
-
if (
|
|
29710
|
+
if (reportInfo) paras.push(generateParagraph(reportInfo, reg.para({ align: "RIGHT", lineSp: scheme.lineSp }), reg.char({ font: scheme.body.font, pt: 12 })));
|
|
28249
29711
|
if (g.approval) paras.push(buildApprovalSeoul(g.approval, null, frame));
|
|
28250
29712
|
} else if (isMinistry) {
|
|
28251
29713
|
if (g.cover) {
|
|
@@ -28284,7 +29746,7 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
|
|
|
28284
29746
|
paras.push(buildApprovalSeoul(g.approval, null, frame));
|
|
28285
29747
|
}
|
|
28286
29748
|
if (docTitle) {
|
|
28287
|
-
const t = buildReportTitleTable(docTitle,
|
|
29749
|
+
const t = buildReportTitleTable(docTitle, reportInfo, frame);
|
|
28288
29750
|
if (t.overflow) warnings.push(`\uC81C\uBAA9\uC774 \uAE38\uC5B4 \uD55C \uC904\uC5D0 \uB2F4\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(20pt\xB7\uC7A5\uD3C9 85%\uAE4C\uC9C0 \uCD95\uC18C) \u2014 \uC81C\uBAA9\uC744 \uC904\uC774\uC138\uC694: "${docTitle.slice(0, 30)}\u2026"`);
|
|
28289
29751
|
if (pendingPageBreak) {
|
|
28290
29752
|
paras.push(t.xml.replace(/^<hp:p /, `<hp:p pageBreak="1" `).replace(/<hp:run charPrIDRef="(\d+)">/, `<hp:run charPrIDRef="$1">${newPageNumCtrl(1)}`));
|
|
@@ -28292,7 +29754,7 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
|
|
|
28292
29754
|
} else paras.push(t.xml);
|
|
28293
29755
|
frontKind = "title";
|
|
28294
29756
|
}
|
|
28295
|
-
if (!docTitle &&
|
|
29757
|
+
if (!docTitle && reportInfo) paras.push(generateParagraph(reportInfo, reg.para({ align: "RIGHT", lineSp: scheme.lineSp }), reg.char({ font: scheme.body.font, pt: 12 })));
|
|
28296
29758
|
if (g.summary) pushSummary(g.summary);
|
|
28297
29759
|
else if (!outline.nodes.some((n) => n.kind === "summary")) warnings.push('\uBCF4\uACE0\uC11C \uC694\uC57D\uBC15\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uC81C\uBAA9 \uC9C1\uD6C4 \uC778\uC6A9\uBB38(>)\uC5D0 \uBCF4\uACE0 \uBAA9\uC801\uC744 \uD55C \uBB38\uC7A5(\uC27C\uD45C \uD5C8\uC6A9) 3\uC904 \uC774\uB0B4 "\u2026\uD558\uACE0\uC790 \uD568"\uC73C\uB85C \uB123\uAC70\uB098 summary \uC635\uC158\uC744 \uC9C0\uC815\uD558\uC138\uC694');
|
|
28298
29760
|
} else {
|
|
@@ -28331,51 +29793,55 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
|
|
|
28331
29793
|
marker = numberer.next(depth, sup);
|
|
28332
29794
|
itemSeq++;
|
|
28333
29795
|
}
|
|
28334
|
-
const
|
|
28335
|
-
const
|
|
28336
|
-
const
|
|
28337
|
-
|
|
28338
|
-
let pt2 = st.pt, ratio = 100, spacing = 0;
|
|
29796
|
+
const mk = isMinistry && node.marker ? node.marker : marker;
|
|
29797
|
+
const lay = markerLayout(st.font, st.pt, st.leadTa, mk);
|
|
29798
|
+
const textW2 = W - lay.left - lay.hang;
|
|
29799
|
+
let ratio = 100, spacing = 0, charBreaks = false;
|
|
28339
29800
|
if (st.oneLine) {
|
|
28340
|
-
const fit = fitOneLine(plain2(text), st.font, st.pt,
|
|
29801
|
+
const fit = fitOneLine(plain2(node.text), st.font, st.pt, textW2, st.pt, 90);
|
|
28341
29802
|
if (fit.overflow) warnings.push(`\u25A1 \uD56D\uBAA9\uC774 \uD55C \uC904\uC5D0 \uB2F4\uAE30\uC9C0 \uC54A\uC544 \uB450 \uC904\uB85C \uAEBE\uC785\uB2C8\uB2E4 \u2014 \uBB38\uC7A5\uC744 \uC904\uC774\uC138\uC694(\uC7A5\uD3C9 90%\xB7\uC790\uAC04 -5 \uB85C\uB3C4 \uCD08\uACFC): "${node.text.slice(0, 30)}\u2026"`);
|
|
28342
29803
|
else {
|
|
28343
29804
|
ratio = fit.ratio;
|
|
28344
29805
|
spacing = fit.spacing;
|
|
28345
29806
|
}
|
|
28346
|
-
} else
|
|
28347
|
-
const
|
|
29807
|
+
} else {
|
|
29808
|
+
const t = plain2(node.text);
|
|
29809
|
+
const cb = fitCharBreaks(t, st.font, st.pt, textW2, textW2, g.autoFitMinRatio ?? 101);
|
|
29810
|
+
const f = cb ?? (g.autoFitMinRatio !== null ? fitParagraph(t, st.font, st.pt, textW2, textW2, g.autoFitMinRatio) : null);
|
|
28348
29811
|
if (f) {
|
|
28349
29812
|
ratio = f.ratio;
|
|
28350
29813
|
spacing = f.spacing;
|
|
28351
29814
|
}
|
|
29815
|
+
charBreaks = !!cb;
|
|
28352
29816
|
}
|
|
28353
|
-
const base = { font: st.font, pt:
|
|
28354
|
-
const geom2 = pt2 !== st.pt ? levelGeometry({ ...st, pt: pt2 }, marker) : geom;
|
|
29817
|
+
const base = { font: st.font, pt: st.pt, bold: st.bold, ratio, spacing };
|
|
28355
29818
|
const consecutiveBox = prevKind === "item" && prevItemDepth === 0 && depth === 0;
|
|
28356
29819
|
const afterBand = depth === 0 && (prevKind === "chapter" && chapterStyle === "band" || prevKind === "title" && !!st.blankBefore);
|
|
28357
29820
|
const before = afterBand ? BOX_GAP_AFTER_BAND : st.blankBefore && !consecutiveBox && prevKind !== "chapter" && prevKind !== "start" && prevKind !== "summary" ? BOX_BLANK_HU : 0;
|
|
28358
29821
|
const keepNext = !!st.keepWithNext && !!nextNode && (nextNode.kind === "item" && nextNode.depth > depth || nextNode.kind === "ref");
|
|
29822
|
+
const paraSpec = { align: "JUSTIFY", left: lay.left, indent: -lay.hang, before, lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: keepNext, keepWord: !charBreaks, autoTab: lay.hang > 0, widowOrphan: true };
|
|
29823
|
+
const markerRun = mk ? markerRunXml(mk, reg.char({ font: st.font, pt: st.pt, bold: st.bold }), lay) : "";
|
|
28359
29824
|
if (isMinistry) {
|
|
28360
|
-
const
|
|
28361
|
-
const
|
|
28362
|
-
const paraId2 = reg.para({ align: "JUSTIFY", left: g2.left, indent: g2.indent, before, after: 600, lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: keepNext, keepWord: false });
|
|
28363
|
-
const runs = ministryRuns(mk, node.text, frame, base, depth === 0 ? MINISTRY.blue : null);
|
|
29825
|
+
const paraId2 = reg.para({ ...paraSpec, after: 600 });
|
|
29826
|
+
const runs = markerRun + ministryRuns("", node.text, frame, base, depth === 0 ? MINISTRY.blue : null);
|
|
28364
29827
|
return `<hp:p paraPrIDRef="${paraId2}" styleIDRef="${styleId}">${runs}</hp:p>`;
|
|
28365
29828
|
}
|
|
28366
|
-
const paraId = reg.para(
|
|
28367
|
-
return
|
|
29829
|
+
const paraId = reg.para(paraSpec);
|
|
29830
|
+
return `<hp:p paraPrIDRef="${paraId}" styleIDRef="${styleId}">${markerRun}${generateRuns(node.text, reg.char(base), inlineMapper(reg, base))}</hp:p>`;
|
|
28368
29831
|
};
|
|
28369
29832
|
const renderRef = (node) => {
|
|
28370
29833
|
const st = scheme.ref;
|
|
28371
29834
|
const marker = isMinistry ? "*" : "\u203B";
|
|
29835
|
+
const lay = markerLayout(st.font, st.pt, 0, marker);
|
|
28372
29836
|
const left = isMinistry ? st.leadTa * taHu(st.pt) : leadLeft(node.depth, st.pt);
|
|
28373
|
-
const
|
|
28374
|
-
const
|
|
28375
|
-
const
|
|
28376
|
-
const
|
|
28377
|
-
const
|
|
28378
|
-
|
|
29837
|
+
const textW2 = W - left - lay.hang;
|
|
29838
|
+
const t = plain2(node.text);
|
|
29839
|
+
const cb = fitCharBreaks(t, st.font, st.pt, textW2, textW2, g.autoFitMinRatio ?? 101);
|
|
29840
|
+
const f = cb ?? (g.autoFitMinRatio !== null ? fitParagraph(t, st.font, st.pt, textW2, textW2, g.autoFitMinRatio) : null);
|
|
29841
|
+
const base = { font: st.font, pt: st.pt, bold: st.bold, ratio: f?.ratio ?? 100, spacing: f?.spacing ?? 0 };
|
|
29842
|
+
const paraId = reg.para({ align: "JUSTIFY", left, indent: -lay.hang, after: isMinistry ? 400 : 0, lineSp: isMinistry ? 130 : st.lineSp ?? scheme.lineSp, keepWord: !cb, autoTab: true, widowOrphan: true });
|
|
29843
|
+
const markerRun = markerRunXml(marker, reg.char({ font: st.font, pt: st.pt, bold: st.bold }), lay);
|
|
29844
|
+
return `<hp:p paraPrIDRef="${paraId}" styleIDRef="0">${markerRun}${generateRuns(node.text, reg.char(base), inlineMapper(reg, base))}</hp:p>`;
|
|
28379
29845
|
};
|
|
28380
29846
|
const renderPara = (node) => {
|
|
28381
29847
|
const st = scheme.body;
|
|
@@ -28389,16 +29855,19 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
|
|
|
28389
29855
|
if (pics.every(Boolean)) return `<hp:p paraPrIDRef="${reg.para({ align: "CENTER", lineSp: scheme.lineSp })}" styleIDRef="0"><hp:run charPrIDRef="${reg.char({ font: st.font, pt: st.pt })}">${pics.join("")}</hp:run></hp:p>`;
|
|
28390
29856
|
}
|
|
28391
29857
|
}
|
|
28392
|
-
let ratio = 100, spacing = 0;
|
|
28393
|
-
if (!node.align
|
|
28394
|
-
const
|
|
29858
|
+
let ratio = 100, spacing = 0, charBreaks = false;
|
|
29859
|
+
if (!node.align) {
|
|
29860
|
+
const t = plain2(node.text);
|
|
29861
|
+
const cb = fitCharBreaks(t, st.font, st.pt, W, W, g.autoFitMinRatio ?? 101);
|
|
29862
|
+
const f = cb ?? (g.autoFitMinRatio !== null ? fitParagraph(t, st.font, st.pt, W, W, g.autoFitMinRatio) : null);
|
|
28395
29863
|
if (f) {
|
|
28396
29864
|
ratio = f.ratio;
|
|
28397
29865
|
spacing = f.spacing;
|
|
28398
29866
|
}
|
|
29867
|
+
charBreaks = !!cb;
|
|
28399
29868
|
}
|
|
28400
29869
|
const base = { font: st.font, pt: st.pt, bold: st.bold, ratio, spacing };
|
|
28401
|
-
const paraId = reg.para({ align: node.align ?? "JUSTIFY", lineSp: scheme.lineSp, keepWord:
|
|
29870
|
+
const paraId = reg.para({ align: node.align ?? "JUSTIFY", lineSp: scheme.lineSp, keepWord: !charBreaks, widowOrphan: true });
|
|
28402
29871
|
return generateParagraph(node.text, paraId, reg.char(base), inlineMapper(reg, base));
|
|
28403
29872
|
};
|
|
28404
29873
|
const renderChapter = (node) => {
|
|
@@ -28426,7 +29895,7 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
|
|
|
28426
29895
|
const fit = fitOneLine(plain2(text), st.font, st.pt, W, st.pt - 2);
|
|
28427
29896
|
const base = { font: st.font, pt: fit.pt, bold: st.bold, ratio: fit.ratio, spacing: fit.spacing };
|
|
28428
29897
|
const before = prevKind === "start" || prevKind === "title" || prevKind === "summary" ? 0 : lineHu(scheme.body);
|
|
28429
|
-
const paraId = reg.para({ align: "LEFT", before, after: Math.round(lineHu(scheme.body) * 0.3), lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: true
|
|
29898
|
+
const paraId = reg.para({ align: "LEFT", before, after: Math.round(lineHu(scheme.body) * 0.3), lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: true });
|
|
28430
29899
|
return generateParagraph(text, paraId, reg.char(base), inlineMapper(reg, base), 2);
|
|
28431
29900
|
};
|
|
28432
29901
|
const renderAttach = (node, first) => {
|
|
@@ -28434,7 +29903,7 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
|
|
|
28434
29903
|
let text = node.text;
|
|
28435
29904
|
if (/^\s*붙\s*임/.test(text)) text = text.replace(/^\s*붙\s*임\s*[::]?\s*/, "\uBD99\uC784 ");
|
|
28436
29905
|
else text = text.replace(/\s+$/, "");
|
|
28437
|
-
const paraId = reg.para({ align: "LEFT", before: first ? lineHu(scheme.body) : 0, lineSp: st.lineSp ?? scheme.lineSp
|
|
29906
|
+
const paraId = reg.para({ align: "LEFT", before: first ? lineHu(scheme.body) : 0, lineSp: st.lineSp ?? scheme.lineSp });
|
|
28438
29907
|
const base = { font: st.font, pt: st.pt, bold: st.bold };
|
|
28439
29908
|
return generateParagraph(text, paraId, reg.char(base), inlineMapper(reg, base));
|
|
28440
29909
|
};
|
|
@@ -28604,6 +30073,13 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
|
|
|
28604
30073
|
scheme
|
|
28605
30074
|
};
|
|
28606
30075
|
}
|
|
30076
|
+
function polishNode(n) {
|
|
30077
|
+
if (n.kind === "block") {
|
|
30078
|
+
const b = n.block;
|
|
30079
|
+
return b.type === "table" && b.rows ? { ...n, block: { ...b, rows: b.rows.map((r) => r.map(polishGongmunText)) } } : n;
|
|
30080
|
+
}
|
|
30081
|
+
return { ...n, text: polishGongmunText(n.text) };
|
|
30082
|
+
}
|
|
28607
30083
|
function legalDepthOf(marker) {
|
|
28608
30084
|
if (/^\d{1,2}\.$/.test(marker)) return 0;
|
|
28609
30085
|
if (/^[가-힣]\.$/.test(marker)) return 1;
|
|
@@ -28660,7 +30136,7 @@ async function markdownToHwpx(markdown, options) {
|
|
|
28660
30136
|
}
|
|
28661
30137
|
const measured = !!gongmun && usesReportFonts(gongmun.preset);
|
|
28662
30138
|
const richAssets = !!gongmun && needsGaejosikAssets(gongmun);
|
|
28663
|
-
const blocks = parseMarkdownToBlocks(md2);
|
|
30139
|
+
const blocks = gongmun ? parseMarkdownToBlocks(md2).map(polishGongmunBlock) : parseMarkdownToBlocks(md2);
|
|
28664
30140
|
const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
|
|
28665
30141
|
const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
|
|
28666
30142
|
const staticBfEnd = staticBorderFillNext(gongmun);
|
|
@@ -29040,6 +30516,8 @@ function parseRenderStyles(headXml) {
|
|
|
29040
30516
|
const root = doc.documentElement;
|
|
29041
30517
|
if (!root) return styles;
|
|
29042
30518
|
const hangulFonts = collectHangulFonts(root);
|
|
30519
|
+
const autoTabPr = /* @__PURE__ */ new Set();
|
|
30520
|
+
const paraTabRef = /* @__PURE__ */ new Map();
|
|
29043
30521
|
const walk = (el) => {
|
|
29044
30522
|
const tag = (el.tagName || "").replace(/^[^:]+:/, "");
|
|
29045
30523
|
if (tag === "charPr") {
|
|
@@ -29064,12 +30542,17 @@ function parseRenderStyles(headXml) {
|
|
|
29064
30542
|
face
|
|
29065
30543
|
});
|
|
29066
30544
|
}
|
|
30545
|
+
} else if (tag === "tabPr") {
|
|
30546
|
+
const id = el.getAttribute("id");
|
|
30547
|
+
if (id != null && el.getAttribute("autoTabLeft") === "1") autoTabPr.add(id);
|
|
29067
30548
|
} else if (tag === "paraPr") {
|
|
29068
30549
|
const id = el.getAttribute("id");
|
|
29069
30550
|
if (id != null) {
|
|
29070
30551
|
const align = findChildByLocalName(el, "align");
|
|
29071
30552
|
styles.paraAlign.set(id, align?.getAttribute("horizontal") || "JUSTIFY");
|
|
29072
30553
|
styles.paraGeom.set(id, parseParaGeom(el));
|
|
30554
|
+
const tab = el.getAttribute("tabPrIDRef");
|
|
30555
|
+
if (tab != null) paraTabRef.set(id, tab);
|
|
29073
30556
|
}
|
|
29074
30557
|
} else if (tag === "borderFill") {
|
|
29075
30558
|
const id = el.getAttribute("id");
|
|
@@ -29094,6 +30577,10 @@ function parseRenderStyles(headXml) {
|
|
|
29094
30577
|
}
|
|
29095
30578
|
};
|
|
29096
30579
|
walk(root);
|
|
30580
|
+
for (const [id, tab] of paraTabRef) {
|
|
30581
|
+
const g = styles.paraGeom.get(id);
|
|
30582
|
+
if (g && autoTabPr.has(tab)) g.autoTabLeft = true;
|
|
30583
|
+
}
|
|
29097
30584
|
return styles;
|
|
29098
30585
|
}
|
|
29099
30586
|
|
|
@@ -31241,7 +32728,8 @@ function patchParagraphUnit(block, orig, edited, ctx, skip) {
|
|
|
31241
32728
|
if (sanitizeText(newPlain) !== newPlain) {
|
|
31242
32729
|
return skip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uD328\uCE58 \uC2DC \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
|
|
31243
32730
|
}
|
|
31244
|
-
const
|
|
32731
|
+
const xml = ctx.scans[mapping.para.sectionIndex]?.xml;
|
|
32732
|
+
const splices = (xml ? markerRunSplices(mapping.para, xml, newPlain) : null) ?? buildParagraphSplices(mapping.para, newPlain, xml);
|
|
31245
32733
|
if (splices === null) return skip("\uBB38\uB2E8\uC5D0 \uD14D\uC2A4\uD2B8 \uB178\uB4DC\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC74C");
|
|
31246
32734
|
ctx.sectionSplices[mapping.para.sectionIndex].push(...splices);
|
|
31247
32735
|
return 1;
|
|
@@ -33335,28 +34823,214 @@ function solveRowHeights(cells, rowCount) {
|
|
|
33335
34823
|
return h;
|
|
33336
34824
|
}
|
|
33337
34825
|
|
|
34826
|
+
// src/render/para-model.ts
|
|
34827
|
+
function ln(el) {
|
|
34828
|
+
return (el.tagName || "").replace(/^[^:]+:/, "");
|
|
34829
|
+
}
|
|
34830
|
+
function elements(el) {
|
|
34831
|
+
const out = [];
|
|
34832
|
+
const children = el.childNodes;
|
|
34833
|
+
if (!children) return out;
|
|
34834
|
+
for (let i = 0; i < children.length; i++) {
|
|
34835
|
+
if (children[i].nodeType === 1) out.push(children[i]);
|
|
34836
|
+
}
|
|
34837
|
+
return out;
|
|
34838
|
+
}
|
|
34839
|
+
function num2(el, attr, fallback = 0) {
|
|
34840
|
+
return el ? toInt32(el.getAttribute(attr) ?? void 0, fallback) : fallback;
|
|
34841
|
+
}
|
|
34842
|
+
function findFirst(el, name, depth = 0) {
|
|
34843
|
+
if (depth > 64) return null;
|
|
34844
|
+
for (const ch of elements(el)) {
|
|
34845
|
+
if (ln(ch) === name) return ch;
|
|
34846
|
+
const found = findFirst(ch, name, depth + 1);
|
|
34847
|
+
if (found) return found;
|
|
34848
|
+
}
|
|
34849
|
+
return null;
|
|
34850
|
+
}
|
|
34851
|
+
var OBJ_TAGS = /* @__PURE__ */ new Set(["tbl", "pic", "container", "equation", "rect", "ellipse", "polygon", "curv", "line", "arc", "ole", "textart"]);
|
|
34852
|
+
var CHAR_CTRL_1SLOT = /* @__PURE__ */ new Set(["lineBreak", "hyphen", "nbSpace", "fwSpace"]);
|
|
34853
|
+
function pushFillers(chars, n, prId) {
|
|
34854
|
+
for (let i = 0; i < n; i++) chars.push({ ch: "", prId });
|
|
34855
|
+
}
|
|
34856
|
+
function pushTextSlots(t, chars, prId, depth) {
|
|
34857
|
+
if (depth > 32) return;
|
|
34858
|
+
const kids = t.childNodes;
|
|
34859
|
+
if (!kids) return;
|
|
34860
|
+
for (let i = 0; i < kids.length; i++) {
|
|
34861
|
+
const c = kids[i];
|
|
34862
|
+
if (c.nodeType === 3 || c.nodeType === 4) {
|
|
34863
|
+
for (const cp of c.textContent ?? "") {
|
|
34864
|
+
chars.push({ ch: cp, prId });
|
|
34865
|
+
if (cp.length === 2) chars.push({ ch: "", prId });
|
|
34866
|
+
}
|
|
34867
|
+
} else if (c.nodeType === 1) {
|
|
34868
|
+
const el = c;
|
|
34869
|
+
const tag = ln(el);
|
|
34870
|
+
if (tag === "tab") {
|
|
34871
|
+
chars.push({ ch: "", prId, tab: true, tabW: num2(el, "width") });
|
|
34872
|
+
pushFillers(chars, 7, prId);
|
|
34873
|
+
} else if (CHAR_CTRL_1SLOT.has(tag)) {
|
|
34874
|
+
chars.push(tag === "nbSpace" ? { ch: " ", prId, nb: true } : { ch: tag === "fwSpace" ? " " : "", prId });
|
|
34875
|
+
} else {
|
|
34876
|
+
pushTextSlots(el, chars, prId, depth + 1);
|
|
34877
|
+
}
|
|
34878
|
+
}
|
|
34879
|
+
}
|
|
34880
|
+
}
|
|
34881
|
+
function buildPara(p) {
|
|
34882
|
+
const chars = [];
|
|
34883
|
+
const objs = [];
|
|
34884
|
+
let segs = [];
|
|
34885
|
+
for (const runEl of elements(p)) {
|
|
34886
|
+
const tag = ln(runEl);
|
|
34887
|
+
if (tag === "run") {
|
|
34888
|
+
const prId = runEl.getAttribute("charPrIDRef");
|
|
34889
|
+
for (const ch of elements(runEl)) {
|
|
34890
|
+
const cn = ln(ch);
|
|
34891
|
+
if (cn === "t") {
|
|
34892
|
+
pushTextSlots(ch, chars, prId, 0);
|
|
34893
|
+
} else if (OBJ_TAGS.has(cn)) {
|
|
34894
|
+
const sz = findChildByLocalName(ch, "sz");
|
|
34895
|
+
const pos = findChildByLocalName(ch, "pos");
|
|
34896
|
+
const w = num2(sz, "width") || num2(findChildByLocalName(ch, "curSz"), "width") || num2(findChildByLocalName(ch, "orgSz"), "width");
|
|
34897
|
+
const h = num2(sz, "height") || num2(findChildByLocalName(ch, "curSz"), "height") || num2(findChildByLocalName(ch, "orgSz"), "height");
|
|
34898
|
+
const inline = pos?.getAttribute("treatAsChar") === "1";
|
|
34899
|
+
const om = inline && cn === "tbl" ? findChildByLocalName(ch, "outMargin") : null;
|
|
34900
|
+
objs.push({
|
|
34901
|
+
el: ch,
|
|
34902
|
+
tag: cn,
|
|
34903
|
+
index: chars.length,
|
|
34904
|
+
inline,
|
|
34905
|
+
width: w,
|
|
34906
|
+
height: h,
|
|
34907
|
+
omL: num2(om, "left"),
|
|
34908
|
+
omR: num2(om, "right")
|
|
34909
|
+
});
|
|
34910
|
+
pushFillers(chars, 8, prId);
|
|
34911
|
+
} else {
|
|
34912
|
+
pushFillers(chars, 8, prId);
|
|
34913
|
+
}
|
|
34914
|
+
}
|
|
34915
|
+
} else if (tag === "linesegarray") {
|
|
34916
|
+
segs = elements(runEl).filter((s) => ln(s) === "lineseg").map((s) => ({
|
|
34917
|
+
textpos: num2(s, "textpos"),
|
|
34918
|
+
vertpos: num2(s, "vertpos"),
|
|
34919
|
+
horzpos: num2(s, "horzpos"),
|
|
34920
|
+
horzsize: num2(s, "horzsize"),
|
|
34921
|
+
textheight: num2(s, "textheight", 1e3),
|
|
34922
|
+
baseline: num2(s, "baseline", 850)
|
|
34923
|
+
}));
|
|
34924
|
+
}
|
|
34925
|
+
}
|
|
34926
|
+
return { chars, segs, objs, paraPrId: p.getAttribute("paraPrIDRef") };
|
|
34927
|
+
}
|
|
34928
|
+
var DEFAULT_TAB_HU = 4e3;
|
|
34929
|
+
function tabAdvance(x, firstLine, geom, saved = 0) {
|
|
34930
|
+
const hang = geom && geom.marginIntent < 0 ? -geom.marginIntent : 0;
|
|
34931
|
+
if (firstLine && geom?.autoTabLeft && hang > 0 && x < hang - 0.5) return hang - x;
|
|
34932
|
+
if (saved > 0) return saved;
|
|
34933
|
+
return (Math.floor(x / DEFAULT_TAB_HU) + 1) * DEFAULT_TAB_HU - x;
|
|
34934
|
+
}
|
|
34935
|
+
function cellContentExtent(cell2, memo) {
|
|
34936
|
+
if (!cell2.sub) return 0;
|
|
34937
|
+
const hit = memo?.cell.get(cell2.el);
|
|
34938
|
+
if (hit !== void 0) return hit;
|
|
34939
|
+
let ext = 0;
|
|
34940
|
+
for (const p of elements(cell2.sub)) {
|
|
34941
|
+
if (ln(p) !== "p") continue;
|
|
34942
|
+
const m = buildPara(p);
|
|
34943
|
+
for (const s of m.segs) ext = Math.max(ext, s.vertpos + s.textheight);
|
|
34944
|
+
const baseV = m.segs[0]?.vertpos ?? 0;
|
|
34945
|
+
for (const o of m.objs) {
|
|
34946
|
+
if (o.inline) {
|
|
34947
|
+
const h = o.tag === "tbl" ? Math.max(o.height, measureTableHeight(o.el, memo)) : o.height;
|
|
34948
|
+
ext = Math.max(ext, baseV + h);
|
|
34949
|
+
continue;
|
|
34950
|
+
}
|
|
34951
|
+
const pos = findChildByLocalName(o.el, "pos");
|
|
34952
|
+
if ((pos?.getAttribute("vertRelTo") ?? "PARA") !== "PARA") continue;
|
|
34953
|
+
const om = findChildByLocalName(o.el, "outMargin");
|
|
34954
|
+
const pushed = baseV - (num2(om, "top") + o.height + num2(om, "bottom"));
|
|
34955
|
+
const anchor = pushed >= -100 ? pushed : baseV;
|
|
34956
|
+
ext = Math.max(ext, anchor + num2(om, "top") + num2(pos, "vertOffset") + o.height);
|
|
34957
|
+
}
|
|
34958
|
+
}
|
|
34959
|
+
memo?.cell.set(cell2.el, ext);
|
|
34960
|
+
return ext;
|
|
34961
|
+
}
|
|
34962
|
+
function collectCells(tbl2) {
|
|
34963
|
+
const inMargin = findChildByLocalName(tbl2, "inMargin");
|
|
34964
|
+
const defL = num2(inMargin, "left", 141), defR = num2(inMargin, "right", 141);
|
|
34965
|
+
const defT = num2(inMargin, "top", 141), defB = num2(inMargin, "bottom", 141);
|
|
34966
|
+
const cells = [];
|
|
34967
|
+
for (const tr of elements(tbl2)) {
|
|
34968
|
+
if (ln(tr) !== "tr") continue;
|
|
34969
|
+
for (const tc2 of elements(tr)) {
|
|
34970
|
+
if (ln(tc2) !== "tc") continue;
|
|
34971
|
+
const addr = findChildByLocalName(tc2, "cellAddr");
|
|
34972
|
+
const span = findChildByLocalName(tc2, "cellSpan");
|
|
34973
|
+
const csz = findChildByLocalName(tc2, "cellSz");
|
|
34974
|
+
const cm = findChildByLocalName(tc2, "cellMargin");
|
|
34975
|
+
if (!addr || !csz) continue;
|
|
34976
|
+
cells.push({
|
|
34977
|
+
el: tc2,
|
|
34978
|
+
// 음수 주소(uint32 역변환·손상 입력) 방어 — colX/rowY 인덱스 이탈로 NaN 좌표 방지
|
|
34979
|
+
ca: Math.max(0, num2(addr, "colAddr")),
|
|
34980
|
+
ra: Math.max(0, num2(addr, "rowAddr")),
|
|
34981
|
+
cs: Math.max(1, num2(span, "colSpan", 1)),
|
|
34982
|
+
rs: Math.max(1, num2(span, "rowSpan", 1)),
|
|
34983
|
+
w: num2(csz, "width"),
|
|
34984
|
+
h: num2(csz, "height"),
|
|
34985
|
+
bfId: tc2.getAttribute("borderFillIDRef"),
|
|
34986
|
+
sub: findChildByLocalName(tc2, "subList"),
|
|
34987
|
+
marginL: cm ? num2(cm, "left", defL) : defL,
|
|
34988
|
+
marginR: cm ? num2(cm, "right", defR) : defR,
|
|
34989
|
+
marginT: cm ? num2(cm, "top", defT) : defT,
|
|
34990
|
+
marginB: cm ? num2(cm, "bottom", defB) : defB
|
|
34991
|
+
});
|
|
34992
|
+
}
|
|
34993
|
+
}
|
|
34994
|
+
return cells;
|
|
34995
|
+
}
|
|
34996
|
+
function measureTableHeight(tbl2, memo) {
|
|
34997
|
+
const hit = memo?.table.get(tbl2);
|
|
34998
|
+
if (hit !== void 0) return hit;
|
|
34999
|
+
const cells = collectCells(tbl2);
|
|
35000
|
+
if (cells.length === 0 || cells.length > 4096) return 0;
|
|
35001
|
+
const nRows = Math.max(...cells.map((c) => c.ra + c.rs));
|
|
35002
|
+
const rowH = solveRowHeights(
|
|
35003
|
+
cells.map((c) => ({ rowAddr: c.ra, rowSpan: c.rs, height: c.h, contentH: c.rs === 1 ? cellContentExtent(c, memo) : void 0 })),
|
|
35004
|
+
nRows
|
|
35005
|
+
);
|
|
35006
|
+
let sum = 0;
|
|
35007
|
+
for (const h of rowH) sum += h;
|
|
35008
|
+
memo?.table.set(tbl2, sum);
|
|
35009
|
+
return sum;
|
|
35010
|
+
}
|
|
35011
|
+
|
|
33338
35012
|
// src/render/reflow.ts
|
|
33339
35013
|
var LINESEG_FLAGS = "393216";
|
|
33340
35014
|
var BASELINE_RATIO = 0.85;
|
|
33341
|
-
function
|
|
35015
|
+
function ln2(el) {
|
|
33342
35016
|
return (el.tagName || "").replace(/^[^:]+:/, "");
|
|
33343
35017
|
}
|
|
33344
|
-
function
|
|
35018
|
+
function elements2(el) {
|
|
33345
35019
|
const out = [];
|
|
33346
35020
|
const kids = el.childNodes;
|
|
33347
35021
|
if (!kids) return out;
|
|
33348
35022
|
for (let i = 0; i < kids.length; i++) if (kids[i].nodeType === 1) out.push(kids[i]);
|
|
33349
35023
|
return out;
|
|
33350
35024
|
}
|
|
33351
|
-
function
|
|
35025
|
+
function num3(el, attr, fallback = 0) {
|
|
33352
35026
|
return el ? toInt32(el.getAttribute(attr) ?? void 0, fallback) : fallback;
|
|
33353
35027
|
}
|
|
33354
35028
|
function shiftParaVert(p, delta) {
|
|
33355
|
-
for (const lsa of
|
|
33356
|
-
if (
|
|
33357
|
-
for (const seg of
|
|
33358
|
-
if (
|
|
33359
|
-
seg.setAttribute("vertpos", String(
|
|
35029
|
+
for (const lsa of elements2(p)) {
|
|
35030
|
+
if (ln2(lsa) !== "linesegarray") continue;
|
|
35031
|
+
for (const seg of elements2(lsa)) {
|
|
35032
|
+
if (ln2(seg) !== "lineseg") continue;
|
|
35033
|
+
seg.setAttribute("vertpos", String(num3(seg, "vertpos") + delta));
|
|
33360
35034
|
}
|
|
33361
35035
|
}
|
|
33362
35036
|
}
|
|
@@ -33377,15 +35051,31 @@ function pitchFor(height, geom) {
|
|
|
33377
35051
|
function reflowPara(p, doc, styles, areaW, startV, mode) {
|
|
33378
35052
|
const m = buildPara(p);
|
|
33379
35053
|
if (m.segs.length > 0) return null;
|
|
35054
|
+
const geom = styles.paraGeom.get(m.paraPrId ?? "") ?? DEFAULT_PARA_GEOM;
|
|
33380
35055
|
const realIdx = [];
|
|
35056
|
+
const widths = [];
|
|
33381
35057
|
let text = "";
|
|
35058
|
+
let x = Math.max(geom.marginIntent, 0);
|
|
33382
35059
|
for (let i = 0; i < m.chars.length; i++) {
|
|
33383
|
-
const
|
|
33384
|
-
if (
|
|
33385
|
-
|
|
33386
|
-
|
|
35060
|
+
const c = m.chars[i];
|
|
35061
|
+
if (c.tab) {
|
|
35062
|
+
const adv = tabAdvance(x, true, geom, c.tabW);
|
|
35063
|
+
realIdx.push(i);
|
|
35064
|
+
widths.push(adv);
|
|
35065
|
+
text += " ";
|
|
35066
|
+
x += adv;
|
|
35067
|
+
continue;
|
|
35068
|
+
}
|
|
35069
|
+
if (c.ch === "") continue;
|
|
35070
|
+
const st = (c.prId != null ? styles.charPr.get(c.prId) : void 0) ?? DEFAULT_CHAR;
|
|
35071
|
+
const w = measureTextWidth(c.ch, st.height, st.ratio, { spacingPct: st.spacing, faceClass: faceClassOf(st.face) });
|
|
35072
|
+
for (let u = 0; u < c.ch.length; u++) {
|
|
35073
|
+
realIdx.push(i);
|
|
35074
|
+
widths.push(u === 0 ? w : 0);
|
|
35075
|
+
}
|
|
35076
|
+
text += c.nb ? "\xA0" : c.ch;
|
|
35077
|
+
x += w;
|
|
33387
35078
|
}
|
|
33388
|
-
const geom = styles.paraGeom.get(m.paraPrId ?? "") ?? DEFAULT_PARA_GEOM;
|
|
33389
35079
|
let domChar = DEFAULT_CHAR;
|
|
33390
35080
|
for (const c of m.chars) {
|
|
33391
35081
|
if (c.ch !== "" && c.prId != null) {
|
|
@@ -33397,8 +35087,8 @@ function reflowPara(p, doc, styles, areaW, startV, mode) {
|
|
|
33397
35087
|
}
|
|
33398
35088
|
}
|
|
33399
35089
|
if (domChar === DEFAULT_CHAR) {
|
|
33400
|
-
for (const run of
|
|
33401
|
-
if (
|
|
35090
|
+
for (const run of elements2(p)) {
|
|
35091
|
+
if (ln2(run) !== "run") continue;
|
|
33402
35092
|
const st = styles.charPr.get(run.getAttribute("charPrIDRef") ?? "");
|
|
33403
35093
|
if (st) {
|
|
33404
35094
|
domChar = st;
|
|
@@ -33407,16 +35097,13 @@ function reflowPara(p, doc, styles, areaW, startV, mode) {
|
|
|
33407
35097
|
}
|
|
33408
35098
|
}
|
|
33409
35099
|
const height = domChar.height || 1e3;
|
|
33410
|
-
const ratio = domChar.ratio || 100;
|
|
33411
|
-
const spacingPct = domChar.spacing || 0;
|
|
33412
35100
|
const marginL = geom.marginLeft;
|
|
33413
35101
|
const avail = Math.max(1e3, areaW - marginL - geom.marginRight);
|
|
33414
35102
|
const firstWidth = avail;
|
|
33415
35103
|
const contWidth = Math.max(500, avail + Math.min(0, geom.marginIntent));
|
|
33416
35104
|
const contHorz = marginL - Math.min(0, geom.marginIntent);
|
|
33417
35105
|
const paraMode = geom.wrapMode ?? mode;
|
|
33418
|
-
const
|
|
33419
|
-
const wrap = text.length === 0 ? { lines: 1, starts: [0], lastLineWidth: 0 } : simulateWrap(text, firstWidth, contWidth, height, ratio, paraMode, { spacingPct, faceClass });
|
|
35106
|
+
const wrap = text.length === 0 ? { lines: 1, starts: [0], lastLineWidth: 0 } : simulateWrap(text, firstWidth, contWidth, height, 100, paraMode, { widths });
|
|
33420
35107
|
const pitch = pitchFor(height, geom);
|
|
33421
35108
|
const baseline = Math.round(height * BASELINE_RATIO);
|
|
33422
35109
|
const spacing = Math.max(0, pitch - height);
|
|
@@ -33426,7 +35113,7 @@ function reflowPara(p, doc, styles, areaW, startV, mode) {
|
|
|
33426
35113
|
const effH = o.tag === "tbl" ? Math.max(o.height, measureTableHeight(o.el)) : o.height;
|
|
33427
35114
|
const pos = findChildByLocalName(o.el, "pos");
|
|
33428
35115
|
const om = findChildByLocalName(o.el, "outMargin");
|
|
33429
|
-
const outT =
|
|
35116
|
+
const outT = num3(om, "top"), outB = num3(om, "bottom");
|
|
33430
35117
|
if (o.inline) {
|
|
33431
35118
|
objBottom = Math.max(objBottom, startV + outT + effH + outB + spacing);
|
|
33432
35119
|
continue;
|
|
@@ -33435,7 +35122,7 @@ function reflowPara(p, doc, styles, areaW, startV, mode) {
|
|
|
33435
35122
|
if (wrapAttr === "BEHIND_TEXT" || wrapAttr === "IN_FRONT_OF_TEXT") continue;
|
|
33436
35123
|
const vertRel = pos?.getAttribute("vertRelTo") ?? "PARA";
|
|
33437
35124
|
if (vertRel === "PAGE" || vertRel === "PAPER") continue;
|
|
33438
|
-
const vo = Math.max(0,
|
|
35125
|
+
const vo = Math.max(0, num3(pos, "vertOffset"));
|
|
33439
35126
|
if (wrapAttr === "TOP_AND_BOTTOM") {
|
|
33440
35127
|
floatBelow = Math.max(floatBelow, vo + outT + effH + outB);
|
|
33441
35128
|
} else {
|
|
@@ -33466,19 +35153,19 @@ function reflowPara(p, doc, styles, areaW, startV, mode) {
|
|
|
33466
35153
|
return { paraBottom: Math.max(textBottom, objBottom), spaceAfter: geom.spaceAfter };
|
|
33467
35154
|
}
|
|
33468
35155
|
function reflowTablesIn(p, doc, styles, mode, counter) {
|
|
33469
|
-
for (const run of
|
|
33470
|
-
if (
|
|
33471
|
-
for (const obj of
|
|
33472
|
-
if (
|
|
33473
|
-
for (const tr of
|
|
33474
|
-
if (
|
|
33475
|
-
for (const tc2 of
|
|
33476
|
-
if (
|
|
35156
|
+
for (const run of elements2(p)) {
|
|
35157
|
+
if (ln2(run) !== "run") continue;
|
|
35158
|
+
for (const obj of elements2(run)) {
|
|
35159
|
+
if (ln2(obj) !== "tbl") continue;
|
|
35160
|
+
for (const tr of elements2(obj)) {
|
|
35161
|
+
if (ln2(tr) !== "tr") continue;
|
|
35162
|
+
for (const tc2 of elements2(tr)) {
|
|
35163
|
+
if (ln2(tc2) !== "tc") continue;
|
|
33477
35164
|
const csz = findChildByLocalName(tc2, "cellSz");
|
|
33478
35165
|
const cm = findChildByLocalName(tc2, "cellMargin");
|
|
33479
|
-
const cellW =
|
|
33480
|
-
const mL = cm ?
|
|
33481
|
-
const mR = cm ?
|
|
35166
|
+
const cellW = num3(csz, "width");
|
|
35167
|
+
const mL = cm ? num3(cm, "left", 141) : 141;
|
|
35168
|
+
const mR = cm ? num3(cm, "right", 141) : 141;
|
|
33482
35169
|
const areaW = Math.max(500, cellW - mL - mR);
|
|
33483
35170
|
const sub = findChildByLocalName(tc2, "subList");
|
|
33484
35171
|
if (sub) reflowBlockFlow(sub, doc, styles, areaW, mode, counter, 0);
|
|
@@ -33490,8 +35177,8 @@ function reflowTablesIn(p, doc, styles, mode, counter) {
|
|
|
33490
35177
|
function reflowBlockFlow(container, doc, styles, areaW, mode, counter, bodyH) {
|
|
33491
35178
|
let cursorV = 0;
|
|
33492
35179
|
let prevSpaceAfter = 0;
|
|
33493
|
-
for (const p of
|
|
33494
|
-
if (
|
|
35180
|
+
for (const p of elements2(container)) {
|
|
35181
|
+
if (ln2(p) !== "p") continue;
|
|
33495
35182
|
reflowTablesIn(p, doc, styles, mode, counter);
|
|
33496
35183
|
const g = styles.paraGeom.get(p.getAttribute("paraPrIDRef") ?? "");
|
|
33497
35184
|
const startV = cursorV + prevSpaceAfter + (g?.spaceBefore ?? 0);
|
|
@@ -33500,10 +35187,10 @@ function reflowBlockFlow(container, doc, styles, areaW, mode, counter, bodyH) {
|
|
|
33500
35187
|
const lsa = findChildByLocalName(p, "linesegarray");
|
|
33501
35188
|
if (lsa) {
|
|
33502
35189
|
let bottom = Number.NEGATIVE_INFINITY;
|
|
33503
|
-
for (const seg of
|
|
33504
|
-
if (
|
|
33505
|
-
const th = Math.max(
|
|
33506
|
-
bottom = Math.max(bottom,
|
|
35190
|
+
for (const seg of elements2(lsa)) {
|
|
35191
|
+
if (ln2(seg) !== "lineseg") continue;
|
|
35192
|
+
const th = Math.max(num3(seg, "vertsize", 1e3), num3(seg, "textheight", 1e3));
|
|
35193
|
+
bottom = Math.max(bottom, num3(seg, "vertpos") + th + num3(seg, "spacing"));
|
|
33507
35194
|
}
|
|
33508
35195
|
if (Number.isFinite(bottom)) {
|
|
33509
35196
|
cursorV = bottom;
|
|
@@ -33562,34 +35249,9 @@ var RegionCollector = class {
|
|
|
33562
35249
|
};
|
|
33563
35250
|
|
|
33564
35251
|
// src/render/svg-render.ts
|
|
33565
|
-
function
|
|
33566
|
-
return (el.tagName || "").replace(/^[^:]+:/, "");
|
|
33567
|
-
}
|
|
33568
|
-
function elements2(el) {
|
|
33569
|
-
const out = [];
|
|
33570
|
-
const children = el.childNodes;
|
|
33571
|
-
if (!children) return out;
|
|
33572
|
-
for (let i = 0; i < children.length; i++) {
|
|
33573
|
-
if (children[i].nodeType === 1) out.push(children[i]);
|
|
33574
|
-
}
|
|
33575
|
-
return out;
|
|
33576
|
-
}
|
|
33577
|
-
function num3(el, attr, fallback = 0) {
|
|
33578
|
-
return el ? toInt32(el.getAttribute(attr) ?? void 0, fallback) : fallback;
|
|
33579
|
-
}
|
|
33580
|
-
function findFirst(el, name, depth = 0) {
|
|
33581
|
-
if (depth > 64) return null;
|
|
33582
|
-
for (const ch of elements2(el)) {
|
|
33583
|
-
if (ln2(ch) === name) return ch;
|
|
33584
|
-
const found = findFirst(ch, name, depth + 1);
|
|
33585
|
-
if (found) return found;
|
|
33586
|
-
}
|
|
33587
|
-
return null;
|
|
33588
|
-
}
|
|
33589
|
-
function escapeXml4(s) {
|
|
35252
|
+
function escapeXml7(s) {
|
|
33590
35253
|
return s.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
33591
35254
|
}
|
|
33592
|
-
var OBJ_TAGS = /* @__PURE__ */ new Set(["tbl", "pic", "container", "equation", "rect", "ellipse", "polygon", "curv", "line", "arc", "ole", "textart"]);
|
|
33593
35255
|
var pt = (u) => String(Math.round(u) / 100);
|
|
33594
35256
|
var ptNum = (u) => Math.round(u) / 100;
|
|
33595
35257
|
function pageNo(ctx) {
|
|
@@ -33613,84 +35275,9 @@ function warnOnce(ctx, key, msg2) {
|
|
|
33613
35275
|
ctx.warned.add(key);
|
|
33614
35276
|
ctx.warnings.push(msg2);
|
|
33615
35277
|
}
|
|
33616
|
-
var CHAR_CTRL_1SLOT = /* @__PURE__ */ new Set(["lineBreak", "hyphen", "nbSpace", "fwSpace"]);
|
|
33617
|
-
function pushFillers(chars, n, prId) {
|
|
33618
|
-
for (let i = 0; i < n; i++) chars.push({ ch: "", prId });
|
|
33619
|
-
}
|
|
33620
|
-
function pushTextSlots(t, chars, prId, depth) {
|
|
33621
|
-
if (depth > 32) return;
|
|
33622
|
-
const kids = t.childNodes;
|
|
33623
|
-
if (!kids) return;
|
|
33624
|
-
for (let i = 0; i < kids.length; i++) {
|
|
33625
|
-
const c = kids[i];
|
|
33626
|
-
if (c.nodeType === 3 || c.nodeType === 4) {
|
|
33627
|
-
for (const cp of c.textContent ?? "") {
|
|
33628
|
-
chars.push({ ch: cp, prId });
|
|
33629
|
-
if (cp.length === 2) chars.push({ ch: "", prId });
|
|
33630
|
-
}
|
|
33631
|
-
} else if (c.nodeType === 1) {
|
|
33632
|
-
const el = c;
|
|
33633
|
-
const tag = ln2(el);
|
|
33634
|
-
if (tag === "tab") {
|
|
33635
|
-
pushFillers(chars, 8, prId);
|
|
33636
|
-
} else if (CHAR_CTRL_1SLOT.has(tag)) {
|
|
33637
|
-
chars.push({ ch: tag === "nbSpace" || tag === "fwSpace" ? " " : "", prId });
|
|
33638
|
-
} else {
|
|
33639
|
-
pushTextSlots(el, chars, prId, depth + 1);
|
|
33640
|
-
}
|
|
33641
|
-
}
|
|
33642
|
-
}
|
|
33643
|
-
}
|
|
33644
|
-
function buildPara(p) {
|
|
33645
|
-
const chars = [];
|
|
33646
|
-
const objs = [];
|
|
33647
|
-
let segs = [];
|
|
33648
|
-
for (const runEl of elements2(p)) {
|
|
33649
|
-
const tag = ln2(runEl);
|
|
33650
|
-
if (tag === "run") {
|
|
33651
|
-
const prId = runEl.getAttribute("charPrIDRef");
|
|
33652
|
-
for (const ch of elements2(runEl)) {
|
|
33653
|
-
const cn = ln2(ch);
|
|
33654
|
-
if (cn === "t") {
|
|
33655
|
-
pushTextSlots(ch, chars, prId, 0);
|
|
33656
|
-
} else if (OBJ_TAGS.has(cn)) {
|
|
33657
|
-
const sz = findChildByLocalName(ch, "sz");
|
|
33658
|
-
const pos = findChildByLocalName(ch, "pos");
|
|
33659
|
-
const w = num3(sz, "width") || num3(findChildByLocalName(ch, "curSz"), "width") || num3(findChildByLocalName(ch, "orgSz"), "width");
|
|
33660
|
-
const h = num3(sz, "height") || num3(findChildByLocalName(ch, "curSz"), "height") || num3(findChildByLocalName(ch, "orgSz"), "height");
|
|
33661
|
-
const inline = pos?.getAttribute("treatAsChar") === "1";
|
|
33662
|
-
const om = inline && cn === "tbl" ? findChildByLocalName(ch, "outMargin") : null;
|
|
33663
|
-
objs.push({
|
|
33664
|
-
el: ch,
|
|
33665
|
-
tag: cn,
|
|
33666
|
-
index: chars.length,
|
|
33667
|
-
inline,
|
|
33668
|
-
width: w,
|
|
33669
|
-
height: h,
|
|
33670
|
-
omL: num3(om, "left"),
|
|
33671
|
-
omR: num3(om, "right")
|
|
33672
|
-
});
|
|
33673
|
-
pushFillers(chars, 8, prId);
|
|
33674
|
-
} else {
|
|
33675
|
-
pushFillers(chars, 8, prId);
|
|
33676
|
-
}
|
|
33677
|
-
}
|
|
33678
|
-
} else if (tag === "linesegarray") {
|
|
33679
|
-
segs = elements2(runEl).filter((s) => ln2(s) === "lineseg").map((s) => ({
|
|
33680
|
-
textpos: num3(s, "textpos"),
|
|
33681
|
-
vertpos: num3(s, "vertpos"),
|
|
33682
|
-
horzpos: num3(s, "horzpos"),
|
|
33683
|
-
horzsize: num3(s, "horzsize"),
|
|
33684
|
-
textheight: num3(s, "textheight", 1e3),
|
|
33685
|
-
baseline: num3(s, "baseline", 850)
|
|
33686
|
-
}));
|
|
33687
|
-
}
|
|
33688
|
-
}
|
|
33689
|
-
return { chars, segs, objs, paraPrId: p.getAttribute("paraPrIDRef") };
|
|
33690
|
-
}
|
|
33691
35278
|
function charW(c, styles) {
|
|
33692
35279
|
const st = (c.prId != null ? styles.charPr.get(c.prId) : void 0) ?? DEFAULT_CHAR;
|
|
33693
|
-
return measureTextWidth(c.ch, st.height, st.ratio, { spacingPct: st.spacing });
|
|
35280
|
+
return measureTextWidth(c.ch, st.height, st.ratio, { spacingPct: st.spacing, faceClass: faceClassOf(st.face) });
|
|
33694
35281
|
}
|
|
33695
35282
|
function lineNaturalWidth(m, styles, start, end) {
|
|
33696
35283
|
let text = 0;
|
|
@@ -33701,12 +35288,35 @@ function lineNaturalWidth(m, styles, start, end) {
|
|
|
33701
35288
|
}
|
|
33702
35289
|
function planLines(m, styles) {
|
|
33703
35290
|
const align = (m.paraPrId != null ? styles.paraAlign.get(m.paraPrId) : void 0) ?? "JUSTIFY";
|
|
35291
|
+
const geom = m.paraPrId != null ? styles.paraGeom.get(m.paraPrId) : void 0;
|
|
35292
|
+
const hang = geom && geom.marginIntent < 0 ? -geom.marginIntent : 0;
|
|
33704
35293
|
const plans = [];
|
|
33705
35294
|
for (let i = 0; i < m.segs.length; i++) {
|
|
33706
35295
|
const seg = m.segs[i];
|
|
33707
35296
|
const start = seg.textpos;
|
|
33708
35297
|
const end = i + 1 < m.segs.length ? m.segs[i + 1].textpos : Math.max(m.chars.length, start);
|
|
33709
|
-
const
|
|
35298
|
+
const tabs = /* @__PURE__ */ new Map();
|
|
35299
|
+
let x = i === 0 ? Math.max(geom?.marginIntent ?? 0, 0) : hang;
|
|
35300
|
+
let fixedTo = start;
|
|
35301
|
+
let fixedW = 0;
|
|
35302
|
+
for (let k = start; k < end && k < m.chars.length; k++) {
|
|
35303
|
+
const c = m.chars[k];
|
|
35304
|
+
if (!c.tab) {
|
|
35305
|
+
x += charW(c, styles);
|
|
35306
|
+
continue;
|
|
35307
|
+
}
|
|
35308
|
+
const adv = tabAdvance(x, i === 0, geom, c.tabW);
|
|
35309
|
+
tabs.set(k, adv);
|
|
35310
|
+
x += adv;
|
|
35311
|
+
fixedTo = k + 1;
|
|
35312
|
+
}
|
|
35313
|
+
if (fixedTo > start) fixedW = lineNaturalWidth(m, styles, start, fixedTo).text + [...tabs.values()].reduce((a, b) => a + b, 0);
|
|
35314
|
+
let textEnd = Math.min(end, m.chars.length);
|
|
35315
|
+
while (textEnd > fixedTo && m.chars[textEnd - 1].ch === " ") textEnd--;
|
|
35316
|
+
const nat = lineNaturalWidth(m, styles, fixedTo, textEnd);
|
|
35317
|
+
for (const o of m.objs) if (o.inline && o.index >= textEnd && o.index < end) nat.obj += o.omL + o.width + o.omR;
|
|
35318
|
+
nat.obj += fixedW;
|
|
35319
|
+
for (const o of m.objs) if (o.inline && o.index >= start && o.index < fixedTo) nat.obj += o.omL + o.width + o.omR;
|
|
33710
35320
|
const isLast = i === m.segs.length - 1;
|
|
33711
35321
|
let xoff = 0;
|
|
33712
35322
|
let scale2 = 1;
|
|
@@ -33720,13 +35330,15 @@ function planLines(m, styles) {
|
|
|
33720
35330
|
}
|
|
33721
35331
|
if (!Number.isFinite(scale2) || scale2 <= 0) scale2 = 1;
|
|
33722
35332
|
scale2 = Math.min(4, Math.max(0.25, scale2));
|
|
33723
|
-
plans.push({ seg, xoff, scale: scale2, start, end });
|
|
35333
|
+
plans.push({ seg, xoff, scale: scale2, start, end, tabs, fixedTo, textEnd });
|
|
33724
35334
|
}
|
|
33725
35335
|
return plans;
|
|
33726
35336
|
}
|
|
33727
35337
|
function advanceTo(m, styles, plan, upto) {
|
|
33728
35338
|
let x = 0;
|
|
33729
|
-
for (let i = plan.start; i < upto && i < m.chars.length; i++)
|
|
35339
|
+
for (let i = plan.start; i < upto && i < m.chars.length; i++) {
|
|
35340
|
+
x += m.chars[i].tab ? plan.tabs.get(i) ?? 0 : charW(m.chars[i], styles) * (i < plan.fixedTo ? 1 : plan.scale);
|
|
35341
|
+
}
|
|
33730
35342
|
for (const o of m.objs) if (o.inline && o.index >= plan.start && o.index < upto) x += o.omL + o.width + o.omR;
|
|
33731
35343
|
return x;
|
|
33732
35344
|
}
|
|
@@ -33766,15 +35378,21 @@ function drawPara(p, ox, oy, areaW, ctx, depth, segPages) {
|
|
|
33766
35378
|
let cursor = ox + seg.horzpos + plan.xoff;
|
|
33767
35379
|
const y = oy + seg.vertpos + seg.baseline;
|
|
33768
35380
|
while (i < plan.end && i < m.chars.length) {
|
|
35381
|
+
if (i >= plan.textEnd && m.chars[i].ch === " ") {
|
|
35382
|
+
i++;
|
|
35383
|
+
continue;
|
|
35384
|
+
}
|
|
33769
35385
|
if (m.chars[i].ch === "") {
|
|
35386
|
+
if (m.chars[i].tab) cursor += plan.tabs.get(i) ?? 0;
|
|
33770
35387
|
for (const o of m.objs) if (o.inline && o.index === i) cursor += o.omL + o.width + o.omR;
|
|
33771
35388
|
i++;
|
|
33772
35389
|
continue;
|
|
33773
35390
|
}
|
|
35391
|
+
const scale2 = i < plan.fixedTo ? 1 : plan.scale;
|
|
33774
35392
|
const prId = m.chars[i].prId;
|
|
33775
35393
|
let j = i;
|
|
33776
35394
|
let piece = "";
|
|
33777
|
-
while (j < plan.end && j < m.chars.length && m.chars[j].prId === prId && m.chars[j].ch !== "") {
|
|
35395
|
+
while (j < plan.end && j < m.chars.length && m.chars[j].prId === prId && m.chars[j].ch !== "" && !(j >= plan.textEnd && m.chars[j].ch === " ")) {
|
|
33778
35396
|
piece += m.chars[j].ch;
|
|
33779
35397
|
j++;
|
|
33780
35398
|
}
|
|
@@ -33791,21 +35409,21 @@ function drawPara(p, ox, oy, areaW, ctx, depth, segPages) {
|
|
|
33791
35409
|
}
|
|
33792
35410
|
const st = (prId != null ? ctx.styles.charPr.get(prId) : void 0) ?? DEFAULT_CHAR;
|
|
33793
35411
|
const renderSeg = (text, cx, hit) => {
|
|
33794
|
-
const sw = measureTextWidth(text, st.height, st.ratio, { spacingPct: st.spacing }) *
|
|
35412
|
+
const sw = measureTextWidth(text, st.height, st.ratio, { spacingPct: st.spacing, faceClass: faceClassOf(st.face) }) * scale2;
|
|
33795
35413
|
if (hit) {
|
|
33796
35414
|
emit(ctx, `<rect x="${pt(cx)}" y="${pt(oy + seg.vertpos)}" width="${pt(sw)}" height="${pt(seg.textheight)}" fill="#ffd54f" fill-opacity="0.45"/>`);
|
|
33797
35415
|
}
|
|
33798
35416
|
if (text.trim().length > 0) {
|
|
33799
35417
|
const attrs = [`x="${pt(cx)}"`, `y="${pt(y)}"`, `font-size="${pt(st.height)}"`];
|
|
33800
|
-
if (st.fontFamily) attrs.push(`font-family="${
|
|
35418
|
+
if (st.fontFamily) attrs.push(`font-family="${escapeXml7(st.fontFamily)}"`);
|
|
33801
35419
|
if ([...text].length > 1 && sw > 50) {
|
|
33802
|
-
attrs.push(`textLength="${pt(sw)}"`, `lengthAdjust="${
|
|
35420
|
+
attrs.push(`textLength="${pt(sw)}"`, `lengthAdjust="${scale2 < 1 ? "spacingAndGlyphs" : "spacing"}"`);
|
|
33803
35421
|
}
|
|
33804
35422
|
if (st.bold) attrs.push(`font-weight="bold"`);
|
|
33805
35423
|
if (st.italic) attrs.push(`font-style="italic"`);
|
|
33806
35424
|
if (st.underline) attrs.push(`text-decoration="underline"`);
|
|
33807
|
-
if (st.color) attrs.push(`fill="${
|
|
33808
|
-
emit(ctx, `<text ${attrs.join(" ")}>${
|
|
35425
|
+
if (st.color) attrs.push(`fill="${escapeXml7(st.color)}"`);
|
|
35426
|
+
emit(ctx, `<text ${attrs.join(" ")}>${escapeXml7(text)}</text>`);
|
|
33809
35427
|
ctx.stats.texts++;
|
|
33810
35428
|
}
|
|
33811
35429
|
return sw;
|
|
@@ -33868,11 +35486,11 @@ function anchorObject(o, ox, oy, baseV, areaW, ctx) {
|
|
|
33868
35486
|
const { PW, PH, ML, MT, BODY_W, BODY_H } = ctx.geom;
|
|
33869
35487
|
const pos = findChildByLocalName(o.el, "pos");
|
|
33870
35488
|
const om = findChildByLocalName(o.el, "outMargin");
|
|
33871
|
-
const omT =
|
|
35489
|
+
const omT = num2(om, "top"), omB = num2(om, "bottom");
|
|
33872
35490
|
const w = o.width, h = o.tag === "tbl" ? Math.max(o.height, measureTableHeight(o.el, ctx.extentMemo)) : o.height;
|
|
33873
35491
|
if (!pos) return { x: ox, y: oy + baseV };
|
|
33874
|
-
const vo =
|
|
33875
|
-
const ho =
|
|
35492
|
+
const vo = num2(pos, "vertOffset");
|
|
35493
|
+
const ho = num2(pos, "horzOffset");
|
|
33876
35494
|
const vrel = pos.getAttribute("vertRelTo") ?? "PARA";
|
|
33877
35495
|
const hrel = pos.getAttribute("horzRelTo") ?? "PARA";
|
|
33878
35496
|
const va = pos.getAttribute("vertAlign") ?? "TOP";
|
|
@@ -33904,13 +35522,13 @@ function drawObject(o, x, y, baseV, areaW, ctx, depth) {
|
|
|
33904
35522
|
if (o.tag === "tbl") drawTable(o.el, x, y, ctx, depth + 1);
|
|
33905
35523
|
else if (o.tag === "pic") drawPic(o.el, x, y, ctx);
|
|
33906
35524
|
else if (o.tag === "container") {
|
|
33907
|
-
for (const ch of
|
|
33908
|
-
const tag =
|
|
35525
|
+
for (const ch of elements(o.el)) {
|
|
35526
|
+
const tag = ln(ch);
|
|
33909
35527
|
if (!OBJ_TAGS.has(tag)) continue;
|
|
33910
35528
|
const sz = findChildByLocalName(ch, "sz");
|
|
33911
35529
|
const off = findChildByLocalName(ch, "offset");
|
|
33912
|
-
const sub = { el: ch, tag, index: 0, inline: true, width:
|
|
33913
|
-
drawObject(sub, x +
|
|
35530
|
+
const sub = { el: ch, tag, index: 0, inline: true, width: num2(sz, "width"), height: num2(sz, "height"), omL: 0, omR: 0 };
|
|
35531
|
+
drawObject(sub, x + num2(off, "x"), y + num2(off, "y"), baseV, areaW, ctx, depth + 1);
|
|
33914
35532
|
}
|
|
33915
35533
|
} else if (o.tag === "equation") {
|
|
33916
35534
|
warnOnce(ctx, "equation", "\uC218\uC2DD \uAC1C\uCCB4\uB294 \uB80C\uB354 \uBBF8\uC9C0\uC6D0 \u2014 \uC0DD\uB7B5");
|
|
@@ -33928,23 +35546,23 @@ function drawShape(o, x, y, ctx, depth) {
|
|
|
33928
35546
|
const el = o.el;
|
|
33929
35547
|
const orgSz = findChildByLocalName(el, "orgSz");
|
|
33930
35548
|
const curSz = findChildByLocalName(el, "curSz");
|
|
33931
|
-
const ow =
|
|
33932
|
-
const w =
|
|
33933
|
-
const h =
|
|
35549
|
+
const ow = num2(orgSz, "width"), oh = num2(orgSz, "height");
|
|
35550
|
+
const w = num2(curSz, "width") || ow || o.width;
|
|
35551
|
+
const h = num2(curSz, "height") || oh || o.height;
|
|
33934
35552
|
const sx = ow > 0 ? w / ow : 1;
|
|
33935
35553
|
const sy = oh > 0 ? h / oh : 1;
|
|
33936
35554
|
const lineShape = findChildByLocalName(el, "lineShape");
|
|
33937
35555
|
const lstyle = lineShape?.getAttribute("style") ?? "SOLID";
|
|
33938
35556
|
const strokeCol = lineShape?.getAttribute("color") || "#000000";
|
|
33939
35557
|
const hasStroke = lstyle !== "NONE";
|
|
33940
|
-
const strokeW = hasStroke ? shapeStrokePt(lineShape ?
|
|
35558
|
+
const strokeW = hasStroke ? shapeStrokePt(lineShape ? num2(lineShape, "width") : 33) : 0;
|
|
33941
35559
|
const dash = /DASH|DOT/.test(lstyle) ? ` stroke-dasharray="${lstyle.includes("DOT") ? "1,1.5" : "3,1.5"}"` : "";
|
|
33942
|
-
const strokeAttr = hasStroke ? ` stroke="${
|
|
35560
|
+
const strokeAttr = hasStroke ? ` stroke="${escapeXml7(strokeCol)}" stroke-width="${strokeW.toFixed(2)}"${dash}` : "";
|
|
33943
35561
|
const fillBrush = findChildByLocalName(el, "fillBrush");
|
|
33944
35562
|
const winBrush = fillBrush ? findChildByLocalName(fillBrush, "winBrush") : null;
|
|
33945
35563
|
const face = winBrush?.getAttribute("faceColor");
|
|
33946
35564
|
const fill = face && face.toLowerCase() !== "none" ? face : "none";
|
|
33947
|
-
const fillAttr = ` fill="${fill === "none" ? "none" :
|
|
35565
|
+
const fillAttr = ` fill="${fill === "none" ? "none" : escapeXml7(fill)}"`;
|
|
33948
35566
|
ctx.stats.shapes++;
|
|
33949
35567
|
const shapeId = ctx.regions.add("shape", bboxOf(ctx, x, y, w, h), { parentId: parentId(ctx) });
|
|
33950
35568
|
emit(ctx, regionOpenTag(shapeId, "shape", pageNo(ctx)));
|
|
@@ -33955,103 +35573,27 @@ function drawShape(o, x, y, ctx, depth) {
|
|
|
33955
35573
|
emit(ctx, `<ellipse cx="${pt(x + w / 2)}" cy="${pt(y + h / 2)}" rx="${pt(w / 2)}" ry="${pt(h / 2)}"${fillAttr}${strokeAttr}/>`);
|
|
33956
35574
|
} else if (o.tag === "line") {
|
|
33957
35575
|
const s = findChildByLocalName(el, "startPt"), e = findChildByLocalName(el, "endPt");
|
|
33958
|
-
const x1 = x +
|
|
33959
|
-
const x2 = x +
|
|
33960
|
-
emit(ctx, `<line x1="${pt(x1)}" y1="${pt(y1)}" x2="${pt(x2)}" y2="${pt(y2)}" stroke="${
|
|
35576
|
+
const x1 = x + num2(s, "x") * sx, y1 = y + num2(s, "y") * sy;
|
|
35577
|
+
const x2 = x + num2(e, "x") * sx, y2 = y + num2(e, "y") * sy;
|
|
35578
|
+
emit(ctx, `<line x1="${pt(x1)}" y1="${pt(y1)}" x2="${pt(x2)}" y2="${pt(y2)}" stroke="${escapeXml7(strokeCol)}" stroke-width="${(strokeW || 0.3).toFixed(2)}"${dash}/>`);
|
|
33961
35579
|
} else if (o.tag === "polygon" || o.tag === "curv") {
|
|
33962
35580
|
const pts = [];
|
|
33963
|
-
for (const c of
|
|
35581
|
+
for (const c of elements(el)) if (ln(c) === "pt") pts.push(`${pt(x + num2(c, "x") * sx)},${pt(y + num2(c, "y") * sy)}`);
|
|
33964
35582
|
if (pts.length >= 2) emit(ctx, `<polygon points="${pts.join(" ")}"${fillAttr}${strokeAttr}/>`);
|
|
33965
35583
|
} else if (o.tag === "arc") {
|
|
33966
|
-
emit(ctx, `<ellipse cx="${pt(x + w / 2)}" cy="${pt(y + h / 2)}" rx="${pt(w / 2)}" ry="${pt(h / 2)}" fill="none"${strokeAttr || ` stroke="${
|
|
35584
|
+
emit(ctx, `<ellipse cx="${pt(x + w / 2)}" cy="${pt(y + h / 2)}" rx="${pt(w / 2)}" ry="${pt(h / 2)}" fill="none"${strokeAttr || ` stroke="${escapeXml7(strokeCol)}" stroke-width="0.3"`}/>`);
|
|
33967
35585
|
}
|
|
33968
35586
|
const dt = findChildByLocalName(el, "drawText");
|
|
33969
35587
|
const sub = dt ? findChildByLocalName(dt, "subList") : null;
|
|
33970
35588
|
if (sub) {
|
|
33971
|
-
for (const p of
|
|
35589
|
+
for (const p of elements(sub)) if (ln(p) === "p") drawPara(p, x, y, w, ctx, depth + 1);
|
|
33972
35590
|
}
|
|
33973
35591
|
ctx.parentStack.pop();
|
|
33974
35592
|
emit(ctx, "</g>");
|
|
33975
35593
|
}
|
|
33976
|
-
function cellContentExtent(cell2, memo) {
|
|
33977
|
-
if (!cell2.sub) return 0;
|
|
33978
|
-
const hit = memo?.cell.get(cell2.el);
|
|
33979
|
-
if (hit !== void 0) return hit;
|
|
33980
|
-
let ext = 0;
|
|
33981
|
-
for (const p of elements2(cell2.sub)) {
|
|
33982
|
-
if (ln2(p) !== "p") continue;
|
|
33983
|
-
const m = buildPara(p);
|
|
33984
|
-
for (const s of m.segs) ext = Math.max(ext, s.vertpos + s.textheight);
|
|
33985
|
-
const baseV = m.segs[0]?.vertpos ?? 0;
|
|
33986
|
-
for (const o of m.objs) {
|
|
33987
|
-
if (o.inline) {
|
|
33988
|
-
const h = o.tag === "tbl" ? Math.max(o.height, measureTableHeight(o.el, memo)) : o.height;
|
|
33989
|
-
ext = Math.max(ext, baseV + h);
|
|
33990
|
-
continue;
|
|
33991
|
-
}
|
|
33992
|
-
const pos = findChildByLocalName(o.el, "pos");
|
|
33993
|
-
if ((pos?.getAttribute("vertRelTo") ?? "PARA") !== "PARA") continue;
|
|
33994
|
-
const om = findChildByLocalName(o.el, "outMargin");
|
|
33995
|
-
const pushed = baseV - (num3(om, "top") + o.height + num3(om, "bottom"));
|
|
33996
|
-
const anchor = pushed >= -100 ? pushed : baseV;
|
|
33997
|
-
ext = Math.max(ext, anchor + num3(om, "top") + num3(pos, "vertOffset") + o.height);
|
|
33998
|
-
}
|
|
33999
|
-
}
|
|
34000
|
-
memo?.cell.set(cell2.el, ext);
|
|
34001
|
-
return ext;
|
|
34002
|
-
}
|
|
34003
35594
|
function edgeLine(x1, y1, x2, y2, e) {
|
|
34004
35595
|
const dash = /DASH|DOT/.test(e.type) ? ` stroke-dasharray="${e.type.includes("DOT") ? "1,1.5" : "3,1.5"}"` : "";
|
|
34005
|
-
return `<line x1="${pt(x1)}" y1="${pt(y1)}" x2="${pt(x2)}" y2="${pt(y2)}" stroke="${
|
|
34006
|
-
}
|
|
34007
|
-
function collectCells(tbl2) {
|
|
34008
|
-
const inMargin = findChildByLocalName(tbl2, "inMargin");
|
|
34009
|
-
const defL = num3(inMargin, "left", 141), defR = num3(inMargin, "right", 141);
|
|
34010
|
-
const defT = num3(inMargin, "top", 141), defB = num3(inMargin, "bottom", 141);
|
|
34011
|
-
const cells = [];
|
|
34012
|
-
for (const tr of elements2(tbl2)) {
|
|
34013
|
-
if (ln2(tr) !== "tr") continue;
|
|
34014
|
-
for (const tc2 of elements2(tr)) {
|
|
34015
|
-
if (ln2(tc2) !== "tc") continue;
|
|
34016
|
-
const addr = findChildByLocalName(tc2, "cellAddr");
|
|
34017
|
-
const span = findChildByLocalName(tc2, "cellSpan");
|
|
34018
|
-
const csz = findChildByLocalName(tc2, "cellSz");
|
|
34019
|
-
const cm = findChildByLocalName(tc2, "cellMargin");
|
|
34020
|
-
if (!addr || !csz) continue;
|
|
34021
|
-
cells.push({
|
|
34022
|
-
el: tc2,
|
|
34023
|
-
// 음수 주소(uint32 역변환·손상 입력) 방어 — colX/rowY 인덱스 이탈로 NaN 좌표 방지
|
|
34024
|
-
ca: Math.max(0, num3(addr, "colAddr")),
|
|
34025
|
-
ra: Math.max(0, num3(addr, "rowAddr")),
|
|
34026
|
-
cs: Math.max(1, num3(span, "colSpan", 1)),
|
|
34027
|
-
rs: Math.max(1, num3(span, "rowSpan", 1)),
|
|
34028
|
-
w: num3(csz, "width"),
|
|
34029
|
-
h: num3(csz, "height"),
|
|
34030
|
-
bfId: tc2.getAttribute("borderFillIDRef"),
|
|
34031
|
-
sub: findChildByLocalName(tc2, "subList"),
|
|
34032
|
-
marginL: cm ? num3(cm, "left", defL) : defL,
|
|
34033
|
-
marginR: cm ? num3(cm, "right", defR) : defR,
|
|
34034
|
-
marginT: cm ? num3(cm, "top", defT) : defT,
|
|
34035
|
-
marginB: cm ? num3(cm, "bottom", defB) : defB
|
|
34036
|
-
});
|
|
34037
|
-
}
|
|
34038
|
-
}
|
|
34039
|
-
return cells;
|
|
34040
|
-
}
|
|
34041
|
-
function measureTableHeight(tbl2, memo) {
|
|
34042
|
-
const hit = memo?.table.get(tbl2);
|
|
34043
|
-
if (hit !== void 0) return hit;
|
|
34044
|
-
const cells = collectCells(tbl2);
|
|
34045
|
-
if (cells.length === 0 || cells.length > 4096) return 0;
|
|
34046
|
-
const nRows = Math.max(...cells.map((c) => c.ra + c.rs));
|
|
34047
|
-
const rowH = solveRowHeights(
|
|
34048
|
-
cells.map((c) => ({ rowAddr: c.ra, rowSpan: c.rs, height: c.h, contentH: c.rs === 1 ? cellContentExtent(c, memo) : void 0 })),
|
|
34049
|
-
nRows
|
|
34050
|
-
);
|
|
34051
|
-
let sum = 0;
|
|
34052
|
-
for (const h of rowH) sum += h;
|
|
34053
|
-
memo?.table.set(tbl2, sum);
|
|
34054
|
-
return sum;
|
|
35596
|
+
return `<line x1="${pt(x1)}" y1="${pt(y1)}" x2="${pt(x2)}" y2="${pt(y2)}" stroke="${escapeXml7(e.color)}" stroke-width="${e.widthPt.toFixed(2)}"${dash}/>`;
|
|
34055
35597
|
}
|
|
34056
35598
|
function drawTable(tbl2, tx, ty, ctx, depth) {
|
|
34057
35599
|
if (depth > 16) {
|
|
@@ -34065,7 +35607,7 @@ function drawTable(tbl2, tx, ty, ctx, depth) {
|
|
|
34065
35607
|
const nCols = Math.max(...cells.map((c) => c.ca + c.cs));
|
|
34066
35608
|
const nRows = Math.max(...cells.map((c) => c.ra + c.rs));
|
|
34067
35609
|
const colCons = cells.map((c) => ({ a: c.ca, b: c.ca + c.cs, size: c.w }));
|
|
34068
|
-
const colX = solveBoundaries(colCons, nCols,
|
|
35610
|
+
const colX = solveBoundaries(colCons, nCols, num2(tblSz, "width") || void 0);
|
|
34069
35611
|
const rowH = solveRowHeights(
|
|
34070
35612
|
cells.map((c) => ({ rowAddr: c.ra, rowSpan: c.rs, height: c.h, contentH: c.rs === 1 ? cellContentExtent(c, ctx.extentMemo) : void 0 })),
|
|
34071
35613
|
nRows
|
|
@@ -34086,7 +35628,7 @@ function drawTable(tbl2, tx, ty, ctx, depth) {
|
|
|
34086
35628
|
}));
|
|
34087
35629
|
for (const g of geom) {
|
|
34088
35630
|
const bf = g.c.bfId != null ? ctx.styles.borderFill.get(g.c.bfId) : void 0;
|
|
34089
|
-
if (bf?.fill) emit(ctx, `<rect x="${pt(g.x)}" y="${pt(g.y)}" width="${pt(g.w)}" height="${pt(g.h)}" fill="${
|
|
35631
|
+
if (bf?.fill) emit(ctx, `<rect x="${pt(g.x)}" y="${pt(g.y)}" width="${pt(g.w)}" height="${pt(g.h)}" fill="${escapeXml7(bf.fill)}"/>`);
|
|
34090
35632
|
}
|
|
34091
35633
|
for (const g of geom) {
|
|
34092
35634
|
const { c } = g;
|
|
@@ -34097,8 +35639,8 @@ function drawTable(tbl2, tx, ty, ctx, depth) {
|
|
|
34097
35639
|
let yoff = 0;
|
|
34098
35640
|
if (va === "CENTER") yoff = Math.max(0, (innerH - extent) / 2);
|
|
34099
35641
|
else if (va === "BOTTOM") yoff = Math.max(0, innerH - extent);
|
|
34100
|
-
for (const p of
|
|
34101
|
-
if (
|
|
35642
|
+
for (const p of elements(c.sub)) {
|
|
35643
|
+
if (ln(p) !== "p") continue;
|
|
34102
35644
|
drawPara(p, g.x + c.marginL, g.y + c.marginT + yoff, g.w - c.marginL - c.marginR, ctx, depth + 1);
|
|
34103
35645
|
}
|
|
34104
35646
|
}
|
|
@@ -34124,7 +35666,7 @@ function imageSymbol(loaded, ctx) {
|
|
|
34124
35666
|
}
|
|
34125
35667
|
function drawPic(pic, x, y, ctx) {
|
|
34126
35668
|
const sz = findChildByLocalName(pic, "sz");
|
|
34127
|
-
const w =
|
|
35669
|
+
const w = num2(sz, "width", 5669), h = num2(sz, "height", 5669);
|
|
34128
35670
|
const img = findFirst(pic, "img");
|
|
34129
35671
|
const ref = img?.getAttribute("binaryItemIDRef");
|
|
34130
35672
|
const loaded = ref != null ? ctx.images.get(ref) : void 0;
|
|
@@ -34140,11 +35682,11 @@ function drawPic(pic, x, y, ctx) {
|
|
|
34140
35682
|
const clip = findChildByLocalName(pic, "imgClip");
|
|
34141
35683
|
const imgDim = findChildByLocalName(pic, "imgDim");
|
|
34142
35684
|
const orgSz = findChildByLocalName(pic, "orgSz");
|
|
34143
|
-
const dimW =
|
|
34144
|
-
const refW = dimW > 0 ? dimW :
|
|
34145
|
-
const refH = dimH > 0 ? dimH :
|
|
34146
|
-
const cl =
|
|
34147
|
-
const cr =
|
|
35685
|
+
const dimW = num2(imgDim, "dimwidth"), dimH = num2(imgDim, "dimheight");
|
|
35686
|
+
const refW = dimW > 0 ? dimW : num2(orgSz, "width");
|
|
35687
|
+
const refH = dimH > 0 ? dimH : num2(orgSz, "height");
|
|
35688
|
+
const cl = num2(clip, "left"), ct = num2(clip, "top");
|
|
35689
|
+
const cr = num2(clip, "right", refW), cb = num2(clip, "bottom", refH);
|
|
34148
35690
|
const cropped = refW > 0 && refH > 0 && clip != null && (cl > 0 || ct > 0 || cr < refW || cb < refH) && cr > cl && cb > ct;
|
|
34149
35691
|
const symId = imageSymbol(loaded, ctx);
|
|
34150
35692
|
if (cropped) {
|
|
@@ -34169,23 +35711,23 @@ function sniffMime(name, bytes) {
|
|
|
34169
35711
|
function readSectionGeom(root) {
|
|
34170
35712
|
const pagePr = findFirst(root, "pagePr");
|
|
34171
35713
|
const margin = pagePr ? findChildByLocalName(pagePr, "margin") : null;
|
|
34172
|
-
let PW =
|
|
35714
|
+
let PW = num2(pagePr, "width", 59528), PH = num2(pagePr, "height", 84188);
|
|
34173
35715
|
if (pagePr?.getAttribute("landscape") === "NARROWLY" && PW < PH) {
|
|
34174
35716
|
const t = PW;
|
|
34175
35717
|
PW = PH;
|
|
34176
35718
|
PH = t;
|
|
34177
35719
|
}
|
|
34178
|
-
const ML =
|
|
34179
|
-
const MT =
|
|
34180
|
-
const BODY_H = PH - MT -
|
|
34181
|
-
const BODY_W = PW - ML -
|
|
35720
|
+
const ML = num2(margin, "left", 8504);
|
|
35721
|
+
const MT = num2(margin, "top", 5668) + num2(margin, "header", 0);
|
|
35722
|
+
const BODY_H = PH - MT - num2(margin, "bottom", 4252) - num2(margin, "footer", 0);
|
|
35723
|
+
const BODY_W = PW - ML - num2(margin, "right", 8504);
|
|
34182
35724
|
return { PW, PH, ML, MT, BODY_W, BODY_H };
|
|
34183
35725
|
}
|
|
34184
35726
|
function renderSectionToPages(root, geom, ctxBase, doReflow, reflowMode) {
|
|
34185
35727
|
const { PW, PH, ML, MT, BODY_W, BODY_H } = geom;
|
|
34186
35728
|
if (doReflow) reflowSection(root, ctxBase.styles, { BODY_W, BODY_H }, reflowMode);
|
|
34187
35729
|
const colPr = findFirst(root, "colPr");
|
|
34188
|
-
const multiCol =
|
|
35730
|
+
const multiCol = num2(colPr, "colCount", 1) > 1;
|
|
34189
35731
|
const paraSegPages = /* @__PURE__ */ new Map();
|
|
34190
35732
|
let nPages = 1;
|
|
34191
35733
|
let maxTopV = 0;
|
|
@@ -34193,20 +35735,20 @@ function renderSectionToPages(root, geom, ctxBase, doReflow, reflowMode) {
|
|
|
34193
35735
|
let prevV = Number.NEGATIVE_INFINITY;
|
|
34194
35736
|
let prevH = Number.NEGATIVE_INFINITY;
|
|
34195
35737
|
let cur = 0;
|
|
34196
|
-
for (const p of
|
|
34197
|
-
if (
|
|
35738
|
+
for (const p of elements(root)) {
|
|
35739
|
+
if (ln(p) !== "p") continue;
|
|
34198
35740
|
const lsa = findChildByLocalName(p, "linesegarray");
|
|
34199
|
-
const segEls = lsa ?
|
|
35741
|
+
const segEls = lsa ? elements(lsa).filter((s) => ln(s) === "lineseg") : [];
|
|
34200
35742
|
const pagesOf = [];
|
|
34201
35743
|
let paraFirst = true;
|
|
34202
35744
|
for (const s of segEls) {
|
|
34203
|
-
const v =
|
|
34204
|
-
const h =
|
|
35745
|
+
const v = num2(s, "vertpos");
|
|
35746
|
+
const h = num2(s, "horzpos");
|
|
34205
35747
|
const brk = v < prevV ? !multiCol || h <= prevH : paraFirst && v === prevV && h <= prevH;
|
|
34206
35748
|
if (brk) cur++;
|
|
34207
35749
|
paraFirst = false;
|
|
34208
35750
|
pagesOf.push(cur);
|
|
34209
|
-
maxTopV = Math.max(maxTopV, v +
|
|
35751
|
+
maxTopV = Math.max(maxTopV, v + num2(s, "textheight", 1e3));
|
|
34210
35752
|
prevV = v;
|
|
34211
35753
|
prevH = h;
|
|
34212
35754
|
}
|
|
@@ -34222,8 +35764,8 @@ function renderSectionToPages(root, geom, ctxBase, doReflow, reflowMode) {
|
|
|
34222
35764
|
geom,
|
|
34223
35765
|
pageH
|
|
34224
35766
|
};
|
|
34225
|
-
for (const p of
|
|
34226
|
-
if (
|
|
35767
|
+
for (const p of elements(root)) {
|
|
35768
|
+
if (ln(p) !== "p") continue;
|
|
34227
35769
|
drawPara(p, ML, MT, BODY_W, ctx, 0, paraSegPages.get(p));
|
|
34228
35770
|
}
|
|
34229
35771
|
return { pages: ctx.pages, pageH };
|
|
@@ -34635,7 +36177,7 @@ function paragraphXml(records, i, j, level, ctx, depth) {
|
|
|
34635
36177
|
let textBuf = "";
|
|
34636
36178
|
const flushText = () => {
|
|
34637
36179
|
if (textBuf) {
|
|
34638
|
-
run.push(`<hp:t>${
|
|
36180
|
+
run.push(`<hp:t>${escapeXml7(textBuf)}</hp:t>`);
|
|
34639
36181
|
textBuf = "";
|
|
34640
36182
|
}
|
|
34641
36183
|
};
|
|
@@ -34954,7 +36496,7 @@ import { readFile } from "fs/promises";
|
|
|
34954
36496
|
|
|
34955
36497
|
// src/render/html.ts
|
|
34956
36498
|
function renderSceneToHtml(scene, pageSvgs, options = {}) {
|
|
34957
|
-
const title =
|
|
36499
|
+
const title = escapeXml7(options.title ?? "kordoc");
|
|
34958
36500
|
const first = scene.pages.find((p) => pageSvgs.has(p.page)) ?? scene.pages[0];
|
|
34959
36501
|
const pageSize = first ? `${first.width}pt ${first.height}pt` : "auto";
|
|
34960
36502
|
const pages = [...pageSvgs.keys()].sort((a, b) => a - b).map((n) => {
|
|
@@ -35280,6 +36822,9 @@ async function dispatch(format, buffer, opts) {
|
|
|
35280
36822
|
const zipFormat = await detectZipFormat(buffer);
|
|
35281
36823
|
if (zipFormat === "xlsx") return parseXlsx(buffer, opts);
|
|
35282
36824
|
if (zipFormat === "docx") return parseDocx(buffer, opts);
|
|
36825
|
+
if (zipFormat === "pptx") {
|
|
36826
|
+
return { success: false, fileType: "pptx", error: "PPTX \uD30C\uC77C\uC740 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4.", code: "UNSUPPORTED_FORMAT" };
|
|
36827
|
+
}
|
|
35283
36828
|
return parseHwpx(buffer, opts);
|
|
35284
36829
|
}
|
|
35285
36830
|
case "hwp": {
|
|
@@ -35301,7 +36846,7 @@ async function dispatch(format, buffer, opts) {
|
|
|
35301
36846
|
}
|
|
35302
36847
|
async function parseImage(buffer, options) {
|
|
35303
36848
|
try {
|
|
35304
|
-
const { parseImageDocument } = await import("./image-ocr-
|
|
36849
|
+
const { parseImageDocument } = await import("./image-ocr-FLIL7MGN.js");
|
|
35305
36850
|
const { blocks, warnings } = await parseImageDocument(buffer, options);
|
|
35306
36851
|
return {
|
|
35307
36852
|
success: true,
|
|
@@ -35360,7 +36905,7 @@ async function parseHwp(buffer, options) {
|
|
|
35360
36905
|
async function parsePdf(buffer, options) {
|
|
35361
36906
|
let parsePdfDocument;
|
|
35362
36907
|
try {
|
|
35363
|
-
const mod = await import("./parser-
|
|
36908
|
+
const mod = await import("./parser-A4TMPJAM.js");
|
|
35364
36909
|
parsePdfDocument = mod.parsePdfDocument;
|
|
35365
36910
|
} catch {
|
|
35366
36911
|
return {
|