HXAssetManager.m 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. //
  2. // HXAssetManager.m
  3. // HXPhotoPickerExample
  4. //
  5. // Created by Silence on 2020/11/5.
  6. // Copyright © 2020 Silence. All rights reserved.
  7. //
  8. #import "HXAssetManager.h"
  9. #import "HXAlbumModel.h"
  10. #import "NSString+HXExtension.h"
  11. #import "PHAsset+HXExtension.h"
  12. #import "HXPhotoTools.h"
  13. @implementation HXAssetManager
  14. + (PHFetchResult<PHAssetCollection *> *)fetchSmartAlbumsWithOptions:(PHFetchOptions * _Nullable)options {
  15. return [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAny options:options];
  16. }
  17. + (PHFetchResult<PHAssetCollection *> *)fetchUserAlbumsWithOptions:(PHFetchOptions * _Nullable)options {
  18. return [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:options];
  19. }
  20. + (void)enumerateAllAlbumsWithOptions:(PHFetchOptions * _Nullable)options
  21. usingBlock:(void (^)(PHAssetCollection *collection))enumerationBlock {
  22. PHFetchResult *smartAlbums = [self fetchSmartAlbumsWithOptions:options];
  23. PHFetchResult *userAlbums = [self fetchUserAlbumsWithOptions:options];
  24. NSArray *allAlbum = [NSArray arrayWithObjects:smartAlbums, userAlbums, nil];
  25. for (PHFetchResult *result in allAlbum) {
  26. for (PHAssetCollection *collection in result) {
  27. if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
  28. if (collection.estimatedAssetCount <= 0) continue;
  29. if (collection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumAllHidden) continue;
  30. if (collection.assetCollectionSubtype == 215) continue;
  31. if (collection.assetCollectionSubtype == 212) continue;
  32. if (collection.assetCollectionSubtype == 204) continue;
  33. if (collection.assetCollectionSubtype == 1000000201) continue;
  34. if (enumerationBlock) {
  35. enumerationBlock(collection);
  36. }
  37. }
  38. }
  39. }
  40. + (void)enumerateAllAlbumModelsWithOptions:(PHFetchOptions * _Nullable)options
  41. usingBlock:(void (^)(HXAlbumModel *albumModel))enumerationBlock {
  42. [self enumerateAllAlbumsWithOptions:nil usingBlock:^(PHAssetCollection *collection) {
  43. HXAlbumModel *albumModel = [[HXAlbumModel alloc] initWithCollection:collection options:options];
  44. if (enumerationBlock) {
  45. enumerationBlock(albumModel);
  46. }
  47. }];
  48. }
  49. /// 获取相机胶卷
  50. + (PHAssetCollection *)fetchCameraRollAlbumWithOptions:(PHFetchOptions * _Nullable)options {
  51. PHFetchResult *smartAlbums = [self fetchSmartAlbumsWithOptions:options];
  52. for (PHAssetCollection *collection in smartAlbums) {
  53. if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
  54. if (collection.estimatedAssetCount <= 0) continue;
  55. if ([self isCameraRollAlbum:collection]) {
  56. return collection;
  57. }
  58. }
  59. return nil;
  60. }
  61. + (BOOL)isCameraRollAlbum:(PHAssetCollection *)assetCollection {
  62. NSString *versionStr = [[UIDevice currentDevice].systemVersion stringByReplacingOccurrencesOfString:@"." withString:@""];
  63. if (versionStr.length <= 1) {
  64. versionStr = [versionStr stringByAppendingString:@"00"];
  65. } else if (versionStr.length <= 2) {
  66. versionStr = [versionStr stringByAppendingString:@"0"];
  67. }
  68. CGFloat version = versionStr.floatValue;
  69. if (version >= 800 && version <= 802) {
  70. return assetCollection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumRecentlyAdded;
  71. } else {
  72. return assetCollection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumUserLibrary;
  73. }
  74. }
  75. + (PHAssetCollection *)fetchAssetCollectionWithIndentifier:(NSString *)localIdentifier {
  76. return [[PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[localIdentifier] options:nil] firstObject];
  77. }
  78. #pragma mark - < PHAsset >
  79. + (PHAsset *)fetchAssetWithLocalIdentifier:(NSString *)localIdentifier {
  80. return [[PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil] firstObject];
  81. }
  82. + (PHFetchResult<PHAsset *> *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection
  83. options:(PHFetchOptions *)options {
  84. return [PHAsset fetchAssetsInAssetCollection:assetCollection options:options];
  85. }
  86. + (UIImage *)originImageForAsset:(PHAsset *)asset {
  87. __block UIImage *resultImage = nil;
  88. PHImageRequestOptions *phImageRequestOptions = [[PHImageRequestOptions alloc] init];
  89. phImageRequestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
  90. phImageRequestOptions.networkAccessAllowed = YES;
  91. phImageRequestOptions.synchronous = YES;
  92. [[PHImageManager defaultManager] requestImageDataForAsset:asset options:phImageRequestOptions resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
  93. resultImage = [UIImage imageWithData:imageData];
  94. }];
  95. return resultImage;
  96. }
  97. + (void)requestVideoURL:(PHAsset *)asset completion:(void (^)(NSURL * _Nullable))completion {
  98. [self requestAVAssetForAsset:asset networkAccessAllowed:YES progressHandler:nil completion:^(AVAsset * _Nonnull avAsset, AVAudioMix * _Nonnull audioMix, NSDictionary * _Nonnull info) {
  99. [asset hx_checkForModificationsWithAssetPathMethodCompletion:^(BOOL isAdjusted) {
  100. NSString *fileName = [[NSString hx_fileName] stringByAppendingString:@".mp4"];
  101. NSString *fullPathToFile = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
  102. NSURL *videoURL = [NSURL fileURLWithPath:fullPathToFile];
  103. if (isAdjusted) {
  104. if ([avAsset isKindOfClass:AVURLAsset.class]) {
  105. NSFileManager *fileManager = [NSFileManager defaultManager];
  106. NSError *error;
  107. [fileManager copyItemAtURL:[(AVURLAsset *)avAsset URL] toURL:videoURL error:&error];
  108. if (error == nil) {
  109. dispatch_async(dispatch_get_main_queue(), ^{
  110. if (completion) {
  111. completion(videoURL);
  112. }
  113. });
  114. return;
  115. }
  116. }
  117. NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
  118. NSString *presetName;
  119. if ([presets containsObject:AVAssetExportPresetHighestQuality]) {
  120. presetName = AVAssetExportPresetHighestQuality;
  121. }else {
  122. presetName = AVAssetExportPresetMediumQuality;
  123. }
  124. AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:avAsset presetName:presetName];
  125. session.outputURL = videoURL;
  126. session.shouldOptimizeForNetworkUse = YES;
  127. NSArray *supportedTypeArray = session.supportedFileTypes;
  128. if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
  129. session.outputFileType = AVFileTypeMPEG4;
  130. } else if (supportedTypeArray.count == 0) {
  131. dispatch_async(dispatch_get_main_queue(), ^{
  132. if (completion) {
  133. completion(nil);
  134. }
  135. });
  136. return;
  137. }else {
  138. session.outputFileType = [supportedTypeArray objectAtIndex:0];
  139. }
  140. [session exportAsynchronouslyWithCompletionHandler:^{
  141. dispatch_async(dispatch_get_main_queue(), ^{
  142. if ([session status] == AVAssetExportSessionStatusCompleted) {
  143. if (completion) {
  144. completion(videoURL);
  145. }
  146. }else if ([session status] == AVAssetExportSessionStatusFailed ||
  147. [session status] == AVAssetExportSessionStatusCancelled) {
  148. if (completion) {
  149. completion(nil);
  150. }
  151. }
  152. });
  153. }];
  154. }else {
  155. PHAssetResource *videoResource = [PHAssetResource assetResourcesForAsset:asset].firstObject;
  156. PHAssetResourceRequestOptions *options = [[PHAssetResourceRequestOptions alloc] init];
  157. options.networkAccessAllowed = YES;
  158. [[PHAssetResourceManager defaultManager] writeDataForAssetResource:videoResource toFile:videoURL options:options completionHandler:^(NSError * _Nullable error) {
  159. dispatch_async(dispatch_get_main_queue(), ^{
  160. if (!error) {
  161. if (completion) {
  162. completion(videoURL);
  163. }
  164. }else {
  165. completion(nil);
  166. }
  167. });
  168. }];
  169. }
  170. }];
  171. }];
  172. }
  173. + (CGSize)getAssetTargetSizeWithAsset:(PHAsset *)asset width:(CGFloat)width {
  174. if (!asset) {
  175. return CGSizeMake(width, width);
  176. }
  177. CGFloat scale = 0.8f;
  178. CGFloat aspectRatio = asset.pixelWidth / (CGFloat)asset.pixelHeight;
  179. CGFloat initialWidth = width;
  180. CGFloat height;
  181. if (asset.pixelWidth < width) {
  182. width = width * 0.5f;
  183. }
  184. height = width / aspectRatio;
  185. CGFloat maxHeight = [UIScreen mainScreen].bounds.size.height;
  186. if (height > maxHeight) {
  187. width = maxHeight / height * width * scale;
  188. height = maxHeight * scale;
  189. }
  190. if (height < initialWidth && width >= initialWidth) {
  191. width = initialWidth / height * width * scale;
  192. height = initialWidth * scale;
  193. }
  194. CGSize size = CGSizeMake(width, height);
  195. return size;
  196. }
  197. + (PHImageRequestID)requestImageForAsset:(PHAsset *)asset
  198. targetSize:(CGSize)targetSize
  199. contentMode:(PHImageContentMode)contentMode
  200. options:(PHImageRequestOptions *)options
  201. completion:(void (^)(UIImage *result, NSDictionary<NSString *, id> *info))completion {
  202. if (!asset) {
  203. completion(nil, nil);
  204. return -1;
  205. }
  206. return [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:targetSize contentMode:contentMode options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
  207. if (completion) {
  208. dispatch_async(dispatch_get_main_queue(), ^{
  209. completion(result, info);
  210. });
  211. }
  212. }];
  213. }
  214. + (PHImageRequestID)requestThumbnailImageForAsset:(PHAsset *)asset
  215. targetWidth:(CGFloat)targetWidth
  216. completion:(void (^)(UIImage *result, NSDictionary<NSString *, id> *info))completion {
  217. return [self requestThumbnailImageForAsset:asset targetWidth:targetWidth deliveryMode:PHImageRequestOptionsDeliveryModeOpportunistic completion:^(UIImage * _Nonnull result, NSDictionary<NSString *,id> * _Nonnull info) {
  218. if (completion) {
  219. dispatch_async(dispatch_get_main_queue(), ^{
  220. completion(result, info);
  221. });
  222. }
  223. }];
  224. }
  225. + (PHImageRequestID)requestThumbnailImageForAsset:(PHAsset *)asset
  226. targetWidth:(CGFloat)targetWidth
  227. deliveryMode:(PHImageRequestOptionsDeliveryMode)deliveryMode
  228. completion:(void (^)(UIImage *result, NSDictionary<NSString *, id> *info))completion {
  229. PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
  230. options.resizeMode = PHImageRequestOptionsResizeModeFast;
  231. options.deliveryMode = deliveryMode;
  232. return [self requestImageForAsset:asset targetSize:[self getAssetTargetSizeWithAsset:asset width:targetWidth] contentMode:PHImageContentModeAspectFill options:options completion:^(UIImage * _Nonnull result, NSDictionary<NSString *,id> * _Nonnull info) {
  233. if (completion) {
  234. dispatch_async(dispatch_get_main_queue(), ^{
  235. completion(result, info);
  236. });
  237. }
  238. }];
  239. }
  240. + (PHImageRequestID)requestPreviewImageForAsset:(PHAsset *)asset
  241. targetSize:(CGSize)targetSize
  242. networkAccessAllowed:(BOOL)networkAccessAllowed
  243. progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
  244. completion:(void (^ _Nullable)(UIImage *result, NSDictionary<NSString *, id> *info))completion; {
  245. PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
  246. options.resizeMode = PHImageRequestOptionsResizeModeFast;
  247. options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
  248. options.networkAccessAllowed = networkAccessAllowed;
  249. options.progressHandler = progressHandler;
  250. return [self requestImageForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFill options:options completion:^(UIImage * _Nonnull result, NSDictionary<NSString *,id> * _Nonnull info) {
  251. if (completion) {
  252. dispatch_async(dispatch_get_main_queue(), ^{
  253. completion(result, info);
  254. });
  255. }
  256. }];
  257. }
  258. + (void)requestVideoURLForAsset:(PHAsset *)asset
  259. toFile:(NSURL * _Nullable)fileURL
  260. exportPreset:(HXVideoExportPreset)exportPreset
  261. videoQuality:(NSInteger)videoQuality
  262. resultHandler:(void (^ _Nullable)(NSURL * _Nullable))resultHandler {
  263. [self requestAVAssetForAsset:asset networkAccessAllowed:YES progressHandler:nil completion:^(AVAsset * _Nonnull asset, AVAudioMix * _Nonnull audioMix, NSDictionary * _Nonnull info) {
  264. if (asset == nil) {
  265. if (resultHandler) {
  266. resultHandler(nil);
  267. }
  268. return;
  269. }
  270. NSString *fileName = [[NSString hx_fileName] stringByAppendingString:@".mp4"];
  271. NSString *fullPathToFile = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
  272. NSURL *videoURL = fileURL ?: [NSURL fileURLWithPath:fullPathToFile];
  273. NSString *presetName = [self presetName:exportPreset];
  274. NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:asset];
  275. if (![presets containsObject:presetName]) {
  276. if (resultHandler) {
  277. resultHandler(nil);
  278. }
  279. return;
  280. }
  281. AVAssetExportSession *session = [AVAssetExportSession exportSessionWithAsset:asset presetName:presetName];
  282. session.outputURL = videoURL;
  283. session.shouldOptimizeForNetworkUse = YES;
  284. NSArray *supportedTypeArray = session.supportedFileTypes;
  285. if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
  286. session.outputFileType = AVFileTypeMPEG4;
  287. }else if (supportedTypeArray.count == 0) {
  288. if (resultHandler) {
  289. resultHandler(nil);
  290. }
  291. return;
  292. }else {
  293. session.outputFileType = [supportedTypeArray objectAtIndex:0];
  294. }
  295. if (videoQuality > 0) {
  296. session.fileLengthLimit = [self exportSessionFileLengthLimitWithSeconds:CMTimeGetSeconds(asset.duration) exportPreset:exportPreset videoQuality:videoQuality];
  297. }
  298. [session exportAsynchronouslyWithCompletionHandler:^{
  299. dispatch_async(dispatch_get_main_queue(), ^{
  300. if (session.status == AVAssetExportSessionStatusCompleted) {
  301. if (resultHandler) {
  302. resultHandler(videoURL);
  303. }
  304. }else {
  305. if (resultHandler) {
  306. resultHandler(nil);
  307. }
  308. }
  309. });
  310. }];
  311. }];
  312. }
  313. + (NSString *)presetName:(HXVideoExportPreset)exportPreset {
  314. switch (exportPreset) {
  315. case HXVideoEditorExportPresetLowQuality:
  316. return AVAssetExportPresetLowQuality;
  317. case HXVideoEditorExportPresetMediumQuality:
  318. return AVAssetExportPresetMediumQuality;
  319. case HXVideoEditorExportPresetHighQuality:
  320. return AVAssetExportPresetHighestQuality;
  321. case HXVideoEditorExportPresetRatio_640x480:
  322. return AVAssetExportPreset640x480;
  323. case HXVideoEditorExportPresetRatio_960x540:
  324. return AVAssetExportPreset960x540;
  325. case HXVideoEditorExportPresetRatio_1280x720:
  326. return AVAssetExportPreset1280x720;
  327. default:
  328. return AVAssetExportPresetMediumQuality;
  329. }
  330. }
  331. + (NSInteger)exportSessionFileLengthLimitWithSeconds:(CGFloat)seconds
  332. exportPreset:(HXVideoExportPreset)exportPreset
  333. videoQuality:(NSInteger)videoQuality {
  334. if (videoQuality > 0) {
  335. CGFloat ratioParam = 0;
  336. if (exportPreset == HXVideoEditorExportPresetRatio_640x480) {
  337. ratioParam = 0.02;
  338. }else if (exportPreset == HXVideoEditorExportPresetRatio_960x540) {
  339. ratioParam = 0.04;
  340. }else if (exportPreset == HXVideoEditorExportPresetRatio_1280x720) {
  341. ratioParam = 0.08;
  342. }
  343. NSInteger quality = MIN(videoQuality, 10);
  344. return seconds * ratioParam * quality * 1000 * 1000;
  345. }
  346. return 0;
  347. }
  348. + (UIImageOrientation)imageOrientationWithCGImageOrientation:(CGImagePropertyOrientation)orientation {
  349. UIImageOrientation sureOrientation;
  350. if (orientation == kCGImagePropertyOrientationUp) {
  351. sureOrientation = UIImageOrientationUp;
  352. } else if (orientation == kCGImagePropertyOrientationUpMirrored) {
  353. sureOrientation = UIImageOrientationUpMirrored;
  354. } else if (orientation == kCGImagePropertyOrientationDown) {
  355. sureOrientation = UIImageOrientationDown;
  356. } else if (orientation == kCGImagePropertyOrientationDownMirrored) {
  357. sureOrientation = UIImageOrientationDownMirrored;
  358. } else if (orientation == kCGImagePropertyOrientationLeftMirrored) {
  359. sureOrientation = UIImageOrientationLeftMirrored;
  360. } else if (orientation == kCGImagePropertyOrientationRight) {
  361. sureOrientation = UIImageOrientationRight;
  362. } else if (orientation == kCGImagePropertyOrientationRightMirrored) {
  363. sureOrientation = UIImageOrientationRightMirrored;
  364. } else if (orientation == kCGImagePropertyOrientationLeft) {
  365. sureOrientation = UIImageOrientationLeft;
  366. } else {
  367. sureOrientation = UIImageOrientationUp;
  368. }
  369. return sureOrientation;
  370. }
  371. + (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset
  372. options:(PHImageRequestOptions *)options
  373. completion:(void (^)(NSData *imageData, UIImageOrientation orientation, NSDictionary<NSString *, id> *info))completion {
  374. PHImageRequestID requestID;
  375. if (@available(iOS 13.0, *)) {
  376. requestID = [[PHImageManager defaultManager] requestImageDataAndOrientationForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, CGImagePropertyOrientation orientation, NSDictionary * _Nullable info) {
  377. if (completion) {
  378. dispatch_async(dispatch_get_main_queue(), ^{
  379. completion(imageData, [self imageOrientationWithCGImageOrientation:orientation], info);
  380. });
  381. }
  382. }];
  383. }else {
  384. requestID = [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
  385. if (completion) {
  386. dispatch_async(dispatch_get_main_queue(), ^{
  387. completion(imageData, orientation, info);
  388. });
  389. }
  390. }];
  391. }
  392. return requestID;
  393. }
  394. + (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset
  395. version:(PHImageRequestOptionsVersion)version
  396. resizeMode:(PHImageRequestOptionsResizeMode)resizeMode
  397. networkAccessAllowed:(BOOL)networkAccessAllowed
  398. progressHandler:(PHAssetImageProgressHandler)progressHandler
  399. completion:(void (^)(NSData *imageData, UIImageOrientation orientation, NSDictionary<NSString *, id> *info))completion {
  400. PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
  401. options.version = version;
  402. options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
  403. options.resizeMode = resizeMode;
  404. options.networkAccessAllowed = networkAccessAllowed;
  405. options.progressHandler = progressHandler;
  406. return [self requestImageDataForAsset:asset options:options completion:^(NSData * _Nonnull imageData, UIImageOrientation orientation, NSDictionary<NSString *,id> * _Nonnull info) {
  407. if (completion) {
  408. dispatch_async(dispatch_get_main_queue(), ^{
  409. completion(imageData, orientation, info);
  410. });
  411. }
  412. }];
  413. }
  414. + (PHLivePhotoRequestID)requestLivePhotoForAsset:(PHAsset *)asset
  415. targetSize:(CGSize)targetSize
  416. contentMode:(PHImageContentMode)contentMode
  417. options:(PHLivePhotoRequestOptions *)options
  418. completion:(void (^)(PHLivePhoto *livePhoto, NSDictionary<NSString *,id> * _Nonnull info))completion {
  419. return [[PHImageManager defaultManager] requestLivePhotoForAsset:asset targetSize:targetSize contentMode:contentMode options:options resultHandler:^(PHLivePhoto * _Nullable livePhoto, NSDictionary * _Nullable info) {
  420. if (completion) {
  421. dispatch_async(dispatch_get_main_queue(), ^{
  422. completion(livePhoto, info);
  423. });
  424. }
  425. }];
  426. }
  427. + (PHLivePhotoRequestID)requestPreviewLivePhotoForAsset:(PHAsset *)asset
  428. targetSize:(CGSize)targetSize
  429. networkAccessAllowed:(BOOL)networkAccessAllowed
  430. progressHandler:(PHAssetImageProgressHandler)progressHandler
  431. completion:(void (^)(PHLivePhoto *livePhoto, NSDictionary<NSString *,id> * _Nonnull info))completion {
  432. PHLivePhotoRequestOptions *options = [[PHLivePhotoRequestOptions alloc] init];
  433. options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
  434. options.networkAccessAllowed = networkAccessAllowed;
  435. options.progressHandler = progressHandler;
  436. return [self requestLivePhotoForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFill options:options completion:^(PHLivePhoto * _Nonnull livePhoto, NSDictionary<NSString *,id> * _Nonnull info) {
  437. if (completion) {
  438. dispatch_async(dispatch_get_main_queue(), ^{
  439. completion(livePhoto, info);
  440. });
  441. }
  442. }];
  443. }
  444. + (PHImageRequestID)requestAVAssetForAsset:(PHAsset *)asset
  445. options:(PHVideoRequestOptions *)options
  446. completion:(void (^)(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info))completion {
  447. return [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
  448. if (completion) {
  449. dispatch_async(dispatch_get_main_queue(), ^{
  450. completion(asset, audioMix, info);
  451. });
  452. }
  453. }];
  454. }
  455. + (PHImageRequestID)requestAVAssetForAsset:(PHAsset *)asset
  456. networkAccessAllowed:(BOOL)networkAccessAllowed
  457. progressHandler:(PHAssetImageProgressHandler)progressHandler
  458. completion:(void (^)(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info))completion {
  459. PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
  460. options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
  461. options.networkAccessAllowed = networkAccessAllowed;
  462. options.progressHandler = progressHandler;
  463. return [self requestAVAssetForAsset:asset options:options completion:^(AVAsset * _Nonnull asset, AVAudioMix * _Nonnull audioMix, NSDictionary * _Nonnull info) {
  464. if (completion) {
  465. dispatch_async(dispatch_get_main_queue(), ^{
  466. completion(asset, audioMix, info);
  467. });
  468. }
  469. }];
  470. }
  471. + (PHImageRequestID)requestPlayerItemForAsset:(PHAsset *)asset
  472. options:(PHVideoRequestOptions * _Nullable)options
  473. completion:(void (^ _Nullable)(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info))completion {
  474. return [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:options resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
  475. if (completion) {
  476. dispatch_async(dispatch_get_main_queue(), ^{
  477. completion(playerItem, info);
  478. });
  479. }
  480. }];
  481. }
  482. + (PHImageRequestID)requestPlayerItemForAsset:(PHAsset *)asset
  483. networkAccessAllowed:(BOOL)networkAccessAllowed
  484. progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
  485. completion:(void (^ _Nullable)(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info))completion {
  486. PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
  487. options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
  488. options.networkAccessAllowed = networkAccessAllowed;
  489. options.progressHandler = progressHandler;
  490. return [self requestPlayerItemForAsset:asset options:options completion:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
  491. if (completion) {
  492. dispatch_async(dispatch_get_main_queue(), ^{
  493. completion(playerItem, info);
  494. });
  495. }
  496. }];
  497. }
  498. + (PHImageRequestID)requestExportSessionForAsset:(PHAsset *)asset
  499. options:(PHVideoRequestOptions * _Nullable)options
  500. exportPreset:(NSString *)exportPreset
  501. completion:(void (^ _Nullable)(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info))completion {
  502. return [[PHImageManager defaultManager] requestExportSessionForVideo:asset options:options exportPreset:exportPreset resultHandler:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
  503. if (completion) {
  504. dispatch_async(dispatch_get_main_queue(), ^{
  505. completion(exportSession, info);
  506. });
  507. }
  508. }];
  509. }
  510. + (PHImageRequestID)requestExportSessionForAsset:(PHAsset *)asset
  511. exportPreset:(NSString *)exportPreset
  512. networkAccessAllowed:(BOOL)networkAccessAllowed
  513. progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
  514. completion:(void (^ _Nullable)(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info))completion {
  515. PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
  516. options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
  517. options.networkAccessAllowed = networkAccessAllowed;
  518. options.progressHandler = progressHandler;
  519. return [self requestExportSessionForAsset:asset options:options exportPreset:exportPreset completion:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
  520. if (completion) {
  521. dispatch_async(dispatch_get_main_queue(), ^{
  522. completion(exportSession, info);
  523. });
  524. }
  525. }];
  526. }
  527. + (BOOL)downloadFininedForInfo:(NSDictionary *)info {
  528. BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
  529. return downloadFinined;
  530. }
  531. + (BOOL)isInCloudForInfo:(NSDictionary *)info {
  532. return [[info objectForKey:PHImageResultIsInCloudKey] boolValue];
  533. }
  534. @end