将音频文件添加到演示文稿中的幻灯片

本主题演示如何使用 Open XML SDK for Office 中的类以编程方式将音频文件添加到演示文稿中的最后一张幻灯片。

获取 Presentation 对象

在 Open XML SDK 中 PresentationDocument , 类表示演示文稿文档包。 若要处理演示文稿文档,请先创建 类的 PresentationDocument 实例,然后使用该实例。 若要从文档创建类实例, Open 请调用使用文件路径的方法,并使用布尔值作为第二个参数来指定文档是否可编辑。 若要打开文档进行读/写,请指定此参数的值 true ,如以下 using 语句所示。 在该代码中,file 参数是一个字符串,表示要从中打开该文档的文件的路径。

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

在 v3.0.0+ 中, Close() 已删除 方法,转而依赖于 using 语句。 这可确保在 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>

在上面的示例中,我们看到有一个 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}" };

接下来,使用以前引用的 mediaEmbedId (嵌入式图片引用) 创建 Media (CT_Media) 元素。 还添加了 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/>) 。 最后,将包含音频的图片元素添加到幻灯片的 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);

    }
}

另请参阅