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 !!!

Significant productivity enhancer: Debugging and Developing O365 Add-Ins using Firebug Lite

In this article I will show you how to add a web based console capability Firebug Lite to your Office Add-Ins. This is particularly helpful when debugging Client Side applications.

Introduction

Firebug is a Firefox plugin and was one of the original developer tools of actual use and power. It has since been superseded by all the powerful work the Chrome Dev team have put into Chrome developer tools, but I still like it (old habits die hard).

Firebug Lite is a browser agnostic JavaScript version of this and provides a subset of functionality, directly in the browser.

This is especially helpful in the case of Client based Add-Ins. Client based Add-Ins use an embedded Internet Explorer experience and the Developer Tools are unavailable. There are ways to debug Add-Ins through Visual Studio, but seeing as I have no intention of writing a line of C#, that does not help me.

Firebug Lite

Adding Firebug Lite to your Office Add-in could not be simpler. Add the following to your application (be warned there are some issues with using it in conjunction with AngularJS).

The Firebug Lite console itself is 300px tall so ideally you need to make your Add-In 450px tall to be able to see it working

    <script type="text/javascript" src="https://getfirebug.com/firebug-lite.js">
        {
            overrideConsole: false,
            startInNewWindow: true,
            startOpened: true,
            enableTrace: true
        }
    </script>

That’s it. !

The JSON parameters are optional and not necessary if you are working in Outlook or OWA. They are necessary in the Word/Excel/PowerPoint clients though as the F12 key have an assigned function. These extra parameters open the Firebug Lite client in a new browser window. Still works, just not embedded directly inside of the Add-In.

From the documentation (Feb 2016 – Firebug 1.4 is live)

1.3. What’s Not in Lite?

Some features are not included in Firebug Lite 1.3, but due the new core that supports code sharing from Firebug, are likely to be included in the Firebug Lite 1.4 version:

  • Live editing for all panels
  • Layout Side Panel
  • Context menu options
  • Tooltips (to show colors and images)
  • Search feature

Other features though are too dependent in browser internals and will not be supported (at least in a near future*), such as:

  • Javascript debugger / Javascript profiler
  • Net panel / HTTP and XHR monitor
  • Access to restricted URI resources
  • Highlight HTML changes

*Discussions about remote debugging indicates that should be possible to support JavaScript debugging in browsers like Google Chrome and Opera in the future.

Looking at the Add-In

I used the basic example from napacloudapp and a stripped out the HTML on the front page – this gave me the ability to still run the Office.initialize in the app.js (necessary to deploy an Office Add-In). Initializing this Office object also gives me programmatic context to the rest of the “host”, be in Outlook or Excel.

f12

Having a console inside of the Add-In gives us a significant amount of flexibility for testing and seeing what is going on. To activate it – focus on the Add-In and hit F12. If you are outside of the Add-In in the browser this will trigger the normal browser developer tools.

In the browser:

f1

In the Outlook client

f2

In Excel

f3

Developing Add-Ins using Firebug Lite?

Oh Yes! Let’s be honest – we are all lazy and would rather not have to go back and forth deploying Add-Ins to test our code – with Firebug Lite now we can start to write the code which will ultimately be deployed as part of our applications. For example:

Got to the Office JavaScript API model page – https://msdn.microsoft.com/en-us/library/office/fp160953.aspx and open the API model on ZoomIt

f4

We can start to see the semblance of the document model for adding data to an excel cell. Let’s see if those objects exist – I can see from the ZoomIt that we can go:

  • Office
  • context
  • document

In the Firebug Lite console (in Excel) type out Office.context.document – and we can see an object exists

f5

type in any old crap and you get just that 🙂

f6

In this manner, not only can we start to test that our code works, we can also do it without having to keep redeploying the Add-In. Once we are comfortable with the code, we can move it to the real code base – this is a real productivity enhancer, especially when you are just getting into Office Add-In JavaScript development.

Building your first Excel Add-In example without deploying anything

Looking at the Build your own first Excel Add-In page we can use some of their code directly inside of the Firebug Lite console.

Click on the enlarge box in the console top right

f7

Then the Up Arrow bottom right – this will give us a pop-up window with a console we can actually read and use

f9

Copy the code from the Excel.run part of the code from the Excel page example and paste it into the right hand Firebug Lite pane

f10

and “Run” (or use CTRL-Enter)

f11

How freaking cool is that !!!!!!!! And we never had to deploy an Add-In to test that out.

Conclusion

Adding Firebug Lite to your Add-Ins during development will be an enormous time saver for you. It will allow you to initially develop you code without having to go through repeated deployments. It will also allow you to debug your code (more on that in later articles) by manipulating your JavaScript functions once they are actually deployed.

In another life I have been using Firebug Lite embedded inside of XULRunner browser, running inside of Eclipse (don’t ask) and it is very cool – more to come on that soon