diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d5b7b67..14066af1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/README.md b/README.md
index c3261b45..22599745 100644
--- a/README.md
+++ b/README.md
@@ -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_) |
# culori.**formatter**(_format = 'rgb'_) → _function (color)_ [<>](https://github.com/evercoder/culori/blob/master/src/formatter.js 'Source')
@@ -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).
-# culori.**differenceEuclidean**(_mode = 'rgb'_) [<>](https://github.com/evercoder/culori/blob/master/src/difference.js 'Source')
+# 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).
+
# culori.**differenceCie76**() [<>](https://github.com/evercoder/culori/blob/master/src/difference.js 'Source')
Computes the [CIE76][cie76] ΔE\*ab 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).
@@ -256,6 +259,10 @@ _Note:_ ΔE\*CMC is not considered a metric since it's not symmetrica
Computes the [DIN99o][din99ode] ΔE\*99o color difference between the colors _a_ and _b_. The computation is done in the [DIN99o][din99o] color space.
+# 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)
# culori.**nearest**(_colors_, _metric = differenceEuclidean()_, _accessor = identity_) → _function(color, n = 1, τ = Infinity)_ [<>](https://github.com/evercoder/culori/blob/master/src/nearest.js 'Source')
@@ -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
diff --git a/src/difference.js b/src/difference.js
index e05b95d4..4b5d28ff 100644
--- a/src/difference.js
+++ b/src/difference.js
@@ -1,7 +1,7 @@
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) => {
@@ -9,10 +9,12 @@ const differenceEuclidean = (mode = 'rgb') => {
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
)
);
@@ -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
};
diff --git a/src/index.js b/src/index.js
index b8a4dae8..2991221f 100644
--- a/src/index.js
+++ b/src/index.js
@@ -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';
@@ -24,6 +25,7 @@ defineMode(lchDef);
defineMode(cubehelixDef);
defineMode(dlabDef);
defineMode(dlchDef);
+defineMode(yiqDef);
let rgb = converter('rgb');
let lrgb = converter('lrgb');
@@ -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,
@@ -50,7 +53,8 @@ export {
lrgb,
cubehelix,
dlab,
- dlch
+ dlch,
+ yiq
};
export { default as formatter } from './formatter';
@@ -84,6 +88,7 @@ export {
differenceCie94,
differenceCiede2000,
differenceCmc,
- differenceDin99o
+ differenceDin99o,
+ differenceKotsarenkoRamos
} from './difference';
export { default as colorsNamed } from './colors/named';
diff --git a/src/yiq/convertRgbToYiq.js b/src/yiq/convertRgbToYiq.js
new file mode 100644
index 00000000..71e95db0
--- /dev/null
+++ b/src/yiq/convertRgbToYiq.js
@@ -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;
+};
diff --git a/src/yiq/convertYiqToRgb.js b/src/yiq/convertYiqToRgb.js
new file mode 100644
index 00000000..d555363d
--- /dev/null
+++ b/src/yiq/convertYiqToRgb.js
@@ -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
+ });
diff --git a/src/yiq/definition.js b/src/yiq/definition.js
new file mode 100644
index 00000000..e94bd607
--- /dev/null
+++ b/src/yiq/definition.js
@@ -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())
+ }
+};
diff --git a/test/difference.js b/test/difference.js
index f2d05586..bfb3c4e5 100644
--- a/test/difference.js
+++ b/test/difference.js
@@ -6,6 +6,7 @@ let {
differenceCie94,
differenceCiede2000,
differenceCmc,
+ differenceKotsarenkoRamos,
rgb,
lab,
round
@@ -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 }),
@@ -130,3 +131,12 @@ tape('cmc difference', function(test) {
test.end();
});
+
+tape('differenceKotsarenkoRamos', function(test) {
+ test.equal(
+ differenceKotsarenkoRamos()('white', 'black'),
+ 0.7108445752103619
+ );
+
+ test.end();
+});
diff --git a/test/yiq.js b/test/yiq.js
new file mode 100644
index 00000000..d602c282
--- /dev/null
+++ b/test/yiq.js
@@ -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();
+});