7

How can you set a camera into landscape mode? Everytime I take a photo, the image gets saved as a portrait image. When the device is in landscape mode the photo looks fine but if I see it in the camera roll it's still portrait mode. This is my take photo function:

// take a photo
@IBAction func takePhoto(sender: AnyObject) {
self.fullScreenView.hidden = false
self.recordButton.enabled = false
self.takephoto.enabled = false
self.recordButton.hidden = true
self.takephoto.hidden = true

session.startRunning()

// customize the quality level or bitrate of the output photo
session.sessionPreset = AVCaptureSessionPresetPhoto

// add the AVCaptureVideoPreviewLayer to the view and set the view in fullscreen
fullScreenView.frame = view.bounds
videoPreviewLayer.frame = fullScreenView.bounds
fullScreenView.layer.addSublayer(videoPreviewLayer)

// add action to fullScreenView
gestureFullScreenView = UITapGestureRecognizer(target: self, action: #selector(ViewController.takePhoto(_:)))
self.fullScreenView.addGestureRecognizer(gestureFullScreenView)

// add action to myView
gestureView = UITapGestureRecognizer(target: self, action: #selector(ViewController.setFrontpage(_:)))
self.view.addGestureRecognizer(gestureView)

if (preview == true) {
    if let videoConnection = stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo) {
        // code for photo capture goes here...

        stillImageOutput?.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: { (sampleBuffer, error) -> Void in
            // process the image data (sampleBuffer) here to get an image file we can put in our view

            if (sampleBuffer != nil) {
                let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
                let image = UIImage(data: imageData, scale: 1.0)

                self.fullScreenView.hidden = true
                self.fullScreenView.gestureRecognizers?.forEach(self.fullScreenView.removeGestureRecognizer)
                self.session.stopRunning()

                // save image to the library
                UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil)

                self.imageViewBackground = UIImageView(frame: self.view.bounds)
                self.imageViewBackground.image = image
                self.imageViewBackground.tag = self.key

                self.view.addSubview(self.imageViewBackground)
            }
        })
    }
}
else {
    preview = true
}
}

My preview looks like that and that's ok:

http://img5.fotos-hochladen.net/uploads/bildschirmfotom4s7diaehy.png

but in the end it looks like that:

http://img5.fotos-hochladen.net/uploads/bildschirmfoto3c2rlwtevf.png

Thanks in advance!

mafioso
  • 1,630
  • 4
  • 25
  • 45

3 Answers3

1

Because your videoConnection's orientation is always in portrait no matters your device is in portrait or landscape. So you should adjust the videoConnection's orientation to the correct one before taking the still photo

Add the following method to get videoOrientation for the current deviceOrientation

func videoOrientation(for deviceOrientation: UIDeviceOrientation) -> AVCaptureVideoOrientation {
    switch deviceOrientation {
    case UIDeviceOrientation.portrait:
        return AVCaptureVideoOrientation.portrait
    case UIDeviceOrientation.landscapeLeft:
        return AVCaptureVideoOrientation.landscapeRight
    case UIDeviceOrientation.landscapeRight:
        return AVCaptureVideoOrientation.landscapeLeft
    case UIDeviceOrientation.portraitUpsideDown:
        return AVCaptureVideoOrientation.portraitUpsideDown
    default:
        return AVCaptureVideoOrientation.portrait
    }
}

Right after the following line

if let videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo) {

Add the following line

videoConnection.videoOrientation = videoOrientation(for: UIDevice.current.orientation)

Note: If your app supports only portrait or landscape mode, this issue still happens because UIDevice.current.orientation will always return the supported orientation. To overcome this, you can use CoreMotion to detect device orientation, then pass it to videoOrientation(for:) method.

Hope this helps :)

Binh Le
  • 486
  • 5
  • 12
  • 1
    For current swift version I did some small changes, but it works fine, I put it in my take picture function – zampnrs Jun 02 '20 at 16:44
1

I got the answer from @Yodagama but he didn't add how to detect the orientation

if let photoOutputConnection = self.photoOutput.connection(with: .video) {

                            // USE the below function HERE
    photoOutputConnection.videoOrientation = videoOrientation()
}
    
photoOutput.capturePhoto(with: settings, delegate: self)

func to detect device orientation:

