Skip to content

Commit 80ee730

Browse files
[PowerPoint] Add export-import-slide snippet (#978)
* [PowerPoint] Add export-import-slide snippet * Updates based on suggestions * API mappings * Apply suggestions from code review Co-authored-by: David Chesnut <[email protected]> --------- Co-authored-by: David Chesnut <[email protected]>
1 parent 8b38053 commit 80ee730

File tree

7 files changed

+368
-0
lines changed

7 files changed

+368
-0
lines changed

playlists-prod/powerpoint.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@
142142
group: Slide Management
143143
api_set:
144144
PowerPointApi: '1.5'
145+
- id: powerpoint-slide-management-export-import-slide
146+
name: Export and import slide
147+
fileName: export-import-slide.yaml
148+
description: Shows how to export and import a slide.
149+
rawUrl: >-
150+
https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/export-import-slide.yaml
151+
group: Slide Management
152+
api_set:
153+
PowerPointApi: '1.8'
145154
- id: powerpoint-tags
146155
name: Work with tags
147156
fileName: tags.yaml

playlists/powerpoint.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@
142142
group: Slide Management
143143
api_set:
144144
PowerPointApi: '1.5'
145+
- id: powerpoint-slide-management-export-import-slide
146+
name: Export and import slide
147+
fileName: export-import-slide.yaml
148+
description: Shows how to export and import a slide.
149+
rawUrl: >-
150+
https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/export-import-slide.yaml
151+
group: Slide Management
152+
api_set:
153+
PowerPointApi: '1.8'
145154
- id: powerpoint-tags
146155
name: Work with tags
147156
fileName: tags.yaml
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
order: 5
2+
id: powerpoint-slide-management-export-import-slide
3+
name: Export and import slide
4+
description: Shows how to export and import a slide.
5+
host: POWERPOINT
6+
api_set:
7+
PowerPointApi: '1.8'
8+
script:
9+
content: |
10+
document.getElementById("export-slide-button").addEventListener("click", () => tryCatch(exportSlide));
11+
document.getElementById("clear-exported-slide-button").addEventListener("click", () => tryCatch(clearExportedSlide));
12+
document.getElementById("import-slide-button").addEventListener("click", () => tryCatch(importSlide));
13+
document.getElementById("slide-image-button").addEventListener("click", () => tryCatch(addSlideImageToNewSlide));
14+
document.getElementById("setup").addEventListener("click", () => tryCatch(setup));
15+
16+
async function exportSlide() {
17+
// Exports current slide.
18+
await PowerPoint.run(async (context) => {
19+
const slide = context.presentation.getSelectedSlides().getItemAt(0);
20+
const slideBase64DataResult = slide.exportAsBase64();
21+
const imageBase64DataResult = slide.getImageAsBase64({ height: 300 });
22+
await context.sync();
23+
24+
localStorage.setItem("exportedSlide", slideBase64DataResult.value);
25+
localStorage.setItem("exportedSlideImage", imageBase64DataResult.value);
26+
27+
updateSlideImage(imageBase64DataResult.value);
28+
29+
console.log("Slide was exported.");
30+
});
31+
}
32+
33+
function clearExportedSlide() {
34+
// Clears exported slide.
35+
localStorage.removeItem("exportedSlide");
36+
localStorage.removeItem("exportedSlideImage");
37+
updateSlideImage("");
38+
console.log("Exported slide was cleared.");
39+
}
40+
41+
async function importSlide() {
42+
// Imports the slide that was most recently exported.
43+
const slideBase64Data = localStorage.getItem("exportedSlide");
44+
if (slideBase64Data === null) {
45+
console.warn("Unable to import. You must first export a slide.");
46+
return;
47+
}
48+
49+
await PowerPoint.run(async (context) => {
50+
const currentSlide = context.presentation.getSelectedSlides().getItemAt(0);
51+
currentSlide.load("id");
52+
await context.sync();
53+
54+
context.presentation.insertSlidesFromBase64(slideBase64Data, { targetSlideId: currentSlide.id });
55+
});
56+
}
57+
58+
async function getSlideImage(options?: PowerPoint.SlideGetImageOptions): Promise<string> {
59+
// Gets slide image.
60+
return PowerPoint.run(async (context) => {
61+
const slide = context.presentation.getSelectedSlides().getItemAt(0);
62+
const imageBase64Result = slide.getImageAsBase64(options);
63+
await context.sync();
64+
65+
return imageBase64Result.value;
66+
});
67+
}
68+
69+
async function getImageDimensions(base64Data: string): Promise<{ width: number; height: number }> {
70+
// Gets image dimensions.
71+
return new Promise((resolve, reject) => {
72+
const image = new Image();
73+
image.onerror = () => {
74+
reject();
75+
};
76+
image.onload = () => {
77+
resolve({ width: image.width, height: image.height });
78+
};
79+
image.src = `data:image/png;base64,${base64Data}`;
80+
});
81+
}
82+
83+
async function addSlideWithImage(imageBase64): Promise<void> {
84+
// Adds a new slide including an image.
85+
return PowerPoint.run(async (context) => {
86+
const presentation = context.presentation;
87+
const currentSlide = presentation.getSelectedSlides().getItemAt(0);
88+
const slideCountResult = context.presentation.slides.getCount();
89+
90+
currentSlide.layout.load();
91+
await context.sync();
92+
93+
const slideCount = slideCountResult.value;
94+
95+
console.log(`Adding slide using layout ${currentSlide.layout.id}`);
96+
97+
// Add a new slide at the end of the presentation.
98+
context.presentation.slides.add({ layoutId: currentSlide.layout.id });
99+
try {
100+
await context.sync();
101+
} catch (err) {
102+
console.error(`Unable to add slide (with layout from current slide). ${err}`);
103+
104+
// Try adding without specifying the layout.
105+
context.presentation.slides.add();
106+
107+
try {
108+
await context.sync();
109+
} catch (err) {
110+
console.error(`Unable to add slide. ${err}`);
111+
throw err;
112+
}
113+
}
114+
115+
console.log("Slide added");
116+
117+
// Get added slide.
118+
const slide = context.presentation.slides.getItemAt(slideCount);
119+
120+
slide.load(["id"]);
121+
122+
await context.sync();
123+
124+
console.log(`Added slide id: ${slide.id}`);
125+
126+
// Switch to the new slide.
127+
context.presentation.setSelectedSlides([slide.id]);
128+
try {
129+
await context.sync();
130+
} catch (err) {
131+
console.error(`Unable to switch to the new slide. ${err}`);
132+
throw err;
133+
}
134+
135+
console.log("Switched to the added slide.");
136+
137+
const activeSlide = context.presentation.getSelectedSlides().getItemAt(0);
138+
activeSlide.load(["id"]);
139+
await context.sync();
140+
141+
console.log(`Active slide id: ${activeSlide.id}`);
142+
143+
const imageDimensions = await getImageDimensions(imageBase64);
144+
const shapeAddOptions = {
145+
height: imageDimensions.height,
146+
width: imageDimensions.width
147+
};
148+
149+
let shape;
150+
151+
shape = await addImageToCurrentSlide(imageBase64);
152+
shape.load(["id"]);
153+
await context.sync();
154+
155+
// Select the added image.
156+
activeSlide.setSelectedShapes([shape.id]);
157+
await context.sync();
158+
});
159+
}
160+
161+
async function addImageToCurrentSlide(
162+
imageBase64: string,
163+
options?: PowerPoint.ShapeAddOptions
164+
): Promise<PowerPoint.Shape> {
165+
// Adds an image to the current slide.
166+
const setSelectedDataOptions: Office.SetSelectedDataOptions = {
167+
coercionType: Office.CoercionType.Image
168+
};
169+
if (options) {
170+
if (options.height) {
171+
setSelectedDataOptions.imageHeight = options.height;
172+
}
173+
if (options.left) {
174+
setSelectedDataOptions.imageLeft = options.left;
175+
}
176+
if (options.top) {
177+
setSelectedDataOptions.imageTop = options.top;
178+
}
179+
if (options.width) {
180+
setSelectedDataOptions.imageWidth = options.width;
181+
}
182+
}
183+
184+
return new Promise((resolve, reject) => {
185+
Office.context.document.setSelectedDataAsync(
186+
imageBase64,
187+
setSelectedDataOptions,
188+
async (result: Office.AsyncResult<void>) => {
189+
if (result.error) {
190+
console.error(`ERROR in setSelectedDataAsync(): ${result.error}`);
191+
reject(result.error);
192+
} else {
193+
const shape = await PowerPoint.run(async (context) => {
194+
const slide = context.presentation.getSelectedSlides().getItemAt(0);
195+
slide.shapes.load();
196+
await context.sync();
197+
198+
return slide.shapes.items[slide.shapes.items.length - 1];
199+
});
200+
resolve(shape);
201+
}
202+
}
203+
);
204+
});
205+
}
206+
207+
async function addSlideImageToNewSlide() {
208+
// Adds an image of current slide to the new slide.
209+
const imageBase64 = await getSlideImage({ height: 500 });
210+
211+
await addSlideWithImage(imageBase64);
212+
}
213+
214+
function updateSlideImage(imageBase64: string) {
215+
const slideImageElement = document.getElementById("slide-image") as HTMLImageElement;
216+
slideImageElement.src = imageBase64 ? `data:image/png;base64,${imageBase64}` : "";
217+
}
218+
219+
async function setup() {
220+
await PowerPoint.run(async (context) => {
221+
// Adds a new slide with some content.
222+
const slideCountResult = context.presentation.slides.getCount();
223+
context.presentation.slides.add();
224+
await context.sync();
225+
226+
const newSlide = context.presentation.slides.getItemAt(slideCountResult.value);
227+
newSlide.load("id");
228+
newSlide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.hexagon);
229+
await context.sync();
230+
231+
console.log(`Added slide - ID: ${newSlide.id}`);
232+
233+
// Switch to the new slide.
234+
context.presentation.setSelectedSlides([newSlide.id]);
235+
await context.sync();
236+
});
237+
}
238+
239+
// Default helper for invoking an action and handling errors.
240+
async function tryCatch(callback) {
241+
try {
242+
await callback();
243+
} catch (error) {
244+
// Note: In a production add-in, you'd want to notify the user through your add-in's UI.
245+
console.error(error);
246+
}
247+
}
248+
language: typescript
249+
template:
250+
content: |-
251+
<section class="ms-Fabric ms-font-m">
252+
This sample demonstrates how to export and import a slide.
253+
</section>
254+
<section class="ms-Fabric setup ms-font-m">
255+
<h3>Set up</h3>
256+
<button id="setup" class="ms-Button">
257+
<span class="ms-Button-label">Set up</span>
258+
</button>
259+
</section>
260+
<section class="ms-Fabric samples ms-font-m">
261+
<h3>Try it out</h3>
262+
<button id="export-slide-button" class="ms-Button">
263+
<span class="ms-Button-label">Export current slide</span>
264+
</button>
265+
<button id="clear-exported-slide-button" class="ms-Button">
266+
<span class="ms-Button-label">Clear exported slide</span>
267+
</button>
268+
<img id="slide-image" src=""/>
269+
<p>Once a slide has been exported, click the <b>Import slide</b> button to insert into the presentation.</p>
270+
<p>To add it to a different presentation, open that presentation and select a slide. It will be inserted after the
271+
selected slide.</p>
272+
<button id="import-slide-button" class="ms-Button">
273+
<span class="ms-Button-label">Import slide</span>
274+
</button><br>
275+
<p>Click the following button to capture an image of the current slide and add it to a new slide at the end of the presentation.</p>
276+
<button id="slide-image-button" class="ms-Button">
277+
<span class="ms-Button-label">Put slide image on another slide</span>
278+
</button>
279+
</section>
280+
language: html
281+
style:
282+
content: |-
283+
section.samples {
284+
margin-top: 20px;
285+
}
286+
287+
section.samples .ms-Button, section.setup .ms-Button {
288+
display: block;
289+
margin-bottom: 5px;
290+
margin-left: 20px;
291+
min-width: 80px;
292+
}
293+
294+
img {
295+
border: 5px solid #555;
296+
}
297+
language: css
298+
libraries: |-
299+
https://appsforoffice.microsoft.com/lib/1/hosted/office.js
300+
@types/office-js
301+
302+
[email protected]/dist/css/fabric.min.css
303+
[email protected]/dist/css/fabric.components.min.css
304+
305+
[email protected]/client/core.min.js
306+
@types/core-js
56 Bytes
Binary file not shown.

