13

Hello I need to disable the rotation of the UIImagePicker.
If the user takes picture when the iPhone is on "landscape" the buttons will rotate and the picture taken will also be rotated. I want to disable that option so the accelerometer will not work and it will always take picture like in portrait mode.
How can I do that?
Thanks, Matan Radomski.

Sam DeHaan
  • 10,246
  • 2
  • 40
  • 48
user1321887
  • 167
  • 1
  • 2
  • 7

4 Answers4

28

Here's the solution: [UIDevice endGeneratingDeviceOrientationNotifications].

Why was it so hard to find? Two reasons:

  1. The UIDevice keeps count of how many times orientation notifications are switched on or off. If it has been switched on more times than it's been switched off, notifications will still be issued.
  2. The UIImagePickerController switches these notifications on when it is presented.

So, calling this method once did nothing to the image picker. To make sure orientation notifications are off and stay off, you need to switch them off before and after the picker is presented.

This does not affect iOS or other apps. It doesn't even fully affect your own app: as with the other method I suggested, the camera buttons continue responding to orientation changes, and the photos taken are also orientation aware. This is curious, because the device orientation hardware is supposed to be switched off if it isn't needed.

@try 
{
    // Create a UIImagePicker in camera mode.
    UIImagePickerController *picker = [[[UIImagePickerController alloc] init] autorelease]; 
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;  
    picker.delegate = self; 

    // Prevent the image picker learning about orientation changes by preventing the device from reporting them.
    UIDevice *currentDevice = [UIDevice currentDevice];

    // The device keeps count of orientation requests.  If the count is more than one, it continues detecting them and sending notifications.  So, switch them off repeatedly until the count reaches zero and they are genuinely off.
    // If orientation notifications are on when the view is presented, it may slide on in landscape mode even if the app is entirely portrait.
    // If other parts of the app require orientation notifications, the number "end" messages sent should be counted.  An equal number of "begin" messages should be sent after the image picker ends.
    while ([currentDevice isGeneratingDeviceOrientationNotifications])
        [currentDevice endGeneratingDeviceOrientationNotifications];

    // Display the camera.
    [self presentModalViewController:picker animated:YES];

    // The UIImagePickerController switches on notifications AGAIN when it is presented, so switch them off again.
    while ([currentDevice isGeneratingDeviceOrientationNotifications])
        [currentDevice endGeneratingDeviceOrientationNotifications];
}
@catch (NSException *exception) 
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No Camera" message:@"Camera is not available" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
    [alert show];
    [alert release];
}

As noted above, the pictures taken may still be in the wrong orientation. If you want them oriented consistently, check their aspect ratio and rotate accordingly. I recommend this answer to How to Rotate a UIImage 90 degrees?

//assume that the image is loaded in landscape mode from disk
UIImage * landscapeImage = [UIImage imageNamed: imgname];
UIImage * portraitImage = [[UIImage alloc] initWithCGImage: landscapeImage.CGImage scale:1.0 orientation: UIImageOrientationLeft] autorelease];
Community
  • 1
  • 1
Cowirrie
  • 7,218
  • 1
  • 29
  • 42
  • Ok listen I'm the developer of change my face I've built it in flash air for iOS and than I recreated it in Xcode now for the problem this is how it should had looked like(my mouse was lying on the side imagine the scroll was a face.) http://i.imgur.com/mmyVh.png see? it fits right in like it was standing but this is how it looks like when the picture is saved and when the user wants to save it or retake it http://i.imgur.com/1LmgD.png see? it was totally rotated. can you help me please? – user1321887 Apr 17 '12 at 14:32
  • I did mention that exact problem at the end of this answer. There seems to be no way to prevent `UIImagePickerController` rotating your images after taking them. However, there are other ways to get camera data. More work is involved, but you have more control over the output. See [AVFoundation camera tutorial](http://stackoverflow.com/q/3643445/1318452). – Cowirrie Apr 17 '12 at 22:22
  • well ok.... (found new video of 2011 with iOS5) in the video library I didn't wanted to create my own GUI but I have to :/ Well thanks a lot! – user1321887 Apr 18 '12 at 17:51
  • You're the perfect solution for my 1 hour search agony! Thanks for sharing this! – haifacarina Nov 20 '12 at 14:53
  • Wonderful solution! Stopping the orientation change notifications worked for me. :) – Sufian Feb 28 '13 at 12:23
  • Hey Great! It works for me. but It doesn't give me an option to press cancel or use the photo. Can anyone give me an idea? Why I am facing this? – sumon Apr 12 '13 at 11:38
  • Man, you just made my day! I will buy you a beer when you visit Warsaw! ;) – Konrad Szczęśniak Jul 23 '13 at 08:47
  • Hey I've tested this in iOS 7 but it seems it is not enough in that case, anyone knows a solution for this under iOS 7? Thks! – lmt Dec 11 '13 at 04:32
  • With the combination of this answer and the next link,my question is solved.http://stackoverflow.com/questions/14437124/application-is-enabled-only-to-portrait-but-uiimagepickercontroller-rotates-in – tounaobun Mar 09 '15 at 11:16
  • This solution worked like a charm for years. Unfortunately on iOS 13, it causes the app to crash due to uncaught exception `’NSInternalInconsistencyException', reason: 'threading violation: expected the main thread'` when delegate calls `imagePickerController:didFinishPickingMediaWithInfo:` or `imagePickerControllerDidCancel:` – qfwfq Apr 10 '20 at 12:52
