TechChain
TechChain

Reputation: 8944

How to get file name in UIImagePickerController with Asset library?

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)
}

Upvotes: 16

Views: 44662

Answers (17)

pableiros
pableiros

Reputation: 16032

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
}

Upvotes: 0

Damien D.
Damien D.

Reputation: 251

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)
}

Upvotes: 25

Giang
Giang

Reputation: 2729

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)
    }

Upvotes: 1

Md. Shofiulla
Md. Shofiulla

Reputation: 2305

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)
}

Upvotes: 4

Uzef Shaikh
Uzef Shaikh

Reputation: 744

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
     }
   }
}

Upvotes: 0

francisfeng
francisfeng

Reputation: 808

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
}

Upvotes: 1

luhuiya
luhuiya

Reputation: 2211

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)
}

Upvotes: 4

FunkyKat
FunkyKat

Reputation: 3223

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
}

Upvotes: 5

Khaled Khaldi
Khaled Khaldi

Reputation: 111

    let fileName = (info[.imageURL] as? URL)?.lastPathComponent

Upvotes: 0

Gulfam Khan
Gulfam Khan

Reputation: 1089

Here is how I did it in swift 4

if let url = info[UIImagePickerController.InfoKey.imageURL] as? URL {
        fileName = url.lastPathComponent
        fileType = url.pathExtension
    }

Upvotes: 19

Hitesh Surani
Hitesh Surani

Reputation: 13537

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)
}

Upvotes: 1

Hilaj S L
Hilaj S L

Reputation: 2046

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)
}

Upvotes: -1

Yaiba
Yaiba

Reputation: 601

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"
    }

}

Upvotes: 6

Srinivasan.M
Srinivasan.M

Reputation: 267

  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)
     }
    }

Upvotes: -1

Tony TRAN
Tony TRAN

Reputation: 2178

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

Upvotes: 2

Bassant Ashraf
Bassant Ashraf

Reputation: 1609

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)

Upvotes: 1

Rajat
Rajat

Reputation: 11127

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)
}

Upvotes: 23

Related Questions