Creating a Open XML PowerPoint presentation from scratch using System.IO.Packaging

Here is how I’ve got to create this sample – One of my customer had a similar requirement when I tried to search a sample for him to demonstrate, I couldn’t find one (blame it on my searching capabilities or whatever .. )

While creating a sample there are a few titbits that I came to know -

1)  In order to create a valid presentation you’ve got to have following parts - presentation, slide, slideLayout, slideMaster and theme

2) By default when you create a package using Packaging API it’s NOT compressed. To have a compressed package you need to specify compression option in CreatePart. Something like this   …

 Dim pPart As PackagePart = p.CreatePart(pURI, contentType,CompressionOption.Fast)
Dim pPart As PackagePart = p.CreatePart(pURI, contentType,CompressionOption.Maximum)
Dim pPart As PackagePart = p.CreatePart(pURI, contentType,CompressionOption.Normal)
Dim pPart As PackagePart = p.CreatePart(pURI, contentType,CompressionOption.NotCompressed)
Dim pPart As PackagePart = p.CreatePart(pURI, contentType,CompressionOption.SuperFast)


The real fun part here is – you can have different parts compressed in different CompressionOption (that implies that I can have a few parts compressed and a few parts uncompressed!) – well at least this is what my testing says.

Here is the code snippet (the code is dependent on a few xmlfiles which are attached as a zip)-


 Public Class Form1

#Region "NamespaceConstants"
    Private Structure constants
        Dim dummy
        Shared presentationmlNamespace As String = ""
        Shared relationshipNamespace As String = ""
        Shared corePropertiesSchema As String = ""
        Shared docPropsVTypes As String = ""
        Shared slidePartNamespace As String = ""
        Shared appPartNamespace As String = ""
        Shared themePartNamespace As String = ""
        Shared slidelayoutNamespace As String = ""
        Shared slidemasterNamespace As String = ""
        Shared mainpartNamespace As String = ""

        Shared mainPartContentType As String = "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"
        Shared slidePartContentType As String = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml"
        Shared slideLayoutContentType As String = "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"
        Shared appPartContentType As String = "application/vnd.openxmlformats-officedocument.extended-properties+xml"
        Shared corePartContentType As String = "application/vnd.openxmlformats-package.core-properties+xml"
        Shared themePartContentType As String = "application/vnd.openxmlformats-officedocument.theme+xml"
        Shared slidemasterContentType As String = "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml"

    End Structure

