【问题标题】:UIImagePickerController camera view rotating strangely on iOS 8 (pictures)UIImagePickerController 相机视图在 iOS 8 上奇怪地旋转(图片)
【发布时间】:2014-11-13 23:21:22
【问题描述】:

我有一个非常简单的应用程序: - 所有方向都允许在屏幕上只有一个按钮 - 按钮显示UIImagePickerController(拍照) - 使用 Xcode 5 和 SDK 7 构建

iOS 8 上,UIImagePickerController 的摄像头无论是横向还是纵向都可以正确显示,但是当我旋转设备时,我的摄像头视图旋转了 90 度,这是一个例子:

  1. 我的应用是纵向的
  2. 我按下显示UIImagePickerController 的按钮
  3. 我在相机视图中并进入横向模式,这是我得到的:

视图为横向,但相机旋转了 90 度

其他人是否已经遇到过这个问题?

PS:如果我拍一张照片(再次以横向拍摄),照片会正确拍摄并正确显示:


编辑

该错误似乎已在我运行 iOS 8.1 的 iPad 上得到修复,但在 iOS 8.1 发行说明中似乎没有与该错误相关:https://developer.apple.com/library/content/releasenotes/General/RN-iOSSDK-8.1/

感谢所有为早期版本的 iOS 8 提出的修复建议!

【问题讨论】:

  • 嗨 Kevin....你是在横向模式下启动相机吗?我面临的问题是我的 iPhone 应用程序处于纵向模式,在一个视图中我有一个相机按钮我只想在横向模式下启动相机。我用谷歌搜索,但没有运气。所以我需要一些想法或一些参考资料,以便我可以在我的项目中应用它。提前致谢:)
  • @wimcNilesh:这个问题不是关于以特殊方向启动相机,而是关于相机屏幕上的方向更改问题。
  • 好的。谢谢。再问一件事“我可以在我的 iPhone 应用程序中以横向模式启动我的相机吗,每个视图都处于纵向模式?”
  • @wimcNilesh:我不知道。您必须搜索答案或提出问题;)
  • .....没问题...但感谢您的快速响应。

标签: ios objective-c uiimagepickercontroller ios8 screen-rotation


【解决方案1】:

我相信这是 iOS 8 的错误。例如,如果您打开联系人应用程序并单击编辑/添加照片/拍照,标准 iOS 应用程序会出现同样的问题!像我一样将问题发布给 Apple 支持。

【讨论】:

  • 感谢您的帮助!我会立即将此问题发布给 Apple。
  • 可能值得指出的是它不会影响 iPhone 6 Plus,假设 6 也一样,似乎只影响我的 ipad Air,
  • 它不会影响我的 iPhone 5s,只会影响我的 iPad mini。我相信 iPad 中的错误
  • 我在运行 iPad 应用时遇到了同样的问题...您使用哪一代 iPad 时注意到了这个错误?它只出现在某些型号上吗?
  • 这个问题似乎在联系人应用程序中得到了解决。但我的应用仍然存在这个问题,即使在 8.1 中也是如此。
【解决方案2】:

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

在这里我保持了 3000 的最大分辨率,这样在您使用视网膜设备时图像质量不会受到特别破坏,但您可以根据需要更改其分辨率。

// 目标C代码:

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

// Swift 4.0 代码:

func scaleAndRotateImage(image: UIImage, MaxResolution iIntMaxResolution: Int) -> UIImage {
        let kMaxResolution = iIntMaxResolution
        let imgRef = image.cgImage!
        let width: CGFloat = CGFloat(imgRef.width)
        let height: CGFloat = CGFloat(imgRef.height)
        var transform = CGAffineTransform.identity
        var bounds = CGRect.init(x: 0, y: 0, width: width, height: height)

        if Int(width) > kMaxResolution || Int(height) > kMaxResolution {
            let ratio: CGFloat = width / height
            if ratio > 1 {
                bounds.size.width = CGFloat(kMaxResolution)
                bounds.size.height = bounds.size.width / ratio
            }
            else {
                bounds.size.height = CGFloat(kMaxResolution)
                bounds.size.width = bounds.size.height * ratio
            }
        }
        let scaleRatio: CGFloat = bounds.size.width / width
        let imageSize = CGSize.init(width: CGFloat(imgRef.width), height: CGFloat(imgRef.height))

        var boundHeight: CGFloat
        let orient = image.imageOrientation
        // The output below is limited by 1 KB.
        // Please Sign Up (Free!) to remove this limitation.

        switch orient {
        case .up:
            //EXIF = 1
            transform = CGAffineTransform.identity
        case .upMirrored:
            //EXIF = 2
            transform = CGAffineTransform.init(translationX: imageSize.width, y: 0.0)
            transform = transform.scaledBy(x: -1.0, y: 1.0)

        case .down:
            //EXIF = 3
            transform = CGAffineTransform.init(translationX: imageSize.width, y: imageSize.height)
            transform = transform.rotated(by: CGFloat(Double.pi / 2))

        case .downMirrored:
            //EXIF = 4
            transform = CGAffineTransform.init(translationX: 0.0, y: imageSize.height)
            transform = transform.scaledBy(x: 1.0, y: -1.0)
        case .leftMirrored:
            //EXIF = 5
            boundHeight = bounds.size.height
            bounds.size.height = bounds.size.width
            bounds.size.width = boundHeight
            transform = CGAffineTransform.init(translationX: imageSize.height, y: imageSize.width)

            transform = transform.scaledBy(x: -1.0, y: 1.0)
            transform = transform.rotated(by: CGFloat(Double.pi / 2) / 2.0)
            break

        default: print("Error in processing image")
        }

        UIGraphicsBeginImageContext(bounds.size)
        let context = UIGraphicsGetCurrentContext()
        if orient == .right || orient == .left {
            context?.scaleBy(x: -scaleRatio, y: scaleRatio)
            context?.translateBy(x: -height, y: 0)
        }
        else {
            context?.scaleBy(x: scaleRatio, y: -scaleRatio)
            context?.translateBy(x: 0, y: -height)
        }
        context?.concatenate(transform)
        context?.draw(imgRef, in: CGRect.init(x: 0, y: 0, width: width, height: height))
        let imageCopy = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return imageCopy!
    }

