2
votes

I've read a lot about editing pptx files with OpenXml like

PresentationDocument presentationDocument = PresentationDocument.Open("C:\\Users\\beggers\\Desktop\\Test.pptx", true)

But how can I modify the XML data of my slides/presentation on runtime? Specialy when I run a new presentation witch is not saved.

I am working on a C# VSTO Add-in and I want to modify my slide/xml in a way, which is not supportet by Microsoft.Office.Interop.

2
If you add a reference to the Open XML SDK in your project, your add-in will have access to your presentation's XML to modify it.John Korchok
As John Korchok has commented, you need to reference the Open XML SDK, however, you need to close and reopen the document for VSTO to see the changes.jAndersen
Hi and thx for your input.... Unfortunately, reopening is not a solution for our case. I am searching for a runtime solution. Currently, we try to find out if we can build a custom solution with COM.ceetrox
Were you able to build a custom solution with COM?Thomas Barnekow
It's only possible with memory manipulation on a c++ level. Thinkcell does this for example... But I don't find any solution about thisceetrox

2 Answers

0
votes

Unfortunately, Microsoft Word is the only Office application that offers an Interop API for reading and even writing Open XML markup, in that case of a given Range object (which can also be the Range representing the whole main document part). Neither Excel nor PowerPoint provides that capability.

Even Microsoft Word does not give you the full markup, though, meaning you can't read or change every aspect of the opened document by reading or making changes to the Open XML markup. Thus, depending on what you would like to do with your document, you will have to close and reopen even Word documents to access and process the full Open XML markup.

0
votes

A sub-optimal yet functional way to do this is round trip using the clipboard. Slide(s) copied to the clipboard are actually packaged up as ppt data (which is just a zip). And you have control over the clipboard and inserting etc slides. So basically:

  1. Programmatically select and copy the content you want to edit to the clipboard using PP APIs.
  2. Read "PowerPoint 14.0 Slides Package" part of clipboard data into memory stream.
  3. Pass/edit memory stream with Open XML.
  4. Copy memory stream back to clipboard.
  5. paste back into PP as needed.

Here's an example of steps 2-3 working using this Open XML example as a base that write all text in the first slide in the clipboard to the console:

using System;
using System.IO; 
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Drawing;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using P = DocumentFormat.OpenXml.Presentation;
using D = DocumentFormat.OpenXml.Drawing;
using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing;

namespace PPClipboardTest
{    
    class Program
    {
        public static string format = "PowerPoint 14.0 Slides Package";


        // Get all the text in a slide.
        public static string[] GetAllTextInSlide(string presentationFile, int slideIndex)
        {
            // Open the presentation as read-only.
            using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, false))
            {
                // Pass the presentation and the slide index
                // to the next GetAllTextInSlide method, and
                // then return the array of strings it returns. 
                return GetAllTextInSlide(presentationDocument, slideIndex);
            }
        }

        public static string[] GetAllTextInSlide(PresentationDocument presentationDocument, int slideIndex)
        {
            // Verify that the presentation document exists.
            if (presentationDocument == null)
            {
                throw new ArgumentNullException("presentationDocument");
            }

            // Verify that the slide index is not out of range.
            if (slideIndex < 0)
            {
                throw new ArgumentOutOfRangeException("slideIndex");
            }

            // Get the presentation part of the presentation document.
            PresentationPart presentationPart = presentationDocument.PresentationPart;

            // Verify that the presentation part and presentation exist.
            if (presentationPart != null && presentationPart.Presentation != null)
            {
                // Get the Presentation object from the presentation part.
                Presentation presentation = presentationPart.Presentation;

                // Verify that the slide ID list exists.
                if (presentation.SlideIdList != null)
                {
                    // Get the collection of slide IDs from the slide ID list.
                    DocumentFormat.OpenXml.OpenXmlElementList slideIds =
                        presentation.SlideIdList.ChildElements;

                    // If the slide ID is in range...
                    if (slideIndex < slideIds.Count)
                    {
                        // Get the relationship ID of the slide.
                        string slidePartRelationshipId = (slideIds[slideIndex] as SlideId).RelationshipId;

                        // Get the specified slide part from the relationship ID.
                        SlidePart slidePart =
                            (SlidePart)presentationPart.GetPartById(slidePartRelationshipId);

                        // Pass the slide part to the next method, and
                        // then return the array of strings that method
                        // returns to the previous method.
                        return GetAllTextInSlide(slidePart);
                    }
                }
            }

            // Else, return null.
            return null;
        }

        public static string[] GetAllTextInSlide(SlidePart slidePart)
        {
            // Verify that the slide part exists.
            if (slidePart == null)
            {
                throw new ArgumentNullException("slidePart");
            }

            // Create a new linked list of strings.
            LinkedList<string> texts = new LinkedList<string>();

            // If the slide exists...
            if (slidePart.Slide != null)
            {
                // Iterate through all the paragraphs in the slide.
                foreach (DocumentFormat.OpenXml.Drawing.Paragraph paragraph in
                    slidePart.Slide.Descendants<DocumentFormat.OpenXml.Drawing.Paragraph>())
                {
                    // Create a new string builder.                    
                    StringBuilder paragraphText = new StringBuilder();

                    // Iterate through the lines of the paragraph.
                    foreach (DocumentFormat.OpenXml.Drawing.Text text in
                        paragraph.Descendants<DocumentFormat.OpenXml.Drawing.Text>())
                    {
                        // Append each line to the previous lines.
                        paragraphText.Append(text.Text);
                    }

                    if (paragraphText.Length > 0)
                    {
                        // Add each paragraph to the linked list.
                        texts.AddLast(paragraphText.ToString());
                    }
                }
            }

            if (texts.Count > 0)
            {
                // Return an array of strings.
                return texts.ToArray();
            }
            else
            {
                return null;
            }
        }



        [STAThread]
        static void Main(string[] args)
        {
            IDataObject iData = new DataObject();

            iData = Clipboard.GetDataObject();
            string[] formats = iData.GetFormats();

            foreach(string f in formats)
            {
                if(f == format)
                {
                    MemoryStream ms = iData.GetData(format) as MemoryStream;

                    using (PresentationDocument pres = PresentationDocument.Open(ms, true))
                    {
                        string[] allText = GetAllTextInSlide(pres, 0);
                        Console.Write("Text in first slide copied to clipboard:\n");
                        foreach (string txt in allText)
                        {
                            
                            Console.Write(txt + "\n");
                        }
                    }

                    /*
                    // Write to file
                    using (FileStream file = new FileStream("file.ppt", FileMode.Create, System.IO.FileAccess.Write)) // Bin chunk from clipboard is just a zip file
                    {
                        byte[] bytes = new byte[ms.Length];
                        ms.Read(bytes, 0, (int)ms.Length);
                        file.Write(bytes, 0, bytes.Length);
                        ms.Close();
                    }
                    */


                    break;
                }
            }            
        }
    }
}