/* AdvancedColor, v1.0 February 19, 2004 (c) 2004 Nate Cook Get (sparse) documentation and version updates at: http://www.natecook.com/downloads/ This file may be distributed and used in any projects (commercial or not) as long as it is unaltered and this notice is intact. I'd love to hear from you with feedback, about bugs, ideas for further features, etc. Thanks! USEAGE #include "AdvancedColor.as" VERSION HISTORY v1.0 Initial release. */ // constructor _global.AdvancedColor = function(aTarget) { this.target = aTarget; this.col = new Color(this.target); } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * static properties * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ AdvancedColor.RGBMAX = 256; AdvancedColor.HUEMAX = 360; AdvancedColor.PCTMAX = 100; /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * static helper methods * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ AdvancedColor.__componentsFromHex = function(hexValue) { var tmp = new Object(); tmp.r = Math.floor(hexValue / (AdvancedColor.RGBMAX * AdvancedColor.RGBMAX)); tmp.g = Math.floor((hexValue / AdvancedColor.RGBMAX) % AdvancedColor.RGBMAX); tmp.b = Math.floor(hexValue % AdvancedColor.RGBMAX); return tmp; } AdvancedColor.__hexFromComponents = function(a,b,c) { a = Number(a).toString(16).toUpperCase(); if (a.length < 2) a = '0' + a; else if (a.length > 2) a = 'FF'; b = Number(b).toString(16).toUpperCase(); if (b.length < 2) b = '0' + b; else if (b.length > 2) b = 'FF'; c = Number(c).toString(16).toUpperCase(); if (c.length < 2) c = '0' + c; else if (c.length > 2) c = 'FF'; return Number('0x' + a + b + c); } AdvancedColor.__hexFromPercentages = function(rgbVal) { return AdvancedColor.__hexFromComponents(rgbVal.r * AdvancedColor.RGBMAX, rgbVal.g * AdvancedColor.RGBMAX, rgbVal.b * AdvancedColor.RGBMAX); } // given three values, return the middle one AdvancedColor.__center = function(a,b,c) { if ((a > b) && (a > c)) { if (b > c) return b; else return c; } else if ((b > a) && (b > c)) { if (a > c) return a; else return c; } else if (a > b) { return a; } else { return b; } } AdvancedColor.__limit = function(value,min,max,wrap) { if (wrap) { while (value > max) value -= (max - min); while (value < min) value += (max - min); } else { if (value > max) value = max; if (value < min) value = min; } return value; } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * convert hue to rgb values using a linear transformation * inputs: min = minimum of r,g,b * max = maximum of r,g,b * hue = value angle hue * output: an object with r,g,b properties on 0 to 1 scale * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ AdvancedColor.__LinearHueToRGB = function(min, max, hue) { var mu, md, F, n; var am = AdvancedColor.RGBMAX; while (hue < 0) hue += AdvancedColor.HUEMAX; n = Math.floor(hue / 60); F = (hue - n*60) / 60; n %= 6; mu = min + ((max - min) * F); md = max - ((max - min) * F); switch (n) { case 0: return {r: max, g: mu, b: min}; case 1: return {r: md, g: max, b: min}; case 2: return {r: min, g: max, b: mu}; case 3: return {r: min, g: md, b: max}; case 4: return {r: mu, g: min, b: max}; case 5: return {r: max, g: min, b: md}; } } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * convert rgb values to a hue using a linear transformation * inputs: red, grn, blu on 0 to 1 scale * output: a hue degree between 0 and 360 * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ AdvancedColor.__LinearRGBToHue = function(red, grn, blu) { var F, min, mid, max, n; max = Math.max(red, Math.max(grn, blu)); min = Math.min(red, Math.min(grn, blu)); // achromatic case if (max - min == 0) { return 0; } mid = AdvancedColor.__center(red, grn, blu); // using this loop to avoid super-ugly nested ifs while (true) { if (red == max) { if (blu == min) n = 0; else n = 5; break; } if (grn == max) { if (blu == min) n = 1; else n = 2; break; } if (red == min) n = 3; else n = 4; break; } if ((n % 2) == 0) { F = mid - min; } else { F = max - mid; } F = F / (max - min); return 60 * (n + F); } // we'll use these for now AdvancedColor.__HueToRGB = AdvancedColor.__LinearHueToRGB; AdvancedColor.__RGBToHue = AdvancedColor.__LinearRGBToHue; /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * convert RGB values to HLS values * inputs: red, grn, blu on 0 to 1 scale * output: object with h,l,s values * h on 0 to 360 scale * l,s on 0 to 1 scale * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ AdvancedColor.RGBtoHLS = function(red,grn,blu) { var min, max, delta; var l, s, h = 0; max = Math.max(red, Math.max(grn, blu)); min = Math.min(red, Math.min(grn, blu)); l = (min + max) / 2; // L if (l == 0) { return {h:h, l:0, s:1}; } delta = (max - min) / 2; if (l < 0.5) { // S s = delta / l; } else { s = delta / (1 - l); } h = AdvancedColor.__RGBToHue(red,grn,blu); return {h:h, l:l, s:s}; } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * convert HLS values to RGB values * inputs: hue,lum,sat : hue on 0 to 360, others on 0 to 1 scale * output: object with r,g,b values on 0 to 1 scale * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ AdvancedColor.HLStoRGB = function(hue,lum,sat) { var delta; if (lum < 0.5) { delta = sat * lum; } else { delta = sat * (1 - lum); } return AdvancedColor.__HueToRGB(lum - delta, lum + delta, hue); } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * convert RGB values to HSV values * inputs: red, grn, blu on 0 to 1 scale * output: object with h,s,v values * h on 0 to 360 scale * s,v on 0 to 1 scale * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ AdvancedColor.RGBtoHSV = function(red,grn,blu) { var min, max; var s, v, h = 0; max = Math.max(red, Math.max(grn, blu)); min = Math.min(red, Math.min(grn, blu)); if (max == 0) { return {h:0, s:0, v:0}; } v = max; s = (max - min) / max; h = AdvancedColor.__RGBToHue(red,grn,blu); return {h:h, s:s, v:v}; } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * convert HSV values to RGB values * inputs: hue,sat,val : hue on 0 to 360, others on 0 to 1 scale * output: object with r,g,b values on 0 to 1 scale * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ AdvancedColor.HSVtoRGB = function(hue,sat,val) { var min = (1 - sat) * val; return AdvancedColor.__HueToRGB(min, val, hue); } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * HSV<->HLS conversions * these simply use the RGB conversions as a go-between * preservation of color may be dubious, here * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ AdvancedColor.HSVtoHLS = function(hue,sat,val) { var rgbVal = AdvancedColor.HSVtoRGB(hue,sat,val); return AdvancedColor.RGBtoHLS(rgbVal.r,rgbVal.g,rgbVal.b); } AdvancedColor.HLStoHSV = function(hue,lum,sat) { var rgbVal = AdvancedColor.HLStoRGB(hue,lum,sat); return AdvancedColor.RGBtoHSV(rgbVal.r,rgbVal.g,rgbVal.b); } var ACP = AdvancedColor.prototype; /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * pass through methods for compatibility * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ ACP.setRGB = function(rgbVal) { this.col.setRGB(rgbVal); } ACP.getRGB = function() { return this.col.getRGB(); } ACP.setTransform = function(trans) { this.col.setTransform(trans); } ACP.getTransform = function() { return this.col.getTransform(); } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * RGB component methods * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ ACP.setRGBComponent = function(r,g,b) { r = AdvancedColor.__limit(r,0,AdvancedColor.RGBMAX,false); g = AdvancedColor.__limit(g,0,AdvancedColor.RGBMAX,false); b = AdvancedColor.__limit(b,0,AdvancedColor.RGBMAX,false); this.col.setRGB(AdvancedColor.__hexFromComponents(r,g,b)); } ACP.getRGBComponent = function() { var tmpVal = AdvancedColor.__componentsFromHex(this.col.getRGB()); return {r:tmpVal.r, g:tmpVal.g, b:tmpVal.b}; } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * HLS component methods * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ ACP.setHLSComponent = function(h,l,s) { h = AdvancedColor.__limit(h,0,AdvancedColor.HUEMAX,true); l = AdvancedColor.__limit(l,0,AdvancedColor.PCTMAX,false) / AdvancedColor.PCTMAX; s = AdvancedColor.__limit(s,0,AdvancedColor.PCTMAX,false) / AdvancedColor.PCTMAX; var rgbVal = AdvancedColor.HLStoRGB(h,l,s); this.col.setRGB(AdvancedColor.__hexFromPercentages(rgbVal)); } ACP.getHLSComponent = function() { var rgbVal = AdvancedColor.__componentsFromHex(this.col.getRGB()); rgbVal.r /= 256; rgbVal.g /= 256; rgbVal.b /= 256; var hlsVal = AdvancedColor.RGBtoHLS(rgbVal.r,rgbVal.g,rgbVal.b); hlsVal.h = Math.round(hlsVal.h); hlsVal.l = Math.round(hlsVal.l * AdvancedColor.PCTMAX); hlsVal.s = Math.round(hlsVal.s * AdvancedColor.PCTMAX); return hlsVal } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * HSV component methods * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ ACP.setHSVComponent = function(h,s,v) { h = AdvancedColor.__limit(h,0,AdvancedColor.HUEMAX,true); s = AdvancedColor.__limit(s,0,AdvancedColor.PCTMAX,false) / AdvancedColor.PCTMAX; v = AdvancedColor.__limit(v,0,AdvancedColor.PCTMAX,false) / AdvancedColor.PCTMAX; var rgbVal = AdvancedColor.HSVtoRGB(h,s,v); this.col.setRGB(AdvancedColor.__hexFromPercentages(rgbVal)); } ACP.getHSVComponent = function() { var rgbVal = AdvancedColor.__componentsFromHex(this.col.getRGB()); rgbVal.r /= 256; rgbVal.g /= 256; rgbVal.b /= 256; var hsvVal = AdvancedColor.RGBtoHSV(rgbVal.r,rgbVal.g,rgbVal.b); hsvVal.h = Math.round(hsvVal.h); hsvVal.s = Math.round(hsvVal.s * AdvancedColor.PCTMAX); hsvVal.v = Math.round(hsvVal.v * AdvancedColor.PCTMAX); return hsvVal; } /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * clean up and hide the global object * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ delete ACP; ASSetPropFlags (_global, ['AdvancedColor'], 1);