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:
- mam swoją aplikację w portrecie
- wciskam przycisk, który pokazuje mi
UIImagePickerController
- 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!
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.
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!
}
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.
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.
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,
- przejdź do aplikacji Kontakty
- Trzymaj urządzenie tak, jakby kamera iPada była zwrócona ku ziemi.
- 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.
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);
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.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?
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;
}
}
}
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
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!
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"];
}
}
}
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