0.1.1 • Published 6 years ago

@akigami/vibrant v0.1.1

Weekly downloads
-
License
MIT
Repository
github
Last release
6 years ago

Vibrant

Extract prominent colors from an image. Fixed version.

New WebWorker support in v3.0

Quantization is the most time-consuming stage in @akigami/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:

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)

Install

$ npm install @akigami/vibrant

Usage

node.js / browserify

// ES5
var Vibrant = require('@akigami/vibrant')
// ES6
import * as Vibrant from '@akigami/vibrant'
// TypeScript
import Vibrant from '@akigami/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 @akigami/vibrant with npm, compiled bundles are available under node_modules/@akigami/vibrant/dist.

<!-- Debug version -->
<script src="/path/to/dist/vibrant.js"></script>
<!-- Uglified version -->
<script src="/path/to/dist/vibrant.min.js"></script>

<script>
  // 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
</script>

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 @akigami/vibrant.

Vibrant.from(src: ImageSource): Builder

Make a Builder for an image. Returns a Builder instance.

constructor(src: ImageSource, opts: Partial<Options>)

NameDescription
imagePath to image file (support HTTP/HTTPs)
optsOptions (optional)
ImageSource
export type ImageSource = string 
  | HTMLImageElement  // Browser only 
  | Buffer            // Node.js only
Options
export interface Options {
    colorCount: number
    quality: number
    maxDimension: number
    filters: Array<Filter>
    ImageClass: ImageClass
    quantizer: Quantizer
    generator?: Generator
}
FieldDefaultDescription
colorCount64amount of colors in initial palette from which the swatches will be generated
quality5Scale down factor used in downsampling stage. 1 means no downsampling. If maxDimension is set, this value will not be used.
maxDimensionundefinedThe max size of the image's longer side used in downsampling stage. This field will override quality.
filters[]An array of filters
ImageClassImage.Node or Image.BrowserAn Image implementation class
quantizerVibrant.Quantizer.MMCQA Quantizer implementation class
generatorVibrant.Generator.DefaultAn Generator instance
Resolvable<T>
export type Resolvable<T> = T | Bluebird<T>
Quantizer
export interface Quantizer {
    (pixels: Pixels, opts: Options): Resolvable<Array<Swatch>>
}
Generator
export interface Generator {
    (swatches: Array<Swatch>, opts?: Object): Resolvable<Palette>
}
Filter

Returns true if the color is to be kept.

export interface Filter {
    (red: number, green: number, blue: number, alpha: number): boolean
}

getPalette(cb?: Callback<Palette>): Bluebird<Palette>

NameDescription
cb(Optional) callback function. Can be omitted when using Promise.
Callback<T>
export interface Callback<T> {
    (err?: Error, result?: T): void
}

getSwatches(cb?: Callback<Palette>): Bluebird<Palette>

Alias of getPalette.

Vibrant.Builder

Helper class for change configurations and create a Vibrant instance. Methods of a Builder instance can be chained like:

Vibrant.from(src)
  .quality(1)
  .clearFilters()
  // ...
  .getPalette()
  .then((palette) => {})

constructor(src: ImageSource, opts: Partial<Options>)

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<Palette>): Bluebird<Palette>

Builds a Vibrant instance as configured and calls its getPalette method.

getSwatches(cb? Callback<Palette>): Bluebird<Palette>

Alias of getPalette.

Vibrant.Swatch

Represents a color swatch generated from an image's palette.

Vec3

export interface Vec3 extends Array<number> {
    0: number,
    1: number,
    2: number
}

constructor(rgb: Vec3, population: number)

Internal use.

NameDescription
rgb[r, g, b]
populationPopulation 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 EPerceptionReturns
<= 1.0Not perceptible by human eyes."Perfect"
1 - 2Perceptible through close observation."Close"
2 - 10Perceptible at a glance."Good"
11 - 49Colors are more similar than opposite"Similar"
50 - 100Colors are exact oppositeWrong

NPM Tasks

TaskDescription
build:browserBuild browser target
build:nodeBuild node.js target
buildBuild all targets
clean:browserClean browser build
clean:nodeClean node.js build
cleanClean all builds
test:browserRun browser specs (karma)
test:nodeRun node.js specs (mocha)
testRun all specs

Notes

Intentional Deviation From vibrant.js

  • @akigami/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.
  • @akigami/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 @akigami/vibrant does it for you).
  • @akigami/vibrant uses one single opts object to hold all options for future expansions. And it feels more node.js-like.
  • @akigami/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.

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.