Creating a PowerPoint 2007 Presentation from a Folder of Images by Using the Open XML SDK 2.0 for Microsoft Office

Summary: Learn how to use the Open XML SDK 2.0 for Microsoft Office to create a PowerPoint 2007 presentation programmatically from a set of image files. (27 printed pages)

Office Visual How To

**Applies to:**2007 Microsoft Office system, Microsoft Office PowerPoint 2007, Open XML SDK 2.0 for Microsoft Office, Microsoft Visual Studio 2008

Joel Krist, iSoftStone

August 2009

Overview

The Open XMLSoftware Development Kit 2.0 for Microsoft Office makes it possible to create and manipulate Microsoft Office Word 2007, Microsoft Office Excel 2007, and Microsoft Office PowerPoint 2007 documents programmatically via the Microsoft Office Open XML Formats. The typesafe classes included with the SDK provide a layer of abstraction between the developer and the Microsoft Office Open XML Formats, simplifying the process of working with Office 2007 documents and enabling the creation of solutions that are not dependent on the presence of the Office client applications to handle document creation.

The sample code in this visual how-to article shows how to create a Microsoft Office PowerPoint 2007 presentation programmatically from a set of image files.

See It Video startup screen

Watch the Video

Length: 08:22 | Size: 14.50 MB | Type: WMV file

Code It | Read It | Explore It

Code It

Download sample code

To illustrate how to create a a PowerPoint 2007 presentation programmatically from a set of image files, this section walks through the following steps:

  1. Creating a template presentation.

  2. Creating a Windows console application solution in .

  3. Adding references to the DocumentFormat.OpenXml, System.Drawing, and WindowsBase assemblies.

  4. Adding the sample code to the solution.

Creating a Template Presentation

The sample code in this visual how-to article creates a presentation that contains slides from image files by using an existing template presentation as a starting point. By using a template that already exists, the code does not have to create the base presentation parts and relationships that are required to create a new presentation from scratch. Instead, it can focus on showing how to create slides from image files.

The sample code was written with the assumption that a template presentation exists and that it has the following characteristics:

  • It contains no slides.

  • It contains a single master slide.

  • It contains a single slide layout.

To create a template presentation with these characteristics, use the following procedure.

To create the Template Presentation

  1. Start Microsoft Office PowerPoint 2007.

  2. Click the View tab and then click Normal on the left side of the Ribbon.

  3. On the Slides tab of the Slides / Outline task pane on the left side of the screen, right-click the thumbnail of the single default slide that PowerPoint created, and then click Delete Slide.

    Figure 1. Delete the default slide

    Delete the default slide

     

  4. Click the View tab, and then click Slide Master in the Presentation Views group to open the Slide Master view.

  5. In Slide Master view, select and delete all of the slide layouts except for the first one.

  6. Select and delete all content placeholders in the single master slide.

  7. Select and delete all content placeholders in the single remaining slide layout.

  8. Rename the slide layout Image Slide.

    The result should be a single master slide and slide layout with no content placeholders.

    Figure 2. Final single master slide and slide layout

    Final single master slide and slide layout

     

  9. Now click the View tab and click Normal in the Presentation Views to switch back to Normal view.

  10. Because the sample code in this article specifies that the template presentation is located in the C:\Temp folder, name the template presentation PresentationTemplate.pptx and then save it to the C:\Temp folder.

  11. Exit PowerPoint.

Creating a Windows Console Application in Visual Studio 2008

This visual how-to article uses a Windows console application to provide the framework for the sample code. However, you could use the same approach that is illustrated here with other application types as well.

To create a Windows Console Application in Visual Studio 2008

  1. Start Microsoft Visual Studio 2008.

  2. On the File menu, point to New, and then click Project.

  3. In the New Project dialog box select the Visual C# Windows type in the Project types pane.

  4. Select Console Application in the Templates pane, and then name the project CreateDeckFromImages.

    Figure 3. Create new solution in the New Project dialog box

    Create new solution in the New Project dialog box

     

  5. Click OK to create the solution.

Adding References to the DocumentFormat.OpenXml, System.Drawing, and WindowsBase Assemblies

