diff options
Diffstat (limited to 'node_modules/color-convert')
| -rw-r--r-- | node_modules/color-convert/CHANGELOG.md | 54 | ||||
| -rw-r--r-- | node_modules/color-convert/LICENSE | 21 | ||||
| -rw-r--r-- | node_modules/color-convert/README.md | 68 | ||||
| -rw-r--r-- | node_modules/color-convert/conversions.js | 839 | ||||
| -rw-r--r-- | node_modules/color-convert/index.js | 81 | ||||
| -rw-r--r-- | node_modules/color-convert/package.json | 48 | ||||
| -rw-r--r-- | node_modules/color-convert/route.js | 97 | 
7 files changed, 1208 insertions, 0 deletions
diff --git a/node_modules/color-convert/CHANGELOG.md b/node_modules/color-convert/CHANGELOG.md new file mode 100644 index 0000000..0a7bce4 --- /dev/null +++ b/node_modules/color-convert/CHANGELOG.md @@ -0,0 +1,54 @@ +# 1.0.0 - 2016-01-07 + +- Removed: unused speed test +- Added: Automatic routing between previously unsupported conversions +([#27](https://github.com/Qix-/color-convert/pull/27)) +- Removed: `xxx2xxx()` and `xxx2xxxRaw()` functions +([#27](https://github.com/Qix-/color-convert/pull/27)) +- Removed: `convert()` class +([#27](https://github.com/Qix-/color-convert/pull/27)) +- Changed: all functions to lookup dictionary +([#27](https://github.com/Qix-/color-convert/pull/27)) +- Changed: `ansi` to `ansi256` +([#27](https://github.com/Qix-/color-convert/pull/27)) +- Fixed: argument grouping for functions requiring only one argument +([#27](https://github.com/Qix-/color-convert/pull/27)) + +# 0.6.0 - 2015-07-23 + +- Added: methods to handle +[ANSI](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) 16/256 colors: +  - rgb2ansi16 +  - rgb2ansi +  - hsl2ansi16 +  - hsl2ansi +  - hsv2ansi16 +  - hsv2ansi +  - hwb2ansi16 +  - hwb2ansi +  - cmyk2ansi16 +  - cmyk2ansi +  - keyword2ansi16 +  - keyword2ansi +  - ansi162rgb +  - ansi162hsl +  - ansi162hsv +  - ansi162hwb +  - ansi162cmyk +  - ansi162keyword +  - ansi2rgb +  - ansi2hsl +  - ansi2hsv +  - ansi2hwb +  - ansi2cmyk +  - ansi2keyword +([#18](https://github.com/harthur/color-convert/pull/18)) + +# 0.5.3 - 2015-06-02 + +- Fixed: hsl2hsv does not return `NaN` anymore when using `[0,0,0]` +([#15](https://github.com/harthur/color-convert/issues/15)) + +--- + +Check out commit logs for older releases diff --git a/node_modules/color-convert/LICENSE b/node_modules/color-convert/LICENSE new file mode 100644 index 0000000..5b4c386 --- /dev/null +++ b/node_modules/color-convert/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2011-2016 Heather Arthur <fayearthur@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/node_modules/color-convert/README.md b/node_modules/color-convert/README.md new file mode 100644 index 0000000..d4b08fc --- /dev/null +++ b/node_modules/color-convert/README.md @@ -0,0 +1,68 @@ +# color-convert + +[](https://travis-ci.org/Qix-/color-convert) + +Color-convert is a color conversion library for JavaScript and node. +It converts all ways between `rgb`, `hsl`, `hsv`, `hwb`, `cmyk`, `ansi`, `ansi16`, `hex` strings, and CSS `keyword`s (will round to closest): + +```js +var convert = require('color-convert'); + +convert.rgb.hsl(140, 200, 100);             // [96, 48, 59] +convert.keyword.rgb('blue');                // [0, 0, 255] + +var rgbChannels = convert.rgb.channels;     // 3 +var cmykChannels = convert.cmyk.channels;   // 4 +var ansiChannels = convert.ansi16.channels; // 1 +``` + +# Install + +```console +$ npm install color-convert +``` + +# API + +Simply get the property of the _from_ and _to_ conversion that you're looking for. + +All functions have a rounded and unrounded variant. By default, return values are rounded. To get the unrounded (raw) results, simply tack on `.raw` to the function. + +All 'from' functions have a hidden property called `.channels` that indicates the number of channels the function expects (not including alpha). + +```js +var convert = require('color-convert'); + +// Hex to LAB +convert.hex.lab('DEADBF');         // [ 76, 21, -2 ] +convert.hex.lab.raw('DEADBF');     // [ 75.56213190997677, 20.653827952644754, -2.290532499330533 ] + +// RGB to CMYK +convert.rgb.cmyk(167, 255, 4);     // [ 35, 0, 98, 0 ] +convert.rgb.cmyk.raw(167, 255, 4); // [ 34.509803921568626, 0, 98.43137254901961, 0 ] +``` + +### Arrays +All functions that accept multiple arguments also support passing an array. + +Note that this does **not** apply to functions that convert from a color that only requires one value (e.g. `keyword`, `ansi256`, `hex`, etc.) + +```js +var convert = require('color-convert'); + +convert.rgb.hex(123, 45, 67);      // '7B2D43' +convert.rgb.hex([123, 45, 67]);    // '7B2D43' +``` + +## Routing + +Conversions that don't have an _explicitly_ defined conversion (in [conversions.js](conversions.js)), but can be converted by means of sub-conversions (e.g. XYZ -> **RGB** -> CMYK), are automatically routed together. This allows just about any color model supported by `color-convert` to be converted to any other model, so long as a sub-conversion path exists. This is also true for conversions requiring more than one step in between (e.g. LCH -> **LAB** -> **XYZ** -> **RGB** -> Hex). + +Keep in mind that extensive conversions _may_ result in a loss of precision, and exist only to be complete. For a list of "direct" (single-step) conversions, see [conversions.js](conversions.js). + +# Contribute + +If there is a new model you would like to support, or want to add a direct conversion between two existing models, please send us a pull request. + +# License +Copyright © 2011-2016, Heather Arthur and Josh Junon. Licensed under the [MIT License](LICENSE). diff --git a/node_modules/color-convert/conversions.js b/node_modules/color-convert/conversions.js new file mode 100644 index 0000000..2657f26 --- /dev/null +++ b/node_modules/color-convert/conversions.js @@ -0,0 +1,839 @@ +/* MIT license */ +/* eslint-disable no-mixed-operators */ +const cssKeywords = require('color-name'); + +// NOTE: conversions should only return primitive values (i.e. arrays, or +//       values that give correct `typeof` results). +//       do not use box values types (i.e. Number(), String(), etc.) + +const reverseKeywords = {}; +for (const key of Object.keys(cssKeywords)) { +	reverseKeywords[cssKeywords[key]] = key; +} + +const convert = { +	rgb: {channels: 3, labels: 'rgb'}, +	hsl: {channels: 3, labels: 'hsl'}, +	hsv: {channels: 3, labels: 'hsv'}, +	hwb: {channels: 3, labels: 'hwb'}, +	cmyk: {channels: 4, labels: 'cmyk'}, +	xyz: {channels: 3, labels: 'xyz'}, +	lab: {channels: 3, labels: 'lab'}, +	lch: {channels: 3, labels: 'lch'}, +	hex: {channels: 1, labels: ['hex']}, +	keyword: {channels: 1, labels: ['keyword']}, +	ansi16: {channels: 1, labels: ['ansi16']}, +	ansi256: {channels: 1, labels: ['ansi256']}, +	hcg: {channels: 3, labels: ['h', 'c', 'g']}, +	apple: {channels: 3, labels: ['r16', 'g16', 'b16']}, +	gray: {channels: 1, labels: ['gray']} +}; + +module.exports = convert; + +// Hide .channels and .labels properties +for (const model of Object.keys(convert)) { +	if (!('channels' in convert[model])) { +		throw new Error('missing channels property: ' + model); +	} + +	if (!('labels' in convert[model])) { +		throw new Error('missing channel labels property: ' + model); +	} + +	if (convert[model].labels.length !== convert[model].channels) { +		throw new Error('channel and label counts mismatch: ' + model); +	} + +	const {channels, labels} = convert[model]; +	delete convert[model].channels; +	delete convert[model].labels; +	Object.defineProperty(convert[model], 'channels', {value: channels}); +	Object.defineProperty(convert[model], 'labels', {value: labels}); +} + +convert.rgb.hsl = function (rgb) { +	const r = rgb[0] / 255; +	const g = rgb[1] / 255; +	const b = rgb[2] / 255; +	const min = Math.min(r, g, b); +	const max = Math.max(r, g, b); +	const delta = max - min; +	let h; +	let s; + +	if (max === min) { +		h = 0; +	} else if (r === max) { +		h = (g - b) / delta; +	} else if (g === max) { +		h = 2 + (b - r) / delta; +	} else if (b === max) { +		h = 4 + (r - g) / delta; +	} + +	h = Math.min(h * 60, 360); + +	if (h < 0) { +		h += 360; +	} + +	const l = (min + max) / 2; + +	if (max === min) { +		s = 0; +	} else if (l <= 0.5) { +		s = delta / (max + min); +	} else { +		s = delta / (2 - max - min); +	} + +	return [h, s * 100, l * 100]; +}; + +convert.rgb.hsv = function (rgb) { +	let rdif; +	let gdif; +	let bdif; +	let h; +	let s; + +	const r = rgb[0] / 255; +	const g = rgb[1] / 255; +	const b = rgb[2] / 255; +	const v = Math.max(r, g, b); +	const diff = v - Math.min(r, g, b); +	const diffc = function (c) { +		return (v - c) / 6 / diff + 1 / 2; +	}; + +	if (diff === 0) { +		h = 0; +		s = 0; +	} else { +		s = diff / v; +		rdif = diffc(r); +		gdif = diffc(g); +		bdif = diffc(b); + +		if (r === v) { +			h = bdif - gdif; +		} else if (g === v) { +			h = (1 / 3) + rdif - bdif; +		} else if (b === v) { +			h = (2 / 3) + gdif - rdif; +		} + +		if (h < 0) { +			h += 1; +		} else if (h > 1) { +			h -= 1; +		} +	} + +	return [ +		h * 360, +		s * 100, +		v * 100 +	]; +}; + +convert.rgb.hwb = function (rgb) { +	const r = rgb[0]; +	const g = rgb[1]; +	let b = rgb[2]; +	const h = convert.rgb.hsl(rgb)[0]; +	const w = 1 / 255 * Math.min(r, Math.min(g, b)); + +	b = 1 - 1 / 255 * Math.max(r, Math.max(g, b)); + +	return [h, w * 100, b * 100]; +}; + +convert.rgb.cmyk = function (rgb) { +	const r = rgb[0] / 255; +	const g = rgb[1] / 255; +	const b = rgb[2] / 255; + +	const k = Math.min(1 - r, 1 - g, 1 - b); +	const c = (1 - r - k) / (1 - k) || 0; +	const m = (1 - g - k) / (1 - k) || 0; +	const y = (1 - b - k) / (1 - k) || 0; + +	return [c * 100, m * 100, y * 100, k * 100]; +}; + +function comparativeDistance(x, y) { +	/* +		See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance +	*/ +	return ( +		((x[0] - y[0]) ** 2) + +		((x[1] - y[1]) ** 2) + +		((x[2] - y[2]) ** 2) +	); +} + +convert.rgb.keyword = function (rgb) { +	const reversed = reverseKeywords[rgb]; +	if (reversed) { +		return reversed; +	} + +	let currentClosestDistance = Infinity; +	let currentClosestKeyword; + +	for (const keyword of Object.keys(cssKeywords)) { +		const value = cssKeywords[keyword]; + +		// Compute comparative distance +		const distance = comparativeDistance(rgb, value); + +		// Check if its less, if so set as closest +		if (distance < currentClosestDistance) { +			currentClosestDistance = distance; +			currentClosestKeyword = keyword; +		} +	} + +	return currentClosestKeyword; +}; + +convert.keyword.rgb = function (keyword) { +	return cssKeywords[keyword]; +}; + +convert.rgb.xyz = function (rgb) { +	let r = rgb[0] / 255; +	let g = rgb[1] / 255; +	let b = rgb[2] / 255; + +	// Assume sRGB +	r = r > 0.04045 ? (((r + 0.055) / 1.055) ** 2.4) : (r / 12.92); +	g = g > 0.04045 ? (((g + 0.055) / 1.055) ** 2.4) : (g / 12.92); +	b = b > 0.04045 ? (((b + 0.055) / 1.055) ** 2.4) : (b / 12.92); + +	const x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805); +	const y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722); +	const z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505); + +	return [x * 100, y * 100, z * 100]; +}; + +convert.rgb.lab = function (rgb) { +	const xyz = convert.rgb.xyz(rgb); +	let x = xyz[0]; +	let y = xyz[1]; +	let z = xyz[2]; + +	x /= 95.047; +	y /= 100; +	z /= 108.883; + +	x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116); +	y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116); +	z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116); + +	const l = (116 * y) - 16; +	const a = 500 * (x - y); +	const b = 200 * (y - z); + +	return [l, a, b]; +}; + +convert.hsl.rgb = function (hsl) { +	const h = hsl[0] / 360; +	const s = hsl[1] / 100; +	const l = hsl[2] / 100; +	let t2; +	let t3; +	let val; + +	if (s === 0) { +		val = l * 255; +		return [val, val, val]; +	} + +	if (l < 0.5) { +		t2 = l * (1 + s); +	} else { +		t2 = l + s - l * s; +	} + +	const t1 = 2 * l - t2; + +	const rgb = [0, 0, 0]; +	for (let i = 0; i < 3; i++) { +		t3 = h + 1 / 3 * -(i - 1); +		if (t3 < 0) { +			t3++; +		} + +		if (t3 > 1) { +			t3--; +		} + +		if (6 * t3 < 1) { +			val = t1 + (t2 - t1) * 6 * t3; +		} else if (2 * t3 < 1) { +			val = t2; +		} else if (3 * t3 < 2) { +			val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; +		} else { +			val = t1; +		} + +		rgb[i] = val * 255; +	} + +	return rgb; +}; + +convert.hsl.hsv = function (hsl) { +	const h = hsl[0]; +	let s = hsl[1] / 100; +	let l = hsl[2] / 100; +	let smin = s; +	const lmin = Math.max(l, 0.01); + +	l *= 2; +	s *= (l <= 1) ? l : 2 - l; +	smin *= lmin <= 1 ? lmin : 2 - lmin; +	const v = (l + s) / 2; +	const sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s); + +	return [h, sv * 100, v * 100]; +}; + +convert.hsv.rgb = function (hsv) { +	const h = hsv[0] / 60; +	const s = hsv[1] / 100; +	let v = hsv[2] / 100; +	const hi = Math.floor(h) % 6; + +	const f = h - Math.floor(h); +	const p = 255 * v * (1 - s); +	const q = 255 * v * (1 - (s * f)); +	const t = 255 * v * (1 - (s * (1 - f))); +	v *= 255; + +	switch (hi) { +		case 0: +			return [v, t, p]; +		case 1: +			return [q, v, p]; +		case 2: +			return [p, v, t]; +		case 3: +			return [p, q, v]; +		case 4: +			return [t, p, v]; +		case 5: +			return [v, p, q]; +	} +}; + +convert.hsv.hsl = function (hsv) { +	const h = hsv[0]; +	const s = hsv[1] / 100; +	const v = hsv[2] / 100; +	const vmin = Math.max(v, 0.01); +	let sl; +	let l; + +	l = (2 - s) * v; +	const lmin = (2 - s) * vmin; +	sl = s * vmin; +	sl /= (lmin <= 1) ? lmin : 2 - lmin; +	sl = sl || 0; +	l /= 2; + +	return [h, sl * 100, l * 100]; +}; + +// http://dev.w3.org/csswg/css-color/#hwb-to-rgb +convert.hwb.rgb = function (hwb) { +	const h = hwb[0] / 360; +	let wh = hwb[1] / 100; +	let bl = hwb[2] / 100; +	const ratio = wh + bl; +	let f; + +	// Wh + bl cant be > 1 +	if (ratio > 1) { +		wh /= ratio; +		bl /= ratio; +	} + +	const i = Math.floor(6 * h); +	const v = 1 - bl; +	f = 6 * h - i; + +	if ((i & 0x01) !== 0) { +		f = 1 - f; +	} + +	const n = wh + f * (v - wh); // Linear interpolation + +	let r; +	let g; +	let b; +	/* eslint-disable max-statements-per-line,no-multi-spaces */ +	switch (i) { +		default: +		case 6: +		case 0: r = v;  g = n;  b = wh; break; +		case 1: r = n;  g = v;  b = wh; break; +		case 2: r = wh; g = v;  b = n; break; +		case 3: r = wh; g = n;  b = v; break; +		case 4: r = n;  g = wh; b = v; break; +		case 5: r = v;  g = wh; b = n; break; +	} +	/* eslint-enable max-statements-per-line,no-multi-spaces */ + +	return [r * 255, g * 255, b * 255]; +}; + +convert.cmyk.rgb = function (cmyk) { +	const c = cmyk[0] / 100; +	const m = cmyk[1] / 100; +	const y = cmyk[2] / 100; +	const k = cmyk[3] / 100; + +	const r = 1 - Math.min(1, c * (1 - k) + k); +	const g = 1 - Math.min(1, m * (1 - k) + k); +	const b = 1 - Math.min(1, y * (1 - k) + k); + +	return [r * 255, g * 255, b * 255]; +}; + +convert.xyz.rgb = function (xyz) { +	const x = xyz[0] / 100; +	const y = xyz[1] / 100; +	const z = xyz[2] / 100; +	let r; +	let g; +	let b; + +	r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986); +	g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415); +	b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570); + +	// Assume sRGB +	r = r > 0.0031308 +		? ((1.055 * (r ** (1.0 / 2.4))) - 0.055) +		: r * 12.92; + +	g = g > 0.0031308 +		? ((1.055 * (g ** (1.0 / 2.4))) - 0.055) +		: g * 12.92; + +	b = b > 0.0031308 +		? ((1.055 * (b ** (1.0 / 2.4))) - 0.055) +		: b * 12.92; + +	r = Math.min(Math.max(0, r), 1); +	g = Math.min(Math.max(0, g), 1); +	b = Math.min(Math.max(0, b), 1); + +	return [r * 255, g * 255, b * 255]; +}; + +convert.xyz.lab = function (xyz) { +	let x = xyz[0]; +	let y = xyz[1]; +	let z = xyz[2]; + +	x /= 95.047; +	y /= 100; +	z /= 108.883; + +	x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116); +	y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116); +	z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116); + +	const l = (116 * y) - 16; +	const a = 500 * (x - y); +	const b = 200 * (y - z); + +	return [l, a, b]; +}; + +convert.lab.xyz = function (lab) { +	const l = lab[0]; +	const a = lab[1]; +	const b = lab[2]; +	let x; +	let y; +	let z; + +	y = (l + 16) / 116; +	x = a / 500 + y; +	z = y - b / 200; + +	const y2 = y ** 3; +	const x2 = x ** 3; +	const z2 = z ** 3; +	y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787; +	x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787; +	z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787; + +	x *= 95.047; +	y *= 100; +	z *= 108.883; + +	return [x, y, z]; +}; + +convert.lab.lch = function (lab) { +	const l = lab[0]; +	const a = lab[1]; +	const b = lab[2]; +	let h; + +	const hr = Math.atan2(b, a); +	h = hr * 360 / 2 / Math.PI; + +	if (h < 0) { +		h += 360; +	} + +	const c = Math.sqrt(a * a + b * b); + +	return [l, c, h]; +}; + +convert.lch.lab = function (lch) { +	const l = lch[0]; +	const c = lch[1]; +	const h = lch[2]; + +	const hr = h / 360 * 2 * Math.PI; +	const a = c * Math.cos(hr); +	const b = c * Math.sin(hr); + +	return [l, a, b]; +}; + +convert.rgb.ansi16 = function (args, saturation = null) { +	const [r, g, b] = args; +	let value = saturation === null ? convert.rgb.hsv(args)[2] : saturation; // Hsv -> ansi16 optimization + +	value = Math.round(value / 50); + +	if (value === 0) { +		return 30; +	} + +	let ansi = 30 +		+ ((Math.round(b / 255) << 2) +		| (Math.round(g / 255) << 1) +		| Math.round(r / 255)); + +	if (value === 2) { +		ansi += 60; +	} + +	return ansi; +}; + +convert.hsv.ansi16 = function (args) { +	// Optimization here; we already know the value and don't need to get +	// it converted for us. +	return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]); +}; + +convert.rgb.ansi256 = function (args) { +	const r = args[0]; +	const g = args[1]; +	const b = args[2]; + +	// We use the extended greyscale palette here, with the exception of +	// black and white. normal palette only has 4 greyscale shades. +	if (r === g && g === b) { +		if (r < 8) { +			return 16; +		} + +		if (r > 248) { +			return 231; +		} + +		return Math.round(((r - 8) / 247) * 24) + 232; +	} + +	const ansi = 16 +		+ (36 * Math.round(r / 255 * 5)) +		+ (6 * Math.round(g / 255 * 5)) +		+ Math.round(b / 255 * 5); + +	return ansi; +}; + +convert.ansi16.rgb = function (args) { +	let color = args % 10; + +	// Handle greyscale +	if (color === 0 || color === 7) { +		if (args > 50) { +			color += 3.5; +		} + +		color = color / 10.5 * 255; + +		return [color, color, color]; +	} + +	const mult = (~~(args > 50) + 1) * 0.5; +	const r = ((color & 1) * mult) * 255; +	const g = (((color >> 1) & 1) * mult) * 255; +	const b = (((color >> 2) & 1) * mult) * 255; + +	return [r, g, b]; +}; + +convert.ansi256.rgb = function (args) { +	// Handle greyscale +	if (args >= 232) { +		const c = (args - 232) * 10 + 8; +		return [c, c, c]; +	} + +	args -= 16; + +	let rem; +	const r = Math.floor(args / 36) / 5 * 255; +	const g = Math.floor((rem = args % 36) / 6) / 5 * 255; +	const b = (rem % 6) / 5 * 255; + +	return [r, g, b]; +}; + +convert.rgb.hex = function (args) { +	const integer = ((Math.round(args[0]) & 0xFF) << 16) +		+ ((Math.round(args[1]) & 0xFF) << 8) +		+ (Math.round(args[2]) & 0xFF); + +	const string = integer.toString(16).toUpperCase(); +	return '000000'.substring(string.length) + string; +}; + +convert.hex.rgb = function (args) { +	const match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i); +	if (!match) { +		return [0, 0, 0]; +	} + +	let colorString = match[0]; + +	if (match[0].length === 3) { +		colorString = colorString.split('').map(char => { +			return char + char; +		}).join(''); +	} + +	const integer = parseInt(colorString, 16); +	const r = (integer >> 16) & 0xFF; +	const g = (integer >> 8) & 0xFF; +	const b = integer & 0xFF; + +	return [r, g, b]; +}; + +convert.rgb.hcg = function (rgb) { +	const r = rgb[0] / 255; +	const g = rgb[1] / 255; +	const b = rgb[2] / 255; +	const max = Math.max(Math.max(r, g), b); +	const min = Math.min(Math.min(r, g), b); +	const chroma = (max - min); +	let grayscale; +	let hue; + +	if (chroma < 1) { +		grayscale = min / (1 - chroma); +	} else { +		grayscale = 0; +	} + +	if (chroma <= 0) { +		hue = 0; +	} else +	if (max === r) { +		hue = ((g - b) / chroma) % 6; +	} else +	if (max === g) { +		hue = 2 + (b - r) / chroma; +	} else { +		hue = 4 + (r - g) / chroma; +	} + +	hue /= 6; +	hue %= 1; + +	return [hue * 360, chroma * 100, grayscale * 100]; +}; + +convert.hsl.hcg = function (hsl) { +	const s = hsl[1] / 100; +	const l = hsl[2] / 100; + +	const c = l < 0.5 ? (2.0 * s * l) : (2.0 * s * (1.0 - l)); + +	let f = 0; +	if (c < 1.0) { +		f = (l - 0.5 * c) / (1.0 - c); +	} + +	return [hsl[0], c * 100, f * 100]; +}; + +convert.hsv.hcg = function (hsv) { +	const s = hsv[1] / 100; +	const v = hsv[2] / 100; + +	const c = s * v; +	let f = 0; + +	if (c < 1.0) { +		f = (v - c) / (1 - c); +	} + +	return [hsv[0], c * 100, f * 100]; +}; + +convert.hcg.rgb = function (hcg) { +	const h = hcg[0] / 360; +	const c = hcg[1] / 100; +	const g = hcg[2] / 100; + +	if (c === 0.0) { +		return [g * 255, g * 255, g * 255]; +	} + +	const pure = [0, 0, 0]; +	const hi = (h % 1) * 6; +	const v = hi % 1; +	const w = 1 - v; +	let mg = 0; + +	/* eslint-disable max-statements-per-line */ +	switch (Math.floor(hi)) { +		case 0: +			pure[0] = 1; pure[1] = v; pure[2] = 0; break; +		case 1: +			pure[0] = w; pure[1] = 1; pure[2] = 0; break; +		case 2: +			pure[0] = 0; pure[1] = 1; pure[2] = v; break; +		case 3: +			pure[0] = 0; pure[1] = w; pure[2] = 1; break; +		case 4: +			pure[0] = v; pure[1] = 0; pure[2] = 1; break; +		default: +			pure[0] = 1; pure[1] = 0; pure[2] = w; +	} +	/* eslint-enable max-statements-per-line */ + +	mg = (1.0 - c) * g; + +	return [ +		(c * pure[0] + mg) * 255, +		(c * pure[1] + mg) * 255, +		(c * pure[2] + mg) * 255 +	]; +}; + +convert.hcg.hsv = function (hcg) { +	const c = hcg[1] / 100; +	const g = hcg[2] / 100; + +	const v = c + g * (1.0 - c); +	let f = 0; + +	if (v > 0.0) { +		f = c / v; +	} + +	return [hcg[0], f * 100, v * 100]; +}; + +convert.hcg.hsl = function (hcg) { +	const c = hcg[1] / 100; +	const g = hcg[2] / 100; + +	const l = g * (1.0 - c) + 0.5 * c; +	let s = 0; + +	if (l > 0.0 && l < 0.5) { +		s = c / (2 * l); +	} else +	if (l >= 0.5 && l < 1.0) { +		s = c / (2 * (1 - l)); +	} + +	return [hcg[0], s * 100, l * 100]; +}; + +convert.hcg.hwb = function (hcg) { +	const c = hcg[1] / 100; +	const g = hcg[2] / 100; +	const v = c + g * (1.0 - c); +	return [hcg[0], (v - c) * 100, (1 - v) * 100]; +}; + +convert.hwb.hcg = function (hwb) { +	const w = hwb[1] / 100; +	const b = hwb[2] / 100; +	const v = 1 - b; +	const c = v - w; +	let g = 0; + +	if (c < 1) { +		g = (v - c) / (1 - c); +	} + +	return [hwb[0], c * 100, g * 100]; +}; + +convert.apple.rgb = function (apple) { +	return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255]; +}; + +convert.rgb.apple = function (rgb) { +	return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535]; +}; + +convert.gray.rgb = function (args) { +	return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255]; +}; + +convert.gray.hsl = function (args) { +	return [0, 0, args[0]]; +}; + +convert.gray.hsv = convert.gray.hsl; + +convert.gray.hwb = function (gray) { +	return [0, 100, gray[0]]; +}; + +convert.gray.cmyk = function (gray) { +	return [0, 0, 0, gray[0]]; +}; + +convert.gray.lab = function (gray) { +	return [gray[0], 0, 0]; +}; + +convert.gray.hex = function (gray) { +	const val = Math.round(gray[0] / 100 * 255) & 0xFF; +	const integer = (val << 16) + (val << 8) + val; + +	const string = integer.toString(16).toUpperCase(); +	return '000000'.substring(string.length) + string; +}; + +convert.rgb.gray = function (rgb) { +	const val = (rgb[0] + rgb[1] + rgb[2]) / 3; +	return [val / 255 * 100]; +}; diff --git a/node_modules/color-convert/index.js b/node_modules/color-convert/index.js new file mode 100644 index 0000000..b648e57 --- /dev/null +++ b/node_modules/color-convert/index.js @@ -0,0 +1,81 @@ +const conversions = require('./conversions'); +const route = require('./route'); + +const convert = {}; + +const models = Object.keys(conversions); + +function wrapRaw(fn) { +	const wrappedFn = function (...args) { +		const arg0 = args[0]; +		if (arg0 === undefined || arg0 === null) { +			return arg0; +		} + +		if (arg0.length > 1) { +			args = arg0; +		} + +		return fn(args); +	}; + +	// Preserve .conversion property if there is one +	if ('conversion' in fn) { +		wrappedFn.conversion = fn.conversion; +	} + +	return wrappedFn; +} + +function wrapRounded(fn) { +	const wrappedFn = function (...args) { +		const arg0 = args[0]; + +		if (arg0 === undefined || arg0 === null) { +			return arg0; +		} + +		if (arg0.length > 1) { +			args = arg0; +		} + +		const result = fn(args); + +		// We're assuming the result is an array here. +		// see notice in conversions.js; don't use box types +		// in conversion functions. +		if (typeof result === 'object') { +			for (let len = result.length, i = 0; i < len; i++) { +				result[i] = Math.round(result[i]); +			} +		} + +		return result; +	}; + +	// Preserve .conversion property if there is one +	if ('conversion' in fn) { +		wrappedFn.conversion = fn.conversion; +	} + +	return wrappedFn; +} + +models.forEach(fromModel => { +	convert[fromModel] = {}; + +	Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels}); +	Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels}); + +	const routes = route(fromModel); +	const routeModels = Object.keys(routes); + +	routeModels.forEach(toModel => { +		const fn = routes[toModel]; + +		convert[fromModel][toModel] = wrapRounded(fn); +		convert[fromModel][toModel].raw = wrapRaw(fn); +	}); +}); + +module.exports = convert; diff --git a/node_modules/color-convert/package.json b/node_modules/color-convert/package.json new file mode 100644 index 0000000..6e48000 --- /dev/null +++ b/node_modules/color-convert/package.json @@ -0,0 +1,48 @@ +{ +  "name": "color-convert", +  "description": "Plain color conversion functions", +  "version": "2.0.1", +  "author": "Heather Arthur <fayearthur@gmail.com>", +  "license": "MIT", +  "repository": "Qix-/color-convert", +  "scripts": { +    "pretest": "xo", +    "test": "node test/basic.js" +  }, +  "engines": { +    "node": ">=7.0.0" +  }, +  "keywords": [ +    "color", +    "colour", +    "convert", +    "converter", +    "conversion", +    "rgb", +    "hsl", +    "hsv", +    "hwb", +    "cmyk", +    "ansi", +    "ansi16" +  ], +  "files": [ +    "index.js", +    "conversions.js", +    "route.js" +  ], +  "xo": { +    "rules": { +      "default-case": 0, +      "no-inline-comments": 0, +      "operator-linebreak": 0 +    } +  }, +  "devDependencies": { +    "chalk": "^2.4.2", +    "xo": "^0.24.0" +  }, +  "dependencies": { +    "color-name": "~1.1.4" +  } +} diff --git a/node_modules/color-convert/route.js b/node_modules/color-convert/route.js new file mode 100644 index 0000000..1a08521 --- /dev/null +++ b/node_modules/color-convert/route.js @@ -0,0 +1,97 @@ +const conversions = require('./conversions'); + +/* +	This function routes a model to all other models. + +	all functions that are routed have a property `.conversion` attached +	to the returned synthetic function. This property is an array +	of strings, each with the steps in between the 'from' and 'to' +	color models (inclusive). + +	conversions that are not possible simply are not included. +*/ + +function buildGraph() { +	const graph = {}; +	// https://jsperf.com/object-keys-vs-for-in-with-closure/3 +	const models = Object.keys(conversions); + +	for (let len = models.length, i = 0; i < len; i++) { +		graph[models[i]] = { +			// http://jsperf.com/1-vs-infinity +			// micro-opt, but this is simple. +			distance: -1, +			parent: null +		}; +	} + +	return graph; +} + +// https://en.wikipedia.org/wiki/Breadth-first_search +function deriveBFS(fromModel) { +	const graph = buildGraph(); +	const queue = [fromModel]; // Unshift -> queue -> pop + +	graph[fromModel].distance = 0; + +	while (queue.length) { +		const current = queue.pop(); +		const adjacents = Object.keys(conversions[current]); + +		for (let len = adjacents.length, i = 0; i < len; i++) { +			const adjacent = adjacents[i]; +			const node = graph[adjacent]; + +			if (node.distance === -1) { +				node.distance = graph[current].distance + 1; +				node.parent = current; +				queue.unshift(adjacent); +			} +		} +	} + +	return graph; +} + +function link(from, to) { +	return function (args) { +		return to(from(args)); +	}; +} + +function wrapConversion(toModel, graph) { +	const path = [graph[toModel].parent, toModel]; +	let fn = conversions[graph[toModel].parent][toModel]; + +	let cur = graph[toModel].parent; +	while (graph[cur].parent) { +		path.unshift(graph[cur].parent); +		fn = link(conversions[graph[cur].parent][cur], fn); +		cur = graph[cur].parent; +	} + +	fn.conversion = path; +	return fn; +} + +module.exports = function (fromModel) { +	const graph = deriveBFS(fromModel); +	const conversion = {}; + +	const models = Object.keys(graph); +	for (let len = models.length, i = 0; i < len; i++) { +		const toModel = models[i]; +		const node = graph[toModel]; + +		if (node.parent === null) { +			// No possible conversion, or this node is the source model. +			continue; +		} + +		conversion[toModel] = wrapConversion(toModel, graph); +	} + +	return conversion; +}; +  | 
