16

I want to get the file name from UIImagePickerController. I do not want to use ALAssetLibrary because it is deprecated in iOS 9. I have used the following code but it always returns the image name as "Asset.jpg" for each file.

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {       
    let originalImage = (info[UIImagePickerControllerOriginalImage] as? UIImage)!
    let url = info[UIImagePickerControllerReferenceURL] as! NSURL
    imageData = UIImageJPEGRepresentation(originalImage, 100) as NSData?
    let data = UploadData()
    data.fileName = url.lastPathComponent     
    picker.dismiss(animated: true, completion: nil)
}
shim
  • 9,289
  • 12
  • 69
  • 108
TechChain
  • 8,404
  • 29
  • 103
  • 228

17 Answers17

25
import Photos

Before iOS 11

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let imageURL = info[UIImagePickerControllerReferenceURL] as? URL {
        let result = PHAsset.fetchAssets(withALAssetURLs: [imageURL], options: nil)
        let assetResources = PHAssetResource.assetResources(for: result.firstObject!)

        print(assetResources.first!.originalFilename)
    }

    dismiss(animated: true, completion: nil)
}

After iOS 11

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let asset = info[UIImagePickerController.InfoKey.phAsset.rawValue] as? PHAsset {
    let assetResources = PHAssetResource.assetResources(for: asset)
    print(assetResources.first!.originalFilename)
  }
    dismiss(animated: true, completion: nil)
}
Damien D.
  • 251
  • 3
  • 5
  • 2
    Not able to get the URL back when the user opens the camera in my app, records a video, and then tries to use that. Any ideas? – Akash Kundu Dec 13 '19 at 07:57
  • Using the camera from within an iOS app does not save the resulting image to the photo gallery. It therefore has no local asset identifier. You'll have to grab the image from the info dictionary using the `originalImage` key and manually save it yourself. – Ash Nov 25 '22 at 11:08
23

I will suggest you to use Photos Framework to get the name of the image, below is the code to get name of selected image

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)
}
Nirav D
  • 71,513
  • 12
  • 161
  • 183
Rajat
  • 10,977
  • 3
  • 38
  • 55
18

Here is how I did it in swift 4

if let url = info[UIImagePickerController.InfoKey.imageURL] as? URL {
        fileName = url.lastPathComponent
        fileType = url.pathExtension
    }
Gulfam Khan
  • 1,010
  • 12
  • 23
6

Update 6th May 2018

Forced unwrapped optionals sometimes return nil, I think it's because user use Camera to capture a new image instead of selecting one from Photos library. I updated the code to return a generated name when I see nil.

Original answer

This works for me without having to rely on filename key (please excuse for force unwrap optionals :) )

extension MyViewController : UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        guard let image = info[UIImagePickerControllerEditedImage] as? UIImage else {
            DDLogDebug("No image chosen")
            return
        }

        if let url = info[UIImagePickerControllerReferenceURL] as? URL {
            let assets = PHAsset.fetchAssets(withALAssetURLs: [url], options: nil)
            if let firstAsset = assets.firstObject,
            let firstResource = PHAssetResource.assetResources(for: firstAsset).first {
                fileName = firstResource.originalFilename
            } else {
                fileName = generateNameForImage()
            }
        } else {
            fileName = generateNameForImage()
        }

        DDLogDebug("File name = \(fileName)")

        dismiss(animated: true)
    }

    func generateNameForImage() -> String {
        return "IMG_random_string"
    }

}
Vinoth Vino
  • 9,166
  • 3
  • 66
  • 70
