00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import <Foundation/CPObject.j>
00024
00025 @import "CGColor.j"
00026
00027 @import "CPCompatibility.j"
00028 @import "CPImage.j"
00029
00030
00031 var _redComponent = 0,
00032 _greenComponent = 1,
00033 _blueComponent = 2,
00034 _alphaCompnent = 3;
00035
00036 var _hueComponent = 0,
00037 _saturationComponent = 1,
00038 _brightnessComponent = 2;
00039
00053 @implementation CPColor : CPObject
00054 {
00055 CPArray _components;
00056
00057 CPImage _patternImage;
00058 CPString _cssString;
00059 }
00060
00074 + (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
00075 {
00076 return [[CPColor alloc] _initWithRGBA:[red, green, blue, alpha]];
00077 }
00078
00088 + (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha
00089 {
00090 return [[CPColor alloc] _initWithRGBA:[white, white, white, alpha]];
00091 }
00092
00102 + (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness
00103 {
00104 if(saturation == 0.0)
00105 return [CPColor colorWithCalibratedWhite: brightness/100.0 alpha: 1.0];
00106
00107 var f = hue % 60,
00108 p = (brightness * (100 - saturation)) / 10000,
00109 q = (brightness * (6000 - saturation * f)) / 600000,
00110 t = (brightness * (6000 - saturation * (60 -f))) / 600000,
00111 b = brightness / 100.0;
00112
00113 switch(FLOOR(hue / 60))
00114 {
00115 case 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: 1.0];
00116 case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: 1.0];
00117 case 2: return [CPColor colorWithCalibratedRed: p green: b blue: t alpha: 1.0];
00118 case 3: return [CPColor colorWithCalibratedRed: p green: q blue: b alpha: 1.0];
00119 case 4: return [CPColor colorWithCalibratedRed: t green: p blue: b alpha: 1.0];
00120 case 5: return [CPColor colorWithCalibratedRed: b green: p blue: q alpha: 1.0];
00121 }
00122 }
00123
00134 + (CPColor)colorWithHexString:(string)hex
00135 {
00136 return [[CPColor alloc] _initWithRGBA: hexToRGB(hex)];
00137 }
00138
00142 + (CPColor)blackColor
00143 {
00144 return [[CPColor alloc] _initWithRGBA:[0.0, 0.0, 0.0, 1.0]];
00145 }
00146
00150 + (CPColor)blueColor
00151 {
00152 return [[CPColor alloc] _initWithRGBA:[0.0, 0.0, 1.0, 1.0]];
00153 }
00154
00158 + (CPColor)darkGrayColor
00159 {
00160 return [CPColor colorWithCalibratedWhite:1.0 / 3.0 alpha:1.0];
00161 }
00162
00166 + (CPColor)grayColor
00167 {
00168 return [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0];
00169 }
00170
00174 + (CPColor)greenColor
00175 {
00176 return [[CPColor alloc] _initWithRGBA:[0.0, 1.0, 0.0, 1.0]];
00177 }
00178
00182 + (CPColor)lightGrayColor
00183 {
00184 return [CPColor colorWithCalibratedWhite:2.0 / 3.0 alpha:1.0];
00185 }
00186
00190 + (CPColor)redColor
00191 {
00192 return [[CPColor alloc] _initWithRGBA:[1.0, 0.0, 0.0, 1.0]];
00193 }
00194
00198 + (CPColor)whiteColor
00199 {
00200 return [[CPColor alloc] _initWithRGBA:[1.0, 1.0, 1.0, 1.0]];
00201 }
00202
00206 + (CPColor)yellowColor
00207 {
00208 return [[CPColor alloc] _initWithRGBA:[1.0, 1.0, 0.0, 1.0]];
00209 }
00210
00214 + (CPColor)shadowColor
00215 {
00216 return [[CPColor alloc] _initWithRGBA:[0.0, 0.0, 0.0, 1.0 / 3.0]];
00217 }
00218
00224 + (CPColor)colorWithPatternImage:(CPImage)anImage
00225 {
00226 return [[CPColor alloc] _initWithPatternImage:anImage];
00227 }
00228
00235 + (CPColor)colorWithCSSString:(CPString)aString
00236 {
00237 return [[CPColor alloc] _initWithCSSString: aString];
00238 }
00239
00240
00241 - (id)_initWithCSSString:(CPString)aString
00242 {
00243 if(aString.indexOf("rgb") == CPNotFound)
00244 return nil;
00245
00246 self = [super init];
00247
00248 var startingIndex = aString.indexOf("(");
00249 var parts = aString.substring(startingIndex+1).split(',');
00250
00251 _components = [
00252 parseInt(parts[0], 10) / 255.0,
00253 parseInt(parts[1], 10) / 255.0,
00254 parseInt(parts[2], 10) / 255.0,
00255 parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
00256 ]
00257
00258 _cssString = aString;
00259
00260 return self;
00261 }
00262
00263
00264 - (id)_initWithRGBA:(CPArray)components
00265 {
00266 self = [super init];
00267
00268 if (self)
00269 {
00270 _components = components;
00271
00272 if (!CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0 && window.Base64 && window.CRC32)
00273 {
00274 var bytes = [0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x8,0x3,0x0,0x0,0x0,0x28,0xcb,0x34,0xbb,0x0,0x0,0x3,0x0,0x50,0x4c,0x54,0x45,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x17,0x89,0x99,0x55,0x0,0x0,0x0,0x1,0x74,0x52,0x4e,0x53,0x0,0x40,0xe6,0xd8,0x66,0x0,0x0,0x0,0x10,0x49,0x44,0x41,0x54,0x78,0xda,0x62,0x60,0x0,0x0,0x0,0x0,0xff,0xff,0x3,0x0,0x0,0x2,0x0,0x1,0x24,0x7f,0x24,0xf1,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82,0xff];
00275 var r_off = 41;
00276 var g_off = 42;
00277 var b_off = 43;
00278 var a_off = 821;
00279 var plte_crc_off = 809;
00280 var trns_crc_off = 822;
00281 var plte_type_off = 37;
00282 var trns_type_off = 817;
00283
00284 bytes[r_off] = Math.round(_components[0]*255);
00285 bytes[g_off] = Math.round(_components[1]*255);
00286 bytes[b_off] = Math.round(_components[2]*255);
00287 bytes[a_off] = Math.round(_components[3]*255);
00288
00289
00290 var new_plte_crc = integerToBytes(CRC32.getCRC(bytes, plte_type_off, 4+768), 4);
00291 var new_trns_crc = integerToBytes(CRC32.getCRC(bytes, trns_type_off, 4+1), 4);
00292
00293
00294 for (var i = 0; i < 4; i++)
00295 {
00296 bytes[plte_crc_off+i] = new_plte_crc[i];
00297 bytes[trns_crc_off+i] = new_trns_crc[i];
00298 }
00299
00300
00301 var base64image = Base64.encode(bytes);
00302
00303 _cssString = "url(\"data:image/png;base64," + base64image + "\")";
00304 }
00305 else
00306 {
00307 var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
00308
00309 _cssString = (hasAlpha ? "rgba(" : "rgb(") +
00310 parseInt(_components[0] * 255.0) + ", " +
00311 parseInt(_components[1] * 255.0) + ", " +
00312 parseInt(_components[2] * 255.0) +
00313 (hasAlpha ? (", " + _components[3]) : "") + ")";
00314 }
00315 }
00316 return self;
00317 }
00318
00319
00320 - (id)_initWithPatternImage:(CPImage)anImage
00321 {
00322 self = [super init];
00323
00324 if (self)
00325 {
00326 _patternImage = anImage;
00327 _cssString = "url(\"" + _patternImage._filename + "\")";
00328 }
00329
00330 return self;
00331 }
00332
00336 - (CPImage)patternImage
00337 {
00338 return _patternImage;
00339 }
00340
00344 - (float)alphaComponent
00345 {
00346 return _components[3];
00347 }
00348
00352 - (float)blueComponent
00353 {
00354 return _components[2];
00355 }
00356
00360 - (float)greenComponent
00361 {
00362 return _components[1];
00363 }
00364
00368 - (float)redComponent
00369 {
00370 return _components[0];
00371 }
00372
00384 - (CPArray)components
00385 {
00386 return _components;
00387 }
00388
00396 - (CPColor)colorWithAlphaComponent:(float)anAlphaComponent
00397 {
00398 var components = _components.slice();
00399
00400 components[components.length - 1] = anAlphaComponent;
00401
00402 return [[[self class] alloc] _initWithRGBA:components];
00403 }
00404
00415 - (CPArray)hsbComponents
00416 {
00417 var red = ROUND(_components[_redComponent] * 255.0),
00418 green = ROUND(_components[_greenComponent] * 255.0),
00419 blue = ROUND(_components[_blueComponent] * 255.0);
00420
00421 var max = MAX(red, green, blue),
00422 min = MIN(red, green, blue),
00423 delta = max - min;
00424
00425 var brightness = max / 255.0,
00426 saturation = (max != 0) ? delta / max : 0;
00427
00428 var hue;
00429 if(saturation == 0)
00430 hue = 0;
00431 else
00432 {
00433 var rr = (max - red) / delta;
00434 var gr = (max - green) / delta;
00435 var br = (max - blue) / delta;
00436
00437 if (red == max)
00438 hue = br - gr;
00439 else if (green == max)
00440 hue = 2 + rr - br;
00441 else
00442 hue = 4 + gr - rr;
00443
00444 hue /= 6;
00445 if (hue < 0)
00446 hue++;
00447 }
00448
00449 return [
00450 ROUND(hue * 360.0),
00451 ROUND(saturation * 100.0),
00452 ROUND(brightness * 100.0)
00453 ];
00454 }
00455
00465 - (CPString)cssString
00466 {
00467 return _cssString;
00468 }
00469
00473 - (CPString)hexString
00474 {
00475 return rgbToHex([self redComponent], [self greenComponent], [self blueComponent])
00476 }
00477
00478 @end
00479
00480 var CPColorComponentsKey = @"CPColorComponentsKey",
00481 CPColorPatternImageKey = @"CPColorPatternImageKey";
00482
00483 @implementation CPColor (CPCoding)
00484
00489 - (id)initWithCoder:(CPCoder)aCoder
00490 {
00491 if ([aCoder containsValueForKey:CPColorPatternImageKey])
00492 return [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
00493
00494 return [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
00495 }
00496
00501 - (void)encodeWithCoder:(CPCoder)aCoder
00502 {
00503 if (_patternImage)
00504 [aCoder encodeObject:_patternImage forKey:CPColorPatternImageKey];
00505 else
00506 [aCoder encodeObject:_components forKey:CPColorComponentsKey];
00507 }
00508
00509 @end
00510
00511 var hexCharacters = "0123456789ABCDEF";
00512
00519 function hexToRGB(hex)
00520 {
00521 if(hex.length != 6)
00522 return null;
00523
00524 hex = hex.toUpperCase();
00525
00526 for(var i=0; i<hex.length; i++)
00527 if(hexCharacters.indexOf(hex.charAt(i)) == -1)
00528 return null;
00529
00530 var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0;
00531 var green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0;
00532 var blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
00533
00534 return [red, green, blue, 1.0];
00535 }
00536
00537 function integerToBytes(integer, length) {
00538 if (!length)
00539 length = (integer == 0) ? 1 : Math.round((Math.log(integer)/Math.log(2))/8+0.5);
00540
00541 var bytes = new Array(length);
00542 for (var i = length-1; i >= 0; i--) {
00543 bytes[i] = integer & 255;
00544 integer = integer >> 8
00545 }
00546 return bytes;
00547 }
00548
00549 function rgbToHex(r,g,b) {
00550 return byteToHex(r) + byteToHex(g) + byteToHex(b);
00551 }
00552
00553 function byteToHex(n) {
00554 if (!n || isNaN(n)) return "00";
00555 n = ROUND(MIN(255,MAX(0,256*n)));
00556 return hexCharacters.charAt((n - n % 16) / 16) +
00557 hexCharacters.charAt(n % 16);
00558 }
00559
00560
00561
00562
00563
00564