iOS camera freezes when previewing video when there is a camera overlay - ios

I am attempting to overlay a view over a video capture session in UIImagePicker. The overlay works fine but when the app gets to the screen where the user can "retake", "play" or "use video", the app crashes and gives the error:
2017-04-16 21:33:04.129212-0400 ChugMug[429:59833] libMobileGestalt
MobileGestalt.c:2690: statfs(/mnt4): No such file or directory
2017-04-16 21:33:04.129871-0400 ChugMug[429:59833] libMobileGestalt
MobileGestalt.c:2587: SInt64 NANDSize(): No kIOMediaSizeKey found for
disk0! 2017-04-16 21:33:09.352085-0400 ChugMug[429:60065]
[MediaRemote] Error Operation requires a client callback to have been
registered. requesting playback queue
The code is quite simple, when the overlay is commented out, the video preview screen and buttons work fine, but when the overlay is present the app freezes at the following screen:
Here is the code for the camera and the overlay:
func startMediaBrowserFromViewController(viewController: UIViewController, usingDelegate delegate: UINavigationControllerDelegate & UIImagePickerControllerDelegate) -> Bool {
// 1
if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum) == false {
return false
}
// 2
let mediaUI = UIImagePickerController()
mediaUI.sourceType = .savedPhotosAlbum
mediaUI.mediaTypes = [kUTTypeMovie as NSString as String]
mediaUI.allowsEditing = true
mediaUI.delegate = delegate
// 3
present(mediaUI, animated: true, completion: nil)
return true
}
func startCameraFromViewController(viewController: UIViewController, withDelegate delegate: UIImagePickerControllerDelegate & UINavigationControllerDelegate) -> Bool {
if UIImagePickerController.isSourceTypeAvailable(.camera) == false {
return false
}
cameraController.sourceType = .camera
cameraController.mediaTypes = [kUTTypeMovie as NSString as String]
cameraController.allowsEditing = false
cameraController.delegate = delegate
cameraController.showsCameraControls = true
//customView stuff
let customViewController = CustomOverlayViewController(
nibName:"CustomOverlayViewController",
bundle: nil
)
let customView = customViewController.view //as! CustomOverlayView
customView?.frame = cameraController.view.frame
present(cameraController, animated: true, completion: {
self.cameraController.cameraOverlayView = customView
customViewController.cameraLabel.text = "Camera Label"
self.cameraController.startVideoCapture()
})
return true
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let mediaType = info[UIImagePickerControllerMediaType] as! NSString
dismiss(animated: true, completion: nil)
// Handle a movie capture
if mediaType == kUTTypeMovie {
guard let path = (info[UIImagePickerControllerMediaURL] as! NSURL).path else { return }
if UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path) {
UISaveVideoAtPathToSavedPhotosAlbum(path, self, nil, nil)
}
}
}
I have no clue what is causing this strange error and cant find anything similar. I hope someone can help me.

Related

Trying to add UIImagePicker Moving to different ViewController and view is not in heirachy

What I am trying to do
I am trying to present a UIImagePicker to select an image from the phone's photo library
What is the issue
When I run the code I get this error message:
[Presentation] Attempt to present <UIImagePickerController: 0x160062000> on
<Nebula.SettingsViewController: 0x15f51b3c0> (from <Nebula.SettingsViewController:
0x15f51b3c0>) whose view is not in the window hierarchy.
It also navigates to the first View Controller of my app (even if this hasn't been shown before to the user in this session)
What have I tried to do to fix it
I used this post to try and use the topVC and present from there, this stops the error however still returns me to a different View Controller therefore doesn't allow me to run anymore code from the proper view controller
My code
#IBAction func pickTapped(_ sender: Any) {
let picker = UIImagePickerController()
picker.sourceType = .photoLibrary
picker.delegate = self
picker.allowsEditing = true
//let topVC = topMostController()
//topVC.present(picker, animated: true)
present(picker, animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
guard let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
print("No image selected")
return
}
guard let imageData = image.pngData() else {
print("Something wrong with image data")
return
}
}
top most VC code
func topMostController() -> UIViewController {
var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
while (topController.presentedViewController != nil) {
topController = topController.presentedViewController!
}
return topController
}

Why does my UIImageView replace the second one?