Yaiba
  • 571
  • 7
  • 14
  • how to get extension of the image? – Ishika Apr 02 '18 at 05:40
  • @Ishika Sorry for late answer, you can check this question, it shows multiple way to get file name/extension: [How to split filename from file extension in Swift?](https://stackoverflow.com/questions/26707352/how-to-split-filename-from-file-extension-in-swift) – Yaiba Apr 18 '18 at 15:38
  • @Nij can you elaborate what issue did you have? thanks – Yaiba May 05 '18 at 10:45
  • This line of code giving nil value 'let fileName = PHAssetResource.assetResources(for: assets.firstObject!).first!.originalFilename' – Neeraj Joshi May 05 '18 at 12:13
  • @Nij Now I remember that it sometimes returns `nil`. I think it's due to user selects Camera to capture a new image instead of selecting an image from Photos library (correct me if I'm wrong). To fix that I have to check for `nil` of those forced unwrapped optionals then return a generated name instead when I see nil. I'll update the answer. Thanks – Yaiba May 06 '18 at 02:58
  • Thanks for your concern. I am only selecting photo library images. – Neeraj Joshi May 07 '18 at 04:58
  • @Nij thanks for your info, I don't work on that project anymore so I don't have time to investigate it further now. Anyway I think you can still use my solution as a safety guard for `nil` issue. If you find the cause please feel free to add a comment and I'll update my answer. Cheers. – Yaiba May 07 '18 at 07:58
  • fetchAssets always returns 0 assets – Sujit Baranwal May 29 '18 at 06:38
  • 1
    UIImagePickerControllerReferenceURL is deprecated – zeus Oct 05 '18 at 09:19
  • @Appincuba to get the extension, call this on the filename: `.split(separator: ".").last` – Ken Mueller Jun 19 '19 at 01:45
5

Swift 5, iOS 11+

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    let photo = info[.phAsset] as? PHAsset
    let filename = photo?.value(forKey: "filename") as! String
}
FunkyKat
  • 3,233
  • 1
  • 23
  • 20
4
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    var selectedFileName = ""
    if #available(iOS 11.0, *) {
        if let imageUrl = info[.imageURL] as? URL {
            selectedFileName = imageUrl.lastPathComponent
        }
    } else {
        if let imageURL = info[.referenceURL] as? URL {
            let result = PHAsset.fetchAssets(withALAssetURLs: [imageURL], options: nil)
            if let firstObject = result.firstObject {
                let assetResources = PHAssetResource.assetResources(for: firstObject)
                selectedFileName = assetResources.first?.originalFilename
            }
        }
    }

    picker.dismiss(animated: true, completion: nil)
}
iOS Developer
  • 464
  • 6
  • 24
luhuiya
  • 2,129
  • 21
  • 20
4

This code is working for me (Swift 5):

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    if let imgUrl = info[UIImagePickerController.InfoKey.imageURL] as? URL{
        let imgName = imgUrl.lastPathComponent
        let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
        let localPath = documentDirectory?.appending(imgName)

        let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
        let data = image.pngData()! as NSData
        data.write(toFile: localPath!, atomically: true)
        let photoURL = URL.init(fileURLWithPath: localPath!)
        let filename = photoURL.lastPathComponent
        print(filename)
       }
    picker.dismiss(animated: true, completion: nil)
}
Md. Shofiulla
  • 2,135
  • 1
  • 13
  • 19
2

You can try this for iOS 11

 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let asset = info[UIImagePickerControllerPHAsset] as? PHAsset {
        if let fileName = (asset.value(forKey: "filename")) as? String {
            //Do your stuff here
        }
    }

    picker.dismiss(animated: true, completion: nil)
}

Make sure you add this NSPhotoLibraryUsageDescription to your Infor.plist

Tony TRAN
  • 2,118
  • 1
  • 15
  • 16
1

Code:

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
    let imageURL = info[UIImagePickerControllerReferenceURL] as NSURL
    let imageName = imageURL.path!.lastPathComponent
    let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String
    let localPath = documentDirectory.stringByAppendingPathComponent(imageName)
    let image = info[UIImagePickerControllerOriginalImage] as UIImage
    let data = UIImagePNGRepresentation(image)
    data.writeToFile(localPath, atomically: true)
    let imageData = NSData(contentsOfFile: localPath)!
    let photoURL = NSURL(fileURLWithPath: localPath)
    let imageWithData = UIImage(data: imageData)!
    picker.dismissViewControllerAnimated(true, completion: nil)
}
Community
  • 1
  • 1
