簡體   English   中英

C# - OpenXML SDK 2.5 - 從包含圖像的布局插入來自幻燈片母版的新幻燈片

[英]C# - OpenXML SDK 2.5 - Insert New Slide from Slide Masters with the layout that contains images

我用在 OpenXML 2.5 SDK 的幫助下創建了我的新幻燈片。 我設計並使用我自己的幻燈片母版來創建一個新幻燈片。 我的幻燈片母版包括一些帶圖像的布局和一些不帶圖像的布局。

如果我從沒有圖像的主布局創建幻燈片,一切正常。 如果我創建一個帶有布局的幻燈片,其中包含圖像,我會得到正確的布局,但是在每個固定圖像之上,還有另一個可移動圖像與固定圖像重疊,因此固定圖像有不必要的重復,我不需要在我新創建的幻燈片中。

我怎么解決這個問題?

我的代碼如下:

       public static void InsertNewSlide(string presentationFile, int position, string layoutName)
      {
        using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
        {

            InsertNewSlide(presentationDocument, position, layoutName);
        }
      }

    public static void InsertNewSlide(PresentationDocument presentationDocument, int position, string layoutName)
    {
        PresentationPart presentationPart = presentationDocument.PresentationPart;

        OpenXML.Slide slide = new OpenXML.Slide(new CommonSlideData(new ShapeTree()));

        SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();

        slide.Save(slidePart);

        SlideMasterPart slideMasterPart = presentationPart.SlideMasterParts.First();

        SlideLayoutPart slideLayoutPart = slideMasterPart.SlideLayoutParts.SingleOrDefault(sl => sl.SlideLayout.CommonSlideData.Name.Value.Equals(layoutName, StringComparison.OrdinalIgnoreCase));

        slidePart.AddPart<SlideLayoutPart>(slideLayoutPart);

        slidePart.Slide.CommonSlideData = (CommonSlideData)slideMasterPart.SlideLayoutParts.SingleOrDefault(sl => sl.SlideLayout.CommonSlideData.Name.Value.Equals(layoutName)).SlideLayout.CommonSlideData.Clone();

        using (Stream stream = slideLayoutPart.GetStream())
        {
            slidePart.SlideLayoutPart.FeedData(stream);

        }

        foreach (ImagePart iPart in slideLayoutPart.ImageParts)
        {
             ImagePart newImagePart = slidePart.AddImagePart(iPart.ContentType, slideLayoutPart.GetIdOfPart(iPart));
                                                        newImagePart.FeedData(iPart.GetStream());
        }
        
        uint maxSlideId = 1;
        SlideId prevSlideId = null;
        var slideIdList = presentationPart.Presentation.SlideIdList;
        foreach (SlideId slideId in slideIdList.ChildElements)
        {
            if (slideId.Id > maxSlideId)
            {
                maxSlideId = slideId.Id;
            }

            position--;
            if (position == 0)
            {
                prevSlideId = slideId;
            }

        }
        maxSlideId++;
        SlideId newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId);
        newSlideId.Id = maxSlideId;
        newSlideId.RelationshipId = presentationPart.GetIdOfPart(slidePart);

        presentationPart.Presentation.Save();
    }

}

多年后,但為了幫助他人 - 無需將不提供占位符功能的節點復制到基於主幻燈片模板(包括圖像)的新幻燈片。

