I am tring to get PHAsset from UIImagePickerController and using following code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// NSURL *imageURL = [info valueForKey:UIImagePickerControllerReferenceURL];
PHAsset *phAsset = [info valueForKey:UIImagePickerControllerPHAsset];
if (phAsset) {
[assetsArr addObject:phAsset];
[galleryArr addObject:[info valueForKey:UIImagePickerControllerOriginalImage]];
}
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self.galleryCollectionView reloadData];
[picker dismissViewControllerAnimated:YES completion:nil];
});
});
}
If source type is UIImagePickerControllerSourceTypePhotoLibrary then I am able to get PHAsset by above code. But if source type is UIImagePickerControllerSourceTypeCamera then PHAsset is nil.
How can i get PHAsset in that case?
If UIImagePickerControllerReferenceURL have some value then you can get asset using following code:
PHFetchResult<PHAsset *> *result = [PHAsset fetchAssetsWithALAssetURLs:[NSArray arrayWithObject:imageURL] options:nil];
It may have more than one asset select according to your requirement.
if you get the image from taking photo, you can get the origin image by Info Dictionary
then save the image at album
and get the PHAsset object.
the code was shown as below:
/// Save image to album.
static func saveImageToAlbum(image: UIImage, completion: ( (Bool, PHAsset?) -> Void )? ) {
let status = PHPhotoLibrary.authorizationStatus()
if status == .denied || status == .restricted {
completion?(false, nil)
return
}
var placeholderAsset: PHObjectPlaceholder? = nil
PHPhotoLibrary.shared().performChanges({
let newAssetRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
placeholderAsset = newAssetRequest.placeholderForCreatedAsset
}) { (suc, error) in
DispatchQueue.main.async {
if suc {
let asset = self.getAsset(from: placeholderAsset?.localIdentifier)
completion?(suc, asset)
} else {
completion?(false, nil)
}
}
}
}
private static func getAsset(from localIdentifier: String?) -> PHAsset? {
guard let id = localIdentifier else {
return nil
}
let result = PHAsset.fetchAssets(withLocalIdentifiers: [id], options: nil)
if result.count > 0{
return result[0]
}
return nil
}
Related
I can load normal images: public.image types.
The Apple proRaw(adobe raw image type: DNG format) can be used in iPhone 12 series.
So, I captured with RAW image and I want to load the DNG file from app.
But I can't load the image using PHPicker.
Normally, the codes below.
PHPickerConfiguration *configuration = [[PHPickerConfiguration alloc] init];
configuration.filter = [PHPickerFilter anyFilterMatchingSubfilters:#[[PHPickerFilter imagesFilter], [PHPickerFilter livePhotosFilter]]];
PHPickerViewController *pickerController = [[PHPickerViewController alloc] initWithConfiguration:configuration];
pickerController.delegate = self;
[pickerController setModalPresentationStyle:UIModalPresentationCustom];
[pickerController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[viewController presentViewController:pickerController animated:YES completion:nil];
-(void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray<PHPickerResult *> *)results API_AVAILABLE(ios(14)) {
[picker dismissViewControllerAnimated:YES completion:nil];
PHPickerResult *result = [results firstObject];
if ([result.itemProvider canLoadObjectOfClass:[UIImage class]]) { // 1
[result.itemProvider loadObjectOfClass:[NSObject class] completionHandler:^(__kindof id<NSItemProviderReading> _Nullable object, NSError * _Nullable error) {
if ([object isKindOfClass:[UIImage class]]) {
UIImage *image = object;
...
}
}];
}
In comment 1 line, returned NO.
How to load raw image using PHPicker?
Using loadFileRepresentation to get the photo's data into a CGImage object worked for me. Something like:
result.itemProvider.loadFileRepresentation(forTypeIdentifier: "public.image") { url, _ in
guard let url = url,
let data = NSData(contentsOf: url),
let source = CGImageSourceCreateWithData(data, nil),
let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil) else {
// handle
}
let image = UIImage(cgImage)
...
}
or
[result.itemProvider loadFileRepresentationForTypeIdentifier:#"public.image" completionHandler:^(NSURL * _Nullable url, NSError * _Nullable error) {
if (url) {
NSData *data = [NSData dataWithContentsOfURL:url];
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, NULL);
UIImage *image = [UIImage imageWithCGImage:cgImage];
...
}
}];
You may need to get the correct orientation using CGImageSourceCopyPropertiesAtIndex to get the metadata dictionary, find the correct value with the kCGImagePropertyOrientation key, transform it from CGImagePropertyOrientation to UIImage.Orientation, and pass it to the UIImage initializer.
It's a bit more involved than just using loadObjectOfClass but it won't require photo access authorization.
You can use this code also. for opening new PHPicker.
For More Knowledge about PHPicker in WWDC21 PHPicker WWDC20 Video and PHPicker WWDC21 Video
WWDC PHPicker Notes PHPicker Notes
import Photos
import PhotosUI
// MARK: - PHPicker Configurations (PHPickerViewControllerDelegate)
extension ViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: .none)
results.forEach { result in
result.itemProvider.loadObject(ofClass: UIImage.self) { reading, error in
guard let image = reading as? UIImage, error == nil else { return }
DispatchQueue.main.async {
self.profilePictureOutlet.image = image
// TODO: - Here you get UIImage
}
result.itemProvider.loadFileRepresentation(forTypeIdentifier: "public.image") { [weak self] url, _ in
// TODO: - Here You Get The URL
}
}
}
}
/// call this method for `PHPicker`
func openPHPicker() {
var phPickerConfig = PHPickerConfiguration(photoLibrary: .shared())
phPickerConfig.selectionLimit = 1
phPickerConfig.filter = PHPickerFilter.any(of: [.images, .livePhotos])
let phPickerVC = PHPickerViewController(configuration: phPickerConfig)
phPickerVC.delegate = self
present(phPickerVC, animated: true)
}
}
I am trying (AND FAILING) to get the user to upload an image and then pass the image name and actual image to another controller. This worked fine on a simulator and an actual device before ios11. But now, it just works on the simulator and crashes every time on the actual device. I am using TestFlight to test this so I am unable to see the errors on the device. But I saw this and was able to create my method which looks like this:
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
if #available(iOS 9.0, *) {
let url = info[UIImagePickerControllerReferenceURL] as! URL
//let assets = PHAsset.fetchAssets(withALAssetURLs: [url], options: nil)
//imageName = PHAssetResource.assetResources(for: assets.firstObject!).first!.originalFilename
let result = PHAsset.fetchAssets(withALAssetURLs: [url], options: nil)
imageName = PHAssetResource.assetResources(for: result.firstObject!).first!.originalFilename
// let asset = result.firstObject
// if(asset == nil){
// print("asset is NIL")
// }else {
// print("asset is not NIL")
// }
// print(asset?.value(forKey: "filename"))
// iconImageName = asset?.value(forKey: "filename") as! String
print("FILENAME START")
print(iconImageName)
print("FILENAME END")
} else {
// Fallback on earlier versions
}
self.dismiss(animated: true, completion: { () -> Void in
})
}
the commented out code are other ways I tried to get the file name. Why does this work on a simulator but not on a real device? I have looked online but this seems like the right way except it is not.
PS: Long story but my device does not work when connected to my Mac, which is why I am using TestFlight.
You can get fileName from UIImagePicker easily by this way:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let imageURL = info[UIImagePickerControllerReferenceURL] as? URL {
let result = PHAsset.fetchAssets(withALAssetURLs: [imageURL], options: nil)
let asset = result.firstObject
print(asset?.value(forKey: "filename"))
}
dismiss(animated: true, completion: nil)
}
For further information, you can follow this answer: https://stackoverflow.com/a/40628457/5167909
I believe you can get the image path(and from there the filename easily) from the info dictionary:
info[UIImagePickerControllerImageURL]
Try this:
PHAsset *asset = [self assetFromDictionary:info];
if (asset) {
NSData *fileData = nil;
NSString *fileName = [self filenameForAsset:asset];
}
- (PHAsset *)assetFromDictionary:(NSDictionary *)info {
PHAsset *asset = nil;
if (#available(iOS 11.0, *)) {
NSURL *assetURL = info[UIImagePickerControllerImageURL];
if (assetURL) {
asset = [info valueForKey:UIImagePickerControllerPHAsset];
}
} else {
NSURL *assetURL = info[UIImagePickerControllerReferenceURL];
if (assetURL) {
asset = [[PHAsset fetchAssetsWithALAssetURLs:#[assetURL] options:nil] lastObject];
}
}
return asset;
}
- (NSString *)filenameForAsset:(PHAsset *)asset {
NSString *filename = #"";
if (#available(iOS 9.0, *)) {
filename = [[PHAssetResource assetResourcesForAsset:asset] firstObject].originalFilename;
} else {
filename = [asset valueForKey:#"filename"];
}
return filename;
}
I am developing an iPhone photo application, so i need to create a separate album with a name "My Album" in camera roll and i need to save my UIImageView image with custom name for example "My Image.png" inside the newly created directory.
How can i do this?
Since the AssetsLibrary is deprecated, please use the Photos framework instead (iOS 8 and later).
// Deprecated!
import AssetsLibrary
// Swift 3.0
let assetsLibrary = ALAssetsLibrary()
assetsLibrary.addAssetsGroupAlbum(withName: "NewAlbum", resultBlock: { assetsGroup in
print(assetsGroup == nil ? "Already created" : "Success")
}, failureBlock: { error in
print(error)
})
You can use the shared PHPhotoLibrary object to create new photos but you can't give them specific names because you will be working with assets that need to be managed by the Photos.app. Each asset has specific properties. You can fetch objects, request changes, asset/thumbnail loading and caching, etc.
To create a custom album, please use the PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle:).
Brief example:
// Swift 3.0
func createPhotoLibraryAlbum(name: String) {
var albumPlaceholder: PHObjectPlaceholder?
PHPhotoLibrary.shared().performChanges({
// Request creating an album with parameter name
let createAlbumRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: name)
// Get a placeholder for the new album
albumPlaceholder = createAlbumRequest.placeholderForCreatedAssetCollection
}, completionHandler: { success, error in
if success {
guard let placeholder = albumPlaceholder else {
fatalError("Album placeholder is nil")
}
let fetchResult = PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [placeholder.localIdentifier], options: nil)
guard let album: PHAssetCollection = fetchResult.firstObject else {
// FetchResult has no PHAssetCollection
return
}
// Saved successfully!
print(album.assetCollectionType)
}
else if let e = error {
// Save album failed with error
}
else {
// Save album failed with no error
}
})
}
Don't forget to import Photos library.
To create a new photo asset on that album, please use the PHAssetChangeRequest.creationRequestForAsset(from:).
// Swift 3.0
func createPhotoOnAlbum(photo: UIImage, album: PHAssetCollection) {
PHPhotoLibrary.shared().performChanges({
// Request creating an asset from the image
let createAssetRequest = PHAssetChangeRequest.creationRequestForAsset(from: photo)
// Request editing the album
guard let albumChangeRequest = PHAssetCollectionChangeRequest(for: album) else {
// Album change request has failed
return
}
// Get a placeholder for the new asset and add it to the album editing request
guard let photoPlaceholder = createAssetRequest.placeholderForCreatedAsset else {
// Photo Placeholder is nil
return
}
albumChangeRequest.addAssets([photoPlaceholder] as NSArray)
}, completionHandler: { success, error in
if success {
// Saved successfully!
}
else if let e = error {
// Save photo failed with error
}
else {
// Save photo failed with no error
}
})
}
UPDATE:
We need to request access to be able to use the Photos library:
PHPhotoLibrary.requestAuthorization { status in
switch status {
...
}
As of iOS 10 and above we also need to add entry for access in the target .plist file for "Privacy - Photo Library Usage Description":
<key>NSPhotoLibraryUsageDescription</key>
<string>Access to photos is needed to provide app features</string>
You can create a custom album and add an image pretty easy with these lines of code in iOS:
// Create the new album.
__block PHObjectPlaceholder *myAlbum;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetCollectionChangeRequest *changeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title];
myAlbum = changeRequest.placeholderForCreatedAssetCollection;
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
PHFetchResult *fetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:#[myAlbum.localIdentifier] options:nil];
PHAssetCollection *assetCollection = fetchResult.firstObject;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
// add asset
PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
[assetCollectionChangeRequest addAssets:#[[assetChangeRequest placeholderForCreatedAsset]]];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(#"Error: %#", error);
}
}];
} else {
NSLog(#"Error: %#", error);
}
}];
Create a new album:
/// Create album with given title
/// - Parameters:
/// - title: the title
/// - completionHandler: the completion handler
func createAlbum(withTitle title: String, completionHandler: #escaping (PHAssetCollection?) -> ()) {
DispatchQueue.global(qos: .background).async {
var placeholder: PHObjectPlaceholder?
PHPhotoLibrary.shared().performChanges({
let createAlbumRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: title)
placeholder = createAlbumRequest.placeholderForCreatedAssetCollection
}, completionHandler: { (created, error) in
var album: PHAssetCollection?
if created {
let collectionFetchResult = placeholder.map { PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [$0.localIdentifier], options: nil) }
album = collectionFetchResult?.firstObject
}
completionHandler(album)
})
}
}
Get an album with with a specified name:
/// Get album with given title
/// - Parameters:
/// - title: the title
/// - completionHandler: the completion handler
func getAlbum(title: String, completionHandler: #escaping (PHAssetCollection?) -> ()) {
DispatchQueue.global(qos: .background).async { [weak self] in
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", title)
let collections = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
if let album = collections.firstObject {
completionHandler(album)
} else {
self?.createAlbum(withTitle: title, completionHandler: { (album) in
completionHandler(album)
})
}
}
}
And save a photo to a Photos album:
func save(photo: UIImage, toAlbum titled: String, completionHandler: #escaping (Bool, Error?) -> ()) {
getAlbum(title: titled) { (album) in
DispatchQueue.global(qos: .background).async {
PHPhotoLibrary.shared().performChanges({
let assetRequest = PHAssetChangeRequest.creationRequestForAsset(from: photo)
let assets = assetRequest.placeholderForCreatedAsset
.map { [$0] as NSArray } ?? NSArray()
let albumChangeRequest = album.flatMap { PHAssetCollectionChangeRequest(for: $0) }
albumChangeRequest?.addAssets(assets)
}, completionHandler: { (success, error) in
completionHandler(success, error)
})
}
}
}
It was working from since iOS 5.0.
Please import AssetsLibrary/AssetsLibrary.h
ALAssetsLibrary* libraryFolder = [[ALAssetsLibrary alloc] init];
[libraryFolder addAssetsGroupAlbumWithName:#"My Album" resultBlock:^(ALAssetsGroup *group)
{
NSLog(#"Adding Folder:'My Album', success: %s", group.editable ? "Success" : "Already created: Not Success");
} failureBlock:^(NSError *error)
{
NSLog(#"Error: Adding on Folder");
}];
You can try My below Method for Create Album for iOS 7 and iOS 8
#define PHOTO_ALBUM_NAME #"AlbumName Videos"
-(void)createAlbum{
// PHPhotoLibrary_class will only be non-nil on iOS 8.x.x
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.x.x ...
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:PHOTO_ALBUM_NAME];
} completionHandler:^(BOOL success, NSError *error) {
if (!success) {
NSLog(#"Error creating album: %#", error);
}else{
NSLog(#"Created");
}
}];
}else{
[self.library addAssetsGroupAlbumWithName:PHOTO_ALBUM_NAME resultBlock:^(ALAssetsGroup *group) {
NSLog(#"adding album:'Compressed Videos', success: %s", group.editable ? "YES" : "NO");
if (group.editable == NO) {
}
} failureBlock:^(NSError *error) {
NSLog(#"error adding album");
}];
}}
/// Save images or videos(保存图片或视频)(kUTTypeImage, kUTTypeMovie)
/// Add to album if specified album name, and create album if needed
/// #params mediaArray UIImage, fileURL for a image or video
+ (void)_saveMediaArray:(NSArray *)mediaArray
options:(LAImageSaverOptions *)options
completion:(void (^)(NSError * _Nullable err))completion
{
NSInteger __block count = 0;
[PHPhotoLibrary.sharedPhotoLibrary performChanges:^{
// Create album if needed
PHAssetCollectionChangeRequest *assetCollectionChangeRequest = nil;
NSMutableArray<PHObjectPlaceholder *> *assetChangeRequestPlaceholders = nil;
if (options.targetAlbumName.length > 0) {
assetChangeRequestPlaceholders = [NSMutableArray arrayWithCapacity:mediaArray.count];
PHFetchOptions *fetchOptions = PHFetchOptions.new;
//fetchOptions.includeAssetSourceTypes = PHAssetSourceTypeUserLibrary;
fetchOptions.predicate = [NSPredicate predicateWithFormat:#"localizedTitle = %#", options.targetAlbumName]; // 不能用 block 形式的 predicate
PHAssetCollection * assetCollection = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:fetchOptions].firstObject;
if (nil == assetCollection) {
assetCollectionChangeRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:options.targetAlbumName];
} else {
assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
}
}
// Save images
for (id item in mediaArray) {
PHAssetChangeRequest *assetChangeRequest = nil;
// image object
if ([item isKindOfClass:UIImage.class]) {
UIImage *image = (UIImage *)item;
assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
[assetChangeRequestPlaceholders addObject:assetChangeRequest.placeholderForCreatedAsset];
++count;
continue;
}
// file url for image or movie
NSURL *fileURL = (NSURL *)item;
if ([item isKindOfClass:NSURL.class] && fileURL.isFileURL) {
NSString *extension = fileURL.pathExtension;
if (extension.length == 0) {
NSLog(#"illegal fileURL(no path extension): %#", fileURL);
continue; // illegal file url
}
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
BOOL isImage = false;
BOOL isVideo = false;
if (nil != uti && CFStringGetLength(uti) > 0) {
isImage = UTTypeConformsTo(uti, kUTTypeImage);
isVideo = UTTypeConformsTo(uti, kUTTypeMovie); // kUTTypeVideo, kUTTypeAudiovisualContent
}
if (isImage) {
assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:fileURL];
[assetChangeRequestPlaceholders addObject:assetChangeRequest.placeholderForCreatedAsset];
++count;
} if (isVideo) {
assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:fileURL];
[assetChangeRequestPlaceholders addObject:assetChangeRequest.placeholderForCreatedAsset];
++count;
} else {
NSLog(#"illegal fileURL(neither image nor movie): %#", fileURL);
continue; // illegal file url
}
}
}
// add to album if needed
[assetCollectionChangeRequest addAssets:assetChangeRequestPlaceholders];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
// not in main thread
dispatch_async(dispatch_get_main_queue(), ^{
completion(error);
});
}];
}
By the way, you can do more about LAImageSaverOptions
#interface LAImageSaverOptions : NSObject
/// to show alert controller on the hostVC
#property(nonatomic, weak, null_resettable) UIViewController *hostVC;
/// total progress
#property (nonatomic, strong, null_resettable) NSProgress *progress;
// album name for saving images
#property (nonatomic, copy, nullable) NSString *targetAlbumName;
#end
you can save image with custom name to sandbox first,and then save it to album,it work to me.
How can I get the name of video file selected from Camera roll or any other album in UIImagePickerController's delegate method ?
I'm able to get the name of image but if using same in video it's returning nil.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if (![mediaType isEqualToString:(NSString *)kUTTypeMovie])
return;
mediaURl = [info objectForKey:UIImagePickerControllerMediaURL];
//NSLog(#"mediaURL %#",mediaURl);
moviePath = mediaURl.absoluteString;
// NSLog(#"moviePath %#",moviePath);
tempFilePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
NSLog(#"filepath %#",tempFilePath);
//if you want only file name
NSArray *ar = [tempFilePath componentsSeparatedByString:#"/"];
NSString *filename = [[ar lastObject] uppercaseString];
NSLog(#"filename %#",filename);
}
Let me know if you have any issues
I know this thread is super old but i thought if someone finds it, here is a working answer in swift:
func fileName(for infoDict: [String : Any]) -> String? {
guard let referenceURL = infoDict[UIImagePickerControllerReferenceURL] as? URL else { return nil }
let result = PHAsset.fetchAssets(withALAssetURLs: [referenceURL], options: nil)
guard let asset = result.firstObject else { return nil }
let firstResource = PHAssetResource.assetResources(for: asset).first
return firstResource?.originalFilename ?? asset.value(forKey: "filename") as? String
}
Swift 4 or later
Working on My Side for the captured image
Use :
imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]){
let fileName = FileInfo.getMediaName(info: info)
}
class : pleas put the method info[:]
class FileInfo {
// Return Media name
static func getMediaName(info:[String : Any]) -> String {
if let asset = info[UIImagePickerControllerPHAsset] as? PHAsset {
let assetResources = PHAssetResource.assetResources(for: asset)
let firstObj = assetResources.first?.originalFilename as! NSString
print(firstObj)
return firstObj
}
}
}
// IMG_02256.jpeg
Im trying to get the image name using PHAssets. But I couldn't find metadata for filename or any method to get the image name. Is there a different way to get the file name?
I know the question has already been answered, but I figured I would provide another option:
extension PHAsset {
var originalFilename: String? {
var fileName: String?
if #available(iOS 9.0, *) {
let resources = PHAssetResource.assetResources(for: self)
if let resource = resources.first {
fileName = resource.originalFilename
}
}
if fileName == nil {
/// This is an undocumented workaround that works as of iOS 9.1
fileName = self.value(forKey: "filename") as? String
}
return fileName
}
}
If you want to get the image name (for example name of last photo in Photos) like IMG_XXX.JPG, you can try this:
PHAsset *asset = nil;
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:YES]];
PHFetchResult *fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions];
if (fetchResult != nil && fetchResult.count > 0) {
// get last photo from Photos
asset = [fetchResult lastObject];
}
if (asset) {
// get photo info from this asset
PHImageRequestOptions * imageRequestOptions = [[PHImageRequestOptions alloc] init];
imageRequestOptions.synchronous = YES;
[[PHImageManager defaultManager]
requestImageDataForAsset:asset
options:imageRequestOptions
resultHandler:^(NSData *imageData, NSString *dataUTI,
UIImageOrientation orientation,
NSDictionary *info)
{
NSLog(#"info = %#", info);
if ([info objectForKey:#"PHImageFileURLKey"]) {
// path looks like this -
// file:///var/mobile/Media/DCIM/###APPLE/IMG_####.JPG
NSURL *path = [info objectForKey:#"PHImageFileURLKey"];
}
}];
}
Hope it helps.
In Swift the code will look like this
PHImageManager.defaultManager().requestImageDataForAsset(asset, options: PHImageRequestOptions(), resultHandler:
{
(imagedata, dataUTI, orientation, info) in
if info!.keys.contains(NSString(string: "PHImageFileURLKey"))
{
let path = info![NSString(string: "PHImageFileURLKey")] as! NSURL
}
})
Swift 4:
let fetchResult = PHAsset.fetchAssets(with: .image, options: nil)
if fetchResult.count > 0 {
if let asset = fetchResult.firstObject {
let date = asset.creationDate ?? Date()
print("Creation date: \(date)")
PHImageManager.default().requestImageData(for: asset, options: PHImageRequestOptions(),
resultHandler: { (imagedata, dataUTI, orientation, info) in
if let info = info {
if info.keys.contains(NSString(string: "PHImageFileURLKey")) {
if let path = info[NSString(string: "PHImageFileURLKey")] as? NSURL {
print(path)
}
}
}
})
}
}
One more option is:
[asset valueForKey:#"filename"]
The "legality" of this is up to you to decide.
Easiest solution for iOS 9+ in Swift 4 (based on skims answer):
extension PHAsset {
var originalFilename: String? {
return PHAssetResource.assetResources(for: self).first?.originalFilename
}
}
For Swift
asset?.value(forKey: "filename") as? String
For objective C
[asset valueForKey:#"filename"]
Simplest answer with Swift when you have reference url to an asset:
if let asset = PHAsset.fetchAssetsWithALAssetURLs([referenceUrl], options: nil).firstObject as? PHAsset {
PHImageManager.defaultManager().requestImageDataForAsset(asset, options: nil, resultHandler: { _, _, _, info in
if let fileName = (info?["PHImageFileURLKey"] as? NSURL)?.lastPathComponent {
//do sth with file name
}
})
}
SWIFT4:
first import Photos
if let asset = PHAsset.fetchAssets(withALAssetURLs: [info[UIImagePickerControllerReferenceURL] as! URL],
options: nil).firstObject {
PHImageManager.default().requestImageData(for: asset, options: nil, resultHandler: { _, _, _, info in
if let fileName = (info?["PHImageFileURLKey"] as? NSURL)?.lastPathComponent {
print("///////" + fileName + "////////")
//do sth with file name
}
})
}
What you really looking for is the localIdentifier which is a unique string that persistently identifies the object.
Use this string to find the object by using the:
fetchAssetsWithLocalIdentifiers:options:, fetchAssetCollectionsWithLocalIdentifiers:options:, or fetchCollectionListsWithLocalIdentifiers:options: method.
More information is available here