Processing Power-Point templates in automated processes is very common requirement. In such a scenarios we usually need to replace template placeholders with the dynamic content retrieved from the database or other data sources. In this article I will show you how to replace Power Point template with text and images using C# based application.
After creating new project we need to add two main references: DocumentFormat.OpenXml from DocumentFormat.OpenXml.dll and WindowsBase (.Net reference). Next, we need to prepare template with placeholders that our application will replace. For texts we will insert placeholder values in the the unique format that we can find parsing the document e.g. [#Paragraph1#].
For the images we need to insert image placeholders (other images) and set their names to match our parameters (e.g. myPicture1). This names needs to be provided in the parameter objects so we can find the placeholders by image name when parsing document.
publicvoidParseTemplate(string templatePath, string templateOutputPath){using(var templateFile =File.Open(templatePath, FileMode.Open, FileAccess.Read))//read our template{using(var stream =newMemoryStream()){ templateFile.CopyTo(stream);//copy templateusing(var presentationDocument = PresentationDocument.Open(stream,true))//open presentation document{// Get the presentation part from the presentation document.var presentationPart = presentationDocument.PresentationPart;// Get the presentation from the presentation part.var presentation = presentationPart.Presentation;var slideList =newList<SlidePart>();//get available slide listforeach(SlideId slideID in presentation.SlideIdList){var slide =(SlidePart)presentationPart.GetPartById(slideID.RelationshipId); slideList.Add(slide); SlideDictionary.Add(slide, slideID);//add to dictionary to be used when needed}//loop all slides and replace images and textsforeach(var slide in slideList){ReplaceImages(presentationDocument, slide);//replace images by namevar paragraphs = slide.Slide.Descendants<Paragraph>().ToList();//get all paragraphs in the slideforeach(var paragraph in paragraphs){ReplaceText(paragraph);//replace text by placeholder name}}var slideCount = presentation.SlideIdList.ToList().Count;//count slidesDeleteSlide(presentation, slideList[slideCount -1]);//delete last slide presentation.Save();//save document changes we've made} stream.Seek(0, SeekOrigin.Begin);//scroll to stream start point//save output fileusing(var fileStream =File.Create(templateOutputPath)){ stream.CopyTo(fileStream);}}}}
When replacing images, we simply need to find placeholders (blips) and replace embed ids with new image relation ids
voidReplaceImages(PresentationDocument presentationDocument, SlidePart slidePart){// get all images in the slidevar imagesToReplace = slidePart.Slide.Descendants<Blip>().ToList();if(imagesToReplace.Any()){var index =0;//image index within the slide//find all image names in the slidevar slidePartImageNames = slidePart.Slide.Descendants<DocumentFormat.OpenXml.Presentation.Picture>().Where(a => a.NonVisualPictureProperties.NonVisualDrawingProperties.Name.HasValue).Select(a => a.NonVisualPictureProperties.NonVisualDrawingProperties.Name.Value).Distinct().ToList();//check all images in the slide and replace them if it matches our parameterforeach(var imagePlaceHolder in slidePartImageNames){//check if we have image parameter that matches slide part imageforeach(var param in PowerPointParameters){//replace it if found by image nameif(param.Image!=null&& param.Name.ToLower()== imagePlaceHolder.ToLower()){var imagePart = slidePart.AddImagePart(ImagePartType.Jpeg);//add image to documentusing(FileStream imgStream =newFileStream(param.Image.FullName, FileMode.Open)){ imagePart.FeedData(imgStream);//feed it with data}var relID = slidePart.GetIdOfPart(imagePart);// get relationship ID imagesToReplace.Skip(index).First().Embed= relID;//assign new relID, skip if this is another image in one slide part}} index +=1;}}}
When replacing text placeholder we need to find all paragraphs in the slide and replace it with the our text if the placeholder id matches
voidReplaceText(Paragraph paragraph){var parent = paragraph.Parent;//get parent element - to be used when removing placeholdervar dataParam =newPowerPointParameter();if(ContainsParam(paragraph, ref dataParam))//check if paragraph is on our parameter list{//insert text listif(dataParam.Name.Contains("string[]"))//check if param is a list{var arrayText = dataParam.Text.Split(Environment.NewLine.ToCharArray());//in our case we split it into linesif(arrayText is IEnumerable)//enumerate if we can{foreach(var itemData in arrayText){ Paragraph bullet =CloneParaGraphWithStyles(paragraph, dataParam.Name, itemData);// create new param - preserve styles parent.InsertBefore(bullet, paragraph);//insert new element}} paragraph.Remove();//delete placeholder}else{//insert text linevar param =CloneParaGraphWithStyles(paragraph, dataParam.Name, dataParam.Text);// create new param - preserve styles parent.InsertBefore(param, paragraph);//insert new element paragraph.Remove();//delete placeholder}}}