iOS:<Photos/Photos.h> Getting Album Video and Pictures

Keywords: iOS less Attribute github

From: http://www.jianshu.com/p/ea0274a33209


Because of the needs of the project, to capture videos and pictures in the album has not been discussed before. Just know that after iOS 8.0, Apple launched a new album management package. Now you can see the framework, and also know that the AlAsset Library has not been used in detail, so it is not compared with PhotoKit.
Let's start with a git: https://github.com/wizetLee/TestPhotoKit



Class Introduction:

//PHAsset: A separate resource in the user photo library, in short, metadata for a single image
// PHAsset combines to form a single PHAsset Collection (PHAsset Collection), which can be an album in the photo library or a moment in the photo, or a special "smart album". This smart album includes all video collections, recently added items, user collections, all serial photos, etc.
//PHCollection List is PHCollection containing PHCollection. Because it's PHCollection itself, collection lists can contain other collection lists that allow complex collection inheritance. Example: Annual - > Selected - > Moment
//PHFetchResult The return result of a series (PHAsset Collection) or album (PHAsset), a collection type, PHAsset or PHAsset Collection's class method can be obtained.
//PHImageManager handles image loading, which is cached.
// PHCaching Image Manager (abstract of PHImage Manager) Processing the cache of the whole loading process of an image. When loading thumbnails with a large number of resources, you can use this class of startCaching Image... Preload the image into memory, and use the same size.
// PHImageRequest Options sets the parameters of how the image is loaded ()
//PHFetchOptions Collection Resource Configuration (arranging resources in a certain (e.g. time) order, hiding/displaying a part of the collection)


First identify the pit you stepped in.

 /*
     1, Problem when first loading APP: Only the appropriate permissions will be obtained without responding to the method
     */
    //This handler is called every time you visit the album to check the authorization of the changed app
    //PHPhotoLibrary 
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        if (status == PHAuthorizationStatusAuthorized) {
          //code
        }
    }];

    /*
     2,Get all the pictures. (Note that you can't get pictures in the film because the pictures in the film contain video s.)
     */
    [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];//So get

    /*
     3,Questions about callback synchronization or asynchronization and number of block callbacks when using PHImageManager requests
     */

    /*
     4,The problem of image size from callback: determined by three parameters
     */
    /*
     Observation in Show AlbumViewController

     Under PH Image Content Model AspectFill, image size has a watershed {125,125} {126,126}.
     When imageOptions.resizeMode = PHImageRequestOptions ResizeModeExact;
     When: Set size less than {125,125}, you will get a picture size of 1/2 of the settings.

     In the PH Image Content Model AspectFit watershed {120,120} {121,121}
     */
    /*
     5,The problem of the disappearance of info dictionary key in callback: when none of the size s of the final image can reach the height/width of the original image, some keys will disappear.
     */

First, let's do a simple exercise: Get all the pictures of the local system.

In collectionView

