如何在iCloud Drive上生成图像缩略图?

6
这看起来很简单,但缺乏文档使得这个问题无法猜测。
我在应用的iCloud驱动器上有照片和视频,并且想要创建这些资产的缩略图。我谈论的是iCloud驱动器上的资产,而不是相机胶卷中的iCloud照片流。我说的是真正的iCloud驱动器文件夹。
与图像相比,从视频中创建缩略图相对“容易”。你只需要两个星期来弄清它的工作原理,考虑到苹果写的糟糕文档,但似乎无法从图像中创建缩略图。
现在我有一个NSMetadataItem数组,每个元素都描述了iCloud文件夹中的一个项目。
至今为止我尝试过的方法无法实现:

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];

这种方法的效果非常棒。你准备好了吗?我们开始吧:success = YESerror = nilthumbnail = nil

另一种方法

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];

}];

错误 = 在此服务器上未找到请求的 URL。缩略图 = 空

这个方法似乎仅适用于视频。我只是试一下。有没有类似于此方法的图像等效方法?


原始方法

NSData *tempData = [NSData dataWithContentsOfUrl:tempURL];

NOPE - 数据 = 空


方法4

第四种可能的方法是使用ALAsset,但在iOS 9上已被弃用。

我认为所有这些方法都会失败,因为它们只适用于本地资源(无论是否存在错误)。有什么想法可以下载图像,以便获取缩略图?

还有其他想法吗?

谢谢


编辑:经过几次测试后,我发现方法1似乎是唯一朝着正确方向的方法。这种方法效果不好,有时会抓取图标,但大多数情况下不起作用。


另一个观点是这样的。无论人们建议我什么,他们总是说要下载整个图像才能获得缩略图。我不认为这是正确的做法。只需看看如何获取视频缩略图即可。您不需要下载整个视频即可获取其缩略图。

所以这个问题仍然没有答案。


你看过http://nshipster.com/phimagemanager/了吗? - Daniel Galasko
是的,但这篇文章讨论的是PHAssets。PH代表照片框架,我认为该框架无法从iCloud Drive检索内容。我在谈论iCloud资产。我不确定这两者之间的关系。我从iCloud得到的是一堆NSMetadataItem。如果您知道如何将NSMetadataItem转换为PHAsset项目,我非常感兴趣。 - Duck
4个回答

3

照片框架或资产库不能在这里使用,因为您必须先将iCloud驱动器中的照片导入到照片库中才能使用这两个框架的任何方法。

您应该查看ImageIO: 获取iCloud驱动器照片的NSData内容,然后按如下方式继续:

CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)(imageData), NULL );

NSDictionary* thumbOpts = [NSDictionary dictionaryWithObjectsAndKeys:
                                    (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
                                    (id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageAlways,
                                    [NSNumber numberWithInt:160],(id)kCGImageSourceThumbnailMaxPixelSize,
                                    nil];

CGImageRef  thumbImageRef = CGImageSourceCreateThumbnailAtIndex(source,0,(__bridge CFDictionaryRef)thumbOpts);

UIImage *thumbnail = [[UIImage alloc] initWithCGImage: thumbImageRef];

好的,但是我该怎么获得imageData?那就是我需要的全部。我记得我的答案说[NSData dataWithContentsOfUrl:tempURL];给了我nil。 - Duck
你检查了吗,你的NSMetaDataItem是否实际从iCloud下载?[metadataItem valueForAttribute:NSMetadataUbiquitousItemIsDownloadedKey];返回什么? - holtmann
缩略图可能无法生成,因为它们不在设备上,而苹果从未解释如何处理此问题,他们提供的方法也没有下载任何内容。顺便说一句,从相机胶卷中下载所有图片似乎很愚蠢,浪费了大量带宽,当你只需要一个100x100的缩略图时。 - Duck
iCloud的行为并不是很透明。我建议采用以下方法:1.使用您的代码请求预生成的缩略图。在我的测试中,我经常第二次调用时得到结果。2.如果仍然没有重新生成的缩略图,请使用startDownloadingUbiquitousItemAtURL:强制下载,然后使用我的代码生成缩略图。 - holtmann

2

经过测试,似乎效果最好的方案是这个:

[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];

这个解决方案并不完美。有时无法提取缩略图,但我找不到其他百分百有效的解决方案。其他方法比这更糟糕。


1
这对我有效。它有一点不同。
func genereatePreviewForOnce(at size: CGSize,completionHandler: @escaping (UIImage?) -> Void) {

        _ = fileURL.startAccessingSecurityScopedResource()

        let fileCoorinator = NSFileCoordinator.init()

        fileCoorinator.coordinate(readingItemAt: fileURL, options: .immediatelyAvailableMetadataOnly, error: nil) { (url) in

            if let res = try? url.resourceValues(forKeys: [.thumbnailDictionaryKey]),

                let dict = res.thumbnailDictionary {

                let image = dict[.NSThumbnail1024x1024SizeKey]

                completionHandler(image)

            } else {

                fileURL.removeCachedResourceValue(forKey: .thumbnailDictionaryKey)

                completionHandler(nil)

            }

            fileURL.stopAccessingSecurityScopedResource()

        }

    }

由于缩略图正在生成背景,您可能需要多次调用此功能。 - mcfans

0

看起来你是事后生成缩略图。如果这是你的文档并且你正在使用UIDocument,请重写fileAttributesToWriteToURL:forSaveOperation:error:方法,在文档保存时插入缩略图。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接