@office-open/pptx 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +3 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +549 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { BevelPresetType, CompoundLine, LineCap, LineJoin, PathShadeType, PenAli
|
|
|
4
4
|
import { ChartCollection, ChartSpace } from "@office-open/core/chart";
|
|
5
5
|
import { DEFAULT_DRAWING_XML, SmartArtCollection, createDataModel, getColorXml, getLayoutXml, getStyleXml } from "@office-open/core/smartart";
|
|
6
6
|
import { attr, attrBool, attrNum, children, findChild, findDeep, textOf, xml } from "@office-open/xml";
|
|
7
|
+
import { toUint8Array } from "undio";
|
|
7
8
|
export * from "@office-open/core/values";
|
|
8
9
|
//#region src/file/drawingml/effects.ts
|
|
9
10
|
/** Convert PPTX simple color to core SolidFillOptions. */
|
|
@@ -5191,6 +5192,274 @@ var ParseContext = class {
|
|
|
5191
5192
|
}
|
|
5192
5193
|
};
|
|
5193
5194
|
//#endregion
|
|
5195
|
+
//#region src/parse/animation.ts
|
|
5196
|
+
/**
|
|
5197
|
+
* Animation parser for PPTX documents.
|
|
5198
|
+
*
|
|
5199
|
+
* Parses p:timing elements and maps animations to their target shapes.
|
|
5200
|
+
*
|
|
5201
|
+
* @module
|
|
5202
|
+
*/
|
|
5203
|
+
const ENTR_PRESET_TO_TYPE = /* @__PURE__ */ new Map();
|
|
5204
|
+
const EXIT_PRESET_TO_TYPE = /* @__PURE__ */ new Map();
|
|
5205
|
+
const EMPH_PRESET_TO_ID = /* @__PURE__ */ new Map();
|
|
5206
|
+
const PATH_PRESET_TO_TYPE = /* @__PURE__ */ new Map();
|
|
5207
|
+
const ENTR_IDS = {
|
|
5208
|
+
appear: 1,
|
|
5209
|
+
fade: 10,
|
|
5210
|
+
fly: 2,
|
|
5211
|
+
wipe: 22,
|
|
5212
|
+
dissolve: 34,
|
|
5213
|
+
split: 21,
|
|
5214
|
+
blinds: 25,
|
|
5215
|
+
checker: 26,
|
|
5216
|
+
randomBars: 24,
|
|
5217
|
+
wheel: 27,
|
|
5218
|
+
zoom: 10,
|
|
5219
|
+
cover: 28,
|
|
5220
|
+
push: 19,
|
|
5221
|
+
strips: 23
|
|
5222
|
+
};
|
|
5223
|
+
const EXIT_IDS = {
|
|
5224
|
+
appear: 53,
|
|
5225
|
+
fade: 59,
|
|
5226
|
+
fly: 51,
|
|
5227
|
+
wipe: 72,
|
|
5228
|
+
dissolve: 84,
|
|
5229
|
+
split: 71,
|
|
5230
|
+
blinds: 75,
|
|
5231
|
+
checker: 76,
|
|
5232
|
+
randomBars: 74,
|
|
5233
|
+
wheel: 77,
|
|
5234
|
+
zoom: 60,
|
|
5235
|
+
cover: 78,
|
|
5236
|
+
push: 69,
|
|
5237
|
+
strips: 73
|
|
5238
|
+
};
|
|
5239
|
+
const EMPH_IDS = {
|
|
5240
|
+
growShrink: 53,
|
|
5241
|
+
spin: 54,
|
|
5242
|
+
growWithTurn: 56,
|
|
5243
|
+
colorChange: 29,
|
|
5244
|
+
transparency: 57,
|
|
5245
|
+
boldFlash: 50,
|
|
5246
|
+
wave: 55,
|
|
5247
|
+
pulse: 58
|
|
5248
|
+
};
|
|
5249
|
+
const PATH_IDS = {
|
|
5250
|
+
customPath: 200,
|
|
5251
|
+
arc: 201,
|
|
5252
|
+
bounce: 202,
|
|
5253
|
+
circle: 203,
|
|
5254
|
+
curve: 204,
|
|
5255
|
+
figureEight: 205,
|
|
5256
|
+
line: 206,
|
|
5257
|
+
loop: 207
|
|
5258
|
+
};
|
|
5259
|
+
for (const [k, v] of Object.entries(ENTR_IDS)) ENTR_PRESET_TO_TYPE.set(v, k);
|
|
5260
|
+
for (const [k, v] of Object.entries(EXIT_IDS)) EXIT_PRESET_TO_TYPE.set(v, k);
|
|
5261
|
+
for (const [k, v] of Object.entries(EMPH_IDS)) EMPH_PRESET_TO_ID.set(v, k);
|
|
5262
|
+
for (const [k, v] of Object.entries(PATH_IDS)) PATH_PRESET_TO_TYPE.set(v, k);
|
|
5263
|
+
const SUBTYPE_TO_DIRECTION = /* @__PURE__ */ new Map();
|
|
5264
|
+
for (const [k, v] of Object.entries({
|
|
5265
|
+
left: 4,
|
|
5266
|
+
right: 8,
|
|
5267
|
+
up: 2,
|
|
5268
|
+
down: 1,
|
|
5269
|
+
horizontal: 16,
|
|
5270
|
+
vertical: 32
|
|
5271
|
+
})) SUBTYPE_TO_DIRECTION.set(v, k);
|
|
5272
|
+
/**
|
|
5273
|
+
* Parse p:timing element and return a map of shape ID → AnimationOptions.
|
|
5274
|
+
*/
|
|
5275
|
+
function parseTiming(el) {
|
|
5276
|
+
const result = /* @__PURE__ */ new Map();
|
|
5277
|
+
const tnLst = findChild(el, "p:tnLst");
|
|
5278
|
+
if (!tnLst) return result;
|
|
5279
|
+
const mainPar = findChild(tnLst, "p:par");
|
|
5280
|
+
if (!mainPar) return result;
|
|
5281
|
+
const mainCTn = findChild(mainPar, "p:cTn");
|
|
5282
|
+
if (!mainCTn) return result;
|
|
5283
|
+
const childTnLst = findChild(mainCTn, "p:childTnLst");
|
|
5284
|
+
if (!childTnLst) return result;
|
|
5285
|
+
const seq = findChild(childTnLst, "p:seq");
|
|
5286
|
+
if (!seq) return result;
|
|
5287
|
+
const seqCTn = findChild(seq, "p:cTn");
|
|
5288
|
+
const seqChildTnLst = seqCTn ? findChild(seqCTn, "p:childTnLst") : void 0;
|
|
5289
|
+
if (!seqChildTnLst) return result;
|
|
5290
|
+
for (const parEl of seqChildTnLst.elements ?? []) {
|
|
5291
|
+
if (parEl.name !== "p:par") continue;
|
|
5292
|
+
const parCTn = findChild(parEl, "p:cTn");
|
|
5293
|
+
if (!parCTn) continue;
|
|
5294
|
+
const parChildTnLst = findChild(parCTn, "p:childTnLst");
|
|
5295
|
+
if (!parChildTnLst) continue;
|
|
5296
|
+
for (const effectEl of parChildTnLst.elements ?? []) {
|
|
5297
|
+
const anim = parseAnimationEffect(effectEl);
|
|
5298
|
+
if (!anim) continue;
|
|
5299
|
+
const shapeId = extractTargetShapeId(effectEl);
|
|
5300
|
+
if (shapeId !== void 0) result.set(shapeId, anim);
|
|
5301
|
+
}
|
|
5302
|
+
}
|
|
5303
|
+
return result;
|
|
5304
|
+
}
|
|
5305
|
+
function parseAnimationEffect(el) {
|
|
5306
|
+
const opts = {};
|
|
5307
|
+
const cTn = findChild(el, "p:cTn") ?? el;
|
|
5308
|
+
const nodeType = attr(cTn, "nodeType");
|
|
5309
|
+
if (nodeType === "clickEffect") opts.trigger = "onClick";
|
|
5310
|
+
else if (nodeType === "withEffect") opts.trigger = "withPrevious";
|
|
5311
|
+
else if (nodeType === "afterEffect") opts.trigger = "afterPrevious";
|
|
5312
|
+
const presetClass = attr(cTn, "presetClass");
|
|
5313
|
+
if (presetClass) opts.class = presetClass;
|
|
5314
|
+
const presetID = attrNum(cTn, "presetID");
|
|
5315
|
+
const dur = attr(cTn, "dur");
|
|
5316
|
+
if (dur) {
|
|
5317
|
+
const ms = parseDuration(dur);
|
|
5318
|
+
if (ms !== void 0) opts.duration = ms;
|
|
5319
|
+
}
|
|
5320
|
+
const stCondLst = findChild(cTn, "p:stCondLst");
|
|
5321
|
+
if (stCondLst) {
|
|
5322
|
+
const cond = findChild(stCondLst, "p:cond");
|
|
5323
|
+
if (cond) {
|
|
5324
|
+
const delay = attr(cond, "delay");
|
|
5325
|
+
if (delay) {
|
|
5326
|
+
const ms = parseDuration(delay);
|
|
5327
|
+
if (ms !== void 0) opts.delay = ms;
|
|
5328
|
+
}
|
|
5329
|
+
}
|
|
5330
|
+
}
|
|
5331
|
+
const presetSubtype = attrNum(cTn, "presetSubtype");
|
|
5332
|
+
if (presetSubtype !== void 0) {
|
|
5333
|
+
const dir = SUBTYPE_TO_DIRECTION.get(presetSubtype);
|
|
5334
|
+
if (dir) opts.direction = dir;
|
|
5335
|
+
}
|
|
5336
|
+
if (presetID !== void 0) {
|
|
5337
|
+
const cls = presetClass ?? "entr";
|
|
5338
|
+
if (cls === "entr") {
|
|
5339
|
+
const type = ENTR_PRESET_TO_TYPE.get(presetID);
|
|
5340
|
+
if (type) opts.type = type;
|
|
5341
|
+
} else if (cls === "exit") {
|
|
5342
|
+
const type = EXIT_PRESET_TO_TYPE.get(presetID);
|
|
5343
|
+
if (type) opts.type = type;
|
|
5344
|
+
} else if (cls === "emph") {
|
|
5345
|
+
const emphType = EMPH_PRESET_TO_ID.get(presetID);
|
|
5346
|
+
if (emphType) {
|
|
5347
|
+
opts.emphasisType = emphType;
|
|
5348
|
+
opts.type = "appear";
|
|
5349
|
+
}
|
|
5350
|
+
} else if (cls === "mediacall") {
|
|
5351
|
+
opts.mediaType = "play";
|
|
5352
|
+
opts.type = "appear";
|
|
5353
|
+
}
|
|
5354
|
+
}
|
|
5355
|
+
const childTnLst = findChild(cTn, "p:childTnLst");
|
|
5356
|
+
if (childTnLst) for (const sub of childTnLst.elements ?? []) switch (sub.name) {
|
|
5357
|
+
case "p:animEffect": {
|
|
5358
|
+
const subCTn = findChild(sub, "p:cTn");
|
|
5359
|
+
if (subCTn) {
|
|
5360
|
+
const subDur = attr(subCTn, "dur");
|
|
5361
|
+
if (subDur) {
|
|
5362
|
+
const ms = parseDuration(subDur);
|
|
5363
|
+
if (ms !== void 0) opts.duration = ms;
|
|
5364
|
+
}
|
|
5365
|
+
}
|
|
5366
|
+
break;
|
|
5367
|
+
}
|
|
5368
|
+
case "p:anim": {
|
|
5369
|
+
const subCTn = findChild(sub, "p:cTn");
|
|
5370
|
+
if (subCTn) {
|
|
5371
|
+
const attrName = findChild(subCTn, "p:attrNameLst");
|
|
5372
|
+
if (attrName) {
|
|
5373
|
+
const name = findChild(attrName, "p:attrName");
|
|
5374
|
+
if (name) {
|
|
5375
|
+
const text = name.elements?.[0]?.text;
|
|
5376
|
+
if (text) opts.attributeName = text;
|
|
5377
|
+
}
|
|
5378
|
+
}
|
|
5379
|
+
}
|
|
5380
|
+
const from = findChild(sub, "p:cb");
|
|
5381
|
+
if (from) {
|
|
5382
|
+
const val = findChild(from, "p:val");
|
|
5383
|
+
if (val) {
|
|
5384
|
+
const v = attr(val, "val");
|
|
5385
|
+
if (v) opts.from = v;
|
|
5386
|
+
}
|
|
5387
|
+
}
|
|
5388
|
+
const toEl = findChild(sub, "p:tavLst");
|
|
5389
|
+
if (toEl) {
|
|
5390
|
+
const tav = findChild(toEl, "p:tav");
|
|
5391
|
+
if (tav) {
|
|
5392
|
+
const toVal = findChild(tav, "p:val");
|
|
5393
|
+
if (toVal) {
|
|
5394
|
+
const v = attr(toVal, "val");
|
|
5395
|
+
if (v) opts.to = v;
|
|
5396
|
+
}
|
|
5397
|
+
}
|
|
5398
|
+
}
|
|
5399
|
+
break;
|
|
5400
|
+
}
|
|
5401
|
+
case "p:animMotion": {
|
|
5402
|
+
opts.pathType = "customPath";
|
|
5403
|
+
const path = attr(sub, "path");
|
|
5404
|
+
if (path) opts.path = path;
|
|
5405
|
+
break;
|
|
5406
|
+
}
|
|
5407
|
+
case "p:animScale":
|
|
5408
|
+
opts.emphasisType = "growShrink";
|
|
5409
|
+
break;
|
|
5410
|
+
case "p:animRot":
|
|
5411
|
+
opts.emphasisType = "spin";
|
|
5412
|
+
break;
|
|
5413
|
+
case "p:animClr":
|
|
5414
|
+
opts.emphasisType = "colorChange";
|
|
5415
|
+
break;
|
|
5416
|
+
case "p:cmd":
|
|
5417
|
+
if (attr(sub, "type") === "call") opts.mediaType = "play";
|
|
5418
|
+
break;
|
|
5419
|
+
}
|
|
5420
|
+
return Object.keys(opts).length > 0 ? opts : void 0;
|
|
5421
|
+
}
|
|
5422
|
+
function extractTargetShapeId(el) {
|
|
5423
|
+
const cBhvr = findDeep$1(el, "p:cBhvr")[0];
|
|
5424
|
+
if (!cBhvr) return void 0;
|
|
5425
|
+
const tgtEl = findChild(cBhvr, "p:tgtEl");
|
|
5426
|
+
if (!tgtEl) return void 0;
|
|
5427
|
+
const spTgt = findChild(tgtEl, "p:spTgt");
|
|
5428
|
+
if (!spTgt) return void 0;
|
|
5429
|
+
return attrNum(spTgt, "spid");
|
|
5430
|
+
}
|
|
5431
|
+
function findDeep$1(parent, name) {
|
|
5432
|
+
const results = [];
|
|
5433
|
+
function walk(el) {
|
|
5434
|
+
if (el.name === name) {
|
|
5435
|
+
results.push(el);
|
|
5436
|
+
return;
|
|
5437
|
+
}
|
|
5438
|
+
for (const child of el.elements ?? []) walk(child);
|
|
5439
|
+
}
|
|
5440
|
+
for (const child of parent.elements ?? []) walk(child);
|
|
5441
|
+
return results;
|
|
5442
|
+
}
|
|
5443
|
+
/**
|
|
5444
|
+
* Parse OOXML duration string to milliseconds.
|
|
5445
|
+
* Format: "PT#H#M#S" or "###ms" or just a number string
|
|
5446
|
+
*/
|
|
5447
|
+
function parseDuration(val) {
|
|
5448
|
+
if (val.startsWith("PT")) {
|
|
5449
|
+
let ms = 0;
|
|
5450
|
+
const sMatch = val.match(/(\d+\.?\d*)S/);
|
|
5451
|
+
if (sMatch) ms += Math.round(parseFloat(sMatch[1]) * 1e3);
|
|
5452
|
+
const mMatch = val.match(/(\d+\.?\d*)M/);
|
|
5453
|
+
if (mMatch) ms += Math.round(parseFloat(mMatch[1]) * 6e4);
|
|
5454
|
+
const hMatch = val.match(/(\d+\.?\d*)H/);
|
|
5455
|
+
if (hMatch) ms += Math.round(parseFloat(hMatch[1]) * 36e5);
|
|
5456
|
+
return ms;
|
|
5457
|
+
}
|
|
5458
|
+
if (val === "indefinite") return void 0;
|
|
5459
|
+
const num = parseInt(val, 10);
|
|
5460
|
+
return isNaN(num) ? void 0 : num;
|
|
5461
|
+
}
|
|
5462
|
+
//#endregion
|
|
5194
5463
|
//#region src/parse/slide.ts
|
|
5195
5464
|
/**
|
|
5196
5465
|
* Slide parser for PPTX documents.
|
|
@@ -5217,9 +5486,31 @@ function parseSlide(el, ctx) {
|
|
|
5217
5486
|
}
|
|
5218
5487
|
if (slideChildren.length > 0) opts.children = slideChildren;
|
|
5219
5488
|
}
|
|
5489
|
+
const hf = findChild(cSld, "p:hf");
|
|
5490
|
+
if (hf) {
|
|
5491
|
+
const hfOpts = {};
|
|
5492
|
+
if (findChild(hf, "p:sldNum")) hfOpts.slideNumber = true;
|
|
5493
|
+
if (findChild(hf, "p:dt")) hfOpts.dateTime = true;
|
|
5494
|
+
if (findChild(hf, "p:ftr")) hfOpts.footer = true;
|
|
5495
|
+
if (findChild(hf, "p:hdr")) hfOpts.header = true;
|
|
5496
|
+
if (Object.keys(hfOpts).length > 0) opts.headerFooter = hfOpts;
|
|
5497
|
+
}
|
|
5220
5498
|
}
|
|
5221
5499
|
const transition = findChild(el, "p:transition");
|
|
5222
5500
|
if (transition) opts.transition = parseTransition(transition);
|
|
5501
|
+
const timing = findChild(el, "p:timing");
|
|
5502
|
+
if (timing) {
|
|
5503
|
+
const animMap = parseTiming(timing);
|
|
5504
|
+
if (animMap.size > 0 && opts.children) {
|
|
5505
|
+
const children = opts.children;
|
|
5506
|
+
for (let i = 0; i < children.length; i++) {
|
|
5507
|
+
const child = children[i];
|
|
5508
|
+
const inner = child[Object.keys(child)[0]] ?? {};
|
|
5509
|
+
const shapeId = inner.id;
|
|
5510
|
+
if (shapeId !== void 0 && animMap.has(shapeId)) inner.animation = animMap.get(shapeId);
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
}
|
|
5223
5514
|
for (const [, path] of ctx.slideRels) {
|
|
5224
5515
|
if (!path.includes("notesSlides")) continue;
|
|
5225
5516
|
const notesEl = ctx.pptx.doc.get(path);
|
|
@@ -5232,8 +5523,18 @@ function parseSlide(el, ctx) {
|
|
|
5232
5523
|
}
|
|
5233
5524
|
function parseSlideChild(el, ctx) {
|
|
5234
5525
|
switch (el.name) {
|
|
5235
|
-
case "p:sp":
|
|
5236
|
-
|
|
5526
|
+
case "p:sp": {
|
|
5527
|
+
const spPr = findChild(el, "p:spPr");
|
|
5528
|
+
const prstGeom = spPr ? findChild(spPr, "a:prstGeom") : void 0;
|
|
5529
|
+
if ((prstGeom ? attr(prstGeom, "prst") : void 0) === "line") return { line: parseLineShape(el) };
|
|
5530
|
+
return { shape: parseShape(el, ctx) };
|
|
5531
|
+
}
|
|
5532
|
+
case "p:pic": {
|
|
5533
|
+
const mediaType = detectMediaType(el);
|
|
5534
|
+
if (mediaType === "video") return { video: parseMediaFrame(el, ctx, "video") };
|
|
5535
|
+
if (mediaType === "audio") return { audio: parseMediaFrame(el, ctx, "audio") };
|
|
5536
|
+
return { picture: parsePicture(el, ctx) };
|
|
5537
|
+
}
|
|
5237
5538
|
case "p:graphicFrame": return parseGraphicFrame(el, ctx);
|
|
5238
5539
|
case "p:cxnSp": return { connector: parseConnector(el) };
|
|
5239
5540
|
case "p:grpSp": return { group: parseGroup(el, ctx) };
|
|
@@ -5352,6 +5653,48 @@ function parseShape(el, _ctx) {
|
|
|
5352
5653
|
if (txBody) parseTextBody(txBody, opts);
|
|
5353
5654
|
return opts;
|
|
5354
5655
|
}
|
|
5656
|
+
function parseLineShape(el) {
|
|
5657
|
+
const opts = {};
|
|
5658
|
+
const nvSpPr = findChild(el, "p:nvSpPr");
|
|
5659
|
+
if (nvSpPr) {
|
|
5660
|
+
const cNvPr = findChild(nvSpPr, "p:cNvPr");
|
|
5661
|
+
if (cNvPr) {
|
|
5662
|
+
const id = attrNum(cNvPr, "id");
|
|
5663
|
+
if (id !== void 0) opts.id = id;
|
|
5664
|
+
const name = attr(cNvPr, "name");
|
|
5665
|
+
if (name) opts.name = name;
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
const spPr = findChild(el, "p:spPr");
|
|
5669
|
+
if (spPr) {
|
|
5670
|
+
const xfrm = findChild(spPr, "a:xfrm");
|
|
5671
|
+
if (xfrm) {
|
|
5672
|
+
const off = findChild(xfrm, "a:off");
|
|
5673
|
+
const ext = findChild(xfrm, "a:ext");
|
|
5674
|
+
const flipH = attrBool(xfrm, "flipH");
|
|
5675
|
+
const flipV = attrBool(xfrm, "flipV");
|
|
5676
|
+
if (off && ext) {
|
|
5677
|
+
const offX = attrNum(off, "x") ?? 0;
|
|
5678
|
+
const offY = attrNum(off, "y") ?? 0;
|
|
5679
|
+
const cx = attrNum(ext, "cx") ?? 0;
|
|
5680
|
+
const cy = attrNum(ext, "cy") ?? 0;
|
|
5681
|
+
const x1 = flipH ? offX + cx : offX;
|
|
5682
|
+
const y1 = flipV ? offY + cy : offY;
|
|
5683
|
+
const x2 = flipH ? offX : offX + cx;
|
|
5684
|
+
const y2 = flipV ? offY : offY + cy;
|
|
5685
|
+
opts.x1 = convertEmuToPixels$1(x1);
|
|
5686
|
+
opts.y1 = convertEmuToPixels$1(y1);
|
|
5687
|
+
opts.x2 = convertEmuToPixels$1(x2);
|
|
5688
|
+
opts.y2 = convertEmuToPixels$1(y2);
|
|
5689
|
+
}
|
|
5690
|
+
}
|
|
5691
|
+
const fill = parseFillFromElement(spPr);
|
|
5692
|
+
if (fill) opts.fill = fill;
|
|
5693
|
+
const outline = parseOutlineFromElement(spPr);
|
|
5694
|
+
if (outline) opts.outline = outline;
|
|
5695
|
+
}
|
|
5696
|
+
return opts;
|
|
5697
|
+
}
|
|
5355
5698
|
function parsePicture(el, ctx) {
|
|
5356
5699
|
const opts = {};
|
|
5357
5700
|
const spPr = findChild(el, "p:spPr");
|
|
@@ -5604,6 +5947,24 @@ function parseTableFrame(el, tbl) {
|
|
|
5604
5947
|
if (attrBool(tblPr, "firstCol")) opts.firstCol = true;
|
|
5605
5948
|
if (attrBool(tblPr, "lastCol")) opts.lastCol = true;
|
|
5606
5949
|
if (attrBool(tblPr, "bandCol")) opts.bandCol = true;
|
|
5950
|
+
const borders = {};
|
|
5951
|
+
for (const [elName, key] of [
|
|
5952
|
+
["a:lnL", "left"],
|
|
5953
|
+
["a:lnR", "right"],
|
|
5954
|
+
["a:lnT", "top"],
|
|
5955
|
+
["a:lnB", "bottom"]
|
|
5956
|
+
]) {
|
|
5957
|
+
const borderEl = findChild(tblPr, elName);
|
|
5958
|
+
if (borderEl) {
|
|
5959
|
+
const borderOpts = {};
|
|
5960
|
+
const w = attrNum(borderEl, "w");
|
|
5961
|
+
if (w !== void 0) borderOpts.width = w;
|
|
5962
|
+
const fill = parseFillFromElement(borderEl);
|
|
5963
|
+
if (typeof fill === "string") borderOpts.color = fill;
|
|
5964
|
+
if (Object.keys(borderOpts).length > 0) borders[key] = borderOpts;
|
|
5965
|
+
}
|
|
5966
|
+
}
|
|
5967
|
+
if (Object.keys(borders).length > 0) opts.borders = borders;
|
|
5607
5968
|
}
|
|
5608
5969
|
const tblGrid = findChild(tbl, "a:tblGrid");
|
|
5609
5970
|
if (tblGrid) {
|
|
@@ -6027,6 +6388,34 @@ function parseFillFromElement(parent) {
|
|
|
6027
6388
|
};
|
|
6028
6389
|
}
|
|
6029
6390
|
if (findChild(parent, "a:noFill")) return { type: "none" };
|
|
6391
|
+
const pattFill = findChild(parent, "a:pattFill");
|
|
6392
|
+
if (pattFill) {
|
|
6393
|
+
const result = {
|
|
6394
|
+
type: "pattern",
|
|
6395
|
+
pattern: attr(pattFill, "prst") ?? ""
|
|
6396
|
+
};
|
|
6397
|
+
const fgClr = findChild(pattFill, "a:fgClr");
|
|
6398
|
+
if (fgClr) {
|
|
6399
|
+
const srgbClr = findChild(fgClr, "a:srgbClr");
|
|
6400
|
+
if (srgbClr) {
|
|
6401
|
+
const val = attr(srgbClr, "val");
|
|
6402
|
+
if (val) result.foregroundColor = val;
|
|
6403
|
+
}
|
|
6404
|
+
}
|
|
6405
|
+
const bgClr = findChild(pattFill, "a:bgClr");
|
|
6406
|
+
if (bgClr) {
|
|
6407
|
+
const srgbClr = findChild(bgClr, "a:srgbClr");
|
|
6408
|
+
if (srgbClr) {
|
|
6409
|
+
const val = attr(srgbClr, "val");
|
|
6410
|
+
if (val) result.backgroundColor = val;
|
|
6411
|
+
}
|
|
6412
|
+
}
|
|
6413
|
+
return result;
|
|
6414
|
+
}
|
|
6415
|
+
const blipFill = findChild(parent, "a:blipFill");
|
|
6416
|
+
if (blipFill) {
|
|
6417
|
+
if (findChild(blipFill, "a:blip")) return { type: "blip" };
|
|
6418
|
+
}
|
|
6030
6419
|
const gradFill = findChild(parent, "a:gradFill");
|
|
6031
6420
|
if (gradFill) {
|
|
6032
6421
|
const stops = [];
|
|
@@ -6068,6 +6457,11 @@ function parseOutlineFromElement(parent) {
|
|
|
6068
6457
|
if (val) opts.color = val;
|
|
6069
6458
|
}
|
|
6070
6459
|
}
|
|
6460
|
+
const prstDash = findChild(ln, "a:prstDash");
|
|
6461
|
+
if (prstDash) {
|
|
6462
|
+
const val = attr(prstDash, "val");
|
|
6463
|
+
if (val) opts.dashStyle = val;
|
|
6464
|
+
}
|
|
6071
6465
|
return Object.keys(opts).length > 0 ? opts : void 0;
|
|
6072
6466
|
}
|
|
6073
6467
|
function parseEffectsFromElement(parent) {
|
|
@@ -6209,6 +6603,96 @@ function imageTypeFromPath(path) {
|
|
|
6209
6603
|
default: return "png";
|
|
6210
6604
|
}
|
|
6211
6605
|
}
|
|
6606
|
+
const VIDEO_EXT_URI = "{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}";
|
|
6607
|
+
const AUDIO_EXT_URI = "{CF1602FD-DB20-4165-A070-5F299619DA56}";
|
|
6608
|
+
/**
|
|
6609
|
+
* Check if a p:pic element is actually a video or audio frame
|
|
6610
|
+
* by looking for media extension URIs in nvPr > extLst.
|
|
6611
|
+
*/
|
|
6612
|
+
function detectMediaType(el) {
|
|
6613
|
+
const nvPicPr = findChild(el, "p:nvPicPr");
|
|
6614
|
+
if (!nvPicPr) return void 0;
|
|
6615
|
+
const nvPr = findChild(nvPicPr, "p:nvPr");
|
|
6616
|
+
if (!nvPr) return void 0;
|
|
6617
|
+
const extLst = findChild(nvPr, "p:extLst");
|
|
6618
|
+
if (!extLst) return void 0;
|
|
6619
|
+
for (const ext of extLst.elements ?? []) {
|
|
6620
|
+
if (ext.name !== "p:ext") continue;
|
|
6621
|
+
const uri = attr(ext, "uri");
|
|
6622
|
+
if (uri === VIDEO_EXT_URI) return "video";
|
|
6623
|
+
if (uri === AUDIO_EXT_URI) return "audio";
|
|
6624
|
+
}
|
|
6625
|
+
}
|
|
6626
|
+
function parseMediaFrame(el, ctx, mediaKind) {
|
|
6627
|
+
const opts = {};
|
|
6628
|
+
const spPr = findChild(el, "p:spPr");
|
|
6629
|
+
if (spPr) parseTransformFromSpPr(spPr, opts);
|
|
6630
|
+
const nvPicPr = findChild(el, "p:nvPicPr");
|
|
6631
|
+
if (nvPicPr) {
|
|
6632
|
+
const cNvPr = findChild(nvPicPr, "p:cNvPr");
|
|
6633
|
+
if (cNvPr) {
|
|
6634
|
+
const name = attr(cNvPr, "name");
|
|
6635
|
+
if (name) opts.name = name;
|
|
6636
|
+
}
|
|
6637
|
+
}
|
|
6638
|
+
const blip = findDeep(el, "a:blip")[0];
|
|
6639
|
+
if (blip) {
|
|
6640
|
+
const rEmbed = attr(blip, "r:embed");
|
|
6641
|
+
if (rEmbed) {
|
|
6642
|
+
const mediaPath = ctx.slideRels.get(rEmbed);
|
|
6643
|
+
if (mediaPath) {
|
|
6644
|
+
const data = ctx.pptx.doc.getRaw(mediaPath);
|
|
6645
|
+
if (data) {
|
|
6646
|
+
opts.data = data;
|
|
6647
|
+
opts.type = mediaTypeFromPath(mediaPath, mediaKind);
|
|
6648
|
+
}
|
|
6649
|
+
}
|
|
6650
|
+
}
|
|
6651
|
+
}
|
|
6652
|
+
if (mediaKind === "video") {
|
|
6653
|
+
const blipFill = findChild(el, "p:blipFill");
|
|
6654
|
+
if (blipFill) {
|
|
6655
|
+
const posterBlip = findChild(blipFill, "a:blip");
|
|
6656
|
+
if (posterBlip) {
|
|
6657
|
+
const rEmbed = attr(posterBlip, "r:embed");
|
|
6658
|
+
if (rEmbed) {
|
|
6659
|
+
const posterPath = ctx.slideRels.get(rEmbed);
|
|
6660
|
+
if (posterPath) {
|
|
6661
|
+
const posterData = ctx.pptx.doc.getRaw(posterPath);
|
|
6662
|
+
if (posterData) {
|
|
6663
|
+
opts.poster = posterData;
|
|
6664
|
+
opts.posterType = imageTypeFromPath(posterPath);
|
|
6665
|
+
}
|
|
6666
|
+
}
|
|
6667
|
+
}
|
|
6668
|
+
}
|
|
6669
|
+
}
|
|
6670
|
+
}
|
|
6671
|
+
return opts;
|
|
6672
|
+
}
|
|
6673
|
+
function mediaTypeFromPath(path, kind) {
|
|
6674
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
6675
|
+
if (kind === "video") switch (ext) {
|
|
6676
|
+
case "mp4": return "mp4";
|
|
6677
|
+
case "mov":
|
|
6678
|
+
case "qt": return "mov";
|
|
6679
|
+
case "wmv": return "wmv";
|
|
6680
|
+
case "avi": return "avi";
|
|
6681
|
+
default: return "mp4";
|
|
6682
|
+
}
|
|
6683
|
+
else switch (ext) {
|
|
6684
|
+
case "mp3": return "mp3";
|
|
6685
|
+
case "wav": return "wav";
|
|
6686
|
+
case "wma": return "wma";
|
|
6687
|
+
case "aac": return "aac";
|
|
6688
|
+
default: return "mp3";
|
|
6689
|
+
}
|
|
6690
|
+
}
|
|
6691
|
+
/**
|
|
6692
|
+
* Parse a:blipFill from a shape's spPr.
|
|
6693
|
+
* Used when a shape has an image fill (not a picture element).
|
|
6694
|
+
* Returns { type: "blip", data } if found.
|
|
6695
|
+
*/
|
|
6212
6696
|
//#endregion
|
|
6213
6697
|
//#region src/parse/slide-layout.ts
|
|
6214
6698
|
const NAME_TO_TYPE = {
|
|
@@ -6361,7 +6845,7 @@ function parseSlideRels(doc, slidePaths, refs) {
|
|
|
6361
6845
|
}
|
|
6362
6846
|
}
|
|
6363
6847
|
function parsePptx(data) {
|
|
6364
|
-
const doc = parseArchive(data);
|
|
6848
|
+
const doc = parseArchive(toUint8Array(data));
|
|
6365
6849
|
const presentation = doc.get("ppt/presentation.xml");
|
|
6366
6850
|
const relsXml = doc.get("ppt/_rels/presentation.xml.rels");
|
|
6367
6851
|
const slides = [];
|
|
@@ -6535,12 +7019,27 @@ function parsePresentation(data) {
|
|
|
6535
7019
|
masterDefs.push(masterDef);
|
|
6536
7020
|
}
|
|
6537
7021
|
if (masterCount > 1) opts.masters = masterDefs;
|
|
7022
|
+
const commentAuthors = /* @__PURE__ */ new Map();
|
|
7023
|
+
if (pptx.partRefs.commentAuthors) {
|
|
7024
|
+
const authorsEl = pptx.doc.get(pptx.partRefs.commentAuthors);
|
|
7025
|
+
if (authorsEl) for (const child of authorsEl.elements ?? []) {
|
|
7026
|
+
if (child.name !== "p:cmAuthor") continue;
|
|
7027
|
+
const id = attrNum(child, "id");
|
|
7028
|
+
const name = attr(child, "name");
|
|
7029
|
+
const initials = attr(child, "initials");
|
|
7030
|
+
if (id !== void 0) commentAuthors.set(id, {
|
|
7031
|
+
name: name ?? "",
|
|
7032
|
+
initials: initials ?? ""
|
|
7033
|
+
});
|
|
7034
|
+
}
|
|
7035
|
+
}
|
|
6538
7036
|
const result = [];
|
|
6539
7037
|
for (let si = 0; si < pptx.slides.length; si++) {
|
|
6540
7038
|
const slidePath = pptx.slides[si];
|
|
6541
7039
|
const slideEl = pptx.doc.get(slidePath);
|
|
6542
7040
|
if (!slideEl) continue;
|
|
6543
|
-
const
|
|
7041
|
+
const slideRels = parseSlideRelMap(pptx.doc, slidePath);
|
|
7042
|
+
const slideOpts = parseSlide(slideEl, new ParseContext(pptx, slideRels));
|
|
6544
7043
|
const layoutPath = slideLayoutPaths.get(slidePath);
|
|
6545
7044
|
if (layoutPath) {
|
|
6546
7045
|
const layoutEl = pptx.doc.get(layoutPath);
|
|
@@ -6551,11 +7050,57 @@ function parsePresentation(data) {
|
|
|
6551
7050
|
if (masterIdx >= 0 && masterDefs[masterIdx]) slideOpts.master = masterDefs[masterIdx].name;
|
|
6552
7051
|
}
|
|
6553
7052
|
}
|
|
7053
|
+
for (const [, relPath] of slideRels) {
|
|
7054
|
+
if (!relPath.includes("/comments/")) continue;
|
|
7055
|
+
const commentsEl = pptx.doc.get(relPath);
|
|
7056
|
+
if (!commentsEl) continue;
|
|
7057
|
+
const comments = [];
|
|
7058
|
+
for (const cm of commentsEl.elements ?? []) {
|
|
7059
|
+
if (cm.name !== "p:cm") continue;
|
|
7060
|
+
const authorId = attrNum(cm, "authorId");
|
|
7061
|
+
const dt = attr(cm, "dt");
|
|
7062
|
+
const idx = attrNum(cm, "idx");
|
|
7063
|
+
const author = authorId !== void 0 ? commentAuthors.get(authorId) : void 0;
|
|
7064
|
+
const pos = findChild(cm, "p:pos");
|
|
7065
|
+
const x = pos ? attrNum(pos, "x") : void 0;
|
|
7066
|
+
const y = pos ? attrNum(pos, "y") : void 0;
|
|
7067
|
+
const txBody = findChild(cm, "p:txBody");
|
|
7068
|
+
const text = txBody ? extractCommentText(txBody) : "";
|
|
7069
|
+
const commentEntry = {};
|
|
7070
|
+
if (authorId !== void 0) commentEntry.authorId = authorId;
|
|
7071
|
+
if (author) commentEntry.author = author.name;
|
|
7072
|
+
if (idx !== void 0) commentEntry.idx = idx;
|
|
7073
|
+
if (dt) commentEntry.date = dt;
|
|
7074
|
+
if (x !== void 0) commentEntry.x = x;
|
|
7075
|
+
if (y !== void 0) commentEntry.y = y;
|
|
7076
|
+
if (text) commentEntry.text = text;
|
|
7077
|
+
comments.push(commentEntry);
|
|
7078
|
+
}
|
|
7079
|
+
if (comments.length > 0) slideOpts.comments = comments;
|
|
7080
|
+
break;
|
|
7081
|
+
}
|
|
6554
7082
|
result.push(slideOpts);
|
|
6555
7083
|
}
|
|
6556
7084
|
opts.slides = result;
|
|
6557
7085
|
return opts;
|
|
6558
7086
|
}
|
|
7087
|
+
/**
|
|
7088
|
+
* Extract plain text from a p:txBody in a comment element.
|
|
7089
|
+
*/
|
|
7090
|
+
function extractCommentText(txBody) {
|
|
7091
|
+
const parts = [];
|
|
7092
|
+
for (const p of txBody.elements ?? []) {
|
|
7093
|
+
if (p.name !== "a:p") continue;
|
|
7094
|
+
for (const r of p.elements ?? []) {
|
|
7095
|
+
if (r.name !== "a:r") continue;
|
|
7096
|
+
for (const t of r.elements ?? []) if (t.name === "a:t") {
|
|
7097
|
+
const text = textOf(t);
|
|
7098
|
+
if (text) parts.push(text);
|
|
7099
|
+
}
|
|
7100
|
+
}
|
|
7101
|
+
}
|
|
7102
|
+
return parts.join("");
|
|
7103
|
+
}
|
|
6559
7104
|
__reExport(/* @__PURE__ */ __exportAll({
|
|
6560
7105
|
AppProperties: () => AppProperties,
|
|
6561
7106
|
AudioFrame: () => AudioFrame,
|