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); } }
Lars,
thanks for the interesting post. Thought you might be interested in this recent post from Ted Neward: http://blogs.tedneward.com/default.aspx#a427bbfdd-c568-458c-b7e7-6a056076b2cc
He’s generating his presentation with F# based on a Powerpoint template from some XML markup. He can also inject slides directly if necessary. Quite cool stuff 🙂
Cheers,
Martin
Thanks for the link. Sadly he uses ppt-format, not pptx.
But nice idea to write presentations in xml+wiki markup
Lars,
Very helpful. Have you done any more with this since them?
A realy nice article. Helped me al lot.
U rocks.. 🙂
Thanks for the article..
Thanks It helped me alot . But after using that code i found that if my template contains images then it is not coping images to clone slide .
@Ashish Goyal, For that you especially need to copy image on Slide.
This code corrupted my file as it contains bar chart.
Oops. I hope you had a copy then?