UIColor+YYAdd.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. //
  2. // UIColor+YYAdd.m
  3. // YYKit <https://github.com/ibireme/YYKit>
  4. //
  5. // Created by ibireme on 13/4/4.
  6. // Copyright (c) 2015 ibireme.
  7. //
  8. // This source code is licensed under the MIT-style license found in the
  9. // LICENSE file in the root directory of this source tree.
  10. //
  11. #import "UIColor+YYAdd.h"
  12. #import "NSString+YYAdd.h"
  13. #import "YYKitMacro.h"
  14. YYSYNTH_DUMMY_CLASS(UIColor_YYAdd)
  15. #define CLAMP_COLOR_VALUE(v) (v) = (v) < 0 ? 0 : (v) > 1 ? 1 : (v)
  16. void YY_RGB2HSL(CGFloat r, CGFloat g, CGFloat b,
  17. CGFloat *h, CGFloat *s, CGFloat *l) {
  18. CLAMP_COLOR_VALUE(r);
  19. CLAMP_COLOR_VALUE(g);
  20. CLAMP_COLOR_VALUE(b);
  21. CGFloat max, min, delta, sum;
  22. max = fmaxf(r, fmaxf(g, b));
  23. min = fminf(r, fminf(g, b));
  24. delta = max - min;
  25. sum = max + min;
  26. *l = sum / 2; // Lightness
  27. if (delta == 0) { // No Saturation, so Hue is undefined (achromatic)
  28. *h = *s = 0;
  29. return;
  30. }
  31. *s = delta / (sum < 1 ? sum : 2 - sum); // Saturation
  32. if (r == max) *h = (g - b) / delta / 6; // color between y & m
  33. else if (g == max) *h = (2 + (b - r) / delta) / 6; // color between c & y
  34. else *h = (4 + (r - g) / delta) / 6; // color between m & y
  35. if (*h < 0) *h += 1;
  36. }
  37. void YY_HSL2RGB(CGFloat h, CGFloat s, CGFloat l,
  38. CGFloat *r, CGFloat *g, CGFloat *b) {
  39. CLAMP_COLOR_VALUE(h);
  40. CLAMP_COLOR_VALUE(s);
  41. CLAMP_COLOR_VALUE(l);
  42. if (s == 0) { // No Saturation, Hue is undefined (achromatic)
  43. *r = *g = *b = l;
  44. return;
  45. }
  46. CGFloat q;
  47. q = (l <= 0.5) ? (l * (1 + s)) : (l + s - (l * s));
  48. if (q <= 0) {
  49. *r = *g = *b = 0.0;
  50. } else {
  51. *r = *g = *b = 0;
  52. int sextant;
  53. CGFloat m, sv, fract, vsf, mid1, mid2;
  54. m = l + l - q;
  55. sv = (q - m) / q;
  56. if (h == 1) h = 0;
  57. h *= 6.0;
  58. sextant = h;
  59. fract = h - sextant;
  60. vsf = q * sv * fract;
  61. mid1 = m + vsf;
  62. mid2 = q - vsf;
  63. switch (sextant) {
  64. case 0: *r = q; *g = mid1; *b = m; break;
  65. case 1: *r = mid2; *g = q; *b = m; break;
  66. case 2: *r = m; *g = q; *b = mid1; break;
  67. case 3: *r = m; *g = mid2; *b = q; break;
  68. case 4: *r = mid1; *g = m; *b = q; break;
  69. case 5: *r = q; *g = m; *b = mid2; break;
  70. }
  71. }
  72. }
  73. void YY_RGB2HSB(CGFloat r, CGFloat g, CGFloat b,
  74. CGFloat *h, CGFloat *s, CGFloat *v) {
  75. CLAMP_COLOR_VALUE(r);
  76. CLAMP_COLOR_VALUE(g);
  77. CLAMP_COLOR_VALUE(b);
  78. CGFloat max, min, delta;
  79. max = fmax(r, fmax(g, b));
  80. min = fmin(r, fmin(g, b));
  81. delta = max - min;
  82. *v = max; // Brightness
  83. if (delta == 0) { // No Saturation, so Hue is undefined (achromatic)
  84. *h = *s = 0;
  85. return;
  86. }
  87. *s = delta / max; // Saturation
  88. if (r == max) *h = (g - b) / delta / 6; // color between y & m
  89. else if (g == max) *h = (2 + (b - r) / delta) / 6; // color between c & y
  90. else *h = (4 + (r - g) / delta) / 6; // color between m & c
  91. if (*h < 0) *h += 1;
  92. }
  93. void YY_HSB2RGB(CGFloat h, CGFloat s, CGFloat v,
  94. CGFloat *r, CGFloat *g, CGFloat *b) {
  95. CLAMP_COLOR_VALUE(h);
  96. CLAMP_COLOR_VALUE(s);
  97. CLAMP_COLOR_VALUE(v);
  98. if (s == 0) {
  99. *r = *g = *b = v; // No Saturation, so Hue is undefined (Achromatic)
  100. } else {
  101. int sextant;
  102. CGFloat f, p, q, t;
  103. if (h == 1) h = 0;
  104. h *= 6;
  105. sextant = floor(h);
  106. f = h - sextant;
  107. p = v * (1 - s);
  108. q = v * (1 - s * f);
  109. t = v * (1 - s * (1 - f));
  110. switch (sextant) {
  111. case 0: *r = v; *g = t; *b = p; break;
  112. case 1: *r = q; *g = v; *b = p; break;
  113. case 2: *r = p; *g = v; *b = t; break;
  114. case 3: *r = p; *g = q; *b = v; break;
  115. case 4: *r = t; *g = p; *b = v; break;
  116. case 5: *r = v; *g = p; *b = q; break;
  117. }
  118. }
  119. }
  120. void YY_RGB2CMYK(CGFloat r, CGFloat g, CGFloat b,
  121. CGFloat *c, CGFloat *m, CGFloat *y, CGFloat *k) {
  122. CLAMP_COLOR_VALUE(r);
  123. CLAMP_COLOR_VALUE(g);
  124. CLAMP_COLOR_VALUE(b);
  125. *c = 1 - r;
  126. *m = 1 - g;
  127. *y = 1 - b;
  128. *k = fmin(*c, fmin(*m, *y));
  129. if (*k == 1) {
  130. *c = *m = *y = 0; // Pure black
  131. } else {
  132. *c = (*c - *k) / (1 - *k);
  133. *m = (*m - *k) / (1 - *k);
  134. *y = (*y - *k) / (1 - *k);
  135. }
  136. }
  137. void YY_CMYK2RGB(CGFloat c, CGFloat m, CGFloat y, CGFloat k,
  138. CGFloat *r, CGFloat *g, CGFloat *b) {
  139. CLAMP_COLOR_VALUE(c);
  140. CLAMP_COLOR_VALUE(m);
  141. CLAMP_COLOR_VALUE(y);
  142. CLAMP_COLOR_VALUE(k);
  143. *r = (1 - c) * (1 - k);
  144. *g = (1 - m) * (1 - k);
  145. *b = (1 - y) * (1 - k);
  146. }
  147. void YY_HSB2HSL(CGFloat h, CGFloat s, CGFloat b,
  148. CGFloat *hh, CGFloat *ss, CGFloat *ll) {
  149. CLAMP_COLOR_VALUE(h);
  150. CLAMP_COLOR_VALUE(s);
  151. CLAMP_COLOR_VALUE(b);
  152. *hh = h;
  153. *ll = (2 - s) * b / 2;
  154. if (*ll <= 0.5) {
  155. *ss = (s) / ((2 - s));
  156. } else {
  157. *ss = (s * b) / (2 - (2 - s) * b);
  158. }
  159. }
  160. void YY_HSL2HSB(CGFloat h, CGFloat s, CGFloat l,
  161. CGFloat *hh, CGFloat *ss, CGFloat *bb) {
  162. CLAMP_COLOR_VALUE(h);
  163. CLAMP_COLOR_VALUE(s);
  164. CLAMP_COLOR_VALUE(l);
  165. *hh = h;
  166. if (l <= 0.5) {
  167. *bb = (s + 1) * l;
  168. *ss = (2 * s) / (s + 1);
  169. } else {
  170. *bb = l + s * (1 - l);
  171. *ss = (2 * s * (1 - l)) / *bb;
  172. }
  173. }
  174. #undef CLAMP_COLOR_VALUE
  175. @implementation UIColor (YYAdd)
  176. + (UIColor *)colorWithHue:(CGFloat)hue
  177. saturation:(CGFloat)saturation
  178. lightness:(CGFloat)lightness
  179. alpha:(CGFloat)alpha {
  180. CGFloat r, g, b;
  181. YY_HSL2RGB(hue, saturation, lightness, &r, &g, &b);
  182. return [UIColor colorWithRed:r green:g blue:b alpha:alpha];
  183. }
  184. + (UIColor *)colorWithCyan:(CGFloat)cyan
  185. magenta:(CGFloat)magenta
  186. yellow:(CGFloat)yellow
  187. black:(CGFloat)black
  188. alpha:(CGFloat)alpha {
  189. CGFloat r, g, b;
  190. YY_CMYK2RGB(cyan, magenta, yellow, black, &r, &g, &b);
  191. return [UIColor colorWithRed:r green:g blue:b alpha:alpha];
  192. }
  193. + (UIColor *)colorWithRGB:(uint32_t)rgbValue {
  194. return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0f
  195. green:((rgbValue & 0xFF00) >> 8) / 255.0f
  196. blue:(rgbValue & 0xFF) / 255.0f
  197. alpha:1];
  198. }
  199. + (UIColor *)colorWithRGBA:(uint32_t)rgbaValue {
  200. return [UIColor colorWithRed:((rgbaValue & 0xFF000000) >> 24) / 255.0f
  201. green:((rgbaValue & 0xFF0000) >> 16) / 255.0f
  202. blue:((rgbaValue & 0xFF00) >> 8) / 255.0f
  203. alpha:(rgbaValue & 0xFF) / 255.0f];
  204. }
  205. + (UIColor *)colorWithRGB:(uint32_t)rgbValue alpha:(CGFloat)alpha {
  206. return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0f
  207. green:((rgbValue & 0xFF00) >> 8) / 255.0f
  208. blue:(rgbValue & 0xFF) / 255.0f
  209. alpha:alpha];
  210. }
  211. - (uint32_t)rgbValue {
  212. CGFloat r = 0, g = 0, b = 0, a = 0;
  213. [self getRed:&r green:&g blue:&b alpha:&a];
  214. int8_t red = r * 255;
  215. uint8_t green = g * 255;
  216. uint8_t blue = b * 255;
  217. return (red << 16) + (green << 8) + blue;
  218. }
  219. - (uint32_t)rgbaValue {
  220. CGFloat r = 0, g = 0, b = 0, a = 0;
  221. [self getRed:&r green:&g blue:&b alpha:&a];
  222. int8_t red = r * 255;
  223. uint8_t green = g * 255;
  224. uint8_t blue = b * 255;
  225. uint8_t alpha = a * 255;
  226. return (red << 24) + (green << 16) + (blue << 8) + alpha;
  227. }
  228. static inline NSUInteger hexStrToInt(NSString *str) {
  229. uint32_t result = 0;
  230. sscanf([str UTF8String], "%X", &result);
  231. return result;
  232. }
  233. static BOOL hexStrToRGBA(NSString *str,
  234. CGFloat *r, CGFloat *g, CGFloat *b, CGFloat *a) {
  235. str = [[str stringByTrim] uppercaseString];
  236. if ([str hasPrefix:@"#"]) {
  237. str = [str substringFromIndex:1];
  238. } else if ([str hasPrefix:@"0X"]) {
  239. str = [str substringFromIndex:2];
  240. }
  241. NSUInteger length = [str length];
  242. // RGB RGBA RRGGBB RRGGBBAA
  243. if (length != 3 && length != 4 && length != 6 && length != 8) {
  244. return NO;
  245. }
  246. //RGB,RGBA,RRGGBB,RRGGBBAA
  247. if (length < 5) {
  248. *r = hexStrToInt([str substringWithRange:NSMakeRange(0, 1)]) / 255.0f;
  249. *g = hexStrToInt([str substringWithRange:NSMakeRange(1, 1)]) / 255.0f;
  250. *b = hexStrToInt([str substringWithRange:NSMakeRange(2, 1)]) / 255.0f;
  251. if (length == 4) *a = hexStrToInt([str substringWithRange:NSMakeRange(3, 1)]) / 255.0f;
  252. else *a = 1;
  253. } else {
  254. *r = hexStrToInt([str substringWithRange:NSMakeRange(0, 2)]) / 255.0f;
  255. *g = hexStrToInt([str substringWithRange:NSMakeRange(2, 2)]) / 255.0f;
  256. *b = hexStrToInt([str substringWithRange:NSMakeRange(4, 2)]) / 255.0f;
  257. if (length == 8) *a = hexStrToInt([str substringWithRange:NSMakeRange(6, 2)]) / 255.0f;
  258. else *a = 1;
  259. }
  260. return YES;
  261. }
  262. + (instancetype)colorWithHexString:(NSString *)hexStr {
  263. CGFloat r, g, b, a;
  264. if (hexStrToRGBA(hexStr, &r, &g, &b, &a)) {
  265. return [UIColor colorWithRed:r green:g blue:b alpha:a];
  266. }
  267. return nil;
  268. }
  269. - (NSString *)hexString {
  270. return [self hexStringWithAlpha:NO];
  271. }
  272. - (NSString *)hexStringWithAlpha {
  273. return [self hexStringWithAlpha:YES];
  274. }
  275. - (NSString *)hexStringWithAlpha:(BOOL)withAlpha {
  276. CGColorRef color = self.CGColor;
  277. size_t count = CGColorGetNumberOfComponents(color);
  278. const CGFloat *components = CGColorGetComponents(color);
  279. static NSString *stringFormat = @"%02x%02x%02x";
  280. NSString *hex = nil;
  281. if (count == 2) {
  282. NSUInteger white = (NSUInteger)(components[0] * 255.0f);
  283. hex = [NSString stringWithFormat:stringFormat, white, white, white];
  284. } else if (count == 4) {
  285. hex = [NSString stringWithFormat:stringFormat,
  286. (NSUInteger)(components[0] * 255.0f),
  287. (NSUInteger)(components[1] * 255.0f),
  288. (NSUInteger)(components[2] * 255.0f)];
  289. }
  290. if (hex && withAlpha) {
  291. hex = [hex stringByAppendingFormat:@"%02lx",
  292. (unsigned long)(self.alpha * 255.0 + 0.5)];
  293. }
  294. return hex;
  295. }
  296. - (UIColor *)colorByAddColor:(UIColor *)add blendMode:(CGBlendMode)blendMode {
  297. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  298. CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
  299. uint8_t pixel[4] = { 0 };
  300. CGContextRef context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, colorSpace, bitmapInfo);
  301. CGContextSetFillColorWithColor(context, self.CGColor);
  302. CGContextFillRect(context, CGRectMake(0, 0, 1, 1));
  303. CGContextSetBlendMode(context, blendMode);
  304. CGContextSetFillColorWithColor(context, add.CGColor);
  305. CGContextFillRect(context, CGRectMake(0, 0, 1, 1));
  306. CGContextRelease(context);
  307. CGColorSpaceRelease(colorSpace);
  308. return [UIColor colorWithRed:pixel[0] / 255.0f green:pixel[1] / 255.0f blue:pixel[2] / 255.0f alpha:pixel[3] / 255.0f];
  309. }
  310. - (UIColor *)colorByChangeHue:(CGFloat)h saturation:(CGFloat)s brightness:(CGFloat)b alpha:(CGFloat)a {
  311. CGFloat hh, ss, bb, aa;
  312. if (![self getHue:&hh saturation:&ss brightness:&bb alpha:&aa]) {
  313. return self;
  314. }
  315. hh += h;
  316. ss += s;
  317. bb += b;
  318. aa += a;
  319. hh -= (int)hh;
  320. hh = hh < 0 ? hh + 1 : hh;
  321. ss = ss < 0 ? 0 : ss > 1 ? 1 : ss;
  322. bb = bb < 0 ? 0 : bb > 1 ? 1 : bb;
  323. aa = aa < 0 ? 0 : aa > 1 ? 1 : aa;
  324. return [UIColor colorWithHue:hh saturation:ss brightness:bb alpha:aa];
  325. }
  326. - (BOOL)getHue:(CGFloat *)hue
  327. saturation:(CGFloat *)saturation
  328. lightness:(CGFloat *)lightness
  329. alpha:(CGFloat *)alpha {
  330. CGFloat r, g, b, a;
  331. if (![self getRed:&r green:&g blue:&b alpha:&a]) {
  332. return NO;
  333. }
  334. YY_RGB2HSL(r, g, b, hue, saturation, lightness);
  335. *alpha = a;
  336. return YES;
  337. }
  338. - (BOOL)getCyan:(CGFloat *)cyan
  339. magenta:(CGFloat *)magenta
  340. yellow:(CGFloat *)yellow
  341. black:(CGFloat *)black
  342. alpha:(CGFloat *)alpha {
  343. CGFloat r, g, b, a;
  344. if (![self getRed:&r green:&g blue:&b alpha:&a]) {
  345. return NO;
  346. }
  347. YY_RGB2CMYK(r, g, b, cyan, magenta, yellow, black);
  348. *alpha = a;
  349. return YES;
  350. }
  351. - (CGFloat)red {
  352. CGFloat r = 0, g, b, a;
  353. [self getRed:&r green:&g blue:&b alpha:&a];
  354. return r;
  355. }
  356. - (CGFloat)green {
  357. CGFloat r, g = 0, b, a;
  358. [self getRed:&r green:&g blue:&b alpha:&a];
  359. return g;
  360. }
  361. - (CGFloat)blue {
  362. CGFloat r, g, b = 0, a;
  363. [self getRed:&r green:&g blue:&b alpha:&a];
  364. return b;
  365. }
  366. - (CGFloat)alpha {
  367. return CGColorGetAlpha(self.CGColor);
  368. }
  369. - (CGFloat)hue {
  370. CGFloat h = 0, s, b, a;
  371. [self getHue:&h saturation:&s brightness:&b alpha:&a];
  372. return h;
  373. }
  374. - (CGFloat)saturation {
  375. CGFloat h, s = 0, b, a;
  376. [self getHue:&h saturation:&s brightness:&b alpha:&a];
  377. return s;
  378. }
  379. - (CGFloat)brightness {
  380. CGFloat h, s, b = 0, a;
  381. [self getHue:&h saturation:&s brightness:&b alpha:&a];
  382. return b;
  383. }
  384. - (CGColorSpaceModel)colorSpaceModel {
  385. return CGColorSpaceGetModel(CGColorGetColorSpace(self.CGColor));
  386. }
  387. - (NSString *)colorSpaceString {
  388. CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(self.CGColor));
  389. switch (model) {
  390. case kCGColorSpaceModelUnknown:
  391. return @"kCGColorSpaceModelUnknown";
  392. case kCGColorSpaceModelMonochrome:
  393. return @"kCGColorSpaceModelMonochrome";
  394. case kCGColorSpaceModelRGB:
  395. return @"kCGColorSpaceModelRGB";
  396. case kCGColorSpaceModelCMYK:
  397. return @"kCGColorSpaceModelCMYK";
  398. case kCGColorSpaceModelLab:
  399. return @"kCGColorSpaceModelLab";
  400. case kCGColorSpaceModelDeviceN:
  401. return @"kCGColorSpaceModelDeviceN";
  402. case kCGColorSpaceModelIndexed:
  403. return @"kCGColorSpaceModelIndexed";
  404. case kCGColorSpaceModelPattern:
  405. return @"kCGColorSpaceModelPattern";
  406. default:
  407. return @"ColorSpaceInvalid";
  408. }
  409. }
  410. @end