I am experimenting with UIImagePickerController to allow photos to be selected from either the library or by taking a photo with the camera.
I followed the steps on a website (https://makeapppie.com/2016/06/28/how-to-use-uiimagepickercontroller-for-a-camera-and-photo-library-in-swift-3-0/) and got this working for the photo library but whenever I try to invoke the camera from my app it gives the error "Thread 1: signal SIGABRT".
This is the code that I am using to invoke the camera:
picker.allowsEditing = false
picker.sourceType = UIImagePickerControllerSourceType.camera
picker.cameraCaptureMode = .photo
picker.modalPresentationStyle = .fullScreen
present(picker,animated: true,completion: nil)
It was my understanding that the SIGABRT error would be expected inside the simulator. However when I tried it on my iPhone 7 I expected it to work and it gave the same error.
I have added the "Privacy - Camera Usage Description" to the Info.plist file.
Any ideas what I have done wrong?
Here's my full code for using/selecting
// MARK: Camera App
func openCameraApp() {
if UIImagePickerController.availableCaptureModes(for: .rear) != nil {
picker.allowsEditing = false
picker.sourceType = UIImagePickerControllerSourceType.camera
picker.cameraCaptureMode = .photo
picker.modalPresentationStyle = .fullScreen
present(picker,
animated: true,
completion: nil)
} else {
noCamera()
}
}
func noCamera(){
let alertVC = UIAlertController(
title: "No Camera",
message: "Sorry, this device has no camera",
preferredStyle: .alert)
let okAction = UIAlertAction(
title: "OK",
style:.default,
handler: nil)
alertVC.addAction(okAction)
present(
alertVC,
animated: true,
completion: nil)
}
// MARK: Photos Albums
func showImagePicker() {
picker.allowsEditing = false
picker.sourceType = .photoLibrary
//picker.modalPresentationStyle = .Popover
present(picker,
animated: true,
completion: nil)
picker.popoverPresentationController?.sourceView = self.view
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
image = chosenImage
self.performSegue(withIdentifier: "ShowEditView", sender: self)
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: false, completion: nil)
}
// MARK: Seque to EditViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowEditView" {
if let vc = segue.destination as? EditViewController {
vc.image = image
//vc.image = images[0]
}
}
}
Ignore the two commented out lines - those are mine for testing things. This code works on all devices, iOS 9+, all orientations (but remember that iPhone is always displayed portrait), and I've never had any problems in either the simulator (it has no camera) nor a physical device.
Of interest is one thing that could cause an issue (not sure if it's throwing SIGABRT) - I'm checking for a rear camera and throwing up an alert if it doesn't exist. (No check for front camera though. I'm not even sure if anything but an iPod touch doesn't have a front facing camera.)
Also, don't forget to add two things to your info.plist for iOS 10:
<key>NSCameraUsageDescription</key>
<string>Used to capture new image for photo effect</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Used to select an image for photo effect</string>
You may put whatever you want in the description tags. Without these, the app will shut down in iOS 10 and Apple will reject your submission. Here's a link to more details.
Related
We have a simple video app where we do not allow users to shoot in portrait. We allow import of videos shot outside the app but would like to block import of video shot in portrait if possible. Would appreciate any help on this!
#IBAction func importVideoTapped(_ sender: Any) {
imagePickerController.sourceType = .savedPhotosAlbum
imagePickerController.delegate = self
imagePickerController.mediaTypes = [kUTTypeMovie as String]
present(imagePickerController, animated: true, completion: nil)
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
viewController.navigationItem.title = "Videos"
}
As far as I can tell, you can't filter the videos that appear in the picker so that only landscape videos are available for selection. So, you'll have to let the user select a video, check if it's landscape, and show an alert otherwise. Something along the lines of the following:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard
let url = info[UIImagePickerControllerMediaURL] as? URL,
let videoTrack = AVAsset(url: url).tracks(withMediaType: AVMediaType.video).first else
{
dismiss(animated: true, completion: nil)
return
}
let size = videoTrack.naturalSize
let transform = videoTrack.preferredTransform
//Check if video is in landscape orientation (left or right)
if (size.width == transform.tx && size.height == transform.ty) || transform.tx == 0 && transform.ty == 0 {
//TODO: store video however you want for later use
dismiss(animated: true, completion: nil)
} else {
let alert = UIAlertController(title: "Invalid video", message: "Please select a landscape video", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
picker.show(alert, sender: nil)
}
}
Make sure to adjust the implementation in whatever way is appropriate to you, and to properly store the video or its url.
I'm presenting an UIImagePickerController to take a photo, the problem is if I take a photo, or cancel the UIImagePickerController I'll return on a white screen and not on my previous ViewController. Only my navigation bar still here. If I click to an other view (with the navigation bar) it's ok, and if I return on the tab where the UIImagePickerController is called it still white.
let picker = UIImagePickerController();
picker.delegate = self;
picker.mediaTypes = [swiftString];
picker.allowsEditing = true
picker.sourceType = UIImagePickerControllerSourceType.camera;
picker.cameraCaptureMode = .photo
self.present(picker, animated:true, completion:nil);
dismiss :
picker.dismiss(animated: true, completion:nil);
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion:nil);
}
If someone have an idea thank's !
Update :
White screen appears always when i call a view with present method. So i think it's conflict with the navigation controller (hierarchy...)
This solve my problem :
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {return}
appDelegate.navigationController.present(picker, animated: true, completion: nil)
If someone have an other alternative to solve it !
Use picker.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext before presenting the imagepicker.
Here's the code I use for the camera:
func openCameraApp() {
if UIImagePickerController.availableCaptureModes(for: .rear) != nil {
picker.allowsEditing = false
picker.sourceType = UIImagePickerControllerSourceType.camera
picker.cameraCaptureMode = .photo
picker.modalPresentationStyle = .fullScreen
present(picker,
animated: true,
completion: nil)
} else {
noCamera()
}
}
func noCamera(){
let alertVC = UIAlertController(
title: "No Camera",
message: "Sorry, this device has no camera",
preferredStyle: .alert)
let okAction = UIAlertAction(
title: "OK",
style:.default,
handler: nil)
alertVC.addAction(okAction)
present(
alertVC,
animated: true,
completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage // do you have this line in your code?
image = chosenImage
self.performSegue(withIdentifier: "ShowEditView", sender: self)
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: false, completion: nil)
}
I notice a couple of things different.
You set .allowsEditing to true. I don't believe that is making a difference.
I'm checking for a camera, but you probably didn't put that code in your question.
I'm setting .modalPresentationStyle to full screen. This could be your issue.
I don't see the imagePickerController(picker: didFinishPickingMediaWithInfo) call. But since it shouldn't build, that definitely isn't the issue.
Inside that call I unwrap the image from info. I believe this is your issue. I've placed a comment on that specific line, asking you to check for this.
Finally, I'm executing a segue to another view controller. (My app is basically a "select" then "edit".)
Set the .modalPresentationStyle to fullScreen
This is the code:
// Only allow photos to be picked,not taken.
imagePickerController.sourceType = .photoLibrary
this is the error: Type 'UIImagePickerControllerSourceType' has no member 'photoLibrary'
Just trying to complete the official tutorial Start Developing iOS Apps (Swift)
//MARK: Actions
#IBAction func selectImageFromPhotoLibrary(sender: UITapGestureRecognizer) {
//Hide the keyboard.
nameTextField.resignFirstResponder()
// UIImagepickerController is a view controller that lets a user pick media from their photo library.
let imagePickerController = UIImagePickerController()
// Only allow photos to be picked,not taken.
imagePickerController.sourceType = .photoLibrary
//Make sure ViewController is notified when the user picks an image.
imagePickerController.delegate = self
present(imagePickerController, animated: true, competion: nil)
}
#IBAction func setDefaultLabelText(sender: UIButton) {
mealNameLabel.text = "Default Text"
}
}
Okay, it looks like you are probably usingSwift 2.2 (maybe it's this for Swift 2.3 also). You want this syntax:
imagePickerController.sourceType = .PhotoLibrary
Note the capitalization. Keep in mind, Xcode 8.2 (released 12 December 2016) will be the last version of Xcode to support Swift 2.x. Sometime in 2017 you will probably need to use Swift 3 for new App Store submissions.
EDIT:
Here's my full Swift 2.2 code, followed by my Swift 3.0 code. Please note two things:
I'm also using the Camera app and have checks to make sure it's present - which isn't the case for the simulator.
Your app will crash in iOS 10 unless you add the following to your info.plist file:
NSCameraUsageDescription
Used to capture new image for photo effect
NSPhotoLibraryUsageDescription
Used to select an image for photo effect
You may put different values in the tags.
Swift 2.2:
let picker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
}
extension SelectViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
// MARK: Camera App
func openCameraApp() {
if UIImagePickerController.availableCaptureModesForCameraDevice(.Rear) != nil {
picker.allowsEditing = false
picker.sourceType = UIImagePickerControllerSourceType.Camera
picker.cameraCaptureMode = .Photo
picker.modalPresentationStyle = .FullScreen
presentViewController(picker,
animated: true,
completion: nil)
} else {
noCamera()
}
}
func noCamera(){
let alertVC = UIAlertController(
title: "No Camera",
message: "Sorry, this device has no camera",
preferredStyle: .Alert)
let okAction = UIAlertAction(
title: "OK",
style:.Default,
handler: nil)
alertVC.addAction(okAction)
presentViewController(
alertVC,
animated: true,
completion: nil)
}
// MARK: Photos Albums
func showImagePicker() {
picker.allowsEditing = false
picker.sourceType = .PhotoLibrary
// picker.modalPresentationStyle = .Popover
presentViewController(picker,
animated: true,
completion: nil)
picker.popoverPresentationController?.sourceView = self.view
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
image = chosenImage
self.performSegueWithIdentifier("ShowEditView", sender: self)
dismissViewControllerAnimated(true, completion: nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
dismissViewControllerAnimated(false, completion: nil)
}
// MARK: Seque to EditViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowEditView" {
if let vc = segue.destinationViewController as? EditViewController {
vc.image = image
}
}
}
}
Swift 3.0 (only the extension code has syntax changes):
func openCameraApp() {
if UIImagePickerController.availableCaptureModes(for: .rear) != nil {
picker.allowsEditing = false
picker.sourceType = UIImagePickerControllerSourceType.camera
picker.cameraCaptureMode = .photo
picker.modalPresentationStyle = .fullScreen
present(picker,
animated: true,
completion: nil)
} else {
noCamera()
}
}
func noCamera(){
let alertVC = UIAlertController(
title: "No Camera",
message: "Sorry, this device has no camera",
preferredStyle: .alert)
let okAction = UIAlertAction(
title: "OK",
style:.default,
handler: nil)
alertVC.addAction(okAction)
present(
alertVC,
animated: true,
completion: nil)
}
// MARK: Photos Albums
func showImagePicker() {
picker.allowsEditing = false
picker.sourceType = .photoLibrary
// picker.modalPresentationStyle = .Popover
present(picker,
animated: true,
completion: nil)
picker.popoverPresentationController?.sourceView = self.view
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
image = chosenImage
self.performSegue(withIdentifier: "ShowEditView", sender: self)
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: false, completion: nil)
}
// MARK: Seque to EditViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowEditView" {
if let vc = segue.destination as? EditViewController {
vc.image = image
// vc.image = images[0]
}
}
}
I try to write an App that needs a screen where you can take multible photos. I have used a code example from http://makeapppie.com/2015/11/04/how-to-make-xib-based-custom-uiimagepickercontroller-cameras-in-swift/.
It seems to be working OK, but my imagePickerController didFinishPickingMediaWithInfo newer get called. I am getting an error message from Xcode "Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates." It sounds to me like this could be the problem, and I have googled it, but havn't gotten any wiser. A lot of people write it's an Apple bug and I havn't found anybody offering a solution.
So do anybody know if it is the Xcode error that is my problem, and in that case have a solution for that or have I written something wrong in my code:
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, CustomOverlayDelegate {
var picker = UIImagePickerController()
#IBAction func shootPhoto(sender: AnyObject) {
if UIImagePickerController.availableCaptureModesForCameraDevice(.Rear) != nil {
picker = UIImagePickerController() //make a clean controller
picker.allowsEditing = false
picker.sourceType = UIImagePickerControllerSourceType.Camera
picker.cameraCaptureMode = .Photo
picker.showsCameraControls = false
//customView stuff
let customViewController = CustomOverlayViewController(
nibName:"CustomOverlayViewController",
bundle: nil
)
let customView:CustomOverlayView = customViewController.view as! CustomOverlayView
customView.frame = self.picker.view.frame
customView.cameraLabel.text = "Hello Cute Camera"
customView.delegate = self
//presentation of the camera
picker.modalPresentationStyle = .FullScreen
presentViewController(picker, animated: true,completion: {
self.picker.cameraOverlayView = customView
})
} else { //no camera found -- alert the user.
let alertVC = UIAlertController(
title: "No Camera",
message: "Sorry, this device has no camera",
preferredStyle: .Alert)
let okAction = UIAlertAction(
title: "OK",
style:.Default,
handler: nil)
alertVC.addAction(okAction)
presentViewController(
alertVC,
animated: true,
completion: nil)
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
print("didFinishPickingMediaWithInfo")
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage //get the image from info
UIImageWriteToSavedPhotosAlbum(chosenImage, self,nil, nil) //save to the photo library
}
//What to do if the image picker cancels.
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
dismissViewControllerAnimated(true, completion: nil)
}
//MARK: Custom View Delegates
func didCancel(overlayView:CustomOverlayView) {
picker.dismissViewControllerAnimated(true, completion: nil)
print("dismissed!!")
}
func didShoot(overlayView:CustomOverlayView) {
picker.takePicture()
overlayView.cameraLabel.text = "Shot Photo"
print("Shot Photo")
}
func weAreDone(overlayView: CustomOverlayView) {
picker.dismissViewControllerAnimated(true,
completion: nil)
print("We are done!")
}
}
Write
picker.delegate = self after
picker = UIImagePickerController() line
Also inherit you class with UIImagePickerControllerDelegate delegate.
It will work.
I have an action sheet that has two options: one where you can choose an image from your library and one where you can take a photo from the camera. The photo library functions properly, but I can't seem to get the camera to work.
Here is my code:
let takePhoto = UIAlertAction(title: "Take photo", style: .Default, handler: {
(alert: UIAlertAction!) -> Void in
// present camera taker
var cameraPicker = UIImagePickerController()
cameraPicker.delegate = self
cameraPicker.sourceType = .Camera
self.presentViewController(cameraPicker, animated: true, completion: nil)
})
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
var selectedAvatar = UIImagePickerControllerOriginalImage
self.dismissViewControllerAnimated(false, completion: nil)
}
I can't seem to find the problem, can anybody help me out? The program crashes when I try to run it and click on Take Photo.
You are most likely running in the simulator. The simulator dont have a camera so to not make the app crash when pressing the button you have to check if cemera is available.
if UIImagePickerController.isSourceTypeAvailable(.Camera) {
...
}
else {
print("Sorry cant take picture")
}
Follow the below code
func takePhoto()
{
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera))
{
picker!.sourceType = UIImagePickerControllerSourceType.Camera
self .presentViewController(picker!, animated: true, completion: nil)
}
else
{
let alertWarning = UIAlertView(title:"Warning", message: "You don't have camera", delegate:nil, cancelButtonTitle:"OK", otherButtonTitles:"")
alertWarning.show()
}
}
func openGallary()
{
picker!.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(picker!, animated: true, completion: nil)
}
//PickerView Delegate Methods
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject])
{
picker .dismissViewControllerAnimated(true, completion: nil)
imageView.image=info[UIImagePickerControllerOriginalImage] as? UIImage
}
func imagePickerControllerDidCancel(picker: UIImagePickerController)
{
println("picker cancel.")
}
There is another reason why the camera can crash when used in a real device as Kirit Modi said in the following tread:
iOS 10 - App crashes To access photo library or device camera via UIImagePickerController
In iOS 10. You have to set privacy Setting for Camera & Photo Library. Camera & Photo Privacy Setting at info.Plist
This solved my crashing issue!