I have two outlets for two different UIImageViews, when I select the first one it'll appear on the first Image View but when I select the second Image, it replaces the first Image View even though it's connected to the second ImageView. This is my code for the Select Image button.
#IBOutlet weak var myImageView1: UIImageView!
#IBOutlet weak var myImageView2: UIImageView!
#IBAction func pickImage1(_ sender: Any) {
let image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.photoLibrary
image.allowsEditing = false
self.present(image, animated: true)
}
//Add didFinishPickingMediaWithInfo here
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
myImageView1.image = image
}
else {
//error
}
self.dismiss(animated: true, completion: nil)
}
#IBAction func pickImage2(_ sender: Any) {
let image2 = UIImagePickerController()
image2.delegate = self
image2.sourceType = UIImagePickerControllerSourceType.photoLibrary
image2.allowsEditing = false
self.present(image2, animated: true)
}
//Add didFinishPickingMediaWithInfo here
func imagePickerController2(_ picker2: UIImagePickerController, didFinishPickingMediaWithInfo2 info2: [String : Any]) {
if let image2 = info2[UIImagePickerControllerOriginalImage] as? UIImage {
myImageView2.image = image2
}
else {
//error
}
self.dismiss(animated: true, completion: nil)
}
Try this code. So you need a flag to remember which image view is clicked, and then set image base on that.
var selected = 1
#IBAction func pickImage1(_ sender: Any) {
let image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.photoLibrary
image.allowsEditing = false
selected = 1
self.present(image, animated: true)
}
//Add didFinishPickingMediaWithInfo here
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
if selected == 1 {
myImageView1.image = image
} else {
myImageView2.image = image
}
}
else {
//error
}
self.dismiss(animated: true, completion: nil)
}
#IBAction func pickImage2(_ sender: Any) {
let image2 = UIImagePickerController()
image2.delegate = self
image2.sourceType = UIImagePickerControllerSourceType.photoLibrary
image2.allowsEditing = false
selected = 2
self.present(image2, animated: true)
}
Moving forward, when you have multiple image views, you can use another method to avoid copying code everywhere.
First, add an unique tag for each image view. Avoid using 0 because the default tag is 0. So you will have image views with tags say 1 to 4.
Call this same method to all your image views so that this function is trigger by clicking on any of them
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
imageView.addGestureRecognizer(tapGestureRecognizer)
Handler looks like this
func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
let image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.photoLibrary
image.allowsEditing = false
let tappedImage = tapGestureRecognizer.view as! UIImageView
selected = tappedImage.tag
self.present(image, animated: true)
}
Finally in image pick delegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
if let imageView = self.view.viewWithTag(selected) as? UIImageView {
imageView.image = image
}
}
else {
//error
}
self.dismiss(animated: true, completion: nil)
}
The problem is that you have renamed the delegate method. If you do that, the method won't be recognized or called.
Another option to the selected answer is to extend UIImageView and have it adhere to UIImagePickerControllerDelegate / UINavigationControllerDelegate.
extension UIImageView: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
//handle error
return
}
image = selectedImage
picker.presentingViewController?.dismiss(animated: true)
}
func presentImagePicker(from viewController: UIViewController) {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
picker.allowsEditing = false
viewController.present(picker, animated: true)
}
}
This is nice because you can then launch the image picker for any UIImageView in your app with one line, like so:
#IBAction func pickImage1(_ sender: UIButton) {
myImageView1.presentImagePicker(from: self)
}

Photo capture permission problems in iOS 11

