使用Rest API将图像内容插入到当前打开的Microsoft Word文档中

8

编辑:为了利用开放的xml代码和互操作性,更改了此问题的文本。

我正在尝试通过功能区将base64编码的图像插入Word文档。以下代码仅供复制:

   public partial class Ribbon1
    {
        private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
        {
        }

        private void InsertPicture_Click(object sender, RibbonControlEventArgs e)
        {
            Word.Application wordApp = null;
            Word.Document currentDocument = null;
            Word.ContentControls controls = null;
            try
            {
                wordApp = (Word.Application) Marshal.GetActiveObject("Word.Application");
                currentDocument = wordApp.ActiveDocument;
                controls = currentDocument.ContentControls;
                
                currentDocument.Range().InsertXML(@"<pkg:package xmlns:pkg=""http://schemas.microsoft.com/office/2006/xmlPackage"">
  <pkg:part pkg:name=""/word/media/image1.png"" pkg:contentType=""image/png"" pkg:compression=""store"">
    <pkg:binaryData>iVBORw0KGgoAAAANSUhEUgAAABEAAAAKCAIA
      AADdHiL1AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAVSURBVChTY3gro0IqGtUz3PTIqAAAlO/H4+qBWxcAAAAASUVORK5CYII=</pkg:binaryData>
  </pkg:part></pkg:package>");
                object tr = true;
                object fa = false;
            }
            catch(Exception ex)
            {
                wordApp.ActiveDocument.Range().InsertAfter(ex.Message);
            }
            finally
            {
                if (controls != null) Marshal.ReleaseComObject(controls); controls = null;
                if (currentDocument != null) Marshal.ReleaseComObject(currentDocument); currentDocument = null;
                if (wordApp != null) Marshal.ReleaseComObject(wordApp); wordApp = null;
            }
        }
    }

然而每当我执行这段代码时,它都会触发异常并显示错误信息:
"无法在指定位置插入XML标记。"
我知道这个错误信息有误导性,因为如果我将xml更改为<Test>Test</Text>,我会在文档中看到"Test"。 有人能解释一下吗?
请注意,所使用的图像只是一个大约为10px x 10px的红色正方形。

1
如果目标文档在Word UI中打开,则使用Interop方法结合Open XML是正确的方法。请查看Range.InsertXML方法。要插入的内容需要以有效的WordOpenXML“OPC平面文件”格式呈现。 - Cindy Meister
感谢@CindyMeister。我在这里遇到的一个问题是,当我尝试使用OpenXml时,文件必须先保存到用户的计算机上(不能在OneDrive中,因为文件位置变成了https uri)。有什么解决方法吗?此外,当我尝试使用WordProcessingDocument.Open时,它会中断,因为“文件正在被另一个进程使用”。有什么想法吗? - C Bauer
我已经更新了问题,并添加了项目符号以更清晰地展示我的问题。 - C Bauer
1
从您展示的第一个代码示例开始。您需要使用Range.InsertXML而不是AddPicture来插入Open XML。但这不是Open XML SDK,它只是图片,包装在必要的Open XML OPC平面文件格式中。这将需要相当多的研究。 - Cindy Meister
@CindyMeister 好的,我没意识到你说用 Xml 的时候只是指 Xml 插入,我以为你是指 OpenXml 。希望你能理解我为什么认为你的评论只是把我重新引回了原始问题。感谢您指出正确的方向。 - C Bauer
1个回答

0
你需要在文件系统中有图像,并且需要使用ActiveDocument对象的Shapes.AddPicture方法。调用此方法时,您可以设置图像位置和大小。
currentDocument.Shapes.AddPicture (imagePath, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, 10, 10, 250, 250);

更多信息请参考此网址:

https://learn.microsoft.com/en-us/office/vba/api/word.shapes.addpicture

这是可用的代码:

private void InsertPicture_Click(object sender, RibbonControlEventArgs e)
{
    Word.Application wordApp = null;
    Word.Document currentDocument = null;
    Word.ContentControls controls = null;
    try
    {
        wordApp = (Word.Application) Marshal.GetActiveObject ("Word.Application");
        currentDocument = wordApp.ActiveDocument;
        controls = currentDocument.ContentControls;
        string imagePath = @"D:\WordAddInTest\App_Data\Yay.jpg";
        currentDocument.Shapes.AddPicture (imagePath, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, 10, 10, 250, 250);


        //              currentDocument.Range ().InsertXML (@"<pkg:package xmlns:pkg=""http://schemas.microsoft.com/office/2006/xmlPackage"">
        //<pkg:part pkg:name=""/word/media/image1.png"" pkg:contentType=""image/png"" pkg:compression=""store"">
        //  <pkg:binaryData>iVBORw0KGgoAAAANSUhEUgAAABEAAAAKCAIA
        //    AADdHiL1AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAVSURBVChTY3gro0IqGtUz3PTIqAAAlO/H4+qBWxcAAAAASUVORK5CYII=</pkg:binaryData>
        //</pkg:part></pkg:package>");
        object tr = true;
        object fa = false;
    }
    catch (Exception ex)
    {
        wordApp.ActiveDocument.Range ().InsertAfter (ex.Message);
    }
    finally
    {
        if (controls != null) Marshal.ReleaseComObject (controls); controls = null;
        if (currentDocument != null) Marshal.ReleaseComObject (currentDocument); currentDocument = null;
        if (wordApp != null) Marshal.ReleaseComObject (wordApp); wordApp = null;
    }
}

使用上述代码收到的输出:

enter image description here

希望这能帮到你!


抱歉,这既没有使用 openxml,也没有利用 base64 编码图像 来回答问题。另外请注意,悬赏指定使用 Range.InsertXML。 - C Bauer
嗯..解决方案基于预编辑问题,您在其中提到如果需要保存文件并且您可以使用任何库来解决问题。让我检查一下是否可以帮助您满足具体要求。 - dj079
好的,我以为你只看到了编辑部分,因为它已经过去13个小时了,而你的回答是在10个小时内完成的,并且你使用了我提供的代码,包括注释掉的insertXML base-64编码图像。 - C Bauer
那是因为在阅读问题后,我试图构建解决方案,并稍后使用您的代码使其更加熟悉。 :) 没想到问题叙述可能已经完全改变了。 - dj079
抱歉,我无法为此选项颁发赏金,因为它本质上与我的第一个版本代码相同,只是将 REST API URL 替换为文件系统位置。如果您了解有关使用二进制图片数据插入 XML 并发布答案的任何信息,我将很乐意颁发赏金,但是扁平文件格式是一场彻底的噩梦,大多数情况下毫无意义,所以我不知道是否会将其强加给任何有良好意愿的回答者而没有先前的经验 :) - C Bauer
1
我理解这一点,也不指望你授予悬赏。我只是想澄清为什么我发布了这个答案。 - dj079

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接