I am trying to take few photos after a single user click on a Camera preview so I can present them and user can pick one that was timed best or use all in a "film strip" mode. The expected user experience is: "I open a camera, take a picture and then I see 5 pictures taken second by second. I do not have to press the 'take picture' button 5 times, one is just enough to start the sequence".
I am new to iOS and Swift and I base my work on a 'Swift Recipes' book (https://www.safaribooksonline.com/library/view/ios-8-swift/9781491908969/).
The source code to take a single photo is:
controller = UIImagePickerController()
if let theController = controller{
theController.sourceType = .Camera
theController.mediaTypes = [kUTTypeImage as NSString]
theController.allowsEditing = true
theController.delegate = self
presentViewController(theController, animated: true, completion: nil)
}
plus the relevant image handling (via func imagePickerController). I tried playing with the controller objecct above, but miserably failed :( I believe that this is not the right way to get what I look for, but I struggle to find the right one. Any help will be appreciated.
On iPhone XS, iPhone XR, and later models: Swipe the Shutter button to the left. On iPhone X and earlier models: Touch and hold the Shutter button. The counter shows how many shots you've taken.
To grab several at once, you can enter selection mode by long-pressing on one photo, and then tapping on other pictures or on a date. Doing the latter will automatically select all the images taken on a specific day.
It's actually really simple! Open the built-in iPhone Camera app. If you have iPhone XS, iPhone XR, iPhone 11, or iPhone 12, slide the shutter button to the left. The camera will keep taking photos until you release the shutter button.
I don't know if there is a mode for this behavior in UIImagePickerController
. If I were you I would use AVFoundation to implement this.
import UIKit
import AVFoundation
class ViewController: UIViewController {
var connection: AVCaptureConnection!
var output: AVCaptureStillImageOutput!
var videoPreviewLayer: AVCaptureVideoPreviewLayer!
@IBOutlet var videPreviewView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.createCamera()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.videoPreviewLayer.bounds = self.videPreviewView.bounds
self.videoPreviewLayer.position = CGPoint(x: CGRectGetMidX(self.videPreviewView.bounds), y: CGRectGetMidY(self.videPreviewView.bounds))
}
func createCamera() {
let captureSession = AVCaptureSession()
if captureSession.canSetSessionPreset(AVCaptureSessionPresetHigh) {
captureSession.sessionPreset = AVCaptureSessionPresetHigh
} else {
println("Error: Couldn't set preset = \(AVCaptureSessionPresetHigh)")
return
}
let cameraDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
var error: NSError?
let inputDevice = AVCaptureDeviceInput.deviceInputWithDevice(cameraDevice, error: &error) as AVCaptureDeviceInput
if let error = error {
println("Error: \(error)")
return
}
if captureSession.canAddInput(inputDevice) {
captureSession.addInput(inputDevice)
} else {
println("Error: Couldn't add input device")
return
}
let imageOutput = AVCaptureStillImageOutput()
if captureSession.canAddOutput(imageOutput) {
captureSession.addOutput(imageOutput)
} else {
println("Error: Couldn't add output")
return
}
// Store imageOutput. We will need it to take photo
self.output = imageOutput
let connection = imageOutput.connections.first as AVCaptureConnection!
// Store this connection in property. We will need it when we take image.
self.connection = connection
connection.videoOrientation = AVCaptureVideoOrientation.Portrait
captureSession.startRunning()
// This will preview the camera
let videoLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
videoLayer.contentsScale = UIScreen.mainScreen().scale
self.videPreviewView.layer.addSublayer(videoLayer)
// Store this layer instance in property. We will place it into a view
self.videoPreviewLayer = videoLayer
}
func takePhoto(completion: (UIImage?, NSError?) -> Void) {
self.output.captureStillImageAsynchronouslyFromConnection(self.connection) { buffer, error in
if let error = error {
completion(nil, error)
} else {
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
let image = UIImage(data: imageData, scale: UIScreen.mainScreen().scale)
completion(image, nil)
}
}
}
}
Now all you have to do is create an action that calls takePhoto
with 3 times. You can use NSTimer
to do this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With