Created
August 12, 2025 18:02
-
-
Save christianselig/350524e85be962974f0b07eb852dc68b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import AVFoundation | |
class ViewController: UIViewController, AVCapturePhotoCaptureDelegate { | |
var captureSession: AVCaptureSession! | |
var photoOutput: AVCapturePhotoOutput! | |
var previewLayer: AVCaptureVideoPreviewLayer! | |
var captureButton: UIButton! | |
var captureStartTime: Date? | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
setupCameraSession() | |
setupPreviewLayer() | |
setupCaptureButton() | |
} | |
func setupCameraSession() { | |
captureSession = AVCaptureSession() | |
captureSession.sessionPreset = .photo | |
let wideCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)! | |
let input = try! AVCaptureDeviceInput(device: wideCamera) | |
captureSession.addInput(input) | |
photoOutput = AVCapturePhotoOutput() | |
let prewarmSettings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg]) | |
prewarmSettings.photoQualityPrioritization = .speed | |
photoOutput.setPreparedPhotoSettingsArray([prewarmSettings]) { didCompletePrewarming, error in | |
print("Prewarming complete: \(didCompletePrewarming) with error: \(String(describing: error))") | |
} | |
if captureSession.canAddOutput(photoOutput) { | |
captureSession.addOutput(photoOutput) | |
} | |
captureSession.startRunning() | |
} | |
func setupPreviewLayer() { | |
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) | |
previewLayer.frame = view.bounds | |
previewLayer.videoGravity = .resizeAspectFill | |
view.layer.addSublayer(previewLayer) | |
} | |
func setupCaptureButton() { | |
captureButton = UIButton(type: .system) | |
captureButton.setTitle("Capture", for: .normal) | |
captureButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .largeTitle) | |
captureButton.backgroundColor = UIColor.systemBlue | |
captureButton.setTitleColor(.white, for: .normal) | |
captureButton.translatesAutoresizingMaskIntoConstraints = false | |
captureButton.addTarget(self, action: #selector(capturePhoto), for: .touchUpInside) | |
view.addSubview(captureButton) | |
NSLayoutConstraint.activate([ | |
captureButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), | |
captureButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), | |
]) | |
} | |
@objc func capturePhoto() { | |
captureStartTime = Date.now | |
let settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg]) | |
settings.photoQualityPrioritization = .speed | |
photoOutput.capturePhoto(with: settings, delegate: self) | |
} | |
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { | |
let callbackTime = Date.now | |
let elapsedTime = callbackTime.timeIntervalSince(captureStartTime!) | |
let image = UIImage(data: photo.fileDataRepresentation()!)! | |
print("Time from button tap to delegate callback: \(elapsedTime * 1000) ms. Image size: \(image.size)") | |
captureStartTime = nil | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment