3

I am working on a custom camera app and the tutorial uses AVCaptureStillImageOutput, which is deprecated for ios 10. I have set up the camera and am now stuck on how to take the photo

Here is my full view where i have the camera

import UIKit
import AVFoundation

var cameraPos = "back"

class View3: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate {


@IBOutlet weak var clickButton: UIButton!
@IBOutlet var cameraView: UIView!
var session: AVCaptureSession?
var stillImageOutput: AVCapturePhotoOutput?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?

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

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

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    clickButton.center.x = cameraView.bounds.width/2
    loadCamera()
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
 }

@IBAction func clickCapture(_ sender: UIButton) {

    if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) {
       // This is where I need help 
        }
}

@IBAction func changeDevice(_ sender: UIButton) {
    if cameraPos == "back"
    {cameraPos = "front"}

    else
    {cameraPos = "back"}


    loadCamera()
}

func loadCamera()
{
    session?.stopRunning()
    videoPreviewLayer?.removeFromSuperlayer()

    session = AVCaptureSession()
    session!.sessionPreset = AVCaptureSessionPresetPhoto

    var backCamera = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .front)

    if cameraPos == "back"
    {
        backCamera = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera, mediaType: AVMediaTypeVideo, position: .back)
    }

    var error: NSError?
    var input: AVCaptureDeviceInput!
    do {
        input = try AVCaptureDeviceInput(device: backCamera)
    } catch let error1 as NSError {
        error = error1
        input = nil
        print(error!.localizedDescription)
    }

    if error == nil && session!.canAddInput(input) {
        session!.addInput(input)

        stillImageOutput = AVCapturePhotoOutput()

if session!.canAddOutput(stillImageOutput) {
            session!.addOutput(stillImageOutput)
            videoPreviewLayer = AVCaptureVideoPreviewLayer(session: session)
            videoPreviewLayer?.frame = cameraView.bounds
            videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
            videoPreviewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.portrait

            cameraView.layer.addSublayer(videoPreviewLayer!)
            session!.startRunning()

        }        }
}
}

This is where i need help

@IBAction func clickCapture(_ sender: UIButton) {

if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo) {
   // This is where I need help 
    }
}

I have gone through the answer here How to use AVCapturePhotoOutput but i do not understand how to incorporate that code in this code, as it involves declaring a new class

Community
  • 1
  • 1
charak
  • 187
  • 3
  • 15

1 Answers1

5

You are almost there.

For Output as AVCapturePhotoOutput

Check out AVCapturePhotoOutput documentation for more help.

These are the steps to capture a photo.

  1. Create an AVCapturePhotoOutput object. Use its properties to determine supported capture settings and to enable certain features (for example, whether to capture Live Photos).
  2. Create and configure an AVCapturePhotoSettings object to choose features and settings for a specific capture (for example, whether to enable image stabilization or flash).
  3. Capture an image by passing your photo settings object to the capturePhoto(with:delegate:) method along with a delegate object implementing the AVCapturePhotoCaptureDelegate protocol. The photo capture output then calls your delegate to notify you of significant events during the capture process.

have this below code on your clickCapture method and don't forgot to confirm and implement to delegate in your class.

let settings = AVCapturePhotoSettings()
let previewPixelType = settings.availablePreviewPhotoPixelFormatTypes.first!
let previewFormat = [kCVPixelBufferPixelFormatTypeKey as String: previewPixelType,
                             kCVPixelBufferWidthKey as String: 160,
                             kCVPixelBufferHeightKey as String: 160,
                             ]
settings.previewPhotoFormat = previewFormat
self.cameraOutput.capturePhoto(with: settings, delegate: self)

For Output as AVCaptureStillImageOutput

if you intend to snap a photo from video connection. you can follow the below steps.

Step 1: Get the connection

if let videoConnection = stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo) {
  // ...
  // Code for photo capture goes here...
}

Step 2: Capture the photo

  • Call the captureStillImageAsynchronouslyFromConnection function on the stillImageOutput.
  • The sampleBuffer represents the data that is captured.

stillImageOutput?.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: { (sampleBuffer, error) -> Void in
  // ...
  // Process the image data (sampleBuffer) here to get an image file we can put in our captureImageView
})

Step 3: Process the Image Data

  • We will need to to take a few steps to process the image data found in sampleBuffer in order to end up with a UIImage that we can insert into our captureImageView and easily use elsewhere in our app.

if sampleBuffer != nil {
  let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
  let dataProvider = CGDataProviderCreateWithCFData(imageData)
  let cgImageRef = CGImageCreateWithJPEGDataProvider(dataProvider, nil, true, CGColorRenderingIntent.RenderingIntentDefault)
  let image = UIImage(CGImage: cgImageRef!, scale: 1.0, orientation: UIImageOrientation.Right)
  // ...
  // Add the image to captureImageView here...
}

Step 4: Save the image

Based on your need either save the image to photos gallery or show that in a image view


For more details check out Create custom camera view guide under Snap a Photo

Bluewings
  • 3,438
  • 3
  • 18
  • 31
  • 1
    the captureStillImageAsynchronouslyFromConnection function is not a member of AVCapturePhotoOutput, it is of AVCaptureStillImageOutput – charak Dec 14 '16 at 07:13
  • `captureStillImageAsynchronouslyFromConnection` is to take photo from a video with custom camera. and `AVCapturePhotoOutput` is used to take picture directly – Bluewings Dec 14 '16 at 07:16
  • but having stillImageOutput as an object of AVCapturePhotoOutput, and then stillImageOutput?.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: { (sampleBuffer, error) -> Void in gives error – charak Dec 14 '16 at 07:18
  • you have to choose the image output ..it can be either `AVCaptureStillImageOutput` or `AVCapturePhotoOutput ` or you can have two outputs as well. then follow the steps mentioned above. – Bluewings Dec 14 '16 at 07:24
  • it will give error for sure as it is member of `AVCaptureStillImageOutput` and not `AVCapturePhotoOutput`. If you want to use `AVCaptureStillImageOutput` you have to follow [this](https://developer.apple.com/reference/avfoundation/avcapturephotooutput)..Remember there is two ways here.. Dont get confused – Bluewings Dec 14 '16 at 07:26
  • I want to use AVCapturePhotoOutput and not AVCaptureStillImageOutput – charak Dec 14 '16 at 08:28
  • then follow above first step which confirms to delegate `AVCapturePhotoCaptureDelegate` .. i edited the answer. – Bluewings Dec 14 '16 at 08:31