La bla bla
La bla bla

Reputation: 8718

iOS taking photo programmatically

I know this is possible, saw this in some apps (iGotYa is I believe the most famous). I know how to set up everything for taking photos, saving it and everything. But how can it be done programmatically? just having the user click some button (in the regular view controller) and it will automatically take a picture using the front camera and saving it (or not, just getting it as a UIImage)

Thanks!

Upvotes: 29

Views: 55648

Answers (6)

Abhijith C R
Abhijith C R

Reputation: 1610

Here's a C# implementation for the same task, for Xamarin iOS.

    public void TakePhoto(Action<byte[]> getImageBytesAction)
    {
        var picker = new UIImagePickerController();
        picker.PrefersStatusBarHidden();
        picker.SourceType = UIImagePickerControllerSourceType.Camera;
        picker.CameraDevice = UIImagePickerControllerCameraDevice.Rear;
        
        picker.ShowsCameraControls = false;
        picker.CameraCaptureMode = UIImagePickerControllerCameraCaptureMode.Photo;
        picker.CameraFlashMode = UIImagePickerControllerCameraFlashMode.Off;

        picker.FinishedPickingMedia += (object sender, UIImagePickerMediaPickedEventArgs e) =>
        {
            var photo = e.OriginalImage;
            picker.DismissModalViewController(false);
            //var imageSource = ImageSource.FromStream(() => photo.AsJPEG().AsStream());
            //invoke the action when finished taking picture
            var correctedImage = new UIImage(photo.CGImage, 2.0f, UIImageOrientation.Up);   //scaling 2.0 makes image half
            getImageBytesAction.Invoke(correctedImage.AsJPEG().ToArray());
        };
        //open photo picker with TakePicture trigger on load completion (added a delay to let the camera adjust light and focus)
        GetTopViewController().PresentViewController(picker, false, async () => { await Task.Delay(1000); picker.TakePicture(); });
    }

Upvotes: 0

Nischal Hada
Nischal Hada

Reputation: 3288

Swift 5.2

For reference https://gist.github.com/hadanischal/33054429b18287c12ed4f4b8d45a1701

Info.plist

<key>NSCameraUsageDescription</key>
<string>Access camera</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Access PhotoLibrary</string>

AVFoundationHelper

import AVFoundation

enum CameraStatus {
    case notDetermined
    case restricted
    case denied
    case authorized
}

protocol AVFoundationHelperProtocol: AnyObject {
    // MARK: - Check and Respond to Camera Authorization Status

    var authorizationStatus: CameraStatus { get }

    // MARK: - Request Camera Permission

    func requestAccess(completionHandler handler: @escaping (Bool) -> Void)
}

final class AVFoundationHelper: AVFoundationHelperProtocol {
    // MARK: - Check and Respond to Camera Authorization Status

    var authorizationStatus: CameraStatus {
        let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
        switch cameraAuthorizationStatus {
        case .notDetermined:
            return CameraStatus.notDetermined
        case .authorized:
            return CameraStatus.authorized
        case .restricted:
            return CameraStatus.restricted
        case .denied:
            return CameraStatus.denied
        @unknown default:
            return CameraStatus.notDetermined
        }
    }

    // MARK: - Request Camera Permission

    func requestAccess(completionHandler handler: @escaping (Bool) -> Void) {
        AVCaptureDevice.requestAccess(for: .video, completionHandler: { accessGranted in
            handler(accessGranted)
        })
    }
}

ViewController

import UIKit

final class ViewController: UIViewController {
    @IBOutlet var cameraAccessButton: UIButton!
    @IBOutlet var photoImageView: UIImageView!

    private var model: AVFoundationHelperProtocol = AVFoundationHelper()

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func cameraButtonPressed(_: Any) {
        let status = model.authorizationStatus
        switch status {
        case .notDetermined:
            model.requestAccess { hasAccess in
                if hasAccess {
                    DispatchQueue.main.async {
                        self.showCameraReader()
                    }
                } else {
                    self.alertCameraAccessNeeded()
                }
            }
        case .restricted, .denied:
            alertCameraAccessNeeded()

        case .authorized:
            showCameraReader()
        }
    }

    private func alertCameraAccessNeeded() {
        let appName = "This app Name"

        let alert = UIAlertController(title: "This feature requires Camera Access",
                                      message: "In iPhone settings, tap \(appName) and turn on Camera access",
                                      preferredStyle: UIAlertController.Style.alert)

        let actionSettings = UIAlertAction(title: "Settings", style: .default, handler: { _ -> Void in
            guard let settingsAppURL = URL(string: UIApplication.openSettingsURLString) else { return }
            UIApplication.shared.open(settingsAppURL)
        })

        let actionCancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { _ -> Void in
        })

        alert.addAction(actionSettings)
        alert.addAction(actionCancel)

        present(alert, animated: true, completion: nil)
    }
}

extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    private func showCameraReader() {
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            let imagePicker = UIImagePickerController()
            imagePicker.sourceType = .camera
            imagePicker.allowsEditing = true
            imagePicker.delegate = self
            present(imagePicker, animated: true)

        } else if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
            let imagePicker = UIImagePickerController()
            imagePicker.sourceType = .photoLibrary
            imagePicker.allowsEditing = true
            imagePicker.delegate = self
            present(imagePicker, animated: true)

        } else {
            // TODO: Implement proper alert
            alertCameraAccessNeeded()
        }
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
        picker.dismiss(animated: true)

        guard let image = info[.editedImage] as? UIImage else {
            print("No image found")
            return
        }
        photoImageView.image = image
        // print out the image size as a test
        print(image.size)
    }
}

