node-vibrant vs get-image-colors
Extracting Dominant and Vibrant Colors from Images in JavaScript
node-vibrantget-image-colors
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
node-vibrant400,6102,40120.2 kB2122 days agoMIT
get-image-colors22,451353297 kB13-MIT

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: node-vibrant vs get-image-colors
  • 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.

  • 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.

README for node-vibrant

node-vibrant

Extract prominent colors from an image.