Fabric.js – change uploaded image color

Fabric.js is amazing library – I know, that we have a lot of drawing possibilities using canvas element, but “vanilla version” is not very readable and difficult to use. With fabric.js, everyting is much simpler and cleaner, we can also use a lot of build-in tools. One of them is image filters. We can modify images in many ways, apply for example sepia filter, but also make other changes. Last time I must just change image color. Yep, user can upload image (or I load image using static url), and I want to force using color, not original. Diffucult? Not with fabric.js.

Because this post is not how to configure and use fabric.js from scratch, I will skip this part and will assume, that you have installed library and its works fine. Let’s say, that we have fabric instance in variable called “canvas” (who would have thought?). First thing is to enable filters backend. We can do this using code from official tutorial:

canvas.filterBackend = new fabric.WebglFilterBackend()

Now we can use all filters from library. Now, we can load image into fabric and make some change. Let’s say, we use external image (not loaded by user, but available on the same, or external server). We can use Image.fromUrl method to load this:

let imageUrl = '/images/mysecretimage.png'
fabric.Image.fromUrl(imageUrl, (myImg) => {
   // callback when we can modify image and add to canvas
   // unfortunately, promises are not supported yet
})

As you can see, we have callback function, in which we can modify image, add it to canvas and also render changes. This is asynchronous and fabric.js doesn’t support promises in this case now – there is open issue on GitHub, but we must wait for changes. Now it’s time for magic, very short magic. How can we overwrite image color? Just use BlendColor filter in tint mode and without any opacity. There is an simple example:

fabric.Image.fromUrl(imageUrl, (myImg) => {
    myImg.filters.push(new fabric.Image.filters.BlendColor({
        color: '#FF0000', // make it red!
        mode: 'tint',
        opacity: 0
    }))

    // Set some data
    myImg.set({left: 0, top: 0, scaleX: 1: scaleY: 1})

    // Add image to canvas
    canvas.add(myImg)

    // Render!
    canvas.renderAll()
})

And it’s all. After that, we will have new image on canvas. Hm.. maybe not image, but red shape from original image? It’s better description of result, because we overwrote original image data. Of course, we can use other filters and other modes in the same way. Fabric.js has a lot of possibilities and I can only recommend to check this library.