【讨论】:

    【解决方案3】:

    我找到了一个简单而准确的补丁来解决这个问题。在呈现 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"];
                    }
                }
    }
    

    您还需要继承 UIImagePickerController 并覆盖以下方法以更好地工作。

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

    使用上述代码后,它可以很好地用于横向,并且方向不会更改为 UIDeviceOrientationFaceUp 模式。

    【讨论】:

    • 但是OP的问题不是关于设备旋转后出现的方向问题吗?问题发生时 UIImagePickerController 已经出现了。
    • shouldAutorotate => NO 为我解决了这个问题。
    【解决方案4】:

    我相信这是我提到的 iOS 8 错误。我提交了一份关于联系人应用程序示例的 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。

    【讨论】:

    • Apple 将我报告的问题关闭为“Duplicate of 17075455 (Open)”。
    • 从 iOS 9 Beta 1 开始,此问题现已得到解决。它不再是“通讯录”应用中的问题。
    【解决方案5】:

    该问题已在 iOS 8.1 中修复 使用联系人应用程序测试。工作正常。

    但是我发现了另一个问题,

    1. 转到联系人应用程序
    2. 让您的设备像 ipad 相机一样面向地面。
    3. 添加联系人 -> 拍照

    用 FaceUp 方向测试它 2 3 次,相机视图将再次开始奇怪地旋转,如您在上面上传的图片中所见。

    【讨论】:

    • 确实如此。我编辑了我的问题让大家知道。我没有设法重现您的问题。你让 iPad 在竖屏模式下始终面向地面会遇到这个问题吗?
    • 我能够用 8.1 重现此问题 - 1) 握住 iPad,使联系人应用程序处于纵向模式 2) 打开相机 3) 将 iPad 平放在桌子上 4) 拿起 iPad 并旋转到横向5) 将 iPad 放回桌子上 6) 取消摄像头 7) 再次打开摄像头 - 你必须将 iPad 平放并拿起它并做一些愚蠢的事情,但它仍然会发生
    • @KevinHirsch 是的,让 iPad 面向地面。并尝试在景观中旋转它,正如克里斯所说,做一些愚蠢的事情。尝试多次关闭和打开相机。此问题将重现
    • @Mann 我会试试的!不要忘记发送错误报告;)
    【解决方案6】:

    正如@hitme 所说,这是 iOS 8 中的一个错误,但您可以通过在呈现之前设置 -[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);
    

    【讨论】:

    • 有趣...设置 cameraViewTransform 如您的 sn-p 所示实际上对我来说有点工作 - 它似乎解决了呈现相机问题后的旋转设备问题。但是它将所有视图旋转到 45° - 右侧为纵向,左侧为横向。此外,如果我注释掉这个开关,它的行为完全一样。然后我注意到你的 sn-p 中根本没有使用 CGFloat 角度。我们如何使用它?谢谢!
    【解决方案7】:

    我遇到了同样的问题,在回归基础并创建了一个实际有效的新项目之后。我追踪到它;

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

    希望对你有帮助。

    【讨论】:

      【解决方案8】:

      我遇到了同样的问题。我在 iOS 7.1.2 和 iOS 8 上都进行了测试。到目前为止,它只发生在 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"];
      }
      

      不推荐,因为它会弄乱presentingViewController的方向。

      Apple 有任何回复吗?

      【讨论】:

      • 苹果没有回复,遗憾的是这个问题在 8.0.2 更新中没有得到解决
      • iOS 8.1 beta 中也没有 :(
      • 我的问题已被苹果关闭为重复。
      【解决方案9】:

      等不及 Apple 解决问题...

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

      【讨论】:

        【解决方案10】:

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

        在显示图像选择器的视图上,如果您没有收到任何方向更改事件,请添加此代码(或使用 didRotateFromInterfaceOrientation 其他方式):

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

        现在轮换时只需关闭并代表您的图像选择器:

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

        工作有点粗糙,但这是我找到的最佳解决方案

        【讨论】:

          【解决方案11】:

          这是我通过将此类别添加到UIImagePickerController 找到的解决方法:

          @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
          

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

          【讨论】:

            【解决方案12】:

            这是我用来修复我的应用程序的代码,如果相机是在桌面上的设备以正面朝上位置启动的情况下将 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"];
                        }
                    }
            }
            

            【讨论】:

              猜你喜欢
              • 2011-09-27
              • 2014-11-13
              • 1970-01-01
              • 2015-07-08
              • 2012-02-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-09-24
              相关资源
              最近更新 更多