blog community

Welcome to blog community Sign in | Join | Help
in Search

Wouter van Vugt

This blog is no longer maintained and has moved

Embed an image into a new WordprocessingML document

In reply to a question raised on Open XML Developer:

How do I embed an image into a new document and display it?

The sample project can be obtained here.

To do this yourself, take the following steps:

  1. Create the package
  2. Create two parts, one for the main document body, one for the image
  3. Relate the package to the main part
  4. Relate the main part to the image part, remember the relationship ID for later use in markup
  5. Store the image bytes inside the image part
  6. Create the main body XML, reference the image

Now the easiest way to reference an image is using VML markup. The following sample shows what you can do.

<?xml version="1.0" encoding="utf-8"?>
<w:document 
  xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main
  xmlns:v="urn:schemas-microsoft-com:vml
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
  <w:body
    <w:p
      <w:r
        <w:pict
          <v:rect style="width:16.56cm;height:5.36cm;" stroked="f"
            <v:fill r:id="rId2" type="frame" /> 
          </v:rect
        </w:pict
      </w:r
    </w:p
  </w:body>
</w:document>

Nothing to special, just a simple document with one paragraph containing a minimal VML picture. The relationship ID is used in the fill element.

Now in code, first the main logic

using (Package package = Package.Open("Sample.docx"))
{
  // Create main part 
  PackagePart mainPart = package.CreatePart( 
    new Uri("/document.xml", UriKind.Relative), 
      "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"); 
  // Create image part 
  PackagePart imagePart = package.CreatePart( 
    new Uri("/image.jpg", UriKind.Relative), 
      "image/jpg"); 
  // Relate package to main part 
  package.CreateRelationship( 
    mainPart.Uri, TargetMode.Internal, 
    "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument");

  // Relate main Part to image part 
  PackageRelationship imageRelationship = mainPart.CreateRelationship( 
    imagePart.Uri, TargetMode.Internal, 
    "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");

  // Store image 
  Size imageSize; 
  using (Stream imageStream = imagePart.GetStream( 
    FileMode.Create, FileAccess.ReadWrite)) 
 
    imageSize = StoreImageBytes(imageStream); 
 
  // Create document XML 
  using (Stream documentStream = mainPart.GetStream( 
    FileMode.Create, FileAccess.ReadWrite)) 
 
    // pass along relationship ID to reference image 
    StoreMainBodyXml(documentStream, 
      imageRelationship.Id, imageSize); 
 
}

Next the helper for storing the image, in this sample an embedded resource is used.

static Size StoreImageBytes(Stream imageStream)

  // this sample uses local resource file, 
  // you can use database or any other source as well 
  Bitmap image = Properties.Resources.Sunset; 
  image.Save(imageStream, ImageFormat.Jpeg); 
  // the image size is passed back for later use in 
  // xml markup, not the nicest approach. 
  return image.Size;
}

Now for the raw XML creation. This sample does not use any templates but creates the XML itself. Since the XML has an extremely simple hierarchy, only one child element anywhere in the sample, a helper method can be used to speed things up.

static void StoreMainBodyXml( 
  Stream documentStream, string relationshipID, 
  Size imageSize) 

  // Create XML using code, no template 
  string xmlnsWml = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
  string xmlnsVml = "urn:schemas-microsoft-com:vml"
  string xmlnsRels = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
  XmlNode workingNode = null
  XmlDocument document = new XmlDocument(); 
  // WML container 
  workingNode = document.CreateElement( 
    "w", "document", xmlnsWml); 
  document.AppendChild(workingNode); 
  workingNode = CreateChildElement( 
    "w", "body", xmlnsWml, workingNode); 
  workingNode = CreateChildElement( 
    "w", "p", xmlnsWml, workingNode); 
  workingNode = CreateChildElement( 
    "w", "r", xmlnsWml, workingNode); 
  workingNode = CreateChildElement( 
    "w", "pict", xmlnsWml, workingNode); 
  // VML picture 
  workingNode = CreateChildElement( 
    "v", "rect", xmlnsVml, workingNode); 
  XmlAttribute styleAttribute = document.CreateAttribute("style"); 
  styleAttribute.Value = String.Format( 
    "width:{0}px;height:{1}px;", imageSize.Width, imageSize.Height); 
  XmlAttribute strokedAttribute = document.CreateAttribute("stroked"); 
  strokedAttribute.Value = "f"
  workingNode.Attributes.Append(styleAttribute); 
  workingNode.Attributes.Append(strokedAttribute); 
  workingNode = CreateChildElement( 
    "v", "fill", xmlnsVml, workingNode); 
  XmlAttribute rIdAttribute = document.CreateAttribute( 
    "r", "id", xmlnsRels); 
  rIdAttribute.Value = relationshipID; 
  XmlAttribute typeAttribute = document.CreateAttribute("type"); 
  typeAttribute.Value = "frame"
  workingNode.Attributes.Append(rIdAttribute); 
  workingNode.Attributes.Append(typeAttribute); 
  document.Save(documentStream);
}

private
static XmlNode CreateChildElement( 
  string prefix, string nodeName, string xmlNamespace, 
  XmlNode parentNode)

  XmlNode child = parentNode.OwnerDocument.CreateElement( 
    prefix, nodeName, xmlNamespace); 
  parentNode.AppendChild(child); 
  return child;
}

That's it.

Hope it helps!

Published Sunday, May 20, 2007 12:15 PM by wouterv

Comments

 

nologin@freemail.hu said:

Hi, I'm getting into a project of creating docx files programatically and among other things I need to add pictures and drawings (actually I need to draw drawings programatically). You mentioned that you could use templates instead of creating the xml from scratches. I searched all over te Internet for examples of OpenXML but couldn't find too many. Do you have examples of using templates? Or any suggestion to make programming Openxml easier? It's kinda "funny" that creating a 10 lines xml requires 45 lines of code. My address is: nologin@freemail.hu
October 14, 2007 5:07 PM
Anonymous comments are disabled

This Blog

Syndication

News


Add to Technorati Favorites
Powered by Community Server, by Telligent Systems