iOS Development

swift – iOS Digicam didFinishProcessingPhoto at all times giving random incorrect orientations

Spread the love


I’ve created the under code instance which reproduces your complete subject.

Be aware that I’ve the iOS “Rotation lock” setting off in management centre.

Testing on iPhone 13 working iOS 17.

The picture orientation which is being set in imageViewForOutput is at all times incorrect.

After I take a photograph in regular portrait, the picture is flipped horizontally (aka the correct is showing on left aspect and left is showing on proper aspect). The orientation is being printed as 6.

After I flip my machine 90 diploma clockwise and take a pic, the picture being set is rotated 90 diploma anti-clockwise. The orientation is being printed as 3.

After I flip my machine 90 diploma anti-clockwise and take a pic, the picture being set is the wrong way up. The orientation is being printed as 1.

I do not know what’s making such random adjustments to orientation. I’ve adopted different stack overflow posts and am ensuring I’m setting the orientation adjustments on the photoOutput.

import UIKit
import SnapKit
import AVFoundation

class ViewController: UIViewController, AVCapturePhotoCaptureDelegate {
    
    var clickerButton = UIButton()
    var flipCameraButton = UIButton()
    var frontCameraDeviceInput: AVCaptureDeviceInput?
    var backCameraDeviceInput: AVCaptureDeviceInput?
    let captureSession = AVCaptureSession()
    let photoOutput = AVCapturePhotoOutput()
    let viewForCameraPreview = UIView()
    var previewLayer : AVCaptureVideoPreviewLayer?
    var imageViewForOutput = UIImageView()

