65.9K
CodeProject 正在变化。 阅读更多。
Home

合并 PowerPoint 演示文稿 (PPTX) 并另存为 PDF

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (6投票s)

2014年2月6日

CPOL

6分钟阅读

viewsIcon

46768

downloadIcon

2192

本文介绍如何使用 Office 自动化 (OpenXML SDK) 在 .NET 应用程序中合并 PowerPoint 演示文稿(PPTX 格式)并另存为 PDF。

简介

本文将介绍如何使用 Open XML、Open XML SDK 2、Microsoft Office Interop、Microsoft Office Object Library 和 Visual Studio 2013 以编程方式将 PowerPoint 2010 演示文稿合并为一个,并将合并后的演示文稿保存为 PDF 格式。 

概述 

我们有三个 PowerPoint 2010 演示文稿:

  1. SamplePresentation1.pptx
  2. SamplePresentation2.pptx 
  3. SamplePresentation3.pptx  
我们将使用一个模板 TemplatePresentation.pptx 将它们合并到一个演示文稿中。首先,让我们使用 Microsoft PowerPoint 手动合并这些演示文稿。以下图像显示了输入演示文稿以及手动复制幻灯片后生成的合并演示文稿: 

TemplatePresentation.pptx  

SamplePresentation1.pptx

SamplePresentation2.pptx

SamplePresentation3.pptx

手动合并的演示文稿 

 

使用 Open XML SDK 合并演示文稿 

以下主题列出了在 Windows Forms 应用程序中合并演示文稿的步骤。

创建 Windows Forms 应用程序项目 

  1. 打开 Visual Studio 2013。单击 **文件 -> 新建 -> 项目**
  2. 选择 **Visual C# -> Windows** 并选择 **Windows Forms 应用程序** 模板

  3. 将演示文稿的名称设置为 **PresentationMerger**,并为解决方案选择所需的保存位置 

设计 Windows 窗体 

  1. 将六个 **按钮** 拖到窗体上,如下图所示

     
  2. 将 2 个 openFileDialog 和 2 个 saveFileDialog 拖到窗体上

  3. 设置控件的属性 

    • openFileDialog1: 

      1. 名称: openFileDialogSelectPresentations

      2. 多选: true

      3. 筛选器: PowerPoint 演示文稿|*.pptx

    • openFileDialog2: 

      1. 名称: openFileDialogSelectTemplate

      2. 筛选器: PowerPoint 演示文稿|*.pptx

    • saveFileDialog1: 

      1. 名称: saveFileDialogMerge

    • saveFileDialog2: 

      1. 名称: saveFileDialogSavePdf

    • button1: 

      1. 名称: btnSelectTemplate

      2. 文本: 选择要使用的模板

    • button2: 

      1. 名称: btnSelectPresentations

      2. 文本: 选择要合并的演示文稿

    • button3: 

      1. 名称: btnMergedPresentation

      2. 文本: 合并后的演示文稿

    • button4: 

      1. 名称: btnConvertedPdf

      2. 文本: 转换后的 PDF

    • button5: 

      1. 名称: btnMerge

      2. 文本: 合并

    • button6: 

      1. 名称: btnSaveAsPdf

      2. 文本: 另存为 PDF

为控件创建事件 

  1. 双击 **btnSelectPresentations** 并输入以下代码 

    private void btnSelectPresentations_Click(object sender, EventArgs e)
    {
        openFileDialogSelectPresentations.ShowDialog();
    }
    

  2. 双击 **btnSelectTemplate** 并输入以下代码 

    private void btnSelectTemplate_Click(object sender, EventArgs e)
    {
        openFileDialogSelectTemplate.ShowDialog();
    }
    

  3. 双击 **buttonMergedOutput** 并输入以下代码  

    private void btnMergedPresentation_Click(object sender, EventArgs e)
    {
        saveFileDialogMerge.ShowDialog();
    }
    
  4. 双击 btnConvertedPdf 并输入以下代码 

    private void btnConvertedPdf_Click(object sender, EventArgs e)
    {
        saveFileDialogSavePdf.ShowDialog();
    }
    

 添加 Open XML 程序集引用 

  1. 右键单击 **PresentationMerger** 项目中的 **References** 并选择 **Add Reference** 

  2. 选择 **DocumentFormat.OpenXml**、**WindowsBase**、**Microsoft.Office.Interop.PowerPoint** 和 **Microsoft Office 14.0 Object Library**,然后单击 OK 


     
     