Hitesh Surani
  • 12,733
  • 6
  • 54
  • 65
1

import Photos

func getFileName(info: [String : Any]) -> String {

    if let imageURL = info[UIImagePickerControllerReferenceURL] as? URL {
        let result = PHAsset.fetchAssets(withALAssetURLs: [imageURL], options: nil)
        let asset = result.firstObject
        let fileName = asset?.value(forKey: "filename")
        let fileUrl = URL(string: fileName as! String)
        if let name = fileUrl?.deletingPathExtension().lastPathComponent {
        print(name)
        return name
        }
    }
    return ""

}

call it inside the method "didFinishPickingMediaWithInfo" like so:

let fileName = getFileName(info: info)
Bassant Ashraf
  • 1,531
  • 2
  • 16
  • 23
  • i implemented same method in result it gives following count=0 in asset = nil in fileName = nil and crash at fileUrl because nil is there – Ahmad Qasim Sep 03 '18 at 16:43
  • have you a another solution one more thing i am testing it on simulator i'm unable to get file name have you any idea – Ahmad Qasim Sep 03 '18 at 16:45
1

I came cross this question when searching for a way to retrieve filename from UIImagePickerController.

I tried all the methods mentioned in the answers, but the results were inconsistent.

As one novice iOS developer my self, I will not try to detail the mechanism between those ways. Instead I will demo my findings.

Note: all under iOS 13 with Swift 5.

The first way, which I don't think it's the really file name because it keeps changing. I guess this is the local path name because image picker saves the image to your app's temporary directory.

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
  guard let url = info[.imageURL] as? NSURL else { return }
  let filename = url.lastPathComponent!
  print(filename) // 46484E68-94E8-47B7-B0F4-E52EA7E480A9.jpeg
}

The second way, which is consitent each time I select it. I think it can be used as file name but not flawless.

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
  let photo = info[.phAsset] as? PHAsset
  var filename = photo?.value(forKey: "filename") as? String ?? ""
  print(filename) // IMG_0228.JPG
}

The third way gets you the original file name, which is the file name you see in your Mac. Say you AirDrop one photo with name "Apple.jpg" to your phone, only with this way will you get the name "Apple.jpg"

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
  let photo = info[.phAsset] as? PHAsset
  let res = PHAssetResource.assetResources(for: photo!)
  let filename = res[0].originalFilename
  print(filename) // Apple.jpg
}
francisfeng
  • 704
  • 1
  • 8
  • 22
1

for iOS 11 and above

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        // get imageURL and asset
        if let asset = info[UIImagePickerController.InfoKey.phAsset] as? PHAsset, let imageURL = info[UIImagePickerController.InfoKey.imageURL] as? URL{
            // got asset and imageURL
        } else {
            // show error
        }
        dismiss(animated: true, completion: nil)
    }
Giang
  • 2,384
  • 2
  • 25
  • 26
0
    let fileName = (info[.imageURL] as? URL)?.lastPathComponent
  • 2
    Code only answers are generally considered low quality. Could you add an explanation to your answer. – Lemon Kazi Oct 30 '19 at 03:12
  • What is the difference between name obtained from below approaches- Approach 1 by @FunkyKat : func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { let photo = info[.phAsset] as? PHAsset let filename = photo?.value(forKey: "filename") as! String } Approach 2 by Khaled: let fileName = (info[.imageURL] as? URL)?.lastPathComponent – Ashutosh Shukla Jul 31 '20 at 05:52
0

i wanted the name of image and tried it, this worked for me hope it work for you as well, you can use phAsset object from uiimagepickercontroller before that PHPhotoLibrary permission is required Note:- before this.......** import Photos **