snippet-extractor-output/snippets.yaml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15935,6 +15935,48 @@
1593515935
slide.delete();
1593615936
});
1593715937
});
15938+
'PowerPoint.Slide#exportAsBase64:member(1)':
15939+
- >-
15940+
// Link to full sample:
15941+
https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/export-import-slide.yaml
15942+
15943+
15944+
// Exports current slide.
15945+
15946+
await PowerPoint.run(async (context) => {
15947+
const slide = context.presentation.getSelectedSlides().getItemAt(0);
15948+
const slideBase64DataResult = slide.exportAsBase64();
15949+
const imageBase64DataResult = slide.getImageAsBase64({ height: 300 });
15950+
await context.sync();
15951+
15952+
localStorage.setItem("exportedSlide", slideBase64DataResult.value);
15953+
localStorage.setItem("exportedSlideImage", imageBase64DataResult.value);
15954+
15955+
updateSlideImage(imageBase64DataResult.value);
15956+
15957+
console.log("Slide was exported.");
15958+
});
15959+
'PowerPoint.Slide#getImageAsBase64:member(1)':
15960+
- >-
15961+
// Link to full sample:
15962+
https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/export-import-slide.yaml
15963+
15964+
15965+
// Exports current slide.
15966+
15967+
await PowerPoint.run(async (context) => {
15968+
const slide = context.presentation.getSelectedSlides().getItemAt(0);
15969+
const slideBase64DataResult = slide.exportAsBase64();
15970+
const imageBase64DataResult = slide.getImageAsBase64({ height: 300 });
15971+
await context.sync();
15972+
15973+
localStorage.setItem("exportedSlide", slideBase64DataResult.value);
15974+
localStorage.setItem("exportedSlideImage", imageBase64DataResult.value);
15975+
15976+
updateSlideImage(imageBase64DataResult.value);
15977+
15978+
console.log("Slide was exported.");
15979+
});
1593815980
'PowerPoint.Slide#setSelectedShapes:member(1)':
1593915981
- >-
1594015982
// Link to full sample:

view-prod/powerpoint.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"powerpoint-insert-slides": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/insert-slides.yaml",
1616
"powerpoint-basics-get-slide-metadata": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-slide-metadata.yaml",
1717
"powerpoint-slide-management-get-set-slides": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-set-slides.yaml",
18+
"powerpoint-slide-management-export-import-slide": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/export-import-slide.yaml",
1819
"powerpoint-tags": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/tags/tags.yaml",
1920
"powerpoint-text-get-set-textrange": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml"
2021
}

0 commit comments

Comments
 (0)