I surely hope I am missing something because I do not understand why this is working the way it does. I have a PNG Image, which has a fully transparent background because I
Yes, the call to UIImageJPEGRepresentation
will convert the resulting image into a JPEG, which doesn't support transparency.
BTW, if your intent is to get the NSData
for the image for other reasons (e.g. uploading to server, emailing, etc.), I would recommend against both UIImageJPEGRepresentation
and UIImagePNGRepresentation
. They lose meta data, can make the asset larger, if suffer some image degradation if you use quality factor of less than 1, etc.
Instead, I'd recommend going back and get the original asset from the Photos framework. Thus, in Swift 3:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let url = info[UIImagePickerControllerReferenceURL] as? URL {
let result = PHAsset.fetchAssets(withALAssetURLs: [url], options: nil)
if let asset = result.firstObject {
let manager = PHImageManager.default()
manager.requestImageData(for: asset, options: nil) { imageData, dataUTI, orientation, info in
if let fileURL = info!["PHImageFileURLKey"] as? URL {
let filename = fileURL.lastPathComponent
// use filename here
}
// use imageData here
}
}
}
picker.dismiss(animated: true)
}
If you have to support iOS 7, too, you'd use the equivalent ALAssetsLibrary
API, but the idea is the same: Get the original asset rather than round-tripping it through a UIImage
.
(For Swift 2 rendition, see previous revision of this answer.)
Swift 3 version of answer by @Rob
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let URL = info[UIImagePickerControllerReferenceURL] as? NSURL {
let result = PHAsset.fetchAssets(withALAssetURLs: [URL as URL], options: nil)
if let asset:PHAsset = result.firstObject! as PHAsset {
let manager = PHImageManager.default()
manager.requestImageData(for: asset, options: nil) { imageData, dataUTI, orientation, info in
let fileURL = info!["PHImageFileURLKey"] as? NSURL
let filename = fileURL?.lastPathComponent;
// use imageData here
}
}
}
picker.dismiss(animated: true, completion: nil)
}
An alternative solution uses the PHAssetResourceManager rather than PHImageManager. Using Xcode 10, Swift 4.2.
func imageFromResourceData(phAsset:PHAsset) {
let assetResources = PHAssetResource.assetResources(for: phAsset)
for resource in assetResources {
if resource.type == PHAssetResourceType.photo {
var imageData = Data()
let options = PHAssetResourceRequestOptions()
options.isNetworkAccessAllowed = true
let _ = PHAssetResourceManager.default().requestData(for: resource, options: options, dataReceivedHandler: { (data:Data) in
imageData.append(data)
}, completionHandler: { (error:Error?) in
if error == nil, let picked = UIImage(data: imageData) {
self.handlePickedImage(picked: picked)
}
})
}
}
}
Use it like this:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
dismiss(animated: true)
let mediaType = info[UIImagePickerController.InfoKey.mediaType] as! NSString
if mediaType == kUTTypeImage || mediaType == kUTTypeLivePhoto {
if #available(iOS 11.0, *) {
if let phAsset = info[UIImagePickerController.InfoKey.phAsset] as? PHAsset {
self.imageFromResourceData(phAsset: phAsset)
}
else {
if let picked = (info[UIImagePickerController.InfoKey.originalImage] as? UIImage) {
self.handlePickedImage(picked: picked)
}
}
}
else if let picked = (info[UIImagePickerController.InfoKey.originalImage] as? UIImage) {
self.handlePickedImage(picked: picked)
}
}
}