UIImagePickerController摄像头视图在iOS 8上奇怪的旋转(图片)

我有一个非常简单的应用程序: – 所有的方向只允许一个屏幕上的button – button显示UIImagePickerController (拍摄照片) – 与Xcode 5和SDK 7构build

iOS 8上UIImagePickerController的相机无论是横向还是纵向显示都正确,但是当旋转设备时,我将相机视图旋转了90度,这里是一个示例:

  1. 我有我的应用程序肖像
  2. 我按下显示UIImagePickerController的button
  3. 我在相机视图,我去风景模式,这是我得到:

视野在风景中,但相机旋转了90度

别人已经有这个问题吗?

PS:如果我拍了一张照片(再次在风景中),照片被正确拍摄,现在正确显示:


编辑

这个错误似乎在运行iOS 8.1的iPad上得到修复,但在iOS 8.1发行说明中并没有涉及到这个错误: https : //developer.apple.com/library/content/releasenotes/General/RN-iOSSDK-8.1/

感谢所有针对早期版本iOS 8的build议修复!

我相信这是一个iOS 8的错误。 例如,如果您打开您的通讯录应用程序,然后点击编辑/添加照片/拍照,同样的问题发生在一个标准的iOS应用程序! 像我一样,将问题提交给Apple支持。

我发现了另一个非常好的解决scheme,目前我正在使用这个问题。 在使用UIImagePickerController捕获图像之后,您只需将图像作为方法传递给此方法即可。 它适用于iOS的所有版本,也适用于Camera的纵向和横向。 它使用UIImageOrientaiton检查图像的EXIF属性,并根据取向值转换和缩放图像,以便获得与相机视图方向相同方向的相同返回图像。

