@office-open/pptx 0.4.5 → 0.4.6

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.mjs CHANGED
@@ -2,7 +2,7 @@ import { i as __toCommonJS, n as __exportAll, r as __reExport, t as __esmMin } f
2
2
  import { AppProperties, BaseXmlComponent, BuilderElement, Formatter, ImportedXmlComponent, NextAttributeComponent, OoxmlMimeType, PrettifyType, Relationships, StringContainer, XmlComponent, addSmartArtRelationships, buildCorePropertiesXml, collectPlaceholderKeys, convertEmuToInches, convertEmuToPixels, convertEmuToPoints, convertInchesToEmu, convertOutput, convertPixelsToEmu, convertPixelsToEmu as convertPixelsToEmu$1, convertPointsToEmu, convertPrettifyType, escapeRegex, formatId, getReferencedMedia, hasPlaceholders, hashedId, parseDocument, replaceChartPlaceholders, replaceImagePlaceholders, replaceSmartArtPlaceholders, uniqueId, uniqueNumericIdCreator, uniqueUuid } from "@office-open/core";
3
3
  import { BevelPresetType, CompoundLine, LineCap, LineJoin, PathShadeType, PenAlignment, PresetDash, PresetGeometry, PresetMaterialType, Stretch, TileFlipMode, buildFill, createBevel, createBlip, createBottomBevel, createColorElement, createColorTransforms, createEffectList, createEffectList as createEffectList$1, createGradientFill, createGradientStop, createGroupTransform2D, createOutline, createOutline as createOutline$1, createScene3D, createScene3D as createScene3D$1, createShape3D, createShape3D as createShape3D$1, createTransform2D, extractBlipFillMedia } from "@office-open/core/drawingml";
4
4
  import { ChartCollection, ChartSpace } from "@office-open/core/chart";
5
- import { attr, attrs, escapeXml, xml } from "@office-open/xml";
5
+ import { attr, xml } from "@office-open/xml";
6
6
  import { DEFAULT_DRAWING_XML, SmartArtCollection, createDataModel, getColorXml, getLayoutXml, getStyleXml } from "@office-open/core/smartart";
7
7
  import { Zip, ZipDeflate, ZipPassThrough, zipSync } from "fflate";
8
8
  export * from "@office-open/core/values";
@@ -599,9 +599,6 @@ init_xml_components();
599
599
  function buildEndParagraphRunProperties(lang = "en-US") {
600
600
  return { "a:endParaRPr": { _attr: { lang } } };
601
601
  }
602
- function buildEndParagraphRunPropertiesXml(lang = "en-US") {
603
- return `<a:endParaRPr${attrs({ lang })}/>`;
604
- }
605
602
  /**
606
603
  * a:endParaRPr — End paragraph run properties.
607
604
  * Lazy: stores lang, builds XML object in prepForXml.
@@ -683,48 +680,7 @@ var ParagraphProperties = class extends XmlComponent {
683
680
  prepForXml(_context) {
684
681
  return buildParagraphProperties(this.options);
685
682
  }
686
- toXml() {
687
- return buildParagraphPropertiesXml(this.options);
688
- }
689
683
  };
690
- function buildBulletChildrenXml(options) {
691
- if (options.type === "none") return "<a:buNone/>";
692
- let s = "";
693
- if (options.color) s += `<a:buClr><a:srgbClr${attrs({ val: options.color.replace("#", "") })}/></a:buClr>`;
694
- if (options.size !== void 0) s += `<a:buSzPct${attrs({ val: `${options.size}%` })}/>`;
695
- s += `<a:buFont${attrs({
696
- typeface: "Arial",
697
- panose: "020B0604020202020204",
698
- pitchFamily: "34",
699
- charset: "0"
700
- })}/>`;
701
- if (options.type === "char") s += `<a:buChar${attrs({ char: options.char ?? "•" })}/>`;
702
- else if (options.type === "autoNum") {
703
- const buAttrs = { type: options.format ?? "arabicPeriod" };
704
- if (options.startAt !== void 0) buAttrs.startAt = options.startAt;
705
- s += `<a:buAutoNum${attrs(buAttrs)}/>`;
706
- }
707
- return s;
708
- }
709
- function buildParagraphPropertiesXml(options) {
710
- const attrStr = attrs({
711
- algn: options.alignment ? TextAlignment[options.alignment] : void 0,
712
- lvl: options.indentLevel,
713
- marL: options.marginIndent,
714
- marR: options.marginRight,
715
- defTabSz: options.defTabSize
716
- });
717
- const body = [];
718
- if (options.lineSpacing !== void 0) body.push(`<a:lnSpc><a:spcPct${attrs({ val: options.lineSpacing * 1e3 })}/></a:lnSpc>`);
719
- if (options.lineSpacingPoints !== void 0) body.push(`<a:lnSpc><a:spcPts${attrs({ val: options.lineSpacingPoints * 100 })}/></a:lnSpc>`);
720
- if (options.marginBottom !== void 0 || options.marginTop !== void 0) body.push(`<a:spcAft><a:spcPts${attrs({ val: options.marginBottom ?? 0 })}/></a:spcAft>`);
721
- if (options.marginTop !== void 0) body.push(`<a:spcBef><a:spcPts${attrs({ val: options.marginTop })}/></a:spcBef>`);
722
- if (options.bullet) body.push(buildBulletChildrenXml(options.bullet));
723
- else if (options.bulletNone !== false) body.push("<a:buNone/>");
724
- if (!attrStr && body.length === 0) return "";
725
- if (body.length === 0) return `<a:pPr${attrStr}/>`;
726
- return `<a:pPr${attrStr}>${body.join("")}</a:pPr>`;
727
- }
728
684
  //#endregion
729
685
  //#region src/file/shape/paragraph/run-properties.ts
730
686
  init_fill();
@@ -821,66 +777,7 @@ var RunProperties = class extends XmlComponent {
821
777
  } }).prepForXml(context) ?? void 0;
822
778
  return buildRunProperties(opts, hyperlinkKey, fillObj, effectListObj, outlineObj);
823
779
  }
824
- toXml(context) {
825
- const opts = this.options;
826
- let hyperlinkKey;
827
- if (opts.hyperlink) {
828
- hyperlinkKey = `hlink_${nextHyperlinkId++}`;
829
- context.fileData?.Hyperlinks?.addHyperlink(hyperlinkKey, opts.hyperlink.url, opts.hyperlink.tooltip);
830
- }
831
- let fillObj;
832
- if (opts.fill !== void 0) fillObj = buildFill(opts.fill).prepForXml(context) ?? void 0;
833
- let outlineObj;
834
- if (opts.outline) outlineObj = createOutline$1({
835
- width: 12700,
836
- type: "solidFill",
837
- color: { value: "000000" }
838
- }).prepForXml(context) ?? void 0;
839
- let effectListObj;
840
- if (opts.shadow) effectListObj = createEffectList$1({ outerShadow: {
841
- blurRadius: 50800,
842
- distance: 38100,
843
- direction: 27e5,
844
- color: {
845
- value: "000000",
846
- transforms: { alpha: 4e4 }
847
- }
848
- } }).prepForXml(context) ?? void 0;
849
- return buildRunPropertiesXml(opts, hyperlinkKey, fillObj, effectListObj, outlineObj);
850
- }
851
780
  };
852
- /**
853
- * String version of buildRunProperties for zero-allocation serialization.
854
- */
855
- function buildRunPropertiesXml(options, hyperlinkKey, fillObject, effectListObject, outlineObject) {
856
- const a = {};
857
- if (options.fontSize) a.sz = options.fontSize * 100;
858
- if (options.bold !== void 0) a.b = options.bold;
859
- if (options.italic !== void 0) a.i = options.italic;
860
- if (options.underline) a.u = UnderlineStyle[options.underline];
861
- if (options.lang) a.lang = options.lang;
862
- if (options.strike) a.strike = StrikeStyle[options.strike];
863
- if (options.baseline !== void 0) a.baseline = options.baseline;
864
- if (options.capitalization) a.cap = TextCapitalization[options.capitalization] ?? options.capitalization;
865
- if (options.spacing !== void 0) a.spc = options.spacing;
866
- if (options.noProof !== void 0) a.noProof = options.noProof;
867
- if (options.dirty !== void 0) a.dirty = options.dirty;
868
- const attrStr = attrs(a);
869
- const body = [];
870
- if (options.font) body.push(`<a:latin${attrs({ typeface: options.font })}/><a:ea${attrs({ typeface: options.font })}/>`);
871
- if (options.hyperlink && hyperlinkKey) {
872
- const h = { "r:id": `{hlink:${hyperlinkKey}}` };
873
- if (options.hyperlink.tooltip) h.tooltip = options.hyperlink.tooltip;
874
- body.push(`<a:hlinkClick${attrs(h)}/>`);
875
- }
876
- if (options.rightToLeft !== void 0) body.push(`<a:rtl${attrs({ val: options.rightToLeft ? 1 : 0 })}/>`);
877
- if (fillObject) body.push(xml(fillObject));
878
- if (outlineObject) body.push(xml(outlineObject));
879
- if (effectListObject) body.push(xml(effectListObject));
880
- if (!attrStr && body.length === 0) return "";
881
- if (body.length === 0) return `<a:rPr${attrStr}/>`;
882
- return `<a:rPr${attrStr}>${body.join("")}</a:rPr>`;
883
- }
884
781
  //#endregion
