1
votes

**Important: question answered after code block**

Platform: C#, OpenXML SDK (2.5), .NET 4.0

What I'm trying to achieve

I've been trying to generate a pptx presentation from some data and images coming from my database. Any generated file gets corrupted, but it's really passing the OOXML validation. I really don't know what else I could do.

What I've already tried

I tried to remove the images, the text, then I've commented the code that deletes the first (template) slide but nothing changes my final result: a corrupted file.

The error

When I try to open the file: "PowerPoint was unable to display some of the text, images, or objects on slides in the file, "filename.pptx", because they have become corrupted. Affected slides have been replaced by blank slides in the presentation and it is not possible to recover the lost information. To ensure that the file can be opened in previous versions of PowerPoint, use the Save As command (File menu) and save the file with either the same or a new name.

Code

Here's the code I'm using to generate the PPTX:

void GenerateSlides(string fullPath, string path, IEnumerable<Data> data)
    {
        var slidePath = fullPath;

        if (!Directory.Exists(path))
            Directory.CreateDirectory(path);

        // Copy the template file to generate new slides
        File.Copy(string.Format("{0}{1}", path, "TemplateTF.pptx"), slidePath, true);

        using (var presentationDocument = PresentationDocument.Open(slidePath, true))
        {
            var presentationPart = presentationDocument.PresentationPart;
            var slideTemplate = (SlidePart)presentationPart.GetPartById("rId2");

            // Recover the data to fullfill the slidepart
            int i = 1;

            foreach (var singleData in data)
            {
                (...)

                // Creates the new image
                var newSlide = CloneSlidePart(presentationPart, slideTemplate);
                var imgId = "rIdImg" + i;
                var imagePart = newSlide.AddImagePart(ImagePartType.Jpeg, imgId);
                var stream = new MemoryStream();
                using (var file = File.Open(string.Format("{0}{1}"
                    , WebConfigurationManager.AppSettings["pathImages"]
                    , singleData.ImageName), FileMode.Open))
                {
                    var buffer = new byte[file.Length];
                    file.Read(buffer, 0, (int)file.Length);
                    stream.Write(buffer, 0, buffer.Length);
                    imagePart.FeedData(new MemoryStream(buffer));
                }
                // Important method to swap the original image
                SwapPhoto(newSlide, imgId);
                i++;

                InsertContent(newSlide, (...));
                SwapPhoto(newSlide, imgId);
                newSlide.Slide.Save();
            }

            DeleteTemplateSlide(presentationPart, slideTemplate);
            presentationPart.Presentation.Save();
        }
    }

void SwapPhoto(SlidePart slidePart, string imgId)
    {
        var blip = slidePart.Slide.Descendants<Drawing.Blip>().First();
        blip.Embed = imgId;
        slidePart.Slide.Save();
    }

void DeleteTemplateSlide(PresentationPart presentationPart, SlidePart slideTemplate)
    {
        var slideIdList = presentationPart.Presentation.SlideIdList;
        foreach (SlideId slideId in slideIdList.ChildElements)
        {
            if (slideId.RelationshipId.Value.Equals("rId2"))
            {
                slideIdList.RemoveChild(slideId);
            }
        }
        presentationPart.DeletePart(slideTemplate);
    }

SlidePart CloneSlidePart(PresentationPart presentationPart, SlidePart slideTemplate)
    {
        var newSlidePart = presentationPart.AddNewPart<SlidePart>("newSlide" + i);
        i++;
        newSlidePart.FeedData(slideTemplate.GetStream(FileMode.Open));
        newSlidePart.AddPart(slideTemplate.SlideLayoutPart);

        var slideIdList = presentationPart.Presentation.SlideIdList;

        uint maxSlideId = 1;
        SlideId prevSlideId = null;
        foreach (SlideId slideId in slideIdList.ChildElements)
        {
            if (slideId.Id > maxSlideId)
            {
                maxSlideId = slideId.Id;
                prevSlideId = slideId;
            }
        }
        maxSlideId++;

        var newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId);
        newSlideId.Id = maxSlideId;
        newSlideId.RelationshipId = presentationPart.GetIdOfPart(newSlidePart);

        return newSlidePart;
    }

void InsertContent(SlidePart slidePart, (...))
    {
        SwapPlaceholderText(slidePart, "Title", "ReplacementString1");
        SwapPlaceholderText(slidePart, "Text", "ReplacementString2");
    }

    void SwapPlaceholderText(SlidePart slidePart, string placeholder, string value)
    {
        var textList = slidePart.Slide.Descendants<Drawing.Text>().Where(
           t => t.Text.Equals(placeholder)).ToList();

        foreach (Drawing.Text text in textList)
        {
            text.Text = value;
        }
    }



Answer

Ok, I realized how different MS Office versions can be.

a) If I try to open the .pptx file with Office 2013: error message + opens perfectly, no logo image nor slidepart showing any aditional information

b) If I try to open the .pptx file with Office 2007: error message + empty slides, no information at all

c) If I try to open the .pptx file with Office 2010: error message + empty slides and the most important information I could ever have: corrupted icon in logo's place!!!

I removed the logo image from my template and voilà, the file is is perfectly generated. Now, if I really NEED to add the logo image, I can do it programatically.

Thanks! After one week trying to realize what the hell was happening, a great friend of mine opened the file using Office 2010, then I DID realize the logo image was corrupted in my original template file.

Thanks :)

1
The (...) line in your foreach is not valid C#.Kyle
Thank you :) It's just the text data I use to replace some text from my slides.Ricardo Augusto

1 Answers

2
votes

Ok, I realized how different MS Office versions can be.

a) If I try to open the .pptx file with Office 2013: error message + opens perfectly, no logo image nor slidepart showing any aditional information b) If I try to open the .pptx file with Office 2007: error message + empty slides, no information at all c) If I try to open the .pptx file with Office 2010: error message + empty slides and the most important information I could ever have: corrupted icon in logo's place!!!

I removed the logo image from my template and voilà, the file is is perfectly generated. Now, if I really NEED to add the logo image, I can do it programatically.

Thanks! After one week trying to realize what the hell was happening, a friend of mine opened the file using Office 2010, then I DID realize the logo image was corrupted in my original template file.