kordoc 3.9.0 → 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 +27 -0
- package/dist/{-6CLKMLK2.js → -3B5FDXW2.js} +18 -12
- package/dist/{chunk-XKDA4FDM.js → chunk-5DL6VCIJ.js} +4 -120
- package/dist/chunk-5DL6VCIJ.js.map +1 -0
- package/dist/{chunk-ITPZD7XK.js → chunk-5TK4X4JQ.js} +32 -313
- 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-EZ5GBTBE.js → chunk-PNXOUDS7.js} +2 -2
- package/dist/{chunk-EZ5GBTBE.js.map → chunk-PNXOUDS7.js.map} +1 -1
- package/dist/{chunk-VHXUD3PW.cjs → chunk-ZQOGTAT5.cjs} +2 -2
- package/dist/{chunk-VHXUD3PW.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 +798 -174
- 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 +680 -56
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +8 -5
- package/dist/mcp.js.map +1 -1
- package/dist/{parser-N4G5KQBE.cjs → parser-6B7BUSX3.cjs} +14 -14
- package/dist/{parser-N4G5KQBE.cjs.map → parser-6B7BUSX3.cjs.map} +1 -1
- package/dist/{parser-NCNME2Z6.js → parser-DKIA66MN.js} +2 -2
- package/dist/{parser-LVI45MVF.js → parser-VCJTQVAH.js} +8 -6
- package/dist/{parser-LVI45MVF.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-XSLV62BH.js → watch-MQTMNUSB.js} +6 -4
- package/dist/{watch-XSLV62BH.js.map → watch-MQTMNUSB.js.map} +1 -1
- package/package.json +2 -2
- package/dist/chunk-ITPZD7XK.js.map +0 -1
- package/dist/chunk-XKDA4FDM.js.map +0 -1
- /package/dist/{-6CLKMLK2.js.map → -3B5FDXW2.js.map} +0 -0
- /package/dist/{parser-NCNME2Z6.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");
|
|
@@ -2505,11 +2505,11 @@ function formatRoman(n, upper) {
|
|
|
2505
2505
|
const values = [1e3, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
|
|
2506
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"];
|
|
2507
2507
|
let result = "";
|
|
2508
|
-
let
|
|
2508
|
+
let num2 = n;
|
|
2509
2509
|
for (let i = 0; i < values.length; i++) {
|
|
2510
|
-
while (
|
|
2510
|
+
while (num2 >= values[i]) {
|
|
2511
2511
|
result += symbols[i];
|
|
2512
|
-
|
|
2512
|
+
num2 -= values[i];
|
|
2513
2513
|
}
|
|
2514
2514
|
}
|
|
2515
2515
|
return result;
|
|
@@ -2517,11 +2517,11 @@ function formatRoman(n, upper) {
|
|
|
2517
2517
|
function formatLatin(n, upper) {
|
|
2518
2518
|
if (n <= 0) return "";
|
|
2519
2519
|
let result = "";
|
|
2520
|
-
let
|
|
2521
|
-
while (
|
|
2522
|
-
|
|
2523
|
-
result = String.fromCharCode((upper ? 65 : 97) +
|
|
2524
|
-
|
|
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);
|
|
2525
2525
|
}
|
|
2526
2526
|
return result;
|
|
2527
2527
|
}
|
|
@@ -2529,15 +2529,15 @@ function formatEastAsianNumber(n, digits, units, zero) {
|
|
|
2529
2529
|
if (n === 0) return zero;
|
|
2530
2530
|
if (n < 0 || n > 99999) return String(n);
|
|
2531
2531
|
let result = "";
|
|
2532
|
-
let
|
|
2532
|
+
let num2 = n;
|
|
2533
2533
|
let unit = 0;
|
|
2534
|
-
while (
|
|
2535
|
-
const d =
|
|
2534
|
+
while (num2 > 0) {
|
|
2535
|
+
const d = num2 % 10;
|
|
2536
2536
|
if (d > 0) {
|
|
2537
2537
|
const digitStr = d === 1 && unit > 0 ? "" : digits[d];
|
|
2538
2538
|
result = digitStr + units[unit] + result;
|
|
2539
2539
|
}
|
|
2540
|
-
|
|
2540
|
+
num2 = Math.floor(num2 / 10);
|
|
2541
2541
|
unit++;
|
|
2542
2542
|
}
|
|
2543
2543
|
return result;
|
|
@@ -2584,8 +2584,8 @@ function expandNumberingFormat(formatStr, counters, numbering) {
|
|
|
2584
2584
|
const idx = levelRef - 1;
|
|
2585
2585
|
const counterVal = counters[idx] ?? 0;
|
|
2586
2586
|
const start = numbering.startNumbers[idx] ?? 1;
|
|
2587
|
-
const
|
|
2588
|
-
result += formatNumber(
|
|
2587
|
+
const num2 = counterVal > 0 ? start - 1 + counterVal : start;
|
|
2588
|
+
result += formatNumber(num2, headFormatToNumFmt(numbering.numberFormats[idx] ?? 0));
|
|
2589
2589
|
i += 2;
|
|
2590
2590
|
continue;
|
|
2591
2591
|
}
|
|
@@ -4153,11 +4153,11 @@ function applyCtrlEffect(ctrl, records, ctx) {
|
|
|
4153
4153
|
const attr = ctrl.data.readUInt32LE(4);
|
|
4154
4154
|
const type = attr & 15;
|
|
4155
4155
|
const format = attr >>> 4 & 255;
|
|
4156
|
-
const
|
|
4157
|
-
ctx.doc.autoCounters.set(type,
|
|
4156
|
+
const num2 = ctx.doc.autoCounters.get(type) ?? 1;
|
|
4157
|
+
ctx.doc.autoCounters.set(type, num2 + 1);
|
|
4158
4158
|
const prefix = ctrl.data.length >= 14 ? wcharAt(ctrl.data, 12) : "";
|
|
4159
4159
|
const suffix = ctrl.data.length >= 16 ? wcharAt(ctrl.data, 14) : "";
|
|
4160
|
-
ctrl.inlineText = `${prefix}${formatNumber(
|
|
4160
|
+
ctrl.inlineText = `${prefix}${formatNumber(num2, shapeFormatToNumFmt(format))}${suffix}`;
|
|
4161
4161
|
}
|
|
4162
4162
|
return;
|
|
4163
4163
|
}
|
|
@@ -4165,8 +4165,8 @@ function applyCtrlEffect(ctrl, records, ctx) {
|
|
|
4165
4165
|
if (ctrl.data.length >= 10) {
|
|
4166
4166
|
const attr = ctrl.data.readUInt32LE(4);
|
|
4167
4167
|
const type = attr & 15;
|
|
4168
|
-
const
|
|
4169
|
-
if (
|
|
4168
|
+
const num2 = ctrl.data.readUInt16LE(8);
|
|
4169
|
+
if (num2 > 0) ctx.doc.autoCounters.set(type, num2);
|
|
4170
4170
|
}
|
|
4171
4171
|
return;
|
|
4172
4172
|
}
|
|
@@ -4228,7 +4228,7 @@ function blocksPlainText(blocks, sep) {
|
|
|
4228
4228
|
return parts.join(sep).trim();
|
|
4229
4229
|
}
|
|
4230
4230
|
function applyNoteEffect(ctrl, records, ctx, autoType) {
|
|
4231
|
-
const
|
|
4231
|
+
const num2 = ctx.doc.autoCounters.get(autoType) ?? 1;
|
|
4232
4232
|
let before = "";
|
|
4233
4233
|
let after = "";
|
|
4234
4234
|
let shape = 0;
|
|
@@ -4239,11 +4239,11 @@ function applyNoteEffect(ctrl, records, ctx, autoType) {
|
|
|
4239
4239
|
if (ctrl.data.length >= 16) {
|
|
4240
4240
|
shape = ctrl.data.readUInt32LE(12) & 255;
|
|
4241
4241
|
}
|
|
4242
|
-
const formatted = formatNumber(
|
|
4242
|
+
const formatted = formatNumber(num2, shapeFormatToNumFmt(shape));
|
|
4243
4243
|
const marker = before || after ? `${before}${formatted}${after}` : `${formatted})`;
|
|
4244
4244
|
const content = blocksPlainText(parseListHeaderParagraphs(ctrl, records, ctx), " ");
|
|
4245
|
-
if ((ctx.doc.autoCounters.get(autoType) ?? 1) <=
|
|
4246
|
-
ctx.doc.autoCounters.set(autoType,
|
|
4245
|
+
if ((ctx.doc.autoCounters.get(autoType) ?? 1) <= num2) {
|
|
4246
|
+
ctx.doc.autoCounters.set(autoType, num2 + 1);
|
|
4247
4247
|
}
|
|
4248
4248
|
ctrl.inlineText = marker;
|
|
4249
4249
|
if (content) ctrl.footnote = content.startsWith(marker) ? content : `${marker} ${content}`;
|
|
@@ -16781,9 +16781,9 @@ var MAX_ROWS2 = 1e4;
|
|
|
16781
16781
|
var MAX_COLS2 = 200;
|
|
16782
16782
|
function cleanNumericValue(raw) {
|
|
16783
16783
|
if (!/^-?\d+\.\d+$/.test(raw)) return raw;
|
|
16784
|
-
const
|
|
16785
|
-
if (!isFinite(
|
|
16786
|
-
const cleaned = parseFloat(
|
|
16784
|
+
const num2 = parseFloat(raw);
|
|
16785
|
+
if (!isFinite(num2)) return raw;
|
|
16786
|
+
const cleaned = parseFloat(num2.toPrecision(15)).toString();
|
|
16787
16787
|
return cleaned;
|
|
16788
16788
|
}
|
|
16789
16789
|
function parseCellRef(ref) {
|
|
@@ -17126,17 +17126,17 @@ function decodeRk(rk) {
|
|
|
17126
17126
|
const fDiv100 = (rk & 1) !== 0;
|
|
17127
17127
|
const fInt = (rk & 2) !== 0;
|
|
17128
17128
|
const val30 = rk >> 2;
|
|
17129
|
-
let
|
|
17129
|
+
let num2;
|
|
17130
17130
|
if (fInt) {
|
|
17131
|
-
|
|
17131
|
+
num2 = val30;
|
|
17132
17132
|
} else {
|
|
17133
17133
|
const high32 = (rk & 4294967292) >>> 0;
|
|
17134
17134
|
const buf = Buffer.alloc(8);
|
|
17135
17135
|
buf.writeUInt32LE(0, 0);
|
|
17136
17136
|
buf.writeUInt32LE(high32, 4);
|
|
17137
|
-
|
|
17137
|
+
num2 = buf.readDoubleLE(0);
|
|
17138
17138
|
}
|
|
17139
|
-
return fDiv100 ?
|
|
17139
|
+
return fDiv100 ? num2 / 100 : num2;
|
|
17140
17140
|
}
|
|
17141
17141
|
function decodeMulRk(data) {
|
|
17142
17142
|
if (data.length < 6) return null;
|
|
@@ -17836,9 +17836,9 @@ function nodeToLatex(el) {
|
|
|
17836
17836
|
case "f": {
|
|
17837
17837
|
const n = firstKid(el, "num");
|
|
17838
17838
|
const d = firstKid(el, "den");
|
|
17839
|
-
const
|
|
17839
|
+
const num2 = n ? childrenToLatex(n) : "";
|
|
17840
17840
|
const den = d ? childrenToLatex(d) : "";
|
|
17841
|
-
return "\\frac" + grp(
|
|
17841
|
+
return "\\frac" + grp(num2) + grp(den);
|
|
17842
17842
|
}
|
|
17843
17843
|
// 첨자
|
|
17844
17844
|
case "sSup": {
|
|
@@ -20479,10 +20479,10 @@ function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "kee
|
|
|
20479
20479
|
const spacing = opts?.spacingPct ?? 0;
|
|
20480
20480
|
const k = height * ratioPct / 100 / 1e3;
|
|
20481
20481
|
const cwCp = (cp) => (cp === 32 ? spaceEm : charWidthEm1000(cp)) * (1 + spacing / 100) * k;
|
|
20482
|
-
const
|
|
20482
|
+
const charW2 = (ch) => cwCp(ch.codePointAt(0));
|
|
20483
20483
|
const rangeW = (from, to) => {
|
|
20484
20484
|
let w = 0;
|
|
20485
|
-
for (const ch of text.slice(from, to)) w +=
|
|
20485
|
+
for (const ch of text.slice(from, to)) w += charW2(ch);
|
|
20486
20486
|
return w;
|
|
20487
20487
|
};
|
|
20488
20488
|
const units = text.match(mode === "keep" ? / +|[^ ]+/g : / +|[^ ]/g) ?? [];
|
|
@@ -20503,7 +20503,7 @@ function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "kee
|
|
|
20503
20503
|
};
|
|
20504
20504
|
for (const u of units) {
|
|
20505
20505
|
if (u[0] === " ") {
|
|
20506
|
-
lineW +=
|
|
20506
|
+
lineW += charW2(" ") * u.length;
|
|
20507
20507
|
pos += u.length;
|
|
20508
20508
|
continue;
|
|
20509
20509
|
}
|
|
@@ -20516,7 +20516,7 @@ function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "kee
|
|
|
20516
20516
|
if (lineW === 0 || w > contWidth + EPS) {
|
|
20517
20517
|
let sub = 0;
|
|
20518
20518
|
for (const ch of u) {
|
|
20519
|
-
const c =
|
|
20519
|
+
const c = charW2(ch);
|
|
20520
20520
|
if (lineW + c > avail + EPS && lineW > 0) breakBefore(pos + sub, 0);
|
|
20521
20521
|
lineW += c;
|
|
20522
20522
|
sub += ch.length;
|
|
@@ -21920,9 +21920,9 @@ function readCommand(input, idx, depth) {
|
|
|
21920
21920
|
const command = name.value;
|
|
21921
21921
|
if (command === "\\") return { value: "#", next: name.next };
|
|
21922
21922
|
if (command === "frac") {
|
|
21923
|
-
const
|
|
21924
|
-
const den = readGroupOrToken(input,
|
|
21925
|
-
return { value: `{${
|
|
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
21926
|
}
|
|
21927
21927
|
if (command === "sqrt") {
|
|
21928
21928
|
let cursor = skipSpaces(input, name.next);
|
|
@@ -24838,6 +24838,629 @@ async function blocksToPdf(blocks, options) {
|
|
|
24838
24838
|
return markdownToPdf(markdown, options);
|
|
24839
24839
|
}
|
|
24840
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
|
+
|
|
24841
25464
|
// src/index.ts
|
|
24842
25465
|
async function parse(input, options) {
|
|
24843
25466
|
let buffer;
|
|
@@ -24925,7 +25548,7 @@ async function parseHwp(buffer, options) {
|
|
|
24925
25548
|
async function parsePdf(buffer, options) {
|
|
24926
25549
|
let parsePdfDocument;
|
|
24927
25550
|
try {
|
|
24928
|
-
const mod = await import("./parser-
|
|
25551
|
+
const mod = await import("./parser-DKIA66MN.js");
|
|
24929
25552
|
parsePdfDocument = mod.parsePdfDocument;
|
|
24930
25553
|
} catch {
|
|
24931
25554
|
return {
|
|
@@ -25062,6 +25685,7 @@ export {
|
|
|
25062
25685
|
patchHwpx,
|
|
25063
25686
|
patchHwpxBlocks,
|
|
25064
25687
|
renderHtml,
|
|
25688
|
+
renderHwpxToSvg,
|
|
25065
25689
|
scanSectionXml,
|
|
25066
25690
|
simulateWrap,
|
|
25067
25691
|
simulateWrapKeepWord
|