22

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?

Bartłomiej Semańczyk
  • 52,820
  • 43
  • 206
  • 318
Priyanka
  • 492
  • 1
  • 5
  • 13

7 Answers7

41

I know the question has already been answered, but I figured I would provide another option:

extension PHAsset {

    var originalFilename: String? {

        var fname:String?

        if #available(iOS 9.0, *) {
            let resources = PHAssetResource.assetResources(for: self)
            if let resource = resources.first {
                fname = resource.originalFilename
            }
        }

        if fname == nil {
            // this is an undocumented workaround that works as of iOS 9.1
            fname = self.value(forKey: "filename") as? String
        }

        return fname
    }
}
Vinoth Vino
  • 6,991
  • 3
  • 54
  • 59
skim
  • 1,907
  • 1
  • 13
  • 16
  • 1
    Note that `PHAssetResource` is available on iOS 9+ only. – lobianco Mar 09 '16 at 22:05
  • I tried using your code with a sort descriptor using 'originalFilename' as key and it gives the 'Unsupported sort descriptor in fetch options' error. – Angelo May 03 '16 at 14:40
  • For some reason my video file says "TPHM1745" as the name of the file when I use ImageCapture app in OSX to see the Camera Roll files, but your method throws "IMG_6564.MP4" – omarojo Jul 25 '18 at 22:49
20

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)
                            }
                        }
                    }
            })
        }
    }
Eridana
  • 2,205
  • 19
  • 25
  • 5
    This is just dirty workaround. `PHImageFileURLKey` is undocumented key and also this URL does not have unique name in last path component if image is edited (with image filter for example). – user500 Apr 07 '15 at 18:36
  • Will the fluff always be file:///var/mobile/Media/DCIM/###APPLE/IMG_####.JPG ? Is there some way to cipher through that and just get the file name for instance test.png? – Nerdy Lime Apps Oct 04 '15 at 23:42
  • 1
    And is there any way from keeping the system from renaming images? If I transfer an image to my device, I would like it to maintain the same filename they have on my computer from which I am transporting them and then importing them into the app. Does that make since? – Nerdy Lime Apps Oct 04 '15 at 23:57
  • 1
    there is no key in this name under info update the answer pls – Kishore Kumar May 06 '16 at 09:20
  • What about if you want to get the name like "18-09-04 14-57-30 1905"? – IndexOutOfDevelopersException Sep 04 '18 at 12:57
  • 1
    @wanttobeprofessional please see updated answer. You can find a date in asset.creationDate property, then format it like you want with (NS)DateFormatter. – Eridana Sep 04 '18 at 13:44
16

One more option is:

[asset valueForKey:@"filename"]

The "legality" of this is up to you to decide.

Leo Natan
  • 55,734
  • 8
  • 140
  • 186
  • 3
    There is no property named 'filename' for PHAsset. How can it work? – Utsav Dusad Jul 05 '16 at 06:50
  • Magic. =] It's a private property, not exposed in public API. It's relatively to use because there are other, public API, properties called `filename`. – Leo Natan Jul 05 '16 at 06:52
  • 1
    @CaseyHancock I think so. Looking at the time the answer was posted, it was _most likely_ tested on iOS 8. Make sure to test in order to be sure. – Leo Natan Mar 27 '17 at 21:51
13

Easiest solution for iOS 9+ in Swift 4 (based on skims answer):

extension PHAsset {
    var originalFilename: String? {
        return PHAssetResource.assetResources(for: self).first?.originalFilename
    }
}
d4Rk
  • 6,007
  • 5
  • 40
  • 54
2

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
        }
    })
}
Bartłomiej Semańczyk
  • 52,820
  • 43
  • 206
  • 318
0

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
                }
            })
        }
Ahmad Labeeb
  • 784
  • 7
  • 15
-1

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

Avi Levin
  • 1,798
  • 21
  • 32