get-image-colors vs node-vibrant
Extracting Dominant and Vibrant Colors from Images in JavaScript
get-image-colorsnode-vibrant

Extracting Dominant and Vibrant Colors from Images in JavaScript

get-image-colors and node-vibrant are both npm packages designed to extract meaningful color palettes from images, commonly used for UI theming, dynamic background generation, or visual analysis. get-image-colors provides a lightweight, promise-based API that returns an array of dominant colors using k-means clustering under the hood. node-vibrant, a Node.js port of Google's Android Palette library, offers a richer set of predefined swatches (Vibrant, Muted, Dark, Light variants) and supports multiple image input types including buffers, URLs, and file paths.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
get-image-colors0353297 kB13-MIT
node-vibrant02,42820.2 kB223 months agoMIT

Extracting Image Colors: get-image-colors vs node-vibrant

Both get-image-colors and node-vibrant solve the same core problem—analyzing an image to extract representative colors—but they do so with different philosophies, APIs, and output structures. Let’s compare how they handle real-world frontend tasks.

🎨 Output Structure: Raw Colors vs Semantic Swatches

get-image-colors returns a simple array of color objects (typically 5–10 entries), each containing RGB, HSL, and hex values. There’s no built-in meaning—just dominant clusters.

// get-image-colors: raw dominant colors
import getColors from 'get-image-colors';

const colors = await getColors('/path/to/image.jpg');
console.log(colors[0].hex); // e.g., "#ff5733"
console.log(colors[0].rgb); // { r: 255, g: 87, b: 51 }

node-vibrant returns a Palette object with named swatches like Vibrant, Muted, DarkVibrant, etc. Each swatch includes not just the color but also population (pixel count) and body/title text color suggestions.

// node-vibrant: semantic swatches
import Vibrant from 'node-vibrant';

const palette = await Vibrant.from('/path/to/image.jpg').getPalette();
console.log(palette.Vibrant.hex); // e.g., "#d94f3a"
console.log(palette.Muted.rgb);  // { r: 120, g: 110, b: 95 }

💡 If your design system needs a “vibrant accent” or “muted background,” node-vibrant gives you that out of the box. With get-image-colors, you’d have to implement your own logic to classify colors by saturation or brightness.

🖼️ Input Handling: Buffers, URLs, and Browser Support

get-image-colors accepts a <img> element, image URL, or file path (in Node.js). In the browser, it creates a hidden canvas to read pixel data.

// Browser usage with <img>
const img = document.querySelector('img');
const colors = await getColors(img);

node-vibrant supports image URLs, file paths, and raw buffers in Node.js. In the browser, you must pass a <img> or <canvas> element explicitly.

// Browser usage with <img>
const img = document.querySelector('img');
const palette = await Vibrant.from(img).getPalette();

Both work in browser and Node.js, but neither handles CORS-protected images automatically—you must ensure the image is loaded with proper CORS headers if reading cross-origin pixels.

⚙️ Customization and Control

get-image-colors allows you to specify the number of colors to extract:

const colors = await getColors(image, { count: 3 });

That’s it—no other tuning options.

node-vibrant lets you adjust target color counts per swatch type and set minimum saturation/brightness thresholds:

const palette = await Vibrant.from(image)
  .quality(5) // reduce quality for speed
  .maxColorCount(64) // limit internal color sampling
  .getPalette();

However, you can’t directly control how many total colors are returned—only how the swatches are generated.

🧪 Error Handling and Reliability

Both libraries reject their promises if the image fails to load or is unreadable (e.g., due to CORS or invalid format).

// get-image-colors error handling
try {
  const colors = await getColors(badImage);
} catch (err) {
  console.error('Color extraction failed:', err.message);
}

// node-vibrant error handling
try {
  const palette = await Vibrant.from(badImage).getPalette();
} catch (err) {
  console.error('Palette generation failed:', err.message);
}

Note: node-vibrant may return null for individual swatches if no suitable color is found (e.g., palette.DarkVibrant could be null). Always check before accessing properties.

📦 Dependencies and Runtime Behavior

get-image-colors depends on get-pixels and kmeans-js. It loads the entire image into memory and runs k-means clustering, which can be slow on large images.

node-vibrant uses its own quantization and scoring logic based on Android’s Palette algorithm. It downsamples images internally for performance but still processes all pixels unless you lower quality.

Neither is optimized for real-time video frame analysis—both are best suited for static images processed once.

🌐 Real-World Use Cases

Case 1: Dynamic Card Theming

You’re building a music app that shows album art and wants to style the play button with a vibrant accent.

  • Best choice: node-vibrant
  • Why? You can directly use palette.Vibrant.rgb without guessing which color is most saturated.
