/****************************
(c) Wataru Kanzaki, Wings-Winds, 2007-2009
http://www.wi-wi.jp/

reffered to http://image-d.isp.jp/commentary/color_cformula/index.html
****************************/

// 6500Kでの標準光源 http://plie.org/shopICC/ICClabo/Labo/cmsnote.html
var _convert={
	x: 95.04,
	y: 100,
	z: 908.89
};

/*** RGB <-> Gamma RGB ***/
/***************
* r: [0.0 .. 1.0]
* g: [0.0 .. 1.0]
* b: [0.0 .. 1.0]
* 
* gamma r: [0.0 .. 1.0]
* gamma g: [0.0 .. 1.0]
* gamma b: [0.0 .. 1.0]
***************/
/**************/
function RGBtoGRGB(r, g, b){
	var des={r:0,g:0,b:0};

	des.r=(r<0.018)?4.5*r:1.099*Math.pow(r,0.45)-0.099;
	des.g=(g<0.018)?4.5*g:1.099*Math.pow(g,0.45)-0.099;
	des.b=(b<0.018)?4.5*b:1.099*Math.pow(b,0.45)-0.099;

	return des;
}

/**************/
function GRGBtoRGB(r, g, b){
	var des={r:0,g:0,b:0};
	
	des.r=(r<0.0812)?r/4.5:Math.pow((r+0.099)/1.099, (1/0.45));
	des.g=(g<0.0812)?g/4.5:Math.pow((g+0.099)/1.099, (1/0.45));
	des.b=(b<0.0812)?b/4.5:Math.pow((b+0.099)/1.099, (1/0.45));

	return des;
}


/*** RGB <-> XYZ ***/
/***************
* r: [0.0 .. 1.0]
* g: [0.0 .. 1.0]
* b: [0.0 .. 1.0]
* 
* x: [0.0 .. 1.0]
* y: [0.0 .. 1.0]
* z: [0.0 .. 1.0]
***************/
/**************/
function RGBtoXYZ(r, g, b){
	var des={x:0,y:0,z:0};
	
	des.x=0.412453*r+0.35758*g+0.180423*b;
	des.y=0.212671*r+0.71516*g+0.072169*b;
	des.z=0.019334*r+0.119193*g+0.950227*b;

	return des;
}

/**************/
function XYZtoRGB(x, y, z){
	var des={r:0,g:0,b:0};

	des.r=3.240479*x-1.53715*y-0.498535*z;
	des.g=-0.969256*x+1.875991*y+0.041556*z;
	des.b=0.055648*x-0.204043*y+1.057311*z;

	return des;
}

/*** RGB <-> HLS ***/
/***************
* r: [0.0 .. 1.0]
* g: [0.0 .. 1.0]
* b: [0.0 .. 1.0]
* 
* h: [0 .. 359] (0=red)
* l: [0.0 .. 1.0]
* s: [0.0 .. 1.0]
***************/
/**************/
function RGBtoHLS(r, g, b){
	var des={h:0,l:0,s:0};
	
	var max=_MAX(r,g,b);
	var min=_MIN(r,g,b);

	des.l=(max+min)/2;
	
	if(max==min){
		des.h=des.s=0;
	}else{

		des.s=(des.l>0.5)?(max-min)/(2-max-min):(max-min)/(max+min);

		var cr=(max-r)/(max-min);
		var cg=(max-g)/(max-min);
		var cb=(max-b)/(max-min);
		
		var h=(r==max)?cb-cg:(g==max)?2+cr-cb:4+cg-cr;
		h*=60;
		if(h<0)
			h+=360;
		des.h=h;
	}
	return des;
}

/**************/
function HLStoRGB(h, l, s){
	var des={r:0,g:0,b:0};
	
	var max=(l>0.5)?l*(1-s)+s:l*(1+s);
	var min=2*l-max;
	
	if(s==0){
		des.r=des.g=des.b=l;
	}else{
		var _h;
		
		_h=h+120;
		if(_h>=360)
			_h-=360;
		des.r=(_h<60)?min+(max-min)*_h/60:(_h<180)?max:(_h<240)?min+(max-min)*(240-_h)/60:min;
		
		_h=h;
		des.g=(_h<60)?min+(max-min)*_h/60:(_h<180)?max:(_h<240)?min+(max-min)*(240-_h)/60:min;
		
		_h=h-120;
		if(_h<=0)
			_h+=360;
		des.b=(_h<60)?min+(max-min)*_h/60:(_h<180)?max:(_h<240)?min+(max-min)*(240-_h)/60:min;
		
	}

	return des;
}


