Programmatically Inserting an image from an O365 Add-In into your Word 2016 document

In this article I will demonstrate how to convert a web based image, displayed in an Add-In, into a base64 encoded string. With that I will then insert it into a Word document, directly from the Add-In.

Introduction

In the previous article I showed how to manually insertInlinePictureFromBase64 an image into a Word 2016 document. In this article I will demonstrate how to convert and existing web based image into base64 encoded string and then insert it.

HTML5 canvas element

Using the HTML5 canvas element we can easily convert an image to base64 using the canvas.toDataURL() method. The following code is a simple example of how to get an image from within the Add-In, convert it and insert it.

NOTE

The canvas.toDataURL() method will trigger a Security Alert if the image is not hosted in the same domain as the Add-In.

//create a canvas element 
var c = document.createElement("canvas"); 
var ctx = c.getContext("2d"); 
var img = document.getElementById("preview"); 
ctx.drawImage(img, 10, 10); 
//create the base64 encoded string and take everything after the comma
//format is normally data:Content-Type;base64,TheStringWeActuallyNeed
var base64 = c.toDataURL().split(",")[1];

//insert the TEXT o fthe base64 string into the word document as text
// Run a batch operation against the Word object model.
Word.run(function (context) {

    // Create a proxy object for the document body.
    var body = context.document.body;

    // Queue a commmand to insert HTML in to the beginning of the body.
    body.insertHtml(base64, Word.InsertLocation.start);

    // Synchronize the document state by executing the queued commands,
    // and return a promise to indicate task completion.
    return context.sync().then(function () {
        console.log('HTML added to the beginning of the document body.');
    });
})
.catch(function (error) {
    console.log('Error: ' + JSON.stringify(error));
    if (error instanceof OfficeExtension.Error) {
        console.log('Debug info: ' + JSON.stringify(error.debugInfo));
    }
});

//Insert the image into the word document as an image created from base64 encoded string
Word.run(function (context) {

    // Create a proxy object for the document body.
    var body = context.document.body;

    // Queue a command to insert the image.
    body.insertInlinePictureFromBase64(base64, 'Start');

    // Synchronize the document state by executing the queued commands,
    // and return a promise to indicate task completion.
    return context.sync().then(function () {
        app.showNotification('Image inserted successfully.');
    });
})
.catch(function (error) {
    app.showNotification("Error: " + JSON.stringify(error));
    if (error instanceof OfficeExtension.Error) {
        app.showNotification("Debug info: " + JSON.stringify(error.debugInfo));
    }
});

As we can see from the image below – the image and text are inserted. There is 4 pages of text for what was originally a 6KB (SIX) image.
This is not a very quick process.

im1

im2

Conclusion

This is pretty slow programmatically and a copy and paste is just as effective. But, it can be done so you never know someone might find use for it in the future 🙂

Advertisements

Inserting a base64 encoded image into a Word 2016 document

In this article I will demonstrate the new Word JavaScript API method which can be used to insert a base64 encoded image into a Word 2016 document.

Introduction

