Search code examples
iosthumbnailsphotosframeworkphasseticloud-drive

How to generate thumbnails of images on iCloud Drive?


This appears easy, but the lack of documentation makes this question impossible to guess.

I have pictures and videos on my app's icloud drive and I want to create thumbnails of these assets. I am talking about assets on iCloud Drive, not the iCloud photo stream inside the camera roll. I am talking about the real iCloud Drive folder.

Creating thumbnails from videos are "easy" compared to images. You just need 2 weeks to figure out how it works, having in mind the poor documentation Apple wrote but thumbnails from images seem impossible.

What I have now is an array of NSMetadataItems each one describing one item on the iCloud folder.

These are the methods I have tried so far that don't work:


METHOD 1

[fileURL startAccessingSecurityScopedResource];

NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] init];
__block NSError *error;

[coordinator coordinateReadingItemAtURL:fileURL
                                options:NSFileCoordinatorReadingImmediatelyAvailableMetadataOnly
                                  error:&error
                             byAccessor:^(NSURL *newURL) {
                               NSDictionary *thumb;
                               BOOL success = [newURL getResourceValue:&thumb forKey:NSURLThumbnailDictionaryKey error:&error];

                               UIImage *thumbnail = thumb[NSThumbnail1024x1024SizeKey];



                             }];

[fileURL stopAccessingSecurityScopedResource];

The results of this method are fantastic. Ready for that? Here we go: success = YES, error = nil and thumbnail = nil.


ANOTHER METHOD

AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:fileURL
                                            options:nil];

AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];

imageGenerator.appliesPreferredTrackTransform = YES;

CMTime time = CMTimeMake(0, 60); // time range in which you want
NSValue *timeValue = [NSValue valueWithCMTime:time];

[imageGenerator generateCGImagesAsynchronouslyForTimes:@[timeValue] completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * error) {

  thumbnail = [[UIImage alloc] initWithCGImage:image];

}];

error = The requested URL was not found on this server. and thumbnail = nil

This method appears to be just for videos. I was trying this just in case. Any equivalent of this method to images?


PRIMITIVE METHOD

NSData *tempData = [NSData dataWithContentsOfUrl:tempURL];

NOPE - data = nil


METHOD 4

The fourth possible method would be using ALAsset but this was deprecated on iOS 9.

I think that all these methods fail because they just work (bug or not) if the resource is local. Any ideas on how to download the image so I can get the thumbnail?

Any other ideas?

thanks


EDIT: after several tests I see that Method 1 is the only one that seems to be in the right direction. This method works poorly, sometimes grabbing the icon but most part of the time not working.


Another point is this. Whatever people suggests me, they always say about downloading the whole image to get the thumbnail. I don't think this is the way to go. Just see how getting thumbnails of video work. You don't download the whole video to get its thumbnail.

So this question remains open.


Solution

  • After testing several solutions, the one that seems to work better is this one:

    [fileURL startAccessingSecurityScopedResource];
    
    NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] init];
    __block NSError *error;
    
    [coordinator coordinateReadingItemAtURL:fileURL
                                    options:NSFileCoordinatorReadingImmediatelyAvailableMetadataOnly
                                      error:&error
                                 byAccessor:^(NSURL *newURL) {
                                   NSDictionary *thumb;
                                   BOOL success = [newURL getResourceValue:&thumb forKey:NSURLThumbnailDictionaryKey error:&error];
    
                                   UIImage *thumbnail = thumb[NSThumbnail1024x1024SizeKey];
    
    
    
                                 }];
    
    [fileURL stopAccessingSecurityScopedResource];
    

    This solution is not perfect. It will fail to bring the thumbnails sometimes but I was not able to find any other solution that works 100%. Others are worst than that.