Home > database >  Convert HSL color to RGB and HEX using SQL
Convert HSL color to RGB and HEX using SQL

Time:11-26

The problem started when I needed to apply conditional formatting to a table with smooth color changes in MS SQL Server Reporting Services (SSRS). It is impossible with standard SSRS functionality. But you can use the table data to smoothly change the color with the Lightness parameter in the HSL color model.

The question is, how to convert HSL to usable in SSRS HEX or RGB color codes using SQL.

No answers were found at Stackoverflow or anywhere else, only for other programming languages

CodePudding user response:

I've based the following solution on this article. As mentioned, I use 2 functions here, and I also return a dataset in both (3 columns for RGB, 1 for the hex):

CREATE OR ALTER FUNCTION dbo.HSLtoRGB (@H numeric(3,0),@S numeric(4,3), @L numeric(4,3)) 
RETURNS table
AS RETURN
    SELECT CONVERT(tinyint,ROUND((RGB1.R1 m.m)*255,0)) AS R,
           CONVERT(tinyint,ROUND((RGB1.G1 m.m)*255,0)) AS G,
           CONVERT(tinyint,ROUND((RGB1.B1 m.m)*255,0)) AS B
    FROM (VALUES(@H, @S, @L))HSL(Hue,Saturation,Lightness)
         CROSS APPLY(VALUES((1-ABS((2*HSL.Lightness - 1))) * HSL.Saturation)) C(Chroma)
         CROSS APPLY(VALUES(HSL.Hue/60,C.Chroma * (1 - ABS((HSL.Hue/60) % 2 - 1))))H([H`],X)
         CROSS APPLY(SELECT TOP (1) * --It's unlikely there would be 2 rows, but just incase limit to 1
                     FROM (VALUES(C.Chroma,H.X,0,0,1),
                                 (H.X,C.Chroma,0,1,2),
                                 (0,C.Chroma,H.X,2,3),
                                 (0,H.X,C.Chroma,3,4),
                                 (H.X,0,C.Chroma,4,5),
                                 (C.Chroma,0,H.X,5,6))V(R1,G1,B1,S,E)
                    WHERE V.S <= H.[H`] AND H.[H`] <= V.E
                    ORDER BY V.E DESC) RGB1 
         CROSS APPLY (VALUES(HSL.Lightness - (C.Chroma / 2)))m(m);
GO
CREATE OR ALTER FUNCTION dbo.HSLtoRGB_HEX (@H numeric(3,0),@S numeric(4,3), @L numeric(4,3)) 
RETURNS table
AS RETURN
    SELECT CONVERT(binary(3),CONCAT(CONVERT(varchar(2),CONVERT(binary(1),CONVERT(tinyint,ROUND((RGB1.R1 m.m)*255,0))),2),
                                    CONVERT(varchar(2),CONVERT(binary(1),CONVERT(tinyint,ROUND((RGB1.G1 m.m)*255,0))),2),
                                    CONVERT(varchar(2),CONVERT(binary(1),CONVERT(tinyint,ROUND((RGB1.B1 m.m)*255,0))),2)),2) AS RGB
    FROM (VALUES(@H, @S, @L))HSL(Hue,Saturation,Lightness)
         CROSS APPLY(VALUES((1-ABS((2*HSL.Lightness - 1))) * HSL.Saturation)) C(Chroma)
         CROSS APPLY(VALUES(HSL.Hue/60,C.Chroma * (1 - ABS((HSL.Hue/60) % 2 - 1))))H([H`],X)
         CROSS APPLY(SELECT TOP(1) * --It's unlikely there would be 2 rows, but just incase limit to 1
                     FROM (VALUES(C.Chroma,H.X,0,0,1),
                                 (H.X,C.Chroma,0,1,2),
                                 (0,C.Chroma,H.X,2,3),
                                 (0,H.X,C.Chroma,3,4),
                                 (H.X,0,C.Chroma,4,5),
                                 (C.Chroma,0,H.X,5,6))V(R1,G1,B1,S,E)
                    WHERE V.S <= H.[H`] AND H.[H`] <= V.E
                    ORDER BY V.E DESC) RGB1
         CROSS APPLY (VALUES(HSL.Lightness - (C.Chroma / 2)))m(m);
GO

SELECT *
FROM (VALUES(210,.79,.3),
            (24,.83,.74),
            (360,1,1),
            (0,0,0))V(H,S,L)
     CROSS APPLY dbo.HSLtoRGB(V.H, V.S, V.L) RGB
     CROSS APPLY dbo.HSLtoRGB_Hex(V.H, V.S, V.L) RGBhex;