So here's my problem. I am trying to create a screen in which there is a UIImageView and a UIButton. When the user presses the button, the camera app opens, you take a photo and if you press "Use Photo" in the Camera app, you are returned to my app's screen and the photo is placed in the UIImageView I mentioned previously.
What happens so far is that when I press the "Use Photo" button, the image is correctly placed in my UIImageView but then the app crashes with the following error:
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryAddUsageDescription key with a string value explaining to the user how the app uses this data.
What I've done so far is:
Placed the key "Privacy - Photo Library Usage Description" with the value "$(PRODUCT_NAME) uses Library in order to process the photos you captured." in the Info.plist file (also checked how it is written in Source form and it's correct according to the Apple Developer Documentation).
Also placed the key "Privacy - Camera Usage Description" with the value "$(PRODUCT_NAME) uses Cameras" in the Info.plist file.
Checked under "TARGETS->->Info->Custom iOS Target Properties" and the 2 key/value pairs that I mentioned in steps 1 and 2, exist.
I will provide you with my code so far:
import UIKit
import Vision
import MobileCoreServices
import AVFoundation
import Photos
class ViewController: UIViewController, UIImagePickerControllerDelegate,
UINavigationControllerDelegate {
var newMedia: Bool?
#IBAction func captureImageButtonPressed(_ sender: Any) {
//let imageName : String = "dolphin"
//randomImageView.image = UIImage.init(named:imageName)
if UIImagePickerController.isSourceTypeAvailable(
UIImagePickerControllerSourceType.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType =
UIImagePickerControllerSourceType.camera
imagePicker.mediaTypes = [kUTTypeImage as String]
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true,
completion: nil)
newMedia = true
}
}
#IBAction func classifyButtonPressed(_ sender: UIButton) {
performVisionRequest()
}
#IBOutlet weak var randomImageView: UIImageView!
#IBOutlet weak var classificationLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
func performVisionRequest() {
let start = DispatchTime.now()
let model = Resnet50()
let request = VNImageRequestHandler(cgImage: randomImageView.image!.cgImage!, options: [:])
do {
let m = try VNCoreMLModel(for: model.model)
let coreMLRequest = VNCoreMLRequest(model: m) { (request, error) in
guard let observation = request.results?.first as? VNClassificationObservation else { return }
let stop = DispatchTime.now()
let nanoTime = stop.uptimeNanoseconds - start.uptimeNanoseconds
let timeInterval = Double(nanoTime)
self.classificationLabel.text = "\(observation.identifier) (\(observation.confidence * 100)%) in \(timeInterval) seconds."
}
try request.perform([coreMLRequest])
} catch {
print(error)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let mediaType = info[UIImagePickerControllerMediaType] as! NSString
self.dismiss(animated: true, completion: nil)
if mediaType.isEqual(to: kUTTypeImage as String) {
let image = info[UIImagePickerControllerOriginalImage]
as! UIImage
randomImageView.image = image
if (newMedia == true) {
UIImageWriteToSavedPhotosAlbum(image, self,
#selector(ViewController.image(image:didFinishSavingWithError:contextInfo:)), nil)
} else if mediaType.isEqual(to: kUTTypeMovie as String) {
// Code to support video here
}
}
}
#objc func image(image: UIImage, didFinishSavingWithError error: NSErrorPointer, contextInfo:UnsafeRawPointer) {
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.present(alert, animated: true,
completion: nil)
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.dismiss(animated: true, completion: nil)
}
}
Any idea why I get the above error in bold? Thank you very much in advance for your time.
NSPhotoLibraryAddUsageDescription was added in iOS 11.
Please add "Privacy - Photo Library Additions Usage Description" in info.plist with a usage description (string), like you did for the other privacy permissions.
Ref: https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html

Select video from PhotoLibrary in iOS using Swift

