views:

473

answers:

3

I've got an NSColor, and I really want the 32-bit RGBA value that it represents. Is there any easy way to get this, besides extracting the float components, then multiplying and ORing and generally doing gross, endian-dependent things?

Edit: Thanks for the help. Really, what I was hoping for was a Cocoa function that already did this, but I'm cool with doing it myself.

+1  A: 

Converting the 4 floats to their integer representation, however you want to accomplish that, is the only way.

Sparr
+1  A: 

Not all colors have an RGBA representation. They may have an approximation in RGBA, but that may or may not be accurate. Furthermore, there are "colors" that are drawn by Core Graphics as patterns (for example, the window background color on some releases of Mac OS X).

Chris Hanson
+3  A: 

Another more brute force approach would be to create a temporary CGBitmapContext and fill with the color.

NSColor *someColor = {whatever};
uint8_t data[4];

CGContextRef ctx = CGBitmapContextCreate((void*)data, 1, 1, 8, 4, colorSpace, kCGImageAlphaFirst | kCGBitmapByteOrder32Big);

CGContextSetRGBFillColor(ctx, [someColor redComponent], [someColor greenComponent], [someColor blueComponent], [someColor alphaComponent]);

CGContextFillRect(ctx, CGRectMake(0,0,1,1));

CGContextRelease(ctx);

FWIW, there are no endian issues with an 8 bit per component color value. Endianness is only with 16 bit or greater integers. You can lay out the memory any way you want, but the 8 bit integer values are the same whether a big endian or little endian machine. (ARGB is the default 8 bit format for Core Graphics and Core Image I believe).

Why not just this?:

uint32_t r = (uint32_t)(MIN(1.0f, MAX(0.0f, [someColor redComponent])) * 255.0f);
uint32_t g = (uint32_t)(MIN(1.0f, MAX(0.0f, [someColor greenComponent])) * 255.0f);
uint32_t b = (uint32_t)(MIN(1.0f, MAX(0.0f, [someColor blueComponent])) * 255.0f);
uint32_t a = (uint32_t)(MIN(1.0f, MAX(0.0f, [someColor alphaComponent])) * 255.0f);
uint32_t value = (r << 24) | (g << 16) | (b << 8) | a;

Then you know exactly how it is laid out in memory.

Or this, if its more clear to you:

uint8_t r = (uint8_t)(MIN(1.0f, MAX(0.0f, [someColor redComponent])) * 255.0f);
uint8_t g = (uint8_t)(MIN(1.0f, MAX(0.0f, [someColor greenComponent])) * 255.0f);
uint8_t b = (uint8_t)(MIN(1.0f, MAX(0.0f, [someColor blueComponent])) * 255.0f);
uint8_t a = (uint8_t)(MIN(1.0f, MAX(0.0f, [someColor alphaComponent])) * 255.0f);

uint8_t data[4];
data[0] = r;
data[1] = g;
data[2] = b;
data[3] = a;
“FWIW, there are no endian issues with an 8 bit per component color value.” Yes there are, if you handle the pixel as a 32-bit unit (with a type such as uint32_t). Try it: Save one RGBA pixel on one system, then load it on another with different endianness. You'll get ABGR.
Peter Hosey