Inserting image content from Rest API to currently opened document in Microsoft Word
Asked Answered
C

1

8

Edit: This question's text has been changed to reflect utilizing open xml code and interop.

I'm trying to insert a base 64 encoded image to a Word document via a ribbon. The following code is for reproduction purposes:

   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;
            }
        }
    }

However whenever I execute this code I hit the catch and the error is:

"XML markup cannot be inserted in the specified location.".

I know this error is misleading because if I change the xml to <Test>Test</Text> I see "Test" in my document. Can anyone shed some light on this?

Note that the image used is just a red square about 10px x 10px

Colombes answered 14/12, 2018 at 15:29 Comment(5)
Open XML in combination with the interop approach is the correct approach if the target document is open in the Word UI. Look at the Range.InsertXML method. The content to be inserted needs to be in valid WordOpenXML "OPC flat file" format.Piassava
Thanks @CindyMeister. One of my issues here is that when I try to use OpenXml, the file has to be saved to the user's machine first (and cannot be in OneDrive because the file location becomes an https uri). Is there a way around this? Additionally, it breaks when I try to use WordProcessingDocument.Open because "the File is in use by another process". Any thoughts?Colombes
I have updated the question with bullet points to more cleanly show my issuesColombes
Start with the first code sample you show. Instead of AddPicture you need Range.InsertXML to insert the Open XML. But it's not the Open XML SDK, it's just the picture, wrapped in the necessary Open XML OPC flat file format. It will take quite a bit of research.Piassava
@CindyMeister Ok I didn't realize that when you said to use Xml that you meant to only use xml insert, I thought you meant the OpenXml library so I hope you understand why I thought your comment had just redirected me back to my original problem. I appreciate you pointing me in the right direction.Colombes
H
0

You will need image to be available on the file-system and you need to use Shapes.AddPicture method of ActiveDocument object. You can set image location and it's size while calling this method.

currentDocument.Shapes.AddPicture (imagePath, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, 10, 10, 250, 250);

Refer to this URL for more information:

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

Here is the working code:

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;
    }
}

Output received with the above code:

enter image description here

Hope this helps!

Hygrothermograph answered 17/12, 2018 at 6:0 Comment(6)
Sorry, this neither uses openxml nor answers the question per utilizing a base 64 encoded image. Also note that the bounty specifies the use of Range.InsertXMLColombes
Humm.. The solution was based on pre-edit question where you had mentioned that you may start looking into saving the file if it's required and you are open solving the problem with either library. Let me check if I can help you out with the specific requirement.Hygrothermograph
Ok, I thought you had only seen the edit since it is 13 hours old and your answer is 10 hours, and you used the code I provided post-edit including the commented insertXML base-64 encoded image.Colombes
That’s because after reading the question I was trying to build the solution and later used your code to make more familiar for you. :) Didn’t think the question narrative could have been completely changed.Hygrothermograph
Sorry I can't award the bounty for this option as it is essentially the same thing as my first version code except you replaced the rest api url with a filesystem location. If you know anything about InsertXML w/ binary picture data and post an answer for that I will happily award bounty, but the flat file format is a total nightmare and mostly nonsensical so I don't know if I would inflict that on any well-meaning answerer without previous experience :)Colombes
I understand that and I don’t expect you to award the bounty. I just wanted to clarify why did I post this answer.Hygrothermograph

© 2022 - 2024 — McMap. All rights reserved.