The sample code uses the classes and enumerations that are in the DocumentFormat.OpenXml.dll assembly that is installed with the Open XML SDK 2.0 for Microsoft Office. To add the reference to the assembly in the following steps or to build the sample code that accompanies this visual how-to, you must first download and install the Open XML SDK 2.0 for Microsoft Office so that the assembly is available.

To add References to the DocumentFormat.OpenXml, WindowsBase, and System.Drawing Assemblies

  1. Add a reference to the DocumentFormat.OpenXml assembly by doing the following:

    1. On the Project menu in Visual Studio, click Add Reference to open the Add Reference dialog box.

    2. Select the .NET tab, scroll down to DocumenFormat.OpenXml, select it, and then click OK.

      Figure 4. Add Reference to DocumentFormat.OpenXML

      Add Reference to DocumentFormat.OpenXml

       

  2. The sample code uses classes defined in the System.Drawing namespace when working with image files. Add a reference to the System.Drawing assembly by doing the following:

    1. On the Project menu in Visual Studio, click Add Reference to open the Add Reference dialog box.

    2. Select the .NET tab, scroll down to System.Drawing, select it, and then click OK.

      Figure 5. Add Reference to System.Drawing

      Add Reference to System.Drawing

       

  3. The classes in the DocumentFormat.OpenXml assembly use the System.IO.Packaging.Package class that is defined in the WindowsBase assembly. Add a reference to the WindowsBase assembly by doing the following:

    1. On the Project menu in Visual Studio, click Add Reference to open the Add Reference dialog box.

    2. Select the .NET tab, scroll down to WindowsBase, select it, and then click OK.

      Figure 6. Add Reference to WindowsBase

      Add Reference to WindowsBase

       

Adding the Sample Code to the Solution

In Visual Studio, replace the contents of the Program.cs source file with the following code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using a = DocumentFormat.OpenXml.Drawing;

class Program
{
  static void Main(string[] args)
  {
    string newPresentation = "DeckFromImages.pptx";
    string presentationTemplate = "PresentationTemplate.pptx";
    string presentationFolder = @"C:\Temp\";
    string imageFolder = @"C:\Temp";
    string[] imageFileExtensions =
      new[] { "*.jpg", "*.jpeg", "*.gif", "*.bmp", "*.png", "*.tif" };

    // Make a copy of the template presentation. This will throw an
    // exception if the template presentation does not exist.
    File.Copy(presentationFolder + presentationTemplate,
      presentationFolder + newPresentation, true);

    // Get the image files in the image folder.
    List<string> imageFileNames = GetImageFileNames(imageFolder,
      imageFileExtensions);

    // Create new slides for the images.
    if (imageFileNames.Count() > 0)
      CreateSlides(imageFileNames,
        presentationFolder + newPresentation);

    // Validate the new presentation.
    OpenXmlValidator validator = new OpenXmlValidator();

    var errors = validator.Validate(
      presentationFolder + newPresentation);

    if (errors.Count() > 0)
    {
      Console.WriteLine("The deck creation process completed but " +
        "the created presentation failed to validate.");
      Console.WriteLine("There are " + errors.Count() +
        " errors:\r\n");

      DisplayValidationErrors(errors);
    }
    else
      Console.WriteLine("The deck creation process completed and " +
        "the created presentation validated with 0 errors.");
  }

