HSL 与 RGB 互换


#include "stdint.h"

/*
 * RGB      HSL
 * 255,255,255  0,0,255
 * 0,255,255    128,255,128
 * 128,255,255  128,255,192
 * 0,0,255      170,255,128
 * 0,128,255    149,255,128
 * 0,0,0        0,0,0
 * 0,0,128      170,255,64
 *
 *
 * 42*r/255 =>
 *
 *
 * */


typedef union
{
    struct
    {
        uint8_t red; // [0,255]
        uint8_t green; // [0,255]
        uint8_t blue; // [0,255]
    };
    struct
    {
        uint8_t r; // [0,255]
        uint8_t g; // [0,255]
        uint8_t b; // [0,255]
    };
} COLOR_RGB;


typedef union
{
    struct
    {
        uint8_t hue; // [0,360] 色调
        uint8_t saturation; // [0,_D_saturation_MAX] 饱和度
        uint8_t luminance; // [0,_D_luminance_MAX] 亮度
    };
    struct
    {
        uint8_t h; // [0,360] 色调
        uint8_t s; // [0,_D_saturation_MAX] 饱和度
        uint8_t l; // [0,_D_luminance_MAX] 亮度
    };
} COLOR_HSL;

typedef struct {
    float r; // [0,255]
    float g; // [0,255]
    float b; // [0,255]
}ColorF;

#define _D_HUE_MAX (255.0)
#define _D_saturation_MAX (255.0)
#define _D_luminance_MAX (255.0)

#define min3v(v1, v2, v3) (v1<v2? (v1<v3? v1:(v2<v3? v2:v3)):(v2<v3? v2:v3))
#define max3v(v1, v2, v3) (v1<v2? (v2<v3? v3:v2):(v1<v3? v3:v1))
// Converts RGB to HSL
static COLOR_HSL rgb2hsl(/*[in]*/const COLOR_RGB rgb, /*[out]*/COLOR_HSL *hsl=0)
{
    ColorF color={(float)rgb.r, (float)rgb.g, (float)rgb.b};
    float h=0, s=0, l=0;
    // normalizes red-green-blue values
    float maxVal = 0;
    float minVal = 0;
    COLOR_HSL HSL;

    const float bh = 1.0/6.0*_D_HUE_MAX;

    color.r = ( color.r )/255.0f;
    color.g = ( color.g )/255.0f;
    color.b = ( color.b )/255.0f;

    maxVal = max3v(color.r, color.g, color.b);
    minVal = min3v(color.r, color.g, color.b);

    // hue
    if(maxVal == minVal)
    {
        h = 0; // undefined
    }
    else if(maxVal==color.r && color.g>=color.b)
    {
        h = bh*(color.g-color.b)/(maxVal-minVal);
    }
    else if(maxVal==color.r && color.g<color.b)
    {
        h = bh*(color.g-color.b)/(maxVal-minVal) + _D_HUE_MAX;
    }
    else if(maxVal==color.g)
    {
        h = bh*(color.b-color.r)/(maxVal-minVal) + 1.0/3.0*_D_HUE_MAX;
    }
    else if(maxVal==color.b)
    {
        h = bh*(color.r-color.g)/(maxVal-minVal) + 2.0/3.0*_D_HUE_MAX;
    }

    // luminance
    l = (maxVal+minVal)/2.0f;

    // saturation
    if(l == 0 || maxVal == minVal)
    {
        s = 0.0;
    }
    else if(0<l && l<=0.5f)
    {
        s = (maxVal-minVal)/(maxVal+minVal);
    }
    else if(l>0.5f)
    {
        s = (maxVal-minVal)/(2.0 - (maxVal+minVal)); //(maxVal-minVal > 0)?
    }

    //  qDebug(">> H=%f; S=%f; L=%f ", h, s, l );

    HSL.h = ((h>_D_HUE_MAX)? _D_HUE_MAX : ((h<0)?0:h));
    HSL.s = (((s>1)? 1 : ((s<0)?0:s))*_D_saturation_MAX);
    HSL.l = (((l>1)? 1 : ((l<0)?0:l))*_D_luminance_MAX);

    if(hsl!=0)
    {
        *hsl=HSL;
    }

    return HSL;
}

// Converts HSL to RGB
static COLOR_RGB hsl2rgb(const COLOR_HSL hsl, COLOR_RGB *rgb=0)
{
    float h =  hsl.h;// /255.0 * _D_HUE_MAX;
    float s =  hsl.s;// /255.0 * _D_saturation_MAX;
    float l =  hsl.l;// /255.0 * _D_luminance_MAX;

    COLOR_RGB rgba;
    ColorF color;

    h = h; // h must be [0, _D_HUE_MAX]
    s = ((float)s)/_D_saturation_MAX; // s must be [0, 1]
    l = ((float)l)/_D_luminance_MAX; // l must be [0, 1]

    if(hsl.s == 0)
    {
        // achromatic color (gray scale)
        color.r=color.g=color.b= l*255.f;
    }
    else
    {
        float q = (l<0.5f)?(l * (1.0f+s)):(l+s - (l*s));
        float p = (2.0f * l) - q;
        float hk = h/_D_HUE_MAX;
        float *tc=(float *) &color;

        color.r = hk + 1.0/3.0; // Tr 0.3333333f=1.0/3.0
        color.g = hk; // Tb
        color.b = hk - 1.0/3.0; // Tg

        for(int i=0; i<3; i++)
        {
            if(tc[i] < 0) tc[i] += 1.0f;
            if(tc[i] > 1) tc[i] -= 1.0f;

            if((tc[i]*6) < 1)
            {
                tc[i] = p + ((q-p)*6.0f*tc[i]);
            }
            else if(1.0<=(tc[i]*6.0) && tc[i]<0.5 )
            {
                tc[i] = q;
            }
            else if( 0.5<=tc[i] && (tc[i]*3.0)<2.0 )
            {
                tc[i] = p + (q-p) * ((2.0f/3.0f) - tc[i]) * 6.0f;
            }
            else tc[i] = p;
        }

        color.r*=255.0f;
        color.g*=255.0f;
        color.b*=255.0f;

    }

    if( 0!=rgb )
    {
        rgb->r = (uint8_t)((color.r>255)? 255 : ((color.r<0)?0 : color.r));
        rgb->g = (uint8_t)((color.g>255)? 255 : ((color.g<0)?0 : color.g));
        rgb->b = (uint8_t)((color.b>255)? 255 : ((color.b<0)?0 : color.b));
        return *rgb;
    }
    else
    {
        rgba.r = (uint8_t)((color.r>255)? 255 : ((color.r<0)?0 : color.r));
        rgba.g = (uint8_t)((color.g>255)? 255 : ((color.g<0)?0 : color.g));
        rgba.b = (uint8_t)((color.b>255)? 255 : ((color.b<0)?0 : color.b));
        return rgba;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值