Convert from HEX color to RGB struct in C

46,850

Solution 1

Assuming that your hex value is a 32-bit 'int' type, and that we use the RGB struct described above, then maybe do something like:

struct RGB colorConverter(int hexValue)
{
  struct RGB rgbColor;
  rgbColor.r = ((hexValue >> 16) & 0xFF) / 255.0;  // Extract the RR byte
  rgbColor.g = ((hexValue >> 8) & 0xFF) / 255.0;   // Extract the GG byte
  rgbColor.b = ((hexValue) & 0xFF) / 255.0;        // Extract the BB byte

  return rgbColor; 
}

Solution 2

If the hex code is a string, you can parse it like this

char *str = "0000FF";
int r, g, b;
sscanf(str, "%02x%02x%02x", &r, &g, &b);

That is to ints, not doubles. Also do check that sscanf returns 3, the number of items read.

Solution 3

An RGB value can be stored as in integer via 0xRRGGBB. Examples:

  • Red: 0xff0000
  • Green: 0x00ff00
  • Blue: 0x0000ff

00 is hex for decimal 0, while ff is 255. 0 corresponds to 0.0 and 255 to 1.0. (Actually you didn't specify what the range is. I'm assuming 0.0 to 1.0.)

So with the above assumptions, you need to extract each component and divide by 255. Since it sounds a lot like a homework question, I'll just show you how you can do the red component.

int hex = 0x123456;
c.r = ((hex >> 16) & 0xff) / 255.0;

Each hex digit takes up 4 bits. So shift to the right by 16 bits (to move everything 4 digits to the right) to make 0xRRGGBB become 0xRR. Now you have the red component. (Just in case there is some data higher up in the integer, you can get rid of it by masking the data via & 0xff.)

If you are dealing with a string "#FFFFFF", then you'd first have to convert it to an integer for the above to work.

Solution 4

I know this is quite old, but I wanted to give also a solution with unions and without any bitwise operations.

union Color
{
    unsigned int hex;
    struct { unsigned char b, g, r; };
};

This way you can convert from HEX to RGB and from RGB to HEX, easily.

union Color hex;
hex.hex = 0x07C73C;

union Color rgb;
rgb.r = 7;
rgb.g = 199;
rgb.b = 60;

printf("RGB(%d, %d, %d), HEX(%06x)", hex.r, hex.g, hex.b, rgb.hex);

Output:

RGB(7, 199, 60), HEX(07c73c)

and to map the values in the range of 0.0 to 1.0 you simply divide it by 255.0 :)

EDIT: The code above^^ is only supported under Little-Endian CPU's architecture, so a better way is to check what endianness does the system runs on.

Then you can check the endianness to define the order of the struct variables.

union Color
{
    unsigned int hex;

#if IS_BIG_ENDIAN
    struct { unsigned char a, r, g, b; };
#else
    struct { unsigned char b, g, r, a; };
#endif
};

This code also supports alpha ( transparency ) in RGBA.

Solution 5