PHPhotoLibrary.requestAuthorization { (status) in
        switch status {
            
        case .notDetermined:
            break
        case .restricted:
            break
        case .denied:
            break
        case .authorized:
            if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {                      
                    let imagePickerController = UIImagePickerController()
                    imagePickerController.delegate = self;
                    imagePickerController.sourceType = .photoLibrary
                    
                    let cancelButtonAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
                    UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes , for: .normal)
                    
                    imagePickerController.modalPresentationStyle = .fullScreen
                    self.present(imagePickerController, animated: true, completion: nil)
                    
                }
            }
        @unknown default:
            fatalError()
        }
    }

implement delegate methods of uiimagepicker and add following inside didFinishPickingMediaWithInfo:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    
    if (info[UIImagePickerController.InfoKey.originalImage] as? UIImage) != nil {

      if let photoObj = (info[UIImagePickerController.InfoKey.phAsset] as? PHAsset) {
          let photoName = pHObjc.localIdentifier 
    // returns local photo id which will be unique for each photo
     }
   }
}
Uzef Shaikh
  • 636
  • 6
  • 11
0

If you are using iOS 15+, you will not be able to get the image url from a picture taken from the camera because the UIImagePickerController.InfoKey.referenceURL key is deprecated since iOS 11, so this is the only solution I found:

First, you need to create an image format enum:

enum ImageFormat: String {
    case png = ".png"
    case jpeg = ".jpeg"
    case gif = ".gif"
    case tiff = ".tiff"
    case unknown = ""

    init(byte: UInt8) {
        switch byte {
        case 0x89:
            self = .png
        case 0xFF:
            self = .jpeg
        case 0x47:
            self = .gif
        case 0x49, 0x4D:
            self = .tiff
        default:
            self = .unknown
        }
    }
}

Then you need this Data extension property:

extension Data {
    var imageFormat: ImageFormat {
        guard let header = map({ $0 as UInt8 })[safe: 0] else {
            return .unknown
        }

        return ImageFormat(byte: header)
    }
}

And finally:

// MARK: - UIImagePickerControllerDelegate

func imagePickerController(_ picker: UIImagePickerController,
                               didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
    guard let image = info[.editedImage] as? UIImage else {
        return
    }

    var imageName: String?
    let data = image.jpegData(compressionQuality: 1)

    if let imgUrl = info[UIImagePickerController.InfoKey.imageURL] as? URL {
        // If the user pick the picture from the photo library
        imageName = imgUrl.lastPathComponent
    } else if let metaData = info[UIImagePickerController.InfoKey.mediaMetadata] as? [String: Any],
              let tiff = metaData["{TIFF}"] as? [String: Any],
              let dateTime = tiff["DateTime"],
              let imageFormat = data?.imageFormat {
        // If the user take the photo from the camera
        imageName = "\(dateTime)\(imageFormat.rawValue)"
    }

    print(imageName!)

    // don't forget to dismiss the picker controller
}
pableiros
  • 14,932
  • 12
  • 99
  • 105
-1
  func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { 

         if let asset = PHAsset.fetchAssets(withALAssetURLs: [info[UIImagePickerControllerReferenceURL] as! URL],options: nil).firstObject {              

            var resources = PHAssetResource.assetResources(for: asset)

            let orgFilename: String = ((resources[0] as? PHAssetResource)?.originalFilename)!

            print("filename:",orgFilename)
     }
    }
Srinivasan.M
  • 257
  • 2
  • 4
  • 5
    Welcome to stackoverflow. Simply posting some code isn't terribly helpful. Can you explain your code? That way others can understand and learn from your answer instead of just copying & pasting some code from the web. Also, does your code use that ALAssetLibrary? (Just guessing from `withALAssetURLs`.) The question states explicitly that that library should not be used. – Robert Sep 12 '18 at 17:24
-1

For me, it is working perfect,

if let imgUrl = info[UIImagePickerControllerImageURL] as? URL{
   let imgName = imgUrl.lastPathComponent
   print(imgName)
   let imgExtension = imgUrl.pathExtension
   print(imgExtension)
}
Hilaj S L
  • 1,936
  • 2
  • 19
  • 31