/* * This is the source code of Telegram for iOS v. 1.1 * It is licensed under GNU GPL v. 2 or later. * You should have received a copy of the license in this archive (see LICENSE). * * Copyright Peter Iakovlev, 2013. */ #import "TGImageManager.h" #import "TGImageManagerTask.h" @interface TGImageManager () { NSMutableArray *_dataSourceList; } @end @implementation TGImageManager + (TGImageManager *)instance { static TGImageManager *singleton = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^ { singleton = [[TGImageManager alloc] init]; }); return singleton; } - (instancetype)init { self = [super init]; if (self != nil) { _dataSourceList = [[NSMutableArray alloc] init]; } return self; } #pragma mark - static UIImage *forceImageDecoding(UIImage *image) { if (image == nil || CGSizeEqualToSize(image.size, CGSizeZero)) return nil; UIGraphicsBeginImageContextWithOptions(image.size, true, image.scale); [image drawAtPoint:CGPointZero blendMode:kCGBlendModeCopy alpha:1.0f]; UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return result; } - (UIImage *)loadImageSyncWithUri:(NSString *)uri canWait:(bool)canWait decode:(bool)decode acceptPartialData:(bool)acceptPartialData asyncTaskId:(__autoreleasing id *)asyncTaskId progress:(void (^)(float))progress partialCompletion:(void (^)(UIImage *))partialCompletion completion:(void (^)(UIImage *))completion { TGDataResource *imageData = [self loadDataSyncWithUri:uri canWait:canWait acceptPartialData:acceptPartialData asyncTaskId:asyncTaskId progress:progress partialCompletion:^(TGDataResource *resource) { if (resource != nil) { UIImage *image = [resource image]; if (image != nil) { if (decode && ![resource isImageDecoded]) image = forceImageDecoding(image); if (partialCompletion != nil) partialCompletion(image); } else { NSData *data = [resource data]; UIImage *dataImage = [[UIImage alloc] initWithData:data]; if (dataImage != nil && decode) dataImage = forceImageDecoding(dataImage); if (partialCompletion != nil) partialCompletion(dataImage); } } } completion:^(TGDataResource *resource) { if (resource != nil) { UIImage *image = [resource image]; if (image != nil) { if (decode && ![resource isImageDecoded]) image = forceImageDecoding(image); if (completion != nil) completion(image); } else { NSData *data = [resource data]; UIImage *dataImage = [[UIImage alloc] initWithData:data]; if (dataImage != nil && decode) dataImage = forceImageDecoding(dataImage); if (completion != nil) completion(dataImage); } } else if (completion != nil) completion(nil); }]; if (imageData != nil) { UIImage *image = [imageData image]; if (image != nil) { if (decode && ![imageData isImageDecoded]) image = forceImageDecoding(image); return image; } else { NSData *data = [imageData data]; UIImage *dataImage = [[UIImage alloc] initWithData:data]; if (dataImage != nil) { if (decode) return forceImageDecoding(dataImage); else return dataImage; } } } return nil; } - (id)beginLoadingImageAsyncWithUri:(NSString *)uri decode:(bool)decode progress:(void (^)(float))progress partialCompletion:(void (^)(UIImage *))partialCompletion completion:(void (^)(UIImage *))completion { return [self _loadDataAsyncWithUri:uri progress:progress partialCompletion:^(TGDataResource *resource) { if (resource != nil) { UIImage *image = [resource image]; if (image != nil) { if (decode && ![resource isImageDecoded]) image = forceImageDecoding(image); if (partialCompletion != nil) partialCompletion(image); } else { NSData *data = [resource data]; UIImage *dataImage = [[UIImage alloc] initWithData:data]; if (dataImage != nil && decode) dataImage = forceImageDecoding(dataImage); if (partialCompletion != nil) partialCompletion(dataImage); } } } completion:^(TGDataResource *resource) { if (resource != nil) { UIImage *image = [resource image]; if (image != nil) { if (decode && ![resource isImageDecoded]) image = forceImageDecoding(image); if (completion != nil) completion(image); } else { NSData *data = [resource data]; UIImage *dataImage = [[UIImage alloc] initWithData:data]; if (dataImage != nil && decode) dataImage = forceImageDecoding(dataImage); if (completion != nil) completion(dataImage); } } else if (completion != nil) completion(nil); }]; } - (TGDataResource *)loadDataSyncWithUri:(NSString *)uri canWait:(bool)canWait acceptPartialData:(bool)acceptPartialData asyncTaskId:(__autoreleasing id *)asyncTaskId progress:(void (^)(float))progress partialCompletion:(void (^)(TGDataResource *))partialCompletion completion:(void (^)(TGDataResource *))completion { __block TGImageDataSource *selectedDataSource = nil; [TGImageDataSource enumerateDataSources:^bool(TGImageDataSource *dataSource) { if ([dataSource canHandleUri:uri]) { selectedDataSource = dataSource; return true; } return false; }]; if (selectedDataSource != nil) return [selectedDataSource loadDataSyncWithUri:uri canWait:canWait acceptPartialData:acceptPartialData asyncTaskId:asyncTaskId progress:progress partialCompletion:partialCompletion completion:completion]; return nil; } - (id)loadAttributeSyncForUri:(NSString *)uri attribute:(NSString *)attribute { __block TGImageDataSource *selectedDataSource = nil; [TGImageDataSource enumerateDataSources:^bool(TGImageDataSource *dataSource) { if ([dataSource canHandleAttributeUri:uri]) { selectedDataSource = dataSource; return true; } return false; }]; if (selectedDataSource != nil) return [selectedDataSource loadAttributeSyncForUri:uri attribute:attribute]; return nil; } - (id)_loadDataAsyncWithUri:(NSString *)uri progress:(void (^)(float progress))progress partialCompletion:(void (^)(TGDataResource *resource))partialCompletion completion:(void (^)(TGDataResource *resource))completion { __block TGImageDataSource *selectedDataSource = nil; [TGImageDataSource enumerateDataSources:^bool(TGImageDataSource *dataSource) { if ([dataSource canHandleUri:uri]) { selectedDataSource = dataSource; return true; } return false; }]; if (selectedDataSource != nil) { TGImageManagerTask *taskId = [[TGImageManagerTask alloc] init]; taskId.dataSource = selectedDataSource; taskId.childTaskId = [selectedDataSource loadDataAsyncWithUri:uri progress:progress partialCompletion:partialCompletion completion:completion]; return taskId; } else { TGLog(@"[TGImageManager#%p Data source not found for URI: %@]", self, uri); if (completion) completion(nil); } return nil; } - (void)cancelTaskWithId:(id)taskId { if ([taskId isKindOfClass:[TGImageManagerTask class]]) { TGImageManagerTask *concreteTaskId = (TGImageManagerTask *)taskId; concreteTaskId->_isCancelled = true; if (concreteTaskId.childTaskId != nil) [concreteTaskId.dataSource cancelTaskById:concreteTaskId.childTaskId]; } } @end