添加 Open XML 代码 

  1. 添加额外的 **using** 语句以引用 Open XML 相关的命名空间

    using System.IO;
    using DocumentFormat.OpenXml;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Presentation;
    
    using Microsoft.Office.Interop.PowerPoint;
    
  2. 创建一个变量来保存幻灯片母版和幻灯片版式的唯一 ID。将变量命名为 uniqueId 

    public partial class Form1 : Form
    {
        static uint uniqueId;
    

  3. 创建 GetMaxSlideMasterId() 方法。此方法返回幻灯片母版 ID。请注意,幻灯片母版 ID 必须大于或等于 2147483648,因为大于 2147483648 的 ID 表示幻灯片母版 ID。此方法会循环遍历幻灯片母版 ID 列表的元素,并检查子 ID 是否大于定义的 max ID。 

    private uint GetMaxSlideMasterId(SlideMasterIdList slideMasterIdList)
    {
        // Slide master identifiers have a minimum value of greater than
        // or equal to 2147483648. 
        uint max = 2147483648;
    
        if (slideMasterIdList != null)
            // Get the maximum id value from the current set of children.
            foreach (SlideMasterId child in
                slideMasterIdList.Elements())
            {
                uint id = child.Id;
    
                if (id > max)
                    max = id;
            }
    
        return max;
    }
    

  4. 创建 GetMaxSlideId() 方法。此方法返回幻灯片 ID。请注意,幻灯片 ID 的最小值必须大于或等于 256,最大值必须小于 2147483648。大于 2147483648 的 ID 表示幻灯片母版 ID。此方法会循环遍历幻灯片 ID 列表的元素,并检查子 ID 是否大于定义的 max ID。 

    private uint GetMaxSlideId(SlideIdList slideIdList)
    {
        // Slide identifiers have a minimum value of greater than or
        // equal to 256 and a maximum value of less than 2147483648. 
        uint max = 256;
    
        if (slideIdList != null)
            // Get the maximum id value from the current set of children.
            foreach (SlideId child in slideIdList.Elements())
            {
                uint id = child.Id;
    
                if (id > max)
                    max = id;
            }
    
        return max;
    }
    

  5. 创建 FixSlideLayoutIds() 方法。此方法将确保每个演示文稿部分中的幻灯片母版部分中的每个幻灯片版式都具有唯一的 ID。这些 ID 必须是唯一的,以便区分每个版式。 

    private void FixSlideLayoutIds(PresentationPart presPart)
    {
        // Make sure that all slide layouts have unique ids.
        foreach (SlideMasterPart slideMasterPart in presPart.SlideMasterParts)
        {
            foreach (SlideLayoutId slideLayoutId in slideMasterPart.SlideMaster.SlideLayoutIdList)
            {
                uniqueId++;
                slideLayoutId.Id = (uint)uniqueId;
            }
    
            slideMasterPart.SlideMaster.Save();
        }
    

  6. 创建 MergePresentation() 方法。此方法将一个 PowerPoint 演示文稿合并到另一个演示文稿中。它通过以可编辑模式打开目标 PowerPoint 来实现,并检查它是否具有现有的幻灯片 ID 列表。如果没有,代码将创建一个。

    private void MergePresentation(string sourcePresentation, string mergedPresentation)
    {
        int id = 0;
    
        // Open the destination presentation.
        using (PresentationDocument myDestDeck = PresentationDocument.Open(mergedPresentation, true))
        {
            PresentationPart destPresPart = myDestDeck.PresentationPart;
    
            // If the merged presentation does not have a SlideIdList 
            // element yet, add it.
            if (destPresPart.Presentation.SlideIdList == null)
                destPresPart.Presentation.SlideIdList = new SlideIdList();
    

    在目标 PowerPoint 演示文稿打开的情况下,我们打开源 PowerPoint 演示文稿。 

    // Open the source presentation. This will throw an exception if
    // the source presentation does not exist.
    using (PresentationDocument mySourceDeck = PresentationDocument.Open(sourcePresentation, false))
    {
        PresentationPart sourcePresPart =
            mySourceDeck.PresentationPart;
    
    

    在两个 PowerPoint 演示文稿都打开的情况下,我们遍历源 PowerPoint 演示文稿的演示文稿部分中的每个幻灯片 ID 列表。然后,我们将这些部分复制并创建新的关系到目标 PowerPoint 演示文稿。请注意,我们必须在 foreach 语句之前获取 Max Slide Master ID 和 Max Slide ID,因为它们将用于生成新幻灯片母版 ID 和幻灯片 ID 的增量 ID。

    调用 GetMaxSlideMasterId()GetMaxSlideId() 方法,以确保我们始终获取最后一个 ID 并将其加一,从而确保所有母版幻灯片 ID 和幻灯片 ID 的 ID 都是唯一的。

    // Get unique ids for the slide master and slide lists
    // for use later.
    uniqueId = GetMaxSlideMasterId(destPresPart.Presentation.SlideMasterIdList);
    
    uint maxSlideId = GetMaxSlideId(destPresPart.Presentation.SlideIdList);
    
    // Copy each slide in the source presentation, in order, to 
    // the destination presentation.
    foreach (SlideId slideId in
        sourcePresPart.Presentation.SlideIdList)
    {
        SlidePart sp;
        SlidePart destSp;
        SlideMasterPart destMasterPart;
        string relId;
        SlideMasterId newSlideMasterId;
        SlideId newSlideId;
    
        // Create a unique relationship id.
        id++;
        sp =
            (SlidePart)sourcePresPart.GetPartById(
            slideId.RelationshipId);
    
        relId = Path.GetFileNameWithoutExtension(sourcePresentation).Replace(" ", "_") + id;
    
        // Add the slide part to the destination presentation.
        destSp = destPresPart.AddPart(sp, relId);
    
        // The slide master part was added. Make sure the
        // relationship between the main presentation part and
        // the slide master part is in place.
        destMasterPart = destSp.SlideLayoutPart.SlideMasterPart;
        destPresPart.AddPart(destMasterPart);
    
        // Add the slide master id to the slide master id list.
        uniqueId++;
        newSlideMasterId = new SlideMasterId();
        newSlideMasterId.RelationshipId =
            destPresPart.GetIdOfPart(destMasterPart);
        newSlideMasterId.Id = uniqueId;
    
        destPresPart.Presentation.SlideMasterIdList.Append(
            newSlideMasterId);
    
        // Add the slide id to the slide id list.
        maxSlideId++;
        newSlideId = new SlideId();
        newSlideId.RelationshipId = relId;
        newSlideId.Id = maxSlideId;
    
        destPresPart.Presentation.SlideIdList.Append(newSlideId);
    }
    
    

    接下来,我们通过调用 FixSlideLayoutIds() 方法来确保目标 PowerPoint 演示文稿中的所有幻灯片 ID 都是唯一的。一旦一切顺利,我们就可以保存目标 PowerPoint 演示文稿了。 

    // Make sure that all slide layout ids are unique.
        FixSlideLayoutIds(destPresPart);
    }
    
    // Save the changes to the destination deck.
    destPresPart.Presentation.Save();
    
    

  7. buttonMerge 创建点击事件。双击 buttonMerge。添加以下变量来存储选定的模板、选定的源演示文稿和目标合并后的 PowerPoint 演示文稿。 

    private void btnMerge_Click(object sender, EventArgs e)
    {
        string presentationTemplate = openFileDialogSelectTemplate.FileName;
        string[] presentationsToBeMerged = openFileDialogSelectPresentations.FileNames;
        string mergedPresentation = saveFileDialogMerge.FileName;
    

  8. 创建模板演示文稿的副本以生成新演示文稿。 

    // Create a copy of template presentation to generate merged presentation
    File.Copy(presentationTemplate, mergedPresentation, true);
    

  9. 循环遍历每个选定的源 PowerPoint 演示文稿并调用 MergePresentationSlides() 方法 

    // Loop through each source presentation and merge the slides into 
    // the merged presentation.
    foreach (string sourcePresentation in presentationsToBeMerged)
        MergePresentation(sourcePresentation, mergedPresentation);
    

将合并后的演示文稿转换为 PDF 

OpenXML SDK 无法将任何 Office 文档转换为其他格式,它只能用于编辑和操作文档,并且由于它基于 SDK 并且适用于服务器端操作,因此在这方面做得非常好。 

为了将 Office 文档转换为 PDF,我使用了 Microsoft Office Interop。双击 btnSaveAsPdf 按钮并使用以下代码调用 ConvertToPdf() 方法,将合并后的演示文稿转换为 PDF。   

private void btnSaveAsPdf_Click(object sender, EventArgs e)
{
    // Get the source PPTX file
    String pptxFile = saveFileDialogMerge.FileName;

    // Get the destination PDF file
    String pdfFile = saveFileDialogSavePdf.FileName;

    // Convert PPTX to PDF
    ConvertToPdf(pptxFile, pdfFile);

}

以下是 ConverToPdf() 方法,它创建 PowerPoint 应用程序实例,加载合并后的 PPTX 并将其转换为 PDF 

public void ConvertToPdf(String pptxFile, String pdfFile)
{
    try
    {
        // Create instance of PowerPoint application
        Microsoft.Office.Interop.PowerPoint.Application ppApp = new
            Microsoft.Office.Interop.PowerPoint.Application();

        // Open the PowerPoint presentation that needs to be converted
        Microsoft.Office.Interop.PowerPoint.Presentation presentation = ppApp.Presentations.Open
            (pptxFile, Microsoft.Office.Core.MsoTriState.msoTrue,
                Microsoft.Office.Core.MsoTriState.msoFalse,
                Microsoft.Office.Core.MsoTriState.msoFalse);

        // Save the file as PDF
        presentation.ExportAsFixedFormat(pdfFile,
                        PpFixedFormatType.ppFixedFormatTypePDF,
                        PpFixedFormatIntent.ppFixedFormatIntentPrint,
                        Microsoft.Office.Core.MsoTriState.msoFalse,
                        PpPrintHandoutOrder.ppPrintHandoutHorizontalFirst,
                        PpPrintOutputType.ppPrintOutputSlides,
                        Microsoft.Office.Core.MsoTriState.msoFalse,
                        null,
                        PpPrintRangeType.ppPrintAll,
                        "",
                        false,
                        false,
                        false,
                        true,
                        true,
                        System.Reflection.Missing.Value);

        // Close the presentation
        presentation.Close();

        // Free the memory
        presentation = null;
        ppApp = null;
        GC.Collect();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.StackTrace);
        throw ex;
    }
}

运行代码 

  1. 按 **F5**        
  2.  单击 选择要合并的模板 按钮 
  3. 在解决方案目录中的 **Presentations** 文件夹内,选择 TemplatePresentation.pptx 并单击 Open
  4. 单击 选择要合并的演示文稿 按钮
  5. 在解决方案目录中的 **Presentations** 文件夹内,选择 "SamplePresentation1.pptx" "SamplePresentation2.pptx" "SamplePresentation3.pptx" 并单击 Open
  6. 单击 合并后的演示文稿 按钮
  7. 选择合并后演示文稿的保存位置,并为其命名(后缀为 .pptx),然后单击 **Save** 按钮
  8. 单击 **Merge** 按钮。现在演示文稿已合并
  9. 单击 Converted PDF 按钮
  10. 选择转换后的 PDF 的保存位置,并为其命名(后缀为 .pdf),然后单击 **Save** 按钮
  11. 单击 Save as PDF 按钮。现在合并后的演示文稿已转换为 PDF。以下图像显示了合并后的演示文稿和转换后的 PDF 

合并后的演示文稿  

合并后的 PDF  

备选方案  

上述解决方案使用开源免费组件完成了工作,但此解决方案仅适用于 PPTX。如果您想对 PPT 和其他演示文稿格式执行相同操作怎么办?此外,从源代码中可以看到,仅合并演示文稿所需行数比预期要多。在实际应用中,开发人员还必须处理业务需求并集成其他复杂的逻辑,如编辑、替换某些单词、复制不同数量的幻灯片等。随着操作数量的增加,复杂性也会增加。 

以下是使用商业 .net powerpoint component 进行审核的代码,它完成了相同的工作 

private void btnMerge_Click(object sender, EventArgs e)
{
    string[] presentationsToBeMerged = openFileDialogSelectPresentations.FileNames;
    string mergedPresentation = saveFileDialogMerge.FileName;

    // Create empty presentation
    Aspose.Slides.Presentation destinationPresentation = new Aspose.Slides.Presentation();

    // Loop through each source presentation and merge the slides into 
    // the merged presentation.
    foreach (string presentation in presentationsToBeMerged)
    {
        // Open the source presentation
        Aspose.Slides.Presentation sourcePresentation = new Aspose.Slides.Presentation(presentation);
        // Get the slides of source presentation
        foreach (Aspose.Slides.Slide slide in sourcePresentation.Slides)
        {
            // Keep adding the slides in merged presentation
            destinationPresentation.Slides.AddClone(slide);
        }
    }

    // Save the merged presentation
    destinationPresentation.Save(mergedPresentation, Aspose.Slides.Export.SaveFormat.Pptx);
}

private void btnSaveAsPdf_Click(object sender, EventArgs e)
{
    // Get the merged PPTX file
    String pptxFile = saveFileDialogMerge.FileName;

    // Get the destination PDF file
    String pdfFile = saveFileDialogSavePdf.FileName;

    // Open the merged presentation
    Aspose.Slides.Presentation mergedPresentation = new Aspose.Slides.Presentation(pptxFile);

    // Convert PPTX to PDF
    mergedPresentation.Save(pdfFile, Aspose.Slides.Export.SaveFormat.Pdf);

}

您会注意到,只需调用 Presentation.Slides.AddClone() 方法即可合并演示文稿,而调用 Save() 方法即可将演示文稿保存为 PPTX、PPT、PDF 以及许多其他格式。因此,只需一行代码即可合并演示文稿,一行代码就足以进行转换。 

代码非常简洁,但第三方库需要付费。您需要自己评估第三方库是否适合您的需求,或者免费/开源组件是否足够。

© . All rights reserved.