I guess RGB could be stored as 0xRRGGBB on some systems, but in Windows it is actually stored as 0xBBGGRR (see http://msdn.microsoft.com/en-us/library/windows/desktop/dd183449). As the article mentions, there are macros GetRValue, GetGValue, and GetBValue already available.

Share:
46,850
Shavkat
Author by

Shavkat

Updated on October 17, 2020

Comments

  • Shavkat
    Shavkat over 3 years

    How do you convert from color HEX code to RGB in pure C using C library only (without C++ or templates)? The RGB struct may be like this:

    typedef struct RGB {
        double r;
        double g;
         double b;
    } RGB1;
    

    The function I'm looking for should return RGB1.

    • cubic1271
      cubic1271 over 13 years
      I'm not sure I understand the question. I believe that flagging things as code and / or inserting newlines into the question in strategic places may be helpful in making the question easier for people to read (and therefore answer).
  • ubiquibacon
    ubiquibacon over 13 years
    Kind of ripping off the answer @konforce gave aren't we?
  • cubic1271
    cubic1271 over 13 years
    Nah. There was code in there for string processing too, but the point konforce made about this probably being a homework question was a good one. Thus, I edited this answer to be more like the one kon posted above.
  • Aaron Cowie
    Aaron Cowie almost 9 years
    Should hexValue be of type unsigned int? I think the &0xFF cancels out the arithmetic shift, but wouldn't a value like 0xFFFFFF cause an overflow when it's passed in?
  • cubic1271
    cubic1271 over 7 years
    'unsigned int' would probably be a little nicer. That said, in this instance it wouldn't really matter since RRGGBB fits in 24 bits, and an 'int' type is (pretty universally) 32 bits in length. This answer does assume that the RRGGBB bits are stored a certain way in the int, though ... so caveat emptor.
  • bb1950328
    bb1950328 over 3 years
    use the format string "%2hx%2hx%2hx" if you want to parse it into unsigned short values
  • user14063792468
    user14063792468 over 3 years
    good answer, but you should check for endianness for answer to be complete. See stackoverflow.com/q/18863913/8339821 for a reference.
  • therealcain
    therealcain over 3 years
    good point, I will do some tests and update the answer.
  • user14063792468
    user14063792468 over 3 years
    great, please comment when you do an update. mb you will get an upvote ;)
  • therealcain
    therealcain over 3 years
    @yvw I updated the answer that supports both endianness, I was very unsure if windows systems are only little-endian, ended up using a CPU check macro.
  • user14063792468
    user14063792468 over 3 years
    The BSD seem to have <endian.h> as <sys/endian.h>. Other systems may not have the header at all.
  • therealcain
    therealcain over 3 years
    @yvw I added BSD and Mac OS.
  • user14063792468
    user14063792468 over 3 years
    where does all those defines come from? For example FreeBSD handbook tells us that __FreeBSD__ is defined in all versions of FreeBSD. I do not see OS_FREEBSD defined on my FreeBSD machine. Maybe you should leave the OS issue? You could do a remark on your answer that you have two snippets of code. One for little endian and one for other.
  • therealcain
    therealcain over 3 years
    @yvw hmm... I saw a list of preprocessor macros of some systems on some GitHub gist. I just did a recheck of that, and fixed it. I found that __BIG_ENDIAN__ is defined by clang and gcc without <endian.h>, maybe I should update the code to use it instead? And I also specified that a cross-platform library would better for this, maybe something like boost endian, but I'm pretty sure it's only for C++.
  • user14063792468
    user14063792468 over 3 years
    I look at FreeBSD blob and do not see any _BIG_ENDIAN define there. There are only _LITTLE_ENDIAN. I think you should stop copy/paste from random git.
  • therealcain
    therealcain over 3 years
    I saw it on github.com/openbsd/src/blob/master/sys/sys/endian.h I think I'm just going to redirect to a different StackOverflow question when it comes to endianness. And just going to show both examples for little and big endian.
  • user14063792468
    user14063792468 over 3 years
    This will be a right call. Check the other answers tho. They do not have to guess the endianess, still they work. Just be careful with union's in C.
  • therealcain
    therealcain over 3 years
    I personally barely use unions, I just wanted to show a different way of doing the same thing. :) I would probably never use something like this, due to also performance decrease ( 14 times slower than bitwise ), and due to compilers/endianness limitations. But I think it's nice to know multiple ways of doing the same things, even if they are not the best. Another way of doing it would be by using unsigned char rgba[4] and use getters/setters that check the endianness of the system to behave accordingly. Maybe i should add that too?
  • user14063792468
    user14063792468 over 3 years
    Just leave the endianness issue. Those who could use your code shall take care of it. Apart from that, if your code adds something new to the answers, feel free to commit.
  • SPA
    SPA over 3 years
    I used sscanf(str.c_str(), "%02hhx%02hhx%02hhx", &r, &g, &b); with an std::string to parse it into unsigned char values,
  • JWDN
    JWDN almost 3 years
    I can't upvote Tor's answer enough! Elegant solution.