Aug 22, 2013 at 9:55 AM
Edited Aug 22, 2013 at 12:12 PM
First off, thanks for this amazing library! Great to see that it has been updated recently :)
Using the recent 18.104.22.168 build, I was able to merge documents (using the InsertDocument method) containing images, which is great.
However, I noticed that it doesn't work for all images. It works great as long as an image is inside <w:drawing> but fails when an image is inside <w:pict>. Then the relationship id of the image remains the same as it was in the original document,
while the relationship id in the document.xml.rels part does change - resulting in a document that can't be opened.
I found the cause for this particular problem. Inside the DocX class, the method merge_images contains the following code to update the relationship id of the image inside the document:
// Replace all instances of remote_Id in the local document with local_Id
var elems = remote_mainDoc.Descendants(XName.Get("blip", DocX.a.NamespaceName));
foreach (var elem in elems)
XAttribute embed = elem.Attribute(XName.Get("embed", DocX.r.NamespaceName));
if (embed != null && embed.Value == remote_Id)
Which explains why images inside <w:pict> don't get updated since they are represented like this in xml:
<v:shapetype id="_x0000_t75" coordsize=...>
<v:stroke joinstyle="miter" />
<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" />
<o:lock v:ext="edit" aspectratio="t" />
<v:shape id="_x0000_s1026" type="#_x0000_t75" style=...>
<v:imagedata r:id="rId7" o:title="Fail2" />
<w10:wrap type="square" anchorx="margin" anchory="margin" />
The solution I came up with:
First, I added the XNamespace "v" inside the Namespaces region of the DocX class:
static internal XNamespace v = "urn:schemas-microsoft-com:vml";
Then I copied and edited the above code that searches and replaces the rId for "blip"/"embed" and edited it to replace the rId for "imagedata"/"id" as well:
// Replace all instances of remote_Id in the local document with local_Id (for shapes as well)
var v_elems = remote_mainDoc.Descendants(XName.Get("imagedata", DocX.v.NamespaceName));
foreach (var elem in v_elems)
XAttribute id = elem.Attribute(XName.Get("id", DocX.r.NamespaceName));
if (id != null && id.Value == remote_Id)
Might not be the most efficient way of going about this but it gets the job done. Thought it might be useful to share.
EDIT: The code needs to be added wherever the "blip"/"embed" code is used. Otherwise when an image already exists, the rId wouldn't be updated.