I am trying to select video from PhotoLibrary using following code
imageController.mediaTypes = [kUTTypeMovie: NSString]
After selecting video, when it is compressing, I am getting array out of boundary issue.
I searched online and found following line. I am unable to convert it into Swift version (link)
imageController.mediaTypes = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeMovie, nil]
Please let us know the Swift version for above line. It is very useful if anyone can provide Swift version of this.
Question2:
I want to show selected video in app and need to play when it is tapped. Can we do it without external plugins and using built in libraries?
Based on Swift 2.2
Suppose you have a imagePickerController and when you want to select both images and videos:
let imagePickerController = UIImagePickerController()
var videoURL: NSURL?
#IBAction func selectImageFromPhotoLibrary(sender: UIBarButtonItem) {
imagePickerController.sourceType = .PhotoLibrary
imagePickerController.delegate = self
imagePickerController.mediaTypes = ["public.image", "public.movie"]
presentViewController(imagePickerController, animated: true, completion: nil)
}
Then after the video is selected, print out its NSURL.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
videoURL = info["UIImagePickerControllerReferenceURL"] as? NSURL
print(videoURL)
imagePickerController.dismissViewControllerAnimated(true, completion: nil)
}
For question 2:
Yes, you can do it through AVPlayer, you need import AVKit and AVFoundation, and you code may look like this:
if let videoURL = videoURL{
let player = AVPlayer(URL: videoURL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
presentViewController(playerViewController, animated: true) {
playerViewController.player!.play()
}
}
I made a demo here you can refer, maybe not 100% what you want.
#IBOutlet weak var imgView: UIImageView!
var imagePickerController = UIImagePickerController()
var videoURL : NSURL?
#IBAction func btnSelectVideo_Action(_ sender: Any) {
imagePickerController.sourceType = .savedPhotosAlbum
imagePickerController.delegate = self
imagePickerController.mediaTypes = [kUTTypeMovie as String]
present(imagePickerController, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
videoURL = info[UIImagePickerControllerMediaURL]as? NSURL
print(videoURL!)
do {
let asset = AVURLAsset(url: videoURL as! URL , options: nil)
let imgGenerator = AVAssetImageGenerator(asset: asset)
imgGenerator.appliesPreferredTrackTransform = true
let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(0, 1), actualTime: nil)
let thumbnail = UIImage(cgImage: cgImage)
imgView.image = thumbnail
} catch let error {
print("*** Error generating thumbnail: \(error.localizedDescription)")
}
self.dismiss(animated: true, completion: nil)
}
For question 2:
let player = AVPlayer(url: videoURL)
let playerController = AVPlayerViewController()
playerController.player = player
self.present(playerController, animated: true) {
player.play()
}
Swift 5+ solution:
func openVideoGallery() {
picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .savedPhotosAlbum
picker.mediaTypes = ["public.movie"]
picker.allowsEditing = false
present(picker, animated: true, completion: nil)
}
Swift 3
import MobileCoreServices
var imagePickerController = UIImagePickerController()
var videoURL: URL?
private func openImgPicker() {
imagePickerController.sourceType = .savedPhotosAlbum
imagePickerController.delegate = self
imagePickerController.mediaTypes = ["public.movie"]
present(imagePickerController, animated: true, completion: nil)
}
extension YourViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
videoURL = info[UIImagePickerControllerMediaURL] as? URL
print("videoURL:\(String(describing: videoURL))")
self.dismiss(animated: true, completion: nil)
}
}
func openCamera() {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera) {
println("captureVideoPressed and camera available.")
var imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .Camera
imagePicker.mediaTypes = [kUTTypeMovie!]
imagePicker.allowsEditing = false
imagePicker.showsCameraControls = true
self.presentViewController(imagePicker, animated: true, completion: nil)
} else {
println("Camera not available.")
}
}
func imagePickerController( didFinishPickingMediaWithInfo info:NSDictionary!) {
videoUrl = info[UIImagePickerControllerMediaURL] as! NSURL!
let pathString = videoUrl.relativePath
self.dismissViewControllerAnimated(true, completion: nil)
}
Swift 4.0
Your class adopts the UIImagePickerControllerDelegate protocol
class classname: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate
After that you need to create
let imagePickerController = UIImagePickerController()
Add this in your button's action:-
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
imagePickerController.mediaTypes = ["public.image", "public.movie"]
present(imagePickerController, animated: true, completion: nil)
Delegate method
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let videoURL = info["UIImagePickerControllerReferenceURL"] as? NSURL
print(videoURL!)
imagePickerController.dismiss(animated: true, completion: nil)
}
Select a Video from Gallery using Swift 4
// Put this code where you want to pick the video from gallery
Let imagePickerController = UIImagePickerController ()
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
imagePickerController.mediaTypes = ["public.movie"]
present(imagePickerController, animated: true, completion: nil)
// UIImagePickerController Delegate Method
func imagePickerController (_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any])
{
let videoURL = info[UIImagePickerControllerMediaURL] as? NSURL
print(videoURL!)
self.dismiss(animated: true, completion: nil)
}
try this pod that i've made :
https://github.com/jhonyourangel/ImagePickerWhatsApp
I was searching for a similar Image and Video Picker for a project and i wasn't able to find one that was able to :
1. Take picture
2. Get a Picture from the library
3. Register a Video
4. Get a video from the library
While i was looking i hopen whatsup of facebook or mabe google have a pod for this kind of needs, i realy liked the whatsapp picker, so i created this one similer to the one in whatsapp.
Prerequisites
In order to use ImageVideoPicker you need cocoapods and an xCode project already created
Installing
to install cocoapods is should be enough just to run sudo gem install cocoapods in the terminal
if this doen't work go to cocoapods
Then navigate the terminal to your project folder, where the file extension .xcodeproj is located and run pod init
this will create a file called Podfile
Open the file in a editor ( sublimeText, xCode, atom, vim ... etc ) and add the line bellow after use_frameworks!
pod 'ImagePickerWhatsApp'
or
pod 'ImagePickerWhatsApp', :path => '/Users/aiu/Documents/cocoapods/ImagePickerWhatsApp'
then just run pod install in the terminal and wait to finish instaling the lib
How to use it
add import ImagePickerWhatsApp to your viewcontroller class
then you can call the picker by calling :
let mp = ImageVideoPicker.makeVCFromStoryboard()
self.present(mp, animated: true, completion: nil)
Delegate
to implement the delegate add mp.delegate = self and the extent the class of you view controller
aso you need to import the iOS Photos framework import Photos
extension ViewController: ImageVideoPickerDelegate {
func onCancel() {
print("no picture selected")
}
func onDoneSelection(assets: [PHAsset]) {
print("selected \(assets.count) assets")
}
}
the func onDoneSelection returns an array of assets that contain the info of where the asset is located : on the device, iTunes library or iCloud.
if you just need to display the images you can use the this code in a collection view or something similar just implement this peace of code
var representedAssetIdentifier: String!
func getImageFrom(asset: Phasset) {
representedAssetIdentifier = asset?.localIdentifier
let imageManager = PHCachingImageManager()
imageManager.requestImage(for: asset!, targetSize: self.frame.size, contentMode: .default, options: nil) { (image, _) in
if(self.representedAssetIdentifier == self.asset?.localIdentifier &&
image != nil) {
self.imageView.image = image
}
}
}
this will show just the thumbnail, but is awesome because is also showing the thumbnail for live photos, and videos
Images and Videos as Data
The lib is intended to be used for sending images or videos over the network, and not to do fancy image or video editing. But this doesn't mea you can't. You can do just about anything since it returns an array of assets, but is you job to implement what you need.
in order to get the data from the asset ImageVideoPicker has one method that will return an completition handler with the data.
ImageVideoPicker.getDataFrom(asset: asset) { (data) in
if data == nil {
print(data as Any, asset.mediaType, asset.localIdentifier)
} else {
print(data!.count as Any, asset.mediaType, asset.localIdentifier)
}
}
that will be all
have fun
func startMediaBrowserFromViewController(viewController: UIViewController!, usingDelegate delegate : protocol<UINavigationControllerDelegate, UIImagePickerControllerDelegate>!) -> Bool {
if UIImagePickerController.isSourceTypeAvailable(.SavedPhotosAlbum) == false {
return false
}
let mediaUI = UIImagePickerController()
mediaUI.sourceType = .SavedPhotosAlbum
mediaUI.mediaTypes = [kUTTypeMovie as String]
mediaUI.allowsEditing = true
mediaUI.delegate = delegate
presentViewController(mediaUI, animated: true, completion: nil)
return true
}
Updated for the current version of Swift:
// Check if the asset is of video media type.
guard (asset.mediaType == PHAssetMediaType.video) else {
print("Not a valid video media type")
return
}
// Obtain the URL of the video.
PHCachingImageManager().requestAVAsset(forVideo: asset, options: nil, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [AnyHashable : Any]?) in
let asset = asset as! AVURLAsset
print("asset.url: ", asset.url) // Here is video URL
// Play the video.
DispatchQueue.main.async(execute: {
let player = AVPlayer(url: asset.url)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
})
})
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
println("Camera Available")
var imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
imagePicker.allowsEditing = false
self.presentViewController(imagePicker, animated: true, completion: nil)
}
Delegate method
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!) {
self.dismissViewControllerAnimated(true, completion: nil)
imageView.image = image
}

