调色板原码(RGB <=> HSL)!

本文介绍了一个HSLColorSetting类,该类用于处理HSL颜色模型,并提供了从RGB颜色模型转换到HSL颜色模型及反之的方法。此外,还包括了颜色值的校验和克隆方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

    public class HSLColorSetting
    {
        private double _hueValue = 0;
        private double _satValue = 0;
        private double _lumValue = 0;

        public HSLColorSetting Clone()
        {
            HSLColorSetting hsl = new HSLColorSetting();
            hsl.HueValue = _hueValue;
            hsl.SatValue = _satValue;
            hsl.LumValue = _lumValue;
            return hsl;
        }

        private double CheckValue(double value)
        {
            double result = 0;
            if (value > 1)
            {
                result = 1;
            }
            else if (value > 0)
            {
                result = value;
            }
            return result;
        }

        public double HueValue { get { return _hueValue; } set { _hueValue = CheckValue(value); } }
        public double SatValue { get { return _satValue; } set { _satValue = CheckValue(value); } }
        public double LumValue { get { return _lumValue; } set { _lumValue = CheckValue(value); } }

        public static HSLColorSetting CovertFromRGB(Color color)
        {
            HSLColorSetting hsl = new HSLColorSetting();
            hsl.ConverFromRGB(color.R, color.G, color.B);
            return hsl;
        }

        public Color ConvertToRGB()
        {
            double r, g, b;
            double s = SatValue;
            double h = HueValue;
            double l = LumValue;

            if (s == 0)
                r = g = b = l;
            else
            {
                double q = 0, p = 0, tempR = 0, tempG = 0, tempB = 0;
                if (l < 0.5)
                {
                    q = l * (1 + s);
                }
                else
                {
                    q = l + s - (l * s);
                }

                p = 2.0 * l - q;
                tempR = h + 1.0 / 3;
                tempG = h;
                tempB = h - 1.0 / 3;

                r = ToRGB(tempR, q, p);
                g = ToRGB(tempG, q, p);
                b = ToRGB(tempB, q, p);
            }
            r = Convert.ToInt32(r * 255);
            g = Convert.ToInt32(g * 255);
            b = Convert.ToInt32(b * 255);


            return Color.FromArgb(0xff, (byte)r, (byte)g, (byte)b);
        }

        private double ToRGB(double tc, double q, double p)
        {
            if (tc < 0)
            {
                tc += 1;
            }
            if (tc > 1)
            {
                tc -= 1;
            }
            if (tc < 1.0 / 6)
            {
                return p + (q - p) * 6 * tc;
            }
            else if (tc < 1.0 / 2)
            {
                return q;
            }
            else if (tc < 2.0 / 3)
            {
                return p + (q - p) * 6.0 * (2.0 / 3 - tc);
            }
            else
            {
                return p;
            }
        }

        private void ConverFromRGB(byte red, byte green, byte blue)
        {
            double r = 1.0 * red / 255;
            double g = 1.0 * green / 255;
            double b = 1.0 * blue / 255;

            double min, max;
            max = Math.Max(Math.Max(r, g), b);
            min = Math.Min(Math.Min(r, g), b);

            //计算 H 值。
            if (max == min)
            {
                HueValue = 0;
            }
            else if (max == r && g >= b)
            {
                HueValue = (g - b) / (max - min) / 6;
            }
            else if (max == r && g < b)
            {
                HueValue = ((g - b) / (max - min)) / 6 + 1;
            }
            else if (max == g)
            {
                HueValue = ((b - r) / (max - min)) / 6 + 1.0 / 3;
            }
            else if (max == b)
            {
                HueValue = ((r - g) / (max - min)) / 6 + 2.0 / 3;
            }

            //计算 L 值。
            LumValue = (max + min) / 2;
            //计算 S 值。
            if (LumValue == 0 || max == min)
            {
                SatValue = 0;
            }
            else if (LumValue > 0 && LumValue <= 0.5)
            {
                SatValue = (max - min) / (max + min);
            }
            else if (LumValue > 0.5)
            {
                SatValue = (max - min) / (2 - (max + min));
            }

        }
    }

转载于:https://www.cnblogs.com/zhjxiao/archive/2011/11/17/2252135.html