- (void)getAllPhotosFromAlbum {//Configuration is simple, but the parameters are more than the price.
    self.options= [[PHImageRequestOptions alloc] init];//Request Options Settings
    self.options.resizeMode=PHImageRequestOptionsResizeModeExact;
//resizeMode custom settings for image size enumeration type*
// PHImageRequestOptionsResizeMode:*
//PHImageRequest Options ResizeModeNone = 0, // Keep the original size
//PHImageRequest Options Resize Model Fast, // Efficient, but does not guarantee that the size of the image is customized
//PHImageRequest Options ResizeModel Exact, // strictly according to custom size

   self.options.synchronous=YES;   //YES must be synchronous NO is not necessarily asynchronous
  imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
        /*
     PHImageRequestOptionsResizeModeNone // No Size Adjustment
     PHImageRequestOptionsResizeModeFast // Arranged by the system, the situation is uncertain: sometimes you set a lower size, according to the size you set, sometimes than
     PHImageRequestOptionsResizeModeExact// Guarantee accuracy to custom size: Precise premise here is to use PH Image Content Model AspectFill
     */

    //SimageOptions.version = PHImageRequest Options Version Current; //version iOS 8.0 after the image editing extension, you can get the original image or edited image according to the next enumeration.
    /*PHImageRequestOptionsVersion: 
     PHImageRequestOptionsVersionCurrent = 0, //Current (Edited? Edited Graph: Original Graph)
     PHImageRequestOptionsVersionUnadjusted, //Edited drawings
     PHImageRequestOptionsVersionOriginal    //Original picture
     */

    //    imageOptions.networkAccessAllowed = YES; // Used to open iClould to download pictures
    //    Callback to download progress of imageOptions.progressHandler//iClould

    imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;//In the case of imageOptions.synchronous = NO, is the final decision asynchronous?

//Container class
  (PHFetchResult *) self.assets= [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
    //Here option is to get the configuration of Collection, and I just set it to nil so that it can be used
   /*
//For example, sort resources by their creation time
         PHFetchOptions *options = [[PHFetchOptions alloc] init];
//    NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES];
         options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; 
//Where: key is the property of the PHAsset class, which is a kvc
         PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
    */
  [self.containView.collectionView reloadData];
}

- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath {
    AlbumCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ALBUMCELLID forIndexPath:indexPath];
//cell.backgroundColor= [UIColor redColor];
    CGSize size =CGSizeMake(50,50);//Custom image size changes are quite complex. Here's how

    //Returns a PHImageRequest ID, which can be used to cancel requests when asynchronous requests are made. Synchronization is no longer possible.
    [[PHImageManager defaultManager] requestImageForAsset:self.assets[indexPath.row] targetSize:size contentMode:PHImageContentModeDefault options:self.options resultHandler:^(UIImage*_Nullable result,NSDictionary*_Nullable info) {
 /*
         The size of the final image is determined by imageOptions.resizeMode (PHImageRequest Options) and PHImageContentMode, and of course, by the size we set.
         Priority 
         PHImageRequestOptions > PHImageContentMode
         */
        //This handler is not executed on the main thread, so if you have UI updates, you have to add them manually to the main thread.
//       dispatch_async(dispatch_get_main_queue(), ^{ //update UI  });

#Pragma If - [PH Image Request Options is Synchronous] returns NO (or options is nil), resultHandler may be called 1 or more times.... Asynchronous callbacks one or more times on this callback.
#Pragma If - [PH Image Request Options is Synchronous] returns YES, resultHandler will be called exactly once synchronization.
//At first, I intended to save all the photos by data bar. But I found that the synchronous card UI was called back many times, and my array became double. So I had to use the task method cell for Item.
    cell.photoImageView.contentMode = UIViewContentModeScaleAspectFit;
    cell.photoImageView.image = result;
}];
  return cell;
}
/*Note that this info dictionary is sometimes used cautiously for null
     The key inside is rather strange.
     Try not to use the key inside.
     Because this key will change: when none of the sizes of the final images we get are as wide as the sizes of the original images.
     Some key s will disappear, such as PHImageFile Sandbox Extension TokenKey, PHImageFile URLKey
     */

    /*
     Under PH Image Content Model AspectFill, image size has a watershed {125,125} {126,126}.
     When imageOptions.resizeMode = PHImageRequestOptions ResizeModeExact;
     When: Set size less than {125,125}, you will get a picture size of 1/2 of the settings.

     In the PH Image Content Model AspectFit watershed {120,120} {121,121}   
     As for why??? I don't know - - Maybe Apple is considering performance... Who knows?
     */

Notice the resultHandler above, return a UI Image, and an NSDictionary, let's not say much about the picture, but the key is that the info is really weird.

This has aroused my concern: the relationship between size and key

The key around the size of size is different...
I also printed out the graph // condition: size = {300,300}


It was supposed that when the size we set was smaller than the original image, a new image would be generated, and the local resources of the image did not exist, so there was less key.

But now it's embarrassing. Looking at the original image of the second image, it's clear that it's smaller than {300,300}. Why don't we have some key s? I don't understand it very well.

Don't get me wrong, the original image of the first picture must be larger than {300,300}. Why not {300,300} because I use PH Image Content Model AspectFit to process the picture, so it's not us {300,300} that shows the proportion of the original image, so you can try it by hand.

And this size is actually a pixel:
CGSizeMake(self.assets[indexPath.row].pixelWidth,self.assets[indexPath.row].pixelHeight);
Or you can get the original image by setting a size that is definitely bigger than the original one... Of course, the latter is unreliable.

Maybe it's the problem of this size, which will lead me to find the local image when I want to get the local image according to this PHimageFileKey, because some part of the image lacks this key because of the size, so I can't find this image, which makes my app bug.... But this method is really unsafe, I suggest that the image returned should be written into the tmp and used again....

Furthermore, the relationship between the number of asynchronous requests and size