func videoOrientation() -> AVCaptureVideoOrientation {
    
    var videoOrientation: AVCaptureVideoOrientation!
    
    let orientation: UIDeviceOrientation = UIDevice.current.orientation
    
    switch orientation {
        
    case .faceUp, .faceDown, .unknown:
        
        // let interfaceOrientation = UIApplication.shared.statusBarOrientation
        
        if let interfaceOrientation = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.windowScene?.interfaceOrientation {
            
            switch interfaceOrientation {
                
            case .portrait, .portraitUpsideDown, .unknown:
                videoOrientation = .portrait
            case .landscapeLeft:
                videoOrientation = .landscapeRight
            case .landscapeRight:
                videoOrientation = .landscapeLeft
            @unknown default:
                videoOrientation = .portrait
            }
        }
        
    case .portrait, .portraitUpsideDown:
        videoOrientation = .portrait
    case .landscapeLeft:
        videoOrientation = .landscapeRight
    case .landscapeRight:
        videoOrientation = .landscapeLeft
    @unknown default:
        videoOrientation = .portrait
    }
    
    return videoOrientation
}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
0

Possible Solution: Saving Image as JPEG instead of PNG

This occurs because PNGs do not store orientation information. Save the photo as a JPG instead and it will be oriented correctly.

Use this code to convert your image to JPG immediately after taking the image (the second line is the operative one here):

let image = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
let imageData:NSData = UIImageJPEGRepresentation(image, 0.9)! // 0.9 is compression value: 0.0 is most compressed/lowest quality and 1.0 is least compressed/highest quality

Source + more info: https://stackoverflow.com/a/34796890/5700898


If that doesn't work

I've edited your code in a couple places, see if the below code now works as you hope:

// initialize saving photo capabilities
func image(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo:UnsafePointer<Void>) {
        if error == nil {
            print("image saved")
        } else {
            print("save error: \(error?.localizedDescription)")
        }
}

// take a photo
@IBAction func takePhoto(sender: AnyObject) {
self.fullScreenView.hidden = false
self.recordButton.enabled = false
self.takephoto.enabled = false
self.recordButton.hidden = true
self.takephoto.hidden = true

session.startRunning()

// customize the quality level or bitrate of the output photo
session.sessionPreset = AVCaptureSessionPresetPhoto

// add the AVCaptureVideoPreviewLayer to the view and set the view in fullscreen
fullScreenView.frame = view.bounds
videoPreviewLayer.frame = fullScreenView.bounds
fullScreenView.layer.addSublayer(videoPreviewLayer)

// add action to fullScreenView
gestureFullScreenView = UITapGestureRecognizer(target: self, action: #selector(ViewController.takePhoto(_:)))
self.fullScreenView.addGestureRecognizer(gestureFullScreenView)

// add action to myView
gestureView = UITapGestureRecognizer(target: self, action: #selector(ViewController.setFrontpage(_:)))
self.view.addGestureRecognizer(gestureView)

if (preview == true) {
    if let videoConnection = stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo) {
        // code for photo capture goes here...

        stillImageOutput?.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: { (sampleBuffer, error) -> Void in
            // process the image data (sampleBuffer) here to get an image file we can put in our view

            if (sampleBuffer != nil) {
                self.stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
        if let videoConnection = self.stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo){
            videoConnection.videoOrientation = self.interfaceToVideoOrientation()
            self.stillImageOutput!.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: {
                (sampleBuffer, error) in
                let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
                let image = UIImage(data: imageData)

                self.fullScreenView.hidden = true
                self.fullScreenView.gestureRecognizers?.forEach(self.fullScreenView.removeGestureRecognizer)
                self.session.stopRunning()

                // save image to the library
                UIImageWriteToSavedPhotosAlbum(image, self, #selector(ViewController.image(_:didFinishSavingWithError:contextInfo:)), nil)

                self.imageViewBackground = UIImageView(frame: self.view.bounds)
                self.imageViewBackground.image = image
                self.imageViewBackground.tag = self.key

                self.view.addSubview(self.imageViewBackground)
            }
        })
    }
}
else {
    preview = true
}
}
Community
  • 1
  • 1
owlswipe
  • 19,159
  • 9
  • 37
  • 82
  • I think I save it as a JPEG or am I wrong? `let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)` – mafioso Aug 02 '16 at 12:38
  • @mafioso Try changing your imageData declaration to the one I made above, I'm not sure if yours works. If that doesn't fix your issue, I'll dig deeper ;). Just let me know. – owlswipe Aug 02 '16 at 12:44
  • ok I will try that ;) but I still have no clue why it works perfectly in portrait mode and not in landscape mode – mafioso Aug 02 '16 at 12:47
  • what should i do with the imageData ? – mafioso Aug 02 '16 at 12:51
  • Replace this line of code in your project (`let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)`) with the line I put in my answer above, @mafioso. – owlswipe Aug 02 '16 at 12:52
  • But this is the line of code where I get the photo so if I replace it I need an image parameter – mafioso Aug 02 '16 at 12:54
  • @mafioso I have presented you with your code but edited in a way that I think will make it work. Try all this code in your project and tell me how it all works (there might be errors, just let me know). – owlswipe Aug 02 '16 at 16:44