885
782
  //#region src/file/shape/paragraph/run.ts
886
783
  init_xml_components();
@@ -903,16 +800,6 @@ var TextRun = class extends XmlComponent {
903
800
  if (this.options.text) children.push({ "a:t": [this.options.text] });
904
801
  return { "a:r": children.length === 0 ? {} : children.length === 1 && "_attr" in children[0] ? children[0] : children };
905
802
  }
906
- toXml(context) {
907
- let s = "<a:r>";
908
- if (RunProperties.hasProperties(this.options)) {
909
- const rp = new RunProperties(this.options);
910
- s += rp.toXml(context);
911
- }
912
- if (this.options.text) s += `<a:t>${escapeXml(this.options.text)}</a:t>`;
913
- s += "</a:r>";
914
- return s;
915
- }
916
803
  };
917
804
  //#endregion
918
805
  //#region src/file/shape/paragraph/paragraph.ts
@@ -942,16 +829,6 @@ var Paragraph = class extends XmlComponent {
942
829
  children.push(buildEndParagraphRunProperties());
943
830
  return { "a:p": children };
944
831
  }
945
- toXml(context) {
946
- let s = "<a:p>";
947
- const pPr = buildParagraphPropertiesXml(this.options.properties ?? {});
948
- if (pPr) s += pPr;
949
- if (this.options.text) s += new TextRun(this.options.text).toXml(context);
950
- if (this.options.children) for (const child of this.options.children) s += child.toXml(context);
951
- s += buildEndParagraphRunPropertiesXml();
952
- s += "</a:p>";
953
- return s;
954
- }
955
832
  };
956
833
  //#endregion
957
834
  //#region src/file/table/table-cell-properties.ts
@@ -1072,25 +949,6 @@ function buildBodyPr(options) {
1072
949
  bodyPrContent.push(...bodyPrChildren);
1073
950
  return { "a:bodyPr": bodyPrContent.length === 1 && "_attr" in bodyPrContent[0] ? bodyPrContent[0] : bodyPrContent.length > 0 ? bodyPrContent : {} };
1074
951
  }
1075
- function buildBodyPrXml(options) {
1076
- let s = "<a:bodyPr";
1077
- const a = {};
1078
- if (options.vertical) a.vert = options.vertical;
1079
- if (options.anchor) a.anchor = VerticalAlignment[options.anchor];
1080
- if (options.wrap) a.wrap = options.wrap;
1081
- if (options.margins?.top !== void 0) a.tIns = options.margins.top;
1082
- if (options.margins?.bottom !== void 0) a.bIns = options.margins.bottom;
1083
- if (options.margins?.left !== void 0) a.lIns = options.margins.left;
1084
- if (options.margins?.right !== void 0) a.rIns = options.margins.right;
1085
- if (options.columns !== void 0) a.numCol = options.columns;
1086
- if (options.columnSpacing !== void 0) a.spcCol = options.columnSpacing * 100;
1087
- s += attrs(a);
1088
- let inner = "";
1089
- if (options.autoFit === "normal") inner += "<a:normAutofit/>";
1090
- else if (options.autoFit === "shape") inner += "<a:spAutoFit/>";
1091
- else if (options.autoFit === "none") inner += "<a:noAutofit/>";
1092
- return inner ? `${s}>${inner}</a:bodyPr>` : `${s}/>`;
1093
- }
1094
952
  /**
1095
953
  * p:txBody — Text body within a shape.
1096
954
  * Lazy: stores options, builds XML object in prepForXml.
@@ -1115,18 +973,6 @@ var TextBody = class extends XmlComponent {
1115
973
  }
1116
974
  return { "p:txBody": children };
1117
975
  }
1118
- toXml(context) {
1119
- let s = "<p:txBody>";
1120
- s += buildBodyPrXml(this.options);
1121
- s += "<a:lstStyle/>";
1122
- if (this.options.paragraphs) for (const p of this.options.paragraphs) {
1123
- const para = typeof p === "string" ? new Paragraph({ children: [new TextRun({ text: p })] }) : p;
1124
- s += para.toXml(context);
1125
- }
1126
- else s += new Paragraph().toXml(context);
1127
- s += "</p:txBody>";
1128
- return s;
1129
- }
1130
976
  };
1131
977
  //#endregion
1132
978
  //#region src/file/notes/notes-slide.ts
@@ -2848,708 +2694,86 @@ var SlideTiming = class extends XmlComponent {
2848
2694
  }
2849
2695
  };
2850
2696
  //#endregion
2851
- //#region src/file/drawingml/transform-2d.ts
2697
+ //#region src/file/transition/transition.ts
2852
2698
  init_xml_components();
2699
+ const ORIENT_TYPES = new Set([
2700
+ "blinds",
2701
+ "checker",
2702
+ "comb",
2703
+ "randomBar"
2704
+ ]);
2705
+ const SIDE_DIR_TYPES = new Set(["push", "wipe"]);
2706
+ const EIGHT_DIR_TYPES = new Set(["cover", "pull"]);
2707
+ function buildTransitionElement(type, dir, orient, thruBlk, spokes) {
2708
+ const attrs = {};
2709
+ if (ORIENT_TYPES.has(type) && dir) attrs.dir = dir;
2710
+ else if (SIDE_DIR_TYPES.has(type) && dir) attrs.dir = dir;
2711
+ else if (EIGHT_DIR_TYPES.has(type) && dir) attrs.dir = dir;
2712
+ else if (type === "strips" && dir) attrs.dir = dir;
2713
+ else if ((type === "fade" || type === "cut") && thruBlk !== void 0) attrs.thruBlk = thruBlk ? 1 : 0;
2714
+ else if (type === "split") {
2715
+ attrs.orient = orient ?? "horz";
2716
+ attrs.dir = dir ?? "out";
2717
+ } else if (type === "wheel") attrs.spokes = spokes ?? 4;
2718
+ else if (type === "zoom" && dir) attrs.dir = dir;
2719
+ return { [`p:${type}`]: Object.keys(attrs).length > 0 ? { _attr: attrs } : {} };
2720
+ }
2721
+ function buildTransition(options) {
2722
+ const children = [];
2723
+ const attrs = {};
2724
+ if (options.speed) attrs.spd = options.speed;
2725
+ if (options.advanceOnClick !== void 0) attrs.advClick = options.advanceOnClick ? 1 : 0;
2726
+ if (options.advanceAfterTime !== void 0) attrs.advTm = options.advanceAfterTime;
2727
+ if (Object.keys(attrs).length > 0) children.push({ _attr: attrs });
2728
+ if (options.type) children.push(buildTransitionElement(options.type, options.dir, options.orient, options.thruBlk, options.spokes));
2729
+ return { "p:transition": children.length === 0 ? {} : children };
2730
+ }
2853
2731
  /**
2854
- * a:xfrm / p:xfrm2D transform for shapes and graphic frames (position + size in EMUs).
2855
- * Delegates to core createTransform2D.
2732
+ * p:transitionSlide transition effect.
2733
+ * Lazy: stores options, builds XML object in prepForXml.
2856
2734
  */