using (Stream stream = slideLayoutPart.GetStream())
{
    slidePart.SlideLayoutPart.FeedData(stream);

顯然假設您沒有在 1 個工作流中添加幻燈片(即您有單獨的讀取和寫入流),以及等效的行

slidePart.Slide.CommonSlideData = (CommonSlideData)layoutPart.SlideLayout.CommonSlideData.Clone();

這兩行代碼將所有主數據復制到新幻燈片上。 例如,運行上面答案中的一個代碼塊,在演示管理器中打開生成的 .pptx 文件並刪除您看到的任何形狀 - 您會注意到每個項目都位於相同副本(母版幻燈片版本),您無法刪除。 因此,這種方法會不必要地使文件膨脹,並使 .pptx 的處理變得混亂,並且不像最終用戶所預測的那樣。

下面的代碼正在工作,包括圖像

public static SlidePart AppendNewSlide(PresentationPart presentationPart, SlideLayoutPart masterLayoutPart, out IEnumerable<Shape> placeholderShapes)
{
    Slide clonedSlide = new Slide() {
        ColorMapOverride = new ColorMapOverride {
            MasterColorMapping = new Draw.MasterColorMapping()
        }
    };

    SlidePart clonedSlidePart = presentationPart.AddNewPart<SlidePart>();
    clonedSlidePart.Slide = clonedSlide;
    clonedSlidePart.AddPart(masterLayoutPart);
    clonedSlide.Save(clonedSlidePart);

    var masterShapeTree = masterLayoutPart.SlideLayout.CommonSlideData.ShapeTree;

    placeholderShapes = (from s in masterShapeTree.ChildElements<Shape>()
                           where s.NonVisualShapeProperties.OfType<ApplicationNonVisualDrawingProperties>().Any(anvdp=>anvdp.PlaceholderShape != null)
                           select new Shape()
                           {
                               NonVisualShapeProperties = (NonVisualShapeProperties)s.NonVisualShapeProperties.CloneNode(true),
                               TextBody = new TextBody(s.TextBody.ChildElements<Draw.Paragraph>().Select(p => p.CloneNode(true))) {
                                   BodyProperties = new Draw.BodyProperties(),
                                   ListStyle = new Draw.ListStyle()
                               },
                               ShapeProperties = new ShapeProperties()
                           }).ToList();

    clonedSlide.CommonSlideData = new CommonSlideData
    {
        ShapeTree = new ShapeTree(placeholderShapes) {
            GroupShapeProperties = (GroupShapeProperties)masterShapeTree.GroupShapeProperties.CloneNode(true),
            NonVisualGroupShapeProperties = (NonVisualGroupShapeProperties)masterShapeTree.NonVisualGroupShapeProperties.CloneNode(true)
        }
    };

    SlideIdList slideIdList = presentationPart.Presentation.SlideIdList;

    // Find the highest slide ID in the current list.
    uint maxSlideId = slideIdList.Max(c=>(uint?)((SlideId)c).Id) ?? 256;

    // Insert the new slide into the slide list after the previous slide.
    slideIdList.Append(new SlideId() {
        Id = ++maxSlideId,
        RelationshipId = presentationPart.GetIdOfPart(clonedSlidePart)
    });
    //presentationPart.Presentation.Save();

    return clonedSlidePart;
}

//helper method used above in separate static class
public static IEnumerable<T> ChildElements<T>(this OpenXmlElement el) where T: OpenXmlElement
{
    if (el.HasChildren)
    {
        var child = el.GetFirstChild<T>();
        while (child != null)
        {
            yield return child;
            child = child.NextSibling<T>();
        }
    }
}

out 參數 placeholderShapes 假設在基於主模板創建新幻燈片后,開發人員希望更改某些占位符內容

我認為您應該省略復制圖像部分的foreach循環。 當我通常從幻燈片母版復制幻燈片時,我使用您正在使用的類似代碼設置,但沒有foreach 然后它從幻燈片母版部分復制給定的幻燈片,包括所有圖像、布局等。

下面列出了我在我的一個項目中使用的代碼( SetTitle(string)調用是對外部方法的調用,我在 SlideMasterPart 中使用硬編碼位置,而不是基於string的布局名稱。

public static void InsertNewSlideB(PresentationDocument presentationDocument, int position, string slideTitle)
{
    if (presentationDocument == null)
    {
        throw new ArgumentNullException("presentationDocument");
    }

    if (slideTitle == null)
    {
       throw new ArgumentNullException("slideTitle");
    }

    PresentationPart presentationPart = presentationDocument.PresentationPart;

    // Verify that the presentation is not empty.
    if (presentationPart == null)
    {
        throw new InvalidOperationException("The presentation document is empty.");
    }

    // Declare and instantiate a new slide.
    Slide slide = new Slide(new CommonSlideData(new ShapeTree()));

    SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();
    slide.Save(slidePart);

    SlideLayoutPart layoutPart = presentationPart.SlideMasterParts.ElementAt(0).SlideLayoutParts.ElementAt(1);
    slidePart.AddPart<SlideLayoutPart>(layoutPart);

    slidePart.Slide.CommonSlideData = (CommonSlideData)layoutPart.SlideLayout.CommonSlideData.Clone();

    SetTitle(slidePart, slideTitle);

    SlideIdList slideIdList = presentationPart.Presentation.SlideIdList;

    // Find the highest slide ID in the current list.
    uint maxSlideId = 1;
    SlideId prevSlideId = null;

    foreach (SlideId slideId in slideIdList.ChildElements)
     {
        if (slideId.Id > maxSlideId)
        {
            maxSlideId = slideId.Id;
        }

        position--;
        if (position == 0)
        {
            prevSlideId = slideId;
        }
    }

    maxSlideId++;

    // Insert the new slide into the slide list after the previous slide.
    SlideId newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId);
    newSlideId.Id = maxSlideId;
    newSlideId.RelationshipId = presentationPart.GetIdOfPart(slidePart);

    // Save the modified presentation.
    presentationPart.Presentation.Save();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM