├── .gitignore ├── package.json ├── Gruntfile.js ├── LICENSE ├── test ├── t1 │ └── test.html ├── t4 │ └── test.html ├── t3 │ └── test.html └── t2 │ └── test.html ├── README.md ├── ColorConverter.min.js ├── index.php └── ColorConverter.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ColorConverter", 3 | "version": "0.0.1", 4 | "private": true, 5 | "license": "MIT", 6 | "devDependencies": { 7 | "grunt": "~0.4.1", 8 | "grunt-contrib-jshint": "~0.6.3", 9 | "grunt-contrib-concat": "~0.3.0", 10 | "grunt-contrib-uglify": "~0.2.1", 11 | "grunt-contrib-copy": "~0.4.1", 12 | "grunt-contrib-clean": "~0.5.0", 13 | "grunt-contrib-watch": "~0.6.0", 14 | "inherits": "*" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | uglify: { 5 | "target": { 6 | "files": { 7 | './ColorConverter.min.js': [ 8 | './ColorConverter.js', 9 | ], 10 | } 11 | } 12 | }, 13 | watch: { 14 | options: { 15 | livereload: true 16 | }, 17 | javascript: { 18 | files: [ 19 | './*.js', 20 | ], 21 | tasks: [ 22 | 'uglify' 23 | ], 24 | options: { 25 | nospawn: true 26 | } 27 | }, 28 | } 29 | }); 30 | grunt.loadNpmTasks('grunt-contrib-watch'); 31 | grunt.loadNpmTasks('grunt-contrib-uglify'); 32 | 33 | grunt.registerTask('default', ['uglify','watch']); 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Rijn Bian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /test/t1/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ColorConverter.js 8 | 9 | 10 | 11 | 12 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /test/t4/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ColorConverter.js 8 | 9 | 10 | 11 | 12 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /test/t3/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ColorConverter.js 8 | 9 | 10 | 11 | 12 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /test/t2/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ColorConverter.js 8 | 9 | 10 | 11 | 12 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ColorConverter.js 2 | 3 | A JavaScript library that makes converting between color spaces. 4 | 5 | ## Demo 6 | 7 | [ColorConverter.js](http://lab.pixelnfinite.com/ColorConverter.js/) 8 | 9 | ## Getting Started 10 | 11 | import the js library. 12 | 13 | `` 14 | 15 | ## Color Conversions 16 | 17 | ### Initialization 18 | 19 | `var CC = new ColorConverter();` 20 | 21 | ### Import colors 22 | 23 | You can push colors through `import` method. 24 | 25 | ``` 26 | /* import a array of colors */ 27 | cc.import([ 28 | ["HSL", 180, 0.5, 0.1], 29 | ["RGB", 180, 50, 50], 30 | ["RGB", "ffffff"], 31 | ["CMYK", 0, 0, 0], 32 | ... 33 | ]); 34 | ``` 35 | 36 | CC will return a array of import result like: 37 | 38 | `[true, true, true, false, ...]` 39 | 40 | ### Export colors 41 | 42 | Export colors with a converted data. 43 | 44 | ``` 45 | CC.export("Lab"); // {L:0,a:0,b:0} 46 | CC.export("RGB",[0,1]); // {R:180,G:50,B:50},{R:180,G:50,B:50} 47 | CC.export("RGB",1,2); // {R:0,G:0,B:0},{R:0,G:0,B:0} 48 | ``` 49 | 50 | ### Reset colors 51 | 52 | delete the colors. 53 | 54 | ``` 55 | CC.reset(); // true 56 | ``` 57 | 58 | ## Extend function 59 | 60 | ### negate 61 | 62 | ``` 63 | function negate(_space, _color) { 64 | var cc = new ColorConverter(); 65 | cc.import([ 66 | [_space, _color], 67 | ]); 68 | var _rgb = cc.export("RGB")[0]; 69 | for (var i in _rgb) { 70 | if (_rgb.hasOwnProperty(i)) { 71 | _rgb[i] = 255 - _rgb[i]; 72 | } 73 | } 74 | cc.reset(); 75 | cc.import([ 76 | ["RGB", _rgb], 77 | ]); 78 | return cc.export(_space); 79 | }; 80 | 81 | console.log( 82 | negate("CMYK", { 83 | C: 0, 84 | M: 0.1, 85 | Y: 0.2, 86 | K: 0.3 87 | })[0] 88 | ); 89 | ``` 90 | 91 | ### lighten / darken 92 | 93 | ``` 94 | function lighten(_space, _color, _ratio) { 95 | var cc = new ColorConverter(); 96 | cc.import([ 97 | [_space, _color], 98 | ]); 99 | var _hsl = cc.export("HSL")[0]; 100 | _hsl.L += _hsl.L * _ratio; 101 | cc.reset(); 102 | cc.import([ 103 | ["HSL", _hsl], 104 | ]); 105 | return cc.export("RGB"); 106 | }; 107 | 108 | console.log( 109 | lighten("RGB", 110 | { 111 | R: 12, 112 | G: 34, 113 | B: 56, 114 | }, 115 | -0.5 /* if ratio < 0 it will be darken function */ 116 | )[0] 117 | ); 118 | ``` 119 | 120 | ### saturate / desaturate 121 | 122 | ``` 123 | function saturate(_space, _color, _ratio) { 124 | var cc = new ColorConverter(); 125 | cc.import([ 126 | [_space, _color], 127 | ]); 128 | var _hsl = cc.export("HSL")[0]; 129 | _hsl.S += _hsl.S * _ratio; 130 | cc.reset(); 131 | cc.import([ 132 | ["HSL", _hsl], 133 | ]); 134 | return cc.export("RGB"); 135 | }; 136 | 137 | console.log( 138 | saturate("RGB", 139 | { 140 | R: 12, 141 | G: 34, 142 | B: 56, 143 | }, 144 | -0.5 /* if ratio < 0 it will be desaturate function */ 145 | )[0] 146 | ); 147 | ``` 148 | 149 | ### rotate 150 | 151 | ``` 152 | function rotate(_space, _color, _degrees) { 153 | var cc = new ColorConverter(); 154 | cc.import([ 155 | [_space, _color], 156 | ]); 157 | var _hsl = cc.export("HSL")[0]; 158 | _hsl.H = (_hsl.H + _degrees) % 360; 159 | _hsl.H = _hsl.H < 0 ? 360 + _hsl.H : _hsl.H; 160 | cc.reset(); 161 | cc.import([ 162 | ["HSL", _hsl], 163 | ]); 164 | return cc.export(_space); 165 | }; 166 | 167 | console.log( 168 | rotate("CMYK", { 169 | C: 0, 170 | M: 0.1, 171 | Y: 0.2, 172 | K: 0.3 173 | }, 15)[0] 174 | ); 175 | ``` 176 | 177 | ## Currently Supported Color Spaces 178 | 179 | * RGB 180 | * RGBA => RGB 181 | * CMY 182 | * CMYK 183 | * HSV (HSB) 184 | * HSL 185 | * XYZ 186 | * Lab (CIELab) 187 | * LCH 188 | * LUV -------------------------------------------------------------------------------- /ColorConverter.min.js: -------------------------------------------------------------------------------- 1 | !function(window,document,undefined){"use strict";function ColorConverter(a){var b=this;if(b.colors=[],!(b instanceof ColorConverter))return new ColorConverter(a);b.options=a||{};for(var c in defaults)null==b.options[c]&&(b.options[c]=defaults[c]);b.options.colors&&b["import"](b.options.colors)}Array.prototype.forEach=function(a,b){var c=this.length,b=arguments[1];if("function"!=typeof a)throw Error("unknown function");for(var d=0;c>d;d++)a.call(b,this[d],d,this)},Array.prototype.getLast=function(){return this instanceof Array?this[this.length-1]:!1},Array.prototype.search=function(a){if(this instanceof Array){var b=[];for(var c in this)this[c]==a&&b.push(c);var d=b.length;return 0==d?!1:1==d?b[0]:b}return!1};var cloneObject=function(a){if("object"!=typeof a)return a;if(null==a)return a;var b=a instanceof Array?new Array:new Object;for(var c in a)b[c]=cloneObject(a[c]);return b};Object.prototype.check=function(){if("object"!=typeof this)return!1;for(var a=flatten(arguments),b=0;b=0},d=function(a){return"[object Array]"===toString.call(a)},e=function(a){return b(a,"callee")},f=[],g=0,h=0,i=a&&a.length;i>h;h++){var j=a[h];if(c(j)&&(d(j)||e(j))){j=flatten(j);var k=0,l=j.length;for(f.length+=l;l>k;)f[g++]=j[k++]}else f[g++]=j}return f},min=function(){for(var a=flatten([arguments]),b=a[0],c=0;ca[c]&&(b=a[c]);return b},max=function(){for(var a=flatten([arguments]),b=a[0],c=0;c=d?c:d,Number(((a*e-b*e)/e).toFixed(f))}},spaces={constant:{Epsilon:216/24389,Kappa:24389/27,XYZ_WhiteRefrence:{X:95.047,Y:100,Z:108.883},CubicRoot:function(a){return Math.pow(a,1/3)}},RGB:{"import":function(){var a=flatten(arguments),b=[];if(console.log(a),a[0].check("R","G","B"))return{RGB:a[0]};if(a.length<3){var c=/([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/,d=a[0].toLowerCase();if(!d||!c.test(d))return!1;if(d=c.exec(d)[0],3===d.length){for(var e="",f=0;3>f;f+=1)e+=d.slice(f,f+1).concat(d.slice(f,f+1));d=e}for(var b=[],f=0;6>f;f+=2)b.push(parseInt("0x"+d.slice(f,f+2)))}else for(var f=0;3>f;f++)b[f]=Number(a[f]);for(var f in b){if(b[f]<0)return!1;if(b[f]>255)return!1}return{RGB:{R:b[0],G:b[1],B:b[2]}}},XYZ:{convert:function(a){function b(a){return 100*(a>.04045?Math.pow((a+.055)/1.055,2.4):a/12.92)}return a.R=b(a.R/255),a.G=b(a.G/255),a.B=b(a.B/255),{X:.412453*a.R+.35758*a.G+.180423*a.B,Y:.212671*a.R+.71516*a.G+.072169*a.B,Z:.019334*a.R+.119193*a.G+.950227*a.B}},cost:1},CMY:{convert:function(a){var b,c,d;return b=(255-a.R)/255,c=(255-a.G)/255,d=(255-a.B)/255,{C:b,M:c,Y:d}},cost:0},CMYK:{convert:function(a){var b,c,d,e;return e=0,b=(255-a.R)/255,c=(255-a.G)/255,d=(255-a.B)/255,e=min([b,c,d]),1==e?b=c=d=0:(b=(b-e)/(1-e),c=(c-e)/(1-e),d=(d-e)/(1-e)),{C:b,M:c,Y:d,K:e}},cost:0},HSL:{convert:function(a){var b,c,d,e,f,g=a.R/255,h=a.G/255,i=a.B/255,j=min(g,h,i),k=max(g,h,i),l=k-j,m=(k+j)/2;return 0==l?(e=0,f=0):(f=.5>m?l/(k+j):l/(2-k-j),b=((k-g)/6+l/2)/l,c=((k-h)/6+l/2)/l,d=((k-i)/6+l/2)/l,g==k?e=d-c:h==k?e=1/3+b-d:i==k&&(e=2/3+c-b),0>e&&(e+=1),e>1&&(e-=1)),{H:360*e,S:f,L:m}},cost:0},HSV:{convert:function(a){var b,c,d,e=a.R/255,f=a.G/255,g=a.B/255,h=min(e,f,g),i=max(e,f,g);if(h==i)return d=h,{H:0,S:0,V:d};var j=e==h?f-g:g==h?e-f:g-e,k=e==h?3:g==h?1:5;return b=60*(k-j/(i-h)),c=(i-h)/i,d=i,{H:b,S:c,V:d}},cost:0}},CMY:{"import":function(){var a=flatten(arguments);if(a[0].check("C","M","Y"))return{CMY:a[0]};if(a.length<3)return!1;for(var b=0;3>b;b++)if(a[b]<0||a[b]>1)return!1;return{CMY:{C:a[0],M:a[1],Y:a[2]}}},RGB:{convert:function(a){var b,c,d;return b=255*(1-a.C),c=255*(1-a.M),d=255*(1-a.Y),{R:b,G:c,B:d}},cost:0}},RGBA:{"import":function(){var a=flatten(arguments);if(a[0].check("R","G","B","A"))return{RGBA:a[0]};if(a.length<7)return!1;for(var b=0;7>b;b++)if(a[b]<0||a[b]>255)return!1;return a[3]>1?!1:{RGBA:{FR:a[0],FG:a[1],FB:a[2],Alpha:a[3],BR:a[4],BG:a[5],BB:a[6]}}},RGB:{convert:function(a){return{R:(1-a.Alpha)*a.BR+a.Alpha*a.FR,G:(1-a.Alpha)*a.BG+a.Alpha*a.FG,B:(1-a.Alpha)*a.BB+a.Alpha*a.FB}},cost:1}},CMYK:{"import":function(){var a=flatten(arguments);if(a[0].check("C","M","Y","K"))return{CMYK:a[0]};if(a.length<4)return!1;for(var b=0;4>b;b++)if(a[b]<0||a[b]>1)return!1;return{CMYK:{C:a[0],M:a[1],Y:a[2],K:a[3]}}},RGB:{convert:function(a){var b,c,d;return b=(1-a.K)*(1-a.C)*255,c=(1-a.K)*(1-a.M)*255,d=(1-a.K)*(1-a.Y)*255,{R:b,G:c,B:d}},cost:0}},HSL:{"import":function(){var a=flatten(arguments);return a[0].check("H","S","L")?{HSL:a[0]}:a.length<3?!1:a[0]<0||a[0]>360||a[1]<0||a[2]<0||a[1]>1||a[2]>1?!1:{HSL:{H:a[0],S:a[1],L:a[2]}}},RGB:{convert:function(a){var b,c,d,e=a.H,f=a.S,g=a.L,h=acc.mul(acc.sub(1,Math.abs(acc.sub(acc.mul(2,g),1))),f),i=e/60,j=acc.mul(h,1-Math.abs(i%2-1)),k=parseInt(i),l=acc.sub(g,acc.div(h,2));switch(k){case 0:b=h,c=j,d=0;break;case 1:b=j,c=h,d=0;break;case 2:b=0,c=h,d=j;break;case 3:b=0,c=j,d=h;break;case 4:b=j,c=0,d=h;break;case 5:b=h,c=0,d=j}return b=acc.add(b,l),c=acc.add(c,l),d=acc.add(d,l),{R:255*b,G:255*c,B:255*d}},cost:0}},HSV:{"import":function(){var a=flatten(arguments);return a[0].check("H","S","L")?{HSL:a[0]}:a.length<3?!1:a[0]<0||a[0]>360||a[1]<0||a[2]<0||a[1]>1||a[2]>1?!1:{HSV:{H:a[0],S:a[1],V:a[2]}}},RGB:{convert:function(a){var b,c,d,e=a.H,f=a.S,g=a.V,h=g*f,i=e/60,j=h*(1-Math.abs(i%2-1)),k=parseInt(i),l=g-h;switch(k){case 0:b=h,c=j,d=0;break;case 1:b=j,c=h,d=0;break;case 2:b=0,c=h,d=j;break;case 3:b=0,c=j,d=h;break;case 4:b=j,c=0,d=h;break;case 5:b=h,c=0,d=j}return b+=l,c+=l,d+=l,{R:255*b,G:255*c,B:255*d}},cost:0}},XYZ:{"import":function(){var a=flatten(arguments);return a[0].check("X","Y","Z")?{XYZ:a[0]}:a.length<3?!1:{XYZ:{X:a[0],Y:a[1],Z:a[2]}}},RGB:{convert:function(a){function b(a){var b=255*a;return 0>b?0:b>255?255:b}var c=a.X/100,d=a.Y/100,e=a.Z/100,f=3.2406*c+-1.5372*d+e*-.4986,g=c*-.9689+1.8758*d+.0415*e,h=.0557*c+d*-.204+1.057*e;return f=f>.0031308?1.055*Math.pow(f,1/2.4)-.055:12.92*f,g=g>.0031308?1.055*Math.pow(g,1/2.4)-.055:12.92*g,h=h>.0031308?1.055*Math.pow(h,1/2.4)-.055:12.92*h,{R:b(f),G:b(g),B:b(h)}},cost:1},Lab:{convert:function(a){function b(a){return a>spaces.constant.Epsilon?spaces.constant.CubicRoot(a):(spaces.constant.Kappa*a+16)/116}var c=spaces.constant.XYZ_WhiteRefrence,d=b(a.X/c.X),e=b(a.Y/c.Y),f=b(a.Z/c.Z);return{L:Math.max(0,116*e-16),a:500*(d-e),b:200*(e-f)}},cost:1},LUV:{convert:function(a){function b(a){return a.X+15*a.Y+3*a.Z}var c=spaces.constant.XYZ_WhiteRefrence,d=a.Y/c.Y,e=d>spaces.constant.Epsilon?116*spaces.constant.CubicRoot(d)-16:spaces.constant.Kappa*d,f=b(a),g=b(c),h=0==f?0:4*a.X/f-4*c.X/g,i=0==f?0:9*a.Y/f-9*c.Y/g,j=13*e*h,k=13*e*i;return{L:e,U:j,V:k}},cost:1}},Lab:{"import":function(){var a=flatten(arguments);return a[0].check("L","a","b")?{Lab:a[0]}:a.length<3?!1:{Lab:{L:a[0],a:a[1],b:a[2]}}},XYZ:{convert:function(a){var b=(a.L+16)/116,c=a.a/500+b,d=b-a.b/200,e=spaces.constant.XYZ_WhiteRefrence,f=c*c*c,g=d*d*d;return{X:e.X*(f>spaces.constant.Epsilon?f:(c-16/116)/7.787),Y:e.Y*(a.L>spaces.constant.Kappa*spaces.constant.Epsilon?Math.pow((a.L+16)/116,3):a.L/spaces.constant.Kappa),Z:e.Z*(g>spaces.constant.Epsilon?g:(d-16/116)/7.787)}},cost:1},LCH:{convert:function(a){var b=Math.atan2(a.b,a.a);return b=b>0?b/Math.PI*180:360-Math.abs(b)/Math.PI*180,0>b?b+=360:b>=360&&(b-=360),{L:a.L,C:Math.sqrt(a.a*a.a+a.b*a.b),H:b}},cost:1}},LCH:{"import":function(){var a=flatten(arguments);return a[0].check("L","C","H")?{LCH:a[0]}:a.length<3?!1:{LCH:{L:a[0],C:a[1],H:a[2]}}},Lab:{convert:function(a){var b=a.H*Math.PI/180;return{L:a.L,a:Math.cos(b)*a.C,b:Math.sin(b)*a.C}},cost:1}},LUV:{"import":function(){var a=flatten(arguments);return a[0].check("L","U","V")?{LUV:a[0]}:a.length<3?!1:{LUV:{L:a[0],U:a[1],V:a[2]}}},XYZ:{convert:function(a){function b(a){return a.X+15*a.Y+3*a.Z}var c=spaces.constant.XYZ_WhiteRefrence,d=-1/3,e=4*c.X/b(c),f=9*c.Y/b(c),g=1/3*(52*a.L/(a.U+13*a.L*e)-1),h=(a.L+16)/116,i=a.L>spaces.constant.Kappa*spaces.constant.Epsilon?h*h*h:a.L/spaces.constant.Kappa,j=-5*i,k=i*(39*a.L/(a.V+13*a.L*f)-5),l=(k-j)/(g-d),m=l*g+j;return{X:100*l,Y:100*i,Z:100*m}},cost:1}}},defaults={colors:[]};ColorConverter.prototype={constructor:ColorConverter,"import":function(){for(var argu=Array.prototype.slice.call(arguments)[0],output=[],self=this,i=0;i_depth;){var _deplicate=[];for(var key in _tokens)if(_tokens.hasOwnProperty(key)){var _on=_tokens[key],_nowkey=_on._path.getLast();if(spaces.hasOwnProperty(_nowkey)){var _obj=eval("(spaces."+_nowkey+")");for(var key in _obj)if(_obj.hasOwnProperty(key)){var _temp=cloneObject(_on);_on._path.search(key)||_on._path.getLast()==_target?_temp._terminal=!0:(_temp._path.push(key),_temp._cost+=eval("(spaces."+_nowkey+"."+key+".cost)")),_deplicate.push(_temp)}_obj=null}}_tokens=_deplicate,_deplicate=null,_depth++}if(!_tokens.length)throw Error("No path to target");var _sort=[];for(var key in _tokens)_tokens.hasOwnProperty(key)&&_tokens[key]&&_tokens[key]._path.getLast()==_target&&_sort.push(_tokens[key]);if(_sort.sort(function(a,b){return a.cost>b.cost?-1:1}),_sort.length){for(var _rp=_sort[0]._path,_temp=eval("(_code."+_rp[0]+")"),i=1;i<_rp.length;i++)_temp=eval("(spaces."+_rp[i-1]+"."+_rp[i]+".convert("+JSON.stringify(_temp)+"))");output.push(_temp)}}),output},reset:function(){var a=this;return a.colors=[],!0}},window.ColorConverter=ColorConverter}(window,document); -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ColorConverter.js - pixelnfinite 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | 213 | 214 | 215 | 216 | 217 |
218 | 221 | A JavaScript library that makes converting between color spaces. 222 |
223 |
224 | 227 |
228 |
229 |
230 |
{{space.name}} {{space.remark||""}}
231 |
232 |
233 |
234 | 235 |
236 |
{{para.key}}
237 | 238 |
{{para.res}}
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 | 251 |

Include ColorConverter.js to your page.

252 |
<script src="ColorConverter.min.js"></script>
253 |
254 | 255 |
256 | 259 |

Initialization

260 |
var CC = new ColorConverter();
261 | 262 |

Import colors

263 |

You can push colors through import method.

264 |
/* import a array of colors */
265 | cc.import([
266 |     ["HSL", 180, 0.5, 0.1],
267 |     ["RGB", 180, 50, 50],
268 |     ["RGB", "ffffff"],
269 |     ["CMYK", 0, 0, 0],
270 |     ...
271 | ]);
272 |

CC will return a array of import result like

273 |
[true, true, true, false, ...]
274 | 275 |

Export colors

276 |

Export colors with a converted data.

277 |
CC.export("Lab");         // {L:0,a:0,b:0}
278 | CC.export("RGB",[0,1]);   // {R:180,G:50,B:50},{R:180,G:50,B:50}
279 | CC.export("RGB",1,2);     // {R:0,G:0,B:0},{R:0,G:0,B:0}
280 | 281 |

Reset colors

282 |

delete the colors.

283 |
CC.reset();        // true
284 | 285 |
286 | 287 |
288 | 291 | 292 |

negate

293 |
function negate(_space, _color) {
294 |     var cc = new ColorConverter();
295 |     cc.import([
296 |         [_space, _color],
297 |     ]);
298 |     var _rgb = cc.export("RGB")[0];
299 |     for (var i in _rgb) {
300 |         if (_rgb.hasOwnProperty(i)) {
301 |             _rgb[i] = 255 - _rgb[i];
302 |         }
303 |     }
304 |     cc.reset();
305 |     cc.import([
306 |         ["RGB", _rgb],
307 |     ]);
308 |     return cc.export(_space);
309 | };
310 | 
311 | console.log(
312 |     negate("CMYK", {
313 |         C: 0,
314 |         M: 0.1,
315 |         Y: 0.2,
316 |         K: 0.3
317 |     })[0]
318 | );
319 | 320 |

lighten / darken

321 |
function lighten(_space, _color, _ratio) {
322 |     var cc = new ColorConverter();
323 |     cc.import([
324 |         [_space, _color],
325 |     ]);
326 |     var _hsl = cc.export("HSL")[0];
327 |     _hsl.L += _hsl.L * _ratio;
328 |     cc.reset();
329 |     cc.import([
330 |         ["HSL", _hsl],
331 |     ]);
332 |     return cc.export("RGB");
333 | };
334 | 
335 | console.log(
336 |     lighten("RGB",
337 |         {
338 |             R: 12,
339 |             G: 34,
340 |             B: 56,
341 |         },
342 |         -0.5  /* if ratio < 0 it will be darken function */
343 |     )[0]
344 | );
345 | 346 |

saturate / desaturate

347 |
function saturate(_space, _color, _ratio) {
348 |     var cc = new ColorConverter();
349 |     cc.import([
350 |         [_space, _color],
351 |     ]);
352 |     var _hsl = cc.export("HSL")[0];
353 |     _hsl.S += _hsl.S * _ratio;
354 |     cc.reset();
355 |     cc.import([
356 |         ["HSL", _hsl],
357 |     ]);
358 |     return cc.export("RGB");
359 | };
360 | 
361 | console.log(
362 |     saturate("RGB",
363 |         {
364 |             R: 12,
365 |             G: 34,
366 |             B: 56,
367 |         },
368 |         -0.5  /* if ratio < 0 it will be desaturate function */
369 |     )[0]
370 | );
371 | 372 |

