Widok kamery UIImagePickerController dziwnie się obraca na iOS 8 (Zdjęcia)

Mam bardzo prostą aplikację: - Wszystkie orientacje są dozwolone tylko za pomocą przycisku na ekranie - Przycisk pokazuje UIImagePickerController (aby zrobić zdjęcie) - Buduj z Xcode 5 i SDK 7

Na iOS 8 , aparat UIImagePickerController pojawia się poprawnie, czy jestem w poziomie, czy w pionie, ale kiedy obrócę urządzenie, mam widok kamery obrócony o 90 stopni, oto przykład:

  1. mam swoją aplikację w portrecie
  2. wciskam przycisk, który pokazuje mi UIImagePickerController
  3. jestem w widoku kamery i przechodzę do trybu poziomego, oto co dostaję:

Widok jest w krajobrazie, ale kamera jest obracana o 90 stopni

Czy ktoś jeszcze ma już ten problem?

PS: a jeśli zrobię zdjęcie (znowu w krajobrazie), zdjęcie jest poprawnie zrobione i teraz poprawnie wyświetlone:


EDIT

Błąd wydaje się być naprawiony na moim iPadzie z systemem iOS 8.1, ale nic nie wydaje się powiązane do tego błędu w iOS 8.1 uwagi do wydania: https://developer.apple.com/library/content/releasenotes/General/RN-iOSSDK-8.1/

Dzięki wszystkim za proponowane poprawki dla wcześniejszych wersji iOS 8!

Author: Cœur, 2014-09-19

12 answers

Uważam, że to błąd iOS 8. Na przykład, jeśli otworzysz aplikację Kontakty i klikniesz Edytuj / Dodaj zdjęcie/Zrób zdjęcie, ten sam problem występuje w standardowej aplikacji na iOS! Opublikuj problem do pomocy technicznej Apple tak, jak ja.

 18
Author: hitme,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-19 21:43:33

Znalazłem inne bardzo dobre rozwiązanie tego problemu, z którego obecnie korzystam. Po przechwyceniu obrazu za pomocą interfejsu UIImagePickerController wystarczy przekazać obraz jako plik graficzny do tej metody. Działa dobrze dla wszystkich wersji iOS, a także dla orientacji pionowej i poziomej aparatu. Sprawdza właściwości Exif obrazu za pomocą UIImageOrientaiton i zgodnie z wartością orientacji, przekształca i skaluje obraz, dzięki czemu otrzymasz ten sam obraz powrotny z tym samym orientacja jako orientacja widoku kamery.

Tutaj zachowałem maksymalną rozdzielczość 3000, aby jakość obrazu nie została zepsuta specjalnie podczas korzystania z urządzeń retina, ale możesz zmienić jego rozdzielczość zgodnie z wymaganiami.

// 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!
    }
 15
Author: sajgan2015,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-03 11:27:05

Znalazłem łatwą i dokładną łatkę, aby rozwiązać ten problem. Dodaj następujący kod przed przedstawieniem interfejsu 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"];
                }
            }
}

Musisz również podklasować UIImagePickerController i nadpisać następującą metodę, jak poniżej, aby działać lepiej.

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

Po użyciu powyższego kodu będzie dobrze działać zarówno dla orientacji poziomej, jak i nie zostanie zmieniona orientacja na tryb UIDeviceOrientationFaceUp.

 5
Author: sajgan2015,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-20 13:45:02

Uważam, że jest to błąd iOS 8, jak wspomniał hitme. Złożyłem zgłoszenie Apple w odniesieniu do przykładu aplikacji Kontakty i zrobiłem otwartą kopię radaru tutaj http://openradar.appspot.com/18416803

Szczegóły zgłoszenia błędu
Podsumowanie: W aplikacji Kontakty jeśli użytkownik obróci urządzenie iPada w orientacji poziomej, a następnie położy urządzenie płasko na biurku lub utrzyma je na poziomie ziemi, Wizjer Kamery zostanie uruchomiony obrócony o 90 stopni z czarnymi paskami po bokach. Użytkownik może następnie zrobić zdjęcie, które wydaje się prawidłowo obrócone. Jest to straszne doświadczenie użytkownika i powoduje, że użytkownik ma wiele trudności w przechwytywaniu obrazu.

