One of the tasks I've had over the last few weeks has been to automatically generate documentation from an architectural model. It's been (and continues to be) a relatively painful, sluggish process, as I'm generating Microsoft Word 2007 documents using the Open XML SDK. Never more so than when I came to add support for including images.

I'm going to do a 10,000' pass through the way that I approached it, so it's not a beginners guide to OpenXML. You're going to need to be able to find your way around an OpenXML document using the Open XML SDK first.

The basic process I'm using is to generate from my architectural model an XML document that will ultimately become a Microsoft Word document, like this:

I have some code that rips through a Word template document, looking for bookmarks and replacing the content of those bookmarks with Open XML fragments. The fragments themselves are derived from the above XML structure using nothing more than good old-fashioned XSLT.

Generating paragraphs of text and tables is pretty simple, as other than transforming the XML and inserting the resulting Open XML into the document, there's not much to it.

Images, on the other hand, are a little more complicated. There are two stages to adding an image to a Word document (or any Open XML document, for that matter). The first is that you must add an "Image Part" that holds the binary representation of the image, itself. Finding out how to do that was pretty easy:

This function adds a new image part to the document and copies the content of the image file. However, getting the image displayed on the page is another matter entirely. It should be no surprise that we must add some markup to the main document to render the image. I created what I consider to be a minimal Open XML fragment that creates a single paragraph containing nothing but the requested image:

Now, do you see those upper-case names in parenthesis (such as {WIDTH-IN-EMUS})? They're placeholders for values that must be dynamically inserted and are derived as follows:

{WIDTH-IN-EMUS}

That's the width of the image. Not measured in terms of flightless birds, but English Metric Units. There are 914400 EMUs to the inch, so it's calculated from:

widthInEmus = widthInPixels / HorizontalResolutionInDPI * 914400;

{HEIGHT-IN-EMUS}

Similarly, this is the height of the image in English Metric Units. Calculated from:

heightInEmus = heightInPixels / VerticalResolutionInDPI * 914400;

{DRAWING-OBJECT-ID}

This is a unique identifier for the Drawing Object. I calculate the initial value by looping through all of the existing <wp:docPr> elements in the document to find the largest Id, then increment it for each new image.

{FILENAME-OF-IMAGE}

Just for the sake of convention, I put the terminal name of the image file in here.

{PICTURE-ID}

This is a unique identifier for the Picture (as opposed to the Drawing Object - hmm?) and is derived in the same way as {DRAWING-OBJECT-ID} but from <pic:cNvPr> elements, not <wp:docPr>.

{RELATIONSHIP-ID-OF-IMAGE-PART}

This is what binds the image placeholder in the document to the image resource that we've embedded in the new Image Part. To get it, we need to change our InsertImage function slightly:

The value returned by InsertImage is the Relationship Id that we insert into this attribute in the XML.

So there you have it (for now). Equipped with your new Image Part and appropriate Open XML fragment, you should now to able to insert images, ad-nauseum, into your Open XML documents. I apologise for having skimmed over the subject at such a high level. Hopefully, I'll get round to posting some more articles on Open XML that will fill in a few of the blanks. In the meantime, if you need some specific help, let me know.

Comments

Baffled
wrote
re: HowTo: Insert an image into a Word document and display it using OpenXML

on Mon, Jan 18 2010 10:05

Hi

I'm needing to do something similar, and so I'm wondering why you are using a Drawing (w:drawing) for your images rather than the Picture ( w:pict ) tag? Would it not be simpler to use the w:pict -> v:imagedata approach?

Steve Morgan
wrote
re: HowTo: Insert an image into a Word document and display it using OpenXML

on Mon, Jan 18 2010 11:21

That's a very good question and one that I don't have a decent answer for at the moment!

All of the examples that I found while researching this topic used Drawing, but using Picture certainly looks far more straightforward.

I'll have to do some more investigation, now.

Thanks for contributing!

egs
wrote
re: HowTo: Insert an image into a Word document and display it using OpenXML

on Thu, Nov 18 2010 0:14

is there an example of {FILENAME-OF-IMAGE} because i have problems with the image

Buck
wrote
re: HowTo: Insert an image into a Word document and display it using OpenXML

on Fri, Jun 24 2011 21:11

Great article.

Is there any example of making this working using a MemoryStream instead of a FileStream? Every time I use a MemoryStreamm, I get a Red X on my document.