none
powerpoint 2010 axes problem with OpenXml interface RRS feed

  • Question

  • Hi All. I am trying to solve a problem that last from several time and still i have no idea how to fix it.

    I am using openxml library in dot.net c# framework 4.0. I just take xxx.pptx files (every file contains only one slide) and trying to merge together in one unique file. I open an empty PowerPoint file and add a series of charts to it using the OpenXML interface. 

    These pptx contain axes.  When i try to open with powerpoint 2007, it works fine and i can see all the axes (horizontal and vertical axis), while when i try to open directly from powerpoint 2010, the axes of all slides are hide by default and manually I must modify this property.

    I discover another thing... if i try to open with powerpoint 2007 and save again the same file and open with powerpoint 2010, in this last case i can see the axes (it doesn't work if i save in the same file with powerpoint 2010) ... but i need before save with office 2007 and that is really annoying!!

    I also tried to compare the xml files inside charts folder (unzipping content in one folder) and comparing xml together...

    i noticed that if I  show the axis  (setting the usual property in office 2010), in the xml file (chartxxx.xml) after this operation i can see one tag called delete set to 0. If I try to modify that and force to 1, the axis is hide.

    But it is not so simple because there isn't anything that differentiate horizontal and vertical axis. And sometimes there is no delete tag and I can see the axis equally

    Anyone have some idea about the problem? Is it a Powerpoint 2010 bug?

     

    Thanks a lot 

    Albert

    • Moved by Paul Zhou Wednesday, February 1, 2012 6:51 AM move for better support (From:.NET Base Class Library)
    Monday, January 30, 2012 4:00 PM

All replies

  • I'm moving this thread to  Open XML Format SDK forum to get better support.

    Have a nice day.


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Wednesday, February 1, 2012 6:53 AM
  • Hi Albert,

    Thank you for posting.

    I will help you involve others to help you. There might be some delay about the response. Appreciate your patience.

    Best Regards,


    Bruce Song [MSFT]
    MSDN Community Support | Feedback to us
    Thursday, February 2, 2012 7:53 AM
  • Hello Albert,

    You haven’t given us much to go on –

    ·         What approach have you used to build a composite presentation out of slides from separate presentations?

    o   String together the xml from each slide?

    o   Using alt+chunk?

    o   Following the sample from a blog or other Forum threads?

    o   Other?

    ·         What do you see if you build the composite through the user interface?

    o   I did that with three slides, each with a chart inserted via the “insert” tab, “Illustrations“ group, “Chart” button of the ribbon in PowerPoint 2010. Then I copied each slide and pasted it into a new presentation, The resultant presentation contained the same charts with their axes)

    ·         What do you see if you save the composite presentation, then unpack it and read the xml in the viewer? (I view in Visual Studio, Click the Edit Menu, Scroll to Advance, Select ‘Format Document’)

    ·         How does that compare with the results of your code?

    Please consider giving us the answers to the above questions then we may be able to give you more help.

    Thanks, and best regards,
    Chris Jensen
    Senior Technical Support Lead


    Chris Jensen
    Thursday, February 2, 2012 7:48 PM
    Moderator
  • Hi Chris,

     

    I work with Alberto. I will get you a bit of sample code shortly but for the moment, this is an explanation of what we do:

    Firstly, we use the OpenXML interface so we are not using PowerPoint directly or through the interop when we generate the presentation.

    We have a charts which are in a slide library in SharePoint. When some are selected we put them together into one PowerPoint file rather then send out a lot of individual files.

    I start with an empty PowerPoint file which contains our theme. I open that in OpenXML. I then loop through each slide in turn from SharePoint, opening it and copying the slide to my new presentation.I then close the presentation and send it off to the requester.

    The process used to do the copy is one which has been documented on here and other places reasonably regularly, but I will put the code over later.

    What we end up with is a presentation which opens perfectly well in Office/2007 and all the slides are visible with all axes available.

    When it is opened in Office/2010 however, the axes of charts are not visible.

    We have spent a while staring at diffs between two files and trying to work out what is happening. As Alberto mentioned, there is a tag in the various Axis sections of the chart xml called 'delete' which clearly has an effect but not a consistent effect.

    A few things I can tell you:

    1) Opening the individual charts directly from SharePoint is fine (ie. Not combining).

    2) In most (if not all) cases, opening the presentation in PowerPoint 2007 and then saving it will end up with a presentation which works in PowerPoint 2010.

    3) In -some- cases, opening the presentation in PowerPoint 2010 and then saving it and re-opening it will result in the axes being visible. Unfortunately this is not consistent and we haven't identified why it works sometimes and not others. We thought is was a service pack issue but we are not sure now.

    I suspect the problem is a bug in how we are putting the charts together or something that we need to tweak in the XML as we add each slide but we have had no luck in identifying what it might be.

    I will try and get some anonymised examples up here later so you can see the detail.

     

    Thanks for your help

     

    Graham

     

     

    Friday, February 3, 2012 10:33 AM
  • Hi Graham and Alberto,

    Here are some debugging thoughts to consider,

    ·         You say that changing the value of the <c:delete val= /> tag from 1 to 0 works sometimes but not consistently. Question, in the exception instances has the value changed again, perhaps back to 1 on either or both axes?

    ·         What is the condition/value of this tag: <c:autoTitleDeleted val="0"/> and does changing it have any effect with the Axes?

    ·         If you take SharePoint out of the process, for example by retrieving individual slides from a local folder, does that change the outcome?

    ·         When you save the presentation as a PowerPoint 2007 then re-open and save it as a PowerPoint 2010 presentation does the issue ever reappear in the presentation whether subsequently opened on the test computer or viewed on a different client system?

    ·         Graham, you said you suspected the problem is a bug in how you are putting the charts together, how does that differ from how you did that with the PowerPoint 2007 charts?

    ·         What other differences beside the delete tag do you see between the 2007 and the 2010 parts including the .rels files?

    Regards,
    Chris Jensen
    Senior Technical Support Lead
     


    Chris Jensen
    Monday, February 6, 2012 3:45 PM
    Moderator
  • Hi Chris,

    Apologies for the delay, I was away on top of a mountain without any Internet connection !.

    I am gathering information for you and will try and dig out a couple of working examples. Hopefully have those by the end of the day.

    Thanks very much for your help, its much appreciated.

    Cheers

    Graham

    Tuesday, February 21, 2012 9:43 AM
  • Hi,

    Is there a way of attaching files to a question ?

    I have a VS 2010 solution which contains a cut-down version of the code. I also have a couple of slides and the combined file which demonstrate the kind of problem we are having. It would be useful to include the files as  a zip file so you can see them.

    If not, I will paste the code on here, but it may not be easy to see ! ..

    I'll start to do that anyway pending finding out whether we can attach files.

    Cheers


    Graham

    Wednesday, February 22, 2012 2:55 PM
  • Hi Chris,

    I am going to describe the process and then paste in some code which hopefully generates a similar enough problem that we can get to the bottom of it.

    I have cut the code down to the minimum to recreate the problem.

    To recreate the problem, create a new VS 2010 solution as described below. It will need a reference to DocumentFormat.OpenXml from the OpenXML SDK version 2.0

    Create a new pptx file in Office 2007 and add a slide with a chart in it. I used the default bar chart.

    Create a second pptx file with a chart in it. Again I used the default bar chart.

    You need a pptx file to use as a starting point (the two slides will be copied into this). I have one which has our theme in it and a single chart. The chart is deleted in the code before the other charts are added.Again, this should be created using Office 2007.

    When you run the application, set an output file, point the slide 1, slide 2 to the new files you created with charts in them. Set the template file to the start point file you created.

    This should create you a new pptx file with two slides in it. If you open this up in Office 2007, the Bar Charts should be as you expect them to be. If you open it up in Office 2010, the Charts don't show an axis and, in our case, the labels are in different places.

    If we open the file up again in Office 2007 and save it and then open the new file in Office 2010, the Axes are back (although for us the charts still had some labels in the wrong place). 

    I am sure we must be doing something wrong when we add the charts and Office 2007 tidies it up when it saves back. It would be good to know what ! ..

    To create the solution, perform the following:

    If you create a form solution called TestOffice2010ForMSDN and a form with the following controls:

    4 text boxes:

    textBoxDestination - to hold the path to the output file

    textBoxSlide1 - to hold the path to the first presentation containing a single slide

    textBoxSlide2 - to hold the path to the second presentation containing a single slide

    textBoxTemplate - to hold the path to a pptx file to be used as a template. (not a potx file though)

    The following buttons (the first 4 just allow a dialog for the path setting)

    buttonOutputFile, buttonSlide1, buttonSlide2,  buttonTemplate- will show a dialogs for each file.

    buttonGeneratePresentation - will trigger the merging.

    I have the following code in the main form.cs

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace TestOffice2010ForMSDN
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void buttonGeneratePresentation_Click(object sender, EventArgs e)
            {
                // test program to combine slides in a presentation to simulate
                // losing the chart axes in Office 2010.
                CombineSlides();
            }
    
            private void CombineSlides()
            {
                //Need to get the Slide URL's from sharePoint and combine them into one slide
                //IList<string> requestedSlides = new List<string>();
                IList<string> reqSlideID = new List<string>();
    
                // Output path
                string destinationPath = textBoxDestination.Text;
                string templatePresentationPath = textBoxTemplate.Text;
    
                // List of slides to add
                if (!string.IsNullOrEmpty(textBoxSlide1.Text))
                    reqSlideID.Add(textBoxSlide1.Text);
                if (!string.IsNullOrEmpty(textBoxSlide2.Text))
                    reqSlideID.Add(textBoxSlide2.Text);
    
                //Create the Initial Presentation from a blank existing presentation
                CreatePresentation.CreateBlankPresentation(destinationPath, templatePresentationPath);
                //Add the requestedslides to the presentation
                AddExistingSlideToPresentation.ExecuteStream(reqSlideID, destinationPath);
    
            }
    
            private void buttonSlide1_Click(object sender, EventArgs e)
            {
                OpenFileDialog dia = new OpenFileDialog()
                {
                    CheckFileExists = true,
                    DefaultExt = "pptx",
                    InitialDirectory = ".",
                    Multiselect = false,
                    Title = "Select the first slide to combine",
                };
    
                DialogResult res =  dia.ShowDialog();
                switch (res)
                {
                    case DialogResult.OK:
                        textBoxSlide1.Text = dia.FileName;
                        break;
                    default:
                        break;
                }
            }
    
            private void buttonSlide2_Click(object sender, EventArgs e)
            {
                OpenFileDialog dia = new OpenFileDialog()
                {
                    CheckFileExists = true,
                    DefaultExt = "pptx",
                    InitialDirectory = ".",
                    Multiselect = false,
                    Title = "Select the second slide to combine",
                };
    
                DialogResult res = dia.ShowDialog();
                switch (res)
                {
                    case DialogResult.OK:
                        textBoxSlide2.Text = dia.FileName;
                        break;
                    default:
                        break;
                }
    
            }
    
            private void buttonOutputFile_Click(object sender, EventArgs e)
            {
                SaveFileDialog dia = new SaveFileDialog()
                {
                    CreatePrompt = true,
                    CheckPathExists = true,
                    OverwritePrompt = true,
                    DefaultExt = "pptx",
                    InitialDirectory = ".",
                    Title = "Please choose an output file",
                };
    
                DialogResult res = dia.ShowDialog();
                switch (res)
                {
                    case DialogResult.OK:
                        textBoxDestination.Text = dia.FileName;
                        break;
                    default:
                        break;
                }
    
            }
    
            private void buttonTemplate_Click(object sender, EventArgs e)
            {
                OpenFileDialog dia = new OpenFileDialog()
                {
                    CheckFileExists = true,
                    DefaultExt = "pptx",
                    InitialDirectory = ".",
                    Multiselect = false,
                    Title = "Select the intial presentation",
                };
    
                DialogResult res = dia.ShowDialog();
                switch (res)
                {
                    case DialogResult.OK:
                        textBoxTemplate.Text = dia.FileName;
                        break;
                    default:
                        break;
                }
    
            }
        }
    }
    

    Then add a new class called CreatePresentation and paste the following into it:

    using System;
    using System.IO;
    using DocumentFormat.OpenXml.Packaging;
    
    namespace TestOffice2010ForMSDN
    {
        public static class CreatePresentation
        {
    
            public static void Execute(string filePath, string templatePath)
            {
                File.Copy(templatePath, filePath, true);
            }
    
            public static void CreateBlankPresentation(string filePath, string templatePath)
            {
                Execute(filePath, templatePath);
    
                using (var presentation = PresentationDocument.Open(filePath, true))
                {
                    DeleteSlideInPresentation.Execute(presentation, 0);
                }
            }
    
        }
    }

    Then a class called AddExistingSlideToPresentation and paste the following code in:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Xml;
    using DocumentFormat.OpenXml;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Presentation;
    
    namespace TestOffice2010ForMSDN
    {
        public class AddExistingSlideToPresentation
        {      
            public static void ExecuteStream(
                IEnumerable<string> sourcePresentationUrls,
                string destinationPresentationFilePath)
            {
                try
                {
                    using (PresentationDocument destinationPresentation = PresentationDocument.Open(destinationPresentationFilePath, true))
                    {
                        PresentationPart destinationPresentationPart = destinationPresentation.PresentationPart;
    
                        if (destinationPresentationPart.Presentation.SlideIdList == null)
                            destinationPresentationPart.Presentation.SlideIdList = new SlideIdList();
    
                        uint uniqueId = GetMaxSlideMasterId(destinationPresentationPart.Presentation.SlideMasterIdList);
                        uint maxSlideId = GetMaxSlideId(destinationPresentationPart.Presentation.SlideIdList);
    
                        foreach (string slideUrl in sourcePresentationUrls)
                        {
                            using (PresentationDocument sourcePresentation = PresentationDocument.Open(slideUrl, true))
                            {
                                PresentationPart sourcePresentationPart = sourcePresentation.PresentationPart;
    
                                foreach (SlideId slideId in sourcePresentationPart.Presentation.SlideIdList)
                                {
                                    AppendSlide(
                                        slideId,
                                        sourcePresentationPart,
                                        destinationPresentationPart,
                                        ref uniqueId,
                                        ref maxSlideId,
                                        false);
                                }
                            }
                        }
    
                        FixSlideLayoutIds(destinationPresentation.PresentationPart, uniqueId);
                        destinationPresentationPart.Presentation.Save();
                        destinationPresentation.Close();
                    }
    
                }
                catch (Exception exception)
                {
                }
            }
    
    
            #region Implementation
            /// <summary>
            /// Append a slide to the destination presentation
            /// </summary>
            /// <param name="slideId"></param>
            /// <param name="sourcePresentationPart"></param>
            /// <param name="destinationPresentationPart"></param>
            /// <param name="uniqueId"></param>
            /// <param name="maxSlideId"></param>
            /// <param name="addMetadata"></param>
            private static void AppendSlide(
                SlideId slideId,
                PresentationPart sourcePresentationPart,
                PresentationPart destinationPresentationPart,
                ref uint uniqueId,
                ref uint maxSlideId,
                bool addMetadata)
            {
                var slidePart = (SlidePart)sourcePresentationPart.GetPartById(slideId.RelationshipId);
    
                string relationshipId = string.Format("riD{0}", DateTime.Now.Ticks);
    
                SlidePart destinationSlidePart = destinationPresentationPart.AddPart(slidePart, relationshipId);
                SlideMasterPart destinationMasterPart = destinationSlidePart.SlideLayoutPart.SlideMasterPart;
                destinationPresentationPart.AddPart(destinationMasterPart);
    
                uniqueId++;
    
                var newSlideMasterId = new SlideMasterId
                {
                    RelationshipId =
                        destinationPresentationPart.GetIdOfPart(destinationMasterPart),
                    Id = uniqueId
                };
    
                destinationPresentationPart.Presentation.SlideMasterIdList.Append(newSlideMasterId);
    
                maxSlideId++;
                var newSlideId = new SlideId
                {
                    RelationshipId = relationshipId,
                    Id = maxSlideId
                };
                destinationPresentationPart.Presentation.SlideIdList.Append(newSlideId);
    
            }
    
            private static void FixSlideLayoutIds(PresentationPart presentationPart, uint uniqueId)
            {
                foreach (var slideMasterPart in presentationPart.SlideMasterParts)
                {
                    foreach (SlideLayoutId slideLayoutId in slideMasterPart.SlideMaster.SlideLayoutIdList)
                    {
                        uniqueId++;
                        slideLayoutId.Id = uniqueId;
                    }
    
                    slideMasterPart.SlideMaster.Save();
                }
            }
    
            private static uint GetMaxSlideId(OpenXmlElement element)
            {
                uint max = 256;
                //Get max id value from set of children
                foreach (var child in element.ChildElements)
                {
                    var attribute = child.GetAttribute("id", "");
    
                    var id = uint.Parse(attribute.Value);
                    if (id > max)
                        max = id;
                }
                return max;
            }
    
            private static uint GetMaxSlideMasterId(OpenXmlElement element)
            {
                var max = 2147483648;
                //Get max id value from set of children
                foreach (var child in element.ChildElements)
                {
                    var attribute = child.GetAttribute("id", "");
    
                    var id = uint.Parse(attribute.Value);
                    if (id > max)
                        max = id;
                }
                return max;
            }
    
             #endregion
        }
    }
    

    And finally, a class called DeleteSlideInPresentation with the following code:

    using System.Collections.Generic;
    using System.IO;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Presentation;
    
    namespace TestOffice2010ForMSDN
    {
        public static class DeleteSlideInPresentation
        {
            public static void Execute(
                PresentationDocument presentation,
                int index)
            {
                SlideIdList slideIdList = presentation.PresentationPart.Presentation.SlideIdList;
    
                //Get the slide index in the presentation and remove from presentation
                SlideId slideId = slideIdList.ChildElements[index] as SlideId;
    
                if (slideId != null)
                {
                    string relationshipID = slideId.RelationshipId;
                    slideIdList.RemoveChild(slideId);
    
                    if (presentation.PresentationPart.Presentation.CustomShowList != null)
                    {
                        foreach (
                            CustomShow customShow in
                                presentation.PresentationPart.Presentation.CustomShowList.Elements<CustomShow>())
                        {
                            if (customShow.SlideList != null)
                            {
                                // Declare a link list of slide list entries.
                                LinkedList<SlideListEntry> slideListEntries = new LinkedList<SlideListEntry>();
                                foreach (SlideListEntry slideListEntry in customShow.SlideList.Elements())
                                {
                                    // Find the slide reference to remove from the custom show.
                                    if (slideListEntry.Id != null && slideListEntry.Id == relationshipID)
                                    {
                                        slideListEntries.AddLast(slideListEntry);
                                    }
                                }
    
                                // Remove all references to the slide from the custom show.
                                foreach (SlideListEntry slideListEntry in slideListEntries)
                                {
                                    customShow.SlideList.RemoveChild(slideListEntry);
                                }
                            }
                        }
                    }
    
                    presentation.PresentationPart.Presentation.Save();
                    SlidePart slidePart = presentation.PresentationPart.GetPartById(relationshipID) as SlidePart;
                    presentation.PresentationPart.DeletePart(slidePart);
                }
            }
        }
    }
    

    Any help gratefully received

    Cheers


    Graham

    Wednesday, February 22, 2012 5:12 PM
  • Hi,

    Anyone have any ideas about this ? Would love to hear ideas or whether people can simulate it using the code I have above ..

    Cheers

    Graham

    Wednesday, February 29, 2012 2:00 PM
  • We are still having this problem. I would really appreciate it if anyone could have let me know if they get the same problem. I suspect someone will see immediately what the problem is ...

    Cheers


    Graham

    Monday, March 5, 2012 3:16 PM