  static void CreateSlides(List<string> imageFileNames,
    string newPresentation)
  {
    string relId;
    SlideId slideId;

    // Slide identifiers have a minimum value of greater than or
    // equal to 256 and a maximum value of less than 2147483648.
    // Assume that the template presentation being used has no slides.
    uint currentSlideId = 256;

    string imageFileNameNoPath;

    long imageWidthEMU = 0;
    long imageHeightEMU = 0;

    // Open the new presentation.
    using (PresentationDocument newDeck =
      PresentationDocument.Open(newPresentation, true))
    {
      PresentationPart presentationPart = newDeck.PresentationPart;

      // Reuse the slide master part. This code assumes that the
      // template presentation being used has at least one
      // master slide.
      var slideMasterPart = presentationPart.SlideMasterParts.First();

      // Reuse the slide layout part. This code assumes that the
      // template presentation being used has at least one
      // slide layout.
      var slideLayoutPart = slideMasterPart.SlideLayoutParts.First();

      // If the new presentation doesn't have a SlideIdList element
      // yet then add it.
      if (presentationPart.Presentation.SlideIdList == null)
        presentationPart.Presentation.SlideIdList = new SlideIdList();

      // Loop through each image file creating slides
      // in the new presentation.
      foreach (string imageFileNameWithPath in imageFileNames)
      {
        imageFileNameNoPath =
          Path.GetFileNameWithoutExtension(imageFileNameWithPath);

        // Create a unique relationship id based on the current
        // slide id.
        relId = "rel" + currentSlideId;

        // Get the bytes, type and size of the image.
        ImagePartType imagePartType = ImagePartType.Png;
        byte[] imageBytes = GetImageData(imageFileNameWithPath,
          ref imagePartType, ref imageWidthEMU, ref imageHeightEMU);

        // Create a slide part for the new slide.
        var slidePart = presentationPart.AddNewPart<SlidePart>(relId);
        GenerateSlidePart(imageFileNameNoPath, imageFileNameNoPath,
          imageWidthEMU, imageHeightEMU).Save(slidePart);

        // Add the relationship between the slide and the
        // slide layout.
        slidePart.AddPart<SlideLayoutPart>(slideLayoutPart);

        // Create an image part for the image used by the new slide.
        // A hardcoded relationship id is used for the image part since
        // there is only one image per slide. If more than one image
        // was being added to the slide an approach similar to that
        // used above for the slide part relationship id could be
        // followed, where the image part relationship id could be
        // incremented for each image part.
        var imagePart = slidePart.AddImagePart(ImagePartType.Jpeg,
          "relId1");
        GenerateImagePart(imagePart, imageBytes);

        // Add the new slide to the slide list.
        slideId = new SlideId();
        slideId.RelationshipId = relId;
        slideId.Id = currentSlideId;
        presentationPart.Presentation.SlideIdList.Append(slideId);

        // Increment the slide id;
        currentSlideId++;
      }

      // Save the changes to the slide master part.
      slideMasterPart.SlideMaster.Save();

      // Save the changes to the new deck.
      presentationPart.Presentation.Save();
    }
  }

  public static List<string> GetImageFileNames(string imageFolder,
    string[] imageFileExtensions)
  {
    // Create a list to hold the names of the files with the
    // requested extensions.
    List<string> fileNames = new List<string>();

    // Loop through each file extension.
    foreach (string extension in imageFileExtensions)
    {
      // Add all the files that match the current extension to the
      // list of file names.
      fileNames.AddRange(Directory.GetFiles(imageFolder, extension,
        SearchOption.TopDirectoryOnly));
    }

    // Return the list of file names.
    return fileNames;
  }

  private static byte[] GetImageData(string imageFilePath,
    ref ImagePartType imagePartType, ref long imageWidthEMU,
    ref long imageHeightEMU)
  {
    byte[] imageFileBytes;
    // Bitmap imageFile;

    // Open a stream on the image file and read it's contents. The
    // following code will generate an exception if an invalid file
    // name is passed.
    using (FileStream fsImageFile = File.OpenRead(imageFilePath))
    {
      imageFileBytes = new byte[fsImageFile.Length];
      fsImageFile.Read(imageFileBytes, 0, imageFileBytes.Length);

      using (Bitmap imageFile = new Bitmap(fsImageFile))
      {
        // Determine the format of the image file. This sample code
        // supports working with the following types of image files:
        //
        // Bitmap (BMP)
        // Graphics Interchange Format (GIF)
        // Joint Photographic Experts Group (JPG, JPEG)
        // Portable Network Graphics (PNG)
        // Tagged Image File Format (TIFF)

        if (imageFile.RawFormat.Guid == ImageFormat.Bmp.Guid)
          imagePartType = ImagePartType.Bmp;
        else if (imageFile.RawFormat.Guid == ImageFormat.Gif.Guid)
          imagePartType = ImagePartType.Gif;
        else if (imageFile.RawFormat.Guid == ImageFormat.Jpeg.Guid)
          imagePartType = ImagePartType.Jpeg;
        else if (imageFile.RawFormat.Guid == ImageFormat.Png.Guid)
          imagePartType = ImagePartType.Png;
        else if (imageFile.RawFormat.Guid == ImageFormat.Tiff.Guid)
          imagePartType = ImagePartType.Tiff;
        else
        {
          throw new ArgumentException(
            "Unsupported image file format: " + imageFilePath);
        }

        // Get the dimensions of the image in English Metric Units
        // (EMU) for use when adding the markup for the image to the
        // slide.
        imageWidthEMU =
        (long)
        ((imageFile.Width / imageFile.HorizontalResolution) * 914400L);
        
        imageHeightEMU =
        (long)
        ((imageFile.Height / imageFile.VerticalResolution) * 914400L);
      }
    }

    return imageFileBytes;
  }

