I am trying to get file name from PHAsset
reference provided by UIImagePickerController
,How do I retrieve the image file name when choose from library and take photo with camera?
I am using Xcode 11.4 and Swift 5.
I am trying to get file name from PHAsset
reference provided by UIImagePickerController
,How do I retrieve the image file name when choose from library and take photo with camera?
I am using Xcode 11.4 and Swift 5.
Given, you already have the PHAsset object, PHAssetResource is what you need to work retrieve the filename.
let assetResources = PHAssetResource.assetResources(for: asset)
This will return you an array of PHAssetResource
instances, among which one of them is the current image.
Inspecting the PHAssetResource instances on the debugger, you can see it contains multiple files. This may include adjustment data, represented by .plist, and one or more photos.
To get the file that is currently accessible, what you need to look for is a key isCurrent
. Apple hasn't exposed this key as a variable for PHAssetResource, however, they don't take any effort hiding the value. And I assume, querying this value doesn't result in an app rejection.
You can query this value directly, or can do it more cleanly by extending PHAssetResource.
extension PHAssetResource {
var isCurrent: Bool? {
self.value(forKey: "isCurrent") as? Bool
}
}
Now, you can ask the [PHAssetResource]
, for the first item that isCurrent
as well as a photo or video.
let resourceTypes: [PHAssetResourceType] = [.photo, .video, .audio, .fullSizePhoto]
let currentAssetResource = assetResources.first(
where: { $0.isCurrent == true && resourceTypes.contains($0.type)
})
And, finally for the filename.
let fileName = currentAssetResource?.originalFilename
Note
PhotoKit expects the developer to work with the abstract asset resource, and not to deal with the underlying files or data. The usage of isCurrent
seems to be allowed. However, the value can be altered or removed with an iOS update. Do it only if you have a strong use-case for extracting the filename.
There are two approaches:
You can retrieve the URL of the temporary file that UIImagePickerController
creates for you using info[.imageURL]
. If you only need, for example, the extension of the asset, this is sufficient.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
// url of temporary file provided by image picker
if let url = info[.imageURL] as? URL {
print("temp URL", url) // file:///private/var/mobile/Containers/Data/Application/.../tmp/FAC0D82B-85A9-4C7A-B69C-58BB53F74CDC.jpeg
}
dismiss(animated: true)
}
But the filename, itself, bears no relationship to the original asset.
You can retrieve the original asset URL from the Photos
framework. We used to be able to use PHImageManager
, call requestImageDataForAsset
, and then use "PHImageFileURLKey"
in the resulting info dictionary, but that doesn’t work anymore.
But as suggested elsewhere, you can asset.requestContentEditingInput
, and that includes the URL of the asset:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
// url of the original asset
if let asset = info[.phAsset] as? PHAsset {
asset.requestContentEditingInput(with: nil) { input, info in
if let fileURL = input?.fullSizeImageURL {
print("original URL", fileURL) // file:///var/mobile/Media/DCIM/100APPLE/IMG_0135.HEIC
}
}
}
dismiss(animated: true)
}
If you do this, you obviously need to request permissions for the photos library, notably:
if PHPhotoLibrary.authorizationStatus() == .notDetermined {
PHPhotoLibrary.requestAuthorization { granted in
print(granted)
}
}
And you need to supply a NSPhotoLibraryUsageDescription
usage string in your Info.plist
.
Personally, it feels wrong to request content editing input when you don’t really need to edit, but AFAIK, that’s the only way to get the original asset name nowadays. (There’s got to be a better way: If you browse the PHAsset
in the debugger, the asset name is actually buried in there, but not exposed ... maybe they did that to avoid confusion with the HEIC
extension.)
Bottom line, it just depends upon what you need the name for. If you just need the path for the temporary file, then use .imageURL
. If you need information about the original asset, use .phAsset
and the Photos/PhotoKit framework.