#End Region

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Using myPackage As Package = Package.Open("C:\somepath\GuineaPig.pptx", FileMode.Create, FileAccess.ReadWrite, FileShare.None)


            'Add package parts app,core and doc
            Dim docPart As PackagePart = CreateBasicPart(New StreamReader("C:\somepath\presentation.xml").BaseStream, myPackage, "ppt/presentation.xml", constants.mainPartContentType, constants.presentationmlNamespace)
            'end add

            'add other *required* parts slide,slidemaster,theme,slidelayout
            Dim pp() As PackagePart

            'add slide part

            pp = New PackagePart() {docPart}
            Dim slidePart As PackagePart = CreateExtendedPart(myPackage, "C:\somepath\slide1.xml", "ppt/slides/slide1.xml", constants.slidePartContentType, constants.slidePartNamespace, pp)
            AdjustPartXML("//p:sldIdLst/p:sldId/@r:id", docPart, constants.slidePartNamespace)

            'end add slide part

            'add theme part

            pp = New PackagePart() {docPart}
            Dim themePart As PackagePart = CreateExtendedPart(myPackage, "C:\somepath\theme1.xml", "ppt/theme/theme1.xml", constants.themePartContentType, constants.themePartNamespace, pp)
            'end add theme part

            'add slide layout part
            pp = New PackagePart() {slidePart}
            Dim slidelayoutPart As PackagePart = CreateExtendedPart(myPackage, "C:\somepath\slidelayout1.xml", "ppt/slideLayouts/slideLayout1.xml", constants.slideLayoutContentType, constants.slidelayoutNamespace, pp)
            'end add slide layout part

            'add slide layout part
            pp = New PackagePart() {docPart, slidelayoutPart}
            Dim slidemasterPart As PackagePart = CreateExtendedPart(myPackage, "C:\somepath\slidemaster1.xml", "ppt/slideMasters/slideMaster1.xml", constants.slidemasterContentType, constants.slidemasterNamespace, pp)
            AdjustPartXML("//p:sldMasterIdLst/p:sldMasterId/@r:id", docPart, constants.slidemasterNamespace)
            'end add slide layout part

            'add other *required* parts slide,slidemaster,theme,slidelayout

            'add other relationships
            AddRelationship(slidemasterPart, themePart, constants.themePartNamespace)
            AddRelationship(slidemasterPart, slidelayoutPart, constants.slidelayoutNamespace)
            AdjustPartXML("//p:sldLayoutIdLst/p:sldLayoutId/@r:id", slidemasterPart, constants.slidelayoutNamespace)
            'end add other relationships

        End Using

    End Sub
    Public Sub AdjustPartXML(ByVal xpath As String, ByVal p As PackagePart, ByVal relationship As String)
        Dim nt As New NameTable
        Dim nsManager As New XmlNamespaceManager(nt)
        nsManager.AddNamespace("p", constants.mainpartNamespace)
        nsManager.AddNamespace("r", constants.relationshipNamespace)
        Dim adoc As New XmlDocument(nt)

        If Not IsNothing(adoc.SelectSingleNode(xpath, nsManager)) Then
            For Each r As PackageRelationship In p.GetRelationshipsByType(relationship)
                adoc.SelectSingleNode(xpath, nsManager).Value = r.Id
                adoc.Save(p.GetStream(FileMode.Create, FileAccess.ReadWrite))
            Next r
        End If
    End Sub
    Private Sub AddRelationship(ByVal frompart As PackagePart, ByVal topart As PackagePart, ByVal relationship As String)
        frompart.CreateRelationship(topart.Uri, TargetMode.Internal, relationship)
    End Sub
    Private Function CreateExtendedPart(ByVal p As Package, ByVal filename As String, ByVal uri As String, ByVal contenttype As String, ByVal relationship As String, ByVal relatewith() As PackagePart) As PackagePart
        Dim xmlDoc As New XmlDocument, xmlFile As New XmlDocument

        Dim pURI As Uri = PackUriHelper.CreatePartUri(New Uri(uri, UriKind.Relative))
        Dim pPart As PackagePart = p.CreatePart(pURI, contenttype)

        For Each pp As PackagePart In relatewith
            pp.CreateRelationship(pPart.Uri, TargetMode.Internal, relationship)

        xmlDoc.Save(pPart.GetStream(FileMode.Create, FileAccess.Write))
        xmlDoc = Nothing
        Return pPart
    End Function

    Private Function CreateBasicPart(ByVal fileStream As Stream, ByVal pptPackage As Package, ByVal uri As String, ByVal contentType As String, ByVal relType As String) As PackagePart

        Dim documentUri As Uri = PackUriHelper.CreatePartUri(New Uri(uri, UriKind.Relative))

        Dim documentPart As PackagePart = pptPackage.CreatePart(documentUri, contentType)

        pptPackage.CreateRelationship(documentPart.Uri, TargetMode.Internal, relType)

        Dim xmlDoc As New XmlDocument

        xmlDoc.Save(documentPart.GetStream(FileMode.Create, FileAccess.Write))

        Return documentPart
    End Function

End Class


Never mind my naming conventions or using structure as a hack – look at the juice :)

By the way – when you work with Open XML one of the great help is sample documents from OpenXMLDeveloper

Whenever I get more time, I’ll expand this code snippet in a more or less generic sample. Keep watching


Technorati tags: Pranav+Wagh, Microsoft+Blogger, OpenXML, Open+XML, PowerPoint, Office2007, Office+2007 tags: Pranav+Wagh, Microsoft+Blogger, OpenXML, Open+XML, PowerPoint, Office2007, Office+2007


Not responsible for errors in content, meaning, tact, or judgment. Live and let live. Toes go in first. I didn't do it. Enjoy.