从Photos.app获取最后一张图片?
我已经看到其他应用程序做到这一点,你可以从照片应用程序导入最后一张照片,以便快速使用,但据我所知,我只知道如何得到一个图像,而不是最后一个(最近一个)。 任何人都可以告诉我如何得到最后的形象?
此代码片段将从相机胶卷(iOS 7及以下版本)获取最新的图像:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; // Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos. [library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) { // Within the group enumeration block, filter to enumerate just photos. [group setAssetsFilter:[ALAssetsFilter allPhotos]]; // Chooses the photo at the last index [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) { // The end of the enumeration is signaled by asset == nil. if (alAsset) { ALAssetRepresentation *representation = [alAsset defaultRepresentation]; UIImage *latestPhoto = [UIImage imageWithCGImage:[representation fullScreenImage]]; // Stop the enumerations *stop = YES; *innerStop = YES; // Do something interesting with the AV asset. [self sendTweet:latestPhoto]; } }]; } failureBlock: ^(NSError *error) { // Typically you should handle an error more gracefully than this. NSLog(@"No groups"); }];
iOS 8及以上版本:
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init]; fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; PHFetchResult *fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions]; PHAsset *lastAsset = [fetchResult lastObject]; [[PHImageManager defaultManager] requestImageForAsset:lastAsset targetSize:self.photoLibraryButton.bounds.size contentMode:PHImageContentModeAspectFill options:PHImageRequestOptionsVersionCurrent resultHandler:^(UIImage *result, NSDictionary *info) { dispatch_async(dispatch_get_main_queue(), ^{ [[self photoLibraryButton] setImage:result forState:UIControlStateNormal]; }); }];
iBrad很好的回答,对我来说几乎是完美的。 例外是它以原始方向返回图像(例如,倒置,-90°等)。
为了解决这个问题,我只是把fullResolutionImage
了fullScreenImage
。
这里:
UIImage *latestPhoto = [UIImage imageWithCGImage:[representation fullScreenImage]];
现在它是一种享受。
iBrad的例子包括一个显然可用的iOS8代码片段,但是我发现自己被他描述的返回types所困惑。 这是抓取最后一张图片的片段,包括版本和大小要求的选项。
值得注意的是能够请求一个特定的版本(原始,当前)和大小。 在我的情况下,因为我希望将返回的图像应用到一个button,我请求它的大小和比例,以适应我应用到的button:
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init]; fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; PHFetchResult *fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions]; PHAsset *lastAsset = [fetchResult lastObject]; [[PHImageManager defaultManager] requestImageForAsset:lastAsset targetSize:self.photoLibraryButton.bounds.size contentMode:PHImageContentModeAspectFill options:PHImageRequestOptionsVersionCurrent resultHandler:^(UIImage *result, NSDictionary *info) { dispatch_async(dispatch_get_main_queue(), ^{ [[self photoLibraryButton] setImage:result forState:UIControlStateNormal]; }); }];
感谢您的回答iBrad应用程序。
只是想指出一个防止特殊情况下的错误,当用户在他/她的照片卷上没有图像(奇怪的情况下,我知道):
// Within the group enumeration block, filter to enumerate just photos. [group setAssetsFilter:[ALAssetsFilter allPhotos]]; //Check that the group has more than one picture if ([group numberOfAssets] > 0) { // Chooses the photo at the last index [group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:([group numberOfAssets] - 1)] options:0 usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) { // The end of the enumeration is signaled by asset == nil. if (alAsset) { ALAssetRepresentation *representation = [alAsset defaultRepresentation]; UIImage *latestPhoto = [UIImage imageWithCGImage:[representation fullScreenImage]]; [self.libraryButton setImage:latestPhoto forState:UIControlStateNormal]; } }]; } else { //Handle this special case }
请参阅Liam的回答。 fullScreenImage
会返回适合您设备屏幕尺寸的缩放图像。 为了获得实际的图像大小:
ALAssetRepresentation *representation = [alAsset defaultRepresentation]; ALAssetOrientation orientation = [representation orientation]; UIImage *latestPhoto = [UIImage imageWithCGImage:[representation fullResolutionImage] scale:[representation scale] orientation:(UIImageOrientation)orientation];
引用fullResolutionImage上的Apple的ALAssetRepresentation类参考:
要从CGImage中创build一个正确旋转的UIImage对象,可以使用imageWithCGImage:scale:orientation:或initWithCGImage:scale:orientation:来传递方向和缩放值。
我发现了一个我感到尴尬的错字,比我们应该弄清楚的要长。 也许这会节省一些别人的时间。
此行在indexSetWithIndex
之后缺less冒号:
[group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:[group numberOfAssets] - 1]options:0 usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) {
这里是Swift中的一个版本,它会请求数据并将其转换为UIImage,因为提供的版本每次都返回一个空的UIImage
let fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)] let fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions) if let lastAsset: PHAsset = fetchResult.lastObject as? PHAsset { let manager = PHImageManager.defaultManager() let imageRequestOptions = PHImageRequestOptions() manager.requestImageDataForAsset(lastAsset, options: imageRequestOptions) { (let imageData: NSData?, let dataUTI: String?, let orientation: UIImageOrientation, let info: [NSObject : AnyObject]?) -> Void in if let imageDataUnwrapped = imageData, lastImageRetrieved = UIImage(data: imageDataUnwrapped) { // do stuff with image } } }
那么,这里是一个解决scheme,如何加载最后的图片与Swift 3家伙:
func loadLastImageThumb(completion: @escaping (UIImage) -> ()) { let imgManager = PHImageManager.default() let fetchOptions = PHFetchOptions() fetchOptions.fetchLimit = 1 fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: true)] let fetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions) if let last = fetchResult.lastObject { let scale = UIScreen.main.scale let size = CGSize(width: 100 * scale, height: 100 * scale) let options = PHImageRequestOptions() imgManager.requestImage(for: last, targetSize: size, contentMode: PHImageContentMode.aspectFill, options: options, resultHandler: { (image, _) in if let image = image { completion(image) } }) } }
如果你需要更多的速度,你也可以使用PHImageRequestOptions
并设置:
options.deliveryMode = .fastFormat options.resizeMode = .fast
这是你在viewController中得到它的方式(你应该把你的类replace成GalleryManager.manager):
GalleryManager.manager.loadLastImageThumb { [weak self] (image) in DispatchQueue.main.async { self?.galleryButton.setImage(image, for: .normal) } }
build立在iBrad的答案,这里是一个快速和肮脏的Swift版本,适用于我在iOS 8.1中:
let imgManager = PHImageManager.defaultManager() var fetchOptions = PHFetchOptions() fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: true)] if let fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions) { imgManager.requestImageForAsset(fetchResult.lastObject as PHAsset, targetSize: self.destinationImageView.frame.size, contentMode: PHImageContentMode.AspectFill, options: nil, resultHandler: { (image, _) in self.destinationImageView.image = image }) }
注意 :这需要iOS 8.0+。 一定要链接照片框架,并添加“导入照片”在您的文件。
下面是iBrad和Javier的答案(效果很好)的组合,但是我得到的是缩略图资源,而不是全分辨率图像。 其他人可能会发现这个方便。
- (void)setCameraRollImage { ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; [library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) { [group setAssetsFilter:[ALAssetsFilter allPhotos]]; if ([group numberOfAssets] > 0) { // Chooses the photo at the last index [group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:([group numberOfAssets] - 1)] options:0 usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) { // The end of the enumeration is signaled by asset == nil. if (alAsset) { UIImage *latestPhoto = [UIImage imageWithCGImage:[alAsset thumbnail]]; [self.cameraRollButton setImage:latestPhoto forState:UIControlStateNormal]; } }]; } } failureBlock: ^(NSError *error) { }]; }
Xamarin.iOS版本的接受答案(如何获得最后一张图片)包括来自其他答案的所有通知:
private void ChooseLastTakenPictureImplementation() { var library = new ALAssetsLibrary(); // Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos. library.Enumerate(ALAssetsGroupType.SavedPhotos, (ALAssetsGroup assetsGroup, ref bool stop) => { if (stop || assetsGroup == null) { return; } //Xamarin does not support ref parameters in nested lamba expressions var lambdaStop = false; //Check that the group has more than one picture if (assetsGroup.Count > 0) { // Within the group enumeration block, filter to enumerate just photos. assetsGroup.SetAssetsFilter(ALAssetsFilter.AllPhotos); // Chooses the photo at the last index assetsGroup.Enumerate(NSEnumerationOptions.Reverse, (ALAsset result, int index, ref bool innerStop) => { // The end of the enumeration is signaled by asset == nil. if (result != null) { var representation = result.DefaultRepresentation; var latestPhoto = new UIImage(representation.GetImage(), representation.Scale, (UIImageOrientation)representation.Orientation); // Stop the enumerations lambdaStop = innerStop = true; // Do something interesting with the AV asset. HandleImageAutoPick(latestPhoto); } }); stop = lambdaStop; return; } else { //Handle this special case where user has no pictures } }, error => { // Typically you should handle an error more gracefully than this. Debug.WriteLine(error.Description); }); }
这是一个非常酷的方法,但其中一个问题是,你必须能够在运行时实例化PHPhotoLibrary和其他PHPhoto类,否则会在iOS 7.XX链接错误只是想指出,因为我运行现在进入这些问题。
此外,我相信你必须在Photos框架中的弱链接,以便应用程序在安装了iOS 8.XX和iOS 7.XX的两个设备上运行(尽pipe我还没有testing过)。
我遇到的问题是如何在运行时实例化PHPhotoLibrary。 有没有人有这样的代码片段?
实际上,对于我正在开发的应用程序,我最终必须编写用于实例化PHPhotoLibrary类和调用PHotos框架方法的运行时代码,以便该应用程序可以在iOS 7.xx和iOS 8.xx上运行。其他人可能会遇到同样的问题问题,所以我提供了下面的代码 – >
// PHPhotoLibrary_class will only be non-nil on iOS 8.xx Class PHPhotoLibrary_class = NSClassFromString(@"PHPhotoLibrary"); if (PHPhotoLibrary_class) { /** * iOS 8..x. . code that has to be called dynamically at runtime and will not link on iOS 7.xx ... [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title]; } completionHandler:^(BOOL success, NSError *error) { if (!success) { NSLog(@"Error creating album: %@", error); } }]; */ // dynamic runtime code for code chunk listed above id sharedPhotoLibrary = [PHPhotoLibrary_class performSelector:NSSelectorFromString(@"sharedPhotoLibrary")]; SEL performChanges = NSSelectorFromString(@"performChanges:completionHandler:"); NSMethodSignature *methodSig = [sharedPhotoLibrary methodSignatureForSelector:performChanges]; NSInvocation* inv = [NSInvocation invocationWithMethodSignature:methodSig]; [inv setTarget:sharedPhotoLibrary]; [inv setSelector:performChanges]; void(^firstBlock)() = ^void() { Class PHAssetCollectionChangeRequest_class = NSClassFromString(@"PHAssetCollectionChangeRequest"); SEL creationRequestForAssetCollectionWithTitle = NSSelectorFromString(@"creationRequestForAssetCollectionWithTitle:"); [PHAssetCollectionChangeRequest_class performSelector:creationRequestForAssetCollectionWithTitle withObject:albumName]; }; void (^secondBlock)(BOOL success, NSError *error) = ^void(BOOL success, NSError *error) { if (success) { [assetsLib enumerateGroupsWithTypes:ALAssetsGroupAlbum usingBlock:^(ALAssetsGroup *group, BOOL *stop) { if (group) { NSString *name = [group valueForProperty:ALAssetsGroupPropertyName]; if ([albumName isEqualToString:name]) { groupFound = true; handler(group, nil); } } } failureBlock:^(NSError *error) { handler(nil, error); }]; } if (error) { NSLog(@"Error creating album: %@", error); handler(nil, error); } }; // Set the first and second blocks. [inv setArgument:&firstBlock atIndex:2]; [inv setArgument:&secondBlock atIndex:3]; [inv invoke]; } else { // code that always creates an album on iOS 7.xx but fails // in certain situations such as if album has been deleted // previously on iOS 8...x. . [assetsLib addAssetsGroupAlbumWithName:albumName resultBlock:^(ALAssetsGroup *group) { handler(group, nil); } failureBlock:^(NSError *error) { NSLog( @"Failed to create album: %@", albumName); handler(nil, error); }]; }
以下代码适用于iOS7和iOS8。 它还检查filter中是否有图像。 在执行代码之前,您应该检查相册权限:
// get the latest image from the album -(void)getLatestPhoto { NSLog(@"MMM TGCameraViewController - getLatestPhoto"); ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; // Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos. [library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) { // Within the group enumeration block, filter to enumerate just photos. [group setAssetsFilter:[ALAssetsFilter allPhotos]]; // For this example, we're only interested in the last item [group numberOfAssets]-1 = last. if ([group numberOfAssets] > 0) { [group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:[group numberOfAssets]-1] options:0 usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) { // The end of the enumeration is signaled by asset == nil. if (alAsset) { ALAssetRepresentation *representation = [alAsset defaultRepresentation]; // Do something interesting with the AV asset. UIImage *img = [UIImage imageWithCGImage:[representation fullScreenImage]]; // use the photo here ... // we only need the first (most recent) photo -- stop the enumeration *innerStop = YES; } }]; } } failureBlock: ^(NSError *error) { // Typically you should handle an error more gracefully than this. NSLog(@"No groups"); }]; }
(这个代码是从这里修改的版本。)