I have an app that lets a user take a picture with the camera. I would like to only allow the user to take landscape photos, not portrait. Is there a way for me to lock the camera orientation?
Below is the code I am using:
func takePhoto() {
//If a camera is available on this device, go to camera. If not, present an error message.
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera){
//Create the image picker controller
imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .Camera
//Present the camera view
presentViewController(imagePicker, animated: true, completion: nil)
}
else {
let alert = UIAlertController(title: "Error", message: "There is no camera available", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: {(alertAction) in alert.dismissViewControllerAnimated(true, completion: nil)}))
self.presentViewController(alert, animated: true, completion: nil)
}
}
Is there a way for me to lock the camera orientation
The camera is a physical object. Its orientation has nothing to do with your app. The only way to "lock the camera orientation" is to reach out and grab the user's wrist so that s/he can't turn the device.
Related
Using this question I ask the user to decide whether they want to use the camera or choose an image from their phone:
//Show alert to select the media source type.
private func showAlert() {
let alert = UIAlertController(title: "Image Selection", message: "From where you want to pick this image?", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action: UIAlertAction) in
self.imagePicker.sourceType = .camera
}))
alert.addAction(UIAlertAction(title: "Photo Album", style: .default, handler: {(action: UIAlertAction) in
self.imagePicker.sourceType = .photoLibrary
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .destructive, handler: nil))
self.present(alert, animated: true, completion: nil)
}
Which I envoke in viewDidLoad as such:
override func viewDidLoad() {
super.viewDidLoad()
firstTextField.delegate = self
showAlert()
present(imagePicker, animated: true, completion: nil)
imagePicker.delegate = self
firstImageView.layer.cornerRadius = 8
}
However when I test this the alert pops up and I choose the photo library, but the library does not appear. I have tried using viewDidAppear but that failed to work as well. No errors appear, it just hides the alert and shows the current view controller.
You may be imagining that code comes to a stop when an alert appears. But it doesn't! And you cannot show two presented view controllers simultaneously. But that is what you are trying to do.
You are saying showAlert(), so now your alert is up, and then you are immediately saying present(imagePicker), which you cannot do because your alert is still up.
Use the action handlers of the showAlert alert to present the image picker. That way, the alert closes and the image picker opens.
In my project I tried to add two things:
A camera source for a person's avatar.
add permission for the camera and photo library access in the info.plist file.
But when I tried to test my app in a real device the app doesn’t show any permission, and when I chose the camera the app exit without error message in the log console?
For the info.plist I use this two line:
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) camera use</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>$(PRODUCT_NAME) photo use</string>
And add a photo I use this code:
#objc func addNewPerson(){
let picker = UIImagePickerController()
let ac = UIAlertController(title: "Choose image", message: nil, preferredStyle: .actionSheet)
let camera = UIAlertAction(title: "Camera", style: .default){
[weak self] _ in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
picker.allowsEditing = false
picker.delegate = self
picker.sourceType = .camera
self?.present(picker,animated: true)
}else{
let alert = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self?.present(alert, animated: true, completion: nil)
}
}
ac.addAction(camera)
let galerie = UIAlertAction(title: "Photo library", style: .default){
[weak self] _ in
picker.allowsEditing = true
picker.delegate = self
self?.present(picker,animated: true)
}
ac.addAction(galerie)
ac.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(ac,animated: true)
}
Thank you.
in your addNewPerson() method before showing the alert you should check if the user already granted access to his Camera you can do that by :
if AVCaptureDevice.AVCaptureDevice.authorizationStatus(AVMediaTypeVideo) == AVAuthorizationStatus.Authorized {
// Already Authorized
} else {
AVCaptureDevice. requestAccess(AVMediaTypeVideo, completionHandler: { (granted: Bool) -> Void in
if granted == true {
// User granted
} else {
// User rejected
}
})
}
and before that make sure you added
Just to mention, in iOS 11 camera access is not required to use the UIImagePicker
Here is copy-pasted fragment from rickster's post.
in iOS 11, UIImagePickerController runs as a separate process from your app. That means:
Your app can't see the user's whole Photos library — it gets read-only access just for whichever asset(s) the user chooses in the image picker.
Because of (1), your app doesn't need the standard privacy authorization for Photos library access. The user explicitly chooses a
specific asset (or multiple) for use in your app, which means the user is granting your app permission to read the asset(s) in question.
If user dennied the camera access, i am showing one alert with cancel and setting button to show it. But the code is not working.
#IBAction func ProfileImageButton(_ sender: UIButton) {
print("profile image Button is pressed")
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
profileimgbool = true
let actionSheet = UIAlertController(title: "Photo Source", message: "choose a Source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action:UIAlertAction) in imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}))
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 checkCameraPermission() {
let cameraMediaType = AVMediaType.video
AVCaptureDevice.requestAccess(for: cameraMediaType) { granted in
if granted {
//Do operation
print("Granted access for camera")
// self.setCamera()
} else {
self.noCameraFound()
print("Denied access for camera ")
}
}
}
func noCameraFound(){
let alert = UIAlertController(title: "CallDoc", message: "Please allow camera access in phone settings", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Back", style: UIAlertActionStyle.cancel, handler: {(action:UIAlertAction) in
}));
alert.addAction(UIAlertAction(title: "Open setting", style: UIAlertActionStyle.default, handler: {(action:UIAlertAction) in
UIApplication.shared.open(NSURL(string:UIApplicationOpenSettingsURLString)! as URL, options: [:], completionHandler: nil)
}));
self.present(alert, animated: true, completion: nil)
}
in my above code my method was checkCameraPermission where i will call this to show alert. I needs to show when user click camera, and when if user denied that black screen will show instead of camera. There i need to show that alert pop up.
Where i can call this checkCameraPermission method to show my popup ?.
Any idea ?
for reference purpose I taken the answer from this tutorial.
step 1
add the avfoundation framework in your project
import AVFoundation
step 2
dont forget to Set Camera Usage Description in Info.plist
When you request permission to use the device’s camera, a short message will appear in the default iOS system dialog. You customize this message by adding the Privacy - Camera Usage Description key to your Info.plist file.
step 3
on your image profile change button action verify the permission, etc.
#IBAction func ProfileImageButton(_ sender: UIButton) {
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
switch cameraAuthorizationStatus {
case .notDetermined: requestCameraPermission()
case .authorized: presentCamera()
case .restricted, .denied: alertCameraAccessNeeded()
}
}
based on the above action the condition will satisfy,
If the user has never responded to a request to access his/her camera, you need to prompt with the iOS system alert to request permission:
func requestCameraPermission() {
AVCaptureDevice.requestAccess(for: .video, completionHandler: {accessGranted in
guard accessGranted == true else { return }
self.presentCamera()
})
}
there after the camera access will continue
func presentCamera() {
let photoPicker = UIImagePickerController()
photoPicker.sourceType = .camera
photoPicker.delegate = self as? UIImagePickerControllerDelegate & UINavigationControllerDelegate
self.present(photoPicker, animated: true, completion: nil)
}
To use the image that the camera captured, you need to set up your view controller to adhere to and implement couple of delegate protocols:
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
// ...
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let photo = info[UIImagePickerControllerOriginalImage] as! UIImage
// do something with the photo... set to UIImageView, save it, etc.
dismiss(animated: true, completion: nil)
}
If camera access has been denied or restricted, you can alert the user and direct them to the Settings app to make the appropriate permissions adjustment:
func alertCameraAccessNeeded() {
let settingsAppURL = URL(string: UIApplicationOpenSettingsURLString)!
let alert = UIAlertController(
title: "Need Camera Access",
message: "Camera access is required to make full use of this app.",
preferredStyle: UIAlertControllerStyle.alert
)
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Allow Camera", style: .cancel, handler: { (alert) -> Void in
UIApplication.shared.open(settingsAppURL, options: [:], completionHandler: nil)
}))
present(alert, animated: true, completion: nil)
}
I am trying to access the photo library for a new app that I am writing. I have an actionSheet that allows the user to choose between their camera and their photo library. When opening the camera, it asks the user for permission but when opening the photo library it does not. Despite this, it still brings the user to their photo library. I specifically referenced it in my info.plist, but there is still no difference. Any help? My code:
#IBAction func allowAccessToPhotos(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a Source", preferredStyle: .actionSheet)
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: "Camera", style: .default, handler: { (action:UIAlertAction) in imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}
As per UIImagePickerController behaviour, It never gives dialogue to the user for Photos access. UIImagePickerController only ask for the Camera permission.
You have to ask for Photos permission manually to the user. By using the below code you can ask the user for Photos permission.
import Photos
#IBAction func allowAccessToPhotos(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a Source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action:UIAlertAction) in imagePickerController.sourceType = .photoLibrary
let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
switch photoAuthorizationStatus {
case .authorized:
self.present(imagePickerController, animated: true, completion: nil)
case .notDetermined:
PHPhotoLibrary.requestAuthorization({
(newStatus) in
DispatchQueue.main.async {
if newStatus == PHAuthorizationStatus.authorized {
self.present(imagePickerController, animated: true, completion: nil)
}else{
print("User denied")
}
}})
break
case .restricted:
print("restricted")
break
case .denied:
print("denied")
break
}}))
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action:UIAlertAction) in imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}))
}
Please refer reference.
Important Note:
If you're not asking for Photos permission to the user then It will cause rejection by the apple team. It depends on your luck, Sometimes the apple team ignore it and sometimes reject our app.
From iOS 11, UIImagePickerController is running remotely on a separate process.
So, your app doesn't need the standard privacy authorization for Photos library access, it gets read-only access just for whichever asset(s) the user chooses in the imagePicker.
To add new asset into photo-library you need NSPhotoLibraryAddUsageDescription in your Info.plist - forum thread
yes you can access photos by PhotosUI library without permission
import PhotosUI
var config = PHPickerConfiguration()
config.selectionLimit = 4
config.filter = .images
let vc = PHPickerViewController(configuration: config)
vc.delegate = self
self.present(vc, animated: true)
extension UIViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
var images = [UIImage]()
for image in results {
if image.itemProvider.canLoadObject(ofClass: UIImage.self) {
image.itemProvider.loadObject(ofClass: UIImage.self) { (newImage, error) in
if let error = error {
print(error.localizedDescription)
} else {
self.images.append(newImage as! UIImage)
}
}
} else {
print("Loaded Assest is not a Image")
}
}
picker.dismiss(animated: true)
}
}
I am working on an iOS app, in which at one point the user takes a picture. However, I want the user to ONLY be able to use the front facing camera. That is, they should not have access to the rear camera. Currently, my code looks like this:
#IBAction func takePicture(sender: UIButton) {
if UIImagePickerController.availableCaptureModesForCameraDevice(.Front) != nil {
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .Camera
imagePickerController.allowsEditing = false
imagePickerController.cameraDevice = .Front
imagePickerController.delegate = self
presentViewController(imagePickerController, animated: true, completion: nil)
}
else {
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)
}
}
Although this defaults the camera to be front facing, it still offers users the choice to switch to the rear camera. Is there a way I can restrict this functionality?
Thanks in advance
If you don't want to allow the user the freedom offered by a UIImagePickerController, simply don't use UIImagePickerController. Devise your own picture-taking interface (by way of AVFoundation), where you are in total control.