HLS ⇔ RGB ⇔ HSV

by matacat
♥4 | Line 197 | Modified 2010-03-15 03:27:11 | MIT License
play

ActionScript3 source code

/**
 * Copyright matacat ( http://wonderfl.net/user/matacat )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/dtn8
 */

<?xml version="1.0" encoding="utf-8"?>

<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"
    applicationComplete="slideChanged()">
    
    <mx:Script><![CDATA[
        
        private var rgb:uint;
        private var h:Number = 0;
        private var l:Number = 0.5;
        private var s:Number = 1;
        private var v:Number = 1;
        
        private function slideChanged():void
        {
            if (tabNav.selectedIndex == 0) hls2rgb();
            else hsv2rgb();
            
            colorWindow.setStyle("backgroundColor", rgb);
            
            var colorText:String = rgb.toString(16).toUpperCase();
            for (var i:int = colorText.length; i < 6; i++) colorText = "0" + colorText;
            colorValue.text = "0x" + colorText;
        }
        
        private function tabChanged(index:Number):void
        {
            if (index == 0) {
                rgb2hls();
                hlsHue.value = hsvHue.value;
                hlsLum.value = l;
                hlsSat.value = s;
            } else {
                rgb2hsv();
                hsvHue.value = hlsHue.value;
                hsvSat.value = s;
                hsvVal.value = v;
            }
        }
        
        private function hsv2rgb():void
        {
            s = s > 1 ? 1 : (s < 0 ? 0 : s);
            v = v > 1 ? 1 : (v < 0 ? 0 : v);
            
            if (s == 0) {  // gray scale
                rgb = 0xFF * v << 16 | 0xFF * v << 8 | 0xFF * v << 0;
                return;
            }
            
            h = h >= 360 ? h % 360 : (h < 0 ? h % 360 + 360 : h);
            
            var i:int = int(h / 60);
            var f:Number = h / 60 - i;
            var p:Number = v * (1 - s);
            var q:Number = v * (1 - s * f);
            var t:Number = v * (1 - s * (1 - f));
            
            switch (i) {
                case 0: rgb = 0xFF * v << 16 | 0xFF * t << 8 | 0xFF * p << 0; break;
                case 1: rgb = 0xFF * q << 16 | 0xFF * v << 8 | 0xFF * p << 0; break;
                case 2: rgb = 0xFF * p << 16 | 0xFF * v << 8 | 0xFF * t << 0; break;
                case 3: rgb = 0xFF * p << 16 | 0xFF * q << 8 | 0xFF * v << 0; break;
                case 4: rgb = 0xFF * t << 16 | 0xFF * p << 8 | 0xFF * v << 0; break;
                case 5: rgb = 0xFF * v << 16 | 0xFF * p << 8 | 0xFF * q << 0;
            }
        }
        
        private function rgb2hsv():void
        {
            var c:Vector.<uint> = Vector.<uint>([ rgb >> 16 & 0xFF, rgb >> 8 & 0xFF, rgb & 0xFF ]);
            
            if (c[0] == c[1] && c[0] == c[2]) {  // gray scale
                h = 0;
                s = 0;
                v = c[0] / 255;
                return;
            }
            
            var max:int, min:int;
            if (c[0] > c[1]) {                               //     R   >   G
                if      (c[1] > c[2]) { max = 0; min = 2; }  //     R   >   G > B
                else if (c[2] > c[0]) { max = 2; min = 1; }  // B > R   >   G
                else                  { max = 0; min = 1; }  //     R >=B>= G
            } else {                                         //     G  > =  R
                if      (c[2] > c[1]) { max = 2; min = 0; }  // B > G  > =  R
                else if (c[0] > c[2]) { max = 1; min = 2; }  //     G  > =  R > B
                else                  { max = 1; min = 0; }  //     G >=B>= R
            }
            
            v = c[max] / 255;
            
            s = (c[max] - c[min]) / c[max];
            
            switch (max) {
                case 0:
                    h = 60 * (c[1] - c[2]) / (c[max] - c[min])      ; break;
                case 1:
                    h = 60 * (c[2] - c[0]) / (c[max] - c[min]) + 120; break;
                case 2:
                    h = 60 * (c[0] - c[1]) / (c[max] - c[min]) + 240;
            }
            
            if (h < 0) h += 360;
        }
        
        private function hls2rgb():void
        {
            l = l > 1 ? 1 : (l < 0 ? 0 : l);
            s = s > 1 ? 1 : (s < 0 ? 0 : s);
            
            if (s == 0) {  // gray scale
                rgb = 0xFF * l << 16 | 0xFF * l << 8 | 0xFF * l << 0;
                return;
            }
            
            var max:Number, min:Number;
            if (l <= 0.5) max = l * (1 + s);
            else          max = l * (1 - s) + s;
            min = 2 * l - max;
            
            rgb = 0xFF * c(h + 120) << 16 | 0xFF * c(h) << 8 | 0xFF * c(h - 120) << 0;
            
            function c(d:Number):Number
            {
                d = d >= 360 ? d % 360 : (d < 0 ? d % 360 + 360 : d);
                
                if      (d <  60) return min + (max - min) * d / 60;
                else if (d < 180) return max;
                else if (d < 240) return min + (max - min) * (240 - d) / 60;
                else              return min;
            }
        }
        
        private function rgb2hls():void
        {
            var c:Vector.<uint> = Vector.<uint>([ rgb >> 16 & 0xFF, rgb >> 8 & 0xFF, rgb & 0xFF ]);
            
            if (c[0] == c[1] && c[0] == c[2]) {  // gray scale
                h = 0;
                l = c[0] / 255;
                s = 0;
                return;
            }
            
            var max:int, min:int;
            if (c[0] > c[1]) {                               //     R   >   G
                if      (c[1] > c[2]) { max = 0; min = 2; }  //     R   >   G > B
                else if (c[2] > c[0]) { max = 2; min = 1; }  // B > R   >   G
                else                  { max = 0; min = 1; }  //     R >=B>= G
            } else {                                         //     G  > =  R
                if      (c[2] > c[1]) { max = 2; min = 0; }  // B > G  > =  R
                else if (c[0] > c[2]) { max = 1; min = 2; }  //     G  > =  R > B
                else                  { max = 1; min = 0; }  //     G >=B>= R
            }
            
            l = (c[max] + c[min]) / 510;  // (max + min) / (2 * 0xFF)
            
            if (l <= 0.5) s = (c[max] - c[min]) /        (c[max] + c[min]) ;
            else          s = (c[max] - c[min]) / (510 - (c[max] + c[min]));
            
            switch (max) {
                case 0:
                    h = 60 * (c[1] - c[2]) / (c[max] - c[min])      ; break;
                case 1:
                    h = 60 * (c[2] - c[0]) / (c[max] - c[min]) + 120; break;
                case 2:
                    h = 60 * (c[0] - c[1]) / (c[max] - c[min]) + 240;
            }
            
            if (h < 0) h += 360;
        }
        
        ]]></mx:Script>
    
    <mx:Panel title="GetColor" layout="horizontal" verticalAlign="middle"
        paddingTop="5" paddingBottom="5" paddingLeft="5" paddingRight="5">
        
        <mx:VBox horizontalAlign="center">
            <mx:Box id="colorWindow" width="70" height="60" borderStyle="outset" />
            <mx:Text id="colorValue" width="70" fontSize="12" />
        </mx:VBox>
        
        
        <mx:TabNavigator id="tabNav" creationPolicy="all" resizeToContent="true"
            change="tabChanged(event.newIndex)">
            
            <mx:VBox label="HLS" paddingTop="5" paddingBottom="5" paddingLeft="5" paddingRight="5">
                <Hslns id="hlsHue" title="H:" max="360" step="1" slideTick="60" slideLabels="['0°', '180°', '360°']"
                    change="h = hlsHue.value; slideChanged()" />
                <Hslns id="hlsLum" title="L:" value="0.5" change="l = hlsLum.value; slideChanged()" />
                <Hslns id="hlsSat" title="S:" value="1" change="s = hlsSat.value; slideChanged()" />
            </mx:VBox>
            
            <mx:VBox label="HSV" paddingTop="5" paddingBottom="5" paddingLeft="5" paddingRight="5">
                <Hslns id="hsvHue" title="H:" max="360" step="1" slideTick="60" slideLabels="['0°', '180°', '360°']"
                    change="h = hsvHue.value; slideChanged()" />
                <Hslns id="hsvSat" title="S:" value="1" change="s = hsvSat.value; slideChanged()" />
                <Hslns id="hsvVal" title="V:" value="1" change="v = hsvVal.value; slideChanged()" />
            </mx:VBox>
            
        </mx:TabNavigator>
        
    </mx:Panel>
    
    <mx:Component className="Hslns">
        <mx:HBox borderStyle="solid" verticalAlign="middle" horizontalAlign="right" width="100%"
            paddingTop="5" paddingBottom="5" paddingLeft="5" paddingRight="5"
            creationComplete="init()">
            
            <mx:Metadata>
                [Event(name="change", type="flash.events.Event")]
            </mx:Metadata>
            
            <mx:Script><![CDATA[
                
                public var title:String = "";
                [Bindable] public var value:Number = 0;
                public var min:Number = 0;
                public var max:Number = 1;
                public var step:Number = 0.01;
                public var slideTick:Number = 0.1;
                public var slideLabels:Array = ["0", "0.5", "1"];
                
                private var e:Event = new Event("change");
                
                private function init():void
                {
                    lab.text = title;
                    sld.value = num.value = value;
                    sld.minimum = num.minimum = min;
                    sld.maximum = num.maximum = max;
                    sld.snapInterval = num.stepSize = step;
                    sld.tickInterval = slideTick;
                    sld.labels = slideLabels;
                }
                
            ]]></mx:Script>
            
            <mx:Label id="lab" />
            <mx:HSlider id="sld" value="{value}" liveDragging="true" change="value = sld.value; dispatchEvent(e)" />
            <mx:NumericStepper id="num" value="{value}" width="60" change="value = num.value; dispatchEvent(e)" />
        </mx:HBox>
    </mx:Component>
    
</mx:Application>