プレゼンテーションに新しいスライドを挿入する

このトピックでは、Open XML SDK のクラスを使用して、プログラムを使用してプレゼンテーションに新しいスライドを挿入する方法について説明します。

PresentationDocument オブジェクトを取得する

Open XML SDK では、PresentationDocument クラスがプレゼンテーション ドキュメント パッケージを表します。 プレゼンテーション ドキュメントを操作するには、最初に PresentationDocument クラスのインスタンスを作成し、次にそのインスタンスを操作します。 ドキュメントからクラスのインスタンスを作成するには、Open(String, Boolean) メソッドを呼び出します。このメソッドは、ファイル パスの他に、2 つ目のパラメーターとしてブール値を使用して、ドキュメントが編集可能かどうかを指定します。 読み取り/書き込み用にドキュメントを開くには、次の using ステートメントに示すように、このパラメーターの値を true に指定します。 このコード セグメントでは、presentationFile パラメーターの文字列はドキュメントを開く元のファイルへの完全なパスを表します。

    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
    {
        // Insert other code here.
    }

The using statement provides a recommended alternative to the typical .Open, .Save, .Close sequence. これによって、閉じかっこに達したときに、 Dispose メソッド (Open XML SDK がリソースをクリーンアップするために使用する内部メソッド) が自動的に呼び出されます。 using ステートメントに続くブロックは、作成された、または using ステートメントで指定されたオブジェクト (この場合は presentationDocument) のスコープを設定します。

プレゼンテーション ドキュメントの基本構造

PresentationML ドキュメントの基本構造は、いくつかのパーツで構成され、そのうちの 1 つであるメイン パーツにプレゼンテーション定義が含まれます。 ISO/IEC 29500 仕様書では、PresentationML パッケージの全体的なフォームについて次のように説明しています。

PresentationML パッケージのメイン パーツは、プレゼンテーションのルート要素から始まります。 この要素にはプレゼンテーションが含まれており、プレゼンテーションは スライド リスト、スライド マスター リスト、ノート マスター リスト、配布資料マスター リストを参照します。 スライド リストはプレゼンテーション内のすべてのスライドを参照します。スライド マスター リストはプレゼンテーションで使用されるスライド マスター全体を参照します。ノート マスターにはノート ページの書式設定に関する情報が含まれます。配布資料マスターは配布資料がどのように表示されるかを示します。

配布資料とは、聴衆に提供できるように一連のスライドを印刷したものです。

テキストやグラフィックのように、各スライドにはコメントノートを含めることができ、レイアウトを指定したり、1 つ以上のカスタム プレゼンテーションに組み込んだりできます。 コメントは、プレゼンテーション スライド デッキをメンテナンスする人向けの注釈です。 ノートは、発表者または聴衆向けのリマインダーまたはテキストの一部です。

PresentationML ドキュメントに含めることができるその他の機能には、アニメーションオーディオビデオ、スライド間の画面切り替え効果があります。

PresentationML ドキュメントは、1 つの大きな本体として単一のパーツに格納されるのではありません。 特定の機能を実装する要素ごとに、専用のパーツに格納されます。 たとえば、ドキュメント内のコメントはすべて 1 つのコメント パーツに格納され、各スライドは、スライド パーツに格納されます。

© ISO/IEC29500: 2008.

次の XML コードの例は、267 と 256 という ID で示される 2 つのスライドを含むプレゼンテーションを表します。

    <p:presentation xmlns:p="…" … > 
       <p:sldMasterIdLst>
          <p:sldMasterId
             xmlns:rel="https://…/relationships" rel:id="rId1"/>
       </p:sldMasterIdLst>
       <p:notesMasterIdLst>
          <p:notesMasterId
             xmlns:rel="https://…/relationships" rel:id="rId4"/>
       </p:notesMasterIdLst>
       <p:handoutMasterIdLst>
          <p:handoutMasterId
             xmlns:rel="https://…/relationships" rel:id="rId5"/>
       </p:handoutMasterIdLst>
       <p:sldIdLst>
          <p:sldId id="267"
             xmlns:rel="https://…/relationships" rel:id="rId2"/>
          <p:sldId id="256"
             xmlns:rel="https://…/relationships" rel:id="rId3"/>
       </p:sldIdLst>
           <p:sldSz cx="9144000" cy="6858000"/>
       <p:notesSz cx="6858000" cy="9144000"/>
    </p:presentation>

Open XML SDK を使用すると、PresentationML 要素に対応する厳密に型指定されたクラスを使用して、ドキュメント構造とコンテンツを作成できます。 これらのクラスは DocumentFormat.OpenXml.Presentation 名前空間にあります。 次の表に、sldsldLayoutsldMasternotesMaster の各要素に対応するクラスのクラス名を示します。

PresentationML の要素 Open XML SDK クラス 説明
sld Slide プレゼンテーション スライド。 SlidePart のルート要素
sldLayout SlideLayout スライド レイアウト。 SlideLayoutPart のルート要素
sldMaster SlideMaster スライド マスター。 SlideMasterPart のルート要素
notesMaster NotesMaster ノート マスター (または handoutMaster)。 NotesMasterPart のルート要素

サンプル コード

