odf.js 1.5.0 → 1.6.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 +4 -3
- package/dist/index.cjs +563 -35
- package/dist/index.d.cts +53 -2
- package/dist/index.d.ts +53 -2
- package/dist/index.js +554 -36
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1494,6 +1494,28 @@ function parseBox(element) {
|
|
|
1494
1494
|
heightPt
|
|
1495
1495
|
};
|
|
1496
1496
|
}
|
|
1497
|
+
function parseLinePoints(element) {
|
|
1498
|
+
const x1Value = attrValue(element, "svg:x1");
|
|
1499
|
+
const y1Value = attrValue(element, "svg:y1");
|
|
1500
|
+
const x2Value = attrValue(element, "svg:x2");
|
|
1501
|
+
const y2Value = attrValue(element, "svg:y2");
|
|
1502
|
+
if (x1Value === void 0 || y1Value === void 0 || x2Value === void 0 || y2Value === void 0) return;
|
|
1503
|
+
const x1Pt = parseOdfLength(x1Value);
|
|
1504
|
+
const y1Pt = parseOdfLength(y1Value);
|
|
1505
|
+
const x2Pt = parseOdfLength(x2Value);
|
|
1506
|
+
const y2Pt = parseOdfLength(y2Value);
|
|
1507
|
+
if (x1Pt === void 0 || y1Pt === void 0 || x2Pt === void 0 || y2Pt === void 0) return;
|
|
1508
|
+
return {
|
|
1509
|
+
from: {
|
|
1510
|
+
xPt: x1Pt,
|
|
1511
|
+
yPt: y1Pt
|
|
1512
|
+
},
|
|
1513
|
+
to: {
|
|
1514
|
+
xPt: x2Pt,
|
|
1515
|
+
yPt: y2Pt
|
|
1516
|
+
}
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1497
1519
|
//#endregion
|
|
1498
1520
|
//#region src/typed/shared/cascade.ts
|
|
1499
1521
|
const STYLE_PARTS = ["content.xml", "styles.xml"];
|
|
@@ -1858,6 +1880,291 @@ function composeOdfGroupTransform(groupFunctions, child) {
|
|
|
1858
1880
|
};
|
|
1859
1881
|
}
|
|
1860
1882
|
//#endregion
|
|
1883
|
+
//#region src/typed/shared/masterpage.ts
|
|
1884
|
+
const STYLES_PART$1 = "styles.xml";
|
|
1885
|
+
const AUTOMATIC_STYLE_PARTS$1 = ["content.xml", STYLES_PART$1];
|
|
1886
|
+
function findMasterPageElement(pkg, masterPageName) {
|
|
1887
|
+
if (masterPageName === void 0) return;
|
|
1888
|
+
const stylesPart = pkg.parts[STYLES_PART$1];
|
|
1889
|
+
if (stylesPart?.kind !== "xml") return;
|
|
1890
|
+
const root = rootElement(stylesPart.nodes);
|
|
1891
|
+
const masterStyles = root === void 0 ? void 0 : findChildElement(root.children, "office:master-styles");
|
|
1892
|
+
if (masterStyles === void 0) return;
|
|
1893
|
+
return childrenWithTag(masterStyles, "style:master-page").find((element) => attrValue(element, "style:name") === masterPageName);
|
|
1894
|
+
}
|
|
1895
|
+
function findPageLayoutElement$1(pkg, pageLayoutName) {
|
|
1896
|
+
if (pageLayoutName === void 0) return;
|
|
1897
|
+
for (const partPath of AUTOMATIC_STYLE_PARTS$1) {
|
|
1898
|
+
const part = pkg.parts[partPath];
|
|
1899
|
+
if (part?.kind !== "xml") continue;
|
|
1900
|
+
const root = rootElement(part.nodes);
|
|
1901
|
+
const automaticStyles = root === void 0 ? void 0 : findChildElement(root.children, "office:automatic-styles");
|
|
1902
|
+
if (automaticStyles === void 0) continue;
|
|
1903
|
+
const found = childrenWithTag(automaticStyles, "style:page-layout").find((element) => attrValue(element, "style:name") === pageLayoutName);
|
|
1904
|
+
if (found !== void 0) return found;
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
function resolveDrawPageSize(page, pkg) {
|
|
1908
|
+
const masterPage = findMasterPageElement(pkg, attrValue(page, "draw:master-page-name"));
|
|
1909
|
+
const pageLayout = findPageLayoutElement$1(pkg, masterPage === void 0 ? void 0 : attrValue(masterPage, "style:page-layout-name"));
|
|
1910
|
+
const properties = pageLayout === void 0 ? void 0 : childrenWithTag(pageLayout, "style:page-layout-properties")[0];
|
|
1911
|
+
return properties === void 0 ? void 0 : parsePageSize(properties);
|
|
1912
|
+
}
|
|
1913
|
+
//#endregion
|
|
1914
|
+
//#region src/typed/shared/path.ts
|
|
1915
|
+
const VIEW_BOX_PATTERN = /^(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)$/;
|
|
1916
|
+
function parseOdfViewBox(value) {
|
|
1917
|
+
const match = VIEW_BOX_PATTERN.exec(value.trim());
|
|
1918
|
+
if (match === null) return;
|
|
1919
|
+
const minX = Number(match[1]);
|
|
1920
|
+
const minY = Number(match[2]);
|
|
1921
|
+
const width = Number(match[3]);
|
|
1922
|
+
const height = Number(match[4]);
|
|
1923
|
+
if (width <= 0 || height <= 0) return;
|
|
1924
|
+
return {
|
|
1925
|
+
minX,
|
|
1926
|
+
minY,
|
|
1927
|
+
width,
|
|
1928
|
+
height
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
function parseOdfPointsList(value) {
|
|
1932
|
+
const points = [];
|
|
1933
|
+
for (const pair of value.trim().split(/\s+/)) {
|
|
1934
|
+
if (pair.length === 0) continue;
|
|
1935
|
+
const [xRaw, yRaw] = pair.split(",");
|
|
1936
|
+
if (xRaw === void 0 || yRaw === void 0) continue;
|
|
1937
|
+
const x = Number(xRaw);
|
|
1938
|
+
const y = Number(yRaw);
|
|
1939
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) continue;
|
|
1940
|
+
points.push({
|
|
1941
|
+
x,
|
|
1942
|
+
y
|
|
1943
|
+
});
|
|
1944
|
+
}
|
|
1945
|
+
return points;
|
|
1946
|
+
}
|
|
1947
|
+
function rawSubpathFromPoints(points, closed) {
|
|
1948
|
+
const start = points[0];
|
|
1949
|
+
if (start === void 0) return;
|
|
1950
|
+
return {
|
|
1951
|
+
start,
|
|
1952
|
+
segments: points.slice(1).map((to) => ({
|
|
1953
|
+
kind: "line",
|
|
1954
|
+
to
|
|
1955
|
+
})),
|
|
1956
|
+
closed
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
const COMMAND_LETTERS = /* @__PURE__ */ new Set([
|
|
1960
|
+
"M",
|
|
1961
|
+
"m",
|
|
1962
|
+
"L",
|
|
1963
|
+
"l",
|
|
1964
|
+
"H",
|
|
1965
|
+
"h",
|
|
1966
|
+
"V",
|
|
1967
|
+
"v",
|
|
1968
|
+
"C",
|
|
1969
|
+
"c",
|
|
1970
|
+
"S",
|
|
1971
|
+
"s",
|
|
1972
|
+
"Q",
|
|
1973
|
+
"q",
|
|
1974
|
+
"T",
|
|
1975
|
+
"t",
|
|
1976
|
+
"A",
|
|
1977
|
+
"a",
|
|
1978
|
+
"Z",
|
|
1979
|
+
"z"
|
|
1980
|
+
]);
|
|
1981
|
+
function isCommandLetter(token) {
|
|
1982
|
+
return COMMAND_LETTERS.has(token);
|
|
1983
|
+
}
|
|
1984
|
+
const PATH_TOKEN_PATTERN = /[MmLlHhVvCcSsQqTtAaZz]|-?(?:\d+\.\d+|\.\d+|\d+)(?:[eE][-+]?\d+)?/g;
|
|
1985
|
+
function tokenizePathData(d) {
|
|
1986
|
+
return d.match(PATH_TOKEN_PATTERN) ?? [];
|
|
1987
|
+
}
|
|
1988
|
+
function parseOdfPathData(d) {
|
|
1989
|
+
const tokens = tokenizePathData(d);
|
|
1990
|
+
const subpaths = [];
|
|
1991
|
+
let current = {
|
|
1992
|
+
x: 0,
|
|
1993
|
+
y: 0
|
|
1994
|
+
};
|
|
1995
|
+
let subpathStart = {
|
|
1996
|
+
x: 0,
|
|
1997
|
+
y: 0
|
|
1998
|
+
};
|
|
1999
|
+
let activeSubpath;
|
|
2000
|
+
let command;
|
|
2001
|
+
let firstMInCommand = true;
|
|
2002
|
+
function startSubpath(point) {
|
|
2003
|
+
activeSubpath = {
|
|
2004
|
+
start: point,
|
|
2005
|
+
segments: [],
|
|
2006
|
+
closed: false
|
|
2007
|
+
};
|
|
2008
|
+
subpaths.push(activeSubpath);
|
|
2009
|
+
subpathStart = point;
|
|
2010
|
+
current = point;
|
|
2011
|
+
}
|
|
2012
|
+
function pushSegment(segment, to) {
|
|
2013
|
+
if (activeSubpath !== void 0) activeSubpath.segments.push(segment);
|
|
2014
|
+
current = to;
|
|
2015
|
+
}
|
|
2016
|
+
let i = 0;
|
|
2017
|
+
while (i < tokens.length) {
|
|
2018
|
+
const token = tokens[i];
|
|
2019
|
+
if (token === void 0) break;
|
|
2020
|
+
if (isCommandLetter(token)) {
|
|
2021
|
+
if (token === "Z" || token === "z") {
|
|
2022
|
+
if (activeSubpath !== void 0) {
|
|
2023
|
+
activeSubpath.closed = true;
|
|
2024
|
+
current = subpathStart;
|
|
2025
|
+
}
|
|
2026
|
+
command = void 0;
|
|
2027
|
+
i += 1;
|
|
2028
|
+
continue;
|
|
2029
|
+
}
|
|
2030
|
+
command = token;
|
|
2031
|
+
firstMInCommand = true;
|
|
2032
|
+
i += 1;
|
|
2033
|
+
continue;
|
|
2034
|
+
}
|
|
2035
|
+
if (command === void 0) {
|
|
2036
|
+
i += 1;
|
|
2037
|
+
continue;
|
|
2038
|
+
}
|
|
2039
|
+
const upper = command.toUpperCase();
|
|
2040
|
+
const relative = command !== upper;
|
|
2041
|
+
if (upper === "M" || upper === "L") {
|
|
2042
|
+
const xTok = tokens[i];
|
|
2043
|
+
const yTok = tokens[i + 1];
|
|
2044
|
+
i += 2;
|
|
2045
|
+
if (xTok === void 0 || yTok === void 0) break;
|
|
2046
|
+
const x = Number(xTok);
|
|
2047
|
+
const y = Number(yTok);
|
|
2048
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) continue;
|
|
2049
|
+
const point = relative ? {
|
|
2050
|
+
x: current.x + x,
|
|
2051
|
+
y: current.y + y
|
|
2052
|
+
} : {
|
|
2053
|
+
x,
|
|
2054
|
+
y
|
|
2055
|
+
};
|
|
2056
|
+
if (upper === "M" && firstMInCommand) {
|
|
2057
|
+
startSubpath(point);
|
|
2058
|
+
firstMInCommand = false;
|
|
2059
|
+
} else pushSegment({
|
|
2060
|
+
kind: "line",
|
|
2061
|
+
to: point
|
|
2062
|
+
}, point);
|
|
2063
|
+
} else if (upper === "H") {
|
|
2064
|
+
const xTok = tokens[i];
|
|
2065
|
+
i += 1;
|
|
2066
|
+
if (xTok === void 0) break;
|
|
2067
|
+
const x = Number(xTok);
|
|
2068
|
+
if (!Number.isFinite(x)) continue;
|
|
2069
|
+
const point = relative ? {
|
|
2070
|
+
x: current.x + x,
|
|
2071
|
+
y: current.y
|
|
2072
|
+
} : {
|
|
2073
|
+
x,
|
|
2074
|
+
y: current.y
|
|
2075
|
+
};
|
|
2076
|
+
pushSegment({
|
|
2077
|
+
kind: "line",
|
|
2078
|
+
to: point
|
|
2079
|
+
}, point);
|
|
2080
|
+
} else if (upper === "V") {
|
|
2081
|
+
const yTok = tokens[i];
|
|
2082
|
+
i += 1;
|
|
2083
|
+
if (yTok === void 0) break;
|
|
2084
|
+
const y = Number(yTok);
|
|
2085
|
+
if (!Number.isFinite(y)) continue;
|
|
2086
|
+
const point = relative ? {
|
|
2087
|
+
x: current.x,
|
|
2088
|
+
y: current.y + y
|
|
2089
|
+
} : {
|
|
2090
|
+
x: current.x,
|
|
2091
|
+
y
|
|
2092
|
+
};
|
|
2093
|
+
pushSegment({
|
|
2094
|
+
kind: "line",
|
|
2095
|
+
to: point
|
|
2096
|
+
}, point);
|
|
2097
|
+
} else if (upper === "C") {
|
|
2098
|
+
const rawArgs = tokens.slice(i, i + 6);
|
|
2099
|
+
i += 6;
|
|
2100
|
+
if (rawArgs.length < 6) break;
|
|
2101
|
+
const x1 = Number(rawArgs[0]);
|
|
2102
|
+
const y1 = Number(rawArgs[1]);
|
|
2103
|
+
const x2 = Number(rawArgs[2]);
|
|
2104
|
+
const y2 = Number(rawArgs[3]);
|
|
2105
|
+
const x = Number(rawArgs[4]);
|
|
2106
|
+
const y = Number(rawArgs[5]);
|
|
2107
|
+
if (![
|
|
2108
|
+
x1,
|
|
2109
|
+
y1,
|
|
2110
|
+
x2,
|
|
2111
|
+
y2,
|
|
2112
|
+
x,
|
|
2113
|
+
y
|
|
2114
|
+
].every(Number.isFinite)) continue;
|
|
2115
|
+
const control1 = relative ? {
|
|
2116
|
+
x: current.x + x1,
|
|
2117
|
+
y: current.y + y1
|
|
2118
|
+
} : {
|
|
2119
|
+
x: x1,
|
|
2120
|
+
y: y1
|
|
2121
|
+
};
|
|
2122
|
+
const control2 = relative ? {
|
|
2123
|
+
x: current.x + x2,
|
|
2124
|
+
y: current.y + y2
|
|
2125
|
+
} : {
|
|
2126
|
+
x: x2,
|
|
2127
|
+
y: y2
|
|
2128
|
+
};
|
|
2129
|
+
const to = relative ? {
|
|
2130
|
+
x: current.x + x,
|
|
2131
|
+
y: current.y + y
|
|
2132
|
+
} : {
|
|
2133
|
+
x,
|
|
2134
|
+
y
|
|
2135
|
+
};
|
|
2136
|
+
pushSegment({
|
|
2137
|
+
kind: "cubic",
|
|
2138
|
+
control1,
|
|
2139
|
+
control2,
|
|
2140
|
+
to
|
|
2141
|
+
}, to);
|
|
2142
|
+
} else i += 1;
|
|
2143
|
+
}
|
|
2144
|
+
return subpaths;
|
|
2145
|
+
}
|
|
2146
|
+
function scaleOdfRawPoint(point, viewBox, frame) {
|
|
2147
|
+
return {
|
|
2148
|
+
xPt: (point.x - viewBox.minX) * (frame.widthPt / viewBox.width),
|
|
2149
|
+
yPt: (point.y - viewBox.minY) * (frame.heightPt / viewBox.height)
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
2152
|
+
function buildOdfSubpaths(rawSubpaths, viewBox, frame) {
|
|
2153
|
+
return rawSubpaths.map((raw) => ({
|
|
2154
|
+
start: scaleOdfRawPoint(raw.start, viewBox, frame),
|
|
2155
|
+
closed: raw.closed,
|
|
2156
|
+
segments: raw.segments.map((segment) => segment.kind === "line" ? {
|
|
2157
|
+
kind: "line",
|
|
2158
|
+
to: scaleOdfRawPoint(segment.to, viewBox, frame)
|
|
2159
|
+
} : {
|
|
2160
|
+
kind: "cubic",
|
|
2161
|
+
control1: scaleOdfRawPoint(segment.control1, viewBox, frame),
|
|
2162
|
+
control2: scaleOdfRawPoint(segment.control2, viewBox, frame),
|
|
2163
|
+
to: scaleOdfRawPoint(segment.to, viewBox, frame)
|
|
2164
|
+
})
|
|
2165
|
+
}));
|
|
2166
|
+
}
|
|
2167
|
+
//#endregion
|
|
1861
2168
|
//#region src/typed/draw/shapes.ts
|
|
1862
2169
|
const ZERO_INSETS = {
|
|
1863
2170
|
insetLeftPt: 0,
|
|
@@ -1939,37 +2246,224 @@ function walkDrawShapes(children, groupFunctions, pkg, out) {
|
|
|
1939
2246
|
}
|
|
1940
2247
|
}
|
|
1941
2248
|
}
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
const
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
2249
|
+
function readOdfFillAndStroke(element, pkg) {
|
|
2250
|
+
const { elements } = resolveStyleElementChain(attrValue(element, "draw:style-name"), "graphic", pkg);
|
|
2251
|
+
let fill;
|
|
2252
|
+
let stroke;
|
|
2253
|
+
for (const styleElement of elements) {
|
|
2254
|
+
const props = childrenWithTag(styleElement, "style:graphic-properties")[0];
|
|
2255
|
+
if (props === void 0) continue;
|
|
2256
|
+
if (attrValue(props, "draw:fill") === "none") fill = void 0;
|
|
2257
|
+
else {
|
|
2258
|
+
const fillColorValue = attrValue(props, "draw:fill-color");
|
|
2259
|
+
const parsedFill = fillColorValue === void 0 ? void 0 : parseOdfColor(fillColorValue);
|
|
2260
|
+
if (parsedFill !== void 0) fill = parsedFill;
|
|
2261
|
+
}
|
|
2262
|
+
if (attrValue(props, "draw:stroke") === "none") stroke = void 0;
|
|
2263
|
+
else {
|
|
2264
|
+
const strokeColorValue = attrValue(props, "svg:stroke-color");
|
|
2265
|
+
const strokeWidthValue = attrValue(props, "svg:stroke-width");
|
|
2266
|
+
const strokeColor = strokeColorValue === void 0 ? void 0 : parseOdfColor(strokeColorValue);
|
|
2267
|
+
const strokeWidthPt = strokeWidthValue === void 0 ? void 0 : parseOdfLength(strokeWidthValue);
|
|
2268
|
+
if (strokeColor !== void 0 && strokeWidthPt !== void 0 && strokeWidthPt > 0) stroke = {
|
|
2269
|
+
color: strokeColor,
|
|
2270
|
+
widthPt: strokeWidthPt
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
return {
|
|
2275
|
+
fill,
|
|
2276
|
+
stroke
|
|
2277
|
+
};
|
|
1955
2278
|
}
|
|
1956
|
-
function
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
2279
|
+
function resolveVectorFrame(element, groupFunctions) {
|
|
2280
|
+
const geometry = resolveOdfShapeGeometry(element);
|
|
2281
|
+
if (geometry === void 0) return;
|
|
2282
|
+
return composeOdfGroupTransform(groupFunctions, geometry).frame;
|
|
2283
|
+
}
|
|
2284
|
+
function readDrawRectVector(element, groupFunctions, pkg) {
|
|
2285
|
+
const frame = resolveVectorFrame(element, groupFunctions);
|
|
2286
|
+
if (frame === void 0) return;
|
|
2287
|
+
const { fill, stroke } = readOdfFillAndStroke(element, pkg);
|
|
2288
|
+
return {
|
|
2289
|
+
kind: "rect",
|
|
2290
|
+
frame,
|
|
2291
|
+
fill,
|
|
2292
|
+
stroke
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
function readDrawEllipseVector(element, groupFunctions, pkg) {
|
|
2296
|
+
const frame = resolveVectorFrame(element, groupFunctions);
|
|
2297
|
+
if (frame === void 0) return;
|
|
2298
|
+
const { fill, stroke } = readOdfFillAndStroke(element, pkg);
|
|
2299
|
+
return {
|
|
2300
|
+
kind: "ellipse",
|
|
2301
|
+
frame,
|
|
2302
|
+
fill,
|
|
2303
|
+
stroke
|
|
2304
|
+
};
|
|
2305
|
+
}
|
|
2306
|
+
function readDrawLineVector(element, groupFunctions, pkg) {
|
|
2307
|
+
const raw = parseLinePoints(element);
|
|
2308
|
+
if (raw === void 0) return;
|
|
2309
|
+
const from = groupFunctions.length === 0 ? raw.from : applyOdfTransform(groupFunctions, raw.from);
|
|
2310
|
+
const to = groupFunctions.length === 0 ? raw.to : applyOdfTransform(groupFunctions, raw.to);
|
|
2311
|
+
const { stroke } = readOdfFillAndStroke(element, pkg);
|
|
2312
|
+
if (stroke === void 0) return;
|
|
2313
|
+
return {
|
|
2314
|
+
kind: "line",
|
|
2315
|
+
from,
|
|
2316
|
+
to,
|
|
2317
|
+
stroke
|
|
2318
|
+
};
|
|
2319
|
+
}
|
|
2320
|
+
function readDrawPathVector(element, groupFunctions, pkg) {
|
|
2321
|
+
const frame = resolveVectorFrame(element, groupFunctions);
|
|
2322
|
+
if (frame === void 0) return;
|
|
2323
|
+
const viewBoxValue = attrValue(element, "svg:viewBox");
|
|
2324
|
+
const viewBox = viewBoxValue === void 0 ? void 0 : parseOdfViewBox(viewBoxValue);
|
|
2325
|
+
if (viewBox === void 0) return;
|
|
2326
|
+
let rawSubpaths;
|
|
2327
|
+
if (element.tag === "draw:path") {
|
|
2328
|
+
const d = attrValue(element, "svg:d");
|
|
2329
|
+
rawSubpaths = d === void 0 ? [] : parseOdfPathData(d);
|
|
2330
|
+
} else {
|
|
2331
|
+
const pointsValue = attrValue(element, "draw:points");
|
|
2332
|
+
const subpath = rawSubpathFromPoints(pointsValue === void 0 ? [] : parseOdfPointsList(pointsValue), element.tag === "draw:polygon");
|
|
2333
|
+
rawSubpaths = subpath === void 0 ? [] : [subpath];
|
|
2334
|
+
}
|
|
2335
|
+
if (rawSubpaths.length === 0) return;
|
|
2336
|
+
const subpaths = buildOdfSubpaths(rawSubpaths, viewBox, frame);
|
|
2337
|
+
const { fill, stroke } = readOdfFillAndStroke(element, pkg);
|
|
2338
|
+
return {
|
|
2339
|
+
kind: "path",
|
|
2340
|
+
frame,
|
|
2341
|
+
subpaths,
|
|
2342
|
+
fill,
|
|
2343
|
+
stroke
|
|
2344
|
+
};
|
|
2345
|
+
}
|
|
2346
|
+
const RECOGNIZED_CUSTOM_SHAPE_PRESETS = /* @__PURE__ */ new Set([
|
|
2347
|
+
"rectangle",
|
|
2348
|
+
"round-rectangle",
|
|
2349
|
+
"ellipse"
|
|
2350
|
+
]);
|
|
2351
|
+
function readCustomShapeVector(element, groupFunctions, pkg) {
|
|
2352
|
+
const geometryElement = childrenWithTag(element, "draw:enhanced-geometry")[0];
|
|
2353
|
+
const type = geometryElement === void 0 ? void 0 : attrValue(geometryElement, "draw:type");
|
|
2354
|
+
if (type === void 0 || !RECOGNIZED_CUSTOM_SHAPE_PRESETS.has(type)) return;
|
|
2355
|
+
const frame = resolveVectorFrame(element, groupFunctions);
|
|
2356
|
+
if (frame === void 0) return;
|
|
2357
|
+
const { fill, stroke } = readOdfFillAndStroke(element, pkg);
|
|
2358
|
+
return {
|
|
2359
|
+
kind: type === "ellipse" ? "ellipse" : "rect",
|
|
2360
|
+
frame,
|
|
2361
|
+
fill,
|
|
2362
|
+
stroke
|
|
2363
|
+
};
|
|
2364
|
+
}
|
|
2365
|
+
function readCustomShapeAsTextShape(element, groupFunctions, pkg) {
|
|
2366
|
+
const paragraphs = elementsWithTag(element.children, "text:p").map((p) => readOdfParagraph(p, pkg));
|
|
2367
|
+
if (!paragraphs.some((paragraph) => paragraph.runs.some((run) => run.text.length > 0))) return;
|
|
2368
|
+
const ownGeometry = resolveOdfShapeGeometry(element);
|
|
2369
|
+
if (ownGeometry === void 0) return;
|
|
2370
|
+
const geometry = composeOdfGroupTransform(groupFunctions, ownGeometry);
|
|
2371
|
+
return {
|
|
2372
|
+
name: attrValue(element, "draw:name"),
|
|
2373
|
+
frame: geometry.frame,
|
|
2374
|
+
rotationDeg: geometry.rotationDeg,
|
|
2375
|
+
...readFrameInsets(element, pkg),
|
|
2376
|
+
blocks: paragraphs
|
|
2377
|
+
};
|
|
2378
|
+
}
|
|
2379
|
+
function nextDocumentIndex(state) {
|
|
2380
|
+
const value = state.next;
|
|
2381
|
+
state.next += 1;
|
|
2382
|
+
return value;
|
|
2383
|
+
}
|
|
2384
|
+
function paintOrderKey(element, state) {
|
|
2385
|
+
const documentIndex = nextDocumentIndex(state);
|
|
2386
|
+
const raw = attrValue(element, "draw:z-index");
|
|
2387
|
+
if (raw === void 0) return documentIndex;
|
|
2388
|
+
const parsed = Number.parseInt(raw, 10);
|
|
2389
|
+
return Number.isInteger(parsed) && parsed >= 0 ? parsed : documentIndex;
|
|
2390
|
+
}
|
|
2391
|
+
function byPaintOrder(items) {
|
|
2392
|
+
return items.slice().sort((a, b) => a.zIndex - b.zIndex).map((item) => item.value);
|
|
2393
|
+
}
|
|
2394
|
+
function walkDrawPageContent(children, groupFunctions, pkg, indexState, shapesOut, vectorsOut) {
|
|
2395
|
+
for (const node of children) {
|
|
2396
|
+
if (node.type !== "element") continue;
|
|
2397
|
+
if (node.tag === "draw:frame") {
|
|
2398
|
+
const zIndex = paintOrderKey(node, indexState);
|
|
2399
|
+
const shape = readDrawFrame(node, groupFunctions, pkg);
|
|
2400
|
+
if (shape !== void 0) shapesOut.push({
|
|
2401
|
+
value: shape,
|
|
2402
|
+
zIndex
|
|
2403
|
+
});
|
|
2404
|
+
} else if (node.tag === "draw:g") {
|
|
2405
|
+
const ownFunctions = readOwnTransformFunctions(node);
|
|
2406
|
+
const nested = ownFunctions.length === 0 ? groupFunctions : [...ownFunctions, ...groupFunctions];
|
|
2407
|
+
walkDrawPageContent(node.children, nested, pkg, indexState, shapesOut, vectorsOut);
|
|
2408
|
+
} else if (node.tag === "draw:rect") {
|
|
2409
|
+
const zIndex = paintOrderKey(node, indexState);
|
|
2410
|
+
const vector = readDrawRectVector(node, groupFunctions, pkg);
|
|
2411
|
+
if (vector !== void 0) vectorsOut.push({
|
|
2412
|
+
value: vector,
|
|
2413
|
+
zIndex
|
|
2414
|
+
});
|
|
2415
|
+
} else if (node.tag === "draw:ellipse" || node.tag === "draw:circle") {
|
|
2416
|
+
const zIndex = paintOrderKey(node, indexState);
|
|
2417
|
+
const vector = readDrawEllipseVector(node, groupFunctions, pkg);
|
|
2418
|
+
if (vector !== void 0) vectorsOut.push({
|
|
2419
|
+
value: vector,
|
|
2420
|
+
zIndex
|
|
2421
|
+
});
|
|
2422
|
+
} else if (node.tag === "draw:line") {
|
|
2423
|
+
const zIndex = paintOrderKey(node, indexState);
|
|
2424
|
+
const vector = readDrawLineVector(node, groupFunctions, pkg);
|
|
2425
|
+
if (vector !== void 0) vectorsOut.push({
|
|
2426
|
+
value: vector,
|
|
2427
|
+
zIndex
|
|
2428
|
+
});
|
|
2429
|
+
} else if (node.tag === "draw:path" || node.tag === "draw:polygon" || node.tag === "draw:polyline") {
|
|
2430
|
+
const zIndex = paintOrderKey(node, indexState);
|
|
2431
|
+
const vector = readDrawPathVector(node, groupFunctions, pkg);
|
|
2432
|
+
if (vector !== void 0) vectorsOut.push({
|
|
2433
|
+
value: vector,
|
|
2434
|
+
zIndex
|
|
2435
|
+
});
|
|
2436
|
+
} else if (node.tag === "draw:custom-shape") {
|
|
2437
|
+
const zIndex = paintOrderKey(node, indexState);
|
|
2438
|
+
const vector = readCustomShapeVector(node, groupFunctions, pkg);
|
|
2439
|
+
if (vector !== void 0) vectorsOut.push({
|
|
2440
|
+
value: vector,
|
|
2441
|
+
zIndex
|
|
2442
|
+
});
|
|
2443
|
+
else {
|
|
2444
|
+
const shape = readCustomShapeAsTextShape(node, groupFunctions, pkg);
|
|
2445
|
+
if (shape !== void 0) shapesOut.push({
|
|
2446
|
+
value: shape,
|
|
2447
|
+
zIndex
|
|
2448
|
+
});
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
1966
2451
|
}
|
|
1967
2452
|
}
|
|
2453
|
+
function readDrawPageContent(children, pkg) {
|
|
2454
|
+
const shapesOut = [];
|
|
2455
|
+
const vectorsOut = [];
|
|
2456
|
+
walkDrawPageContent(children, [], pkg, { next: 0 }, shapesOut, vectorsOut);
|
|
2457
|
+
return {
|
|
2458
|
+
shapes: byPaintOrder(shapesOut),
|
|
2459
|
+
vectors: byPaintOrder(vectorsOut)
|
|
2460
|
+
};
|
|
2461
|
+
}
|
|
2462
|
+
//#endregion
|
|
2463
|
+
//#region src/typed/odp/read.ts
|
|
2464
|
+
const CONTENT_PART$2 = "content.xml";
|
|
1968
2465
|
function readSlideSize(page, pkg) {
|
|
1969
|
-
|
|
1970
|
-
const pageLayout = findPageLayoutElement$1(pkg, masterPage === void 0 ? void 0 : attrValue(masterPage, "style:page-layout-name"));
|
|
1971
|
-
const properties = pageLayout === void 0 ? void 0 : childrenWithTag(pageLayout, "style:page-layout-properties")[0];
|
|
1972
|
-
return (properties === void 0 ? void 0 : parsePageSize(properties)) ?? SLIDE_SIZE_WIDESCREEN;
|
|
2466
|
+
return resolveDrawPageSize(page, pkg) ?? SLIDE_SIZE_WIDESCREEN;
|
|
1973
2467
|
}
|
|
1974
2468
|
function readSlideNotes(page) {
|
|
1975
2469
|
const notes = childrenWithTag(page, "presentation:notes")[0];
|
|
@@ -1986,7 +2480,7 @@ function readSlide(page, pkg) {
|
|
|
1986
2480
|
};
|
|
1987
2481
|
}
|
|
1988
2482
|
function readOdp(pkg) {
|
|
1989
|
-
const contentPart = pkg.parts[CONTENT_PART$
|
|
2483
|
+
const contentPart = pkg.parts[CONTENT_PART$2];
|
|
1990
2484
|
const root = contentPart?.kind === "xml" ? rootElement(contentPart.nodes) : void 0;
|
|
1991
2485
|
const body = root === void 0 ? void 0 : findChildElement(root.children, "office:body");
|
|
1992
2486
|
const presentation = body === void 0 ? void 0 : findChildElement(body.children, "office:presentation");
|
|
@@ -1998,9 +2492,9 @@ function readOdp(pkg) {
|
|
|
1998
2492
|
}
|
|
1999
2493
|
//#endregion
|
|
2000
2494
|
//#region src/typed/odt/read.ts
|
|
2001
|
-
const CONTENT_PART = "content.xml";
|
|
2495
|
+
const CONTENT_PART$1 = "content.xml";
|
|
2002
2496
|
const STYLES_PART = "styles.xml";
|
|
2003
|
-
const AUTOMATIC_STYLE_PARTS = [CONTENT_PART, STYLES_PART];
|
|
2497
|
+
const AUTOMATIC_STYLE_PARTS = [CONTENT_PART$1, STYLES_PART];
|
|
2004
2498
|
function readOutlineLevel(headingElement) {
|
|
2005
2499
|
const raw = attrValue(headingElement, "text:outline-level");
|
|
2006
2500
|
if (raw === void 0) return 1;
|
|
@@ -2048,7 +2542,7 @@ function parseKnownOdfLength(value) {
|
|
|
2048
2542
|
if (parsed === void 0) throw new Error(`readOdt: internal error -- "${value}" is not a valid ODF length literal`);
|
|
2049
2543
|
return parsed;
|
|
2050
2544
|
}
|
|
2051
|
-
const DEFAULT_PAGE_SIZE = PAGE_SIZE_A4;
|
|
2545
|
+
const DEFAULT_PAGE_SIZE$1 = PAGE_SIZE_A4;
|
|
2052
2546
|
const DEFAULT_MARGIN_PT = parseKnownOdfLength("2cm");
|
|
2053
2547
|
const DEFAULT_MARGINS = {
|
|
2054
2548
|
topPt: DEFAULT_MARGIN_PT,
|
|
@@ -2078,17 +2572,17 @@ function readFirstMasterPageGeometry(pkg) {
|
|
|
2078
2572
|
const pageSize = properties === void 0 ? void 0 : parsePageSize(properties);
|
|
2079
2573
|
const margins = properties === void 0 ? void 0 : parseMargins(properties);
|
|
2080
2574
|
return {
|
|
2081
|
-
pageSize: pageSize ?? DEFAULT_PAGE_SIZE,
|
|
2575
|
+
pageSize: pageSize ?? DEFAULT_PAGE_SIZE$1,
|
|
2082
2576
|
margins: margins ?? DEFAULT_MARGINS
|
|
2083
2577
|
};
|
|
2084
2578
|
}
|
|
2085
2579
|
function readOdt(pkg) {
|
|
2086
|
-
const contentPart = pkg.parts[CONTENT_PART];
|
|
2087
|
-
if (contentPart?.kind !== "xml") throw new Error(`readOdt: package has no ${CONTENT_PART} part`);
|
|
2580
|
+
const contentPart = pkg.parts[CONTENT_PART$1];
|
|
2581
|
+
if (contentPart?.kind !== "xml") throw new Error(`readOdt: package has no ${CONTENT_PART$1} part`);
|
|
2088
2582
|
const contentRoot = rootElement(contentPart.nodes);
|
|
2089
2583
|
const body = contentRoot === void 0 ? void 0 : findChildElement(contentRoot.children, "office:body");
|
|
2090
2584
|
const textElement = body === void 0 ? void 0 : findChildElement(body.children, "office:text");
|
|
2091
|
-
if (textElement === void 0) throw new Error(`readOdt: ${CONTENT_PART} has no office:body/office:text element`);
|
|
2585
|
+
if (textElement === void 0) throw new Error(`readOdt: ${CONTENT_PART$1} has no office:body/office:text element`);
|
|
2092
2586
|
const metadata = readOdfMetadata(pkg);
|
|
2093
2587
|
const { pageSize, margins } = readFirstMasterPageGeometry(pkg);
|
|
2094
2588
|
return {
|
|
@@ -2101,4 +2595,28 @@ function readOdt(pkg) {
|
|
|
2101
2595
|
};
|
|
2102
2596
|
}
|
|
2103
2597
|
//#endregion
|
|
2104
|
-
|
|
2598
|
+
//#region src/typed/odg/read.ts
|
|
2599
|
+
const CONTENT_PART = "content.xml";
|
|
2600
|
+
const DEFAULT_PAGE_SIZE = PAGE_SIZE_A4;
|
|
2601
|
+
function readPage(page, pkg) {
|
|
2602
|
+
const size = resolveDrawPageSize(page, pkg) ?? DEFAULT_PAGE_SIZE;
|
|
2603
|
+
const { shapes, vectors } = readDrawPageContent(page.children, pkg);
|
|
2604
|
+
return {
|
|
2605
|
+
size,
|
|
2606
|
+
shapes,
|
|
2607
|
+
vectors
|
|
2608
|
+
};
|
|
2609
|
+
}
|
|
2610
|
+
function readOdg(pkg) {
|
|
2611
|
+
const contentPart = pkg.parts[CONTENT_PART];
|
|
2612
|
+
const root = contentPart?.kind === "xml" ? rootElement(contentPart.nodes) : void 0;
|
|
2613
|
+
const body = root === void 0 ? void 0 : findChildElement(root.children, "office:body");
|
|
2614
|
+
const drawing = body === void 0 ? void 0 : findChildElement(body.children, "office:drawing");
|
|
2615
|
+
const pages = drawing === void 0 ? [] : childrenWithTag(drawing, "draw:page");
|
|
2616
|
+
return {
|
|
2617
|
+
metadata: readOdfMetadata(pkg),
|
|
2618
|
+
pages: pages.map((page) => readPage(page, pkg))
|
|
2619
|
+
};
|
|
2620
|
+
}
|
|
2621
|
+
//#endregion
|
|
2622
|
+
export { AlignmentSchema, AttributeSchema, BinaryPartSchema, MANIFEST_PART, META_PART, MIMETYPE_PART, ManifestEntrySchema, ManifestProblemSchema, ManifestSchema, ODF_MEDIA_TYPES, ODF_NAMESPACES, PackageSchema, PartSchema, STYLE_FAMILIES, StylePropertiesSchema, StyleRegistry, TableCursor, XmlCdataSchema, XmlCommentSchema, XmlDeclarationSchema, XmlElementSchema, XmlNodeSchema, XmlPartSchema, XmlPiSchema, XmlTextSchema, applyOdfTransform, attrValue, base64ToBytes, buildManifest, buildOdfSubpaths, buildStylePropertyElements, buildXml, bytesToBase64, canonicalPropertiesString, cellReference, childrenWithTag, columnIndexToLetters, composeOdfGroupTransform, decodeOdfText, decodePackage, decodeXmlText, el, elementsWithTag, encodePackage, encodeXmlText, ensureSpan, findChildElement, findStyleElement, formatOdfColor, formatOdfLength, formatPercentageMultiplier, formatPt, getOdfSpaceCount, isStyleFamily, isXmlNode, measureOdfNodeLength, mediaTypeForExtension, netRotationDeg, packageCodec, paragraphPropertiesToAttributes, parseBox, parseLength, parseLinePoints, parseMargins, parseOdfColor, parseOdfLength, parseOdfPathData, parseOdfPointsList, parseOdfTransform, parseOdfViewBox, parsePackage, parsePageSize, parseParagraphProperties, parseStyleElementProperties, parseTextProperties, parseXml, rawSubpathFromPoints, readDrawFrame, readDrawPageContent, readManifest, readMimetype, readOdfMetadata, readOdfParagraph, readOdfTable, readOdg, readOdp, readOdt, resolveDrawPageSize, resolveOdfShapeGeometry, resolveStyle, resolveStyleElementChain, rootElement, scaleOdfRawPoint, serializePackage, setDocumentMediaType, sniffImageFormat, sumOdfNodeLength, syncManifest, textPropertiesToAttributes, txt, unzipPackage, validateManifest, walkDrawShapes, writeManifest, writeMimetype, xmlCodec, xmlnsAttributes, zipPackage };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "odf.js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Type-safe, lossless round-trip conversion between OpenDocument Format packages (odt, ods, odp) and JSON, hand-written and dependency-minimal, built on Zod 4 codecs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"license": "MIT",
|
|
62
62
|
"packageManager": "pnpm@11.6.0",
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"document-content-model": "^1.
|
|
64
|
+
"document-content-model": "^1.2.0",
|
|
65
65
|
"fast-xml-parser": "^5.10.1",
|
|
66
66
|
"fflate": "^0.8.3",
|
|
67
67
|
"zod": "^4.4.3"
|