I need to create a presentation with quite recurring contents. So first created a template presentation using Powerpoint. Then I tried to unpack and modify with XSL. I did this with word before, and was quite happy. But for PPTX you have to create two new files per slide. That ended in a mess.
That brought me to the Open Xml SDK 2.0. Still a mess, but it is a little better.
I want to clone a template slide multiple times, and then “inject” my contents into the predefined shapes. That should be easy.
But it took me a while to find out how to correctly clone a slide. So I thought I’d share that with you.
var presentationFile = "SomeFile.pptx"; using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true)) { var presentationPart = presentationDocument.PresentationPart; var templatePart = presentationPart.GetSlidePartsInOrder().Last(); var newSlidePart = templatePart.CloneSlide(); presentationPart.AppendSlide(newSlidePart); }
The real code…
… is in this extensions. I created something to find slide parts in the right order, because the order of slide parts stored can be different to the order they appear in. Then I created a utility that clones a slide, and another one that appends the new slide part to the presentation part, which will finally show it.
public static class OpenXmlUtils { public static IEnumerable<SlidePart> GetSlidePartsInOrder(this PresentationPart presentationPart) { SlideIdList slideIdList = presentationPart.Presentation.SlideIdList; return slideIdList.ChildElements .Cast<SlideId>() .Select(x => presentationPart.GetPartById(x.RelationshipId)) .Cast<SlidePart>(); } public static SlidePart CloneSlide(this SlidePart templatePart) { // find the presentationPart: makes the API more fluent var presentationPart = templatePart.GetParentParts() .OfType<PresentationPart>() .Single(); // clone slide contents Slide currentSlide = (Slide)templatePart.Slide.CloneNode(true); var slidePartClone = presentationPart.AddNewPart<SlidePart>(); currentSlide.Save(slidePartClone); // copy layout part slidePartClone.AddPart(templatePart.SlideLayoutPart); return slidePartClone; } public static void AppendSlide(this PresentationPart presentationPart, SlidePart newSlidePart) { SlideIdList slideIdList = presentationPart.Presentation.SlideIdList; // find the highest id uint maxSlideId = slideIdList.ChildElements .Cast<SlideId>() .Max(x => x.Id.Value); // Insert the new slide into the slide list after the previous slide. var id = maxSlideId + 1; SlideId newSlideId = new SlideId(); slideIdList.Append(newSlideId); newSlideId.Id = id; newSlideId.RelationshipId = presentationPart.GetIdOfPart(newSlidePart); } }