Copying a slide from one presentation to another using Open XML SDK
Asked Answered
B

2

6

Sorry my English :)

There is a code

using (var sourceDoc = PresentationDocument.Open(@"d:\source.pptx", false))
{
    using (var destDoc = PresentationDocument.Open(@"d:\dest.pptx", true))
    {

    }
}

I try copy slide №2 from sourceDoc and paste into destDoc position 4.


There are articles with same title "Copying A Slide From One Presentation To Another" and "How to Assemble Multiple PowerPoint Decks", but unfortunately I cannot apply that. I just confused. For example:

uniqueId = GetMaxIdFromChild(destPresPart.Presentation.SlideMasterIdList);

what does mean? Compile time say error.


UPDATE #1

I created method to copy slide to another presentation

/// <summary>
/// Copy one slide to another presentation
/// </summary>
/// <param name="sourcePresentationPath"></param>
/// <param name="slidePosition">
/// Slide number from source presentation which will be copy to destinition presentation
/// </param>
/// <param name="destPresentationPath"></param>
/// <remarks>Slide copy to end destinition presentation</remarks>
public static void CopySlideTo(string sourcePresentationPath, int slidePosition, string destPresentationPath)
{
    using (PresentationDocument sourcePresentationDocument = PresentationDocument.Open(sourcePresentationPath, false))
    {
        var sourcePresentationPart = sourcePresentationDocument.PresentationPart;
        var sourcePresentation = sourcePresentationPart.Presentation;
        SlideIdList sourceSlideIdList = sourcePresentation.SlideIdList;
        SlideId slideIdSelectedSlide = sourceSlideIdList.ChildElements[slidePosition - 1] as SlideId;
        SlidePart sourceSlidePart = sourcePresentationPart.GetPartById(slideIdSelectedSlide.RelationshipId) as SlidePart;

        SlidePart destSlidePart = null;
        SlideIdList destSlideIdList = null;
        PresentationPart destPresentationPart = null;
        using (PresentationDocument destPresentationDocument = PresentationDocument.Open(destPresentationPath, true))
        {
            var addedSlidePart = destPresentationDocument.PresentationPart.AddPart(sourceSlidePart);                    

            destSlideIdList = destPresentationDocument.PresentationPart.Presentation.SlideIdList;

            destPresentationPart = destPresentationDocument.PresentationPart;                   

            SlideId lastSlideIdInDestPresentation = destSlideIdList.ChildElements.Last() as SlideId;

            // Insert the new slide into the slide list after last slide 
            SlideId addedSlideId = destSlideIdList.InsertAfter(new SlideId(), lastSlideIdInDestPresentation);
            addedSlideId.Id = lastSlideIdInDestPresentation.Id++;
            addedSlideId.RelationshipId = destPresentationPart.GetIdOfPart(addedSlidePart);

            destPresentationPart.Presentation.Save();
        }
    }

Slide is copied, but without background. How also move background?


UPDATE #2

I finally created method to copy a slide to another presentation

public class Extensions
{
    static uint uniqueId;                       

    /// <summary>
    /// Copy one slide to another presentation
    /// </summary>
    /// <param name="sourcePresentationPath"></param>
    /// <param name="slidePosition">
    /// Slide number from source presentation which will be copy to destinition presentation
    /// </param>
    /// <param name="destPresentationPath"></param>
    /// <remarks>Slide is copied to end destinition presentation</remarks>
    [SuppressMessage("ReSharper", "SuggestVarOrType_SimpleTypes")]
    public static void CopySlideTo(string sourcePresentationPath, int slidePosition, string destPresentationPath)
    {
        using (PresentationDocument sourcePresentationDocument = PresentationDocument.Open(sourcePresentationPath, false))
        {
            var sourcePresentationPart = sourcePresentationDocument.PresentationPart;
            var sourcePresentation = sourcePresentationPart.Presentation;
            SlideIdList sourceSlideIdList = sourcePresentation.SlideIdList;
            SlideId slideIdSelectedSlide = sourceSlideIdList.ChildElements[slidePosition - 1] as SlideId;
            SlidePart sourceSlidePart = sourcePresentationPart.GetPartById(slideIdSelectedSlide.RelationshipId) as SlidePart;
            using (PresentationDocument destPresentationDocument = PresentationDocument.Open(destPresentationPath, true))
            {
                var addedSlidePart = destPresentationDocument.PresentationPart.AddPart(sourceSlidePart);                    

                var destSlideIdList = destPresentationDocument.PresentationPart.Presentation.SlideIdList;

                var destPresentationPart = destPresentationDocument.PresentationPart;                   

                SlideId lastSlideIdInDestPresentation = destSlideIdList.ChildElements.Last() as SlideId;

                // Insert the new slide into the slide list after last slide 
                SlideId addedSlideId = destSlideIdList.InsertAfter(new SlideId(), lastSlideIdInDestPresentation);
                addedSlideId.Id = lastSlideIdInDestPresentation.Id++;
                addedSlideId.RelationshipId = destPresentationPart.GetIdOfPart(addedSlidePart);

                // Get the existing slide master part.
                SlideMasterPart destPresPartSlideMasterPart = destPresentationPart.SlideMasterParts.ElementAt(0);
                string relationshipId = destPresentationPart.GetIdOfPart(destPresPartSlideMasterPart);

                // Get the new slide master part.
                SlideMasterPart sourcePresPartSlideMasterPart = sourcePresentationPart.SlideMasterParts.ElementAt(0);

                // Remove the existing theme part.
                destPresentationPart.DeletePart(destPresentationPart.ThemePart);

                // Remove the old slide master part.
                destPresentationPart.DeletePart(destPresPartSlideMasterPart);

                // Import the new slide master part, and reuse the old relationship ID.
                sourcePresPartSlideMasterPart = destPresentationPart.AddPart(sourcePresPartSlideMasterPart, relationshipId);

                // Change to the new theme part.
                destPresentationPart.AddPart(sourcePresPartSlideMasterPart.ThemePart);

                var newSlideLayouts = new Dictionary<string, SlideLayoutPart>();

                foreach (var slideLayoutPart in sourcePresPartSlideMasterPart.SlideLayoutParts)
                {
                    newSlideLayouts.Add(GetSlideLayoutType(slideLayoutPart), slideLayoutPart);
                }

                // Remove the slide layout relationship on all slides. 
                foreach (var slidePart in destPresentationPart.SlideParts)
                {                        
                    string layoutType = null;

                    if (slidePart.SlideLayoutPart != null)
                    {
                        // Determine the slide layout type for each slide.
                        layoutType = GetSlideLayoutType(slidePart.SlideLayoutPart);

                        // Delete the old layout part.
                        slidePart.DeletePart(slidePart.SlideLayoutPart);
                    }

                    SlideLayoutPart newLayoutPart = null;
                    if (layoutType != null && newSlideLayouts.TryGetValue(layoutType, out newLayoutPart))
                    {
                        // Apply the new layout part.
                        slidePart.AddPart(newLayoutPart);
                    }
                }
                FixSlideLayoutIds(destPresentationPart);
                destPresentationPart.Presentation.Save();                    
            }
        }
    }

    static void FixSlideLayoutIds(PresentationPart presPart)
    {
        // Make sure that all slide layouts have unique ids.
        foreach (SlideMasterPart slideMasterPart in presPart.SlideMasterParts)
        {
            foreach (SlideLayoutId slideLayoutId in slideMasterPart.SlideMaster.SlideLayoutIdList)
            {
                uniqueId++;
                slideLayoutId.Id = (uint)uniqueId;
            }

            slideMasterPart.SlideMaster.Save();
        }
    }

    /// <summary>
    /// Get the slide layout type.
    /// </summary>
    /// <param name="slideLayoutPart"></param>
    /// <returns></returns>
    private static string GetSlideLayoutType(SlideLayoutPart slideLayoutPart)
    {
        CommonSlideData slideData = slideLayoutPart.SlideLayout.CommonSlideData;

        return slideData.Name;
    }
}

// Client code
Extensions.CopySlideTo(@"D:\temp\source.pptx", 1, @"D:\temp\dest.pptx");

Now when I open result (d:\temp\dest.pptx) see

enter image description here

However, if click Repair result is ok.

Why this is happend? How fix it? I suspect that something wrong with slide layout adding.

Boxthorn answered 23/3, 2018 at 15:44 Comment(4)
What is the error?Tinned
@TacyNathan, uniqueId is not variable and not some C# keyword.Boxthorn
The link creates a VSTO plugin. You should try to use openXml SDK tool to reflect the C# code required to produce your ppt. That would be a good starting pointStrontia
@FortyTwo, I think you are talking about Open XML SDK Productivity Tool. Yes, that tool shows how look C# code for certain .pptx, but I need to know proccess copy slide to another presentation.Boxthorn
B
4

Luckily, I still pulled out the win:

public static void Copy(Stream sourcePresentationStream, uint copiedSlidePosition, Stream destPresentationStream)
{            
    using (var destDoc = PresentationDocument.Open(destPresentationStream, true))
    {
        var sourceDoc = PresentationDocument.Open(sourcePresentationStream, false);
        var destPresentationPart = destDoc.PresentationPart;
        var destPresentation = destPresentationPart.Presentation;

        _uniqueId = GetMaxIdFromChild(destPresentation.SlideMasterIdList);
        uint maxId = GetMaxIdFromChild(destPresentation.SlideIdList);

        var sourcePresentationPart = sourceDoc.PresentationPart;
        var sourcePresentation = sourcePresentationPart.Presentation;

        int copiedSlideIndex = (int)--copiedSlidePosition;

        int countSlidesInSourcePresentation = sourcePresentation.SlideIdList.Count();                
        if (copiedSlideIndex < 0 || copiedSlideIndex >= countSlidesInSourcePresentation)
            throw new ArgumentOutOfRangeException(nameof(copiedSlidePosition));

        SlideId copiedSlideId = sourcePresentationPart.Presentation.SlideIdList.ChildElements[copiedSlideIndex] as SlideId;
        SlidePart copiedSlidePart = sourcePresentationPart.GetPartById(copiedSlideId.RelationshipId) as SlidePart; 

        SlidePart addedSlidePart = destPresentationPart.AddPart<SlidePart>(copiedSlidePart);

        SlideMasterPart addedSlideMasterPart = destPresentationPart.AddPart(addedSlidePart.SlideLayoutPart.SlideMasterPart);    


        // Create new slide ID
        maxId++;
        SlideId slideId = new SlideId
        {
            Id = maxId,
            RelationshipId = destDoc.PresentationPart.GetIdOfPart(addedSlidePart)
        };
        destPresentation.SlideIdList.Append(slideId);

        // Create new master slide ID
        _uniqueId++;
        SlideMasterId slideMaterId = new SlideMasterId
        {
            Id = _uniqueId,
            RelationshipId = destDoc.PresentationPart.GetIdOfPart(addedSlideMasterPart)
        };
        destDoc.PresentationPart.Presentation.SlideMasterIdList.Append(slideMaterId);

        // change slide layout ID
        FixSlideLayoutIds(destDoc.PresentationPart);

        destDoc.PresentationPart.Presentation.Save();
    }
    sourcePresentationStream.Close();
    destPresentationStream.Close();
}
Boxthorn answered 1/4, 2018 at 18:42 Comment(4)
Could you share your FixSlideLayoutIds method?Jeaninejeanlouis
hey @Adam - I am not very familiar to .NET / C# but I want to implement something similar. Can you help me with working sample program please. This code have some missing dependencies when I run in VS and I am not sure how to fix themCopilot
@Copilot the code dependances are i believe in the orgiginal code above.Impeachment
For me still giving that error message but after repair it works, still very good job mateFootlocker
T
3

You didn't declare the variable type. This is what you meant to do right?

var uniqueId = GetMaxIdFromChild(destPresPart.Presentation.SlideMasterIdList);
Tinned answered 24/3, 2018 at 18:13 Comment(1)
Code from articles is not my. Maybe you right. However, I still have not idea how I can copy one slide to another by this code or another code.Boxthorn

© 2022 - 2024 — McMap. All rights reserved.