iOS : How to convert a video PHAsset to NSData - ios

I want to put the videos stored on my iPhone to my Google Drive.
I have already done with images, but with videos, it's an other problem...
For images, no problem, I convert my asset to an NSData with this method :
data = UIImagePNGRepresentation(result!)!
And I put the image to my drive !
But, for videos, I tried many different ways, but no, I can't.
How can I do ?
Thanks a lot !

I did it !
This is the solution :
PHCachingImageManager().requestAVAssetForVideo(asset, options: nil, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [NSObject : AnyObject]?) in
dispatch_async(dispatch_get_main_queue(), {
let asset = asset as? AVURLAsset
var data = NSData(contentsOfURL: asset.URL)
})
})
And after, you have the good NSData variable which you can use to put your video to the Cloud !

Please add Bellow solution its work for me
if you miss option.isNetworkAccessAllowed = true then you get error for genera the url
private let options: PHVideoRequestOptions = PHVideoRequestOptions()
option.isNetworkAccessAllowed = true
PHImageManager.default().requestAVAsset(-------

Updated for Swift 5
PHImageManager or PHCachingImageManager can be used here
PHImageManager.default().requestAVAsset(forVideo: asset,
options: nil) { (asset, audioMix, info) in
if
let asset = asset as? AVURLAsset,
let data = NSData(contentsOf: asset.url) {
//do smth with data
}
}
}

Fetch synchronously Image/Video Swift 5 + caching
extension PHAsset {
func getImage() -> UIImage? {
let manager = PHCachingImageManager.default
let option = PHImageRequestOptions()
option.isSynchronous = true
var img: UIImage? = nil
manager().requestImage(for: self, targetSize: CGSize(width: self.pixelWidth, height: self.pixelHeight), contentMode: .aspectFit, options: nil, resultHandler: {(result, info) -> Void in
img = result!
})
return img
}
func getVideo() -> NSData? {
let manager = PHCachingImageManager.default
let option = PHImageRequestOptions()
option.isSynchronous = true
var resultData: NSData? = nil
manager().requestAVAsset(forVideo: self, options: nil) { (asset, audioMix, info) in
if let asset = asset as? AVURLAsset, let data = NSData(contentsOf: asset.url) {
resultData = data
}
}
return resultData
}
}

Related

iOS Photos library - how to get the REAL filename?

I am looking for either a Swift or Objective C solution for this. Here, I am showing my example using swift.
I am using the Photos framework on iOS and having a hard time finding the REAL filename instead of the IMG_4227.JPG type. The name of my image is actually myawesomefilename.jpg and I see this file name if I airdrop or transfer to dropbox the image from my iPhone. But when I use the Photos framework, I get the names as IMG_4227.JPG.
There is an app on the app store which is able to get the real file names of all images, so it is definitely possible. I just don't know how.
Here's how I am currently getting the IMG_4227.JPG type names:
func exifTapped(asset: PHAsset) {
print("name: \(asset.value(forKey: "filename"))")
getURL(ofPhotoWith: asset) { (url) in
print("URL: \(url)")
let data = NSData.init(contentsOf: url!)!
if let imageSource = CGImageSourceCreateWithData(data, nil) {
let imageProperties2 = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)! as NSDictionary
print("imageProperties2: ", imageProperties2)
}
}
}
func getURL(ofPhotoWith mPhasset: PHAsset, completionHandler : #escaping ((_ responseURL : URL?) -> Void)) {
if mPhasset.mediaType == .image {
let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
options.isNetworkAccessAllowed = true
options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
return true
}
mPhasset.requestContentEditingInput(with: options, completionHandler: { (contentEditingInput, info) in
completionHandler(contentEditingInput!.fullSizeImageURL)
})
} else if mPhasset.mediaType == .video {
let options: PHVideoRequestOptions = PHVideoRequestOptions()
options.version = .original
options.isNetworkAccessAllowed = true
PHImageManager.default().requestAVAsset(forVideo: mPhasset, options: options, resultHandler: { (asset, audioMix, info) in
if let urlAsset = asset as? AVURLAsset {
let localVideoUrl = urlAsset.url
completionHandler(localVideoUrl)
} else {
completionHandler(nil)
}
})
}
}
EDIT: None of the duplicate solutions are any different than what I already have and they all give the IMG_4227.JPG type names instead of the real name. So this is not a duplicate.
I figured it out.
let resources = PHAssetResource.assetResources(for: asset)
print("Filename: \((resources.first as! PHAssetResource).originalFilename)")

