Library code snippets
Inserting images into Word documents using XML
I've seen many, many requests on the Microsoft newsgroups asking how you can insert a picture into a Word document without saving it to the file system first. This example application described in this blog illustrates both methods for inserting a picture firstly using the Word object model (InlineShapes.AddPicture) and secondly using Word's XML support (InsertXML).
The Word object model code is very straight forward:
private void buttonInsertNormal_Click(object sender, System.EventArgs e)
{
object oMissing = Type.Missing;
object oCollapseEnd = Word.WdCollapseDirection.wdCollapseEnd;
_wordApp.ActiveDocument.Content.Collapse(ref oCollapseEnd);
string filename = @"c:\temp\WordMLImage.bmp";
try
{
pictureBox1.Image.Save(filename);
_wordApp.ActiveWindow.Selection.Range.InlineShapes.AddPicture(filename,
ref oMissing, ref oMissing, ref oMissing);
}
finally
{
File.Delete(filename);
}
}
The only problem with this code is the requirement to write the image to the file system so Word can reload it. There are many circumstances where you would prefer to avoid touching the file system or maybe your application does not have write permission.
Fortunately there is an alternative approach using Word's XML support. This approach requires us to constructing a WordML document fragment representing the image to be inserted and then calling Word's InsertXML function to place the image in the document.
The code to do this is as follows:
private void buttonInsertWordML_Click(object sender, System.EventArgs e)
{
object oMissing = Type.Missing;
object oCollapseEnd = Word.WdCollapseDirection.wdCollapseEnd;
_wordApp.ActiveDocument.Content.Collapse(ref oCollapseEnd);
try
{
PictWriter pw = new PictWriter(pictureBox1.Image, "Example Image", "Example Image");
_wordApp.ActiveWindow.Selection.Range.InsertXML(pw.ToString(), ref oMissing);
}
catch (Exception ex)
{
// do something sensible here.
}
}
You will notice the use of a custom class called Sentient.WordML.PictWriter which handles the task of converting the image into the WordML document fragment. The complete class source is included in the zip download at the top of the article however the core elements are the following two methods.
WriteDoc handles writing the WordML document wrapper. InsertXML expects a complete WordML document including full namespace references and style definitions if you are using styles (we are not). WritePict handles writing the actual image data into the XML stream as Base64.
///<summary>
/// Write the whole WordML document
///</summary>
///<param name="wtr">The XmlTextWriter to write to</param>
protected void WriteDoc(XmlTextWriter wtr)
{
// start <xml> tag
wtr.WriteStartDocument();
// add processing instructions
wtr.WriteProcessingInstruction("mso-application", "progid=\"Word.Document\"");
// start <wordDocument> tag
wtr.WriteStartElement("w", "wordDocument", WordMLNS);
// write namespaces
foreach(string prefix in _namespaces.AllKeys)
{
wtr.WriteAttributeString("xmlns", prefix, null, _namespaces[prefix]);
}
// start <body> tag
wtr.WriteStartElement("body", WordMLNS);
// call WritePict to add our image to the Xml stream.
WritePict(wtr);
// end <body> tag
wtr.WriteEndElement();
// end <wordDocument> tag
wtr.WriteEndElement();
// end <xml> tag
wtr.WriteEndDocument();
}
///<summary>
/// Write the Pict WordML element
///</summary>
///<param name="wtr">The XmlTextWriter to write to</param>
protected void WritePict(XmlTextWriter wtr)
{
if(_data==null)
{
return;
}
// start <pict> tag
wtr.WriteStartElement("pict", WordMLNS);
// start <binData> tag
wtr.WriteStartElement("binData", WordMLNS);
wtr.WriteAttributeString("name", WordMLNS, string.Format("wordml://{0}{1}", _name, _extension));
// write the image as Base64
wtr.WriteBase64(_data, 0, _data.Length);
// end <binData> tag
wtr.WriteEndElement();
// start <shape> tag which describes the shape containing the image
wtr.WriteStartElement("shape", VMLNS);
wtr.WriteAttributeString("id", "_x0000_" + _name);
wtr.WriteAttributeString("style", string.Format("width:{0}px;height:{1}px", _width, _height));
// start <imagedata> tag which links to the <binData> above.
wtr.WriteStartElement("imagedata", VMLNS);
wtr.WriteAttributeString("src", string.Format("wordml://{0}{1}", _name, _extension));
wtr.WriteAttributeString("title", OfficeNS, _title);
// end <imagedata> tag
wtr.WriteEndElement();
// end <shape> tag
wtr.WriteEndElement();
// end <pict> tag
wtr.WriteEndElement();
}
As you can see the InsertXML approach requires a little more code however does achieve our objective of not touching the file system.
The only drawback I've found with the InsertXML approach is you dont get the image autosizing functionality which means if you want the image to be reduced or enlarged in size you'll have to do this yourself in code either by resizing the image before inserting it or using the Word object model to manipulate the InlineShape properties after it has been inserted.
A major bonus is that using InsertXML is considerably faster than writing the image to the file system and then calling InlineShape.Add so you get a considerable performance improvement especially if you are working with large images.
If you know of a better way to do this please add a comment.
Related articles
Related discussion
-
Creating a Windows Service in VB.NET
by Templario55 (107 replies)
-
Read HTML tags in XML Reader
by jhuerta (6 replies)
-
Help with XMLWriter
by Thulasee (1 replies)
-
convert class into xml schema?
by jpek42 (3 replies)
-
How to extract specific information from XML [C# 2003]
by azroccouk (1 replies)
Related podcasts
-
Object-Oriented Programming in Ruby
In this episode, I talk with Scott Bellware about object-oriented programming in Ruby, and Ruby's object model. This is taken from a private conversation, and the audio quality suffers at times. Much thanks to Scott for allowing this to be released.This episode of the Alt.NET Podcast is bro...
Events coming up
-
Aug
28
St. Louis Day of .NET
St. Charles, United States
Technical conference with be 2 full days of content with over 40 sessions from local and national speakers, with topics such as:•.NET languages: C#, VB.NET•Technologies: WPF, Silverlight, WCF•Development tools: Visual Studio, TFS, Expression Blend
Hi ,
I read your artcle and it is very nice. I have a question which is related to word :
Is it possible to copy the Images from the word 2007 document but the document is not saved till.
I mean when user is creating a new document and before saving the document can we copy the images that are inserted into the document into desktop folder.
Hi,
I want to create report in word document. For that I am using an existing word document and from c# I want to insert chart in word document , each chart in diff. page in same word document . Any help would be appreciated.
Thanks in advance.
Hiral
Hello!
I want exact opposite code. I want to extract and save the Images from Word.
I want to do following task :
1) A word file with text, tables and images.
2) Extracting all info. to XML document and images
3) write another file to include above extracted info with some replacement and insert images as it is.
Thank you
Hemant
Hi,
I want to do the same in ASP. Can u please guide me how to do? As i am confused
Please help me. its very urgent
Thanx
Preeti
This thread is for discussions of Inserting images into Word documents using XML.