@hirokisakabe/pom 9.1.2 → 10.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/dist/buildContext.js +2 -2
- package/dist/buildContext.js.map +1 -1
- package/dist/buildPptx.d.ts +2 -1
- package/dist/buildPptx.d.ts.map +1 -1
- package/dist/buildPptx.js +4 -3
- package/dist/buildPptx.js.map +1 -1
- package/dist/calcYogaLayout/calcYogaLayout.js +1 -1
- package/dist/calcYogaLayout/calcYogaLayout.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/registry/definitions/icon.js +1 -1
- package/dist/registry/definitions/list.js.map +1 -1
- package/dist/renderPptx/nodes/chart.js +172 -47
- package/dist/renderPptx/nodes/chart.js.map +1 -1
- package/dist/renderPptx/nodes/flow.js +4 -1
- package/dist/renderPptx/nodes/flow.js.map +1 -1
- package/dist/renderPptx/nodes/icon.js +5 -2
- package/dist/renderPptx/nodes/icon.js.map +1 -1
- package/dist/renderPptx/nodes/list.js +7 -9
- package/dist/renderPptx/nodes/list.js.map +1 -1
- package/dist/renderPptx/nodes/matrix.js +4 -1
- package/dist/renderPptx/nodes/matrix.js.map +1 -1
- package/dist/renderPptx/nodes/processArrow.js +8 -2
- package/dist/renderPptx/nodes/processArrow.js.map +1 -1
- package/dist/renderPptx/nodes/pyramid.js +4 -1
- package/dist/renderPptx/nodes/pyramid.js.map +1 -1
- package/dist/renderPptx/nodes/shape.js +5 -2
- package/dist/renderPptx/nodes/shape.js.map +1 -1
- package/dist/renderPptx/nodes/table.js +89 -59
- package/dist/renderPptx/nodes/table.js.map +1 -1
- package/dist/renderPptx/nodes/text.js +1 -18
- package/dist/renderPptx/nodes/text.js.map +1 -1
- package/dist/renderPptx/nodes/timeline.js +9 -3
- package/dist/renderPptx/nodes/timeline.js.map +1 -1
- package/dist/renderPptx/nodes/tree.js +4 -1
- package/dist/renderPptx/nodes/tree.js.map +1 -1
- package/dist/renderPptx/pptxAuthoring.js +381 -0
- package/dist/renderPptx/pptxAuthoring.js.map +1 -0
- package/dist/renderPptx/renderPptx.js +157 -126
- package/dist/renderPptx/renderPptx.js.map +1 -1
- package/dist/renderPptx/textOptions.js +7 -8
- package/dist/renderPptx/textOptions.js.map +1 -1
- package/dist/renderPptx/units.js +3 -3
- package/dist/renderPptx/units.js.map +1 -1
- package/dist/renderPptx/utils/backgroundBorder.js +30 -44
- package/dist/renderPptx/utils/backgroundBorder.js.map +1 -1
- package/dist/renderPptx/utils/contentArea.js +1 -1
- package/dist/renderPptx/utils/contentArea.js.map +1 -1
- package/dist/renderPptx/utils/glimpsePicture.js +3 -22
- package/dist/renderPptx/utils/glimpsePicture.js.map +1 -1
- package/dist/renderPptx/utils/glimpseShape.js +6 -25
- package/dist/renderPptx/utils/glimpseShape.js.map +1 -1
- package/dist/renderPptx/utils/glimpseTextBox.js +41 -60
- package/dist/renderPptx/utils/glimpseTextBox.js.map +1 -1
- package/dist/renderPptx/utils/straightLine.js +5 -2
- package/dist/renderPptx/utils/straightLine.js.map +1 -1
- package/dist/renderPptx/utils/visualStyle.js +3 -33
- package/dist/renderPptx/utils/visualStyle.js.map +1 -1
- package/dist/renderPptx/writablePptx.d.ts +23 -0
- package/dist/renderPptx/writablePptx.d.ts.map +1 -0
- package/dist/renderPptx/writablePptx.js +74 -0
- package/dist/renderPptx/writablePptx.js.map +1 -0
- package/dist/shared/measureImage.js.map +1 -1
- package/package.json +4 -5
- package/dist/renderPptx/glimpseTextBoxes.js +0 -646
- package/dist/renderPptx/glimpseTextBoxes.js.map +0 -1
|
@@ -1,646 +0,0 @@
|
|
|
1
|
-
import { EMU_PER_IN, pxToEmu, pxToPt } from "./units.js";
|
|
2
|
-
import { createTextOptions, resolveSubSup } from "./textOptions.js";
|
|
3
|
-
import { parseGradient, parseLinearGradient } from "../shared/gradient.js";
|
|
4
|
-
import { addPicture, addShape, addTextBox, asEmu, asHundredthPt, asOoxmlAngle, asOoxmlPercent, asPt, createPptx, readPptx } from "@pptx-glimpse/document";
|
|
5
|
-
//#region src/renderPptx/glimpseTextBoxes.ts
|
|
6
|
-
/**
|
|
7
|
-
* Text primitive の @pptx-glimpse/document writer への段階的 swap。
|
|
8
|
-
*
|
|
9
|
-
* 混在期間の合成方式は「pptxgenjs 出力 zip をベースに、swap 済み Text
|
|
10
|
-
* primitive の shape XML だけを glimpse writer で生成して該当 marker shape と
|
|
11
|
-
* 差し替える」方式を採用する。pptxgenjs 側にはまだ Shape / Image / Table /
|
|
12
|
-
* Chart など未 swap primitive と slide master 生成が残っているため、既存 zip を
|
|
13
|
-
* ベースにすると [Content_Types].xml / rels / media parts の管理を現行実装へ
|
|
14
|
-
* 寄せられる。代替案として glimpse の package をベースに未 swap primitive を
|
|
15
|
-
* pptxgenjs から取り込む方式も検討したが、初回スライス時点では pptxgenjs 側の
|
|
16
|
-
* 非 text primitive と master 出力を XML part 単位で切り出す責務が増え、以降の
|
|
17
|
-
* primitive swap より先に package 合成の複雑さが大きくなるため採用しない。
|
|
18
|
-
*
|
|
19
|
-
* marker shape は描画順を保持するためだけに pptxgenjs へ追加し、write 時に
|
|
20
|
-
* glimpse の `<p:sp>` で丸ごと置換する。Text content 自体は pptxgenjs `addText`
|
|
21
|
-
* を経由しない。
|
|
22
|
-
*/
|
|
23
|
-
const MARKER_PREFIX = "pom-text:";
|
|
24
|
-
const SHAPE_MARKER_PREFIX = "pom-shape:";
|
|
25
|
-
const PICTURE_MARKER_PREFIX = "pom-picture:";
|
|
26
|
-
const SLIDE_BACKGROUND_MARKER_BASE = 1014333;
|
|
27
|
-
const HYPERLINK_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
|
28
|
-
const IMAGE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
|
29
|
-
async function loadJSZip() {
|
|
30
|
-
const mod = await import("jszip");
|
|
31
|
-
return mod.default ?? mod;
|
|
32
|
-
}
|
|
33
|
-
function cleanHex(color) {
|
|
34
|
-
return color?.replace(/^#/, "").toUpperCase();
|
|
35
|
-
}
|
|
36
|
-
function toColorInput(color) {
|
|
37
|
-
const hex = cleanHex(color);
|
|
38
|
-
return hex ? {
|
|
39
|
-
kind: "srgb",
|
|
40
|
-
hex
|
|
41
|
-
} : void 0;
|
|
42
|
-
}
|
|
43
|
-
function toUnderlineInput(underline) {
|
|
44
|
-
if (underline === void 0 || underline === false) return void 0;
|
|
45
|
-
if (underline === true) return true;
|
|
46
|
-
return {
|
|
47
|
-
style: underline.style,
|
|
48
|
-
color: toColorInput(underline.color)
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
function toBaselineInput(subscript, superscript) {
|
|
52
|
-
if (subscript) return "subscript";
|
|
53
|
-
if (superscript) return "superscript";
|
|
54
|
-
}
|
|
55
|
-
function toGlowInput(glow) {
|
|
56
|
-
if (!glow) return void 0;
|
|
57
|
-
return {
|
|
58
|
-
radius: asEmu(Math.round(pxToEmu(glow.size ?? 8))),
|
|
59
|
-
color: toColorInput(glow.color ?? "FFFFFF")
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
function toOutlineInput(outline) {
|
|
63
|
-
if (!outline) return void 0;
|
|
64
|
-
return {
|
|
65
|
-
width: asEmu(Math.round(pxToEmu(outline.size ?? 1))),
|
|
66
|
-
color: toColorInput(outline.color ?? "FFFFFF")
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
function toCharSpacing(letterSpacingPx) {
|
|
70
|
-
if (letterSpacingPx === void 0) return void 0;
|
|
71
|
-
return Math.round(pxToPt(letterSpacingPx) * 100);
|
|
72
|
-
}
|
|
73
|
-
function toTextGradientInput(value) {
|
|
74
|
-
if (!value) return void 0;
|
|
75
|
-
const linear = parseLinearGradient(value);
|
|
76
|
-
if (!linear) return void 0;
|
|
77
|
-
const dmlAngle = ((linear.angle - 90) % 360 + 360) % 360;
|
|
78
|
-
return {
|
|
79
|
-
angle: asOoxmlAngle(Math.round(dmlAngle * 6e4)),
|
|
80
|
-
stops: linear.stops.map((stop) => ({
|
|
81
|
-
position: asOoxmlPercent(Math.round(stop.position * 1e3)),
|
|
82
|
-
color: toColorInput(stop.color)
|
|
83
|
-
}))
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function stripUndefined(value) {
|
|
87
|
-
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
88
|
-
}
|
|
89
|
-
function buildRunProperties(node, run, gradientFill) {
|
|
90
|
-
const fontSizePx = run?.fontSize ?? node.fontSize ?? 24;
|
|
91
|
-
const letterSpacingPx = run?.letterSpacing ?? node.letterSpacing;
|
|
92
|
-
const subSup = run ? resolveSubSup(run, node) : node;
|
|
93
|
-
const color = gradientFill ? void 0 : toColorInput(run?.color ?? node.color);
|
|
94
|
-
return stripUndefined({
|
|
95
|
-
fontFace: run?.fontFamily ?? node.fontFamily ?? "Noto Sans JP",
|
|
96
|
-
fontSize: asPt(pxToPt(fontSizePx)),
|
|
97
|
-
color,
|
|
98
|
-
gradientFill,
|
|
99
|
-
bold: run?.bold ?? node.bold,
|
|
100
|
-
italic: run?.italic ?? node.italic,
|
|
101
|
-
underline: toUnderlineInput(resolveUnderline(node, run)),
|
|
102
|
-
strike: run?.strike ?? node.strike,
|
|
103
|
-
baseline: toBaselineInput(subSup.subscript, subSup.superscript),
|
|
104
|
-
highlight: toColorInput(run?.highlight ?? node.highlight),
|
|
105
|
-
glow: toGlowInput(node.glow),
|
|
106
|
-
outline: toOutlineInput(node.outline),
|
|
107
|
-
charSpacing: toCharSpacing(letterSpacingPx)
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
function resolveUnderline(node, run) {
|
|
111
|
-
if (run?.underline !== void 0) return run.underline;
|
|
112
|
-
if (node.underline !== void 0) return node.underline;
|
|
113
|
-
return run?.href ? true : void 0;
|
|
114
|
-
}
|
|
115
|
-
function createParagraphProperties(node) {
|
|
116
|
-
const lineHeight = node.lineHeight ?? 1.3;
|
|
117
|
-
const fontSizePx = node.fontSize ?? 24;
|
|
118
|
-
return stripUndefined({
|
|
119
|
-
align: node.textAlign,
|
|
120
|
-
lineSpacing: asHundredthPt(Math.round(pxToPt(fontSizePx * lineHeight) * 100))
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
function buildParagraphs(node) {
|
|
124
|
-
const gradientFill = toTextGradientInput(node.textGradient);
|
|
125
|
-
const sourceRuns = node.runs && node.runs.length > 0 ? node.runs.map((run) => ({
|
|
126
|
-
text: run.text,
|
|
127
|
-
properties: buildRunProperties(node, run, gradientFill),
|
|
128
|
-
href: run.href
|
|
129
|
-
})) : [{
|
|
130
|
-
text: node.text ?? "",
|
|
131
|
-
properties: buildRunProperties(node, void 0, gradientFill)
|
|
132
|
-
}];
|
|
133
|
-
const paragraphRuns = [[]];
|
|
134
|
-
for (const run of sourceRuns) run.text.replace(/\r*\n/g, "\n").split("\n").forEach((line, index) => {
|
|
135
|
-
if (index > 0) paragraphRuns.push([]);
|
|
136
|
-
paragraphRuns[paragraphRuns.length - 1]?.push({
|
|
137
|
-
...run,
|
|
138
|
-
text: line
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
return {
|
|
142
|
-
paragraphs: paragraphRuns.map((runs) => ({
|
|
143
|
-
properties: createParagraphProperties(node),
|
|
144
|
-
runs
|
|
145
|
-
})),
|
|
146
|
-
hyperlinks: paragraphRuns.flatMap((runs) => runs.map((run) => run.text ? run.href : void 0))
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
function withGlowAlpha(xml, node) {
|
|
150
|
-
const glow = node.glow;
|
|
151
|
-
if (!glow) return xml;
|
|
152
|
-
const alpha = Math.round((glow.opacity ?? .75) * 1e5);
|
|
153
|
-
const color = cleanHex(glow.color ?? "FFFFFF");
|
|
154
|
-
const target = `<a:glow rad="${Math.round(pxToEmu(glow.size ?? 8))}"><a:srgbClr val="${color}"/></a:glow>`;
|
|
155
|
-
const replacement = `<a:glow rad="${Math.round(pxToEmu(glow.size ?? 8))}"><a:srgbClr val="${color}"><a:alpha val="${alpha}"/></a:srgbClr></a:glow>`;
|
|
156
|
-
return xml.replaceAll(target, replacement);
|
|
157
|
-
}
|
|
158
|
-
function withShapeGlowAlpha(xml, glow) {
|
|
159
|
-
if (!glow) return xml;
|
|
160
|
-
const alpha = Math.round((glow.opacity ?? .75) * 1e5);
|
|
161
|
-
const color = cleanHex(glow.color ?? "FFFFFF");
|
|
162
|
-
const target = `<a:glow rad="${Math.round(pxToEmu(glow.size ?? 8))}"><a:srgbClr val="${color}"/></a:glow>`;
|
|
163
|
-
const replacement = `<a:glow rad="${Math.round(pxToEmu(glow.size ?? 8))}"><a:srgbClr val="${color}"><a:alpha val="${alpha}"/></a:srgbClr></a:glow>`;
|
|
164
|
-
return xml.replaceAll(target, replacement);
|
|
165
|
-
}
|
|
166
|
-
function colorWithOptionalAlphaXml(color, opacity) {
|
|
167
|
-
const clean = cleanHex(color) ?? color;
|
|
168
|
-
if (opacity === void 0) return `<a:srgbClr val="${clean}"/>`;
|
|
169
|
-
return `<a:srgbClr val="${clean}"><a:alpha val="${Math.round(opacity * 1e5)}"/></a:srgbClr>`;
|
|
170
|
-
}
|
|
171
|
-
function buildGradFillXml(value, opacity) {
|
|
172
|
-
const gradient = parseGradient(value);
|
|
173
|
-
if (!gradient) return void 0;
|
|
174
|
-
const gsXml = gradient.value.stops.map((stop) => `<a:gs pos="${Math.round(stop.position * 1e3)}">${colorWithOptionalAlphaXml(stop.color, opacity)}</a:gs>`).join("");
|
|
175
|
-
if (gradient.kind === "linear") {
|
|
176
|
-
const dmlAngle = ((gradient.value.angle - 90) % 360 + 360) % 360;
|
|
177
|
-
return `<a:gradFill flip="none" rotWithShape="1"><a:gsLst>${gsXml}</a:gsLst><a:lin ang="${Math.round(dmlAngle * 6e4)}" scaled="0"/></a:gradFill>`;
|
|
178
|
-
}
|
|
179
|
-
const { centerX, centerY } = gradient.value;
|
|
180
|
-
return `<a:gradFill flip="none" rotWithShape="1"><a:gsLst>${gsXml}</a:gsLst><a:path path="circle"><a:fillToRect l="${Math.round(centerX * 1e3)}" t="${Math.round(centerY * 1e3)}" r="${Math.round((100 - centerX) * 1e3)}" b="${Math.round((100 - centerY) * 1e3)}"/></a:path></a:gradFill>`;
|
|
181
|
-
}
|
|
182
|
-
function withSolidFillAlpha(xml, color, opacity) {
|
|
183
|
-
if (color === void 0 || opacity === void 0) return xml;
|
|
184
|
-
const clean = cleanHex(color);
|
|
185
|
-
return xml.replaceAll(`<a:solidFill><a:srgbClr val="${clean}"/></a:solidFill>`, `<a:solidFill>${colorWithOptionalAlphaXml(clean ?? color, opacity)}</a:solidFill>`);
|
|
186
|
-
}
|
|
187
|
-
function withGradientFill(xml, backgroundGradient, opacity, preset) {
|
|
188
|
-
if (!backgroundGradient) return xml;
|
|
189
|
-
const gradFill = buildGradFillXml(backgroundGradient, opacity);
|
|
190
|
-
if (!gradFill) return xml;
|
|
191
|
-
if (preset === "line") return xml.replace(/<a:ln\b([^>]*)>([\s\S]*?)<\/a:ln>/, (match, attrs, body) => {
|
|
192
|
-
const nextBody = body.replace(/<a:(?:solidFill|gradFill)\b[\s\S]*?<\/a:(?:solidFill|gradFill)>|<a:noFill\/>/, gradFill);
|
|
193
|
-
return nextBody === body ? match : `<a:ln${attrs}>${nextBody}</a:ln>`;
|
|
194
|
-
});
|
|
195
|
-
return xml.replace(/<a:(?:solidFill|gradFill)\b[\s\S]*?<\/a:(?:solidFill|gradFill)>|<a:noFill\/>/, gradFill);
|
|
196
|
-
}
|
|
197
|
-
function withRoundRectAdjust(xml, input, rectRadius) {
|
|
198
|
-
if (input.preset !== "roundRect" || rectRadius === void 0) return xml;
|
|
199
|
-
const adj = Math.round(rectRadius * EMU_PER_IN * 1e5 / Math.min(input.width, input.height));
|
|
200
|
-
return xml.replace(/<a:prstGeom prst="roundRect"><a:avLst\/><\/a:prstGeom>/, `<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val ${adj}"/></a:avLst></a:prstGeom>`);
|
|
201
|
-
}
|
|
202
|
-
function shadowXml(shadow) {
|
|
203
|
-
if (!shadow) return void 0;
|
|
204
|
-
const blur = Math.round((shadow.blur ?? 3) * 12700);
|
|
205
|
-
const dist = Math.round((shadow.offset ?? 23e3 / 12700) * 12700);
|
|
206
|
-
const dir = Math.round((shadow.angle ?? 90) * 6e4);
|
|
207
|
-
const color = cleanHex(shadow.color ?? "000000") ?? "000000";
|
|
208
|
-
const alpha = Math.round((shadow.opacity ?? .35) * 1e5);
|
|
209
|
-
const type = shadow.type ?? "outer";
|
|
210
|
-
return `<a:${type}Shdw sx="100000" sy="100000" kx="0" ky="0" algn="bl" blurRad="${blur}" rotWithShape="1" dist="${dist}" dir="${dir}"><a:srgbClr val="${color}"><a:alpha val="${alpha}"/></a:srgbClr></a:${type}Shdw>`;
|
|
211
|
-
}
|
|
212
|
-
function withShadow(xml, shadow) {
|
|
213
|
-
const effect = shadowXml(shadow);
|
|
214
|
-
if (!effect) return xml;
|
|
215
|
-
if (xml.includes("<a:effectLst>")) return xml.replace("</a:effectLst>", `${effect}</a:effectLst>`);
|
|
216
|
-
return xml.replace("</p:spPr>", `<a:effectLst>${effect}</a:effectLst></p:spPr>`);
|
|
217
|
-
}
|
|
218
|
-
function withLineFlip(xml, flipH, flipV) {
|
|
219
|
-
if (!flipH && !flipV) return xml;
|
|
220
|
-
return xml.replace("<a:xfrm", `<a:xfrm${flipH ? " flipH=\"1\"" : ""}${flipV ? " flipV=\"1\"" : ""}`);
|
|
221
|
-
}
|
|
222
|
-
function withLineZeroExtent(xml, preset, zeroWidth, zeroHeight) {
|
|
223
|
-
if (preset !== "line" || !zeroWidth && !zeroHeight) return xml;
|
|
224
|
-
return xml.replace(/<a:ext cx="(\d+)" cy="(\d+)"\/>/, (_match, cx, cy) => `<a:ext cx="${zeroWidth ? "0" : cx}" cy="${zeroHeight ? "0" : cy}"/>`);
|
|
225
|
-
}
|
|
226
|
-
function withPrstDash(xml, dashType) {
|
|
227
|
-
return xml.replace(/<a:ln\b([^>]*)>([\s\S]*?)<\/a:ln>/g, (match, attrs, body) => {
|
|
228
|
-
const bodyText = body;
|
|
229
|
-
if (bodyText.includes("<a:prstDash")) return match;
|
|
230
|
-
return `<a:ln${attrs}>${bodyText.replace(/(<a:(?:solidFill|noFill\/)>[\s\S]*?<\/a:solidFill>|<a:noFill\/>)/, `$1<a:prstDash val="${dashType}"/>`)}</a:ln>`;
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
function withUnsupportedDashStyle(xml, dashType) {
|
|
234
|
-
if (dashType !== "lgDashDotDot") return xml;
|
|
235
|
-
return withPrstDash(xml, dashType);
|
|
236
|
-
}
|
|
237
|
-
function withPptxGenLineArrowDefaults(xml, preset) {
|
|
238
|
-
if (preset !== "line") return xml;
|
|
239
|
-
return withPrstDash(xml.replace(/<a:(headEnd|tailEnd) type="([^"]+)" w="med" len="med"\/>/g, "<a:$1 type=\"$2\"/>"), "solid");
|
|
240
|
-
}
|
|
241
|
-
function withPptxGenParagraphDefaults(xml) {
|
|
242
|
-
let result = xml.replaceAll("baseline=\"-25000\"", "baseline=\"-40000\"");
|
|
243
|
-
result = result.replace(/<a:bodyPr\b([^>]*)\/>/g, (_match, attrs) => {
|
|
244
|
-
const attrText = attrs;
|
|
245
|
-
const withRtl = /(?:^|\s)rtlCol=/.test(attrText) ? attrText : `${attrText} rtlCol="0"`;
|
|
246
|
-
return `<a:bodyPr${/(?:^|\s)anchor=/.test(withRtl) ? withRtl : `${withRtl} anchor="t"`}/>`;
|
|
247
|
-
});
|
|
248
|
-
result = result.replace(/<a:pPr([^>]*)>([\s\S]*?)<\/a:pPr>/g, (match, attrs, body) => {
|
|
249
|
-
const attrText = attrs;
|
|
250
|
-
const nextAttrs = /(?:^|\s)indent=/.test(attrText) ? attrText : `${attrText} indent="0" marL="0"`;
|
|
251
|
-
const bodyText = body;
|
|
252
|
-
return `<a:pPr${nextAttrs}>${bodyText.includes("<a:buNone/>") ? bodyText : `${bodyText}<a:buNone/>`}</a:pPr>`;
|
|
253
|
-
});
|
|
254
|
-
result = result.replace(/<a:p>(?!<a:pPr)/g, "<a:p><a:pPr indent=\"0\" marL=\"0\"><a:buNone/></a:pPr>");
|
|
255
|
-
return result;
|
|
256
|
-
}
|
|
257
|
-
function createTextBoxXml(node, name) {
|
|
258
|
-
const textOptions = createTextOptions(node);
|
|
259
|
-
const { paragraphs, hyperlinks } = buildParagraphs(node);
|
|
260
|
-
return {
|
|
261
|
-
xml: createTextBoxXmlFromInput({
|
|
262
|
-
offsetX: asEmu(Math.round(textOptions.x * EMU_PER_IN)),
|
|
263
|
-
offsetY: asEmu(Math.round(textOptions.y * EMU_PER_IN)),
|
|
264
|
-
width: asEmu(Math.round(textOptions.w * EMU_PER_IN)),
|
|
265
|
-
height: asEmu(Math.round(textOptions.h * EMU_PER_IN)),
|
|
266
|
-
rotation: node.rotate !== void 0 ? asOoxmlAngle(Math.round(node.rotate * 6e4)) : void 0,
|
|
267
|
-
name,
|
|
268
|
-
body: {
|
|
269
|
-
marginLeft: asEmu(0),
|
|
270
|
-
marginRight: asEmu(0),
|
|
271
|
-
marginTop: asEmu(0),
|
|
272
|
-
marginBottom: asEmu(0)
|
|
273
|
-
},
|
|
274
|
-
paragraphs
|
|
275
|
-
}, { xmlTransform: (xml) => withGlowAlpha(xml, node) }),
|
|
276
|
-
hyperlinks
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
function createTextBoxXmlFromInput(input, options) {
|
|
280
|
-
const source = createPptx();
|
|
281
|
-
const slideHandle = source.slides[0]?.handle;
|
|
282
|
-
if (!slideHandle) throw new Error("createPptx did not create an editable slide");
|
|
283
|
-
const edit = addTextBox(source, slideHandle, input).edits?.at(-1);
|
|
284
|
-
if (edit?.kind !== "addTextBox") throw new Error("addTextBox did not produce an addTextBox edit");
|
|
285
|
-
const xml = withPptxGenParagraphDefaults(edit.xml);
|
|
286
|
-
return options?.xmlTransform ? options.xmlTransform(xml) : xml;
|
|
287
|
-
}
|
|
288
|
-
function geometryPointXml(point) {
|
|
289
|
-
return `<a:pt x="${Math.round(point.x * EMU_PER_IN)}" y="${Math.round(point.y * EMU_PER_IN)}"/>`;
|
|
290
|
-
}
|
|
291
|
-
function buildCustomGeometryXml(geometry) {
|
|
292
|
-
if (!geometry.points.find((point) => "x" in point)) return void 0;
|
|
293
|
-
let hasMoveTo = false;
|
|
294
|
-
const commands = geometry.points.map((point) => {
|
|
295
|
-
if ("close" in point) return hasMoveTo ? "<a:close/>" : "";
|
|
296
|
-
if (!hasMoveTo) {
|
|
297
|
-
hasMoveTo = true;
|
|
298
|
-
return `<a:moveTo>${geometryPointXml(point)}</a:moveTo>`;
|
|
299
|
-
}
|
|
300
|
-
return `<a:lnTo>${geometryPointXml(point)}</a:lnTo>`;
|
|
301
|
-
}).join("");
|
|
302
|
-
return `<a:custGeom><a:avLst/><a:gdLst/><a:ahLst/><a:cxnLst/><a:rect l="l" t="t" r="r" b="b"/><a:pathLst><a:path w="${Math.round(geometry.width * EMU_PER_IN)}" h="${Math.round(geometry.height * EMU_PER_IN)}">${commands}</a:path></a:pathLst></a:custGeom>`;
|
|
303
|
-
}
|
|
304
|
-
function withCustomGeometry(xml, geometry) {
|
|
305
|
-
if (!geometry) return xml;
|
|
306
|
-
const customGeometry = buildCustomGeometryXml(geometry);
|
|
307
|
-
if (!customGeometry) return xml;
|
|
308
|
-
return xml.replace(/<a:prstGeom\b[\s\S]*?<\/a:prstGeom>/, customGeometry);
|
|
309
|
-
}
|
|
310
|
-
function withOutlineGradientFill(xml, outlineGradient, opacity) {
|
|
311
|
-
if (!outlineGradient) return xml;
|
|
312
|
-
const gradFill = buildGradFillXml(outlineGradient, opacity);
|
|
313
|
-
if (!gradFill) return xml;
|
|
314
|
-
const lineFillPattern = /<a:(?:solidFill|gradFill)\b[\s\S]*?<\/a:(?:solidFill|gradFill)>|<a:noFill\/>/;
|
|
315
|
-
if (/<a:ln\b[^>]*\/>/.test(xml)) return xml.replace(/<a:ln\b([^>]*)\/>/, (_match, attrs) => `<a:ln${attrs}>${gradFill}</a:ln>`);
|
|
316
|
-
return xml.replace(/(<a:ln\b[^>]*>)([\s\S]*?)(<\/a:ln>)/, (_match, open, body, close) => {
|
|
317
|
-
return `${open}${lineFillPattern.test(body) ? body.replace(lineFillPattern, gradFill) : `${gradFill}${body}`}${close}`;
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
function createShapeXml(input, options) {
|
|
321
|
-
const source = createPptx();
|
|
322
|
-
const slideHandle = source.slides[0]?.handle;
|
|
323
|
-
if (!slideHandle) throw new Error("createPptx did not create an editable slide");
|
|
324
|
-
const edit = addShape(source, slideHandle, input).edits?.at(-1);
|
|
325
|
-
if (edit?.kind !== "addShape") throw new Error("addShape did not produce an addShape edit");
|
|
326
|
-
let xml = edit.xml;
|
|
327
|
-
xml = withShapeGlowAlpha(xml, options?.glow);
|
|
328
|
-
xml = withSolidFillAlpha(xml, options?.fillColor, options?.fillOpacity);
|
|
329
|
-
xml = withGradientFill(xml, options?.backgroundGradient, options?.fillOpacity, input.preset);
|
|
330
|
-
xml = withOutlineGradientFill(xml, options?.outlineGradient, options?.outlineOpacity ?? options?.fillOpacity);
|
|
331
|
-
xml = withRoundRectAdjust(xml, input, options?.rectRadius);
|
|
332
|
-
xml = withShadow(xml, options?.shadow);
|
|
333
|
-
xml = withUnsupportedDashStyle(xml, options?.dashType);
|
|
334
|
-
xml = withLineFlip(xml, options?.flipH, options?.flipV);
|
|
335
|
-
xml = withLineZeroExtent(xml, input.preset, options?.zeroWidth, options?.zeroHeight);
|
|
336
|
-
xml = withPptxGenLineArrowDefaults(xml, input.preset);
|
|
337
|
-
xml = withCustomGeometry(xml, options?.customGeometry);
|
|
338
|
-
return xml;
|
|
339
|
-
}
|
|
340
|
-
var GlimpseTextBoxRegistry = class {
|
|
341
|
-
registered = [];
|
|
342
|
-
textCount = 0;
|
|
343
|
-
shapeCount = 0;
|
|
344
|
-
pictureCount = 0;
|
|
345
|
-
slideBackgroundCount = 0;
|
|
346
|
-
register(node) {
|
|
347
|
-
const index = this.textCount++;
|
|
348
|
-
const marker = `${MARKER_PREFIX}${index}`;
|
|
349
|
-
const name = `Text ${index + 1}`;
|
|
350
|
-
const { xml, hyperlinks } = createTextBoxXml(node, name);
|
|
351
|
-
this.registered.push({
|
|
352
|
-
kind: "shape",
|
|
353
|
-
marker,
|
|
354
|
-
name,
|
|
355
|
-
xml,
|
|
356
|
-
hyperlinks
|
|
357
|
-
});
|
|
358
|
-
return marker;
|
|
359
|
-
}
|
|
360
|
-
registerTextBox(input, options) {
|
|
361
|
-
const index = this.textCount++;
|
|
362
|
-
const marker = `${MARKER_PREFIX}${index}`;
|
|
363
|
-
const name = options?.name ?? `Text ${index + 1}`;
|
|
364
|
-
const xml = createTextBoxXmlFromInput({
|
|
365
|
-
...input,
|
|
366
|
-
name
|
|
367
|
-
}, options);
|
|
368
|
-
this.registered.push({
|
|
369
|
-
kind: "shape",
|
|
370
|
-
marker,
|
|
371
|
-
name,
|
|
372
|
-
xml,
|
|
373
|
-
hyperlinks: options?.hyperlinks ?? []
|
|
374
|
-
});
|
|
375
|
-
return marker;
|
|
376
|
-
}
|
|
377
|
-
registerShape(input, options) {
|
|
378
|
-
const index = this.shapeCount++;
|
|
379
|
-
const marker = `${SHAPE_MARKER_PREFIX}${index}`;
|
|
380
|
-
const name = options?.name ?? `Shape ${index + 1}`;
|
|
381
|
-
const xml = createShapeXml({
|
|
382
|
-
...input,
|
|
383
|
-
name
|
|
384
|
-
}, options);
|
|
385
|
-
this.registered.push({
|
|
386
|
-
kind: "shape",
|
|
387
|
-
marker,
|
|
388
|
-
name,
|
|
389
|
-
xml,
|
|
390
|
-
hyperlinks: []
|
|
391
|
-
});
|
|
392
|
-
return marker;
|
|
393
|
-
}
|
|
394
|
-
registerPicture(input, options) {
|
|
395
|
-
const index = this.pictureCount++;
|
|
396
|
-
const marker = `${PICTURE_MARKER_PREFIX}${index}`;
|
|
397
|
-
const name = options?.name ?? `Picture ${index + 1}`;
|
|
398
|
-
this.registered.push({
|
|
399
|
-
kind: "picture",
|
|
400
|
-
marker,
|
|
401
|
-
name,
|
|
402
|
-
input: {
|
|
403
|
-
...input,
|
|
404
|
-
name
|
|
405
|
-
},
|
|
406
|
-
shadow: options?.shadow
|
|
407
|
-
});
|
|
408
|
-
return marker;
|
|
409
|
-
}
|
|
410
|
-
registerSlideBackgroundGradient(backgroundGradient, slideNumber, opacity) {
|
|
411
|
-
const xml = buildGradFillXml(backgroundGradient, opacity);
|
|
412
|
-
if (!xml) return void 0;
|
|
413
|
-
const marker = (SLIDE_BACKGROUND_MARKER_BASE + this.slideBackgroundCount++).toString(16).toUpperCase().padStart(6, "0");
|
|
414
|
-
this.registered.push({
|
|
415
|
-
kind: "slideBackground",
|
|
416
|
-
marker,
|
|
417
|
-
slideNumber,
|
|
418
|
-
xml
|
|
419
|
-
});
|
|
420
|
-
return marker;
|
|
421
|
-
}
|
|
422
|
-
get isEmpty() {
|
|
423
|
-
return this.registered.length === 0;
|
|
424
|
-
}
|
|
425
|
-
get entries() {
|
|
426
|
-
return this.registered;
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
function escapeRegExp(value) {
|
|
430
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
431
|
-
}
|
|
432
|
-
function replaceShapeId(xml, id, name) {
|
|
433
|
-
return xml.replace(/<p:cNvPr id="[^"]+" name="[^"]*"/, `<p:cNvPr id="${xmlAttr(id)}" name="${xmlAttr(name)}"`);
|
|
434
|
-
}
|
|
435
|
-
function xmlAttr(value) {
|
|
436
|
-
return value.replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<").replaceAll(">", ">");
|
|
437
|
-
}
|
|
438
|
-
function slideRelsPath(slidePath) {
|
|
439
|
-
return `ppt/slides/_rels/${slidePath.split("/").at(-1)}.rels`;
|
|
440
|
-
}
|
|
441
|
-
var SlideRelationshipEditor = class {
|
|
442
|
-
xml;
|
|
443
|
-
nextId;
|
|
444
|
-
changed = false;
|
|
445
|
-
constructor(xml) {
|
|
446
|
-
this.xml = xml;
|
|
447
|
-
const ids = Array.from(xml.matchAll(/\bId="rId(\d+)"/g), (match) => Number(match[1]));
|
|
448
|
-
this.nextId = Math.max(0, ...ids) + 1;
|
|
449
|
-
}
|
|
450
|
-
addHyperlink(href) {
|
|
451
|
-
const id = `rId${this.nextId++}`;
|
|
452
|
-
const rel = `<Relationship Id="${id}" Type="${HYPERLINK_REL_TYPE}" Target="${xmlAttr(href)}" TargetMode="External"/>`;
|
|
453
|
-
this.xml = this.xml.replace("</Relationships>", `${rel}</Relationships>`);
|
|
454
|
-
this.changed = true;
|
|
455
|
-
return id;
|
|
456
|
-
}
|
|
457
|
-
addImageRelationship(id, target) {
|
|
458
|
-
if (new RegExp(`\\bId="${escapeRegExp(id)}"`).test(this.xml)) return;
|
|
459
|
-
const rel = `<Relationship Id="${xmlAttr(id)}" Type="${IMAGE_REL_TYPE}" Target="${xmlAttr(target)}"/>`;
|
|
460
|
-
this.xml = this.xml.replace("</Relationships>", `${rel}</Relationships>`);
|
|
461
|
-
const numeric = id.match(/^rId(\d+)$/)?.[1];
|
|
462
|
-
if (numeric) this.nextId = Math.max(this.nextId, Number(numeric) + 1);
|
|
463
|
-
this.changed = true;
|
|
464
|
-
}
|
|
465
|
-
get result() {
|
|
466
|
-
return {
|
|
467
|
-
xml: this.xml,
|
|
468
|
-
changed: this.changed
|
|
469
|
-
};
|
|
470
|
-
}
|
|
471
|
-
};
|
|
472
|
-
function createRelationshipEditor(xml) {
|
|
473
|
-
return new SlideRelationshipEditor(xml ?? "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"></Relationships>");
|
|
474
|
-
}
|
|
475
|
-
function withHyperlinkRelationships(xml, hyperlinks, addRelationship) {
|
|
476
|
-
if (!hyperlinks.some(Boolean)) return xml;
|
|
477
|
-
let index = 0;
|
|
478
|
-
return xml.replace(/<a:rPr\b([^>]*)>([\s\S]*?)<\/a:rPr>/g, (match, attrs, body) => {
|
|
479
|
-
const href = hyperlinks[index++];
|
|
480
|
-
if (!href) return match;
|
|
481
|
-
return `<a:rPr${attrs}>${body}<a:hlinkClick r:id="${addRelationship(href)}"/></a:rPr>`;
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
function findSlideHandle(source, slidePath) {
|
|
485
|
-
return source.slides.find((slide) => slide.partPath === slidePath)?.handle;
|
|
486
|
-
}
|
|
487
|
-
function findMediaPart(source, partPath) {
|
|
488
|
-
const media = source.packageGraph.media.find((part) => part.partPath === partPath);
|
|
489
|
-
if (!media) throw new Error(`addPicture media part was not found: ${partPath}`);
|
|
490
|
-
return media;
|
|
491
|
-
}
|
|
492
|
-
function findSlideImageTarget(source, slidePath, relationshipId) {
|
|
493
|
-
const relationship = source.packageGraph.relationships.find((group) => group.sourcePartPath === slidePath)?.relationships.find((candidate) => candidate.id === relationshipId);
|
|
494
|
-
if (!relationship) throw new Error(`addPicture relationship was not found: ${relationshipId}`);
|
|
495
|
-
return relationship.target;
|
|
496
|
-
}
|
|
497
|
-
function applyGlimpseTextBoxesToXml(xml, registry, addRelationship) {
|
|
498
|
-
let result = xml;
|
|
499
|
-
for (const entry of registry.entries) {
|
|
500
|
-
if (entry.kind !== "shape") continue;
|
|
501
|
-
const re = new RegExp(`<p:sp><p:nvSpPr><p:cNvPr id="([^"]+)" name="${escapeRegExp(entry.marker)}"[\\s\\S]*?</p:sp>`, "g");
|
|
502
|
-
result = result.replace(re, (_match, id) => {
|
|
503
|
-
return withHyperlinkRelationships(replaceShapeId(entry.xml, id, entry.name), entry.hyperlinks, addRelationship);
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
return result;
|
|
507
|
-
}
|
|
508
|
-
function applySlideBackgroundGradientsToXml(xml, registry, slidePath) {
|
|
509
|
-
let result = xml;
|
|
510
|
-
const slideNumber = Number(slidePath.match(/slide(\d+)\.xml$/)?.[1]);
|
|
511
|
-
for (const entry of registry.entries) {
|
|
512
|
-
if (entry.kind !== "slideBackground") continue;
|
|
513
|
-
if (entry.slideNumber !== slideNumber) continue;
|
|
514
|
-
const target = `<p:bgPr><a:solidFill><a:srgbClr val="${entry.marker}"/></a:solidFill></p:bgPr>`;
|
|
515
|
-
result = result.replace(target, `<p:bgPr>${entry.xml}</p:bgPr>`);
|
|
516
|
-
}
|
|
517
|
-
return result;
|
|
518
|
-
}
|
|
519
|
-
function withPptxGenPictureSizingXml(xml, hasSizing) {
|
|
520
|
-
if (!hasSizing) return xml;
|
|
521
|
-
return xml.replace("<a:stretch><a:fillRect/></a:stretch>", "<a:stretch/>");
|
|
522
|
-
}
|
|
523
|
-
function applyGlimpsePicturesToXml(xml, registry, source, slidePath, relationshipEditor, addMedia) {
|
|
524
|
-
let result = xml;
|
|
525
|
-
let editedSource = source;
|
|
526
|
-
for (const entry of registry.entries) {
|
|
527
|
-
if (entry.kind !== "picture") continue;
|
|
528
|
-
const re = new RegExp(`<p:sp><p:nvSpPr><p:cNvPr id="([^"]+)" name="${escapeRegExp(entry.marker)}"[\\s\\S]*?</p:sp>`, "g");
|
|
529
|
-
result = result.replace(re, (_match, id) => {
|
|
530
|
-
const slideHandle = findSlideHandle(editedSource, slidePath);
|
|
531
|
-
if (!slideHandle) throw new Error(`slide handle was not found: ${slidePath}`);
|
|
532
|
-
editedSource = addPicture(editedSource, slideHandle, entry.input);
|
|
533
|
-
const edit = editedSource.edits?.at(-1);
|
|
534
|
-
if (edit?.kind !== "addPicture") throw new Error("addPicture did not produce an addPicture edit");
|
|
535
|
-
addMedia(findMediaPart(editedSource, edit.mediaPartPath));
|
|
536
|
-
relationshipEditor.addImageRelationship(edit.relationshipId, findSlideImageTarget(editedSource, slidePath, edit.relationshipId));
|
|
537
|
-
return withShadow(withPptxGenPictureSizingXml(replaceShapeId(edit.xml, id, entry.name), entry.input.crop !== void 0), entry.shadow);
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
return {
|
|
541
|
-
xml: result,
|
|
542
|
-
source: editedSource
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
function ensureContentTypeDefault(xml, extension, contentType) {
|
|
546
|
-
if (new RegExp(`<Default\\s+[^>]*Extension="${escapeRegExp(extension)}"[^>]*/>`).test(xml)) return xml;
|
|
547
|
-
const entry = `<Default Extension="${xmlAttr(extension)}" ContentType="${xmlAttr(contentType)}"/>`;
|
|
548
|
-
return xml.replace("</Types>", `${entry}</Types>`);
|
|
549
|
-
}
|
|
550
|
-
async function applyGlimpseMediaParts(zip, mediaParts) {
|
|
551
|
-
const mediaList = Array.from(mediaParts);
|
|
552
|
-
if (mediaList.length === 0) return;
|
|
553
|
-
const contentTypesFile = zip.file("[Content_Types].xml");
|
|
554
|
-
if (!contentTypesFile) throw new Error("[Content_Types].xml was not found in pptx output");
|
|
555
|
-
let contentTypesXml = await contentTypesFile.async("text");
|
|
556
|
-
for (const media of mediaList) {
|
|
557
|
-
zip.file(media.partPath, media.bytes);
|
|
558
|
-
const extension = media.partPath.split(".").at(-1);
|
|
559
|
-
if (!extension) continue;
|
|
560
|
-
contentTypesXml = ensureContentTypeDefault(contentTypesXml, extension, media.contentType);
|
|
561
|
-
}
|
|
562
|
-
zip.file("[Content_Types].xml", contentTypesXml);
|
|
563
|
-
}
|
|
564
|
-
async function applyGlimpseTextBoxes(data, registry) {
|
|
565
|
-
const zip = await (await loadJSZip()).loadAsync(data);
|
|
566
|
-
let source = registry.entries.some((entry) => entry.kind === "picture") ? readPptx(data instanceof Uint8Array ? data : new Uint8Array(data)) : void 0;
|
|
567
|
-
const addedMedia = /* @__PURE__ */ new Map();
|
|
568
|
-
const slidePaths = Object.keys(zip.files).filter((path) => /^ppt\/slides\/slide\d+\.xml$/.test(path));
|
|
569
|
-
for (const path of slidePaths) {
|
|
570
|
-
const file = zip.file(path);
|
|
571
|
-
if (!file) continue;
|
|
572
|
-
const original = await file.async("text");
|
|
573
|
-
const relsPath = slideRelsPath(path);
|
|
574
|
-
const relsFile = zip.file(relsPath);
|
|
575
|
-
const relationshipEditor = createRelationshipEditor(relsFile ? await relsFile.async("text") : void 0);
|
|
576
|
-
const withSlideBackground = applySlideBackgroundGradientsToXml(original, registry, path);
|
|
577
|
-
const pictureResult = source ? applyGlimpsePicturesToXml(withSlideBackground, registry, source, path, relationshipEditor, (media) => {
|
|
578
|
-
addedMedia.set(media.partPath, media);
|
|
579
|
-
}) : {
|
|
580
|
-
xml: withSlideBackground,
|
|
581
|
-
source
|
|
582
|
-
};
|
|
583
|
-
source = pictureResult.source;
|
|
584
|
-
const replaced = applyGlimpseTextBoxesToXml(pictureResult.xml, registry, (href) => relationshipEditor.addHyperlink(href));
|
|
585
|
-
if (replaced !== original) zip.file(path, replaced);
|
|
586
|
-
const relationships = relationshipEditor.result;
|
|
587
|
-
if (relationships.changed) zip.file(relsPath, relationships.xml);
|
|
588
|
-
}
|
|
589
|
-
await applyGlimpseMediaParts(zip, addedMedia.values());
|
|
590
|
-
return zip;
|
|
591
|
-
}
|
|
592
|
-
function patchPptxWriteForGlimpseTextBoxes(pptx, registry) {
|
|
593
|
-
if (registry.isEmpty) return;
|
|
594
|
-
const originalWrite = pptx.write.bind(pptx);
|
|
595
|
-
const patchedWrite = async (rawProps) => {
|
|
596
|
-
const props = typeof rawProps === "string" ? { outputType: rawProps } : rawProps;
|
|
597
|
-
const zip = await applyGlimpseTextBoxes(await originalWrite({ outputType: "uint8array" }), registry);
|
|
598
|
-
const outputType = props?.outputType;
|
|
599
|
-
if (outputType === "STREAM") return zip.generateAsync({
|
|
600
|
-
type: "nodebuffer",
|
|
601
|
-
compression: props?.compression ? "DEFLATE" : "STORE"
|
|
602
|
-
});
|
|
603
|
-
if (outputType) return zip.generateAsync({
|
|
604
|
-
type: outputType,
|
|
605
|
-
compression: props?.compression ? "DEFLATE" : "STORE"
|
|
606
|
-
});
|
|
607
|
-
return zip.generateAsync({
|
|
608
|
-
type: "blob",
|
|
609
|
-
compression: props?.compression ? "DEFLATE" : "STORE"
|
|
610
|
-
});
|
|
611
|
-
};
|
|
612
|
-
pptx.write = patchedWrite;
|
|
613
|
-
const patchedStream = async (props) => pptx.write({
|
|
614
|
-
outputType: "STREAM",
|
|
615
|
-
compression: props?.compression
|
|
616
|
-
});
|
|
617
|
-
pptx.stream = patchedStream;
|
|
618
|
-
const patchedWriteFile = async (rawProps) => {
|
|
619
|
-
const props = typeof rawProps === "string" ? { fileName: rawProps } : rawProps;
|
|
620
|
-
if (!(typeof process !== "undefined" && Boolean(process.versions?.node))) {
|
|
621
|
-
const browserWriter = pptx;
|
|
622
|
-
if (typeof browserWriter.writeFileToBrowser !== "function") throw new Error("pptx.writeFile browser download helper is unavailable; use pptx.write({ outputType: 'blob' }) instead");
|
|
623
|
-
const rawName = props?.fileName ?? "Presentation.pptx";
|
|
624
|
-
const fileName = rawName.toLowerCase().endsWith(".pptx") ? rawName : `${rawName}.pptx`;
|
|
625
|
-
const blob = await patchedWrite({
|
|
626
|
-
outputType: "blob",
|
|
627
|
-
compression: props?.compression
|
|
628
|
-
});
|
|
629
|
-
await browserWriter.writeFileToBrowser(fileName, blob);
|
|
630
|
-
return fileName;
|
|
631
|
-
}
|
|
632
|
-
const rawName = props?.fileName ?? "Presentation.pptx";
|
|
633
|
-
const fileName = rawName.toLowerCase().endsWith(".pptx") ? rawName : `${rawName}.pptx`;
|
|
634
|
-
const buffer = await patchedWrite({
|
|
635
|
-
outputType: "nodebuffer",
|
|
636
|
-
compression: props?.compression
|
|
637
|
-
});
|
|
638
|
-
await (await import("fs")).promises.writeFile(fileName, buffer);
|
|
639
|
-
return fileName;
|
|
640
|
-
};
|
|
641
|
-
pptx.writeFile = patchedWriteFile;
|
|
642
|
-
}
|
|
643
|
-
//#endregion
|
|
644
|
-
export { GlimpseTextBoxRegistry, cleanHex, patchPptxWriteForGlimpseTextBoxes, toColorInput };
|
|
645
|
-
|
|
646
|
-
//# sourceMappingURL=glimpseTextBoxes.js.map
|