@shbernal/ts-pptx 1.0.0 → 3.0.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 +10 -3
- package/dist/{autopage-tmfjRzL4.js → autopage-MxulehqQ.js} +3 -4
- package/dist/{autopage-tmfjRzL4.js.map → autopage-MxulehqQ.js.map} +1 -1
- package/dist/browser.d.ts +14 -6
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +12 -4
- package/dist/browser.js.map +1 -1
- package/dist/{diagnostics-DzY9Tyfm.d.ts → diagnostics-BqBTmA3a.d.ts} +95 -23
- package/dist/diagnostics-BqBTmA3a.d.ts.map +1 -0
- package/dist/{enums-D3aF4QGb.d.ts → enums-oLLeaSW3.d.ts} +2 -1
- package/dist/{enums-D3aF4QGb.d.ts.map → enums-oLLeaSW3.d.ts.map} +1 -1
- package/dist/{errors-DRLpOpgQ.d.ts → errors-BENA-Xuw.d.ts} +3 -3
- package/dist/{errors-DRLpOpgQ.d.ts.map → errors-BENA-Xuw.d.ts.map} +1 -1
- package/dist/errors-DGE9zh3U.js.map +1 -1
- package/dist/{fit-CbxyHN69.js → fit-DGSwMMNs.js} +0 -0
- package/dist/{fit-CbxyHN69.js.map → fit-DGSwMMNs.js.map} +1 -1
- package/dist/{html-dom-wVa3TiG7.js → html-dom--J-Xuucf.js} +19 -5
- package/dist/html-dom--J-Xuucf.js.map +1 -0
- package/dist/html.d.ts +3 -3
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +6 -3
- package/dist/html.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +1 -1
- package/dist/inspect.js +2 -2
- package/dist/inspect.js.map +1 -1
- package/dist/math.d.ts +1 -1
- package/dist/math.js +2 -1
- package/dist/math.js.map +1 -1
- package/dist/measure.d.ts +2 -2
- package/dist/measure.js +1 -1
- package/dist/node.d.ts +14 -6
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +11 -3
- package/dist/node.js.map +1 -1
- package/dist/{pres-5x1bjCzk.d.ts → pres-2WsBGimU.d.ts} +3 -3
- package/dist/{pres-5x1bjCzk.d.ts.map → pres-2WsBGimU.d.ts.map} +1 -1
- package/dist/{presentation-RGOiun5P.d.ts → presentation-CTVPpiwP.d.ts} +912 -485
- package/dist/presentation-CTVPpiwP.d.ts.map +1 -0
- package/dist/{presentation-B0JWdTN1.js → presentation-DAcOfzsP.js} +880 -366
- package/dist/presentation-DAcOfzsP.js.map +1 -0
- package/dist/read.d.ts +4 -4
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +2 -2
- package/dist/script.d.ts +2 -2
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +0 -0
- package/dist/script.js.map +1 -1
- package/dist/{shapes-BZU8UTW2.js → shapes-BWifcHDV.js} +1520 -996
- package/dist/shapes-BWifcHDV.js.map +1 -0
- package/dist/{slide-B6mDaM-P.d.ts → slide-YuSCGa45.d.ts} +409 -103
- package/dist/slide-YuSCGa45.d.ts.map +1 -0
- package/dist/{image-size-C5Z1sKof.js → st-enums-CgadEyPM.js} +235 -4
- package/dist/st-enums-CgadEyPM.js.map +1 -0
- package/dist/{text-WRUbOy2r.js → text-120VFSDm.js} +1027 -369
- package/dist/text-120VFSDm.js.map +1 -0
- package/dist/{units-internal-7JcMfYti.js → units-internal-CiFWZWk4.js} +2 -1
- package/dist/units-internal-CiFWZWk4.js.map +1 -0
- package/dist/zip.d.ts +2 -2
- package/dist/zip.js.map +1 -1
- package/package.json +38 -36
- package/dist/diagnostics-DzY9Tyfm.d.ts.map +0 -1
- package/dist/html-dom-wVa3TiG7.js.map +0 -1
- package/dist/image-size-C5Z1sKof.js.map +0 -1
- package/dist/presentation-B0JWdTN1.js.map +0 -1
- package/dist/presentation-RGOiun5P.d.ts.map +0 -1
- package/dist/shapes-BZU8UTW2.js.map +0 -1
- package/dist/slide-B6mDaM-P.d.ts.map +0 -1
- package/dist/text-WRUbOy2r.js.map +0 -1
- package/dist/units-internal-7JcMfYti.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { n as warn, r as warnOnce } from "./diagnostics-DYQC7xLV.js";
|
|
2
2
|
import { n as InvalidOptionError, o as UnsupportedFeatureError, r as MediaError, t as InternalError } from "./errors-DGE9zh3U.js";
|
|
3
3
|
import { a as FIXED_PCT_PER_PERCENT, d as emuToInches, g as pixelsToEmu, i as EMU_PER_POINT, l as STANDARD_LAYOUTS, m as inchesToEmu, r as EMU_PER_INCH, s as PERCENT_SCALE, t as ANGLE_UNITS_PER_DEGREE, v as ptToHundredths } from "./units-B-JUKwCS.js";
|
|
4
|
-
import { $ as connectorPresetFor, C as DEF_PRES_LAYOUT_NAME, D as DEF_TEXT_GLOW, E as DEF_SLIDE_MARGIN_IN, F as PIECHART_COLORS, G as PlaceholderType, I as REGEX_HEX_COLOR, K as SchemeColor, L as SLDNUMFLDID, M as LAYOUT_IDX_SERIES_BASE, N as LETTERS, O as DEF_TEXT_SHADOW, Q as asChartType, R as XML_DECL, S as DEF_PRES_LAYOUT, T as DEF_SHAPE_SHADOW, Z as VALID_SHAPE_PRESETS, _ as DEF_CELL_BORDER, a as lineWidthToEmu, b as DEF_CHART_GRIDLINE, c as resolveTableColWidthsEmu, d as AXIS_ID_CATEGORY_PRIMARY, et as isChartExType, f as AXIS_ID_CATEGORY_SECONDARY, g as BARCHART_COLORS, h as AXIS_ID_VALUE_SECONDARY, i as inch2Emu, k as IMG_BROKEN, l as transparencyToAlpha, m as AXIS_ID_VALUE_PRIMARY, n as convertRotationDegrees, o as marginToEmu, p as AXIS_ID_SERIES_PRIMARY, r as getSmartParseNumber, s as opacityToAlpha, t as convertArcAngle, u as valToPts, v as DEF_CELL_MARGIN_IN, x as DEF_FONT_COLOR, y as DEF_CHART_BORDER } from "./units-internal-
|
|
5
|
-
import {
|
|
6
|
-
import { t as getSlidesForTableRows } from "./autopage-
|
|
7
|
-
import { _ as parseFontMetrics, m as FontMetricsRegistry, n as measureText, r as computeTableLayout, t as applyMeasuredFit } from "./fit-
|
|
4
|
+
import { $ as connectorPresetFor, C as DEF_PRES_LAYOUT_NAME, D as DEF_TEXT_GLOW, E as DEF_SLIDE_MARGIN_IN, F as PIECHART_COLORS, G as PlaceholderType, I as REGEX_HEX_COLOR, K as SchemeColor, L as SLDNUMFLDID, M as LAYOUT_IDX_SERIES_BASE, N as LETTERS, O as DEF_TEXT_SHADOW, Q as asChartType, R as XML_DECL, S as DEF_PRES_LAYOUT, T as DEF_SHAPE_SHADOW, Z as VALID_SHAPE_PRESETS, _ as DEF_CELL_BORDER, a as lineWidthToEmu, b as DEF_CHART_GRIDLINE, c as resolveTableColWidthsEmu, d as AXIS_ID_CATEGORY_PRIMARY, et as isChartExType, f as AXIS_ID_CATEGORY_SECONDARY, g as BARCHART_COLORS, h as AXIS_ID_VALUE_SECONDARY, i as inch2Emu, k as IMG_BROKEN, l as transparencyToAlpha, m as AXIS_ID_VALUE_PRIMARY, n as convertRotationDegrees, o as marginToEmu, p as AXIS_ID_SERIES_PRIMARY, r as getSmartParseNumber, s as opacityToAlpha, t as convertArcAngle, u as valToPts, v as DEF_CELL_MARGIN_IN, x as DEF_FONT_COLOR, y as DEF_CHART_BORDER } from "./units-internal-CiFWZWk4.js";
|
|
5
|
+
import { E as svgMarkupToDataUri, S as getImageSizeFromBase64, T as decodeBase64ToBytes, a as PRESET_MATERIALS, g as PACKAGE_REL_NS, h as OFFICE_REL, i as PRESET_LINE_DASHES, n as LIGHT_RIGS, r as LIGHT_RIG_DIRECTIONS, s as TEXT_HORZ_OVERFLOW, t as BEVEL_PRESETS, u as checkEnumOrWarn, x as fitSrcRectPercents } from "./st-enums-CgadEyPM.js";
|
|
6
|
+
import { t as getSlidesForTableRows } from "./autopage-MxulehqQ.js";
|
|
7
|
+
import { _ as parseFontMetrics, m as FontMetricsRegistry, n as measureText, r as computeTableLayout, t as applyMeasuredFit } from "./fit-DGSwMMNs.js";
|
|
8
8
|
import { a as flattenEmbeddedFaces, i as FONT_REL_TYPE, n as FONT_DATA_CONTENT_TYPE, o as serializeEmbeddedFontLst, r as FONT_DATA_EXTENSION, t as EMBEDDED_FONT_SLOTS } from "./embedded-fonts-MaynAHa9.js";
|
|
9
9
|
import { ZipWriter } from "./zip.js";
|
|
10
10
|
//#region src/media/content-type.ts
|
|
@@ -1326,7 +1326,7 @@ function addImageDefinition(target, opt) {
|
|
|
1326
1326
|
let defWidth = intWidth;
|
|
1327
1327
|
let defHeight = intHeight;
|
|
1328
1328
|
let szAuto;
|
|
1329
|
-
if ((!intWidth || !intHeight) && strImgExtn
|
|
1329
|
+
if ((!intWidth || !intHeight) && !(strImgExtn === "svg" && !intWidth && !intHeight)) {
|
|
1330
1330
|
const natural = strImageData ? getImageSizeFromBase64(strImageData) : null;
|
|
1331
1331
|
if (natural) {
|
|
1332
1332
|
if (!intWidth && !intHeight) {
|
|
@@ -1829,7 +1829,10 @@ function groupObjectsDefinition(target, objectNames, opts) {
|
|
|
1829
1829
|
const key = encodeXmlAttrValue(name);
|
|
1830
1830
|
const matches = target._slideObjects.filter((obj) => obj.options?.objectName === key);
|
|
1831
1831
|
const [obj, ambiguous] = matches;
|
|
1832
|
-
if (!obj)
|
|
1832
|
+
if (!obj) {
|
|
1833
|
+
const hint = findNameInGroups(target._slideObjects, key) ? "it is already inside a group (an object can only belong to one group)" : "no top-level object on this slide has that objectName";
|
|
1834
|
+
throw new InvalidOptionError("group/unresolved-object-name", `groupObjects(): cannot group "${name}" — ${hint}.`);
|
|
1835
|
+
}
|
|
1833
1836
|
if (ambiguous) throw new InvalidOptionError("group/ambiguous-object-name", `groupObjects(): objectName "${name}" is ambiguous — ${matches.length} objects on this slide share it. Give them unique objectNames.`);
|
|
1834
1837
|
if (!GROUPABLE_TYPES.includes(obj._type) || obj.options?.placeholder) {
|
|
1835
1838
|
const kind = obj.options?.placeholder ? "placeholder" : obj._type;
|
|
@@ -1958,23 +1961,6 @@ function addMediaDefinition(target, opt) {
|
|
|
1958
1961
|
target._slideObjects.push(slideData);
|
|
1959
1962
|
}
|
|
1960
1963
|
//#endregion
|
|
1961
|
-
//#region src/gen/define/notes.ts
|
|
1962
|
-
/**
|
|
1963
|
-
* Adds Notes to a slide.
|
|
1964
|
-
* @param {PresSlideInternal} `target` slide object
|
|
1965
|
-
* @param {string | NotesProps | NotesProps[]} `notes` plain text, or rich runs (inline formatting / hyperlinks)
|
|
1966
|
-
*/
|
|
1967
|
-
function addNotesDefinition(target, notes) {
|
|
1968
|
-
const runs = typeof notes === "string" ? [{ text: notes }] : (Array.isArray(notes) ? notes : [notes]).map((run) => ({
|
|
1969
|
-
text: run.text,
|
|
1970
|
-
options: run.options
|
|
1971
|
-
}));
|
|
1972
|
-
target._slideObjects.push({
|
|
1973
|
-
_type: "notes",
|
|
1974
|
-
text: runs
|
|
1975
|
-
});
|
|
1976
|
-
}
|
|
1977
|
-
//#endregion
|
|
1978
1964
|
//#region src/gen/define/preview-image.ts
|
|
1979
1965
|
/**
|
|
1980
1966
|
* Register a preview/cover image as a slide media rel (deduped like `addImage`) and return its rId.
|
|
@@ -2007,11 +1993,140 @@ function registerPreviewImage(target, cover) {
|
|
|
2007
1993
|
return rId;
|
|
2008
1994
|
}
|
|
2009
1995
|
//#endregion
|
|
1996
|
+
//#region src/gen/define/model3d.ts
|
|
1997
|
+
/** OPC content type for a glTF binary, as PowerPoint spells it in `[Content_Types].xml`. */
|
|
1998
|
+
const GLB_CONTENT_TYPE = "model/gltf.binary";
|
|
1999
|
+
/** `.rels` `Type` URI for the embedded 3D model part. Note `2017/06` — not the namespace's `2017`. */
|
|
2000
|
+
const MODEL3D_REL_TYPE = "http://schemas.microsoft.com/office/2017/06/relationships/model3d";
|
|
2001
|
+
/** Fixed-point denominator for `am3d` linear values: `am3d:up@dy="36000000"` is the unit vector. */
|
|
2002
|
+
const AM3D_UNIT = 36e6;
|
|
2003
|
+
/** Denominator of every `am3d` rational (`meterPerModelUnit`, `scale`, `illuminance`, `intensity`). */
|
|
2004
|
+
const AM3D_RATIO_DEN = 1e6;
|
|
2005
|
+
/** `am3d:perspective@fov` is in 60000ths of a degree, like every other DrawingML angle. */
|
|
2006
|
+
const FOV_PER_DEGREE = 6e4;
|
|
2007
|
+
/**
|
|
2008
|
+
* The camera PowerPoint wrote for the 2×2×2 cube fixture, in caller units (metres / degrees).
|
|
2009
|
+
* `z` is `sqrt(3)/2 / sin(22.5°)` — the bounding sphere of a 1-metre cube framed at a 45° fov.
|
|
2010
|
+
*/
|
|
2011
|
+
const DEFAULT_CAMERA = {
|
|
2012
|
+
pos: {
|
|
2013
|
+
x: 0,
|
|
2014
|
+
y: 0,
|
|
2015
|
+
z: 2.2630334
|
|
2016
|
+
},
|
|
2017
|
+
lookAt: {
|
|
2018
|
+
x: 0,
|
|
2019
|
+
y: 0,
|
|
2020
|
+
z: 0
|
|
2021
|
+
},
|
|
2022
|
+
up: {
|
|
2023
|
+
x: 0,
|
|
2024
|
+
y: 1,
|
|
2025
|
+
z: 0
|
|
2026
|
+
},
|
|
2027
|
+
fov: 45
|
|
2028
|
+
};
|
|
2029
|
+
/** `am3d:meterPerModelUnit` for the cube fixture: 1 / (its 2-unit largest extent). */
|
|
2030
|
+
const DEFAULT_METER_PER_MODEL_UNIT = .5;
|
|
2031
|
+
/** Reject a non-finite camera component rather than letting `NaN` reach the XML as `"NaN"`. */
|
|
2032
|
+
function toAm3dUnits(point, fallback, label) {
|
|
2033
|
+
const src = point ?? fallback;
|
|
2034
|
+
for (const axis of [
|
|
2035
|
+
"x",
|
|
2036
|
+
"y",
|
|
2037
|
+
"z"
|
|
2038
|
+
]) if (!Number.isFinite(src[axis])) throw new InvalidOptionError("model3d/invalid-camera", `addModel3d(): camera.${label}.${axis} must be a finite number, got ${String(src[axis])}.`);
|
|
2039
|
+
return {
|
|
2040
|
+
x: Math.round(src.x * AM3D_UNIT),
|
|
2041
|
+
y: Math.round(src.y * AM3D_UNIT),
|
|
2042
|
+
z: Math.round(src.z * AM3D_UNIT)
|
|
2043
|
+
};
|
|
2044
|
+
}
|
|
2045
|
+
/** Resolve `camera` + `meterPerModelUnit` into the wire units {@link Model3dInternal} carries. */
|
|
2046
|
+
function resolveCamera(camera, meterPerModelUnit) {
|
|
2047
|
+
const fovDeg = camera?.fov ?? DEFAULT_CAMERA.fov;
|
|
2048
|
+
if (!Number.isFinite(fovDeg) || fovDeg <= 0 || fovDeg >= 180) throw new InvalidOptionError("model3d/invalid-fov", `addModel3d(): camera.fov must be greater than 0 and less than 180 degrees, got ${String(fovDeg)}.`);
|
|
2049
|
+
const scale = meterPerModelUnit ?? DEFAULT_METER_PER_MODEL_UNIT;
|
|
2050
|
+
if (!Number.isFinite(scale) || scale <= 0) throw new InvalidOptionError("model3d/invalid-scale", `addModel3d(): meterPerModelUnit must be a finite number greater than 0, got ${String(scale)}.`);
|
|
2051
|
+
const up = toAm3dUnits(camera?.up, DEFAULT_CAMERA.up, "up");
|
|
2052
|
+
return {
|
|
2053
|
+
pos: toAm3dUnits(camera?.pos, DEFAULT_CAMERA.pos, "pos"),
|
|
2054
|
+
lookAt: toAm3dUnits(camera?.lookAt, DEFAULT_CAMERA.lookAt, "lookAt"),
|
|
2055
|
+
up: {
|
|
2056
|
+
dx: up.x,
|
|
2057
|
+
dy: up.y,
|
|
2058
|
+
dz: up.z
|
|
2059
|
+
},
|
|
2060
|
+
fov: Math.round(fovDeg * FOV_PER_DEGREE),
|
|
2061
|
+
meterPerModelUnitN: Math.round(scale * AM3D_RATIO_DEN)
|
|
2062
|
+
};
|
|
2063
|
+
}
|
|
2064
|
+
/**
|
|
2065
|
+
* Adds an embedded 3D model to a slide definition.
|
|
2066
|
+
* @param {PresSlideInternal} target - slide the model will be added to
|
|
2067
|
+
* @param {Model3dProps} opt - 3D model options
|
|
2068
|
+
*/
|
|
2069
|
+
function addModel3dDefinition(target, opt) {
|
|
2070
|
+
const strData = opt.data || "";
|
|
2071
|
+
const strPath = opt.path || "";
|
|
2072
|
+
if (!strPath && !strData) throw new InvalidOptionError("model3d/missing-source", "addModel3d(): either `data` or `path` are required!");
|
|
2073
|
+
const camera = resolveCamera(opt.camera, opt.meterPerModelUnit);
|
|
2074
|
+
const nameIdx = nextObjectNameIdx(target, "model3d");
|
|
2075
|
+
const objectName = opt.objectName ? encodeXmlAttrValue(validateObjectName(opt.objectName, "model3d")) : `3D Model ${nameIdx + 1}`;
|
|
2076
|
+
const modelRid = getNewRelId(target);
|
|
2077
|
+
const mediaSlideKey = target._slideNum == null ? "sm" : target._slideNum >= 1e3 ? `sl-${target._slideNum}` : target._slideNum;
|
|
2078
|
+
target._relsMedia.push({
|
|
2079
|
+
path: strPath || "preencoded.glb",
|
|
2080
|
+
type: GLB_CONTENT_TYPE,
|
|
2081
|
+
extn: "glb",
|
|
2082
|
+
data: strData,
|
|
2083
|
+
rId: modelRid,
|
|
2084
|
+
model3dRelType: MODEL3D_REL_TYPE,
|
|
2085
|
+
Target: `../media/model3d-${mediaSlideKey}-${target._relsMedia.length + 1}.glb`
|
|
2086
|
+
});
|
|
2087
|
+
if (!opt.preview?.path && !opt.preview?.data) warn("model3d/preview-missing", "addModel3d(): no `preview` image supplied, so a gray placeholder is embedded. PowerPoint 2019+ draws the live model over it, but thumbnails, PDF export and older viewers show the placeholder.");
|
|
2088
|
+
const previewRid = registerPreviewImage(target, opt.preview);
|
|
2089
|
+
const slideData = {
|
|
2090
|
+
_type: "model3d",
|
|
2091
|
+
options: {
|
|
2092
|
+
x: opt.x ?? 0,
|
|
2093
|
+
y: opt.y ?? 0,
|
|
2094
|
+
w: opt.w ?? 4,
|
|
2095
|
+
h: opt.h ?? 3,
|
|
2096
|
+
objectName,
|
|
2097
|
+
...opt.altText ? { altText: opt.altText } : {}
|
|
2098
|
+
},
|
|
2099
|
+
model3d: {
|
|
2100
|
+
modelRid,
|
|
2101
|
+
previewRid,
|
|
2102
|
+
...camera
|
|
2103
|
+
}
|
|
2104
|
+
};
|
|
2105
|
+
target._slideObjects.push(slideData);
|
|
2106
|
+
}
|
|
2107
|
+
//#endregion
|
|
2108
|
+
//#region src/gen/define/notes.ts
|
|
2109
|
+
/**
|
|
2110
|
+
* Adds Notes to a slide.
|
|
2111
|
+
* @param {PresSlideInternal} `target` slide object
|
|
2112
|
+
* @param {string | NotesProps | NotesProps[]} `notes` plain text, or rich runs (inline formatting / hyperlinks)
|
|
2113
|
+
*/
|
|
2114
|
+
function addNotesDefinition(target, notes) {
|
|
2115
|
+
const runs = typeof notes === "string" ? [{ text: notes }] : (Array.isArray(notes) ? notes : [notes]).map((run) => ({
|
|
2116
|
+
text: run.text,
|
|
2117
|
+
options: run.options
|
|
2118
|
+
}));
|
|
2119
|
+
target._slideObjects.push({
|
|
2120
|
+
_type: "notes",
|
|
2121
|
+
text: runs
|
|
2122
|
+
});
|
|
2123
|
+
}
|
|
2124
|
+
//#endregion
|
|
2010
2125
|
//#region src/gen/define/ole.ts
|
|
2011
2126
|
/** Rel type for an embedded OPC package (an Office file, itself a zip). */
|
|
2012
|
-
const PACKAGE_REL = "
|
|
2127
|
+
const PACKAGE_REL = OFFICE_REL + "package";
|
|
2013
2128
|
/** Rel type for a generic OLE-server blob — a compound-file `.bin` (ECMA-376 Part 1 §15.2.10). */
|
|
2014
|
-
const OLE_OBJECT_REL = "
|
|
2129
|
+
const OLE_OBJECT_REL = OFFICE_REL + "oleObject";
|
|
2015
2130
|
/**
|
|
2016
2131
|
* Embeddable payload formats, keyed by file extension. The six Office extensions are OPC packages
|
|
2017
2132
|
* and keep their own extension in `ppt/embeddings/`; everything else is embedded as a generic OLE
|
|
@@ -2148,6 +2263,44 @@ function normalizeBorderTuple(border) {
|
|
|
2148
2263
|
border
|
|
2149
2264
|
];
|
|
2150
2265
|
}
|
|
2266
|
+
/** Fill a border's defaulted keys, preserving anything else the caller set (`cap`, `dashType`, …). */
|
|
2267
|
+
function withBorderDefaults(side) {
|
|
2268
|
+
return {
|
|
2269
|
+
...side,
|
|
2270
|
+
type: side.type || DEF_CELL_BORDER.type,
|
|
2271
|
+
color: side.color || DEF_CELL_BORDER.color,
|
|
2272
|
+
width: typeof side.width === "number" ? side.width : DEF_CELL_BORDER.width
|
|
2273
|
+
};
|
|
2274
|
+
}
|
|
2275
|
+
/**
|
|
2276
|
+
* Resolve `TableProps.outerBorder` into the `[top, right, bottom, left]` tuple the emitter
|
|
2277
|
+
* applies to the table's edge cells, with `undefined` for a side the caller left out.
|
|
2278
|
+
*
|
|
2279
|
+
* A sparse side is *not* the same as `{ type: 'none' }`: it means "leave this edge to
|
|
2280
|
+
* whatever `border` (or the cell's own `options.border`) already drew", whereas `'none'` is
|
|
2281
|
+
* an explicit instruction to erase the rule there. Keeping the hole is what lets
|
|
2282
|
+
* `outerBorder: [rule, undefined, rule, undefined]` add rules above and below a table
|
|
2283
|
+
* without also clearing its left and right edges.
|
|
2284
|
+
*/
|
|
2285
|
+
function normalizeOuterBorder(outer) {
|
|
2286
|
+
if (!outer || typeof outer !== "object") return void 0;
|
|
2287
|
+
const sides = Array.isArray(outer) ? outer : [
|
|
2288
|
+
outer,
|
|
2289
|
+
outer,
|
|
2290
|
+
outer,
|
|
2291
|
+
outer
|
|
2292
|
+
];
|
|
2293
|
+
const resolved = [
|
|
2294
|
+
0,
|
|
2295
|
+
1,
|
|
2296
|
+
2,
|
|
2297
|
+
3
|
|
2298
|
+
].map((idx) => {
|
|
2299
|
+
const side = sides[idx];
|
|
2300
|
+
return side && typeof side === "object" ? withBorderDefaults(side) : void 0;
|
|
2301
|
+
});
|
|
2302
|
+
return resolved.some((side) => side !== void 0) ? resolved : void 0;
|
|
2303
|
+
}
|
|
2151
2304
|
/**
|
|
2152
2305
|
* Adds a table object to a slide definition.
|
|
2153
2306
|
* @param {PresSlideInternal} target - slide object that the table should be added to
|
|
@@ -2197,6 +2350,9 @@ function applyTableHeaderColumnSugar(tableRows, opt) {
|
|
|
2197
2350
|
/**
|
|
2198
2351
|
* Transform loosely-typed table rows (strings / numbers / TableCell) into a grid of
|
|
2199
2352
|
* well-formed TableCell objects with fully-resolved 4-side cell borders.
|
|
2353
|
+
*
|
|
2354
|
+
* @param srcRows - the rows as authored, after the `headerRow`/`columns` sugar
|
|
2355
|
+
* @param opt - the table's options
|
|
2200
2356
|
*/
|
|
2201
2357
|
function normalizeTableRows(srcRows, opt) {
|
|
2202
2358
|
const arrRows = [];
|
|
@@ -2238,12 +2394,7 @@ function normalizeTableRows(srcRows, opt) {
|
|
|
2238
2394
|
3
|
|
2239
2395
|
].forEach((idx) => {
|
|
2240
2396
|
const side = cellBorderTuple[idx];
|
|
2241
|
-
cellBorderTuple[idx] =
|
|
2242
|
-
...side,
|
|
2243
|
-
type: side.type || DEF_CELL_BORDER.type,
|
|
2244
|
-
color: side.color || DEF_CELL_BORDER.color,
|
|
2245
|
-
width: typeof side.width === "number" ? side.width : DEF_CELL_BORDER.width
|
|
2246
|
-
};
|
|
2397
|
+
cellBorderTuple[idx] = withBorderDefaults(side);
|
|
2247
2398
|
});
|
|
2248
2399
|
newCellOptions.border = cellBorderTuple;
|
|
2249
2400
|
newRow.push(newCell);
|
|
@@ -2259,10 +2410,11 @@ function normalizeTableRows(srcRows, opt) {
|
|
|
2259
2410
|
* the fill. Tables were the last major object kind not wired into `registerImageFillMedia`
|
|
2260
2411
|
* (shapes do it at `define/shape.ts`, text boxes at `define/text.ts`).
|
|
2261
2412
|
*
|
|
2262
|
-
*
|
|
2413
|
+
* Three fill sources are walked, which between them cover every way a picture reaches a table:
|
|
2263
2414
|
* the resolved cells (per-cell `options.fill`, plus `headerRow` and `columns[i]`, both baked
|
|
2264
|
-
* onto cells by the sugar step above),
|
|
2265
|
-
* `gen/slide/objects/table.ts` copies it onto each cell at emit time
|
|
2415
|
+
* onto cells by the sugar step above), the table-level `fill`, which is *not* baked —
|
|
2416
|
+
* `gen/slide/objects/table.ts` copies it onto each cell at emit time — and `tableFill`, which
|
|
2417
|
+
* lands on `a:tblPr` itself and so needs its own relationship for the same reason.
|
|
2266
2418
|
*
|
|
2267
2419
|
* Keyed on fill **object identity**, not on the image source. The sugar spreads its options
|
|
2268
2420
|
* shallowly, so one `headerRow` fill object is shared by every cell it styles; registering
|
|
@@ -2285,6 +2437,7 @@ function registerTableImageFills(target, rows, opt) {
|
|
|
2285
2437
|
registerImageFillMedia(target, fill);
|
|
2286
2438
|
};
|
|
2287
2439
|
register(opt.fill);
|
|
2440
|
+
register(opt.tableFill);
|
|
2288
2441
|
rows.forEach((row) => {
|
|
2289
2442
|
row.forEach((cell) => {
|
|
2290
2443
|
register(cell.options?.fill);
|
|
@@ -2319,7 +2472,7 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
|
|
|
2319
2472
|
];
|
|
2320
2473
|
if (!Array.isArray(opt.margin) || opt.margin.length !== 4 || opt.margin.some((v) => typeof v !== "number" || !Number.isFinite(v))) opt.margin = DEF_CELL_MARGIN_IN;
|
|
2321
2474
|
if (!JSON.stringify({ arrRows }).includes("hyperlink")) {
|
|
2322
|
-
if (!opt.color) opt.color =
|
|
2475
|
+
if (!opt.color) opt.color = DEF_FONT_COLOR;
|
|
2323
2476
|
}
|
|
2324
2477
|
if (typeof opt.border === "string") {
|
|
2325
2478
|
warn("table/invalid-border", "addTable `border` option must be an object. Ex: `{border: {type:'none'}}`");
|
|
@@ -2332,14 +2485,15 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
|
|
|
2332
2485
|
2,
|
|
2333
2486
|
3
|
|
2334
2487
|
].forEach((idx) => {
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
type: border[idx].type || DEF_CELL_BORDER.type,
|
|
2338
|
-
color: border[idx].color || DEF_CELL_BORDER.color,
|
|
2339
|
-
width: border[idx].width || DEF_CELL_BORDER.width
|
|
2340
|
-
} : { type: "none" };
|
|
2488
|
+
const side = border[idx];
|
|
2489
|
+
border[idx] = side ? withBorderDefaults(side) : { type: "none" };
|
|
2341
2490
|
});
|
|
2342
2491
|
}
|
|
2492
|
+
if (typeof opt.outerBorder === "string") {
|
|
2493
|
+
warn("table/invalid-outer-border", "addTable `outerBorder` option must be an object. Ex: `{outerBorder: {type:'solid'}}`");
|
|
2494
|
+
opt.outerBorder = void 0;
|
|
2495
|
+
}
|
|
2496
|
+
opt.outerBorder = normalizeOuterBorder(opt.outerBorder);
|
|
2343
2497
|
opt.autoPage = typeof opt.autoPage === "boolean" ? opt.autoPage : false;
|
|
2344
2498
|
opt.autoPagePlaceholder = typeof opt.autoPagePlaceholder === "boolean" ? opt.autoPagePlaceholder : false;
|
|
2345
2499
|
opt.autoPageRepeatHeader = typeof opt.autoPageRepeatHeader === "boolean" ? opt.autoPageRepeatHeader : false;
|
|
@@ -2381,7 +2535,7 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
|
|
|
2381
2535
|
}
|
|
2382
2536
|
} else if (opt.w) {} else opt.w = Math.floor((presLayout._sizeW || presLayout.width) / EMU_PER_INCH - arrTableMargin[1] - arrTableMargin[3]);
|
|
2383
2537
|
if (opt.fitColumns === "shrink") {
|
|
2384
|
-
const availWin = (presLayout._sizeW || presLayout.width) / EMU_PER_INCH - getSmartParseNumber(opt.x, "X", presLayout) / EMU_PER_INCH - arrTableMargin[
|
|
2538
|
+
const availWin = (presLayout._sizeW || presLayout.width) / EMU_PER_INCH - getSmartParseNumber(opt.x, "X", presLayout) / EMU_PER_INCH - arrTableMargin[1];
|
|
2385
2539
|
if (availWin > 0) {
|
|
2386
2540
|
if (Array.isArray(opt.colW)) {
|
|
2387
2541
|
const sumIn = opt.colW.reduce((p, n) => p + (Number.isFinite(n) ? n : 0), 0);
|
|
@@ -2763,6 +2917,24 @@ var SlideBuilder = class {
|
|
|
2763
2917
|
return this;
|
|
2764
2918
|
}
|
|
2765
2919
|
/**
|
|
2920
|
+
* Add an embedded 3D model (PowerPoint's Insert ▸ 3D Models) to the Slide.
|
|
2921
|
+
*
|
|
2922
|
+
* The `.glb` bytes ship inside the `.pptx`, so PowerPoint 2019+ renders the model live and lets
|
|
2923
|
+
* the viewer orbit it. Everything else — older PowerPoint, thumbnails, PDF export — draws the
|
|
2924
|
+
* `preview` picture instead; without one a neutral gray placeholder is embedded.
|
|
2925
|
+
*
|
|
2926
|
+
* Most models also need `meterPerModelUnit`: ts-pptx does not parse the `.glb`, so it cannot
|
|
2927
|
+
* measure the bounding box PowerPoint would have scaled the scene by. Set it to
|
|
2928
|
+
* `1 / <largest bounding-box dimension in model units>`.
|
|
2929
|
+
* @param {Model3dProps} options - 3D model options
|
|
2930
|
+
* @return {SlideBuilder} this Slide
|
|
2931
|
+
* @example slide.addModel3d({ path: 'engine.glb', preview: { path: 'engine.png' }, x: 1, y: 1, w: 6, h: 4 })
|
|
2932
|
+
*/
|
|
2933
|
+
addModel3d(options) {
|
|
2934
|
+
addModel3dDefinition(this, options);
|
|
2935
|
+
return this;
|
|
2936
|
+
}
|
|
2937
|
+
/**
|
|
2766
2938
|
* Add speaker notes to Slide
|
|
2767
2939
|
* @param {string | NotesProps | NotesProps[]} notes - notes text, or rich runs with inline
|
|
2768
2940
|
* formatting / hyperlinks. A plain string is the single-run case; pass run objects to add
|
|
@@ -3045,23 +3217,75 @@ function genXmlColorSelection(props) {
|
|
|
3045
3217
|
case "image":
|
|
3046
3218
|
outText += genXmlImageFill(typeof props === "string" ? void 0 : props);
|
|
3047
3219
|
break;
|
|
3048
|
-
default:
|
|
3049
|
-
outText += "";
|
|
3050
|
-
break;
|
|
3220
|
+
default: outText += "";
|
|
3051
3221
|
}
|
|
3052
3222
|
}
|
|
3053
3223
|
return outText;
|
|
3054
3224
|
}
|
|
3055
3225
|
//#endregion
|
|
3056
3226
|
//#region src/gen/drawingml/line.ts
|
|
3227
|
+
/** Every key `BorderProps` defines. Keep in step with the interface in `types/style.ts`. */
|
|
3228
|
+
const BORDER_KEYS = [
|
|
3229
|
+
"type",
|
|
3230
|
+
"dashType",
|
|
3231
|
+
"color",
|
|
3232
|
+
"width",
|
|
3233
|
+
"transparency",
|
|
3234
|
+
"cap"
|
|
3235
|
+
];
|
|
3236
|
+
/**
|
|
3237
|
+
* Resolve the `a:prstDash/@val` a border should emit.
|
|
3238
|
+
*
|
|
3239
|
+
* `BorderProps.type` is a three-way switch, so on its own it can only say "dashed" and
|
|
3240
|
+
* every dashed border collapses onto `sysDash`. `dashType` names the preset directly and
|
|
3241
|
+
* therefore wins when both are given; `type: 'none'` never reaches here, being decided by
|
|
3242
|
+
* the caller before any dash is chosen.
|
|
3243
|
+
*
|
|
3244
|
+
* A value outside `ST_PresetLineDashVal` would make the part schema-invalid, which
|
|
3245
|
+
* PowerPoint reports as a corrupt file rather than a mis-set option — so an unrecognized
|
|
3246
|
+
* one is reported and dropped back to what `type` implies.
|
|
3247
|
+
* @param {BorderProps} border - the caller's border properties
|
|
3248
|
+
* @returns {string} a value legal for `a:prstDash/@val`
|
|
3249
|
+
*/
|
|
3250
|
+
function resolveBorderDash(border) {
|
|
3251
|
+
const fromType = border.type === "dash" ? "sysDash" : "solid";
|
|
3252
|
+
return checkEnumOrWarn(border.dashType, PRESET_LINE_DASHES, "border/invalid-dash-type", "border: dashType") ?? fromType;
|
|
3253
|
+
}
|
|
3254
|
+
/**
|
|
3255
|
+
* Report an authored key that is not part of `BorderProps`, which the library would
|
|
3256
|
+
* otherwise drop without a sound.
|
|
3257
|
+
*
|
|
3258
|
+
* TypeScript's excess-property check already rejects a stray key on a border written
|
|
3259
|
+
* *inline* at the call site. It deliberately does not fire when the border is built as
|
|
3260
|
+
* a variable first (`const b = {...}; addTable(rows, { border: b })`) — a variable may
|
|
3261
|
+
* legitimately be a supertype. That exemption covers precisely the reuse pattern a
|
|
3262
|
+
* shared grid style encourages, so the mistake reaches here typed as valid and the
|
|
3263
|
+
* wrong-named value is discarded during generation. A `.pptx` gives no other signal:
|
|
3264
|
+
* nothing throws, the deck opens, and the border simply renders at its default weight.
|
|
3265
|
+
* @param border - the caller's border properties
|
|
3266
|
+
*/
|
|
3267
|
+
function warnUnknownBorderKeys(border) {
|
|
3268
|
+
for (const key in border) {
|
|
3269
|
+
if (!Object.hasOwn(border, key) || BORDER_KEYS.includes(key)) continue;
|
|
3270
|
+
warnOnce("border/unknown-key", `border: unknown option \`${key}\` is ignored — valid keys are ${BORDER_KEYS.join(", ")}. Line thickness is \`width\`, in points.`, {
|
|
3271
|
+
received: key,
|
|
3272
|
+
valid: BORDER_KEYS
|
|
3273
|
+
});
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3057
3276
|
/**
|
|
3058
3277
|
* Resolve a border's line width in points, falling back to `defaultPt` when `width`
|
|
3059
3278
|
* is not a usable number.
|
|
3279
|
+
*
|
|
3280
|
+
* Every `BorderProps` the library reads — table cell borders, table-style regions, and
|
|
3281
|
+
* every chart border — resolves its width through here, so this doubles as the one
|
|
3282
|
+
* place that can vet a border's shape for all of them ({@link warnUnknownBorderKeys}).
|
|
3060
3283
|
* @param {BorderProps} border - border properties (may carry `width`)
|
|
3061
3284
|
* @param {number} defaultPt - width to use when `width` is not a finite number
|
|
3062
3285
|
* @returns {number} resolved width in points
|
|
3063
3286
|
*/
|
|
3064
3287
|
function resolveBorderWidth(border, defaultPt) {
|
|
3288
|
+
warnUnknownBorderKeys(border);
|
|
3065
3289
|
const val = border.width;
|
|
3066
3290
|
return typeof val === "number" && !isNaN(val) ? val : defaultPt;
|
|
3067
3291
|
}
|
|
@@ -3467,7 +3691,34 @@ function makeSeriesDataPointsXml(chartType, obj, opts, varyColors) {
|
|
|
3467
3691
|
* gridlines, optional axis title -- but PowerPoint requires the child elements in a
|
|
3468
3692
|
* fixed order that differs per axis, so they stay as three separate builders rather
|
|
3469
3693
|
* than one parameterized one. Called by {@link ./chart-xml}'s axis region.
|
|
3470
|
-
|
|
3694
|
+
*
|
|
3695
|
+
* Sub-blocks are shared where they can be shared *exactly*: {@link axisLineSpPr} covers
|
|
3696
|
+
* `<c:spPr>`, which differs between the three only by indent width. `<c:txPr>` is
|
|
3697
|
+
* deliberately left duplicated — its inherited indentation is irregular *within* each copy
|
|
3698
|
+
* as well as between them (the category axis closes `</a:defRPr>` at three spaces, the value
|
|
3699
|
+
* axis at six), so parameterising it would take about as many indent arguments as it has
|
|
3700
|
+
* lines and would hide the quirks rather than share the structure.
|
|
3701
|
+
*/
|
|
3702
|
+
/**
|
|
3703
|
+
* The `<c:spPr>` axis-line block, identical in shape on all three axes.
|
|
3704
|
+
*
|
|
3705
|
+
* The only thing that differed between the three copies was how far each was indented — two
|
|
3706
|
+
* spaces on the category and series axes, one on the value axis — and that irregularity is
|
|
3707
|
+
* inherited, not meaningful. It is reproduced here rather than normalised because inter-element
|
|
3708
|
+
* whitespace being inert does not make changing it free: byte-identity is the gate that proves
|
|
3709
|
+
* an emitter refactor changed nothing, and it cannot tell a "harmless" whitespace edit from a
|
|
3710
|
+
* real one. `indent` keeps the quirk visible at the call site.
|
|
3711
|
+
* @param {number} indent - leading spaces on the `<c:spPr>` line; children step out by 2 and 4
|
|
3712
|
+
* @param {number} widthEmu - line width for `a:ln@w`
|
|
3713
|
+
* @param {boolean | undefined} show - false emits `<a:noFill/>` instead of a colour
|
|
3714
|
+
* @param {string | undefined} color - line colour, defaulting to {@link DEF_GRIDLINE_COLOR}
|
|
3715
|
+
* @param {string} dash - `a:prstDash@val`
|
|
3716
|
+
* @return {string} XML `<c:spPr>`
|
|
3717
|
+
*/
|
|
3718
|
+
function axisLineSpPr(indent, widthEmu, show, color, dash) {
|
|
3719
|
+
const at = (extra) => " ".repeat(indent + extra);
|
|
3720
|
+
return `${at(0)}<c:spPr>${at(2)}<a:ln w="${widthEmu}" cap="flat">` + (!show ? "<a:noFill/>" : genXmlColorSelection(color || DEF_GRIDLINE_COLOR)) + `${at(4)}<a:prstDash val="${dash}"/>${at(4)}<a:round/>${at(2)}</a:ln>${at(0)}</c:spPr>`;
|
|
3721
|
+
}
|
|
3471
3722
|
function makeCatAxis(opts, axisId, valAxisId) {
|
|
3472
3723
|
let strXml = "";
|
|
3473
3724
|
const usesValueAxisForCategories = opts._type === "scatter" || opts._type === "bubble" || opts._type === "bubble3D";
|
|
@@ -3476,7 +3727,7 @@ function makeCatAxis(opts, axisId, valAxisId) {
|
|
|
3476
3727
|
else strXml += "<c:" + (opts.catLabelFormatCode ? "dateAx" : "catAx") + ">";
|
|
3477
3728
|
strXml += " <c:axId val=\"" + axisId + "\"/>";
|
|
3478
3729
|
strXml += " <c:scaling>";
|
|
3479
|
-
strXml += "<c:orientation val=\"" + (opts.catAxisOrientation ||
|
|
3730
|
+
strXml += "<c:orientation val=\"" + (opts.catAxisOrientation || "minMax") + "\"/>";
|
|
3480
3731
|
if (opts.catAxisMaxVal || opts.catAxisMaxVal === 0) strXml += `<c:max val="${opts.catAxisMaxVal}"/>`;
|
|
3481
3732
|
if (opts.catAxisMinVal || opts.catAxisMinVal === 0) strXml += `<c:min val="${opts.catAxisMinVal}"/>`;
|
|
3482
3733
|
strXml += "</c:scaling>";
|
|
@@ -3509,13 +3760,7 @@ function makeCatAxis(opts, axisId, valAxisId) {
|
|
|
3509
3760
|
strXml += " <c:minorTickMark val=\"" + (opts.catAxisMinorTickMark || "none") + "\"/>";
|
|
3510
3761
|
strXml += " <c:tickLblPos val=\"" + (opts.catAxisLabelPos || (opts.barDir === "col" ? "low" : "nextTo")) + "\"/>";
|
|
3511
3762
|
}
|
|
3512
|
-
strXml +=
|
|
3513
|
-
strXml += ` <a:ln w="${opts.catAxisLineSize ? valToPts(opts.catAxisLineSize) : EMU_PER_POINT}" cap="flat">`;
|
|
3514
|
-
strXml += !opts.catAxisLineShow ? "<a:noFill/>" : genXmlColorSelection(opts.catAxisLineColor || DEF_GRIDLINE_COLOR);
|
|
3515
|
-
strXml += " <a:prstDash val=\"" + (opts.catAxisLineStyle || "solid") + "\"/>";
|
|
3516
|
-
strXml += " <a:round/>";
|
|
3517
|
-
strXml += " </a:ln>";
|
|
3518
|
-
strXml += " </c:spPr>";
|
|
3763
|
+
strXml += axisLineSpPr(2, opts.catAxisLineSize ? valToPts(opts.catAxisLineSize) : EMU_PER_POINT, opts.catAxisLineShow, opts.catAxisLineColor, opts.catAxisLineStyle || "solid");
|
|
3519
3764
|
strXml += " <c:txPr>";
|
|
3520
3765
|
if (opts.catAxisLabelRotate) strXml += `<a:bodyPr rot="${convertRotationDegrees(opts.catAxisLabelRotate)}"/>`;
|
|
3521
3766
|
else strXml += "<a:bodyPr/>";
|
|
@@ -3579,7 +3824,7 @@ function makeValAxis(opts, valAxisId) {
|
|
|
3579
3824
|
strXml += " <c:axId val=\"" + valAxisId + "\"/>";
|
|
3580
3825
|
strXml += " <c:scaling>";
|
|
3581
3826
|
if (opts.valAxisLogScaleBase) strXml += `<c:logBase val="${opts.valAxisLogScaleBase}"/>`;
|
|
3582
|
-
strXml += "<c:orientation val=\"" + (opts.valAxisOrientation ||
|
|
3827
|
+
strXml += "<c:orientation val=\"" + (opts.valAxisOrientation || "minMax") + "\"/>";
|
|
3583
3828
|
if (opts.valAxisMaxVal || opts.valAxisMaxVal === 0) strXml += `<c:max val="${opts.valAxisMaxVal}"/>`;
|
|
3584
3829
|
if (opts.valAxisMinVal || opts.valAxisMinVal === 0) strXml += `<c:min val="${opts.valAxisMinVal}"/>`;
|
|
3585
3830
|
strXml += " </c:scaling>";
|
|
@@ -3606,13 +3851,7 @@ function makeValAxis(opts, valAxisId) {
|
|
|
3606
3851
|
strXml += " <c:minorTickMark val=\"" + (opts.valAxisMinorTickMark || "none") + "\"/>";
|
|
3607
3852
|
strXml += " <c:tickLblPos val=\"" + (opts.valAxisLabelPos || (opts.barDir === "col" ? "nextTo" : "low")) + "\"/>";
|
|
3608
3853
|
}
|
|
3609
|
-
strXml +=
|
|
3610
|
-
strXml += ` <a:ln w="${opts.valAxisLineSize ? valToPts(opts.valAxisLineSize) : EMU_PER_POINT}" cap="flat">`;
|
|
3611
|
-
strXml += !opts.valAxisLineShow ? "<a:noFill/>" : genXmlColorSelection(opts.valAxisLineColor || DEF_GRIDLINE_COLOR);
|
|
3612
|
-
strXml += " <a:prstDash val=\"" + (opts.valAxisLineStyle || "solid") + "\"/>";
|
|
3613
|
-
strXml += " <a:round/>";
|
|
3614
|
-
strXml += " </a:ln>";
|
|
3615
|
-
strXml += " </c:spPr>";
|
|
3854
|
+
strXml += axisLineSpPr(1, opts.valAxisLineSize ? valToPts(opts.valAxisLineSize) : EMU_PER_POINT, opts.valAxisLineShow, opts.valAxisLineColor, opts.valAxisLineStyle || "solid");
|
|
3616
3855
|
strXml += " <c:txPr>";
|
|
3617
3856
|
strXml += ` <a:bodyPr${opts.valAxisLabelRotate ? " rot=\"" + convertRotationDegrees(opts.valAxisLabelRotate).toString() + "\"" : ""}/>`;
|
|
3618
3857
|
strXml += " <a:lstStyle/>";
|
|
@@ -3647,7 +3886,7 @@ function makeSerAxis(opts, axisId, valAxisId) {
|
|
|
3647
3886
|
let strXml = "";
|
|
3648
3887
|
strXml += "<c:serAx>";
|
|
3649
3888
|
strXml += " <c:axId val=\"" + axisId + "\"/>";
|
|
3650
|
-
strXml += " <c:scaling><c:orientation val=\"" + (opts.serAxisOrientation ||
|
|
3889
|
+
strXml += " <c:scaling><c:orientation val=\"" + (opts.serAxisOrientation || "minMax") + "\"/></c:scaling>";
|
|
3651
3890
|
strXml += " <c:delete val=\"" + (opts.serAxisHidden ? "1" : "0") + "\"/>";
|
|
3652
3891
|
strXml += " <c:axPos val=\"" + (opts.barDir === "col" ? "b" : "l") + "\"/>";
|
|
3653
3892
|
strXml += opts.serGridLine && opts.serGridLine.style !== "none" ? createGridLineElement(opts.serGridLine) : "";
|
|
@@ -3665,13 +3904,7 @@ function makeSerAxis(opts, axisId, valAxisId) {
|
|
|
3665
3904
|
strXml += " <c:majorTickMark val=\"out\"/>";
|
|
3666
3905
|
strXml += " <c:minorTickMark val=\"none\"/>";
|
|
3667
3906
|
strXml += ` <c:tickLblPos val="${opts.serAxisLabelPos || (opts.barDir === "col" ? "low" : "nextTo")}"/>`;
|
|
3668
|
-
strXml += "
|
|
3669
|
-
strXml += " <a:ln w=\"12700\" cap=\"flat\">";
|
|
3670
|
-
strXml += !opts.serAxisLineShow ? "<a:noFill/>" : genXmlColorSelection(opts.serAxisLineColor || DEF_GRIDLINE_COLOR);
|
|
3671
|
-
strXml += " <a:prstDash val=\"solid\"/>";
|
|
3672
|
-
strXml += " <a:round/>";
|
|
3673
|
-
strXml += " </a:ln>";
|
|
3674
|
-
strXml += " </c:spPr>";
|
|
3907
|
+
strXml += axisLineSpPr(2, EMU_PER_POINT, opts.serAxisLineShow, opts.serAxisLineColor, "solid");
|
|
3675
3908
|
strXml += " <c:txPr>";
|
|
3676
3909
|
strXml += " <a:bodyPr/>";
|
|
3677
3910
|
strXml += " <a:lstStyle/>";
|
|
@@ -5021,7 +5254,8 @@ function chartExLayoutId(type) {
|
|
|
5021
5254
|
/**
|
|
5022
5255
|
* A deterministic `uniqueId` GUID for a `<cx:series>`, derived from the chart's package-global id.
|
|
5023
5256
|
* PowerPoint stamps a random GUID here; deriving it keeps output byte-stable (the project pins
|
|
5024
|
-
* chart determinism —
|
|
5257
|
+
* chart determinism — the package-wide id this derives from is assigned at write time in
|
|
5258
|
+
* `package/assemble.ts`, STEP 2). `seriesIdx`
|
|
5025
5259
|
* distinguishes multiple series within one chart (pareto emits two), varying the 4th GUID group so
|
|
5026
5260
|
* every series still gets a distinct id.
|
|
5027
5261
|
*/
|
|
@@ -5265,9 +5499,15 @@ function makeXmlChartEx(rel) {
|
|
|
5265
5499
|
* template — analogous to the default theme/worksheet boilerplate the library already embeds. They
|
|
5266
5500
|
* reference theme scheme colors, so they adapt to the deck theme without per-chart customization.
|
|
5267
5501
|
*/
|
|
5268
|
-
/**
|
|
5502
|
+
/**
|
|
5503
|
+
* The `cs:colorStyle` payload for a chartEx chart's `colors{N}.xml` part (theme-accent cycle).
|
|
5504
|
+
* @raw-xml-asset Captured verbatim from PowerPoint; not built here, so not a migration target.
|
|
5505
|
+
*/
|
|
5269
5506
|
const CHARTEX_COLORS_BODY = "<cs:colorStyle xmlns:cs=\"http://schemas.microsoft.com/office/drawing/2012/chartStyle\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" meth=\"cycle\" id=\"10\"><a:schemeClr val=\"accent1\"/><a:schemeClr val=\"accent2\"/><a:schemeClr val=\"accent3\"/><a:schemeClr val=\"accent4\"/><a:schemeClr val=\"accent5\"/><a:schemeClr val=\"accent6\"/><cs:variation/><cs:variation><a:lumMod val=\"60000\"/></cs:variation><cs:variation><a:lumMod val=\"80000\"/><a:lumOff val=\"20000\"/></cs:variation><cs:variation><a:lumMod val=\"80000\"/></cs:variation><cs:variation><a:lumMod val=\"60000\"/><a:lumOff val=\"40000\"/></cs:variation><cs:variation><a:lumMod val=\"50000\"/></cs:variation><cs:variation><a:lumMod val=\"70000\"/><a:lumOff val=\"30000\"/></cs:variation><cs:variation><a:lumMod val=\"70000\"/></cs:variation><cs:variation><a:lumMod val=\"50000\"/><a:lumOff val=\"50000\"/></cs:variation></cs:colorStyle>";
|
|
5270
|
-
/**
|
|
5507
|
+
/**
|
|
5508
|
+
* The `cs:chartStyle` payload for a chartEx chart's `style{N}.xml` part (PowerPoint default).
|
|
5509
|
+
* @raw-xml-asset Captured verbatim from PowerPoint; not built here, so not a migration target.
|
|
5510
|
+
*/
|
|
5271
5511
|
const CHARTEX_STYLE_BODY = "<cs:chartStyle xmlns:cs=\"http://schemas.microsoft.com/office/drawing/2012/chartStyle\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" id=\"395\"><cs:axisTitle><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef><cs:defRPr sz=\"1197\"/></cs:axisTitle><cs:categoryAxis><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"15000\"/><a:lumOff val=\"85000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr><cs:defRPr sz=\"1197\"/></cs:categoryAxis><cs:chartArea mods=\"allowNoFillOverride allowNoLineOverride\"><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:solidFill><a:schemeClr val=\"bg1\"/></a:solidFill><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"15000\"/><a:lumOff val=\"85000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr><cs:defRPr sz=\"1330\"/></cs:chartArea><cs:dataLabel><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef><cs:defRPr sz=\"1197\"/></cs:dataLabel><cs:dataLabelCallout><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"dk1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef><cs:spPr><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill><a:ln><a:solidFill><a:schemeClr val=\"dk1\"><a:lumMod val=\"25000\"/><a:lumOff val=\"75000\"/></a:schemeClr></a:solidFill></a:ln></cs:spPr><cs:defRPr sz=\"1197\"/><cs:bodyPr rot=\"0\" spcFirstLastPara=\"1\" vertOverflow=\"clip\" horzOverflow=\"clip\" vert=\"horz\" wrap=\"square\" lIns=\"36576\" tIns=\"18288\" rIns=\"36576\" bIns=\"18288\" anchor=\"ctr\" anchorCtr=\"1\"><a:spAutoFit/></cs:bodyPr></cs:dataLabelCallout><cs:dataPoint><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"><cs:styleClr val=\"auto\"/></cs:fillRef><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill></cs:spPr></cs:dataPoint><cs:dataPoint3D><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"><cs:styleClr val=\"auto\"/></cs:fillRef><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill></cs:spPr></cs:dataPoint3D><cs:dataPointLine><cs:lnRef idx=\"0\"><cs:styleClr val=\"auto\"/></cs:lnRef><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"28575\" cap=\"rnd\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:round/></a:ln></cs:spPr></cs:dataPointLine><cs:dataPointMarker><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"><cs:styleClr val=\"auto\"/></cs:fillRef><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:ln w=\"9525\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></cs:spPr></cs:dataPointMarker><cs:dataPointMarkerLayout symbol=\"circle\" size=\"5\"/><cs:dataPointWireframe><cs:lnRef idx=\"0\"><cs:styleClr val=\"auto\"/></cs:lnRef><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"28575\" cap=\"rnd\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:round/></a:ln></cs:spPr></cs:dataPointWireframe><cs:dataTable><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef><cs:spPr><a:ln w=\"9525\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"15000\"/><a:lumOff val=\"85000\"/></a:schemeClr></a:solidFill></a:ln></cs:spPr><cs:defRPr sz=\"1197\"/></cs:dataTable><cs:downBar><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"dk1\"/></cs:fontRef><cs:spPr><a:solidFill><a:schemeClr val=\"dk1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></a:solidFill><a:ln w=\"9525\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></a:solidFill></a:ln></cs:spPr></cs:downBar><cs:dropLine><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"35000\"/><a:lumOff val=\"65000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:dropLine><cs:errorBar><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:errorBar><cs:floor><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef></cs:floor><cs:gridlineMajor><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"15000\"/><a:lumOff val=\"85000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:gridlineMajor><cs:gridlineMinor><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"15000\"/><a:lumOff val=\"85000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:gridlineMinor><cs:hiLoLine><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"75000\"/><a:lumOff val=\"25000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:hiLoLine><cs:leaderLine><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"35000\"/><a:lumOff val=\"65000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr></cs:leaderLine><cs:legend><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef><cs:defRPr sz=\"1197\"/></cs:legend><cs:plotArea mods=\"allowNoFillOverride allowNoLineOverride\"><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef></cs:plotArea><cs:plotArea3D mods=\"allowNoFillOverride allowNoLineOverride\"><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef></cs:plotArea3D><cs:seriesAxis><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"15000\"/><a:lumOff val=\"85000\"/></a:schemeClr></a:solidFill><a:round/></a:ln></cs:spPr><cs:defRPr sz=\"1197\"/></cs:seriesAxis><cs:seriesLine><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"9525\" cap=\"flat\"><a:solidFill><a:srgbClr val=\"D9D9D9\"/></a:solidFill><a:round/></a:ln></cs:spPr></cs:seriesLine><cs:title><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef><cs:defRPr sz=\"1862\"/></cs:title><cs:trendline><cs:lnRef idx=\"0\"><cs:styleClr val=\"auto\"/></cs:lnRef><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef><cs:spPr><a:ln w=\"19050\" cap=\"rnd\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"sysDash\"/></a:ln></cs:spPr></cs:trendline><cs:trendlineLabel><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef><cs:defRPr sz=\"1197\"/></cs:trendlineLabel><cs:upBar><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"dk1\"/></cs:fontRef><cs:spPr><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill><a:ln w=\"9525\"><a:solidFill><a:schemeClr val=\"tx1\"><a:lumMod val=\"15000\"/><a:lumOff val=\"85000\"/></a:schemeClr></a:solidFill></a:ln></cs:spPr></cs:upBar><cs:valueAxis><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"><a:lumMod val=\"65000\"/><a:lumOff val=\"35000\"/></a:schemeClr></cs:fontRef><cs:defRPr sz=\"1197\"/></cs:valueAxis><cs:wall><cs:lnRef idx=\"0\"/><cs:fillRef idx=\"0\"/><cs:effectRef idx=\"0\"/><cs:fontRef idx=\"minor\"><a:schemeClr val=\"tx1\"/></cs:fontRef></cs:wall></cs:chartStyle>";
|
|
5272
5512
|
/** Build the `ppt/charts/colors{N}.xml` part body. */
|
|
5273
5513
|
function makeChartExColorsXml() {
|
|
@@ -5279,7 +5519,6 @@ function makeChartExStyleXml() {
|
|
|
5279
5519
|
}
|
|
5280
5520
|
//#endregion
|
|
5281
5521
|
//#region src/gen/chart/embed-xlsx.ts
|
|
5282
|
-
const PACKAGE_REL_NS$2 = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
5283
5522
|
function relationship$2(id, type, target) {
|
|
5284
5523
|
return voidEl("Relationship", {
|
|
5285
5524
|
Id: id,
|
|
@@ -5289,7 +5528,7 @@ function relationship$2(id, type, target) {
|
|
|
5289
5528
|
}
|
|
5290
5529
|
/** `<Relationships>` wrapper shared by the workbook's `.rels` parts (all flat, no indent). */
|
|
5291
5530
|
function relationships(rels) {
|
|
5292
|
-
return el("Relationships", { xmlns: PACKAGE_REL_NS
|
|
5531
|
+
return el("Relationships", { xmlns: PACKAGE_REL_NS }, rels.map(raw));
|
|
5293
5532
|
}
|
|
5294
5533
|
/**
|
|
5295
5534
|
* Build the chart's embedded Excel workbook as a standalone OPC package and
|
|
@@ -5308,22 +5547,22 @@ function buildEmbeddedWorksheet(chartObject) {
|
|
|
5308
5547
|
const IS_MULTI_CAT_AXES = (data[0]?.labels?.length ?? 0) > 1;
|
|
5309
5548
|
zipExcel.add("[Content_Types].xml", XML_DECL + "<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\"> <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/> <Default Extension=\"xml\" ContentType=\"application/xml\"/> <Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"/> <Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/> <Override PartName=\"/xl/theme/theme1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.theme+xml\"/> <Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\"/> <Override PartName=\"/xl/sharedStrings.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml\"/> <Override PartName=\"/xl/tables/table1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml\"/> <Override PartName=\"/docProps/core.xml\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\"/> <Override PartName=\"/docProps/app.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\"/></Types>\n");
|
|
5310
5549
|
zipExcel.add("_rels/.rels", XML_DECL + relationships([
|
|
5311
|
-
relationship$2("rId1", "
|
|
5312
|
-
relationship$2("rId2", "
|
|
5313
|
-
relationship$2("rId3", "
|
|
5550
|
+
relationship$2("rId1", PACKAGE_REL_NS + "/metadata/core-properties", "docProps/core.xml"),
|
|
5551
|
+
relationship$2("rId2", OFFICE_REL + "extended-properties", "docProps/app.xml"),
|
|
5552
|
+
relationship$2("rId3", OFFICE_REL + "officeDocument", "xl/workbook.xml")
|
|
5314
5553
|
]) + "\n");
|
|
5315
5554
|
zipExcel.add("docProps/app.xml", XML_DECL + "<Properties xmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties\" xmlns:vt=\"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes\"><Application>Microsoft Macintosh Excel</Application><DocSecurity>0</DocSecurity><ScaleCrop>false</ScaleCrop><HeadingPairs><vt:vector size=\"2\" baseType=\"variant\"><vt:variant><vt:lpstr>Worksheets</vt:lpstr></vt:variant><vt:variant><vt:i4>1</vt:i4></vt:variant></vt:vector></HeadingPairs><TitlesOfParts><vt:vector size=\"1\" baseType=\"lpstr\"><vt:lpstr>Sheet1</vt:lpstr></vt:vector></TitlesOfParts><Company></Company><LinksUpToDate>false</LinksUpToDate><SharedDoc>false</SharedDoc><HyperlinksChanged>false</HyperlinksChanged><AppVersion>16.0300</AppVersion></Properties>\n");
|
|
5316
5555
|
zipExcel.add("docProps/core.xml", XML_DECL + "<cp:coreProperties xmlns:cp=\"http://schemas.openxmlformats.org/package/2006/metadata/core-properties\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:dcterms=\"http://purl.org/dc/terms/\" xmlns:dcmitype=\"http://purl.org/dc/dcmitype/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><dc:creator>TsPptx</dc:creator><cp:lastModifiedBy>TsPptx</cp:lastModifiedBy><dcterms:created xsi:type=\"dcterms:W3CDTF\">" + (/* @__PURE__ */ new Date()).toISOString() + "</dcterms:created><dcterms:modified xsi:type=\"dcterms:W3CDTF\">" + (/* @__PURE__ */ new Date()).toISOString() + "</dcterms:modified></cp:coreProperties>");
|
|
5317
5556
|
zipExcel.add("xl/_rels/workbook.xml.rels", XML_DECL + relationships([
|
|
5318
|
-
relationship$2("rId3", "
|
|
5319
|
-
relationship$2("rId2", "
|
|
5320
|
-
relationship$2("rId1", "
|
|
5321
|
-
relationship$2("rId4", "
|
|
5557
|
+
relationship$2("rId3", OFFICE_REL + "styles", "styles.xml"),
|
|
5558
|
+
relationship$2("rId2", OFFICE_REL + "theme", "theme/theme1.xml"),
|
|
5559
|
+
relationship$2("rId1", OFFICE_REL + "worksheet", "worksheets/sheet1.xml"),
|
|
5560
|
+
relationship$2("rId4", OFFICE_REL + "sharedStrings", "sharedStrings.xml")
|
|
5322
5561
|
]));
|
|
5323
5562
|
zipExcel.add("xl/styles.xml", XML_DECL + "<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><numFmts count=\"1\"><numFmt numFmtId=\"0\" formatCode=\"General\"/></numFmts><fonts count=\"4\"><font><sz val=\"9\"/><color indexed=\"8\"/><name val=\"Geneva\"/></font><font><sz val=\"9\"/><color indexed=\"8\"/><name val=\"Geneva\"/></font><font><sz val=\"10\"/><color indexed=\"8\"/><name val=\"Geneva\"/></font><font><sz val=\"18\"/><color indexed=\"8\"/><name val=\"Arial\"/></font></fonts><fills count=\"2\"><fill><patternFill patternType=\"none\"/></fill><fill><patternFill patternType=\"gray125\"/></fill></fills><borders count=\"1\"><border><left/><right/><top/><bottom/><diagonal/></border></borders><dxfs count=\"0\"/><tableStyles count=\"0\"/><colors><indexedColors><rgbColor rgb=\"ff000000\"/><rgbColor rgb=\"ffffffff\"/><rgbColor rgb=\"ffff0000\"/><rgbColor rgb=\"ff00ff00\"/><rgbColor rgb=\"ff0000ff\"/><rgbColor rgb=\"ffffff00\"/><rgbColor rgb=\"ffff00ff\"/><rgbColor rgb=\"ff00ffff\"/><rgbColor rgb=\"ff000000\"/><rgbColor rgb=\"ffffffff\"/><rgbColor rgb=\"ff878787\"/><rgbColor rgb=\"fff9f9f9\"/></indexedColors></colors></styleSheet>\n");
|
|
5324
5563
|
zipExcel.add("xl/theme/theme1.xml", XML_DECL + "<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office Theme\"><a:themeElements><a:clrScheme name=\"Office\"><a:dk1><a:sysClr val=\"windowText\" lastClr=\"000000\"/></a:dk1><a:lt1><a:sysClr val=\"window\" lastClr=\"FFFFFF\"/></a:lt1><a:dk2><a:srgbClr val=\"44546A\"/></a:dk2><a:lt2><a:srgbClr val=\"E7E6E6\"/></a:lt2><a:accent1><a:srgbClr val=\"4472C4\"/></a:accent1><a:accent2><a:srgbClr val=\"ED7D31\"/></a:accent2><a:accent3><a:srgbClr val=\"A5A5A5\"/></a:accent3><a:accent4><a:srgbClr val=\"FFC000\"/></a:accent4><a:accent5><a:srgbClr val=\"5B9BD5\"/></a:accent5><a:accent6><a:srgbClr val=\"70AD47\"/></a:accent6><a:hlink><a:srgbClr val=\"0563C1\"/></a:hlink><a:folHlink><a:srgbClr val=\"954F72\"/></a:folHlink></a:clrScheme><a:fontScheme name=\"Office\"><a:majorFont><a:latin typeface=\"Calibri Light\" panose=\"020F0302020204030204\"/><a:ea typeface=\"\"/><a:cs typeface=\"\"/><a:font script=\"Jpan\" typeface=\"Yu Gothic Light\"/><a:font script=\"Hang\" typeface=\"맑은 고딕\"/><a:font script=\"Hans\" typeface=\"DengXian Light\"/><a:font script=\"Hant\" typeface=\"新細明體\"/><a:font script=\"Arab\" typeface=\"Times New Roman\"/><a:font script=\"Hebr\" typeface=\"Times New Roman\"/><a:font script=\"Thai\" typeface=\"Tahoma\"/><a:font script=\"Ethi\" typeface=\"Nyala\"/><a:font script=\"Beng\" typeface=\"Vrinda\"/><a:font script=\"Gujr\" typeface=\"Shruti\"/><a:font script=\"Khmr\" typeface=\"MoolBoran\"/><a:font script=\"Knda\" typeface=\"Tunga\"/><a:font script=\"Guru\" typeface=\"Raavi\"/><a:font script=\"Cans\" typeface=\"Euphemia\"/><a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/><a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/><a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/><a:font script=\"Thaa\" typeface=\"MV Boli\"/><a:font script=\"Deva\" typeface=\"Mangal\"/><a:font script=\"Telu\" typeface=\"Gautami\"/><a:font script=\"Taml\" typeface=\"Latha\"/><a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/><a:font script=\"Orya\" typeface=\"Kalinga\"/><a:font script=\"Mlym\" typeface=\"Kartika\"/><a:font script=\"Laoo\" typeface=\"DokChampa\"/><a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/><a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/><a:font script=\"Viet\" typeface=\"Times New Roman\"/><a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/><a:font script=\"Geor\" typeface=\"Sylfaen\"/></a:majorFont><a:minorFont><a:latin typeface=\"Calibri\" panose=\"020F0502020204030204\"/><a:ea typeface=\"\"/><a:cs typeface=\"\"/><a:font script=\"Jpan\" typeface=\"Yu Gothic\"/><a:font script=\"Hang\" typeface=\"맑은 고딕\"/><a:font script=\"Hans\" typeface=\"DengXian\"/><a:font script=\"Hant\" typeface=\"新細明體\"/><a:font script=\"Arab\" typeface=\"Arial\"/><a:font script=\"Hebr\" typeface=\"Arial\"/><a:font script=\"Thai\" typeface=\"Tahoma\"/><a:font script=\"Ethi\" typeface=\"Nyala\"/><a:font script=\"Beng\" typeface=\"Vrinda\"/><a:font script=\"Gujr\" typeface=\"Shruti\"/><a:font script=\"Khmr\" typeface=\"DaunPenh\"/><a:font script=\"Knda\" typeface=\"Tunga\"/><a:font script=\"Guru\" typeface=\"Raavi\"/><a:font script=\"Cans\" typeface=\"Euphemia\"/><a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/><a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/><a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/><a:font script=\"Thaa\" typeface=\"MV Boli\"/><a:font script=\"Deva\" typeface=\"Mangal\"/><a:font script=\"Telu\" typeface=\"Gautami\"/><a:font script=\"Taml\" typeface=\"Latha\"/><a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/><a:font script=\"Orya\" typeface=\"Kalinga\"/><a:font script=\"Mlym\" typeface=\"Kartika\"/><a:font script=\"Laoo\" typeface=\"DokChampa\"/><a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/><a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/><a:font script=\"Viet\" typeface=\"Arial\"/><a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/><a:font script=\"Geor\" typeface=\"Sylfaen\"/></a:minorFont></a:fontScheme><a:fmtScheme name=\"Office\"><a:fillStyleLst><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"110000\"/><a:satMod val=\"105000\"/><a:tint val=\"67000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"105000\"/><a:satMod val=\"103000\"/><a:tint val=\"73000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"105000\"/><a:satMod val=\"109000\"/><a:tint val=\"81000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:satMod val=\"103000\"/><a:lumMod val=\"102000\"/><a:tint val=\"94000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:satMod val=\"110000\"/><a:lumMod val=\"100000\"/><a:shade val=\"100000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"99000\"/><a:satMod val=\"120000\"/><a:shade val=\"78000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w=\"6350\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln><a:ln w=\"12700\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln><a:ln w=\"19050\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad=\"57150\" dist=\"19050\" dir=\"5400000\" algn=\"ctr\" rotWithShape=\"0\"><a:srgbClr val=\"000000\"><a:alpha val=\"63000\"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:solidFill><a:schemeClr val=\"phClr\"><a:tint val=\"95000\"/><a:satMod val=\"170000\"/></a:schemeClr></a:solidFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"93000\"/><a:satMod val=\"150000\"/><a:shade val=\"98000\"/><a:lumMod val=\"102000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:tint val=\"98000\"/><a:satMod val=\"130000\"/><a:shade val=\"90000\"/><a:lumMod val=\"103000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"63000\"/><a:satMod val=\"120000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements><a:objectDefaults/><a:extraClrSchemeLst/><a:extLst><a:ext uri=\"{05A4C25C-085E-4340-85A3-A5531E510DB2}\"><thm15:themeFamily xmlns:thm15=\"http://schemas.microsoft.com/office/thememl/2012/main\" name=\"Office Theme\" id=\"{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}\" vid=\"{4A3C46E8-61CC-4603-A589-7422A47A8E4A}\"/></a:ext></a:extLst></a:theme>");
|
|
5325
5564
|
zipExcel.add("xl/workbook.xml", XML_DECL + "<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x15\" xmlns:x15=\"http://schemas.microsoft.com/office/spreadsheetml/2010/11/main\"><fileVersion appName=\"xl\" lastEdited=\"7\" lowestEdited=\"6\" rupBuild=\"10507\"/><workbookPr/><bookViews><workbookView xWindow=\"0\" yWindow=\"500\" windowWidth=\"20960\" windowHeight=\"15960\"/></bookViews><sheets><sheet name=\"Sheet1\" sheetId=\"1\" r:id=\"rId1\"/></sheets><calcPr calcId=\"0\" concurrentCalc=\"0\"/></workbook>\n");
|
|
5326
|
-
zipExcel.add("xl/worksheets/_rels/sheet1.xml.rels", XML_DECL + relationships([relationship$2("rId1", "
|
|
5565
|
+
zipExcel.add("xl/worksheets/_rels/sheet1.xml.rels", XML_DECL + relationships([relationship$2("rId1", OFFICE_REL + "table", "../tables/table1.xml")]) + "\n");
|
|
5327
5566
|
zipExcel.add("xl/sharedStrings.xml", buildXlsxSharedStrings(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES));
|
|
5328
5567
|
zipExcel.add("xl/tables/table1.xml", buildXlsxTable(chartObject, data, intBubbleCols));
|
|
5329
5568
|
zipExcel.add("xl/worksheets/sheet1.xml", buildXlsxSheet(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES));
|
|
@@ -5504,7 +5743,7 @@ function buildXlsxSheet(chartObject, data, intBubbleCols, IS_MULTI_CAT_AXES) {
|
|
|
5504
5743
|
* @return {string} the chart part's `.rels` XML
|
|
5505
5744
|
*/
|
|
5506
5745
|
function buildChartRelsXml(embeddingTarget) {
|
|
5507
|
-
return XML_DECL + relationships([relationship$2("rId1", "
|
|
5746
|
+
return XML_DECL + relationships([relationship$2("rId1", OFFICE_REL + "package", embeddingTarget)]);
|
|
5508
5747
|
}
|
|
5509
5748
|
/**
|
|
5510
5749
|
* Build the `.rels` for a chartEx chart part: the embedded workbook (rId1, via `<cx:externalData>`)
|
|
@@ -5516,7 +5755,7 @@ function buildChartRelsXml(embeddingTarget) {
|
|
|
5516
5755
|
*/
|
|
5517
5756
|
function buildChartExRelsXml(embeddingTarget, colorsTarget, styleTarget) {
|
|
5518
5757
|
return XML_DECL + relationships([
|
|
5519
|
-
relationship$2("rId1", "
|
|
5758
|
+
relationship$2("rId1", OFFICE_REL + "package", embeddingTarget),
|
|
5520
5759
|
relationship$2("rId2", "http://schemas.microsoft.com/office/2011/relationships/chartColorStyle", colorsTarget),
|
|
5521
5760
|
relationship$2("rId3", "http://schemas.microsoft.com/office/2011/relationships/chartStyle", styleTarget)
|
|
5522
5761
|
]);
|
|
@@ -5634,6 +5873,63 @@ function encodeSlideMediaRels(layout, runtime, onMediaError = "throw") {
|
|
|
5634
5873
|
return imageProms;
|
|
5635
5874
|
}
|
|
5636
5875
|
//#endregion
|
|
5876
|
+
//#region src/gen/prepare.ts
|
|
5877
|
+
/**
|
|
5878
|
+
* ts-pptx: the pre-serialization pass
|
|
5879
|
+
*
|
|
5880
|
+
* Everything that must happen to authored slide state *before* any XML is built. Two callers
|
|
5881
|
+
* reach serialization and both need it:
|
|
5882
|
+
*
|
|
5883
|
+
* - `package/assemble.ts` — the normal `write`/`stream`/`writeFile` path, building a
|
|
5884
|
+
* complete `.pptx`.
|
|
5885
|
+
* - `PresentationCore.extractSlides()` — serializes slide bodies only, for splicing into
|
|
5886
|
+
* an already-loaded deck via `Presentation.appendSlides()` (`ts-pptx/read`).
|
|
5887
|
+
*
|
|
5888
|
+
* The second used to reimplement the first inline, kept in step by a comment that said
|
|
5889
|
+
* "exactly as ... does". Nothing failed when they drifted: `extractSlides` would simply emit
|
|
5890
|
+
* slides that did not match what a normal write produces, and no test compares the two.
|
|
5891
|
+
*
|
|
5892
|
+
* Two primitives rather than one combined pass, because the package path has work of its own
|
|
5893
|
+
* that must land *between* them: it de-duplicates identical media across the deck (which
|
|
5894
|
+
* needs the encoded bytes {@link encodeMediaForTargets} produces) and assigns package-unique
|
|
5895
|
+
* chart part filenames, both before any slide content is baked. Exposing the halves lets
|
|
5896
|
+
* `assemble` keep its established order exactly while still sharing the code.
|
|
5897
|
+
*
|
|
5898
|
+
* The order across the two is load-bearing:
|
|
5899
|
+
*
|
|
5900
|
+
* 1. **Media first.** It is the only asynchronous step, and the sync XML pass reads the
|
|
5901
|
+
* `rel.data` it populates.
|
|
5902
|
+
* 2. **Backfill placeholders**, so a slide inherits its layout's placeholder objects before
|
|
5903
|
+
* anything measures or serializes them.
|
|
5904
|
+
* 3. **Bake measured fit last**, because it measures the text step 2 may have just added and
|
|
5905
|
+
* writes the `fontScale` the sync XML pass then reads.
|
|
5906
|
+
*
|
|
5907
|
+
* The two functions take different target sets on purpose: media lives on layouts and the
|
|
5908
|
+
* master as well as on slides, while placeholder backfill and measured fit apply only to
|
|
5909
|
+
* slides. `extractSlides` passes only its slides to both, because it emits no layout or
|
|
5910
|
+
* master parts.
|
|
5911
|
+
*/
|
|
5912
|
+
/**
|
|
5913
|
+
* Step 1: load and base64-encode every media rel on the given targets, populating `rel.data`.
|
|
5914
|
+
* @param {ReadonlyArray<PresSlideInternal | SlideLayoutInternal>} targets - media-bearing targets (slides, layouts, master)
|
|
5915
|
+
* @param {RuntimeAdapter} runtime - runtime adapter used to load media
|
|
5916
|
+
* @param {'throw' | 'placeholder'} onMediaError - failure policy for unloadable media
|
|
5917
|
+
*/
|
|
5918
|
+
async function encodeMediaForTargets(targets, runtime, onMediaError) {
|
|
5919
|
+
const promises = [];
|
|
5920
|
+
for (const target of targets) promises.push(...encodeSlideMediaRels(target, runtime, onMediaError));
|
|
5921
|
+
await Promise.all(promises);
|
|
5922
|
+
}
|
|
5923
|
+
/**
|
|
5924
|
+
* Steps 2 and 3: backfill inherited layout placeholders, then bake measured text fit.
|
|
5925
|
+
* @param {PresSlideInternal[]} slides - the slides to prepare
|
|
5926
|
+
* @param {FontMetricsRegistry} fontMetrics - registered font metrics; an empty registry skips the fit bake
|
|
5927
|
+
*/
|
|
5928
|
+
function bakeSlideContent(slides, fontMetrics) {
|
|
5929
|
+
for (const slide of slides) if (slide._slideLayout) addPlaceholdersToSlideLayouts(slide);
|
|
5930
|
+
applyMeasuredFit(slides, fontMetrics);
|
|
5931
|
+
}
|
|
5932
|
+
//#endregion
|
|
5637
5933
|
//#region src/gen/slide/shape-ids.ts
|
|
5638
5934
|
/**
|
|
5639
5935
|
* Every object a slide renders, paired with the `<p:cNvPr>` id it is rendered with: top-level
|
|
@@ -6352,9 +6648,7 @@ function genXmlParagraphProperties(textObj, isDefault) {
|
|
|
6352
6648
|
case "justify":
|
|
6353
6649
|
paragraphPropXml += " algn=\"just\"";
|
|
6354
6650
|
break;
|
|
6355
|
-
default:
|
|
6356
|
-
paragraphPropXml += "";
|
|
6357
|
-
break;
|
|
6651
|
+
default: paragraphPropXml += "";
|
|
6358
6652
|
}
|
|
6359
6653
|
if (opts.lineSpacing) strXmlLnSpc = el("a:lnSpc", null, raw(voidEl("a:spcPts", { val: clampLineSpacingPts(opts.lineSpacing) })));
|
|
6360
6654
|
else if (opts.lineSpacingMultiple) strXmlLnSpc = el("a:lnSpc", null, raw(voidEl("a:spcPct", { val: Math.round(opts.lineSpacingMultiple * PERCENT_SCALE) })));
|
|
@@ -6366,13 +6660,13 @@ function genXmlParagraphProperties(textObj, isDefault) {
|
|
|
6366
6660
|
const isPictureBullet = !!(bulletImage && (bulletImage.path || bulletImage.data));
|
|
6367
6661
|
if (opts.bullet?.indent) bulletMarL = valToPts(opts.bullet.indent);
|
|
6368
6662
|
if (opts.bullet.color && !isPictureBullet) strXmlBulletColor = el("a:buClr", null, raw(createColorElement(opts.bullet.color)));
|
|
6369
|
-
let bulletSizePct
|
|
6663
|
+
let bulletSizePct;
|
|
6370
6664
|
if (opts.bullet.size !== void 0) {
|
|
6371
6665
|
const bulletSize = Number(opts.bullet.size);
|
|
6372
6666
|
if (isNaN(bulletSize) || bulletSize < 25 || bulletSize > 400) warn("bullet/size-out-of-range", "`bullet.size` must be a percentage between 25 and 400!");
|
|
6373
6667
|
else bulletSizePct = Math.round(bulletSize * FIXED_PCT_PER_PERCENT);
|
|
6374
6668
|
}
|
|
6375
|
-
const strXmlBulletSize = voidEl("a:buSzPct", { val: bulletSizePct });
|
|
6669
|
+
const strXmlBulletSize = bulletSizePct === void 0 ? "" : voidEl("a:buSzPct", { val: bulletSizePct });
|
|
6376
6670
|
const strXmlBulletFont = opts.bullet.fontFace ? voidEl("a:buFont", { typeface: opts.bullet.fontFace }) : "";
|
|
6377
6671
|
const bulletIndentAttrs = () => ` marL="${opts.indentLevel && opts.indentLevel > 0 ? bulletMarL + bulletMarL * opts.indentLevel : bulletMarL}" indent="-${bulletMarL}"`;
|
|
6378
6672
|
if (isPictureBullet) {
|
|
@@ -6407,7 +6701,7 @@ function genXmlParagraphProperties(textObj, isDefault) {
|
|
|
6407
6701
|
}
|
|
6408
6702
|
} else if (opts.bullet) {
|
|
6409
6703
|
paragraphPropXml += ` marL="${opts.indentLevel && opts.indentLevel > 0 ? bulletMarL + bulletMarL * opts.indentLevel : bulletMarL}" indent="-${bulletMarL}"`;
|
|
6410
|
-
strXmlBullet =
|
|
6704
|
+
strXmlBullet = buChar("•");
|
|
6411
6705
|
} else if (!opts.bullet) {
|
|
6412
6706
|
paragraphPropXml += " indent=\"0\" marL=\"0\"";
|
|
6413
6707
|
strXmlBullet = voidEl("a:buNone");
|
|
@@ -7094,10 +7388,7 @@ function genXmlCustGeom(options, cx, cy, layout) {
|
|
|
7094
7388
|
pt(point.x, point.y)
|
|
7095
7389
|
].map(raw), BEZ_INDENT));
|
|
7096
7390
|
break;
|
|
7097
|
-
case "quadratic":
|
|
7098
|
-
nodes.push(el("a:quadBezTo", null, [pt(point.curve.x1, point.curve.y1), pt(point.x, point.y)].map(raw), BEZ_INDENT));
|
|
7099
|
-
break;
|
|
7100
|
-
default: break;
|
|
7391
|
+
case "quadratic": nodes.push(el("a:quadBezTo", null, [pt(point.curve.x1, point.curve.y1), pt(point.x, point.y)].map(raw), BEZ_INDENT));
|
|
7101
7392
|
}
|
|
7102
7393
|
else if ("close" in point) nodes.push(voidEl("a:close", null, SPACE_BEFORE_SLASH));
|
|
7103
7394
|
else if (point.moveTo || i === 0) nodes.push(el("a:moveTo", null, raw(pt(point.x, point.y))));
|
|
@@ -7186,40 +7477,46 @@ function genXmlCustGeom(options, cx, cy, layout) {
|
|
|
7186
7477
|
* ts-pptx: DrawingML image sizing & cropping
|
|
7187
7478
|
*
|
|
7188
7479
|
* Build the `<a:srcRect>` (+ `<a:stretch>`) blipFill children for the image
|
|
7189
|
-
* sizing modes (`cover` / `contain` / `crop`)
|
|
7480
|
+
* sizing modes (`cover` / `contain` / `crop` / `stretch`), for the implicit
|
|
7481
|
+
* aspect-correct placement a vector source gets, and for explicit percentage crops.
|
|
7190
7482
|
*/
|
|
7191
7483
|
/** Every `<a:srcRect>` below is followed by this same fill directive. */
|
|
7192
7484
|
const STRETCH = el("a:stretch", null, raw(voidEl("a:fillRect")));
|
|
7485
|
+
/** The `<a:srcRect>` fitting `imgSize` into `boxDim`, followed by the fill directive. */
|
|
7486
|
+
function fitSrcRect(type, imgSize, boxDim) {
|
|
7487
|
+
const { l, r, t, b } = fitSrcRectPercents(type, imgSize, boxDim);
|
|
7488
|
+
return voidEl("a:srcRect", {
|
|
7489
|
+
l,
|
|
7490
|
+
r,
|
|
7491
|
+
t,
|
|
7492
|
+
b
|
|
7493
|
+
}) + STRETCH;
|
|
7494
|
+
}
|
|
7193
7495
|
const ImageSizingXml = {
|
|
7194
7496
|
cover: function(imgSize, boxDim) {
|
|
7195
|
-
|
|
7196
|
-
return voidEl("a:srcRect", {
|
|
7197
|
-
l,
|
|
7198
|
-
r,
|
|
7199
|
-
t,
|
|
7200
|
-
b
|
|
7201
|
-
}) + STRETCH;
|
|
7497
|
+
return fitSrcRect("cover", imgSize, boxDim);
|
|
7202
7498
|
},
|
|
7203
7499
|
contain: function(imgSize, boxDim) {
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
b
|
|
7210
|
-
}) + STRETCH;
|
|
7500
|
+
return fitSrcRect("contain", imgSize, boxDim);
|
|
7501
|
+
},
|
|
7502
|
+
/** No source rectangle at all: the image fills the box, aspect ratio be damned. */
|
|
7503
|
+
stretch: function() {
|
|
7504
|
+
return STRETCH;
|
|
7211
7505
|
},
|
|
7212
7506
|
crop: function(imgSize, boxDim) {
|
|
7213
7507
|
const l = boxDim.x;
|
|
7214
7508
|
const r = imgSize.w - (boxDim.x + boxDim.w);
|
|
7215
7509
|
const t = boxDim.y;
|
|
7216
7510
|
const b = imgSize.h - (boxDim.y + boxDim.h);
|
|
7217
|
-
if (l < 0 || r < 0 || t < 0 || b < 0)
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7511
|
+
if (l < 0 || r < 0 || t < 0 || b < 0) {
|
|
7512
|
+
const over = [
|
|
7513
|
+
l < 0 && `x (${l < 0 ? -l : 0} past left edge)`,
|
|
7514
|
+
r < 0 && `x+w (${-r} past right edge)`,
|
|
7515
|
+
t < 0 && `y (${-t} past top edge)`,
|
|
7516
|
+
b < 0 && `y+h (${-b} past bottom edge)`
|
|
7517
|
+
].filter(Boolean).join(", ");
|
|
7518
|
+
throw new InvalidOptionError("image/crop-window-overflows", `addImage sizing.type 'crop': crop window overflows image bounds — ${over}. Ensure x≥0, y≥0, x+w≤w, y+h≤h.`);
|
|
7519
|
+
}
|
|
7223
7520
|
return voidEl("a:srcRect", {
|
|
7224
7521
|
l: Math.round(1e5 * (l / imgSize.w)),
|
|
7225
7522
|
r: Math.round(1e5 * (r / imgSize.w)),
|
|
@@ -7229,6 +7526,23 @@ const ImageSizingXml = {
|
|
|
7229
7526
|
}
|
|
7230
7527
|
};
|
|
7231
7528
|
/**
|
|
7529
|
+
* The blipFill children for a vector source the caller gave no `sizing` for: letterbox it to its
|
|
7530
|
+
* own aspect ratio inside its frame, the way `sizing: 'contain'` would — an SVG carries an
|
|
7531
|
+
* intrinsic ratio, and stretching a glyph into a box that disagrees with it is never the intent.
|
|
7532
|
+
*
|
|
7533
|
+
* Returns `null` when the two ratios already agree, which is the overwhelmingly common case (a
|
|
7534
|
+
* square icon in a square box). The caller then emits the plain `<a:stretch>` it always did, so
|
|
7535
|
+
* this default costs nothing — neither bytes nor a behaviour change — until it actually differs.
|
|
7536
|
+
* @param imgSize - the vector's intrinsic size (viewBox or width/height)
|
|
7537
|
+
* @param boxDim - the picture's displayed frame
|
|
7538
|
+
* @returns the `<a:srcRect>` + `<a:stretch>` children, or `null` if no letterboxing is needed
|
|
7539
|
+
*/
|
|
7540
|
+
function genXmlVectorAspectFit(imgSize, boxDim) {
|
|
7541
|
+
const { l, r, t, b } = fitSrcRectPercents("contain", imgSize, boxDim);
|
|
7542
|
+
if (l === 0 && r === 0 && t === 0 && b === 0) return null;
|
|
7543
|
+
return fitSrcRect("contain", imgSize, boxDim);
|
|
7544
|
+
}
|
|
7545
|
+
/**
|
|
7232
7546
|
* Build an explicit `<a:srcRect>` crop from percentage edge insets (0–100), emitted verbatim.
|
|
7233
7547
|
* Each inset is the percent of the *source* image trimmed from that edge; values serialize in
|
|
7234
7548
|
* 1000ths of a percent (DrawingML `ST_Percentage`, where 100% = 100000). Unlike `sizing: 'crop'`
|
|
@@ -7265,10 +7579,12 @@ function genXmlImageCrop(crop, objectName) {
|
|
|
7265
7579
|
function renderImageObject(slideItemObj, idx, slide, x, y, cx, cy, imgWidth, imgHeight, placeholderObj, locationAttrs, sizing, rounding) {
|
|
7266
7580
|
let strSlideXml = "";
|
|
7267
7581
|
slideItemObj.options = slideItemObj.options || {};
|
|
7582
|
+
const mediaRel = (slide._relsMedia || []).find((rel) => rel.rId === slideItemObj.imageRid);
|
|
7583
|
+
const relData = mediaRel?.data;
|
|
7584
|
+
const naturalSize = () => typeof relData === "string" ? getImageSizeFromBase64(relData) : null;
|
|
7268
7585
|
if (slideItemObj.options._szAuto) {
|
|
7269
7586
|
const szAuto = slideItemObj.options._szAuto;
|
|
7270
|
-
const
|
|
7271
|
-
const natural = typeof relData === "string" ? getImageSizeFromBase64(relData) : null;
|
|
7587
|
+
const natural = naturalSize();
|
|
7272
7588
|
if (natural) {
|
|
7273
7589
|
if (szAuto.w && szAuto.h) {
|
|
7274
7590
|
cx = pixelsToEmu(natural.w, 96);
|
|
@@ -7299,7 +7615,8 @@ function renderImageObject(slideItemObj, idx, slide, x, y, cx, cy, imgWidth, img
|
|
|
7299
7615
|
imgOpts.biLevel ? raw(voidEl("a:biLevel", { thresh: Math.round(imgOpts.biLevel.threshold * PERCENT_SCALE) })) : null
|
|
7300
7616
|
];
|
|
7301
7617
|
strSlideXml += "<p:blipFill>";
|
|
7302
|
-
|
|
7618
|
+
const isVector = mediaRel?.extn === "svg";
|
|
7619
|
+
if (isVector) strSlideXml += el("a:blip", { "r:embed": `rId${(slideItemObj.imageRid ?? 0) - 1}` }, [...blipEffects(" "), raw(el("a:extLst", null, raw(el("a:ext", { uri: "{96DAC541-7B7A-43D3-8B79-37D633B846F1}" }, raw(voidEl("asvg:svgBlip", {
|
|
7303
7620
|
"xmlns:asvg": "http://schemas.microsoft.com/office/drawing/2016/SVG/main",
|
|
7304
7621
|
"r:embed": `rId${slideItemObj.imageRid}`
|
|
7305
7622
|
}, { openPrefix: " " })), {
|
|
@@ -7323,8 +7640,7 @@ function renderImageObject(slideItemObj, idx, slide, x, y, cx, cy, imgWidth, img
|
|
|
7323
7640
|
h: imgHeight
|
|
7324
7641
|
};
|
|
7325
7642
|
if (sizing.type === "cover" || sizing.type === "contain") {
|
|
7326
|
-
const
|
|
7327
|
-
const natural = typeof relData === "string" ? getImageSizeFromBase64(relData) : null;
|
|
7643
|
+
const natural = naturalSize();
|
|
7328
7644
|
if (natural) cropSize = natural;
|
|
7329
7645
|
else warn("image/unmeasurable-natural-size", `sizing '${sizing.type}' could not measure natural dimensions for image "${slideItemObj.options.objectName}"; falling back to displayed aspect ratio (crop may be inexact). Provide a raster image (PNG/JPEG/GIF/BMP/WebP) or an SVG with width/height or a viewBox to enable an aspect-correct crop.`);
|
|
7330
7646
|
}
|
|
@@ -7336,7 +7652,14 @@ function renderImageObject(slideItemObj, idx, slide, x, y, cx, cy, imgWidth, img
|
|
|
7336
7652
|
});
|
|
7337
7653
|
imgWidth = boxW;
|
|
7338
7654
|
imgHeight = boxH;
|
|
7339
|
-
} else
|
|
7655
|
+
} else {
|
|
7656
|
+
const natural = isVector ? naturalSize() : null;
|
|
7657
|
+
const aspectFit = natural ? genXmlVectorAspectFit(natural, {
|
|
7658
|
+
w: imgWidth,
|
|
7659
|
+
h: imgHeight
|
|
7660
|
+
}) : null;
|
|
7661
|
+
strSlideXml += aspectFit ?? el("a:stretch", null, raw(voidEl("a:fillRect")), { openPrefix: " " });
|
|
7662
|
+
}
|
|
7340
7663
|
strSlideXml += "</p:blipFill>";
|
|
7341
7664
|
strSlideXml += "<p:spPr>";
|
|
7342
7665
|
strSlideXml += el("a:xfrm", locationAttrs, [raw(voidEl("a:off", {
|
|
@@ -7410,6 +7733,216 @@ function renderMediaObject(slideItemObj, idx, x, y, cx, cy, locationAttrs) {
|
|
|
7410
7733
|
]);
|
|
7411
7734
|
}
|
|
7412
7735
|
//#endregion
|
|
7736
|
+
//#region src/gen/slide/objects/model3d.ts
|
|
7737
|
+
/** The `am3d` namespace, doubling as `a:graphicData@uri` and the `mc:Choice Requires` token's URI. */
|
|
7738
|
+
const AM3D_NS = "http://schemas.microsoft.com/office/drawing/2017/model3d";
|
|
7739
|
+
/** Denominator of every `am3d` rational element (`@n`/`@d`). */
|
|
7740
|
+
const RATIO_DEN = 1e6;
|
|
7741
|
+
/**
|
|
7742
|
+
* `am3d:raster@rName`/`@rVer` — the renderer that produced the cached preview. PowerPoint stamps
|
|
7743
|
+
* its own renderer here; ts-pptx did not rasterize anything, but the attributes are what PowerPoint
|
|
7744
|
+
* writes and the element is where the preview blip lives, so they are reproduced verbatim.
|
|
7745
|
+
*/
|
|
7746
|
+
const RASTER = {
|
|
7747
|
+
rName: "Office3DRenderer",
|
|
7748
|
+
rVer: "16.0.8326"
|
|
7749
|
+
};
|
|
7750
|
+
/**
|
|
7751
|
+
* `am3d:objViewport@viewportSz`. Bounding-box derived in PowerPoint's output (a cube and a slab
|
|
7752
|
+
* gave different values); the cube's is emitted, matching the fixed default camera.
|
|
7753
|
+
*/
|
|
7754
|
+
const OBJ_VIEWPORT_SZ = 3338805;
|
|
7755
|
+
/** The three point lights PowerPoint writes for every inserted model — key, fill and rim. */
|
|
7756
|
+
const PT_LIGHTS = [
|
|
7757
|
+
{
|
|
7758
|
+
clr: {
|
|
7759
|
+
r: 1e5,
|
|
7760
|
+
g: 75e3,
|
|
7761
|
+
b: 5e4
|
|
7762
|
+
},
|
|
7763
|
+
intensityN: 9765625,
|
|
7764
|
+
pos: {
|
|
7765
|
+
x: 21959998,
|
|
7766
|
+
y: 70920001,
|
|
7767
|
+
z: 16344003
|
|
7768
|
+
}
|
|
7769
|
+
},
|
|
7770
|
+
{
|
|
7771
|
+
clr: {
|
|
7772
|
+
r: 4e4,
|
|
7773
|
+
g: 6e4,
|
|
7774
|
+
b: 95e3
|
|
7775
|
+
},
|
|
7776
|
+
intensityN: 1225e4,
|
|
7777
|
+
pos: {
|
|
7778
|
+
x: -37964106,
|
|
7779
|
+
y: 51130435,
|
|
7780
|
+
z: 57631972
|
|
7781
|
+
}
|
|
7782
|
+
},
|
|
7783
|
+
{
|
|
7784
|
+
clr: {
|
|
7785
|
+
r: 86837,
|
|
7786
|
+
g: 72700,
|
|
7787
|
+
b: 1e5
|
|
7788
|
+
},
|
|
7789
|
+
intensityN: 3125e3,
|
|
7790
|
+
pos: {
|
|
7791
|
+
x: -37739122,
|
|
7792
|
+
y: 58056624,
|
|
7793
|
+
z: -34769649
|
|
7794
|
+
}
|
|
7795
|
+
}
|
|
7796
|
+
];
|
|
7797
|
+
/** `am3d:ambientLight` — neutral 50% scRGB at half illuminance, constant like the point lights. */
|
|
7798
|
+
const AMBIENT = {
|
|
7799
|
+
clr: {
|
|
7800
|
+
r: 5e4,
|
|
7801
|
+
g: 5e4,
|
|
7802
|
+
b: 5e4
|
|
7803
|
+
},
|
|
7804
|
+
illuminanceN: 5e5
|
|
7805
|
+
};
|
|
7806
|
+
/** `<am3d:clr><a:scrgbClr …/></am3d:clr>` — the colour wrapper both light kinds share. */
|
|
7807
|
+
function lightColor(clr) {
|
|
7808
|
+
return el("am3d:clr", null, raw(voidEl("a:scrgbClr", clr)));
|
|
7809
|
+
}
|
|
7810
|
+
/** The `am3d:camera` block: eye position, up vector, aim point and perspective fov. */
|
|
7811
|
+
function cameraEl(model) {
|
|
7812
|
+
return el("am3d:camera", null, [
|
|
7813
|
+
raw(voidEl("am3d:pos", model.pos)),
|
|
7814
|
+
raw(voidEl("am3d:up", model.up)),
|
|
7815
|
+
raw(voidEl("am3d:lookAt", model.lookAt)),
|
|
7816
|
+
raw(voidEl("am3d:perspective", { fov: model.fov }))
|
|
7817
|
+
]);
|
|
7818
|
+
}
|
|
7819
|
+
/**
|
|
7820
|
+
* The `am3d:trans` block: model-unit scale plus an identity placement. Only `meterPerModelUnit`
|
|
7821
|
+
* varies — `preTrans`/`scale`/`rot`/`postTrans` are the identity PowerPoint writes for a model
|
|
7822
|
+
* inserted without any subsequent 3D manipulation, and `am3d:rot` is emitted attribute-less.
|
|
7823
|
+
*/
|
|
7824
|
+
function transEl(model) {
|
|
7825
|
+
const unit = {
|
|
7826
|
+
n: RATIO_DEN,
|
|
7827
|
+
d: RATIO_DEN
|
|
7828
|
+
};
|
|
7829
|
+
return el("am3d:trans", null, [
|
|
7830
|
+
raw(voidEl("am3d:meterPerModelUnit", {
|
|
7831
|
+
n: model.meterPerModelUnitN,
|
|
7832
|
+
d: RATIO_DEN
|
|
7833
|
+
})),
|
|
7834
|
+
raw(voidEl("am3d:preTrans", {
|
|
7835
|
+
dx: 0,
|
|
7836
|
+
dy: 0,
|
|
7837
|
+
dz: 0
|
|
7838
|
+
})),
|
|
7839
|
+
raw(el("am3d:scale", null, [
|
|
7840
|
+
raw(voidEl("am3d:sx", unit)),
|
|
7841
|
+
raw(voidEl("am3d:sy", unit)),
|
|
7842
|
+
raw(voidEl("am3d:sz", unit))
|
|
7843
|
+
])),
|
|
7844
|
+
raw(voidEl("am3d:rot")),
|
|
7845
|
+
raw(voidEl("am3d:postTrans", {
|
|
7846
|
+
dx: 0,
|
|
7847
|
+
dy: 0,
|
|
7848
|
+
dz: 0
|
|
7849
|
+
}))
|
|
7850
|
+
]);
|
|
7851
|
+
}
|
|
7852
|
+
/** The fixed lighting rig: one ambient light and three point lights, in PowerPoint's order. */
|
|
7853
|
+
function lightsXml() {
|
|
7854
|
+
return el("am3d:ambientLight", null, [raw(lightColor(AMBIENT.clr)), raw(voidEl("am3d:illuminance", {
|
|
7855
|
+
n: AMBIENT.illuminanceN,
|
|
7856
|
+
d: RATIO_DEN
|
|
7857
|
+
}))]) + PT_LIGHTS.map((light) => el("am3d:ptLight", { rad: 0 }, [
|
|
7858
|
+
raw(lightColor(light.clr)),
|
|
7859
|
+
raw(voidEl("am3d:intensity", {
|
|
7860
|
+
n: light.intensityN,
|
|
7861
|
+
d: RATIO_DEN
|
|
7862
|
+
})),
|
|
7863
|
+
raw(voidEl("am3d:pos", light.pos))
|
|
7864
|
+
])).join("");
|
|
7865
|
+
}
|
|
7866
|
+
/** The `mc:Fallback` picture — the cached preview, drawn by everything that is not PowerPoint 2019+. */
|
|
7867
|
+
function fallbackPic(picId, objectName, altText, model, xf) {
|
|
7868
|
+
return el("p:pic", null, [
|
|
7869
|
+
raw(el("p:nvPicPr", null, [
|
|
7870
|
+
raw(cNvPrOpen(picId, objectName, altText) + "/>"),
|
|
7871
|
+
raw(el("p:cNvPicPr", null, raw(voidEl("a:picLocks", {
|
|
7872
|
+
noGrp: "1",
|
|
7873
|
+
noRot: "1",
|
|
7874
|
+
noChangeAspect: "1",
|
|
7875
|
+
noMove: "1",
|
|
7876
|
+
noResize: "1",
|
|
7877
|
+
noEditPoints: "1",
|
|
7878
|
+
noAdjustHandles: "1",
|
|
7879
|
+
noChangeArrowheads: "1",
|
|
7880
|
+
noChangeShapeType: "1",
|
|
7881
|
+
noCrop: "1"
|
|
7882
|
+
})))),
|
|
7883
|
+
raw(voidEl("p:nvPr"))
|
|
7884
|
+
])),
|
|
7885
|
+
raw(el("p:blipFill", null, [raw(voidEl("a:blip", { "r:embed": `rId${model.previewRid}` })), raw(el("a:stretch", null, raw(voidEl("a:fillRect"))))])),
|
|
7886
|
+
raw(el("p:spPr", null, [raw(el("a:xfrm", null, [raw(voidEl("a:off", {
|
|
7887
|
+
x: xf.x,
|
|
7888
|
+
y: xf.y
|
|
7889
|
+
})), raw(voidEl("a:ext", {
|
|
7890
|
+
cx: xf.cx,
|
|
7891
|
+
cy: xf.cy
|
|
7892
|
+
}))])), raw(el("a:prstGeom", { prst: "rect" }, raw(voidEl("a:avLst"))))]))
|
|
7893
|
+
]);
|
|
7894
|
+
}
|
|
7895
|
+
/**
|
|
7896
|
+
* Render a `model3d` slide object to its `<mc:AlternateContent>` XML. The `mc:Choice` carries the
|
|
7897
|
+
* real `<p:graphicFrame>` (the `am3d:model3d` graphicData PowerPoint 2019+ renders live); the
|
|
7898
|
+
* `mc:Fallback` carries the cached preview picture. See `gen/define/model3d.ts`.
|
|
7899
|
+
*/
|
|
7900
|
+
function renderModel3dObject(slideItemObj, idx, x, y, cx, cy) {
|
|
7901
|
+
const model = slideItemObj.model3d;
|
|
7902
|
+
if (!model) return "";
|
|
7903
|
+
const opts = slideItemObj.options || {};
|
|
7904
|
+
const altText = opts.altText || "";
|
|
7905
|
+
const spPr = el("am3d:spPr", null, [raw(el("a:xfrm", null, [raw(voidEl("a:off", {
|
|
7906
|
+
x: 0,
|
|
7907
|
+
y: 0
|
|
7908
|
+
})), raw(voidEl("a:ext", {
|
|
7909
|
+
cx,
|
|
7910
|
+
cy
|
|
7911
|
+
}))])), raw(el("a:prstGeom", { prst: "rect" }, raw(voidEl("a:avLst"))))]);
|
|
7912
|
+
const model3d = el("am3d:model3d", { "r:embed": `rId${model.modelRid}` }, [
|
|
7913
|
+
raw(spPr),
|
|
7914
|
+
raw(cameraEl(model)),
|
|
7915
|
+
raw(transEl(model)),
|
|
7916
|
+
raw(el("am3d:raster", RASTER, raw(voidEl("am3d:blip", { "r:embed": `rId${model.previewRid}` })))),
|
|
7917
|
+
raw(voidEl("am3d:objViewport", { viewportSz: OBJ_VIEWPORT_SZ })),
|
|
7918
|
+
raw(lightsXml())
|
|
7919
|
+
]);
|
|
7920
|
+
const graphicFrame = el("p:graphicFrame", null, [
|
|
7921
|
+
raw(el("p:nvGraphicFramePr", null, [
|
|
7922
|
+
raw(cNvPrOpen(idx + 2, opts.objectName, altText) + "/>"),
|
|
7923
|
+
raw(el("p:cNvGraphicFramePr", null, raw(voidEl("a:graphicFrameLocks")))),
|
|
7924
|
+
raw(voidEl("p:nvPr"))
|
|
7925
|
+
])),
|
|
7926
|
+
raw(el("p:xfrm", null, [raw(voidEl("a:off", {
|
|
7927
|
+
x,
|
|
7928
|
+
y
|
|
7929
|
+
})), raw(voidEl("a:ext", {
|
|
7930
|
+
cx,
|
|
7931
|
+
cy
|
|
7932
|
+
}))])),
|
|
7933
|
+
raw(el("a:graphic", null, raw(el("a:graphicData", { uri: AM3D_NS }, raw(model3d)))))
|
|
7934
|
+
]);
|
|
7935
|
+
return el("mc:AlternateContent", { "xmlns:mc": MC_NS }, [raw(el("mc:Choice", {
|
|
7936
|
+
"xmlns:am3d": AM3D_NS,
|
|
7937
|
+
Requires: "am3d"
|
|
7938
|
+
}, raw(graphicFrame))), raw(el("mc:Fallback", null, raw(fallbackPic(idx + 2, opts.objectName, altText, model, {
|
|
7939
|
+
x,
|
|
7940
|
+
y,
|
|
7941
|
+
cx,
|
|
7942
|
+
cy
|
|
7943
|
+
}))))]);
|
|
7944
|
+
}
|
|
7945
|
+
//#endregion
|
|
7413
7946
|
//#region src/gen/slide/objects/ole.ts
|
|
7414
7947
|
/** VML namespace — declared by an OLE object's `mc:Choice Requires="v"` (no VML content is emitted). */
|
|
7415
7948
|
const VML_NS = "urn:schemas-microsoft-com:vml";
|
|
@@ -7483,13 +8016,64 @@ function renderOleObject(slideItemObj, idx, x, y, cx, cy) {
|
|
|
7483
8016
|
//#endregion
|
|
7484
8017
|
//#region src/gen/drawingml/table-border.ts
|
|
7485
8018
|
/**
|
|
7486
|
-
*
|
|
7487
|
-
*
|
|
7488
|
-
*
|
|
7489
|
-
* @param {BorderProps
|
|
7490
|
-
* @return {string}
|
|
8019
|
+
* One `<a:lnX>` border element. Every side of a table cell — the four edges and the two
|
|
8020
|
+
* diagonals — is a `CT_LineProperties`, so they differ only in element name.
|
|
8021
|
+
* @param {string} name - the element's local name (`lnL`, `lnTlToBr`, …)
|
|
8022
|
+
* @param {BorderProps} border - the resolved border for that side
|
|
8023
|
+
* @return {string} the border element XML
|
|
8024
|
+
*/
|
|
8025
|
+
function genBorderLine(name, border) {
|
|
8026
|
+
const cap = createLineCap(border.cap);
|
|
8027
|
+
if (border.type === "none") return el(`a:${name}`, {
|
|
8028
|
+
w: 0,
|
|
8029
|
+
cap,
|
|
8030
|
+
cmpd: "sng",
|
|
8031
|
+
algn: "ctr"
|
|
8032
|
+
}, raw(voidEl("a:noFill")));
|
|
8033
|
+
return el(`a:${name}`, {
|
|
8034
|
+
w: valToPts(resolveBorderWidth(border, 1)),
|
|
8035
|
+
cap,
|
|
8036
|
+
cmpd: "sng",
|
|
8037
|
+
algn: "ctr"
|
|
8038
|
+
}, [
|
|
8039
|
+
genXmlColorSelection({
|
|
8040
|
+
color: border.color ?? "363636",
|
|
8041
|
+
transparency: border.transparency
|
|
8042
|
+
}),
|
|
8043
|
+
voidEl("a:prstDash", { val: resolveBorderDash(border) }),
|
|
8044
|
+
voidEl("a:round"),
|
|
8045
|
+
voidEl("a:headEnd", {
|
|
8046
|
+
type: "none",
|
|
8047
|
+
w: "med",
|
|
8048
|
+
len: "med"
|
|
8049
|
+
}),
|
|
8050
|
+
voidEl("a:tailEnd", {
|
|
8051
|
+
type: "none",
|
|
8052
|
+
w: "med",
|
|
8053
|
+
len: "med"
|
|
8054
|
+
})
|
|
8055
|
+
].map(raw));
|
|
8056
|
+
}
|
|
8057
|
+
/**
|
|
8058
|
+
* Emit the border children of an `<a:tcPr>` for a table cell: the four edges, then the two
|
|
8059
|
+
* diagonals when the cell asks for them.
|
|
8060
|
+
*
|
|
8061
|
+
* The edges are shared by normal cells and the dummy span (`_hmerge`/`_vmerge`) cells so a
|
|
8062
|
+
* merged region's outer edges render with the same border as its origin cell. The diagonals
|
|
8063
|
+
* are **not**: a diagonal across a merged region is one stroke corner-to-corner, and
|
|
8064
|
+
* repeating it on each covered cell would draw a sawtooth instead. Only the span origin
|
|
8065
|
+
* carries them, which is also where PowerPoint puts them.
|
|
8066
|
+
*
|
|
8067
|
+
* A side may be missing, and missing is not the same as `{type:'none'}`: `none` writes an
|
|
8068
|
+
* explicit `w="0"` rule, which is direct formatting and overrides whatever a built-in table
|
|
8069
|
+
* style would have drawn there, while an omitted side leaves that edge to the style. The
|
|
8070
|
+
* definition step sends every cell here dense; a caller reaching this directly may not.
|
|
8071
|
+
*
|
|
8072
|
+
* @param {BorderProps[]} cellBorder - up to a 4-tuple of border props in [top, right, bottom, left] order
|
|
8073
|
+
* @param {TableCellDiagonals} [diagonal] - the cell's optional corner-to-corner rules
|
|
8074
|
+
* @return {string} concatenated border element XML, in the document order PowerPoint expects
|
|
7491
8075
|
*/
|
|
7492
|
-
function genTableCellBorderXml(cellBorder) {
|
|
8076
|
+
function genTableCellBorderXml(cellBorder, diagonal) {
|
|
7493
8077
|
let strXml = "";
|
|
7494
8078
|
[
|
|
7495
8079
|
{
|
|
@@ -7511,42 +8095,113 @@ function genTableCellBorderXml(cellBorder) {
|
|
|
7511
8095
|
].forEach((obj) => {
|
|
7512
8096
|
const border = cellBorder[obj.idx];
|
|
7513
8097
|
if (!border) return;
|
|
7514
|
-
|
|
7515
|
-
if (border.type !== "none") strXml += el(`a:${obj.name}`, {
|
|
7516
|
-
w: valToPts(resolveBorderWidth(border, 1)),
|
|
7517
|
-
cap,
|
|
7518
|
-
cmpd: "sng",
|
|
7519
|
-
algn: "ctr"
|
|
7520
|
-
}, [
|
|
7521
|
-
genXmlColorSelection({
|
|
7522
|
-
color: border.color ?? "363636",
|
|
7523
|
-
transparency: border.transparency
|
|
7524
|
-
}),
|
|
7525
|
-
voidEl("a:prstDash", { val: border.type === "dash" ? "sysDash" : "solid" }),
|
|
7526
|
-
voidEl("a:round"),
|
|
7527
|
-
voidEl("a:headEnd", {
|
|
7528
|
-
type: "none",
|
|
7529
|
-
w: "med",
|
|
7530
|
-
len: "med"
|
|
7531
|
-
}),
|
|
7532
|
-
voidEl("a:tailEnd", {
|
|
7533
|
-
type: "none",
|
|
7534
|
-
w: "med",
|
|
7535
|
-
len: "med"
|
|
7536
|
-
})
|
|
7537
|
-
].map(raw));
|
|
7538
|
-
else strXml += el(`a:${obj.name}`, {
|
|
7539
|
-
w: 0,
|
|
7540
|
-
cap,
|
|
7541
|
-
cmpd: "sng",
|
|
7542
|
-
algn: "ctr"
|
|
7543
|
-
}, raw(voidEl("a:noFill")));
|
|
8098
|
+
strXml += genBorderLine(obj.name, border);
|
|
7544
8099
|
});
|
|
8100
|
+
if (diagonal?.tlToBr) strXml += genBorderLine("lnTlToBr", diagonal.tlToBr);
|
|
8101
|
+
if (diagonal?.blToTr) strXml += genBorderLine("lnBlToTr", diagonal.blToTr);
|
|
7545
8102
|
return strXml;
|
|
7546
8103
|
}
|
|
7547
8104
|
//#endregion
|
|
8105
|
+
//#region src/gen/drawingml/table-cell3d.ts
|
|
8106
|
+
/**
|
|
8107
|
+
* Vet one enumerated value before it reaches the XML, reporting and dropping anything outside
|
|
8108
|
+
* its `ST_` union. See `ooxml/check-enum.ts` for why the write path drops rather than throws.
|
|
8109
|
+
*/
|
|
8110
|
+
function resolveEnum(value, valid, field) {
|
|
8111
|
+
return checkEnumOrWarn(value, valid, "table/invalid-cell3d", `table cell: cell3D \`${field}\``, { field });
|
|
8112
|
+
}
|
|
8113
|
+
/**
|
|
8114
|
+
* A bevel dimension in EMU (`ST_PositiveCoordinate`), from a width in points.
|
|
8115
|
+
* A negative or non-finite value cannot be written, so it falls back to the attribute's
|
|
8116
|
+
* own default of 76200 EMU (6pt) rather than emitting something PowerPoint would reject.
|
|
8117
|
+
*/
|
|
8118
|
+
function bevelSizeEmu(points, field) {
|
|
8119
|
+
if (points === void 0 || points === null) return null;
|
|
8120
|
+
if (!Number.isFinite(points) || points < 0) {
|
|
8121
|
+
warnOnce("table/invalid-cell3d", `table cell: cell3D \`${field}\` must be a non-negative number of points; \`${String(points)}\` is ignored.`, {
|
|
8122
|
+
received: points,
|
|
8123
|
+
field
|
|
8124
|
+
});
|
|
8125
|
+
return null;
|
|
8126
|
+
}
|
|
8127
|
+
return valToPts(points);
|
|
8128
|
+
}
|
|
8129
|
+
/**
|
|
8130
|
+
* Emit a cell's `<a:cell3D>`, or `''` when it has none.
|
|
8131
|
+
* @param {TableCell3DProps} [cell3D] - the cell's 3-D options
|
|
8132
|
+
* @return {string} the `a:cell3D` element XML
|
|
8133
|
+
*/
|
|
8134
|
+
function genTableCell3DXml(cell3D) {
|
|
8135
|
+
if (!cell3D || typeof cell3D !== "object") return "";
|
|
8136
|
+
const bevel = voidEl("a:bevel", {
|
|
8137
|
+
w: bevelSizeEmu(cell3D.width, "width"),
|
|
8138
|
+
h: bevelSizeEmu(cell3D.height, "height"),
|
|
8139
|
+
prst: resolveEnum(cell3D.preset, BEVEL_PRESETS, "preset")
|
|
8140
|
+
});
|
|
8141
|
+
const rig = resolveEnum(cell3D.lightRig?.rig, LIGHT_RIGS, "lightRig.rig");
|
|
8142
|
+
const dir = resolveEnum(cell3D.lightRig?.dir, LIGHT_RIG_DIRECTIONS, "lightRig.dir");
|
|
8143
|
+
const lightRig = rig && dir ? voidEl("a:lightRig", {
|
|
8144
|
+
rig,
|
|
8145
|
+
dir
|
|
8146
|
+
}) : "";
|
|
8147
|
+
if (cell3D.lightRig && !lightRig) warnOnce("table/invalid-cell3d", "table cell: cell3D `lightRig` needs both `rig` and `dir` (both are required by CT_LightRig); the light rig is dropped and the bevel takes the renderer default.", { received: cell3D.lightRig });
|
|
8148
|
+
return el("a:cell3D", { prstMaterial: resolveEnum(cell3D.material, PRESET_MATERIALS, "material") }, [raw(bevel), lightRig ? raw(lightRig) : null]);
|
|
8149
|
+
}
|
|
8150
|
+
//#endregion
|
|
7548
8151
|
//#region src/gen/slide/objects/table.ts
|
|
7549
8152
|
/**
|
|
8153
|
+
* Validate a cell's `horzOverflow` before it reaches the XML, reporting and dropping anything
|
|
8154
|
+
* outside `ST_TextHorzOverflowType`. `undefined` (the common case) emits nothing.
|
|
8155
|
+
*/
|
|
8156
|
+
function resolveHorzOverflow(value) {
|
|
8157
|
+
return checkEnumOrWarn(value, TEXT_HORZ_OVERFLOW, "table/invalid-horz-overflow", "table cell: horzOverflow");
|
|
8158
|
+
}
|
|
8159
|
+
/**
|
|
8160
|
+
* Overlay `TableProps.outerBorder` onto one cell's own 4-side border tuple.
|
|
8161
|
+
*
|
|
8162
|
+
* The perimeter is decided per **grid position**, not per authored cell, which is what makes
|
|
8163
|
+
* merges work: a colspan's origin sits at the left of its span and its covered `_hmerge`
|
|
8164
|
+
* cells sit to the right, so a span straddling the last column gets that column's rule on the
|
|
8165
|
+
* covered cell — exactly where PowerPoint defines a merged region's outer edge. A cell in the
|
|
8166
|
+
* table's interior touches no edge and comes back untouched.
|
|
8167
|
+
*
|
|
8168
|
+
* Returns the input array (not a copy) when nothing applies, so the common no-perimeter path
|
|
8169
|
+
* allocates nothing and stays byte-identical. Never mutates: `arrTabRows` holds the caller's
|
|
8170
|
+
* own cell objects and repeated `write()` calls must not accumulate borders.
|
|
8171
|
+
*
|
|
8172
|
+
* @param base - the cell's resolved `[top, right, bottom, left]` borders, or `null` when it has none
|
|
8173
|
+
* @param outer - the normalized perimeter tuple, `undefined` for a side the caller left out
|
|
8174
|
+
* @param at - where this cell sits in the merge grid
|
|
8175
|
+
* @returns the borders to emit, or `null` when there are none and the perimeter adds none
|
|
8176
|
+
*/
|
|
8177
|
+
function applyOuterBorder(base, outer, at) {
|
|
8178
|
+
if (!outer) return base;
|
|
8179
|
+
const onEdge = [
|
|
8180
|
+
at.rIdx === 0,
|
|
8181
|
+
at.cIdx === at.lastCol,
|
|
8182
|
+
at.rIdx === at.lastRow,
|
|
8183
|
+
at.cIdx === 0
|
|
8184
|
+
];
|
|
8185
|
+
const applies = [
|
|
8186
|
+
0,
|
|
8187
|
+
1,
|
|
8188
|
+
2,
|
|
8189
|
+
3
|
|
8190
|
+
].filter((idx) => onEdge[idx] && outer[idx]);
|
|
8191
|
+
if (applies.length === 0) return base;
|
|
8192
|
+
const merged = base ? [...base] : [
|
|
8193
|
+
{ type: "none" },
|
|
8194
|
+
{ type: "none" },
|
|
8195
|
+
{ type: "none" },
|
|
8196
|
+
{ type: "none" }
|
|
8197
|
+
];
|
|
8198
|
+
for (const idx of applies) {
|
|
8199
|
+
const side = outer[idx];
|
|
8200
|
+
if (side) merged[idx] = side;
|
|
8201
|
+
}
|
|
8202
|
+
return merged;
|
|
8203
|
+
}
|
|
8204
|
+
/**
|
|
7550
8205
|
* Render a `table` slide object to its `<p:graphicFrame>` XML (merge-grid, row/col spans, per-cell styling).
|
|
7551
8206
|
*/
|
|
7552
8207
|
function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, itemOpts) {
|
|
@@ -7589,8 +8244,15 @@ function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, item
|
|
|
7589
8244
|
firstCol: objTabOpts.hasFirstColumn ? "1" : null,
|
|
7590
8245
|
lastCol: objTabOpts.hasLastColumn ? "1" : null
|
|
7591
8246
|
};
|
|
7592
|
-
|
|
7593
|
-
|
|
8247
|
+
const tblPrChildren = (objTabOpts.tableFill ? genXmlColorSelection(objTabOpts.tableFill) : "") + (objTabOpts.tableStyle ? el("a:tableStyleId", null, objTabOpts.tableStyle) : "");
|
|
8248
|
+
tblInner = tblPrChildren ? el("a:tblPr", tblPrAttrs, raw(tblPrChildren)) : voidEl("a:tblPr", tblPrAttrs);
|
|
8249
|
+
}
|
|
8250
|
+
const outerBorder = !objTabOpts.outerBorder ? void 0 : Array.isArray(objTabOpts.outerBorder) ? objTabOpts.outerBorder : [
|
|
8251
|
+
objTabOpts.outerBorder,
|
|
8252
|
+
objTabOpts.outerBorder,
|
|
8253
|
+
objTabOpts.outerBorder,
|
|
8254
|
+
objTabOpts.outerBorder
|
|
8255
|
+
];
|
|
7594
8256
|
{
|
|
7595
8257
|
const gridColsEmu = resolveTableColWidthsEmu(objTabOpts.colW, cx, intColCnt);
|
|
7596
8258
|
tblInner += el("a:tblGrid", null, gridColsEmu.map((w) => raw(voidEl("a:gridCol", { w }))));
|
|
@@ -7642,8 +8304,14 @@ function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, item
|
|
|
7642
8304
|
else if (objTabOpts.rowH && !isNaN(Number(objTabOpts.rowH))) intRowH = inch2Emu(Number(objTabOpts.rowH));
|
|
7643
8305
|
else if (itemOpts.cy || itemOpts.h) intRowH = Math.round((itemOpts.h ? cy : typeof itemOpts.cy === "number" ? itemOpts.cy : 1) / arrTabRows.length);
|
|
7644
8306
|
const rowCells = [];
|
|
7645
|
-
cells.forEach((cellObj) => {
|
|
8307
|
+
cells.forEach((cellObj, cIdx) => {
|
|
7646
8308
|
const cell = cellObj;
|
|
8309
|
+
const at = {
|
|
8310
|
+
rIdx,
|
|
8311
|
+
cIdx,
|
|
8312
|
+
lastRow: arrTabRows.length - 1,
|
|
8313
|
+
lastCol: cells.length - 1
|
|
8314
|
+
};
|
|
7647
8315
|
const cellSpanAttrs = {
|
|
7648
8316
|
rowSpan: cell.options?.rowspan && cell.options.rowspan > 1 ? cell.options.rowspan : void 0,
|
|
7649
8317
|
gridSpan: cell.options?.colspan && cell.options.colspan > 1 ? cell.options.colspan : void 0,
|
|
@@ -7652,11 +8320,11 @@ function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, item
|
|
|
7652
8320
|
};
|
|
7653
8321
|
if (cell._hmerge || cell._vmerge) {
|
|
7654
8322
|
const origin = cell._spanOrigin;
|
|
8323
|
+
const originOpts = origin?.options || {};
|
|
7655
8324
|
let spanPrXml = "";
|
|
8325
|
+
const originBorder = applyOuterBorder(Array.isArray(originOpts.border) ? originOpts.border : null, outerBorder, at);
|
|
8326
|
+
if (originBorder) spanPrXml += genTableCellBorderXml(originBorder);
|
|
7656
8327
|
if (origin) {
|
|
7657
|
-
const originOpts = origin.options || {};
|
|
7658
|
-
const originBorder = Array.isArray(originOpts.border) ? originOpts.border : null;
|
|
7659
|
-
if (originBorder) spanPrXml += genTableCellBorderXml(originBorder);
|
|
7660
8328
|
const spanFill = originOpts.fill || "";
|
|
7661
8329
|
if (spanFill) spanPrXml += genXmlColorSelection(spanFill);
|
|
7662
8330
|
}
|
|
@@ -7694,16 +8362,25 @@ function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, item
|
|
|
7694
8362
|
cellMargin
|
|
7695
8363
|
];
|
|
7696
8364
|
if (!Array.isArray(cellMargin) || cellMargin.length !== 4 || cellMargin.some((v) => typeof v !== "number" || !isFinite(v))) cellMargin = DEF_CELL_MARGIN_IN;
|
|
8365
|
+
const cellHorzOverflow = resolveHorzOverflow(cellOpts.horzOverflow);
|
|
7697
8366
|
const tcPrAttrs = {
|
|
7698
8367
|
marL: marginToEmu(cellMargin[3]),
|
|
7699
8368
|
marR: marginToEmu(cellMargin[1]),
|
|
7700
8369
|
marT: marginToEmu(cellMargin[0]),
|
|
7701
8370
|
marB: marginToEmu(cellMargin[2]),
|
|
7702
8371
|
anchor: cellValign,
|
|
7703
|
-
|
|
8372
|
+
anchorCtr: cellOpts.anchorCtr ? "1" : null,
|
|
8373
|
+
vert: cellTextDir,
|
|
8374
|
+
horzOverflow: cellHorzOverflow
|
|
7704
8375
|
};
|
|
7705
|
-
const cellBorder = Array.isArray(cellOpts.border) ? cellOpts.border : null;
|
|
7706
|
-
|
|
8376
|
+
const cellBorder = applyOuterBorder(Array.isArray(cellOpts.border) ? cellOpts.border : null, outerBorder, at);
|
|
8377
|
+
const cellDiagonal = cellOpts.diagonal;
|
|
8378
|
+
const cellBorderXml = cellBorder || cellDiagonal ? genTableCellBorderXml(cellBorder ?? [], cellDiagonal) : "";
|
|
8379
|
+
rowCells.push(el("a:tc", cellSpanAttrs, [raw(genXmlTextBody(cell)), raw(el("a:tcPr", tcPrAttrs, [
|
|
8380
|
+
raw(cellBorderXml),
|
|
8381
|
+
raw(genTableCell3DXml(cellOpts.cell3D)),
|
|
8382
|
+
raw(cellFill)
|
|
8383
|
+
], { closePrefix: " " }))], { closePrefix: " " }));
|
|
7707
8384
|
});
|
|
7708
8385
|
tblInner += el("a:tr", { h: intRowH }, rowCells.map(raw));
|
|
7709
8386
|
});
|
|
@@ -7942,7 +8619,6 @@ function renderZoomObject(slideItemObj, idx, x, y, cx, cy) {
|
|
|
7942
8619
|
}
|
|
7943
8620
|
//#endregion
|
|
7944
8621
|
//#region src/gen/slide/object.ts
|
|
7945
|
-
const PACKAGE_REL_NS$1 = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
7946
8622
|
/** The MS-2007 `media` rel that pairs with an ECMA audio/video/online rel on the same Target. */
|
|
7947
8623
|
const MS_MEDIA_REL = "http://schemas.microsoft.com/office/2007/relationships/media";
|
|
7948
8624
|
/** Slide→chartEx-part relationship type (MS, not the ECMA `.../relationships/chart`). */
|
|
@@ -8153,6 +8829,9 @@ function slideObjectToXml(slide) {
|
|
|
8153
8829
|
case "zoom":
|
|
8154
8830
|
strSlideXml += renderZoomObject(slideItemObj, idx, x, y, cx, cy);
|
|
8155
8831
|
break;
|
|
8832
|
+
case "model3d":
|
|
8833
|
+
strSlideXml += renderModel3dObject(slideItemObj, idx, x, y, cx, cy);
|
|
8834
|
+
break;
|
|
8156
8835
|
case "group": {
|
|
8157
8836
|
const groupChildren = slideItemObj._groupObjects || [];
|
|
8158
8837
|
let innerXml = "";
|
|
@@ -8204,9 +8883,7 @@ function slideObjectToXml(slide) {
|
|
|
8204
8883
|
strSlideXml += "</p:grpSp>";
|
|
8205
8884
|
break;
|
|
8206
8885
|
}
|
|
8207
|
-
default:
|
|
8208
|
-
strSlideXml += "";
|
|
8209
|
-
break;
|
|
8886
|
+
default: strSlideXml += "";
|
|
8210
8887
|
}
|
|
8211
8888
|
return strSlideXml;
|
|
8212
8889
|
};
|
|
@@ -8303,12 +8980,12 @@ function slideObjectRelationsToXml(slide, defaultRels) {
|
|
|
8303
8980
|
lastRid = Math.max(lastRid, rel.rId);
|
|
8304
8981
|
if (isHyperlinkRel(rel)) if (rel.data === "slide") rels.push(voidEl("Relationship", {
|
|
8305
8982
|
Id: `rId${rel.rId}`,
|
|
8306
|
-
Type: "
|
|
8983
|
+
Type: OFFICE_REL + "slide",
|
|
8307
8984
|
Target: `slide${rel.Target}.xml`
|
|
8308
8985
|
}));
|
|
8309
8986
|
else rels.push(voidEl("Relationship", {
|
|
8310
8987
|
Id: `rId${rel.rId}`,
|
|
8311
|
-
Type: "
|
|
8988
|
+
Type: OFFICE_REL + "hyperlink",
|
|
8312
8989
|
Target: rel.Target,
|
|
8313
8990
|
TargetMode: "External"
|
|
8314
8991
|
}));
|
|
@@ -8317,7 +8994,7 @@ function slideObjectRelationsToXml(slide, defaultRels) {
|
|
|
8317
8994
|
lastRid = Math.max(lastRid, rel.rId);
|
|
8318
8995
|
rels.push(voidEl("Relationship", {
|
|
8319
8996
|
Id: `rId${rel.rId}`,
|
|
8320
|
-
Type: rel.isChartEx ? CHARTEX_REL : "
|
|
8997
|
+
Type: rel.isChartEx ? CHARTEX_REL : OFFICE_REL + "chart",
|
|
8321
8998
|
Target: rel.Target
|
|
8322
8999
|
}));
|
|
8323
9000
|
});
|
|
@@ -8332,10 +9009,11 @@ function slideObjectRelationsToXml(slide, defaultRels) {
|
|
|
8332
9009
|
});
|
|
8333
9010
|
lastRid = Math.max(lastRid, rel.rId);
|
|
8334
9011
|
if (rel.oleRelType) rels.push(media(rel.oleRelType));
|
|
8335
|
-
else if (
|
|
8336
|
-
else if (relType.includes("
|
|
8337
|
-
else if (relType.includes("
|
|
8338
|
-
else if (relType.includes("
|
|
9012
|
+
else if (rel.model3dRelType) rels.push(media(rel.model3dRelType));
|
|
9013
|
+
else if (relType.includes("image")) rels.push(media(OFFICE_REL + "image"));
|
|
9014
|
+
else if (relType.includes("audio")) rels.push(hasTarget(relTarget) ? media(MS_MEDIA_REL) : media(OFFICE_REL + "audio"));
|
|
9015
|
+
else if (relType.includes("video")) rels.push(hasTarget(relTarget) ? media(MS_MEDIA_REL) : media(OFFICE_REL + "video"));
|
|
9016
|
+
else if (relType.includes("online")) rels.push(hasTarget(relTarget) ? media(MS_MEDIA_REL, "External") : media(OFFICE_REL + "video", "External"));
|
|
8339
9017
|
});
|
|
8340
9018
|
defaultRels.forEach((rel, idx) => {
|
|
8341
9019
|
rels.push(voidEl("Relationship", {
|
|
@@ -8344,7 +9022,7 @@ function slideObjectRelationsToXml(slide, defaultRels) {
|
|
|
8344
9022
|
Target: rel.target
|
|
8345
9023
|
}));
|
|
8346
9024
|
});
|
|
8347
|
-
return XML_DECL + "\r\n" + el("Relationships", { xmlns: PACKAGE_REL_NS
|
|
9025
|
+
return XML_DECL + "\r\n" + el("Relationships", { xmlns: PACKAGE_REL_NS }, rels.map(raw));
|
|
8348
9026
|
}
|
|
8349
9027
|
//#endregion
|
|
8350
9028
|
//#region src/gen/slide/slide.ts
|
|
@@ -8422,7 +9100,6 @@ function getLayoutIdxForSlide(slides, slideLayouts, slideNumber) {
|
|
|
8422
9100
|
}
|
|
8423
9101
|
//#endregion
|
|
8424
9102
|
//#region src/gen/slide/notes.ts
|
|
8425
|
-
const PACKAGE_REL_NS = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
8426
9103
|
/**
|
|
8427
9104
|
* Collect the speaker-notes runs for a slide (flattened across any number of `addNotes()` calls).
|
|
8428
9105
|
* @param {PresSlideInternal} slide - the slide object
|
|
@@ -8906,19 +9583,19 @@ function makeXmlNotesSlide(slide) {
|
|
|
8906
9583
|
function makeXmlNotesSlideRel(slide, slideNumber) {
|
|
8907
9584
|
const hlinkRels = buildNotesSlideRels(slide).map((rel) => voidEl("Relationship", {
|
|
8908
9585
|
Id: `rId${rel.rId}`,
|
|
8909
|
-
Type: "
|
|
9586
|
+
Type: OFFICE_REL + "hyperlink",
|
|
8910
9587
|
Target: rel.Target,
|
|
8911
9588
|
TargetMode: "External"
|
|
8912
9589
|
})).join("");
|
|
8913
9590
|
return XML_DECL + el("Relationships", { xmlns: PACKAGE_REL_NS }, [
|
|
8914
9591
|
raw(voidEl("Relationship", {
|
|
8915
9592
|
Id: "rId1",
|
|
8916
|
-
Type: "
|
|
9593
|
+
Type: OFFICE_REL + "notesMaster",
|
|
8917
9594
|
Target: "../notesMasters/notesMaster1.xml"
|
|
8918
9595
|
})),
|
|
8919
9596
|
raw(voidEl("Relationship", {
|
|
8920
9597
|
Id: "rId2",
|
|
8921
|
-
Type: "
|
|
9598
|
+
Type: OFFICE_REL + "slide",
|
|
8922
9599
|
Target: `../slides/slide${slideNumber}.xml`
|
|
8923
9600
|
})),
|
|
8924
9601
|
raw(hlinkRels)
|
|
@@ -8935,7 +9612,7 @@ function makeXmlNotesSlideRel(slide, slideNumber) {
|
|
|
8935
9612
|
function makeXmlNotesMasterRel() {
|
|
8936
9613
|
return XML_DECL + "\r\n" + el("Relationships", { xmlns: PACKAGE_REL_NS }, raw(voidEl("Relationship", {
|
|
8937
9614
|
Id: "rId1",
|
|
8938
|
-
Type: "
|
|
9615
|
+
Type: OFFICE_REL + "theme",
|
|
8939
9616
|
Target: "../theme/theme2.xml"
|
|
8940
9617
|
})), {
|
|
8941
9618
|
childPrefix: "\n ",
|
|
@@ -9421,11 +10098,10 @@ function makeXmlCustomProperties(props) {
|
|
|
9421
10098
|
* Emit the package root relationships (app/core/presentation, plus custom-props
|
|
9422
10099
|
* when present).
|
|
9423
10100
|
*/
|
|
9424
|
-
const SCHEMA_BASE = "http://schemas.openxmlformats.org/";
|
|
9425
10101
|
function relationship$1(id, type, target) {
|
|
9426
10102
|
return voidEl("Relationship", {
|
|
9427
10103
|
Id: id,
|
|
9428
|
-
Type:
|
|
10104
|
+
Type: type,
|
|
9429
10105
|
Target: target
|
|
9430
10106
|
}, { openPrefix: "\n " });
|
|
9431
10107
|
}
|
|
@@ -9434,11 +10110,11 @@ function relationship$1(id, type, target) {
|
|
|
9434
10110
|
* @returns XML
|
|
9435
10111
|
*/
|
|
9436
10112
|
function makeXmlRootRels(hasCustomProps) {
|
|
9437
|
-
return XML_DECL + "\r\n" + el("Relationships", { xmlns:
|
|
9438
|
-
raw(relationship$1("rId1", "
|
|
9439
|
-
raw(relationship$1("rId2", "
|
|
9440
|
-
raw(relationship$1("rId3", "officeDocument
|
|
9441
|
-
hasCustomProps ? raw(relationship$1("rId4", "
|
|
10113
|
+
return XML_DECL + "\r\n" + el("Relationships", { xmlns: PACKAGE_REL_NS }, [
|
|
10114
|
+
raw(relationship$1("rId1", OFFICE_REL + "extended-properties", "docProps/app.xml")),
|
|
10115
|
+
raw(relationship$1("rId2", PACKAGE_REL_NS + "/metadata/core-properties", "docProps/core.xml")),
|
|
10116
|
+
raw(relationship$1("rId3", OFFICE_REL + "officeDocument", "ppt/presentation.xml")),
|
|
10117
|
+
hasCustomProps ? raw(relationship$1("rId4", OFFICE_REL + "custom-properties", "docProps/custom.xml")) : null
|
|
9442
10118
|
], { closePrefix: "\n " });
|
|
9443
10119
|
}
|
|
9444
10120
|
//#endregion
|
|
@@ -9478,13 +10154,13 @@ function presentationFontRelStart(slides) {
|
|
|
9478
10154
|
}
|
|
9479
10155
|
function makeXmlPresentationRels(slides, embeddedFonts) {
|
|
9480
10156
|
let intRelNum = 1;
|
|
9481
|
-
const rels = [relationship(1, "
|
|
9482
|
-
for (let idx = 1; idx <= slides.length; idx++) rels.push(relationship(++intRelNum, "
|
|
10157
|
+
const rels = [relationship(1, OFFICE_REL + "slideMaster", "slideMasters/slideMaster1.xml")];
|
|
10158
|
+
for (let idx = 1; idx <= slides.length; idx++) rels.push(relationship(++intRelNum, OFFICE_REL + "slide", `slides/slide${idx}.xml`));
|
|
9483
10159
|
intRelNum++;
|
|
9484
|
-
rels.push(relationship(intRelNum + 0, "
|
|
9485
|
-
if ((slides || []).some((slide) => (slide._comments || []).length > 0)) rels.push(relationship(intRelNum + 5, "
|
|
10160
|
+
rels.push(relationship(intRelNum + 0, OFFICE_REL + "notesMaster", "notesMasters/notesMaster1.xml"), relationship(intRelNum + 1, OFFICE_REL + "presProps", "presProps.xml"), relationship(intRelNum + 2, OFFICE_REL + "viewProps", "viewProps.xml"), relationship(intRelNum + 3, OFFICE_REL + "theme", "theme/theme1.xml"), relationship(intRelNum + 4, OFFICE_REL + "tableStyles", "tableStyles.xml"));
|
|
10161
|
+
if ((slides || []).some((slide) => (slide._comments || []).length > 0)) rels.push(relationship(intRelNum + 5, OFFICE_REL + "commentAuthors", "commentAuthors.xml"));
|
|
9486
10162
|
for (const face of flattenEmbeddedFaces(embeddedFonts || [], presentationFontRelStart(slides))) rels.push(relationship(face.rId, FONT_REL_TYPE, `fonts/font${face.partIndex}.fntdata`));
|
|
9487
|
-
return XML_DECL + "\r\n" + el("Relationships", { xmlns:
|
|
10163
|
+
return XML_DECL + "\r\n" + el("Relationships", { xmlns: PACKAGE_REL_NS }, rels.map(raw));
|
|
9488
10164
|
}
|
|
9489
10165
|
//#endregion
|
|
9490
10166
|
//#region src/gen/pres/presentation.ts
|
|
@@ -9614,79 +10290,11 @@ function makeXmlViewProps() {
|
|
|
9614
10290
|
* @see: http://openxmldeveloper.org/discussions/formats/f/13/p/2398/8107.aspx
|
|
9615
10291
|
* @return {string} XML
|
|
9616
10292
|
*/
|
|
9617
|
-
function makeXmlTableStyles(
|
|
9618
|
-
|
|
10293
|
+
function makeXmlTableStyles() {
|
|
10294
|
+
return XML_DECL + "\r\n" + voidEl("a:tblStyleLst", {
|
|
9619
10295
|
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
|
9620
10296
|
def: "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}"
|
|
9621
|
-
};
|
|
9622
|
-
if (!tableStyles || tableStyles.length === 0) return XML_DECL + "\r\n" + voidEl("a:tblStyleLst", attrs);
|
|
9623
|
-
return XML_DECL + "\r\n" + el("a:tblStyleLst", attrs, tableStyles.map(({ guid, def }) => raw(el("a:tblStyle", {
|
|
9624
|
-
styleId: guid,
|
|
9625
|
-
styleName: def.name
|
|
9626
|
-
}, [
|
|
9627
|
-
["wholeTbl", def.wholeTbl],
|
|
9628
|
-
["band1H", def.band1H],
|
|
9629
|
-
["band2H", def.band2H],
|
|
9630
|
-
["band1V", def.band1V],
|
|
9631
|
-
["band2V", def.band2V],
|
|
9632
|
-
["lastCol", def.lastCol],
|
|
9633
|
-
["firstCol", def.firstCol],
|
|
9634
|
-
["lastRow", def.lastRow],
|
|
9635
|
-
["firstRow", def.firstRow]
|
|
9636
|
-
].map(([name, region]) => region ? raw(genXmlTableStyleRegion(name, region)) : null)))));
|
|
9637
|
-
}
|
|
9638
|
-
/**
|
|
9639
|
-
* Build one `CT_TablePartStyle` region (e.g. `firstRow`, `band1H`) for a custom table style.
|
|
9640
|
-
* Emits `tcTxStyle` (text) before `tcStyle` (cell fill/borders) per the schema sequence.
|
|
9641
|
-
* @param {string} name - region element name
|
|
9642
|
-
* @param {TableStyleRegionProps} region - region styling
|
|
9643
|
-
* @return {string} XML
|
|
9644
|
-
*/
|
|
9645
|
-
function genXmlTableStyleRegion(name, region) {
|
|
9646
|
-
const children = [region.bold !== void 0 || region.italic !== void 0 || region.color ? raw(el("a:tcTxStyle", {
|
|
9647
|
-
b: region.bold ? "on" : null,
|
|
9648
|
-
i: region.italic ? "on" : null
|
|
9649
|
-
}, [raw(voidEl("a:fontRef", { idx: "minor" })), region.color ? raw(createColorElement(region.color)) : null])) : null, region.border !== void 0 || region.fill !== void 0 ? raw(el("a:tcStyle", null, [region.border !== void 0 ? raw(genXmlTableStyleBorders(region.border)) : null, region.fill !== void 0 ? raw(el("a:fill", null, raw(genXmlColorSelection(region.fill)))) : null])) : null];
|
|
9650
|
-
return el(`a:${name}`, null, children);
|
|
9651
|
-
}
|
|
9652
|
-
/**
|
|
9653
|
-
* Build the `tcBdr` border block for a custom table style region.
|
|
9654
|
-
* A single `BorderProps` styles all four sides plus the interior grid lines; a
|
|
9655
|
-
* TRBL array styles only the four outer sides. Sides are emitted in schema order.
|
|
9656
|
-
* @param {BorderProps | BorderProps[]} border - border definition
|
|
9657
|
-
* @return {string} XML
|
|
9658
|
-
*/
|
|
9659
|
-
function genXmlTableStyleBorders(border) {
|
|
9660
|
-
let sides;
|
|
9661
|
-
if (Array.isArray(border)) {
|
|
9662
|
-
const [top, right, bottom, left] = border;
|
|
9663
|
-
sides = [
|
|
9664
|
-
["left", left],
|
|
9665
|
-
["right", right],
|
|
9666
|
-
["top", top],
|
|
9667
|
-
["bottom", bottom]
|
|
9668
|
-
];
|
|
9669
|
-
} else sides = [
|
|
9670
|
-
["left", border],
|
|
9671
|
-
["right", border],
|
|
9672
|
-
["top", border],
|
|
9673
|
-
["bottom", border],
|
|
9674
|
-
["insideH", border],
|
|
9675
|
-
["insideV", border]
|
|
9676
|
-
];
|
|
9677
|
-
return el("a:tcBdr", null, sides.map(([side, b]) => {
|
|
9678
|
-
if (!b) return null;
|
|
9679
|
-
if (b.type === "none") return raw(el(`a:${side}`, null, raw(el("a:ln", null, raw(voidEl("a:noFill"))))));
|
|
9680
|
-
return raw(el(`a:${side}`, null, raw(el("a:ln", {
|
|
9681
|
-
w: lineWidthToEmu(resolveBorderWidth(b, 1)),
|
|
9682
|
-
cap: "flat",
|
|
9683
|
-
cmpd: "sng",
|
|
9684
|
-
algn: "ctr"
|
|
9685
|
-
}, [raw(genXmlColorSelection({
|
|
9686
|
-
color: b.color ?? "666666",
|
|
9687
|
-
transparency: b.transparency
|
|
9688
|
-
})), raw(voidEl("a:prstDash", { val: b.type === "dash" ? "sysDash" : "solid" }))]))));
|
|
9689
|
-
}));
|
|
10297
|
+
});
|
|
9690
10298
|
}
|
|
9691
10299
|
//#endregion
|
|
9692
10300
|
//#region src/gen/slide/comments.ts
|
|
@@ -10280,18 +10888,14 @@ function createChartMediaRels(slide, zip, chartPromises) {
|
|
|
10280
10888
|
async function buildPackageParts(source, props) {
|
|
10281
10889
|
const pres = source.presentation;
|
|
10282
10890
|
const arrChartPromises = [];
|
|
10283
|
-
let arrMediaPromises = [];
|
|
10284
10891
|
const zip = new ZipWriter();
|
|
10285
10892
|
registerTransitionSounds(pres.slides);
|
|
10286
10893
|
const onMediaError = props.onMediaError ?? "throw";
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
});
|
|
10293
|
-
arrMediaPromises = arrMediaPromises.concat(encodeSlideMediaRels(pres.masterSlide, source.runtime, onMediaError));
|
|
10294
|
-
return await Promise.all(arrMediaPromises).then(async () => {
|
|
10894
|
+
return await encodeMediaForTargets([
|
|
10895
|
+
...pres.slides,
|
|
10896
|
+
...pres.slideLayouts,
|
|
10897
|
+
pres.masterSlide
|
|
10898
|
+
], source.runtime, onMediaError).then(async () => {
|
|
10295
10899
|
const canonicalMediaTargets = /* @__PURE__ */ new Map();
|
|
10296
10900
|
for (const target of [
|
|
10297
10901
|
...pres.slides,
|
|
@@ -10317,10 +10921,7 @@ async function buildPackageParts(source, props) {
|
|
|
10317
10921
|
rel.fileName = `${chartBase}.xml`;
|
|
10318
10922
|
rel.Target = `/ppt/charts/${chartBase}.xml`;
|
|
10319
10923
|
}
|
|
10320
|
-
pres.slides.
|
|
10321
|
-
if (slide._slideLayout) addPlaceholdersToSlideLayouts(slide);
|
|
10322
|
-
});
|
|
10323
|
-
applyMeasuredFit(pres.slides, source.fontMetrics);
|
|
10924
|
+
bakeSlideContent(pres.slides, source.fontMetrics);
|
|
10324
10925
|
const hasCustomProps = source.customProperties.length > 0;
|
|
10325
10926
|
zip.add("[Content_Types].xml", makeXmlContTypes(pres.slides, pres.slideLayouts, pres.masterSlide, hasCustomProps, pres.embeddedFonts));
|
|
10326
10927
|
zip.add("_rels/.rels", makeXmlRootRels(hasCustomProps));
|
|
@@ -10333,7 +10934,7 @@ async function buildPackageParts(source, props) {
|
|
|
10333
10934
|
zip.add("ppt/theme/theme2.xml", makeXmlTheme(pres));
|
|
10334
10935
|
zip.add("ppt/presentation.xml", makeXmlPresentation(pres));
|
|
10335
10936
|
zip.add("ppt/presProps.xml", makeXmlPresProps());
|
|
10336
|
-
zip.add("ppt/tableStyles.xml", makeXmlTableStyles(
|
|
10937
|
+
zip.add("ppt/tableStyles.xml", makeXmlTableStyles());
|
|
10337
10938
|
zip.add("ppt/viewProps.xml", makeXmlViewProps());
|
|
10338
10939
|
pres.slideLayouts.forEach((layout, idx) => {
|
|
10339
10940
|
zip.add(`ppt/slideLayouts/slideLayout${idx + 1}.xml`, makeXmlLayout(layout));
|
|
@@ -10391,60 +10992,20 @@ async function writePackage(source, props) {
|
|
|
10391
10992
|
//#endregion
|
|
10392
10993
|
//#region src/presentation.ts
|
|
10393
10994
|
/**
|
|
10394
|
-
*
|
|
10395
|
-
*
|
|
10396
|
-
* TypeScript/ESM library that creates PowerPoint (pptx) presentations
|
|
10397
|
-
* https://github.com/gitbrent/PptxGenJS
|
|
10398
|
-
*
|
|
10399
|
-
* This framework is released under the MIT Public License (MIT)
|
|
10995
|
+
* ts-pptx: the presentation core
|
|
10400
10996
|
*
|
|
10401
|
-
*
|
|
10997
|
+
* Home of {@link PresentationCore}, the class every entry point subclasses with a runtime
|
|
10998
|
+
* adapter (`index.ts`, `node.ts`, `browser.ts`). See the class doc below for the layout of
|
|
10999
|
+
* its body and where package assembly actually happens.
|
|
10402
11000
|
*
|
|
10403
|
-
*
|
|
10404
|
-
*
|
|
11001
|
+
* Units: this library takes user coordinates in inches and converts to EMU on output — see
|
|
11002
|
+
* `units.ts` for the conversions and `STANDARD_LAYOUTS` for the built-in slide sizes.
|
|
10405
11003
|
*
|
|
10406
|
-
*
|
|
10407
|
-
*
|
|
10408
|
-
*
|
|
10409
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10410
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
10411
|
-
* furnished to do so, subject to the following conditions:
|
|
10412
|
-
*
|
|
10413
|
-
* The above copyright notice and this permission notice shall be included in all
|
|
10414
|
-
* copies or substantial portions of the Software.
|
|
10415
|
-
*
|
|
10416
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
10417
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
10418
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
10419
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
10420
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
10421
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
10422
|
-
* SOFTWARE.
|
|
11004
|
+
* Derived from PptxGenJS (C) 2015-present Brent Ely (MIT), which in turn took some code from
|
|
11005
|
+
* the OfficeGen project (Copyright 2013 Ziv Barber). This project is likewise MIT; the full
|
|
11006
|
+
* license text is in `LICENSE` at the repository root.
|
|
10423
11007
|
*/
|
|
10424
|
-
|
|
10425
|
-
* Units of Measure used in PowerPoint documents
|
|
10426
|
-
*
|
|
10427
|
-
* PowerPoint (DrawingML) positions and sizes shapes in `EMU`; font sizing is in points.
|
|
10428
|
-
* This library takes user coordinates in inches and converts to EMU on output.
|
|
10429
|
-
* - 914400 EMUs is 1 inch
|
|
10430
|
-
* - 12700 EMUs is 1 point
|
|
10431
|
-
* - 72 points is 1 inch
|
|
10432
|
-
*
|
|
10433
|
-
* @see https://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/
|
|
10434
|
-
*/
|
|
10435
|
-
/**
|
|
10436
|
-
* Object Layouts
|
|
10437
|
-
*
|
|
10438
|
-
* - 16x9 (10" x 5.625")
|
|
10439
|
-
* - 16x10 (10" x 6.25")
|
|
10440
|
-
* - 4x3 (10" x 7.5")
|
|
10441
|
-
* - Wide (13.33" x 7.5")
|
|
10442
|
-
* - [custom] (any size)
|
|
10443
|
-
*
|
|
10444
|
-
* @see https://docs.microsoft.com/en-us/office/open-xml/structure-of-a-presentationml-document
|
|
10445
|
-
* @see https://docs.microsoft.com/en-us/previous-versions/office/developer/office-2010/hh273476(v=office.14)
|
|
10446
|
-
*/
|
|
10447
|
-
const VERSION = "1.0.0";
|
|
11008
|
+
const VERSION = "3.0.0";
|
|
10448
11009
|
function standardLayoutToPresLayout(layout) {
|
|
10449
11010
|
return {
|
|
10450
11011
|
name: layout.name,
|
|
@@ -10600,7 +11161,6 @@ var PresentationCore = class {
|
|
|
10600
11161
|
}
|
|
10601
11162
|
/** custom document properties stored in docProps/custom.xml */
|
|
10602
11163
|
_customProperties;
|
|
10603
|
-
_tableStyles;
|
|
10604
11164
|
/**
|
|
10605
11165
|
* slide layout definition objects, used for generating slide layout files.
|
|
10606
11166
|
* `protected` (not `private`) so the browser entry subclass can resolve
|
|
@@ -10679,7 +11239,6 @@ var PresentationCore = class {
|
|
|
10679
11239
|
this._slides = [];
|
|
10680
11240
|
this._sections = [];
|
|
10681
11241
|
this._customProperties = [];
|
|
10682
|
-
this._tableStyles = [];
|
|
10683
11242
|
this._masterSlide = {
|
|
10684
11243
|
addChart: null,
|
|
10685
11244
|
addComment: null,
|
|
@@ -10746,7 +11305,6 @@ var PresentationCore = class {
|
|
|
10746
11305
|
runtime: this._runtime,
|
|
10747
11306
|
presentation: this.internalPresentation,
|
|
10748
11307
|
customProperties: this._customProperties,
|
|
10749
|
-
tableStyles: this._tableStyles,
|
|
10750
11308
|
fontMetrics: this._fontMetrics
|
|
10751
11309
|
};
|
|
10752
11310
|
}
|
|
@@ -10766,15 +11324,8 @@ var PresentationCore = class {
|
|
|
10766
11324
|
*/
|
|
10767
11325
|
extractSlides = async (opts = {}) => {
|
|
10768
11326
|
const onMediaError = opts.onMediaError ?? "throw";
|
|
10769
|
-
|
|
10770
|
-
this._slides.
|
|
10771
|
-
mediaPromises = mediaPromises.concat(encodeSlideMediaRels(slide, this._runtime, onMediaError));
|
|
10772
|
-
});
|
|
10773
|
-
await Promise.all(mediaPromises);
|
|
10774
|
-
this._slides.forEach((slide) => {
|
|
10775
|
-
if (slide._slideLayout) addPlaceholdersToSlideLayouts(slide);
|
|
10776
|
-
});
|
|
10777
|
-
applyMeasuredFit(this._slides, this._fontMetrics);
|
|
11327
|
+
await encodeMediaForTargets(this._slides, this._runtime, onMediaError);
|
|
11328
|
+
bakeSlideContent(this._slides, this._fontMetrics);
|
|
10778
11329
|
const slides = this._slides.map((slide) => {
|
|
10779
11330
|
const relByRid = new Map(slide._relsMedia.map((rel) => [rel.rId, rel]));
|
|
10780
11331
|
const avPreviewRids = /* @__PURE__ */ new Set();
|
|
@@ -11193,32 +11744,139 @@ var PresentationCore = class {
|
|
|
11193
11744
|
if (propsClone.background) addBackgroundDefinition(propsClone.background, newLayout);
|
|
11194
11745
|
if (newLayout._slideNumberProps && !this._masterSlide._slideNumberProps) this._masterSlide._slideNumberProps = newLayout._slideNumberProps;
|
|
11195
11746
|
}
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
|
|
11747
|
+
};
|
|
11748
|
+
//#endregion
|
|
11749
|
+
//#region src/clip.ts
|
|
11750
|
+
const HALF_DISC = {
|
|
11751
|
+
deep: {
|
|
11752
|
+
topEdgeX: .31788,
|
|
11753
|
+
botEdgeX: .31788,
|
|
11754
|
+
tipTopX: .30061,
|
|
11755
|
+
tipTopY: .01078,
|
|
11756
|
+
tipBotX: .30061,
|
|
11757
|
+
tipBotY: .98922,
|
|
11758
|
+
apexY: .5,
|
|
11759
|
+
c1b: {
|
|
11760
|
+
x: .11594,
|
|
11761
|
+
y: .86833
|
|
11762
|
+
},
|
|
11763
|
+
c2b: {
|
|
11764
|
+
x: 0,
|
|
11765
|
+
y: .69392
|
|
11766
|
+
},
|
|
11767
|
+
c1t: {
|
|
11768
|
+
x: 0,
|
|
11769
|
+
y: .30609
|
|
11770
|
+
},
|
|
11771
|
+
c2t: {
|
|
11772
|
+
x: .11594,
|
|
11773
|
+
y: .13167
|
|
11774
|
+
}
|
|
11775
|
+
},
|
|
11776
|
+
shallow: {
|
|
11777
|
+
topEdgeX: .12611,
|
|
11778
|
+
botEdgeX: .11128,
|
|
11779
|
+
tipTopX: .09976,
|
|
11780
|
+
tipTopY: .05448,
|
|
11781
|
+
tipBotX: .09976,
|
|
11782
|
+
tipBotY: .97617,
|
|
11783
|
+
apexY: .51533,
|
|
11784
|
+
c1b: {
|
|
11785
|
+
x: .03522,
|
|
11786
|
+
y: .83247
|
|
11787
|
+
},
|
|
11788
|
+
c2b: {
|
|
11789
|
+
x: 0,
|
|
11790
|
+
y: .67725
|
|
11791
|
+
},
|
|
11792
|
+
c1t: {
|
|
11793
|
+
x: 0,
|
|
11794
|
+
y: .3534
|
|
11795
|
+
},
|
|
11796
|
+
c2t: {
|
|
11797
|
+
x: .03522,
|
|
11798
|
+
y: .19818
|
|
11799
|
+
}
|
|
11220
11800
|
}
|
|
11221
11801
|
};
|
|
11802
|
+
/**
|
|
11803
|
+
* Half-disc clip path for a `w × h` box. Authored flat-right; `flat: 'left'` mirrors `x → 1 - x`.
|
|
11804
|
+
*/
|
|
11805
|
+
function halfDisc(w, h, flat, preset) {
|
|
11806
|
+
const s = HALF_DISC[preset];
|
|
11807
|
+
const fx = flat === "left" ? (x) => (1 - x) * w : (x) => x * w;
|
|
11808
|
+
const fy = (y) => y * h;
|
|
11809
|
+
return [
|
|
11810
|
+
{
|
|
11811
|
+
x: fx(s.topEdgeX),
|
|
11812
|
+
y: fy(0),
|
|
11813
|
+
moveTo: true
|
|
11814
|
+
},
|
|
11815
|
+
{
|
|
11816
|
+
x: fx(1),
|
|
11817
|
+
y: fy(0)
|
|
11818
|
+
},
|
|
11819
|
+
{
|
|
11820
|
+
x: fx(1),
|
|
11821
|
+
y: fy(1)
|
|
11822
|
+
},
|
|
11823
|
+
{
|
|
11824
|
+
x: fx(s.botEdgeX),
|
|
11825
|
+
y: fy(1)
|
|
11826
|
+
},
|
|
11827
|
+
{
|
|
11828
|
+
x: fx(s.tipBotX),
|
|
11829
|
+
y: fy(s.tipBotY)
|
|
11830
|
+
},
|
|
11831
|
+
{
|
|
11832
|
+
x: fx(0),
|
|
11833
|
+
y: fy(s.apexY),
|
|
11834
|
+
curve: {
|
|
11835
|
+
type: "cubic",
|
|
11836
|
+
x1: fx(s.c1b.x),
|
|
11837
|
+
y1: fy(s.c1b.y),
|
|
11838
|
+
x2: fx(s.c2b.x),
|
|
11839
|
+
y2: fy(s.c2b.y)
|
|
11840
|
+
}
|
|
11841
|
+
},
|
|
11842
|
+
{
|
|
11843
|
+
x: fx(s.tipTopX),
|
|
11844
|
+
y: fy(s.tipTopY),
|
|
11845
|
+
curve: {
|
|
11846
|
+
type: "cubic",
|
|
11847
|
+
x1: fx(s.c1t.x),
|
|
11848
|
+
y1: fy(s.c1t.y),
|
|
11849
|
+
x2: fx(s.c2t.x),
|
|
11850
|
+
y2: fy(s.c2t.y)
|
|
11851
|
+
}
|
|
11852
|
+
},
|
|
11853
|
+
{ close: true }
|
|
11854
|
+
];
|
|
11855
|
+
}
|
|
11856
|
+
/**
|
|
11857
|
+
* Resolve a {@link ClipShape} to a freeform `points` path filling a `w × h` box, ready to hand
|
|
11858
|
+
* to `addImage({ points })`.
|
|
11859
|
+
*
|
|
11860
|
+
* `w`/`h` are the image box's size **in inches** and must match the `w`/`h` the picture is drawn
|
|
11861
|
+
* at — the path is emitted in the box's own coordinate space, not normalized (see the module
|
|
11862
|
+
* note above).
|
|
11863
|
+
* @param {ClipShape} shape - the named silhouette and its options
|
|
11864
|
+
* @param {number} w - image box width (inches)
|
|
11865
|
+
* @param {number} h - image box height (inches)
|
|
11866
|
+
* @returns {GeometryPoint[]} the freeform path, for `addImage({ points })`
|
|
11867
|
+
* @example
|
|
11868
|
+
* const w = 5.22, h = 7.5
|
|
11869
|
+
* slide.addImage({
|
|
11870
|
+
* path: 'cover.jpg', x: 0, y: 0, w, h,
|
|
11871
|
+
* points: clipPath({ kind: 'half-disc', flat: 'right' }, w, h),
|
|
11872
|
+
* sizing: { type: 'cover' }, // center-crop the photo into the "D"
|
|
11873
|
+
* })
|
|
11874
|
+
*/
|
|
11875
|
+
function clipPath(shape, w, h) {
|
|
11876
|
+
switch (shape.kind) {
|
|
11877
|
+
case "half-disc": return halfDisc(w, h, shape.flat, shape.preset ?? "deep");
|
|
11878
|
+
}
|
|
11879
|
+
}
|
|
11222
11880
|
//#endregion
|
|
11223
11881
|
//#region src/types/text.ts
|
|
11224
11882
|
/** Factory for a single inline text run. Prevents `as never` casts when building mixed-style run arrays. */
|
|
@@ -11233,6 +11891,6 @@ function textRuns(runs) {
|
|
|
11233
11891
|
return runs;
|
|
11234
11892
|
}
|
|
11235
11893
|
//#endregion
|
|
11236
|
-
export { textRuns as n,
|
|
11894
|
+
export { PresentationCore as i, textRuns as n, clipPath as r, textRun as t };
|
|
11237
11895
|
|
|
11238
|
-
//# sourceMappingURL=text-
|
|
11896
|
+
//# sourceMappingURL=text-120VFSDm.js.map
|