JXHPhotoManager.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. //
  2. // JXHPhotoManager.m
  3. // 我的社保
  4. //
  5. // Created by shanp on 2020/9/15.
  6. //
  7. #import "JXHPhotoManager.h"
  8. #import "JXHPhotoAlbumManager.h"
  9. #import "JXHMacro.h"
  10. #import <JXHSystemShortcut.h>
  11. #import "SPSBGeneralManager.h"
  12. #import <NSObject+JXHNotification.h>
  13. @interface JXHPhotoManager () {
  14. UIImage *_originImage;
  15. UIImage *_thumbnailImage;
  16. CGSize _thumbnailImageSize;
  17. UIImage *_previewImage;
  18. CGSize _previewImageSize;
  19. PHImageRequestID _currentRequestId;
  20. }
  21. @end
  22. @implementation JXHPhotoManager
  23. - (instancetype)init {
  24. self = [super init];
  25. if (!self) return nil;
  26. @weakify(self)
  27. [self addNotificationName:UIApplicationDidReceiveMemoryWarningNotification block:^(id _Nullable object, NSDictionary * _Nullable userInfo) {
  28. @strongify(self)
  29. [self cleanCache];
  30. }];
  31. return self;
  32. }
  33. - (void)dealloc {
  34. [self removeNotificationName:UIApplicationDidReceiveMemoryWarningNotification];
  35. }
  36. - (BOOL)isEqual:(id)object {
  37. return [[object class] isEqual:[JXHPhotoManager class]] && [((JXHPhotoManager *)object).jxh_phAsset isEqual:self.jxh_phAsset];
  38. }
  39. #pragma mark - 原图
  40. - (nullable UIImage *)originImage {
  41. if (_originImage) {
  42. return _originImage;
  43. }
  44. __block UIImage *resultImage;
  45. PHImageRequestOptions *phImageRequestOptions = PHImageRequestOptions.new;
  46. phImageRequestOptions.synchronous = true;
  47. [[PHImageManager defaultManager] requestImageForAsset:_jxh_phAsset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:phImageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {
  48. resultImage = result;
  49. }];
  50. _originImage = resultImage;
  51. return _originImage;
  52. }
  53. - (void)requestOriginImageWithCompletion:(void (^_Nullable)(UIImage * _Nullable, NSDictionary *_Nullable))completion withProgressHandler:(nullable PHAssetImageProgressHandler)phProgressHandler {
  54. if (_originImage) {
  55. // 如果已经有缓存的图片则直接拿缓存的图片
  56. if (completion) {
  57. completion(_originImage, nil);
  58. }
  59. return;
  60. }
  61. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  62. [[PHImageManager defaultManager] cancelImageRequest:self->_currentRequestId];
  63. PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];
  64. imageRequestOptions.networkAccessAllowed = true; // 允许访问网络
  65. imageRequestOptions.progressHandler = phProgressHandler;
  66. @weakify(self)
  67. self->_currentRequestId = [[PHImageManager defaultManager] requestImageForAsset:self->_jxh_phAsset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:imageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {
  68. // 排除取消,错误,低清图三种情况,即已经获取到了高清图时,把这张高清图缓存到 _originImage 中
  69. @strongify(self)
  70. BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];
  71. if (self && downloadFinined) {
  72. self->_originImage = result;
  73. }
  74. if (completion && downloadFinined) {
  75. dispatch_async(dispatch_get_main_queue(), ^{
  76. completion(result, info);
  77. });
  78. }
  79. }];
  80. });
  81. }
  82. #pragma mark - 缩略图
  83. - (nullable UIImage *)thumbnailWithSize:(CGSize)size contentMode:(JXHImageContentMode)imageContentMode {
  84. if (_thumbnailImage && CGSizeEqualToSize(size, _thumbnailImageSize)) {
  85. return _thumbnailImage;
  86. }
  87. __block UIImage *resultImage;
  88. PHImageRequestOptions *phImageRequestOptions = [[PHImageRequestOptions alloc] init];
  89. phImageRequestOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
  90. // 在 PHImageManager 中,targetSize 等 size 都是使用 px 作为单位,因此需要对targetSize 中对传入的 Size 进行处理,宽高各自乘以 ScreenScale,从而得到正确的图片
  91. [[PHImageManager defaultManager] requestImageForAsset:_jxh_phAsset targetSize:CGSizeMake(size.width * jxh_screenScale(), size.height * jxh_screenScale()) contentMode:(PHImageContentMode)imageContentMode options:phImageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {
  92. resultImage = result;
  93. }];
  94. _thumbnailImage = resultImage;
  95. _thumbnailImageSize = size;
  96. return _thumbnailImage;
  97. }
  98. - (void)requestThumbnailImageWithSize:(CGSize)size contentMode:(JXHImageContentMode)imageContentMode completion:(void (^_Nullable)(UIImage *_Nullable, NSDictionary *_Nullable))completion {
  99. if (_thumbnailImage && CGSizeEqualToSize(size, _thumbnailImageSize)) {
  100. if (completion) {
  101. completion(_thumbnailImage, nil);
  102. }
  103. return;
  104. }
  105. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  106. [[PHImageManager defaultManager] cancelImageRequest:self->_currentRequestId];
  107. PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];
  108. imageRequestOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
  109. // 在 PHImageManager 中,targetSize 等 size 都是使用 px 作为单位,因此需要对targetSize 中对传入的 Size 进行处理,宽高各自乘以 ScreenScale,从而得到正确的图片
  110. @weakify(self)
  111. self->_currentRequestId = [[PHImageManager defaultManager] requestImageForAsset:self->_jxh_phAsset targetSize:CGSizeMake(size.width * jxh_screenScale(), size.height * jxh_screenScale()) contentMode:(PHImageContentMode)imageContentMode options:imageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {
  112. @strongify(self)
  113. // 排除取消,错误,低清图三种情况,即已经获取到了高清图时,把这张高清图缓存到 _thumbnailImage 中
  114. // debugLog(@"%@", [NSThread currentThread]);
  115. BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];
  116. if (self && downloadFinined) {
  117. self->_thumbnailImage = result;
  118. self->_thumbnailImageSize = size;
  119. }
  120. if (completion && downloadFinined) {
  121. dispatch_async(dispatch_get_main_queue(), ^{
  122. completion(result, info);
  123. });
  124. }
  125. }];
  126. });
  127. }
  128. #pragma mark - 预览图
  129. - (nullable UIImage *)previewImageWithSize:(CGSize)size {
  130. if (_previewImage && CGSizeEqualToSize(size, _previewImageSize)) {
  131. return _previewImage;
  132. }
  133. __block UIImage *resultImage;
  134. PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];
  135. imageRequestOptions.synchronous = true;
  136. [[PHImageManager defaultManager] requestImageForAsset:_jxh_phAsset targetSize:CGSizeMake(size.width * jxh_screenScale(), size.height * jxh_screenScale()) contentMode:PHImageContentModeAspectFit options:imageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {
  137. resultImage = result;
  138. }];
  139. _previewImage = resultImage;
  140. _previewImageSize = size;
  141. return _previewImage;
  142. }
  143. - (void)requestPreviewImageWithSize:(CGSize)size completion:(void (^_Nullable)(UIImage *_Nullable, NSDictionary *_Nullable))completion progressHandler:(PHAssetImageProgressHandler)phProgressHandler {
  144. if (_previewImage && CGSizeEqualToSize(size, _previewImageSize)) {
  145. // 如果已经有缓存的图片则直接拿缓存的图片
  146. if (completion) {
  147. completion(_previewImage, nil);
  148. }
  149. return;
  150. }
  151. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  152. [[PHImageManager defaultManager] cancelImageRequest:self->_currentRequestId];
  153. PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];
  154. imageRequestOptions.networkAccessAllowed = true; // 允许访问网络
  155. imageRequestOptions.progressHandler = phProgressHandler;
  156. @weakify(self)
  157. self->_currentRequestId = [[PHImageManager defaultManager] requestImageForAsset:self->_jxh_phAsset targetSize:CGSizeMake(size.width * jxh_screenScale(), size.height * jxh_screenScale()) contentMode:PHImageContentModeAspectFit options:imageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {
  158. @strongify(self)
  159. // 排除取消,错误,低清图三种情况,即已经获取到了高清图时,把这张高清图缓存到 _previewImage 中
  160. BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];
  161. if (self && downloadFinined) {
  162. self->_previewImage = result;
  163. self->_previewImageSize = size;
  164. }
  165. if (completion && downloadFinined) {
  166. dispatch_async(dispatch_get_main_queue(), ^{
  167. completion(result, info);
  168. });
  169. }
  170. }];
  171. });
  172. }
  173. - (void)getCover {
  174. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  175. if (self->_jxh_phAsset.mediaType != PHAssetMediaTypeVideo) {
  176. return;
  177. }
  178. if (self->_jxh_playItem) {
  179. return;
  180. }
  181. [[PHImageManager defaultManager] cancelImageRequest:self->_currentRequestId];
  182. PHVideoRequestOptions *videoRequestOptions = PHVideoRequestOptions.new;
  183. videoRequestOptions.networkAccessAllowed = true;
  184. self->_currentRequestId = [[PHImageManager defaultManager] requestPlayerItemForVideo:self->_jxh_phAsset options:videoRequestOptions resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
  185. if (self && playerItem) {
  186. self->_jxh_playItem = playerItem;
  187. }
  188. }];
  189. });
  190. }
  191. - (void)requestVideoWithCompletion:(void (^_Nullable)(AVPlayerItem *_Nullable, NSDictionary *_Nullable))completion progressHandler:(nullable PHAssetVideoProgressHandler)progressHandler {
  192. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  193. [[PHImageManager defaultManager] cancelImageRequest:self->_currentRequestId];
  194. PHVideoRequestOptions *videoRequestOptions = PHVideoRequestOptions.new;
  195. videoRequestOptions.networkAccessAllowed = true;
  196. videoRequestOptions.progressHandler = progressHandler;
  197. self->_currentRequestId = [[PHImageManager defaultManager] requestPlayerItemForVideo:self->_jxh_phAsset options:videoRequestOptions resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
  198. if (self && playerItem) {
  199. self->_jxh_playItem = playerItem;
  200. }
  201. if (completion) {
  202. dispatch_async(dispatch_get_main_queue(), ^{
  203. completion(playerItem, info);
  204. });
  205. }
  206. }];
  207. });
  208. }
  209. - (void)cleanCache {
  210. _originImage = nil;
  211. _thumbnailImage = nil;
  212. _previewImage = nil;
  213. }
  214. @end