hwpx-js 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +409 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +407 -40
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -34,7 +34,8 @@ __export(index_exports, {
|
|
|
34
34
|
createDefaultStyles: () => createDefaultStyles,
|
|
35
35
|
read: () => read,
|
|
36
36
|
utils: () => utils_exports,
|
|
37
|
-
write: () => write
|
|
37
|
+
write: () => write,
|
|
38
|
+
writePdf: () => writePdf2
|
|
38
39
|
});
|
|
39
40
|
module.exports = __toCommonJS(index_exports);
|
|
40
41
|
|
|
@@ -813,14 +814,15 @@ var XmlParser = class {
|
|
|
813
814
|
// src/codecs/hwpx/xml/parse-header.ts
|
|
814
815
|
function parseHeaderXml(xml) {
|
|
815
816
|
const root = parseXml(xml);
|
|
817
|
+
const refList = findChild(root, "hh:refList") || root;
|
|
816
818
|
return {
|
|
817
|
-
fontFaces: parseFontFaces(
|
|
818
|
-
borderFills: parseBorderFills(
|
|
819
|
-
charProperties: parseCharProperties(
|
|
820
|
-
paraProperties: parseParaProperties(
|
|
821
|
-
styles: parseStyles(
|
|
822
|
-
bulletProperties: parseBullets(
|
|
823
|
-
numberingProperties: parseNumberings(
|
|
819
|
+
fontFaces: parseFontFaces(refList),
|
|
820
|
+
borderFills: parseBorderFills(refList),
|
|
821
|
+
charProperties: parseCharProperties(refList),
|
|
822
|
+
paraProperties: parseParaProperties(refList),
|
|
823
|
+
styles: parseStyles(refList),
|
|
824
|
+
bulletProperties: parseBullets(refList),
|
|
825
|
+
numberingProperties: parseNumberings(refList),
|
|
824
826
|
compatibleDoc: parseCompatibleDoc(root)
|
|
825
827
|
};
|
|
826
828
|
}
|
|
@@ -894,15 +896,21 @@ function parseCharProperties(root) {
|
|
|
894
896
|
if (!propsNode) return props;
|
|
895
897
|
for (const cpNode of findChildren(propsNode, "hh:charPr")) {
|
|
896
898
|
const fontRefNode = findChild(cpNode, "hh:fontRef");
|
|
899
|
+
const hasBoldElement = !!findChild(cpNode, "hh:bold");
|
|
900
|
+
const hasItalicElement = !!findChild(cpNode, "hh:italic");
|
|
901
|
+
const underlineNode = findChild(cpNode, "hh:underline");
|
|
902
|
+
const strikeoutNode = findChild(cpNode, "hh:strikeout");
|
|
903
|
+
const underline = underlineNode ? attrStr(underlineNode, "type", "NONE") : attrStr(cpNode, "underline", "NONE");
|
|
904
|
+
const strikeout = strikeoutNode ? attrStr(strikeoutNode, "shape", "NONE") === "NONE" ? "NONE" : "CONTINUOUS" : attrStr(cpNode, "strikeout", "NONE");
|
|
897
905
|
props.push({
|
|
898
906
|
id: attrInt(cpNode, "id"),
|
|
899
907
|
height: attrInt(cpNode, "height", 1e3),
|
|
900
908
|
textColor: parseColor(attrStr(cpNode, "textColor", "#000000")),
|
|
901
|
-
shadeColor: cpNode.attrs["shadeColor"] ? parseColor(attrStr(cpNode, "shadeColor")) : void 0,
|
|
902
|
-
bold: attrBool(cpNode, "bold"),
|
|
903
|
-
italic: attrBool(cpNode, "italic"),
|
|
904
|
-
underline
|
|
905
|
-
strikeout
|
|
909
|
+
shadeColor: cpNode.attrs["shadeColor"] && cpNode.attrs["shadeColor"] !== "none" ? parseColor(attrStr(cpNode, "shadeColor")) : void 0,
|
|
910
|
+
bold: hasBoldElement || attrBool(cpNode, "bold"),
|
|
911
|
+
italic: hasItalicElement || attrBool(cpNode, "italic"),
|
|
912
|
+
underline,
|
|
913
|
+
strikeout,
|
|
906
914
|
useFontSpace: attrBool(cpNode, "useFontSpace"),
|
|
907
915
|
useKerning: attrBool(cpNode, "useKerning"),
|
|
908
916
|
spacing: cpNode.attrs["spacing"] !== void 0 ? attrInt(cpNode, "spacing") : void 0,
|
|
@@ -926,24 +934,54 @@ function parseParaProperties(root) {
|
|
|
926
934
|
const propsNode = findChild(root, "hh:paraProperties");
|
|
927
935
|
if (!propsNode) return props;
|
|
928
936
|
for (const ppNode of findChildren(propsNode, "hh:paraPr")) {
|
|
929
|
-
const
|
|
930
|
-
const
|
|
937
|
+
const alignNode = findChild(ppNode, "hh:align");
|
|
938
|
+
const alignment = alignNode ? attrStr(alignNode, "horizontal", "JUSTIFY") : attrStr(ppNode, "align", "JUSTIFY");
|
|
939
|
+
let marginNode = findChild(ppNode, "hh:parMargin") || findChild(ppNode, "hh:margin");
|
|
940
|
+
let lineSpacingNode = findChild(ppNode, "hh:lineSpacing");
|
|
941
|
+
const switchNode = findChild(ppNode, "hp:switch");
|
|
942
|
+
if (switchNode) {
|
|
943
|
+
const caseNode = findChild(switchNode, "hp:case");
|
|
944
|
+
if (caseNode) {
|
|
945
|
+
if (!marginNode) marginNode = findChild(caseNode, "hh:margin");
|
|
946
|
+
if (!lineSpacingNode) lineSpacingNode = findChild(caseNode, "hh:lineSpacing");
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
let paraMargin = { left: 0, right: 0, indent: 0, prevSpacing: 0, nextSpacing: 0 };
|
|
950
|
+
if (marginNode) {
|
|
951
|
+
const leftChild = findChild(marginNode, "hc:left");
|
|
952
|
+
if (leftChild) {
|
|
953
|
+
const intentChild = findChild(marginNode, "hc:intent");
|
|
954
|
+
const rightChild = findChild(marginNode, "hc:right");
|
|
955
|
+
const prevChild = findChild(marginNode, "hc:prev");
|
|
956
|
+
const nextChild = findChild(marginNode, "hc:next");
|
|
957
|
+
paraMargin = {
|
|
958
|
+
left: leftChild ? attrInt(leftChild, "value") : 0,
|
|
959
|
+
right: rightChild ? attrInt(rightChild, "value") : 0,
|
|
960
|
+
indent: intentChild ? attrInt(intentChild, "value") : 0,
|
|
961
|
+
prevSpacing: prevChild ? attrInt(prevChild, "value") : 0,
|
|
962
|
+
nextSpacing: nextChild ? attrInt(nextChild, "value") : 0
|
|
963
|
+
};
|
|
964
|
+
} else {
|
|
965
|
+
paraMargin = {
|
|
966
|
+
left: attrInt(marginNode, "left"),
|
|
967
|
+
right: attrInt(marginNode, "right"),
|
|
968
|
+
indent: attrInt(marginNode, "indent"),
|
|
969
|
+
prevSpacing: attrInt(marginNode, "prev"),
|
|
970
|
+
nextSpacing: attrInt(marginNode, "next")
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
const headingNode = findChild(ppNode, "hh:heading");
|
|
931
975
|
props.push({
|
|
932
976
|
id: attrInt(ppNode, "id"),
|
|
933
|
-
alignment
|
|
934
|
-
heading: ppNode.attrs["heading"] ? ppNode.attrs["heading"] : void 0,
|
|
977
|
+
alignment,
|
|
978
|
+
heading: headingNode ? attrStr(headingNode, "type", "NONE") : ppNode.attrs["heading"] ? ppNode.attrs["heading"] : void 0,
|
|
935
979
|
breakBefore: ppNode.attrs["breakBefore"] ? ppNode.attrs["breakBefore"] : void 0,
|
|
936
980
|
lineSpacing: lineSpacingNode ? {
|
|
937
981
|
type: attrStr(lineSpacingNode, "type", "PERCENT"),
|
|
938
982
|
value: attrInt(lineSpacingNode, "value", 160)
|
|
939
983
|
} : { type: "PERCENT", value: 160 },
|
|
940
|
-
paraMargin
|
|
941
|
-
left: attrInt(marginNode, "left"),
|
|
942
|
-
right: attrInt(marginNode, "right"),
|
|
943
|
-
indent: attrInt(marginNode, "indent"),
|
|
944
|
-
prevSpacing: attrInt(marginNode, "prev"),
|
|
945
|
-
nextSpacing: attrInt(marginNode, "next")
|
|
946
|
-
} : { left: 0, right: 0, indent: 0, prevSpacing: 0, nextSpacing: 0 }
|
|
984
|
+
paraMargin
|
|
947
985
|
});
|
|
948
986
|
}
|
|
949
987
|
return props;
|
|
@@ -1015,12 +1053,24 @@ function parseSectionXml(xml) {
|
|
|
1015
1053
|
};
|
|
1016
1054
|
}
|
|
1017
1055
|
function parseSectionDef(root) {
|
|
1018
|
-
|
|
1056
|
+
let secPr = findChild(root, "hs:secPr");
|
|
1057
|
+
if (!secPr) {
|
|
1058
|
+
for (const p of findChildren(root, "hp:p")) {
|
|
1059
|
+
for (const run of findChildren(p, "hp:run")) {
|
|
1060
|
+
const found = findChild(run, "hp:secPr");
|
|
1061
|
+
if (found) {
|
|
1062
|
+
secPr = found;
|
|
1063
|
+
break;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
if (secPr) break;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1019
1069
|
if (!secPr) {
|
|
1020
1070
|
return defaultSectionDef();
|
|
1021
1071
|
}
|
|
1022
|
-
const pagePr = findChild(secPr, "hs:pagePr");
|
|
1023
|
-
const pageMarginNode = findChild(secPr, "hs:pageMargin");
|
|
1072
|
+
const pagePr = findChild(secPr, "hp:pagePr") || findChild(secPr, "hs:pagePr");
|
|
1073
|
+
const pageMarginNode = findChild(secPr, "hs:pageMargin") || (pagePr ? findChild(pagePr, "hp:margin") || findChild(pagePr, "hs:margin") : void 0);
|
|
1024
1074
|
const colPr = findChild(secPr, "hs:colPr");
|
|
1025
1075
|
let columns;
|
|
1026
1076
|
if (colPr && attrInt(colPr, "count", 1) > 1) {
|
|
@@ -1046,7 +1096,7 @@ function parseSectionDef(root) {
|
|
|
1046
1096
|
return {
|
|
1047
1097
|
pageWidth: pagePr ? attrInt(pagePr, "width", 59528) : 59528,
|
|
1048
1098
|
pageHeight: pagePr ? attrInt(pagePr, "height", 84188) : 84188,
|
|
1049
|
-
landscape: pagePr ? attrStr(pagePr, "landscape") === "LANDSCAPE" : false,
|
|
1099
|
+
landscape: pagePr ? attrStr(pagePr, "landscape") === "LANDSCAPE" || attrStr(pagePr, "landscape") === "WIDELY" : false,
|
|
1050
1100
|
gutterType: pagePr ? attrStr(pagePr, "gutterType", "LEFT_ONLY") : "LEFT_ONLY",
|
|
1051
1101
|
pageMargin: pageMarginNode ? parsePageMargin(pageMarginNode) : defaultPageMargin(),
|
|
1052
1102
|
columns,
|
|
@@ -1076,11 +1126,11 @@ function parseParagraph(pNode) {
|
|
|
1076
1126
|
for (const runNode of findChildren(pNode, "hp:run")) {
|
|
1077
1127
|
const charPrIDRef = attrInt(runNode, "charPrIDRef");
|
|
1078
1128
|
const lineBreak = findChild(runNode, "hp:lineBreak");
|
|
1079
|
-
const
|
|
1129
|
+
const pageBreak2 = findChild(runNode, "hp:pageBreak");
|
|
1080
1130
|
const colBreak = findChild(runNode, "hp:colBreak");
|
|
1081
1131
|
if (lineBreak) {
|
|
1082
1132
|
runs.push({ t: "break", breakType: "LINE", charPrIDRef });
|
|
1083
|
-
} else if (
|
|
1133
|
+
} else if (pageBreak2) {
|
|
1084
1134
|
runs.push({ t: "break", breakType: "PAGE", charPrIDRef });
|
|
1085
1135
|
} else if (colBreak) {
|
|
1086
1136
|
runs.push({ t: "break", breakType: "COLUMN", charPrIDRef });
|
|
@@ -1095,29 +1145,36 @@ function parseParagraph(pNode) {
|
|
|
1095
1145
|
runs.push({ t: "picture", picture: parsePicture(picNode), charPrIDRef });
|
|
1096
1146
|
continue;
|
|
1097
1147
|
}
|
|
1098
|
-
const runTextNode = findChild(runNode, "hp:runText");
|
|
1148
|
+
const runTextNode = findChild(runNode, "hp:runText") || findChild(runNode, "hp:t");
|
|
1099
1149
|
const text = runTextNode ? getTextContent(runTextNode) : "";
|
|
1100
1150
|
runs.push({ t: "text", text, charPrIDRef });
|
|
1101
1151
|
}
|
|
1102
1152
|
}
|
|
1153
|
+
const pageBreakVal = attrStr(pNode, "pageBreak", "0");
|
|
1154
|
+
const pageBreak = pageBreakVal === "1" || pageBreakVal === "true";
|
|
1103
1155
|
return {
|
|
1104
1156
|
paraPrIDRef: attrInt(pNode, "paraPrIDRef"),
|
|
1105
1157
|
styleIDRef: attrInt(pNode, "styleIDRef"),
|
|
1106
|
-
runs
|
|
1158
|
+
runs,
|
|
1159
|
+
...pageBreak ? { pageBreak: true } : {}
|
|
1107
1160
|
};
|
|
1108
1161
|
}
|
|
1109
1162
|
function parseTable(tblNode) {
|
|
1110
1163
|
const rowCount = attrInt(tblNode, "rowCnt", 1);
|
|
1111
1164
|
const colCount = attrInt(tblNode, "colCnt", 1);
|
|
1112
|
-
const width = attrInt(tblNode, "width", 0);
|
|
1113
1165
|
const borderFillIDRef = attrInt(tblNode, "borderFillIDRef", 1);
|
|
1114
1166
|
const cellSpacing = attrInt(tblNode, "cellSpacing", 0);
|
|
1167
|
+
const szNode = findChild(tblNode, "hp:sz");
|
|
1168
|
+
const width = szNode ? attrInt(szNode, "width", 0) : attrInt(tblNode, "width", 0);
|
|
1115
1169
|
const colSzNodes = findChildren(tblNode, "hp:colSz");
|
|
1116
|
-
|
|
1170
|
+
let colWidths = colSzNodes.map((n) => attrInt(n, "width", 0));
|
|
1117
1171
|
const rows = [];
|
|
1118
1172
|
for (const trNode of findChildren(tblNode, "hp:tr")) {
|
|
1119
1173
|
rows.push(parseTableRow(trNode));
|
|
1120
1174
|
}
|
|
1175
|
+
if (colWidths.length === 0 && rows.length > 0) {
|
|
1176
|
+
colWidths = rows[0].cells.map((c) => c.width);
|
|
1177
|
+
}
|
|
1121
1178
|
return {
|
|
1122
1179
|
rowCount,
|
|
1123
1180
|
colCount,
|
|
@@ -1129,21 +1186,31 @@ function parseTable(tblNode) {
|
|
|
1129
1186
|
};
|
|
1130
1187
|
}
|
|
1131
1188
|
function parseTableRow(trNode) {
|
|
1132
|
-
const height = attrInt(trNode, "height", 0);
|
|
1133
1189
|
const cells = [];
|
|
1134
1190
|
for (const tcNode of findChildren(trNode, "hp:tc")) {
|
|
1135
1191
|
cells.push(parseTableCell(tcNode));
|
|
1136
1192
|
}
|
|
1193
|
+
const height = attrInt(trNode, "height", 0) || (cells.length > 0 ? cells[0].height : 0);
|
|
1137
1194
|
return { height, cells };
|
|
1138
1195
|
}
|
|
1139
1196
|
function parseTableCell(tcNode) {
|
|
1140
|
-
const
|
|
1141
|
-
const
|
|
1142
|
-
const
|
|
1143
|
-
const
|
|
1197
|
+
const cellSpanNode = findChild(tcNode, "hp:cellSpan");
|
|
1198
|
+
const colSpan = cellSpanNode ? attrInt(cellSpanNode, "colSpan", 1) : attrInt(tcNode, "colSpan", 1);
|
|
1199
|
+
const rowSpan = cellSpanNode ? attrInt(cellSpanNode, "rowSpan", 1) : attrInt(tcNode, "rowSpan", 1);
|
|
1200
|
+
const cellSzNode = findChild(tcNode, "hp:cellSz");
|
|
1201
|
+
const width = cellSzNode ? attrInt(cellSzNode, "width", 0) : attrInt(tcNode, "width", 0);
|
|
1202
|
+
const height = cellSzNode ? attrInt(cellSzNode, "height", 0) : attrInt(tcNode, "height", 0);
|
|
1144
1203
|
const borderFillIDRef = attrInt(tcNode, "borderFillIDRef", 1);
|
|
1145
1204
|
let padding;
|
|
1146
|
-
|
|
1205
|
+
const cellMarginNode = findChild(tcNode, "hp:cellMargin");
|
|
1206
|
+
if (cellMarginNode) {
|
|
1207
|
+
padding = {
|
|
1208
|
+
left: attrInt(cellMarginNode, "left"),
|
|
1209
|
+
right: attrInt(cellMarginNode, "right"),
|
|
1210
|
+
top: attrInt(cellMarginNode, "top"),
|
|
1211
|
+
bottom: attrInt(cellMarginNode, "bottom")
|
|
1212
|
+
};
|
|
1213
|
+
} else if (tcNode.attrs["paddingLeft"] !== void 0) {
|
|
1147
1214
|
padding = {
|
|
1148
1215
|
left: attrInt(tcNode, "paddingLeft"),
|
|
1149
1216
|
right: attrInt(tcNode, "paddingRight"),
|
|
@@ -2060,6 +2127,303 @@ function detectFormat(data) {
|
|
|
2060
2127
|
return "unknown";
|
|
2061
2128
|
}
|
|
2062
2129
|
|
|
2130
|
+
// src/codecs/pdf/writer.ts
|
|
2131
|
+
var PdfBuilder = class {
|
|
2132
|
+
constructor() {
|
|
2133
|
+
this.objects = [];
|
|
2134
|
+
this.offsets = [];
|
|
2135
|
+
this.output = "";
|
|
2136
|
+
}
|
|
2137
|
+
nextId() {
|
|
2138
|
+
return this.objects.length + 1;
|
|
2139
|
+
}
|
|
2140
|
+
addObject(content) {
|
|
2141
|
+
const id = this.nextId();
|
|
2142
|
+
this.objects.push(content);
|
|
2143
|
+
return id;
|
|
2144
|
+
}
|
|
2145
|
+
build() {
|
|
2146
|
+
this.output = "%PDF-1.4\n%\xC0\xC1\xC2\xC3\n";
|
|
2147
|
+
for (let i = 0; i < this.objects.length; i++) {
|
|
2148
|
+
this.offsets.push(this.output.length);
|
|
2149
|
+
this.output += `${i + 1} 0 obj
|
|
2150
|
+
${this.objects[i]}
|
|
2151
|
+
endobj
|
|
2152
|
+
`;
|
|
2153
|
+
}
|
|
2154
|
+
const xrefOffset = this.output.length;
|
|
2155
|
+
this.output += "xref\n";
|
|
2156
|
+
this.output += `0 ${this.objects.length + 1}
|
|
2157
|
+
`;
|
|
2158
|
+
this.output += "0000000000 65535 f \n";
|
|
2159
|
+
for (const off of this.offsets) {
|
|
2160
|
+
this.output += off.toString().padStart(10, "0") + " 00000 n \n";
|
|
2161
|
+
}
|
|
2162
|
+
this.output += "trailer\n";
|
|
2163
|
+
this.output += `<< /Size ${this.objects.length + 1} /Root 1 0 R >>
|
|
2164
|
+
`;
|
|
2165
|
+
this.output += "startxref\n";
|
|
2166
|
+
this.output += `${xrefOffset}
|
|
2167
|
+
`;
|
|
2168
|
+
this.output += "%%EOF\n";
|
|
2169
|
+
return stringToBytes(this.output);
|
|
2170
|
+
}
|
|
2171
|
+
};
|
|
2172
|
+
function writePdf(doc, opts) {
|
|
2173
|
+
const korFont = opts?.fontName || "Malgun Gothic";
|
|
2174
|
+
const latFont = opts?.latinFontName || "Helvetica";
|
|
2175
|
+
const pdf = new PdfBuilder();
|
|
2176
|
+
const catalogId = pdf.addObject("");
|
|
2177
|
+
const pagesId = pdf.addObject("");
|
|
2178
|
+
const cidFontId = pdf.addObject(
|
|
2179
|
+
`<< /Type /Font /Subtype /CIDFontType2 /BaseFont /${sanitizeName(korFont)} /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /DW 1000 >>`
|
|
2180
|
+
);
|
|
2181
|
+
const korFontId = pdf.addObject(
|
|
2182
|
+
`<< /Type /Font /Subtype /Type0 /BaseFont /${sanitizeName(korFont)} /Encoding /Identity-H /DescendantFonts [${cidFontId} 0 R] /ToUnicode ${pdf.nextId() + 1} 0 R >>`
|
|
2183
|
+
);
|
|
2184
|
+
const cmapStream = buildToUnicodeCMap();
|
|
2185
|
+
const cmapId = pdf.addObject(
|
|
2186
|
+
`<< /Length ${cmapStream.length} >>
|
|
2187
|
+
stream
|
|
2188
|
+
${cmapStream}
|
|
2189
|
+
endstream`
|
|
2190
|
+
);
|
|
2191
|
+
pdf.objects[korFontId - 1] = `<< /Type /Font /Subtype /Type0 /BaseFont /${sanitizeName(korFont)} /Encoding /Identity-H /DescendantFonts [${cidFontId} 0 R] /ToUnicode ${cmapId} 0 R >>`;
|
|
2192
|
+
const latFontId = pdf.addObject(
|
|
2193
|
+
`<< /Type /Font /Subtype /Type1 /BaseFont /${sanitizeName(latFont)} /Encoding /WinAnsiEncoding >>`
|
|
2194
|
+
);
|
|
2195
|
+
const fontResources = `/F1 ${korFontId} 0 R /F2 ${latFontId} 0 R`;
|
|
2196
|
+
const pageIds = [];
|
|
2197
|
+
for (const section of doc.sections) {
|
|
2198
|
+
const pageW = section.def.pageWidth / 7200 * 72;
|
|
2199
|
+
const pageH = section.def.pageHeight / 7200 * 72;
|
|
2200
|
+
const ml = section.def.pageMargin.left / 7200 * 72;
|
|
2201
|
+
const mr = section.def.pageMargin.right / 7200 * 72;
|
|
2202
|
+
const mt = section.def.pageMargin.top / 7200 * 72;
|
|
2203
|
+
const mb = section.def.pageMargin.bottom / 7200 * 72;
|
|
2204
|
+
const bodyW = pageW - ml - mr;
|
|
2205
|
+
const bodyH = pageH - mt - mb;
|
|
2206
|
+
const ctx = {
|
|
2207
|
+
doc,
|
|
2208
|
+
pdf,
|
|
2209
|
+
pagesId,
|
|
2210
|
+
fontResources,
|
|
2211
|
+
pageW,
|
|
2212
|
+
pageH,
|
|
2213
|
+
ml,
|
|
2214
|
+
mr,
|
|
2215
|
+
mt,
|
|
2216
|
+
mb,
|
|
2217
|
+
bodyW,
|
|
2218
|
+
bodyH,
|
|
2219
|
+
pageIds
|
|
2220
|
+
};
|
|
2221
|
+
renderSection(ctx, section);
|
|
2222
|
+
}
|
|
2223
|
+
pdf.objects[0] = `<< /Type /Catalog /Pages ${pagesId} 0 R >>`;
|
|
2224
|
+
const kids = pageIds.map((id) => `${id} 0 R`).join(" ");
|
|
2225
|
+
pdf.objects[1] = `<< /Type /Pages /Kids [${kids}] /Count ${pageIds.length} >>`;
|
|
2226
|
+
return pdf.build();
|
|
2227
|
+
}
|
|
2228
|
+
function renderSection(ctx, section) {
|
|
2229
|
+
let page = newPage(ctx);
|
|
2230
|
+
for (const para of section.paragraphs) {
|
|
2231
|
+
for (const run of para.runs) {
|
|
2232
|
+
if (run.t === "text") {
|
|
2233
|
+
const fontSize = getFontSize(ctx.doc, run.charPrIDRef);
|
|
2234
|
+
const lineHeight = fontSize * 1.6;
|
|
2235
|
+
if (page.y - lineHeight < 0) {
|
|
2236
|
+
flushPage(ctx, page);
|
|
2237
|
+
page = newPage(ctx);
|
|
2238
|
+
}
|
|
2239
|
+
if (run.text) {
|
|
2240
|
+
const color = getTextColor(ctx.doc, run.charPrIDRef);
|
|
2241
|
+
const bold = isBold(ctx.doc, run.charPrIDRef);
|
|
2242
|
+
if (color !== "0 0 0") {
|
|
2243
|
+
page.ops.push(color + " rg");
|
|
2244
|
+
}
|
|
2245
|
+
const lines = wrapText(run.text, fontSize, ctx.bodyW);
|
|
2246
|
+
for (const line of lines) {
|
|
2247
|
+
if (page.y - lineHeight < 0) {
|
|
2248
|
+
flushPage(ctx, page);
|
|
2249
|
+
page = newPage(ctx);
|
|
2250
|
+
}
|
|
2251
|
+
page.ops.push("BT");
|
|
2252
|
+
page.ops.push(`/F1 ${fontSize} Tf`);
|
|
2253
|
+
page.ops.push(`${ctx.ml} ${ctx.mt + page.y - lineHeight} Td`);
|
|
2254
|
+
page.ops.push(`<${toUtf16Hex(line)}> Tj`);
|
|
2255
|
+
page.ops.push("ET");
|
|
2256
|
+
page.y -= lineHeight;
|
|
2257
|
+
}
|
|
2258
|
+
if (color !== "0 0 0") {
|
|
2259
|
+
page.ops.push("0 0 0 rg");
|
|
2260
|
+
}
|
|
2261
|
+
} else {
|
|
2262
|
+
page.y -= fontSize * 1.6;
|
|
2263
|
+
}
|
|
2264
|
+
} else if (run.t === "table") {
|
|
2265
|
+
const tableHeight = estimateTableHeight(run.table, ctx.doc);
|
|
2266
|
+
if (page.y - tableHeight < 0 && page.y < ctx.bodyH - 10) {
|
|
2267
|
+
flushPage(ctx, page);
|
|
2268
|
+
page = newPage(ctx);
|
|
2269
|
+
}
|
|
2270
|
+
renderTable(ctx, page, run.table);
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
flushPage(ctx, page);
|
|
2275
|
+
}
|
|
2276
|
+
function newPage(ctx) {
|
|
2277
|
+
return { ops: [], y: ctx.bodyH };
|
|
2278
|
+
}
|
|
2279
|
+
function flushPage(ctx, page) {
|
|
2280
|
+
if (page.ops.length === 0) return;
|
|
2281
|
+
const stream = page.ops.join("\n");
|
|
2282
|
+
const streamId = ctx.pdf.addObject(
|
|
2283
|
+
`<< /Length ${byteLength(stream)} >>
|
|
2284
|
+
stream
|
|
2285
|
+
${stream}
|
|
2286
|
+
endstream`
|
|
2287
|
+
);
|
|
2288
|
+
const pageId = ctx.pdf.addObject(
|
|
2289
|
+
`<< /Type /Page /Parent ${ctx.pagesId} 0 R /MediaBox [0 0 ${fmt(ctx.pageW)} ${fmt(ctx.pageH)}] /Resources << /Font << ${ctx.fontResources} >> >> /Contents ${streamId} 0 R >>`
|
|
2290
|
+
);
|
|
2291
|
+
ctx.pageIds.push(pageId);
|
|
2292
|
+
}
|
|
2293
|
+
function renderTable(ctx, page, table) {
|
|
2294
|
+
const tableW = table.width / 7200 * 72;
|
|
2295
|
+
const scale = Math.min(1, ctx.bodyW / tableW);
|
|
2296
|
+
const startX = ctx.ml;
|
|
2297
|
+
const startY = ctx.mt + page.y;
|
|
2298
|
+
for (const row of table.rows) {
|
|
2299
|
+
const rowH = row.height / 7200 * 72 * scale;
|
|
2300
|
+
let cellX = startX;
|
|
2301
|
+
for (const cell of row.cells) {
|
|
2302
|
+
const cellW = cell.width / 7200 * 72 * scale;
|
|
2303
|
+
const cellH = cell.height / 7200 * 72 * scale;
|
|
2304
|
+
const cellY = startY - rowH;
|
|
2305
|
+
page.ops.push("0.5 w");
|
|
2306
|
+
page.ops.push(`${fmt(cellX)} ${fmt(cellY)} ${fmt(cellW)} ${fmt(cellH)} re S`);
|
|
2307
|
+
const text = cell.paragraphs.flatMap((p) => p.runs.filter((r) => r.t === "text").map((r) => r.text)).join(" ");
|
|
2308
|
+
if (text) {
|
|
2309
|
+
const fontSize = 8 * scale;
|
|
2310
|
+
const textX = cellX + 3;
|
|
2311
|
+
const textY = cellY + cellH - fontSize - 2;
|
|
2312
|
+
page.ops.push("BT");
|
|
2313
|
+
page.ops.push(`/F1 ${fmt(fontSize)} Tf`);
|
|
2314
|
+
page.ops.push(`${fmt(textX)} ${fmt(textY)} Td`);
|
|
2315
|
+
page.ops.push(`<${toUtf16Hex(text.substring(0, 100))}> Tj`);
|
|
2316
|
+
page.ops.push("ET");
|
|
2317
|
+
}
|
|
2318
|
+
cellX += cellW;
|
|
2319
|
+
}
|
|
2320
|
+
page.y -= rowH;
|
|
2321
|
+
startY === ctx.mt + page.y + rowH;
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
function estimateTableHeight(table, doc) {
|
|
2325
|
+
let h = 0;
|
|
2326
|
+
for (const row of table.rows) {
|
|
2327
|
+
h += row.height / 7200 * 72;
|
|
2328
|
+
}
|
|
2329
|
+
return h;
|
|
2330
|
+
}
|
|
2331
|
+
function getFontSize(doc, charPrIDRef) {
|
|
2332
|
+
const cp = doc.head.charProperties.find((c) => c.id === charPrIDRef);
|
|
2333
|
+
if (!cp) return 10;
|
|
2334
|
+
return cp.height / 100;
|
|
2335
|
+
}
|
|
2336
|
+
function getTextColor(doc, charPrIDRef) {
|
|
2337
|
+
const cp = doc.head.charProperties.find((c) => c.id === charPrIDRef);
|
|
2338
|
+
if (!cp || cp.textColor === 0) return "0 0 0";
|
|
2339
|
+
const r = (cp.textColor & 255) / 255;
|
|
2340
|
+
const g = (cp.textColor >> 8 & 255) / 255;
|
|
2341
|
+
const b = (cp.textColor >> 16 & 255) / 255;
|
|
2342
|
+
return `${fmt(r)} ${fmt(g)} ${fmt(b)}`;
|
|
2343
|
+
}
|
|
2344
|
+
function isBold(doc, charPrIDRef) {
|
|
2345
|
+
const cp = doc.head.charProperties.find((c) => c.id === charPrIDRef);
|
|
2346
|
+
return cp?.bold || false;
|
|
2347
|
+
}
|
|
2348
|
+
function wrapText(text, fontSize, maxWidth) {
|
|
2349
|
+
const lines = [];
|
|
2350
|
+
let current = "";
|
|
2351
|
+
let currentWidth = 0;
|
|
2352
|
+
for (const ch of text) {
|
|
2353
|
+
const w = ch.charCodeAt(0) > 127 ? fontSize : fontSize * 0.5;
|
|
2354
|
+
if (currentWidth + w > maxWidth && current) {
|
|
2355
|
+
lines.push(current);
|
|
2356
|
+
current = "";
|
|
2357
|
+
currentWidth = 0;
|
|
2358
|
+
}
|
|
2359
|
+
current += ch;
|
|
2360
|
+
currentWidth += w;
|
|
2361
|
+
}
|
|
2362
|
+
if (current) lines.push(current);
|
|
2363
|
+
return lines.length > 0 ? lines : [""];
|
|
2364
|
+
}
|
|
2365
|
+
function buildToUnicodeCMap() {
|
|
2366
|
+
return [
|
|
2367
|
+
"/CIDInit /ProcSet findresource begin",
|
|
2368
|
+
"12 dict begin",
|
|
2369
|
+
"begincmap",
|
|
2370
|
+
"/CIDSystemInfo",
|
|
2371
|
+
"<< /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def",
|
|
2372
|
+
"/CMapName /Adobe-Identity-UCS def",
|
|
2373
|
+
"/CMapType 2 def",
|
|
2374
|
+
"1 begincodespacerange",
|
|
2375
|
+
"<0000> <FFFF>",
|
|
2376
|
+
"endcodespacerange",
|
|
2377
|
+
"1 beginbfrange",
|
|
2378
|
+
"<0000> <FFFF> <0000>",
|
|
2379
|
+
"endbfrange",
|
|
2380
|
+
"endcmap",
|
|
2381
|
+
"CMapName currentdict /CMap defineresource pop",
|
|
2382
|
+
"end",
|
|
2383
|
+
"end"
|
|
2384
|
+
].join("\n");
|
|
2385
|
+
}
|
|
2386
|
+
function toUtf16Hex(str) {
|
|
2387
|
+
let hex = "";
|
|
2388
|
+
for (let i = 0; i < str.length; i++) {
|
|
2389
|
+
const code = str.charCodeAt(i);
|
|
2390
|
+
hex += code.toString(16).padStart(4, "0");
|
|
2391
|
+
}
|
|
2392
|
+
return hex.toUpperCase();
|
|
2393
|
+
}
|
|
2394
|
+
function sanitizeName(name) {
|
|
2395
|
+
return name.replace(/[^a-zA-Z0-9]/g, "");
|
|
2396
|
+
}
|
|
2397
|
+
function fmt(n) {
|
|
2398
|
+
return Number(n.toFixed(2)).toString();
|
|
2399
|
+
}
|
|
2400
|
+
function byteLength(str) {
|
|
2401
|
+
let len = 0;
|
|
2402
|
+
for (let i = 0; i < str.length; i++) {
|
|
2403
|
+
const code = str.charCodeAt(i);
|
|
2404
|
+
if (code <= 127) len++;
|
|
2405
|
+
else if (code <= 2047) len += 2;
|
|
2406
|
+
else len += 3;
|
|
2407
|
+
}
|
|
2408
|
+
return len;
|
|
2409
|
+
}
|
|
2410
|
+
function stringToBytes(str) {
|
|
2411
|
+
const bytes = [];
|
|
2412
|
+
for (let i = 0; i < str.length; i++) {
|
|
2413
|
+
const code = str.charCodeAt(i);
|
|
2414
|
+
if (code <= 255) {
|
|
2415
|
+
bytes.push(code);
|
|
2416
|
+
} else {
|
|
2417
|
+
if (code <= 2047) {
|
|
2418
|
+
bytes.push(192 | code >> 6, 128 | code & 63);
|
|
2419
|
+
} else {
|
|
2420
|
+
bytes.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63);
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
return new Uint8Array(bytes);
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2063
2427
|
// src/utils/id.ts
|
|
2064
2428
|
var IdCounter = class {
|
|
2065
2429
|
constructor(start = 0) {
|
|
@@ -2392,6 +2756,9 @@ function read(data, opts) {
|
|
|
2392
2756
|
}
|
|
2393
2757
|
return readHwpx(data, opts);
|
|
2394
2758
|
}
|
|
2759
|
+
function writePdf2(doc, opts) {
|
|
2760
|
+
return writePdf(doc, opts);
|
|
2761
|
+
}
|
|
2395
2762
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2396
2763
|
0 && (module.exports = {
|
|
2397
2764
|
HWPXBuilder,
|
|
@@ -2408,6 +2775,7 @@ function read(data, opts) {
|
|
|
2408
2775
|
createDefaultStyles,
|
|
2409
2776
|
read,
|
|
2410
2777
|
utils,
|
|
2411
|
-
write
|
|
2778
|
+
write,
|
|
2779
|
+
writePdf
|
|
2412
2780
|
});
|
|
2413
2781
|
//# sourceMappingURL=index.cjs.map
|