WFCCUtilities.m 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. //
  2. // WFCCUtilities.m
  3. // WFChatClient
  4. //
  5. // Created by heavyrain on 2017/9/7.
  6. // Copyright © 2017年 WildFireChat. All rights reserved.
  7. //
  8. #import "WFCCUtilities.h"
  9. #import <CommonCrypto/CommonDigest.h>
  10. #import "WFCCNetworkService.h"
  11. static NSMutableDictionary *wfcUrlImageDict;
  12. static NSLock *wfcImageLock;
  13. @implementation WFCCUtilities
  14. + (CGSize)imageScaleSize:(CGSize)imageSize targetSize:(CGSize)targetSize thumbnailPoint:(CGPoint *)thumbnailPoint {
  15. if (imageSize.width == 0 && imageSize.height == 0) {
  16. return targetSize;
  17. }
  18. CGFloat imageWidth = imageSize.width;
  19. CGFloat imageHeight = imageSize.height;
  20. CGFloat targetWidth = targetSize.width;
  21. CGFloat targetHeight = targetSize.height;
  22. CGFloat scaleFactor = 0.0;
  23. CGFloat scaledWidth = 0.0;
  24. CGFloat scaledHeight = 0.0;
  25. if (imageWidth/imageHeight < 2.4 && imageHeight/imageWidth < 2.4) {
  26. CGFloat widthFactor = targetWidth / imageWidth;
  27. CGFloat heightFactor = targetHeight / imageHeight;
  28. if (widthFactor < heightFactor)
  29. scaleFactor = widthFactor;
  30. else
  31. scaleFactor = heightFactor;
  32. scaledWidth = imageWidth * scaleFactor;
  33. scaledHeight = imageHeight * scaleFactor;
  34. if (widthFactor > heightFactor) {
  35. if (thumbnailPoint) {
  36. thumbnailPoint->y = (targetHeight - scaledHeight) * 0.5;
  37. }
  38. } else if (widthFactor < heightFactor) {
  39. if (thumbnailPoint) {
  40. thumbnailPoint->x = (targetWidth - scaledWidth) * 0.5;
  41. }
  42. }
  43. } else {
  44. if(imageWidth/imageHeight > 2.4) {
  45. scaleFactor = 100 * targetHeight / imageHeight / 240;
  46. } else {
  47. scaleFactor = 100 * targetWidth / imageWidth / 240;
  48. }
  49. scaledWidth = imageWidth * scaleFactor;
  50. scaledHeight = imageHeight * scaleFactor;
  51. }
  52. return CGSizeMake(scaledWidth, scaledHeight);
  53. }
  54. + (UIImage *)generateThumbnail:(UIImage *)image
  55. withWidth:(CGFloat)targetWidth
  56. withHeight:(CGFloat)targetHeight {
  57. UIImage *targetImage = nil;
  58. CGPoint thumbnailPoint = CGPointMake(0.0, 0.0);
  59. CGSize targetSize = [WFCCUtilities imageScaleSize:image.size targetSize:CGSizeMake(targetWidth, targetHeight) thumbnailPoint:&thumbnailPoint];
  60. CGFloat scaledWidth = targetSize.width;
  61. CGFloat scaledHeight = targetSize.height;
  62. CGFloat imageWidth = image.size.width;
  63. CGFloat imageHeight = image.size.height;
  64. UIGraphicsBeginImageContext(CGSizeMake(scaledWidth, scaledHeight));
  65. CGRect thumbnailRect = CGRectZero;
  66. thumbnailRect.origin = thumbnailPoint;
  67. thumbnailRect.size.width = scaledWidth;
  68. thumbnailRect.size.height = scaledHeight;
  69. [image drawInRect:thumbnailRect];
  70. targetImage = UIGraphicsGetImageFromCurrentImageContext();
  71. if(imageWidth/imageHeight > 2.4) {
  72. CGRect rect = CGRectZero;
  73. rect.origin.x = ( targetImage.size.width - 240)/2;
  74. rect.size.width = 240;
  75. rect.origin.y = 0;
  76. rect.size.height = targetImage.size.height;
  77. CGImageRef imageRef = CGImageCreateWithImageInRect([ targetImage CGImage], rect);
  78. targetImage = [UIImage imageWithCGImage:imageRef];
  79. CGImageRelease(imageRef);
  80. } else if(imageHeight/imageWidth > 2.4) {
  81. CGRect rect = CGRectZero;
  82. rect.origin.y = ( targetImage.size.height - 240)/2;
  83. rect.size.height = 240;
  84. rect.origin.x = 0;
  85. rect.size.width = targetImage.size.width;
  86. CGImageRef imageRef = CGImageCreateWithImageInRect([ targetImage CGImage], rect);
  87. targetImage = [UIImage imageWithCGImage:imageRef];
  88. CGImageRelease(imageRef);
  89. }
  90. if ( targetImage == nil)
  91. NSLog(@"could not scale image");
  92. UIGraphicsEndImageContext();
  93. return targetImage;
  94. }
  95. + (UIImage *)image:(UIImage *)image scaleInSize:(CGSize)size {
  96. CGFloat originWidth = image.size.width;
  97. CGFloat originHeight = image.size.height;
  98. if(originWidth * originHeight < size.width * size.height) {
  99. return image;
  100. }
  101. CGFloat scale = originWidth/size.width < originHeight/size.height ? originHeight/size.height : originWidth/size.width;
  102. CGFloat scaledWidth = originWidth/scale;
  103. CGFloat scaledHeight = originHeight/scale;
  104. //处理那种长条型图片
  105. if(originWidth/originHeight > 3 || originHeight/originWidth > 3) {
  106. scaledWidth *= sqrt(MAX(originWidth/originHeight, originHeight/originWidth));
  107. scaledHeight *= sqrt(MAX(originWidth/originHeight, originHeight/originWidth));
  108. }
  109. UIGraphicsBeginImageContext(CGSizeMake(scaledWidth, scaledHeight));
  110. CGRect rect = CGRectMake(0, 0, scaledWidth, scaledHeight);
  111. [image drawInRect:rect];
  112. UIImage *targetImage = UIGraphicsGetImageFromCurrentImageContext();
  113. return targetImage;
  114. }
  115. + (NSString *)getSendBoxFilePath:(NSString *)localPath {
  116. if (!localPath.length) {
  117. return localPath;
  118. }
  119. if ([[NSFileManager defaultManager] fileExistsAtPath:localPath]) {
  120. return localPath;
  121. } else {
  122. NSUInteger location = [localPath rangeOfString:@"Containers/Data/Application/"].location;
  123. if (location != NSNotFound) {
  124. location =
  125. MIN(MIN([localPath rangeOfString:@"Documents" options:NSCaseInsensitiveSearch range:NSMakeRange(location, localPath.length - location)].location,
  126. [localPath rangeOfString:@"Library" options:NSCaseInsensitiveSearch range:NSMakeRange(location, localPath.length - location)].location),
  127. [localPath rangeOfString:@"tmp" options:NSCaseInsensitiveSearch range:NSMakeRange(location, localPath.length - location)].location);
  128. }
  129. if (location != NSNotFound) {
  130. NSString *relativePath = [localPath substringFromIndex:location];
  131. return [NSHomeDirectory() stringByAppendingPathComponent:relativePath];
  132. } else {
  133. return localPath;
  134. }
  135. }
  136. }
  137. + (NSString *)getDocumentPathWithComponent:(NSString *)componentPath {
  138. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
  139. NSUserDomainMask, YES);
  140. NSString *documentDirectory = [paths objectAtIndex:0];
  141. NSString *path = [documentDirectory stringByAppendingPathComponent:componentPath];
  142. if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
  143. [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
  144. }
  145. return path;
  146. }
  147. + (UIImage *)imageWithRightOrientation:(UIImage *)aImage {
  148. // No-op if the orientation is already correct
  149. if (aImage.imageOrientation == UIImageOrientationUp)
  150. return aImage;
  151. // We need to calculate the proper transformation to make the image upright.
  152. // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
  153. CGAffineTransform transform = CGAffineTransformIdentity;
  154. switch (aImage.imageOrientation) {
  155. case UIImageOrientationDown:
  156. case UIImageOrientationDownMirrored:
  157. transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
  158. transform = CGAffineTransformRotate(transform, M_PI);
  159. break;
  160. case UIImageOrientationLeft:
  161. case UIImageOrientationLeftMirrored:
  162. transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
  163. transform = CGAffineTransformRotate(transform, M_PI_2);
  164. break;
  165. case UIImageOrientationRight:
  166. case UIImageOrientationRightMirrored:
  167. transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
  168. transform = CGAffineTransformRotate(transform, -M_PI_2);
  169. break;
  170. default:
  171. break;
  172. }
  173. switch (aImage.imageOrientation) {
  174. case UIImageOrientationUpMirrored:
  175. case UIImageOrientationDownMirrored:
  176. transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
  177. transform = CGAffineTransformScale(transform, -1, 1);
  178. break;
  179. case UIImageOrientationLeftMirrored:
  180. case UIImageOrientationRightMirrored:
  181. transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
  182. transform = CGAffineTransformScale(transform, -1, 1);
  183. break;
  184. default:
  185. break;
  186. }
  187. // Now we draw the underlying CGImage into a new context, applying the transform
  188. // calculated above.
  189. CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
  190. CGImageGetBitsPerComponent(aImage.CGImage), 0,
  191. CGImageGetColorSpace(aImage.CGImage),
  192. CGImageGetBitmapInfo(aImage.CGImage));
  193. CGContextConcatCTM(ctx, transform);
  194. switch (aImage.imageOrientation) {
  195. case UIImageOrientationLeft:
  196. case UIImageOrientationLeftMirrored:
  197. case UIImageOrientationRight:
  198. case UIImageOrientationRightMirrored:
  199. // Grr...
  200. CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
  201. break;
  202. default:
  203. CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
  204. break;
  205. }
  206. // And now we just create a new UIImage from the drawing context
  207. CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
  208. UIImage *img = [UIImage imageWithCGImage:cgimg];
  209. CGContextRelease(ctx);
  210. CGImageRelease(cgimg);
  211. return img;
  212. }
  213. + (BOOL)isExternalTarget:(NSString *)targetId {
  214. if([targetId containsString:@"@"]) {
  215. NSArray *components = [targetId componentsSeparatedByString:@"@"];
  216. return components.count == 2;
  217. }
  218. return false;
  219. }
  220. + (NSString *)getExternalDomain:(NSString *)targetId {
  221. if([targetId containsString:@"@"]) {
  222. NSArray *components = [targetId componentsSeparatedByString:@"@"];
  223. if(components.count == 2) {
  224. return components[1];
  225. }
  226. }
  227. return nil;
  228. }
  229. + (NSString *)getTargetWithoutDomain:(NSString *)targetId {
  230. if([targetId containsString:@"@"]) {
  231. NSArray *components = [targetId componentsSeparatedByString:@"@"];
  232. if(components.count == 2) {
  233. return components[0];
  234. }
  235. }
  236. return targetId;
  237. }
  238. + (NSAttributedString *)getExternal:(NSString *)domainId withName:(NSString *)name withColor:(UIColor *)color {
  239. return [WFCCUtilities getExternal:domainId withName:name withColor:color withSize:0];
  240. }
  241. + (NSAttributedString *)getExternal:(NSString *)domainId withName:(NSString *)name withColor:(UIColor *)color withSize:(CGFloat)fontSize {
  242. WFCCDomainInfo *domainInfo = [[WFCCIMService sharedWFCIMService] getDomainInfo:domainId refresh:NO];
  243. NSString *domainName = domainInfo.name.length?domainInfo.name:domainId;
  244. NSMutableAttributedString *atts;
  245. if(name.length) {
  246. atts = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ @%@", name, domainName]];
  247. [atts setAttributes:@{NSForegroundColorAttributeName : color} range:NSMakeRange(name.length, domainName.length+2)];
  248. if(fontSize > 0) {
  249. [atts addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:fontSize] range:NSMakeRange(name.length, domainName.length+2)];
  250. }
  251. } else {
  252. atts = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"@%@", domainName]];
  253. [atts setAttributes:@{NSForegroundColorAttributeName : color} range:NSMakeRange(0, domainName.length+1)];
  254. if(fontSize > 0) {
  255. [atts addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:fontSize] range:NSMakeRange(0, domainName.length+1)];
  256. }
  257. }
  258. return atts;
  259. }
  260. + (NSString *)rf_EncryptMD5:(NSString *)str {
  261. if (str.length<=0) return nil;
  262. const char *cStr = [str UTF8String];
  263. unsigned char digest[16];
  264. CC_MD5( cStr, (unsigned int)strlen(cStr), digest );
  265. NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
  266. for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
  267. [output appendFormat:@"%02x", digest[i]];
  268. }
  269. return output;
  270. }
  271. + (UIImage *)getUserImage:(NSString *)url {
  272. if (!url.length) {
  273. return nil;
  274. }
  275. [wfcImageLock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
  276. UIImage *image = [wfcUrlImageDict objectForKey:url];
  277. if (!image) {
  278. image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]];
  279. if (wfcUrlImageDict.count > 50) {
  280. [wfcUrlImageDict removeAllObjects];
  281. }
  282. if (image) {
  283. [wfcUrlImageDict setObject:image forKey:url];
  284. }
  285. }
  286. [wfcImageLock unlock];
  287. return image;
  288. }
  289. + (void)generateNewGroupPortrait:(NSString *)groupId
  290. width:(int)PortraitWidth
  291. defaultUserPortrait:(UIImage *(^)(NSString *userId))defaultUserPortraitBlock {
  292. NSNumber *createTime = [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"wfc_group_generate_portrait_time_%@_%d", groupId, PortraitWidth]];
  293. long now = [[[NSDate alloc] init] timeIntervalSince1970];
  294. if ((now - [createTime longLongValue]) < 10) {//防止连续刷新时,多次生成
  295. return;
  296. }
  297. [[NSUserDefaults standardUserDefaults] setObject:@(now) forKey:[NSString stringWithFormat:@"wfc_group_generate_portrait_time_%@_%d", groupId, PortraitWidth]];
  298. UIView *combineHeadView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, PortraitWidth, PortraitWidth)];
  299. [combineHeadView setBackgroundColor:[UIColor colorWithRed:219.f/255 green:223.f/255 blue:224.f/255 alpha:1.f]];
  300. [[WFCCIMService sharedWFCIMService] getGroupMembers:groupId refresh:NO success:^(NSString *groupId, NSArray<WFCCGroupMember *> *members) {
  301. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  302. if (!members.count) {
  303. return;
  304. }
  305. NSMutableArray *memberIds = [[NSMutableArray alloc] init];
  306. for (WFCCGroupMember *member in members) {
  307. [memberIds addObject:member.memberId];
  308. }
  309. long long now = [[[NSDate alloc] init] timeIntervalSince1970];
  310. int gridMemberCount = MIN((int)memberIds.count, 9);
  311. CGFloat padding = 3;
  312. int numPerRow = 3;
  313. if (gridMemberCount <= 4) {
  314. numPerRow = 2;
  315. }
  316. int row = (int)(gridMemberCount - 1) / numPerRow + 1;
  317. int column = numPerRow;
  318. int firstCol = (int)(gridMemberCount - (row - 1)*column);
  319. CGFloat width = (PortraitWidth - padding) / numPerRow - padding;
  320. CGFloat Y = (PortraitWidth - (row * (width + padding) + padding))/2;
  321. NSString *fullPath = @"";
  322. for (int i = 0; i < row; i++) {
  323. int c = column;
  324. if (i == 0) {
  325. c = firstCol;
  326. }
  327. CGFloat X = (PortraitWidth - (c * (width + padding) + padding))/2;
  328. for (int j = 0; j < c; j++) {
  329. __block UIImageView *imageView;
  330. dispatch_sync(dispatch_get_main_queue(), ^{
  331. imageView = [[UIImageView alloc] initWithFrame:CGRectMake(X + j *(width + padding) + padding, Y + i * (width + padding) + padding, width, width)];
  332. });
  333. int index;
  334. if (i == 0) {
  335. index = j;
  336. } else {
  337. index = j + (i-1)*column + firstCol;
  338. }
  339. NSString *userId = [memberIds objectAtIndex:index];
  340. dispatch_semaphore_t sema = dispatch_semaphore_create(0);
  341. __block WFCCUserInfo *user = nil;
  342. [[WFCCIMService sharedWFCIMService] getUserInfo:userId refresh:NO success:^(WFCCUserInfo *userInfo) {
  343. user = userInfo;
  344. dispatch_semaphore_signal(sema);
  345. } error:^(int errorCode) {
  346. dispatch_semaphore_signal(sema);
  347. }];
  348. dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(20 * NSEC_PER_SEC)));
  349. fullPath = [NSString stringWithFormat:@"%@%@", fullPath, user.portrait?user.portrait:userId];
  350. UIImage *image;
  351. if (user.portrait.length) {
  352. image = [WFCCUtilities getUserImage:user.portrait];
  353. if (!image) {
  354. image = defaultUserPortraitBlock(user.userId);
  355. }
  356. } else {
  357. image = defaultUserPortraitBlock(user.userId);
  358. }
  359. dispatch_sync(dispatch_get_main_queue(), ^{
  360. imageView.image = image;
  361. [combineHeadView addSubview:imageView];
  362. });
  363. }
  364. }
  365. __block UIImage *image;
  366. dispatch_sync(dispatch_get_main_queue(), ^{
  367. UIGraphicsBeginImageContextWithOptions(combineHeadView.frame.size, NO, 2.0);
  368. [combineHeadView.layer renderInContext:UIGraphicsGetCurrentContext()];
  369. image = UIGraphicsGetImageFromCurrentImageContext();
  370. UIGraphicsEndImageContext();
  371. });
  372. NSString *mdt = [WFCCUtilities rf_EncryptMD5:fullPath];
  373. NSString *fileName = [NSString stringWithFormat:@"%@-%lld-%d-%@", groupId, now, PortraitWidth, mdt];
  374. NSString *path = [[WFCCUtilities getDocumentPathWithComponent:@"/group_portrait"] stringByAppendingPathComponent:fileName];
  375. NSData *imgData = UIImageJPEGRepresentation(image, 0.85);
  376. [imgData writeToFile:path atomically:YES];
  377. [[NSUserDefaults standardUserDefaults] setObject:path forKey:[NSString stringWithFormat:@"wfc_group_generated_portrait_%@_%d", groupId, PortraitWidth]];
  378. [[NSUserDefaults standardUserDefaults] synchronize];
  379. dispatch_async(dispatch_get_main_queue(), ^{
  380. [[NSNotificationCenter defaultCenter] postNotificationName:@"GroupPortraitChanged" object:groupId userInfo:@{@"path":path}];
  381. });
  382. });
  383. } error:^(int errorCode) {
  384. }];
  385. }
  386. //如果已经生成了,会立即返回地址。如果没有生成,会返回空,然后生成之后通知GroupPortraitChanged
  387. + (NSString *)getGroupGridPortrait:(NSString *)groupId
  388. width:(int)width
  389. generateIfNotExist:(BOOL)generateIfNotExist
  390. defaultUserPortrait:(UIImage *(^)(NSString *userId))defaultUserPortraitBlock {
  391. //Setp1 检查是否有此群组的记录
  392. NSString *path = [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"wfc_group_generated_portrait_%@_%d", groupId, width]];
  393. if (!path.length) { //记录不存在,生成
  394. if (generateIfNotExist) {
  395. [WFCCUtilities generateNewGroupPortrait:groupId width:width defaultUserPortrait:defaultUserPortraitBlock];
  396. }
  397. } else { //记录存在
  398. //修正沙盒路径
  399. path = [WFCCUtilities getSendBoxFilePath:path];
  400. //检查文件是否存在
  401. NSFileManager* fileManager = [NSFileManager defaultManager];
  402. if ([fileManager fileExistsAtPath:path]) { //文件存在
  403. if (generateIfNotExist) {
  404. [[WFCCIMService sharedWFCIMService] getGroupInfo:groupId refresh:NO success:^(WFCCGroupInfo *groupInfo) {
  405. //分析文件名,获取更新时间,hash值
  406. //Path 格式为 groupId-updatetime-width-hash
  407. NSString *str = path.lastPathComponent;
  408. str = [str substringFromIndex:groupId.length];
  409. NSArray *arr = [str componentsSeparatedByString:@"-"];
  410. long long timestamp = [arr[1] longLongValue];
  411. //检查群组日期,超过7天,或生成之后群组有更新,检查头像是否有变化是否需要重新生成
  412. long long now = [[[NSDate alloc] init] timeIntervalSince1970];
  413. if (timestamp + 7 * 24 * 3600 < now || timestamp*1000 < groupInfo.updateDt) {
  414. [[WFCCIMService sharedWFCIMService] getGroupMembers:groupId refresh:NO success:^(NSString *groupId, NSArray<WFCCGroupMember *> *members) {
  415. if (!members.count) {
  416. return;
  417. }
  418. NSString *fullPath = @"";
  419. for (int i = 0; i < MIN(members.count, 9); i++) {
  420. NSString *userId = members[i].memberId;
  421. WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:userId refresh:NO];
  422. fullPath = [NSString stringWithFormat:@"%@%@", fullPath, userInfo.portrait ? userInfo.portrait : userId];
  423. }
  424. NSString *mdt = [WFCCUtilities rf_EncryptMD5:fullPath];
  425. if (![mdt isEqualToString:arr[3]]) {
  426. [WFCCUtilities generateNewGroupPortrait:groupId width:width defaultUserPortrait:defaultUserPortraitBlock];
  427. }
  428. } error:^(int errorCode) {
  429. //log here
  430. }];
  431. }
  432. } error:^(int errorCode) {
  433. }];
  434. }
  435. return path;
  436. } else { //文件不存在
  437. if (generateIfNotExist) {
  438. [WFCCUtilities generateNewGroupPortrait:groupId width:width defaultUserPortrait:defaultUserPortraitBlock];
  439. }
  440. }
  441. }
  442. return nil;
  443. }
  444. + (NSString *)getGroupGridPortrait:(NSString *)groupId
  445. memberPortraits:(NSArray<NSDictionary<NSString*, NSString*>*> *)groupMembers
  446. width:(int)PortraitWidth
  447. defaultUserPortrait:(UIImage *(^)(NSString *userId))defaultUserPortraitBlock {
  448. __block UIView *combineHeadView;
  449. dispatch_sync(dispatch_get_main_queue(), ^{
  450. combineHeadView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, PortraitWidth, PortraitWidth)];
  451. [combineHeadView setBackgroundColor:[UIColor colorWithRed:219.f/255 green:223.f/255 blue:224.f/255 alpha:1.f]];
  452. });
  453. long long now = [[[NSDate alloc] init] timeIntervalSince1970];
  454. int gridMemberCount = MIN((int)groupMembers.count, 9);
  455. CGFloat padding = 3;
  456. int numPerRow = 3;
  457. if (gridMemberCount <= 4) {
  458. numPerRow = 2;
  459. }
  460. int row = (int)(gridMemberCount - 1) / numPerRow + 1;
  461. int column = numPerRow;
  462. int firstCol = (int)(gridMemberCount - (row - 1)*column);
  463. CGFloat width = (PortraitWidth - padding) / numPerRow - padding;
  464. CGFloat Y = (PortraitWidth - (row * (width + padding) + padding))/2;
  465. NSString *fullPath = @"";
  466. for (int i = 0; i < row; i++) {
  467. int c = column;
  468. if (i == 0) {
  469. c = firstCol;
  470. }
  471. CGFloat X = (PortraitWidth - (c * (width + padding) + padding))/2;
  472. for (int j = 0; j < c; j++) {
  473. __block UIImageView *imageView;
  474. dispatch_sync(dispatch_get_main_queue(), ^{
  475. imageView = [[UIImageView alloc] initWithFrame:CGRectMake(X + j *(width + padding) + padding, Y + i * (width + padding) + padding, width, width)];
  476. });
  477. int index;
  478. if (i == 0) {
  479. index = j;
  480. } else {
  481. index = j + (i-1)*column + firstCol;
  482. }
  483. NSDictionary *dict = [groupMembers objectAtIndex:index];
  484. NSString *userId = dict[@"userId"];
  485. NSString *portrait = dict[@"portrait"];
  486. fullPath = [NSString stringWithFormat:@"%@%@", fullPath, portrait?portrait:userId];
  487. UIImage *image;
  488. if (portrait.length) {
  489. image = [WFCCUtilities getUserImage:portrait];
  490. if (!image) {
  491. image = defaultUserPortraitBlock(userId);
  492. }
  493. } else {
  494. image = defaultUserPortraitBlock(userId);
  495. }
  496. dispatch_sync(dispatch_get_main_queue(), ^{
  497. imageView.image = image;
  498. [combineHeadView addSubview:imageView];
  499. });
  500. }
  501. }
  502. __block UIImage *image;
  503. dispatch_sync(dispatch_get_main_queue(), ^{
  504. UIGraphicsBeginImageContextWithOptions(combineHeadView.frame.size, NO, 2.0);
  505. [combineHeadView.layer renderInContext:UIGraphicsGetCurrentContext()];
  506. image = UIGraphicsGetImageFromCurrentImageContext();
  507. UIGraphicsEndImageContext();
  508. });
  509. NSString *mdt = [WFCCUtilities rf_EncryptMD5:fullPath];
  510. NSString *fileName = [NSString stringWithFormat:@"%@-%lld-%d-%@", groupId, now, PortraitWidth, mdt];
  511. NSString *path = [[WFCCUtilities getDocumentPathWithComponent:@"/group_portrait"] stringByAppendingPathComponent:fileName];
  512. NSData *imgData = UIImageJPEGRepresentation(image, 0.85);
  513. [imgData writeToFile:path atomically:YES];
  514. return path;
  515. }
  516. + (void)load {
  517. wfcUrlImageDict = [[NSMutableDictionary alloc] init];
  518. wfcImageLock = [[NSLock alloc] init];
  519. }
  520. + (NSString *)getGroupMemberExtra:(WFCCGroupMemberSourceType)sourceType sourceTargetId:(NSString *)sourceTargetId {
  521. NSDictionary *extraDict;
  522. if(sourceTargetId.length) {
  523. extraDict = @{@"s"/*source*/:@{@"t"/*type*/:@(sourceType), @"i"/*targetId*/:sourceTargetId}};
  524. } else {
  525. extraDict = @{@"s"/*source*/:@{@"t"/*type*/:@(sourceType)}};
  526. }
  527. NSData *extraData = [NSJSONSerialization dataWithJSONObject:extraDict
  528. options:kNilOptions
  529. error:nil];
  530. return [[NSString alloc] initWithData:extraData encoding:NSUTF8StringEncoding];
  531. }
  532. + (WFCCGroupMemberSourceType)getGroupMemberSourceType:(NSString *)memberExtra sourceTargetId:(NSMutableString *)sourceTargetId {
  533. NSError *__error = nil;
  534. NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:[memberExtra dataUsingEncoding:NSUTF8StringEncoding]
  535. options:kNilOptions
  536. error:&__error];
  537. if (!__error && dictionary[@"s"] && [dictionary[@"s"] isKindOfClass:[NSDictionary class]]) {
  538. NSDictionary *source = dictionary[@"s"];
  539. if(source[@"t"]) {
  540. int sourceType = [[source valueForKey:@"t"] intValue];
  541. if(sourceType > 0) {
  542. if(source[@"i"] && [[source valueForKey:@"i"] isKindOfClass:NSString.class]) {
  543. [sourceTargetId setString:[source valueForKey:@"i"]];
  544. }
  545. return sourceType;
  546. }
  547. }
  548. }
  549. return GroupMemberSource_Unknown;
  550. }
  551. + (NSString *)getUserDisplayName:(NSString *)userId inGroup:(NSString *)groupId {
  552. if ([[WFCCNetworkService sharedInstance].userId isEqualToString:userId]) {
  553. return @"你";
  554. } else {
  555. WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:userId inGroup:groupId refresh:NO];
  556. if(userInfo) {
  557. return userInfo.readableName;
  558. } else {
  559. return userId;
  560. }
  561. }
  562. }
  563. @end