HSL 到 RGB 转换器问题

HSL to RGB converter issue

此转换器假定 H、S 和 L 包含在集合 [0, 1] 中。

但是我希望H在[0, 359]之间(包括0和359)和S&L在[0, 100]之间(包括0和100)我不知道该怎么做(也在 Java 中)。

我从 here 那里拿了这个转换器。

public class testdos {
    public static void main(String[] args) {
        // hslToRgb([0, 359], [0, 100], [0, 100]);
    }

    public static int[] hslToRgb(float h, float s, float l) {
        // i added this sysout line
        System.out.println("HSL(" + h + "," + s + "," + l + ")");

        float r, g, b;

        if (s == 0f) {
            r = g = b = l; // achromatic
        } else {
            float q = l < 0.5f ? l * (1 + s) : l + s - l * s;
            float p = 2 * l - q;
            r = hueToRgb(p, q, h + 1f / 3f);
            g = hueToRgb(p, q, h);
            b = hueToRgb(p, q, h - 1f / 3f);
        }
        int[] rgb = { to255(r), to255(g), to255(b) };

        // and i added this to print it, don't know if its the best way to do it
        System.out.print("RGB(");
        for (int i = 0; i < rgb.length; i++) {
            if ((i + 1) != rgb.length) {
                System.out.print(rgb[i] + ",");
            }
            else {
                System.out.print(rgb[i]);
            }
        }
        System.out.println(")");

        return rgb;
    }

    public static int to255(float v) {
        return (int) Math.min(255, 256 * v);
    }

    /** Helper method that converts hue to rgb */
    public static float hueToRgb(float p, float q, float t) {
        if (t < 0f)
            t += 1f;
        if (t > 1f)
            t -= 1f;
        if (t < 1f / 6f)
            return p + (q - p) * 6f * t;
        if (t < 1f / 2f)
            return q;
        if (t < 2f / 3f)
            return p + (q - p) * (2f / 3f - t) * 6f;
        return p;
    }
}

除以 h、s 和 l 范围得到 0 和 1 之间的数字。您还 class 名称以大写字母开头。

编辑添加:为什么我必须 class 名称以大写字符开头?

因为这是 Java 约定,所以您可以编写如下代码:

Testdoc testdoc = new TestDoc();

并直观地看到 Testdoc class 名称和 testdoc 字段名称之间的区别。

这是修改后的代码。

public class Testdos {
    public static void main(String[] args) {
        // hslToRgb([0, 359], [0, 100], [0, 100]);
    }

    /**
     * Converts an HSL color value to RGB. Conversion formula adapted from
     * http://en.wikipedia.org/wiki/HSL_color_space. Assumes h, s, and l are
     * contained in the set [0, 1] and returns r, g, and b in the set [0, 255].
     *
     * @param h The hue
     * @param s The saturation
     * @param l The lightness
     * @return int array, the RGB representation
     */
    public static int[] hslToRgb(float h, float s, float l) {
        // i added this sysout line
        System.out.println("HSL(" + h + "," + s + "," + l + ")");

        h /= 359.0;
        s /= 100.0;
        l /= 100.0;

        float r, g, b;

        if (s == 0f) {
            r = g = b = l; // achromatic
        } else {
            float q = l < 0.5f ? l * (1 + s) : l + s - l * s;
            float p = 2 * l - q;
            r = hueToRgb(p, q, h + 1f / 3f);
            g = hueToRgb(p, q, h);
            b = hueToRgb(p, q, h - 1f / 3f);
        }
        int[] rgb = { to255(r), to255(g), to255(b) };

        // and i added this to print it, don't know if its the best way to do it
        System.out.print("RGB(");
        for (int i = 0; i < rgb.length; i++) {
            if ((i + 1) != rgb.length) {
                System.out.print(rgb[i] + ",");
            } else {
                System.out.print(rgb[i]);
            }
        }
        System.out.println(")");

        return rgb;
    }

    public static int to255(float v) {
        return (int) Math.min(255, 256 * v);
    }

    /** Helper method that converts hue to rgb */
    public static float hueToRgb(float p, float q, float t) {
        if (t < 0f)
            t += 1f;
        if (t > 1f)
            t -= 1f;
        if (t < 1f / 6f)
            return p + (q - p) * 6f * t;
        if (t < 1f / 2f)
            return q;
        if (t < 2f / 3f)
            return p + (q - p) * (2f / 3f - t) * 6f;
        return p;
    }
}

您提供的hslToRgb()方法接受三个float数据类型的参数。必须提供给所有这些参数的取值范围是:0.0f to 1.0f:

int[] hslToRgb(float h, float s, float l) { ... }

