プレゼンテーションのスライドにオーディオ ファイルを追加する

このトピックでは、Open XML SDK for Office のクラスを使用して、プログラムを使用してプレゼンテーションの最後のスライドにオーディオ ファイルを追加する方法について説明します。

Presentation オブジェクトの取得

Open XML SDK では、 PresentationDocument クラスはプレゼンテーション ドキュメント パッケージを表します。 プレゼンテーション ドキュメントを操作するには、まず PresentationDocument クラスのインスタンスを作成してから、そのインスタンスを操作します。 ドキュメントからクラス インスタンスを作成するには、ファイル パスを使用する Open メソッドを呼び出し、2 番目のパラメーターとしてブール値を使用してドキュメントを編集可能にするかどうかを指定します。 読み取り/書き込みのためにドキュメントを開くには、次のusingステートメントに示すように、このパラメーターの値trueを指定します。 このコードでは、ファイル パラメーターは開くドキュメントのファイルのパスを表す文字列です。

using (PresentationDocument presentationDocument = PresentationDocument.Open(filePath, true))

v3.0.0 以降では、using ステートメントに依存することを優先して、Close() メソッドが削除されました。 これにより、閉じかっこに達したときに、 Dispose() メソッドが自動的に呼び出されます。 using ステートメントに続くブロックは、using ステートメントで作成または名前付けされたオブジェクトのスコープを確立します(この場合はppt

オーディオのファイルの構造

PresentationML ドキュメントは、Picture (<pic/>) 要素を含む多数のパーツで構成されます。

ISO/IEC 29500 仕様の次のテキストでは、PresentationML パッケージの全体的な形式について説明します。

オーディオ ファイル (<audioFile/>) は、オーディオ ファイルの存在を指定します。 この要素は、オブジェクトのビジュアル以外のプロパティ内で指定されます。 オーディオは、ドキュメント内での表現方法であるため、オブジェクトにアタッチする必要があります。 ただし、オーディオの実際の再生は、タイミング要素で指定されたタイミング ノード リスト内で実行されます。

オーディオ ファイルがアタッチされている次の Picture オブジェクトについて考えてみましょう。

<p:pic>  
  <p:nvPicPr>  
    <p:cNvPr id="7" name="Rectangle 6">  
      <a:hlinkClick r:id="" action="ppaction://media"/>  
    </p:cNvPr>  
    <p:cNvPicPr>  
      <a:picLocks noRot="1"/>  
    </p:cNvPicPr>  
    <p:nvPr>  
      <a:audioFile r:link="rId1"/>  
    </p:nvPr>  
  </p:nvPicPr>  
</p:pic>

上の例では、この図に 1 つの audioFile 要素がアタッチされていることがわかります。 この画像は、通常の画像や図形と同様にドキュメント内に配置されます。 この画像の ID (この場合は 7) は、タイミング ノード リスト内からこの audioFile 要素を参照するために使用されます。 リンクされたリレーションシップ ID は、再生目的で実際のオーディオ ファイルを取得するために使用されます。

© ISO/IEC 29500: 2016

次の XML スキーマ フラグメントは、audioFile の内容を定義します。

<xsd:complexType name="CT_TLMediaNodeAudio">
	<xsd:sequence>
		<xsd:element name="cMediaNode" type="CT_TLCommonMediaNodeData" minOccurs="1" maxOccurs="1"/>
	</xsd:sequence>
  <xsd:attribute name="isNarration" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>

サンプル コードの動作のしくみ

using ステートメントで読み取り/書き込みアクセス用のプレゼンテーション ファイルを開いた後、コードはプレゼンテーション ドキュメントからプレゼンテーション パーツを取得します。 次に、最後のスライドのリレーションシップ ID を取得し、リレーションシップ ID からスライド パーツを取得します。

//Get presentation part
PresentationPart presentationPart = presentationDocument.PresentationPart;

//Get slides ids.
OpenXmlElementList slidesIds = presentationPart.Presentation.SlideIdList.ChildElements;

//Get relationsipId of the last slide
string? audioSlidePartRelationshipId = ((SlideId)slidesIds[slidesIds.ToArray().Length - 1]).RelationshipId;

if (audioSlidePartRelationshipId == null)
{
    throw new NullReferenceException("Slide id not found");
}

//Get slide part by relationshipID
SlidePart? slidePart = (SlidePart)presentationPart.GetPartById(audioSlidePartRelationshipId);

このコードではまず、追加するオーディオ ファイルのメディア データ パーツを作成します。 オーディオ ファイル ストリームを開いた状態で、メディア データ パーツ オブジェクトにフィードします。 次に、オーディオとメディアの関係の参照は、オーディオ ファイルへの今後の参照用の embedId とメディア参照用の mediaEmbedId を使用してスライドに追加されます。

その後、オーディオのプレースホルダーとして使用するサンプル画像と共に画像パーツが追加されます。 図オブジェクトは、ビジュアル以外のキャンバス プロパティを指定する非ビジュアル描画プロパティ (<cNvPr/>) など、さまざまな要素を使用して作成されます。 これにより、保存する画像の外観に影響を与えない追加情報を使用できます。 上記で説明した <audioFile/> 要素も含まれています。 HyperLinkOnClick (<hlinkClick/>) 要素は、テキストまたは画像の実行に適用するクリック時のハイパーリンク情報を指定します。 ハイパーリンクのテキストまたは画像をクリックすると、リンクがフェッチされます。 非ビジュアル図描画プロパティ (<cNvPicPr/>) は、図キャンバスのビジュアル以外のプロパティを指定します。 使用される要素の詳細については、ISO/IEC 29500 を参照してください

// Create audio Media Data Part (content type, extension)
MediaDataPart mediaDataPart = presentationDocument.CreateMediaDataPart("audio/mp3", ".mp3");

//Get the audio file and feed the stream
using (Stream mediaDataPartStream = File.OpenRead(audioFilePath))
{
    mediaDataPart.FeedData(mediaDataPartStream);
}
//Adds a AudioReferenceRelationship to the MainDocumentPart
slidePart.AddAudioReferenceRelationship(mediaDataPart, embedId);

//Adds a MediaReferenceRelationship to the SlideLayoutPart
slidePart.AddMediaReferenceRelationship(mediaDataPart, mediaEmbedId);

NonVisualDrawingProperties nonVisualDrawingProperties = new NonVisualDrawingProperties() { Id = shapeId, Name = "audio" };
A.AudioFromFile audioFromFile = new A.AudioFromFile() { Link = embedId };

ApplicationNonVisualDrawingProperties appNonVisualDrawingProperties = new ApplicationNonVisualDrawingProperties();
appNonVisualDrawingProperties.Append(audioFromFile);

//adds sample image to the slide with id to be used as reference in blip
ImagePart imagePart = slidePart.AddImagePart(ImagePartType.Png, imgEmbedId);
using (Stream data = File.OpenRead(coverPicPath))
{
    imagePart.FeedData(data);
}

if (slidePart!.Slide!.CommonSlideData!.ShapeTree == null)
{
    throw new NullReferenceException("Presentation shape tree is empty");
}

//Getting existing shape tree element from PowerPoint
ShapeTree shapeTree = slidePart.Slide.CommonSlideData.ShapeTree;

// specifies the existence of a picture within a presentation.
// It can have non-visual properties, a picture fill as well as shape properties attached to it.
Picture picture = new Picture();
NonVisualPictureProperties nonVisualPictureProperties = new NonVisualPictureProperties();

A.HyperlinkOnClick hyperlinkOnClick = new A.HyperlinkOnClick() { Id = "", Action = "ppaction://media" };
nonVisualDrawingProperties.Append(hyperlinkOnClick);

NonVisualPictureDrawingProperties nonVisualPictureDrawingProperties = new NonVisualPictureDrawingProperties();
A.PictureLocks pictureLocks = new A.PictureLocks() { NoChangeAspect = true };
nonVisualPictureDrawingProperties.Append(pictureLocks);

ApplicationNonVisualDrawingPropertiesExtensionList appNonVisualDrawingPropertiesExtensionList = new ApplicationNonVisualDrawingPropertiesExtensionList();
ApplicationNonVisualDrawingPropertiesExtension appNonVisualDrawingPropertiesExtension = new ApplicationNonVisualDrawingPropertiesExtension() { Uri = "{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}" };

次に、Media(CT_Media) 要素は、以前に参照された mediaEmbedId(Embedded Picture Reference) を使用して作成されます。 Blip 要素も追加されます。この要素は、イメージ (バイナリラージイメージまたは画像) の存在を指定し、画像データへの参照を含みます。 Blip の Embed 属性は、前に作成したイメージ パーツでプレースホルダー イメージを指定するために使用されます。

P14.Media media = new() { Embed = mediaEmbedId };
media.AddNamespaceDeclaration("p14", "http://schemas.microsoft.com/office/powerpoint/2010/main");

appNonVisualDrawingPropertiesExtension.Append(media);
appNonVisualDrawingPropertiesExtensionList.Append(appNonVisualDrawingPropertiesExtension);
appNonVisualDrawingProperties.Append(appNonVisualDrawingPropertiesExtensionList);

nonVisualPictureProperties.Append(nonVisualDrawingProperties);
nonVisualPictureProperties.Append(nonVisualPictureDrawingProperties);
nonVisualPictureProperties.Append(appNonVisualDrawingProperties);

//Prepare shape properties to display picture
BlipFill blipFill = new BlipFill();
A.Blip blip = new A.Blip() { Embed = imgEmbedId };

Offset(<off/>)、Stretch(<stretch/>)、fillRectangle(<fillRect/>) などのその他のすべての要素は、ShapeProperties(<spPr/>) に追加され、ShapeProperties は Picture 要素 (<pic/>) に追加されます。 最後に、オーディオを含む picture 要素がスライドの ShapeTree(<sp/>) に追加されます。

スライドにオーディオを追加するために使用できる完全なサンプル コードを次に示します。

サンプル コード

AddAudio(args[0], args[1], args[2]);

static void AddAudio(string filePath, string audioFilePath, string coverPicPath)
{

    string imgEmbedId = "rId4", embedId = "rId3", mediaEmbedId = "rId2";
    UInt32Value shapeId = 5;
    using (PresentationDocument presentationDocument = PresentationDocument.Open(filePath, true))
    {

        if (presentationDocument.PresentationPart == null || presentationDocument.PresentationPart.Presentation.SlideIdList == null)
        {
            throw new NullReferenceException("Presentation Part is empty or there are no slides in it");
        }

        //Get presentation part
        PresentationPart presentationPart = presentationDocument.PresentationPart;

        //Get slides ids.
        OpenXmlElementList slidesIds = presentationPart.Presentation.SlideIdList.ChildElements;

        //Get relationsipId of the last slide
        string? audioSlidePartRelationshipId = ((SlideId)slidesIds[slidesIds.ToArray().Length - 1]).RelationshipId;

        if (audioSlidePartRelationshipId == null)
        {
            throw new NullReferenceException("Slide id not found");
        }

        //Get slide part by relationshipID
        SlidePart? slidePart = (SlidePart)presentationPart.GetPartById(audioSlidePartRelationshipId);

        // Create audio Media Data Part (content type, extension)
        MediaDataPart mediaDataPart = presentationDocument.CreateMediaDataPart("audio/mp3", ".mp3");

        //Get the audio file and feed the stream
        using (Stream mediaDataPartStream = File.OpenRead(audioFilePath))
        {
            mediaDataPart.FeedData(mediaDataPartStream);
        }
        //Adds a AudioReferenceRelationship to the MainDocumentPart
        slidePart.AddAudioReferenceRelationship(mediaDataPart, embedId);

        //Adds a MediaReferenceRelationship to the SlideLayoutPart
        slidePart.AddMediaReferenceRelationship(mediaDataPart, mediaEmbedId);

        NonVisualDrawingProperties nonVisualDrawingProperties = new NonVisualDrawingProperties() { Id = shapeId, Name = "audio" };
        A.AudioFromFile audioFromFile = new A.AudioFromFile() { Link = embedId };

        ApplicationNonVisualDrawingProperties appNonVisualDrawingProperties = new ApplicationNonVisualDrawingProperties();
        appNonVisualDrawingProperties.Append(audioFromFile);

        //adds sample image to the slide with id to be used as reference in blip
        ImagePart imagePart = slidePart.AddImagePart(ImagePartType.Png, imgEmbedId);
        using (Stream data = File.OpenRead(coverPicPath))
        {
            imagePart.FeedData(data);
        }

        if (slidePart!.Slide!.CommonSlideData!.ShapeTree == null)
        {
            throw new NullReferenceException("Presentation shape tree is empty");
        }

        //Getting existing shape tree element from PowerPoint
        ShapeTree shapeTree = slidePart.Slide.CommonSlideData.ShapeTree;

        // specifies the existence of a picture within a presentation.
        // It can have non-visual properties, a picture fill as well as shape properties attached to it.
        Picture picture = new Picture();
        NonVisualPictureProperties nonVisualPictureProperties = new NonVisualPictureProperties();

        A.HyperlinkOnClick hyperlinkOnClick = new A.HyperlinkOnClick() { Id = "", Action = "ppaction://media" };
        nonVisualDrawingProperties.Append(hyperlinkOnClick);

        NonVisualPictureDrawingProperties nonVisualPictureDrawingProperties = new NonVisualPictureDrawingProperties();
        A.PictureLocks pictureLocks = new A.PictureLocks() { NoChangeAspect = true };
        nonVisualPictureDrawingProperties.Append(pictureLocks);

        ApplicationNonVisualDrawingPropertiesExtensionList appNonVisualDrawingPropertiesExtensionList = new ApplicationNonVisualDrawingPropertiesExtensionList();
        ApplicationNonVisualDrawingPropertiesExtension appNonVisualDrawingPropertiesExtension = new ApplicationNonVisualDrawingPropertiesExtension() { Uri = "{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}" };

        P14.Media media = new() { Embed = mediaEmbedId };
        media.AddNamespaceDeclaration("p14", "http://schemas.microsoft.com/office/powerpoint/2010/main");

        appNonVisualDrawingPropertiesExtension.Append(media);
        appNonVisualDrawingPropertiesExtensionList.Append(appNonVisualDrawingPropertiesExtension);
        appNonVisualDrawingProperties.Append(appNonVisualDrawingPropertiesExtensionList);

        nonVisualPictureProperties.Append(nonVisualDrawingProperties);
        nonVisualPictureProperties.Append(nonVisualPictureDrawingProperties);
        nonVisualPictureProperties.Append(appNonVisualDrawingProperties);

        //Prepare shape properties to display picture
        BlipFill blipFill = new BlipFill();
        A.Blip blip = new A.Blip() { Embed = imgEmbedId };

        A.Stretch stretch = new A.Stretch();
        A.FillRectangle fillRectangle = new A.FillRectangle();
        A.Transform2D transform2D = new A.Transform2D();
        A.Offset offset = new A.Offset() { X = 1524000L, Y = 857250L };
        A.Extents extents = new A.Extents() { Cx = 9144000L, Cy = 5143500L };
        A.PresetGeometry presetGeometry = new A.PresetGeometry() { Preset = A.ShapeTypeValues.Rectangle };
        A.AdjustValueList adjValueList = new A.AdjustValueList();

        stretch.Append(fillRectangle);
        blipFill.Append(blip);
        blipFill.Append(stretch);
        transform2D.Append(offset);
        transform2D.Append(extents);
        presetGeometry.Append(adjValueList);

        ShapeProperties shapeProperties = new ShapeProperties();
        shapeProperties.Append(transform2D);
        shapeProperties.Append(presetGeometry);

        //adds all elements to the slide's shape tree
        picture.Append(nonVisualPictureProperties);
        picture.Append(blipFill);
        picture.Append(shapeProperties);

        shapeTree.Append(picture);

    }
}

関連項目