const palette = await Vibrant.from(albumArt).getPalette();
if (palette.Vibrant) {
  playButton.style.backgroundColor = palette.Vibrant.hex;
  playButton.style.color = palette.Vibrant.titleTextColor;
}

Case 2: Simple Background Gradient

You want to generate a subtle gradient from the two most dominant colors in a user-uploaded photo.

  • Best choice: get-image-colors
  • Why? You just need the top 2 colors—no need for semantic labels.
const [c1, c2] = await getColors(photo, { count: 2 });
container.style.background = `linear-gradient(${c1.hex}, ${c2.hex})`;

📌 Summary Table

Featureget-image-colorsnode-vibrant
OutputArray of raw color objectsObject with named swatches (Vibrant, etc.)
Semantic Labels❌ No✅ Yes
Custom Color Count✅ Yes (count option)❌ No (fixed swatch set)
Text Color Helpers❌ No✅ Yes (titleTextColor, bodyTextColor)
Browser Support✅ Via <img> or URL✅ Via <img> or <canvas>
Node.js Support✅ Via file path or buffer✅ Via file path, URL, or buffer

💡 Final Recommendation

  • Use get-image-colors for lightweight, performance-sensitive scenarios where you only need dominant colors and don’t care about their perceptual role.
  • Use node-vibrant when your UI relies on consistent, human-meaningful color roles (e.g., “use the vibrant color for buttons, muted for backgrounds”) and you can accept slightly heavier processing.

Both are actively maintained and production-ready—your choice should hinge on whether you need Google’s Palette semantics or just raw color data.

How to Choose: get-image-colors vs node-vibrant

  • get-image-colors:

    Choose get-image-colors if you need a minimal, fast, and straightforward way to extract a small set of dominant colors without complex configuration. It’s ideal for simple use cases like generating a background tint or picking a primary accent color, especially in environments where bundle size or dependency count matters. However, it doesn’t provide semantic labels like 'vibrant' or 'muted', so you’ll need to post-process results if you need those distinctions.

  • node-vibrant:

    Choose node-vibrant when you require Google’s Palette-inspired swatch system with clearly defined roles (e.g., Vibrant, Muted, DarkVibrant). It’s better suited for applications that dynamically theme UI elements based on image content—like media players or photo galleries—where consistent, human-readable color roles are essential. Be aware that it has more runtime overhead due to its comprehensive palette generation logic.

README for get-image-colors

get-image-colors

Extract colors from images. Supports GIF, JPG, PNG, and even SVG!

example color palette

Installation

npm install get-image-colors --save

This package is intended for use in node environments. It won't work in a browser because it has node-specific dependencies.

Note: when installing with webpack, if you get the error

Can't resolve 'fs' in '/node_modules/get-svg-colors' 

as per an open issue in webpack-contrib, you will need to add node: { fs: 'empty' } to your webpack.base.config:

module.exports = {
    ... ,
    node: { fs: 'empty' }
}

Usage

const path = require('path')
const getColors = require('get-image-colors')

getColors(path.join(__dirname, 'double-rainbow.png')).then(colors => {
  // `colors` is an array of color objects
})

You can also use a buffer as an input source.

const fs = require('fs')
const buffer = fs.readFileSync(path.join(__dirname, 'double-rainbow.gif'))
const getColors = require('get-image-colors')

getColors(buffer, 'image/gif').then(colors => {
  // `colors` is an array of color objects
})

colors is an array of chroma.js color objects. chroma.js objects have methods that lets you pick the color format you want (RGB hex, HSL, etc), and give you access to powerful color manipulation features:

colors.map(color => color.hex())
// => ['#FFFFFF', '#123123', '#F0F0F0']

colors[0].alpha(0.5).css()
// => 'rgb(0,128,128)''

If you don't like promises, you can use node-style callbacks too:

getColors(filename, function (err, colors) {
  if (err) throw err
  // ...
})

The default number of colors returned is 5. You can specify a different number of colors by passing an options object into the call to getColors:

const path = require('path')
const getColors = require('get-image-colors')

const options = {
  count: 10,
  type: 'image/png'
}
getColors(path.join(__dirname, 'double-rainbow.png'), options).then(colors => {
  // `colors` is an array of 10 color objects
})

How it Works

get-image-colors uses get-pixels to create a pixel array, then extracts a color palette with get-rgba-palette, which uses quantize under the hood.

Colors are converted from get-rgba-palette's flat array format into chroma.js color instances.

Tests

npm install
npm test

Dependencies

  • chroma-js: JavaScript library for color conversions
  • get-pixels: Reads the pixels of an image as an ndarray
  • get-rgba-palette: gets a palette of prominent colors from an array of pixels
  • get-svg-colors: Extract stroke and fill colors from SVG files

Dev Dependencies

  • mocha: simple, flexible, fun test framework

License

MIT