2

I'm trying to get camera preview and photos working in a swiftUI app, I can display the preview and snap a photo but proportions are coming out wrong. The preview screen looks good, but as soon as the capture happens, it gets distorted and doesn't stay in portrait.

The preview screen looks like this:

enter image description here

Some code:

class CameraController: UIViewController {
    //...
    override func viewDidLoad() {
        //...
        // Setup preview layer
        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        previewLayer?.videoGravity = .resizeAspectFill
        previewLayer?.connection?.videoOrientation = .portrait
        previewLayer?.frame = view.frame
        view.layer.insertSublayer(previewLayer!, at: 0)
        //...
    }
}

But after I snap a photo, the Image I'm displaying in a VStack looks like:

enter image description here

The code is:

VStack {
    Image(uiImage: self.inputImage!)
        .resizable()
        .aspectRatio(contentMode: .fit)
        .edgesIgnoringSafeArea(.all)
}

I'm using .fit because I want to see the whole thing, and it's just coming out all wrong. Also, here's my camera setup code happening inside viewDidLoad:

captureSession.beginConfiguration()

// Get device
captureDevice = AVCaptureDevice.default(.builtInDualCamera, for: .video, position: .back)

do {
    // Create input
    let captureDeviceInput = try AVCaptureDeviceInput(device: captureDevice!)
    captureSession.addInput(captureDeviceInput)

    // Create output
    photoOutput = AVCapturePhotoOutput()
    captureSession.sessionPreset = .photo
    photoOutput?.setPreparedPhotoSettingsArray(
        [AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])],
        completionHandler: nil
    )
    captureSession.connections.first?.videoOrientation = .portrait // tested with and and without this line
    captureSession.addOutput(photoOutput!)
    captureSession.commitConfiguration()
} catch {
    print(error)
}

Any help much appreciated!

aliak
  • 428
  • 4
  • 12

1 Answers1

3

It returns only on landscape because the image which was taken with in-app camera has an orientation. You need to normalize it and display it.

I make an extension of UIImage with

func fixOrientation(img:UIImage) -> UIImage {

  if (img.imageOrientation == UIImageOrientation.Up) { 
      return img;
  }

  UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale);
  let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
  img.drawInRect(rect)

  let normalizedImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext();
  return normalizedImage;

}

Original answer from here: Normalize Pictures taken by camera

Also I just did a few changes to copy and paste solution for the ImagePickerManager:

ImagePickerManager

FrugalResolution
  • 568
  • 4
  • 18