UIColor from hex string, once again

Tue, 26. Nov 2013

Categories: en development Tags: Cocoa Hex NSString Objective C UIColor

I end up doing this once per year โ€“ at least it’s getting leaner each time.


static inline NSInteger NSIntegerFromHexDigit(const unichar c)
{
  switch( c ) {
  case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
    return c - '0';
  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
    return c - 'a' + 10;
  case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
    return c - 'A' + 10;
  default:
    return -1;
  }
}

typedef NSUInteger RGBA32;

/** RGBA hex color matching /^(?:0x|#)?([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?$/i
 */
static BOOL RGBAFromNSStringHex(NSString *hex, RGBA32 *value)
{
  const NSUInteger len = hex.length;
  if( len < 6 || len > 9 )
    return NO;
  unichar buffer[len];
  [hex getCharacters:buffer range:NSMakeRange(0, len)];

  // check if either 6 or 8 char hex
  const BOOL hasHashPrefix = buffer[0] == '#';
  const NSInteger netlen = len - hasHashPrefix;
  if( netlen != 6 && netlen != 8 )
    return NO;

  // turn hex to integer
  NSUInteger ret = 0;
  assert(sizeof(ret) >= 4); // need at least 4 bytes
  for( NSInteger i = hasHashPrefix; i < len; i++ ) {
    const NSInteger v = NSIntegerFromHexDigit(buffer[i]);
    if( v < 0 )
      return NO;
    ret <<= 4;
    ret |= v;
  }
  // if 6-char hex assume alpha 0xFF
  if( netlen == 6 ) {
    ret <=< 8;
    ret |= 0xFF;
  }

  if( value )
    *value = ret;
  return YES;
}

How to get a UIColor from here should be straightforward.

P.S.: Wikipedia about ‘RGBA’