Contents

Combining Images From Base64 for Exporting

A Tutorial on Converting and Combining Images from Base64

Want some music while reading? 🎵📻

Requirements

  1. React / React knowledge
  2. Canvas element knowledge
  3. react-base64-downloader package
  4. merge-base64 package

Background

In my recent project VerifyHut, there was an interesting feature that I learned during the development process. The app offers a way to export the signature image into PNG format. Not only the signature itself, but also the all of the related information will be exported along with the signature.

Demo

Github Repo

Below is the signature image after exporting:

https://user-images.githubusercontent.com/49280437/160287816-d4ed45b2-09ee-4d48-bab9-05b5da0fff91.jpg

On the right side, the information starts with the timestamp, signer and the reason for the signature to be created. So let’s find out how to do this.

If you’re interested in how to do this, this post is for you!

Signature Image

The signature’s image is saved into the MongoDB database as Buffer. I chose Buffer type because I did some research and they said the most suitable type for base64 string is Buffer.

To prepare the signature for exporting we just have to convert it with this line of code

1
Buffer.from(signature.image, "base64").toString()

This code converts the Buffer type to base64 string so that we could combine it with another base64 string to create the final image

Signature Image’s Height

Next, we need to know the signature’s image height to prepare the information image, so that both of the images have the same height. Check the code Below

1
2
3
4
5
6
const sigBase64 = Buffer.from(signature.image, "base64").toString("binary")
const i = new Image()
i.src = sigBase64
i.onload = () => {
    setSigHeight(i.height)
}

First, we convert the Buffer to binary string so that we can create an image from it. After that, when the image is loaded, we can check its height and use that height for the next step.

Signature’s Information

My technique to create the information canvas includes 2 steps: transforming the information text to canvas and converting the text to base64 string.

I use canvas because for me it’s the most straight-forward way to get a base64 string from text and I could also hide the canvas, only get the base64 string out of it when the user clicks export to PNG.

Create Information Canvas

This is my first helper function. This function converts the information texts into canvas. Let’s take a look at the code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const createInfoCanvas = (
    canvas, 
    dimensions = { width: 100, height: 100 },
    info, 
    style = {}
) => {
    const { width, height } = dimensions
    let ctx = null
    const canvasEl = canvas.current
    canvasEl.width = width
    canvasEl.height = height
    
    ctx = canvasEl.getContext("2d")
    ctx.fillStyle = "white"
    ctx.fillRect(0, 0, canvasEl.width, canvasEl.height)

    const { fontSize = 15, fontFamily = "Arial", color = "black", textAlign = "left", textBaseline = "top" } = style

    ctx.beginPath()
    ctx.font = fontSize + "px " + fontFamily
    ctx.textAlign = textAlign
    ctx.textBaseline = textBaseline
    ctx.fillStyle = color
    info.forEach(i => {
        ctx.fillText(i.text, i.x, i.y)
    })
    ctx.stroke()
    return canvasEl
}

Basically, the function set up a canvas that has specific height and width. The width is set to 100 as default and we use the height from the previous step here. The style object is for setting up the text style when we display the text on the image. Info is an array of the text objects that we will display. For each object, we fill them on the canvas at a specific coordination, in our case the coordination consists of x and y.

1
2
3
4
5
6
7
8
9
const canvasEl = createInfoCanvas(
    canvas, 
    { width: 310, height: sigHeight }, 
    [
        { text: createdAt || "", x: 0, y: sigHeight / 2 },
        { text: signerName || "", x: 0, y: (sigHeight / 2) + 18 },
        { text: reason || "", x: 0, y: (sigHeight / 2) + 36 }
    ],
)

This is how we use the helper function. The y coordinations have some calculations there because I want to align the text in the middle of the canvas.

Get Base64 String From Canvas

The second helper function is for converting the canvas to bae64 string

1
const getInfoBase64 = (canvasEl) => canvasEl.toDataURL()

This code is very straight-forward, we use the canvas above, apply the toDataURL method to the canvas to get the base64 string from it.

Merging the Images and Exporting

I use the merge-base64 package for combining the two images and react-base64-downloader package for triggering the download for the image. The code for this is as Below

1
2
const mergedImage = await mergeImages([image.split(",")[1], infoBase64.split(",")[1]])
triggerBase64Download(mergedImage, "signature")

The image variable is the base64 string of the signature from the previous step. We split the strings and take only the later parts. Specifically, we don’t need this part

data:image/png;base64

Conclusion

I hope you all know how to merge and download 2 image using base64 after reading this post. It might look complicated but it’s not, if it’s difficult maybe just because I’m wordy 😁. Thanks for reading!