UIImagePickerController camera view rotating strangely on iOS 8 (pictures)

后端 未结 12 1454
我寻月下人不归
我寻月下人不归 2020-12-07 16:34

I have a very simple application: - All orientations are permitted with only a button on a screen - The button show a UIImagePickerController (to take a photo)

相关标签:
12条回答
  • 2020-12-07 17:23

    I know it's an iOS bug, but i've implemented a temporary fix:

    on the view that presents the image picker, add this code if you don't get any orientation changes events (or use didRotateFromInterfaceOrientation otherwhise):

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

    now on rotation simply dismiss and represent your imagepicker:

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

    works a bit rough, but this is the best solution i've found

    0 讨论(0)
  • 2020-12-07 17:28

    Cannot wait for Apple to fix the issue...

    - (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;
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-07 17:29

    I believe that this is an iOS 8 Bug as hitme mentioned. I filed an Apple Ticket in regards to the example of the contacts app and made an open radar copy of it here http://openradar.appspot.com/18416803

    Details of Bug Report
    Summary: In the Contacts app if the user rotates the iPad device so its in landscape orientation and then lays the device flat on a desk or holds it level with the ground the Camera Viewfinder will be launched rotated 90 degrees with black bars on the sides. The user can then take the photo which appears correctly rotated. This is a terrible user experience and results in the user having lots of difficulty in capturing an image.

    Steps to Reproduce:
    1. Open Contacts App
    2. Rotate iPad to Landscape Mode
    3. Lay the iPad to flat on a desk
    4. Add New Contact
    5. Add Photo > Take Photo 6. Pick up the iPad

    Expected Results:
    Image Capture Viewfinder Displays in full screen oriented in Landscape mode.

    Actual Results:
    Image Capture Viewfinder is rotated 90 degrees and is not full screen.

    Versions Affected: iOS 8.0, 8.0.2, & 8.1.

    0 讨论(0)
  • 2020-12-07 17:30

    I have found an another very good solution for this issue which i am using currently. You just need to pass the image as an arugument to this method after capturing image using UIImagePickerController. It works well for all version of iOS and also for both portrait and landscape orientations of Camera. It checks for EXIF property of image using UIImageOrientaiton and accordind to the value of orientation, it transforms & scales the image so you will get the same return image with same orientation as your camera view orientation.

    Here i have kept maximum resolutions of 3000 so that the image quality doesn't get spoiled specially while you are using retina devices but you can change its resolution as per your requirement.

    // Objective C code:

    - (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 Code:

    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!
        }
    
    0 讨论(0)
  • 2020-12-07 17:33

    Here's a fix I've found by adding this category to 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
    

    I realise it is hacky calling UIViewController lifecycle methods directly, but this is the only solution I've found. Hopefully Apple will fix this soon!

    0 讨论(0)
  • 2020-12-07 17:34

    I had the same issue and after getting back to basics and creating a new project which actually worked.. I tracked it down to;

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

    Hope it helps.

    0 讨论(0)
提交回复
热议问题