kordoc 3.8.4 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/{-ZAIG6FWT.js → -3B5FDXW2.js} +18 -12
- package/dist/{chunk-2UDAEQPW.js → chunk-5DL6VCIJ.js} +4 -120
- package/dist/chunk-5DL6VCIJ.js.map +1 -0
- package/dist/{chunk-6EDNKPXQ.js → chunk-5TK4X4JQ.js} +373 -315
- package/dist/chunk-5TK4X4JQ.js.map +1 -0
- package/dist/chunk-FU25KFFZ.js +938 -0
- package/dist/chunk-FU25KFFZ.js.map +1 -0
- package/dist/chunk-MZA7AXHN.js +124 -0
- package/dist/chunk-MZA7AXHN.js.map +1 -0
- package/dist/{chunk-T4SGNVVS.js → chunk-PNXOUDS7.js} +2 -2
- package/dist/{chunk-T4SGNVVS.js.map → chunk-PNXOUDS7.js.map} +1 -1
- package/dist/{chunk-Z3O36LBJ.cjs → chunk-ZQOGTAT5.cjs} +2 -2
- package/dist/{chunk-Z3O36LBJ.cjs.map → chunk-ZQOGTAT5.cjs.map} +1 -1
- package/dist/cli.js +33 -6
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1136 -173
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +1018 -55
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +8 -5
- package/dist/mcp.js.map +1 -1
- package/dist/{parser-ZVKCFXR3.cjs → parser-6B7BUSX3.cjs} +14 -14
- package/dist/{parser-ZVKCFXR3.cjs.map → parser-6B7BUSX3.cjs.map} +1 -1
- package/dist/{parser-2THIF623.js → parser-DKIA66MN.js} +2 -2
- package/dist/{parser-PR7CPMM4.js → parser-VCJTQVAH.js} +8 -6
- package/dist/{parser-PR7CPMM4.js.map → parser-VCJTQVAH.js.map} +1 -1
- package/dist/render-4I72JOAR.js +9 -0
- package/dist/render-4I72JOAR.js.map +1 -0
- package/dist/{watch-2HYPNMOB.js → watch-MQTMNUSB.js} +6 -4
- package/dist/{watch-2HYPNMOB.js.map → watch-MQTMNUSB.js.map} +1 -1
- package/package.json +2 -2
- package/dist/chunk-2UDAEQPW.js.map +0 -1
- package/dist/chunk-6EDNKPXQ.js.map +0 -1
- /package/dist/{-ZAIG6FWT.js.map → -3B5FDXW2.js.map} +0 -0
- /package/dist/{parser-2THIF623.js.map → parser-DKIA66MN.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
sanitizeHref,
|
|
20
20
|
stripDtd,
|
|
21
21
|
toArrayBuffer
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-PNXOUDS7.js";
|
|
23
23
|
import {
|
|
24
24
|
parsePageRange
|
|
25
25
|
} from "./chunk-GE43BE46.js";
|
|
@@ -478,9 +478,9 @@ async function extractHwpxStyles(zip, decompressed) {
|
|
|
478
478
|
function parseCharProperties(doc, map) {
|
|
479
479
|
const tagNames = ["hh:charPr", "charPr", "hp:charPr"];
|
|
480
480
|
for (const tagName of tagNames) {
|
|
481
|
-
const
|
|
482
|
-
for (let i = 0; i <
|
|
483
|
-
const el =
|
|
481
|
+
const elements2 = doc.getElementsByTagName(tagName);
|
|
482
|
+
for (let i = 0; i < elements2.length; i++) {
|
|
483
|
+
const el = elements2[i];
|
|
484
484
|
const id = el.getAttribute("id") || el.getAttribute("IDRef") || "";
|
|
485
485
|
if (!id) continue;
|
|
486
486
|
const prop = {};
|
|
@@ -514,9 +514,9 @@ function parseCharProperties(doc, map) {
|
|
|
514
514
|
function parseStyleElements(doc, map) {
|
|
515
515
|
const tagNames = ["hh:style", "style", "hp:style"];
|
|
516
516
|
for (const tagName of tagNames) {
|
|
517
|
-
const
|
|
518
|
-
for (let i = 0; i <
|
|
519
|
-
const el =
|
|
517
|
+
const elements2 = doc.getElementsByTagName(tagName);
|
|
518
|
+
for (let i = 0; i < elements2.length; i++) {
|
|
519
|
+
const el = elements2[i];
|
|
520
520
|
const id = el.getAttribute("id") || el.getAttribute("IDRef") || String(i);
|
|
521
521
|
const name = el.getAttribute("name") || el.getAttribute("engName") || "";
|
|
522
522
|
const charPrId = el.getAttribute("charPrIDRef") || void 0;
|
|
@@ -528,9 +528,9 @@ function parseStyleElements(doc, map) {
|
|
|
528
528
|
function parseNumberings(doc, map) {
|
|
529
529
|
const tagNames = ["hh:numbering", "numbering"];
|
|
530
530
|
for (const tagName of tagNames) {
|
|
531
|
-
const
|
|
532
|
-
for (let i = 0; i <
|
|
533
|
-
const el =
|
|
531
|
+
const elements2 = doc.getElementsByTagName(tagName);
|
|
532
|
+
for (let i = 0; i < elements2.length; i++) {
|
|
533
|
+
const el = elements2[i];
|
|
534
534
|
const id = el.getAttribute("id") || "";
|
|
535
535
|
if (!id) continue;
|
|
536
536
|
const def = { heads: /* @__PURE__ */ new Map() };
|
|
@@ -557,9 +557,9 @@ function parseNumberings(doc, map) {
|
|
|
557
557
|
function parseBullets(doc, map) {
|
|
558
558
|
const tagNames = ["hh:bullet", "bullet"];
|
|
559
559
|
for (const tagName of tagNames) {
|
|
560
|
-
const
|
|
561
|
-
for (let i = 0; i <
|
|
562
|
-
const el =
|
|
560
|
+
const elements2 = doc.getElementsByTagName(tagName);
|
|
561
|
+
for (let i = 0; i < elements2.length; i++) {
|
|
562
|
+
const el = elements2[i];
|
|
563
563
|
const id = el.getAttribute("id") || "";
|
|
564
564
|
const char = el.getAttribute("char") || "";
|
|
565
565
|
if (id && char) map.set(id, char);
|
|
@@ -570,9 +570,9 @@ function parseBullets(doc, map) {
|
|
|
570
570
|
function parseParaHeadings(doc, map) {
|
|
571
571
|
const tagNames = ["hh:paraPr", "paraPr"];
|
|
572
572
|
for (const tagName of tagNames) {
|
|
573
|
-
const
|
|
574
|
-
for (let i = 0; i <
|
|
575
|
-
const el =
|
|
573
|
+
const elements2 = doc.getElementsByTagName(tagName);
|
|
574
|
+
for (let i = 0; i < elements2.length; i++) {
|
|
575
|
+
const el = elements2[i];
|
|
576
576
|
const id = el.getAttribute("id") || "";
|
|
577
577
|
if (!id) continue;
|
|
578
578
|
const heading = findChildByLocalName(el, "heading");
|
|
@@ -664,8 +664,10 @@ var CONVERT_MAP = {
|
|
|
664
664
|
SUCC: "\\succ",
|
|
665
665
|
UPLUS: "\\uplus",
|
|
666
666
|
"\xB1": "\\pm",
|
|
667
|
+
"+-": "\\pm",
|
|
667
668
|
"-+": "\\mp",
|
|
668
669
|
"\xF7": "\\div",
|
|
670
|
+
cdot: "\\cdot",
|
|
669
671
|
CIRC: "\\circ",
|
|
670
672
|
BULLET: "\\bullet",
|
|
671
673
|
DEG: " ^\\circ",
|
|
@@ -1054,6 +1056,10 @@ function hmlToLatex(hmlEqStr) {
|
|
|
1054
1056
|
const t = tokens[i];
|
|
1055
1057
|
if (t in CONVERT_MAP) tokens[i] = CONVERT_MAP[t];
|
|
1056
1058
|
else if (t in MIDDLE_CONVERT_MAP) tokens[i] = MIDDLE_CONVERT_MAP[t];
|
|
1059
|
+
else {
|
|
1060
|
+
const quoted = /^"(.+)"$/.exec(t);
|
|
1061
|
+
if (quoted) tokens[i] = `\\text{${quoted[1]}}`;
|
|
1062
|
+
}
|
|
1057
1063
|
}
|
|
1058
1064
|
tokens = tokens.filter((tok) => tok.length !== 0);
|
|
1059
1065
|
tokens = replaceBracket(tokens);
|
|
@@ -2499,11 +2505,11 @@ function formatRoman(n, upper) {
|
|
|
2499
2505
|
const values = [1e3, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
|
|
2500
2506
|
const symbols = upper ? ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"] : ["m", "cm", "d", "cd", "c", "xc", "l", "xl", "x", "ix", "v", "iv", "i"];
|
|
2501
2507
|
let result = "";
|
|
2502
|
-
let
|
|
2508
|
+
let num2 = n;
|
|
2503
2509
|
for (let i = 0; i < values.length; i++) {
|
|
2504
|
-
while (
|
|
2510
|
+
while (num2 >= values[i]) {
|
|
2505
2511
|
result += symbols[i];
|
|
2506
|
-
|
|
2512
|
+
num2 -= values[i];
|
|
2507
2513
|
}
|
|
2508
2514
|
}
|
|
2509
2515
|
return result;
|
|
@@ -2511,11 +2517,11 @@ function formatRoman(n, upper) {
|
|
|
2511
2517
|
function formatLatin(n, upper) {
|
|
2512
2518
|
if (n <= 0) return "";
|
|
2513
2519
|
let result = "";
|
|
2514
|
-
let
|
|
2515
|
-
while (
|
|
2516
|
-
|
|
2517
|
-
result = String.fromCharCode((upper ? 65 : 97) +
|
|
2518
|
-
|
|
2520
|
+
let num2 = n;
|
|
2521
|
+
while (num2 > 0) {
|
|
2522
|
+
num2--;
|
|
2523
|
+
result = String.fromCharCode((upper ? 65 : 97) + num2 % 26) + result;
|
|
2524
|
+
num2 = Math.floor(num2 / 26);
|
|
2519
2525
|
}
|
|
2520
2526
|
return result;
|
|
2521
2527
|
}
|
|
@@ -2523,15 +2529,15 @@ function formatEastAsianNumber(n, digits, units, zero) {
|
|
|
2523
2529
|
if (n === 0) return zero;
|
|
2524
2530
|
if (n < 0 || n > 99999) return String(n);
|
|
2525
2531
|
let result = "";
|
|
2526
|
-
let
|
|
2532
|
+
let num2 = n;
|
|
2527
2533
|
let unit = 0;
|
|
2528
|
-
while (
|
|
2529
|
-
const d =
|
|
2534
|
+
while (num2 > 0) {
|
|
2535
|
+
const d = num2 % 10;
|
|
2530
2536
|
if (d > 0) {
|
|
2531
2537
|
const digitStr = d === 1 && unit > 0 ? "" : digits[d];
|
|
2532
2538
|
result = digitStr + units[unit] + result;
|
|
2533
2539
|
}
|
|
2534
|
-
|
|
2540
|
+
num2 = Math.floor(num2 / 10);
|
|
2535
2541
|
unit++;
|
|
2536
2542
|
}
|
|
2537
2543
|
return result;
|
|
@@ -2578,8 +2584,8 @@ function expandNumberingFormat(formatStr, counters, numbering) {
|
|
|
2578
2584
|
const idx = levelRef - 1;
|
|
2579
2585
|
const counterVal = counters[idx] ?? 0;
|
|
2580
2586
|
const start = numbering.startNumbers[idx] ?? 1;
|
|
2581
|
-
const
|
|
2582
|
-
result += formatNumber(
|
|
2587
|
+
const num2 = counterVal > 0 ? start - 1 + counterVal : start;
|
|
2588
|
+
result += formatNumber(num2, headFormatToNumFmt(numbering.numberFormats[idx] ?? 0));
|
|
2583
2589
|
i += 2;
|
|
2584
2590
|
continue;
|
|
2585
2591
|
}
|
|
@@ -4147,11 +4153,11 @@ function applyCtrlEffect(ctrl, records, ctx) {
|
|
|
4147
4153
|
const attr = ctrl.data.readUInt32LE(4);
|
|
4148
4154
|
const type = attr & 15;
|
|
4149
4155
|
const format = attr >>> 4 & 255;
|
|
4150
|
-
const
|
|
4151
|
-
ctx.doc.autoCounters.set(type,
|
|
4156
|
+
const num2 = ctx.doc.autoCounters.get(type) ?? 1;
|
|
4157
|
+
ctx.doc.autoCounters.set(type, num2 + 1);
|
|
4152
4158
|
const prefix = ctrl.data.length >= 14 ? wcharAt(ctrl.data, 12) : "";
|
|
4153
4159
|
const suffix = ctrl.data.length >= 16 ? wcharAt(ctrl.data, 14) : "";
|
|
4154
|
-
ctrl.inlineText = `${prefix}${formatNumber(
|
|
4160
|
+
ctrl.inlineText = `${prefix}${formatNumber(num2, shapeFormatToNumFmt(format))}${suffix}`;
|
|
4155
4161
|
}
|
|
4156
4162
|
return;
|
|
4157
4163
|
}
|
|
@@ -4159,8 +4165,8 @@ function applyCtrlEffect(ctrl, records, ctx) {
|
|
|
4159
4165
|
if (ctrl.data.length >= 10) {
|
|
4160
4166
|
const attr = ctrl.data.readUInt32LE(4);
|
|
4161
4167
|
const type = attr & 15;
|
|
4162
|
-
const
|
|
4163
|
-
if (
|
|
4168
|
+
const num2 = ctrl.data.readUInt16LE(8);
|
|
4169
|
+
if (num2 > 0) ctx.doc.autoCounters.set(type, num2);
|
|
4164
4170
|
}
|
|
4165
4171
|
return;
|
|
4166
4172
|
}
|
|
@@ -4222,7 +4228,7 @@ function blocksPlainText(blocks, sep) {
|
|
|
4222
4228
|
return parts.join(sep).trim();
|
|
4223
4229
|
}
|
|
4224
4230
|
function applyNoteEffect(ctrl, records, ctx, autoType) {
|
|
4225
|
-
const
|
|
4231
|
+
const num2 = ctx.doc.autoCounters.get(autoType) ?? 1;
|
|
4226
4232
|
let before = "";
|
|
4227
4233
|
let after = "";
|
|
4228
4234
|
let shape = 0;
|
|
@@ -4233,11 +4239,11 @@ function applyNoteEffect(ctrl, records, ctx, autoType) {
|
|
|
4233
4239
|
if (ctrl.data.length >= 16) {
|
|
4234
4240
|
shape = ctrl.data.readUInt32LE(12) & 255;
|
|
4235
4241
|
}
|
|
4236
|
-
const formatted = formatNumber(
|
|
4242
|
+
const formatted = formatNumber(num2, shapeFormatToNumFmt(shape));
|
|
4237
4243
|
const marker = before || after ? `${before}${formatted}${after}` : `${formatted})`;
|
|
4238
4244
|
const content = blocksPlainText(parseListHeaderParagraphs(ctrl, records, ctx), " ");
|
|
4239
|
-
if ((ctx.doc.autoCounters.get(autoType) ?? 1) <=
|
|
4240
|
-
ctx.doc.autoCounters.set(autoType,
|
|
4245
|
+
if ((ctx.doc.autoCounters.get(autoType) ?? 1) <= num2) {
|
|
4246
|
+
ctx.doc.autoCounters.set(autoType, num2 + 1);
|
|
4241
4247
|
}
|
|
4242
4248
|
ctrl.inlineText = marker;
|
|
4243
4249
|
if (content) ctrl.footnote = content.startsWith(marker) ? content : `${marker} ${content}`;
|
|
@@ -16775,9 +16781,9 @@ var MAX_ROWS2 = 1e4;
|
|
|
16775
16781
|
var MAX_COLS2 = 200;
|
|
16776
16782
|
function cleanNumericValue(raw) {
|
|
16777
16783
|
if (!/^-?\d+\.\d+$/.test(raw)) return raw;
|
|
16778
|
-
const
|
|
16779
|
-
if (!isFinite(
|
|
16780
|
-
const cleaned = parseFloat(
|
|
16784
|
+
const num2 = parseFloat(raw);
|
|
16785
|
+
if (!isFinite(num2)) return raw;
|
|
16786
|
+
const cleaned = parseFloat(num2.toPrecision(15)).toString();
|
|
16781
16787
|
return cleaned;
|
|
16782
16788
|
}
|
|
16783
16789
|
function parseCellRef(ref) {
|
|
@@ -17120,17 +17126,17 @@ function decodeRk(rk) {
|
|
|
17120
17126
|
const fDiv100 = (rk & 1) !== 0;
|
|
17121
17127
|
const fInt = (rk & 2) !== 0;
|
|
17122
17128
|
const val30 = rk >> 2;
|
|
17123
|
-
let
|
|
17129
|
+
let num2;
|
|
17124
17130
|
if (fInt) {
|
|
17125
|
-
|
|
17131
|
+
num2 = val30;
|
|
17126
17132
|
} else {
|
|
17127
17133
|
const high32 = (rk & 4294967292) >>> 0;
|
|
17128
17134
|
const buf = Buffer.alloc(8);
|
|
17129
17135
|
buf.writeUInt32LE(0, 0);
|
|
17130
17136
|
buf.writeUInt32LE(high32, 4);
|
|
17131
|
-
|
|
17137
|
+
num2 = buf.readDoubleLE(0);
|
|
17132
17138
|
}
|
|
17133
|
-
return fDiv100 ?
|
|
17139
|
+
return fDiv100 ? num2 / 100 : num2;
|
|
17134
17140
|
}
|
|
17135
17141
|
function decodeMulRk(data) {
|
|
17136
17142
|
if (data.length < 6) return null;
|
|
@@ -17830,9 +17836,9 @@ function nodeToLatex(el) {
|
|
|
17830
17836
|
case "f": {
|
|
17831
17837
|
const n = firstKid(el, "num");
|
|
17832
17838
|
const d = firstKid(el, "den");
|
|
17833
|
-
const
|
|
17839
|
+
const num2 = n ? childrenToLatex(n) : "";
|
|
17834
17840
|
const den = d ? childrenToLatex(d) : "";
|
|
17835
|
-
return "\\frac" + grp(
|
|
17841
|
+
return "\\frac" + grp(num2) + grp(den);
|
|
17836
17842
|
}
|
|
17837
17843
|
// 첨자
|
|
17838
17844
|
case "sSup": {
|
|
@@ -20473,10 +20479,10 @@ function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "kee
|
|
|
20473
20479
|
const spacing = opts?.spacingPct ?? 0;
|
|
20474
20480
|
const k = height * ratioPct / 100 / 1e3;
|
|
20475
20481
|
const cwCp = (cp) => (cp === 32 ? spaceEm : charWidthEm1000(cp)) * (1 + spacing / 100) * k;
|
|
20476
|
-
const
|
|
20482
|
+
const charW2 = (ch) => cwCp(ch.codePointAt(0));
|
|
20477
20483
|
const rangeW = (from, to) => {
|
|
20478
20484
|
let w = 0;
|
|
20479
|
-
for (const ch of text.slice(from, to)) w +=
|
|
20485
|
+
for (const ch of text.slice(from, to)) w += charW2(ch);
|
|
20480
20486
|
return w;
|
|
20481
20487
|
};
|
|
20482
20488
|
const units = text.match(mode === "keep" ? / +|[^ ]+/g : / +|[^ ]/g) ?? [];
|
|
@@ -20497,7 +20503,7 @@ function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "kee
|
|
|
20497
20503
|
};
|
|
20498
20504
|
for (const u of units) {
|
|
20499
20505
|
if (u[0] === " ") {
|
|
20500
|
-
lineW +=
|
|
20506
|
+
lineW += charW2(" ") * u.length;
|
|
20501
20507
|
pos += u.length;
|
|
20502
20508
|
continue;
|
|
20503
20509
|
}
|
|
@@ -20510,7 +20516,7 @@ function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "kee
|
|
|
20510
20516
|
if (lineW === 0 || w > contWidth + EPS) {
|
|
20511
20517
|
let sub = 0;
|
|
20512
20518
|
for (const ch of u) {
|
|
20513
|
-
const c =
|
|
20519
|
+
const c = charW2(ch);
|
|
20514
20520
|
if (lineW + c > avail + EPS && lineW > 0) breakBefore(pos + sub, 0);
|
|
20515
20521
|
lineW += c;
|
|
20516
20522
|
sub += ch.length;
|
|
@@ -20770,6 +20776,16 @@ function buildPrvText(blocks) {
|
|
|
20770
20776
|
}
|
|
20771
20777
|
return lines.join("\n").slice(0, 1024);
|
|
20772
20778
|
}
|
|
20779
|
+
function findMathDelim(s, from) {
|
|
20780
|
+
let i = s.indexOf("$$", from);
|
|
20781
|
+
while (i > 0) {
|
|
20782
|
+
let backslashes = 0;
|
|
20783
|
+
for (let j = i - 1; j >= 0 && s[j] === "\\"; j--) backslashes++;
|
|
20784
|
+
if (backslashes % 2 === 0) break;
|
|
20785
|
+
i = s.indexOf("$$", i + 1);
|
|
20786
|
+
}
|
|
20787
|
+
return i;
|
|
20788
|
+
}
|
|
20773
20789
|
function parseMarkdownToBlocks(md2) {
|
|
20774
20790
|
const lines = md2.split("\n");
|
|
20775
20791
|
const blocks = [];
|
|
@@ -20780,6 +20796,45 @@ function parseMarkdownToBlocks(md2) {
|
|
|
20780
20796
|
i++;
|
|
20781
20797
|
continue;
|
|
20782
20798
|
}
|
|
20799
|
+
const mathOpen = /^\s*\$\$/.exec(line);
|
|
20800
|
+
if (mathOpen) {
|
|
20801
|
+
const afterOpen = line.slice(mathOpen[0].length);
|
|
20802
|
+
const closeSame = findMathDelim(afterOpen, 0);
|
|
20803
|
+
if (closeSame >= 0) {
|
|
20804
|
+
const inner = afterOpen.slice(0, closeSame).trim();
|
|
20805
|
+
const trailing2 = afterOpen.slice(closeSame + 2).trim();
|
|
20806
|
+
if (inner) blocks.push({ type: "equation", text: inner });
|
|
20807
|
+
if (trailing2) blocks.push({ type: "paragraph", text: trailing2 });
|
|
20808
|
+
i++;
|
|
20809
|
+
continue;
|
|
20810
|
+
}
|
|
20811
|
+
const mathLines = [];
|
|
20812
|
+
if (afterOpen.trim()) mathLines.push(afterOpen);
|
|
20813
|
+
let closed = false;
|
|
20814
|
+
let trailing = "";
|
|
20815
|
+
let j = i + 1;
|
|
20816
|
+
for (; j < lines.length; j++) {
|
|
20817
|
+
const l = lines[j];
|
|
20818
|
+
if (!l.trim() || /^\s*(`{3,}|~{3,})/.test(l)) break;
|
|
20819
|
+
const end = findMathDelim(l, 0);
|
|
20820
|
+
if (end >= 0) {
|
|
20821
|
+
const before = l.slice(0, end);
|
|
20822
|
+
if (before.trim()) mathLines.push(before);
|
|
20823
|
+
trailing = l.slice(end + 2).trim();
|
|
20824
|
+
closed = true;
|
|
20825
|
+
j++;
|
|
20826
|
+
break;
|
|
20827
|
+
}
|
|
20828
|
+
mathLines.push(l);
|
|
20829
|
+
}
|
|
20830
|
+
if (closed) {
|
|
20831
|
+
const text = mathLines.join("\n").trim();
|
|
20832
|
+
if (text) blocks.push({ type: "equation", text });
|
|
20833
|
+
if (trailing) blocks.push({ type: "paragraph", text: trailing });
|
|
20834
|
+
i = j;
|
|
20835
|
+
continue;
|
|
20836
|
+
}
|
|
20837
|
+
}
|
|
20783
20838
|
const fenceMatch = line.match(/^(`{3,}|~{3,})(.*)$/);
|
|
20784
20839
|
if (fenceMatch) {
|
|
20785
20840
|
const fence = fenceMatch[1];
|
|
@@ -21172,6 +21227,7 @@ function precomputeGongmunList(blocks, gongmun) {
|
|
|
21172
21227
|
i++;
|
|
21173
21228
|
continue;
|
|
21174
21229
|
}
|
|
21230
|
+
const passThrough = (t) => t === "table" || t === "html_table" || t === "equation";
|
|
21175
21231
|
const run = [];
|
|
21176
21232
|
while (i < blocks.length) {
|
|
21177
21233
|
const t = blocks[i].type;
|
|
@@ -21180,9 +21236,9 @@ function precomputeGongmunList(blocks, gongmun) {
|
|
|
21180
21236
|
i++;
|
|
21181
21237
|
continue;
|
|
21182
21238
|
}
|
|
21183
|
-
if (t
|
|
21239
|
+
if (passThrough(t)) {
|
|
21184
21240
|
let j = i + 1;
|
|
21185
|
-
while (j < blocks.length && (blocks[j].type
|
|
21241
|
+
while (j < blocks.length && passThrough(blocks[j].type)) j++;
|
|
21186
21242
|
if (j < blocks.length && blocks[j].type === "list_item") {
|
|
21187
21243
|
i = j;
|
|
21188
21244
|
continue;
|
|
@@ -21708,6 +21764,280 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3) {
|
|
|
21708
21764
|
return `<hp:tbl id="${tblId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="0" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="2" noShading="0"><hp:sz width="${tblW}" widthRelTo="ABSOLUTE" height="${cellH * rowCnt}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="0" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:inMargin left="510" right="510" top="141" bottom="141"/>` + trXmls.join("") + `</hp:tbl>`;
|
|
21709
21765
|
}
|
|
21710
21766
|
|
|
21767
|
+
// src/hwpx/equation-generate.ts
|
|
21768
|
+
var MAX_EQUATION_SOURCE = 1e4;
|
|
21769
|
+
var MAX_GROUP_DEPTH = 64;
|
|
21770
|
+
var COMMAND_MAP = {
|
|
21771
|
+
alpha: "alpha",
|
|
21772
|
+
beta: "beta",
|
|
21773
|
+
gamma: "gamma",
|
|
21774
|
+
delta: "delta",
|
|
21775
|
+
epsilon: "epsilon",
|
|
21776
|
+
zeta: "zeta",
|
|
21777
|
+
eta: "eta",
|
|
21778
|
+
theta: "theta",
|
|
21779
|
+
iota: "iota",
|
|
21780
|
+
kappa: "kappa",
|
|
21781
|
+
lambda: "lambda",
|
|
21782
|
+
mu: "mu",
|
|
21783
|
+
nu: "nu",
|
|
21784
|
+
xi: "xi",
|
|
21785
|
+
pi: "pi",
|
|
21786
|
+
rho: "rho",
|
|
21787
|
+
sigma: "sigma",
|
|
21788
|
+
tau: "tau",
|
|
21789
|
+
upsilon: "upsilon",
|
|
21790
|
+
phi: "phi",
|
|
21791
|
+
chi: "chi",
|
|
21792
|
+
psi: "psi",
|
|
21793
|
+
omega: "omega",
|
|
21794
|
+
Gamma: "GAMMA",
|
|
21795
|
+
Delta: "DELTA",
|
|
21796
|
+
Theta: "THETA",
|
|
21797
|
+
Lambda: "LAMBDA",
|
|
21798
|
+
Xi: "XI",
|
|
21799
|
+
Pi: "PI",
|
|
21800
|
+
Sigma: "SIGMA",
|
|
21801
|
+
Upsilon: "UPSILON",
|
|
21802
|
+
Phi: "PHI",
|
|
21803
|
+
Psi: "PSI",
|
|
21804
|
+
Omega: "OMEGA",
|
|
21805
|
+
le: "LEQ",
|
|
21806
|
+
leq: "LEQ",
|
|
21807
|
+
ge: "GEQ",
|
|
21808
|
+
geq: "GEQ",
|
|
21809
|
+
ne: "!=",
|
|
21810
|
+
neq: "!=",
|
|
21811
|
+
pm: "+-",
|
|
21812
|
+
mp: "-+",
|
|
21813
|
+
times: "TIMES",
|
|
21814
|
+
cdot: "cdot",
|
|
21815
|
+
ast: "AST",
|
|
21816
|
+
circ: "CIRC",
|
|
21817
|
+
bullet: "BULLET",
|
|
21818
|
+
in: "IN",
|
|
21819
|
+
notin: "NOTIN",
|
|
21820
|
+
subset: "SUBSET",
|
|
21821
|
+
subseteq: "SUBSETEQ",
|
|
21822
|
+
supset: "SUPERSET",
|
|
21823
|
+
supseteq: "SUPSETEQ",
|
|
21824
|
+
cup: "CUP",
|
|
21825
|
+
cap: "SMALLINTER",
|
|
21826
|
+
emptyset: "EMPTYSET",
|
|
21827
|
+
forall: "FORALL",
|
|
21828
|
+
exists: "EXIST",
|
|
21829
|
+
infinity: "INF",
|
|
21830
|
+
infty: "INF",
|
|
21831
|
+
partial: "Partial",
|
|
21832
|
+
nabla: "NABLA",
|
|
21833
|
+
int: "int",
|
|
21834
|
+
iint: "dint",
|
|
21835
|
+
iiint: "tint",
|
|
21836
|
+
oint: "oint",
|
|
21837
|
+
sum: "sum",
|
|
21838
|
+
prod: "prod",
|
|
21839
|
+
lim: "lim",
|
|
21840
|
+
to: "->",
|
|
21841
|
+
rightarrow: "->",
|
|
21842
|
+
leftarrow: "larrow",
|
|
21843
|
+
leftrightarrow: "<->",
|
|
21844
|
+
Rightarrow: "RARROW",
|
|
21845
|
+
Leftarrow: "LARROW",
|
|
21846
|
+
Leftrightarrow: "LRARROW",
|
|
21847
|
+
cdots: "CDOTS",
|
|
21848
|
+
ldots: "LDOTS",
|
|
21849
|
+
vdots: "VDOTS",
|
|
21850
|
+
ddots: "DDOTS"
|
|
21851
|
+
};
|
|
21852
|
+
var ACCENT_COMMANDS = {
|
|
21853
|
+
bar: "bar",
|
|
21854
|
+
overline: "bar",
|
|
21855
|
+
vec: "vec",
|
|
21856
|
+
overrightarrow: "vec",
|
|
21857
|
+
hat: "hat",
|
|
21858
|
+
widehat: "hat",
|
|
21859
|
+
tilde: "tilde",
|
|
21860
|
+
widetilde: "tilde",
|
|
21861
|
+
dot: "dot",
|
|
21862
|
+
ddot: "ddot",
|
|
21863
|
+
underline: "under"
|
|
21864
|
+
};
|
|
21865
|
+
var RESERVED_WORDS = new Set(
|
|
21866
|
+
[...Object.keys(CONVERT_MAP), ...Object.keys(MIDDLE_CONVERT_MAP), "over", "root", "of"].filter((w) => /^[A-Za-z]+$/.test(w))
|
|
21867
|
+
);
|
|
21868
|
+
function skipSpaces(input, idx) {
|
|
21869
|
+
while (idx < input.length && /\s/.test(input[idx])) idx++;
|
|
21870
|
+
return idx;
|
|
21871
|
+
}
|
|
21872
|
+
function normalizeEqEdit(input) {
|
|
21873
|
+
return input.replace(/\s+/g, " ").trim();
|
|
21874
|
+
}
|
|
21875
|
+
function stripMathDelimiters(input) {
|
|
21876
|
+
let s = input.trim();
|
|
21877
|
+
if (s.startsWith("$$") && s.endsWith("$$")) s = s.slice(2, -2).trim();
|
|
21878
|
+
if (s.startsWith("\\[") && s.endsWith("\\]")) s = s.slice(2, -2).trim();
|
|
21879
|
+
return s;
|
|
21880
|
+
}
|
|
21881
|
+
function readBalanced(input, idx, open, close) {
|
|
21882
|
+
let depth = 1;
|
|
21883
|
+
let cursor = idx + 1;
|
|
21884
|
+
while (cursor < input.length) {
|
|
21885
|
+
const ch = input[cursor];
|
|
21886
|
+
if (ch === "\\") {
|
|
21887
|
+
cursor += 2;
|
|
21888
|
+
continue;
|
|
21889
|
+
}
|
|
21890
|
+
if (ch === open) depth++;
|
|
21891
|
+
else if (ch === close) depth--;
|
|
21892
|
+
if (depth === 0) {
|
|
21893
|
+
return { value: input.slice(idx + 1, cursor), next: cursor + 1 };
|
|
21894
|
+
}
|
|
21895
|
+
cursor++;
|
|
21896
|
+
}
|
|
21897
|
+
return { value: input.slice(idx + 1), next: input.length };
|
|
21898
|
+
}
|
|
21899
|
+
function readGroupOrToken(input, idx, depth) {
|
|
21900
|
+
const start = skipSpaces(input, idx);
|
|
21901
|
+
if (depth > MAX_GROUP_DEPTH) return { value: input.slice(start), next: input.length };
|
|
21902
|
+
if (input[start] === "{") {
|
|
21903
|
+
const group = readBalanced(input, start, "{", "}");
|
|
21904
|
+
return { value: convertLatexFragment(group.value, depth + 1), next: group.next };
|
|
21905
|
+
}
|
|
21906
|
+
if (input[start] === "\\") {
|
|
21907
|
+
const cmd = readCommand(input, start, depth + 1);
|
|
21908
|
+
return { value: cmd.value, next: cmd.next };
|
|
21909
|
+
}
|
|
21910
|
+
return { value: input[start] ?? "", next: Math.min(start + 1, input.length) };
|
|
21911
|
+
}
|
|
21912
|
+
function readCommandName(input, idx) {
|
|
21913
|
+
if (input[idx + 1] === "\\") return { value: "\\", next: idx + 2 };
|
|
21914
|
+
const match = /^[A-Za-z]+/.exec(input.slice(idx + 1));
|
|
21915
|
+
if (match) return { value: match[0], next: idx + 1 + match[0].length };
|
|
21916
|
+
return { value: input[idx + 1] ?? "", next: Math.min(idx + 2, input.length) };
|
|
21917
|
+
}
|
|
21918
|
+
function readCommand(input, idx, depth) {
|
|
21919
|
+
const name = readCommandName(input, idx);
|
|
21920
|
+
const command = name.value;
|
|
21921
|
+
if (command === "\\") return { value: "#", next: name.next };
|
|
21922
|
+
if (command === "frac") {
|
|
21923
|
+
const num2 = readGroupOrToken(input, name.next, depth);
|
|
21924
|
+
const den = readGroupOrToken(input, num2.next, depth);
|
|
21925
|
+
return { value: `{${num2.value}} over {${den.value}}`, next: den.next };
|
|
21926
|
+
}
|
|
21927
|
+
if (command === "sqrt") {
|
|
21928
|
+
let cursor = skipSpaces(input, name.next);
|
|
21929
|
+
let root = null;
|
|
21930
|
+
if (input[cursor] === "[") {
|
|
21931
|
+
const opt = readBalanced(input, cursor, "[", "]");
|
|
21932
|
+
root = { value: convertLatexFragment(opt.value, depth + 1), next: opt.next };
|
|
21933
|
+
cursor = opt.next;
|
|
21934
|
+
}
|
|
21935
|
+
const body = readGroupOrToken(input, cursor, depth);
|
|
21936
|
+
if (root) return { value: `root {${root.value}} of {${body.value}}`, next: body.next };
|
|
21937
|
+
return { value: `sqrt{${body.value}}`, next: body.next };
|
|
21938
|
+
}
|
|
21939
|
+
if (command === "begin") {
|
|
21940
|
+
const env = readGroupOrToken(input, name.next, depth);
|
|
21941
|
+
const endTag = `\\end{${env.value}}`;
|
|
21942
|
+
const endIdx = input.indexOf(endTag, env.next);
|
|
21943
|
+
if (endIdx === -1) return { value: env.value, next: env.next };
|
|
21944
|
+
const body = convertLatexFragment(input.slice(env.next, endIdx), depth + 1);
|
|
21945
|
+
if (env.value === "matrix" || env.value === "pmatrix" || env.value === "bmatrix") {
|
|
21946
|
+
return { value: `{${env.value}{${body}}}`, next: endIdx + endTag.length };
|
|
21947
|
+
}
|
|
21948
|
+
return { value: body, next: endIdx + endTag.length };
|
|
21949
|
+
}
|
|
21950
|
+
if (command === "left" || command === "right") {
|
|
21951
|
+
const kw = command === "left" ? "LEFT" : "RIGHT";
|
|
21952
|
+
const cursor = skipSpaces(input, name.next);
|
|
21953
|
+
let delimiter = input[cursor] ?? "";
|
|
21954
|
+
let next = delimiter ? cursor + 1 : cursor;
|
|
21955
|
+
if (delimiter === "\\") {
|
|
21956
|
+
const escaped = readCommandName(input, cursor);
|
|
21957
|
+
delimiter = escaped.value === "\\" ? "\\" : COMMAND_MAP[escaped.value] ?? escaped.value;
|
|
21958
|
+
next = escaped.next;
|
|
21959
|
+
}
|
|
21960
|
+
return { value: delimiter ? `${kw} ${delimiter}` : kw, next };
|
|
21961
|
+
}
|
|
21962
|
+
if (command in ACCENT_COMMANDS) {
|
|
21963
|
+
const body = readGroupOrToken(input, name.next, depth);
|
|
21964
|
+
return { value: `${ACCENT_COMMANDS[command]}{${body.value}}`, next: body.next };
|
|
21965
|
+
}
|
|
21966
|
+
if (command === "mathrm" || command === "text") {
|
|
21967
|
+
const start = skipSpaces(input, name.next);
|
|
21968
|
+
if (input[start] === "{") {
|
|
21969
|
+
const group = readBalanced(input, start, "{", "}");
|
|
21970
|
+
return { value: `"${group.value}"`, next: group.next };
|
|
21971
|
+
}
|
|
21972
|
+
const tok = readGroupOrToken(input, start, depth);
|
|
21973
|
+
return { value: `"${tok.value}"`, next: tok.next };
|
|
21974
|
+
}
|
|
21975
|
+
return { value: COMMAND_MAP[command] ?? command, next: name.next };
|
|
21976
|
+
}
|
|
21977
|
+
function convertLatexFragment(input, depth) {
|
|
21978
|
+
if (depth > MAX_GROUP_DEPTH) return normalizeEqEdit(input);
|
|
21979
|
+
let out = "";
|
|
21980
|
+
let idx = 0;
|
|
21981
|
+
while (idx < input.length) {
|
|
21982
|
+
const ch = input[idx];
|
|
21983
|
+
if (ch === "\\") {
|
|
21984
|
+
const cmd = readCommand(input, idx, depth + 1);
|
|
21985
|
+
out += ` ${cmd.value} `;
|
|
21986
|
+
idx = cmd.next;
|
|
21987
|
+
continue;
|
|
21988
|
+
}
|
|
21989
|
+
if (ch === "{") {
|
|
21990
|
+
const group = readBalanced(input, idx, "{", "}");
|
|
21991
|
+
out += `{${convertLatexFragment(group.value, depth + 1)}}`;
|
|
21992
|
+
idx = group.next;
|
|
21993
|
+
continue;
|
|
21994
|
+
}
|
|
21995
|
+
if (ch === "_" || ch === "^") {
|
|
21996
|
+
const script = readGroupOrToken(input, idx + 1, depth);
|
|
21997
|
+
out += ` ${ch}{${script.value}}`;
|
|
21998
|
+
idx = script.next;
|
|
21999
|
+
continue;
|
|
22000
|
+
}
|
|
22001
|
+
if (ch === "&") {
|
|
22002
|
+
out += " & ";
|
|
22003
|
+
idx++;
|
|
22004
|
+
continue;
|
|
22005
|
+
}
|
|
22006
|
+
out += ch;
|
|
22007
|
+
idx++;
|
|
22008
|
+
}
|
|
22009
|
+
return normalizeEqEdit(out);
|
|
22010
|
+
}
|
|
22011
|
+
function quoteReservedKeywords(latex) {
|
|
22012
|
+
return latex.replace(/([_^])\s*\{\s*([A-Za-z]+)\s*\}/g, (match, op, word) => RESERVED_WORDS.has(word) ? `${op}{"${word}"}` : match);
|
|
22013
|
+
}
|
|
22014
|
+
function latexLikeToEqEdit(input) {
|
|
22015
|
+
const src = stripMathDelimiters(input);
|
|
22016
|
+
if (src.length > MAX_EQUATION_SOURCE) return normalizeEqEdit(src);
|
|
22017
|
+
return convertLatexFragment(quoteReservedKeywords(src), 0);
|
|
22018
|
+
}
|
|
22019
|
+
function estimateEquationMetrics(script) {
|
|
22020
|
+
const cleaned = script.replace(/[{}\\^_]/g, "").replace(/\s+/g, " ").trim();
|
|
22021
|
+
const width = Math.min(Math.max(cleaned.length, 5) * 700 + 2e3, 4e4);
|
|
22022
|
+
const rowCount = Math.max(1, (script.match(/#/g) ?? []).length + 1);
|
|
22023
|
+
if (/\bmatrix\b|#/.test(script)) {
|
|
22024
|
+
if (rowCount >= 4) return { width, height: 5500, baseline: 55 };
|
|
22025
|
+
if (rowCount === 3) return { width, height: 4500, baseline: 60 };
|
|
22026
|
+
return { width, height: 3260, baseline: 63 };
|
|
22027
|
+
}
|
|
22028
|
+
if (/\bover\b|\broot\b|\bsqrt\b/.test(script)) return { width, height: 3010, baseline: 69 };
|
|
22029
|
+
return { width, height: 1450, baseline: 71 };
|
|
22030
|
+
}
|
|
22031
|
+
function generateEquationXml(script, zOrder = 0) {
|
|
22032
|
+
const { width, height, baseline } = estimateEquationMetrics(script);
|
|
22033
|
+
const eqId = 2000000001 + zOrder;
|
|
22034
|
+
return `<hp:equation id="${eqId}" zOrder="${zOrder}" numberingType="EQUATION" textWrap="TOP_AND_BOTTOM" textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" version="Equation Version 60" baseLine="${baseline}" textColor="#000000" baseUnit="1200" lineMode="CHAR" font="HYhwpEQ"><hp:sz width="${width}" widthRelTo="ABSOLUTE" height="${height}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="1" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="56" right="56" top="0" bottom="0"/><hp:shapeComment>\uC218\uC2DD\uC785\uB2C8\uB2E4.</hp:shapeComment><hp:script>${escapeXml(script)}</hp:script></hp:equation>`;
|
|
22035
|
+
}
|
|
22036
|
+
function generateEquationParagraph(input, zOrder = 0) {
|
|
22037
|
+
const script = latexLikeToEqEdit(input);
|
|
22038
|
+
return `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${generateEquationXml(script, zOrder)}</hp:run></hp:p>`;
|
|
22039
|
+
}
|
|
22040
|
+
|
|
21711
22041
|
// src/hwpx/gen-section.ts
|
|
21712
22042
|
function generateSecPr(gongmun) {
|
|
21713
22043
|
const m = gongmun ? {
|
|
@@ -21755,6 +22085,15 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
|
|
|
21755
22085
|
xml = codeLines.map((line) => generateParagraph(line || " ", PARA_CODE)).join("\n ");
|
|
21756
22086
|
break;
|
|
21757
22087
|
}
|
|
22088
|
+
case "equation": {
|
|
22089
|
+
if (isFirst) {
|
|
22090
|
+
const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
|
|
22091
|
+
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
|
|
22092
|
+
isFirst = false;
|
|
22093
|
+
}
|
|
22094
|
+
xml = generateEquationParagraph(block.text || "", blockIdx);
|
|
22095
|
+
break;
|
|
22096
|
+
}
|
|
21758
22097
|
case "blockquote":
|
|
21759
22098
|
xml = generateParagraph(
|
|
21760
22099
|
block.text || "",
|
|
@@ -24499,6 +24838,629 @@ async function blocksToPdf(blocks, options) {
|
|
|
24499
24838
|
return markdownToPdf(markdown, options);
|
|
24500
24839
|
}
|
|
24501
24840
|
|
|
24841
|
+
// src/render/svg-render.ts
|
|
24842
|
+
import JSZip10 from "jszip";
|
|
24843
|
+
|
|
24844
|
+
// src/render/layout.ts
|
|
24845
|
+
function toInt32(v, fallback = 0) {
|
|
24846
|
+
if (v == null || v === "") return fallback;
|
|
24847
|
+
const n = Number(v);
|
|
24848
|
+
if (!Number.isFinite(n)) return fallback;
|
|
24849
|
+
return n > 2147483647 ? n - 4294967296 : n;
|
|
24850
|
+
}
|
|
24851
|
+
function solveBoundaries(constraints, count, total) {
|
|
24852
|
+
const x = new Array(count + 1).fill(void 0);
|
|
24853
|
+
x[0] = 0;
|
|
24854
|
+
if (total != null && total > 0) x[count] = total;
|
|
24855
|
+
let changed = true;
|
|
24856
|
+
let guard = 0;
|
|
24857
|
+
while (changed && guard++ < count + 8) {
|
|
24858
|
+
changed = false;
|
|
24859
|
+
for (const c of constraints) {
|
|
24860
|
+
if (c.a < 0 || c.b > count || c.a >= c.b) continue;
|
|
24861
|
+
const xa = x[c.a];
|
|
24862
|
+
const xb = x[c.b];
|
|
24863
|
+
if (xa != null && xb == null) {
|
|
24864
|
+
x[c.b] = xa + c.size;
|
|
24865
|
+
changed = true;
|
|
24866
|
+
} else if (xb != null && xa == null) {
|
|
24867
|
+
x[c.a] = xb - c.size;
|
|
24868
|
+
changed = true;
|
|
24869
|
+
}
|
|
24870
|
+
}
|
|
24871
|
+
}
|
|
24872
|
+
let i = 0;
|
|
24873
|
+
while (i <= count) {
|
|
24874
|
+
if (x[i] != null) {
|
|
24875
|
+
i++;
|
|
24876
|
+
continue;
|
|
24877
|
+
}
|
|
24878
|
+
let lo = i - 1;
|
|
24879
|
+
let hi = i;
|
|
24880
|
+
while (hi <= count && x[hi] == null) hi++;
|
|
24881
|
+
const loV = x[lo];
|
|
24882
|
+
const hiV = hi <= count ? x[hi] : loV + (hi - lo) * 1e3;
|
|
24883
|
+
const n = hi - lo;
|
|
24884
|
+
for (let k = 1; k < n; k++) x[lo + k] = loV + (hiV - loV) * k / n;
|
|
24885
|
+
if (hi > count) x[count] = hiV;
|
|
24886
|
+
i = hi;
|
|
24887
|
+
}
|
|
24888
|
+
const out = x;
|
|
24889
|
+
for (let k = 1; k <= count; k++) if (out[k] < out[k - 1]) out[k] = out[k - 1];
|
|
24890
|
+
return out;
|
|
24891
|
+
}
|
|
24892
|
+
function solveRowHeights(cells, rowCount) {
|
|
24893
|
+
const h = new Array(rowCount).fill(0);
|
|
24894
|
+
for (const c of cells) {
|
|
24895
|
+
if (c.rowSpan === 1 && c.rowAddr >= 0 && c.rowAddr < rowCount) {
|
|
24896
|
+
h[c.rowAddr] = Math.max(h[c.rowAddr], c.height);
|
|
24897
|
+
}
|
|
24898
|
+
}
|
|
24899
|
+
for (const c of cells) {
|
|
24900
|
+
if (c.rowSpan <= 1) continue;
|
|
24901
|
+
const rows = [];
|
|
24902
|
+
for (let r = c.rowAddr; r < Math.min(c.rowAddr + c.rowSpan, rowCount); r++) rows.push(r);
|
|
24903
|
+
const known = rows.reduce((s, r) => s + h[r], 0);
|
|
24904
|
+
const missing = rows.filter((r) => h[r] === 0);
|
|
24905
|
+
if (missing.length > 0 && c.height > known) {
|
|
24906
|
+
const each = (c.height - known) / missing.length;
|
|
24907
|
+
for (const r of missing) h[r] = each;
|
|
24908
|
+
}
|
|
24909
|
+
}
|
|
24910
|
+
for (const c of cells) {
|
|
24911
|
+
if (c.rowSpan === 1 && c.contentH != null && c.rowAddr >= 0 && c.rowAddr < rowCount) {
|
|
24912
|
+
if (c.contentH > h[c.rowAddr]) h[c.rowAddr] = c.contentH;
|
|
24913
|
+
}
|
|
24914
|
+
}
|
|
24915
|
+
return h;
|
|
24916
|
+
}
|
|
24917
|
+
|
|
24918
|
+
// src/render/head-styles.ts
|
|
24919
|
+
var DEFAULT_CHAR = { height: 1e3, bold: false, italic: false, underline: false, ratio: 100, spacing: 0 };
|
|
24920
|
+
function borderWidthPt(v) {
|
|
24921
|
+
const n = parseFloat(v ?? "");
|
|
24922
|
+
if (!Number.isFinite(n)) return 0.34;
|
|
24923
|
+
return n * 2.834645;
|
|
24924
|
+
}
|
|
24925
|
+
function parseEdge(el) {
|
|
24926
|
+
if (!el) return void 0;
|
|
24927
|
+
const type = el.getAttribute("type") ?? "NONE";
|
|
24928
|
+
if (type === "NONE") return void 0;
|
|
24929
|
+
return { type, widthPt: borderWidthPt(el.getAttribute("width")), color: el.getAttribute("color") ?? "#000000" };
|
|
24930
|
+
}
|
|
24931
|
+
function parseRenderStyles(headXml) {
|
|
24932
|
+
const styles = { charPr: /* @__PURE__ */ new Map(), paraAlign: /* @__PURE__ */ new Map(), borderFill: /* @__PURE__ */ new Map() };
|
|
24933
|
+
const doc = createXmlParser().parseFromString(headXml, "text/xml");
|
|
24934
|
+
const root = doc.documentElement;
|
|
24935
|
+
if (!root) return styles;
|
|
24936
|
+
const walk = (el) => {
|
|
24937
|
+
const tag = (el.tagName || "").replace(/^[^:]+:/, "");
|
|
24938
|
+
if (tag === "charPr") {
|
|
24939
|
+
const id = el.getAttribute("id");
|
|
24940
|
+
if (id != null) {
|
|
24941
|
+
const ratioEl = findChildByLocalName(el, "ratio");
|
|
24942
|
+
const spacingEl = findChildByLocalName(el, "spacing");
|
|
24943
|
+
const underlineEl = findChildByLocalName(el, "underline");
|
|
24944
|
+
const textColor = el.getAttribute("textColor");
|
|
24945
|
+
styles.charPr.set(id, {
|
|
24946
|
+
height: Number(el.getAttribute("height")) || 1e3,
|
|
24947
|
+
bold: findChildByLocalName(el, "bold") != null,
|
|
24948
|
+
italic: findChildByLocalName(el, "italic") != null,
|
|
24949
|
+
underline: underlineEl != null && (underlineEl.getAttribute("type") ?? "NONE") !== "NONE",
|
|
24950
|
+
color: textColor && textColor !== "#000000" && textColor.toLowerCase() !== "none" ? textColor : void 0,
|
|
24951
|
+
ratio: Number(ratioEl?.getAttribute("hangul")) || 100,
|
|
24952
|
+
spacing: Number(spacingEl?.getAttribute("hangul")) || 0
|
|
24953
|
+
});
|
|
24954
|
+
}
|
|
24955
|
+
} else if (tag === "paraPr") {
|
|
24956
|
+
const id = el.getAttribute("id");
|
|
24957
|
+
if (id != null) {
|
|
24958
|
+
const align = findChildByLocalName(el, "align");
|
|
24959
|
+
styles.paraAlign.set(id, align?.getAttribute("horizontal") || "JUSTIFY");
|
|
24960
|
+
}
|
|
24961
|
+
} else if (tag === "borderFill") {
|
|
24962
|
+
const id = el.getAttribute("id");
|
|
24963
|
+
if (id != null) {
|
|
24964
|
+
const bf = {
|
|
24965
|
+
left: parseEdge(findChildByLocalName(el, "leftBorder")),
|
|
24966
|
+
right: parseEdge(findChildByLocalName(el, "rightBorder")),
|
|
24967
|
+
top: parseEdge(findChildByLocalName(el, "topBorder")),
|
|
24968
|
+
bottom: parseEdge(findChildByLocalName(el, "bottomBorder"))
|
|
24969
|
+
};
|
|
24970
|
+
const fillBrush = findChildByLocalName(el, "fillBrush");
|
|
24971
|
+
const winBrush = fillBrush ? findChildByLocalName(fillBrush, "winBrush") : null;
|
|
24972
|
+
const face = winBrush?.getAttribute("faceColor");
|
|
24973
|
+
if (face && face.toLowerCase() !== "none") bf.fill = face;
|
|
24974
|
+
styles.borderFill.set(id, bf);
|
|
24975
|
+
}
|
|
24976
|
+
}
|
|
24977
|
+
const children = el.childNodes;
|
|
24978
|
+
for (let i = 0; i < children.length; i++) {
|
|
24979
|
+
const ch = children[i];
|
|
24980
|
+
if (ch.nodeType === 1) walk(ch);
|
|
24981
|
+
}
|
|
24982
|
+
};
|
|
24983
|
+
walk(root);
|
|
24984
|
+
return styles;
|
|
24985
|
+
}
|
|
24986
|
+
|
|
24987
|
+
// src/render/svg-render.ts
|
|
24988
|
+
function ln(el) {
|
|
24989
|
+
return (el.tagName || "").replace(/^[^:]+:/, "");
|
|
24990
|
+
}
|
|
24991
|
+
function elements(el) {
|
|
24992
|
+
const out = [];
|
|
24993
|
+
const children = el.childNodes;
|
|
24994
|
+
if (!children) return out;
|
|
24995
|
+
for (let i = 0; i < children.length; i++) {
|
|
24996
|
+
if (children[i].nodeType === 1) out.push(children[i]);
|
|
24997
|
+
}
|
|
24998
|
+
return out;
|
|
24999
|
+
}
|
|
25000
|
+
function num(el, attr, fallback = 0) {
|
|
25001
|
+
return el ? toInt32(el.getAttribute(attr) ?? void 0, fallback) : fallback;
|
|
25002
|
+
}
|
|
25003
|
+
function findFirst(el, name, depth = 0) {
|
|
25004
|
+
if (depth > 64) return null;
|
|
25005
|
+
for (const ch of elements(el)) {
|
|
25006
|
+
if (ln(ch) === name) return ch;
|
|
25007
|
+
const found = findFirst(ch, name, depth + 1);
|
|
25008
|
+
if (found) return found;
|
|
25009
|
+
}
|
|
25010
|
+
return null;
|
|
25011
|
+
}
|
|
25012
|
+
function escapeXml3(s) {
|
|
25013
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
25014
|
+
}
|
|
25015
|
+
var OBJ_TAGS = /* @__PURE__ */ new Set(["tbl", "pic", "container", "equation", "rect", "ellipse", "polygon", "curv", "line", "arc", "ole", "textart"]);
|
|
25016
|
+
var pt = (u) => String(Math.round(u) / 100);
|
|
25017
|
+
function warnOnce(ctx, key, msg2) {
|
|
25018
|
+
if (ctx.warned.has(key)) return;
|
|
25019
|
+
ctx.warned.add(key);
|
|
25020
|
+
ctx.warnings.push(msg2);
|
|
25021
|
+
}
|
|
25022
|
+
function textOfT(t) {
|
|
25023
|
+
let s = "";
|
|
25024
|
+
const walk = (n, d) => {
|
|
25025
|
+
if (d > 32) return;
|
|
25026
|
+
const kids2 = n.childNodes;
|
|
25027
|
+
if (!kids2) return;
|
|
25028
|
+
for (let i = 0; i < kids2.length; i++) {
|
|
25029
|
+
const c = kids2[i];
|
|
25030
|
+
if (c.nodeType === 3) s += c.textContent ?? "";
|
|
25031
|
+
else if (c.nodeType === 1) walk(c, d + 1);
|
|
25032
|
+
}
|
|
25033
|
+
};
|
|
25034
|
+
walk(t, 0);
|
|
25035
|
+
return s;
|
|
25036
|
+
}
|
|
25037
|
+
function buildPara(p) {
|
|
25038
|
+
const chars = [];
|
|
25039
|
+
const objs = [];
|
|
25040
|
+
let segs = [];
|
|
25041
|
+
for (const runEl of elements(p)) {
|
|
25042
|
+
const tag = ln(runEl);
|
|
25043
|
+
if (tag === "run") {
|
|
25044
|
+
const prId = runEl.getAttribute("charPrIDRef");
|
|
25045
|
+
for (const ch of elements(runEl)) {
|
|
25046
|
+
const cn = ln(ch);
|
|
25047
|
+
if (cn === "t") {
|
|
25048
|
+
for (const c of textOfT(ch)) chars.push({ ch: c, prId });
|
|
25049
|
+
} else if (OBJ_TAGS.has(cn)) {
|
|
25050
|
+
const sz = findChildByLocalName(ch, "sz");
|
|
25051
|
+
const pos = findChildByLocalName(ch, "pos");
|
|
25052
|
+
objs.push({
|
|
25053
|
+
el: ch,
|
|
25054
|
+
tag: cn,
|
|
25055
|
+
index: chars.length,
|
|
25056
|
+
inline: pos?.getAttribute("treatAsChar") === "1",
|
|
25057
|
+
width: num(sz, "width"),
|
|
25058
|
+
height: num(sz, "height")
|
|
25059
|
+
});
|
|
25060
|
+
}
|
|
25061
|
+
}
|
|
25062
|
+
} else if (tag === "linesegarray") {
|
|
25063
|
+
segs = elements(runEl).filter((s) => ln(s) === "lineseg").map((s) => ({
|
|
25064
|
+
textpos: num(s, "textpos"),
|
|
25065
|
+
vertpos: num(s, "vertpos"),
|
|
25066
|
+
horzpos: num(s, "horzpos"),
|
|
25067
|
+
horzsize: num(s, "horzsize"),
|
|
25068
|
+
textheight: num(s, "textheight", 1e3),
|
|
25069
|
+
baseline: num(s, "baseline", 850)
|
|
25070
|
+
}));
|
|
25071
|
+
}
|
|
25072
|
+
}
|
|
25073
|
+
return { chars, segs, objs, paraPrId: p.getAttribute("paraPrIDRef") };
|
|
25074
|
+
}
|
|
25075
|
+
function charW(c, styles) {
|
|
25076
|
+
const st = (c.prId != null ? styles.charPr.get(c.prId) : void 0) ?? DEFAULT_CHAR;
|
|
25077
|
+
return measureTextWidth(c.ch, st.height, st.ratio, { spacingPct: st.spacing });
|
|
25078
|
+
}
|
|
25079
|
+
function lineNaturalWidth(m, styles, start, end) {
|
|
25080
|
+
let text = 0;
|
|
25081
|
+
for (let i = start; i < end && i < m.chars.length; i++) text += charW(m.chars[i], styles);
|
|
25082
|
+
let obj = 0;
|
|
25083
|
+
for (const o of m.objs) if (o.inline && o.index >= start && o.index < end) obj += o.width;
|
|
25084
|
+
return { text, obj };
|
|
25085
|
+
}
|
|
25086
|
+
function planLines(m, styles) {
|
|
25087
|
+
const align = (m.paraPrId != null ? styles.paraAlign.get(m.paraPrId) : void 0) ?? "JUSTIFY";
|
|
25088
|
+
const plans = [];
|
|
25089
|
+
for (let i = 0; i < m.segs.length; i++) {
|
|
25090
|
+
const seg = m.segs[i];
|
|
25091
|
+
const start = seg.textpos;
|
|
25092
|
+
const end = i + 1 < m.segs.length ? m.segs[i + 1].textpos : Math.max(m.chars.length, start);
|
|
25093
|
+
const nat = lineNaturalWidth(m, styles, start, end);
|
|
25094
|
+
const isLast = i === m.segs.length - 1;
|
|
25095
|
+
let xoff = 0;
|
|
25096
|
+
let scale = 1;
|
|
25097
|
+
const avail = seg.horzsize - nat.obj;
|
|
25098
|
+
if (nat.text > 0 && (!isLast || align === "DISTRIBUTE" || align === "DISTRIBUTE_SPACE")) {
|
|
25099
|
+
scale = avail > 0 ? avail / nat.text : 1;
|
|
25100
|
+
} else if (nat.text + nat.obj > 0 && isLast) {
|
|
25101
|
+
const w = nat.text + nat.obj;
|
|
25102
|
+
if (align === "CENTER") xoff = Math.max(0, (seg.horzsize - w) / 2);
|
|
25103
|
+
else if (align === "RIGHT") xoff = Math.max(0, seg.horzsize - w);
|
|
25104
|
+
}
|
|
25105
|
+
if (!Number.isFinite(scale) || scale <= 0) scale = 1;
|
|
25106
|
+
scale = Math.min(4, Math.max(0.25, scale));
|
|
25107
|
+
plans.push({ seg, xoff, scale, start, end });
|
|
25108
|
+
}
|
|
25109
|
+
return plans;
|
|
25110
|
+
}
|
|
25111
|
+
function advanceTo(m, styles, plan, upto) {
|
|
25112
|
+
let x = 0;
|
|
25113
|
+
for (let i = plan.start; i < upto && i < m.chars.length; i++) x += charW(m.chars[i], styles) * plan.scale;
|
|
25114
|
+
for (const o of m.objs) if (o.inline && o.index >= plan.start && o.index < upto) x += o.width;
|
|
25115
|
+
return x;
|
|
25116
|
+
}
|
|
25117
|
+
function drawPara(p, ox, oy, areaW, ctx, depth) {
|
|
25118
|
+
if (depth > 16) {
|
|
25119
|
+
warnOnce(ctx, "depth", "\uC911\uCCA9 \uAE4A\uC774 16 \uCD08\uACFC \u2014 \uC774\uD558 \uC0DD\uB7B5");
|
|
25120
|
+
return;
|
|
25121
|
+
}
|
|
25122
|
+
const m = buildPara(p);
|
|
25123
|
+
if (m.segs.length === 0) {
|
|
25124
|
+
for (const o of m.objs) drawObject(o, ox, oy, 0, areaW, ctx, depth);
|
|
25125
|
+
return;
|
|
25126
|
+
}
|
|
25127
|
+
const plans = planLines(m, ctx.styles);
|
|
25128
|
+
const baseV = m.segs[0].vertpos;
|
|
25129
|
+
for (const plan of plans) {
|
|
25130
|
+
const { seg } = plan;
|
|
25131
|
+
let i = plan.start;
|
|
25132
|
+
let cursor = ox + seg.horzpos + plan.xoff;
|
|
25133
|
+
const y = oy + seg.vertpos + seg.baseline;
|
|
25134
|
+
while (i < plan.end && i < m.chars.length) {
|
|
25135
|
+
const prId = m.chars[i].prId;
|
|
25136
|
+
let j = i;
|
|
25137
|
+
let piece = "";
|
|
25138
|
+
while (j < plan.end && j < m.chars.length && m.chars[j].prId === prId) {
|
|
25139
|
+
piece += m.chars[j].ch;
|
|
25140
|
+
j++;
|
|
25141
|
+
}
|
|
25142
|
+
for (const o of m.objs) {
|
|
25143
|
+
if (o.inline && o.index > i && o.index < j) {
|
|
25144
|
+
piece = piece.slice(0, o.index - i);
|
|
25145
|
+
j = o.index;
|
|
25146
|
+
break;
|
|
25147
|
+
}
|
|
25148
|
+
}
|
|
25149
|
+
{
|
|
25150
|
+
const cut = piece.search(/ {2,}/);
|
|
25151
|
+
if (cut > 0) {
|
|
25152
|
+
piece = piece.slice(0, cut);
|
|
25153
|
+
j = i + cut;
|
|
25154
|
+
} else if (cut === 0) {
|
|
25155
|
+
const runEnd = piece.match(/^ +/)[0].length;
|
|
25156
|
+
piece = piece.slice(0, runEnd);
|
|
25157
|
+
j = i + runEnd;
|
|
25158
|
+
}
|
|
25159
|
+
}
|
|
25160
|
+
const st = (prId != null ? ctx.styles.charPr.get(prId) : void 0) ?? DEFAULT_CHAR;
|
|
25161
|
+
const w = measureTextWidth(piece, st.height, st.ratio, { spacingPct: st.spacing }) * plan.scale;
|
|
25162
|
+
if (piece.trim().length > 0) {
|
|
25163
|
+
const attrs = [`x="${pt(cursor)}"`, `y="${pt(y)}"`, `font-size="${pt(st.height)}"`];
|
|
25164
|
+
if ([...piece].length > 1 && w > 50) {
|
|
25165
|
+
attrs.push(`textLength="${pt(w)}"`, `lengthAdjust="${plan.scale < 1 ? "spacingAndGlyphs" : "spacing"}"`);
|
|
25166
|
+
}
|
|
25167
|
+
if (st.bold) attrs.push(`font-weight="bold"`);
|
|
25168
|
+
if (st.italic) attrs.push(`font-style="italic"`);
|
|
25169
|
+
if (st.underline) attrs.push(`text-decoration="underline"`);
|
|
25170
|
+
if (st.color) attrs.push(`fill="${escapeXml3(st.color)}"`);
|
|
25171
|
+
ctx.svg.push(`<text ${attrs.join(" ")}>${escapeXml3(piece)}</text>`);
|
|
25172
|
+
ctx.stats.texts++;
|
|
25173
|
+
}
|
|
25174
|
+
cursor += w;
|
|
25175
|
+
for (const o of m.objs) if (o.inline && o.index === j) cursor += o.width;
|
|
25176
|
+
i = j;
|
|
25177
|
+
}
|
|
25178
|
+
}
|
|
25179
|
+
for (const o of m.objs) {
|
|
25180
|
+
if (o.inline) {
|
|
25181
|
+
let plan = plans[0];
|
|
25182
|
+
for (const pl of plans) if (pl.start <= o.index && (o.index < pl.end || pl === plans[plans.length - 1])) plan = pl;
|
|
25183
|
+
const x = ox + plan.seg.horzpos + plan.xoff + advanceTo(m, ctx.styles, plan, o.index);
|
|
25184
|
+
const yTop = oy + plan.seg.vertpos + Math.max(0, plan.seg.baseline - o.height);
|
|
25185
|
+
drawObject(o, x, yTop, baseV, areaW, ctx, depth);
|
|
25186
|
+
} else {
|
|
25187
|
+
const { x, y } = anchorObject(o, ox, oy, baseV, areaW, ctx);
|
|
25188
|
+
drawObject(o, x, y, baseV, areaW, ctx, depth);
|
|
25189
|
+
}
|
|
25190
|
+
}
|
|
25191
|
+
}
|
|
25192
|
+
function anchorObject(o, ox, oy, baseV, areaW, ctx) {
|
|
25193
|
+
const { PW, PH, ML, MT, BODY_W, BODY_H } = ctx.geom;
|
|
25194
|
+
const pos = findChildByLocalName(o.el, "pos");
|
|
25195
|
+
const om = findChildByLocalName(o.el, "outMargin");
|
|
25196
|
+
const omT = num(om, "top"), omB = num(om, "bottom");
|
|
25197
|
+
const w = o.width, h = o.height;
|
|
25198
|
+
if (!pos) return { x: ox, y: oy + baseV };
|
|
25199
|
+
const vo = num(pos, "vertOffset");
|
|
25200
|
+
const ho = num(pos, "horzOffset");
|
|
25201
|
+
const vrel = pos.getAttribute("vertRelTo") ?? "PARA";
|
|
25202
|
+
const hrel = pos.getAttribute("horzRelTo") ?? "PARA";
|
|
25203
|
+
const va = pos.getAttribute("vertAlign") ?? "TOP";
|
|
25204
|
+
const ha = pos.getAttribute("horzAlign") ?? "LEFT";
|
|
25205
|
+
const wrap = o.el.getAttribute("textWrap") ?? "TOP_AND_BOTTOM";
|
|
25206
|
+
let y;
|
|
25207
|
+
if (vrel === "PAPER") {
|
|
25208
|
+
y = va === "BOTTOM" ? PH - h - vo : va === "CENTER" ? (PH - h) / 2 + vo : vo;
|
|
25209
|
+
} else if (vrel === "PAGE") {
|
|
25210
|
+
y = va === "BOTTOM" ? MT + BODY_H - h - vo : va === "CENTER" ? MT + (BODY_H - h) / 2 + vo : MT + vo;
|
|
25211
|
+
} else if (wrap === "TOP_AND_BOTTOM") {
|
|
25212
|
+
const pushed = baseV - (omT + h + omB);
|
|
25213
|
+
const anchor = pushed >= -100 ? pushed : baseV;
|
|
25214
|
+
y = oy + anchor + omT + vo;
|
|
25215
|
+
} else {
|
|
25216
|
+
y = oy + baseV + vo;
|
|
25217
|
+
}
|
|
25218
|
+
let x;
|
|
25219
|
+
if (hrel === "PAGE") {
|
|
25220
|
+
x = ha === "RIGHT" ? ML + BODY_W - w - ho : ha === "CENTER" ? ML + (BODY_W - w) / 2 + ho : ML + ho;
|
|
25221
|
+
} else if (hrel === "PAPER") {
|
|
25222
|
+
x = ha === "RIGHT" ? PW - w - ho : ha === "CENTER" ? (PW - w) / 2 + ho : ho;
|
|
25223
|
+
} else {
|
|
25224
|
+
x = ha === "RIGHT" ? ox + areaW - w - ho : ha === "CENTER" ? ox + (areaW - w) / 2 + ho : ox + ho;
|
|
25225
|
+
}
|
|
25226
|
+
return { x, y };
|
|
25227
|
+
}
|
|
25228
|
+
function drawObject(o, x, y, baseV, areaW, ctx, depth) {
|
|
25229
|
+
if (o.tag === "tbl") drawTable(o.el, x, y, ctx, depth + 1);
|
|
25230
|
+
else if (o.tag === "pic") drawPic(o.el, x, y, ctx);
|
|
25231
|
+
else if (o.tag === "container") {
|
|
25232
|
+
for (const ch of elements(o.el)) {
|
|
25233
|
+
const tag = ln(ch);
|
|
25234
|
+
if (!OBJ_TAGS.has(tag)) continue;
|
|
25235
|
+
const sz = findChildByLocalName(ch, "sz");
|
|
25236
|
+
const off = findChildByLocalName(ch, "offset");
|
|
25237
|
+
const sub = { el: ch, tag, index: 0, inline: true, width: num(sz, "width"), height: num(sz, "height") };
|
|
25238
|
+
drawObject(sub, x + num(off, "x"), y + num(off, "y"), baseV, areaW, ctx, depth + 1);
|
|
25239
|
+
}
|
|
25240
|
+
} else if (o.tag === "equation") {
|
|
25241
|
+
warnOnce(ctx, "equation", "\uC218\uC2DD \uAC1C\uCCB4\uB294 \uB80C\uB354 \uBBF8\uC9C0\uC6D0 \u2014 \uC0DD\uB7B5");
|
|
25242
|
+
} else {
|
|
25243
|
+
warnOnce(ctx, `shape:${o.tag}`, `\uB3C4\uD615 \uAC1C\uCCB4(${o.tag}) \uB80C\uB354 \uBBF8\uC9C0\uC6D0 \u2014 \uC0DD\uB7B5`);
|
|
25244
|
+
}
|
|
25245
|
+
}
|
|
25246
|
+
function cellContentExtent(cell, ctx) {
|
|
25247
|
+
if (!cell.sub) return 0;
|
|
25248
|
+
let ext = 0;
|
|
25249
|
+
for (const p of elements(cell.sub)) {
|
|
25250
|
+
if (ln(p) !== "p") continue;
|
|
25251
|
+
const m = buildPara(p);
|
|
25252
|
+
for (const s of m.segs) ext = Math.max(ext, s.vertpos + s.textheight);
|
|
25253
|
+
const baseV = m.segs[0]?.vertpos ?? 0;
|
|
25254
|
+
for (const o of m.objs) {
|
|
25255
|
+
if (o.inline) continue;
|
|
25256
|
+
const pos = findChildByLocalName(o.el, "pos");
|
|
25257
|
+
if ((pos?.getAttribute("vertRelTo") ?? "PARA") !== "PARA") continue;
|
|
25258
|
+
const om = findChildByLocalName(o.el, "outMargin");
|
|
25259
|
+
const pushed = baseV - (num(om, "top") + o.height + num(om, "bottom"));
|
|
25260
|
+
const anchor = pushed >= -100 ? pushed : baseV;
|
|
25261
|
+
ext = Math.max(ext, anchor + num(om, "top") + num(pos, "vertOffset") + o.height);
|
|
25262
|
+
}
|
|
25263
|
+
}
|
|
25264
|
+
return ext;
|
|
25265
|
+
}
|
|
25266
|
+
function edgeLine(x1, y1, x2, y2, e) {
|
|
25267
|
+
const dash = /DASH|DOT/.test(e.type) ? ` stroke-dasharray="${e.type.includes("DOT") ? "1,1.5" : "3,1.5"}"` : "";
|
|
25268
|
+
return `<line x1="${pt(x1)}" y1="${pt(y1)}" x2="${pt(x2)}" y2="${pt(y2)}" stroke="${escapeXml3(e.color)}" stroke-width="${e.widthPt.toFixed(2)}"${dash}/>`;
|
|
25269
|
+
}
|
|
25270
|
+
function drawTable(tbl, tx, ty, ctx, depth) {
|
|
25271
|
+
if (depth > 16) {
|
|
25272
|
+
warnOnce(ctx, "depth", "\uC911\uCCA9 \uAE4A\uC774 16 \uCD08\uACFC \u2014 \uC774\uD558 \uC0DD\uB7B5");
|
|
25273
|
+
return;
|
|
25274
|
+
}
|
|
25275
|
+
ctx.stats.tables++;
|
|
25276
|
+
const tblSz = findChildByLocalName(tbl, "sz");
|
|
25277
|
+
const inMargin = findChildByLocalName(tbl, "inMargin");
|
|
25278
|
+
const defL = num(inMargin, "left", 141), defR = num(inMargin, "right", 141);
|
|
25279
|
+
const defT = num(inMargin, "top", 141), defB = num(inMargin, "bottom", 141);
|
|
25280
|
+
const cells = [];
|
|
25281
|
+
for (const tr of elements(tbl)) {
|
|
25282
|
+
if (ln(tr) !== "tr") continue;
|
|
25283
|
+
for (const tc of elements(tr)) {
|
|
25284
|
+
if (ln(tc) !== "tc") continue;
|
|
25285
|
+
const addr = findChildByLocalName(tc, "cellAddr");
|
|
25286
|
+
const span = findChildByLocalName(tc, "cellSpan");
|
|
25287
|
+
const csz = findChildByLocalName(tc, "cellSz");
|
|
25288
|
+
const cm = findChildByLocalName(tc, "cellMargin");
|
|
25289
|
+
if (!addr || !csz) continue;
|
|
25290
|
+
cells.push({
|
|
25291
|
+
el: tc,
|
|
25292
|
+
ca: num(addr, "colAddr"),
|
|
25293
|
+
ra: num(addr, "rowAddr"),
|
|
25294
|
+
cs: Math.max(1, num(span, "colSpan", 1)),
|
|
25295
|
+
rs: Math.max(1, num(span, "rowSpan", 1)),
|
|
25296
|
+
w: num(csz, "width"),
|
|
25297
|
+
h: num(csz, "height"),
|
|
25298
|
+
bfId: tc.getAttribute("borderFillIDRef"),
|
|
25299
|
+
sub: findChildByLocalName(tc, "subList"),
|
|
25300
|
+
marginL: cm ? num(cm, "left", defL) : defL,
|
|
25301
|
+
marginR: cm ? num(cm, "right", defR) : defR,
|
|
25302
|
+
marginT: cm ? num(cm, "top", defT) : defT,
|
|
25303
|
+
marginB: cm ? num(cm, "bottom", defB) : defB
|
|
25304
|
+
});
|
|
25305
|
+
}
|
|
25306
|
+
}
|
|
25307
|
+
if (cells.length === 0 || cells.length > 4096) return;
|
|
25308
|
+
const nCols = Math.max(...cells.map((c) => c.ca + c.cs));
|
|
25309
|
+
const nRows = Math.max(...cells.map((c) => c.ra + c.rs));
|
|
25310
|
+
const colCons = cells.map((c) => ({ a: c.ca, b: c.ca + c.cs, size: c.w }));
|
|
25311
|
+
const colX = solveBoundaries(colCons, nCols, num(tblSz, "width") || void 0);
|
|
25312
|
+
const rowH = solveRowHeights(
|
|
25313
|
+
cells.map((c) => ({ rowAddr: c.ra, rowSpan: c.rs, height: c.h, contentH: c.rs === 1 ? cellContentExtent(c, ctx) : void 0 })),
|
|
25314
|
+
nRows
|
|
25315
|
+
);
|
|
25316
|
+
const rowY = [0];
|
|
25317
|
+
for (let r = 0; r < nRows; r++) rowY.push(rowY[r] + rowH[r]);
|
|
25318
|
+
const geom = cells.map((c) => ({
|
|
25319
|
+
c,
|
|
25320
|
+
x: tx + colX[c.ca],
|
|
25321
|
+
y: ty + rowY[c.ra],
|
|
25322
|
+
w: colX[Math.min(c.ca + c.cs, nCols)] - colX[c.ca],
|
|
25323
|
+
h: rowY[Math.min(c.ra + c.rs, nRows)] - rowY[c.ra]
|
|
25324
|
+
}));
|
|
25325
|
+
for (const g of geom) {
|
|
25326
|
+
const bf = g.c.bfId != null ? ctx.styles.borderFill.get(g.c.bfId) : void 0;
|
|
25327
|
+
if (bf?.fill) ctx.svg.push(`<rect x="${pt(g.x)}" y="${pt(g.y)}" width="${pt(g.w)}" height="${pt(g.h)}" fill="${escapeXml3(bf.fill)}"/>`);
|
|
25328
|
+
}
|
|
25329
|
+
for (const g of geom) {
|
|
25330
|
+
const { c } = g;
|
|
25331
|
+
if (!c.sub) continue;
|
|
25332
|
+
const innerH = g.h - c.marginT - c.marginB;
|
|
25333
|
+
const extent = cellContentExtent(c, ctx);
|
|
25334
|
+
const va = c.sub.getAttribute("vertAlign") ?? "TOP";
|
|
25335
|
+
let yoff = 0;
|
|
25336
|
+
if (va === "CENTER") yoff = Math.max(0, (innerH - extent) / 2);
|
|
25337
|
+
else if (va === "BOTTOM") yoff = Math.max(0, innerH - extent);
|
|
25338
|
+
for (const p of elements(c.sub)) {
|
|
25339
|
+
if (ln(p) !== "p") continue;
|
|
25340
|
+
drawPara(p, g.x + c.marginL, g.y + c.marginT + yoff, g.w - c.marginL - c.marginR, ctx, depth + 1);
|
|
25341
|
+
}
|
|
25342
|
+
}
|
|
25343
|
+
for (const g of geom) {
|
|
25344
|
+
const bf = g.c.bfId != null ? ctx.styles.borderFill.get(g.c.bfId) : void 0;
|
|
25345
|
+
if (!bf) continue;
|
|
25346
|
+
if (bf.top) ctx.svg.push(edgeLine(g.x, g.y, g.x + g.w, g.y, bf.top));
|
|
25347
|
+
if (bf.bottom) ctx.svg.push(edgeLine(g.x, g.y + g.h, g.x + g.w, g.y + g.h, bf.bottom));
|
|
25348
|
+
if (bf.left) ctx.svg.push(edgeLine(g.x, g.y, g.x, g.y + g.h, bf.left));
|
|
25349
|
+
if (bf.right) ctx.svg.push(edgeLine(g.x + g.w, g.y, g.x + g.w, g.y + g.h, bf.right));
|
|
25350
|
+
}
|
|
25351
|
+
}
|
|
25352
|
+
function drawPic(pic, x, y, ctx) {
|
|
25353
|
+
const sz = findChildByLocalName(pic, "sz");
|
|
25354
|
+
const w = num(sz, "width", 5669), h = num(sz, "height", 5669);
|
|
25355
|
+
const img = findFirst(pic, "img");
|
|
25356
|
+
const ref = img?.getAttribute("binaryItemIDRef");
|
|
25357
|
+
const loaded = ref != null ? ctx.images.get(ref) : void 0;
|
|
25358
|
+
if (!loaded) {
|
|
25359
|
+
ctx.svg.push(`<rect x="${pt(x)}" y="${pt(y)}" width="${pt(w)}" height="${pt(h)}" fill="#eee" stroke="#c00" stroke-width="0.5"/>`);
|
|
25360
|
+
warnOnce(ctx, `img:${ref}`, `\uC774\uBBF8\uC9C0 \uBC14\uC774\uB108\uB9AC \uB204\uB77D: ${ref ?? "(ref \uC5C6\uC74C)"}`);
|
|
25361
|
+
return;
|
|
25362
|
+
}
|
|
25363
|
+
ctx.stats.images++;
|
|
25364
|
+
const orgSz = findChildByLocalName(pic, "orgSz");
|
|
25365
|
+
const clip = findChildByLocalName(pic, "imgClip");
|
|
25366
|
+
const orgW = num(orgSz, "width"), orgH = num(orgSz, "height");
|
|
25367
|
+
const cl = num(clip, "left"), ct = num(clip, "top");
|
|
25368
|
+
const cr = num(clip, "right", orgW), cb = num(clip, "bottom", orgH);
|
|
25369
|
+
const cropped = orgW > 0 && orgH > 0 && clip != null && (cl > 0 || ct > 0 || cr < orgW || cb < orgH) && cr > cl && cb > ct;
|
|
25370
|
+
if (cropped) {
|
|
25371
|
+
ctx.svg.push(
|
|
25372
|
+
`<svg x="${pt(x)}" y="${pt(y)}" width="${pt(w)}" height="${pt(h)}" viewBox="${pt(cl)} ${pt(ct)} ${pt(cr - cl)} ${pt(cb - ct)}" preserveAspectRatio="none"><image x="0" y="0" width="${pt(orgW)}" height="${pt(orgH)}" preserveAspectRatio="none" href="${loaded.dataUri}"/></svg>`
|
|
25373
|
+
);
|
|
25374
|
+
} else {
|
|
25375
|
+
ctx.svg.push(`<image x="${pt(x)}" y="${pt(y)}" width="${pt(w)}" height="${pt(h)}" preserveAspectRatio="none" href="${loaded.dataUri}"/>`);
|
|
25376
|
+
}
|
|
25377
|
+
}
|
|
25378
|
+
function sniffMime(name, bytes) {
|
|
25379
|
+
const lower = name.toLowerCase();
|
|
25380
|
+
if (lower.endsWith(".png") || bytes.length > 4 && bytes[0] === 137 && bytes[1] === 80) return "image/png";
|
|
25381
|
+
if (lower.endsWith(".bmp") || bytes.length > 2 && bytes[0] === 66 && bytes[1] === 77) return "image/bmp";
|
|
25382
|
+
if (lower.endsWith(".gif")) return "image/gif";
|
|
25383
|
+
if (lower.endsWith(".svg")) return "image/svg+xml";
|
|
25384
|
+
return "image/jpeg";
|
|
25385
|
+
}
|
|
25386
|
+
async function renderHwpxToSvg(input, options) {
|
|
25387
|
+
const maxImg = options?.maxImageBytes ?? 40 * 1024 * 1024;
|
|
25388
|
+
let zip;
|
|
25389
|
+
try {
|
|
25390
|
+
zip = await JSZip10.loadAsync(input);
|
|
25391
|
+
} catch {
|
|
25392
|
+
throw new KordocError("HWPX(ZIP) \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4 \u2014 \uB80C\uB354\uB294 HWPX\uB9CC \uC9C0\uC6D0");
|
|
25393
|
+
}
|
|
25394
|
+
const secFile = zip.file("Contents/section0.xml") ?? zip.file(/Contents\/section\d+\.xml$/i).sort((a, b) => a.name.localeCompare(b.name))[0];
|
|
25395
|
+
if (!secFile) throw new KordocError("Contents/section0.xml \uC5C6\uC74C \u2014 HWPX\uAC00 \uC544\uB2C8\uAC70\uB098 \uC190\uC0C1\uB428");
|
|
25396
|
+
const secXml = await secFile.async("string");
|
|
25397
|
+
if (secXml.length > MAX_DECOMPRESS_SIZE) throw new KordocError("\uC139\uC158 XML\uC774 \uD5C8\uC6A9 \uD06C\uAE30\uB97C \uCD08\uACFC");
|
|
25398
|
+
if (!secXml.includes("linesegarray")) {
|
|
25399
|
+
throw new KordocError("\uC870\uD310 \uCE90\uC2DC(linesegarray) \uC5C6\uC74C \u2014 \uD55C\uCEF4\uC5D0\uC11C \uC800\uC7A5\uD55C HWPX\uB9CC \uB80C\uB354 \uAC00\uB2A5");
|
|
25400
|
+
}
|
|
25401
|
+
const warnings = [];
|
|
25402
|
+
const headFile = zip.file("Contents/header.xml") ?? zip.file("Contents/head.xml");
|
|
25403
|
+
const styles = headFile ? parseRenderStyles(await headFile.async("string")) : { charPr: /* @__PURE__ */ new Map(), paraAlign: /* @__PURE__ */ new Map(), borderFill: /* @__PURE__ */ new Map() };
|
|
25404
|
+
if (!headFile) warnings.push("header.xml \uC5C6\uC74C \u2014 \uAE30\uBCF8 \uC2A4\uD0C0\uC77C\uB85C \uB80C\uB354");
|
|
25405
|
+
const binmap = /* @__PURE__ */ new Map();
|
|
25406
|
+
const hpf = zip.file(/content\.hpf$/i)[0];
|
|
25407
|
+
if (hpf) {
|
|
25408
|
+
const man = await hpf.async("string");
|
|
25409
|
+
for (const m of man.matchAll(/<[^>]*\bid="([^"]+)"[^>]*\bhref="(BinData\/[^"]+)"[^>]*>/g)) binmap.set(m[1], m[2]);
|
|
25410
|
+
for (const m of man.matchAll(/<[^>]*\bhref="(BinData\/[^"]+)"[^>]*\bid="([^"]+)"[^>]*>/g)) binmap.set(m[2], m[1]);
|
|
25411
|
+
}
|
|
25412
|
+
const images = /* @__PURE__ */ new Map();
|
|
25413
|
+
const refs = /* @__PURE__ */ new Set();
|
|
25414
|
+
for (const m of secXml.matchAll(/binaryItemIDRef="([^"]+)"/g)) refs.add(m[1]);
|
|
25415
|
+
for (const ref of refs) {
|
|
25416
|
+
let href = binmap.get(ref);
|
|
25417
|
+
if (!href) {
|
|
25418
|
+
const cand = zip.file(new RegExp(`BinData/.*${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "i"))[0];
|
|
25419
|
+
href = cand?.name;
|
|
25420
|
+
}
|
|
25421
|
+
if (!href) continue;
|
|
25422
|
+
const f = zip.file(href) ?? zip.file("Contents/" + href);
|
|
25423
|
+
if (!f) continue;
|
|
25424
|
+
const bytes = await f.async("uint8array");
|
|
25425
|
+
if (bytes.length > maxImg) {
|
|
25426
|
+
warnings.push(`\uC774\uBBF8\uC9C0 ${href} ${(bytes.length / 1048576).toFixed(1)}MB \u2014 \uD55C\uB3C4 \uCD08\uACFC\uB85C \uC0DD\uB7B5`);
|
|
25427
|
+
continue;
|
|
25428
|
+
}
|
|
25429
|
+
images.set(ref, { dataUri: `data:${sniffMime(href, bytes)};base64,${Buffer.from(bytes).toString("base64")}` });
|
|
25430
|
+
}
|
|
25431
|
+
const doc = createXmlParser().parseFromString(secXml, "text/xml");
|
|
25432
|
+
const root = doc.documentElement;
|
|
25433
|
+
if (!root) throw new KordocError("\uC139\uC158 XML \uD30C\uC2F1 \uC2E4\uD328");
|
|
25434
|
+
const pagePr = findFirst(root, "pagePr");
|
|
25435
|
+
const margin = pagePr ? findChildByLocalName(pagePr, "margin") : null;
|
|
25436
|
+
const PW = num(pagePr, "width", 59528), PH = num(pagePr, "height", 84188);
|
|
25437
|
+
const ML = num(margin, "left", 8504);
|
|
25438
|
+
const MT = num(margin, "top", 5668) + num(margin, "header", 0);
|
|
25439
|
+
const BODY_H = PH - MT - num(margin, "bottom", 4252) - num(margin, "footer", 0);
|
|
25440
|
+
const BODY_W = PW - ML - num(margin, "right", 8504);
|
|
25441
|
+
const ctx = {
|
|
25442
|
+
svg: [],
|
|
25443
|
+
geom: { PW, PH, ML, MT, BODY_W, BODY_H },
|
|
25444
|
+
styles,
|
|
25445
|
+
images,
|
|
25446
|
+
warnings,
|
|
25447
|
+
warned: /* @__PURE__ */ new Set(),
|
|
25448
|
+
stats: { texts: 0, images: 0, tables: 0 }
|
|
25449
|
+
};
|
|
25450
|
+
for (const p of elements(root)) {
|
|
25451
|
+
if (ln(p) !== "p") continue;
|
|
25452
|
+
const segs = findChildByLocalName(p, "linesegarray");
|
|
25453
|
+
const first = segs ? elements(segs)[0] : null;
|
|
25454
|
+
if (first && num(first, "vertpos") > BODY_H) continue;
|
|
25455
|
+
drawPara(p, ML, MT, BODY_W, ctx, 0);
|
|
25456
|
+
}
|
|
25457
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${pt(PW)} ${pt(PH)}" width="${pt(PW)}" height="${pt(PH)}" font-family="'HCR Batang','\uD568\uCD08\uB86C\uBC14\uD0D5','Hancom Batang',AppleMyungjo,'Noto Serif CJK KR',serif" xml:space="preserve">
|
|
25458
|
+
<rect width="100%" height="100%" fill="white"/>
|
|
25459
|
+
${ctx.svg.join("\n")}
|
|
25460
|
+
</svg>`;
|
|
25461
|
+
return { svg, width: Math.round(PW) / 100, height: Math.round(PH) / 100, warnings, stats: ctx.stats };
|
|
25462
|
+
}
|
|
25463
|
+
|
|
24502
25464
|
// src/index.ts
|
|
24503
25465
|
async function parse(input, options) {
|
|
24504
25466
|
let buffer;
|
|
@@ -24586,7 +25548,7 @@ async function parseHwp(buffer, options) {
|
|
|
24586
25548
|
async function parsePdf(buffer, options) {
|
|
24587
25549
|
let parsePdfDocument;
|
|
24588
25550
|
try {
|
|
24589
|
-
const mod = await import("./parser-
|
|
25551
|
+
const mod = await import("./parser-DKIA66MN.js");
|
|
24590
25552
|
parsePdfDocument = mod.parsePdfDocument;
|
|
24591
25553
|
} catch {
|
|
24592
25554
|
return {
|
|
@@ -24723,6 +25685,7 @@ export {
|
|
|
24723
25685
|
patchHwpx,
|
|
24724
25686
|
patchHwpxBlocks,
|
|
24725
25687
|
renderHtml,
|
|
25688
|
+
renderHwpxToSvg,
|
|
24726
25689
|
scanSectionXml,
|
|
24727
25690
|
simulateWrap,
|
|
24728
25691
|
simulateWrapKeepWord
|