6
votes

Apologies if this has already been answered but I've seen plenty of posts along similar lines and nothing has so far helped me.

Basically I'm building an app that takes a PowerPoint 'template' and replaces text and images sourced from a database. Most of it is complete but I'm struggling to solve a problem when I replace images. The template has lots of blank images inserted, ready to replace and they are all square as they are just placeholders. I can replace them no problem but the new images are stretched either vertically or horizontally depending on the image I pull from the database. It's basically filling the placeholders shape.

I must admit I am finding it hard to get my head around the document model so maybe I'm trying to change the wrong thing, I had tried to change the "extents" properties of the blip.parent.shape but I was guessing and got no joy.

Below is the code that works as far as swapping the image out (credit to original author amos http://atakala.com/browser/Item.aspx?user_id=amos&dict_id=2291). I'm not sure where even to attempt the resize, once the image is in place or before... any help would be much appreciated. I'm not worried about the actual size for now, I can calculate that myself, it's just being able to change the image size that is the problem.

As well as the sample code (which might not be that useful) I've linked to my sample project. The sample and files should all be placed in c:\test to work. It's just a few images, the c# project and program.cs file, plus a sample PPTX file.

DOWNLOAD Sample zip file

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using d = DocumentFormat.OpenXml.Drawing;
using System.IO;

namespace PPTX_Image_Replace_test
{
class Program
{
    static void Main(string[] args)
    {
        TestImageReplace(@"C:\test\TestImageReplaceAndResize.pptx");
    }

    public static void TestImageReplace(string fileName)
    {
        // make a copy of the original and edit that
        string outputFileName = Path.Combine(Path.GetDirectoryName(fileName), "New_" + Path.GetFileName(fileName));
        File.Copy(fileName, outputFileName,true);


        using (PresentationDocument document = PresentationDocument.Open(outputFileName, true))
        {
            ReplaceFirstImageMatchingAltText(document, @"C:\test\Arrow_UP.png", "changeme");
        }
    }

    public static void ReplaceFirstImageMatchingAltText(PresentationDocument presentationDocument, string newImagePath, string alternateTextToFind)
    {
        OpenXmlElementList slideIds = presentationDocument.PresentationPart.Presentation.SlideIdList.ChildElements;

        foreach (SlideId sID in slideIds) // loop thru the SlideIDList
        {
            string relId = sID.RelationshipId; // get first slide relationship
            SlidePart slide = (SlidePart)presentationDocument.PresentationPart.GetPartById(relId); // Get the slide part from the relationship ID. 

            var pictures = slide.Slide.Descendants<ShapeTree>().First().Descendants<Picture>().ToList();
            foreach (var picture in pictures)
            {
                // get photo desc to see if it matches search text 
                var nonVisualPictureProperties = picture.Descendants<NonVisualPictureProperties>().FirstOrDefault();
                if (nonVisualPictureProperties == null)
                    continue;
                var nonVisualDrawingProperties99 = nonVisualPictureProperties.Descendants<NonVisualDrawingProperties>().FirstOrDefault();
                if (nonVisualDrawingProperties99 == null)
                    continue;
                var desc = nonVisualDrawingProperties99.Description;
                if (desc == null || desc.Value == null || !desc.Value.Contains(alternateTextToFind))
                    continue;

                BlipFill blipFill = picture.Descendants<BlipFill>().First();
                var blip = blipFill.Descendants<DocumentFormat.OpenXml.Drawing.Blip>().First();
                string embedId = blip.Embed; // now we need to find the embedded content and update it. 


                // find the content 
                ImagePart imagePart = (ImagePart)slide.GetPartById(embedId);
                if (imagePart != null)
                {
                    using (FileStream fileStream = new FileStream(newImagePath, FileMode.Open))
                    {
                        imagePart.FeedData(fileStream);
                        fileStream.Close();
                    }

                    return; // found the photo and replaced it. 
                }
            }
        }
    }
}
}
1
I had a similar issue with word images, maybe my answer here can be of any help. I have no experience with powerpoint, but it looks a bit similar to me with the Blip etc.Alexander Derck
Thanks Alexander, this was the kind of thing I had tried, but I can't seem to get at the drawing object. Appreciate you looking though.. I'll keep trying and hoping!Alan Schofield

1 Answers

2
votes

Typically after days for getting nowhere, as soon as I post the question, I find the answer! It was remarkably simple in the end.

I already had a reference to the picture so I simply modifed the trasnform there, the last bit of code now looks like this..

                // find the content 
                ImagePart imagePart = (ImagePart)slide.GetPartById(embedId);
                if (imagePart != null)
                {

                    d.Transform2D transform =  picture.Descendants<d.Transform2D>().First();
                    transform.Extents.Cx = 800000; // replace with correct calcualted values eventually
                    transform.Extents.Cy = 400000; // replace with correct calculated values eventually

                    using (FileStream fileStream = new FileStream(newImagePath, FileMode.Open))
                    {
                        imagePart.FeedData(fileStream);
                        fileStream.Close();
                    }

                    return; // found the photo and replaced it. 
                }

Guess I just couldn't see the wood for the trees.......