I have Open Office XML code that slices and dices PowerPoint files.
Due to the nature of the Open XML SDK, much of this code reads to and writes from files on the file system. The goal is to eliminate these temporary files completely, and replace them with byte arrays and/or in-memory streams.
Some of this code merges together PowerPoints from different slide sources. An example of this code follows. Imagine a database containing PowerPoint presentations. PmlDocument
is a class in Open XML Power Tools:
foreach (var item in database)
{
var openXmlDocument = new OpenXmlPowerToolsDocument(item.data);
var document = new PmlDocument(openXmlDocument);
sources.Add(new SlideSource(document, false));
}
PmlDocument newDocument = PresentationBuilder.BuildPresentation(sources);
byte[] data = newDocument.DocumentByteArray;
Where byte[] data
represents a new PowerPoint PPTX, which I can then save back to the database.
This code works perfectly fine, because I'm already working with byte arrays in this example. The problem occurs when I have to deal with PresentationDocument
objects. A great deal of processing already occurs in our program with these objects, and the current way to obtain the byte array from such objects is to do this:
presentationDocument.SaveAs(fileName);
byte[] array = File.ReadAllBytes(fileName);
Which is not what I want.
Unfortunately, there doesn't appear to be a better way to extract the bytes from a PresentationDocument
. Does anyone know how to do this in memory, perhaps with a MemoryStream
object?
Note: I've read OfficeTalk: Working with In-Memory Open XML Documents, but it appears to assume that you already have a byte array in the proper document format.
Looking at the source here, PresentationDocument
inherits from OpenXmlPackage
Which implements the SaveAs
method, and when followed eventually calls:
/// <summary>
/// Creates a clone of this OpenXml package, opened on the given stream.
/// The cloned OpenXml package is opened with the same settings, i.e.,
/// FileOpenAccess and OpenSettings, as this OpenXml package.
/// </summary>
/// <param name="stream">The IO stream on which to open the OpenXml package.</param>
/// <returns>The cloned OpenXml package.</returns>
public OpenXmlPackage Clone(Stream stream)`
In the end this just copies the OpenXmlPart
to the stream
using (OpenXmlPackage clone = CreateClone(stream))
{
foreach (var part in Parts)
{
clone.AddPart(part.OpenXmlPart, part.RelationshipId);
}
}
When you know it's there, you can eventually find it in the documentation!
All-in-all, this gives you the ability to save directly to the bytes without going to file first.