Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
## Culori Changelog

### 0.5.0
### 0.5.1

Removed default export from ES build, and cleaned up the build process. Added Prettier, ESLint.
**Breaking:** Removed the `culori()` function, which was an alias for `culori.rgb()`. This makes the build simpler and clarifies the API a bit.

Cleaned up the build process; added Prettier, ESLint.

### Previously

Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ The available modes (color spaces) are listed below. Each color space has a conv
| `cubehelix` | Cubehelix color space | culori.**cubehelix**(_color_) |
| `dlab` | DIN99o Lab color space | culori.**dlab**(_color_) |
| `dlch` | DIN99o LCh color space | culori.**dlch**(_color_) |
| `yiq` | YIQ color space | culori.**yiq**(_color_) |

<a name="culoriFormatter" href="#culoriFormatter">#</a> culori.**formatter**(_format = 'rgb'_) → _function (color)_ [<>](https://github.com/evercoder/culori/blob/master/src/formatter.js 'Source')

Expand Down Expand Up @@ -228,10 +229,12 @@ samples(5).map(grays);

These methods are concerned to finding the [distance between two colors](https://en.wikipedia.org/wiki/Color_difference) based on various formulas. Each of these formulas will return a _function (colorA, colorB)_ that lets you measure the distance between two colors. Also available as a separate [d3 plugin](https://github.com/evercoder/d3-color-difference).

<a name="culoriDifferenceEuclidean" href="#culoriDifferenceEuclidean">#</a> culori.**differenceEuclidean**(_mode = 'rgb'_) [<>](https://github.com/evercoder/culori/blob/master/src/difference.js 'Source')
<a name="culoriDifferenceEuclidean" href="#culoriDifferenceEuclidean">#</a> culori.**differenceEuclidean**(_mode = 'rgb'_, _weights = [1, 1, 1]_) [<>](https://github.com/evercoder/culori/blob/master/src/difference.js 'Source')

Returns a [Euclidean distance](https://en.wikipedia.org/wiki/Color_difference#Euclidean) function in a certain color space.

You can optionally assign different weights to the channels in the color space. See, for example, the [Kotsarenko/Ramos distance](#culoriDifferenceKotsarenkoRamos).

<a name="culoriDifferenceCie76" href="#culoriDifferenceCie76">#</a> culori.**differenceCie76**() [<>](https://github.com/evercoder/culori/blob/master/src/difference.js 'Source')

Computes the [CIE76][cie76] ΔE\*<sub>ab</sub> color difference between the colors _a_ and _b_. The computation is done in the Lab color space and it is analogous to [culori.differenceEuclidean('lab')](#culoriDifferenceEuclidean).
Expand All @@ -256,6 +259,10 @@ _Note:_ ΔE\*<sub>CMC</sub> is not considered a metric since it's not symmetrica

Computes the [DIN99o][din99ode] ΔE\*<sub>99o</sub> color difference between the colors _a_ and _b_. The computation is done in the [DIN99o][din99o] color space.

<a name="culoriDifferenceKotsarenkoRamos" href="#culoriDifferenceKotsarenkoRamos">#</a> culori.**differenceKotsarenkoRamos**() [<>](https://github.com/evercoder/culori/blob/master/src/difference.js 'Source')

Computes the [Kotsarenko/Ramos][kotsarekno-ramos] color difference between the colors _a_ and _b_. This is a weighted Euclidean distance in the [YIQ][yiq] color space.

#### Nearest color(s)

<a name="culoriNearest" href="#culoriNearest">#</a> culori.**nearest**(_colors_, _metric = differenceEuclidean()_, _accessor = identity_) → _function(color, n = 1, τ = Infinity)_ [<>](https://github.com/evercoder/culori/blob/master/src/nearest.js 'Source')
Expand Down Expand Up @@ -355,3 +362,5 @@ These libraries add more functionality to culori:
[cmc]: https://en.wikipedia.org/wiki/Color_difference#CMC_l:c_(1984)
[din99o]: https://de.wikipedia.org/wiki/DIN99-Farbraum
[din99ode]: https://de.wikipedia.org/wiki/DIN99-Farbraum#Farbabstandsformel
[kotsarekno-ramos]: http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf
[yiq]: https://en.wikipedia.org/wiki/YIQ
25 changes: 21 additions & 4 deletions src/difference.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { getModeDefinition } from './modes';
import converter from './converter';

const differenceEuclidean = (mode = 'rgb') => {
const differenceEuclidean = (mode = 'rgb', weights = [1, 1, 1]) => {
let channels = getModeDefinition(mode).channels;
let conv = converter(mode);
return (std, smp) => {
let ConvStd = conv(std);
let ConvSmp = conv(smp);
return Math.sqrt(
channels.reduce(
(delta, k) =>
(delta, k, idx) =>
// ignore alpha channel in computing the euclidean distance
delta +
(k === 'alpha' ? 0 : Math.pow(ConvStd[k] - ConvSmp[k], 2)),
(k === 'alpha'
? 0
: weights[idx] * Math.pow(ConvStd[k] - ConvSmp[k], 2)),
0
)
);
Expand Down Expand Up @@ -194,11 +196,26 @@ const differenceCmc = (l = 1, c = 1) => {

const differenceDin99o = () => differenceEuclidean('dlab');

/*
"Measuring perceived color difference using YIQ NTSC
transmission color space in mobile applications"

by Yuriy Kotsarenko, Fernando Ramos in:
Programación Matemática y Software (2010)

Available at:

http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf
*/
const differenceKotsarenkoRamos = () =>
differenceEuclidean('yiq', [0.5053, 0.299, 0.1957]);

export {
differenceEuclidean,
differenceCie76,
differenceCie94,
differenceCiede2000,
differenceCmc,
differenceDin99o
differenceDin99o,
differenceKotsarenkoRamos
};
9 changes: 7 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import lchDef from './lch/definition';
import cubehelixDef from './cubehelix/definition';
import dlabDef from './dlab/definition';
import dlchDef from './dlch/definition';
import yiqDef from './yiq/definition';

import { defineMode } from './modes';
import converter from './converter';
Expand All @@ -24,6 +25,7 @@ defineMode(lchDef);
defineMode(cubehelixDef);
defineMode(dlabDef);
defineMode(dlchDef);
defineMode(yiqDef);

let rgb = converter('rgb');
let lrgb = converter('lrgb');
Expand All @@ -36,6 +38,7 @@ let lch = converter('lch');
let cubehelix = converter('cubehelix');
let dlab = converter('dlab');
let dlch = converter('dlch');
let yiq = converter('yiq');

export {
defineMode,
Expand All @@ -50,7 +53,8 @@ export {
lrgb,
cubehelix,
dlab,
dlch
dlch,
yiq
};

export { default as formatter } from './formatter';
Expand Down Expand Up @@ -84,6 +88,7 @@ export {
differenceCie94,
differenceCiede2000,
differenceCmc,
differenceDin99o
differenceDin99o,
differenceKotsarenkoRamos
} from './difference';
export { default as colorsNamed } from './colors/named';
13 changes: 13 additions & 0 deletions src/yiq/convertRgbToYiq.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import convertRgbToLrgb from '../lrgb/convertRgbToLrgb';

export default rgb => {
let { r, g, b, alpha } = convertRgbToLrgb(rgb);
let res = {
mode: 'yiq',
y: 0.29889531 * r + 0.58662247 * g + 0.11448223 * b,
i: 0.59597799 * r - 0.2741761 * g - 0.32180189 * b,
q: 0.21147017 * r - 0.52261711 * g + 0.31114694 * b
};
if (alpha !== undefined) res.alpha = alpha;
return res;
};
9 changes: 9 additions & 0 deletions src/yiq/convertYiqToRgb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import convertLrgbToRgb from '../lrgb/convertLrgbToRgb';

export default ({ y, i, q, alpha }) =>
convertLrgbToRgb({
r: y + 0.95608445 * i + 0.6208885 * q,
g: y - 0.27137664 * i - 0.6486059 * q,
b: y - 1.10561724 * i + 1.70250126 * q,
alpha
});
42 changes: 42 additions & 0 deletions src/yiq/definition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import convertRgbToYiq from './convertRgbToYiq';
import convertYiqToRgb from './convertYiqToRgb';
import interpolateNumber from '../interpolate/interpolateNumber';
import interpolateAlpha from '../interpolate/interpolateAlpha';
import interpolateFunctionLinear from '../interpolate/interpolateFunctionLinear';

/*
YIQ Color Space

References
----------

Wikipedia:
https://en.wikipedia.org/wiki/YIQ

"Measuring perceived color difference using YIQ NTSC
transmission color space in mobile applications"

by Yuriy Kotsarenko, Fernando Ramos in:
Programación Matemática y Software (2010)

Available at:

http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf
*/

export default {
mode: 'yiq',
output: {
rgb: convertYiqToRgb
},
input: {
rgb: convertRgbToYiq
},
channels: ['y', 'i', 'q', 'alpha'],
interpolate: {
y: interpolateFunctionLinear(interpolateNumber()),
i: interpolateFunctionLinear(interpolateNumber()),
q: interpolateFunctionLinear(interpolateNumber()),
alpha: interpolateFunctionLinear(interpolateAlpha())
}
};
12 changes: 11 additions & 1 deletion test/difference.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ let {
differenceCie94,
differenceCiede2000,
differenceCmc,
differenceKotsarenkoRamos,
rgb,
lab,
round
Expand Down Expand Up @@ -119,7 +120,7 @@ tape('ciede2000 difference', function(test) {
test.end();
});

tape('cmc difference', function(test) {
tape('differenceCmc', function(test) {
test.equal(
differenceCmc()(
lab({ l: 1, a: 0, b: 0, alpha: 0.5 }),
Expand All @@ -130,3 +131,12 @@ tape('cmc difference', function(test) {

test.end();
});

tape('differenceKotsarenkoRamos', function(test) {
test.equal(
differenceKotsarenkoRamos()('white', 'black'),
0.7108445752103619
);

test.end();
});
23 changes: 23 additions & 0 deletions test/yiq.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
let tape = require('tape');
let culori = require('../');
let { yiq, formatter } = culori;

let rgb = formatter('rgb');

tape('rgb to yiq and back', function(test) {
test.deepEqual(
rgb(yiq('rgb(255, 255, 255)')),
'rgb(255, 255, 255)',
'white'
);

test.deepEqual(rgb(yiq('rgb(0, 0, 0)')), 'rgb(0, 0, 0)', 'black');

test.deepEqual(rgb(yiq('rgb(100, 0, 0)')), 'rgb(100, 0, 0)', 'red');

test.deepEqual(rgb(yiq('rgb(0, 120, 0)')), 'rgb(0, 120, 0)', 'blue');

test.deepEqual(rgb(yiq('rgb(0, 0, 89)')), 'rgb(0, 0, 89)', 'green');

test.end();
});