Color-Thief Node plugin error: "Image given has not completed loading"

874 Views Asked by At

Working in Node/Express, I was trying to get the npm package color-thief to grab the dominant color from an image, and it failed because "image given has not completed loading".

The image was, again, local, so it shouldn't have had this particular problem. And besides that, color-thief returns a promise, and I was using async/await, so it should have waited however long it took for the image to load instead of throwing an error.

Below is my SSCCE code:

const ColorThief = require('color-thief');

let colorThief = new ColorThief();

async function getDominantColor() {
    const img = 'public/img/seed/big-waves-2193828__340.webp';
    const dominantColor = await colorThief.getColor(img);
    console.log(dominantColor);
}

getDominantColor();
2

There are 2 best solutions below

0
R Greenstreet On BEST ANSWER

The issue turned out to be that the plugin apparently does not support .webp files.

It works fine with .jpg and .png, though the Documentation (which isn't easy to get to) doesn't explicitly state what file types it does/does not support.

I've submitted a feature request on Github to either add support for webp or update the documentation with an explicit list of supported filetypes, but the author states at the very bottom of his blog regarding the project:

"In the short term I'm not planning on doing any more work on the script."

Just figured I would try to save someone else using this in the future some headache and time

0
xb1itz On

As per R Greenstreet answer above, Color-Thief does not support other formats than .jpg or .png.
So to workaround this, you need to convert image on the fly.

The fastest and most convenient way I could find is just to use node sharp module. And the code itself is just a few lines...

const sharp = require('sharp');

let image = await sharp(imageData);
let imageData = await image.metadata();

if (imageData.format === 'webp') {
    image = await image.toFormat('png').toBuffer();
} else {
    image = await image.toBuffer();
}

I know, this is not the optimal solution, but if you want a stable fix, this should be fine.