├── .gitignore ├── .travis.yml ├── tea.yaml ├── package.json ├── .eslintrc.json ├── index.js ├── readme.md └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | -------------------------------------------------------------------------------- /tea.yaml: -------------------------------------------------------------------------------- 1 | # https://tea.xyz/what-is-this-file 2 | --- 3 | version: 1.0.0 4 | codeOwners: 5 | - '0x18CEa38f92a0E9b028ea27DD935B36A55Cf83b06' 6 | quorum: 1 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "color-normalize", 3 | "version": "2.0.0", 4 | "description": "Convert any color data to sanitized output format", 5 | "main": "index.js", 6 | "browser": "index.js", 7 | "module": "./index.js", 8 | "type": "module", 9 | "exports": { 10 | "import": "./index.js" 11 | }, 12 | "scripts": { 13 | "test": "node test.js" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/colorjs/color-normalize.git" 18 | }, 19 | "keywords": [ 20 | "color", 21 | "colorjs", 22 | "rgb", 23 | "rgba", 24 | "color-space", 25 | "css" 26 | ], 27 | "author": "Dmitry Yv ", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/colorjs/color-normalize/issues" 31 | }, 32 | "homepage": "https://github.com/colorjs/color-normalize#readme", 33 | "dependencies": { 34 | "color-rgba": "^3.0.0", 35 | "dtype": "^2.0.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "node": true, 5 | "commonjs": true, 6 | "es6": true 7 | }, 8 | "extends": "eslint:recommended", 9 | "rules": { 10 | "strict": 2, 11 | "indent": 0, 12 | "linebreak-style": 0, 13 | "quotes": 0, 14 | "semi": 0, 15 | "no-cond-assign": 1, 16 | "no-constant-condition": 1, 17 | "no-duplicate-case": 1, 18 | "no-empty": 1, 19 | "no-ex-assign": 1, 20 | "no-extra-boolean-cast": 1, 21 | "no-extra-semi": 1, 22 | "no-fallthrough": 1, 23 | "no-func-assign": 1, 24 | "no-global-assign": 1, 25 | "no-implicit-globals": 2, 26 | "no-inner-declarations": ["error", "functions"], 27 | "no-irregular-whitespace": 2, 28 | "no-loop-func": 1, 29 | "no-multi-str": 1, 30 | "no-mixed-spaces-and-tabs": 1, 31 | "no-proto": 1, 32 | "no-sequences": 1, 33 | "no-throw-literal": 1, 34 | "no-unmodified-loop-condition": 1, 35 | "no-useless-call": 1, 36 | "no-void": 1, 37 | "no-with": 2, 38 | "wrap-iife": 1, 39 | "no-redeclare": 1, 40 | "no-unused-vars": ["error", { "vars": "all", "args": "none" }], 41 | "no-sparse-arrays": 1 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** @module color-normalize */ 2 | import rgba from 'color-rgba' 3 | import dtype from 'dtype' 4 | 5 | export default function normalize(color, type) { 6 | if (type === 'float' || !type) type = 'array' 7 | else if (type === 'uint') type = 'uint8' 8 | else if (type === 'uint_clamped') type = 'uint8_clamped' 9 | 10 | var output = new (dtype(type))(4) 11 | var normalize = type !== 'uint8' && type !== 'uint8_clamped' 12 | 13 | // attempt to parse non-array arguments 14 | if (Object(color) !== color) { 15 | color = rgba(color) 16 | color[0] /= 255 17 | color[1] /= 255 18 | color[2] /= 255 19 | } 20 | 21 | // 0, 1 are possible contradictory values for Arrays: 22 | // [1,1,1] input gives [1,1,1] output instead of [1/255,1/255,1/255], which may be collision if input is meant to be uint. 23 | // converting [1,1,1] to [1/255,1/255,1/255] in case of float input gives larger mistake since [1,1,1] float is frequent edge value, whereas [0,1,1], [1,1,1] etc. uint inputs are relatively rare 24 | if (isInt(color)) { 25 | output[0] = color[0] 26 | output[1] = color[1] 27 | output[2] = color[2] 28 | output[3] = color[3] ?? 255 29 | 30 | if (normalize) { 31 | output[0] /= 255 32 | output[1] /= 255 33 | output[2] /= 255 34 | output[3] /= 255 35 | } 36 | 37 | return output 38 | } 39 | 40 | if (!normalize) { 41 | output[0] = Math.min(Math.max(color[0] * 255 | 0, 0), 255) 42 | output[1] = Math.min(Math.max(color[1] * 255 | 0, 0), 255) 43 | output[2] = Math.min(Math.max(color[2] * 255 | 0, 0), 255) 44 | output[3] = color[3] == null ? 255 : Math.min(Math.max(color[3] * 255 | 0, 0), 255) 45 | } else { 46 | output[0] = color[0] 47 | output[1] = color[1] 48 | output[2] = color[2] 49 | output[3] = color[3] ?? 1 50 | } 51 | 52 | return output 53 | } 54 | 55 | function isInt(color) { 56 | if (color instanceof Uint8Array || color instanceof Uint8ClampedArray) return true 57 | 58 | return Array.isArray(color) && 59 | (!color[0] || color[0] > 1) && 60 | (!color[1] || color[1] > 1) && 61 | (!color[2] || color[2] > 1) && 62 | (!color[3] || color[3] > 1) 63 | } 64 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # color-normalize [![Build Status](https://travis-ci.org/colorjs/color-normalize.png)](https://travis-ci.org/colorjs/color-normalize) [![size](https://img.shields.io/bundlephobia/minzip/color-normalize?label=size)](https://bundlephobia.com/result?p=color-normalize) ![stable](https://img.shields.io/badge/stability-stable-green) 2 | 3 | Convert any color argument (string, color, number, object etc.) to an array with channels data of desired output format. 4 | 5 | 6 | ## Usage 7 | 8 | [![npm install color-normalize](https://nodei.co/npm/color-normalize.png?mini=true)](https://npmjs.org/package/color-normalize/) 9 | 10 | ```js 11 | const rgba = require('color-normalize') 12 | 13 | rgba('red') // [1, 0, 0, 1] 14 | rgba('rgb(80, 120, 160)', 'uint8') // Uint8Array<[80, 120, 160, 255]> 15 | rgba('rgba(255, 255, 255, .5)', 'float64') // Float64Array<[1, 1, 1, .5]> 16 | rgba('hsla(109, 50%, 50%, .75)', 'uint8') // Uint8Array<[87, 191, 64, 191]> 17 | rgba(new Float32Array([0, 0.25, 0, 1]), 'uint8_clamped') // Uint8ClampedArray<[0, 64, 0, 255]> 18 | rgba(new Uint8Array([0, 72, 0, 255]), 'array') // [0, 0.2823529411764706, 0, 1] 19 | 20 | // ambivalent input 21 | rgba([0,0,0]) // [0,0,0] 22 | rgba([.5,.5,.5]) // [.5,.5,.5] 23 | rgba([1,1,1]) // [1,1,1] 24 | rgba([127,127,127]) // [.5,.5,.5] 25 | rgba([255,255,255]) // [1,1,1] 26 | ``` 27 | 28 | Output format can be any [dtype](https://npmjs.org/package/dtype): `uint8`, `uint8_clamped`, `array`, `float32`, `float64` etc. By default it converts to `array` with `0..1` range values. 29 | 30 | 31 | ## Related 32 | 33 | * [color-alpha](https://github.com/colorjs/color-alpha) − change alpha of a color string. 34 | * [color-interpolate](https://github.com/colorjs/color-interpolate) − interpolate by color palette. 35 | * [color-parse](https://github.com/colorjs/color-parse) − comprehensive color string parser. 36 | * [color-rgba](https://github.com/colorjs/color-rgba) − get rgba channel values from a string. 37 | * [flatten-vertex-data](https://npmjs.org/package/flatten-vertex-data) − ensure sequence of point coordinates is flat. 38 | 39 | ## License 40 | 41 | (c) 2017 Dmitry Iv. MIT License 42 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | import rgba from './index.js' 3 | 4 | assert.deepEqual(rgba('red'), [1, 0, 0, 1]) 5 | assert.deepEqual(rgba('rgb(80, 120, 160)', 'uint8'), new Uint8Array([80, 120, 160, 255])) 6 | assert.deepEqual(rgba('rgb(255, 255, 255, .5)', 'float64'), new Float64Array([1, 1, 1, .5])) 7 | assert.deepEqual(rgba('rgba(255, 255, 255, .5)', 'float64'), new Float64Array([1, 1, 1, .5])) 8 | assert.deepEqual(rgba('hsla(109, 50%, 50%, .75)', 'uint8'), new Uint8Array([87, 191, 63, 191])) 9 | assert.deepEqual(rgba(new Float32Array([0, 0.25, 0, 1]), 'uint8_clamped'), new Uint8ClampedArray([0, 63, 0, 255])) 10 | assert.deepEqual(rgba(new Uint8Array([0, 72, 0, 255]), 'array'), [0, 0.2823529411764706, 0, 1]) 11 | assert.deepEqual(rgba(new Uint8Array([0, 72, 0, 255]), 'uint8'), new Uint8Array([0, 72, 0, 255])) 12 | 13 | assert.deepEqual(rgba([0, 0, 0, 1]), [0, 0, 0, 1]) 14 | assert.deepEqual(rgba(0x00ff00), [0, 1, 0, 1]) 15 | 16 | assert.deepEqual(rgba(new Uint8Array([0, 72, 0]), 'uint8'), new Uint8Array([0, 72, 0, 255])) 17 | 18 | assert.deepEqual(rgba([127.5, 127.5, 127.5, 127.5]), [.5, .5, .5, .5]) 19 | assert.deepEqual(rgba([127, 127, 127, 127], 'uint8'), new Uint8Array([127, 127, 127, 127])) 20 | assert.deepEqual(rgba([.5, .5, .5, .5]), [.5, .5, .5, .5]) 21 | assert.deepEqual(rgba([.5, .5, .5, .5], 'uint8'), new Uint8Array([127, 127, 127, 127])) 22 | assert.deepEqual(rgba([0, 0, 0, 0]), [0, 0, 0, 0]) 23 | assert.deepEqual(rgba([0, 0, 0, 0], 'uint'), new Uint8Array([0, 0, 0, 0])) 24 | assert.deepEqual(rgba([0, 0, 0]), [0, 0, 0, 1]) 25 | assert.deepEqual(rgba([0, 0, 0], 'uint'), new Uint8Array([0, 0, 0, 255])) 26 | assert.deepEqual(rgba([0, 0, 1]), [0, 0, 1, 1]) 27 | assert.deepEqual(rgba([0, 0, 1], 'uint'), new Uint8Array([0, 0, 255, 255])) 28 | assert.deepEqual(rgba([1, 1, 1]), [1, 1, 1, 1]) 29 | assert.deepEqual(rgba([1, 1, 1], 'uint'), new Uint8Array([255, 255, 255, 255])) 30 | 31 | 32 | assert.deepEqual(rgba([0, 0, 0]), [0, 0, 0, 1]) 33 | // assert.deepEqual(rgba([.5,.5,.5]), [.5,.5,.5,1]) 34 | assert.deepEqual(rgba([1, 1, 1]), [1, 1, 1, 1]) 35 | assert.deepEqual(rgba([127.5, 127.5, 127.5]), [.5, .5, .5, 1]) 36 | assert.deepEqual(rgba([255, 255, 255]), [1, 1, 1, 1]) 37 | --------------------------------------------------------------------------------