3

Back in 2010, How to prevent a modal UIImagePickerController from rotating? found no happy answer to this question.

I found an alternative, but it's also like to get you rejected from the App Store: remove all observers from the window.

If some part of your app outside a viewController needs orientation change messages, it can register for them:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]];

The window, not surprisingly, registers for such notifications, then rotates the view controllers if they accept the new orientation. It's not conveniently watching for UIDeviceOrientationDidChangeNotification, so there must be a privately named equivalent. All you can do is remove every notification from the window:

[[NSNotificationCenter defaultCenter] removeObserver:[[self view] window]];

There is no restoring this, if you just wanted to temporarily suppress orientation changes. Neither can we tell if the window was watching for any important notifications from other sources. It's incomplete, too - the button for turning over, and the button for taking a photo, move and rotate on their own.

Screenshot of iPad in landscape mode with camera UI still in portrait

How can you fix that quirk? You could switch off showsCameraControls on the UIImagePicker, and provide your own cameraOverlayView with the camera buttons on it. Or continue randomly removing notifications by traversing an entire view hierarchy (also rejection material) removing notifications from everything:

- (void) removeAllNotificationsFromView:(UIView*) view;
{
    // This recurses through the view hierarchy removing all notifications for everything.
    // This is potentially destructive, and may result in rejection from the App Store.
    [[NSNotificationCenter defaultCenter] removeObserver:view];
    for (UIView *subview in [view subviews])
        [self removeAllNotificationsFromView:subview];
}

[self removeAllNotificationsFromView:imagePicker.view];

I don't recommend using this, but it provides some interesting insights into how orientation changes are detected and propagated.

Community
  • 1
  • 1
Cowirrie
  • 7,218
  • 1
  • 29
  • 42
  • If this would cause my app to be rejected than I cannot use this. I need my app to be uploaded to the app store. do you know a way to do this without getting my app rejected? – user1321887 Apr 14 '12 at 14:41
  • 1
    If I had a better solution, would I write 274 words about this one? – Cowirrie Apr 14 '12 at 15:11
  • Looking closer at your question - is the real problem the UI being rotated, or the resulting images? Do you simply need to guarantee that all the pictures you save are in portrait orientation? That is achievable - just rotate them 90 degrees if their width is greater than their height. – Cowirrie Apr 14 '12 at 15:12
  • Ok listen I'm the developer of change my face I've built it in flash air for iOS and than I recreated it in Xcode now for the problem this is how it should had looked like(my mouse was lying on the side imagine the scroll was a face.) http://i.imgur.com/mmyVh.png see? it fits right in like it was standing but this is how it looks like when the picture is saved and when the user wants to save it or retake it http://i.imgur.com/1LmgD.png see? it was totally rotated. can you help me please? – user1321887 Apr 17 '12 at 14:32
1

None of the above solutions worked for me. What worked is this (for iOS 7 that i have tested it on)-

  1. Subclass UIImagePickerController

  2. Override shouldAutorotate method and return NO.

    -(BOOL)shouldAutorotate
    {
        return NO;
    }
Vikram Rao
  • 514
  • 3
  • 16
-3

Add following code to your view

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{
     return NO;
}
Akshay Aher
  • 2,525
  • 2
  • 18
  • 33
Ravi Kumar Karunanithi
  • 2,151
  • 2
  • 19
  • 41