澎湃iPad上线版本

UIColor-Expanded.m 22KB

    #import "UIColor-Expanded.h" /* Thanks to Poltras, Millenomi, Eridius, Nownot, WhatAHam, jberry, and everyone else who helped out but whose name is inadvertantly omitted */ /* Current outstanding request list: - PolarBearFarm - color descriptions ([UIColor warmGrayWithHintOfBlueTouchOfRedAndSplashOfYellowColor]) - Crayola color set - Eridius - UIColor needs a method that takes 2 colors and gives a third complementary one - Consider UIMutableColor that can be adjusted (brighter, cooler, warmer, thicker-alpha, etc) */ /* FOR REFERENCE: Color Space Models: enum CGColorSpaceModel { kCGColorSpaceModelUnknown = -1, kCGColorSpaceModelMonochrome, kCGColorSpaceModelRGB, kCGColorSpaceModelCMYK, kCGColorSpaceModelLab, kCGColorSpaceModelDeviceN, kCGColorSpaceModelIndexed, kCGColorSpaceModelPattern }; */ static const char *colorNameDB; // Complete dictionary of color name -> color mappings, generated // by a call to +namedColors or +colorWithName: static NSDictionary *colorNameCache = nil; static NSLock *colorNameCacheLock; #if SUPPORTS_UNDOCUMENTED_API // UIColor_Undocumented // Undocumented methods of UIColor @interface UIColor (UIColor_Undocumented) - (NSString *)styleString; @end #endif // SUPPORTS_UNDOCUMENTED_API @interface UIColor (UIColor_Expanded_Support) + (void)populateColorNameCache; @end #pragma mark - @implementation UIColor (UIColor_Expanded) - (CGColorSpaceModel)colorSpaceModel { return CGColorSpaceGetModel(CGColorGetColorSpace(self.CGColor)); } - (NSString *)colorSpaceString { switch (self.colorSpaceModel) { case kCGColorSpaceModelUnknown: return @"kCGColorSpaceModelUnknown"; case kCGColorSpaceModelMonochrome: return @"kCGColorSpaceModelMonochrome"; case kCGColorSpaceModelRGB: return @"kCGColorSpaceModelRGB"; case kCGColorSpaceModelCMYK: return @"kCGColorSpaceModelCMYK"; case kCGColorSpaceModelLab: return @"kCGColorSpaceModelLab"; case kCGColorSpaceModelDeviceN: return @"kCGColorSpaceModelDeviceN"; case kCGColorSpaceModelIndexed: return @"kCGColorSpaceModelIndexed"; case kCGColorSpaceModelPattern: return @"kCGColorSpaceModelPattern"; default: return @"Not a valid color space"; } } - (BOOL)canProvideRGBComponents { switch (self.colorSpaceModel) { case kCGColorSpaceModelRGB: case kCGColorSpaceModelMonochrome: return YES; default: return NO; } } - (NSArray *)arrayFromRGBAComponents { NSAssert(self.canProvideRGBComponents, @"Must be an RGB color to use -arrayFromRGBAComponents"); CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return nil; return [NSArray arrayWithObjects: [NSNumber numberWithFloat:r], [NSNumber numberWithFloat:g], [NSNumber numberWithFloat:b], [NSNumber numberWithFloat:a], nil]; } - (BOOL)red:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha { const CGFloat *components = CGColorGetComponents(self.CGColor); CGFloat r,g,b,a; switch (self.colorSpaceModel) { case kCGColorSpaceModelMonochrome: r = g = b = components[0]; a = components[1]; break; case kCGColorSpaceModelRGB: r = components[0]; g = components[1]; b = components[2]; a = components[3]; break; default: // We don't know how to handle this model return NO; } if (red) *red = r; if (green) *green = g; if (blue) *blue = b; if (alpha) *alpha = a; return YES; } - (BOOL)hue:(CGFloat *)hue saturation:(CGFloat *)saturation brightness:(CGFloat *)brightness alpha:(CGFloat *)alpha { CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return NO; [UIColor red:r green:g blue:b toHue:hue saturation:saturation brightness:brightness]; if (alpha) *alpha = a; return YES; } - (CGFloat)red { NSAssert(self.canProvideRGBComponents, @"Must be an RGB color to use -red"); const CGFloat *c = CGColorGetComponents(self.CGColor); return c[0]; } - (CGFloat)green { NSAssert(self.canProvideRGBComponents, @"Must be an RGB color to use -green"); const CGFloat *c = CGColorGetComponents(self.CGColor); if (self.colorSpaceModel == kCGColorSpaceModelMonochrome) return c[0]; return c[1]; } - (CGFloat)blue { NSAssert(self.canProvideRGBComponents, @"Must be an RGB color to use -blue"); const CGFloat *c = CGColorGetComponents(self.CGColor); if (self.colorSpaceModel == kCGColorSpaceModelMonochrome) return c[0]; return c[2]; } - (CGFloat)white { NSAssert(self.colorSpaceModel == kCGColorSpaceModelMonochrome, @"Must be a Monochrome color to use -white"); const CGFloat *c = CGColorGetComponents(self.CGColor); return c[0]; } - (CGFloat)hue { NSAssert(self.canProvideRGBComponents, @"Must be an RGB color to use -hue"); CGFloat h = 0.0f; [self hue:&h saturation:nil brightness:nil alpha:nil]; return h; } - (CGFloat)saturation { NSAssert(self.canProvideRGBComponents, @"Must be an RGB color to use -saturation"); CGFloat s = 0.0f; [self hue:nil saturation:&s brightness:nil alpha:nil]; return s; } - (CGFloat)brightness { NSAssert(self.canProvideRGBComponents, @"Must be an RGB color to use -brightness"); CGFloat v = 0.0f; [self hue:nil saturation:nil brightness:&v alpha:nil]; return v; } - (CGFloat)alpha { return CGColorGetAlpha(self.CGColor); } - (CGFloat)luminance { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use luminance"); CGFloat r,g,b; if (![self red:&r green:&g blue:&b alpha:nil]) return 0.0f; // http://en.wikipedia.org/wiki/Luma_(video) // Y = 0.2126 R + 0.7152 G + 0.0722 B return r*0.2126f + g*0.7152f + b*0.0722f; } - (UInt32)rgbHex { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use rgbHex"); CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return 0; r = MIN(MAX(r, 0.0f), 1.0f); g = MIN(MAX(g, 0.0f), 1.0f); b = MIN(MAX(b, 0.0f), 1.0f); return (((int)roundf(r * 255)) << 16) | (((int)roundf(g * 255)) << 8) | (((int)roundf(b * 255))); } #pragma mark Arithmetic operations - (UIColor *)colorByLuminanceMapping { return [UIColor colorWithWhite:self.luminance alpha:1.0f]; } - (UIColor *)colorByMultiplyingByRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use arithmetic operations"); CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return nil; return [UIColor colorWithRed:MAX(0.0, MIN(1.0, r * red)) green:MAX(0.0, MIN(1.0, g * green)) blue:MAX(0.0, MIN(1.0, b * blue)) alpha:MAX(0.0, MIN(1.0, a * alpha))]; } - (UIColor *)colorByAddingRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use arithmetic operations"); CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return nil; return [UIColor colorWithRed:MAX(0.0, MIN(1.0, r + red)) green:MAX(0.0, MIN(1.0, g + green)) blue:MAX(0.0, MIN(1.0, b + blue)) alpha:MAX(0.0, MIN(1.0, a + alpha))]; } - (UIColor *)colorByLighteningToRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use arithmetic operations"); CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return nil; return [UIColor colorWithRed:MAX(r, red) green:MAX(g, green) blue:MAX(b, blue) alpha:MAX(a, alpha)]; } - (UIColor *)colorByDarkeningToRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use arithmetic operations"); CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return nil; return [UIColor colorWithRed:MIN(r, red) green:MIN(g, green) blue:MIN(b, blue) alpha:MIN(a, alpha)]; } - (UIColor *)colorByMultiplyingBy:(CGFloat)f { return [self colorByMultiplyingByRed:f green:f blue:f alpha:1.0f]; } - (UIColor *)colorByAdding:(CGFloat)f { return [self colorByMultiplyingByRed:f green:f blue:f alpha:0.0f]; } - (UIColor *)colorByLighteningTo:(CGFloat)f { return [self colorByLighteningToRed:f green:f blue:f alpha:0.0f]; } - (UIColor *)colorByDarkeningTo:(CGFloat)f { return [self colorByDarkeningToRed:f green:f blue:f alpha:1.0f]; } - (UIColor *)colorByMultiplyingByColor:(UIColor *)color { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use arithmetic operations"); CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return nil; return [self colorByMultiplyingByRed:r green:g blue:b alpha:1.0f]; } - (UIColor *)colorByAddingColor:(UIColor *)color { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use arithmetic operations"); CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return nil; return [self colorByAddingRed:r green:g blue:b alpha:0.0f]; } - (UIColor *)colorByLighteningToColor:(UIColor *)color { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use arithmetic operations"); CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return nil; return [self colorByLighteningToRed:r green:g blue:b alpha:0.0f]; } - (UIColor *)colorByDarkeningToColor:(UIColor *)color { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use arithmetic operations"); CGFloat r,g,b,a; if (![self red:&r green:&g blue:&b alpha:&a]) return nil; return [self colorByDarkeningToRed:r green:g blue:b alpha:1.0f]; } #pragma mark Complementary Colors, etc // Pick a color that is likely to contrast well with this color - (UIColor *)contrastingColor { return (self.luminance > 0.5f) ? [UIColor blackColor] : [UIColor whiteColor]; } // Pick the color that is 180 degrees away in hue - (UIColor *)complementaryColor { // Convert to HSB CGFloat h,s,v,a; if (![self hue:&h saturation:&s brightness:&v alpha:&a]) return nil; // Pick color 180 degrees away h += 180.0f; if (h > 360.f) h -= 360.0f; // Create a color in RGB return [UIColor colorWithHue:h saturation:s brightness:v alpha:a]; } // Pick two colors more colors such that all three are equidistant on the color wheel // (120 degrees and 240 degress difference in hue from self) - (NSArray*)triadicColors { return [self analogousColorsWithStepAngle:120.0f pairCount:1]; } // Pick n pairs of colors, stepping in increasing steps away from this color around the wheel - (NSArray*)analogousColorsWithStepAngle:(CGFloat)stepAngle pairCount:(int)pairs { // Convert to HSB CGFloat h,s,v,a; if (![self hue:&h saturation:&s brightness:&v alpha:&a]) return nil; NSMutableArray* colors = [NSMutableArray arrayWithCapacity:pairs * 2]; if (stepAngle < 0.0f) stepAngle *= -1.0f; for (int i = 1; i <= pairs; ++i) { CGFloat a = fmodf(stepAngle * i, 360.0f); CGFloat h1 = fmodf(h + a, 360.0f); CGFloat h2 = fmodf(h + 360.0f - a, 360.0f); [colors addObject:[UIColor colorWithHue:h1 saturation:s brightness:v alpha:a]]; [colors addObject:[UIColor colorWithHue:h2 saturation:s brightness:v alpha:a]]; } return [[colors copy] autorelease]; } #pragma mark String utilities - (NSString *)stringFromColor { NSAssert(self.canProvideRGBComponents, @"Must be an RGB color to use -stringFromColor"); NSString *result; switch (self.colorSpaceModel) { case kCGColorSpaceModelRGB: result = [NSString stringWithFormat:@"{%0.3f, %0.3f, %0.3f, %0.3f}", self.red, self.green, self.blue, self.alpha]; break; case kCGColorSpaceModelMonochrome: result = [NSString stringWithFormat:@"{%0.3f, %0.3f}", self.white, self.alpha]; break; default: result = nil; } return result; } - (NSString *)hexStringFromColor { return [NSString stringWithFormat:@"%0.6X", (unsigned int)self.rgbHex]; } - (NSString *)closestColorName { NSAssert(self.canProvideRGBComponents, @"Must be a RGB color to use closestColorName"); int targetHex = self.rgbHex; int rInt = (targetHex >> 16) & 0x0ff; int gInt = (targetHex >> 8) & 0x0ff; int bInt = (targetHex >> 0) & 0x0ff; float bestScore = MAXFLOAT; const char* bestPos = nil; // Walk the colorNameDB looking for the name with closest match for (const char* p = colorNameDB; (p = strchr(p, '#')); ++p) { int r,g,b; if (sscanf(p+1, "%2x%2x%2x", &r, &g, &b) == 3) { // Calculate difference between this color and the target color int rDiff = abs(rInt - r); int gDiff = abs(gInt - g); int bDiff = abs(bInt - b); float score = logf(rDiff+1) + logf(gDiff+1) + logf(bDiff+1); // Track the best score/name seen if (score < bestScore) { bestScore = score; bestPos = p; } } } // bestPos now points to the # following the best name seen // Backup to the start of the name and return it const char* name; for (name = bestPos-1; *name != ','; --name) ; ++name; NSString *result = [[[NSString alloc] initWithBytes:name length:bestPos - name encoding:NSUTF8StringEncoding] autorelease]; return result; } + (UIColor *)colorWithString:(NSString *)stringToConvert { NSScanner *scanner = [NSScanner scannerWithString:stringToConvert]; if (![scanner scanString:@"{" intoString:NULL]) return nil; const NSUInteger kMaxComponents = 4; float c[kMaxComponents]; NSUInteger i = 0; if (![scanner scanFloat:&c[i++]]) return nil; while (1) { if ([scanner scanString:@"}" intoString:NULL]) break; if (i >= kMaxComponents) return nil; if ([scanner scanString:@"," intoString:NULL]) { if (![scanner scanFloat:&c[i++]]) return nil; } else { // either we're at the end of there's an unexpected character here // both cases are error conditions return nil; } } if (![scanner isAtEnd]) return nil; UIColor *color; switch (i) { case 2: // monochrome color = [UIColor colorWithWhite:c[0] alpha:c[1]]; break; case 4: // RGB color = [UIColor colorWithRed:c[0] green:c[1] blue:c[2] alpha:c[3]]; break; default: color = nil; } return color; } #pragma mark Class methods + (UIColor *)randomColor { return [UIColor colorWithRed:random() / (CGFloat)RAND_MAX green:random() / (CGFloat)RAND_MAX blue:random() / (CGFloat)RAND_MAX alpha:1.0f]; } + (UIColor *)colorWithRGBHex:(UInt32)hex { int r = (hex >> 16) & 0xFF; int g = (hex >> 8) & 0xFF; int b = (hex) & 0xFF; return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f]; } // Returns a UIColor by scanning the string for a hex number and passing that to +[UIColor colorWithRGBHex:] // Skips any leading whitespace and ignores any trailing characters + (UIColor *)colorWithHexString:(NSString *)stringToConvert { NSScanner *scanner = [NSScanner scannerWithString:stringToConvert]; unsigned hexNum; if (![scanner scanHexInt:&hexNum]) return nil; return [UIColor colorWithRGBHex:hexNum]; } // Lookup a color using css 3/svg color name + (UIColor *)colorWithName:(NSString *)cssColorName { return [[UIColor namedColors] objectForKey:cssColorName]; } // Return complete mapping of css3/svg color names --> colors + (NSDictionary *)namedColors { [colorNameCacheLock lock]; if (colorNameCache == nil) [UIColor populateColorNameCache]; [colorNameCacheLock unlock]; return colorNameCache; } + (UIColor *)colorWithHue:(CGFloat)hue saturation:(CGFloat)saturation brightness:(CGFloat)brightness alpha:(CGFloat)alpha { // Convert hsb to rgb CGFloat r,g,b; [self hue:hue saturation:saturation brightness:brightness toRed:&r green:&g blue:&b]; // Create a color with rgb return [self colorWithRed:r green:g blue:b alpha:alpha]; } #pragma mark Color Space Conversions + (void)hue:(CGFloat)h saturation:(CGFloat)s brightness:(CGFloat)v toRed:(CGFloat *)pR green:(CGFloat *)pG blue:(CGFloat *)pB { CGFloat r,g,b; // From Foley and Van Dam if (s == 0.0f) { // Achromatic color: there is no hue r = g = b = v; } else { // Chromatic color: there is a hue if (h == 360.0f) h = 0.0f; h /= 60.0f; // h is now in [0, 6) int i = floorf(h); // largest integer <= h CGFloat f = h - i; // fractional part of h CGFloat p = v * (1 - s); CGFloat q = v * (1 - (s * f)); CGFloat t = v * (1 - (s * (1 - f))); switch (i) { case 0: r = v; g = t; b = p; break; case 1: r = q; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = q; b = v; break; case 4: r = t; g = p; b = v; break; case 5: r = v; g = p; b = q; break; } } if (pR) *pR = r; if (pG) *pG = g; if (pB) *pB = b; } + (void)red:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b toHue:(CGFloat *)pH saturation:(CGFloat *)pS brightness:(CGFloat *)pV { CGFloat h,s,v; // From Foley and Van Dam CGFloat max = MAX(r, MAX(g, b)); CGFloat min = MIN(r, MIN(g, b)); // Brightness v = max; // Saturation s = (max != 0.0f) ? ((max - min) / max) : 0.0f; if (s == 0.0f) { // No saturation, so undefined hue h = 0.0f; } else { // Determine hue CGFloat rc = (max - r) / (max - min); // Distance of color from red CGFloat gc = (max - g) / (max - min); // Distance of color from green CGFloat bc = (max - b) / (max - min); // Distance of color from blue if (r == max) h = bc - gc; // resulting color between yellow and magenta else if (g == max) h = 2 + rc - bc; // resulting color between cyan and yellow else /* if (b == max) */ h = 4 + gc - rc; // resulting color between magenta and cyan h *= 60.0f; // Convert to degrees if (h < 0.0f) h += 360.0f; // Make non-negative } if (pH) *pH = h; if (pS) *pS = s; if (pV) *pV = v; } #pragma mark UIColor_Expanded initialization + (void)load { colorNameCacheLock = [[NSLock alloc] init]; } @end #pragma mark - #if SUPPORTS_UNDOCUMENTED_API @implementation UIColor (UIColor_Undocumented_Expanded) - (NSString *)fetchStyleString { return [self styleString]; } // Convert a color into RGB Color space, courtesy of Poltras // via http://ofcodeandmen.poltras.com/2009/01/22/convert-a-cgcolorref-to-another-cgcolorspaceref/ // - (UIColor *)rgbColor { // Call to undocumented method "styleString". NSString *style = [self styleString]; NSScanner *scanner = [NSScanner scannerWithString:style]; CGFloat red, green, blue; if (![scanner scanString:@"rgb(" intoString:NULL]) return nil; if (![scanner scanFloat:&red]) return nil; if (![scanner scanString:@"," intoString:NULL]) return nil; if (![scanner scanFloat:&green]) return nil; if (![scanner scanString:@"," intoString:NULL]) return nil; if (![scanner scanFloat:&blue]) return nil; if (![scanner scanString:@")" intoString:NULL]) return nil; if (![scanner isAtEnd]) return nil; return [UIColor colorWithRed:red green:green blue:blue alpha:self.alpha]; } @end #endif // SUPPORTS_UNDOCUMENTED_API @implementation UIColor (UIColor_Expanded_Support) /* * Database of color names and hex rgb values, derived * from the css 3 color spec: * http://www.w3.org/TR/css3-color/ * * We think this is a very compact way of storing * this information, and relatively cheap to lookup. * * Note that we search for color names starting with ',' * and terminated by '#', so that we don't get false matches. * For this reason, the database begins with ','. */ static const char *colorNameDB = "," "aliceblue#f0f8ff,antiquewhite#faebd7,aqua#00ffff,aquamarine#7fffd4,azure#f0ffff," "beige#f5f5dc,bisque#ffe4c4,black#000000,blanchedalmond#ffebcd,blue#0000ff," "blueviolet#8a2be2,brown#a52a2a,burlywood#deb887,cadetblue#5f9ea0,chartreuse#7fff00," "chocolate#d2691e,coral#ff7f50,cornflowerblue#6495ed,cornsilk#fff8dc,crimson#dc143c," "cyan#00ffff,darkblue#00008b,darkcyan#008b8b,darkgoldenrod#b8860b,darkgray#a9a9a9," "darkgreen#006400,darkgrey#a9a9a9,darkkhaki#bdb76b,darkmagenta#8b008b," "darkolivegreen#556b2f,darkorange#ff8c00,darkorchid#9932cc,darkred#8b0000," "darksalmon#e9967a,darkseagreen#8fbc8f,darkslateblue#483d8b,darkslategray#2f4f4f," "darkslategrey#2f4f4f,darkturquoise#00ced1,darkviolet#9400d3,deeppink#ff1493," "deepskyblue#00bfff,dimgray#696969,dimgrey#696969,dodgerblue#1e90ff," "firebrick#b22222,floralwhite#fffaf0,forestgreen#228b22,fuchsia#ff00ff," "gainsboro#dcdcdc,ghostwhite#f8f8ff,gold#ffd700,goldenrod#daa520,gray#808080," "green#008000,greenyellow#adff2f,grey#808080,honeydew#f0fff0,hotpink#ff69b4," "indianred#cd5c5c,indigo#4b0082,ivory#fffff0,khaki#f0e68c,lavender#e6e6fa," "lavenderblush#fff0f5,lawngreen#7cfc00,lemonchiffon#fffacd,lightblue#add8e6," "lightcoral#f08080,lightcyan#e0ffff,lightgoldenrodyellow#fafad2,lightgray#d3d3d3," "lightgreen#90ee90,lightgrey#d3d3d3,lightpink#ffb6c1,lightsalmon#ffa07a," "lightseagreen#20b2aa,lightskyblue#87cefa,lightslategray#778899," "lightslategrey#778899,lightsteelblue#b0c4de,lightyellow#ffffe0,lime#00ff00," "limegreen#32cd32,linen#faf0e6,magenta#ff00ff,maroon#800000,mediumaquamarine#66cdaa," "mediumblue#0000cd,mediumorchid#ba55d3,mediumpurple#9370db,mediumseagreen#3cb371," "mediumslateblue#7b68ee,mediumspringgreen#00fa9a,mediumturquoise#48d1cc," "mediumvioletred#c71585,midnightblue#191970,mintcream#f5fffa,mistyrose#ffe4e1," "moccasin#ffe4b5,navajowhite#ffdead,navy#000080,oldlace#fdf5e6,olive#808000," "olivedrab#6b8e23,orange#ffa500,orangered#ff4500,orchid#da70d6,palegoldenrod#eee8aa," "palegreen#98fb98,paleturquoise#afeeee,palevioletred#db7093,papayawhip#ffefd5," "peachpuff#ffdab9,peru#cd853f,pink#ffc0cb,plum#dda0dd,powderblue#b0e0e6," "purple#800080,red#ff0000,rosybrown#bc8f8f,royalblue#4169e1,saddlebrown#8b4513," "salmon#fa8072,sandybrown#f4a460,seagreen#2e8b57,seashell#fff5ee,sienna#a0522d," "silver#c0c0c0,skyblue#87ceeb,slateblue#6a5acd,slategray#708090,slategrey#708090," "snow#fffafa,springgreen#00ff7f,steelblue#4682b4,tan#d2b48c,teal#008080," "thistle#d8bfd8,tomato#ff6347,turquoise#40e0d0,violet#ee82ee,wheat#f5deb3," "white#ffffff,whitesmoke#f5f5f5,yellow#ffff00,yellowgreen#9acd32"; + (void)populateColorNameCache { NSAssert(colorNameCache == nil, @"+pouplateColorNameCache was called when colorNameCache was not nil"); NSMutableDictionary *cache = [NSMutableDictionary dictionary]; for (const char* entry = colorNameDB; (entry = strchr(entry, ',')); ) { // Step forward to the start of the name ++entry; // Find the following hash const char* h = strchr(entry, '#'); NSAssert(h, @"Malformed colorNameDB"); // Get the name NSString* name = [[NSString alloc] initWithBytes:entry length:h - entry encoding:NSUTF8StringEncoding]; // Get the color, and add to the dictionary int hex, increment; if (sscanf(++h, "%x%n", &hex, &increment) != 1) break; [cache setObject:[self colorWithRGBHex:hex] forKey:name]; // Cleanup and move to the next item [name release]; entry = h + increment; } colorNameCache = [cache copy]; } @end