I have set up the insertion of the image from the photo library and now I am trying to let the user also select a video from the photo library or camera roll in iOS. I have written the following code:-
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBAction func didTapOnImageView(sender: UITapGestureRecognizer) {
//call Alert function
self.showAlert()
}
//Show alert to selected the media source type.
private func showAlert() {
var alertStyle = UIAlertController.Style.actionSheet
if (UIDevice.current.userInterfaceIdiom == .pad) {
alertStyle = UIAlertController.Style.alert
}
let alert = UIAlertController(title: "Image Selection", message: "From where you want to pick this image?", preferredStyle: alertStyle)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action: UIAlertAction) in
self.getImage(fromSourceType: .camera)
}))
alert.addAction(UIAlertAction(title: "Photo Album", style: .default, handler: {(action: UIAlertAction) in
self.getImage(fromSourceType: .photoLibrary)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .destructive, handler: nil))
self.present(alert, animated: true, completion: nil)
}
//get image from source type
private func getImage(fromSourceType sourceType: UIImagePickerController.SourceType) {
//Check is source type available
if UIImagePickerController.isSourceTypeAvailable(sourceType) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.sourceType = sourceType
imagePickerController.mediaTypes = ["public.image", "public.movie"]
self.present(imagePickerController, animated: true, completion: nil)
}
}
//MARK:- UIImagePickerViewDelegate.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
self.dismiss(animated: true) { [weak self] in
guard let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
//Setting image to your image view
self?.imageView.image = image
self?.imageView.contentMode = .scaleToFill
self?.image20 = self?.imageView.image
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
It works perfectly fine for choosing the image and displaying it, but, now I am able to select the video but, not display it. Could anyone please help on what shall I include in the imagePickerController delegate to obtain the video URL and display it? Thanks for the help! Appreciate it!
You can definitely catch the vide data from your imagePicker, like so:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
picker.dismiss(animated: true) {
if let image = info[.originalImage] as? UIImage,
let data = image.jpegData(compressionQuality: 0.8) {
}
}
if let videoURL = info[.mediaURL] as? URL {
do {
let videoData = try Data(contentsOf: videoURL, options: .mappedIfSafe)
} catch {
print("Error: \(error.localizedDescription)")
}
}
}
Now, after fetching the Data of your selected video file, your next step is to do the research of playing the video data in a view. You can start from this: Implementing video view in the Storyboard
But take heed of the age of that link, it's from 2015, but it should still help you out.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
videoURL = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerReferenceURL")] as? URL
}
after getting videoURL you can pass it to AVPlayer to play it.
let player = AVPlayer(url: videoURL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true) {
playerViewController.player!.play()
}
Related
For some reason in my new project this code is not working which has worked for me before. The current code does not change the ui of profileImage.
Delegates
UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIGestureRecognizerDelegate
Code:
#IBOutlet weak var profileImage: UIImageView!
#IBAction func changeProfilePicture(_ sender: Any) {
print("Profile picture tapped")
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.allowsEditing = true
let alertController = UIAlertController(title: "Add Picture", message: "", preferredStyle: .actionSheet)
let photoLibraryAction = UIAlertAction(title: "Photo Library", style: .default) { (action) in
pickerController.sourceType = .photoLibrary
self.present(pickerController, animated: true, completion: nil)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive, handler: nil)
alertController.addAction(photoLibraryAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : Any]?) {
self.profileImage.image = image
self.dismiss(animated: true, completion: nil)
}
Console Output
errors encountered while discovering extensions: Error
Domain=PlugInKit Code=13 "query cancelled"
UserInfo={NSLocalizedDescription=query cancelled}
I have tried
#objc func
internal func
#objc internal func
self.profileImage.image = image does not set the UI and change the image
Correct delegate method
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.originalImage] as? UIImage {
self.profileImage.image = image
}
else
if let image = info[.editedImage] as? UIImage {
self.profileImage.image = image
}
self.dismiss(animated: true, completion: nil)
}
I am trying to record video and then save it on an IOS device, I am able to record it but I am wondering how to save it on the device?
import UIKit
import AVKit
import MobileCoreServices
class ViewController: UIViewController , UIImagePickerControllerDelegate , UINavigationControllerDelegate {
#IBOutlet weak var RecordButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func RecordAction(_ sender: UIButton) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
print("Camera Available")
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .camera
imagePicker.mediaTypes = [kUTTypeMovie as String]
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
} else {
print("Camera UnAvaialable")
}
}
}
First make sure to add below Privacies to info.plist :
Privacy - Photo Library Additions Usage Description
Privacy - Camera Usage Description
Privacy - Microphone Usage Description
and add below functions under ViewDidLoad
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : Any]) {
dismiss(animated: true, completion: nil)
guard
let mediaType = info[UIImagePickerControllerMediaType] as? String,
mediaType == (kUTTypeMovie as String),
let url = info[UIImagePickerControllerMediaURL] as? URL,
UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(url.path)
else {
return
}
// Handle a movie capture
UISaveVideoAtPathToSavedPhotosAlbum(
url.path,
self,
#selector(video(_:didFinishSavingWithError:contextInfo:)),
nil)
}
#objc func video(_ videoPath: String, didFinishSavingWithError error: Error?, contextInfo info: AnyObject) {
let title = (error == nil) ? "Success" : "Error"
let message = (error == nil) ? "Video was saved" : "Video failed to save"
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil))
present(alert, animated: true, completion: nil)
}
I am trying to have a user choose an image from their gallery or camera, then upload it to the app. This works, but the only problem is that it doesn't save it in the app. As soon as the user closes the app, the image that the user chose disappears. I also do not have any save function because i don't know how to implement one.
I am using Xcode 8.3.2 in Swift 3.0. Here is the code below:
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func chooseImage(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action:UIAlertAction) in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}else{
print("Camera not available")
}
}))
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action:UIAlertAction) in
imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
imageView.image = image
picker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Remember to save image you need to store image as NSData
// Code to store image
let defaults = UserDefaults.standard
// To save as data:
// From StoryBoard, if you want to save "image" data on the imageView of
// MainStoryBoard, following codes will work.
let image = UIImagePNGRepresentation(imageView.image!) as NSData?
defaults.set(image, forKey: "test") // saving image into userdefault
// for retrieving the image
if (UserDefaults.standard.object(forKey: "test") as? NSData) != nil {
let photo = UserDefaults.standard.object(forKey: "test") as! NSData
img2.image = UIImage(data: photo as Data) // img2 set your imageview on which you want photo to appear
// Now you can set img2.image
}
Edited
How to use in your code
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : Any]) {
let defaults = UserDefaults.standard
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
imageView.image = image
let saveImage = UIImagePNGRepresentation(image!) as NSData?
defaults.set(saveImage, forKey: "test") // saving image into userdefault
picker.dismiss(animated: true, completion: nil)
}
And in your view did load use retrieving method
If the image exist and in nsdata format then only it will show save image. Thats it.
You can save image in your document directory with below function
func saveImageDocumentDirectory(tempImage:UIImage){
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = documentsDirectoryURL.appendingPathComponent("ImageName.png")
do {
try UIImagePNGRepresentation(tempImage)?.write(to: fileURL)
} catch {
print(error)
}
}
To retrieve Image you can use
func getImage()->URL?{
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = documentsDirectoryURL.appendingPathComponent("ImageName.png")
if FileManager.default.fileExists(atPath: fileURL.path){
return fileURL
}else{
return nil
}
}
You can use any name you like and store image with different name to store multiple image.
I am currently making a program in swift that involves a screen of choosing an image from either camera or photo library using action sheet. This is fully functional however I would like to be able to choose a square section from the selected image, similar to apple default apps. How can I implement this? Here is my functional code:
func chooseImage(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action:UIAlertAction) in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}else{
print("Camera not available")
}
}))
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action:UIAlertAction) in
imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Default", style: .default, handler: { (action:UIAlertAction) in
self.avatarImageView.image = UIImage(named: "Avatar.png")
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
avatarImageView.image = image
picker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
// Saves the User singleton object onto the device
static func saveData() {
let savedData = NSKeyedArchiver.archivedData(withRootObject: User.sharedUser)
UserDefaults.standard.set(savedData, forKey: "user")
}
You can use default controls to achieve image cropping.
self.imgPicker.allowsEditing = true
Delegate Method
//MARK: image picker delegate method
//MARK:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var image : UIImage!
if let img = info[UIImagePickerControllerEditedImage] as? UIImage
{
image = img
}
else if let img = info[UIImagePickerControllerOriginalImage] as? UIImage
{
image = img
}
picker.dismiss(animated: true,completion: nil)
}
Swift 4.0+
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
var image : UIImage!
if let img = info[UIImagePickerController.InfoKey.editedImage] as? UIImage
{
image = img
}
else if let img = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
{
image = img
}
picker.dismiss(animated: true, completion: nil)
}
Don't forget to set allowsEditing to true.
Another option is to use TOCropViewController. Its does more with much less code. What I found good about it that it allows you to change the cropping rectangle.
class ViewController: UIViewController, CropViewControllerDelegate {
... //your viewcontroller code
func presentCropViewController {
let image: UIImage = ... //Load an image
let cropViewController = CropViewController(image: image)
cropViewController.delegate = self
present(cropViewController, animated: true, completion: nil)
}
func cropViewController(_ cropViewController: CropViewController,
didCropToImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
// 'image' is the newly cropped version of the original image
}
}
Swift 5.0
The shortest way of declaring:
//MARK: image picker delegate method
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var image : UIImage!
if let img = info[.editedImage] as? UIImage {
image = img
} else if let img = info[.originalImage] as? UIImage {
image = img
}
picker.dismiss(animated: true,completion: nil)
}
Button sender:
#objc func buttonClicked(sender: UIButton!) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary) {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = UIImagePickerController.SourceType.photoLibrary
picker.allowsEditing = true
present(picker, animated: true, completion: nil)
}
}
Don't forget to grant Photo Library access in .plist
- (void)cropViewController:(TOCropViewController *)cropViewController didCropToImage:(UIImage *)image withRect:(CGRect)cropRect angle:(NSInteger)angle
{
[[NSUserDefaults standardUserDefaults] setObject:UIImageJPEGRepresentation(image, 1) forKey:#"image"];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"cameraOn"];
[cropViewController dismissViewControllerAnimated:YES completion:^{
[self performSegueWithIdentifier:#"YourSegueIdentifier" sender:self];
}];
//UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
For (iOS13): Do all ViewController "cropController.modalPresentationStyle =.fullScreen" using storyboard or code.
This is work good and easily navigate to another controller. I also attached image so you can easily understand how to change presentation style.
I would like to be able to view a list of both photos and videos stored on the user's iPhone so I can allow them to select the file for upload. So far, I have it working where photos show up in the list, but no videos are showing up. The code I'm using to display the photos library is the following:
#IBAction func btnAddPicOrVideo(sender: AnyObject) {
let pickerC = UIImagePickerController()
pickerC.delegate = self
self.presentViewController(pickerC, animated: true, completion: nil)
}
As I mentioned, I'm able to display a list of photos and select one of them just fine. The problem is that I'm unable to see or select any videos. Is there a way to specify for both pictures and videos to be displayed? Or, do I have to display pictures and videos separately?
I'm currently running my code on the simulator and I have a video file stored on it locally.
Thanks in advance.
I was able to get this resolved by specifying
import MobileCoreServices
and I changed the code I specified above as such:
#IBAction func btnAddPicOrVideo(sender: AnyObject) {
let pickerC = UIImagePickerController()
pickerC.mediaTypes = [kUTTypeImage as NSString, kUTTypeMovie as NSString]
pickerC.delegate = self
self.presentViewController(pickerC, animated: true, completion: nil)
}
class ScoutDetailPage: UIViewController,UIImagePickerControllerDelegate {
var picker:UIImagePickerController? = UIImagePickerController()
let imageView = UIImageView ()
{
override func viewDidLoad(){
// Do any additional setup after loading the view.
self.loadOrTakePhotos()
}
func loadOrTakePhotos()
{
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera))
{
picker!.sourceType = UIImagePickerControllerSourceType.Camera
picker?.delegate = self
self .presentViewController(picker!, animated: true, completion: nil)
}
}
else if (pickersegment.selectedSegmentIndex == 1)
{
picker!.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
picker?.delegate = self
self.presentViewController(picker!, animated: true, completion: nil)
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
let pickedimage = info[UIImagePickerControllerOriginalImage] as! UIImage
imageView.image = pickedimage
if (imageView.image != nil)
{
print("image not empty")
// Do something here.
picker .dismissViewControllerAnimated(false, completion: nil)
}
else
{
print("IMAGE VIEW NIL")
}
}
func image(image: UIImage, didFinishSavingWithError error: NSErrorPointer, contextInfo:UnsafePointer<Void>) {
if error != nil {
let alert = UIAlertController(title: "Save Failed",
message: "Failed to save image",
preferredStyle: UIAlertControllerStyle.Alert)
let cancelAction = UIAlertAction(title: "OK",
style: .Cancel, handler: nil)
alert.addAction(cancelAction)
self.presentViewController(alert, animated: true,
completion: nil)
}
}
}