CodePudding user response:

After all I came to rewriting the VBA function from here to SQL

It has the following parameters:

  • @HueDegree [0,360]
  • @Saturation [0,1]
  • @Lightness [0,1]
  • @Format ('RGB' or 'HEX')

Result is a color code in chosen format

create function dbo.f_convertHSL (
    @HueDegree numeric(3,0), 
    @Saturation numeric(6,3), 
    @Lightness numeric(6,3), 
    @Format varchar(3) )
returns varchar(100)
as

begin

    declare @HuePercent numeric(6,3),
            @Red numeric(6,3), 
            @Green numeric(6,3), 
            @Blue numeric(6,3),
            @Temp1 numeric(6,3), 
            @Temp2 numeric(6,3),
            @TempR numeric(6,3),
            @TempG numeric(6,3),
            @TempB numeric(6,3), 
            @Result varchar(100);

    if @Saturation = 0 
    begin
        select @Red = @Lightness * 255,
               @Green = @Lightness * 255,
               @Blue = @Lightness * 255;

        if @Format = 'RGB'
            select @Result = cast(cast(@Red as int) as varchar)   ', '
                               cast(cast(@Green as int) as varchar)   ', '
                               cast(cast(@Blue as int) as varchar);
        else if @Format = 'HEX'
            select @Result = '#'   convert(varchar(2), convert(varbinary(1), cast(@Red as int)), 2)
                                   convert(varchar(2), convert(varbinary(1), cast(@Green as int)), 2)
                                   convert(varchar(2), convert(varbinary(1), cast(@Blue as int)), 2);
        else select @Result = 'Format should be RGB or HEX';

        return @Result;
    end;

    if @Lightness < 0.5
        select @Temp1 = @Lightness * (1   @Saturation);
    else
        select @Temp1 = @Lightness   @Saturation - @Lightness * @Saturation;

    select @Temp2 = 2 * @Lightness - @Temp1
         , @HuePercent = @HueDegree / 360.0;

    select @TempR = @HuePercent   0.333
         , @TempG = @HuePercent
         , @TempB = @HuePercent - 0.333;

    if @TempR < 0 select @TempR = @TempR   1;
    if @TempR > 1 select @TempR = @TempR - 1;
    if @TempG < 0 select @TempG = @TempG   1;
    if @TempG > 1 select @TempG = @TempG - 1;
    if @TempB < 0 select @TempB = @TempB   1;
    if @TempB > 1 select @TempB = @TempB - 1;

    if @TempR * 6 < 1 select @Red = @Temp2   (@Temp1 - @Temp2) * 6 * @TempR
    else if @TempR * 2 < 1 select @Red = @Temp1
    else if @TempR * 3 < 2 select @Red = @Temp2   (@Temp1 - @Temp2) * (0.666 - @TempR) * 6
    else select @Red = @Temp2;

    if @TempG * 6 < 1 select @Green = @Temp2   (@Temp1 - @Temp2) * 6 * @TempG
    else if @TempG * 2 < 1 select @Green = @Temp1
    else if @TempG * 3 < 2 select @Green = @Temp2   (@Temp1 - @Temp2) * (0.666 - @TempG) * 6
    else select @Green = @Temp2;

    if @TempB * 6 < 1 select @Blue = @Temp2   (@Temp1 - @Temp2) * 6 * @TempB
    else if @TempB * 2 < 1 select @Blue = @Temp1
    else if @TempB * 3 < 2 select @Blue = @Temp2   (@Temp1 - @Temp2) * (0.666 - @TempB) * 6
    else select @Blue = @Temp2;

    select @Red = round(@Red * 255, 0),
           @Green = round(@Green * 255, 0),
           @Blue = round(@Blue * 255, 0);

    if @Format = 'RGB'
        select @Result = cast(cast(@Red as int) as varchar)   ', '
                              cast(cast(@Green as int) as varchar)   ', '
                              cast(cast(@Blue as int) as varchar);
    else if @Format = 'HEX'
        select @Result = '#'   convert(varchar(2), convert(varbinary(1), cast(@Red as int)), 2)
                               convert(varchar(2), convert(varbinary(1), cast(@Green as int)), 2)
                               convert(varchar(2), convert(varbinary(1), cast(@Blue as int)), 2);
    else select @Result = 'Format should be RGB or HEX';

    return @Result;

end;

Usage examples:

select dbo.f_convertHSL(24, 0.83, 0.74, 'RGB')
result: 244, 178, 134
select dbo.f_convertHSL(24, 0.83, 0.74, 'HEX')
result: #F4B286

Result can be confirmed for example here

  • Related