相反,您想为这些参数提供一个特定的范围值,这反过来使该方法更容易在外行人的术语中使用,就实际需要提供的内容而言。

H  (0° to 360°  as in Degrees)
S  (0% to 100%  as in Percent)
L  (0% to 100%  as in Percent)

做个小除法就可以了。这可以通过将参数提供给方法或内置到看起来是您想要的方法中来完成。后者在某种程度上更有优势,因为在将参数应用于 hslToRgb() 方法时,您无需记住公式(无论它多么简单)来执行这些除法。

在传递参数之前做数学运算:

// Hue is: 65°   Saturation is: 36%   Lightness is: 87%
float hue =        (float) 65/360;
float saturation = (float) 36/100;
float lightness  = (float) 87/100;
int[] rgb = hslToRgb(hue, saturation, lightness); 

传递参数时进行计算:

// Hue is: 65°   Saturation is: 36%   Lightness is: 87%
int[] rgb = hslToRgb((float)65/360, (float)36/100, (float)87/100); 

谁在乎呢!让方法搞定:

// Hue is: 65°   Saturation is: 36%   Lightness is: 87%
int[] rgb = hslToRgb(65, 36, 87);

最后一个示例需要将一些代码添加到 hslToRgb() 方法中。这没什么大不了的,但在我们开始之前,您需要确保认识到对于颜色准确性、色相、饱和度和亮度参数 可以 分别以浮点度和浮点百分比给出值。换句话说,提供如下参数:

int[] rgb = hslToRgb(65, 36, 87);

               AND

int[] rgb = hslToRgb(65.8, 36.2, 87.5);

将被视为具有有效参数的有效调用。通过向 hslToRgb() 方法添加少量代码,可以提供 or ,例如:

int[] rgb = hslToRgb(0.1806f, 36, 87.5);

这是一个带有有效参数的有效调用,将产生与上述其他示例完全相同的 RGB 值。

修改hslToRgb()方法:

只需将这三行代码添加到hslToRGB()方法的顶部:

public static int[] hslToRGB(float h, float s, float l) {
    if (h > 1.0f) { h = (h < 0 ? 0 : h > 360 ? 360 : h) / 360; }
    if (s > 1.0f) { s = (s < 0 ? 0 : s > 100 ? 100 : s) / 100; }
    if (l > 1.0f) { l = (l < 0 ? 0 : l > 100 ? 100 : l) / 100; }

    // .... the rest of method code here ....
}

这三行代码是做什么的?

使用这些代码行,Hue (h) 参数可以作为集合 [0.0 到 1.0] 或集合 [0.0 到 360.0] 或集合 [0 到 360] 提供。饱和度 (s) 和亮度 (l) 参数可以作为集合 [0.0 到 1.0] 或集合 [0.0 到 100.0] 或集合 [0 到 100] 提供。如果提供的任何参数小于其最小范围 (0),则默认为该参数特定的最小值,对于所有参数都为 0。另一方面,如果提供的任何参数大于其最大范围,则默认为该参数特定最大值。

由于所有三行代码基本上都对每个特定参数执行相同的操作,因此我们将解释第一行:

if (h > 1.0f) { h = (h < 0 ? 0 : h > 360 ? 360 : h) / 360; }

if 语句 (h > 1.0f) 的条件检查提供的 Hue (h) 参数是否在 [0.0 到 1.0] 的集合内。如果提供的参数大于 1.0,那么它必须作为文字度值提供并且 if 语句条件为 true 因此运行 此语句的代码块中包含的代码由嵌套的 Ternary Operator statements. If the if statement condition is false then the supplied value is merely used. Ultimately, if the condition is true then we want to take the supplied argument and divide it by 360 but first we use the nested Ternary Operator 语句组成,以确保提供的参数在有效范围内(0 到 360):

h < 0 ? 0 :

如果提供的参数 (h) 小于 0(例如 -22 或 -0.202 的任意值),则将 h 设置为默认值 0,否则我们检查参数值是否为大于 360:

: h > 360 ? 360 :

如果提供的参数 (h) 大于 360(例如 365 或 378.8 的任意值),则将 h 设置为默认值 360,否则认为提供的参数确实在适当的范围,我们将使用它,因此将提供的值除以 360;

: h) / 360

如何使用此方法:

int[] rgb = hslToRGB(65, 36, 87);
System.out.println("RGB is: " + java.util.Arrays.toString(rgb));
String hex = "#" + Integer.toHexString(new Color(rgb[0], rgb[1], rgb[2]).getRGB() & 0x00ffffff);
System.out.println("In Hexadecimal: " + hex.toUpperCase());

控制台输出:

RGB is: [232, 234, 210]
In Hexadecimal: #E8EAD2