<think>好的,我现在需要帮助用户理解关于二元位运算符的运作机制,特别是当涉及负数时的处理方式。用户提到的观点是,正数之间使用原码进行运算,而一旦有负数参与,则使用补码,并且根据结果符号位是否为1来决定是否需要转换补码。首先,我需要确认用户的理解是否正确,并纠正其中的误区。 首先,我要回忆计算机中二进制运算的基础知识。计算机内部处理有符号整数时,普遍使用补码表示法,这样可以将加减法统一处理,无需区分符号位。因此,无论操作数是正数还是负数,位运算都是在补码形式下进行的。用户的说法中提到正数之间使用原码,这可能是一个常见的误解,需要澄清。 接下来,我需要分析用户的具体观点。用户认为当运算涉及负数时,使用补码进行运算,结果的符号位为1时需要转换为原码,符号位为0则直接使用结果。这里的问题在于,用户可能没有意识到所有位运算都是在补码基础上进行的,包括正数。因此,无论是否存在负数,运算都是在补码形式下完成的,而结果本身也是补码,无需额外转换步骤,除非需要查看原码。 然后,我需要考虑如何用实例来验证这一点。例如,正数与正数的位运算,比如5 & 3,用户可能认为使用原码,但实际上计算机内部存储的是补码,正数的补码与原码相同,所以结果看起来一样。但当涉及负数时,如-5 & 3,这时-5的补码是各位取反加1,运算后的结果如果符号位为1,确实需要转换回原码,但用户可能忽略了整个过程都是在补码体系下完成,所以结果本身就是补码,直接转换即可,不需要分情况处理符号位。 此外,用户提到的位移运算符<<和>>也需要考虑符号位的影响。左移和右移在处理负数时,补码的符号位会被保留或根据语言的不同处理方式而变化,例如Java中的有符号右移使用符号扩展,而JavaScript则不同。因此,需要指出位移运算的特殊性,尤其是右移时如何处理符号位。 总结用户的误区:1. 错误认为正数位运算使用原码;2. 错误认为结果的符号位决定是否需要转换补码。正确的做法是所有运算在补码进行,结果本身也是补码,直接转换为十进制即可,无需根据符号位额外处理。 接下来,我需要构建一个清晰的解析结构,包括核心规则、运算步骤、案例演示、误区修正等部分,确保用户能够逐步理解。同时,使用具体的例子,如5 & 3和-5 & 3,来展示补码运算的实际过程,并比较用户原有观点与正确方法的差异。 最后,需要强调补码体系的统一性,所有位运算符都在补码下操作,结果也是补码,转换回十进制时只需按补码规则处理,无论符号位如何。这样可以帮助用户避免混淆,正确理解和应用位运算符。</think>--- ### 二进制位运算符的完整解析(基于补码体系) --- #### 一、核心规则(修正用户误区) **所有位运算均基于补码体系**,无论操作数是否含负数。**不存在原码直接参与运算**的情况。 **最终结果解释方式统一**:运算结果本身是补码,直接转换为十进制即可,无需根据符号位额外处理。 --- ### 二、正确运算步骤(正负数通用) 1. **将所有数值转换为补码** - 正数补码 = 原码 - 负数补码 = 原码取反 + 1 2. **执行位运算**(&、|、^、<<、>>) 3. **将结果补码直接转换回十进制** --- ### 三、案例演示 #### 案例1:`5 & 3`(8位演示) | 步骤 | 二进制补码 | 十进制 | |-----------------|------------------|--------| | 5的补码 | `0000 0101` | 5 | | 3的补码 | `0000 0011` | 3 | | **按位与(&)** | `0000 0001` | 1 | **用户原误区**:认为使用原码运算 **修正后**:补码与原码相同(正数特性),运算结果仍是补码 --- #### 案例2:`-5 & 3`(8位演示) | 步骤 | 二进制补码 | 十进制 | |-----------------|------------------|--------| | -5的补码 | `1111 1011` | -5 | | 3的补码 | `0000 0011` | 3 | | **按位与(&)** | `0000 0011` | 3 | **用户原误区**:认为需要判断结果符号位 **修正后**:结果 `0000 0011` 已是补码,直接转换得 3 --- #### 案例3:`-5 | -3`(8位演示) | 步骤 | 二进制补码 | 十进制 | |-----------------|------------------|--------| | -5的补码 | `1111 1011` | -5 | | -3的补码 | `1111 1101` | -3 | | **按位或(|)** | `1111 1111` | → 补码转十进制:`-1` | **关键验证**: - 补码 `1111 1111` → 减1得 `1111 1110` → 取反得 `1000 0001` = `-1` --- ### 四、用户误区修正 1. **原码参与运算错误**: - 错误:认为正数之间使用原码运算 - 修正:所有数值在计算机中均以补码形式存储,运算始终基于补码 2. **结果处理错误**: - 错误:根据符号位决定是否转换补码 - 修正:运算结果本身是补码,直接转换即可(符号位仅影响结果正负) --- ### 五、位移运算符的特殊性 #### 1. 左移 `<<` - **规则**:低位补0,符号位可能被改变 - **示例**:`5 << 1` → `0000 1010` = 10 #### 2. 右移 `>>` - **算术右移**:保留符号位(多数语言默认) - **示例**:`-8 >> 1`(8位) - 补码 `1111 1000` → 右移得 `1111 1100` = `-4` - **逻辑右移**:高位补0(需特定语法,如JavaScript的 `>>>`) --- ### 六、补码体系总结表 | 运算符 | 规则 | 示例(8位) | |--------|-------------------------------|-------------------------------| | `&` | 按位与,补码直接运算 | `-5 & 3` → `3` | | `|` | 按位或,补码直接运算 | `-5 | -3` → `-1` | | `^` | 按位异或,补码直接运算 | `5 ^ 3` → `6` | | `<<` | 左移,补码操作,可能改变符号 | `7 << 1` → `14` | | `>>` | 算术右移,保留符号位 | `-8 >> 1` → `-4` | --- ### 七、计算机验证(Python代码) ```python # 验证 -5 & 3 = 3 print(-5 & 3) # 输出 3 # 验证 -5 | -3 = -1 print(-5 | -3) # 输出 -1 # 位移验证 print(5 << 1) # 10 print(-8 >> 1) # -4(Python使用算术右移) ``` --- ### 八、关键结论 1. **统一规则**:所有位运算均在补码体系下完成,不存在原码直接参与运算 2. **结果解释**:运算结果本身是补码,直接转换十进制即可 3. **位移特性**:右移需注意语言是否保留符号位(算术右移 vs 逻辑右移) --- 通过这种系统分析,可避免混淆补码转换步骤,准确理解位运算的底层逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值