  private static Slide GenerateSlidePart(string imageName,
    string imageDescription, long imageWidthEMU, long imageHeightEMU)
  {
    var element =
      new Slide(
        new CommonSlideData(
          new ShapeTree(
            new NonVisualGroupShapeProperties(
              new NonVisualDrawingProperties()
              { Id = (UInt32Value)1U, Name = "" },
              new NonVisualGroupShapeDrawingProperties(),
              new AppNonVisualDrawingProperties()),
            new GroupShapeProperties(
              new a.TransformGroup(
                new a.Offset() { X = 0L, Y = 0L },
                new a.Extents() { Cx = 0L, Cy = 0L },
                new a.ChildOffset() { X = 0L, Y = 0L },
                new a.ChildExtents() { Cx = 0L, Cy = 0L })),
            new Picture(
              new NonVisualPictureProperties(
                new NonVisualDrawingProperties()
                {
                  Id = (UInt32Value)4U,
                  Name = imageName,
                  Description = imageDescription
                },
                new NonVisualPictureDrawingProperties(
                  new a.PictureLocks() { NoChangeAspect = true }),
                new AppNonVisualDrawingProperties()),
                new BlipFillProperties(
                  new a.Blip() { Embed = "relId1" },
                  new a.Stretch(
                    new a.FillRectangle())),
                new ShapeProperties(
                  new a.Transform2D(
                    new a.Offset() { X = 0L, Y = 0L },
                    new a.Extents()
                    {
                      Cx = imageWidthEMU,
                      Cy = imageHeightEMU
                    }),
                  new a.PresetGeometry(
                    new a.AdjustValueList())
                    { Preset = a.ShapeTypeValues.Rectangle }
                )))),
        new ColorMapOverride(
          new a.MasterColorMapping()));

    return element;
  }

  private static void GenerateImagePart(OpenXmlPart part,
    byte[] imageFileBytes)
  {
    // Write the contents of the image to the ImagePart.
    using (BinaryWriter writer = new BinaryWriter(part.GetStream()))
    {
      writer.Write(imageFileBytes);
      writer.Flush();
    }
  }

  static void DisplayValidationErrors(
    IEnumerable<ValidationErrorInfo> errors)
  {
    int errorIndex = 1;

    foreach (ValidationErrorInfo errorInfo in errors)
    {
      Console.WriteLine(errorInfo.Description);
      Console.WriteLine(errorInfo.Path.XPath);

      if (++errorIndex <= errors.Count())
        Console.WriteLine("================");
    }
  }
}

 

Build and run the solution in Visual Studio by pressing CTRL+F5. When you build and run the sample code, it creates a presentation in the C:\Temp folder named DeckFromImages.pptx. The code creates a new presentation from a template presentation named PresentationTemplate.pptx. The new presentation contains slides that the code creates from image files with .jpg, .jpeg, .gif, .bmp, .png, and .tif extensions, also located in the C:\Temp folder.

To change the names or location of the new presentation or the template presentation, modify the sample code and change the value of the newPresentation, presentationTemplate, or presentationFolder variables defined in the Main method. To change the location of the image files that are used to create slides, edit the value of the imageFolder variable. To change the file extensions of the image file types that are used to create slides, modify the value of the imageFileExtensions variable and adjust the code in the GetImageData method to match.