/*** RGB <-> Gray ***/
/***************
* r: [0.0 .. 1.0]
* g: [0.0 .. 1.0]
* b: [0.0 .. 1.0]
* 
* y: [0 .. 255]
***************/
/**************/
function RGBtoGRAY(r, g, b){
	var des={y:0};
	
	var grgb=RGBtoGRGB(r,g,b);

	des=GRGBtoGRAY(grgb.r*255, grgb.g*255, grgb.b*255);

	return des;
}

/*** Gamma RGB <-> Gray ***/
/***************
* r: [0.0 .. 255]
* g: [0.0 .. 255]
* b: [0.0 .. 255]
* 
* y: [0.0 .. 255]
***************/
/**************/
function GRGBtoGRAY(r, g, b){
	var des={y:0};

	des.y=0.299*r+0.587*g+0.114*b;

	return des;
}

/*** RGB <-> HSV ***/
/***************
* r: [0.0 .. 1.0]
* g: [0.0 .. 1.0]
* b: [0.0 .. 1.0]
* 
* h: [0 .. 359] (0=red)
* s: [0.0 .. 1.0]
* v: [0.0 .. 1.0]
***************/
/**************/
function RGBtoHSV(r, g, b){
	var des={h:0,s:0,v:0};
	
	var max=_MAX(r,g,b);
	var min=_MIN(r,g,b);
	
	des.v=max;
	
	if(max==0){
		des.s=des.h=0;
	}else{
		des.s=(max-min)/max;
		
		var cr=(max-r)/(max-min);
		var cg=(max-g)/(max-min);
		var cb=(max-b)/(max-min);
		
		var h=(r==max)?cb-cg:(g==max)?2+cr-cb:4+cg-cr;
		h*=60;
		if(h<0)
			h+=360;
		des.h=h;
	}

	return des;
}

/**************/
function HSVtoRGB(h, s, v){
	var des={r:0,g:0,b:0};

	if(s==0){
		des.r=des.g=des.b=v;
	}else{
		var i=Math.floor(h/60);
		var f=h/60-i;
		var m=v*(1-s);
		var n=v*(1-s*f);
		var k=v*(1-s*(1-f));
		
		switch(i){
		case 0:
			r=v;
			g=k;
			b=m;
			break;
		case 1:
			r=n;
			g=v;
			b=m;
			break;
		case 2:
			r=m;
			g=v;
			b=k;
			break;
		case 3:
			r=m;
			g=n;
			b=v;
			break;
		case 4:
			r=k;
			g=m;
			b=v;
			break;
		case 5:
			r=v;
			g=m;
			b=n;
			break;
		default:
			break;
		}// switch(i)
		des.r=r;
		des.g=g;
		des.b=b;
	}// if(s==0)
	return des;
}

/*** RGB <-> CMY ***/
/***************
* c: [0.0 .. 1.0]
* m: [0.0 .. 1.0]
* y: [0.0 .. 1.0]
* 
* r: [0.0 .. 1.0]
* g: [0.0 .. 1.0]
* b: [0.0 .. 1.0]
***************/
/**************/
function RGBtoCMY(r, g, b){
	var des={c:0,m:0,y:0};

	des.c=1.0-r;
	des.m=1.0-g;
	des.y=1.0-b;

	return des;
}

/**************/
function CMYtoRGB(c, m, y){
	var des={r:0,g:0,b:0};

	des.r=1.0-c;
	des.g=1.0-m;
	des.b=1.0-y;

	return des;
}

