1

I'm making a simple video capture app. I have used UIImageView as my preview layer as I may need to use CIFilter. But the problem is when image is converted from CIImage to UIImage and displayed in image view its orientation changes. How can I fix it

import UIKit
import  AVKit

class VideoCaptureVC: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {

 
    @IBOutlet weak var VideoPreviewImageView: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let capturesession = AVCaptureSession()
        guard let rearcamera = AVCaptureDevice.default(for: .video) else{return}
       // guard let mic = AVCaptureDevice.default(for: .audio) else{return}
        guard let inputdevice = try? AVCaptureDeviceInput(device: rearcamera) else {return}
        capturesession.addInput(inputdevice)
        
  
        
        /*let previewlayer = AVCaptureVideoPreviewLayer(session: capturesession)
        previewlayer.videoGravity = AVLayerVideoGravity.resizeAspect
        previewlayer.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
        previewlayer.frame = CGRect(x: 0, y: 0, width: 400, height: 200)
        VideoPreviewView.layer.addSublayer(previewlayer)*/
        
       let previewLayer = AVCaptureVideoPreviewLayer(session: capturesession)
        view.layer.addSublayer(previewLayer)
     
  
        let videoOutput = AVCaptureVideoDataOutput()
     
        
            
        
        
        videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoquueu"))
        capturesession.addOutput(videoOutput)
        capturesession.startRunning()

       
    }
    
    
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        
       let imagebuffer =  CMSampleBufferGetImageBuffer(sampleBuffer)
        let cameraimage = CIImage(cvPixelBuffer: imagebuffer!)
        
        DispatchQueue.main.async {
            self.VideoPreviewImageView.image = UIImage(ciImage: cameraimage)
           
           
        }
        
        
    }
    

    

}

[Here is my current video preview in image view][1]: https://i.stack.imgur.com/bJNpD.jpg

I was able to fix it by creating an extension

extension UIImage {
    
func fixOrientation() -> UIImage {
    if self.imageOrientation == UIImage.Orientation.up {
return self
}
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
    self.draw(in: CGRect(x:0,y: 0, width: self.size.width, height: self.size.height))
    let normalizedImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return normalizedImage;
}

And setting orientation to right

UIImage(ciImage: filteredimage,scale: 1.0,orientation: .right).fixOrientation()
stark
  • 41
  • 3

1 Answers1

3

There is another constructor for your UIImage which also inputs orientation:

UIImage(ciImage: cameraImage, scale: 1.0, orientation: orientation)

so what you are interested in is how to determine orientation. This depends on your application on what you are trying to achieve; some applications are locked in specific orientations and others change orientation depending on how user holds his device.

By default the camera should be in one of the two landscape orientations. I would expect that device orientation is landscape left (and user interface orientation landscape right) because that means naturally user should put his phone in landscape with home button on the right to take a photo. That position means that device is in landscape left while UI was rotated to landscape right (UI rotates the other way than device so that user may see it naturally).

Anyway you can do some trial and error to fill in your orientation by using one of few possible properties such as:

  • Device: UIDevice.current.orientation a bit tricky one as it can also be face-down or face-up
  • Status bar: UIApplication.shared.statusBarOrientation this one was mostly used but is now deprecated. It also takes in effect your support for view controller interface orientation support. It is usable in some cases but not in all
  • Scene: self.view.window!.windowScene!.interfaceOrientation I expect this is the replacement for the statusBarOrientation approach

Once you decide which to use for base orientation I suggest you simply try all cases with switch statement and apply correct rotations to your UIImage when constructing it. So for instance:

UIImage(ciImage: cameraImage, scale: 1.0, orientation: {
    switch UIDevice.current.orientation {
    case .landscapeRight: return .up
    case .landscapeLeft: return .down
    case .portrait: return .left
    case .portraitUpsideDown: return .right
    default: return .up
    }
}())
Matic Oblak
  • 16,318
  • 3
  • 24
  • 43
  • 1
    Hi thanks for your reply but for me I made my app as Portrait but camera view is in landscape when using a CIImage.Here is my screen shot https://i.stack.imgur.com/bJNpD.jpg – stark Aug 10 '21 at 09:42
  • @stark it appears to me that image needs to be rotated “right” in this case. So in the last last snipped I added you should swap values for portrait and portraitUpsideDown. Or if you wish to discard device orientation completely then you can simply use .right and there is no “switch” statement. – Matic Oblak Aug 10 '21 at 09:51
  • Thanks I was able to fix it. I have updated my solution – stark Aug 10 '21 at 10:40