Objective C

In .h file

@interface ABCViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIImageView *imageView;

- (IBAction)takePhoto:  (UIButton *)sender;
- (IBAction)selectPhoto:(UIButton *)sender;

@end

In .m file

@interface ABCViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>

- (IBAction)takePhoto:(UIButton *)sender {


if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
    
        UIAlertView *myAlertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                        message:@"Device has no camera"
                                                        delegate:nil
                                                        cancelButtonTitle:@"OK"
                                                        otherButtonTitles: nil];
        
        [myAlertView show];
        
    } else {
    
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.delegate = self;
    picker.allowsEditing = YES;
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;
    
    [self presentViewController:picker animated:YES completion:NULL];

}
    
}

- (IBAction)selectPhoto:(UIButton *)sender {
    
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.delegate = self;
    picker.allowsEditing = YES;
    picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    
    [self presentViewController:picker animated:YES completion:NULL];

    
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    
    UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
    self.imageView.image = chosenImage;
    
    [picker dismissViewControllerAnimated:YES completion:NULL];
    
}


- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {

    [picker dismissViewControllerAnimated:YES completion:NULL];
    
}

Upvotes: -1

varender singh
varender singh

Reputation: 371

Here is the code for Objective -C Custom Camera. You can add features, buttons according to your wish.

#import "CustomCameraVC.h"

@interface CustomCameraVC ()  {
    BOOL frontCamera;
}
@property (strong,nonatomic) AVCaptureSession *captureSession;
@property (strong,nonatomic) AVCaptureStillImageOutput *stillImageOutput;
@property (strong,nonatomic) AVCaptureVideoPreviewLayer *videoPreviewLayer;
@property (weak, nonatomic) IBOutlet UIView *viewCamera;


@end

@implementation CustomCameraVC

- (void)viewDidLoad {
    [super viewDidLoad];        
}

-(void)viewWillAppear:(BOOL)animated  {
    [super viewWillAppear:YES];
    frontCamera = NO;
    [self showCameraWithFrontCamera:frontCamera];

}

-(void)showCameraWithFrontCamera:(BOOL)flag {
    self.captureSession = [[AVCaptureSession alloc]init];
    self.captureSession.sessionPreset = AVCaptureSessionPresetPhoto;
    AVCaptureDevice *captureDevice;
    if(flag)  {
      captureDevice= [self frontCamera];
    }
    else {
      captureDevice= [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    }
    NSError *error = nil;
    AVCaptureDeviceInput *input =   [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];

    [self.captureSession addInput:input];
    self.stillImageOutput = [AVCaptureStillImageOutput new];
    self.stillImageOutput.outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
    [self.captureSession addOutput:_stillImageOutput];
    self.videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];

    self.videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    self.videoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait;
    [self.viewCamera.layer addSublayer:self.videoPreviewLayer];
    [self.captureSession startRunning];
    self.videoPreviewLayer.frame = self.viewCamera.bounds;
}


- (AVCaptureDevice *)frontCamera {
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *device in devices) {
        if ([device position] == AVCaptureDevicePositionFront) {
            return device;
        }
    }
    return nil;
}


- (IBAction)btnCaptureImagePressed:(id)sender {

     AVCaptureConnection * videoConnection =  [_stillImageOutput connectionWithMediaType:AVMediaTypeVideo];

    [_stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef  _Nullable sampleBuffer, NSError * _Nullable error) {
       NSData *imageData =  [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:sampleBuffer];
        UIImage *image = [[UIImage alloc]initWithData: imageData];
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
    }];

}

@end

Upvotes: 2

GrandSteph
GrandSteph

Reputation: 2301

You can also do it without AVFoundation and it is in my opinion an easier way to implement it using only the UIImagePickerController. There are 3 conditions:

  1. Obviously the device needs to have a camera
  2. You must hide the camera controls
  3. Then simply use the takePicture method from UIImagePickerController

Below is a simple example that you woul typically trigger after a button push

- (IBAction)takePhoto:(id)sender 
{
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.delegate = self;
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;
    picker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
    picker.showsCameraControls = NO;
    [self presentViewController:picker animated:YES
                     completion:^ {
                         [picker takePicture];
                     }];
}

Upvotes: 15

samwize
samwize

Reputation: 27383

VLBCameraView is a library that uses AVFoundation to take photo.

A preview is shown in the view, which you can then call the method VLBCameraView#takePicture programmatically to take a photo.

Comes with CocoaPods.

Upvotes: 2

Pochi
Pochi

Reputation: 13459

This is very simple, just use the AVFoundation reference guide:

https://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/04_MediaCapture.html

If you don't want the user to see the preview input you can just skip the set preview layer part of the code.

Edit: To be more detailed.

1)You set your capture configuration using the AVFoundation.

  • Set the camera input to frontal, turn off flash etc etc.

2)You SKIP the part where the video preview layer is set.

3)You call the captureStillImageAsynchronouslyFromConnection:completionHandler: method whenever you want the picture to be taken.

Note: If you want the flash to not be heard and such then you might be violating the user rights in some countries (japan for example). One workaround I know of to do so is by capturing a frame of a video (does not trigger flash).

Upvotes: 25

Related Questions