Colours.m 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454
  1. // Copyright (C) 2013 by Benjamin Gordon
  2. //
  3. // Permission is hereby granted, free of charge, to any
  4. // person obtaining a copy of this software and
  5. // associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including
  7. // without limitation the rights to use, copy, modify, merge,
  8. // publish, distribute, sublicense, and/or sell copies of the
  9. // Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall
  13. // be included in all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  17. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  19. // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  20. // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. #import "Colours.h"
  23. #import <objc/runtime.h>
  24. #pragma mark - Static Block
  25. static CGFloat (^RAD)(CGFloat) = ^CGFloat (CGFloat degree){
  26. return degree * M_PI/180;
  27. };
  28. #pragma mark - Create correct iOS/OSX implementation
  29. #if TARGET_OS_IPHONE || TARGET_OS_TV
  30. #import <UIKit/UIKit.h>
  31. @implementation UIColor (Colours)
  32. #define ColorClass UIColor
  33. #elif TARGET_OS_MAC
  34. #import <AppKit/AppKit.h>
  35. @implementation NSColor (Colours)
  36. #define ColorClass NSColor
  37. #endif
  38. #pragma mark - Color from Hex
  39. + (instancetype)colorFromHexString:(NSString *)hexString
  40. {
  41. unsigned rgbValue = 0;
  42. hexString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
  43. NSScanner *scanner = [NSScanner scannerWithString:hexString];
  44. [scanner scanHexInt:&rgbValue];
  45. return [[self class] colorWithR:((rgbValue & 0xFF0000) >> 16) G:((rgbValue & 0xFF00) >> 8) B:(rgbValue & 0xFF) A:1.0];
  46. }
  47. #pragma mark - Hex from Color
  48. - (NSString *)hexString
  49. {
  50. NSArray *colorArray = [self rgbaArray];
  51. int r = [colorArray[0] floatValue] * 255;
  52. int g = [colorArray[1] floatValue] * 255;
  53. int b = [colorArray[2] floatValue] * 255;
  54. NSString *red = [NSString stringWithFormat:@"%02x", r];
  55. NSString *green = [NSString stringWithFormat:@"%02x", g];
  56. NSString *blue = [NSString stringWithFormat:@"%02x", b];
  57. return [NSString stringWithFormat:@"#%@%@%@", red, green, blue];
  58. }
  59. #pragma mark - Color from RGBA
  60. + (instancetype)colorFromRGBAArray:(NSArray *)rgbaArray
  61. {
  62. if (rgbaArray.count < 4) {
  63. return [[self class] clearColor];
  64. }
  65. return [[self class] colorWithRed:[rgbaArray[0] floatValue]
  66. green:[rgbaArray[1] floatValue]
  67. blue:[rgbaArray[2] floatValue]
  68. alpha:[rgbaArray[3] floatValue]];
  69. }
  70. + (instancetype)colorFromRGBADictionary:(NSDictionary *)rgbaDict
  71. {
  72. if (rgbaDict[kColoursRGBA_R] && rgbaDict[kColoursRGBA_G] && rgbaDict[kColoursRGBA_B] && rgbaDict[kColoursRGBA_A]) {
  73. return [[self class] colorWithRed:[rgbaDict[kColoursRGBA_R] floatValue]
  74. green:[rgbaDict[kColoursRGBA_G] floatValue]
  75. blue:[rgbaDict[kColoursRGBA_B] floatValue]
  76. alpha:[rgbaDict[kColoursRGBA_A] floatValue]];
  77. }
  78. return [[self class] clearColor];
  79. }
  80. #pragma mark - RGBA from Color
  81. - (NSArray *)rgbaArray
  82. {
  83. CGFloat r=0,g=0,b=0,a=0;
  84. if ([self respondsToSelector:@selector(getRed:green:blue:alpha:)]) {
  85. [self getRed:&r green:&g blue:&b alpha:&a];
  86. }
  87. else {
  88. const CGFloat *components = CGColorGetComponents(self.CGColor);
  89. r = components[0];
  90. g = components[1];
  91. b = components[2];
  92. a = components[3];
  93. }
  94. return @[@(r),
  95. @(g),
  96. @(b),
  97. @(a)];
  98. }
  99. - (NSDictionary *)rgbaDictionary
  100. {
  101. CGFloat r=0,g=0,b=0,a=0;
  102. if ([self respondsToSelector:@selector(getRed:green:blue:alpha:)]) {
  103. [self getRed:&r green:&g blue:&b alpha:&a];
  104. }
  105. else {
  106. const CGFloat *components = CGColorGetComponents(self.CGColor);
  107. r = components[0];
  108. g = components[1];
  109. b = components[2];
  110. a = components[3];
  111. }
  112. return @{kColoursRGBA_R:@(r),
  113. kColoursRGBA_G:@(g),
  114. kColoursRGBA_B:@(b),
  115. kColoursRGBA_A:@(a)};
  116. }
  117. #pragma mark - HSBA from Color
  118. - (NSArray *)hsbaArray
  119. {
  120. // Takes a [self class] and returns Hue,Saturation,Brightness,Alpha values in NSNumber form
  121. CGFloat h=0,s=0,b=0,a=0;
  122. if ([self respondsToSelector:@selector(getHue:saturation:brightness:alpha:)]) {
  123. [self getHue:&h saturation:&s brightness:&b alpha:&a];
  124. }
  125. return @[@(h),
  126. @(s),
  127. @(b),
  128. @(a)];
  129. }
  130. - (NSDictionary *)hsbaDictionary
  131. {
  132. CGFloat h=0,s=0,b=0,a=0;
  133. if ([self respondsToSelector:@selector(getHue:saturation:brightness:alpha:)]) {
  134. [self getHue:&h saturation:&s brightness:&b alpha:&a];
  135. }
  136. return @{kColoursHSBA_H:@(h),
  137. kColoursHSBA_S:@(s),
  138. kColoursHSBA_B:@(b),
  139. kColoursHSBA_A:@(a)};
  140. }
  141. #pragma mark - Color from HSBA
  142. + (instancetype)colorFromHSBAArray:(NSArray *)hsbaArray
  143. {
  144. if (hsbaArray.count < 4) {
  145. return [[self class] clearColor];
  146. }
  147. return [[self class] colorWithHue:[hsbaArray[0] doubleValue]
  148. saturation:[hsbaArray[1] doubleValue]
  149. brightness:[hsbaArray[2] doubleValue]
  150. alpha:[hsbaArray[3] doubleValue]];
  151. }
  152. + (instancetype)colorFromHSBADictionary:(NSDictionary *)hsbaDict
  153. {
  154. if (hsbaDict[kColoursHSBA_H] && hsbaDict[kColoursHSBA_S] && hsbaDict[kColoursHSBA_B] && hsbaDict[kColoursHSBA_A]) {
  155. return [[self class] colorWithHue:[hsbaDict[kColoursHSBA_H] doubleValue]
  156. saturation:[hsbaDict[kColoursHSBA_S] doubleValue]
  157. brightness:[hsbaDict[kColoursHSBA_B] doubleValue]
  158. alpha:[hsbaDict[kColoursHSBA_A] doubleValue]];
  159. }
  160. return [[self class] clearColor];
  161. }
  162. #pragma mark - LAB from Color
  163. - (NSArray *)CIE_LabArray {
  164. // Convert Color to XYZ format first
  165. NSArray *rgba = [self rgbaArray];
  166. CGFloat R = [rgba[0] floatValue];
  167. CGFloat G = [rgba[1] floatValue];
  168. CGFloat B = [rgba[2] floatValue];
  169. // Create deltaR block
  170. void (^deltaRGB)(CGFloat *R);
  171. deltaRGB = ^(CGFloat *R) {
  172. *R = (*R > 0.04045) ? pow((*R + 0.055)/1.055, 2.40) : (*R/12.92);
  173. };
  174. deltaRGB(&R);
  175. deltaRGB(&G);
  176. deltaRGB(&B);
  177. CGFloat X = R*41.24 + G*35.76 + B*18.05;
  178. CGFloat Y = R*21.26 + G*71.52 + B*7.22;
  179. CGFloat Z = R*1.93 + G*11.92 + B*95.05;
  180. // Convert XYZ to L*a*b*
  181. X = X/95.047;
  182. Y = Y/100.000;
  183. Z = Z/108.883;
  184. // Create deltaF block
  185. void (^deltaF)(CGFloat *f);
  186. deltaF = ^(CGFloat *f){
  187. *f = (*f > pow((6.0/29.0), 3.0)) ? pow(*f, 1.0/3.0) : (1/3)*pow((29.0/6.0), 2.0) * *f + 4/29.0;
  188. };
  189. deltaF(&X);
  190. deltaF(&Y);
  191. deltaF(&Z);
  192. NSNumber *L = @(116*Y - 16);
  193. NSNumber *a = @(500 * (X - Y));
  194. NSNumber *b = @(200 * (Y - Z));
  195. return @[L,
  196. a,
  197. b,
  198. rgba[3]];
  199. }
  200. - (NSDictionary *)CIE_LabDictionary {
  201. NSArray *colors = [self CIE_LabArray];
  202. return @{kColoursCIE_L:colors[0],
  203. kColoursCIE_A:colors[1],
  204. kColoursCIE_B:colors[2],
  205. kColoursCIE_alpha:colors[3],};
  206. }
  207. #pragma mark - LCH from Color
  208. - (NSArray*)CIE_LCHArray {
  209. // www.brucelindbloom.com/index.html?Equations.html
  210. NSArray *Lab = [self CIE_LabArray];
  211. NSMutableArray *LCH = [Lab mutableCopy];
  212. //L = L, a = a
  213. //C
  214. LCH[1] = @(sqrt(pow([Lab[1] doubleValue], 2) + pow([Lab[2] doubleValue], 2)));
  215. //H
  216. double h = atan2([Lab[2] doubleValue], [Lab[1] doubleValue]);
  217. h = h * 180/M_PI;
  218. if (h < 0) {
  219. h += 360;
  220. } else if ( h >= 360) {
  221. h -= 360;
  222. }
  223. LCH[2] = @(h);
  224. return LCH;
  225. }
  226. - (NSDictionary *)CIE_LCHDictionary {
  227. NSArray *colors = [self CIE_LCHArray];
  228. return @{kColoursCIE_L:colors[0],
  229. kColoursCIE_C:colors[1],
  230. kColoursCIE_H:colors[2],
  231. kColoursCIE_alpha:colors[3],};
  232. }
  233. #pragma mark - Color from LAB
  234. + (instancetype)colorFromCIE_LabArray:(NSArray *)colors {
  235. if (!colors || colors.count < 4) {
  236. return [[self class] clearColor];
  237. }
  238. // Convert LAB to XYZ
  239. CGFloat L = [colors[0] floatValue];
  240. CGFloat A = [colors[1] floatValue];
  241. CGFloat B = [colors[2] floatValue];
  242. CGFloat Y = (L + 16.0)/116.0;
  243. CGFloat X = A/500 + Y;
  244. CGFloat Z = Y - B/200;
  245. void (^deltaXYZ)(CGFloat *);
  246. deltaXYZ = ^(CGFloat *k){
  247. *k = (pow(*k, 3.0) > 0.008856) ? pow(*k, 3.0) : (*k - 4/29.0)/7.787;
  248. };
  249. deltaXYZ(&X);
  250. deltaXYZ(&Y);
  251. deltaXYZ(&Z);
  252. X = X*.95047;
  253. Y = Y*1.00000;
  254. Z = Z*1.08883;
  255. // Convert XYZ to RGB
  256. CGFloat R = X*3.2406 + Y*-1.5372 + Z*-0.4986;
  257. CGFloat G = X*-0.9689 + Y*1.8758 + Z*0.0415;
  258. CGFloat _B = X*0.0557 + Y*-0.2040 + Z*1.0570;
  259. void (^deltaRGB)(CGFloat *);
  260. deltaRGB = ^(CGFloat *k){
  261. *k = (*k > 0.0031308) ? 1.055 * (pow(*k, (1/2.4))) - 0.055 : *k * 12.92;
  262. };
  263. deltaRGB(&R);
  264. deltaRGB(&G);
  265. deltaRGB(&_B);
  266. // return Color
  267. return [[self class] colorFromRGBAArray:@[@(R), @(G), @(_B), colors[3]]];
  268. }
  269. + (instancetype)colorFromCIE_LabDictionary:(NSDictionary *)colors {
  270. if (!colors) {
  271. return [[self class] clearColor];
  272. }
  273. if (colors[kColoursCIE_L] && colors[kColoursCIE_A] && colors[kColoursCIE_B] && colors[kColoursCIE_alpha]) {
  274. return [self colorFromCIE_LabArray:@[colors[kColoursCIE_L],
  275. colors[kColoursCIE_A],
  276. colors[kColoursCIE_B],
  277. colors[kColoursCIE_alpha]]];
  278. }
  279. return [[self class] clearColor];
  280. }
  281. #pragma mark - Color from LCH
  282. + (instancetype)colorFromCIE_LCHArray:(NSArray *)colors {
  283. if (!colors) {
  284. return [[self class] clearColor];
  285. }
  286. NSMutableArray *Lab = [colors mutableCopy];
  287. double H = [colors[2] doubleValue] * M_PI/180;;
  288. Lab[1] = @([colors[1] doubleValue] * cos(H));
  289. Lab[2] = @([colors[1] doubleValue] * sin(H));
  290. return [[self class] colorFromCIE_LabArray:Lab];
  291. }
  292. + (instancetype)colorFromCIE_LCHDictionary:(NSDictionary *)colors {
  293. if (!colors) {
  294. return [[self class] clearColor];
  295. }
  296. if (colors[kColoursCIE_L] && colors[kColoursCIE_C] && colors[kColoursCIE_H] && colors[kColoursCIE_alpha]) {
  297. return [self colorFromCIE_LCHArray:@[colors[kColoursCIE_L],
  298. colors[kColoursCIE_C],
  299. colors[kColoursCIE_H],
  300. colors[kColoursCIE_alpha]]];
  301. }
  302. return [[self class] clearColor];
  303. }
  304. #pragma mark - Color to CMYK
  305. - (NSArray *)cmykArray
  306. {
  307. // Convert RGB to CMY
  308. NSArray *rgb = [self rgbaArray];
  309. CGFloat C = 1 - [rgb[0] floatValue];
  310. CGFloat M = 1 - [rgb[1] floatValue];
  311. CGFloat Y = 1 - [rgb[2] floatValue];
  312. // Find K
  313. CGFloat K = MIN(1, MIN(C, MIN(Y, M)));
  314. if (K == 1) {
  315. C = 0;
  316. M = 0;
  317. Y = 0;
  318. }
  319. else {
  320. void (^newCMYK)(CGFloat *);
  321. newCMYK = ^(CGFloat *x){
  322. *x = (*x - K)/(1 - K);
  323. };
  324. newCMYK(&C);
  325. newCMYK(&M);
  326. newCMYK(&Y);
  327. }
  328. return @[@(C),
  329. @(M),
  330. @(Y),
  331. @(K)];
  332. }
  333. - (NSDictionary *)cmykDictionary
  334. {
  335. NSArray *colors = [self cmykArray];
  336. return @{kColoursCMYK_C:colors[0],
  337. kColoursCMYK_M:colors[1],
  338. kColoursCMYK_Y:colors[2],
  339. kColoursCMYK_K:colors[3]};
  340. }
  341. #pragma mark - CMYK to Color
  342. + (instancetype)colorFromCMYKArray:(NSArray *)cmyk
  343. {
  344. if (!cmyk || cmyk.count < 4) {
  345. return [[self class] clearColor];
  346. }
  347. // Find CMY values
  348. CGFloat C = [cmyk[0] floatValue];
  349. CGFloat M = [cmyk[1] floatValue];
  350. CGFloat Y = [cmyk[2] floatValue];
  351. CGFloat K = [cmyk[3] floatValue];
  352. void (^cmyTransform)(CGFloat *);
  353. cmyTransform = ^(CGFloat *x){
  354. *x = *x * (1 - K) + K;
  355. };
  356. cmyTransform(&C);
  357. cmyTransform(&M);
  358. cmyTransform(&Y);
  359. // Translate CMY to RGB
  360. CGFloat R = 1 - C;
  361. CGFloat G = 1 - M;
  362. CGFloat B = 1 - Y;
  363. // return the Color
  364. return [[self class] colorFromRGBAArray:@[@(R),
  365. @(G),
  366. @(B),
  367. @(1)]];
  368. }
  369. + (instancetype)colorFromCMYKDictionary:(NSDictionary *)cmyk
  370. {
  371. if (!cmyk) {
  372. return [[self class] clearColor];
  373. }
  374. if (cmyk[kColoursCMYK_C] && cmyk[kColoursCMYK_M] && cmyk[kColoursCMYK_Y] && cmyk[kColoursCMYK_K]) {
  375. return [[self class] colorFromCMYKArray:@[cmyk[kColoursCMYK_C],
  376. cmyk[kColoursCMYK_M],
  377. cmyk[kColoursCMYK_Y],
  378. cmyk[kColoursCMYK_K]]];
  379. }
  380. return [[self class] clearColor];
  381. }
  382. #pragma mark - Color Components
  383. - (NSDictionary *)colorComponents
  384. {
  385. NSMutableDictionary *components = [[self rgbaDictionary] mutableCopy];
  386. [components addEntriesFromDictionary:[self hsbaDictionary]];
  387. [components addEntriesFromDictionary:[self CIE_LabDictionary]];
  388. return components;
  389. }
  390. - (CGFloat)red
  391. {
  392. return [[self rgbaArray][0] floatValue];
  393. }
  394. - (CGFloat)green
  395. {
  396. return [[self rgbaArray][1] floatValue];
  397. }
  398. - (CGFloat)blue
  399. {
  400. return [[self rgbaArray][2] floatValue];
  401. }
  402. - (CGFloat)hue
  403. {
  404. return [[self hsbaArray][0] floatValue];
  405. }
  406. - (CGFloat)saturation
  407. {
  408. return [[self hsbaArray][1] floatValue];
  409. }
  410. - (CGFloat)brightness
  411. {
  412. return [[self hsbaArray][2] floatValue];
  413. }
  414. - (CGFloat)alpha
  415. {
  416. return [[self rgbaArray][3] floatValue];
  417. }
  418. - (CGFloat)CIE_Lightness
  419. {
  420. return [[self CIE_LabArray][0] floatValue];
  421. }
  422. - (CGFloat)CIE_a
  423. {
  424. return [[self CIE_LabArray][1] floatValue];
  425. }
  426. - (CGFloat)CIE_b
  427. {
  428. return [[self CIE_LabArray][2] floatValue];
  429. }
  430. - (CGFloat)cyan {
  431. return [[self cmykArray][0] floatValue];
  432. }
  433. - (CGFloat)magenta {
  434. return [[self cmykArray][1] floatValue];
  435. }
  436. - (CGFloat)yellow {
  437. return [[self cmykArray][2] floatValue];
  438. }
  439. - (CGFloat)keyBlack {
  440. return [[self cmykArray][3] floatValue];
  441. }
  442. #pragma mark - Darken/Lighten
  443. - (instancetype)darken:(CGFloat)percentage {
  444. return [self modifyBrightnessByPercentage:1.0-percentage];
  445. }
  446. - (instancetype)lighten:(CGFloat)percentage {
  447. return [self modifyBrightnessByPercentage:percentage+1.0];
  448. }
  449. - (instancetype)modifyBrightnessByPercentage:(CGFloat)percentage {
  450. NSMutableDictionary *hsba = [[self hsbaDictionary] mutableCopy];
  451. [hsba setObject:@([hsba[kColoursHSBA_B] floatValue] * percentage) forKey:kColoursHSBA_B];
  452. return [ColorClass colorFromHSBADictionary:hsba];
  453. }
  454. #pragma mark - Generate Color Scheme
  455. - (NSArray *)colorSchemeOfType:(ColorScheme)type
  456. {
  457. NSArray *hsbArray = [self hsbaArray];
  458. float hue = [hsbArray[0] floatValue] * 360;
  459. float sat = [hsbArray[1] floatValue] * 100;
  460. float bright = [hsbArray[2] floatValue] * 100;
  461. float alpha = [hsbArray[3] floatValue];
  462. switch (type) {
  463. case ColorSchemeAnalagous:
  464. return [[self class] analagousColorsFromHue:hue saturation:sat brightness:bright alpha:alpha];
  465. case ColorSchemeMonochromatic:
  466. return [[self class] monochromaticColorsFromHue:hue saturation:sat brightness:bright alpha:alpha];
  467. case ColorSchemeTriad:
  468. return [[self class] triadColorsFromHue:hue saturation:sat brightness:bright alpha:alpha];
  469. case ColorSchemeComplementary:
  470. return [[self class] complementaryColorsFromHue:hue saturation:sat brightness:bright alpha:alpha];
  471. default:
  472. return nil;
  473. }
  474. }
  475. #pragma mark - Color Scheme Generation - Helper methods
  476. + (NSArray *)analagousColorsFromHue:(float)h saturation:(float)s brightness:(float)b alpha:(float)a
  477. {
  478. return @[[[self class] colorWithHue:[[self class] addDegrees:30 toDegree:h]/360 saturation:(s-5)/100 brightness:(b-10)/100 alpha:a],
  479. [[self class] colorWithHue:[[self class] addDegrees:15 toDegree:h]/360 saturation:(s-5)/100 brightness:(b-5)/100 alpha:a],
  480. [[self class] colorWithHue:[[self class] addDegrees:-15 toDegree:h]/360 saturation:(s-5)/100 brightness:(b-5)/100 alpha:a],
  481. [[self class] colorWithHue:[[self class] addDegrees:-30 toDegree:h]/360 saturation:(s-5)/100 brightness:(b-10)/100 alpha:a]];
  482. }
  483. + (NSArray *)monochromaticColorsFromHue:(float)h saturation:(float)s brightness:(float)b alpha:(float)a
  484. {
  485. return @[[[self class] colorWithHue:h/360 saturation:(s/2)/100 brightness:(b/3)/100 alpha:a],
  486. [[self class] colorWithHue:h/360 saturation:s/100 brightness:(b/2)/100 alpha:a],
  487. [[self class] colorWithHue:h/360 saturation:(s/3)/100 brightness:(2*b/3)/100 alpha:a],
  488. [[self class] colorWithHue:h/360 saturation:s/100 brightness:(4*b/5)/100 alpha:a]];
  489. }
  490. + (NSArray *)triadColorsFromHue:(float)h saturation:(float)s brightness:(float)b alpha:(float)a
  491. {
  492. return @[[[self class] colorWithHue:[[self class] addDegrees:120 toDegree:h]/360 saturation:(7*s/6)/100 brightness:(b-5)/100 alpha:a],
  493. [[self class] colorWithHue:[[self class] addDegrees:120 toDegree:h]/360 saturation:s/100 brightness:b/100 alpha:a],
  494. [[self class] colorWithHue:[[self class] addDegrees:240 toDegree:h]/360 saturation:s/100 brightness:b/100 alpha:a],
  495. [[self class] colorWithHue:[[self class] addDegrees:240 toDegree:h]/360 saturation:(7*s/6)/100 brightness:(b-5)/100 alpha:a]];
  496. }
  497. + (NSArray *)complementaryColorsFromHue:(float)h saturation:(float)s brightness:(float)b alpha:(float)a
  498. {
  499. return @[[[self class] colorWithHue:h/360 saturation:s/100 brightness:(4*b/5)/100 alpha:a],
  500. [[self class] colorWithHue:h/360 saturation:(5*s/7)/100 brightness:b/100 alpha:a],
  501. [[self class] colorWithHue:[[self class] addDegrees:180 toDegree:h]/360 saturation:s/100 brightness:b/100 alpha:a],
  502. [[self class] colorWithHue:[[self class] addDegrees:180 toDegree:h]/360 saturation:(5*s/7)/100 brightness:b/100 alpha:a]];
  503. }
  504. #pragma mark - Contrasting Color
  505. - (instancetype)blackOrWhiteContrastingColor
  506. {
  507. NSArray *rgbaArray = [self rgbaArray];
  508. double a = 1 - ((0.299 * [rgbaArray[0] doubleValue]) + (0.587 * [rgbaArray[1] doubleValue]) + (0.114 * [rgbaArray[2] doubleValue]));
  509. return a < 0.5 ? [[self class] blackColor] : [[self class] whiteColor];
  510. }
  511. #pragma mark - Complementary Color
  512. - (instancetype)complementaryColor
  513. {
  514. NSMutableDictionary *hsba = [[self hsbaDictionary] mutableCopy];
  515. float newH = [[self class] addDegrees:180.0f toDegree:([hsba[kColoursHSBA_H] floatValue]*360.0f)];
  516. [hsba setObject:@(newH/360.0f) forKey:kColoursHSBA_H];
  517. return [[self class] colorFromHSBADictionary:hsba];
  518. }
  519. #pragma mark - Distance between Colors
  520. - (CGFloat)distanceFromColor:(id)color
  521. {
  522. // Defaults to CIE94
  523. return [self distanceFromColor:color type:ColorDistanceCIE94];
  524. }
  525. - (CGFloat)distanceFromColor:(id)color type:(ColorDistance)distanceType {
  526. /**
  527. *
  528. * Detecting a difference in two colors is not as trivial as it sounds.
  529. * One's first instinct is to go for a difference in RGB values, leaving
  530. * you with a sum of the differences of each point. It looks great! Until
  531. * you actually start comparing colors. Why do these two reds have a different
  532. * distance than these two blues *in real life* vs computationally?
  533. * Human visual perception is next in the line of things between a color
  534. * and your brain. Some colors are just perceived to have larger variants inside
  535. * of their respective areas than others, so we need a way to model this
  536. * human variable to colors. Enter CIELAB. This color formulation is supposed to be
  537. * this model. So now we need to standardize a unit of distance between any two
  538. * colors that works independent of how humans visually perceive that distance.
  539. * Enter CIE76,94,2000. These are methods that use user-tested data and other
  540. * mathematically and statistically significant correlations to output this info.
  541. * You can read the wiki articles below to get a better understanding historically
  542. * of how we moved to newer and better color distance formulas, and what
  543. * their respective pros/cons are.
  544. *
  545. * References:
  546. *
  547. * http://en.wikipedia.org/wiki/Color_difference
  548. * http://en.wikipedia.org/wiki/Just_noticeable_difference
  549. * http://en.wikipedia.org/wiki/CIELAB
  550. *
  551. */
  552. // Check if it's a color
  553. if (![color isKindOfClass:[self class]]) {
  554. // NSLog(@"Not a %@ object.", NSStringFromClass([self class]));
  555. return MAXFLOAT;
  556. }
  557. // Set Up Common Variables
  558. NSArray *lab1 = [self CIE_LabArray];
  559. NSArray *lab2 = [color CIE_LabArray];
  560. CGFloat L1 = [lab1[0] floatValue];
  561. CGFloat A1 = [lab1[1] floatValue];
  562. CGFloat B1 = [lab1[2] floatValue];
  563. CGFloat L2 = [lab2[0] floatValue];
  564. CGFloat A2 = [lab2[1] floatValue];
  565. CGFloat B2 = [lab2[2] floatValue];
  566. // CIE76 first
  567. if (distanceType == ColorDistanceCIE76) {
  568. CGFloat distance = sqrtf(pow((L1-L2), 2) + pow((A1-A2), 2) + pow((B1-B2), 2));
  569. return distance;
  570. }
  571. // More Common Variables
  572. CGFloat kL = 1;
  573. CGFloat kC = 1;
  574. CGFloat kH = 1;
  575. CGFloat k1 = 0.045;
  576. CGFloat k2 = 0.015;
  577. CGFloat deltaL = L1 - L2;
  578. CGFloat C1 = sqrt((A1*A1) + (B1*B1));
  579. CGFloat C2 = sqrt((A2*A2) + (B2*B2));
  580. CGFloat deltaC = C1 - C2;
  581. CGFloat deltaH = sqrt(pow((A1-A2), 2.0) + pow((B1-B2), 2.0) - pow(deltaC, 2.0));
  582. CGFloat sL = 1;
  583. CGFloat sC = 1 + k1*(sqrt((A1*A1) + (B1*B1)));
  584. CGFloat sH = 1 + k2*(sqrt((A1*A1) + (B1*B1)));
  585. // CIE94
  586. if (distanceType == ColorDistanceCIE94) {
  587. return sqrt(pow((deltaL/(kL*sL)), 2.0) + pow((deltaC/(kC*sC)), 2.0) + pow((deltaH/(kH*sH)), 2.0));
  588. }
  589. // CIE2000
  590. // More variables
  591. CGFloat deltaLPrime = L2 - L1;
  592. CGFloat meanL = (L1 + L2)/2;
  593. CGFloat meanC = (C1 + C2)/2;
  594. CGFloat aPrime1 = A1 + A1/2*(1 - sqrt(pow(meanC, 7.0)/(pow(meanC, 7.0) + pow(25.0, 7.0))));
  595. CGFloat aPrime2 = A2 + A2/2*(1 - sqrt(pow(meanC, 7.0)/(pow(meanC, 7.0) + pow(25.0, 7.0))));
  596. CGFloat cPrime1 = sqrt((aPrime1*aPrime1) + (B1*B1));
  597. CGFloat cPrime2 = sqrt((aPrime2*aPrime2) + (B2*B2));
  598. CGFloat cMeanPrime = (cPrime1 + cPrime2)/2;
  599. CGFloat deltaCPrime = cPrime1 - cPrime2;
  600. CGFloat hPrime1 = atan2(B1, aPrime1);
  601. CGFloat hPrime2 = atan2(B2, aPrime2);
  602. hPrime1 = fmodf(hPrime1, RAD(360.0));
  603. hPrime2 = fmodf(hPrime2, RAD(360.0));
  604. CGFloat deltahPrime = 0;
  605. if (fabs(hPrime1 - hPrime2) <= RAD(180.0)) {
  606. deltahPrime = hPrime2 - hPrime1;
  607. }
  608. else {
  609. deltahPrime = (hPrime2 <= hPrime1) ? hPrime2 - hPrime1 + RAD(360.0) : hPrime2 - hPrime1 - RAD(360.0);
  610. }
  611. CGFloat deltaHPrime = 2 * sqrt(cPrime1*cPrime2) * sin(deltahPrime/2);
  612. CGFloat meanHPrime = (fabs(hPrime1 - hPrime2) <= RAD(180.0)) ? (hPrime1 + hPrime2)/2 : (hPrime1 + hPrime2 + RAD(360.0))/2;
  613. CGFloat T = 1 - 0.17*cos(meanHPrime - RAD(30.0)) + 0.24*cos(2*meanHPrime)+0.32*cos(3*meanHPrime + RAD(6.0)) - 0.20*cos(4*meanHPrime - RAD(63.0));
  614. sL = 1 + (0.015 * pow((meanL - 50), 2))/sqrt(20 + pow((meanL - 50), 2));
  615. sC = 1 + 0.045*cMeanPrime;
  616. sH = 1 + 0.015*cMeanPrime*T;
  617. CGFloat Rt = -2 * sqrt(pow(cMeanPrime, 7)/(pow(cMeanPrime, 7) + pow(25.0, 7))) * sin(RAD(60.0)* exp(-1 * pow((meanHPrime - RAD(275.0))/RAD(25.0), 2)));
  618. // Finally return CIE2000 distance
  619. return sqrt(pow((deltaLPrime/(kL*sL)), 2) + pow((deltaCPrime/(kC*sC)), 2) + pow((deltaHPrime/(kH*sH)), 2) + Rt*(deltaC/(kC*sC))*(deltaHPrime/(kH*sH)));
  620. }
  621. #pragma mark - Compare Colors
  622. + (NSArray *)sortColors:(NSArray *)colors withComparison:(ColorComparison)comparison {
  623. return [colors sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
  624. return [self compareColor:obj1 andColor:obj2 withComparison:comparison];
  625. }];
  626. }
  627. + (NSComparisonResult)compareColor:(id)colorA andColor:(id)colorB withComparison:(ColorComparison)comparison {
  628. if (![colorA isKindOfClass:[self class]] || ![colorB isKindOfClass:[self class]]) {
  629. return NSOrderedSame;
  630. }
  631. // Check Colors
  632. NSString *key = @"";
  633. boolean_t greater = true;
  634. NSDictionary *c1 = [colorA colorsForComparison:comparison key:&key greater:&greater];
  635. NSDictionary *c2 = [colorB colorsForComparison:comparison key:&key greater:&greater];
  636. return [self compareValue:[c1[key] floatValue] andValue:[c2[key] floatValue] greaterThan:greater];
  637. }
  638. #pragma mark - System Colors
  639. + (instancetype)infoBlueColor
  640. {
  641. return [[self class] colorWithR:47 G:112 B:225 A:1.0];
  642. }
  643. + (instancetype)successColor
  644. {
  645. return [[self class] colorWithR:83 G:215 B:106 A:1.0];
  646. }
  647. + (instancetype)warningColor
  648. {
  649. return [[self class] colorWithR:221 G:170 B:59 A:1.0];
  650. }
  651. + (instancetype)dangerColor
  652. {
  653. return [[self class] colorWithR:229 G:0 B:15 A:1.0];
  654. }
  655. #pragma mark - Whites
  656. + (instancetype)antiqueWhiteColor
  657. {
  658. return [[self class] colorWithR:250 G:235 B:215 A:1.0];
  659. }
  660. + (instancetype)oldLaceColor
  661. {
  662. return [[self class] colorWithR:253 G:245 B:230 A:1.0];
  663. }
  664. + (instancetype)ivoryColor
  665. {
  666. return [[self class] colorWithR:255 G:255 B:240 A:1.0];
  667. }
  668. + (instancetype)seashellColor
  669. {
  670. return [[self class] colorWithR:255 G:245 B:238 A:1.0];
  671. }
  672. + (instancetype)ghostWhiteColor
  673. {
  674. return [[self class] colorWithR:248 G:248 B:255 A:1.0];
  675. }
  676. + (instancetype)snowColor
  677. {
  678. return [[self class] colorWithR:255 G:250 B:250 A:1.0];
  679. }
  680. + (instancetype)linenColor
  681. {
  682. return [[self class] colorWithR:250 G:240 B:230 A:1.0];
  683. }
  684. #pragma mark - Grays
  685. + (instancetype)black25PercentColor
  686. {
  687. return [[self class] colorWithWhite:0.25 alpha:1.0];
  688. }
  689. + (instancetype)black50PercentColor
  690. {
  691. return [[self class] colorWithWhite:0.5 alpha:1.0];
  692. }
  693. + (instancetype)black75PercentColor
  694. {
  695. return [[self class] colorWithWhite:0.75 alpha:1.0];
  696. }
  697. + (instancetype)warmGrayColor
  698. {
  699. return [[self class] colorWithR:133 G:117 B:112 A:1.0];
  700. }
  701. + (instancetype)coolGrayColor
  702. {
  703. return [[self class] colorWithR:118 G:122 B:133 A:1.0];
  704. }
  705. + (instancetype)charcoalColor
  706. {
  707. return [[self class] colorWithR:34 G:34 B:34 A:1.0];
  708. }
  709. #pragma mark - Blues
  710. + (instancetype)tealColor
  711. {
  712. return [[self class] colorWithR:28 G:160 B:170 A:1.0];
  713. }
  714. + (instancetype)steelBlueColor
  715. {
  716. return [[self class] colorWithR:103 G:153 B:170 A:1.0];
  717. }
  718. + (instancetype)robinEggColor
  719. {
  720. return [[self class] colorWithR:141 G:218 B:247 A:1.0];
  721. }
  722. + (instancetype)pastelBlueColor
  723. {
  724. return [[self class] colorWithR:99 G:161 B:247 A:1.0];
  725. }
  726. + (instancetype)turquoiseColor
  727. {
  728. return [[self class] colorWithR:112 G:219 B:219 A:1.0];
  729. }
  730. + (instancetype)skyBlueColor
  731. {
  732. return [[self class] colorWithR:0 G:178 B:238 A:1.0];
  733. }
  734. + (instancetype)indigoColor
  735. {
  736. return [[self class] colorWithR:13 G:79 B:139 A:1.0];
  737. }
  738. + (instancetype)denimColor
  739. {
  740. return [[self class] colorWithR:67 G:114 B:170 A:1.0];
  741. }
  742. + (instancetype)blueberryColor
  743. {
  744. return [[self class] colorWithR:89 G:113 B:173 A:1.0];
  745. }
  746. + (instancetype)cornflowerColor
  747. {
  748. return [[self class] colorWithR:100 G:149 B:237 A:1.0];
  749. }
  750. + (instancetype)babyBlueColor
  751. {
  752. return [[self class] colorWithR:190 G:220 B:230 A:1.0];
  753. }
  754. + (instancetype)midnightBlueColor
  755. {
  756. return [[self class] colorWithR:13 G:26 B:35 A:1.0];
  757. }
  758. + (instancetype)fadedBlueColor
  759. {
  760. return [[self class] colorWithR:23 G:137 B:155 A:1.0];
  761. }
  762. + (instancetype)icebergColor
  763. {
  764. return [[self class] colorWithR:200 G:213 B:219 A:1.0];
  765. }
  766. + (instancetype)waveColor
  767. {
  768. return [[self class] colorWithR:102 G:169 B:251 A:1.0];
  769. }
  770. #pragma mark - Greens
  771. + (instancetype)emeraldColor
  772. {
  773. return [[self class] colorWithR:1 G:152 B:117 A:1.0];
  774. }
  775. + (instancetype)grassColor
  776. {
  777. return [[self class] colorWithR:99 G:214 B:74 A:1.0];
  778. }
  779. + (instancetype)pastelGreenColor
  780. {
  781. return [[self class] colorWithR:126 G:242 B:124 A:1.0];
  782. }
  783. + (instancetype)seafoamColor
  784. {
  785. return [[self class] colorWithR:77 G:226 B:140 A:1.0];
  786. }
  787. + (instancetype)paleGreenColor
  788. {
  789. return [[self class] colorWithR:176 G:226 B:172 A:1.0];
  790. }
  791. + (instancetype)cactusGreenColor
  792. {
  793. return [[self class] colorWithR:99 G:111 B:87 A:1.0];
  794. }
  795. + (instancetype)chartreuseColor
  796. {
  797. return [[self class] colorWithR:69 G:139 B:0 A:1.0];
  798. }
  799. + (instancetype)hollyGreenColor
  800. {
  801. return [[self class] colorWithR:32 G:87 B:14 A:1.0];
  802. }
  803. + (instancetype)oliveColor
  804. {
  805. return [[self class] colorWithR:91 G:114 B:34 A:1.0];
  806. }
  807. + (instancetype)oliveDrabColor
  808. {
  809. return [[self class] colorWithR:107 G:142 B:35 A:1.0];
  810. }
  811. + (instancetype)moneyGreenColor
  812. {
  813. return [[self class] colorWithR:134 G:198 B:124 A:1.0];
  814. }
  815. + (instancetype)honeydewColor
  816. {
  817. return [[self class] colorWithR:216 G:255 B:231 A:1.0];
  818. }
  819. + (instancetype)limeColor
  820. {
  821. return [[self class] colorWithR:56 G:237 B:56 A:1.0];
  822. }
  823. + (instancetype)cardTableColor
  824. {
  825. return [[self class] colorWithR:87 G:121 B:107 A:1.0];
  826. }
  827. #pragma mark - Reds
  828. + (instancetype)salmonColor
  829. {
  830. return [[self class] colorWithR:233 G:87 B:95 A:1.0];
  831. }
  832. + (instancetype)brickRedColor
  833. {
  834. return [[self class] colorWithR:151 G:27 B:16 A:1.0];
  835. }
  836. + (instancetype)easterPinkColor
  837. {
  838. return [[self class] colorWithR:241 G:167 B:162 A:1.0];
  839. }
  840. + (instancetype)grapefruitColor
  841. {
  842. return [[self class] colorWithR:228 G:31 B:54 A:1.0];
  843. }
  844. + (instancetype)pinkColor
  845. {
  846. return [[self class] colorWithR:255 G:95 B:154 A:1.0];
  847. }
  848. + (instancetype)indianRedColor
  849. {
  850. return [[self class] colorWithR:205 G:92 B:92 A:1.0];
  851. }
  852. + (instancetype)strawberryColor
  853. {
  854. return [[self class] colorWithR:190 G:38 B:37 A:1.0];
  855. }
  856. + (instancetype)coralColor
  857. {
  858. return [[self class] colorWithR:240 G:128 B:128 A:1.0];
  859. }
  860. + (instancetype)maroonColor
  861. {
  862. return [[self class] colorWithR:80 G:4 B:28 A:1.0];
  863. }
  864. + (instancetype)watermelonColor
  865. {
  866. return [[self class] colorWithR:242 G:71 B:63 A:1.0];
  867. }
  868. + (instancetype)tomatoColor
  869. {
  870. return [[self class] colorWithR:255 G:99 B:71 A:1.0];
  871. }
  872. + (instancetype)pinkLipstickColor
  873. {
  874. return [[self class] colorWithR:255 G:105 B:180 A:1.0];
  875. }
  876. + (instancetype)paleRoseColor
  877. {
  878. return [[self class] colorWithR:255 G:228 B:225 A:1.0];
  879. }
  880. + (instancetype)crimsonColor
  881. {
  882. return [[self class] colorWithR:187 G:18 B:36 A:1.0];
  883. }
  884. #pragma mark - Purples
  885. + (instancetype)eggplantColor
  886. {
  887. return [[self class] colorWithR:105 G:5 B:98 A:1.0];
  888. }
  889. + (instancetype)pastelPurpleColor
  890. {
  891. return [[self class] colorWithR:207 G:100 B:235 A:1.0];
  892. }
  893. + (instancetype)palePurpleColor
  894. {
  895. return [[self class] colorWithR:229 G:180 B:235 A:1.0];
  896. }
  897. + (instancetype)coolPurpleColor
  898. {
  899. return [[self class] colorWithR:140 G:93 B:228 A:1.0];
  900. }
  901. + (instancetype)violetColor
  902. {
  903. return [[self class] colorWithR:191 G:95 B:255 A:1.0];
  904. }
  905. + (instancetype)plumColor
  906. {
  907. return [[self class] colorWithR:139 G:102 B:139 A:1.0];
  908. }
  909. + (instancetype)lavenderColor
  910. {
  911. return [[self class] colorWithR:204 G:153 B:204 A:1.0];
  912. }
  913. + (instancetype)raspberryColor
  914. {
  915. return [[self class] colorWithR:135 G:38 B:87 A:1.0];
  916. }
  917. + (instancetype)fuschiaColor
  918. {
  919. return [[self class] colorWithR:255 G:20 B:147 A:1.0];
  920. }
  921. + (instancetype)grapeColor
  922. {
  923. return [[self class] colorWithR:54 G:11 B:88 A:1.0];
  924. }
  925. + (instancetype)periwinkleColor
  926. {
  927. return [[self class] colorWithR:135 G:159 B:237 A:1.0];
  928. }
  929. + (instancetype)orchidColor
  930. {
  931. return [[self class] colorWithR:218 G:112 B:214 A:1.0];
  932. }
  933. #pragma mark - Yellows
  934. + (instancetype)goldenrodColor
  935. {
  936. return [[self class] colorWithR:215 G:170 B:51 A:1.0];
  937. }
  938. + (instancetype)yellowGreenColor
  939. {
  940. return [[self class] colorWithR:192 G:242 B:39 A:1.0];
  941. }
  942. + (instancetype)bananaColor
  943. {
  944. return [[self class] colorWithR:229 G:227 B:58 A:1.0];
  945. }
  946. + (instancetype)mustardColor
  947. {
  948. return [[self class] colorWithR:205 G:171 B:45 A:1.0];
  949. }
  950. + (instancetype)buttermilkColor
  951. {
  952. return [[self class] colorWithR:254 G:241 B:181 A:1.0];
  953. }
  954. + (instancetype)goldColor
  955. {
  956. return [[self class] colorWithR:139 G:117 B:18 A:1.0];
  957. }
  958. + (instancetype)creamColor
  959. {
  960. return [[self class] colorWithR:240 G:226 B:187 A:1.0];
  961. }
  962. + (instancetype)lightCreamColor
  963. {
  964. return [[self class] colorWithR:240 G:238 B:215 A:1.0];
  965. }
  966. + (instancetype)wheatColor
  967. {
  968. return [[self class] colorWithR:240 G:238 B:215 A:1.0];
  969. }
  970. + (instancetype)beigeColor
  971. {
  972. return [[self class] colorWithR:245 G:245 B:220 A:1.0];
  973. }
  974. #pragma mark - Oranges
  975. + (instancetype)peachColor
  976. {
  977. return [[self class] colorWithR:242 G:187 B:97 A:1.0];
  978. }
  979. + (instancetype)burntOrangeColor
  980. {
  981. return [[self class] colorWithR:184 G:102 B:37 A:1.0];
  982. }
  983. + (instancetype)pastelOrangeColor
  984. {
  985. return [[self class] colorWithR:248 G:197 B:143 A:1.0];
  986. }
  987. + (instancetype)cantaloupeColor
  988. {
  989. return [[self class] colorWithR:250 G:154 B:79 A:1.0];
  990. }
  991. + (instancetype)carrotColor
  992. {
  993. return [[self class] colorWithR:237 G:145 B:33 A:1.0];
  994. }
  995. + (instancetype)mandarinColor
  996. {
  997. return [[self class] colorWithR:247 G:145 B:55 A:1.0];
  998. }
  999. #pragma mark - Browns
  1000. + (instancetype)chiliPowderColor
  1001. {
  1002. return [[self class] colorWithR:199 G:63 B:23 A:1.0];
  1003. }
  1004. + (instancetype)burntSiennaColor
  1005. {
  1006. return [[self class] colorWithR:138 G:54 B:15 A:1.0];
  1007. }
  1008. + (instancetype)chocolateColor
  1009. {
  1010. return [[self class] colorWithR:94 G:38 B:5 A:1.0];
  1011. }
  1012. + (instancetype)coffeeColor
  1013. {
  1014. return [[self class] colorWithR:141 G:60 B:15 A:1.0];
  1015. }
  1016. + (instancetype)cinnamonColor
  1017. {
  1018. return [[self class] colorWithR:123 G:63 B:9 A:1.0];
  1019. }
  1020. + (instancetype)almondColor
  1021. {
  1022. return [[self class] colorWithR:196 G:142 B:72 A:1.0];
  1023. }
  1024. + (instancetype)eggshellColor
  1025. {
  1026. return [[self class] colorWithR:252 G:230 B:201 A:1.0];
  1027. }
  1028. + (instancetype)sandColor
  1029. {
  1030. return [[self class] colorWithR:222 G:182 B:151 A:1.0];
  1031. }
  1032. + (instancetype)mudColor
  1033. {
  1034. return [[self class] colorWithR:70 G:45 B:29 A:1.0];
  1035. }
  1036. + (instancetype)siennaColor
  1037. {
  1038. return [[self class] colorWithR:160 G:82 B:45 A:1.0];
  1039. }
  1040. + (instancetype)dustColor
  1041. {
  1042. return [[self class] colorWithR:236 G:214 B:197 A:1.0];
  1043. }
  1044. #pragma mark - Private
  1045. #pragma mark - RGBA Helper method
  1046. + (instancetype)colorWithR:(CGFloat)red G:(CGFloat)green B:(CGFloat)blue A:(CGFloat)alpha
  1047. {
  1048. return [[self class] colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha];
  1049. }
  1050. #pragma mark - Degrees Helper method for Color Schemes
  1051. + (float)addDegrees:(float)addDeg toDegree:(float)staticDeg
  1052. {
  1053. staticDeg += addDeg;
  1054. if (staticDeg > 360) {
  1055. float offset = staticDeg - 360;
  1056. return offset;
  1057. }
  1058. else if (staticDeg < 0) {
  1059. return -1 * staticDeg;
  1060. }
  1061. else {
  1062. return staticDeg;
  1063. }
  1064. }
  1065. #pragma mark - Color Comparison
  1066. - (NSDictionary *)colorsForComparison:(ColorComparison)comparison key:(NSString **)key greater:(boolean_t *)greaterThan {
  1067. switch (comparison) {
  1068. case ColorComparisonRed:
  1069. *key = kColoursRGBA_R;
  1070. *greaterThan = true;
  1071. return [self rgbaDictionary];
  1072. case ColorComparisonGreen:
  1073. *key = kColoursRGBA_G;
  1074. *greaterThan = true;
  1075. return [self rgbaDictionary];
  1076. case ColorComparisonBlue:
  1077. *key = kColoursRGBA_B;
  1078. *greaterThan = true;
  1079. return [self rgbaDictionary];
  1080. case ColorComparisonDarkness:
  1081. *key = kColoursHSBA_B;
  1082. *greaterThan = false;
  1083. return [self hsbaDictionary];
  1084. case ColorComparisonLightness:
  1085. *key = kColoursHSBA_B;
  1086. *greaterThan = true;
  1087. return [self hsbaDictionary];
  1088. case ColorComparisonSaturated:
  1089. *key = kColoursHSBA_S;
  1090. *greaterThan = true;
  1091. return [self hsbaDictionary];
  1092. case ColorComparisonDesaturated:
  1093. *key = kColoursHSBA_S;
  1094. *greaterThan = false;
  1095. return [self hsbaDictionary];
  1096. default:
  1097. *key = kColoursRGBA_R;
  1098. *greaterThan = true;
  1099. return [self rgbaDictionary];
  1100. }
  1101. }
  1102. + (NSComparisonResult)compareValue:(CGFloat)v1 andValue:(CGFloat)v2 greaterThan:(boolean_t)greaterThan {
  1103. CGFloat comparison = v1 - v2;
  1104. comparison = (greaterThan == true ? 1 : -1)*comparison;
  1105. return (comparison == 0.0 ? NSOrderedSame : (comparison < 0.0 ? NSOrderedDescending : NSOrderedAscending));
  1106. }
  1107. #pragma mark - Swizzle
  1108. #pragma mark - On Load - Flip methods
  1109. + (void)load {
  1110. static dispatch_once_t onceToken;
  1111. dispatch_once(&onceToken, ^{
  1112. Class class = [self class];
  1113. SEL rgbaSelector = @selector(getRed:green:blue:alpha:);
  1114. SEL swizzledRGBASelector = @selector(colours_getRed:green:blue:alpha:);
  1115. SEL hsbaSelector = @selector(getHue:saturation:brightness:alpha:);
  1116. SEL swizzledHSBASelector = @selector(colours_getHue:saturation:brightness:alpha:);
  1117. Method rgbaMethod = class_getInstanceMethod(class, rgbaSelector);
  1118. Method swizzledRGBAMethod = class_getInstanceMethod(class, swizzledRGBASelector);
  1119. Method hsbaMethod = class_getInstanceMethod(class, hsbaSelector);
  1120. Method swizzledHSBAMethod = class_getInstanceMethod(class, swizzledHSBASelector);
  1121. // Attempt adding the methods
  1122. BOOL didAddRGBAMethod =
  1123. class_addMethod(class,
  1124. rgbaSelector,
  1125. method_getImplementation(swizzledRGBAMethod),
  1126. method_getTypeEncoding(swizzledRGBAMethod));
  1127. BOOL didAddHSBAMethod =
  1128. class_addMethod(class,
  1129. hsbaSelector,
  1130. method_getImplementation(swizzledHSBAMethod),
  1131. method_getTypeEncoding(swizzledHSBAMethod));
  1132. // Replace methods
  1133. if (didAddRGBAMethod) {
  1134. class_replaceMethod(class,
  1135. swizzledRGBASelector,
  1136. method_getImplementation(swizzledRGBAMethod),
  1137. method_getTypeEncoding(swizzledRGBAMethod));
  1138. } else {
  1139. method_exchangeImplementations(rgbaMethod, swizzledRGBAMethod);
  1140. }
  1141. if (didAddHSBAMethod) {
  1142. class_replaceMethod(class,
  1143. swizzledHSBASelector,
  1144. method_getImplementation(swizzledHSBAMethod),
  1145. method_getTypeEncoding(swizzledHSBAMethod));
  1146. } else {
  1147. method_exchangeImplementations(hsbaMethod, swizzledHSBAMethod);
  1148. }
  1149. });
  1150. }
  1151. #pragma mark - Swizzled Methods
  1152. - (BOOL)colours_getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha
  1153. {
  1154. if (CGColorGetNumberOfComponents(self.CGColor) == 4) {
  1155. return [self colours_getRed:red green:green blue:blue alpha:alpha];
  1156. }
  1157. else if (CGColorGetNumberOfComponents(self.CGColor) == 2) {
  1158. CGFloat white;
  1159. CGFloat m_alpha;
  1160. [self getWhite:&white alpha:&m_alpha];
  1161. *red = white * 1.0;
  1162. *green = white * 1.0;
  1163. *blue = white * 1.0;
  1164. if (alpha) {
  1165. *alpha = m_alpha;
  1166. }
  1167. return YES;
  1168. }
  1169. return NO;
  1170. }
  1171. - (BOOL)colours_getHue:(CGFloat *)hue saturation:(CGFloat *)saturation brightness:(CGFloat *)brightness alpha:(CGFloat *)alpha
  1172. {
  1173. if (CGColorGetNumberOfComponents(self.CGColor) == 4) {
  1174. return [self colours_getHue:hue saturation:saturation brightness:brightness alpha:alpha];
  1175. }
  1176. else if (CGColorGetNumberOfComponents(self.CGColor) == 2) {
  1177. CGFloat white = 0;
  1178. CGFloat a = 0;
  1179. [self getWhite:&white alpha:&a];
  1180. *hue = 0;
  1181. *saturation = 0;
  1182. *brightness = white * 1.0;
  1183. if (alpha) {
  1184. *alpha = a * 1.0;
  1185. }
  1186. return YES;
  1187. }
  1188. return NO;
  1189. }
  1190. @end