Convert RGB color to HEX Color using SQL

  • Hello all I have a field in one of my tables that has the RGB colors stored as 255,255,255 format. Is there a way to convert this to Hex color code to be used inside SSRS for a conditional color expression?

    Thanks!

    Thomas

    ***SQL born on date Spring 2013:-)

  • thomashohner (3/14/2015)


    Hello all I have a field in one of my tables that has the RGB colors stored as 255,255,255 format. Is there a way to convert this to Hex color code to be used inside SSRS for a conditional color expression?

    Thanks!

    Thomas

    I'm not familiar with the "Hex Color Code" inside of SSRS. What datatype should it be and what does one look like? Should they be character based and look like the following? #FFFFFF

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Yes sir,

    Did I say it wrong on what data type it should be?

    ***SQL born on date Spring 2013:-)

  • I also have the color stored as a Int

    So I have either this format 255,255,224 or 14745599

    ***SQL born on date Spring 2013:-)

  • thomashohner (3/14/2015)


    Yes sir,

    Did I say it wrong on what data type it should be?

    Oh no... You did fine. It's just that I can't even spell "SSRS" and, although my assistant DBA's name is "Google", I wanted to be absolutely sure. 😛

    Here's a quick example of the code you could use for an Inline Table Valued Function to solve the string version. I'm playing with the INT solution and intend to write a function that will take either the string version or the INT version.

    DECLARE @StringRGB VARCHAR(11);

    SELECT @StringRGB = '127,16,0';

    WITH

    cteParms AS

    (

    SELECT HexDigits = '0123456789ABCDEF'

    ,R = MAX(CASE WHEN split.ItemNumber = 1 THEN Item ELSE 0 END)

    ,G = MAX(CASE WHEN split.ItemNumber = 2 THEN Item ELSE 0 END)

    ,B = MAX(CASE WHEN split.ItemNumber = 3 THEN Item ELSE 0 END)

    FROM dbo.DelimitedSplit8K(@StringRGB,',') split

    )

    SELECT RGBHexColor = '#'

    + SUBSTRING(HexDigits,R/16+1,1)+SUBSTRING(HexDigits,R%16+1,1)

    + SUBSTRING(HexDigits,G/16+1,1)+SUBSTRING(HexDigits,G%16+1,1)

    + SUBSTRING(HexDigits,B/16+1,1)+SUBSTRING(HexDigits,B%16+1,1)

    FROM cteParms

    ;

    If you don't know what "dbo.DelimitedSplit8K" is, you can find it in the "Resources" section of the following article.

    http://www.sqlservercentral.com/articles/Tally+Table/72993/

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Wow Jeff you always amaze!

    Just blown away 😀

    I was trying to figure out a efficient solution. I found this Scalar Function online it use the INT version of my column . However I prefer even though it works not to use it as I know it might cause some performance issues.

    As this query has the potential to run into several hundred thousand rows.

    CREATE FUNCTION [dbo].[ARGB2RGB]

    (@ARGB AS BIGINT )

    RETURNS VARCHAR (15)

    AS

    BEGIN

    DECLARE @Octet1 TINYINT

    DECLARE @Octet2 TINYINT

    DECLARE @Octet3 TINYINT

    DECLARE @Octet4 TINYINT

    DECLARE @RestOfColor BIGINT

    SET @Octet1 = @ARGB / 16777216

    SET @RestOfColor = @ARGB - ( @Octet1 * CAST(16777216 AS BIGINT) )

    SET @Octet2 = @RestOfColor / 65536

    SET @RestOfColor = @RestOfColor - ( @Octet2 * 65536 )

    SET @Octet3 = @RestOfColor / 256

    SET @Octet4 = @RestOfColor - ( @Octet3 * 256 )

    RETURN

    '#' + RIGHT(sys.fn_varbintohexstr(@Octet4), 2)

    + RIGHT(sys.fn_varbintohexstr(@Octet3), 2)

    + RIGHT(sys.fn_varbintohexstr(@Octet2), 2)

    END

    ***SQL born on date Spring 2013:-)

  • This will really make it so you don't want to use the scalar function you posted. The sys.fn_varbintohexstr function calls yet another scalar function called sys.fn_varbintohexsubstring and it not only contains flow control logic, but it also contains a WHILE loop.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Hi Thomas,

    here is a quick example of RGB triplet string into a hex conversion

    😎

    DECLARE @STRCD VARCHAR(11) = '255,128,255';

    SELECT

    CONVERT(VARCHAR(11),CONVERT(BINARY(1),CONVERT(INT,SUBSTRING(@STRCD,1,CHARINDEX(',',@STRCD)-1),0),0)

    + CONVERT(BINARY(1),CONVERT(INT,SUBSTRING(@STRCD,CHARINDEX(',',@STRCD) + 1,CHARINDEX(',',@STRCD)-1),0),0)

    + CONVERT(BINARY(1),CONVERT(INT,RIGHT(@STRCD,CHARINDEX(',',REVERSE(@STRCD),1)-1),0),0),1);

    Result

    0xFF80FF

  • Huh... It's been a long time since I've played with hex in SQL Server. I believe I may have an even better and faster way than what I posted. It might make the integer problem a whole lot easier, as well.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • I am currently building the report with my test data. Its small so my original function is working well but wont on larger data sets. The stuff you pointed out about my original function scares the living tar out of me. You and Erik is why I come here its a amazing learning experience!

    Excited to see what you come up with for the INT column. I have been playing and dissecting both yours and Eriks code and I'm just blown away how quick you guys did that. (That's the way I learn to take things apart and see how they move.)Some day I want to be there answering questions instead of asking them!

    Thanks so much guys. 😀

    ***SQL born on date Spring 2013:-)

  • With the integer you will have to reverse the byte order, here is a quick example

    😎

    DECLARE @COLOURINT INT = 14745599;

    SELECT CHAR(35) + CONVERT(VARCHAR(6),SUBSTRING(CONVERT(BINARY(3),@COLOURINT,1),3,1) + SUBSTRING(CONVERT(BINARY(3),@COLOURINT,1),2,1) + SUBSTRING(CONVERT(BINARY(3),@COLOURINT,1),1,1),2)

    Result

    #FFFFE0

  • Holy smokes Batman

    That is awesome Erik!

    I can put that directly into the code and this makes it where I don't have to install any other objects beside my SP.

    Just put it in the Update Statement sweet!!

    I love SQL Server Central !!

    So much thanks to you and Jeff. Now After I finish my report to understand what you guys were doing.

    ***SQL born on date Spring 2013:-)

  • thomashohner (3/14/2015)


    I am currently building the report with my test data. Its small so my original function is working well but wont on larger data sets. The stuff you pointed out about my original function scares the living tar out of me. You and Erik is why I come here its a amazing learning experience!

    Excited to see what you come up with for the INT column. I have been playing and dissecting both yours and Eriks code and I'm just blown away how quick you guys did that. (That's the way I learn to take things apart and see how they move.)Some day I want to be there answering questions instead of asking them!

    Thanks so much guys. 😀

    Heh... OMG!!! Was this ever fun to revisit! Thank YOU for asking the question. I taught myself something new about CONVERT (the new functionality is available in 2008 and above) on this go around. I also avoided the use of DelimitedSplit8k so that we wouldn't have to worry so much about dependent code within the function. Seemed appropriate in this case since PARSENAME also provided some serious "shortcut" technology in resolving both types of inputs.

    This will handle both types of inputs that you asked for and, I believe, in a spritely fashion. As usual, details are in the code where they belong.

    CREATE FUNCTION dbo.RGBCode

    /**********************************************************************************************************************

    Purpose:

    Given an "RGB" value in the form of either "R,G,B" where each value is a decimal octet (0-255) or single

    "DecimalColorValue" that represents the full color, convert the given value to an HTML Color Value in the form of

    "#rrggbb" where "rr", "gg", and "bb" are two character representations of hex bytes.

    Programmer's Notes:

    1. Note that this function uses functionality from the CONVERT function that is only available in SQL Server 2008

    and above. It will NOT work in 2005 and below.

    2. If any individual parameter cannot be implicitly converted to an INT, the code will fail with the following

    error:

    Msg 245, Level 16, State 1, Line 1

    Conversion failed when converting the nvarchar value 'x38' to data type int.

    3. No error checking is done for negative numbers or octets being in the range of 0-255 and will return incorrect

    results if such problem parameters are passed in.

    4. If more than 3 delimited values are provided as the input, only 3 of the values will be used from right to

    left as "R,G,B".

    Usage Examples:

    --===== Simple Single Value Syntax using "R,G,B" values (Strawberry Color #BE2625, in this case)

    SELECT RGBCode FROM dbo.RGBCode('190,38,37')

    ;

    --===== This will return the same value as if '190,38,37' were used. See Note 4 in the "Programmer's Notes" above.

    SELECT RGBCode FROM dbo.RGBCode('100,190,38,37')

    ;

    --===== Simple Single Value Syntax using a "DecimalColorValue" value (Strawberry Color #BE2625, in this case).

    -- Note that the code does a byte reversal to support when the decimal values come from a GUI where the LSB is

    furthest to the right and the MSB is furthest to the left at the machine language level.

    SELECT RGBCode FROM dbo.RGBCode(2434750)

    ;

    --===== Multi-row Syntax using "R,G,B" values.

    SELECT ca.RGBCode

    FROM dbo.SomeTable st

    CROSS APPLY dbo.RGBCode(st.RGBColumn) ca

    ;

    --===== Multi-row Syntax using a "DecimalColorValue" value.

    -- Note that the code does a byte reversal to support when the decimal values come from a GUI where the LSB

    and MSB are reversed compared to SQL Server returns at the machine language level.

    SELECT ca.RGBCode

    FROM dbo.SomeTable st

    CROSS APPLY dbo.RGBCode(st.DecimalColorValue) ca

    ;

    Revision History:

    Rev 00 - 14 Mar 2015 - Jeff Moden

    - Initial creation and partial unit testing.

    - Reference: http://www.sqlservercentral.com/Forums/Topic1668566-391-1.aspx (Original requirement)

    - Reference: http://www.december.com/html/spec/colorcodes.html (HTML Color Codes)

    **********************************************************************************************************************/

    --===== Define the I/O for this function

    (@StringRGB VARCHAR(20))

    RETURNS TABLE WITH SCHEMABINDING AS

    RETURN WITH

    cteReDelim AS ( --=== Prepare for parsing with PARSENAME.

    SELECT Newstring = REPLACE(@StringRGB,',','.')

    )

    ,cteRGBHex AS ( --=== Parses the input string whether it is "R,G,B" or "DecimalValue"

    SELECT RGB = CONVERT

    ( --== Convert each part to a decimal value and add them up.

    BINARY(3)

    ,ISNULL(PARSENAME(NewString,1),0) --Only one filled if single decimal passed in.

    +ISNULL(PARSENAME(NewString,2),0)*256

    +ISNULL(PARSENAME(NewString,3),0)*65536

    )

    FROM cteReDelim

    )

    ,cteReverse AS ( --=== Reverses the bytes if a single decimal value was passed in.

    SELECT RGB = CASE

    WHEN @StringRGB LIKE '%,%'

    THEN RGB

    ELSE CONVERT(BINARY(3),REVERSE(RGB))

    END

    FROM cteRGBHex

    )

    --===== Convert the resulting 0xHEX to a string and prefix with "#".

    SELECT RGBCode = '#' + CONVERT(CHAR(7),RGB,2)

    FROM cteReverse

    ;

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Eirikur Eiriksson (3/14/2015)


    With the integer you will have to reverse the byte order, here is a quick example

    😎

    DECLARE @COLOURINT INT = 14745599;

    SELECT CHAR(35) + CONVERT(VARCHAR(6),SUBSTRING(CONVERT(BINARY(3),@COLOURINT,1),3,1) + SUBSTRING(CONVERT(BINARY(3),@COLOURINT,1),2,1) + SUBSTRING(CONVERT(BINARY(3),@COLOURINT,1),1,1),2)

    Result

    #FFFFE0

    I make no claims of performance, in this case, and have no clue if it will be better or worse for performance (out of time for today). I just want to show what is possible with the new functionality available in CONVERT as of 2008 that does the same thing as Eirikur's good code above..

    DECLARE @COLOURINT INT = 14745599;

    SELECT '#'+CONVERT(CHAR(7),CONVERT(BINARY(3),REVERSE(CONVERT(BINARY(3),@COLOURINT))),2);

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Thanks again Jeff , "Jefe el Sql ",

    I ran both convert codes and on my limited test data (1,000 rows) they were both uber fast. Not even a 1 ms.

    The real test of course would be production with 500,000 + rows so I should see that on Monday.

    However, even though this is the first time I have ever come across this situation, when I googled it, it was clear I was not the first to come across this situation.

    This would be a great article for us SSRS/BI folks. I however don't have the skill nor the intellect to do so. I now however am researching more information on Convert because of this.

    I can honestly say SQL Server Central beat my Google Fu again.

    Thanks again Gentlemen truly a inspiration to us sql noobies:-)

    ***SQL born on date Spring 2013:-)

Viewing 15 posts - 1 through 15 (of 34 total)

You must be logged in to reply to this topic. Login to reply