/*** RGB <-> CMYK ***/
/***************
* c: [0.0 .. 1.0]
* m: [0.0 .. 1.0]
* y: [0.0 .. 1.0]
* k: [0.0 .. 1.0]
* 
* r: [0.0 .. 1.0]
* g: [0.0 .. 1.0]
* b: [0.0 .. 1.0]
***************/
/**************/
function RGBtoCMYK(r, g, b){
	var des={c:0,m:0,y:0,k:0};

	var k=_MIN(1-r, 1-g, 1-b);
	des.c=(1-r-k)/(1-k);
	des.m=(1-g-k)/(1-k);
	des.y=(1-b-k)/(1-k);
	des.k=k;

	return des;
}

/**************/
function CMYKtoRGB(c, m, y, k){
	var des={r:0,g:0,b:0};
	des.r=1-_MIN(1, c*(1-k)+k);
	des.g=1-_MIN(1, m*(1-k)+k);
	des.b=1-_MIN(1, y*(1-k)+k);

	return des;
}

/*** RGB <-> L*a*b ***/
/** via XYZ **/
/***************
* r: [0.0 .. 1.0]
* g: [0.0 .. 1.0]
* b: [0.0 .. 1.0]
* 
* l: [0 .. 100]
* a: [-134 .. 220]
* b: [-140 .. 122]
***************/
/**************/
function RGBtoLAB(r, g, b){
	var des={l:0,a:0,b:0};

	var xyz=RGBtoXYZ(r, g, b);
	des=XYZtoLAB(xyz.x, xyz.y, xyz.z);

	return des;
}

/*** LAB <-> RGB ***/
/***************
* l: [0.0 .. 1.0]
* a: [-134 .. 222]
* b: [-140 .. 120]
* 
* r: [0 .. 1.0]
* g: [0 .. 1.0]
* b: [0 .. 1.0]
***************/
/**************/
function LABtoRGB(l, a, b){
	var des={r:0,g:0,b:0};

	var xyz=LABtoXYZ(l, a, b);

	des=XYZtoRGB(xyz.x, xyz.y, xyz.z);
	
	return des;
}

/*** LAB <-> XYZ ***/
/***************
* l: [0 .. 100]
* a: [-134 .. 220]
* b: [-140 .. 122]
* 
* x: [0 .. 1.0]
* y: [0 .. 1.0]
* z: [0 .. 1.0]
***************/
/**************/
function LABtoXYZ(l, a, b){
	var des={x:0,y:0,z:0};
	
	var xn=_convert.z;
	var yn=_convert.y;
	var zn=_convert.z;
	
	var yr=(l>7.9996248)?Math.pow((l+16)/116, 3):l/903.3;

	var fy=(yr>0.008856)?(l+16)/116:(903.3*yr+16)/116;
	var fx=a*0.002+fy;
	var fz=fy-b*0.005;
	
	var xr=(Math.pow(fx, 3)>0.008856)?Math.pow(fx, 3):(116*fx-16)/903.3;
	var zr=(Math.pow(fz, 3)>0.008856)?Math.pow(fz, 3):(116*fz-16)/903.3;
	
	des.x=xr*xn*0.0001;
	des.y=yr*yn;// while(des.y<0.1)des.y*=10;
	des.z=zr*zn*0.0001;

	return des;
}
/**************/
function XYZtoLAB(x, y, z){
	var des={l:0,a:0,b:0};
	var xn=_convert.z;
	var yn=_convert.y;
	var zn=_convert.z;

	// 計算式 http://konicaminolta.jp/instruments/knowledge/color/part4/05.html
	var fx=(x/xn>0.008856)?Math.pow(x/xn, 1/3):7.787*x/xn+16/116;
	var fy=(y/yn>0.008856)?Math.pow(y/yn, 1/3):7.787*y/yn+16/116;
	var fz=(z/zn>0.008856)?Math.pow(z/zn, 1/3):7.787*z/zn+16/116;
	
	des.l=116*fy-16;
	des.a=500*(fx-fy);
	des.b=200*(fy-fz);

	return des;
}


/*** utils **/
function HEXtoDEC(h){
	return parseInt(h,16);
}

function _MAX(){
	var n=0;
	for(var i=0;i<arguments.length;i++){
		if(n<arguments[i])
			n=arguments[i];
	}
	return n;
}

function _MIN(){
	if(arguments.length==0)
		return 0;
	for(var i=1,n=arguments[0];i<arguments.length;i++){
		if(n>arguments[i])
			n=arguments[i];
	}
	return n;
}
