Saving Camera-Captured Picture to Photo with AVCaptureSession

How do you save a picture from the capture-screen with AVCaptureSession to Photo? My capture-screen looks like a square as show below.

Yet I've ended up with an 1080 × 1920 image as shown below. I have an iPhone XR, and I always end up with 1080 × 1920 images. How come the aspect ration never changes?

My code has the following lines

import UIKit
import AVFoundation

class CaptureViewController: UIViewController, AVCapturePhotoCaptureDelegate {
	var captureSession: AVCaptureSession!
	var cameraDevices: AVCaptureDevice!
	var imagePhotoOutput: AVCapturePhotoOutput!
	
	enum CameraCase {
		case front
		case back
	}
	
	
	// MARK: - IBAction
	@IBAction func takePictureTapped(_ sender: UIButton) {
		snapPicture()
	}
	
	
	// MARK: - Life cycle
	override func viewDidLoad() {
		super.viewDidLoad()
	}
	
	override func viewWillAppear(_ animated: Bool) {
		super.viewWillAppear(animated)
		
		prepareCamera(cameraCase: .back)
	}
	
	
	// MARK: - Camera
	func prepareCamera(cameraCase: CameraCase) {
		/* removing existing layers */
		if let sublayers = self.view.layer.sublayers {
			for sublayer in sublayers {
				if sublayer.isKind(of: AVCaptureVideoPreviewLayer.self) {
					sublayer.removeFromSuperlayer()
				}
			}
		}
		
		/* creating a capture session */
		captureSession = AVCaptureSession()
		
		guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: cameraCase == .front ? .front : .back).devices.first else { return }
		let videoInput = try? AVCaptureDeviceInput(device: device)
		if captureSession.canAddInput(videoInput!) {
			captureSession.addInput(videoInput!)
			imagePhotoOutput = AVCapturePhotoOutput() // setting output destination
			captureSession.addOutput(imagePhotoOutput) // adding photo output to session
		}
		
		/* creating a capture layer */
		let previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session: captureSession)
		previewLayer.frame = CGRect(x: 0.0, y: 200.0, width: view.frame.width, height: view.frame.height - 500.0)
		previewLayer.videoGravity = AVLayerVideoGravity.resize
		
		/* adding video capture layer to the view layer */
		self.view.layer.addSublayer(previewLayer)
		
		/* starting capture session */
		DispatchQueue.global(qos: .background).async {
			self.captureSession.startRunning()
		}
	}
	
	func snapPicture() {
		let settingsForMonitoring = AVCapturePhotoSettings()
		imagePhotoOutput?.capturePhoto(with: settingsForMonitoring, delegate: self as AVCapturePhotoCaptureDelegate)
	}
	
	
	// MARK: - Delegate methods
	func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
		if error == nil {
			guard let imageData = photo.fileDataRepresentation() else {
				print("Error while generating image from photo capture data.");
				return
			}
			
			if let image = UIImage(data: imageData) {
				saveImage(image)
			}
		}
	}
	
	
	// MARK: - Saving an image to Photo Library
	func saveImage(_ image: UIImage) {
		UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError: contextInfo:)), nil)
	}
	
	@objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
		if let error = error {
			print("An error has occurred: \(error.localizedDescription)")
		} else {
			print("Saved...")
		}
	}
}

Thanks.
Answered by Tomato in 740615022

I guess it's the matter of setting a preset to AVCaptureSession.

If I set the preset to

captureSession.sessionPreset = .hd1280x720

, I get a different image.

Accepted Answer

I guess it's the matter of setting a preset to AVCaptureSession.

Saving Camera-Captured Picture to Photo with AVCaptureSession
 
 
Q