When my self.options.synchronous=NO; // is an asynchronous request process (it turns out that the asynchronous request is not determined by the synchronous attribute of options)
This PHImageRequest Options can control the number of asynchronous requests based on its delivery mode attribute
PHImageRequestOptionsDeliveryMode:
PHImageRequest Options Delivery Model Opportunistic// Judge from my self.options.synchronous whether the return result is one or more
PHImageRequest Options Delivery Model HighQualityFormat // Formulated synchronously returns a result that returns a slightly better picture quality than the size we set (actually related to the resizeMode enumeration of PHImageRequest Options)
PHImageRequest Options Delivery ModeFastFormat// Returns only once, and the quality of the graph obtained is not good when the efficiency is high.

 The resizeMode mode I'm working with here is to force customized image sizes, i.e.
Self. options. resizeMode = PHImageRequest Options ResizeModel Exact; // Loading mode strictly according to custom image size

If not for this enumeration, the first thumbnail returned by PHImageRequest Options Delivery Model Opportunistic and the smallest thumbnail returned by PHImageRequest Options Delivery Model FastFormat default is {60,60}.
PHImageRequest Options Resize Model Exact can be set at will

It's worth noting that when we choose PH Image Request Options Delivery Model Opportunistic, the number of returns is related to size. If the size you set is too small, it will only be called back once. If the size is too large, the first return is a small thumbnail (the thumbnail Max is {60,60}, the specific value is proportional), the second callback will get the picture we want.

In a word, the real size of the picture is related to resize mode, PHIMAGE Request Options Delivery mode and the size we set. When we apply it, we should try it several times and observe what we really need.

The next thing I'm looking for is video... The question arises again. Does this PhotoKit provide a way to find video?
And then I revised this... Changed to find Video metadata haha ha ha ha ha
self.assets= [PHAsset fetchAssetsWithMediaType:**PHAssetMediaTypeVideo** options:nil];

But I seem to have stepped on the pit I dug again.



It's all pictures... No, it's not.

Looking back, I found that PHImage Manager provided us with three ways to find Vide. I chose one of the common methods.

PHFetchResult *assetsResult = [PHAssetfetch AssetsWithMediaType:PHAssetMediaType Videooptions:nil];
PHVideoRequestOptions *options2 = [[PHVideoRequestOptions alloc] init];
options2.deliveryMode=PHVideoRequestOptionsDeliveryModeAutomatic;
for(PHAsset *a in assetsResult) {                       
   [[PHImageManager defaultManager] requestAVAssetForVideo:a options:options2 resultHandler:^(AVAsset*_Nullable asset,
    AVAudioMix*_Nullable audioMix,NSDictionary*_Nullable info) {
    NSLog(@"%@",info);
  }];
}

Find you...

But you are... PHImageFile Sandbox Extension TokenKey... Inside this key



It seems that the address needs to be intercepted and the video can be found by inputting it directly into finder, but the previous string has to let us manually fetch its substrings just by getting the Path of videos.

It's very unsafe. I'm really afraid that this key will suddenly be miss ed again for some reason...
Then I looked at the type of asset and found that its type was AVURLAsset. It was interesting to see that one of them had a URL attribute! And it's the absolute path of asset. It's perfect.

//Vieo Path Acquisition
if (asset && [asset isKindOfClass:[AVURLAsset class]] && [NSString stringWithFormat:@"%@",((AVURLAsset *)asset).URL].length > 0) {
  NSString *videoURLStr = [NSString stringWithFormat:@"%@",((AVURLAsset *)asset).URL];
  videoPath = [videoURLStr substringWithRange:NSMakeRange([videoURLStr rangeOfString:@"/"].location, videoURLStr.length -[videoURLStr rangeOfString:@"/"].location)];
}//This operation of intercepting strings is redundant for Citrus

II. Access to resources based on actual needs

What's the practical method? Sometimes you look for a lot of pictures, and then find, adjust and adjust them. It's really not a good way to do that. Why can't you choose from the categories I have classified!!!!

Okay, let's just talk about this situation. At the beginning, you must see a graph of the relationship between resources and the collection of resources.

Get all user-defined albums: 1\2\3 are the albums I created, the following code can capture the content of the albums I created.


Capturing pictures/video s in system albums




collection cell is not handled, but the effect is obvious, the same tableView to select the part you want to find can be
The seven identical pictures in the middle are actually pictures of seven identical videos I put into the system.

Explain it.

PHFetchResult*smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];

This method of collecting resource sets needs to fill in two enumeration types. I would appreciate it if you could mention any mistakes.


Reference article:
http://objccn.io/issue-21-4/#PhotoKit-Object-Model
http://kayosite.com/ios-development-and-detail-of-photo-framework-part-two.html


Posted by justravis on Wed, 09 Jan 2019 15:48:10 -0800