MWPhoto.m 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. //
  2. // MWPhoto.m
  3. // MWPhotoBrowser
  4. //
  5. // Created by Michael Waterfall on 17/10/2010.
  6. // Copyright 2010 d3i. All rights reserved.
  7. //
  8. #import "MWPhoto.h"
  9. #import "MWPhotoBrowser.h"
  10. #import "EMSDWebImageDecoder.h"
  11. #import "EMSDWebImageManager.h"
  12. #import "EMSDWebImageOperation.h"
  13. #import <AssetsLibrary/AssetsLibrary.h>
  14. @interface MWPhoto () {
  15. BOOL _loadingInProgress;
  16. id <EMSDWebImageOperation> _webImageOperation;
  17. }
  18. - (void)imageLoadingComplete;
  19. @end
  20. @implementation MWPhoto
  21. @synthesize underlyingImage = _underlyingImage; // synth property from protocol
  22. #pragma mark - Class Methods
  23. + (MWPhoto *)photoWithImage:(UIImage *)image {
  24. return [[MWPhoto alloc] initWithImage:image];
  25. }
  26. // Deprecated
  27. + (MWPhoto *)photoWithFilePath:(NSString *)path {
  28. return [MWPhoto photoWithURL:[NSURL fileURLWithPath:path]];
  29. }
  30. + (MWPhoto *)photoWithURL:(NSURL *)url {
  31. return [[MWPhoto alloc] initWithURL:url];
  32. }
  33. #pragma mark - Init
  34. - (id)initWithImage:(UIImage *)image {
  35. if ((self = [super init])) {
  36. _image = image;
  37. }
  38. return self;
  39. }
  40. // Deprecated
  41. - (id)initWithFilePath:(NSString *)path {
  42. if ((self = [super init])) {
  43. _photoURL = [NSURL fileURLWithPath:path];
  44. }
  45. return self;
  46. }
  47. - (id)initWithURL:(NSURL *)url {
  48. if ((self = [super init])) {
  49. _photoURL = [url copy];
  50. }
  51. return self;
  52. }
  53. #pragma mark - MWPhoto Protocol Methods
  54. - (UIImage *)underlyingImage {
  55. return _underlyingImage;
  56. }
  57. - (void)loadUnderlyingImageAndNotify {
  58. // NSAssert([[NSThread currentThread] isMainThread], @"This method must be called on the main thread.");
  59. if (_loadingInProgress) return;
  60. _loadingInProgress = YES;
  61. @try {
  62. if (self.underlyingImage) {
  63. [self imageLoadingComplete];
  64. } else {
  65. [self performLoadUnderlyingImageAndNotify];
  66. }
  67. }
  68. @catch (NSException *exception) {
  69. self.underlyingImage = nil;
  70. _loadingInProgress = NO;
  71. [self imageLoadingComplete];
  72. }
  73. @finally {
  74. }
  75. }
  76. // Set the underlyingImage
  77. - (void)performLoadUnderlyingImageAndNotify {
  78. // Get underlying image
  79. if (_image) {
  80. // We have UIImage!
  81. self.underlyingImage = _image;
  82. [self imageLoadingComplete];
  83. } else if (_photoURL) {
  84. // Check what type of url it is
  85. if ([[[_photoURL scheme] lowercaseString] isEqualToString:@"assets-library"]) {
  86. // Load from asset library async
  87. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  88. @autoreleasepool {
  89. @try {
  90. ALAssetsLibrary *assetslibrary = [[ALAssetsLibrary alloc] init];
  91. [assetslibrary assetForURL:self->_photoURL
  92. resultBlock:^(ALAsset *asset){
  93. ALAssetRepresentation *rep = [asset defaultRepresentation];
  94. CGImageRef iref = [rep fullScreenImage];
  95. if (iref) {
  96. self.underlyingImage = [UIImage imageWithCGImage:iref];
  97. }
  98. [self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO];
  99. }
  100. failureBlock:^(NSError *error) {
  101. self.underlyingImage = nil;
  102. MWLog(@"Photo from asset library error: %@",error);
  103. [self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO];
  104. }];
  105. } @catch (NSException *e) {
  106. MWLog(@"Photo from asset library error: %@", e);
  107. [self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO];
  108. }
  109. }
  110. });
  111. } else if ([_photoURL isFileReferenceURL]) {
  112. // Load from local file async
  113. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  114. @autoreleasepool {
  115. @try {
  116. self.underlyingImage = [UIImage imageWithContentsOfFile:self->_photoURL.path];
  117. if (!self->_underlyingImage) {
  118. MWLog(@"Error loading photo from path: %@", _photoURL.path);
  119. }
  120. } @finally {
  121. [self performSelectorOnMainThread:@selector(imageLoadingComplete) withObject:nil waitUntilDone:NO];
  122. }
  123. }
  124. });
  125. } else {
  126. // Load async from web (using SDWebImage)
  127. @try {
  128. EMSDWebImageManager *manager = [EMSDWebImageManager sharedManager];
  129. _webImageOperation = [manager downloadImageWithURL:_photoURL
  130. options:0
  131. progress:^(NSInteger receivedSize, NSInteger expectedSize) {
  132. if (expectedSize > 0) {
  133. float progress = receivedSize / (float)expectedSize;
  134. NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
  135. [NSNumber numberWithFloat:progress], @"progress",
  136. self, @"photo", nil];
  137. [[NSNotificationCenter defaultCenter] postNotificationName:MWPHOTO_PROGRESS_NOTIFICATION object:dict];
  138. }
  139. }
  140. completed:^(UIImage *image, NSError *error, EMSDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
  141. if (error) {
  142. MWLog(@"SDWebImage failed to download image: %@", error);
  143. }
  144. self->_webImageOperation = nil;
  145. self.underlyingImage = image;
  146. [self imageLoadingComplete];
  147. }];
  148. } @catch (NSException *e) {
  149. MWLog(@"Photo from web: %@", e);
  150. _webImageOperation = nil;
  151. [self imageLoadingComplete];
  152. }
  153. }
  154. } else {
  155. // Failed - no source
  156. @throw [NSException exceptionWithName:@"" reason:nil userInfo:nil];
  157. }
  158. }
  159. // Release if we can get it again from path or url
  160. - (void)unloadUnderlyingImage {
  161. _loadingInProgress = NO;
  162. self.underlyingImage = nil;
  163. }
  164. - (void)imageLoadingComplete {
  165. // NSAssert([[NSThread currentThread] isMainThread], @"This method must be called on the main thread.");
  166. // Complete so notify
  167. _loadingInProgress = NO;
  168. // Notify on next run loop
  169. [self performSelector:@selector(postCompleteNotification) withObject:nil afterDelay:0];
  170. }
  171. - (void)postCompleteNotification {
  172. [[NSNotificationCenter defaultCenter] postNotificationName:MWPHOTO_LOADING_DID_END_NOTIFICATION
  173. object:self];
  174. }
  175. - (void)cancelAnyLoading {
  176. if (_webImageOperation) {
  177. [_webImageOperation cancel];
  178. _loadingInProgress = NO;
  179. }
  180. }
  181. @end