サンプル コードを使用して、既存のプレゼンテーションに新しいスライドを追加できます。 このプログラム内では、次のように InsertNewSlide メソッドを呼び出して、"Myppt10.pptx" という名前のプレゼンテーション ファイルのポジション 1 に、"My new slide" というタイトルの新しいスライドを追加できます。

    InsertNewSlide(@"C:\Users\Public\Documents\Myppt10.pptx", 1, "My new slide");

プログラムを実行すると、新しいスライドは、プレゼンテーションの 2 番目のスライドとして表示されます。

以下に、C# と Visual Basic による完全なサンプル コードを示します。


using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using System;
using Drawing = DocumentFormat.OpenXml.Drawing;

InsertNewSlide(args[0], int.Parse(args[1]), args[2]);

// Insert a slide into the specified presentation.
static void InsertNewSlide(string presentationFile, int position, string slideTitle)
{
    // Open the source document as read/write. 
    using (PresentationDocument presentationDocument = PresentationDocument.Open(presentationFile, true))
    {
        // Pass the source document and the position and title of the slide to be inserted to the next method.
        InsertNewSlideFromPresentation(presentationDocument, position, slideTitle);
    }
}

// Insert the specified slide into the presentation at the specified position.
static void InsertNewSlideFromPresentation(PresentationDocument presentationDocument, int position, string slideTitle)
{
    PresentationPart? presentationPart = presentationDocument.PresentationPart;

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

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

    // Construct the slide content.            
    // Specify the non-visual properties of the new slide.
    CommonSlideData commonSlideData = slide.CommonSlideData ?? slide.AppendChild(new CommonSlideData());
    ShapeTree shapeTree = commonSlideData.ShapeTree ?? commonSlideData.AppendChild(new ShapeTree());
    NonVisualGroupShapeProperties nonVisualProperties = shapeTree.AppendChild(new NonVisualGroupShapeProperties());
    nonVisualProperties.NonVisualDrawingProperties = new NonVisualDrawingProperties() { Id = 1, Name = "" };
    nonVisualProperties.NonVisualGroupShapeDrawingProperties = new NonVisualGroupShapeDrawingProperties();
    nonVisualProperties.ApplicationNonVisualDrawingProperties = new ApplicationNonVisualDrawingProperties();

    // Specify the group shape properties of the new slide.
    shapeTree.AppendChild(new GroupShapeProperties());

    // Declare and instantiate the title shape of the new slide.
    Shape titleShape = shapeTree.AppendChild(new Shape());

    drawingObjectId++;

    // Specify the required shape properties for the title shape. 
    titleShape.NonVisualShapeProperties = new NonVisualShapeProperties
        (new NonVisualDrawingProperties() { Id = drawingObjectId, Name = "Title" },
        new NonVisualShapeDrawingProperties(new Drawing.ShapeLocks() { NoGrouping = true }),
        new ApplicationNonVisualDrawingProperties(new PlaceholderShape() { Type = PlaceholderValues.Title }));
    titleShape.ShapeProperties = new ShapeProperties();

    // Specify the text of the title shape.
    titleShape.TextBody = new TextBody(new Drawing.BodyProperties(),
            new Drawing.ListStyle(),
            new Drawing.Paragraph(new Drawing.Run(new Drawing.Text() { Text = slideTitle })));

    // Declare and instantiate the body shape of the new slide.
    Shape bodyShape = shapeTree.AppendChild(new Shape());
    drawingObjectId++;

    // Specify the required shape properties for the body shape.
    bodyShape.NonVisualShapeProperties = new NonVisualShapeProperties(new NonVisualDrawingProperties() { Id = drawingObjectId, Name = "Content Placeholder" },
            new NonVisualShapeDrawingProperties(new Drawing.ShapeLocks() { NoGrouping = true }),
            new ApplicationNonVisualDrawingProperties(new PlaceholderShape() { Index = 1 }));
    bodyShape.ShapeProperties = new ShapeProperties();

    // Specify the text of the body shape.
    bodyShape.TextBody = new TextBody(new Drawing.BodyProperties(),
            new Drawing.ListStyle(),
            new Drawing.Paragraph());

    // Create the slide part for the new slide.
    SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();

    // Save the new slide part.
    slide.Save(slidePart);

    // Modify the slide ID list in the presentation part.
    // The slide ID list should not be null.
    SlideIdList? slideIdList = presentationPart.Presentation.SlideIdList;

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

    OpenXmlElementList slideIds = slideIdList?.ChildElements ?? default;

    foreach (SlideId slideId in slideIds)
    {
        if (slideId.Id is not null && slideId.Id > maxSlideId)
        {
            maxSlideId = slideId.Id;
        }

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

    }

    maxSlideId++;

    // Get the ID of the previous slide.
    SlidePart lastSlidePart;

    if (prevSlideId is not null && prevSlideId.RelationshipId is not null)
    {
        lastSlidePart = (SlidePart)presentationPart.GetPartById(prevSlideId.RelationshipId!);
    }
    else
    {
        string? firstRelId = ((SlideId)slideIds[0]).RelationshipId;
        // If the first slide does not contain a relationship ID, throw an exception.
        if (firstRelId is null)
        {
            throw new ArgumentNullException(nameof(firstRelId));
        }

        lastSlidePart = (SlidePart)presentationPart.GetPartById(firstRelId);
    }

    // Use the same slide layout as that of the previous slide.
    if (lastSlidePart.SlideLayoutPart is not null)
    {
        slidePart.AddPart(lastSlidePart.SlideLayoutPart);
    }

    // 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();
}