Capture picture automatically in IOS

My requirement is to write a sample IOS app that would automatically capture a camera picture. Using the various S.O links provided I did implement the below code -
My CameraViewController.h class is defined as follows :
#interface CameraViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
#property (strong, nonatomic) IBOutlet UIImageView *ImageView;
#end
And CameraViewController.m has the below code :
-(void)viewDidAppear:(BOOL)animated
{
NSLog(#"Setting the background now");
UIImagePickerController *picker = [[UIImagePickerController alloc] init];picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
picker.cameraDevice = UIImagePickerControllerCameraDeviceRear;
picker.showsCameraControls = NO;
picker.navigationBarHidden = NO;
picker.toolbarHidden = NO;
[self presentViewController:picker animated:YES completion:NULL];
NSLog(#"Taking the picture now");
[picker takePicture];
}
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSLog(#"Entered the case of finishing pictures");
}
- (void) imagePickerControllerDidCancel: (UIImagePickerController *) picker
{
NSLog(#"Entered the case of cancel");
}
What the above code does is successfully launch the camera app , however I am not sure if the takePicture API is able to successfully click a picture . I do not see any saved pictures in the Photos app inside my Ipad so I assume that the picture has not been clicked .
Can someone please tell me if my code above is correct or what do I need to do to automate the part of clicking the capture button once the Camera controls are displayed
[Please go to 'Using UIImagePickerController to Select Pictures and Take Photos' in the Apple documentation for the property cameraOverlayView of class UIImagePickerController for a complete example application that does what you need, and more.]
You specified your CameraViewController as adopting the UIImagePickerControllerDelegate protocol and thus you must implement two messages:
- (void) imagePickerController: (UIImagePickerController *) picker
didFinishPickingMediaWithInfo: (NSDictionary *) info;
and
- (void) imagePickerControllerDidCancel: (UIImagePickerController *) picker;
As the iOS documentation describes, the NSDictionary* info has a key UIImagePickerControllerOriginalImage which will return the UIImage. Access it as something like:
UIImage *snapshot = (UIImage *) [info objectForKey: UIImagePickerControllerOriginalImage];
Since your plan is to take a picture automatically (w/o user interaction) using takePicture then be sure to specify
picker.showsCameraControls = NO;
You need to implement the UIImagePIckerControllerDelegate's imagePickerController:didFinishPickingMediaWithInfo: method.
After that, look inside the mediaInfo dictionary and there's a UIImage inside it you can use.
I know this is old, but a better alternative to using a timer (see the comments from the accepted answer) would be to implement the completion handler instead of passing in NULL.
[self presentViewController:picker animated:YES completion:^{
NSLog(#"Taking the picture now");
[picker takePicture];
}];
That way, the picture is taken consistently every time, and you don't waste time adding an unnecessary delay.
**You can auto capturing both camera image and video recording by use this code.**
import UIKit
import AVFoundation
import MobileCoreServices
class ViewController: UIViewController, UIGestureRecognizerDelegate {
let captureSession = AVCaptureSession()
var captureDevice : AVCaptureDevice?
var imagePicker = UIImagePickerController()
var flagVideoRecording = false
var arrImages = [UIImage]()
var countVideoRecording = 0
var labelTime = UILabel()
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(actionRepeatCapturing), name: .AVCaptureSessionDidStartRunning, object: nil)
}
#objc func actionRepeatCapturing() {
flagVideoRecording = false
startCapturingBothImageAndRecordView()
}
//MARK:- UIButton's Action
#IBAction func actionCaptureImage(_ sender: UIButton) {
flagVideoRecording = false
if AVCaptureDevice.authorizationStatus(for: AVMediaType.video) == AVAuthorizationStatus.authorized {
startCapturingBothImageAndRecordView()
} else {
AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { (granted: Bool) -> Void in
if granted == true {
self.startCapturingBothImageAndRecordView()
} else {
DispatchQueue.main.async {
self.alertToEncourageAccessInitially("Camera access required for capturing photos!", actionTitle: "Allow Camera")
}
}
})
}
}
#IBAction func actionCaptureVideo(_ sender: UIButton) {
flagVideoRecording = true
if AVCaptureDevice.authorizationStatus(for: AVMediaType.video) == AVAuthorizationStatus.authorized {
switch AVAudioSession.sharedInstance().recordPermission {
case AVAudioSession.RecordPermission.granted:
self.startCapturingBothImageAndRecordView()
case AVAudioSession.RecordPermission.denied:
self.alertToEncourageAccessInitially("Microphone access required for record your voice!", actionTitle: "Allow Microphone")
case AVAudioSession.RecordPermission.undetermined:
AVAudioSession.sharedInstance().requestRecordPermission({ (granted) in
if granted {
self.startCapturingBothImageAndRecordView()
} else {
self.alertToEncourageAccessInitially("Microphone access required for record your voice!", actionTitle: "Allow Microphone")
}
})
default:
break
}
} else {
AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { (granted: Bool) -> Void in
if granted == true {
switch AVAudioSession.sharedInstance().recordPermission {
case AVAudioSession.RecordPermission.granted:
self.startCapturingBothImageAndRecordView()
case AVAudioSession.RecordPermission.denied:
self.alertToEncourageAccessInitially("Microphone access required for record your voice!", actionTitle: "Allow Microphone")
case AVAudioSession.RecordPermission.undetermined:
AVAudioSession.sharedInstance().requestRecordPermission({ (granted) in
if granted {
self.startCapturingBothImageAndRecordView()
} else {
self.alertToEncourageAccessInitially("Microphone access required for record your voice!", actionTitle: "Allow Microphone")
}
})
default:
break
}
} else {
DispatchQueue.main.async {
self.alertToEncourageAccessInitially("Camera access required for record video", actionTitle: "Allow Camera")
}
}
})
}
}
}
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func startCapturingBothImageAndRecordView() {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) {
debugPrint("captureVideoPressed and camera available.")
imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .camera
if flagVideoRecording {
imagePicker.mediaTypes = [kUTTypeMovie as String]
imagePicker.allowsEditing = false
imagePicker.showsCameraControls = false
let viewTime = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 40))
viewTime.backgroundColor = .black
viewTime.alpha = 0.1
labelTime = UILabel(frame: CGRect(x: self.view.frame.width/2-50, y: 10, width: 100, height: 25))
labelTime.font = UIFont.boldSystemFont(ofSize: 17)
labelTime.text = "00.00:00"
labelTime.textColor = .white
labelTime.textAlignment = .center
labelTime.backgroundColor = .red
imagePicker.view.addSubview(viewTime)
imagePicker.view.addSubview(labelTime)
self.timer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(self.actionStopVideoRecording),
userInfo: nil,
repeats: true)
} else {
imagePicker.allowsEditing = false
imagePicker.showsCameraControls = false
}
} else {
debugPrint("Camera not available.")
}
self.present(self.imagePicker, animated: true, completion: {
if self.flagVideoRecording {
self.imagePicker.startVideoCapture()
} else {
self.imagePicker.takePicture()
}
})
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if flagVideoRecording {
if let videoFileURL = info[UIImagePickerController.InfoKey.mediaURL] as? URL {
debugPrint(videoFileURL)
// let data = try Data(contentsOf: videoFileURL, options: .mappedIfSafe)
// debugPrint(data)
}
self.dismiss(animated: true, completion: nil)
} else {
if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage{
arrImages.append(pickedImage)
}
sleep(1)
if arrImages.count >= 5 {
self.dismiss(animated: true, completion: nil)
} else {
NotificationCenter.default.post(name: .AVCaptureSessionDidStartRunning, object: nil, userInfo: nil)
}
}
}
#objc func actionStopVideoRecording() {
countVideoRecording += 1
labelTime.text = countVideoRecording == 10 ? "00:00:\(countVideoRecording)":"00:00:0\(countVideoRecording)"
if countVideoRecording == 10 {
imagePicker.stopVideoCapture()
timer?.invalidate()
timer = nil
}
}
}
extension ViewController {
func alertToEncourageAccessInitially(_ msgString: String, actionTitle: String) {
let alert = UIAlertController(
title: "IMPORTANT",
message: msgString,
preferredStyle: UIAlertController.Style.alert
)
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: actionTitle, style: .destructive, handler: { (alert) -> Void in
let myUrl = URL(string: UIApplication.openSettingsURLString)!
if let url = URL(string: "\(myUrl)"), !url.absoluteString.isEmpty {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
// or outside scope use this
guard let url = URL(string: "\(myUrl)"), !url.absoluteString.isEmpty else {
return
}
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}))
present(alert, animated: true, completion: nil)
}
}

Resources