Yesterday I was trying to update an image in a Word Document using OpenXML 2.0. I did a search on google and I found loads of search results explaining how to do so. This was all good and I started to write some code to do so. What I discovered after I had taken these great examples was that the picture did get updated, but the size of the image was fitted to the size of the Content control. I needed to insert the picture and then maintain whatever the size of the image was. This information I could not find anywhere, so I decided to do a little research and write my own code to do so. The tool I used to find out what and where to change was by using the OpenXMLSdkTool (Deflector) which is an absolutely necessary tool for decoding any docx files. I do recommend that you take a look at it. It has really helped me in understanding and writing my code.
By googling a little bit I fell over this great article http://www.codeproject.com/KB/office/Word_2007_Images.aspx?msg=3189465
where Abay Thomas describes on how to update an image in an Image Placeholder. I recommend you taking a look at this as the function I have below contains code from this project. I then looked into my own docx file using the deflector tool to see what information is stored regarding that image and the image placeholder. By clicking down on the treelist in the Document Explorer, I found the place where the Image information is contained. This gave me an overview of which elements I was going to use and what needed to be updated.
From the information gathered from the deflector tool, I decided that I was going to loop through the whole document and find all the DRAWING elements. For each of the DRAWING elements I would search for the BLIP containing the image I wanted to update. Once I had found the correct DRAWING element, I needed to change the EXTENT of the Image Placeholder and the EXTENTS of the image itself. Once these are changed, the docx file needed to be saved. The code for this would look as follows:
The values in the EXTENT are in EMUs so I needed to convert from pixel to EMU. 1 pixel is 9525 EMU. So to calculate the EMU you just need to multiply the pixels with 9525 and write this value to the cx can cy parameters in the EXTENT and EXTENTS elements
public void UpdateResizedImage(string imagePlaceHolderTagName, Image resizedImage)
{
string imageRelationshipId = GetImagePlaceHolderRelationShipId(imagePlaceHolderTagName);
foreach (Drawing d in this.mainDocPart.Document.Descendants<Drawing>().ToList())
{
foreach (DocumentFormat.OpenXml.Drawing.Blip b in d.Descendants<DocumentFormat.OpenXml.Drawing.Blip>().ToList())
{
if (b.Embed.ToString() == imageRelationshipId)
{
DocumentFormat.OpenXml.Drawing.Wordprocessing.Extent e = d.Descendants<DocumentFormat.OpenXml.Drawing.Wordprocessing.Extent>().FirstOrDefault();
long imageWidthEMU = (long)(resizedImage.Width * 9525);
long imageHeightEMU = (long)(resizedImage.Height * 9525);
e.Cx = imageWidthEMU;
e.Cy = imageHeightEMU;
DocumentFormat.OpenXml.Drawing.Extents e2 = d.Descendants<DocumentFormat.OpenXml.Drawing.Extents>().FirstOrDefault();
e2.Cx = imageWidthEMU;
e2.Cy = imageHeightEMU;
mainDocPart.Document.Save();
}
}
}
}
To use the the method above
...
using DocumentFormat.OpenXML;
using DocumentFormat.OpenXMLPackaging;
using DocumentFormat.OpenXML.Wordprocessing;
...
...
WordprocessingDocument wrd = WordprocessingDocument.Open("test.docx", true);
MainDocumentPart mainDocPart = wrd.MainDocumentPart;
...
...
Bitmap image = New Bitmap("test.jpg");
UpdateResizedImage("ImagePlaceHolder1", image);
And there you have it. The image will now be sized to its own size. Good luck. Let me know if you have any suggestions for improvement of this code.
By googling a little bit I fell over this great article http://www.codeproject.com/KB/office/Word_2007_Images.aspx?msg=3189465
where Abay Thomas describes on how to update an image in an Image Placeholder. I recommend you taking a look at this as the function I have below contains code from this project. I then looked into my own docx file using the deflector tool to see what information is stored regarding that image and the image placeholder. By clicking down on the treelist in the Document Explorer, I found the place where the Image information is contained. This gave me an overview of which elements I was going to use and what needed to be updated.
From the information gathered from the deflector tool, I decided that I was going to loop through the whole document and find all the DRAWING elements. For each of the DRAWING elements I would search for the BLIP containing the image I wanted to update. Once I had found the correct DRAWING element, I needed to change the EXTENT of the Image Placeholder and the EXTENTS of the image itself. Once these are changed, the docx file needed to be saved. The code for this would look as follows:
The values in the EXTENT are in EMUs so I needed to convert from pixel to EMU. 1 pixel is 9525 EMU. So to calculate the EMU you just need to multiply the pixels with 9525 and write this value to the cx can cy parameters in the EXTENT and EXTENTS elements
public void UpdateResizedImage(string imagePlaceHolderTagName, Image resizedImage)
{
string imageRelationshipId = GetImagePlaceHolderRelationShipId(imagePlaceHolderTagName);
foreach (Drawing d in this.mainDocPart.Document.Descendants<Drawing>().ToList())
{
foreach (DocumentFormat.OpenXml.Drawing.Blip b in d.Descendants<DocumentFormat.OpenXml.Drawing.Blip>().ToList())
{
if (b.Embed.ToString() == imageRelationshipId)
{
DocumentFormat.OpenXml.Drawing.Wordprocessing.Extent e = d.Descendants<DocumentFormat.OpenXml.Drawing.Wordprocessing.Extent>().FirstOrDefault();
long imageWidthEMU = (long)(resizedImage.Width * 9525);
long imageHeightEMU = (long)(resizedImage.Height * 9525);
e.Cx = imageWidthEMU;
e.Cy = imageHeightEMU;
DocumentFormat.OpenXml.Drawing.Extents e2 = d.Descendants<DocumentFormat.OpenXml.Drawing.Extents>().FirstOrDefault();
e2.Cx = imageWidthEMU;
e2.Cy = imageHeightEMU;
mainDocPart.Document.Save();
}
}
}
}
To use the the method above
...
using DocumentFormat.OpenXML;
using DocumentFormat.OpenXMLPackaging;
using DocumentFormat.OpenXML.Wordprocessing;
...
...
WordprocessingDocument wrd = WordprocessingDocument.Open("test.docx", true);
MainDocumentPart mainDocPart = wrd.MainDocumentPart;
...
...
Bitmap image = New Bitmap("test.jpg");
UpdateResizedImage("ImagePlaceHolder1", image);
And there you have it. The image will now be sized to its own size. Good luck. Let me know if you have any suggestions for improvement of this code.