Color Thief

repository·master·Indexed 12 days ago

https://github.com/lokesh/color-thief

A library for extracting dominant colors, palettes, and semantic swatches from images in the browser and Node.js. Version 3.5.0 supports wide-gamut (Display P3) color spaces, OKLCH quantization, live video extraction via observe(), and a CLI for command-line extraction.

Tokens
10.4K
Snippets
39
Records
51
Agent score
93%

What's inside Color Thief

  1. Handle Wide-gamut (Display P3) images in the browser

    master

    By default, colors are read and reported in sRGB. For P3-tagged/wide-gamut images, use the gamut option to preserve saturation.

    • gamut: 'display-p3': Forces reading through a P3 canvas and reports P3 colors.
    • gamut: 'auto': Reports P3 only if the image uses out-of-sRGB colors; otherwise behaves like sRGB.

    Note on compatibility: .rgb(), .array(), and .hex() always return sRGB (gamut-mapped). For raw P3 components, use .oklch() or .css(). In Node.js, output is currently sRGB.

    // Force P3
    const palette = await getPalette(img, { gamut: 'display-p3' });
    palette[0].css();            // 'color(display-p3 0.92 0.2 0.14)'
    palette[0].gamut;            // 'display-p3'
    
    // Auto
    const auto = await getPalette(img, { gamut: 'auto' });
  2. Extract colors from a specific image region

    master

    You can sample only a specific part of an image by providing a region option. The coordinates are fractions of the image size (0–1) measured from the top-left, making the region resolution-independent.

    Example: Sample the bottom third

    const palette = await getPalette(img, {
        region: { x: 0, y: 0.66, width: 1, height: 0.34 },
    });

    Example: Center crop

    const color = await getColor(img, {
        region: { x: 0.25, y: 0.25, width: 0.5, height: 0.5 },
    });

    This works with all extraction functions (including *Sync, observe(), and the CLI) in both browser and Node.js. Values that run past the edge are clamped; out-of-range or zero-sized values will throw an error.

    // Colors from the bottom third
    const palette = await getPalette(img, {
        region: { x: 0, y: 0.66, width: 1, height: 0.34 },
    });
    
    // Center crop
    const color = await getColor(img, {
        region: { x: 0.25, y: 0.25, width: 0.5, height: 0.5 },
    });
  3. Install Color Thief

    master

    You can install Color Thief via npm for use in Node.js or browser bundlers, or load it directly from a CDN for simple browser usage.

    npm:

    npm install colorthief

    CDN:

    <script src="https://unpkg.com/colorthief@3/dist/umd/color-thief.global.js"></script>
  4. Quick Start with Color Thief

    master

    Color Thief provides synchronous APIs for the browser and asynchronous APIs for both the browser and Node.js. You can extract a single dominant color, a full palette, or semantic swatches.

    Dominant Color: Use getColorSync (browser) or getColor (async) to get the primary color. Palette: Use getPaletteSync (browser) or getPalette (async) to get an array of colors. Semantic Swatches: Use getSwatches (async) to get named color groups like Vibrant or Muted.

    import { getColorSync, getPaletteSync, getSwatches } from 'colorthief';
    
    // Dominant color
    const color = getColorSync(img);
    color.hex();      // '#e84393'
    color.css();      // 'rgb(232, 67, 147)'
    color.isDark;     // false
    color.textColor;  // '#000000'
    
    // Palette
    const palette = getPaletteSync(img, { colorCount: 6 });
    palette.forEach(c => console.log(c.hex()));
    
    // Semantic swatches (Vibrant, Muted, DarkVibrant, etc.)
    const swatches = await getSwatches(img);
    swatches.Vibrant?.color.hex();
  5. Run extraction in a Web Worker

    master

    To prevent blocking the main thread, run Color Thief inside a Web Worker using ImageBitmap. Bitmaps are transferable, allowing pixels to move to the worker without being cloned.

    Important: Color objects cannot survive structured cloning. When sending data back from a worker, map the palette to plain data (e.g., hex strings).

    Note: The worker: true option is deprecated and ignored as of v3. Use the manual Web Worker pattern described below.

    // main.js
    const bitmap = await createImageBitmap(await (await fetch(url)).blob());
    const worker = new Worker('./palette-worker.js', { type: 'module' });
    worker.postMessage({ bitmap }, [bitmap]); // transferred, not cloned
    worker.onmessage = (e) => render(e.data.palette);
    // palette-worker.js
    import { getPalette } from 'colorthief';
    
    self.onmessage = async ({ data }) => {
        const palette = await getPalette(data.bitmap, { colorCount: 5 });
        // Color objects don't survive structured clone — send plain data
        self.postMessage({ palette: palette.map((c) => c.hex()) });
    };
  6. Use Color Thief in Node.js

    master

    In Node.js, Color Thief uses sharp for image decoding. The API is asynchronous and accepts file paths or Buffers as sources.

    Example:

    import { getColor, getPalette } from 'colorthief';
    
    // From a file path
    const color = await getColor('/path/to/image.jpg');
    console.log(color.hex());
    
    // From a Buffer
    const palette = await getPalette(Buffer.from(data), { colorCount: 5 });
    import { getColor, getPalette } from 'colorthief';
    
    const color = await getColor('/path/to/image.jpg');
    console.log(color.hex());
    
    const palette = await getPalette(Buffer.from(data), { colorCount: 5 });
  7. How region extraction works

    master

    Color Thief supports sub-rectangle (region) extraction using normalized coordinates. A Region is defined using values between 0 and 1, making it independent of the actual pixel dimensions of the image.

    When a region is provided, the crop is applied to the decoded pixel buffer immediately after loading and before any sampling occurs. This ensures that all entry points (async, sync, observe(), progressive, and CLI) and all custom loaders or quantizers benefit from region support.

    Region Object Shape:

    {
      x: number;      // Horizontal start (0 to 1)
      y: number;      // Vertical start (0 to 1)
      width: number;  // Width as a fraction of image width (0 to 1)
      height: number; // Height as a fraction of image height (0 to 1)
    }
  8. Understand Swatch and SwatchRole for semantic colors

    master

    A Swatch is a semantic color object that includes accessibility information. It pairs a Color with a SwatchRole and provides specific text colors for readability.

    Available SwatchRole values:

    • 'Vibrant'
    • 'Muted'
    • 'DarkVibrant'
    • 'DarkMuted'
    • 'LightVibrant'
    • 'LightMuted'

    A SwatchMap is a record that maps these roles to their corresponding Swatch (or null if no match is found).

  9. Configure the --region option for sub-rectangle sampling

    master

    To sample a specific part of an image instead of the whole thing, use the --region flag. The value must be a comma-separated list of four numbers representing x,y,width,height as fractions of the total image dimensions (ranging from 0 to 1).

    Example: To sample the bottom third of an image, use 0,0.66,1,0.34 (starting at 66% height, spanning 100% width and 34% height).

    colorthief image.png --region 0,0.66,1,0.34
  10. Configure extraction options

    master

    When calling extraction functions, you can pass an options object to customize the behavior.

    OptionDefaultDescription
    colorCount10Number of palette colors (2–20)
    quality10Sampling rate (1 = every pixel, 10 = every 10th)
    colorSpace'oklch'Quantization space: 'rgb' or 'oklch'
    regionSample a sub-rectangle: { x, y, width, height } as 0–1 fractions
    gamut'srgb'Output gamut: 'srgb', 'display-p3', or 'auto' (browser only)
    signalAbortSignal to cancel extraction
    ignoreWhitetrueSkip white pixels
  11. How to offload Color Thief extraction to a Web Worker

    master

    The built-in Web Worker support (via worker: true or extractInWorker()) has been removed in v3 to avoid performance penalties caused by structured cloning of pixel arrays.

    To achieve off-main-thread extraction, you should run the Color Thief library itself inside your own Web Worker. Because Color Thief supports ImageBitmap and OffscreenCanvas as sources, you can perform the entire pipeline—decoding, pixel sampling, and quantization—off-thread. Using ImageBitmap is recommended as it can be transferred to the worker without copying.

  12. Define a sampling Region using normalized coordinates

    master

    A Region allows you to sample a specific sub-rectangle of an image. Coordinates and dimensions are expressed as fractions of the image's width and height (0–1), making the definition resolution-independent.

    // Example: Sampling the bottom third of an image
    const region: Region = {
      x: 0,
      y: 0.66,
      width: 1,
      height: 0.34
    };
    // Bottom third of the image
    { x: 0, y: 0.66, width: 1, height: 0.34 }