YYCGUtilities.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. //
  2. // YYCGUtilities.m
  3. // YYKit <https://github.com/ibireme/YYKit>
  4. //
  5. // Created by ibireme on 15/2/28.
  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 "YYCGUtilities.h"
  12. #import <Accelerate/Accelerate.h>
  13. #import "UIView+YYAdd.h"
  14. CGContextRef YYCGContextCreateARGBBitmapContext(CGSize size, BOOL opaque, CGFloat scale) {
  15. size_t width = ceil(size.width * scale);
  16. size_t height = ceil(size.height * scale);
  17. if (width < 1 || height < 1) return NULL;
  18. //pre-multiplied ARGB, 8-bits per component
  19. CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
  20. CGImageAlphaInfo alphaInfo = (opaque ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaPremultipliedFirst);
  21. CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo);
  22. CGColorSpaceRelease(space);
  23. if (context) {
  24. CGContextTranslateCTM(context, 0, height);
  25. CGContextScaleCTM(context, scale, -scale);
  26. }
  27. return context;
  28. }
  29. CGContextRef YYCGContextCreateGrayBitmapContext(CGSize size, CGFloat scale) {
  30. size_t width = ceil(size.width * scale);
  31. size_t height = ceil(size.height * scale);
  32. if (width < 1 || height < 1) return NULL;
  33. //DeviceGray, 8-bits per component
  34. CGColorSpaceRef space = CGColorSpaceCreateDeviceGray();
  35. CGImageAlphaInfo alphaInfo = kCGImageAlphaNone;
  36. CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, kCGBitmapByteOrderDefault | alphaInfo);
  37. CGColorSpaceRelease(space);
  38. if (context) {
  39. CGContextTranslateCTM(context, 0, height);
  40. CGContextScaleCTM(context, scale, -scale);
  41. }
  42. return context;
  43. }
  44. CGFloat YYScreenScale() {
  45. static CGFloat scale;
  46. static dispatch_once_t onceToken;
  47. dispatch_once(&onceToken, ^{
  48. scale = [UIScreen mainScreen].scale;
  49. });
  50. return scale;
  51. }
  52. CGSize YYScreenSize() {
  53. static CGSize size;
  54. static dispatch_once_t onceToken;
  55. dispatch_once(&onceToken, ^{
  56. size = [UIScreen mainScreen].bounds.size;
  57. if (size.height < size.width) {
  58. CGFloat tmp = size.height;
  59. size.height = size.width;
  60. size.width = tmp;
  61. }
  62. });
  63. return size;
  64. }
  65. // return 0 when succeed
  66. static int matrix_invert(__CLPK_integer N, double *matrix) {
  67. __CLPK_integer error = 0;
  68. __CLPK_integer pivot_tmp[6 * 6];
  69. __CLPK_integer *pivot = pivot_tmp;
  70. double workspace_tmp[6 * 6];
  71. double *workspace = workspace_tmp;
  72. bool need_free = false;
  73. if (N > 6) {
  74. need_free = true;
  75. pivot = malloc(N * N * sizeof(__CLPK_integer));
  76. if (!pivot) return -1;
  77. workspace = malloc(N * sizeof(double));
  78. if (!workspace) {
  79. free(pivot);
  80. return -1;
  81. }
  82. }
  83. dgetrf_(&N, &N, matrix, &N, pivot, &error);
  84. if (error == 0) {
  85. dgetri_(&N, matrix, &N, pivot, workspace, &N, &error);
  86. }
  87. if (need_free) {
  88. free(pivot);
  89. free(workspace);
  90. }
  91. return error;
  92. }
  93. CGAffineTransform YYCGAffineTransformGetFromPoints(CGPoint before[3], CGPoint after[3]) {
  94. if (before == NULL || after == NULL) return CGAffineTransformIdentity;
  95. CGPoint p1, p2, p3, q1, q2, q3;
  96. p1 = before[0]; p2 = before[1]; p3 = before[2];
  97. q1 = after[0]; q2 = after[1]; q3 = after[2];
  98. double A[36];
  99. A[ 0] = p1.x; A[ 1] = p1.y; A[ 2] = 0; A[ 3] = 0; A[ 4] = 1; A[ 5] = 0;
  100. A[ 6] = 0; A[ 7] = 0; A[ 8] = p1.x; A[ 9] = p1.y; A[10] = 0; A[11] = 1;
  101. A[12] = p2.x; A[13] = p2.y; A[14] = 0; A[15] = 0; A[16] = 1; A[17] = 0;
  102. A[18] = 0; A[19] = 0; A[20] = p2.x; A[21] = p2.y; A[22] = 0; A[23] = 1;
  103. A[24] = p3.x; A[25] = p3.y; A[26] = 0; A[27] = 0; A[28] = 1; A[29] = 0;
  104. A[30] = 0; A[31] = 0; A[32] = p3.x; A[33] = p3.y; A[34] = 0; A[35] = 1;
  105. int error = matrix_invert(6, A);
  106. if (error) return CGAffineTransformIdentity;
  107. double B[6];
  108. B[0] = q1.x; B[1] = q1.y; B[2] = q2.x; B[3] = q2.y; B[4] = q3.x; B[5] = q3.y;
  109. double M[6];
  110. M[0] = A[ 0] * B[0] + A[ 1] * B[1] + A[ 2] * B[2] + A[ 3] * B[3] + A[ 4] * B[4] + A[ 5] * B[5];
  111. M[1] = A[ 6] * B[0] + A[ 7] * B[1] + A[ 8] * B[2] + A[ 9] * B[3] + A[10] * B[4] + A[11] * B[5];
  112. M[2] = A[12] * B[0] + A[13] * B[1] + A[14] * B[2] + A[15] * B[3] + A[16] * B[4] + A[17] * B[5];
  113. M[3] = A[18] * B[0] + A[19] * B[1] + A[20] * B[2] + A[21] * B[3] + A[22] * B[4] + A[23] * B[5];
  114. M[4] = A[24] * B[0] + A[25] * B[1] + A[26] * B[2] + A[27] * B[3] + A[28] * B[4] + A[29] * B[5];
  115. M[5] = A[30] * B[0] + A[31] * B[1] + A[32] * B[2] + A[33] * B[3] + A[34] * B[4] + A[35] * B[5];
  116. CGAffineTransform transform = CGAffineTransformMake(M[0], M[2], M[1], M[3], M[4], M[5]);
  117. return transform;
  118. }
  119. CGAffineTransform YYCGAffineTransformGetFromViews(UIView *from, UIView *to) {
  120. if (!from || !to) return CGAffineTransformIdentity;
  121. CGPoint before[3], after[3];
  122. before[0] = CGPointMake(0, 0);
  123. before[1] = CGPointMake(0, 1);
  124. before[2] = CGPointMake(1, 0);
  125. after[0] = [from convertPoint:before[0] toViewOrWindow:to];
  126. after[1] = [from convertPoint:before[1] toViewOrWindow:to];
  127. after[2] = [from convertPoint:before[2] toViewOrWindow:to];
  128. return YYCGAffineTransformGetFromPoints(before, after);
  129. }
  130. UIViewContentMode YYCAGravityToUIViewContentMode(NSString *gravity) {
  131. static NSDictionary *dic;
  132. static dispatch_once_t onceToken;
  133. dispatch_once(&onceToken, ^{
  134. dic = @{ kCAGravityCenter:@(UIViewContentModeCenter),
  135. kCAGravityTop:@(UIViewContentModeTop),
  136. kCAGravityBottom:@(UIViewContentModeBottom),
  137. kCAGravityLeft:@(UIViewContentModeLeft),
  138. kCAGravityRight:@(UIViewContentModeRight),
  139. kCAGravityTopLeft:@(UIViewContentModeTopLeft),
  140. kCAGravityTopRight:@(UIViewContentModeTopRight),
  141. kCAGravityBottomLeft:@(UIViewContentModeBottomLeft),
  142. kCAGravityBottomRight:@(UIViewContentModeBottomRight),
  143. kCAGravityResize:@(UIViewContentModeScaleToFill),
  144. kCAGravityResizeAspect:@(UIViewContentModeScaleAspectFit),
  145. kCAGravityResizeAspectFill:@(UIViewContentModeScaleAspectFill) };
  146. });
  147. if (!gravity) return UIViewContentModeScaleToFill;
  148. return (UIViewContentMode)((NSNumber *)dic[gravity]).integerValue;
  149. }
  150. NSString *YYUIViewContentModeToCAGravity(UIViewContentMode contentMode) {
  151. switch (contentMode) {
  152. case UIViewContentModeScaleToFill: return kCAGravityResize;
  153. case UIViewContentModeScaleAspectFit: return kCAGravityResizeAspect;
  154. case UIViewContentModeScaleAspectFill: return kCAGravityResizeAspectFill;
  155. case UIViewContentModeRedraw: return kCAGravityResize;
  156. case UIViewContentModeCenter: return kCAGravityCenter;
  157. case UIViewContentModeTop: return kCAGravityTop;
  158. case UIViewContentModeBottom: return kCAGravityBottom;
  159. case UIViewContentModeLeft: return kCAGravityLeft;
  160. case UIViewContentModeRight: return kCAGravityRight;
  161. case UIViewContentModeTopLeft: return kCAGravityTopLeft;
  162. case UIViewContentModeTopRight: return kCAGravityTopRight;
  163. case UIViewContentModeBottomLeft: return kCAGravityBottomLeft;
  164. case UIViewContentModeBottomRight: return kCAGravityBottomRight;
  165. default: return kCAGravityResize;
  166. }
  167. }
  168. CGRect YYCGRectFitWithContentMode(CGRect rect, CGSize size, UIViewContentMode mode) {
  169. rect = CGRectStandardize(rect);
  170. size.width = size.width < 0 ? -size.width : size.width;
  171. size.height = size.height < 0 ? -size.height : size.height;
  172. CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
  173. switch (mode) {
  174. case UIViewContentModeScaleAspectFit:
  175. case UIViewContentModeScaleAspectFill: {
  176. if (rect.size.width < 0.01 || rect.size.height < 0.01 ||
  177. size.width < 0.01 || size.height < 0.01) {
  178. rect.origin = center;
  179. rect.size = CGSizeZero;
  180. } else {
  181. CGFloat scale;
  182. if (mode == UIViewContentModeScaleAspectFit) {
  183. if (size.width / size.height < rect.size.width / rect.size.height) {
  184. scale = rect.size.height / size.height;
  185. } else {
  186. scale = rect.size.width / size.width;
  187. }
  188. } else {
  189. if (size.width / size.height < rect.size.width / rect.size.height) {
  190. scale = rect.size.width / size.width;
  191. } else {
  192. scale = rect.size.height / size.height;
  193. }
  194. }
  195. size.width *= scale;
  196. size.height *= scale;
  197. rect.size = size;
  198. rect.origin = CGPointMake(center.x - size.width * 0.5, center.y - size.height * 0.5);
  199. }
  200. } break;
  201. case UIViewContentModeCenter: {
  202. rect.size = size;
  203. rect.origin = CGPointMake(center.x - size.width * 0.5, center.y - size.height * 0.5);
  204. } break;
  205. case UIViewContentModeTop: {
  206. rect.origin.x = center.x - size.width * 0.5;
  207. rect.size = size;
  208. } break;
  209. case UIViewContentModeBottom: {
  210. rect.origin.x = center.x - size.width * 0.5;
  211. rect.origin.y += rect.size.height - size.height;
  212. rect.size = size;
  213. } break;
  214. case UIViewContentModeLeft: {
  215. rect.origin.y = center.y - size.height * 0.5;
  216. rect.size = size;
  217. } break;
  218. case UIViewContentModeRight: {
  219. rect.origin.y = center.y - size.height * 0.5;
  220. rect.origin.x += rect.size.width - size.width;
  221. rect.size = size;
  222. } break;
  223. case UIViewContentModeTopLeft: {
  224. rect.size = size;
  225. } break;
  226. case UIViewContentModeTopRight: {
  227. rect.origin.x += rect.size.width - size.width;
  228. rect.size = size;
  229. } break;
  230. case UIViewContentModeBottomLeft: {
  231. rect.origin.y += rect.size.height - size.height;
  232. rect.size = size;
  233. } break;
  234. case UIViewContentModeBottomRight: {
  235. rect.origin.x += rect.size.width - size.width;
  236. rect.origin.y += rect.size.height - size.height;
  237. rect.size = size;
  238. } break;
  239. case UIViewContentModeScaleToFill:
  240. case UIViewContentModeRedraw:
  241. default: {
  242. rect = rect;
  243. }
  244. }
  245. return rect;
  246. }