5
votes

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!

2

2 Answers

1
votes

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 :)

0
votes

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
}
}