kordoc 3.16.1 → 3.17.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 +32 -12
- package/dist/{-YVONYEEN.js → -3KPDRR3A.js} +7 -7
- package/dist/chunk-DCZVOIEO.cjs.map +1 -1
- package/dist/{chunk-QOPY6URE.js → chunk-E6NQWOFQ.js} +2 -2
- package/dist/{chunk-VNIQK4AL.cjs → chunk-EL2Y4BL2.cjs} +2 -2
- package/dist/chunk-EL2Y4BL2.cjs.map +1 -0
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-K4L563FA.js → chunk-HVEEFHN7.js} +2 -2
- package/dist/{chunk-IY3NX4FT.js → chunk-NKICMZ7F.js} +79 -3
- package/dist/chunk-NKICMZ7F.js.map +1 -0
- package/dist/{chunk-CDFCA37S.js → chunk-SADQWCWR.js} +127 -68
- package/dist/chunk-SADQWCWR.js.map +1 -0
- package/dist/{chunk-7WUTJXKP.js → chunk-TDIDUEBH.js} +3 -3
- package/dist/{chunk-I6T3DKYK.js → chunk-VUS6LRVY.js} +7 -7
- package/dist/{chunk-F62GOZFB.js → chunk-WHMNPQXW.js} +2 -2
- package/dist/cli.js +12 -12
- package/dist/formula-5NKVS2LR.cjs.map +1 -1
- package/dist/index.cjs +393 -258
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +203 -68
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +8 -8
- package/dist/page-range-P7SDW6LR.cjs.map +1 -1
- package/dist/{parser-B4O7CW5Q.js → parser-CYJMOXUR.js} +4 -4
- package/dist/parser-CYJMOXUR.js.map +1 -0
- package/dist/{parser-3O2UF6VO.cjs → parser-I5GC4QQ5.cjs} +15 -15
- package/dist/parser-I5GC4QQ5.cjs.map +1 -0
- package/dist/{parser-BNEAMKUF.js → parser-LHBXIKXX.js} +3 -3
- package/dist/parser-LHBXIKXX.js.map +1 -0
- package/dist/provider-G4C2V2PD.cjs.map +1 -1
- package/dist/render-HY7KKYPV.js +10 -0
- package/dist/seal-ITGYHENO.js +10 -0
- package/dist/{watch-RLF5F3TN.js → watch-VT7BSLNI.js} +7 -7
- package/package.json +1 -1
- package/dist/chunk-CDFCA37S.js.map +0 -1
- package/dist/chunk-IY3NX4FT.js.map +0 -1
- package/dist/chunk-VNIQK4AL.cjs.map +0 -1
- package/dist/parser-3O2UF6VO.cjs.map +0 -1
- package/dist/parser-B4O7CW5Q.js.map +0 -1
- package/dist/parser-BNEAMKUF.js.map +0 -1
- package/dist/render-QCNMRR7L.js +0 -10
- package/dist/seal-REDSMUI5.js +0 -10
- /package/dist/{-YVONYEEN.js.map → -3KPDRR3A.js.map} +0 -0
- /package/dist/{chunk-QOPY6URE.js.map → chunk-E6NQWOFQ.js.map} +0 -0
- /package/dist/{chunk-K4L563FA.js.map → chunk-HVEEFHN7.js.map} +0 -0
- /package/dist/{chunk-7WUTJXKP.js.map → chunk-TDIDUEBH.js.map} +0 -0
- /package/dist/{chunk-I6T3DKYK.js.map → chunk-VUS6LRVY.js.map} +0 -0
- /package/dist/{chunk-F62GOZFB.js.map → chunk-WHMNPQXW.js.map} +0 -0
- /package/dist/{render-QCNMRR7L.js.map → render-HY7KKYPV.js.map} +0 -0
- /package/dist/{seal-REDSMUI5.js.map → seal-ITGYHENO.js.map} +0 -0
- /package/dist/{watch-RLF5F3TN.js.map → watch-VT7BSLNI.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -1120,8 +1120,9 @@ interface RenderSvgResult {
|
|
|
1120
1120
|
};
|
|
1121
1121
|
}
|
|
1122
1122
|
/**
|
|
1123
|
-
* HWPX(한컴 저장본) → 레이아웃 보존 SVG (
|
|
1124
|
-
* 조판 캐시(linesegarray)가 없는
|
|
1123
|
+
* HWPX(한컴 저장본) → 레이아웃 보존 SVG. **전 구역(section*)을 세로 스택으로** 렌더한다.
|
|
1124
|
+
* 조판 캐시(linesegarray)가 없는 구역은 reflow 옵션으로 합성 조판(없으면 그 구역 생략);
|
|
1125
|
+
* 렌더 가능한 구역이 하나도 없으면 KordocError.
|
|
1125
1126
|
*/
|
|
1126
1127
|
declare function renderHwpxToSvg(input: ArrayBuffer | Uint8Array, options?: RenderSvgOptions): Promise<RenderSvgResult>;
|
|
1127
1128
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1120,8 +1120,9 @@ interface RenderSvgResult {
|
|
|
1120
1120
|
};
|
|
1121
1121
|
}
|
|
1122
1122
|
/**
|
|
1123
|
-
* HWPX(한컴 저장본) → 레이아웃 보존 SVG (
|
|
1124
|
-
* 조판 캐시(linesegarray)가 없는
|
|
1123
|
+
* HWPX(한컴 저장본) → 레이아웃 보존 SVG. **전 구역(section*)을 세로 스택으로** 렌더한다.
|
|
1124
|
+
* 조판 캐시(linesegarray)가 없는 구역은 reflow 옵션으로 합성 조판(없으면 그 구역 생략);
|
|
1125
|
+
* 렌더 가능한 구역이 하나도 없으면 KordocError.
|
|
1125
1126
|
*/
|
|
1126
1127
|
declare function renderHwpxToSvg(input: ArrayBuffer | Uint8Array, options?: RenderSvgOptions): Promise<RenderSvgResult>;
|
|
1127
1128
|
|
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-E6NQWOFQ.js";
|
|
23
23
|
import {
|
|
24
24
|
parsePageRange
|
|
25
25
|
} from "./chunk-GE43BE46.js";
|
|
@@ -22833,6 +22833,77 @@ var DEFAULT_PARA_GEOM = {
|
|
|
22833
22833
|
spaceAfter: 0
|
|
22834
22834
|
};
|
|
22835
22835
|
var DEFAULT_CHAR = { height: 1e3, bold: false, italic: false, underline: false, ratio: 100, spacing: 0 };
|
|
22836
|
+
var FONT_ALIASES = {
|
|
22837
|
+
"\uD568\uCD08\uB86C\uBC14\uD0D5": "'HCR Batang','\uD568\uCD08\uB86C\uBC14\uD0D5','\uD55C\uCEF4\uBC14\uD0D5'",
|
|
22838
|
+
"\uD55C\uCEF4\uBC14\uD0D5": "'HCR Batang','\uD568\uCD08\uB86C\uBC14\uD0D5','\uD55C\uCEF4\uBC14\uD0D5'",
|
|
22839
|
+
"\uD568\uCD08\uB86C\uB3CB\uC6C0": "'HCR Dotum','\uD568\uCD08\uB86C\uB3CB\uC6C0','\uD55C\uCEF4\uB3CB\uC6C0'",
|
|
22840
|
+
"\uD55C\uCEF4\uB3CB\uC6C0": "'HCR Dotum','\uD568\uCD08\uB86C\uB3CB\uC6C0','\uD55C\uCEF4\uB3CB\uC6C0'",
|
|
22841
|
+
"\uB9D1\uC740 \uACE0\uB515": "'Malgun Gothic','\uB9D1\uC740 \uACE0\uB515'",
|
|
22842
|
+
"\uB9D1\uC740\uACE0\uB515": "'Malgun Gothic','\uB9D1\uC740 \uACE0\uB515'",
|
|
22843
|
+
"\uAD74\uB9BC": "'Gulim','\uAD74\uB9BC'",
|
|
22844
|
+
"\uAD74\uB9BC\uCCB4": "'GulimChe','\uAD74\uB9BC\uCCB4','Gulim'",
|
|
22845
|
+
"\uB3CB\uC6C0": "'Dotum','\uB3CB\uC6C0'",
|
|
22846
|
+
"\uB3CB\uC6C0\uCCB4": "'DotumChe','\uB3CB\uC6C0\uCCB4','Dotum'",
|
|
22847
|
+
"\uBC14\uD0D5": "'Batang','\uBC14\uD0D5'",
|
|
22848
|
+
"\uBC14\uD0D5\uCCB4": "'BatangChe','\uBC14\uD0D5\uCCB4','Batang'",
|
|
22849
|
+
"\uAD81\uC11C": "'Gungsuh','\uAD81\uC11C'",
|
|
22850
|
+
"\uAD81\uC11C\uCCB4": "'GungsuhChe','\uAD81\uC11C\uCCB4','Gungsuh'",
|
|
22851
|
+
"\uB098\uB214\uACE0\uB515": "'NanumGothic','\uB098\uB214\uACE0\uB515'",
|
|
22852
|
+
"\uB098\uB214\uBA85\uC870": "'NanumMyeongjo','\uB098\uB214\uBA85\uC870'",
|
|
22853
|
+
"\uB9D1\uC740 \uACE0\uB515 Semilight": "'Malgun Gothic Semilight','\uB9D1\uC740 \uACE0\uB515'"
|
|
22854
|
+
};
|
|
22855
|
+
function isSerifFace(face) {
|
|
22856
|
+
return /바탕|명조|Batang|Myeong|Mincho|궁서|Gungsuh|Serif|신명|순명|Song|송/i.test(face);
|
|
22857
|
+
}
|
|
22858
|
+
function cssQuote(name) {
|
|
22859
|
+
return /^[A-Za-z0-9_-]+$/.test(name) ? name : `'${name.replace(/['"\\]/g, "")}'`;
|
|
22860
|
+
}
|
|
22861
|
+
function hwpFaceToCssStack(face) {
|
|
22862
|
+
const trimmed = (face ?? "").trim();
|
|
22863
|
+
if (!trimmed) return "";
|
|
22864
|
+
const generic = isSerifFace(trimmed) ? "'HCR Batang','Batang','Noto Serif KR',serif" : "'Malgun Gothic','HCR Dotum','Noto Sans KR',sans-serif";
|
|
22865
|
+
const head = FONT_ALIASES[trimmed] ?? cssQuote(trimmed);
|
|
22866
|
+
return `${head},${generic}`;
|
|
22867
|
+
}
|
|
22868
|
+
function collectHangulFonts(root) {
|
|
22869
|
+
const map = /* @__PURE__ */ new Map();
|
|
22870
|
+
const findFaces = (el, depth) => {
|
|
22871
|
+
if (depth > 24) return null;
|
|
22872
|
+
for (const ch of Array.from(el.childNodes)) {
|
|
22873
|
+
if (ch.nodeType !== 1) continue;
|
|
22874
|
+
const e = ch;
|
|
22875
|
+
if ((e.tagName || "").replace(/^[^:]+:/, "") === "fontfaces") return e;
|
|
22876
|
+
const f = findFaces(e, depth + 1);
|
|
22877
|
+
if (f) return f;
|
|
22878
|
+
}
|
|
22879
|
+
return null;
|
|
22880
|
+
};
|
|
22881
|
+
const faces = findFaces(root, 0);
|
|
22882
|
+
if (!faces) return map;
|
|
22883
|
+
let group = null;
|
|
22884
|
+
let firstGroup = null;
|
|
22885
|
+
for (const ch of Array.from(faces.childNodes)) {
|
|
22886
|
+
if (ch.nodeType !== 1) continue;
|
|
22887
|
+
const e = ch;
|
|
22888
|
+
if ((e.tagName || "").replace(/^[^:]+:/, "") !== "fontface") continue;
|
|
22889
|
+
if (!firstGroup) firstGroup = e;
|
|
22890
|
+
if ((e.getAttribute("lang") ?? "").toUpperCase() === "HANGUL") {
|
|
22891
|
+
group = e;
|
|
22892
|
+
break;
|
|
22893
|
+
}
|
|
22894
|
+
}
|
|
22895
|
+
group = group ?? firstGroup;
|
|
22896
|
+
if (!group) return map;
|
|
22897
|
+
for (const ch of Array.from(group.childNodes)) {
|
|
22898
|
+
if (ch.nodeType !== 1) continue;
|
|
22899
|
+
const e = ch;
|
|
22900
|
+
if ((e.tagName || "").replace(/^[^:]+:/, "") !== "font") continue;
|
|
22901
|
+
const id = e.getAttribute("id");
|
|
22902
|
+
const face = e.getAttribute("face");
|
|
22903
|
+
if (id != null && face) map.set(id, face);
|
|
22904
|
+
}
|
|
22905
|
+
return map;
|
|
22906
|
+
}
|
|
22836
22907
|
function borderWidthPt(v) {
|
|
22837
22908
|
const n = parseFloat(v ?? "");
|
|
22838
22909
|
if (!Number.isFinite(n)) return 0.34;
|
|
@@ -22884,6 +22955,7 @@ function parseRenderStyles(headXml) {
|
|
|
22884
22955
|
const doc = createXmlParser().parseFromString(headXml, "text/xml");
|
|
22885
22956
|
const root = doc.documentElement;
|
|
22886
22957
|
if (!root) return styles;
|
|
22958
|
+
const hangulFonts = collectHangulFonts(root);
|
|
22887
22959
|
const walk = (el) => {
|
|
22888
22960
|
const tag = (el.tagName || "").replace(/^[^:]+:/, "");
|
|
22889
22961
|
if (tag === "charPr") {
|
|
@@ -22893,6 +22965,9 @@ function parseRenderStyles(headXml) {
|
|
|
22893
22965
|
const spacingEl = findChildByLocalName(el, "spacing");
|
|
22894
22966
|
const underlineEl = findChildByLocalName(el, "underline");
|
|
22895
22967
|
const textColor = el.getAttribute("textColor");
|
|
22968
|
+
const fontRef = findChildByLocalName(el, "fontRef");
|
|
22969
|
+
const fontId = fontRef?.getAttribute("hangul") ?? fontRef?.getAttribute("latin");
|
|
22970
|
+
const face = fontId != null ? hangulFonts.get(fontId) : void 0;
|
|
22896
22971
|
styles.charPr.set(id, {
|
|
22897
22972
|
height: Number(el.getAttribute("height")) || 1e3,
|
|
22898
22973
|
bold: findChildByLocalName(el, "bold") != null,
|
|
@@ -22900,7 +22975,8 @@ function parseRenderStyles(headXml) {
|
|
|
22900
22975
|
underline: underlineEl != null && (underlineEl.getAttribute("type") ?? "NONE") !== "NONE",
|
|
22901
22976
|
color: textColor && textColor !== "#000000" && textColor.toLowerCase() !== "none" ? textColor : void 0,
|
|
22902
22977
|
ratio: Number(ratioEl?.getAttribute("hangul")) || 100,
|
|
22903
|
-
spacing: Number(spacingEl?.getAttribute("hangul")) || 0
|
|
22978
|
+
spacing: Number(spacingEl?.getAttribute("hangul")) || 0,
|
|
22979
|
+
fontFamily: face ? hwpFaceToCssStack(face) : void 0
|
|
22904
22980
|
});
|
|
22905
22981
|
}
|
|
22906
22982
|
} else if (tag === "paraPr") {
|
|
@@ -26031,7 +26107,7 @@ function reflowPara(p, doc, styles, areaW, startV, mode) {
|
|
|
26031
26107
|
const lsa = doc.createElement("hp:linesegarray");
|
|
26032
26108
|
for (let li = 0; li < wrap.starts.length; li++) {
|
|
26033
26109
|
const startReal = wrap.starts[li];
|
|
26034
|
-
const textpos = startReal < realIdx.length ? realIdx[startReal] :
|
|
26110
|
+
const textpos = startReal < realIdx.length ? realIdx[startReal] : 0;
|
|
26035
26111
|
const vertpos = startV + li * pitch;
|
|
26036
26112
|
const isFirst = li === 0;
|
|
26037
26113
|
const seg = doc.createElement("hp:lineseg");
|
|
@@ -26311,6 +26387,7 @@ function drawPara(p, ox, oy, areaW, ctx, depth, segPages) {
|
|
|
26311
26387
|
}
|
|
26312
26388
|
if (text.trim().length > 0) {
|
|
26313
26389
|
const attrs = [`x="${pt(cx)}"`, `y="${pt(y)}"`, `font-size="${pt(st.height)}"`];
|
|
26390
|
+
if (st.fontFamily) attrs.push(`font-family="${st.fontFamily}"`);
|
|
26314
26391
|
if ([...text].length > 1 && sw > 50) {
|
|
26315
26392
|
attrs.push(`textLength="${pt(sw)}"`, `lengthAdjust="${plan.scale < 1 ? "spacingAndGlyphs" : "spacing"}"`);
|
|
26316
26393
|
}
|
|
@@ -26486,7 +26563,11 @@ function cellContentExtent(cell) {
|
|
|
26486
26563
|
for (const s of m.segs) ext = Math.max(ext, s.vertpos + s.textheight);
|
|
26487
26564
|
const baseV = m.segs[0]?.vertpos ?? 0;
|
|
26488
26565
|
for (const o of m.objs) {
|
|
26489
|
-
if (o.inline)
|
|
26566
|
+
if (o.inline) {
|
|
26567
|
+
const h = o.tag === "tbl" ? Math.max(o.height, measureTableHeight(o.el)) : o.height;
|
|
26568
|
+
ext = Math.max(ext, baseV + h);
|
|
26569
|
+
continue;
|
|
26570
|
+
}
|
|
26490
26571
|
const pos = findChildByLocalName(o.el, "pos");
|
|
26491
26572
|
if ((pos?.getAttribute("vertRelTo") ?? "PARA") !== "PARA") continue;
|
|
26492
26573
|
const om = findChildByLocalName(o.el, "outMargin");
|
|
@@ -26647,6 +26728,67 @@ function sniffMime(name, bytes) {
|
|
|
26647
26728
|
if (lower.endsWith(".svg")) return "image/svg+xml";
|
|
26648
26729
|
return "image/jpeg";
|
|
26649
26730
|
}
|
|
26731
|
+
function readSectionGeom(root) {
|
|
26732
|
+
const pagePr = findFirst(root, "pagePr");
|
|
26733
|
+
const margin = pagePr ? findChildByLocalName(pagePr, "margin") : null;
|
|
26734
|
+
let PW = num2(pagePr, "width", 59528), PH = num2(pagePr, "height", 84188);
|
|
26735
|
+
if (pagePr?.getAttribute("landscape") === "NARROWLY" && PW < PH) {
|
|
26736
|
+
const t = PW;
|
|
26737
|
+
PW = PH;
|
|
26738
|
+
PH = t;
|
|
26739
|
+
}
|
|
26740
|
+
const ML = num2(margin, "left", 8504);
|
|
26741
|
+
const MT = num2(margin, "top", 5668) + num2(margin, "header", 0);
|
|
26742
|
+
const BODY_H = PH - MT - num2(margin, "bottom", 4252) - num2(margin, "footer", 0);
|
|
26743
|
+
const BODY_W = PW - ML - num2(margin, "right", 8504);
|
|
26744
|
+
return { PW, PH, ML, MT, BODY_W, BODY_H };
|
|
26745
|
+
}
|
|
26746
|
+
function renderSectionToPages(root, geom, ctxBase, hasCache, reflowMode) {
|
|
26747
|
+
const { PW, PH, ML, MT, BODY_W, BODY_H } = geom;
|
|
26748
|
+
if (!hasCache) reflowSection(root, ctxBase.styles, { BODY_W, BODY_H }, reflowMode);
|
|
26749
|
+
const colPr = findFirst(root, "colPr");
|
|
26750
|
+
const multiCol = num2(colPr, "colCount", 1) > 1;
|
|
26751
|
+
const paraSegPages = /* @__PURE__ */ new Map();
|
|
26752
|
+
let nPages = 1;
|
|
26753
|
+
let maxTopV = 0;
|
|
26754
|
+
{
|
|
26755
|
+
let prevV = Number.NEGATIVE_INFINITY;
|
|
26756
|
+
let prevH = Number.NEGATIVE_INFINITY;
|
|
26757
|
+
let cur = 0;
|
|
26758
|
+
for (const p of elements2(root)) {
|
|
26759
|
+
if (ln2(p) !== "p") continue;
|
|
26760
|
+
const lsa = findChildByLocalName(p, "linesegarray");
|
|
26761
|
+
const segEls = lsa ? elements2(lsa).filter((s) => ln2(s) === "lineseg") : [];
|
|
26762
|
+
const pagesOf = [];
|
|
26763
|
+
let paraFirst = true;
|
|
26764
|
+
for (const s of segEls) {
|
|
26765
|
+
const v = num2(s, "vertpos");
|
|
26766
|
+
const h = num2(s, "horzpos");
|
|
26767
|
+
const brk = v < prevV ? !multiCol || h <= prevH : paraFirst && v === prevV && h <= prevH;
|
|
26768
|
+
if (brk) cur++;
|
|
26769
|
+
paraFirst = false;
|
|
26770
|
+
pagesOf.push(cur);
|
|
26771
|
+
maxTopV = Math.max(maxTopV, v + num2(s, "textheight", 1e3));
|
|
26772
|
+
prevV = v;
|
|
26773
|
+
prevH = h;
|
|
26774
|
+
}
|
|
26775
|
+
paraSegPages.set(p, pagesOf);
|
|
26776
|
+
nPages = Math.max(nPages, cur + 1);
|
|
26777
|
+
}
|
|
26778
|
+
}
|
|
26779
|
+
const ctx = {
|
|
26780
|
+
...ctxBase,
|
|
26781
|
+
pages: Array.from({ length: nPages }, () => []),
|
|
26782
|
+
page: 0,
|
|
26783
|
+
geom
|
|
26784
|
+
};
|
|
26785
|
+
for (const p of elements2(root)) {
|
|
26786
|
+
if (ln2(p) !== "p") continue;
|
|
26787
|
+
drawPara(p, ML, MT, BODY_W, ctx, 0, paraSegPages.get(p));
|
|
26788
|
+
}
|
|
26789
|
+
const pageH = nPages === 1 ? Math.max(PH, MT + maxTopV + 2e3) : PH;
|
|
26790
|
+
return { pages: ctx.pages, pageH };
|
|
26791
|
+
}
|
|
26650
26792
|
async function renderHwpxToSvg(input, options) {
|
|
26651
26793
|
const maxImg = options?.maxImageBytes ?? 40 * 1024 * 1024;
|
|
26652
26794
|
const ab = input instanceof Uint8Array ? input.buffer.slice(input.byteOffset, input.byteOffset + input.byteLength) : input;
|
|
@@ -26657,18 +26799,18 @@ async function renderHwpxToSvg(input, options) {
|
|
|
26657
26799
|
} catch {
|
|
26658
26800
|
throw new KordocError("HWPX(ZIP) \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4 \u2014 \uB80C\uB354\uB294 HWPX\uB9CC \uC9C0\uC6D0");
|
|
26659
26801
|
}
|
|
26660
|
-
const
|
|
26661
|
-
if (
|
|
26662
|
-
const secXml = await secFile.async("string");
|
|
26663
|
-
if (secXml.length > MAX_DECOMPRESS_SIZE) throw new KordocError("\uC139\uC158 XML\uC774 \uD5C8\uC6A9 \uD06C\uAE30\uB97C \uCD08\uACFC");
|
|
26664
|
-
const hasCache = /<(?:[A-Za-z][\w.-]*:)?linesegarray[\s/>]/.test(secXml);
|
|
26665
|
-
if (!hasCache && !options?.reflow) {
|
|
26666
|
-
throw new KordocError("\uC870\uD310 \uCE90\uC2DC(linesegarray) \uC5C6\uC74C \u2014 \uD55C\uCEF4\uC5D0\uC11C \uC800\uC7A5\uD55C HWPX\uB9CC \uB80C\uB354 \uAC00\uB2A5 (reflow \uC635\uC158\uC73C\uB85C \uD569\uC131 \uB80C\uB354 \uAC00\uB2A5)");
|
|
26667
|
-
}
|
|
26802
|
+
const secFiles = zip.file(/Contents\/section\d+\.xml$/i).sort((a, b) => a.name.localeCompare(b.name));
|
|
26803
|
+
if (secFiles.length === 0) throw new KordocError("Contents/section0.xml \uC5C6\uC74C \u2014 HWPX\uAC00 \uC544\uB2C8\uAC70\uB098 \uC190\uC0C1\uB428");
|
|
26668
26804
|
const warnings = [];
|
|
26669
26805
|
const headFile = zip.file("Contents/header.xml") ?? zip.file("Contents/head.xml");
|
|
26670
26806
|
const styles = headFile ? parseRenderStyles(await headFile.async("string")) : { charPr: /* @__PURE__ */ new Map(), paraAlign: /* @__PURE__ */ new Map(), paraGeom: /* @__PURE__ */ new Map(), borderFill: /* @__PURE__ */ new Map() };
|
|
26671
26807
|
if (!headFile) warnings.push("header.xml \uC5C6\uC74C \u2014 \uAE30\uBCF8 \uC2A4\uD0C0\uC77C\uB85C \uB80C\uB354");
|
|
26808
|
+
const secXmls = [];
|
|
26809
|
+
for (const f of secFiles) {
|
|
26810
|
+
const xml = await f.async("string");
|
|
26811
|
+
if (xml.length > MAX_DECOMPRESS_SIZE) throw new KordocError("\uC139\uC158 XML\uC774 \uD5C8\uC6A9 \uD06C\uAE30\uB97C \uCD08\uACFC");
|
|
26812
|
+
secXmls.push(xml);
|
|
26813
|
+
}
|
|
26672
26814
|
const binmap = /* @__PURE__ */ new Map();
|
|
26673
26815
|
const hpf = zip.file(/content\.hpf$/i)[0];
|
|
26674
26816
|
if (hpf) {
|
|
@@ -26680,7 +26822,7 @@ async function renderHwpxToSvg(input, options) {
|
|
|
26680
26822
|
const MAX_TOTAL_IMAGE_BYTES = 128 * 1024 * 1024;
|
|
26681
26823
|
const images = /* @__PURE__ */ new Map();
|
|
26682
26824
|
const refs = /* @__PURE__ */ new Set();
|
|
26683
|
-
for (const m of
|
|
26825
|
+
for (const xml of secXmls) for (const m of xml.matchAll(/binaryItemIDRef="([^"]+)"/g)) refs.add(m[1]);
|
|
26684
26826
|
let totalImgBytes = 0;
|
|
26685
26827
|
for (const ref of refs) {
|
|
26686
26828
|
if (images.size >= MAX_IMAGE_REFS) {
|
|
@@ -26707,48 +26849,7 @@ async function renderHwpxToSvg(input, options) {
|
|
|
26707
26849
|
totalImgBytes += bytes.length;
|
|
26708
26850
|
images.set(ref, { dataUri: `data:${sniffMime(href, bytes)};base64,${Buffer.from(bytes).toString("base64")}` });
|
|
26709
26851
|
}
|
|
26710
|
-
const
|
|
26711
|
-
const root = doc.documentElement;
|
|
26712
|
-
if (!root) throw new KordocError("\uC139\uC158 XML \uD30C\uC2F1 \uC2E4\uD328");
|
|
26713
|
-
const pagePr = findFirst(root, "pagePr");
|
|
26714
|
-
const margin = pagePr ? findChildByLocalName(pagePr, "margin") : null;
|
|
26715
|
-
const PW = num2(pagePr, "width", 59528), PH = num2(pagePr, "height", 84188);
|
|
26716
|
-
const ML = num2(margin, "left", 8504);
|
|
26717
|
-
const MT = num2(margin, "top", 5668) + num2(margin, "header", 0);
|
|
26718
|
-
const BODY_H = PH - MT - num2(margin, "bottom", 4252) - num2(margin, "footer", 0);
|
|
26719
|
-
const BODY_W = PW - ML - num2(margin, "right", 8504);
|
|
26720
|
-
if (!hasCache) reflowSection(root, styles, { BODY_W, BODY_H }, options?.reflowMode ?? "keep");
|
|
26721
|
-
const colPr = findFirst(root, "colPr");
|
|
26722
|
-
const multiCol = num2(colPr, "colCount", 1) > 1;
|
|
26723
|
-
const paraSegPages = /* @__PURE__ */ new Map();
|
|
26724
|
-
let nPages = 1;
|
|
26725
|
-
let maxTopV = 0;
|
|
26726
|
-
{
|
|
26727
|
-
let prevV = Number.NEGATIVE_INFINITY;
|
|
26728
|
-
let prevH = Number.NEGATIVE_INFINITY;
|
|
26729
|
-
let cur = 0;
|
|
26730
|
-
for (const p of elements2(root)) {
|
|
26731
|
-
if (ln2(p) !== "p") continue;
|
|
26732
|
-
const lsa = findChildByLocalName(p, "linesegarray");
|
|
26733
|
-
const segEls = lsa ? elements2(lsa).filter((s) => ln2(s) === "lineseg") : [];
|
|
26734
|
-
const pagesOf = [];
|
|
26735
|
-
for (const s of segEls) {
|
|
26736
|
-
const v = num2(s, "vertpos");
|
|
26737
|
-
const h = num2(s, "horzpos");
|
|
26738
|
-
if (v < prevV && (!multiCol || h <= prevH)) cur++;
|
|
26739
|
-
pagesOf.push(cur);
|
|
26740
|
-
maxTopV = Math.max(maxTopV, v + num2(s, "textheight", 1e3));
|
|
26741
|
-
prevV = v;
|
|
26742
|
-
prevH = h;
|
|
26743
|
-
}
|
|
26744
|
-
paraSegPages.set(p, pagesOf);
|
|
26745
|
-
nPages = Math.max(nPages, cur + 1);
|
|
26746
|
-
}
|
|
26747
|
-
}
|
|
26748
|
-
const ctx = {
|
|
26749
|
-
pages: Array.from({ length: nPages }, () => []),
|
|
26750
|
-
page: 0,
|
|
26751
|
-
geom: { PW, PH, ML, MT, BODY_W, BODY_H },
|
|
26852
|
+
const ctxBase = {
|
|
26752
26853
|
styles,
|
|
26753
26854
|
images,
|
|
26754
26855
|
defs: [],
|
|
@@ -26757,23 +26858,57 @@ async function renderHwpxToSvg(input, options) {
|
|
|
26757
26858
|
warned: /* @__PURE__ */ new Set(),
|
|
26758
26859
|
stats: { texts: 0, images: 0, tables: 0 }
|
|
26759
26860
|
};
|
|
26760
|
-
|
|
26761
|
-
|
|
26762
|
-
|
|
26861
|
+
const rendered = [];
|
|
26862
|
+
let noCacheSkipped = false;
|
|
26863
|
+
for (let si = 0; si < secXmls.length; si++) {
|
|
26864
|
+
const secXml = secXmls[si];
|
|
26865
|
+
const hasCache = /<(?:[A-Za-z][\w.-]*:)?linesegarray[\s/>]/.test(secXml);
|
|
26866
|
+
if (!hasCache && !options?.reflow) {
|
|
26867
|
+
noCacheSkipped = true;
|
|
26868
|
+
warnings.push(`\uAD6C\uC5ED ${si}: \uC870\uD310 \uCE90\uC2DC \uC5C6\uC74C \u2014 reflow \uC635\uC158 \uD544\uC694, \uC0DD\uB7B5`);
|
|
26869
|
+
continue;
|
|
26870
|
+
}
|
|
26871
|
+
const doc = createXmlParser().parseFromString(secXml, "text/xml");
|
|
26872
|
+
const root = doc.documentElement;
|
|
26873
|
+
if (!root) {
|
|
26874
|
+
warnings.push(`\uAD6C\uC5ED ${si} XML \uD30C\uC2F1 \uC2E4\uD328 \u2014 \uC0DD\uB7B5`);
|
|
26875
|
+
continue;
|
|
26876
|
+
}
|
|
26877
|
+
const geom = readSectionGeom(root);
|
|
26878
|
+
const { pages, pageH } = renderSectionToPages(root, geom, ctxBase, hasCache, options?.reflowMode ?? "keep");
|
|
26879
|
+
rendered.push({ pages, PW: geom.PW, pageH, clipId: `pgclip${si}` });
|
|
26880
|
+
}
|
|
26881
|
+
if (rendered.length === 0) {
|
|
26882
|
+
if (noCacheSkipped) {
|
|
26883
|
+
throw new KordocError("\uC870\uD310 \uCE90\uC2DC(linesegarray) \uC5C6\uC74C \u2014 \uD55C\uCEF4\uC5D0\uC11C \uC800\uC7A5\uD55C HWPX\uB9CC \uB80C\uB354 \uAC00\uB2A5 (reflow \uC635\uC158\uC73C\uB85C \uD569\uC131 \uB80C\uB354 \uAC00\uB2A5)");
|
|
26884
|
+
}
|
|
26885
|
+
throw new KordocError("\uB80C\uB354\uD560 \uAD6C\uC5ED\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 HWPX\uAC00 \uC190\uC0C1\uB418\uC5C8\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4");
|
|
26763
26886
|
}
|
|
26764
|
-
const pageH = nPages === 1 ? Math.max(PH, MT + maxTopV + 2e3) : PH;
|
|
26765
26887
|
const GAP = 2400;
|
|
26766
|
-
const
|
|
26767
|
-
const
|
|
26768
|
-
|
|
26888
|
+
const clipDefs = [];
|
|
26889
|
+
const groups = [];
|
|
26890
|
+
let y = 0;
|
|
26891
|
+
let maxPW = 0;
|
|
26892
|
+
let pageNo = 0;
|
|
26893
|
+
for (const rs of rendered) {
|
|
26894
|
+
maxPW = Math.max(maxPW, rs.PW);
|
|
26895
|
+
clipDefs.push(`<clipPath id="${rs.clipId}"><rect x="0" y="0" width="${pt(rs.PW)}" height="${pt(rs.pageH)}"/></clipPath>`);
|
|
26896
|
+
for (const buf of rs.pages) {
|
|
26897
|
+
pageNo++;
|
|
26898
|
+
groups.push(
|
|
26899
|
+
`<g data-page="${pageNo}" transform="translate(0 ${pt(y)})"><rect width="${pt(rs.PW)}" height="${pt(rs.pageH)}" fill="white" stroke="#c9c7c4" stroke-width="0.75"/><g clip-path="url(#${rs.clipId})">
|
|
26769
26900
|
${buf.join("\n")}
|
|
26770
26901
|
</g></g>`
|
|
26771
|
-
|
|
26772
|
-
|
|
26773
|
-
|
|
26774
|
-
|
|
26902
|
+
);
|
|
26903
|
+
y += rs.pageH + GAP;
|
|
26904
|
+
}
|
|
26905
|
+
}
|
|
26906
|
+
const totalH = Math.max(0, y - GAP);
|
|
26907
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${pt(maxPW)} ${pt(totalH)}" width="${pt(maxPW)}pt" height="${pt(totalH)}pt" font-family="'HCR Batang','\uD568\uCD08\uB86C\uBC14\uD0D5','Hancom Batang',AppleMyungjo,'Noto Serif CJK KR',serif" xml:space="preserve">
|
|
26908
|
+
<defs>${clipDefs.join("")}${ctxBase.defs.join("")}</defs>
|
|
26909
|
+
${groups.join("\n")}
|
|
26775
26910
|
</svg>`;
|
|
26776
|
-
return { svg, width: Math.round(
|
|
26911
|
+
return { svg, width: Math.round(maxPW) / 100, height: Math.round(totalH) / 100, pageCount: pageNo, warnings, stats: ctxBase.stats };
|
|
26777
26912
|
}
|
|
26778
26913
|
|
|
26779
26914
|
// src/index.ts
|
|
@@ -26863,7 +26998,7 @@ async function parseHwp(buffer, options) {
|
|
|
26863
26998
|
async function parsePdf(buffer, options) {
|
|
26864
26999
|
let parsePdfDocument;
|
|
26865
27000
|
try {
|
|
26866
|
-
const mod = await import("./parser-
|
|
27001
|
+
const mod = await import("./parser-LHBXIKXX.js");
|
|
26867
27002
|
parsePdfDocument = mod.parsePdfDocument;
|
|
26868
27003
|
} catch {
|
|
26869
27004
|
return {
|