RGB、HSL 和 HSV 互相转换

Jul 02, 2020 • 预计阅读时间 3 分钟

原版是 JS 写的,转为 C 版本可以在 iOS 中使用。

https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c

typedef struct {
    NSUInteger r;
    NSUInteger g;
    NSUInteger b;
    CGFloat a;
} RGB;

typedef struct {
    NSUInteger h;
    CGFloat s;
    CGFloat l;
    CGFloat a;
} HSL;

typedef struct {
    NSUInteger h;
    CGFloat s;
    CGFloat v;
    CGFloat a;
} HSV;

/**
 * Converts an RGB color value to HSL. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes r, g, and b are contained in the set [0, 255] and
 * returns h, s, and l in the set [0, 1].
 *
 * @param   Number  r       The red color value
 * @param   Number  g       The green color value
 * @param   Number  b       The blue color value
 * @return  Array           The HSL representation
 */
OBJC_EXTERN HSL RGBToHSL(RGB rgb) {
    CGFloat r = rgb.r / 255.0, g = rgb.g / 255.0, b = rgb.b / 255.0;
    CGFloat max = MAX(MAX(r, g), b), min = MIN(MIN(r, g), b);
    CGFloat h = 0, s = 0, l = (max + min) / 2;

    if (max == min) {
        h = s = 0; // achromatic
    } else {
        CGFloat d = max - min;
        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

        if (max == r) {
            h = (g - b) / d + (g < b ? 6 : 0);
        } else if (max == g) {
            h = (b - r) / d + 2;
        } else {
            h = (r - g) / d + 4;
        }

        h /= 6;
    }

    return (HSL){ .h = round(h * 360), .s = s, .l = l, .a = rgb.a};
}

/**
 * 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   Number  h       The hue
 * @param   Number  s       The saturation
 * @param   Number  l       The lightness
 * @return  Array           The RGB representation
 */
OBJC_EXTERN RGB HSLToRGB(HSL hsl) {
    CGFloat h = hsl.h / 360.0, s = hsl.s, l = hsl.l;
    CGFloat r = 0, g = 0, b = 0;

    if (s == 0) {
        r = g = b = l; // achromatic
    } else {
        CGFloat (^hue2rgb)(CGFloat, CGFloat, CGFloat) = ^CGFloat (CGFloat p, CGFloat q, CGFloat t){
            if (t < 0.0) t += 1;
            if (t > 1.0) t -= 1;
            if (t < 1 / 6.0) return p + (q - p) * 6 * t;
            if (t < 1 / 2.0) return q;
            if (t < 2 / 3.0) return p + (q - p) * (2 / 3.0 - t) * 6;

            return p;
        };

        CGFloat q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        CGFloat p = 2 * l - q;
        r = hue2rgb(p, q, h + 1 / 3.0);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1 / 3.0);
    }

    NSUInteger red = round(r * 255);
    NSUInteger green = round(g * 255);
    NSUInteger blue = round(b * 255);

    return (RGB){ .r = red, .g = green, .b = blue, .a = hsl.a };
}

/**
 * Converts an RGB color value to HSV. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
 * Assumes r, g, and b are contained in the set [0, 255] and
 * returns h, s, and v in the set [0, 1].
 *
 * @param   Number  r       The red color value
 * @param   Number  g       The green color value
 * @param   Number  b       The blue color value
 * @return  Array           The HSV representation
 */
OBJC_EXTERN HSV RGBToHSV(RGB rgb) {
    CGFloat r = rgb.r / 255.0, g = rgb.g / 255.0, b = rgb.b / 255.0;
    CGFloat max = MAX(MAX(r, g), b), min = MIN(MIN(r, g), b);
    CGFloat h = 0, s = 0, v = max;

    CGFloat d = max - min;
    s = max == 0 ? 0 : d / max;

    if (max == min) {
        h = 0; // achromatic
    } else {
        if (max == r) {
            h = (g - b) / d + (g < b ? 6 : 0);
        } else if (max == g) {
            h = (b - r) / d + 2;
        } else {
            h = (r - g) / d + 4;
        }

        h /= 6;
    }

    return (HSV){ .h = round(h * 360), .s = s, .v = v, .a = rgb.a };
}

/**
 * Converts an HSV color value to RGB. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
 * Assumes h, s, and v are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   Number  h       The hue
 * @param   Number  s       The saturation
 * @param   Number  v       The value
 * @return  Array           The RGB representation
 */
OBJC_EXTERN RGB HSVToRGB(HSV hsv) {
    CGFloat r = 0, g = 0, b = 0, h = hsv.h / 360.0, s = hsv.s, v = hsv.v;

    NSUInteger i = floor(h * 6);
    CGFloat f = h * 6 - i;
    CGFloat p = v * (1 - s);
    CGFloat q = v * (1 - f * s);
    CGFloat t = v * (1 - (1 - f) * s);

    switch (i % 6) {
        case 0: { r = v; g = t; b = p; break; }
        case 1: { r = q; g = v; b = p; break; }
        case 2: { r = p; g = v; b = t; break; }
        case 3: { r = p; g = q; b = v; break; }
        case 4: { r = t; g = p; b = v; break; }
        case 5: { r = v; g = p; b = q; break; }
    }

    NSUInteger red = round(r * 255);
    NSUInteger green = round(g * 255);
    NSUInteger blue = round(b * 255);

    return (RGB){ .r = red, .g = green, .b = blue, .a = hsv.a };
}
iOS
版权声明:如果转发请带上本文链接和注明来源。

lvv.me

iOS/macOS Developer

iOS 中使用 CSS 的 HLS 颜色

使用自签名代码证书运行不受信任的程序