使用 Open XML SDK 将幻灯片从一个演示文稿复制到另一个演示文稿

Ada*_*dam 6 c# powerpoint ms-office openxml openxml-sdk

对不起我的英语:)

\n\n

有一个代码

\n\n
using (var sourceDoc = PresentationDocument.Open(@"d:\\source.pptx", false))\n{\n    using (var destDoc = PresentationDocument.Open(@"d:\\dest.pptx", true))\n    {\n\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我尝试从位置 4 复制幻灯片 \xe2\x84\x962sourceDoc并粘贴到destDoc位置 4。

\n\n
\n\n

有同标题的文章“将幻灯片从一个演示文稿复制到另一个演示文稿”“如何组装多个 PowerPoint 幻灯片”,但不幸的是我无法应用它。我只是很困惑。例如:

\n\n
uniqueId = GetMaxIdFromChild(destPresPart.Presentation.SlideMasterIdList);\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是什么意思?编译时说错误。

\n\n
\n\n

更新#1

\n\n

我创建了将幻灯片复制到另一个演示文稿的方法

\n\n
/// <summary>\n/// Copy one slide to another presentation\n/// </summary>\n/// <param name="sourcePresentationPath"></param>\n/// <param name="slidePosition">\n/// Slide number from source presentation which will be copy to destinition presentation\n/// </param>\n/// <param name="destPresentationPath"></param>\n/// <remarks>Slide copy to end destinition presentation</remarks>\npublic static void CopySlideTo(string sourcePresentationPath, int slidePosition, string destPresentationPath)\n{\n    using (PresentationDocument sourcePresentationDocument = PresentationDocument.Open(sourcePresentationPath, false))\n    {\n        var sourcePresentationPart = sourcePresentationDocument.PresentationPart;\n        var sourcePresentation = sourcePresentationPart.Presentation;\n        SlideIdList sourceSlideIdList = sourcePresentation.SlideIdList;\n        SlideId slideIdSelectedSlide = sourceSlideIdList.ChildElements[slidePosition - 1] as SlideId;\n        SlidePart sourceSlidePart = sourcePresentationPart.GetPartById(slideIdSelectedSlide.RelationshipId) as SlidePart;\n\n        SlidePart destSlidePart = null;\n        SlideIdList destSlideIdList = null;\n        PresentationPart destPresentationPart = null;\n        using (PresentationDocument destPresentationDocument = PresentationDocument.Open(destPresentationPath, true))\n        {\n            var addedSlidePart = destPresentationDocument.PresentationPart.AddPart(sourceSlidePart);                    \n\n            destSlideIdList = destPresentationDocument.PresentationPart.Presentation.SlideIdList;\n\n            destPresentationPart = destPresentationDocument.PresentationPart;                   \n\n            SlideId lastSlideIdInDestPresentation = destSlideIdList.ChildElements.Last() as SlideId;\n\n            // Insert the new slide into the slide list after last slide \n            SlideId addedSlideId = destSlideIdList.InsertAfter(new SlideId(), lastSlideIdInDestPresentation);\n            addedSlideId.Id = lastSlideIdInDestPresentation.Id++;\n            addedSlideId.RelationshipId = destPresentationPart.GetIdOfPart(addedSlidePart);\n\n            destPresentationPart.Presentation.Save();\n        }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

幻灯片已复制,但没有背景。怎么还移动背景呢?

\n\n
\n\n

更新#2

\n\n

我终于创建了将幻灯片复制到另一个演示文稿的方法

\n\n
public class Extensions\n{\n    static uint uniqueId;                       \n\n    /// <summary>\n    /// Copy one slide to another presentation\n    /// </summary>\n    /// <param name="sourcePresentationPath"></param>\n    /// <param name="slidePosition">\n    /// Slide number from source presentation which will be copy to destinition presentation\n    /// </param>\n    /// <param name="destPresentationPath"></param>\n    /// <remarks>Slide is copied to end destinition presentation</remarks>\n    [SuppressMessage("ReSharper", "SuggestVarOrType_SimpleTypes")]\n    public static void CopySlideTo(string sourcePresentationPath, int slidePosition, string destPresentationPath)\n    {\n        using (PresentationDocument sourcePresentationDocument = PresentationDocument.Open(sourcePresentationPath, false))\n        {\n            var sourcePresentationPart = sourcePresentationDocument.PresentationPart;\n            var sourcePresentation = sourcePresentationPart.Presentation;\n            SlideIdList sourceSlideIdList = sourcePresentation.SlideIdList;\n            SlideId slideIdSelectedSlide = sourceSlideIdList.ChildElements[slidePosition - 1] as SlideId;\n            SlidePart sourceSlidePart = sourcePresentationPart.GetPartById(slideIdSelectedSlide.RelationshipId) as SlidePart;\n            using (PresentationDocument destPresentationDocument = PresentationDocument.Open(destPresentationPath, true))\n            {\n                var addedSlidePart = destPresentationDocument.PresentationPart.AddPart(sourceSlidePart);                    \n\n                var destSlideIdList = destPresentationDocument.PresentationPart.Presentation.SlideIdList;\n\n                var destPresentationPart = destPresentationDocument.PresentationPart;                   \n\n                SlideId lastSlideIdInDestPresentation = destSlideIdList.ChildElements.Last() as SlideId;\n\n                // Insert the new slide into the slide list after last slide \n                SlideId addedSlideId = destSlideIdList.InsertAfter(new SlideId(), lastSlideIdInDestPresentation);\n                addedSlideId.Id = lastSlideIdInDestPresentation.Id++;\n                addedSlideId.RelationshipId = destPresentationPart.GetIdOfPart(addedSlidePart);\n\n                // Get the existing slide master part.\n                SlideMasterPart destPresPartSlideMasterPart = destPresentationPart.SlideMasterParts.ElementAt(0);\n                string relationshipId = destPresentationPart.GetIdOfPart(destPresPartSlideMasterPart);\n\n                // Get the new slide master part.\n                SlideMasterPart sourcePresPartSlideMasterPart = sourcePresentationPart.SlideMasterParts.ElementAt(0);\n\n                // Remove the existing theme part.\n                destPresentationPart.DeletePart(destPresentationPart.ThemePart);\n\n                // Remove the old slide master part.\n                destPresentationPart.DeletePart(destPresPartSlideMasterPart);\n\n                // Import the new slide master part, and reuse the old relationship ID.\n                sourcePresPartSlideMasterPart = destPresentationPart.AddPart(sourcePresPartSlideMasterPart, relationshipId);\n\n                // Change to the new theme part.\n                destPresentationPart.AddPart(sourcePresPartSlideMasterPart.ThemePart);\n\n                var newSlideLayouts = new Dictionary<string, SlideLayoutPart>();\n\n                foreach (var slideLayoutPart in sourcePresPartSlideMasterPart.SlideLayoutParts)\n                {\n                    newSlideLayouts.Add(GetSlideLayoutType(slideLayoutPart), slideLayoutPart);\n                }\n\n                // Remove the slide layout relationship on all slides. \n                foreach (var slidePart in destPresentationPart.SlideParts)\n                {                        \n                    string layoutType = null;\n\n                    if (slidePart.SlideLayoutPart != null)\n                    {\n                        // Determine the slide layout type for each slide.\n                        layoutType = GetSlideLayoutType(slidePart.SlideLayoutPart);\n\n                        // Delete the old layout part.\n                        slidePart.DeletePart(slidePart.SlideLayoutPart);\n                    }\n\n                    SlideLayoutPart newLayoutPart = null;\n                    if (layoutType != null && newSlideLayouts.TryGetValue(layoutType, out newLayoutPart))\n                    {\n                        // Apply the new layout part.\n                        slidePart.AddPart(newLayoutPart);\n                    }\n                }\n                FixSlideLayoutIds(destPresentationPart);\n                destPresentationPart.Presentation.Save();                    \n            }\n        }\n    }\n\n    static void FixSlideLayoutIds(PresentationPart presPart)\n    {\n        // Make sure that all slide layouts have unique ids.\n        foreach (SlideMasterPart slideMasterPart in presPart.SlideMasterParts)\n        {\n            foreach (SlideLayoutId slideLayoutId in slideMasterPart.SlideMaster.SlideLayoutIdList)\n            {\n                uniqueId++;\n                slideLayoutId.Id = (uint)uniqueId;\n            }\n\n            slideMasterPart.SlideMaster.Save();\n        }\n    }\n\n    /// <summary>\n    /// Get the slide layout type.\n    /// </summary>\n    /// <param name="slideLayoutPart"></param>\n    /// <returns></returns>\n    private static string GetSlideLayoutType(SlideLayoutPart slideLayoutPart)\n    {\n        CommonSlideData slideData = slideLayoutPart.SlideLayout.CommonSlideData;\n\n        return slideData.Name;\n    }\n}\n\n// Client code\nExtensions.CopySlideTo(@"D:\\temp\\source.pptx", 1, @"D:\\temp\\dest.pptx");\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在当我打开结果时(d:\\temp\\dest.pptx ) 时看到

\n\n

在此输入图像描述

\n\n

但是,如果单击“修复”结果就可以了。

\n\n

为什么会出现这样的情况呢?怎么解决呢?我怀疑添加幻灯片布局有问题。

\n

Ada*_*dam 4

幸运的是,我还是赢得了胜利:

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 您能分享您的 FixSlideLayoutIds 方法吗? (2认同)