为了其他人的利益,我想更新此线程并添加到亚当的上述答案中。
实际上,前几天我设法一起破解了一些工作代码(在亚当发布他的答案之前),但这非常困难。文档确实很差,而且那里没有很多信息。
我不知道 Adam 在他的回答中使用的 Inline 和 Run 元素,但诀窍似乎在于获取 Descendants<> 属性,然后您几乎可以解析任何元素,例如正常的 XML 映射。
byte[] docBytes = File.ReadAllBytes(_myFilePath);
using (MemoryStream ms = new MemoryStream())
{
ms.Write(docBytes, 0, docBytes.Length);
using (WordprocessingDocument wpdoc = WordprocessingDocument.Open(ms, true))
{
MainDocumentPart mainPart = wpdoc.MainDocumentPart;
Document doc = mainPart.Document;
// now you can use doc.Descendants<T>()
}
}
一旦你有了这个,搜索东西就相当容易了,尽管你必须弄清楚所有东西都叫什么。比如<pic:nvPicPr>就是Picture.NonVisualPictureProperties等等。
正如 Adam 所说,您需要找到替换图像的元素是 Blip 元素。但是您需要找到与您要替换的图像相对应的正确 blip。
Adam 展示了一种使用 Inline 元素的方法。我只是直接潜入并寻找所有的图片元素。我不确定哪种方式更好或更健壮(我不知道文档之间的 xml 结构有多一致,以及这是否会导致代码中断)。
Blip GetBlipForPicture(string picName, Document document)
{
return document.Descendants<Picture>()
.Where(p => picName == p.NonVisualPictureProperties.NonVisualDrawingProperties.Name)
.Select(p => p.BlipFill.Blip)
.Single(); // return First or ToList or whatever here, there can be more than one
}
查看 Adam 的 XML 示例以了解此处的不同元素并查看我要搜索的内容。
blip 在Embed 属性中有一个 ID,例如:<a:blip r:embed="rId4" cstate="print" />,它的作用是将 Blip 映射到 Media 文件夹中的图像(如果重命名为 .docx,则可以看到所有这些文件夹和文件到 .zip 并解压缩)。你可以在_rels\document.xml.rels找到映射:
<Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.png" />
所以你需要做的是添加一个新图像,然后将这个 blip 指向你新创建的图像的 id:
// add new ImagePart
ImagePart newImg = mainPart.AddImagePart(ImagePartType.Png);
// Put image data into the ImagePart (from a filestream)
newImg .FeedData(File.Open(_myImgPath, FileMode.Open, FileAccess.Read));
// Get the blip
Blip blip = GetBlipForPicture("MyPlaceholder.png", doc);
// Point blip at new image
blip.Embed = mainPart.GetIdOfPart(newImg);
我认为这只是孤立了 Media 文件夹中的旧图像,这并不理想,尽管可以这么说它可能足够聪明地垃圾收集它。可能有更好的方法,但我找不到。
无论如何,你有它。这个线程现在是关于如何在网络上任何地方交换图像的最完整的文档(我知道这一点,我花了几个小时搜索)。所以希望有些人会发现它很有用。