How to get file name in UIImagePickerController with Asset library?
Asked Answered
C

17

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)
}
Clie answered 16/11, 2016 at 9:6 Comment(0)
N
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)
}
Nowise answered 16/11, 2016 at 9:33 Comment(3)
PHAsset.fetchAssets(withALAssetURLs: [imageURL], options: nil) is deprecated in iOS 11. Do you have a replacement?Repugnant
UIImagePickerControllerReferenceURL is deprecatedBrouhaha
Deprecation note says to use PHPicker. So use PHPickerViewController instead of UIImagePickerController.Anachronous
P
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)
}
Profound answered 8/8, 2018 at 6:57 Comment(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?Hokusai
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.Cuisine
N
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)
}
Nowise answered 16/11, 2016 at 9:33 Comment(3)
PHAsset.fetchAssets(withALAssetURLs: [imageURL], options: nil) is deprecated in iOS 11. Do you have a replacement?Repugnant
UIImagePickerControllerReferenceURL is deprecatedBrouhaha
Deprecation note says to use PHPicker. So use PHPickerViewController instead of UIImagePickerController.Anachronous
W
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
    }
Wicklow answered 22/6, 2019 at 14:1 Comment(0)
V
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"
    }

}
Vasyuta answered 20/4, 2017 at 11:35 Comment(10)
how to get extension of the image?Alurta
@Alurta 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?Vasyuta
@Nij can you elaborate what issue did you have? thanksVasyuta
This line of code giving nil value 'let fileName = PHAssetResource.assetResources(for: assets.firstObject!).first!.originalFilename'Linea
@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. ThanksVasyuta
Thanks for your concern. I am only selecting photo library images.Linea
@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.Vasyuta
fetchAssets always returns 0 assetsShabby
UIImagePickerControllerReferenceURL is deprecatedBrouhaha
@Appincuba to get the extension, call this on the filename: .split(separator: ".").lastCostanzia
D
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
}
Decoration answered 12/3, 2020 at 13:19 Comment(2)
Getting nil into this info[.phAsset] as? PHAsset. Any other solution ?Geomorphology
@available(iOS, introduced: 11.0, deprecated: 100000, message: "Will be removed in a future release, use PHPicker.")Anachronous
N
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)
}
Nephology answered 24/10, 2018 at 3:25 Comment(0)
M
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)
}
Marjorie answered 22/12, 2020 at 12:42 Comment(0)
E
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

Emmeram answered 24/10, 2017 at 8:45 Comment(5)
unable to get file name using your code in ios 11.0.3. any solution?Isreal
Did you add NSPhotoLibraryUsageDescription keyword and value to your Info.plist? Then approve the permission request from your device when the system popup appears.Emmeram
@MangiReddy - have you stated import Photos?Castro
@Castro YesIsreal
@Isreal - I'm having the same issues as you; I thought adding the import solved it, but I was wrong.Castro
A
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)
}
Amoy answered 16/11, 2016 at 9:15 Comment(0)
C
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)
Cramer answered 9/9, 2017 at 22:46 Comment(2)
i implemented same method in result it gives following <PHUnauthorizedFetchResult: 0x600000139140> count=0 in asset = nil in fileName = nil and crash at fileUrl because nil is thereSterilization
have you a another solution one more thing i am testing it on simulator i'm unable to get file name have you any ideaSterilization
G
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
}
Genipap answered 6/8, 2020 at 15:55 Comment(0)
S
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)
    }
Sterner answered 22/2, 2021 at 8:30 Comment(0)
W
0
    let fileName = (info[.imageURL] as? URL)?.lastPathComponent
Witchery answered 29/10, 2019 at 22:6 Comment(2)
Code only answers are generally considered low quality. Could you add an explanation to your answer.Tilt
What is the difference between name obtained from below approaches- Approach 1 by @Decoration : 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)?.lastPathComponentEthaethan
H
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
     }
   }
}
Heartfelt answered 7/12, 2020 at 8:23 Comment(0)
M
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
}
Mychael answered 9/8, 2022 at 22:53 Comment(0)
C
-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)
     }
    }
Checkerboard answered 12/9, 2018 at 12:8 Comment(1)
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.Tarriance
G
-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)
}
Golf answered 24/4, 2019 at 11:34 Comment(1)
Oh really? Starting with UIImagePickerControllerImageURL is Objective-C constant and other code is swiftKimberly

© 2022 - 2024 — McMap. All rights reserved.