I'm using UIImagePickerController to select a video or an image from the user's gallery. With the photos, there's no problem, everything is displayed the way it should be. The problem comes when I'm trying to generate a thumbnail for a video.
Basically, the thumbnail image could end up being displayed upside down or 90 degrees to the left or right. I'm not sure why it happens. Am I missing something or doing something wrong?
extension PostVC : UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let videoUrl = info[UIImagePickerController.InfoKey.mediaURL] as? URL {
if let thumbnail = self.generateThumbnailForImage(videoUrl) {
self.videoUrl = videoUrl
self.photoImageView.image = thumbnail
self.selectedImage = thumbnail
}
}
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
selectedImage = image
photoImageView.image = image
shareButton.isEnabled = true
}
dismiss(animated: true, completion: nil)
}
func generateThumbnailForImage(_ fileUrl: URL) -> UIImage? {
let asset = AVAsset(url: fileUrl)
let imageGenerator = AVAssetImageGenerator(asset: asset)
do {
let thumbnailCGImage = try imageGenerator.copyCGImage(at: CMTimeMake(value: 1, timescale: 10), actualTime: nil) // 1 sec
return UIImage(cgImage: thumbnailCGImage)
} catch let err {
SVProgressHUD.showError(withStatus: err.localizedDescription)
}
return nil
}
}
It seems like setting the imageGenerator.appliesPreferredTrackTransform = true solves this issue.
Related
I'm displaying to the user an image picker to select a video from the gallery. That works, i pass the mediatype ["public.movie"] and all the videos of the gallery are displayed to pick up. When the user picks it i receive in my dellegate:
extension VNInventoryCollectionVC: UIImagePickerControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)
if let pickedImage = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.originalImage)] as? UIImage
{
pickImageCallback?(pickedImage)
}
if let videoURL = info["UIImagePickerControllerReferenceURL"] as? URL
{
print(videoURL)
pickImageCallback?(videoURL)
}
dismiss(animated: true)
}
}
After the callback i'm trying to create a image thumbnail from that video, and that is where i'm not able to do it:
let thumbnail = getThumbnailFrom(path: multimedia.video!)
cell.image.image = thumbnail
The function that generates the thumbnail is:
func getThumbnailFrom(path: URL) -> UIImage? {
do {
print("Video URL: \(path)")
print("Video absolute URL: \(path.absoluteURL)")
//let asset = AVURLAsset(url: path.absoluteURL! , options: nil)
var asset : AVAsset = AVAsset(url: path.absoluteURL) as! AVAsset
let imgGenerator = AVAssetImageGenerator(asset: asset)
imgGenerator.appliesPreferredTrackTransform = true
let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
let thumbnail = UIImage(cgImage: cgImage)
return thumbnail
} catch let error {
print("*** Error generating thumbnail: \(error.localizedDescription)")
return nil
}
}
In the console the video url displayed is:
Video URL: assets-library://asset/asset.MP4?id=84D1CEDD-7AE4-4FE5-897E-47608DC2CFF0&ext=MP4
Video absolute URL: assets-library://asset/asset.MP4?id=84D1CEDD-7AE4-4FE5-897E-47608DC2CFF0&ext=MP4
The displayed error is that is unable to open the file. The line that breaks is:
let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
I suppose the problem is with the url, that i have an assets url and i would require an absolute file path or something like that.
Use UIImagePickerController.InfoKey.mediaURL to key into the info dictionary. UIImagePickerController.InfoKey.referenceURL is deprecated.
func didSelectVideo(at url: URL) {
let asset = AVAsset(url: url)
let generator = AVAssetImageGenerator(asset: asset)
generator.appliesPreferredTrackTransform = true
let cgImage = try! generator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
let thumbnail = UIImage(cgImage: cgImage)
cell.image.image = thumbnail
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
dismiss(animated: true) {
guard let url = info[.mediaURL] as? URL else { return }
self.didSelectVideo(at: url)
}
}
GIFU library using to display a Gif image in UIImageView picked from UIImagePickerController
public func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
let imageUrl = info[.referenceURL] as! NSURL
let imageName = imageUrl.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let photoURL = NSURL(fileURLWithPath: documentDirectory)
let localPath = photoURL.appendingPathComponent(imageName!)
let image = info[.originalImage]as! UIImage
let data = image.jpegData(compressionQuality: 0)
do {
try data?.write(to: localPath!, options: Data.WritingOptions.atomic)
}
catch
{
// Catch exception here and act accordingly
}
self.pickerController(picker, didSelect: data)
}
func didSelect(image: Data?) {
tempImage.prepareForAnimation(withGIFData: image!, loopCount: 3) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
self.tempImage.startAnimating()
})
}
}
Image displaying but not animating, looks image format gets changed after selecting.
You are converting GIF to jpeg data using the following line of code.
let data = image.jpegData(compressionQuality: 0)
Avoid data conversion to JPEG, now(I guess from iOS 13 onwards) native controller does have support for previewing gif file on selection try that.
I am using UIImagePickerController to use my camera like so:
#objc func toggle() {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
//Define UIImagePickerController variable
let imagePicker = UIImagePickerController()
//Assign the delegate
imagePicker.delegate = self
//Set image picker source type
imagePicker.sourceType = .camera
//Allow Photo Editing
imagePicker.allowsEditing = true
//Present camera
UIApplication.topViewController()?.present(imagePicker, animated: true, completion: nil)
}
}
Now I am trying to capture the image taken using the didFinishPickingMediaWithInfo method, I got this example online:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let imageUrl = info[UIImagePickerControllerOriginalImage] as! NSURL
let imageName = imageUrl.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let photoURL = NSURL(fileURLWithPath: documentDirectory)
let localPath = photoURL.appendingPathComponent(imageName!)
let image = info[UIImagePickerControllerOriginalImage]as! UIImage
let data = UIImagePNGRepresentation(image)
do
{
try data?.write(to: localPath!, options: Data.WritingOptions.atomic)
}
catch
{
// Catch exception here and act accordingly
}
UIApplication.topViewController()?.dismiss(animated: true, completion: nil);
}
But I changed UIImagePickerControllerReferenceURL to UIImagePickerControllerOriginalImage as UIImagePickerControllerReferenceURL is nil. but after I change that I get this fatal error:
Could not cast value of type 'UIImage' (0x1b6b02b58) to 'NSURL'
How do I save the image take from the camera? What am I doing wrong?
Write your code as following this will give you image.
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
UIImagePickerControllerOriginalImage return image not NSURL
Write following code to get image url in iOS 11. From iOS 11 UIImagePickerControllerImageURL is available, earlier there are UIImagePickerControllerMediaURL key to get image url.
if #available(iOS 11.0, *) {
if let imageURL = info[UIImagePickerControllerImageURL] as? URL {
print(imageURL)
}
} else {
if let imageUrl = info[UIImagePickerControllerMediaURL] as? URL {
print(imageUrl)
}
}
I hope this will help you.
The one who are searching for complete method to implement for Swift 4.2+
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage{
imageView.image = pickedImage
}
imgPicker.dismiss(animated: true, completion: nil)
}
This will return you the original image according to new syntax
For Image URL and Media URL, Use the respective
let imgURL = info[UIImagePickerController.InfoKey.imageURL]
let mediaURL = info[UIImagePickerController.InfoKey.mediaURL]
Anybody know how to upload a video to firebase?
I used this link: record video in swift
I managed to record and have a playback in same view Gif of my video on giphy
The code to play the video I just recorded is:
#IBAction func playVideo(sender: AnyObject) {
print("Play a video")
// Find the video in the app's document directory
let paths = NSSearchPathForDirectoriesInDomains(
NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentsDirectory: AnyObject = paths[0]
let dataPath = documentsDirectory.stringByAppendingPathComponent(saveFileName)
let videoAsset = (AVAsset(URL: NSURL(fileURLWithPath: dataPath)))
let playerItem = AVPlayerItem(asset: videoAsset)
print(playerItem)
let videoView = UIView(frame: CGRectMake(self.view.bounds.origin.x, self.view.bounds.origin.y, self.view.bounds.width, self.view.bounds.height))
let pathURL = NSURL.fileURLWithPath(dataPath)
moviePlayer = MPMoviePlayerController(contentURL: pathURL)
if let player = moviePlayer {
player.view.frame = videoView.bounds
player.prepareToPlay()
player.scalingMode = .AspectFill
videoView.addSubview(player.view)
}
moviePlayer!.view.frame = videoPreview.bounds
moviePlayer!.view.center = CGPointMake(CGRectGetMidX(videoPreview.bounds), CGRectGetMidY(videoPreview.bounds))
videoPreview.addSubview((moviePlayer?.view)!)
}
And I know how to upload a PICTURE to Firebase I need to use NSStringlike this:
var base64String : NSString!
//let pic = UIImagePNGRepresentation(UIImage(named: "3")!)
let picture = UIImageJPEGRepresentation(self.profilePictureImageView.image!, 0.1)!
self.base64String = picture.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let updatedProfileInfo = [
"provider": USER_REF.authData.provider,
"email": self.emailTextfield.text!,
"Username": self.usernameTextfield.text!,
"ProfilePicture" : self.base64String,
"ProfileDescription" : self.bioDescriptionTextfield.text
]
USER_REF.updateChildValues(updatedProfileInfo)
But how do you do with videos?
Thank you
This was my solution on using the UIImagePicker object class to select a video or image in my device and upload it to Fireabase:
#IBAction func uploadButton(_ sender: Any) {
// Configuration
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.delegate = self
picker.mediaTypes = [kUTTypeImage as String, kUTTypeMovie as String]
// Present the UIImagePicker Controller
present(picker, animated: true, completion: nil)
}
// The didFinishPickingMediaWithInfo let's you select an image/video and let's you decide what to do with it. In my example, I decided to convert the selected data into video and upload it to Firebase Storage
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let videoURL = info[UIImagePickerControllerMediaURL] as? NSURL {
// we selected a video
print("Here's the file URL: ", videoURL)
// Where we'll store the video:
let storageReference = FIRStorage.storage().reference().child("video.mov")
// Start the video storage process
storageReference.putFile(videoURL as URL, metadata: nil, completion: { (metadata, error) in
if error == nil {
print("Successful video upload")
} else {
print(error?.localizedDescription)
}
})
}
//Dismiss the controller after picking some media
dismiss(animated: true, completion: nil)
}
How can i retrieve or make a thumbnail image of the selected video to be used in a another view controller after the video has been selected by user?
func imagePickerController1(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
// 1
let mediaType = info[UIImagePickerControllerMediaType] as! NSString
// 2
dismissViewControllerAnimated(true) {
// 3
if mediaType == kUTTypeMovie {
let moviePlayer = MPMoviePlayerViewController(contentURL: info[UIImagePickerControllerMediaURL] as! NSURL)
self.presentMoviePlayerViewControllerAnimated(moviePlayer)
}
}
let destination = self.storyboard!.instantiateViewControllerWithIdentifier("FinializePost")
self.navigationController!.pushViewController(destination, animated: true);
}
You can use this code:
let URL_originalvideo = info[UIImagePickerControllerMediaURL]
let asset: AVAsset = AVAsset.assetWithURL(URL_originalvideo) as AVAsset
let imageGenerator = AVAssetImageGenerator(asset: asset);
let time = CMTimeMakeWithSeconds(1.0, 1)
var actualTime : CMTime = CMTimeMake(0, 0)
var error : NSError?
let myImage = imageGenerator.copyCGImageAtTime(time, actualTime: &actualTime, error: &error)
myImage is what you need.