Read It

The sample code in this visual how-to article illustrates how to create a PowerPoint 2007 presentation from a set of image files. To accomplish that task, the sample code performs the following actions:

  • Creates a new presentation by making a copy of an existing template presentation.

  • Determines the image files to use to create the slides in the new presentation.

  • Opens the new presentation and accesses the main presentation part in that presentation.

  • Gets the first slide master part from the presentation part.

  • Gets the first slide layout part from the slide master part.

  • For each image file:

    • Generates a unique Relationship ID based on the current Slide Id.

    • Gets the image file bytes, type, and size data.

    • Creates a slide part for a new slide.

    • Creates a relationship between the new slide and the slide layout.

    • Creates an image part for the new slide to use and streams the image file bytes into the image part.

    • Adds the ID of the new slide to the Slide ID list in the presentation part.

    • Increments the current Slide ID.

  • Saves the changes to the slide master part.

  • Saves the changes to the presentation part.

  • Validates the new presentation.

This section uses code snippets from the Code It section to describe the approach to the solution.

The sample code creates the new presentation by making a copy of an existing template presentation. After it makes a copy of the template, the code calls the GetImageFileNames method to get a list of the names of the image files to create slides from.

// Make a copy of the template presentation. This will throw an
// exception if the template presentation does not exist.
File.Copy(presentationFolder + presentationTemplate,
  presentationFolder + newPresentation, true);

// Get the image files in the image folder.
List<string> imageFileNames = GetImageFileNames(imageFolder,
  imageFileExtensions);

 

The GetImageFileNames method accepts the path to the image folder and a string array that contains the image file extensions to process. The method iterates through the file extensions and builds a list of file names that match those extensions as it goes. It then returns the list of image file names.

public static List<string> GetImageFileNames(string imageFolder,
  string[] imageFileExtensions)
{
  // Create a list to hold the names of the files with the
  // requested extensions.
  List<string> fileNames = new List<string>();

  // Loop through each file extension.
  foreach (string extension in imageFileExtensions)
  {
    // Add all the files that match the current extension to the
    // list of file names.
    fileNames.AddRange(Directory.GetFiles(imageFolder, extension,
      SearchOption.TopDirectoryOnly));
  }

  // Return the list of file names.
  return fileNames;
}

 

After it builds the list of image file names, the code calls the CreateSlides method and passes it the list of image file names along with the path to the new presentation to which to add the slides.

// Create new slides for the images.
if (imageFileNames.Count() > 0)
  CreateSlides(imageFileNames,
    presentationFolder + newPresentation);

 

The CreateSlides method opens the new presentation. It gets the presentation, the first slide master, and the first slide layout parts, and then ensures that the Slide ID List for the presentation exists.