在这里,我保留了最高3000的分辨率,以便在使用视网膜设备时不会特意损坏图像质量,但是您可以按照您的要求更改其分辨率。

 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info; { UIImage *imagePicked = [info valueForKey:UIImagePickerControllerOriginalImage]; imagePicked = [self scaleAndRotateImage:imagePicked]; [[self delegate] sendImage:imagePicked]; [self.imagePicker dismissViewControllerAnimated:YES completion:nil]; } - (UIImage *) scaleAndRotateImage: (UIImage *)image { int kMaxResolution = 3000; // Or whatever CGImageRef imgRef = image.CGImage; CGFloat width = CGImageGetWidth(imgRef); CGFloat height = CGImageGetHeight(imgRef); CGAffineTransform transform = CGAffineTransformIdentity; CGRect bounds = CGRectMake(0, 0, width, height); if (width > kMaxResolution || height > kMaxResolution) { CGFloat ratio = width/height; if (ratio > 1) { bounds.size.width = kMaxResolution; bounds.size.height = bounds.size.width / ratio; } else { bounds.size.height = kMaxResolution; bounds.size.width = bounds.size.height * ratio; } } CGFloat scaleRatio = bounds.size.width / width; CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); CGFloat boundHeight; UIImageOrientation orient = image.imageOrientation; switch(orient) { case UIImageOrientationUp: //EXIF = 1 transform = CGAffineTransformIdentity; break; case UIImageOrientationUpMirrored: //EXIF = 2 transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0); transform = CGAffineTransformScale(transform, -1.0, 1.0); break; case UIImageOrientationDown: //EXIF = 3 transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height); transform = CGAffineTransformRotate(transform, M_PI); break; case UIImageOrientationDownMirrored: //EXIF = 4 transform = CGAffineTransformMakeTranslation(0.0, imageSize.height); transform = CGAffineTransformScale(transform, 1.0, -1.0); break; case UIImageOrientationLeftMirrored: //EXIF = 5 boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width); transform = CGAffineTransformScale(transform, -1.0, 1.0); transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0); break; case UIImageOrientationLeft: //EXIF = 6 boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeTranslation(0.0, imageSize.width); transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0); break; case UIImageOrientationRightMirrored: //EXIF = 7 boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeScale(-1.0, 1.0); transform = CGAffineTransformRotate(transform, M_PI / 2.0); break; case UIImageOrientationRight: //EXIF = 8 boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0); transform = CGAffineTransformRotate(transform, M_PI / 2.0); break; default: [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"]; } UIGraphicsBeginImageContext(bounds.size); CGContextRef context = UIGraphicsGetCurrentContext(); if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) { CGContextScaleCTM(context, -scaleRatio, scaleRatio); CGContextTranslateCTM(context, -height, 0); } else { CGContextScaleCTM(context, scaleRatio, -scaleRatio); CGContextTranslateCTM(context, 0, -height); } CGContextConcatCTM(context, transform); CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef); UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return imageCopy; } 

我发现了一个简单而准确的补丁来解决这个问题。 在呈现UIImagePickerController之前添加以下代码:

 if (iOS8_Device) { if([[UIDevice currentDevice]orientation] == UIDeviceOrientationFaceUp) { if([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { [[UIDevice currentDevice]setValue:[NSNumber numberWithInteger:UIDeviceOrientationLandscapeRight] forKey:@"orientation"]; } else { [[UIDevice currentDevice]setValue:[NSNumber numberWithInteger:UIDeviceOrientationLandscapeLeft] forKey:@"orientation"]; } } } 

你也需要inheritanceUIImagePickerController并重写下面的方法来更好地工作。

 - (BOOL)shouldAutorotate { [super shouldAutorotate]; return NO; } 

使用上面的代码后,它将适用于横向和横向,并且方向不会更改为UIDeviceOrientationFaceUp模式。

我相信这是一个iOS 8的bug,因为hitme提到。 我提交了关于联系人应用程序示例的Apple Ticket,并在此处打开了一个公开的雷达副本http://openradar.appspot.com/18416803

错误报告的详细信息
简介:在“联系人”应用程序中,如果用户将iPad设备以横向方式旋转,然后将设备放置在桌面上或将其与地面保持平齐,则摄像机取景器将以两侧黑条旋转90度。 用户可以拍下正确旋转的照片。 这是一个糟糕的用户体验,并导致用户在捕捉图像时遇到很多困难。

重现步骤:
1.打开联系人应用程序
2.将iPad旋转到风景模式
3.将iPad平放在桌子上
4.添加新联系人
5.添加照片>拍照6.拿起iPad

预期成绩:
图像捕捉取景器以横向模式全屏显示。

实际结果:
图像捕捉取景器旋转90度而不是全屏。

受影响的版本:iOS 8.0,8.0.2和8.1。

这个问题已经在与联系人应用程序的iOS 8.1testing中得到解决。 工作正常。

但是我发现另一个问题,

  1. 转到联系人应用程序
  2. 让你的设备像iPad相机面对地面。
  3. 添加联系人 – >拍照

使用FaceUp方向testing2 3次,相机视图将再次奇怪地开始旋转,如您在上面上传的图片中看到的。

正如@hitme所说,这是iOS 8中的一个bug,但是你可以通过设置-[UIImagePickerController cameraViewTransform]来解决这个问题:

 CGFloat angle; switch (interfaceOrientation) { case UIInterfaceOrientationLandscapeLeft: angle = M_PI_2; break; case UIInterfaceOrientationLandscapeRight: angle = -M_PI_2; break; case UIInterfaceOrientationPortraitUpsideDown: angle = M_PI; break; default: angle = 0; break; } imagePicker.cameraViewTransform = CGAffineTransformMakeRotation([UIApplication sharedApplication].statusBarOrientation); 

我有同样的问题,回到基础和创build一个新的项目,实际上工作..我追查到;

 -(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { // Had forgot to call the following.. [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; } 

希望能帮助到你。

我得到了同样的问题。 我在iOS 7.1.2和iOS 8上进行了testing。到目前为止,它只发生在iOS 8的iPad设备上。所以我暂时通过下面的代码修复它:

 // In my app, I subclass UIImagePickerController and code my own control buttons // showsCameraControls = NO; - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationPortrait] forKey:@"orientation"]; } 

这是不推荐的,因为它会搞乱呈现ViewController的方向。

苹果有答复吗?

不能等待苹果解决这个问题…

 - (void)viewWillAppear:(BOOL)animated { ... if (iPad & iOS 8) { switch (device_orientation) { case UIDeviceOrientationPortraitUpsideDown: self.cameraViewTransform = CGAffineTransformMakeRotation(DEGREES_RADIANS(180)); break; case UIDeviceOrientationLandscapeLeft: self.cameraViewTransform = CGAffineTransformMakeRotation(DEGREES_RADIANS(90)); break; case UIDeviceOrientationLandscapeRight: self.cameraViewTransform = CGAffineTransformMakeRotation(DEGREES_RADIANS(-90)); break; default: break; } } } 

我知道这是一个iOS的错误,但我已经实施了一个临时修复:

在呈现图像select器的视图中,如果您没有获取任何方向更改事件(或使用didRotateFromInterfaceOrientation otherwhise),请添加此代码:

 - (void)viewDidLoad { [super viewDidLoad]; // .... if ([[UIDevice currentDevice].systemVersion floatValue] >=8) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil]; } } 

现在旋转简单地解雇并代表你的imagepicker:

 - (void)didRotate:(NSNotification *)notification { if (self.presentedViewController && self.presentedViewController==self.imagePickerController) { [self dismissViewControllerAnimated:NO completion:^{ [self presentViewController:self.imagePickerController animated:NO completion:nil]; }]; } } 

工作有点粗糙,但这是我find的最好的解决scheme

以下是通过将此类别添加到UIImagePickerControllerfind的修复程序:

 @implementation UIImagePickerController (Rotation) - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { [self viewWillAppear:NO]; [self viewDidAppear:NO]; } - (void)viewWillDisappear:(BOOL)animated { [[UIApplication sharedApplication] setStatusBarHidden:NO]; } @end 

我意识到这是hacky直接调用UIViewController生命周期方法,但这是我find的唯一的解决scheme。 希望苹果能很快解决这个问题!

这是我用来修复我的应用程序的代码,如果摄像头以桌面上的设备启动时,将openCV摄像头旋转到横向位置。 相机需要强制进入肖像模式的应用程序才能正常工作。

 - (BOOL)shouldAutorotate { [super shouldAutorotate]; return NO; } -(void)viewDidAppear:(BOOL)animated { [super viewDidAppear: animated]; if([[UIDevice currentDevice]orientation] == UIDeviceOrientationFaceUp) { if([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { [[UIDevice currentDevice]setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:@"orientation"]; } else { [[UIDevice currentDevice]setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:@"orientation"]; } } }