Tobe_Sta
Tobe_Sta

Reputation: 478

iOS: Back facing camera photos upside down, front facing photos right way up

My iPad app can only be used in landscape orientations. After what feels like I've looked at dozens of stack answers, I am unable to properly take a photo the right way up (the meta data corrects it but is only useful on macs). When the app is physically in LandscapeLeft it returns an upside down photo, whereas in LandscapeRight, it's correct.

As far as I can tell, setting VideoOrientation for the preview layer provides me the correct orientation when previewing the photo.

_capturePreview = [[ISCapturePreview alloc] init];
    [self addSubview:_capturePreview];

    // Session
    self.session = [AVCaptureSession new];
    [self.session setSessionPreset:AVCaptureSessionPresetPhoto];

    // Capture device
    AVCaptureDevice* inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    NSError *error;

    // Device input
    self.deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:&error];
    if ( [self.session canAddInput:self.deviceInput] )
        [self.session addInput:self.deviceInput];

    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

    // Preview
    AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
    [previewLayer setBackgroundColor:[[UIColor blackColor] CGColor]];
    [previewLayer.connection setVideoOrientation:(AVCaptureVideoOrientation)orientation];
    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    CALayer *rootLayer = [[self capturePreview] layer];
    [rootLayer setMasksToBounds:YES];
    [previewLayer setFrame:CGRectMake(0, 0, 1024, 600)];
    [rootLayer insertSublayer:previewLayer atIndex:0];

    AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    if ([self.session canAddOutput:stillImageOutput])
    {
        [stillImageOutput setOutputSettings:@{AVVideoCodecKey : AVVideoCodecJPEG}];
        [self.session addOutput:stillImageOutput];
        [self setStillImageOutput:stillImageOutput];
    }

    [self.session startRunning];

And the output code is here. Setting the VideoOrientation here in my tests has no impact.

    - (void)takePhotoButtonWasPressed:(id)sender{
[[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[(AVCaptureVideoPreviewLayer *)[[self capturePreview] layer] connection] videoOrientation]];

// Capture a still image.
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {

    if (imageDataSampleBuffer)
    {
        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [[UIImage alloc] initWithData:imageData];
}];}

Upvotes: 0

Views: 392

Answers (1)

jniegsch
jniegsch

Reputation: 420

I currently cannot test the code myself, but if you set the available orientations (in the project settings) to both landscapeLeft and landscapeRight, iOS might be handling the orientation itself, so try not setting the orientation. Furthermore if you change the orientation of the device after the view has loaded, you will be using the wrong orientation, so think of adding an observer to check for changes. In addition apple says you should use UITraitCollection and UITraitEnvironment instead of UIInterfaceOrientation starting with iOS8.

I hope this helps you :)

Upvotes: 0

Related Questions