Pass url of image from Local Library

I am trying to display an image from the local library in another view using its url like so...
let myImgObj = messagesFromTheDisk[indexPath.row].images
print(myImgObj)
print(myImgObj[0].url)
Printing myImgObj gives [MyApp.ProductImage(url: assets-library://asset/asset.PNG?id=A636DA16-8C7C-4CC5-ADB3-E944DC24BDA1&ext=PNG)] and printing myImgObj[0].url gives assets-library://asset/asset.PNG?id=A636DA16-8C7C-4CC5-ADB3-E944DC24BDA1&ext=PNG
But when I try to show display this image its showing as null though there seems to be an url. I'm using the library SDWebImage to display the image like so...
cell.productImageView.sd_setImage(with: myImgObj[0].url, placeholderImage:UIImage(named: "sampleImg"))
What am I doing wrong...?
I set the image libary url nil and use the contentsOfFile to not catche the images in the disk so that immediate loading of images will be implemented and it works.However you must put the images not in .xcassettes folder but a separate group folder.
let bundlePath = Bundle.main.path(forResource: myImgObj, ofType: "jpg")
imageView.sd_setImage(with: nil, placeholderImage: UIImage(contentsOfFile: bundlePath!))
This is without SDWebImage as I don't it need for PHAssets. I am fetching assests from library from my custom album like this :
func fetchCustomAlbumPhotos( completion : (_ array : [PHAsset]) -> Void)
{
var assetCollection = PHAssetCollection()
var photoAssets = PHFetchResult<AnyObject>()
var arrayOfPHAsset = [PHAsset]()
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", CustomAlbum.albumName)
let collection:PHFetchResult = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
if let _:AnyObject = collection.firstObject{
assetCollection = collection.firstObject!
}else {
completion([])
}
_ = collection.count
photoAssets = PHAsset.fetchAssets(in: assetCollection, options: nil) as! PHFetchResult<AnyObject>
photoAssets.enumerateObjects({(object: AnyObject!,
count: Int,
stop: UnsafeMutablePointer<ObjCBool>) in
if object is PHAsset{
let asset = object as! PHAsset
arrayOfPHAsset.append(asset)
}
})
completion(arrayOfPHAsset)
}
This is how I call it in my ViewController's viewDidLoad() method:
CustomAlbum().fetchCustomAlbumPhotos { (array) in
self.arrayOfPHAsset = array
self.collectionView.reloadData()
}
From that function i get arrayOfPHAsset and this is how I am displaying them in my collection view cellForItemAt method:
let asset : PHAsset = arrayOfPHAsset[indexPath.item]
Or convert your url to PHAsset
self.imageURL = (info[UIImagePickerControllerReferenceURL] as? NSURL)!
let asset = PHAsset.fetchAssetsWithALAssetURLs([imageUrl], options: nil).firstObject as! PHAsset
And request Image for that PHAsset
if asset.mediaType == .video{
cell.videoIndicatorImage.isHidden = false
}
cell.userImagesStoredInAlbum.alpha = 0
let imageSize = CGSize(width: asset.pixelWidth,height: asset.pixelHeight)
DispatchQueue.main.async {
PHImageManager.default().requestImage(for: asset, targetSize: imageSize, contentMode: .aspectFill, options: nil, resultHandler: {(result, info)in
if result != nil {
cell.userImagesStoredInAlbum.image = result
UIView .animate(withDuration: 0.5, delay: 0, options: .curveEaseIn, animations: {
cell.userImagesStoredInAlbum.alpha = 1
}, completion: { (succes) in
})
}
})
}

how to get image from PHImageFileURLKey

guys.
I am getting images URL from photos by using below code.
func getAllImagesURL() -> [URL]
{
var arr_URL = [URL]()
for index in 0..<fetchResult.count
{
imgManager.requestImageData(for: fetchResult.object(at: index) as PHAsset, options: requestOptions, resultHandler: { (imagedata, dataUTI, orientation, info) in
if let fileName = (info?["PHImageFileURLKey"] as? URL)
{
//do sth with file name
arr_URL.append(fileName)
}
})
}
return arr_URL
}
By using this URL key I want to get the image from photos.I have searched and found below code.But it still not working.
func getImage(assetUrl: URL) -> UIImage? {
let asset = PHAsset.fetchAssets(withALAssetURLs: [assetUrl], options: nil)
guard let result = asset.firstObject else {
return nil
}
var assetImage: UIImage?
let options = PHImageRequestOptions()
options.isSynchronous = true
PHImageManager.default().requestImage(for: result, targetSize: UIScreen.main.bounds.size, contentMode: PHImageContentMode.aspectFill, options: options) { image, info in
assetImage = image
}
return assetImage
}
It returns nil.So please help me.How to get the image by using URL key.
Thanks in Advance..
In the getImage(assetUrl: URL) -> UIImage? method, you are using
let asset = PHAsset.fetchAssets(withALAssetURLs: [assetUrl], options: nil)
here assetUrl is the url that should be taken from if you are using the AssetsLibrary. This library is deprecated from iOS 9.0 onwards. We have to use Photos library instead.
BTW, you are already getting all the images(data) in getAllImageURLs() method. Just convert that method to get all the images and process those images as required. You can use the below method to get all the images.
func getAllImages() -> [UIImage]?
{
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: true)]
let fetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions)
var allImages = [UIImage]()
for index in 0..<fetchResult.count
{
let asset = fetchResult.object(at: index) as PHAsset
imgManager.requestImage(for: asset, targetSize: UIScreen.main.bounds.size, contentMode: .aspectFill, options: requestOptions, resultHandler: { (uiimage, info) in
allImages.append(uiimage!)
})
}
return allImages
}
NOTE: tweak this method as per your requirements.

