Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/Vibrant-Colors/node-vibrant
🎨 Extract prominent colors from an image
https://github.com/Vibrant-Colors/node-vibrant
Last synced: 11 days ago
JSON representation
🎨 Extract prominent colors from an image
- Host: GitHub
- URL: https://github.com/Vibrant-Colors/node-vibrant
- Owner: Vibrant-Colors
- License: mit
- Created: 2015-06-04T13:30:08.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2024-05-07T14:49:34.000Z (6 months ago)
- Last Synced: 2024-10-29T15:43:36.730Z (15 days ago)
- Language: TypeScript
- Homepage:
- Size: 1.11 MB
- Stars: 2,023
- Watchers: 16
- Forks: 108
- Open Issues: 34
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# node-vibrant
[![Build Status](https://travis-ci.org/akfish/node-vibrant.svg?branch=master)](https://travis-ci.org/akfish/node-vibrant)Extract prominent colors from an image.
## ** NOTICE **
This project is refactored into a monorepo in version 3.2.0 (see [develop](https://github.com/akfish/node-vibrant/tree/develop) branch, npm version `[email protected]`).
We will not merge new PRs to v3.1 related to new featuresets during this time. However, bug fixes and security vulnerability fixes are still highly encouraged.
## New WebWorker support in v3.0
Quantization is the most time-consuming stage in `node-vibrant`. In v3.0, the quantization can be run in the WebWorker to avoid freezing the UI thread.
Here's how to use this feature:
1. Use WebWorker build `dist/vibrant.worker.js` or `dist/vibrant.worker.min.js`. Or if you are re-bundling with webpack, use `lib/bundle.worker.js` as entry
2. Use WebWorker quantizer:
```ts
let v = Vibrant.from(src)
.useQuantizer(Vibrant.Quantizer.WebWorker)
// Other configurations
```## Features
- Identical API for both node.js and browser environment
- Support browserify/webpack
- Consistent results (*See [Result Consistency](#result-consistency))## Install
```bash
$ npm install node-vibrant
```## Usage
### node.js / browserify```js
// ES5
var Vibrant = require('node-vibrant')
// ES6
import * as Vibrant from 'node-vibrant'
// TypeScript
import Vibrant = require('node-vibrant')// Using builder
Vibrant.from('path/to/image').getPalette((err, palette) => console.log(palette))
// Promise
Vibrant.from('path/to/image').getPalette()
.then((palette) => console.log(palette))// Using constructor
let v = new Vibrant('path/to/image', opts)
v.getPalette((err, palette) => console.log(palette))
// Promise
v.getPalette().then((palette) => console.log(palette))
```### Browser
If you installed node-vibrant with `npm`, compiled bundles are available under `node_modules/node-vibrant/dist`.
Or you can download bundles from [Relases](https://github.com/akfish/node-vibrant/releases).```html
// Use `Vibrant` in script
// Vibrant is exported to global. window.Vibrant === Vibrant
Vibrant.from('path/to/image').getPalette(function(err, palette) {});
// Promise
Vibrant.from('path/to/image').getPalette().then(function(palette) {});
// Or
var v = new Vibrant('/path/to/image', opts);
// ... same as in node.js```
## Contribution Guidelines
1. Make changes
2. Write test specs if necessary
3. Pass tests
4. Commit **source files only** (without compiled files)## References
### `Vibrant`
Main class of `node-vibrant`.#### `Vibrant.from(src: ImageSource): Builder`
Make a `Builder` for an image. Returns a `Builder` instance.#### `constructor(src: ImageSource, opts: Partial)`
Name | Description
------- | ---------------------------------------
`image` | Path to image file (support HTTP/HTTPs)
`opts` | Options (optional)##### `ImageSource`
```ts
export type ImageSource = string
| HTMLImageElement // Browser only
| Buffer // Node.js only
```##### `Options`
```ts
export interface Options {
colorCount: number
quality: number
maxDimension: number
filters: Array
ImageClass: ImageClass
quantizer: Quantizer
generator?: Generator
}
```Field | Default | Description
-------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------
`colorCount` | 64 | amount of colors in initial palette from which the swatches will be generated
`quality` | 5 | Scale down factor used in downsampling stage. `1` means no downsampling. If `maxDimension` is set, this value will not be used.
`maxDimension` | `undefined` | The max size of the image's longer side used in downsampling stage. This field will override `quality`.
`filters` | `[]` | An array of filters
`ImageClass` | `Image.Node` or `Image.Browser` | An `Image` implementation class
`quantizer` | `Vibrant.Quantizer.MMCQ` | A `Quantizer` implementation class
`generator` | `Vibrant.Generator.Default` | An `Generator` instance##### `Resolvable`
```ts
export type Resolvable = T | Promise
```##### `Quantizer`
```ts
export interface Quantizer {
(pixels: Pixels, opts: Options): Resolvable>
}
```##### `Generator`
```ts
export interface Generator {
(swatches: Array, opts?: Object): Resolvable
}
```##### `Filter`
Returns `true` if the color is to be kept.
```ts
export interface Filter {
(red: number, green: number, blue: number, alpha: number): boolean
}
```#### `getPalette(cb?: Callback): Promise`
Name | Description
---- | -----------------
`cb` | (Optional) callback function. Can be omitted when using `Promise`.##### `Callback`
```ts
export interface Callback {
(err?: Error, result?: T): void
}
```#### `getSwatches(cb?: Callback): Promise`
Alias of `getPalette`.### `Vibrant.Builder`
Helper class for change configurations and create a `Vibrant` instance. Methods of a `Builder` instance can be chained like:```ts
Vibrant.from(src)
.quality(1)
.clearFilters()
// ...
.getPalette()
.then((palette) => {})
```#### `constructor(src: ImageSource, opts: Partial)`
Arguments are the same as `Vibrant.constructor`.#### `quality(q: number): Builder`
Sets `opts.quality` to `q`. Returns this `Builder` instance.#### `maxColorCount(n: number): Builder`
Sets `opts.colorCount` to `n`. Returns this `Builder` instance.#### `maxDimension(d: number): Builder`
Sets `opts.maxDimension` to `d`. Returns this `Builder` instance.#### `addFilter(f: Filter): Builder`
Adds a filter function. Returns this `Builder` instance.#### `removeFilter(f: Filter): Builder`
Removes a filter function. Returns this `Builder` instance.#### `clearFilters(): Builder`
Clear all filters. Returns this `Builder` instance.#### `useImageClass(imageClass: ImageClass): Builder`
Specifies which `Image` implementation class to use. Returns this `Builder` instance.#### `useQuantizer(quantizer: Quantizer): Builder`
Specifies which `Quantizer` implementation class to use. Returns this `Builder` instance.#### `useGenerator(generator: Generator): Builder`
Sets `opts.generator` to `generator`. Returns this `Builder` instance.#### `build(): Vibrant`
Builds and returns a `Vibrant` instance as configured.#### `getPalette(cb?: Callback): Promise`
Builds a `Vibrant` instance as configured and calls its `getPalette` method.#### `getSwatches(cb? Callback): Promise`
Alias of `getPalette`.### `Vibrant.Swatch`
Represents a color swatch generated from an image's palette.#### `Vec3`
```ts
export interface Vec3 extends Array {
0: number,
1: number,
2: number
}
```#### `constructor(rgb: Vec3, population: number)`
Internal use.Name | Description
------------ | -----------------------------------
`rgb` | `[r, g, b]`
`population` | Population of the color in an image#### `getHsl(): Vec3`
#### `getPopulation(): number`
#### `getRgb(): Vec3`
#### `getHex(): string`
#### `getTitleTextColor(): string`
Returns an appropriate color to use for any 'title' text which is displayed over this `Swatch`'s color.#### `getBodyTextColor(): string`
Returns an appropriate color to use for any 'body' text which is displayed over this `Swatch`'s color.### `Vibrant.Util`
Utility methods. Internal usage.#### `hexToRgb(hex: string): Vec3`
#### `rgbToHex(r: number, g: number, b: number): string`
#### `hslToRgb(h: number, s: number, l: number): Vec3`
#### `rgbToHsl(r: number, g: number, b: number): Vec3`
#### `xyzToRgb(x: number, y: number, z: number): Vec3`
#### `rgbToXyz(r: number, g: number, b: number): Vec3`
#### `xyzToCIELab(x: number, y: number, z: number): Vec3`
#### `rgbToCIELab(l: number, a: number, b: number): Vec3`
#### `deltaE94(lab1: number, lab2: number): number`
Computes CIE delta E 1994 diff between `lab1` and `lab2`. The 2 colors are in CIE-Lab color space. Used in tests to compare 2 colors' perceptual similarity.#### `rgbDiff(rgb1: Vec3, rgb2: Vec3): number`
Compute CIE delta E 1994 diff between `rgb1` and `rgb2`.#### `hexDiff(hex1: string, hex2: string): number`
Compute CIE delta E 1994 diff between `hex1` and `hex2`.#### `getColorDiffStatus(d: number): string`
Gets a string to describe the meaning of the color diff. Used in tests.Delta E | Perception | Returns
-------- | -------------------------------------- | -----------
<= 1.0 | Not perceptible by human eyes. | `"Perfect"`
1 - 2 | Perceptible through close observation. | `"Close"`
2 - 10 | Perceptible at a glance. | `"Good"`
11 - 49 | Colors are more similar than opposite | `"Similar"`
50 - 100 | Colors are exact opposite | `Wrong`## NPM Tasks
Task | Description
--------------- | --------------------------------------
`build:browser` | Build browser target
`build:node` | Build node.js target
`build` | Build all targets
`clean:browser` | Clean browser build
`clean:node` | Clean node.js build
`clean` | Clean all builds
`test:browser` | Run browser specs (karma)
`test:node` | Run node.js specs (mocha)
`test` | Run all specs## Notes
### Intentional Deviation From `vibrant.js`
- `node-vibrant` takes image path, not the image object as parameter for the obvious reason that node.js environment has no access to HTML DOM object.
- `node-vibrant` provides asynchronous API since most node.js image processing library is asynchronous. And the original `vibrant.js` workflow is asynchronous any way (though you will have to handle the image loading yourself, while `node-vibrant` does it for you).
- `node-vibrant` uses one single `opts` object to hold all options for future expansions. And it feels more node.js-like.
- `node-vibrant` uses method call to initiate image processing instead of constructor so that developers can use it with `Promise`.### Result Consistency
The results is consistent within each user's browser instance regardelss of visible region or display size of the image, unlike the original `vibrant.js` implementation.However, due to the very nature of HTML5 canvas element, image rendering is platform/machine-dependent. Thus the resulting swatches in browser environment varies and may not be the same as in node.js nor in another machine. See [Canvas Fingerprinting](https://en.wikipedia.org/wiki/Canvas_fingerprinting).
The test specs use CIE delta E 1994 color difference to measure inconsistencies across platforms. It compares the generated color on node.js, Chrome, Firefox and IE11. At `quality` == 1 (no downsampling) and no filters, the results are rather consistent. Color diffs between browsers are mostly not perceptible by human eyes. Downsampling _will_ cause perceptible inconsistent results across browsers due to differences in canvas implementations.