rotate

373 |
function rotate(_space, _color, _degrees) {
374 |     var cc = new ColorConverter();
375 |     cc.import([
376 |         [_space, _color],
377 |     ]);
378 |     var _hsl = cc.export("HSL")[0];
379 |     _hsl.H = (_hsl.H + _degrees) % 360;
380 |     _hsl.H = _hsl.H < 0 ? 360 + _hsl.H : _hsl.H;
381 |     cc.reset();
382 |     cc.import([
383 |         ["HSL", _hsl],
384 |     ]);
385 |     return cc.export(_space);
386 | };
387 | 
388 | console.log(
389 |     rotate("CMYK", {
390 |         C: 0,
391 |         M: 0.1,
392 |         Y: 0.2,
393 |         K: 0.3
394 |     }, 15)[0]
395 | );
396 |
397 | 398 |
399 | 402 |
* RGB
403 | * RGBA => RGB
404 | * CMY
405 | * CMYK
406 | * HSV (HSB)
407 | * HSL
408 | * XYZ
409 | * Lab (CIELab)
410 | * LCH
411 | * LUV
412 |
413 | 414 | 415 | 416 |
417 | 420 |

Code and documentation copyright 2015 Rijn, pixelnfinite.com.

421 |

Code released under the MIT license.

422 |
423 |
424 | 427 |
428 | 429 | 430 | 431 | -------------------------------------------------------------------------------- /ColorConverter.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Color Converter 3 | * @author Rijn 4 | */ 5 | 6 | ; 7 | (function(window, document, undefined) { 8 | "use strict"; 9 | 10 | /* Rewrite foreach method to support ie */ 11 | Array.prototype.forEach = function(fun, context) { 12 | var len = this.length, 13 | context = arguments[1]; 14 | if (typeof fun !== "function") { 15 | throw Error("unknown function"); 16 | } 17 | for (var i = 0; i < len; i++) { 18 | fun.call(context, this[i], i, this); 19 | } 20 | }; 21 | /* Get the last element from Array */ 22 | Array.prototype.getLast = function() { 23 | return this instanceof Array ? this[this.length - 1] : false; 24 | }; 25 | /* Serach object form Array */ 26 | Array.prototype.search = function(str) { 27 | if (this instanceof Array) { 28 | var found = []; 29 | for (var i in this) { 30 | if (this[i] == str) { 31 | found.push(i); 32 | } 33 | } 34 | var num = found.length; 35 | if (num == 0) return false; 36 | if (num == 1) return found[0]; 37 | return found; 38 | } else { 39 | return false; 40 | } 41 | }; 42 | /* Deep copy Object */ 43 | var cloneObject = function(oldObj) { 44 | if (typeof(oldObj) != 'object') return oldObj; 45 | if (oldObj == null) return oldObj; 46 | var newObj = oldObj instanceof Array ? new Array() : new Object(); 47 | for (var i in oldObj) 48 | newObj[i] = cloneObject(oldObj[i]); 49 | return newObj; 50 | }; 51 | /* Check property */ 52 | Object.prototype.check = function() { 53 | if (typeof this !== 'object') return false; 54 | var argu = flatten(arguments); 55 | for (var i = 0; i < argu.length; i++) { 56 | if (!this.hasOwnProperty(argu[i])) { 57 | return false; 58 | } 59 | }; 60 | return true; 61 | }; 62 | 63 | /* Flatten function */ 64 | var flatten = function(input) { 65 | var has = function(obj, key) { 66 | return obj != null && hasOwnProperty.call(obj, key); 67 | }, 68 | isArrayLike = function(collection) { 69 | var length = collection && collection.length; 70 | return typeof length == 'number' && length >= 0; 71 | }, 72 | /* if obj is array */ 73 | isArray = function(obj) { 74 | return toString.call(obj) === '[object Array]'; 75 | }, 76 | /* if obj is arguments*/ 77 | isArguments = function(obj) { 78 | return has(obj, 'callee'); 79 | }, 80 | output = [], 81 | idx = 0; 82 | /* flatten function from underscore */ 83 | for (var i = 0, length = input && input.length; i < length; i++) { 84 | var value = input[i]; 85 | if (isArrayLike(value) && (isArray(value) || isArguments(value))) { 86 | value = flatten(value); 87 | var j = 0, 88 | len = value.length; 89 | output.length += len; 90 | while (j < len) { 91 | output[idx++] = value[j++]; 92 | } 93 | } else { 94 | output[idx++] = value; 95 | } 96 | } 97 | return output; 98 | }, 99 | /* find the minimum or maximum element */ 100 | min = function() { 101 | var _input = flatten([arguments]), 102 | tempVal = _input[0]; 103 | for (var i = 0; i < _input.length; i++) { 104 | if (tempVal > _input[i]) { 105 | tempVal = _input[i]; 106 | } 107 | } 108 | return tempVal; 109 | }, 110 | max = function() { 111 | var _input = flatten([arguments]), 112 | tempVal = _input[0]; 113 | for (var i = 0; i < _input.length; i++) { 114 | if (tempVal < _input[i]) { 115 | tempVal = _input[i]; 116 | } 117 | } 118 | return tempVal; 119 | }, 120 | /* AccOperation for Float */ 121 | acc = { 122 | div: function(arg1, arg2) { 123 | var t1 = 0, 124 | t2 = 0, 125 | r1, r2; 126 | try { 127 | t1 = arg1.toString().split(".")[1].length 128 | } catch (e) {} 129 | try { 130 | t2 = arg2.toString().split(".")[1].length 131 | } catch (e) {} 132 | 133 | r1 = Number(arg1.toString().replace(".", "")) 134 | r2 = Number(arg2.toString().replace(".", "")) 135 | return acc.mul((r1 / r2), Math.pow(10, t2 - t1)); 136 | 137 | }, 138 | mul: function(arg1, arg2) { 139 | var m = 0, 140 | s1 = arg1.toString(), 141 | s2 = arg2.toString(); 142 | try { 143 | m += s1.split(".")[1].length 144 | } catch (e) {} 145 | try { 146 | m += s2.split(".")[1].length 147 | } catch (e) {} 148 | return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m) 149 | }, 150 | add: function(arg1, arg2) { 151 | var r1, r2, m; 152 | try { 153 | r1 = arg1.toString().split(".")[1].length 154 | } catch (e) { 155 | r1 = 0 156 | } 157 | try { 158 | r2 = arg2.toString().split(".")[1].length 159 | } catch (e) { 160 | r2 = 0 161 | } 162 | m = Math.pow(10, Math.max(r1, r2)) 163 | return Number((arg1 * m + arg2 * m) / m); 164 | }, 165 | sub: function(arg1, arg2) { 166 | var r1, r2, m, n; 167 | try { 168 | r1 = arg1.toString().split(".")[1].length 169 | } catch (e) { 170 | r1 = 0 171 | } 172 | try { 173 | r2 = arg2.toString().split(".")[1].length 174 | } catch (e) { 175 | r2 = 0 176 | } 177 | m = Math.pow(10, Math.max(r1, r2)); 178 | n = (r1 >= r2) ? r1 : r2; 179 | return Number(((arg1 * m - arg2 * m) / m).toFixed(n)); 180 | } 181 | }, 182 | /* Color spaces defination */ 183 | spaces = { 184 | constant: { 185 | Epsilon: 216 / 24389, 186 | Kappa: 24389 / 27, 187 | XYZ_WhiteRefrence: { 188 | X: 95.047, 189 | Y: 100.000, 190 | Z: 108.883, 191 | }, 192 | CubicRoot: function(n) { 193 | return Math.pow(n, 1.0 / 3.0); 194 | }, 195 | }, 196 | RGB: { 197 | import: function() { 198 | var input = flatten(arguments), 199 | rgbColor = []; 200 | 201 | console.log(input); 202 | 203 | if (input[0].check("R", "G", "B")) { 204 | return { 205 | RGB: input[0], 206 | }; 207 | }; 208 | 209 | if (input.length < 3) { 210 | var reg = /([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/; 211 | var sColor = input[0].toLowerCase(); 212 | if (sColor && reg.test(sColor)) { 213 | sColor = reg.exec(sColor)[0]; 214 | if (sColor.length === 3) { 215 | var sColorNew = ""; 216 | for (var i = 0; i < 3; i += 1) { 217 | sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1)); 218 | } 219 | sColor = sColorNew; 220 | } 221 | var rgbColor = []; 222 | for (var i = 0; i < 6; i += 2) { 223 | rgbColor.push(parseInt("0x" + sColor.slice(i, i + 2))); 224 | } 225 | } else { 226 | return false; 227 | } 228 | } else { 229 | for (var i = 0; i < 3; i++) { 230 | rgbColor[i] = Number(input[i]); 231 | } 232 | } 233 | 234 | for (var i in rgbColor) { 235 | if (rgbColor[i] < 0) return false; 236 | if (rgbColor[i] > 255) return false; 237 | }; 238 | 239 | return { 240 | RGB: { 241 | R: rgbColor[0], 242 | G: rgbColor[1], 243 | B: rgbColor[2], 244 | }, 245 | }; 246 | }, 247 | XYZ: { 248 | convert: function(_rgb) { 249 | function PivotRgb(n) { 250 | return (n > 0.04045 ? Math.pow((n + 0.055) / 1.055, 2.4) : n / 12.92) * 100.0; 251 | } 252 | _rgb.R = PivotRgb(_rgb.R / 255); 253 | _rgb.G = PivotRgb(_rgb.G / 255); 254 | _rgb.B = PivotRgb(_rgb.B / 255); 255 | 256 | return { 257 | X: _rgb.R * 0.412453 + _rgb.G * 0.357580 + _rgb.B * 0.180423, 258 | Y: _rgb.R * 0.212671 + _rgb.G * 0.715160 + _rgb.B * 0.072169, 259 | Z: _rgb.R * 0.019334 + _rgb.G * 0.119193 + _rgb.B * 0.950227, 260 | }; 261 | }, 262 | cost: 1, 263 | }, 264 | CMY: { 265 | convert: function(_rgb) { 266 | var c, m, y; 267 | 268 | c = (255 - _rgb.R) / 255; 269 | m = (255 - _rgb.G) / 255; 270 | y = (255 - _rgb.B) / 255; 271 | 272 | return { 273 | C: c, 274 | M: m, 275 | Y: y, 276 | }; 277 | }, 278 | cost: 0, 279 | }, 280 | CMYK: { 281 | convert: function(_rgb) { 282 | var cmyMin = 0, 283 | c, m, y, k; 284 | 285 | k = 0; 286 | 287 | c = (255 - _rgb.R) / 255; 288 | m = (255 - _rgb.G) / 255; 289 | y = (255 - _rgb.B) / 255; 290 | 291 | k = min([c, m, y]); 292 | 293 | if (k == 1.0) { 294 | c = m = y = 0; 295 | } else { 296 | c = (c - k) / (1 - k); 297 | m = (m - k) / (1 - k); 298 | y = (y - k) / (1 - k); 299 | } 300 | 301 | return { 302 | C: c, 303 | M: m, 304 | Y: y, 305 | K: k, 306 | }; 307 | }, 308 | cost: 0, 309 | }, 310 | HSL: { 311 | convert: function(_rgb) { 312 | var R = _rgb.R / 255, 313 | G = _rgb.G / 255, 314 | B = _rgb.B / 255, 315 | Min = min(R, G, B), 316 | Max = max(R, G, B), 317 | del_Max = Max - Min, 318 | L = (Max + Min) / 2.0, 319 | del_R, del_G, del_B, 320 | H, S; 321 | 322 | if (del_Max == 0) { 323 | H = 0; 324 | S = 0; 325 | } else { 326 | if (L < 0.5) 327 | S = del_Max / (Max + Min); 328 | else 329 | S = del_Max / (2 - Max - Min); 330 | 331 | del_R = (((Max - R) / 6.0) + (del_Max / 2.0)) / del_Max; 332 | del_G = (((Max - G) / 6.0) + (del_Max / 2.0)) / del_Max; 333 | del_B = (((Max - B) / 6.0) + (del_Max / 2.0)) / del_Max; 334 | 335 | if (R == Max) H = del_B - del_G; 336 | else if (G == Max) H = (1.0 / 3.0) + del_R - del_B; 337 | else if (B == Max) H = (2.0 / 3.0) + del_G - del_R; 338 | 339 | if (H < 0) H += 1; 340 | if (H > 1) H -= 1; 341 | }; 342 | 343 | return { 344 | H: H * 360, 345 | S: S, 346 | L: L, 347 | }; 348 | }, 349 | cost: 0, 350 | }, 351 | HSV: { 352 | convert: function(_rgb) { 353 | var r = _rgb.R / 255, 354 | g = _rgb.G / 255, 355 | b = _rgb.B / 255, 356 | minRGB = min(r, g, b), 357 | maxRGB = max(r, g, b), 358 | H, S, V; 359 | 360 | if (minRGB == maxRGB) { 361 | V = minRGB; 362 | return { 363 | H: 0, 364 | S: 0, 365 | V: V, 366 | } 367 | } else { 368 | var d = (r == minRGB) ? g - b : ((b == minRGB) ? r - g : b - r), 369 | h = (r == minRGB) ? 3 : ((b == minRGB) ? 1 : 5); 370 | H = 60 * (h - d / (maxRGB - minRGB)); 371 | S = (maxRGB - minRGB) / maxRGB; 372 | V = maxRGB; 373 | return { 374 | H: H, 375 | S: S, 376 | V: V, 377 | } 378 | } 379 | }, 380 | cost: 0, 381 | }, 382 | }, 383 | CMY: { 384 | import: function() { 385 | var input = flatten(arguments); 386 | 387 | if (input[0].check("C", "M", "Y")) { 388 | return { 389 | CMY: input[0], 390 | }; 391 | }; 392 | 393 | if (input.length < 3) { 394 | return false; 395 | } 396 | for (var i = 0; i < 3; i++) { 397 | if (input[i] < 0 || input[i] > 1) return false; 398 | } 399 | return { 400 | CMY: { 401 | C: input[0], 402 | M: input[1], 403 | Y: input[2], 404 | }, 405 | } 406 | }, 407 | RGB: { 408 | convert: function(_cmy) { 409 | var r, g, b; 410 | 411 | r = (1 - _cmy.C) * 255; 412 | g = (1 - _cmy.M) * 255; 413 | b = (1 - _cmy.Y) * 255; 414 | 415 | return { 416 | R: r, 417 | G: g, 418 | B: b, 419 | }; 420 | }, 421 | cost: 0, 422 | }, 423 | }, 424 | RGBA: { 425 | import: function() { 426 | var input = flatten(arguments); 427 | 428 | if (input[0].check("R", "G", "B", "A")) { 429 | return { 430 | RGBA: input[0], 431 | }; 432 | }; 433 | 434 | if (input.length < 7) { 435 | return false; 436 | } 437 | for (var i = 0; i < 7; i++) { 438 | if (input[i] < 0 || input[i] > 255) return false; 439 | } 440 | if (input[3] > 1) return false; 441 | return { 442 | RGBA: { 443 | FR: input[0], 444 | FG: input[1], 445 | FB: input[2], 446 | 447 | Alpha: input[3], 448 | BR: input[4], 449 | BG: input[5], 450 | BB: input[6], 451 | 452 | }, 453 | } 454 | }, 455 | RGB: { 456 | convert: function(_rgba) { 457 | return { 458 | R: (1 - _rgba.Alpha) * _rgba.BR + _rgba.Alpha * _rgba.FR, 459 | G: (1 - _rgba.Alpha) * _rgba.BG + _rgba.Alpha * _rgba.FG, 460 | B: (1 - _rgba.Alpha) * _rgba.BB + _rgba.Alpha * _rgba.FB, 461 | } 462 | }, 463 | cost: 1, 464 | }, 465 | }, 466 | CMYK: { 467 | import: function() { 468 | var input = flatten(arguments); 469 | 470 | if (input[0].check("C", "M", "Y", "K")) { 471 | return { 472 | CMYK: input[0], 473 | }; 474 | }; 475 | 476 | if (input.length < 4) { 477 | return false; 478 | } 479 | for (var i = 0; i < 4; i++) { 480 | if (input[i] < 0 || input[i] > 1) return false; 481 | } 482 | return { 483 | CMYK: { 484 | C: input[0], 485 | M: input[1], 486 | Y: input[2], 487 | K: input[3], 488 | }, 489 | } 490 | }, 491 | RGB: { 492 | convert: function(_cmyk) { 493 | var r, g, b; 494 | 495 | r = ((1 - _cmyk.K) * (1 - _cmyk.C)) * 255; 496 | g = ((1 - _cmyk.K) * (1 - _cmyk.M)) * 255; 497 | b = ((1 - _cmyk.K) * (1 - _cmyk.Y)) * 255; 498 | 499 | return { 500 | R: r, 501 | G: g, 502 | B: b, 503 | }; 504 | }, 505 | cost: 0, 506 | }, 507 | }, 508 | HSL: { 509 | import: function() { 510 | var input = flatten(arguments); 511 | 512 | if (input[0].check("H", "S", "L")) { 513 | return { 514 | HSL: input[0], 515 | }; 516 | }; 517 | 518 | if (input.length < 3) { 519 | return false; 520 | }; 521 | 522 | if (input[0] < 0 || input[0] > 360 || input[1] < 0 || input[2] < 0 || input[1] > 1 || input[2] > 1) return false; 523 | 524 | return { 525 | HSL: { 526 | H: input[0], 527 | S: input[1], 528 | L: input[2], 529 | }, 530 | }; 531 | }, 532 | RGB: { 533 | convert: function(_hsl) { 534 | var H = _hsl.H, 535 | S = _hsl.S, 536 | L = _hsl.L, 537 | _r, _g, _b, 538 | 539 | c = acc.mul(acc.sub(1, Math.abs(acc.sub(acc.mul(2, L), 1))), S), 540 | h = H / 60, 541 | x = acc.mul(c, (1 - Math.abs(h % 2 - 1))), 542 | i = parseInt(h), 543 | m = acc.sub(L, acc.div(c, 2)); 544 | 545 | switch (i) { 546 | case 0: 547 | _r = c; 548 | _g = x; 549 | _b = 0; 550 | break; 551 | case 1: 552 | _r = x; 553 | _g = c; 554 | _b = 0; 555 | break; 556 | case 2: 557 | _r = 0; 558 | _g = c; 559 | _b = x; 560 | break; 561 | case 3: 562 | _r = 0; 563 | _g = x; 564 | _b = c; 565 | break; 566 | case 4: 567 | _r = x; 568 | _g = 0; 569 | _b = c; 570 | break; 571 | case 5: 572 | _r = c; 573 | _g = 0; 574 | _b = x; 575 | break; 576 | }; 577 | 578 | _r = acc.add(_r, m); 579 | _g = acc.add(_g, m); 580 | _b = acc.add(_b, m); 581 | 582 | return { 583 | R: _r * 255, 584 | G: _g * 255, 585 | B: _b * 255, 586 | }; 587 | }, 588 | cost: 0, 589 | }, 590 | }, 591 | HSV: { 592 | import: function() { 593 | var input = flatten(arguments); 594 | 595 | if (input[0].check("H", "S", "L")) { 596 | return { 597 | HSL: input[0], 598 | }; 599 | }; 600 | 601 | if (input.length < 3) { 602 | return false; 603 | } 604 | 605 | if (input[0] < 0 || input[0] > 360 || input[1] < 0 || input[2] < 0 || input[1] > 1 || input[2] > 1) return false; 606 | 607 | return { 608 | HSV: { 609 | H: input[0], 610 | S: input[1], 611 | V: input[2], 612 | }, 613 | } 614 | }, 615 | RGB: { 616 | convert: function(_hsv) { 617 | var H = _hsv.H, 618 | S = _hsv.S, 619 | V = _hsv.V, 620 | _r, _g, _b, 621 | 622 | c = V * S, 623 | h = H / 60, 624 | x = c * (1 - Math.abs(h % 2 - 1)), 625 | i = parseInt(h), 626 | m = V - c; 627 | 628 | switch (i) { 629 | case 0: 630 | _r = c; 631 | _g = x; 632 | _b = 0; 633 | break; 634 | case 1: 635 | _r = x; 636 | _g = c; 637 | _b = 0; 638 | break; 639 | case 2: 640 | _r = 0; 641 | _g = c; 642 | _b = x; 643 | break; 644 | case 3: 645 | _r = 0; 646 | _g = x; 647 | _b = c; 648 | break; 649 | case 4: 650 | _r = x; 651 | _g = 0; 652 | _b = c; 653 | break; 654 | case 5: 655 | _r = c; 656 | _g = 0; 657 | _b = x; 658 | break; 659 | }; 660 | _r += m; 661 | _g += m; 662 | _b += m; 663 | return { 664 | R: _r * 255, 665 | G: _g * 255, 666 | B: _b * 255, 667 | }; 668 | }, 669 | cost: 0, 670 | }, 671 | }, 672 | XYZ: { 673 | import: function() { 674 | var input = flatten(arguments); 675 | 676 | if (input[0].check("X", "Y", "Z")) { 677 | return { 678 | XYZ: input[0], 679 | }; 680 | }; 681 | 682 | if (input.length < 3) { 683 | return false; 684 | } 685 | 686 | return { 687 | XYZ: { 688 | X: input[0], 689 | Y: input[1], 690 | Z: input[2], 691 | }, 692 | } 693 | }, 694 | RGB: { 695 | convert: function(_xyz) { 696 | 697 | function ToRgb(n) { 698 | var result = 255 * n; 699 | if (result < 0) return 0; 700 | if (result > 255) return 255; 701 | return result; 702 | } 703 | 704 | var x = _xyz.X / 100.0, 705 | y = _xyz.Y / 100.0, 706 | z = _xyz.Z / 100.0, 707 | 708 | r = x * 3.2406 + y * -1.5372 + z * -0.4986, 709 | g = x * -0.9689 + y * 1.8758 + z * 0.0415, 710 | b = x * 0.0557 + y * -0.2040 + z * 1.0570; 711 | 712 | r = r > 0.0031308 ? 1.055 * Math.pow(r, 1 / 2.4) - 0.055 : 12.92 * r; 713 | g = g > 0.0031308 ? 1.055 * Math.pow(g, 1 / 2.4) - 0.055 : 12.92 * g; 714 | b = b > 0.0031308 ? 1.055 * Math.pow(b, 1 / 2.4) - 0.055 : 12.92 * b; 715 | 716 | return { 717 | R: ToRgb(r), 718 | G: ToRgb(g), 719 | B: ToRgb(b), 720 | }; 721 | }, 722 | cost: 1, 723 | }, 724 | Lab: { 725 | convert: function(_xyz) { 726 | 727 | function PivotXyz(n) { 728 | return n > spaces.constant.Epsilon ? spaces.constant.CubicRoot(n) : (spaces.constant.Kappa * n + 16) / 116; 729 | } 730 | 731 | var white = spaces.constant.XYZ_WhiteRefrence, 732 | x = PivotXyz(_xyz.X / white.X), 733 | y = PivotXyz(_xyz.Y / white.Y), 734 | z = PivotXyz(_xyz.Z / white.Z); 735 | 736 | return { 737 | L: Math.max(0, 116 * y - 16), 738 | a: 500 * (x - y), 739 | b: 200 * (y - z), 740 | } 741 | }, 742 | cost: 1, 743 | }, 744 | LUV: { 745 | convert: function(_xyz) { 746 | 747 | function GetDenominator(xyz) { 748 | return xyz.X + 15.0 * xyz.Y + 3.0 * xyz.Z; 749 | } 750 | 751 | var white = spaces.constant.XYZ_WhiteRefrence, 752 | y = _xyz.Y / white.Y, 753 | L = y > spaces.constant.Epsilon ? 116.0 * spaces.constant.CubicRoot(y) - 16.0 : spaces.constant.Kappa * y, 754 | targetDenominator = GetDenominator(_xyz), 755 | referenceDenominator = GetDenominator(white), 756 | xTarget = targetDenominator == 0 ? 0 : ((4.0 * _xyz.X / targetDenominator) - (4.0 * white.X / referenceDenominator)), 757 | yTarget = targetDenominator == 0 ? 0 : ((9.0 * _xyz.Y / targetDenominator) - (9.0 * white.Y / referenceDenominator)), 758 | U = 13.0 * L * xTarget, 759 | V = 13.0 * L * yTarget; 760 | 761 | return { 762 | L: L, 763 | U: U, 764 | V: V, 765 | } 766 | }, 767 | cost: 1, 768 | }, 769 | }, 770 | Lab: { 771 | import: function() { 772 | var input = flatten(arguments); 773 | 774 | if (input[0].check("L", "a", "b")) { 775 | return { 776 | Lab: input[0], 777 | }; 778 | }; 779 | 780 | if (input.length < 3) { 781 | return false; 782 | } 783 | 784 | return { 785 | Lab: { 786 | L: input[0], 787 | a: input[1], 788 | b: input[2], 789 | }, 790 | }; 791 | }, 792 | XYZ: { 793 | convert: function(_lab) { 794 | var y = (_lab.L + 16.0) / 116.0, 795 | x = _lab.a / 500.0 + y, 796 | z = y - _lab.b / 200.0, 797 | white = spaces.constant.XYZ_WhiteRefrence, 798 | x3 = x * x * x, 799 | z3 = z * z * z; 800 | return { 801 | X: white.X * (x3 > spaces.constant.Epsilon ? x3 : (x - 16.0 / 116.0) / 7.787), 802 | Y: white.Y * (_lab.L > (spaces.constant.Kappa * spaces.constant.Epsilon) ? Math.pow(((_lab.L + 16.0) / 116.0), 3) : _lab.L / spaces.constant.Kappa), 803 | Z: white.Z * (z3 > spaces.constant.Epsilon ? z3 : (z - 16.0 / 116.0) / 7.787), 804 | }; 805 | }, 806 | cost: 1, 807 | }, 808 | LCH: { 809 | convert: function(_lab) { 810 | var h = Math.atan2(_lab.b, _lab.a); 811 | 812 | if (h > 0) { 813 | h = (h / Math.PI) * 180.0; 814 | } else { 815 | h = 360 - (Math.abs(h) / Math.PI) * 180.0; 816 | } 817 | 818 | if (h < 0) { 819 | h += 360.0; 820 | } else if (h >= 360) { 821 | h -= 360.0; 822 | } 823 | 824 | return { 825 | L: _lab.L, 826 | C: Math.sqrt(_lab.a * _lab.a + _lab.b * _lab.b), 827 | H: h, 828 | } 829 | }, 830 | cost: 1, 831 | }, 832 | }, 833 | LCH: { 834 | import: function() { 835 | var input = flatten(arguments); 836 | 837 | if (input[0].check("L", "C", "H")) { 838 | return { 839 | LCH: input[0], 840 | }; 841 | }; 842 | 843 | if (input.length < 3) { 844 | return false; 845 | } 846 | 847 | return { 848 | LCH: { 849 | L: input[0], 850 | C: input[1], 851 | H: input[2], 852 | }, 853 | }; 854 | }, 855 | Lab: { 856 | convert: function(_lch) { 857 | var hRadians = _lch.H * Math.PI / 180.0; 858 | return { 859 | L: _lch.L, 860 | a: Math.cos(hRadians) * _lch.C, 861 | b: Math.sin(hRadians) * _lch.C, 862 | }; 863 | }, 864 | cost: 1, 865 | }, 866 | }, 867 | LUV: { 868 | import: function() { 869 | var input = flatten(arguments); 870 | 871 | if (input[0].check("L", "U", "V")) { 872 | return { 873 | LUV: input[0], 874 | }; 875 | }; 876 | 877 | if (input.length < 3) { 878 | return false; 879 | } 880 | 881 | return { 882 | LUV: { 883 | L: input[0], 884 | U: input[1], 885 | V: input[2], 886 | }, 887 | }; 888 | }, 889 | XYZ: { 890 | convert: function(_luv) { 891 | 892 | function GetDenominator(xyz) { 893 | return xyz.X + 15.0 * xyz.Y + 3.0 * xyz.Z; 894 | } 895 | 896 | var white = spaces.constant.XYZ_WhiteRefrence, 897 | c = -1.0 / 3.0, 898 | uPrime = (4.0 * white.X) / GetDenominator(white), 899 | vPrime = (9.0 * white.Y) / GetDenominator(white), 900 | a = (1.0 / 3.0) * ((52.0 * _luv.L) / (_luv.U + 13 * _luv.L * uPrime) - 1.0), 901 | imteL_16_116 = (_luv.L + 16.0) / 116.0, 902 | y = _luv.L > spaces.constant.Kappa * spaces.constant.Epsilon ? imteL_16_116 * imteL_16_116 * imteL_16_116 : _luv.L / spaces.constant.Kappa, 903 | b = -5.0 * y, 904 | d = y * ((39.0 * _luv.L) / (_luv.V + 13.0 * _luv.L * vPrime) - 5.0), 905 | x = (d - b) / (a - c), 906 | z = x * a + b; 907 | return { 908 | X: 100 * x, 909 | Y: 100 * y, 910 | Z: 100 * z, 911 | }; 912 | }, 913 | cost: 1, 914 | }, 915 | }, 916 | }; 917 | 918 | var defaults = { 919 | colors: [], 920 | }; 921 | 922 | /* Main function */ 923 | function ColorConverter(options) { 924 | var self = this; 925 | self.colors = []; 926 | 927 | if (!(self instanceof ColorConverter)) { 928 | return new ColorConverter(options); 929 | }; 930 | 931 | self.options = options || {}; 932 | 933 | for (var i in defaults) { 934 | if (self.options[i] == null) { 935 | self.options[i] = defaults[i]; 936 | }; 937 | }; 938 | 939 | if (!!self.options.colors) { 940 | self.import(self.options.colors); 941 | }; 942 | }; 943 | 944 | /* Extend functions */ 945 | ColorConverter.prototype = { 946 | 947 | constructor: ColorConverter, 948 | 949 | import: function() { 950 | var argu = Array.prototype.slice.call(arguments)[0], 951 | output = [], 952 | self = this; 953 | 954 | for (var i = 0; i < argu.length; i++) { 955 | 956 | var _temp = flatten(argu[i]); 957 | /*split temp*/ 958 | var _format = _temp.shift(), 959 | _para = _temp; 960 | 961 | if (!spaces.hasOwnProperty(_format)) { 962 | throw Error("Unsupport color spaces"); 963 | }; 964 | 965 | var _obj = eval("(spaces." + _format + ".import)"); 966 | 967 | if (_obj === undefined) { 968 | throw Error("Cannot convert from " + _format); 969 | }; 970 | 971 | var _res = _obj.call(this, _para); 972 | 973 | if (!!_res) { 974 | self.colors.push(_res); 975 | output.push(self.colors.length - 1); 976 | } else { 977 | output.push(false); 978 | }; 979 | }; 980 | 981 | return output; 982 | }, 983 | 984 | export: function() { 985 | var argu = flatten(arguments), 986 | format = argu.shift(), 987 | list = argu, 988 | output = [], 989 | self = this; 990 | 991 | if (!list.length) { 992 | for (var i in self.colors) { 993 | if (self.colors.hasOwnProperty(i)) { 994 | list.push(i); 995 | }; 996 | }; 997 | }; 998 | 999 | list.forEach(function(_i) { 1000 | 1001 | var _code = self.colors[_i]; 1002 | 1003 | if (_code === undefined) { 1004 | throw Error("Undefined color"); 1005 | }; 1006 | 1007 | var _key = (function(_code) { 1008 | for (var i in _code) { 1009 | return i; 1010 | } 1011 | })(_code), 1012 | _temp = _code[_key], 1013 | _tokens = [{ 1014 | _path: [_key], 1015 | _cost: 0, 1016 | _terminal: false, 1017 | }], 1018 | _target = format, 1019 | _depth = 0; 1020 | 1021 | 1022 | 1023 | while (!(function(tokens, target) { 1024 | var flag = false; 1025 | for (var key in tokens) { 1026 | if (tokens.hasOwnProperty(key)) { 1027 | if (!tokens[key]._terminal) { 1028 | return false; 1029 | }; 1030 | }; 1031 | }; 1032 | return true; 1033 | })(_tokens, _target) && _depth < 10) { 1034 | 1035 | var _deplicate = []; 1036 | 1037 | for (var key in _tokens) { 1038 | if (_tokens.hasOwnProperty(key)) { 1039 | 1040 | var _on = _tokens[key], 1041 | _nowkey = _on._path.getLast(); 1042 | 1043 | if (spaces.hasOwnProperty(_nowkey)) { 1044 | 1045 | var _obj = eval("(spaces." + _nowkey + ")"); 1046 | 1047 | for (var key in _obj) { 1048 | if (_obj.hasOwnProperty(key)) { 1049 | 1050 | var _temp = cloneObject(_on); 1051 | 1052 | if (_on._path.search(key) || _on._path.getLast() == _target) { 1053 | _temp._terminal = true; 1054 | } else { 1055 | _temp._path.push(key); 1056 | _temp._cost += eval("(spaces." + _nowkey + "." + key + ".cost)"); 1057 | }; 1058 | 1059 | _deplicate.push(_temp); 1060 | }; 1061 | }; 1062 | 1063 | _obj = null; 1064 | 1065 | }; 1066 | }; 1067 | }; 1068 | 1069 | _tokens = _deplicate; 1070 | _deplicate = null; 1071 | 1072 | _depth++; 1073 | }; 1074 | 1075 | if (!_tokens.length) { 1076 | throw Error("No path to target"); 1077 | }; 1078 | 1079 | var _sort = []; 1080 | 1081 | for (var key in _tokens) { 1082 | if (_tokens.hasOwnProperty(key) && _tokens[key] && _tokens[key]._path.getLast() == _target) { 1083 | _sort.push(_tokens[key]); 1084 | }; 1085 | }; 1086 | 1087 | _sort.sort(function(a, b) { 1088 | return a.cost > b.cost ? -1 : 1; 1089 | }); 1090 | 1091 | if (!!_sort.length) { 1092 | 1093 | var _rp = _sort[0]._path, 1094 | _temp = eval("(_code." + _rp[0] + ")"); 1095 | 1096 | for (var i = 1; i < _rp.length; i++) { 1097 | _temp = eval("(spaces." + _rp[i - 1] + "." + _rp[i] + ".convert(" + JSON.stringify(_temp) + "))"); 1098 | }; 1099 | 1100 | output.push(_temp); 1101 | 1102 | } 1103 | 1104 | }) 1105 | return output; 1106 | }, 1107 | 1108 | reset: function() { 1109 | var self = this; 1110 | self.colors = []; 1111 | return true; 1112 | }, 1113 | 1114 | } 1115 | 1116 | window.ColorConverter = ColorConverter; 1117 | 1118 | })(window, document); 1119 | --------------------------------------------------------------------------------