Color Thief

by Lokesh Dhakar

Grab the color palette from an image using just Javascript.
Works in the browser and in Node.

Github

Examples

Try it yourself

Drag an image here
Drop it!

Getting started

The Color Thief package includes multiple distribution files to support different environments and build processes. Here is the list of all the files in the /dist folder and what formats they support:

  • color-thief.js - CommonJS module for use in Node.
  • color-thief.mjs - ES6 module. For modern browsers as well as Webpack and Rollup.
  • color-thief.umd.js - UMD module. For simple script tag loading that exposes a global variable or for RequireJS AMD support.
  • color-thief.min.js - Duplicate of color-thief.umd.js. Kept around to maintain backwards compatibility.

Using in Node

  1. Install and import. The name of the package is colorthief, not color-thief.
    $ npm i --save colorthief
    const ColorThief = require('colorthief');
  2. Get colors. Both the getColor() and getPalette() methods return a Promise when used in Node.
    const img = resolve(process.cwd(), 'rainbow.png');
    
    ColorThief.getColor(img)
        .then(color => { console.log(color) })
        .catch(err => { console.log(err) })
    
    ColorThief.getPalette(img, 5)
        .then(palette => { console.log(palette) })
        .catch(err => { console.log(err) })

Using in the browser

1. Install

There are multiples ways to install Color Thief when using it in the browser:

  • Install as dependency with npm. The name of the package is colorthief, not color-thief.
    $ npm i --save colorthief
  • Load from a CDN. The distribution files are hosted on cdnjs for quick access.
    <script src="https://cdnjs.cloudflare.com/ajax/libs/color-thief/2.3.0/color-thief.umd.js"></script>
  • Download from Github. You can download a zip of the latest release (or any previous one) from the project's Github Releases page.

2. Import and use

  • As a global variable.
    <script src="node_modules/colorthief/dist/color-thief.umd.js"></script>
    <script>
        const colorThief = new ColorThief();
        const img = document.querySelector('img');
    
        // Make sure image is finished loading
        if (img.complete) {
          colorThief.getColor(img);
        } else {
          image.addEventListener('load', function() {
            colorThief.getColor(img);
          });
        }
    </script>
  • As an ES6 module.
    index.html
    <script type="module" src="app.js"></script>
    app.js
    import ColorThief from './node_modules/colorthief/dist/color-thief.mjs'
    
    const colorThief = new ColorThief();
    const img = document.querySelector('img');
    
    if (img.complete) {
      colorThief.getColor(img);
    } else {
      image.addEventListener('load', function() {
        colorThief.getColor(img);
      });
    }
    
  • With RequireJS. The /dist/color-thief.umd.js file uses the UMD (Universal Module Definition) format. This includes RequireJS AMD support.

API

Note: Both `getColor` and `getPalette` return a `Promise` when used in Node.

getColor(image [, quality])
Returns: [Number, Number, Number]

Gets the dominant color from the image. Color is returned as an array of three integers representing red, green, and blue values.

image - When called in the browser, this argument expects an HTML image element, not a URL. When run in Node, this argument expects a path to the image.

quality is an optional argument that must be an Integer of value 1 or greater, and defaults to 10. The number determines how many pixels are skipped before the next one is sampled. We rarely need to sample every single pixel in the image to get good results. The bigger the number, the faster a value will be returned.

getPalette(image [, colorCount, quality]
Returns: [[Number, Number, Number], ...]

Gets a palette from the image by clustering similar colors. The palette is returned as an array containing colors, each color itself an array of three integers.

FAQ

All questions are about the usage of Color Thief in the browser, not Node.

Do I have to wait for the image to load?

Yes. If you see an error that reads: Cannot read property '0' of null, it is likely that the image had not finished loading when you passed it to getColor() or getPalette().

// RISKY 🙀
const colorThief = new ColorThief();
const img = document.querySelector('img');

colorThief.getColor(img);

// BETTER 👍
const colorThief = new ColorThief();
const img = document.querySelector('img');

if (img.complete) {
  colorThief.getColor(img);
} else {
  image.addEventListener('load', function() {
    colorThief.getColor(img);
  });
}

How do I test the script locally?

If you are testing the script locally in a web browser, you might see the following error: Access to script at 'file://...' from origin 'null' has been blocked by CORS policy. This is because the browser restricts direct access to the filesystem.

To get around this, you can set up a minimal server to host the files. One option is http-server. To run this on demand without installing it as a project dependency, you can use the npx command:

$ npx http-server

Now you can visit http://localhost:8080 to view your server.

Does it work if the image is hosted on another domain?

A) If you manage the server hosting the image...

Yes. If you are seeing an error that reads: The canvas has been tainted by cross-origin data., then you are running into a cross-origin resouce sharing (CORS) issue. Check the following two items:

  1. CORS policy on the server. Is the server hosting the image properly configured? Make sure the requesting domain is whitelisted in the access-control-allow-origin header, or the server hosting the image has an open policy: access-control-allow-origin: *.
  2. crossorigin attr. The HTML image element must be given a crossorigin attribute.
    <img src="https://aws.com/s3/image.jpg" crossorigin="anonymous" />

    If you're dynamically adding the image element, you can do the following:

    const colorThief = new ColorThief();
    const img = new Image();
    
    img.addEventListener('load', function() {
      colorThief.getColor(img);
    });
    
    img.crossOrigin = 'Anonymous';
    img.src = 'https://aws.com/s3/image.jpeg'

B) If you don't have access to the server hosting the image...

You can use a proxy server that pulls down the image and returns it with a more liberal CORS policy. Below you can see an example of this with an image that is proxied through a public Google server. If you don't own the proxy server, just know, that you are at their mercy. But this is handy in a pinch for testing.

const colorThief = new ColorThief();
const img = new Image();

img.addEventListener('load', function() {
  colorThief.getColor(img);
});

let imageURL = 'https://i.pinimg.com/564x/3b/b4/9b/3bb49bd2a7f86e29b5670da1fe03fee4.jpg';
let googleProxyURL = 'https://images1-focus-opensocial.googleusercontent.com/gadgets/proxy?container=focus&refresh=2592000&url=';

img.crossOrigin = 'Anonymous';
img.src = googleProxyURL + encodeURIComponent(imageURL);

How do I get hex values?

The ColorThief methods return colors as an array of three integers representing red, green, and blue values. If you are looking to use the output in CSS, you can do that using the rgb format: color: rgb(102, 51, 153). If you do need to convert to hex, you can use the following function:

const rgbToHex = (r, g, b) => '#' + [r, g, b].map(x => {
  const hex = x.toString(16)
  return hex.length === 1 ? '0' + hex : hex
}).join('')

rgbToHex(102, 51, 153); // #663399

Help

Trouble using Color Thief?

Follow the steps below to get help. Make sure you have read the documentation on this page first.

  1. Search Stackoverflow to see if other people have run into the same issue you are having.
  2. If your issue is unique, then post a new question on Stackoverflow. Use the color-thief tag to make it easier to find.

Have a feature request?

  1. Search through existing Github Issues and PRs to see if the feature has been discussed or already created.
  2. If your feature request is unique, then post a new issue in Github detailing your request.

Found a bug?

  1. Search through existing Github Issues that have been reported to avoid creating a duplicate issue.
  2. If your bug has not been reported, create a new issue. In your bug report, please includes the version of the library you are using, your browser and operating system, and steps to recreate.

License

Color Thief is licensed under the MIT License.

Github provides a nice summary of the license:
"A short and simple permissive license with conditions only requiring preservation of copyright and license notices. Licensed works, modifications, and larger works may be distributed under different terms and without source code."