Displaying images from the canvas in your Figma plugin UI
Source code for this tutorial is available here: https://github.com/PluginFinchy/Image-to-ui
If you’re reading this, you probably want to know how to take some form of image data from your Figma canvas, and display it within your UI. It could be that you want to provide context to the users selection, or show all the icons in your design system in one view. Whatever the use case, the implementation isn’t exactly easy. But hopefully this tutorial will break down the steps and simplify the process for you.
Difficulty: Medium
This tutorial assumes you have some working knowledge of Figma plugins already, have an understanding of asynchronous javascript and promises, and that you’ve already set up a plugin with a UI.
*I’m using the default template that Figma gives you when selecting ‘With UI & Browser APIs’ and have cleared the contents of ‘code.ts’ and ‘ui.html’
To get started, we a need a node to export. For simplicity, in this example I will use the first node the user has selected. We can get that with figma.curentPage.selection[0]
//code.tsfigma.showUI(__html__);let exportNode = figma.currentPage.selection[0]
We’re going to get the image data for that node using a function from the Figma API called exportAsync
If you look at the exportAsync page in the API documentation, the signature section tells us that exportAsync takes an optional parameter, of type ExportSettings and returns a Promise which resolves to a Uint8Array
A Uint8Array is a data structure, in this case it contains all the byte data of the image
Lets configure the exportAsync settings to export a PNG at 2x resolution
exportNode.exportAsync({
format: "PNG",
constraint: {
type: "SCALE",
value: 2,
}
})
This function returns a promise, so we need to handle that. The simple way is to use .then
and handle a resolution and a rejection
Doing that, our code.ts looks like this
//code.tsfigma.showUI(__html__);let exportNode = figma.currentPage.selection[0]exportNode.exportAsync({
format: "PNG",
constraint: {
type: "SCALE",
value: 2,
}
}).then(
resolved => {
sendToUi(resolved)
},
rejected => {
console.error(rejected)
}
)
You’ll notice I’ve added a new function called sendToUi
which we’ll use to send the Uint8Array to the plugin UI
Let’s create a new function called sendToUi which we will use to post a message to the ui.
//code.tsfunction sendToUi(imagedata){
figma.ui.postMessage({type: 'exportImage', data: imagedata})
}
I’m sending an object with a type of ‘exportImage’ and data which is the resolved promise from exportAsync. We add a type, to make it easy to handle different messages in the UI, in case we had multiple messages we were sending to the UI.
Now we need to respond in the UI, when it hears that message.
//ui.html<script>
onmessage = (event) => {
let msgType = event.data.pluginMessage.type
let msg = event.data.pluginMessageif(msgType === 'exportImage' ){
let imageData = msg.data
console.log(imageData)
}
}</script>
Now’s a good opportunity to test your code up until this point. If everything works, you should see a Uint8Array in the console.
So we’ve got Uint8Array in our plugin UI, great! But we’re not quite finished yet. The browser can’t display a Uint8Array, we need to convert the binary data from the array into something it can display. Let’s convert this array of bytes into a base64 string.
let base64img = `data:image/png;base64,` + btoa(String.fromCharCode.apply(null,imageData))
Essentially what this line of code does is take every byte in the array, and turn it into base64 data. And we define what the data type is at the beginning of the string with data:image/png;base64,
Now we’ve got a string we can use as a URL to set the source of an image in our UI. Let’s change our plugin’s background image to be the image of our selection.
//ui.html
<script>onmessage = (event) => {
let msgType = event.data.pluginMessage.type
let msg = event.data.pluginMessageif(msgType === 'exportImage' ){
let imageData = msg.datalet base64img = `data:image/png;base64,` + btoa(String.fromCharCode.apply(null,imageData))document.body.style.backgroundImage = `url(${base64img})`}}</script>
That’s it! We’ve used the Figma API to export image data as a Uint8Array, sent that data to the UI, and converted it into a base64 string.
Why not try changing the export format, such as sending an SVG to the UI. Or try modifying this code to send multiple images to your UI. I’d love to see what you do with it.