// Open the new presentation.
using (PresentationDocument newDeck =
  PresentationDocument.Open(newPresentation, true))
{
  PresentationPart presentationPart = newDeck.PresentationPart;

  // Reuse the slide master part. This code requires that 
  // the template presentation being used has at least one
  // master slide.
  var slideMasterPart = presentationPart.SlideMasterParts.First();

  // Reuse the slide layout part. This code requires that 
  // the template presentation being used has at least one
  // slide layout.
  var slideLayoutPart = slideMasterPart.SlideLayoutParts.First();

  // If the new presentation doesn't have a SlideIdList element
  // yet then add it.
  if (presentationPart.Presentation.SlideIdList == null)
    presentationPart.Presentation.SlideIdList = new SlideIdList();

 

Next, the CreateSlides method loops through each image file to create the slides. The code gets the image file's base name and creates a unique relationship ID based on the current Slide ID. It then calls the GetImageData method to get the image file's bytes, type, and sizing information.

// Loop through each image file creating slides
// in the new presentation.
foreach (string imageFileNameWithPath in imageFileNames)
{
  imageFileNameNoPath =
    Path.GetFileNameWithoutExtension(imageFileNameWithPath);

  // Create a unique relationship id based on the current
  // slide id.
  relId = "rel" + currentSlideId;

  // Get the bytes, type, and size of the image.
  ImagePartType imagePartType = ImagePartType.Png;
  byte[] imageBytes = GetImageData(imageFileNameWithPath,
    ref imagePartType, ref imageWidthEMU, ref imageHeightEMU);

 

The GetImageData method opens a FileStream on the image file and reads the file contents into a byte array. It determines the image file's type, and then calculates the horizontal and vertical extents of the image in English Metric Units (EMU). The code uses those measurements when it creates the new slide that is based on the image and sets the extent-related attributes.

private static byte[] GetImageData(string imageFilePath,
  ref ImagePartType imagePartType, ref long imageWidthEMU,
  ref long imageHeightEMU)
{
  byte[] imageFileBytes;
  // Bitmap imageFile;

  // Open a stream on the image file and read its contents. The
  // following code will generate an exception if an invalid file
  // name is passed.
  using (FileStream fsImageFile = File.OpenRead(imageFilePath))
  {
    imageFileBytes = new byte[fsImageFile.Length];
    fsImageFile.Read(imageFileBytes, 0, imageFileBytes.Length);

    using (Bitmap imageFile = new Bitmap(fsImageFile))
    {
      // Determine the format of the image file. This sample code
      // supports working with the following types of image files:
      //
      // Bitmap (BMP)
      // Graphics Interchange Format (GIF)
      // Joint Photographic Experts Group (JPG, JPEG)
      // Portable Network Graphics (PNG)
      // Tagged Image File Format (TIFF)

      if (imageFile.RawFormat.Guid == ImageFormat.Bmp.Guid)
        imagePartType = ImagePartType.Bmp;
      else if (imageFile.RawFormat.Guid == ImageFormat.Gif.Guid)
        imagePartType = ImagePartType.Gif;
      else if (imageFile.RawFormat.Guid == ImageFormat.Jpeg.Guid)
        imagePartType = ImagePartType.Jpeg;
      else if (imageFile.RawFormat.Guid == ImageFormat.Png.Guid)
        imagePartType = ImagePartType.Png;
      else if (imageFile.RawFormat.Guid == ImageFormat.Tiff.Guid)
        imagePartType = ImagePartType.Tiff;
      else
      {
        throw new ArgumentException(
          "Unsupported image file format: " + imageFilePath);
      }

      // Get the dimensions of the image in English Metric Units
      // (EMU) for use when adding the markup for the image to the
      // slide.
      imageWidthEMU =
      (long)
      ((imageFile.Width / imageFile.HorizontalResolution) * 914400L);
      
      imageHeightEMU =
      (long)
      ((imageFile.Height / imageFile.VerticalResolution) * 914400L);
    }
  }

  return imageFileBytes;
}

 

After it gets the image data, the CreateSlides method creates a new slide part, adds the relationship between the new slide and the slide layout, and creates an image part.

// Create a slide part for the new slide.
var slidePart = presentationPart.AddNewPart<SlidePart>(relId);
GenerateSlidePart(imageFileNameNoPath, imageFileNameNoPath,
  imageWidthEMU, imageHeightEMU).Save(slidePart);

// Add the relationship between the slide and the
// slide layout.
slidePart.AddPart<SlideLayoutPart>(slideLayoutPart);

// Create an image part for the image used by the new slide.
// A hardcoded relationship id is used for the image part since
// there is only one image per slide. If more than one image
// was being added to the slide, an approach similar to that 
// used before for the slide part relationship id could be
// followed, where the image part relationship id could be
// incremented for each image part.
var imagePart = slidePart.AddImagePart(ImagePartType.Jpeg,
  "relId1");
GenerateImagePart(imagePart, imageBytes);

 

The code uses helper methods to generate the slide and image parts.

private static Slide GenerateSlidePart(string imageName,
  string imageDescription, long imageWidthEMU, long imageHeightEMU)
{
  var element =
    new Slide(
      new CommonSlideData(
        new ShapeTree(
          new NonVisualGroupShapeProperties(
            new NonVisualDrawingProperties()
            { Id = (UInt32Value)1U, Name = "" },
            new NonVisualGroupShapeDrawingProperties(),
            new AppNonVisualDrawingProperties()),
          new GroupShapeProperties(
            new a.TransformGroup(
              new a.Offset() { X = 0L, Y = 0L },
              new a.Extents() { Cx = 0L, Cy = 0L },
              new a.ChildOffset() { X = 0L, Y = 0L },
              new a.ChildExtents() { Cx = 0L, Cy = 0L })),
          new Picture(
            new NonVisualPictureProperties(
              new NonVisualDrawingProperties()
              { Id = (UInt32Value)4U, Name = imageName,
                Description = imageDescription },
              new NonVisualPictureDrawingProperties(
                new a.PictureLocks() { NoChangeAspect = true }),
              new AppNonVisualDrawingProperties()),
              new BlipFillProperties(
                new a.Blip() { Embed = "relId1" },
                new a.Stretch(
                  new a.FillRectangle())),
              new ShapeProperties(
                new a.Transform2D(
                  new a.Offset() { X = 0L, Y = 0L },
                  new a.Extents()
                  { Cx = imageWidthEMU,
                    Cy = imageHeightEMU }),
                new a.PresetGeometry(
                  new a.AdjustValueList())
                { Preset = a.ShapeTypeValues.Rectangle }
              )))),
      new ColorMapOverride(
        new a.MasterColorMapping()));

  return element;
}

private static void GenerateImagePart(OpenXmlPart part,
  byte[] imageFileBytes)
{
  // Write the contents of the image to the ImagePart.
  using (BinaryWriter writer = new BinaryWriter(part.GetStream()))
  {
    writer.Write(imageFileBytes);
    writer.Flush();
  }
}

 

The code then adds the ID of the new slide into the Slide ID List that is in the presentation part, and increments the current Slide ID by one in preparation for the creation of the next slide.

// Add the new slide to the slide list.
slideId = new SlideId();
slideId.RelationshipId = relId;
slideId.Id = currentSlideId;
presentationPart.Presentation.SlideIdList.Append(slideId);

// Increment the slide id;
currentSlideId++;

 

After it processes all of the image files, the CreateSlides method saves the changes to the slide master and presentation parts.

// Save the changes to the slide master part.
slideMasterPart.SlideMaster.Save();

// Save the changes to the new deck.
presentationPart.Presentation.Save();

 

Finally, the code validates the new presentation by using the OpenXmlValidator class. If there are validation errors, it calls the DisplayValidationErrors helper method, passing the collection of ValidationErrorInfo objects.

// Validate the new presentation.
OpenXmlValidator validator = new OpenXmlValidator();

var errors = validator.Validate(
  presentationFolder + newPresentation);

if (errors.Count() > 0)
{
  Console.WriteLine("The deck creation process completed but " +
    "the created presentation failed to validate.");
  Console.WriteLine("There are " + errors.Count() + 
    " errors:\r\n");

  DisplayValidationErrors(errors);
}
else
  Console.WriteLine("The deck creation process completed and " +
    "the created presentation validated with 0 errors.");

 

The DisplayValidationErrors method loops through the passed ValidationErrorInfo objects and displays the error description and the path to the part where the error occurred.

static void DisplayValidationErrors(
  IEnumerable<ValidationErrorInfo> errors)
{
  int errorIndex = 1;

  foreach (ValidationErrorInfo errorInfo in errors)
  {
    Console.WriteLine(errorInfo.Description);
    Console.WriteLine(errorInfo.Path.XPath);

    if (++errorIndex <= errors.Count())
      Console.WriteLine("================");
  }
}

 

NoteNote

When you use the Open XML SDK 2.0 for Microsoft Office to create a document-generation solution, it is best practice to create a template document first, and then use DocumentReflector, a tool that comes with the SDK. DocumentReflector can generate C# code that uses the SDK typesafe classes to reproduce your template document and the functionality that it contains. You can then use that code to help you add functionality or to help you understand the Open XML document parts and relationships that are required to implement a specific document feature. For more information about best practices and the Open XML SDK 2.0 for Microsoft Office, see Erika Ehrli's blog entry Getting Started Best Practices.

Explore It