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:
- Create the package
- Create two parts, one for the main document body, one for the image
- Relate the package to the main part
- Relate the main part to the image part, remember the relationship ID for later use in markup
- Store the image bytes inside the image part
- 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!