2857
- var Transform2D = class extends XmlComponent {
2858
- core;
2859
- constructor(options, prefix = "a") {
2860
- super(`${prefix}:xfrm`);
2861
- this.core = createTransform2D(options, `${prefix}:xfrm`);
2735
+ var Transition = class extends BaseXmlComponent {
2736
+ options;
2737
+ constructor(options = {}) {
2738
+ super("p:transition");
2739
+ this.options = options;
2862
2740
  }
2863
- prepForXml(context) {
2864
- return this.core["prepForXml"]?.(context);
2741
+ prepForXml(_context) {
2742
+ return buildTransition(this.options);
2865
2743
  }
2866
2744
  };
2867
2745
  //#endregion
2868
- //#region src/file/media/audio-frame.ts
2746
+ //#region src/file/slide/slide.ts
2869
2747
  init_xml_components();
2870
- const MEDIA_EXT_URI$1 = "{CF1602FD-DB20-4165-A070-5F299619DA56}";
2748
+ function isAnimatable(child) {
2749
+ return "ShapeId" in child && "Animation" in child;
2750
+ }
2751
+ function collectAnimations(children) {
2752
+ const entries = [];
2753
+ for (const child of children) if (isAnimatable(child)) {
2754
+ const anim = child.Animation;
2755
+ if (anim) entries.push({
2756
+ spid: child.ShapeId,
2757
+ options: anim
2758
+ });
2759
+ }
2760
+ return entries;
2761
+ }
2871
2762
  /**
2872
- * p:picAn audio frame on a slide.
2873
- *
2874
- * Uses a media relationship for the audio file (via {media:fileName} placeholder).
2763
+ * p:sldA slide in a presentation.
2764
+ * Lazy: stores options, builds XML object in prepForXml.
2875
2765
  */
2876
- var AudioFrame = class AudioFrame extends XmlComponent {
2877
- static nextId = 200;
2878
- audioData;
2879
- shapeId;
2880
- animationOptions;
2881
- constructor(options) {
2882
- super("p:pic");
2883
- const id = AudioFrame.nextId++;
2884
- this.shapeId = id;
2885
- this.animationOptions = options.animation;
2886
- const name = options.name ?? `Audio ${id}`;
2887
- const mediaFileName = `${name.replace(/\s+/g, "_")}.${options.type}`;
2888
- this.audioData = {
2889
- type: options.type,
2890
- fileName: mediaFileName,
2891
- transformation: {
2892
- pixels: {
2893
- x: options.width ?? 0,
2894
- y: options.height ?? 0
2895
- },
2896
- emus: {
2897
- x: convertPixelsToEmu$1(options.width ?? 0),
2898
- y: convertPixelsToEmu$1(options.height ?? 0)
2899
- }
2900
- },
2901
- data: options.data
2902
- };
2903
- this.root.push(new BuilderElement({
2904
- name: "p:nvPicPr",
2905
- children: [
2906
- new BuilderElement({
2907
- name: "a:cNvPr",
2908
- attributes: {
2909
- id: {
2910
- key: "id",
2911
- value: id
2912
- },
2913
- name: {
2914
- key: "name",
2915
- value: name
2916
- },
2917
- descr: {
2918
- key: "descr",
2919
- value: ""
2920
- }
2921
- }
2922
- }),
2923
- new BuilderElement({
2924
- name: "a:cNvPicPr",
2925
- children: [new BuilderElement({
2926
- name: "a:picLocks",
2927
- attributes: { noChangeAspect: {
2928
- key: "noChangeAspect",
2929
- value: "1"
2930
- } }
2931
- })]
2932
- }),
2933
- new BuilderElement({
2934
- name: "p:nvPr",
2935
- children: [new BuilderElement({
2936
- name: "p:extLst",
2937
- children: [new BuilderElement({
2938
- name: "p:ext",
2939
- attributes: { uri: {
2940
- key: "uri",
2941
- value: MEDIA_EXT_URI$1
2942
- } },
2943
- children: [new BuilderElement({
2944
- name: "p14:media",
2945
- attributes: {
2946
- "r:embed": {
2947
- key: "r:embed",
2948
- value: `{media:${mediaFileName}}`
2949
- },
2950
- "xmlns:p14": {
2951
- key: "xmlns:p14",
2952
- value: "http://schemas.microsoft.com/office/powerpoint/2010/main"
2953
- }
2954
- }
2955
- })]
2956
- })]
2957
- })]
2958
- })
2959
- ]
2960
- }));
2961
- this.root.push(new BuilderElement({
2962
- name: "p:blipFill",
2963
- children: [new BuilderElement({
2964
- name: "a:stretch",
2965
- children: [new BuilderElement({ name: "a:fillRect" })]
2966
- })]
2967
- }));
2968
- this.root.push(new BuilderElement({
2969
- name: "p:spPr",
2970
- children: [new Transform2D({
2971
- x: convertPixelsToEmu$1(options.x ?? 0),
2972
- y: convertPixelsToEmu$1(options.y ?? 0),
2973
- width: convertPixelsToEmu$1(options.width ?? 0),
2974
- height: convertPixelsToEmu$1(options.height ?? 0)
2975
- }), new PresetGeometry({ preset: "rect" })]
2976
- }));
2977
- }
2978
- get ShapeId() {
2979
- return this.shapeId;
2980
- }
2981
- get Animation() {
2982
- return this.animationOptions;
2983
- }
2984
- prepForXml(context) {
2985
- context.fileData?.Media.addMedia(this.audioData.fileName, this.audioData);
2986
- return super.prepForXml(context);
2987
- }
2988
- };
2989
- //#endregion
2990
- //#region src/file/media/video-frame.ts
2991
- init_xml_components();
2992
- const MEDIA_EXT_URI = "{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}";
2993
- /** Minimal 1x1 transparent PNG (67 bytes). */
2994
- const MINIMAL_PNG = new Uint8Array([
2995
- 137,
2996
- 80,
2997
- 78,
2998
- 71,
2999
- 13,
3000
- 10,
3001
- 26,
3002
- 10,
3003
- 0,
3004
- 0,
3005
- 0,
3006
- 13,
3007
- 73,
3008
- 72,
3009
- 68,
3010
- 82,
3011
- 0,
3012
- 0,
3013
- 0,
3014
- 1,
3015
- 0,
3016
- 0,
3017
- 0,
3018
- 1,
3019
- 8,
3020
- 6,
3021
- 0,
3022
- 0,
3023
- 0,
3024
- 31,
3025
- 21,
3026
- 196,
3027
- 137,
3028
- 0,
3029
- 0,
3030
- 0,
3031
- 13,
3032
- 73,
3033
- 68,
3034
- 65,
3035
- 84,
3036
- 8,
3037
- 215,
3038
- 99,
3039
- 24,
3040
- 5,
3041
- 163,
3042
- 0,
3043
- 0,
3044
- 0,
3045
- 2,
3046
- 0,
3047
- 1,
3048
- 226,
3049
- 33,
3050
- 188,
3051
- 51,
3052
- 0,
3053
- 0,
3054
- 0,
3055
- 0,
3056
- 73,
3057
- 69,
3058
- 78,
3059
- 68,
3060
- 174,
3061
- 66,
3062
- 96,
3063
- 130
3064
- ]);
3065
- /**
3066
- * p:pic — A video frame on a slide.
3067
- *
3068
- * Uses three relationships:
3069
- * - Image relationship for poster frame (via {posterFileName} placeholder)
3070
- * - Video relationship for video file (via {video:fileName} placeholder in a:videoFile r:link)
3071
- * - Media relationship for video file (via {media:fileName} placeholder in p14:media r:embed)
3072
- */
3073
- var VideoFrame = class VideoFrame extends XmlComponent {
3074
- static nextId = 100;
3075
- posterData;
3076
- videoData;
3077
- shapeId;
3078
- animationOptions;
3079
- constructor(options) {
3080
- super("p:pic");
3081
- const id = VideoFrame.nextId++;
3082
- this.shapeId = id;
3083
- this.animationOptions = options.animation;
3084
- const name = options.name ?? `Video ${id}`;
3085
- const mediaFileName = `${name.replace(/\s+/g, "_")}.${options.type}`;
3086
- const posterBytes = options.poster ?? MINIMAL_PNG;
3087
- const posterType = options.posterType ?? "png";
3088
- const posterFileName = `${name.replace(/\s+/g, "_")}_poster.${posterType}`;
3089
- this.videoData = {
3090
- type: options.type,
3091
- fileName: mediaFileName,
3092
- transformation: {
3093
- pixels: {
3094
- x: options.width ?? 0,
3095
- y: options.height ?? 0
3096
- },
3097
- emus: {
3098
- x: convertPixelsToEmu$1(options.width ?? 0),
3099
- y: convertPixelsToEmu$1(options.height ?? 0)
3100
- }
3101
- },
3102
- data: options.data
3103
- };
3104
- this.posterData = {
3105
- type: posterType === "jpg" ? "jpg" : "png",
3106
- fileName: posterFileName,
3107
- transformation: {
3108
- pixels: {
3109
- x: options.width ?? 0,
3110
- y: options.height ?? 0
3111
- },
3112
- emus: {
3113
- x: convertPixelsToEmu$1(options.width ?? 0),
3114
- y: convertPixelsToEmu$1(options.height ?? 0)
3115
- }
3116
- },
3117
- data: posterBytes
3118
- };
3119
- const nvPrChildren = [new BuilderElement({
3120
- name: "a:videoFile",
3121
- attributes: { "r:link": {
3122
- key: "r:link",
3123
- value: `{video:${mediaFileName}}`
3124
- } }
3125
- }), new BuilderElement({
3126
- name: "p:extLst",
3127
- children: [new BuilderElement({
3128
- name: "p:ext",
3129
- attributes: { uri: {
3130
- key: "uri",
3131
- value: MEDIA_EXT_URI
3132
- } },
3133
- children: [new BuilderElement({
3134
- name: "p14:media",
3135
- attributes: {
3136
- "r:embed": {
3137
- key: "r:embed",
3138
- value: `{media:${mediaFileName}}`
3139
- },
3140
- "xmlns:p14": {
3141
- key: "xmlns:p14",
3142
- value: "http://schemas.microsoft.com/office/powerpoint/2010/main"
3143
- }
3144
- }
3145
- })]
3146
- })]
3147
- })];
3148
- this.root.push(new BuilderElement({
3149
- name: "p:nvPicPr",
3150
- children: [
3151
- new BuilderElement({
3152
- name: "p:cNvPr",
3153
- attributes: {
3154
- id: {
3155
- key: "id",
3156
- value: id
3157
- },
3158
- name: {
3159
- key: "name",
3160
- value: name
3161
- },
3162
- descr: {
3163
- key: "descr",
3164
- value: ""
3165
- }
3166
- }
3167
- }),
3168
- new BuilderElement({
3169
- name: "p:cNvPicPr",
3170
- children: [new BuilderElement({
3171
- name: "a:picLocks",
3172
- attributes: { noChangeAspect: {
3173
- key: "noChangeAspect",
3174
- value: "1"
3175
- } }
3176
- })]
3177
- }),
3178
- new BuilderElement({
3179
- name: "p:nvPr",
3180
- children: nvPrChildren
3181
- })
3182
- ]
3183
- }));
3184
- this.root.push(new BuilderElement({
3185
- name: "p:blipFill",
3186
- children: [new BuilderElement({
3187
- name: "a:blip",
3188
- attributes: { "r:embed": {
3189
- key: "r:embed",
3190
- value: `{${posterFileName}}`
3191
- } }
3192
- }), new BuilderElement({
3193
- name: "a:stretch",
3194
- children: [new BuilderElement({ name: "a:fillRect" })]
3195
- })]
3196
- }));
3197
- this.root.push(new BuilderElement({
3198
- name: "p:spPr",
3199
- children: [new Transform2D({
3200
- x: convertPixelsToEmu$1(options.x ?? 0),
3201
- y: convertPixelsToEmu$1(options.y ?? 0),
3202
- width: convertPixelsToEmu$1(options.width ?? 0),
3203
- height: convertPixelsToEmu$1(options.height ?? 0)
3204
- }), new PresetGeometry({ preset: "rect" })]
3205
- }));
3206
- }
3207
- get ShapeId() {
3208
- return this.shapeId;
3209
- }
3210
- get Animation() {
3211
- return this.animationOptions;
3212
- }
3213
- prepForXml(context) {
3214
- const file = context.fileData;
3215
- file?.Media.addImage(this.posterData.fileName, this.posterData);
3216
- file?.Media.addMedia(this.videoData.fileName, this.videoData);
3217
- return super.prepForXml(context);
3218
- }
3219
- };
3220
- //#endregion
3221
- //#region src/file/drawingml/outline.ts
3222
- const DASH_STYLE_MAP = {
3223
- solid: "SOLID",
3224
- dash: "DASH",
3225
- dashDot: "DASH_DOT",
3226
- lgDash: "LG_DASH",
3227
- sysDot: "SYS_DOT",
3228
- sysDash: "SYS_DASH"
3229
- };
3230
- const ARROWHEAD_MAP = {
3231
- triangle: "TRIANGLE",
3232
- stealth: "STEALTH",
3233
- diamond: "DIAMOND",
3234
- oval: "OVAL",
3235
- open: "ARROW"
3236
- };
3237
- const ARROWHEAD_SIZE_MAP = {
3238
- sm: "SMALL",
3239
- med: "MEDIUM",
3240
- lg: "LARGE"
3241
- };
3242
- function toCoreLineEnd(type, width, length) {
3243
- return {
3244
- type: ARROWHEAD_MAP[type] ?? "TRIANGLE",
3245
- ...width ? { width: ARROWHEAD_SIZE_MAP[width] } : {},
3246
- ...length ? { length: ARROWHEAD_SIZE_MAP[length] } : {}
3247
- };
3248
- }
3249
- /**
3250
- * Creates an outline element using pptx's simplified API.
3251
- */
3252
- const createOutlineCompat = (options = {}, arrowheads) => createOutline$1({
3253
- width: options.width,
3254
- ...options.color ? {
3255
- type: "solidFill",
3256
- color: { value: options.color.replace("#", "") }
3257
- } : { type: "noFill" },
3258
- ...options.dashStyle && { dash: DASH_STYLE_MAP[options.dashStyle] ?? "SOLID" },
3259
- ...arrowheads?.endType ? { headEnd: toCoreLineEnd(arrowheads.endType, arrowheads.width, arrowheads.length) } : {},
3260
- ...arrowheads?.beginType ? { tailEnd: toCoreLineEnd(arrowheads.beginType, arrowheads.width, arrowheads.length) } : {}
3261
- });
3262
- //#endregion
3263
- //#region src/file/drawingml/shape-properties.ts
3264
- init_xml_components();
3265
- init_effects();
3266
- init_fill();
3267
- /**
3268
- * p:spPr — Shape properties (transform, geometry, fill, outline, effects).
3269
- * Lazy: stores options, builds XML object directly in prepForXml.
3270
- */
3271
- var ShapeProperties = class extends BaseXmlComponent {
3272
- options;
3273
- constructor(options) {
3274
- super("p:spPr");
3275
- this.options = options;
3276
- }
3277
- prepForXml(context) {
3278
- const opts = this.options;
3279
- const children = [];
3280
- if (opts.x !== void 0 || opts.y !== void 0 || opts.width !== void 0 || opts.height !== void 0 || opts.flipHorizontal !== void 0 || opts.rotation !== void 0) {
3281
- const xfrmObj = new Transform2D(opts).prepForXml(context);
3282
- if (xfrmObj) children.push(xfrmObj);
3283
- }
3284
- const geomObj = new PresetGeometry({ preset: opts.geometry ?? "rect" }).prepForXml(context);
3285
- if (geomObj) children.push(geomObj);
3286
- const media = opts.fill ? extractBlipFillMedia(opts.fill) : void 0;
3287
- if (media) context.fileData?.Media.addImage(media.fileName, {
3288
- data: media.data,
3289
- fileName: media.fileName,
3290
- type: media.type,
3291
- transformation: {
3292
- pixels: {
3293
- x: 0,
3294
- y: 0
3295
- },
3296
- emus: {
3297
- x: 0,
3298
- y: 0
3299
- }
3300
- }
3301
- });
3302
- const fillObj = buildFill(opts.fill !== void 0 ? opts.fill : { type: "none" }).prepForXml(context);
3303
- if (fillObj) children.push(fillObj);
3304
- if (opts.outline) {
3305
- const outlineObj = createOutlineCompat(opts.outline).prepForXml(context);
3306
- if (outlineObj) children.push(outlineObj);
3307
- }
3308
- if (opts.effects) {
3309
- const effectObj = createPptxEffectList(opts.effects);
3310
- if (effectObj) {
3311
- const effectXmlObj = effectObj.prepForXml(context);
3312
- if (effectXmlObj) children.push(effectXmlObj);
3313
- }
3314
- const scene3d = buildScene3D(opts.effects);
3315
- if (scene3d) {
3316
- const sceneObj = scene3d.prepForXml(context);
3317
- if (sceneObj) children.push(sceneObj);
3318
- }
3319
- const shape3d = buildShape3D(opts.effects);
3320
- if (shape3d) {
3321
- const shapeObj = shape3d.prepForXml(context);
3322
- if (shapeObj) children.push(shapeObj);
3323
- }
3324
- }
3325
- if (opts.connectionSites && opts.connectionSites.length > 0) {
3326
- const cxnChildren = [];
3327
- for (const site of opts.connectionSites) {
3328
- const siteAttrs = { pos: `${site.x} ${site.y}` };
3329
- if (site.angle !== void 0) siteAttrs.ang = site.angle;
3330
- cxnChildren.push({ "a:cxn": { _attr: siteAttrs } });
3331
- }
3332
- children.push({ "a:cxnLst": cxnChildren });
3333
- }
3334
- return { "p:spPr": children };
3335
- }
3336
- };
3337
- //#endregion
3338
- //#region src/file/shape/shape.ts
3339
- init_xml_components();
3340
- /**
3341
- * Pure function: builds p:ph element for placeholder.
3342
- */
3343
- function buildPlaceholder(type, index) {
3344
- const attrs = { type };
3345
- if (index !== void 0) attrs.idx = index;
3346
- return { "p:ph": { _attr: attrs } };
3347
- }
3348
- /**
3349
- * p:sp — A shape on a slide.
3350
- * Lazy: stores options, builds XML object in prepForXml.
3351
- *
3352
- * x/y/width/height accept pixel values and are internally converted to EMUs.
3353
- */
3354
- var Shape = class Shape extends XmlComponent {
3355
- static nextId = 2;
3356
- shapeId;
3357
- animationOptions;
3358
- options;
3359
- constructor(options = {}) {
3360
- super("p:sp");
3361
- const id = options.id ?? Shape.nextId++;
3362
- this.shapeId = id;
3363
- this.animationOptions = options.animation;
3364
- this.options = {
3365
- ...options,
3366
- id
3367
- };
3368
- }
3369
- get ShapeId() {
3370
- return this.shapeId;
3371
- }
3372
- get Animation() {
3373
- return this.animationOptions;
3374
- }
3375
- prepForXml(context) {
3376
- const opts = this.options;
3377
- const id = this.shapeId;
3378
- const name = opts.name ?? `Shape ${id}`;
3379
- const children = [];
3380
- const nvPrChildren = [];
3381
- if (opts.placeholder) nvPrChildren.push(buildPlaceholder(opts.placeholder, opts.placeholderIndex));
3382
- children.push({ "p:nvSpPr": [
3383
- { "p:cNvPr": { _attr: {
3384
- id,
3385
- name
3386
- } } },
3387
- { "p:cNvSpPr": {} },
3388
- { "p:nvPr": nvPrChildren.length > 0 ? nvPrChildren : {} }
3389
- ] });
3390
- const spPrObj = new ShapeProperties({
3391
- x: opts.x !== void 0 ? convertPixelsToEmu$1(opts.x) : void 0,
3392
- y: opts.y !== void 0 ? convertPixelsToEmu$1(opts.y) : void 0,
3393
- width: opts.width !== void 0 ? convertPixelsToEmu$1(opts.width) : void 0,
3394
- height: opts.height !== void 0 ? convertPixelsToEmu$1(opts.height) : void 0,
3395
- geometry: opts.geometry,
3396
- fill: opts.fill,
3397
- outline: opts.outline,
3398
- effects: opts.effects,
3399
- flipHorizontal: opts.flipHorizontal,
3400
- rotation: opts.rotation
3401
- }).prepForXml(context);
3402
- if (spPrObj) children.push(spPrObj);
3403
- const txBodyObj = new TextBody({
3404
- paragraphs: opts.paragraphs ?? (opts.text ? [new Paragraph({ text: opts.text })] : void 0),
3405
- vertical: opts.textVertical,
3406
- anchor: opts.textAnchor,
3407
- autoFit: opts.textAutoFit,
3408
- wrap: opts.textWrap,
3409
- margins: opts.textMargins,
3410
- columns: opts.textColumns,
3411
- columnSpacing: opts.textColumnSpacing
3412
- }).prepForXml(context);
3413
- if (txBodyObj) children.push(txBodyObj);
3414
- return { "p:sp": children };
3415
- }
3416
- toXml(context) {
3417
- const opts = this.options;
3418
- const id = this.shapeId;
3419
- const name = escapeXml(opts.name ?? `Shape ${id}`);
3420
- let s = "<p:sp><p:nvSpPr>";
3421
- s += `<p:cNvPr${attrs({
3422
- id,
3423
- name
3424
- })}/>`;
3425
- s += "<p:cNvSpPr/>";
3426
- if (opts.placeholder) {
3427
- const phAttrs = { type: opts.placeholder };
3428
- if (opts.placeholderIndex !== void 0) phAttrs.idx = opts.placeholderIndex;
3429
- s += `<p:nvPr><p:ph${attrs(phAttrs)}/></p:nvPr>`;
3430
- } else s += "<p:nvPr/>";
3431
- s += "</p:nvSpPr>";
3432
- const spPrObj = new ShapeProperties({
3433
- x: opts.x !== void 0 ? convertPixelsToEmu$1(opts.x) : void 0,
3434
- y: opts.y !== void 0 ? convertPixelsToEmu$1(opts.y) : void 0,
3435
- width: opts.width !== void 0 ? convertPixelsToEmu$1(opts.width) : void 0,
3436
- height: opts.height !== void 0 ? convertPixelsToEmu$1(opts.height) : void 0,
3437
- geometry: opts.geometry,
3438
- fill: opts.fill,
3439
- outline: opts.outline,
3440
- effects: opts.effects,
3441
- flipHorizontal: opts.flipHorizontal,
3442
- rotation: opts.rotation
3443
- }).prepForXml(context);
3444
- if (spPrObj) s += xml(spPrObj);
3445
- const txBodyOpts = {
3446
- paragraphs: opts.paragraphs ?? (opts.text ? [new Paragraph({ text: opts.text })] : void 0),
3447
- vertical: opts.textVertical,
3448
- anchor: opts.textAnchor,
3449
- autoFit: opts.textAutoFit,
3450
- wrap: opts.textWrap,
3451
- margins: opts.textMargins,
3452
- columns: opts.textColumns,
3453
- columnSpacing: opts.textColumnSpacing
3454
- };
3455
- s += new TextBody(txBodyOpts).toXml(context);
3456
- s += "</p:sp>";
3457
- return s;
3458
- }
3459
- };
3460
- //#endregion
3461
- //#region src/file/transition/transition.ts
3462
- init_xml_components();
3463
- const ORIENT_TYPES = new Set([
3464
- "blinds",
3465
- "checker",
3466
- "comb",
3467
- "randomBar"
3468
- ]);
3469
- const SIDE_DIR_TYPES = new Set(["push", "wipe"]);
3470
- const EIGHT_DIR_TYPES = new Set(["cover", "pull"]);
3471
- function buildTransitionElement(type, dir, orient, thruBlk, spokes) {
3472
- const attrs = {};
3473
- if (ORIENT_TYPES.has(type) && dir) attrs.dir = dir;
3474
- else if (SIDE_DIR_TYPES.has(type) && dir) attrs.dir = dir;
3475
- else if (EIGHT_DIR_TYPES.has(type) && dir) attrs.dir = dir;
3476
- else if (type === "strips" && dir) attrs.dir = dir;
3477
- else if ((type === "fade" || type === "cut") && thruBlk !== void 0) attrs.thruBlk = thruBlk ? 1 : 0;
3478
- else if (type === "split") {
3479
- attrs.orient = orient ?? "horz";
3480
- attrs.dir = dir ?? "out";
3481
- } else if (type === "wheel") attrs.spokes = spokes ?? 4;
3482
- else if (type === "zoom" && dir) attrs.dir = dir;
3483
- return { [`p:${type}`]: Object.keys(attrs).length > 0 ? { _attr: attrs } : {} };
3484
- }
3485
- function buildTransition(options) {
3486
- const children = [];
3487
- const attrs = {};
3488
- if (options.speed) attrs.spd = options.speed;
3489
- if (options.advanceOnClick !== void 0) attrs.advClick = options.advanceOnClick ? 1 : 0;
3490
- if (options.advanceAfterTime !== void 0) attrs.advTm = options.advanceAfterTime;
3491
- if (Object.keys(attrs).length > 0) children.push({ _attr: attrs });
3492
- if (options.type) children.push(buildTransitionElement(options.type, options.dir, options.orient, options.thruBlk, options.spokes));
3493
- return { "p:transition": children.length === 0 ? {} : children };
3494
- }
3495
- /**
3496
- * p:transition — Slide transition effect.
3497
- * Lazy: stores options, builds XML object in prepForXml.
3498
- */
3499
- var Transition = class extends BaseXmlComponent {
3500
- options;
3501
- constructor(options = {}) {
3502
- super("p:transition");
3503
- this.options = options;
3504
- }
3505
- prepForXml(_context) {
3506
- return buildTransition(this.options);
3507
- }
3508
- };
3509
- //#endregion
3510
- //#region src/file/slide/slide.ts
3511
- init_xml_components();
3512
- const NV_GRP_SP_PR = "<p:nvGrpSpPr><p:cNvPr id=\"1\" name=\"\"/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr>";
3513
- const GRP_SP_PR = "<p:grpSpPr><a:xfrm><a:off x=\"0\" y=\"0\"/><a:ext cx=\"0\" cy=\"0\"/><a:chOff x=\"0\" y=\"0\"/><a:chExt cx=\"0\" cy=\"0\"/></a:xfrm></p:grpSpPr>";
3514
- const CLR_MAP_OVR = "<p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr>";
3515
- const XMLNS = " xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:p=\"http://schemas.openxmlformats.org/presentationml/2006/main\"";
3516
- function collectAnimations(children) {
3517
- const entries = [];
3518
- for (const child of children) {
3519
- let anim;
3520
- let spid;
3521
- if (child instanceof Shape) {
3522
- anim = child.Animation;
3523
- spid = child.ShapeId;
3524
- } else if (child instanceof VideoFrame) {
3525
- anim = child.Animation;
3526
- spid = child.ShapeId;
3527
- } else if (child instanceof AudioFrame) {
3528
- anim = child.Animation;
3529
- spid = child.ShapeId;
3530
- }
3531
- if (anim && spid !== void 0) entries.push({
3532
- spid,
3533
- options: anim
3534
- });
3535
- }
3536
- return entries;
3537
- }
3538
- /**
3539
- * p:sld — A slide in a presentation.
3540
- * Lazy: stores options, builds XML object in prepForXml.
3541
- */
3542
- var Slide = class extends XmlComponent {
3543
- children;
3544
- background;
3545
- transition;
3546
- HeaderFooter;
3547
- constructor(children, background, transition, headerFooter) {
3548
- super("p:sld");
3549
- this.children = children;
3550
- this.background = background;
3551
- this.transition = transition;
3552
- this.HeaderFooter = headerFooter;
2766
+ var Slide = class extends XmlComponent {
2767
+ children;
2768
+ background;
2769
+ transition;
2770
+ HeaderFooter;
2771
+ constructor(children, background, transition, headerFooter) {
2772
+ super("p:sld");
2773
+ this.children = children;
2774
+ this.background = background;
2775
+ this.transition = transition;
2776
+ this.HeaderFooter = headerFooter;
3553
2777
  }
3554
2778
  prepForXml(context) {
3555
2779
  const children = [];
@@ -3606,35 +2830,6 @@ var Slide = class extends XmlComponent {
3606
2830
  }
3607
2831
  return { "p:sld": children };
3608
2832
  }
3609
- toXml(context) {
3610
- let s = `<p:sld${XMLNS}>`;
3611
- s += "<p:cSld>";
3612
- if (this.background) {
3613
- const bgObj = this.background.prepForXml(context);
3614
- if (bgObj) s += xml(bgObj);
3615
- }
3616
- s += "<p:spTree>";
3617
- s += NV_GRP_SP_PR;
3618
- s += GRP_SP_PR;
3619
- for (const child of this.children) if (typeof child.toXml === "function") s += child.toXml(context);
3620
- else {
3621
- const obj = child.prepForXml(context);
3622
- if (obj) s += xml(obj);
3623
- }
3624
- s += "</p:spTree></p:cSld>";
3625
- s += CLR_MAP_OVR;
3626
- if (this.transition) {
3627
- const transObj = buildTransition(this.transition);
3628
- if (transObj) s += xml(transObj);
3629
- }
3630
- const animations = collectAnimations(this.children);
3631
- if (animations.length > 0) {
3632
- const timingObj = new SlideTiming(animations).prepForXml(context);
3633
- if (timingObj) s += xml(timingObj);
3634
- }
3635
- s += "</p:sld>";
3636
- return s;
3637
- }
3638
2833
  };
3639
2834
  //#endregion
3640
2835
  //#region src/file/table-styles.ts
@@ -4117,6 +3312,250 @@ var File = class {
4117
3312
  }
4118
3313
  };
4119
3314
  //#endregion
3315
+ //#region src/file/drawingml/outline.ts
3316
+ const DASH_STYLE_MAP = {
3317
+ solid: "SOLID",
3318
+ dash: "DASH",
3319
+ dashDot: "DASH_DOT",
3320
+ lgDash: "LG_DASH",
3321
+ sysDot: "SYS_DOT",
3322
+ sysDash: "SYS_DASH"
3323
+ };
3324
+ const ARROWHEAD_MAP = {
3325
+ triangle: "TRIANGLE",
3326
+ stealth: "STEALTH",
3327
+ diamond: "DIAMOND",
3328
+ oval: "OVAL",
3329
+ open: "ARROW"
3330
+ };
3331
+ const ARROWHEAD_SIZE_MAP = {
3332
+ sm: "SMALL",
3333
+ med: "MEDIUM",
3334
+ lg: "LARGE"
3335
+ };
3336
+ function toCoreLineEnd(type, width, length) {
3337
+ return {
3338
+ type: ARROWHEAD_MAP[type] ?? "TRIANGLE",
3339
+ ...width ? { width: ARROWHEAD_SIZE_MAP[width] } : {},
3340
+ ...length ? { length: ARROWHEAD_SIZE_MAP[length] } : {}
3341
+ };
3342
+ }
3343
+ /**
3344
+ * Creates an outline element using pptx's simplified API.
3345
+ */
3346
+ const createOutlineCompat = (options = {}, arrowheads) => createOutline$1({
3347
+ width: options.width,
3348
+ ...options.color ? {
3349
+ type: "solidFill",
3350
+ color: { value: options.color.replace("#", "") }
3351
+ } : { type: "noFill" },
3352
+ ...options.dashStyle && { dash: DASH_STYLE_MAP[options.dashStyle] ?? "SOLID" },
3353
+ ...arrowheads?.endType ? { headEnd: toCoreLineEnd(arrowheads.endType, arrowheads.width, arrowheads.length) } : {},
3354
+ ...arrowheads?.beginType ? { tailEnd: toCoreLineEnd(arrowheads.beginType, arrowheads.width, arrowheads.length) } : {}
3355
+ });
3356
+ //#endregion
3357
+ //#region src/file/drawingml/transform-2d.ts
3358
+ init_xml_components();
3359
+ /**
3360
+ * a:xfrm / p:xfrm — 2D transform for shapes and graphic frames (position + size in EMUs).
3361
+ * Delegates to core createTransform2D.
3362
+ */
3363
+ var Transform2D = class extends XmlComponent {
3364
+ core;
3365
+ constructor(options, prefix = "a") {
3366
+ super(`${prefix}:xfrm`);
3367
+ this.core = createTransform2D(options, `${prefix}:xfrm`);
3368
+ }
3369
+ prepForXml(context) {
3370
+ return this.core["prepForXml"]?.(context);
3371
+ }
3372
+ };
3373
+ //#endregion
3374
+ //#region src/file/drawingml/shape-properties.ts
3375
+ init_xml_components();
3376
+ init_effects();
3377
+ init_fill();
3378
+ /**
3379
+ * p:spPr — Shape properties (transform, geometry, fill, outline, effects).
3380
+ * Lazy: stores options, builds XML object directly in prepForXml.
3381
+ */
3382
+ var ShapeProperties = class extends BaseXmlComponent {
3383
+ options;
3384
+ constructor(options) {
3385
+ super("p:spPr");
3386
+ this.options = options;
3387
+ }
3388
+ prepForXml(context) {
3389
+ const opts = this.options;
3390
+ const children = [];
3391
+ if (opts.x !== void 0 || opts.y !== void 0 || opts.width !== void 0 || opts.height !== void 0 || opts.flipHorizontal !== void 0 || opts.rotation !== void 0) {
3392
+ const xfrmObj = new Transform2D(opts).prepForXml(context);
3393
+ if (xfrmObj) children.push(xfrmObj);
3394
+ }
3395
+ const geomObj = new PresetGeometry({ preset: opts.geometry ?? "rect" }).prepForXml(context);
3396
+ if (geomObj) children.push(geomObj);
3397
+ const media = opts.fill ? extractBlipFillMedia(opts.fill) : void 0;
3398
+ if (media) context.fileData?.Media.addImage(media.fileName, {
3399
+ data: media.data,
3400
+ fileName: media.fileName,
3401
+ type: media.type,
3402
+ transformation: {
3403
+ pixels: {
3404
+ x: 0,
3405
+ y: 0
3406
+ },
3407
+ emus: {
3408
+ x: 0,
3409
+ y: 0
3410
+ }
3411
+ }
3412
+ });
3413
+ const fillObj = buildFill(opts.fill !== void 0 ? opts.fill : { type: "none" }).prepForXml(context);
3414
+ if (fillObj) children.push(fillObj);
3415
+ if (opts.outline) {
3416
+ const outlineObj = createOutlineCompat(opts.outline).prepForXml(context);
3417
+ if (outlineObj) children.push(outlineObj);
3418
+ }
3419
+ if (opts.effects) {
3420
+ const effectObj = createPptxEffectList(opts.effects);
3421
+ if (effectObj) {
3422
+ const effectXmlObj = effectObj.prepForXml(context);
3423
+ if (effectXmlObj) children.push(effectXmlObj);
3424
+ }
3425
+ const scene3d = buildScene3D(opts.effects);
3426
+ if (scene3d) {
3427
+ const sceneObj = scene3d.prepForXml(context);
3428
+ if (sceneObj) children.push(sceneObj);
3429
+ }
3430
+ const shape3d = buildShape3D(opts.effects);
3431
+ if (shape3d) {
3432
+ const shapeObj = shape3d.prepForXml(context);
3433
+ if (shapeObj) children.push(shapeObj);
3434
+ }
3435
+ }
3436
+ if (opts.connectionSites && opts.connectionSites.length > 0) {
3437
+ const cxnChildren = [];
3438
+ for (const site of opts.connectionSites) {
3439
+ const siteAttrs = { pos: `${site.x} ${site.y}` };
3440
+ if (site.angle !== void 0) siteAttrs.ang = site.angle;
3441
+ cxnChildren.push({ "a:cxn": { _attr: siteAttrs } });
3442
+ }
3443
+ children.push({ "a:cxnLst": cxnChildren });
3444
+ }
3445
+ return { "p:spPr": children };
3446
+ }
3447
+ };
3448
+ //#endregion
3449
+ //#region src/util/position.ts
3450
+ /**
3451
+ * Position/size conversion utilities for PPTX components.
3452
+ * @module
3453
+ */
3454
+ /**
3455
+ * Converts pixel position/size values to EMU, defaulting missing values to 0.
3456
+ *
3457
+ * Used by components that always need a transform (ChartFrame, Picture,
3458
+ * TableFrame, SmartArtFrame, MediaFrameBase, etc.).
3459
+ */
3460
+ function emuPosition(opts) {
3461
+ return {
3462
+ x: convertPixelsToEmu$1(opts.x ?? 0),
3463
+ y: convertPixelsToEmu$1(opts.y ?? 0),
3464
+ width: convertPixelsToEmu$1(opts.width ?? 0),
3465
+ height: convertPixelsToEmu$1(opts.height ?? 0)
3466
+ };
3467
+ }
3468
+ /**
3469
+ * Converts pixel position/size values to EMU, preserving undefined.
3470
+ *
3471
+ * Used by Shape which may omit position to let PowerPoint auto-layout.
3472
+ */
3473
+ function emuPositionOptional(opts) {
3474
+ return {
3475
+ x: opts.x !== void 0 ? convertPixelsToEmu$1(opts.x) : void 0,
3476
+ y: opts.y !== void 0 ? convertPixelsToEmu$1(opts.y) : void 0,
3477
+ width: opts.width !== void 0 ? convertPixelsToEmu$1(opts.width) : void 0,
3478
+ height: opts.height !== void 0 ? convertPixelsToEmu$1(opts.height) : void 0
3479
+ };
3480
+ }
3481
+ //#endregion
3482
+ //#region src/file/shape/shape.ts
3483
+ init_xml_components();
3484
+ /**
3485
+ * Pure function: builds p:ph element for placeholder.
3486
+ */
3487
+ function buildPlaceholder(type, index) {
3488
+ const attrs = { type };
3489
+ if (index !== void 0) attrs.idx = index;
3490
+ return { "p:ph": { _attr: attrs } };
3491
+ }
3492
+ /**
3493
+ * p:sp — A shape on a slide.
3494
+ * Lazy: stores options, builds XML object in prepForXml.
3495
+ *
3496
+ * x/y/width/height accept pixel values and are internally converted to EMUs.
3497
+ */
3498
+ var Shape = class Shape extends XmlComponent {
3499
+ static nextId = 2;
3500
+ shapeId;
3501
+ animationOptions;
3502
+ options;
3503
+ constructor(options = {}) {
3504
+ super("p:sp");
3505
+ const id = options.id ?? Shape.nextId++;
3506
+ this.shapeId = id;
3507
+ this.animationOptions = options.animation;
3508
+ this.options = {
3509
+ ...options,
3510
+ id
3511
+ };
3512
+ }
3513
+ get ShapeId() {
3514
+ return this.shapeId;
3515
+ }
3516
+ get Animation() {
3517
+ return this.animationOptions;
3518
+ }
3519
+ prepForXml(context) {
3520
+ const opts = this.options;
3521
+ const id = this.shapeId;
3522
+ const name = opts.name ?? `Shape ${id}`;
3523
+ const children = [];
3524
+ const nvPrChildren = [];
3525
+ if (opts.placeholder) nvPrChildren.push(buildPlaceholder(opts.placeholder, opts.placeholderIndex));
3526
+ children.push({ "p:nvSpPr": [
3527
+ { "p:cNvPr": { _attr: {
3528
+ id,
3529
+ name
3530
+ } } },
3531
+ { "p:cNvSpPr": {} },
3532
+ { "p:nvPr": nvPrChildren.length > 0 ? nvPrChildren : {} }
3533
+ ] });
3534
+ const spPrObj = new ShapeProperties({
3535
+ ...emuPositionOptional(opts),
3536
+ geometry: opts.geometry,
3537
+ fill: opts.fill,
3538
+ outline: opts.outline,
3539
+ effects: opts.effects,
3540
+ flipHorizontal: opts.flipHorizontal,
3541
+ rotation: opts.rotation
3542
+ }).prepForXml(context);
3543
+ if (spPrObj) children.push(spPrObj);
3544
+ const txBodyObj = new TextBody({
3545
+ paragraphs: opts.paragraphs ?? (opts.text ? [new Paragraph({ text: opts.text })] : void 0),
3546
+ vertical: opts.textVertical,
3547
+ anchor: opts.textAnchor,
3548
+ autoFit: opts.textAutoFit,
3549
+ wrap: opts.textWrap,
3550
+ margins: opts.textMargins,
3551
+ columns: opts.textColumns,
3552
+ columnSpacing: opts.textColumnSpacing
3553
+ }).prepForXml(context);
3554
+ if (txBodyObj) children.push(txBodyObj);
3555
+ return { "p:sp": children };
3556
+ }
3557
+ };
3558
+ //#endregion
4120
3559
  //#region src/file/shape/paragraph/text.ts
4121
3560
  init_xml_components();
4122
3561
  /**
@@ -4502,6 +3941,281 @@ var ConnectorShape = class ConnectorShape extends XmlComponent {
4502
3941
  }
4503
3942
  };
4504
3943
  //#endregion
3944
+ //#region src/file/media/media-frame-base.ts
3945
+ /**
3946
+ * Shared base class for media frames (video, audio) on slides.
3947
+ * @module
3948
+ */
3949
+ init_xml_components();
3950
+ /**
3951
+ * Builds an IMediaData object from pixel dimensions and raw data.
3952
+ * Generic parameter preserves the specific type literal for correct union narrowing.
3953
+ */
3954
+ function buildMediaData(type, fileName, width, height, data) {
3955
+ return {
3956
+ type,
3957
+ fileName,
3958
+ transformation: {
3959
+ pixels: {
3960
+ x: width,
3961
+ y: height
3962
+ },
3963
+ emus: {
3964
+ x: convertPixelsToEmu$1(width),
3965
+ y: convertPixelsToEmu$1(height)
3966
+ }
3967
+ },
3968
+ data
3969
+ };
3970
+ }
3971
+ /**
3972
+ * Base class for media frames (video, audio) on slides.
3973
+ *
3974
+ * Encapsulates the common structure: ID assignment, media data building,
3975
+ * p:spPr (Transform2D + PresetGeometry), p:blipFill, p:nvPicPr parts,
3976
+ * and media registration in prepForXml.
3977
+ */
3978
+ var MediaFrameBase = class extends XmlComponent {
3979
+ shapeId;
3980
+ animationOptions;
3981
+ mediaData;
3982
+ posterData;
3983
+ constructor(options, id, mediaFileName, params) {
3984
+ super("p:pic");
3985
+ this.shapeId = id;
3986
+ this.animationOptions = options.animation;
3987
+ const name = options.name ?? `Media ${id}`;
3988
+ const w = options.width ?? 0;
3989
+ const h = options.height ?? 0;
3990
+ this.mediaData = buildMediaData(options.type, mediaFileName, w, h, options.data);
3991
+ if (params.posterBytes) {
3992
+ const pt = params.posterType ?? "png";
3993
+ const pfn = params.posterFileName ?? `${name.replace(/\s+/g, "_")}_poster.${pt}`;
3994
+ this.posterData = buildMediaData(pt === "jpg" ? "jpg" : "png", pfn, w, h, params.posterBytes);
3995
+ }
3996
+ const nvPrChildren = [...params.nvPrExtraChildren ?? []];
3997
+ nvPrChildren.push(new BuilderElement({
3998
+ name: "p:extLst",
3999
+ children: [new BuilderElement({
4000
+ name: "p:ext",
4001
+ attributes: { uri: {
4002
+ key: "uri",
4003
+ value: params.extUri
4004
+ } },
4005
+ children: [new BuilderElement({
4006
+ name: "p14:media",
4007
+ attributes: {
4008
+ "r:embed": {
4009
+ key: "r:embed",
4010
+ value: `{media:${mediaFileName}}`
4011
+ },
4012
+ "xmlns:p14": {
4013
+ key: "xmlns:p14",
4014
+ value: "http://schemas.microsoft.com/office/powerpoint/2010/main"
4015
+ }
4016
+ }
4017
+ })]
4018
+ })]
4019
+ }));
4020
+ this.root.push(new BuilderElement({
4021
+ name: "p:nvPicPr",
4022
+ children: [
4023
+ new BuilderElement({
4024
+ name: `${params.cNvPrPrefix}:cNvPr`,
4025
+ attributes: {
4026
+ id: {
4027
+ key: "id",
4028
+ value: id
4029
+ },
4030
+ name: {
4031
+ key: "name",
4032
+ value: name
4033
+ },
4034
+ descr: {
4035
+ key: "descr",
4036
+ value: ""
4037
+ }
4038
+ }
4039
+ }),
4040
+ new BuilderElement({
4041
+ name: `${params.cNvPrPrefix}:cNvPicPr`,
4042
+ children: [new BuilderElement({
4043
+ name: "a:picLocks",
4044
+ attributes: { noChangeAspect: {
4045
+ key: "noChangeAspect",
4046
+ value: "1"
4047
+ } }
4048
+ })]
4049
+ }),
4050
+ new BuilderElement({
4051
+ name: "p:nvPr",
4052
+ children: nvPrChildren
4053
+ })
4054
+ ]
4055
+ }));
4056
+ const blipFillChildren = [];
4057
+ if (this.posterData) blipFillChildren.push(new BuilderElement({
4058
+ name: "a:blip",
4059
+ attributes: { "r:embed": {
4060
+ key: "r:embed",
4061
+ value: `{${this.posterData.fileName}}`
4062
+ } }
4063
+ }));
4064
+ blipFillChildren.push(new BuilderElement({
4065
+ name: "a:stretch",
4066
+ children: [new BuilderElement({ name: "a:fillRect" })]
4067
+ }));
4068
+ this.root.push(new BuilderElement({
4069
+ name: "p:blipFill",
4070
+ children: blipFillChildren
4071
+ }));
4072
+ this.root.push(new BuilderElement({
4073
+ name: "p:spPr",
4074
+ children: [new Transform2D({ ...emuPosition(options) }), new PresetGeometry({ preset: "rect" })]
4075
+ }));
4076
+ }
4077
+ get ShapeId() {
4078
+ return this.shapeId;
4079
+ }
4080
+ get Animation() {
4081
+ return this.animationOptions;
4082
+ }
4083
+ prepForXml(context) {
4084
+ const file = context.fileData;
4085
+ if (this.posterData) file?.Media.addImage(this.posterData.fileName, this.posterData);
4086
+ file?.Media.addMedia(this.mediaData.fileName, this.mediaData);
4087
+ return super.prepForXml(context);
4088
+ }
4089
+ };
4090
+ //#endregion
4091
+ //#region src/file/media/video-frame.ts
4092
+ init_xml_components();
4093
+ const MEDIA_EXT_URI$1 = "{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}";
4094
+ /** Minimal 1x1 transparent PNG (67 bytes). */
4095
+ const MINIMAL_PNG = new Uint8Array([
4096
+ 137,
4097
+ 80,
4098
+ 78,
4099
+ 71,
4100
+ 13,
4101
+ 10,
4102
+ 26,
4103
+ 10,
4104
+ 0,
4105
+ 0,
4106
+ 0,
4107
+ 13,
4108
+ 73,
4109
+ 72,
4110
+ 68,
4111
+ 82,
4112
+ 0,
4113
+ 0,
4114
+ 0,
4115
+ 1,
4116
+ 0,
4117
+ 0,
4118
+ 0,
4119
+ 1,
4120
+ 8,
4121
+ 6,
4122
+ 0,
4123
+ 0,
4124
+ 0,
4125
+ 31,
4126
+ 21,
4127
+ 196,
4128
+ 137,
4129
+ 0,
4130
+ 0,
4131
+ 0,
4132
+ 13,
4133
+ 73,
4134
+ 68,
4135
+ 65,
4136
+ 84,
4137
+ 8,
4138
+ 215,
4139
+ 99,
4140
+ 24,
4141
+ 5,
4142
+ 163,
4143
+ 0,
4144
+ 0,
4145
+ 0,
4146
+ 2,
4147
+ 0,
4148
+ 1,
4149
+ 226,
4150
+ 33,
4151
+ 188,
4152
+ 51,
4153
+ 0,
4154
+ 0,
4155
+ 0,
4156
+ 0,
4157
+ 73,
4158
+ 69,
4159
+ 78,
4160
+ 68,
4161
+ 174,
4162
+ 66,
4163
+ 96,
4164
+ 130
4165
+ ]);
4166
+ /**
4167
+ * p:pic — A video frame on a slide.
4168
+ *
4169
+ * Uses three relationships:
4170
+ * - Image relationship for poster frame (via {posterFileName} placeholder)
4171
+ * - Video relationship for video file (via {video:fileName} placeholder in a:videoFile r:link)
4172
+ * - Media relationship for video file (via {media:fileName} placeholder in p14:media r:embed)
4173
+ */
4174
+ var VideoFrame = class VideoFrame extends MediaFrameBase {
4175
+ static nextId = 100;
4176
+ constructor(options) {
4177
+ const id = VideoFrame.nextId++;
4178
+ const name = options.name ?? `Video ${id}`;
4179
+ const mediaFileName = `${name.replace(/\s+/g, "_")}.${options.type}`;
4180
+ const posterBytes = options.poster ?? MINIMAL_PNG;
4181
+ const posterType = options.posterType ?? "png";
4182
+ const posterFileName = `${name.replace(/\s+/g, "_")}_poster.${posterType}`;
4183
+ super(options, id, mediaFileName, {
4184
+ extUri: MEDIA_EXT_URI$1,
4185
+ cNvPrPrefix: "p",
4186
+ nvPrExtraChildren: [new BuilderElement({
4187
+ name: "a:videoFile",
4188
+ attributes: { "r:link": {
4189
+ key: "r:link",
4190
+ value: `{video:${mediaFileName}}`
4191
+ } }
4192
+ })],
4193
+ posterBytes,
4194
+ posterType,
4195
+ posterFileName
4196
+ });
4197
+ }
4198
+ };
4199
+ //#endregion
4200
+ //#region src/file/media/audio-frame.ts
4201
+ const MEDIA_EXT_URI = "{CF1602FD-DB20-4165-A070-5F299619DA56}";
4202
+ /**
4203
+ * p:pic — An audio frame on a slide.
4204
+ *
4205
+ * Uses a media relationship for the audio file (via {media:fileName} placeholder).
4206
+ */
4207
+ var AudioFrame = class AudioFrame extends MediaFrameBase {
4208
+ static nextId = 200;
4209
+ constructor(options) {
4210
+ const id = AudioFrame.nextId++;
4211
+ const mediaFileName = `${(options.name ?? `Audio ${id}`).replace(/\s+/g, "_")}.${options.type}`;
4212
+ super(options, id, mediaFileName, {
4213
+ extUri: MEDIA_EXT_URI,
4214
+ cNvPrPrefix: "a"
4215
+ });
4216
+ }
4217
+ };
4218
+ //#endregion
4505
4219
  //#region src/file/shape-tree/shape-tree.ts
4506
4220
  init_xml_components();
4507
4221
  /**
@@ -4673,12 +4387,7 @@ var Picture = class Picture extends XmlComponent {
4673
4387
  this.root.push(new BlipFill(fileName));
4674
4388
  this.root.push(new BuilderElement({
4675
4389
  name: "p:spPr",
4676
- children: [new Transform2D({
4677
- x: convertPixelsToEmu$1(options.x ?? 0),
4678
- y: convertPixelsToEmu$1(options.y ?? 0),
4679
- width: convertPixelsToEmu$1(options.width ?? 0),
4680
- height: convertPixelsToEmu$1(options.height ?? 0)
4681
- }), new PresetGeometry({ preset: "rect" })]
4390
+ children: [new Transform2D({ ...emuPosition(options) }), new PresetGeometry({ preset: "rect" })]
4682
4391
  }));
4683
4392
  }
4684
4393
  prepForXml(context) {
@@ -4873,12 +4582,7 @@ var TableFrame = class extends XmlComponent {
4873
4582
  constructor(options) {
4874
4583
  super("p:graphicFrame");
4875
4584
  this.root.push(new GraphicFrameNonVisual$2());
4876
- this.root.push(new Transform2D({
4877
- x: convertPixelsToEmu$1(options.x ?? 0),
4878
- y: convertPixelsToEmu$1(options.y ?? 0),
4879
- width: convertPixelsToEmu$1(options.width ?? 0),
4880
- height: convertPixelsToEmu$1(options.height ?? 0)
4881
- }, "p"));
4585
+ this.root.push(new Transform2D({ ...emuPosition(options) }, "p"));
4882
4586
  const table = new Table(options);
4883
4587
  this.root.push(new Graphic(table));
4884
4588
  }
@@ -4902,12 +4606,7 @@ var ChartFrame = class extends XmlComponent {
4902
4606
  this.chartKey = `chart_${nextChartFrameId++}`;
4903
4607
  const id = nextChartFrameId++;
4904
4608
  this.root.push(new GraphicFrameNonVisual$1(id));
4905
- this.root.push(new Transform2D({
4906
- x: convertPixelsToEmu$1(options.x ?? 0),
4907
- y: convertPixelsToEmu$1(options.y ?? 0),
4908
- width: convertPixelsToEmu$1(options.width ?? 0),
4909
- height: convertPixelsToEmu$1(options.height ?? 0)
4910
- }, "p"));
4609
+ this.root.push(new Transform2D({ ...emuPosition(options) }, "p"));
4911
4610
  this.root.push(new ChartGraphic(this.chartKey));
4912
4611
  }
4913
4612
  prepForXml(context) {
@@ -5009,12 +4708,7 @@ var SmartArtFrame = class extends XmlComponent {
5009
4708
  const id = nextSmartArtFrameId++;
5010
4709
  const name = options.name ?? `Diagram ${id}`;
5011
4710
  this.root.push(new GraphicFrameNonVisual(id, name));
5012
- this.root.push(new Transform2D({
5013
- x: convertPixelsToEmu$1(options.x ?? 0),
5014
- y: convertPixelsToEmu$1(options.y ?? 0),
5015
- width: convertPixelsToEmu$1(options.width ?? 0),
5016
- height: convertPixelsToEmu$1(options.height ?? 0)
5017
- }, "p"));
4711
+ this.root.push(new Transform2D({ ...emuPosition(options) }, "p"));
5018
4712
  this.root.push(new SmartArtGraphic(this.smartArtKey));
5019
4713
  }
5020
4714
  prepForXml(context) {