Kroki do odtworzenia:
1. Otwórz Aplikację Kontakty
2. Obróć iPada do trybu poziomego
3. Połóż iPada na płasko na biurku
4. Dodaj Nowy Kontakt
5. Dodaj Zdjęcie > Zrób Zdjęcie 6. Pick up the iPad

Oczekiwane Wyniki:
Wizjer do przechwytywania obrazu wyświetla się na pełnym ekranie zorientowane w trybie poziomym.

Rzeczywiste Wyniki:
Wizjer do przechwytywania obrazu jest obrócony o 90 stopni i nie jest Pełny ekran.

Dotyczy Wersji: iOS 8.0, 8.0.2 i 8.1.

 4
Author: Polar Bear,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-14 05:23:38

Problem został rozwiązany w iOS 8.1 Przetestowano za pomocą aplikacji Kontakty. działa dobrze.

Ale kolejny problem znalazłem,

  1. przejdź do aplikacji Kontakty
  2. Trzymaj urządzenie tak, jakby kamera iPada była zwrócona ku ziemi.
  3. Dodaj kontakt - > Zrób zdjęcie

Przetestuj go 2 3 razy z orientacją twarzy, widok kamery zacznie się dziwnie obracać, jak widać na zdjęciach przesłanych powyżej.

 3
Author: Mann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-22 07:35:47

Jak powiedział @ hitme, jest to błąd w iOS 8, ale możesz obejść problem, ustawiając -[UIImagePickerController cameraViewTransform] przed przedstawieniem:

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);
 1
Author: Austin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-12 16:49:09

Miałem ten sam problem i po powrocie do podstaw i stworzeniu nowego projektu, który faktycznie działał.. Namierzyłem to;

-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    // Had forgot to call the following..
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
Mam nadzieję, że to pomoże.
 1
Author: PaulB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-07 15:08:07

Mam ten sam problem. Testowałem na iOS 7.1.2 i iOS 8. Do tej pory zdarzyło się to tylko na urządzeniu iPad z iOS 8. Więc tymczasowo naprawiam go za pomocą następującego kodu:

// 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"];
}

Nie jest to zalecane, ponieważ zakłóci orientację presentingViewController.

Czy są już jakieś odpowiedzi od Apple?

 0
Author: Ray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-25 08:45:46

Nie można się doczekać, aż Apple naprawi problem...

- (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
Author: Ray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-09 05:35:53

Wiem, że to błąd iOS, ale zaimplementowałem tymczasową poprawkę:

W widoku prezentującym selektor obrazu, Dodaj ten kod, jeśli nie otrzymasz żadnych zdarzeń zmiany orientacji (lub użyj didRotateFromInterfaceOrientation otherwhise):

- (void)viewDidLoad {
   [super viewDidLoad];
   // ....

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

}

Teraz na rotacji po prostu Odrzuć i reprezentuj swój imagepicker:

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

Działa trochę szorstko, ale jest to najlepsze rozwiązanie, jakie znalazłem

 0
Author: Eliktz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-13 09:38:39

Oto poprawka, którą znalazłem dodając tę kategorię do 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

Zdaję sobie sprawę, że to hakerskie wywoływanie metod cyklu życia bezpośrednio, ale to jedyne rozwiązanie, jakie znalazłem. Mam nadzieję, że Apple wkrótce to naprawi!

 0
Author: Rowan Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-17 13:26:19

Jest to kod, którego użyłem do naprawy mojej aplikacji, która obracała kamerę openCV w krajobrazie, jeśli kamera została uruchomiona z urządzeniem na biurku w pozycji twarzą do góry. Aby aplikacja działała poprawnie, aparat musiał zostać włączony w tryb portretowy.

- (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"];
            }
        }
}
 0
Author: Cosworth66,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-09 01:17:30