How to upload PHAssets in background

In Objective-C I want to upload all PHAssets (images and videos) to my server in background. Can any please suggest me how can I do this?
let mPhasset : PHAsset = PHAsset()
if mPhasset.mediaType == .image {
let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
return true
}
mPhasset.requestContentEditingInput(with: options, completionHandler: {(contentEditingInput: PHContentEditingInput?, info: [AnyHashable: Any]) -> Void in
if let url = contentEditingInput?.fullSizeImageURL {
// IMPORTANT
// this url avaiable only in this block
// we can't perform async operation in bg
// cause access will expired
// Now you can copy using FileManager
// and after this upload copied file
}
})
// Alternative
let imageManager = PHCachingImageManager()
let opt = PHImageRequestOptions()
opt.resizeMode = .exact
opt.deliveryMode = .highQualityFormat
imageManager.requestImage(for: mPhasset,
targetSize: CGSize(width: mPhasset.pixelWidth, height: mPhasset.pixelHeight),
contentMode: .aspectFill,
options: opt,
resultHandler:
{ (image: UIImage?, _) in
// now you can go to background and do whatever you want
// benefit that you don't need to copy file in main thread
// which can lag your app
// disadvantage of this method: we load image in memory
})
} else if mPhasset.mediaType == .video {
let options: PHVideoRequestOptions = PHVideoRequestOptions()
options.version = .current
PHImageManager.default().requestExportSession(forVideo: mPhasset, options: options, exportPreset: AVAssetExportPresetHighestQuality, resultHandler: { (session, info) in
// if we just request video url asset and try upload to server
// we will have problems with slow mo videos
// also we will be on the main thread and access for video will expire, if we go to background
// + size of video is very huge
guard let session = session else { return }
session.outputURL = URL(fileURLWithPath: "our output path")
session.outputFileType = AVFileTypeQuickTimeMovie
session.shouldOptimizeForNetworkUse = true
session.exportAsynchronously {
if (session.status == .completed) {
// success
} else {
}
}
})
}

How to get image metadata in iOS 9 using Photos Framework

I want to display image metadata using UIImagePickerController in Swift.
where the image is been selected from gallery and would be displayed in the imageView along with the meta data such as PixelHeight,PixelWidth,PixelXDimension,PixelYDimension,Coordinates,Size,Date Created and Imagename.
At first, you can get info[UIImagePickerControllerReferenceURL] from UIImagePickerController. Then you can do things like the following:
let assetURL = info[UIImagePickerControllerReferenceURL] as! NSURL
let asset = PHAsset.fetchAssetsWithALAssetURLs([assetURL], options: nil)
guard let result = asset.firstObject where result is PHAsset else {
return
}
let imageManager = PHImageManager.defaultManager()
imageManager.requestImageDataForAsset(result as! PHAsset, options: nil, resultHandler:{
(data, responseString, imageOriet, info) -> Void in
let imageData: NSData = data!
if let imageSource = CGImageSourceCreateWithData(imageData, nil) {
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)! as NSDictionary
//now you have got meta data in imageProperties, you can display PixelHeight, PixelWidth, etc.
}
})

Resources