In the latest version of Office 365 Word 2016 (May 2016) a new capability has been released “insertInlinePictureFromBase64”. The documentation so far is a little sparse but can be found here (http://dev.office.com/reference/add-ins/word/body) . The new method is part of the body object within the JavaScript API model. For more information on the version of Word you need to get this to work check out this link (Office add-in requirement sets).

Do you have the correct version?

I found this StackOverflow answer which gave code similar to the following to test to see if you have the correct version of the JavaScript API available.

Word.run(function (context) {
	// Create a proxy object for the document body.
	var body = context.document.body;
	// Queue a commmand to insert HTML in to the beginning of the body.
	if (Office.context.requirements.isSetSupported("WordApi", "1.2")) {
		body.insertHtml('<strong>"You have the right version"</strong>', Word.InsertLocation.start);
	} else {
	body.insertHtml('<strong>"You do not have the right version. This functionality requires Word with at least January 2016 update!! (check  builds 6568+)"</strong>', Word.InsertLocation.start);
	}
		// Synchronize the document state by executing the queued commands,
		// and return a promise to indicate task completion.
		return context.sync().then(function () {
			console.log('HTML added to the beginning of the document body.');
	});
})

I created a simple Add-In examples locally, containing a message DIV and some FirebugLite.

Inserting an image.

Taking one of the examples from the documentation page and modifying it slightly we can see the basics of how the insert will happen:

var img = '' //a base64 encoded string

// Run a batch operation against the Word object model.
Word.run(function (context) {

    // Create a proxy object for the document body.
    var body = context.document.body;

    // Queue a command to insert the image.
    body.insertInlinePictureFromBase64(img, 'End');

    // Synchronize the document state by executing the queued commands,
    // and return a promise to indicate task completion.
    return context.sync().then(function () {
        app.showNotification('Image inserted successfully.');
    });
})
.catch(function (error) {
    app.showNotification("Error: " + JSON.stringify(error));
    if (error instanceof OfficeExtension.Error) {
        app.showNotification("Debug info: " + JSON.stringify(error.debugInfo));
    }
});

As we can see from the code, what is happening is the the “context” of the Word document is being manipulated in memory and then “sync’ed” with the actual HTML managing the Word document. The “Word document” itself is not a webpage. It can handle HTML but it is not a web browser and is not capable of being manipulated directly from the Add-In. If this works we should see an image.

What is a base64 encoded string anyway?

Base64 is a group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation. The term Base64 originates from a specific MIME content transfer encoding.” (https://en.wikipedia.org/wiki/Base64)

If you look for examples of base64 encoded images on the web you can see something like this – https://css-tricks.com/examples/DataURIs/ which shows two ways of referencing an image using the encoded string. Firstly in CSS and secondarily as an image. View the source of the page

i2

i1

The “base64 encoded string” takes the form “data:”+ [content-type]+”;base64,” and then the actual string

data:image/gif;base64,R0lGODlhEAAQA……………

“data:”+”image/gif”+”;base64,”R0lGODlhEAAQA……………….”

I am not using the full string for the base64 encoded image in my code snippets, because it is unwieldy in the context of the blog post.

THIS IS THE REALLY IMPORTANT PART !!!!
In the case of insertInlinePictureFromBase64 the entire string does not work! You only use everything after the comma.
THIS IS THE REALLY IMPORTANT PART !!!!

In my case only the following is necessary

var img = ‘R0lGODlhEAAQA……

In Summary

As you can see from the image below when you put this all together inside your JavaScript you can insert images into your Word document..

i3

Using the Jellyfish image example (which is a really long text string)

i4

 

Conclusion

In this article we seen how the new body.insertInlinePictureFromBase64 method can be used with the Word API to insert an image into a word document. Particular attention has to be paid to the string being inserted for the image, it must not include the content-type or the data signifier.

In the next article we will look at how we can easily a base64 encoded image for ourselves programmatically in the context of an Add-In

 

 

Getting started locally with a basic O365 Word Add-In (no web hosting)

In this article I will demonstrate how to add a local shared drive to your Trust center which will facilitate developing basic Add-In functionality locally. This will not works for Add-Ins which require internet access (c:\local cannot call https) but for testing out your Word API skills this is perfect.

Introduction

Using the example set out on Word Add Ins (https://github.com/OfficeDev/office-js-docs/blob/master/word/word-add-ins.md) I was able to start playing with the Word JavaScript API locally. But at times I did not have a network share to map my add in with. With a little searching though I found that you can map a local file with \\localhost.

Taking from the example (which you should read first) I am going to modify the section about adding a trust center with an example.

My files are located at c:\Users\mroden\WebstormProjects\Azure\xomino365\localWordDev

Adding the Trust Center

Within Word 2016 select

  • File
  • Options
  • Trust Center
  • Click the Trust Center Setting Button
  • Select the Trust Center Add-Ins option on the left

In the Catalog URL bar I add \\localhost\C$\Users\mroden\WebstormProjects\Azure\xomino365\localWordDev and “Add Catalog”

w5

The Catalog is added as a network share

w6

make sure you check the “Show in Menu” option and restart Word

Using the example manifest

Using the example manifest provided in the Github Project (link again) and my own GUID I was able to create a manifest to my local files like this

 

<?xml version="1.0" encoding="UTF-8"?>
    <OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="TaskPaneApp">
        <Id>0646c7a1-c876-482b-9119-e0f25c30b610</Id>
        <Version>1.0.0.0</Version>
        <ProviderName>Microsoft</ProviderName>
        <DefaultLocale>en-US</DefaultLocale>
        <DisplayName DefaultValue="Boilerplate content" />
        <Description DefaultValue="Insert boilerplate content into a Word document." />
        <Hosts>
            <Host Name="Document"/>
        </Hosts>
        <DefaultSettings>
            <SourceLocation DefaultValue="c:\Users\mroden\WebstormProjects\Azure\xomino365\localWordDev\App\Home\home.html" />
        </DefaultSettings>
        <Permissions>ReadWriteDocument</Permissions>
    </OfficeApp>

Using that I was then able to run the example code. There were a couple of warning though to accept to get this to work.

w1

w2

w3

There we have it – the locally hosted example working.

w4

Using the technique to add firebuglite to the Add-In I was then able to start to copy an paste example code from Microsoft examples and start to learn the Word API and its nuances.

I am also found this Office Snippets site which was GREAT to get started as well

http://officesnippetexplorer.azurewebsites.net/#/add-in/word

Conclusion

Being able to map a localhost as a “network drive” allowed me to get started without the need to constantly check code into my local Git repository and sync it with Azure

Productive !!!