    override func viewDidLoad() {
        tremendous.viewDidLoad()
        
        view.backgroundColor = .black
        
        view.addSubview(viewForCameraPreview)
        viewForCameraPreview.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        let padding = 15.0
        
        let buttonSize = 70.0
        
        
        clickerButton.addTarget(self, motion: #selector(clickPhoto(sender:)), for: .touchUpInside)
        view.addSubview(clickerButton)
        clickerButton.snp.makeConstraints { make in
            make.measurement.equalTo(buttonSize)
            make.centerX.equalToSuperview()
            make.backside.equalTo(view.safeAreaLayoutGuide.snp.backside).inset(padding)
        }
        clickerButton.layer.cornerRadius = buttonSize / 2
        clickerButton.clipsToBounds = true
        clickerButton.layer.borderColor = UIColor.white.cgColor
        clickerButton.layer.borderWidth = 5
        
        flipCameraButton.addTarget(self, motion: #selector(flipCamera(sender:)), for: .touchUpInside)
        flipCameraButton.setTitle("F", for: .regular)
        flipCameraButton.titleLabel?.font = UIFont.systemFont(ofSize: 50, weight: .daring)
        flipCameraButton.setTitleColor(.white, for: .regular)
        view.addSubview(flipCameraButton)
        flipCameraButton.snp.makeConstraints { make in
            make.measurement.equalTo(buttonSize)
            make.proper.equalTo(clickerButton.snp.left).inset(-padding)
            make.centerY.equalTo(clickerButton)
        }
        
        imageViewForOutput.layer.borderColor = UIColor.white.cgColor
        imageViewForOutput.layer.borderWidth = 2
        imageViewForOutput.contentMode = .scaleAspectFit
        view.addSubview(imageViewForOutput)
        imageViewForOutput.snp.makeConstraints { make in
            make.measurement.equalTo(200)
            make.high.equalTo(view.safeAreaLayoutGuide.snp.high).offset(padding)
            make.left.equalTo(view.safeAreaLayoutGuide.snp.left).offset(padding)
        }
        
        configureCameras()
        whichCameraStuff()
        startCamera()
    }
    
    @objc func flipCamera(sender: UIButton) {
        sender.isSelected = !sender.isSelected
        whichCameraStuff()
    }

    func configureCameras(){
        if let frontCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, place: .entrance) {
            frontCameraDeviceInput = strive? AVCaptureDeviceInput(machine: frontCamera)
        }
        if let backCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, place: .again) {
            backCameraDeviceInput = strive? AVCaptureDeviceInput(machine: backCamera)
        }
        photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey : AVVideoCodecType.jpeg])], completionHandler: nil)
        if captureSession.canAddOutput(photoOutput) {
            captureSession.addOutput(photoOutput)
        }
    }
    
    func whichCameraStuff(){
        captureSession.beginConfiguration()
        
        if flipCameraButton.isSelected {
            if let b = backCameraDeviceInput, captureSession.inputs.comprises(b) {
                captureSession.removeInput(b)
            }
            if let f = frontCameraDeviceInput, !captureSession.inputs.comprises(f) {
                captureSession.addInput(f)
            }
        } else {
            if let f = frontCameraDeviceInput, captureSession.inputs.comprises(f) {
                captureSession.removeInput(f)
            }
            if let b = backCameraDeviceInput, !captureSession.inputs.comprises(b) {
                captureSession.addInput(b)
            }
        }
        
        captureSession.commitConfiguration()
    }
    
    func startCamera(){
        DispatchQueue.world().async {
            self.captureSession.startRunning()
            self.addCameraPreviewIfNeeded()
        }
    }
    
    func addCameraPreviewIfNeeded(){
        DispatchQueue.foremost.async {
            if self.previewLayer == nil {
                self.previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
                if let pl = self.previewLayer {
                    pl.videoGravity = AVLayerVideoGravity.resizeAspectFill
                    pl.connection?.automaticallyAdjustsVideoMirroring = false
                    self.viewForCameraPreview.layer.insertSublayer(pl, at: 0)
                    pl.body = self.viewForCameraPreview.bounds
                    self.updateVideoOrientation()
                }
            }
            self.previewLayer?.isHidden = false
        }
    }
    
    func updateVideoOrientation() {
        guard let pl = self.previewLayer, let connection = pl.connection else {
            return
        }
        guard connection.isVideoOrientationSupported else {
            return
        }

        let videoOrientation = UIDevice.present.orientation.asCaptureVideoOrientation

        if connection.videoOrientation == videoOrientation {
            print("no change to videoOrientation")
            return
        }
        
        print("videoOrientation: (videoOrientation)")
        previewLayer?.connection?.videoOrientation = videoOrientation
        photoOutput.connection(with: AVMediaType.video)?.videoOrientation = videoOrientation
        previewLayer?.body = viewForCameraPreview.bounds
        previewLayer?.removeAllAnimations()
    }
    
    override func viewWillTransition(to measurement: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        tremendous.viewWillTransition(to: measurement, with: coordinator)

        coordinator.animate(alongsideTransition: nil, completion: { [weak self] (context) in
            DispatchQueue.foremost.async(execute: {
                self?.updateVideoOrientation()
            })
        })
    }
    
    @objc func clickPhoto(sender: UIButton) {
        guard captureSession.isRunning else {
            return
        }
        let settings = AVCapturePhotoSettings()
        settings.flashMode = .off
        photoOutput.capturePhoto(with: settings, delegate: self)
    }
    
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photograph: AVCapturePhoto, error: Error?) {
        if let e = error {
            print("Error: (e)")
        } else if let cgImage = photograph.cgImageRepresentation() {
            let orientation = photograph.metadata[kCGImagePropertyOrientation as String] as! NSNumber
            let imageOrientation = UIImage.Orientation(rawValue: orientation.intValue)!
            print("orientation: (orientation), imageOrientation: (imageOrientation)")
            let picture = UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation)
            imageViewForOutput.picture = picture
        }
    }
}

extension UIDeviceOrientation {
    var asCaptureVideoOrientation: AVCaptureVideoOrientation {
        change self {
        case .landscapeLeft: return .landscapeRight
        case .landscapeRight: return .landscapeLeft
        case .portraitUpsideDown: return .portraitUpsideDown
        default: return .portrait
        }
    }
}

One thought on “swift – iOS Digicam didFinishProcessingPhoto at all times giving random incorrect orientations

  1. obviously like your website but you need to test the spelling on quite a few of your posts Several of them are rife with spelling problems and I to find it very troublesome to inform the reality on the other hand Ill certainly come back again

Leave a Reply

Your email address will not be published. Required fields are marked *